1 /*
2 * HPPA emulation cpu helpers for qemu.
3 *
4 * Copyright (c) 2016 Richard Henderson <rth@twiddle.net>
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #include "qemu/osdep.h"
21 #include "qemu/log.h"
22 #include "cpu.h"
23 #include "fpu/softfloat.h"
24 #include "exec/helper-proto.h"
25 #include "qemu/qemu-print.h"
26 #include "hw/hppa/hppa_hardware.h"
27
cpu_hppa_get_psw(CPUHPPAState * env)28 target_ulong cpu_hppa_get_psw(CPUHPPAState *env)
29 {
30 target_ulong psw;
31 target_ulong mask1 = (target_ulong)-1 / 0xf;
32 target_ulong maskf = (target_ulong)-1 / 0xffff * 0xf;
33
34 /* Fold carry bits down to 8 consecutive bits. */
35 /* ^^^b^^^c^^^d^^^e^^^f^^^g^^^h^^^i^^^j^^^k^^^l^^^m^^^n^^^o^^^p^^^^ */
36 psw = (env->psw_cb >> 4) & mask1;
37 /* .......b...c...d...e...f...g...h...i...j...k...l...m...n...o...p */
38 psw |= psw >> 3;
39 /* .......b..bc..cd..de..ef..fg..gh..hi..ij..jk..kl..lm..mn..no..op */
40 psw |= psw >> 6;
41 psw &= maskf;
42 /* .............bcd............efgh............ijkl............mnop */
43 psw |= psw >> 12;
44 /* .............bcd.........bcdefgh........efghijkl........ijklmnop */
45 psw |= env->psw_cb_msb << 39;
46 /* .............bcd........abcdefgh........efghijkl........ijklmnop */
47
48 /* For hppa64, the two 8-bit fields are discontiguous. */
49 if (hppa_is_pa20(env)) {
50 psw = (psw & 0xff00000000ull) | ((psw & 0xff) << 8);
51 } else {
52 psw = (psw & 0xff) << 8;
53 }
54
55 psw |= env->psw_n * PSW_N;
56 psw |= ((env->psw_v >> 31) & 1) * PSW_V;
57 psw |= env->psw | env->psw_xb;
58
59 return psw;
60 }
61
update_gva_offset_mask(CPUHPPAState * env)62 void update_gva_offset_mask(CPUHPPAState *env)
63 {
64 uint64_t gom;
65
66 if (env->psw & PSW_W) {
67 gom = (env->dr[2] & HPPA64_DIAG_SPHASH_ENABLE)
68 ? MAKE_64BIT_MASK(0, 62) &
69 ~((uint64_t)HPPA64_PDC_CACHE_RET_SPID_VAL << 48)
70 : MAKE_64BIT_MASK(0, 62);
71 } else {
72 gom = MAKE_64BIT_MASK(0, 32);
73 }
74
75 env->gva_offset_mask = gom;
76 }
77
cpu_hppa_put_psw(CPUHPPAState * env,target_ulong psw)78 void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
79 {
80 uint64_t reserved;
81 target_ulong cb = 0;
82
83 /* Do not allow reserved bits to be set. */
84 if (hppa_is_pa20(env)) {
85 reserved = MAKE_64BIT_MASK(40, 24) | MAKE_64BIT_MASK(28, 4);
86 reserved |= PSW_G; /* PA1.x only */
87 reserved |= PSW_E; /* not implemented */
88 } else {
89 reserved = MAKE_64BIT_MASK(32, 32) | MAKE_64BIT_MASK(28, 2);
90 reserved |= PSW_O | PSW_W; /* PA2.0 only */
91 reserved |= PSW_E | PSW_Y | PSW_Z; /* not implemented */
92 }
93 psw &= ~reserved;
94
95 env->psw = psw & (uint32_t)~(PSW_B | PSW_N | PSW_V | PSW_X | PSW_CB);
96 env->psw_xb = psw & (PSW_X | PSW_B);
97 env->psw_n = (psw / PSW_N) & 1;
98 env->psw_v = -((psw / PSW_V) & 1);
99
100 env->psw_cb_msb = (psw >> 39) & 1;
101 cb |= ((psw >> 38) & 1) << 60;
102 cb |= ((psw >> 37) & 1) << 56;
103 cb |= ((psw >> 36) & 1) << 52;
104 cb |= ((psw >> 35) & 1) << 48;
105 cb |= ((psw >> 34) & 1) << 44;
106 cb |= ((psw >> 33) & 1) << 40;
107 cb |= ((psw >> 32) & 1) << 36;
108 cb |= ((psw >> 15) & 1) << 32;
109 cb |= ((psw >> 14) & 1) << 28;
110 cb |= ((psw >> 13) & 1) << 24;
111 cb |= ((psw >> 12) & 1) << 20;
112 cb |= ((psw >> 11) & 1) << 16;
113 cb |= ((psw >> 10) & 1) << 12;
114 cb |= ((psw >> 9) & 1) << 8;
115 cb |= ((psw >> 8) & 1) << 4;
116 env->psw_cb = cb;
117
118 update_gva_offset_mask(env);
119 }
120
hppa_cpu_dump_state(CPUState * cs,FILE * f,int flags)121 void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
122 {
123 #ifndef CONFIG_USER_ONLY
124 static const char cr_name[32][5] = {
125 "RC", "CR1", "CR2", "CR3",
126 "CR4", "CR5", "CR6", "CR7",
127 "PID1", "PID2", "CCR", "SAR",
128 "PID3", "PID4", "IVA", "EIEM",
129 "ITMR", "ISQF", "IOQF", "IIR",
130 "ISR", "IOR", "IPSW", "EIRR",
131 "TR0", "TR1", "TR2", "TR3",
132 "TR4", "TR5", "TR6", "TR7",
133 };
134 #endif
135
136 CPUHPPAState *env = cpu_env(cs);
137 target_ulong psw = cpu_hppa_get_psw(env);
138 target_ulong psw_cb;
139 char psw_c[20];
140 int i, w;
141 uint64_t m;
142
143 if (hppa_is_pa20(env)) {
144 w = 16;
145 m = UINT64_MAX;
146 } else {
147 w = 8;
148 m = UINT32_MAX;
149 }
150
151 qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
152 "IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
153 env->iasq_f >> 32, w, m & env->iaoq_f,
154 hppa_form_gva_mask(env->gva_offset_mask, env->iasq_f,
155 env->iaoq_f),
156 env->iasq_b >> 32, w, m & env->iaoq_b,
157 hppa_form_gva_mask(env->gva_offset_mask, env->iasq_b,
158 env->iaoq_b));
159
160 psw_c[0] = (psw & PSW_W ? 'W' : '-');
161 psw_c[1] = (psw & PSW_E ? 'E' : '-');
162 psw_c[2] = (psw & PSW_S ? 'S' : '-');
163 psw_c[3] = (psw & PSW_T ? 'T' : '-');
164 psw_c[4] = (psw & PSW_H ? 'H' : '-');
165 psw_c[5] = (psw & PSW_L ? 'L' : '-');
166 psw_c[6] = (psw & PSW_N ? 'N' : '-');
167 psw_c[7] = (psw & PSW_X ? 'X' : '-');
168 psw_c[8] = (psw & PSW_B ? 'B' : '-');
169 psw_c[9] = (psw & PSW_C ? 'C' : '-');
170 psw_c[10] = (psw & PSW_V ? 'V' : '-');
171 psw_c[11] = (psw & PSW_M ? 'M' : '-');
172 psw_c[12] = (psw & PSW_F ? 'F' : '-');
173 psw_c[13] = (psw & PSW_R ? 'R' : '-');
174 psw_c[14] = (psw & PSW_Q ? 'Q' : '-');
175 psw_c[15] = (psw & PSW_P ? 'P' : '-');
176 psw_c[16] = (psw & PSW_D ? 'D' : '-');
177 psw_c[17] = (psw & PSW_I ? 'I' : '-');
178 psw_c[18] = '\0';
179 psw_cb = ((env->psw_cb >> 4) & 0x1111111111111111ull)
180 | (env->psw_cb_msb << 60);
181
182 qemu_fprintf(f, "PSW %0*" PRIx64 " CB %0*" PRIx64 " %s\n",
183 w, m & psw, w, m & psw_cb, psw_c);
184
185 for (i = 0; i < 32; i++) {
186 qemu_fprintf(f, "GR%02d %0*" PRIx64 "%c",
187 i, w, m & env->gr[i],
188 (i & 3) == 3 ? '\n' : ' ');
189 }
190 #ifndef CONFIG_USER_ONLY
191 for (i = 0; i < 32; i++) {
192 qemu_fprintf(f, "%-4s %0*" PRIx64 "%c",
193 cr_name[i], w, m & env->cr[i],
194 (i & 3) == 3 ? '\n' : ' ');
195 }
196 qemu_fprintf(f, "ISQB %0*" PRIx64 " IOQB %0*" PRIx64 "\n",
197 w, m & env->cr_back[0], w, m & env->cr_back[1]);
198 for (i = 0; i < 8; i++) {
199 qemu_fprintf(f, "SR%02d %08x%c", i, (uint32_t)(env->sr[i] >> 32),
200 (i & 3) == 3 ? '\n' : ' ');
201 }
202 #endif
203
204 if (flags & CPU_DUMP_FPU) {
205 static const char rm[4][4] = { "RN", "RZ", "R+", "R-" };
206 char flg[6], ena[6];
207 uint32_t fpsr = env->fr0_shadow;
208
209 flg[0] = (fpsr & R_FPSR_FLG_V_MASK ? 'V' : '-');
210 flg[1] = (fpsr & R_FPSR_FLG_Z_MASK ? 'Z' : '-');
211 flg[2] = (fpsr & R_FPSR_FLG_O_MASK ? 'O' : '-');
212 flg[3] = (fpsr & R_FPSR_FLG_U_MASK ? 'U' : '-');
213 flg[4] = (fpsr & R_FPSR_FLG_I_MASK ? 'I' : '-');
214 flg[5] = '\0';
215
216 ena[0] = (fpsr & R_FPSR_ENA_V_MASK ? 'V' : '-');
217 ena[1] = (fpsr & R_FPSR_ENA_Z_MASK ? 'Z' : '-');
218 ena[2] = (fpsr & R_FPSR_ENA_O_MASK ? 'O' : '-');
219 ena[3] = (fpsr & R_FPSR_ENA_U_MASK ? 'U' : '-');
220 ena[4] = (fpsr & R_FPSR_ENA_I_MASK ? 'I' : '-');
221 ena[5] = '\0';
222
223 qemu_fprintf(f, "FPSR %08x flag %s enable %s %s\n",
224 fpsr, flg, ena, rm[FIELD_EX32(fpsr, FPSR, RM)]);
225
226 for (i = 0; i < 32; i++) {
227 qemu_fprintf(f, "FR%02d %016" PRIx64 "%c",
228 i, env->fr[i], (i & 3) == 3 ? '\n' : ' ');
229 }
230 }
231
232 qemu_fprintf(f, "\n");
233 }
234