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/>.
20 #include "qemu/osdep.h"
23 #include "fpu/softfloat.h"
24 #include "exec/helper-proto.h"
27 #define CONVERT_BIT(X, SRC, DST) \
28 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
30 uint64_t cpu_alpha_load_fpcr (CPUAlphaState
*env
)
32 return (uint64_t)env
->fpcr
<< 32;
35 void cpu_alpha_store_fpcr (CPUAlphaState
*env
, uint64_t val
)
37 uint32_t fpcr
= val
>> 32;
40 t
|= CONVERT_BIT(fpcr
, FPCR_INED
, FPCR_INE
);
41 t
|= CONVERT_BIT(fpcr
, FPCR_UNFD
, FPCR_UNF
);
42 t
|= CONVERT_BIT(fpcr
, FPCR_OVFD
, FPCR_OVF
);
43 t
|= CONVERT_BIT(fpcr
, FPCR_DZED
, FPCR_DZE
);
44 t
|= CONVERT_BIT(fpcr
, FPCR_INVD
, FPCR_INV
);
47 env
->fpcr_exc_enable
= ~t
& FPCR_STATUS_MASK
;
49 switch (fpcr
& FPCR_DYN_MASK
) {
52 t
= float_round_nearest_even
;
54 case FPCR_DYN_CHOPPED
:
55 t
= float_round_to_zero
;
64 env
->fpcr_dyn_round
= t
;
66 env
->fpcr_flush_to_zero
= (fpcr
& FPCR_UNFD
) && (fpcr
& FPCR_UNDZ
);
67 env
->fp_status
.flush_inputs_to_zero
= (fpcr
& FPCR_DNZ
) != 0;
70 uint64_t helper_load_fpcr(CPUAlphaState
*env
)
72 return cpu_alpha_load_fpcr(env
);
75 void helper_store_fpcr(CPUAlphaState
*env
, uint64_t val
)
77 cpu_alpha_store_fpcr(env
, val
);
80 static uint64_t *cpu_alpha_addr_gr(CPUAlphaState
*env
, unsigned reg
)
82 #ifndef CONFIG_USER_ONLY
84 if (reg
>= 8 && reg
<= 14) {
85 return &env
->shadow
[reg
- 8];
86 } else if (reg
== 25) {
87 return &env
->shadow
[7];
94 uint64_t cpu_alpha_load_gr(CPUAlphaState
*env
, unsigned reg
)
96 return *cpu_alpha_addr_gr(env
, reg
);
99 void cpu_alpha_store_gr(CPUAlphaState
*env
, unsigned reg
, uint64_t val
)
101 *cpu_alpha_addr_gr(env
, reg
) = val
;
104 #if defined(CONFIG_USER_ONLY)
105 int alpha_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
,
108 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
110 cs
->exception_index
= EXCP_MMFAULT
;
111 cpu
->env
.trap_arg0
= address
;
115 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
116 static int get_physical_address(CPUAlphaState
*env
, target_ulong addr
,
117 int prot_need
, int mmu_idx
,
118 target_ulong
*pphys
, int *pprot
)
120 CPUState
*cs
= CPU(alpha_env_get_cpu(env
));
121 target_long saddr
= addr
;
122 target_ulong phys
= 0;
123 target_ulong L1pte
, L2pte
, L3pte
;
124 target_ulong pt
, index
;
128 /* Ensure that the virtual address is properly sign-extended from
129 the last implemented virtual address bit. */
130 if (saddr
>> TARGET_VIRT_ADDR_SPACE_BITS
!= saddr
>> 63) {
134 /* Translate the superpage. */
135 /* ??? When we do more than emulate Unix PALcode, we'll need to
136 determine which KSEG is actually active. */
137 if (saddr
< 0 && ((saddr
>> 41) & 3) == 2) {
138 /* User-space cannot access KSEG addresses. */
139 if (mmu_idx
!= MMU_KERNEL_IDX
) {
143 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
144 We would not do this if the 48-bit KSEG is enabled. */
145 phys
= saddr
& ((1ull << 40) - 1);
146 phys
|= (saddr
& (1ull << 40)) << 3;
148 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
153 /* Interpret the page table exactly like PALcode does. */
157 /* L1 page table read. */
158 index
= (addr
>> (TARGET_PAGE_BITS
+ 20)) & 0x3ff;
159 L1pte
= ldq_phys(cs
->as
, pt
+ index
*8);
161 if (unlikely((L1pte
& PTE_VALID
) == 0)) {
165 if (unlikely((L1pte
& PTE_KRE
) == 0)) {
168 pt
= L1pte
>> 32 << TARGET_PAGE_BITS
;
170 /* L2 page table read. */
171 index
= (addr
>> (TARGET_PAGE_BITS
+ 10)) & 0x3ff;
172 L2pte
= ldq_phys(cs
->as
, pt
+ index
*8);
174 if (unlikely((L2pte
& PTE_VALID
) == 0)) {
178 if (unlikely((L2pte
& PTE_KRE
) == 0)) {
181 pt
= L2pte
>> 32 << TARGET_PAGE_BITS
;
183 /* L3 page table read. */
184 index
= (addr
>> TARGET_PAGE_BITS
) & 0x3ff;
185 L3pte
= ldq_phys(cs
->as
, pt
+ index
*8);
187 phys
= L3pte
>> 32 << TARGET_PAGE_BITS
;
188 if (unlikely((L3pte
& PTE_VALID
) == 0)) {
193 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
194 # error page bits out of date
197 /* Check access violations. */
198 if (L3pte
& (PTE_KRE
<< mmu_idx
)) {
199 prot
|= PAGE_READ
| PAGE_EXEC
;
201 if (L3pte
& (PTE_KWE
<< mmu_idx
)) {
204 if (unlikely((prot
& prot_need
) == 0 && prot_need
)) {
208 /* Check fault-on-operation violations. */
209 prot
&= ~(L3pte
>> 1);
211 if (unlikely((prot
& prot_need
) == 0)) {
212 ret
= (prot_need
& PAGE_EXEC
? MM_K_FOE
:
213 prot_need
& PAGE_WRITE
? MM_K_FOW
:
214 prot_need
& PAGE_READ
? MM_K_FOR
: -1);
223 hwaddr
alpha_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
225 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
229 fail
= get_physical_address(&cpu
->env
, addr
, 0, 0, &phys
, &prot
);
230 return (fail
>= 0 ? -1 : phys
);
233 int alpha_cpu_handle_mmu_fault(CPUState
*cs
, vaddr addr
, int rw
,
236 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
237 CPUAlphaState
*env
= &cpu
->env
;
241 fail
= get_physical_address(env
, addr
, 1 << rw
, mmu_idx
, &phys
, &prot
);
242 if (unlikely(fail
>= 0)) {
243 cs
->exception_index
= EXCP_MMFAULT
;
244 env
->trap_arg0
= addr
;
245 env
->trap_arg1
= fail
;
246 env
->trap_arg2
= (rw
== 2 ? -1 : rw
);
250 tlb_set_page(cs
, addr
& TARGET_PAGE_MASK
, phys
& TARGET_PAGE_MASK
,
251 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
254 #endif /* USER_ONLY */
256 void alpha_cpu_do_interrupt(CPUState
*cs
)
258 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
259 CPUAlphaState
*env
= &cpu
->env
;
260 int i
= cs
->exception_index
;
262 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
264 const char *name
= "<unknown>";
273 case EXCP_SMP_INTERRUPT
:
274 name
= "smp_interrupt";
276 case EXCP_CLK_INTERRUPT
:
277 name
= "clk_interrupt";
279 case EXCP_DEV_INTERRUPT
:
280 name
= "dev_interrupt";
307 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64
" sp=%016" PRIx64
"\n",
308 ++count
, name
, env
->error_code
, env
->pc
, env
->ir
[IR_SP
]);
311 cs
->exception_index
= -1;
313 #if !defined(CONFIG_USER_ONLY)
321 case EXCP_SMP_INTERRUPT
:
324 case EXCP_CLK_INTERRUPT
:
327 case EXCP_DEV_INTERRUPT
:
347 /* There are 64 entry points for both privileged and unprivileged,
348 with bit 0x80 indicating unprivileged. Each entry point gets
349 64 bytes to do its job. */
351 i
= 0x2000 + (i
- 0x80) * 64;
357 cpu_abort(cs
, "Unhandled CPU exception");
360 /* Remember where the exception happened. Emulate real hardware in
361 that the low bit of the PC indicates PALmode. */
362 env
->exc_addr
= env
->pc
| env
->pal_mode
;
364 /* Continue execution at the PALcode entry point. */
365 env
->pc
= env
->palbr
+ i
;
367 /* Switch to PALmode. */
369 #endif /* !USER_ONLY */
372 bool alpha_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
374 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
375 CPUAlphaState
*env
= &cpu
->env
;
378 /* We never take interrupts while in PALmode. */
383 /* Fall through the switch, collecting the highest priority
384 interrupt that isn't masked by the processor status IPL. */
385 /* ??? This hard-codes the OSF/1 interrupt levels. */
386 switch (env
->ps
& PS_INT_MASK
) {
388 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
389 idx
= EXCP_DEV_INTERRUPT
;
393 if (interrupt_request
& CPU_INTERRUPT_TIMER
) {
394 idx
= EXCP_CLK_INTERRUPT
;
398 if (interrupt_request
& CPU_INTERRUPT_SMP
) {
399 idx
= EXCP_SMP_INTERRUPT
;
403 if (interrupt_request
& CPU_INTERRUPT_MCHK
) {
408 cs
->exception_index
= idx
;
410 alpha_cpu_do_interrupt(cs
);
416 void alpha_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
419 static const char *linux_reg_names
[] = {
420 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
421 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
422 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
423 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
425 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
426 CPUAlphaState
*env
= &cpu
->env
;
429 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS %02x\n",
431 for (i
= 0; i
< 31; i
++) {
432 cpu_fprintf(f
, "IR%02d %s " TARGET_FMT_lx
" ", i
,
433 linux_reg_names
[i
], cpu_alpha_load_gr(env
, i
));
435 cpu_fprintf(f
, "\n");
438 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
439 env
->lock_addr
, env
->lock_value
);
441 for (i
= 0; i
< 31; i
++) {
442 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
443 *((uint64_t *)(&env
->fir
[i
])));
445 cpu_fprintf(f
, "\n");
447 cpu_fprintf(f
, "\n");
450 /* This should only be called from translate, via gen_excp.
451 We expect that ENV->PC has already been updated. */
452 void QEMU_NORETURN
helper_excp(CPUAlphaState
*env
, int excp
, int error
)
454 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
455 CPUState
*cs
= CPU(cpu
);
457 cs
->exception_index
= excp
;
458 env
->error_code
= error
;
462 /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
463 void QEMU_NORETURN
dynamic_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
466 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
467 CPUState
*cs
= CPU(cpu
);
469 cs
->exception_index
= excp
;
470 env
->error_code
= error
;
472 cpu_restore_state(cs
, retaddr
);
473 /* Floating-point exceptions (our only users) point to the next PC. */
479 void QEMU_NORETURN
arith_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
480 int exc
, uint64_t mask
)
482 env
->trap_arg0
= exc
;
483 env
->trap_arg1
= mask
;
484 dynamic_excp(env
, retaddr
, EXCP_ARITH
, 0);