#include "host-utils.h"
#include "helper.h"
+
+#ifndef CONFIG_USER_ONLY
+static inline void cpu_mips_tlb_flush (CPUState *env, int flush_global);
+#endif
+
/*****************************************************************************/
/* Exceptions processing helpers */
helper_raise_exception_err(exception, 0);
}
-void helper_interrupt_restart (void)
-{
- if (!(env->CP0_Status & (1 << CP0St_EXL)) &&
- !(env->CP0_Status & (1 << CP0St_ERL)) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- (env->CP0_Status & (1 << CP0St_IE)) &&
- (env->CP0_Status & env->CP0_Cause & CP0Ca_IP_mask)) {
- env->CP0_Cause &= ~(0x1f << CP0Ca_EC);
- helper_raise_exception(EXCP_EXT_INTERRUPT);
- }
-}
-
#if !defined(CONFIG_USER_ONLY)
static void do_restore_state (void *pc_ptr)
{
}
#endif /* TARGET_MIPS64 */
+static const int multiple_regs[] = { 16, 17, 18, 19, 20, 21, 22, 23, 30 };
+
+void helper_lwm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldl_raw
+#else
+ uint32_t (*ldfun)(target_ulong);
+
+ switch (mem_idx)
+ {
+ case 0: ldfun = ldl_kernel; break;
+ case 1: ldfun = ldl_super; break;
+ default:
+ case 2: ldfun = ldl_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] = (target_long) ldfun(addr);
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] = (target_long) ldfun(addr);
+ }
+}
+
+void helper_swm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stl_raw
+#else
+ void (*stfun)(target_ulong, uint32_t);
+
+ switch (mem_idx)
+ {
+ case 0: stfun = stl_kernel; break;
+ case 1: stfun = stl_super; break;
+ default:
+ case 2: stfun = stl_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+ addr += 4;
+ }
+ }
+
+ if (do_r31) {
+ stfun(addr, env->active_tc.gpr[31]);
+ }
+}
+
+#if defined(TARGET_MIPS64)
+void helper_ldm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef ldfun
+#define ldfun ldq_raw
+#else
+ uint64_t (*ldfun)(target_ulong);
+
+ switch (mem_idx)
+ {
+ case 0: ldfun = ldq_kernel; break;
+ case 1: ldfun = ldq_super; break;
+ default:
+ case 2: ldfun = ldq_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ env->active_tc.gpr[multiple_regs[i]] = ldfun(addr);
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ env->active_tc.gpr[31] = ldfun(addr);
+ }
+}
+
+void helper_sdm (target_ulong addr, target_ulong reglist, uint32_t mem_idx)
+{
+ target_ulong base_reglist = reglist & 0xf;
+ target_ulong do_r31 = reglist & 0x10;
+#ifdef CONFIG_USER_ONLY
+#undef stfun
+#define stfun stq_raw
+#else
+ void (*stfun)(target_ulong, uint64_t);
+
+ switch (mem_idx)
+ {
+ case 0: stfun = stq_kernel; break;
+ case 1: stfun = stq_super; break;
+ default:
+ case 2: stfun = stq_user; break;
+ }
+#endif
+
+ if (base_reglist > 0 && base_reglist <= ARRAY_SIZE (multiple_regs)) {
+ target_ulong i;
+
+ for (i = 0; i < base_reglist; i++) {
+ stfun(addr, env->active_tc.gpr[multiple_regs[i]]);
+ addr += 8;
+ }
+ }
+
+ if (do_r31) {
+ stfun(addr, env->active_tc.gpr[31]);
+ }
+}
+#endif
+
#ifndef CONFIG_USER_ONLY
/* CP0 helpers */
target_ulong helper_mfc0_mvpcontrol (void)
default: cpu_abort(env, "Invalid MMU mode!\n"); break;
}
}
- cpu_mips_update_irq(env);
}
void helper_mttc0_status(target_ulong arg1)
{
uint32_t mask = 0x00C00300;
uint32_t old = env->CP0_Cause;
+ int i;
if (env->insn_flags & ISA_MIPS32R2)
mask |= 1 << CP0Ca_DC;
cpu_mips_start_count(env);
}
- /* Handle the software interrupt as an hardware one, as they
- are very similar */
- if (arg1 & CP0Ca_IP_mask) {
- cpu_mips_update_irq(env);
+ /* Set/reset software interrupts */
+ for (i = 0 ; i < 2 ; i++) {
+ if ((old ^ env->CP0_Cause) & (1 << (CP0Ca_IP + i))) {
+ cpu_mips_soft_irq(env, i, env->CP0_Cause & (1 << (CP0Ca_IP + i)));
+ }
}
}
void helper_mtc0_ebase (target_ulong arg1)
{
/* vectored interrupts not implemented */
- /* Multi-CPU not implemented */
- env->CP0_EBase = 0x80000000 | (arg1 & 0x3FFFF000);
+ env->CP0_EBase = (env->CP0_EBase & ~0x3FFFF000) | (arg1 & 0x3FFFF000);
}
void helper_mtc0_config0 (target_ulong arg1)
}
/* MIPS MT functions */
-target_ulong helper_dmt(target_ulong arg1)
+target_ulong helper_dmt(void)
{
// TODO
- arg1 = 0;
- // rt = arg1
-
- return arg1;
+ return 0;
}
-target_ulong helper_emt(target_ulong arg1)
+target_ulong helper_emt(void)
{
// TODO
- arg1 = 0;
- // rt = arg1
-
- return arg1;
+ return 0;
}
-target_ulong helper_dvpe(target_ulong arg1)
+target_ulong helper_dvpe(void)
{
// TODO
- arg1 = 0;
- // rt = arg1
-
- return arg1;
+ return 0;
}
-target_ulong helper_evpe(target_ulong arg1)
+target_ulong helper_evpe(void)
{
// TODO
- arg1 = 0;
- // rt = arg1
-
- return arg1;
+ return 0;
}
#endif /* !CONFIG_USER_ONLY */
// TODO: store to TC register
}
-target_ulong helper_yield(target_ulong arg1)
+target_ulong helper_yield(target_ulong arg)
{
+ target_long arg1 = arg;
+
if (arg1 < 0) {
/* No scheduling policy implemented. */
if (arg1 != -2) {
#ifndef CONFIG_USER_ONLY
/* TLB management */
-void cpu_mips_tlb_flush (CPUState *env, int flush_global)
+static void cpu_mips_tlb_flush (CPUState *env, int flush_global)
{
/* Flush qemu's TLB and discard all shadowed entries. */
tlb_flush (env, flush_global);
target_ulong t0 = env->CP0_Status;
env->CP0_Status = t0 & ~(1 << CP0St_IE);
- cpu_mips_update_irq(env);
-
return t0;
}
target_ulong t0 = env->CP0_Status;
env->CP0_Status = t0 | (1 << CP0St_IE);
- cpu_mips_update_irq(env);
-
return t0;
}
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_nearest_even, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float64_to_int64_round_to_zero(fdt0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
dt2 = float32_to_int64_round_to_zero(fst0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float64_to_int32_round_to_zero(fdt0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
wt2 = float32_to_int32_round_to_zero(fst0, &env->active_fpu.fp_status);
update_fcr31();
if (GET_FP_CAUSE(env->active_fpu.fcr31) & (FP_OVERFLOW | FP_INVALID))
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_up, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float64_to_int64(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint64_t dt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
dt2 = float32_to_int64(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float64_to_int32(fdt0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
uint32_t wt2;
+ set_float_exception_flags(0, &env->active_fpu.fp_status);
set_float_rounding_mode(float_round_down, &env->active_fpu.fp_status);
wt2 = float32_to_int32(fst0, &env->active_fpu.fp_status);
RESTORE_ROUNDING_MODE;
{
if (float64_is_signaling_nan(a) ||
float64_is_signaling_nan(b) ||
- (sig && (float64_is_nan(a) || float64_is_nan(b)))) {
+ (sig && (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)))) {
float_raise(float_flag_invalid, status);
return 1;
- } else if (float64_is_nan(a) || float64_is_nan(b)) {
+ } else if (float64_is_quiet_nan(a) || float64_is_quiet_nan(b)) {
return 1;
} else {
return 0;
{
if (float32_is_signaling_nan(a) ||
float32_is_signaling_nan(b) ||
- (sig && (float32_is_nan(a) || float32_is_nan(b)))) {
+ (sig && (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)))) {
float_raise(float_flag_invalid, status);
return 1;
- } else if (float32_is_nan(a) || float32_is_nan(b)) {
+ } else if (float32_is_quiet_nan(a) || float32_is_quiet_nan(b)) {
return 1;
} else {
return 0;