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 /* Ensure that the virtual address is properly sign-extended from
130 the last implemented virtual address bit. */
131 if (saddr
>> TARGET_VIRT_ADDR_SPACE_BITS
!= saddr
>> 63) {
135 /* Translate the superpage. */
136 /* ??? When we do more than emulate Unix PALcode, we'll need to
137 determine which KSEG is actually active. */
138 if (saddr
< 0 && ((saddr
>> 41) & 3) == 2) {
139 /* User-space cannot access KSEG addresses. */
140 if (mmu_idx
!= MMU_KERNEL_IDX
) {
144 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
145 We would not do this if the 48-bit KSEG is enabled. */
146 phys
= saddr
& ((1ull << 40) - 1);
147 phys
|= (saddr
& (1ull << 40)) << 3;
149 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
154 /* Interpret the page table exactly like PALcode does. */
158 /* L1 page table read. */
159 index
= (addr
>> (TARGET_PAGE_BITS
+ 20)) & 0x3ff;
160 L1pte
= ldq_phys(cs
->as
, pt
+ index
*8);
162 if (unlikely((L1pte
& PTE_VALID
) == 0)) {
166 if (unlikely((L1pte
& PTE_KRE
) == 0)) {
169 pt
= L1pte
>> 32 << TARGET_PAGE_BITS
;
171 /* L2 page table read. */
172 index
= (addr
>> (TARGET_PAGE_BITS
+ 10)) & 0x3ff;
173 L2pte
= ldq_phys(cs
->as
, pt
+ index
*8);
175 if (unlikely((L2pte
& PTE_VALID
) == 0)) {
179 if (unlikely((L2pte
& PTE_KRE
) == 0)) {
182 pt
= L2pte
>> 32 << TARGET_PAGE_BITS
;
184 /* L3 page table read. */
185 index
= (addr
>> TARGET_PAGE_BITS
) & 0x3ff;
186 L3pte
= ldq_phys(cs
->as
, pt
+ index
*8);
188 phys
= L3pte
>> 32 << TARGET_PAGE_BITS
;
189 if (unlikely((L3pte
& PTE_VALID
) == 0)) {
194 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
195 # error page bits out of date
198 /* Check access violations. */
199 if (L3pte
& (PTE_KRE
<< mmu_idx
)) {
200 prot
|= PAGE_READ
| PAGE_EXEC
;
202 if (L3pte
& (PTE_KWE
<< mmu_idx
)) {
205 if (unlikely((prot
& prot_need
) == 0 && prot_need
)) {
209 /* Check fault-on-operation violations. */
210 prot
&= ~(L3pte
>> 1);
212 if (unlikely((prot
& prot_need
) == 0)) {
213 ret
= (prot_need
& PAGE_EXEC
? MM_K_FOE
:
214 prot_need
& PAGE_WRITE
? MM_K_FOW
:
215 prot_need
& PAGE_READ
? MM_K_FOR
: -1);
224 hwaddr
alpha_cpu_get_phys_page_debug(CPUState
*cs
, vaddr addr
)
226 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
230 fail
= get_physical_address(&cpu
->env
, addr
, 0, 0, &phys
, &prot
);
231 return (fail
>= 0 ? -1 : phys
);
234 int alpha_cpu_handle_mmu_fault(CPUState
*cs
, vaddr addr
, int rw
,
237 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
238 CPUAlphaState
*env
= &cpu
->env
;
242 fail
= get_physical_address(env
, addr
, 1 << rw
, mmu_idx
, &phys
, &prot
);
243 if (unlikely(fail
>= 0)) {
244 cs
->exception_index
= EXCP_MMFAULT
;
245 env
->trap_arg0
= addr
;
246 env
->trap_arg1
= fail
;
247 env
->trap_arg2
= (rw
== 2 ? -1 : rw
);
251 tlb_set_page(cs
, addr
& TARGET_PAGE_MASK
, phys
& TARGET_PAGE_MASK
,
252 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
255 #endif /* USER_ONLY */
257 void alpha_cpu_do_interrupt(CPUState
*cs
)
259 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
260 CPUAlphaState
*env
= &cpu
->env
;
261 int i
= cs
->exception_index
;
263 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
265 const char *name
= "<unknown>";
274 case EXCP_SMP_INTERRUPT
:
275 name
= "smp_interrupt";
277 case EXCP_CLK_INTERRUPT
:
278 name
= "clk_interrupt";
280 case EXCP_DEV_INTERRUPT
:
281 name
= "dev_interrupt";
308 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64
" sp=%016" PRIx64
"\n",
309 ++count
, name
, env
->error_code
, env
->pc
, env
->ir
[IR_SP
]);
312 cs
->exception_index
= -1;
314 #if !defined(CONFIG_USER_ONLY)
322 case EXCP_SMP_INTERRUPT
:
325 case EXCP_CLK_INTERRUPT
:
328 case EXCP_DEV_INTERRUPT
:
348 /* There are 64 entry points for both privileged and unprivileged,
349 with bit 0x80 indicating unprivileged. Each entry point gets
350 64 bytes to do its job. */
352 i
= 0x2000 + (i
- 0x80) * 64;
358 cpu_abort(cs
, "Unhandled CPU exception");
361 /* Remember where the exception happened. Emulate real hardware in
362 that the low bit of the PC indicates PALmode. */
363 env
->exc_addr
= env
->pc
| env
->pal_mode
;
365 /* Continue execution at the PALcode entry point. */
366 env
->pc
= env
->palbr
+ i
;
368 /* Switch to PALmode. */
370 #endif /* !USER_ONLY */
373 bool alpha_cpu_exec_interrupt(CPUState
*cs
, int interrupt_request
)
375 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
376 CPUAlphaState
*env
= &cpu
->env
;
379 /* We never take interrupts while in PALmode. */
384 /* Fall through the switch, collecting the highest priority
385 interrupt that isn't masked by the processor status IPL. */
386 /* ??? This hard-codes the OSF/1 interrupt levels. */
387 switch (env
->ps
& PS_INT_MASK
) {
389 if (interrupt_request
& CPU_INTERRUPT_HARD
) {
390 idx
= EXCP_DEV_INTERRUPT
;
394 if (interrupt_request
& CPU_INTERRUPT_TIMER
) {
395 idx
= EXCP_CLK_INTERRUPT
;
399 if (interrupt_request
& CPU_INTERRUPT_SMP
) {
400 idx
= EXCP_SMP_INTERRUPT
;
404 if (interrupt_request
& CPU_INTERRUPT_MCHK
) {
409 cs
->exception_index
= idx
;
411 alpha_cpu_do_interrupt(cs
);
417 void alpha_cpu_dump_state(CPUState
*cs
, FILE *f
, fprintf_function cpu_fprintf
,
420 static const char *linux_reg_names
[] = {
421 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
422 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
423 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
424 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
426 AlphaCPU
*cpu
= ALPHA_CPU(cs
);
427 CPUAlphaState
*env
= &cpu
->env
;
430 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS %02x\n",
432 for (i
= 0; i
< 31; i
++) {
433 cpu_fprintf(f
, "IR%02d %s " TARGET_FMT_lx
" ", i
,
434 linux_reg_names
[i
], cpu_alpha_load_gr(env
, i
));
436 cpu_fprintf(f
, "\n");
439 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
440 env
->lock_addr
, env
->lock_value
);
442 for (i
= 0; i
< 31; i
++) {
443 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
444 *((uint64_t *)(&env
->fir
[i
])));
446 cpu_fprintf(f
, "\n");
448 cpu_fprintf(f
, "\n");
451 /* This should only be called from translate, via gen_excp.
452 We expect that ENV->PC has already been updated. */
453 void QEMU_NORETURN
helper_excp(CPUAlphaState
*env
, int excp
, int error
)
455 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
456 CPUState
*cs
= CPU(cpu
);
458 cs
->exception_index
= excp
;
459 env
->error_code
= error
;
463 /* This may be called from any of the helpers to set up EXCEPTION_INDEX. */
464 void QEMU_NORETURN
dynamic_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
467 AlphaCPU
*cpu
= alpha_env_get_cpu(env
);
468 CPUState
*cs
= CPU(cpu
);
470 cs
->exception_index
= excp
;
471 env
->error_code
= error
;
473 cpu_restore_state(cs
, retaddr
);
474 /* Floating-point exceptions (our only users) point to the next PC. */
480 void QEMU_NORETURN
arith_excp(CPUAlphaState
*env
, uintptr_t retaddr
,
481 int exc
, uint64_t mask
)
483 env
->trap_arg0
= exc
;
484 env
->trap_arg1
= mask
;
485 dynamic_excp(env
, retaddr
, EXCP_ARITH
, 0);