qdev: split out UI portions into a new function
[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 "softfloat.h"
26
27 uint64_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
97 void 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)
162 int cpu_alpha_handle_mmu_fault (CPUState *env, target_ulong address, int rw,
163 int mmu_idx)
164 {
165 env->exception_index = EXCP_MMFAULT;
166 env->trap_arg0 = address;
167 return 1;
168 }
169 #else
170 void 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 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
203 static 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 /* Ensure that the virtual address is properly sign-extended from
215 the last implemented virtual address bit. */
216 if (saddr >> TARGET_VIRT_ADDR_SPACE_BITS != saddr >> 63) {
217 goto exit;
218 }
219
220 /* Translate the superpage. */
221 /* ??? When we do more than emulate Unix PALcode, we'll need to
222 determine which KSEG is actually active. */
223 if (saddr < 0 && ((saddr >> 41) & 3) == 2) {
224 /* User-space cannot access KSEG addresses. */
225 if (mmu_idx != MMU_KERNEL_IDX) {
226 goto exit;
227 }
228
229 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
230 We would not do this if the 48-bit KSEG is enabled. */
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 /* Interpret the page table exactly like PALcode does. */
240
241 pt = env->ptbr;
242
243 /* L1 page table read. */
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 /* L2 page table read. */
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 /* L3 page table read. */
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 /* Check access violations. */
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 /* Check fault-on-operation violations. */
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
309 target_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
318 int cpu_alpha_handle_mmu_fault(CPUState *env, target_ulong addr, int rw,
319 int mmu_idx)
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 /* USER_ONLY */
338
339 void 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 /* There are 64 entry points for both privileged and unprivileged,
429 with bit 0x80 indicating unprivileged. Each entry point gets
430 64 bytes to do its job. */
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 /* Remember where the exception happened. Emulate real hardware in
442 that the low bit of the PC indicates PALmode. */
443 env->exc_addr = env->pc | env->pal_mode;
444
445 /* Continue execution at the PALcode entry point. */
446 env->pc = env->palbr + i;
447
448 /* Switch to PALmode. */
449 if (!env->pal_mode) {
450 env->pal_mode = 1;
451 swap_shadow_regs(env);
452 }
453 #endif /* !USER_ONLY */
454 }
455
456 void 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 }