]> git.proxmox.com Git - mirror_qemu.git/blob - target-alpha/helper.c
target-alpha: Swap shadow registers moving to/from PALmode.
[mirror_qemu.git] / target-alpha / helper.c
1 /*
2 * Alpha emulation cpu helpers for qemu.
3 *
4 * Copyright (c) 2007 Jocelyn Mayer
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 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 <stdint.h>
21 #include <stdlib.h>
22 #include <stdio.h>
23
24 #include "cpu.h"
25 #include "exec-all.h"
26 #include "softfloat.h"
27
28 uint64_t cpu_alpha_load_fpcr (CPUState *env)
29 {
30 uint64_t r = 0;
31 uint8_t t;
32
33 t = env->fpcr_exc_status;
34 if (t) {
35 r = FPCR_SUM;
36 if (t & float_flag_invalid) {
37 r |= FPCR_INV;
38 }
39 if (t & float_flag_divbyzero) {
40 r |= FPCR_DZE;
41 }
42 if (t & float_flag_overflow) {
43 r |= FPCR_OVF;
44 }
45 if (t & float_flag_underflow) {
46 r |= FPCR_UNF;
47 }
48 if (t & float_flag_inexact) {
49 r |= FPCR_INE;
50 }
51 }
52
53 t = env->fpcr_exc_mask;
54 if (t & float_flag_invalid) {
55 r |= FPCR_INVD;
56 }
57 if (t & float_flag_divbyzero) {
58 r |= FPCR_DZED;
59 }
60 if (t & float_flag_overflow) {
61 r |= FPCR_OVFD;
62 }
63 if (t & float_flag_underflow) {
64 r |= FPCR_UNFD;
65 }
66 if (t & float_flag_inexact) {
67 r |= FPCR_INED;
68 }
69
70 switch (env->fpcr_dyn_round) {
71 case float_round_nearest_even:
72 r |= FPCR_DYN_NORMAL;
73 break;
74 case float_round_down:
75 r |= FPCR_DYN_MINUS;
76 break;
77 case float_round_up:
78 r |= FPCR_DYN_PLUS;
79 break;
80 case float_round_to_zero:
81 r |= FPCR_DYN_CHOPPED;
82 break;
83 }
84
85 if (env->fpcr_dnz) {
86 r |= FPCR_DNZ;
87 }
88 if (env->fpcr_dnod) {
89 r |= FPCR_DNOD;
90 }
91 if (env->fpcr_undz) {
92 r |= FPCR_UNDZ;
93 }
94
95 return r;
96 }
97
98 void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
99 {
100 uint8_t t;
101
102 t = 0;
103 if (val & FPCR_INV) {
104 t |= float_flag_invalid;
105 }
106 if (val & FPCR_DZE) {
107 t |= float_flag_divbyzero;
108 }
109 if (val & FPCR_OVF) {
110 t |= float_flag_overflow;
111 }
112 if (val & FPCR_UNF) {
113 t |= float_flag_underflow;
114 }
115 if (val & FPCR_INE) {
116 t |= float_flag_inexact;
117 }
118 env->fpcr_exc_status = t;
119
120 t = 0;
121 if (val & FPCR_INVD) {
122 t |= float_flag_invalid;
123 }
124 if (val & FPCR_DZED) {
125 t |= float_flag_divbyzero;
126 }
127 if (val & FPCR_OVFD) {
128 t |= float_flag_overflow;
129 }
130 if (val & FPCR_UNFD) {
131 t |= float_flag_underflow;
132 }
133 if (val & FPCR_INED) {
134 t |= float_flag_inexact;
135 }
136 env->fpcr_exc_mask = t;
137
138 switch (val & FPCR_DYN_MASK) {
139 case FPCR_DYN_CHOPPED:
140 t = float_round_to_zero;
141 break;
142 case FPCR_DYN_MINUS:
143 t = float_round_down;
144 break;
145 case FPCR_DYN_NORMAL:
146 t = float_round_nearest_even;
147 break;
148 case FPCR_DYN_PLUS:
149 t = float_round_up;
150 break;
151 }
152 env->fpcr_dyn_round = t;
153
154 env->fpcr_flush_to_zero
155 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
156
157 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
158 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
159 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
160 }
161
162 #if defined(CONFIG_USER_ONLY)
163 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
164 int mmu_idx, int is_softmmu)
165 {
166 env->exception_index = EXCP_MMFAULT;
167 env->trap_arg0 = address;
168 return 1;
169 }
170 #else
171 void swap_shadow_regs(CPUState *env)
172 {
173 uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
174
175 i0 = env->ir[8];
176 i1 = env->ir[9];
177 i2 = env->ir[10];
178 i3 = env->ir[11];
179 i4 = env->ir[12];
180 i5 = env->ir[13];
181 i6 = env->ir[14];
182 i7 = env->ir[25];
183
184 env->ir[8] = env->shadow[0];
185 env->ir[9] = env->shadow[1];
186 env->ir[10] = env->shadow[2];
187 env->ir[11] = env->shadow[3];
188 env->ir[12] = env->shadow[4];
189 env->ir[13] = env->shadow[5];
190 env->ir[14] = env->shadow[6];
191 env->ir[25] = env->shadow[7];
192
193 env->shadow[0] = i0;
194 env->shadow[1] = i1;
195 env->shadow[2] = i2;
196 env->shadow[3] = i3;
197 env->shadow[4] = i4;
198 env->shadow[5] = i5;
199 env->shadow[6] = i6;
200 env->shadow[7] = i7;
201 }
202
203 target_phys_addr_t cpu_get_phys_page_debug (CPUState *env, target_ulong addr)
204 {
205 return -1;
206 }
207
208 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
209 int mmu_idx, int is_softmmu)
210 {
211 return 0;
212 }
213 #endif /* USER_ONLY */
214
215 void do_interrupt (CPUState *env)
216 {
217 int i = env->exception_index;
218
219 if (qemu_loglevel_mask(CPU_LOG_INT)) {
220 static int count;
221 const char *name = "<unknown>";
222
223 switch (i) {
224 case EXCP_RESET:
225 name = "reset";
226 break;
227 case EXCP_MCHK:
228 name = "mchk";
229 break;
230 case EXCP_SMP_INTERRUPT:
231 name = "smp_interrupt";
232 break;
233 case EXCP_CLK_INTERRUPT:
234 name = "clk_interrupt";
235 break;
236 case EXCP_DEV_INTERRUPT:
237 name = "dev_interrupt";
238 break;
239 case EXCP_MMFAULT:
240 name = "mmfault";
241 break;
242 case EXCP_UNALIGN:
243 name = "unalign";
244 break;
245 case EXCP_OPCDEC:
246 name = "opcdec";
247 break;
248 case EXCP_ARITH:
249 name = "arith";
250 break;
251 case EXCP_FEN:
252 name = "fen";
253 break;
254 case EXCP_CALL_PAL:
255 name = "call_pal";
256 break;
257 case EXCP_STL_C:
258 name = "stl_c";
259 break;
260 case EXCP_STQ_C:
261 name = "stq_c";
262 break;
263 }
264 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
265 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
266 }
267
268 env->exception_index = -1;
269
270 #if !defined(CONFIG_USER_ONLY)
271 switch (i) {
272 case EXCP_RESET:
273 i = 0x0000;
274 break;
275 case EXCP_MCHK:
276 i = 0x0080;
277 break;
278 case EXCP_SMP_INTERRUPT:
279 i = 0x0100;
280 break;
281 case EXCP_CLK_INTERRUPT:
282 i = 0x0180;
283 break;
284 case EXCP_DEV_INTERRUPT:
285 i = 0x0200;
286 break;
287 case EXCP_MMFAULT:
288 i = 0x0280;
289 break;
290 case EXCP_UNALIGN:
291 i = 0x0300;
292 break;
293 case EXCP_OPCDEC:
294 i = 0x0380;
295 break;
296 case EXCP_ARITH:
297 i = 0x0400;
298 break;
299 case EXCP_FEN:
300 i = 0x0480;
301 break;
302 case EXCP_CALL_PAL:
303 i = env->error_code;
304 /* There are 64 entry points for both privileged and unprivileged,
305 with bit 0x80 indicating unprivileged. Each entry point gets
306 64 bytes to do its job. */
307 if (i & 0x80) {
308 i = 0x2000 + (i - 0x80) * 64;
309 } else {
310 i = 0x1000 + i * 64;
311 }
312 break;
313 default:
314 cpu_abort(env, "Unhandled CPU exception");
315 }
316
317 /* Remember where the exception happened. Emulate real hardware in
318 that the low bit of the PC indicates PALmode. */
319 env->exc_addr = env->pc | env->pal_mode;
320
321 /* Continue execution at the PALcode entry point. */
322 env->pc = env->palbr + i;
323
324 /* Switch to PALmode. */
325 if (!env->pal_mode) {
326 env->pal_mode = 1;
327 swap_shadow_regs(env);
328 }
329 #endif /* !USER_ONLY */
330 }
331
332 void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
333 int flags)
334 {
335 static const char *linux_reg_names[] = {
336 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
337 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
338 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
339 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
340 };
341 int i;
342
343 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
344 env->pc, env->ps);
345 for (i = 0; i < 31; i++) {
346 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
347 linux_reg_names[i], env->ir[i]);
348 if ((i % 3) == 2)
349 cpu_fprintf(f, "\n");
350 }
351
352 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
353 env->lock_addr, env->lock_value);
354
355 for (i = 0; i < 31; i++) {
356 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
357 *((uint64_t *)(&env->fir[i])));
358 if ((i % 3) == 2)
359 cpu_fprintf(f, "\n");
360 }
361 cpu_fprintf(f, "\n");
362 }