1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <stdint.h>
21#include <stdlib.h>
22#include <stdio.h>
23
24#include "cpu.h"
25#include "softfloat.h"
26
27uint64_t cpu_alpha_load_fpcr (CPUState *env)
28{
29 uint64_t r = 0;
30 uint8_t t;
31
32 t = env->fpcr_exc_status;
33 if (t) {
34 r = FPCR_SUM;
35 if (t & float_flag_invalid) {
36 r |= FPCR_INV;
37 }
38 if (t & float_flag_divbyzero) {
39 r |= FPCR_DZE;
40 }
41 if (t & float_flag_overflow) {
42 r |= FPCR_OVF;
43 }
44 if (t & float_flag_underflow) {
45 r |= FPCR_UNF;
46 }
47 if (t & float_flag_inexact) {
48 r |= FPCR_INE;
49 }
50 }
51
52 t = env->fpcr_exc_mask;
53 if (t & float_flag_invalid) {
54 r |= FPCR_INVD;
55 }
56 if (t & float_flag_divbyzero) {
57 r |= FPCR_DZED;
58 }
59 if (t & float_flag_overflow) {
60 r |= FPCR_OVFD;
61 }
62 if (t & float_flag_underflow) {
63 r |= FPCR_UNFD;
64 }
65 if (t & float_flag_inexact) {
66 r |= FPCR_INED;
67 }
68
69 switch (env->fpcr_dyn_round) {
70 case float_round_nearest_even:
71 r |= FPCR_DYN_NORMAL;
72 break;
73 case float_round_down:
74 r |= FPCR_DYN_MINUS;
75 break;
76 case float_round_up:
77 r |= FPCR_DYN_PLUS;
78 break;
79 case float_round_to_zero:
80 r |= FPCR_DYN_CHOPPED;
81 break;
82 }
83
84 if (env->fpcr_dnz) {
85 r |= FPCR_DNZ;
86 }
87 if (env->fpcr_dnod) {
88 r |= FPCR_DNOD;
89 }
90 if (env->fpcr_undz) {
91 r |= FPCR_UNDZ;
92 }
93
94 return r;
95}
96
97void cpu_alpha_store_fpcr (CPUState *env, uint64_t val)
98{
99 uint8_t t;
100
101 t = 0;
102 if (val & FPCR_INV) {
103 t |= float_flag_invalid;
104 }
105 if (val & FPCR_DZE) {
106 t |= float_flag_divbyzero;
107 }
108 if (val & FPCR_OVF) {
109 t |= float_flag_overflow;
110 }
111 if (val & FPCR_UNF) {
112 t |= float_flag_underflow;
113 }
114 if (val & FPCR_INE) {
115 t |= float_flag_inexact;
116 }
117 env->fpcr_exc_status = t;
118
119 t = 0;
120 if (val & FPCR_INVD) {
121 t |= float_flag_invalid;
122 }
123 if (val & FPCR_DZED) {
124 t |= float_flag_divbyzero;
125 }
126 if (val & FPCR_OVFD) {
127 t |= float_flag_overflow;
128 }
129 if (val & FPCR_UNFD) {
130 t |= float_flag_underflow;
131 }
132 if (val & FPCR_INED) {
133 t |= float_flag_inexact;
134 }
135 env->fpcr_exc_mask = t;
136
137 switch (val & FPCR_DYN_MASK) {
138 case FPCR_DYN_CHOPPED:
139 t = float_round_to_zero;
140 break;
141 case FPCR_DYN_MINUS:
142 t = float_round_down;
143 break;
144 case FPCR_DYN_NORMAL:
145 t = float_round_nearest_even;
146 break;
147 case FPCR_DYN_PLUS:
148 t = float_round_up;
149 break;
150 }
151 env->fpcr_dyn_round = t;
152
153 env->fpcr_flush_to_zero
154 = (val & (FPCR_UNDZ|FPCR_UNFD)) == (FPCR_UNDZ|FPCR_UNFD);
155
156 env->fpcr_dnz = (val & FPCR_DNZ) != 0;
157 env->fpcr_dnod = (val & FPCR_DNOD) != 0;
158 env->fpcr_undz = (val & FPCR_UNDZ) != 0;
159}
160
161#if defined(CONFIG_USER_ONLY)
162int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
163 int mmu_idx, int is_softmmu)
164{
165 env->exception_index = EXCP_MMFAULT;
166 env->trap_arg0 = address;
167 return 1;
168}
169#else
170void swap_shadow_regs(CPUState *env)
171{
172 uint64_t i0, i1, i2, i3, i4, i5, i6, i7;
173
174 i0 = env->ir[8];
175 i1 = env->ir[9];
176 i2 = env->ir[10];
177 i3 = env->ir[11];
178 i4 = env->ir[12];
179 i5 = env->ir[13];
180 i6 = env->ir[14];
181 i7 = env->ir[25];
182
183 env->ir[8] = env->shadow[0];
184 env->ir[9] = env->shadow[1];
185 env->ir[10] = env->shadow[2];
186 env->ir[11] = env->shadow[3];
187 env->ir[12] = env->shadow[4];
188 env->ir[13] = env->shadow[5];
189 env->ir[14] = env->shadow[6];
190 env->ir[25] = env->shadow[7];
191
192 env->shadow[0] = i0;
193 env->shadow[1] = i1;
194 env->shadow[2] = i2;
195 env->shadow[3] = i3;
196 env->shadow[4] = i4;
197 env->shadow[5] = i5;
198 env->shadow[6] = i6;
199 env->shadow[7] = i7;
200}
201
202
203static int get_physical_address(CPUState *env, target_ulong addr,
204 int prot_need, int mmu_idx,
205 target_ulong *pphys, int *pprot)
206{
207 target_long saddr = addr;
208 target_ulong phys = 0;
209 target_ulong L1pte, L2pte, L3pte;
210 target_ulong pt, index;
211 int prot = 0;
212 int ret = MM_K_ACV;
213
214
215
216 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
217 goto exit;
218 }
219
220
221
222
223 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
224
225 if (mmu_idx != MMU_KERNEL_IDX) {
226 goto exit;
227 }
228
229
230
231 phys = saddr & ((1ull << 40) - 1);
232 phys |= (saddr & (1ull << 40)) << 3;
233
234 prot = PAGE_READ | PAGE_WRITE | PAGE_EXEC;
235 ret = -1;
236 goto exit;
237 }
238
239
240
241 pt = env->ptbr;
242
243
244 index = (addr >> (TARGET_PAGE_BITS + 20)) & 0x3ff;
245 L1pte = ldq_phys(pt + index*8);
246
247 if (unlikely((L1pte & PTE_VALID) == 0)) {
248 ret = MM_K_TNV;
249 goto exit;
250 }
251 if (unlikely((L1pte & PTE_KRE) == 0)) {
252 goto exit;
253 }
254 pt = L1pte >> 32 << TARGET_PAGE_BITS;
255
256
257 index = (addr >> (TARGET_PAGE_BITS + 10)) & 0x3ff;
258 L2pte = ldq_phys(pt + index*8);
259
260 if (unlikely((L2pte & PTE_VALID) == 0)) {
261 ret = MM_K_TNV;
262 goto exit;
263 }
264 if (unlikely((L2pte & PTE_KRE) == 0)) {
265 goto exit;
266 }
267 pt = L2pte >> 32 << TARGET_PAGE_BITS;
268
269
270 index = (addr >> TARGET_PAGE_BITS) & 0x3ff;
271 L3pte = ldq_phys(pt + index*8);
272
273 phys = L3pte >> 32 << TARGET_PAGE_BITS;
274 if (unlikely((L3pte & PTE_VALID) == 0)) {
275 ret = MM_K_TNV;
276 goto exit;
277 }
278
279#if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
280# error page bits out of date
281#endif
282
283
284 if (L3pte & (PTE_KRE << mmu_idx)) {
285 prot |= PAGE_READ | PAGE_EXEC;
286 }
287 if (L3pte & (PTE_KWE << mmu_idx)) {
288 prot |= PAGE_WRITE;
289 }
290 if (unlikely((prot & prot_need) == 0 && prot_need)) {
291 goto exit;
292 }
293
294
295 prot &= ~(L3pte >> 1);
296 ret = -1;
297 if (unlikely((prot & prot_need) == 0)) {
298 ret = (prot_need & PAGE_EXEC ? MM_K_FOE :
299 prot_need & PAGE_WRITE ? MM_K_FOW :
300 prot_need & PAGE_READ ? MM_K_FOR : -1);
301 }
302
303 exit:
304 *pphys = phys;
305 *pprot = prot;
306 return ret;
307}
308
309target_phys_addr_t cpu_get_phys_page_debug(CPUState *env, target_ulong addr)
310{
311 target_ulong phys;
312 int prot, fail;
313
314 fail = get_physical_address(env, addr, 0, 0, &phys, &prot);
315 return (fail >= 0 ? -1 : phys);
316}
317
318int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
319 int mmu_idx, int is_softmmu)
320{
321 target_ulong phys;
322 int prot, fail;
323
324 fail = get_physical_address(env, addr, 1 << rw, mmu_idx, &phys, &prot);
325 if (unlikely(fail >= 0)) {
326 env->exception_index = EXCP_MMFAULT;
327 env->trap_arg0 = addr;
328 env->trap_arg1 = fail;
329 env->trap_arg2 = (rw == 2 ? -1 : rw);
330 return 1;
331 }
332
333 tlb_set_page(env, addr & TARGET_PAGE_MASK, phys & TARGET_PAGE_MASK,
334 prot, mmu_idx, TARGET_PAGE_SIZE);
335 return 0;
336}
337#endif
338
339void do_interrupt (CPUState *env)
340{
341 int i = env->exception_index;
342
343 if (qemu_loglevel_mask(CPU_LOG_INT)) {
344 static int count;
345 const char *name = "<unknown>";
346
347 switch (i) {
348 case EXCP_RESET:
349 name = "reset";
350 break;
351 case EXCP_MCHK:
352 name = "mchk";
353 break;
354 case EXCP_SMP_INTERRUPT:
355 name = "smp_interrupt";
356 break;
357 case EXCP_CLK_INTERRUPT:
358 name = "clk_interrupt";
359 break;
360 case EXCP_DEV_INTERRUPT:
361 name = "dev_interrupt";
362 break;
363 case EXCP_MMFAULT:
364 name = "mmfault";
365 break;
366 case EXCP_UNALIGN:
367 name = "unalign";
368 break;
369 case EXCP_OPCDEC:
370 name = "opcdec";
371 break;
372 case EXCP_ARITH:
373 name = "arith";
374 break;
375 case EXCP_FEN:
376 name = "fen";
377 break;
378 case EXCP_CALL_PAL:
379 name = "call_pal";
380 break;
381 case EXCP_STL_C:
382 name = "stl_c";
383 break;
384 case EXCP_STQ_C:
385 name = "stq_c";
386 break;
387 }
388 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64 " sp=%016" PRIx64 "\n",
389 ++count, name, env->error_code, env->pc, env->ir[IR_SP]);
390 }
391
392 env->exception_index = -1;
393
394#if !defined(CONFIG_USER_ONLY)
395 switch (i) {
396 case EXCP_RESET:
397 i = 0x0000;
398 break;
399 case EXCP_MCHK:
400 i = 0x0080;
401 break;
402 case EXCP_SMP_INTERRUPT:
403 i = 0x0100;
404 break;
405 case EXCP_CLK_INTERRUPT:
406 i = 0x0180;
407 break;
408 case EXCP_DEV_INTERRUPT:
409 i = 0x0200;
410 break;
411 case EXCP_MMFAULT:
412 i = 0x0280;
413 break;
414 case EXCP_UNALIGN:
415 i = 0x0300;
416 break;
417 case EXCP_OPCDEC:
418 i = 0x0380;
419 break;
420 case EXCP_ARITH:
421 i = 0x0400;
422 break;
423 case EXCP_FEN:
424 i = 0x0480;
425 break;
426 case EXCP_CALL_PAL:
427 i = env->error_code;
428
429
430
431 if (i & 0x80) {
432 i = 0x2000 + (i - 0x80) * 64;
433 } else {
434 i = 0x1000 + i * 64;
435 }
436 break;
437 default:
438 cpu_abort(env, "Unhandled CPU exception");
439 }
440
441
442
443 env->exc_addr = env->pc | env->pal_mode;
444
445
446 env->pc = env->palbr + i;
447
448
449 if (!env->pal_mode) {
450 env->pal_mode = 1;
451 swap_shadow_regs(env);
452 }
453#endif
454}
455
456void cpu_dump_state (CPUState *env, FILE *f, fprintf_function cpu_fprintf,
457 int flags)
458{
459 static const char *linux_reg_names[] = {
460 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
461 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
462 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
463 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
464 };
465 int i;
466
467 cpu_fprintf(f, " PC " TARGET_FMT_lx " PS %02x\n",
468 env->pc, env->ps);
469 for (i = 0; i < 31; i++) {
470 cpu_fprintf(f, "IR%02d %s " TARGET_FMT_lx " ", i,
471 linux_reg_names[i], env->ir[i]);
472 if ((i % 3) == 2)
473 cpu_fprintf(f, "\n");
474 }
475
476 cpu_fprintf(f, "lock_a " TARGET_FMT_lx " lock_v " TARGET_FMT_lx "\n",
477 env->lock_addr, env->lock_value);
478
479 for (i = 0; i < 31; i++) {
480 cpu_fprintf(f, "FIR%02d " TARGET_FMT_lx " ", i,
481 *((uint64_t *)(&env->fir[i])));
482 if ((i % 3) == 2)
483 cpu_fprintf(f, "\n");
484 }
485 cpu_fprintf(f, "\n");
486}
487