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/exec-all.h"
25 #include "exec/helper-proto.h"
26 #include "qemu/qemu-print.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
cpu_hppa_put_psw(CPUHPPAState * env,target_ulong psw)62 void cpu_hppa_put_psw(CPUHPPAState *env, target_ulong psw)
63 {
64 uint64_t reserved;
65 target_ulong cb = 0;
66
67 /* Do not allow reserved bits to be set. */
68 if (hppa_is_pa20(env)) {
69 reserved = MAKE_64BIT_MASK(40, 24) | MAKE_64BIT_MASK(28, 4);
70 reserved |= PSW_G; /* PA1.x only */
71 reserved |= PSW_E; /* not implemented */
72 } else {
73 reserved = MAKE_64BIT_MASK(32, 32) | MAKE_64BIT_MASK(28, 2);
74 reserved |= PSW_O | PSW_W; /* PA2.0 only */
75 reserved |= PSW_E | PSW_Y | PSW_Z; /* not implemented */
76 }
77 psw &= ~reserved;
78
79 env->psw = psw & (uint32_t)~(PSW_B | PSW_N | PSW_V | PSW_X | PSW_CB);
80 env->psw_xb = psw & (PSW_X | PSW_B);
81 env->psw_n = (psw / PSW_N) & 1;
82 env->psw_v = -((psw / PSW_V) & 1);
83
84 env->psw_cb_msb = (psw >> 39) & 1;
85 cb |= ((psw >> 38) & 1) << 60;
86 cb |= ((psw >> 37) & 1) << 56;
87 cb |= ((psw >> 36) & 1) << 52;
88 cb |= ((psw >> 35) & 1) << 48;
89 cb |= ((psw >> 34) & 1) << 44;
90 cb |= ((psw >> 33) & 1) << 40;
91 cb |= ((psw >> 32) & 1) << 36;
92 cb |= ((psw >> 15) & 1) << 32;
93 cb |= ((psw >> 14) & 1) << 28;
94 cb |= ((psw >> 13) & 1) << 24;
95 cb |= ((psw >> 12) & 1) << 20;
96 cb |= ((psw >> 11) & 1) << 16;
97 cb |= ((psw >> 10) & 1) << 12;
98 cb |= ((psw >> 9) & 1) << 8;
99 cb |= ((psw >> 8) & 1) << 4;
100 env->psw_cb = cb;
101 }
102
hppa_cpu_dump_state(CPUState * cs,FILE * f,int flags)103 void hppa_cpu_dump_state(CPUState *cs, FILE *f, int flags)
104 {
105 #ifndef CONFIG_USER_ONLY
106 static const char cr_name[32][5] = {
107 "RC", "CR1", "CR2", "CR3",
108 "CR4", "CR5", "CR6", "CR7",
109 "PID1", "PID2", "CCR", "SAR",
110 "PID3", "PID4", "IVA", "EIEM",
111 "ITMR", "ISQF", "IOQF", "IIR",
112 "ISR", "IOR", "IPSW", "EIRR",
113 "TR0", "TR1", "TR2", "TR3",
114 "TR4", "TR5", "TR6", "TR7",
115 };
116 #endif
117
118 CPUHPPAState *env = cpu_env(cs);
119 target_ulong psw = cpu_hppa_get_psw(env);
120 target_ulong psw_cb;
121 char psw_c[20];
122 int i, w;
123 uint64_t m;
124
125 if (hppa_is_pa20(env)) {
126 w = 16;
127 m = UINT64_MAX;
128 } else {
129 w = 8;
130 m = UINT32_MAX;
131 }
132
133 qemu_fprintf(f, "IA_F %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n"
134 "IA_B %08" PRIx64 ":%0*" PRIx64 " (" TARGET_FMT_lx ")\n",
135 env->iasq_f >> 32, w, m & env->iaoq_f,
136 hppa_form_gva_psw(psw, env->iasq_f, env->iaoq_f),
137 env->iasq_b >> 32, w, m & env->iaoq_b,
138 hppa_form_gva_psw(psw, env->iasq_b, env->iaoq_b));
139
140 psw_c[0] = (psw & PSW_W ? 'W' : '-');
141 psw_c[1] = (psw & PSW_E ? 'E' : '-');
142 psw_c[2] = (psw & PSW_S ? 'S' : '-');
143 psw_c[3] = (psw & PSW_T ? 'T' : '-');
144 psw_c[4] = (psw & PSW_H ? 'H' : '-');
145 psw_c[5] = (psw & PSW_L ? 'L' : '-');
146 psw_c[6] = (psw & PSW_N ? 'N' : '-');
147 psw_c[7] = (psw & PSW_X ? 'X' : '-');
148 psw_c[8] = (psw & PSW_B ? 'B' : '-');
149 psw_c[9] = (psw & PSW_C ? 'C' : '-');
150 psw_c[10] = (psw & PSW_V ? 'V' : '-');
151 psw_c[11] = (psw & PSW_M ? 'M' : '-');
152 psw_c[12] = (psw & PSW_F ? 'F' : '-');
153 psw_c[13] = (psw & PSW_R ? 'R' : '-');
154 psw_c[14] = (psw & PSW_Q ? 'Q' : '-');
155 psw_c[15] = (psw & PSW_P ? 'P' : '-');
156 psw_c[16] = (psw & PSW_D ? 'D' : '-');
157 psw_c[17] = (psw & PSW_I ? 'I' : '-');
158 psw_c[18] = '\0';
159 psw_cb = ((env->psw_cb >> 4) & 0x1111111111111111ull)
160 | (env->psw_cb_msb << 60);
161
162 qemu_fprintf(f, "PSW %0*" PRIx64 " CB %0*" PRIx64 " %s\n",
163 w, m & psw, w, m & psw_cb, psw_c);
164
165 for (i = 0; i < 32; i++) {
166 qemu_fprintf(f, "GR%02d %0*" PRIx64 "%c",
167 i, w, m & env->gr[i],
168 (i & 3) == 3 ? '\n' : ' ');
169 }
170 #ifndef CONFIG_USER_ONLY
171 for (i = 0; i < 32; i++) {
172 qemu_fprintf(f, "%-4s %0*" PRIx64 "%c",
173 cr_name[i], w, m & env->cr[i],
174 (i & 3) == 3 ? '\n' : ' ');
175 }
176 qemu_fprintf(f, "ISQB %0*" PRIx64 " IOQB %0*" PRIx64 "\n",
177 w, m & env->cr_back[0], w, m & env->cr_back[1]);
178 for (i = 0; i < 8; i++) {
179 qemu_fprintf(f, "SR%02d %08x%c", i, (uint32_t)(env->sr[i] >> 32),
180 (i & 3) == 3 ? '\n' : ' ');
181 }
182 #endif
183
184 if (flags & CPU_DUMP_FPU) {
185 static const char rm[4][4] = { "RN", "RZ", "R+", "R-" };
186 char flg[6], ena[6];
187 uint32_t fpsr = env->fr0_shadow;
188
189 flg[0] = (fpsr & R_FPSR_FLG_V_MASK ? 'V' : '-');
190 flg[1] = (fpsr & R_FPSR_FLG_Z_MASK ? 'Z' : '-');
191 flg[2] = (fpsr & R_FPSR_FLG_O_MASK ? 'O' : '-');
192 flg[3] = (fpsr & R_FPSR_FLG_U_MASK ? 'U' : '-');
193 flg[4] = (fpsr & R_FPSR_FLG_I_MASK ? 'I' : '-');
194 flg[5] = '\0';
195
196 ena[0] = (fpsr & R_FPSR_ENA_V_MASK ? 'V' : '-');
197 ena[1] = (fpsr & R_FPSR_ENA_Z_MASK ? 'Z' : '-');
198 ena[2] = (fpsr & R_FPSR_ENA_O_MASK ? 'O' : '-');
199 ena[3] = (fpsr & R_FPSR_ENA_U_MASK ? 'U' : '-');
200 ena[4] = (fpsr & R_FPSR_ENA_I_MASK ? 'I' : '-');
201 ena[5] = '\0';
202
203 qemu_fprintf(f, "FPSR %08x flag %s enable %s %s\n",
204 fpsr, flg, ena, rm[FIELD_EX32(fpsr, FPSR, RM)]);
205
206 for (i = 0; i < 32; i++) {
207 qemu_fprintf(f, "FR%02d %016" PRIx64 "%c",
208 i, env->fr[i], (i & 3) == 3 ? '\n' : ' ');
209 }
210 }
211
212 qemu_fprintf(f, "\n");
213 }
214