diff options
Diffstat (limited to 'target-mips')
-rw-r--r-- | target-mips/cpu.h | 11 | ||||
-rw-r--r-- | target-mips/machine.c | 16 | ||||
-rw-r--r-- | target-mips/op_helper.c | 14 | ||||
-rw-r--r-- | target-mips/translate.c | 55 |
4 files changed, 83 insertions, 13 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h index a9b2c7ae38..8b9a92ebdc 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -168,6 +168,7 @@ struct TCState { target_ulong CP0_TCSchedule; target_ulong CP0_TCScheFBack; int32_t CP0_Debug_tcstatus; + target_ulong CP0_UserLocal; }; typedef struct CPUMIPSState CPUMIPSState; @@ -362,6 +363,7 @@ struct CPUMIPSState { int32_t CP0_Config3; #define CP0C3_M 31 #define CP0C3_ISA_ON_EXC 16 +#define CP0C3_ULRI 13 #define CP0C3_DSPP 10 #define CP0C3_LPA 7 #define CP0C3_VEIC 6 @@ -470,6 +472,8 @@ struct CPUMIPSState { /* MIPS DSP resources access. */ #define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */ #define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */ + /* Extra flag about HWREna register. */ +#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ @@ -479,8 +483,6 @@ struct CPUMIPSState { uint32_t CP0_TCStatus_rw_bitmask; /* Read/write bits in CP0_TCStatus */ int insn_flags; /* Supported instruction set */ - target_ulong tls_value; /* For usermode emulation */ - CPU_COMMON /* Fields from here on are preserved across CPU reset. */ @@ -523,7 +525,7 @@ void mips_cpu_list (FILE *f, fprintf_function cpu_fprintf); extern void cpu_wrdsp(uint32_t rs, uint32_t mask_num, CPUMIPSState *env); extern uint32_t cpu_rddsp(uint32_t mask_num, CPUMIPSState *env); -#define CPU_SAVE_VERSION 3 +#define CPU_SAVE_VERSION 4 /* MMU modes definitions. We carefully match the indices with our hflags layout. */ @@ -682,7 +684,8 @@ static inline void cpu_get_tb_cpu_state(CPUMIPSState *env, target_ulong *pc, { *pc = env->active_tc.PC; *cs_base = 0; - *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK); + *flags = env->hflags & (MIPS_HFLAG_TMASK | MIPS_HFLAG_BMASK | + MIPS_HFLAG_HWRENA_ULR); } static inline int mips_vpe_active(CPUMIPSState *env) diff --git a/target-mips/machine.c b/target-mips/machine.c index 0a07db8540..0496faa910 100644 --- a/target-mips/machine.c +++ b/target-mips/machine.c @@ -25,6 +25,7 @@ static void save_tc(QEMUFile *f, TCState *tc) qemu_put_betls(f, &tc->CP0_TCSchedule); qemu_put_betls(f, &tc->CP0_TCScheFBack); qemu_put_sbe32s(f, &tc->CP0_Debug_tcstatus); + qemu_put_betls(f, &tc->CP0_UserLocal); } static void save_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu) @@ -151,7 +152,7 @@ void cpu_save(QEMUFile *f, void *opaque) save_fpu(f, &env->fpus[i]); } -static void load_tc(QEMUFile *f, TCState *tc) +static void load_tc(QEMUFile *f, TCState *tc, int version_id) { int i; @@ -173,6 +174,9 @@ static void load_tc(QEMUFile *f, TCState *tc) qemu_get_betls(f, &tc->CP0_TCSchedule); qemu_get_betls(f, &tc->CP0_TCScheFBack); qemu_get_sbe32s(f, &tc->CP0_Debug_tcstatus); + if (version_id >= 4) { + qemu_get_betls(f, &tc->CP0_UserLocal); + } } static void load_fpu(QEMUFile *f, CPUMIPSFPUContext *fpu) @@ -194,11 +198,12 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) MIPSCPU *cpu = mips_env_get_cpu(env); int i; - if (version_id != 3) + if (version_id < 3) { return -EINVAL; + } /* Load active TC */ - load_tc(f, &env->active_tc); + load_tc(f, &env->active_tc, version_id); /* Load active FPU */ load_fpu(f, &env->active_fpu); @@ -298,8 +303,9 @@ int cpu_load(QEMUFile *f, void *opaque, int version_id) qemu_get_sbe32s(f, &env->CP0_DESAVE); /* Load inactive TC state */ - for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) - load_tc(f, &env->tcs[i]); + for (i = 0; i < MIPS_SHADOW_SET_MAX; i++) { + load_tc(f, &env->tcs[i], version_id); + } for (i = 0; i < MIPS_FPU_MAX; i++) load_fpu(f, &env->fpus[i]); diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c index 4704216834..27651a4a00 100644 --- a/target-mips/op_helper.c +++ b/target-mips/op_helper.c @@ -1297,7 +1297,19 @@ void helper_mtc0_srsconf4(CPUMIPSState *env, target_ulong arg1) void helper_mtc0_hwrena(CPUMIPSState *env, target_ulong arg1) { - env->CP0_HWREna = arg1 & 0x0000000F; + uint32_t mask = 0x0000000F; + + if (env->CP0_Config3 & (1 << CP0C3_ULRI)) { + mask |= (1 << 29); + + if (arg1 & (1 << 29)) { + env->hflags |= MIPS_HFLAG_HWRENA_ULR; + } else { + env->hflags &= ~MIPS_HFLAG_HWRENA_ULR; + } + } + + env->CP0_HWREna = arg1 & mask; } void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1) diff --git a/target-mips/translate.c b/target-mips/translate.c index d95ab9efe7..1b2bf7f790 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -1072,6 +1072,7 @@ typedef struct DisasContext { uint32_t hflags, saved_hflags; int bstate; target_ulong btarget; + bool ulri; } DisasContext; enum { @@ -4215,7 +4216,18 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; + goto die; // break; + case 2: + if (ctx->ulri) { + tcg_gen_ld32s_tl(arg, cpu_env, + offsetof(CPUMIPSState, + active_tc.CP0_UserLocal)); + rn = "UserLocal"; + } else { + tcg_gen_movi_tl(arg, 0); + } + break; default: goto die; } @@ -4802,7 +4814,15 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ rn = "ContextConfig"; + goto die; // break; + case 2: + if (ctx->ulri) { + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; + } + break; default: goto die; } @@ -4862,6 +4882,7 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); + ctx->bstate = BS_STOP; rn = "HWREna"; break; default: @@ -5406,7 +5427,17 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */ rn = "ContextConfig"; + goto die; // break; + case 2: + if (ctx->ulri) { + tcg_gen_ld_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; + } else { + tcg_gen_movi_tl(arg, 0); + } + break; default: goto die; } @@ -5978,7 +6009,15 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 1: // gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */ rn = "ContextConfig"; + goto die; // break; + case 2: + if (ctx->ulri) { + tcg_gen_st_tl(arg, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + rn = "UserLocal"; + } + break; default: goto die; } @@ -6038,6 +6077,7 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int reg, int sel) case 0: check_insn(ctx, ISA_MIPS32R2); gen_helper_mtc0_hwrena(cpu_env, arg); + ctx->bstate = BS_STOP; rn = "HWREna"; break; default: @@ -9060,12 +9100,20 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd) break; case 29: #if defined(CONFIG_USER_ONLY) - tcg_gen_ld_tl(t0, cpu_env, offsetof(CPUMIPSState, tls_value)); + tcg_gen_ld_tl(t0, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); gen_store_gpr(t0, rt); break; #else - /* XXX: Some CPUs implement this in hardware. - Not supported yet. */ + if ((ctx->hflags & MIPS_HFLAG_CP0) || + (ctx->hflags & MIPS_HFLAG_HWRENA_ULR)) { + tcg_gen_ld_tl(t0, cpu_env, + offsetof(CPUMIPSState, active_tc.CP0_UserLocal)); + gen_store_gpr(t0, rt); + } else { + generate_exception(ctx, EXCP_RI); + } + break; #endif default: /* Invalid */ MIPS_INVAL("rdhwr"); @@ -15609,6 +15657,7 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bstate = BS_NONE; /* Restore delay slot state from the tb context. */ ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */ + ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI); restore_cpu_state(env, &ctx); #ifdef CONFIG_USER_ONLY ctx.mem_idx = MIPS_HFLAG_UM; |