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/>.
26 #include "softfloat.h"
28 uint64_t cpu_alpha_load_fpcr (CPUState
*env
)
33 t
= env
->fpcr_exc_status
;
36 if (t
& float_flag_invalid
) {
39 if (t
& float_flag_divbyzero
) {
42 if (t
& float_flag_overflow
) {
45 if (t
& float_flag_underflow
) {
48 if (t
& float_flag_inexact
) {
53 t
= env
->fpcr_exc_mask
;
54 if (t
& float_flag_invalid
) {
57 if (t
& float_flag_divbyzero
) {
60 if (t
& float_flag_overflow
) {
63 if (t
& float_flag_underflow
) {
66 if (t
& float_flag_inexact
) {
70 switch (env
->fpcr_dyn_round
) {
71 case float_round_nearest_even
:
74 case float_round_down
:
80 case float_round_to_zero
:
81 r
|= FPCR_DYN_CHOPPED
;
98 void cpu_alpha_store_fpcr (CPUState
*env
, uint64_t val
)
103 if (val
& FPCR_INV
) {
104 t
|= float_flag_invalid
;
106 if (val
& FPCR_DZE
) {
107 t
|= float_flag_divbyzero
;
109 if (val
& FPCR_OVF
) {
110 t
|= float_flag_overflow
;
112 if (val
& FPCR_UNF
) {
113 t
|= float_flag_underflow
;
115 if (val
& FPCR_INE
) {
116 t
|= float_flag_inexact
;
118 env
->fpcr_exc_status
= t
;
121 if (val
& FPCR_INVD
) {
122 t
|= float_flag_invalid
;
124 if (val
& FPCR_DZED
) {
125 t
|= float_flag_divbyzero
;
127 if (val
& FPCR_OVFD
) {
128 t
|= float_flag_overflow
;
130 if (val
& FPCR_UNFD
) {
131 t
|= float_flag_underflow
;
133 if (val
& FPCR_INED
) {
134 t
|= float_flag_inexact
;
136 env
->fpcr_exc_mask
= t
;
138 switch (val
& FPCR_DYN_MASK
) {
139 case FPCR_DYN_CHOPPED
:
140 t
= float_round_to_zero
;
143 t
= float_round_down
;
145 case FPCR_DYN_NORMAL
:
146 t
= float_round_nearest_even
;
152 env
->fpcr_dyn_round
= t
;
154 env
->fpcr_flush_to_zero
155 = (val
& (FPCR_UNDZ
|FPCR_UNFD
)) == (FPCR_UNDZ
|FPCR_UNFD
);
157 env
->fpcr_dnz
= (val
& FPCR_DNZ
) != 0;
158 env
->fpcr_dnod
= (val
& FPCR_DNOD
) != 0;
159 env
->fpcr_undz
= (val
& FPCR_UNDZ
) != 0;
162 #if defined(CONFIG_USER_ONLY)
163 int cpu_alpha_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
164 int mmu_idx
, int is_softmmu
)
166 env
->exception_index
= EXCP_MMFAULT
;
167 env
->trap_arg0
= address
;
171 void swap_shadow_regs(CPUState
*env
)
173 uint64_t i0
, i1
, i2
, i3
, i4
, i5
, i6
, i7
;
184 env
->ir
[8] = env
->shadow
[0];
185 env
->ir
[9] = env
->shadow
[1];
186 env
->ir
[10] = env
->shadow
[2];
187 env
->ir
[11] = env
->shadow
[3];
188 env
->ir
[12] = env
->shadow
[4];
189 env
->ir
[13] = env
->shadow
[5];
190 env
->ir
[14] = env
->shadow
[6];
191 env
->ir
[25] = env
->shadow
[7];
203 /* Returns the OSF/1 entMM failure indication, or -1 on success. */
204 static int get_physical_address(CPUState
*env
, target_ulong addr
,
205 int prot_need
, int mmu_idx
,
206 target_ulong
*pphys
, int *pprot
)
208 target_long saddr
= addr
;
209 target_ulong phys
= 0;
210 target_ulong L1pte
, L2pte
, L3pte
;
211 target_ulong pt
, index
;
215 /* Ensure that the virtual address is properly sign-extended from
216 the last implemented virtual address bit. */
217 if (saddr
>> TARGET_VIRT_ADDR_SPACE_BITS
!= saddr
>> 63) {
221 /* Translate the superpage. */
222 /* ??? When we do more than emulate Unix PALcode, we'll need to
223 determine which KSEG is actually active. */
224 if (saddr
< 0 && ((saddr
>> 41) & 3) == 2) {
225 /* User-space cannot access KSEG addresses. */
226 if (mmu_idx
!= MMU_KERNEL_IDX
) {
230 /* For the benefit of the Typhoon chipset, move bit 40 to bit 43.
231 We would not do this if the 48-bit KSEG is enabled. */
232 phys
= saddr
& ((1ull << 40) - 1);
233 phys
|= (saddr
& (1ull << 40)) << 3;
235 prot
= PAGE_READ
| PAGE_WRITE
| PAGE_EXEC
;
240 /* Interpret the page table exactly like PALcode does. */
244 /* L1 page table read. */
245 index
= (addr
>> (TARGET_PAGE_BITS
+ 20)) & 0x3ff;
246 L1pte
= ldq_phys(pt
+ index
*8);
248 if (unlikely((L1pte
& PTE_VALID
) == 0)) {
252 if (unlikely((L1pte
& PTE_KRE
) == 0)) {
255 pt
= L1pte
>> 32 << TARGET_PAGE_BITS
;
257 /* L2 page table read. */
258 index
= (addr
>> (TARGET_PAGE_BITS
+ 10)) & 0x3ff;
259 L2pte
= ldq_phys(pt
+ index
*8);
261 if (unlikely((L2pte
& PTE_VALID
) == 0)) {
265 if (unlikely((L2pte
& PTE_KRE
) == 0)) {
268 pt
= L2pte
>> 32 << TARGET_PAGE_BITS
;
270 /* L3 page table read. */
271 index
= (addr
>> TARGET_PAGE_BITS
) & 0x3ff;
272 L3pte
= ldq_phys(pt
+ index
*8);
274 phys
= L3pte
>> 32 << TARGET_PAGE_BITS
;
275 if (unlikely((L3pte
& PTE_VALID
) == 0)) {
280 #if PAGE_READ != 1 || PAGE_WRITE != 2 || PAGE_EXEC != 4
281 # error page bits out of date
284 /* Check access violations. */
285 if (L3pte
& (PTE_KRE
<< mmu_idx
)) {
286 prot
|= PAGE_READ
| PAGE_EXEC
;
288 if (L3pte
& (PTE_KWE
<< mmu_idx
)) {
291 if (unlikely((prot
& prot_need
) == 0 && prot_need
)) {
295 /* Check fault-on-operation violations. */
296 prot
&= ~(L3pte
>> 1);
298 if (unlikely((prot
& prot_need
) == 0)) {
299 ret
= (prot_need
& PAGE_EXEC
? MM_K_FOE
:
300 prot_need
& PAGE_WRITE
? MM_K_FOW
:
301 prot_need
& PAGE_READ
? MM_K_FOR
: -1);
310 target_phys_addr_t
cpu_get_phys_page_debug(CPUState
*env
, target_ulong addr
)
315 fail
= get_physical_address(env
, addr
, 0, 0, &phys
, &prot
);
316 return (fail
>= 0 ? -1 : phys
);
319 int cpu_alpha_handle_mmu_fault(CPUState
*env
, target_ulong addr
, int rw
,
320 int mmu_idx
, int is_softmmu
)
325 fail
= get_physical_address(env
, addr
, 1 << rw
, mmu_idx
, &phys
, &prot
);
326 if (unlikely(fail
>= 0)) {
327 env
->exception_index
= EXCP_MMFAULT
;
328 env
->trap_arg0
= addr
;
329 env
->trap_arg1
= fail
;
330 env
->trap_arg2
= (rw
== 2 ? -1 : rw
);
334 tlb_set_page(env
, addr
& TARGET_PAGE_MASK
, phys
& TARGET_PAGE_MASK
,
335 prot
, mmu_idx
, TARGET_PAGE_SIZE
);
338 #endif /* USER_ONLY */
340 void do_interrupt (CPUState
*env
)
342 int i
= env
->exception_index
;
344 if (qemu_loglevel_mask(CPU_LOG_INT
)) {
346 const char *name
= "<unknown>";
355 case EXCP_SMP_INTERRUPT
:
356 name
= "smp_interrupt";
358 case EXCP_CLK_INTERRUPT
:
359 name
= "clk_interrupt";
361 case EXCP_DEV_INTERRUPT
:
362 name
= "dev_interrupt";
389 qemu_log("INT %6d: %s(%#x) pc=%016" PRIx64
" sp=%016" PRIx64
"\n",
390 ++count
, name
, env
->error_code
, env
->pc
, env
->ir
[IR_SP
]);
393 env
->exception_index
= -1;
395 #if !defined(CONFIG_USER_ONLY)
403 case EXCP_SMP_INTERRUPT
:
406 case EXCP_CLK_INTERRUPT
:
409 case EXCP_DEV_INTERRUPT
:
429 /* There are 64 entry points for both privileged and unprivileged,
430 with bit 0x80 indicating unprivileged. Each entry point gets
431 64 bytes to do its job. */
433 i
= 0x2000 + (i
- 0x80) * 64;
439 cpu_abort(env
, "Unhandled CPU exception");
442 /* Remember where the exception happened. Emulate real hardware in
443 that the low bit of the PC indicates PALmode. */
444 env
->exc_addr
= env
->pc
| env
->pal_mode
;
446 /* Continue execution at the PALcode entry point. */
447 env
->pc
= env
->palbr
+ i
;
449 /* Switch to PALmode. */
450 if (!env
->pal_mode
) {
452 swap_shadow_regs(env
);
454 #endif /* !USER_ONLY */
457 void cpu_dump_state (CPUState
*env
, FILE *f
, fprintf_function cpu_fprintf
,
460 static const char *linux_reg_names
[] = {
461 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
462 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
463 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
464 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
468 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS %02x\n",
470 for (i
= 0; i
< 31; i
++) {
471 cpu_fprintf(f
, "IR%02d %s " TARGET_FMT_lx
" ", i
,
472 linux_reg_names
[i
], env
->ir
[i
]);
474 cpu_fprintf(f
, "\n");
477 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
478 env
->lock_addr
, env
->lock_value
);
480 for (i
= 0; i
< 31; i
++) {
481 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
482 *((uint64_t *)(&env
->fir
[i
])));
484 cpu_fprintf(f
, "\n");
486 cpu_fprintf(f
, "\n");