2 * Alpha emulation cpu helpers for qemu.
4 * Copyright (c) 2007 Jocelyn Mayer
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.
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.
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/>.
25 #include "softfloat.h"
27 uint64_t cpu_alpha_load_fpcr (CPUState
*env
)
32 t
= env
->fpcr_exc_status
;
35 if (t
& float_flag_invalid
) {
38 if (t
& float_flag_divbyzero
) {
41 if (t
& float_flag_overflow
) {
44 if (t
& float_flag_underflow
) {
47 if (t
& float_flag_inexact
) {
52 t
= env
->fpcr_exc_mask
;
53 if (t
& float_flag_invalid
) {
56 if (t
& float_flag_divbyzero
) {
59 if (t
& float_flag_overflow
) {
62 if (t
& float_flag_underflow
) {
65 if (t
& float_flag_inexact
) {
69 switch (env
->fpcr_dyn_round
) {
70 case float_round_nearest_even
:
73 case float_round_down
:
79 case float_round_to_zero
:
80 r
|= FPCR_DYN_CHOPPED
;
97 void cpu_alpha_store_fpcr (CPUState
*env
, uint64_t val
)
102 if (val
& FPCR_INV
) {
103 t
|= float_flag_invalid
;
105 if (val
& FPCR_DZE
) {
106 t
|= float_flag_divbyzero
;
108 if (val
& FPCR_OVF
) {
109 t
|= float_flag_overflow
;
111 if (val
& FPCR_UNF
) {
112 t
|= float_flag_underflow
;
114 if (val
& FPCR_INE
) {
115 t
|= float_flag_inexact
;
117 env
->fpcr_exc_status
= t
;
120 if (val
& FPCR_INVD
) {
121 t
|= float_flag_invalid
;
123 if (val
& FPCR_DZED
) {
124 t
|= float_flag_divbyzero
;
126 if (val
& FPCR_OVFD
) {
127 t
|= float_flag_overflow
;
129 if (val
& FPCR_UNFD
) {
130 t
|= float_flag_underflow
;
132 if (val
& FPCR_INED
) {
133 t
|= float_flag_inexact
;
135 env
->fpcr_exc_mask
= t
;
137 switch (val
& FPCR_DYN_MASK
) {
138 case FPCR_DYN_CHOPPED
:
139 t
= float_round_to_zero
;
142 t
= float_round_down
;
144 case FPCR_DYN_NORMAL
:
145 t
= float_round_nearest_even
;
151 env
->fpcr_dyn_round
= t
;
153 env
->fpcr_flush_to_zero
154 = (val
& (FPCR_UNDZ
|FPCR_UNFD
)) == (FPCR_UNDZ
|FPCR_UNFD
);
156 env
->fpcr_dnz
= (val
& FPCR_DNZ
) != 0;
157 env
->fpcr_dnod
= (val
& FPCR_DNOD
) != 0;
158 env
->fpcr_undz
= (val
& FPCR_UNDZ
) != 0;
161 #if defined(CONFIG_USER_ONLY)
162 int cpu_alpha_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
163 int mmu_idx
, int is_softmmu
)
165 env
->exception_index
= EXCP_MMFAULT
;
166 env
->trap_arg0
= address
;
170 void swap_shadow_regs(CPUState
*env
)
172 uint64_t i0
, i1
, i2
, i3
, i4
, i5
, i6
, i7
;
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];
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
)
207 target_long saddr
= addr
;
208 target_ulong phys
= 0;
209 target_ulong L1pte
, L2pte
, L3pte
;
210 target_ulong pt
, index
;
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) {
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
) {
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;
234 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
239 /* Interpret the page table exactly like PALcode does. */
243 /* L1 page table read. */
244 index
= (addr
>> (TARGET_PAGE_BITS
+ 20)) & 0x3ff;
245 L1pte
= ldq_phys(pt
+ index
*8);
247 if (unlikely((L1pte
& PTE_VALID
) == 0)) {
251 if (unlikely((L1pte
& PTE_KRE
) == 0)) {
254 pt
= L1pte
>> 32 << TARGET_PAGE_BITS
;
256 /* L2 page table read. */
257 index
= (addr
>> (TARGET_PAGE_BITS
+ 10)) & 0x3ff;
258 L2pte
= ldq_phys(pt
+ index
*8);
260 if (unlikely((L2pte
& PTE_VALID
) == 0)) {
264 if (unlikely((L2pte
& PTE_KRE
) == 0)) {
267 pt
= L2pte
>> 32 << TARGET_PAGE_BITS
;
269 /* L3 page table read. */
270 index
= (addr
>> TARGET_PAGE_BITS
) & 0x3ff;
271 L3pte
= ldq_phys(pt
+ index
*8);
273 phys
= L3pte
>> 32 << TARGET_PAGE_BITS
;
274 if (unlikely((L3pte
& PTE_VALID
) == 0)) {
279 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
280 # error page bits out of date
283 /* Check access violations. */
284 if (L3pte
& (PTE_KRE
<< mmu_idx
)) {
285 prot
|= PAGE_READ
| PAGE_EXEC
;
287 if (L3pte
& (PTE_KWE
<< mmu_idx
)) {
290 if (unlikely((prot
& prot_need
) == 0 && prot_need
)) {
294 /* Check fault-on-operation violations. */
295 prot
&= ~(L3pte
>> 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);
309 target_phys_addr_t
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
314 fail
= get_physical_address(env
, addr
, 0, 0, &phys
, &prot
);
315 return (fail
>= 0 ? -1 : phys
);
318 int cpu_alpha_handle_mmu_fault(CPUState
*env
, target_ulong addr
, int rw
,
319 int mmu_idx
, int is_softmmu
)
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
);
333 tlb_set_page(env
, addr
& TARGET_PAGE_MASK
, phys
& TARGET_PAGE_MASK
,
334 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
337 #endif /* USER_ONLY */
339 void do_interrupt (CPUState
*env
)
341 int i
= env
->exception_index
;
343 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
345 const char *name
= "<unknown>";
354 case EXCP_SMP_INTERRUPT
:
355 name
= "smp_interrupt";
357 case EXCP_CLK_INTERRUPT
:
358 name
= "clk_interrupt";
360 case EXCP_DEV_INTERRUPT
:
361 name
= "dev_interrupt";
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
]);
392 env
->exception_index
= -1;
394 #if !defined(CONFIG_USER_ONLY)
402 case EXCP_SMP_INTERRUPT
:
405 case EXCP_CLK_INTERRUPT
:
408 case EXCP_DEV_INTERRUPT
:
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. */
432 i
= 0x2000 + (i
- 0x80) * 64;
438 cpu_abort(env
, "Unhandled CPU exception");
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
;
445 /* Continue execution at the PALcode entry point. */
446 env
->pc
= env
->palbr
+ i
;
448 /* Switch to PALmode. */
449 if (!env
->pal_mode
) {
451 swap_shadow_regs(env
);
453 #endif /* !USER_ONLY */
456 void cpu_dump_state (CPUState
*env
, FILE *f
, fprintf_function cpu_fprintf
,
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",
467 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS %02x\n",
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
]);
473 cpu_fprintf(f
, "\n");
476 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
477 env
->lock_addr
, env
->lock_value
);
479 for (i
= 0; i
< 31; i
++) {
480 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
481 *((uint64_t *)(&env
->fir
[i
])));
483 cpu_fprintf(f
, "\n");
485 cpu_fprintf(f
, "\n");