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)
164 int cpu_alpha_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
165 int mmu_idx
, int is_softmmu
)
168 env
->exception_index
= EXCP_ITB_MISS
;
170 env
->exception_index
= EXCP_DFAULT
;
171 env
->ipr
[IPR_EXC_ADDR
] = address
;
176 void do_interrupt (CPUState
*env
)
178 env
->exception_index
= -1;
183 target_phys_addr_t
cpu_get_phys_page_debug (CPUState
*env
, target_ulong addr
)
188 int cpu_alpha_handle_mmu_fault (CPUState
*env
, target_ulong address
, int rw
,
189 int mmu_idx
, int is_softmmu
)
194 /* Instruction translation buffer miss */
195 env
->exception_index
= EXCP_ITB_MISS
;
197 if (env
->ipr
[IPR_EXC_ADDR
] & 1)
198 env
->exception_index
= EXCP_DTB_MISS_PAL
;
200 env
->exception_index
= EXCP_DTB_MISS_NATIVE
;
201 opc
= (ldl_code(env
->pc
) >> 21) << 4;
207 env
->ipr
[IPR_MM_STAT
] = opc
;
213 int cpu_alpha_mfpr (CPUState
*env
, int iprn
, uint64_t *valp
)
218 hwpcb
= env
->ipr
[IPR_PCBB
];
221 if (env
->features
& FEATURE_ASN
)
222 *valp
= env
->ipr
[IPR_ASN
];
227 *valp
= ((int64_t)(env
->ipr
[IPR_ASTEN
] << 60)) >> 60;
230 *valp
= ((int64_t)(env
->ipr
[IPR_ASTSR
] << 60)) >> 60;
237 if (env
->features
& FEATURE_SPS
)
238 *valp
= env
->ipr
[IPR_ESP
];
240 *valp
= ldq_raw(hwpcb
+ 8);
243 *valp
= ((int64_t)(env
->ipr
[IPR_FEN
] << 63)) >> 63;
250 *valp
= ((int64_t)(env
->ipr
[IPR_IPL
] << 59)) >> 59;
253 if (!(env
->ipr
[IPR_EXC_ADDR
] & 1)) {
256 if (env
->features
& FEATURE_SPS
)
257 *valp
= env
->ipr
[IPR_KSP
];
259 *valp
= ldq_raw(hwpcb
+ 0);
263 *valp
= ((int64_t)(env
->ipr
[IPR_MCES
] << 59)) >> 59;
266 /* Implementation specific */
270 *valp
= ((int64_t)env
->ipr
[IPR_PCBB
] << 16) >> 16;
273 *valp
= env
->ipr
[IPR_PRBR
];
276 *valp
= env
->ipr
[IPR_PTBR
];
279 *valp
= (int64_t)((int32_t)env
->ipr
[IPR_SCBB
]);
286 *valp
= (int64_t)((int16_t)env
->ipr
[IPR_SISR
]);
288 if (env
->features
& FEATURE_SPS
)
289 *valp
= env
->ipr
[IPR_SSP
];
291 *valp
= ldq_raw(hwpcb
+ 16);
294 if (env
->features
& FEATURE_VIRBND
)
295 *valp
= env
->ipr
[IPR_SYSPTBR
];
300 if ((env
->features
& FEATURE_TBCHK
)) {
329 if (env
->features
& FEATURE_SPS
)
330 *valp
= env
->ipr
[IPR_USP
];
332 *valp
= ldq_raw(hwpcb
+ 24);
335 if (env
->features
& FEATURE_VIRBND
)
336 *valp
= env
->ipr
[IPR_VIRBND
];
341 *valp
= env
->ipr
[IPR_VPTB
];
344 *valp
= env
->ipr
[IPR_WHAMI
];
355 int cpu_alpha_mtpr (CPUState
*env
, int iprn
, uint64_t val
, uint64_t *oldvalp
)
357 uint64_t hwpcb
, tmp64
;
361 hwpcb
= env
->ipr
[IPR_PCBB
];
368 tmp8
= ((int8_t)(env
->ipr
[IPR_ASTEN
] << 4)) >> 4;
371 tmp8
|= (val
>> 4) & 0xF;
372 env
->ipr
[IPR_ASTEN
] &= ~0xF;
373 env
->ipr
[IPR_ASTEN
] |= tmp8
;
377 tmp8
= ((int8_t)(env
->ipr
[IPR_ASTSR
] << 4)) >> 4;
380 tmp8
|= (val
>> 4) & 0xF;
381 env
->ipr
[IPR_ASTSR
] &= ~0xF;
382 env
->ipr
[IPR_ASTSR
] |= tmp8
;
385 env
->ipr
[IPR_DATFX
] &= ~0x1;
386 env
->ipr
[IPR_DATFX
] |= val
& 1;
387 tmp64
= ldq_raw(hwpcb
+ 56);
388 tmp64
&= ~0x8000000000000000ULL
;
389 tmp64
|= (val
& 1) << 63;
390 stq_raw(hwpcb
+ 56, tmp64
);
393 if (env
->features
& FEATURE_SPS
)
394 env
->ipr
[IPR_ESP
] = val
;
396 stq_raw(hwpcb
+ 8, val
);
399 env
->ipr
[IPR_FEN
] = val
& 1;
400 tmp64
= ldq_raw(hwpcb
+ 56);
403 stq_raw(hwpcb
+ 56, tmp64
);
406 /* XXX: TODO: Send IRQ to CPU #ir[16] */
409 *oldvalp
= ((int64_t)(env
->ipr
[IPR_IPL
] << 59)) >> 59;
410 env
->ipr
[IPR_IPL
] &= ~0x1F;
411 env
->ipr
[IPR_IPL
] |= val
& 0x1F;
412 /* XXX: may issue an interrupt or ASR _now_ */
416 if (!(env
->ipr
[IPR_EXC_ADDR
] & 1)) {
419 if (env
->features
& FEATURE_SPS
)
420 env
->ipr
[IPR_KSP
] = val
;
422 stq_raw(hwpcb
+ 0, val
);
426 env
->ipr
[IPR_MCES
] &= ~((val
& 0x7) | 0x18);
427 env
->ipr
[IPR_MCES
] |= val
& 0x18;
430 /* Implementation specific */
439 env
->ipr
[IPR_PRBR
] = val
;
446 env
->ipr
[IPR_SCBB
] = (uint32_t)val
;
450 env
->ipr
[IPR_SISR
] |= 1 << (val
& 0xF);
451 /* XXX: request a software interrupt _now_ */
459 if (env
->features
& FEATURE_SPS
)
460 env
->ipr
[IPR_SSP
] = val
;
462 stq_raw(hwpcb
+ 16, val
);
465 if (env
->features
& FEATURE_VIRBND
)
466 env
->ipr
[IPR_SYSPTBR
] = val
;
481 tlb_flush_page(env
, val
);
484 tlb_flush_page(env
, val
);
487 tlb_flush_page(env
, val
);
490 if (env
->features
& FEATURE_SPS
)
491 env
->ipr
[IPR_USP
] = val
;
493 stq_raw(hwpcb
+ 24, val
);
496 if (env
->features
& FEATURE_VIRBND
)
497 env
->ipr
[IPR_VIRBND
] = val
;
502 env
->ipr
[IPR_VPTB
] = val
;
517 void do_interrupt (CPUState
*env
)
521 env
->ipr
[IPR_EXC_ADDR
] = env
->pc
| 1;
522 excp
= env
->exception_index
;
523 env
->exception_index
= -1;
525 /* XXX: disable interrupts and memory mapping */
526 if (env
->ipr
[IPR_PAL_BASE
] != -1ULL) {
527 /* We use native PALcode */
528 env
->pc
= env
->ipr
[IPR_PAL_BASE
] + excp
;
530 /* We use emulated PALcode */
533 env
->pc
= env
->ipr
[IPR_EXC_ADDR
] & ~7;
534 env
->ipr
[IPR_EXC_ADDR
] = env
->ipr
[IPR_EXC_ADDR
] & 1;
535 /* XXX: re-enable interrupts and memory mapping */
540 void cpu_dump_state (CPUState
*env
, FILE *f
,
541 int (*cpu_fprintf
)(FILE *f
, const char *fmt
, ...),
544 static const char *linux_reg_names
[] = {
545 "v0 ", "t0 ", "t1 ", "t2 ", "t3 ", "t4 ", "t5 ", "t6 ",
546 "t7 ", "s0 ", "s1 ", "s2 ", "s3 ", "s4 ", "s5 ", "fp ",
547 "a0 ", "a1 ", "a2 ", "a3 ", "a4 ", "a5 ", "t8 ", "t9 ",
548 "t10", "t11", "ra ", "t12", "at ", "gp ", "sp ", "zero",
552 cpu_fprintf(f
, " PC " TARGET_FMT_lx
" PS " TARGET_FMT_lx
"\n",
554 for (i
= 0; i
< 31; i
++) {
555 cpu_fprintf(f
, "IR%02d %s " TARGET_FMT_lx
" ", i
,
556 linux_reg_names
[i
], env
->ir
[i
]);
558 cpu_fprintf(f
, "\n");
561 cpu_fprintf(f
, "lock_a " TARGET_FMT_lx
" lock_v " TARGET_FMT_lx
"\n",
562 env
->lock_addr
, env
->lock_value
);
564 for (i
= 0; i
< 31; i
++) {
565 cpu_fprintf(f
, "FIR%02d " TARGET_FMT_lx
" ", i
,
566 *((uint64_t *)(&env
->fir
[i
])));
568 cpu_fprintf(f
, "\n");
570 cpu_fprintf(f
, "\n");