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 "exec/exec-all.h"
24 #include "fpu/softfloat.h"
25 #include "exec/helper-proto.h"
28 #define CONVERT_BIT(X, SRC, DST) \
29 (SRC > DST ? (X) / (SRC / DST) & (DST) : ((X) & SRC) * (DST / SRC))
31 uint64_t cpu_alpha_load_fpcr (CPUAlphaState
*env
)
33 return (uint64_t)env
->fpcr
<< 32;
36 void cpu_alpha_store_fpcr (CPUAlphaState
*env
, uint64_t val
)
38 uint32_t fpcr
= val
>> 32;
41 t
|= CONVERT_BIT(fpcr
, FPCR_INED
, FPCR_INE
);
42 t
|= CONVERT_BIT(fpcr
, FPCR_UNFD
, FPCR_UNF
);
43 t
|= CONVERT_BIT(fpcr
, FPCR_OVFD
, FPCR_OVF
);
44 t
|= CONVERT_BIT(fpcr
, FPCR_DZED
, FPCR_DZE
);
45 t
|= CONVERT_BIT(fpcr
, FPCR_INVD
, FPCR_INV
);
48 env
->fpcr_exc_enable
= ~t
& FPCR_STATUS_MASK
;
50 switch (fpcr
& FPCR_DYN_MASK
) {
53 t
= float_round_nearest_even
;
55 case FPCR_DYN_CHOPPED
:
56 t
= float_round_to_zero
;
65 env
->fpcr_dyn_round
= t
;
67 env
->fpcr_flush_to_zero
= (fpcr
& FPCR_UNFD
) && (fpcr
& FPCR_UNDZ
);
68 env
->fp_status
.flush_inputs_to_zero
= (fpcr
& FPCR_DNZ
) != 0;
71 uint64_t helper_load_fpcr(CPUAlphaState
*env
)
73 return cpu_alpha_load_fpcr(env
);
76 void helper_store_fpcr(CPUAlphaState
*env
, uint64_t val
)
78 cpu_alpha_store_fpcr(env
, val
);
81 static uint64_t *cpu_alpha_addr_gr(CPUAlphaState
*env
, unsigned reg
)
83 #ifndef CONFIG_USER_ONLY
85 if (reg
>= 8 && reg
<= 14) {
86 return &env
->shadow
[reg
- 8];
87 } else if (reg
== 25) {
88 return &env
->shadow
[7];
95 uint64_t cpu_alpha_load_gr(CPUAlphaState
*env
, unsigned reg
)
97 return *cpu_alpha_addr_gr(env
, reg
);
100 void cpu_alpha_store_gr(CPUAlphaState
*env
, unsigned reg
, uint64_t val
)
102 *cpu_alpha_addr_gr(env
, reg
) = val
;
105 #if defined(CONFIG_USER_ONLY)
106 int alpha_cpu_handle_mmu_fault(CPUState
*cs
, vaddr address
,
109 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
111 cs
->exception_index
= EXCP_MMFAULT
;
112 cpu
->env
.trap_arg0
= address
;
116 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
117 static int get_physical_address(CPUAlphaState
*env
, target_ulong addr
,
118 int prot_need
, int mmu_idx
,
119 target_ulong
*pphys
, int *pprot
)
121 CPUState
*cs
= CPU(alpha_env_get_cpu(env
));
122 target_long saddr
= addr
;
123 target_ulong phys
= 0;
124 target_ulong L1pte
, L2pte
, L3pte
;
125 target_ulong pt
, index
;
129 /* Handle physical accesses. */
130 if (mmu_idx
== MMU_PHYS_IDX
) {
132 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
137 /* Ensure that the virtual address is properly sign-extended from
138 the last implemented virtual address bit. */
139 if (saddr
>> TARGET_VIRT_ADDR_SPACE_BITS
!= saddr
>> 63) {
143 /* Translate the superpage. */
144 /* ??? When we do more than emulate Unix PALcode, we'll need to
145 determine which KSEG is actually active. */
146 if (saddr
< 0 && ((saddr
>> 41) & 3) == 2) {
147 /* User-space cannot access KSEG addresses. */
148 if (mmu_idx
!= MMU_KERNEL_IDX
) {
152 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
153 We would not do this if the 48-bit KSEG is enabled. */
154 phys
= saddr
& ((1ull << 40) - 1);
155 phys
|= (saddr
& (1ull << 40)) << 3;
157 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
162 /* Interpret the page table exactly like PALcode does. */
166 /* L1 page table read. */
167 index
= (addr
>> (TARGET_PAGE_BITS
+ 20)) & 0x3ff;
168 L1pte
= ldq_phys(cs
->as
, pt
+ index
*8);
170 if (unlikely((L1pte
& PTE_VALID
) == 0)) {
174 if (unlikely((L1pte
& PTE_KRE
) == 0)) {
177 pt
= L1pte
>> 32 << TARGET_PAGE_BITS
;
179 /* L2 page table read. */
180 index
= (addr
>> (TARGET_PAGE_BITS
+ 10)) & 0x3ff;
181 L2pte
= ldq_phys(cs
->as
, pt
+ index
*8);
183 if (unlikely((L2pte
& PTE_VALID
) == 0)) {
187 if (unlikely((L2pte
& PTE_KRE
) == 0)) {
190 pt
= L2pte
>> 32 << TARGET_PAGE_BITS
;
192 /* L3 page table read. */
193 index
= (addr
>> TARGET_PAGE_BITS
) & 0x3ff;
194 L3pte
= ldq_phys(cs
->as
, pt
+ index
*8);
196 phys
= L3pte
>> 32 << TARGET_PAGE_BITS
;
197 if (unlikely((L3pte
& PTE_VALID
) == 0)) {
202 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
203 # error page bits out of date
206 /* Check access violations. */
207 if (L3pte
& (PTE_KRE
<< mmu_idx
)) {
208 prot
|= PAGE_READ
| PAGE_EXEC
;
210 if (L3pte
& (PTE_KWE
<< mmu_idx
)) {
213 if (unlikely((prot
& prot_need
) == 0 && prot_need
)) {
217 /* Check fault-on-operation violations. */
218 prot
&= ~(L3pte
>> 1);
220 if (unlikely((prot
& prot_need
) == 0)) {
221 ret
= (prot_need
& PAGE_EXEC
? MM_K_FOE
:
222 prot_need
& PAGE_WRITE
? MM_K_FOW
:
223 prot_need
& PAGE_READ
? MM_K_FOR
: -1);
232 hwaddr
alpha_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
234 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
238 fail
= get_physical_address(&cpu
->env
, addr
, 0, 0, &phys
, &prot
);
239 return (fail
>= 0 ? -1 : phys
);
242 int alpha_cpu_handle_mmu_fault(CPUState
*cs
, vaddr addr
, int rw
,
245 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
246 CPUAlphaState
*env
= &cpu
->env
;
250 fail
= get_physical_address(env
, addr
, 1 << rw
, mmu_idx
, &phys
, &prot
);
251 if (unlikely(fail
>= 0)) {
252 cs
->exception_index
= EXCP_MMFAULT
;
253 env
->trap_arg0
= addr
;
254 env
->trap_arg1
= fail
;
255 env
->trap_arg2
= (rw
== 2 ? -1 : rw
);
259 tlb_set_page(cs
, addr
& TARGET_PAGE_MASK
, phys
& TARGET_PAGE_MASK
,
260 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
263 #endif /* USER_ONLY */
265 void alpha_cpu_do_interrupt(CPUState
*cs
)
267 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
268 CPUAlphaState
*env
= &cpu
->env
;
269 int i
= cs
->exception_index
;
271 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
273 const char *name
= "<unknown>";
282 case EXCP_SMP_INTERRUPT
:
283 name
= "smp_interrupt";
285 case EXCP_CLK_INTERRUPT
:
286 name
= "clk_interrupt";
288 case EXCP_DEV_INTERRUPT
:
289 name
= "dev_interrupt";
310 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64
" sp=%016" PRIx64
"\n",
311 ++count
, name
, env
->error_code
, env
->pc
, env
->ir
[IR_SP
]);
314 cs
->exception_index
= -1;
316 #if !defined(CONFIG_USER_ONLY)
324 case EXCP_SMP_INTERRUPT
:
327 case EXCP_CLK_INTERRUPT
:
330 case EXCP_DEV_INTERRUPT
:
350 /* There are 64 entry points for both privileged and unprivileged,
351 with bit 0x80 indicating unprivileged. Each entry point gets
352 64 bytes to do its job. */
354 i
= 0x2000 + (i
- 0x80) * 64;
360 cpu_abort(cs
, "Unhandled CPU exception");
363 /* Remember where the exception happened. Emulate real hardware in
364 that the low bit of the PC indicates PALmode. */
365 env
->exc_addr
= env
->pc
| env
->pal_mode
;
367 /* Continue execution at the PALcode entry point. */
368 env
->pc
= env
->palbr
+ i
;
370 /* Switch to PALmode. */
372 #endif /* !USER_ONLY */
375 bool alpha_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
377 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
378 CPUAlphaState
*env
= &cpu
->env
;
381 /* We never take interrupts while in PALmode. */
386 /* Fall through the switch, collecting the highest priority
387 interrupt that isn't masked by the processor status IPL. */
388 /* ??? This hard-codes the OSF/1 interrupt levels. */
389 switch (env
->ps
& PS_INT_MASK
) {
391 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
392 idx
= EXCP_DEV_INTERRUPT
;
396 if (interrupt_request
& CPU_INTERRUPT_TIMER
) {
397 idx
= EXCP_CLK_INTERRUPT
;
401 if (interrupt_request
& CPU_INTERRUPT_SMP
) {
402 idx
= EXCP_SMP_INTERRUPT
;
406 if (interrupt_request
& CPU_INTERRUPT_MCHK
) {
411 cs
->exception_index
= idx
;
413 alpha_cpu_do_interrupt(cs
);
419 void alpha_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
422 static const char *linux_reg_names
[] = {
423 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
424 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
425 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
426 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
428 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
429 CPUAlphaState
*env
= &cpu
->env
;
432 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS %02x\n",
434 for (i
= 0; i
< 31; i
++) {
435 cpu_fprintf(f
, "IR%02d %s " TARGET_FMT_lx
" ", i
,
436 linux_reg_names
[i
], cpu_alpha_load_gr(env
, i
));
438 cpu_fprintf(f
, "\n");
441 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
442 env
->lock_addr
, env
->lock_value
);
444 for (i
= 0; i
< 31; i
++) {
445 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
446 *((uint64_t *)(&env
->fir
[i
])));
448 cpu_fprintf(f
, "\n");
450 cpu_fprintf(f
, "\n");
453 /* This should only be called from translate, via gen_excp.
454 We expect that ENV->PC has already been updated. */
455 void QEMU_NORETURN
helper_excp(CPUAlphaState
*env
, int excp
, int error
)
457 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
458 CPUState
*cs
= CPU(cpu
);
460 cs
->exception_index
= excp
;
461 env
->error_code
= error
;
465 /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
466 void QEMU_NORETURN
dynamic_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
469 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
470 CPUState
*cs
= CPU(cpu
);
472 cs
->exception_index
= excp
;
473 env
->error_code
= error
;
475 cpu_restore_state(cs
, retaddr
);
476 /* Floating-point exceptions (our only users) point to the next PC. */
482 void QEMU_NORETURN
arith_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
483 int exc
, uint64_t mask
)
485 env
->trap_arg0
= exc
;
486 env
->trap_arg1
= mask
;
487 dynamic_excp(env
, retaddr
, EXCP_ARITH
, 0);