@@ -227,6 +227,7 @@ struct CPUMIPSState {
target_ulong CP0_EntryLo0;
target_ulong CP0_EntryLo1;
target_ulong CP0_Context;
+ target_ulong CP0_UserLocal;
int32_t CP0_PageMask;
int32_t CP0_PageGrain;
int32_t CP0_Wired;
@@ -361,6 +362,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
@@ -296,6 +296,7 @@ DEF_HELPER_1(rdhwr_cpunum, tl, env)
DEF_HELPER_1(rdhwr_synci_step, tl, env)
DEF_HELPER_1(rdhwr_cc, tl, env)
DEF_HELPER_1(rdhwr_ccres, tl, env)
+DEF_HELPER_1(rdhwr_ul, tl, env)
DEF_HELPER_2(pmon, void, env, int)
DEF_HELPER_1(wait, void, env)
@@ -1301,7 +1301,13 @@ 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 |= 0x20000000;
+ }
+
+ env->CP0_HWREna = arg1 & mask;
}
void helper_mtc0_count(CPUMIPSState *env, target_ulong arg1)
@@ -2091,6 +2097,18 @@ target_ulong helper_rdhwr_ccres(CPUMIPSState *env)
return 0;
}
+target_ulong helper_rdhwr_ul(CPUMIPSState *env)
+{
+ if ((env->hflags & MIPS_HFLAG_CP0) ||
+ (env->CP0_HWREna & (1 << 29))) {
+ return env->CP0_UserLocal;
+ } else {
+ helper_raise_exception(env, EXCP_RI);
+ }
+
+ return 0;
+}
+
void helper_pmon(CPUMIPSState *env, int function)
{
function /= 2;
@@ -4216,7 +4216,17 @@ static void gen_mfc0(CPUMIPSState *env, DisasContext *ctx,
case 1:
// gen_helper_mfc0_contextconfig(arg); /* SmartMIPS ASE */
rn = "ContextConfig";
+ goto die;
// break;
+ case 2:
+ if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_UserLocal));
+ tcg_gen_ext32s_tl(arg, arg);
+ rn = "UserLocal";
+ } else {
+ tcg_gen_movi_tl(arg, 0);
+ }
default:
goto die;
}
@@ -4804,7 +4814,15 @@ static void gen_mtc0(CPUMIPSState *env, DisasContext *ctx,
case 1:
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
rn = "ContextConfig";
+ goto die;
// break;
+ case 2:
+ if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+ tcg_gen_st_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_UserLocal));
+ rn = "UserLocal";
+ }
+ break;
default:
goto die;
}
@@ -5409,7 +5427,17 @@ static void gen_dmfc0(CPUMIPSState *env, DisasContext *ctx,
case 1:
// gen_helper_dmfc0_contextconfig(arg); /* SmartMIPS ASE */
rn = "ContextConfig";
+ goto die;
// break;
+ case 2:
+ if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+ tcg_gen_ld_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_UserLocal));
+ rn = "UserLocal";
+ } else {
+ tcg_gen_movi_tl(arg, 0);
+ }
+ break;
default:
goto die;
}
@@ -5982,7 +6010,15 @@ static void gen_dmtc0(CPUMIPSState *env, DisasContext *ctx,
case 1:
// gen_helper_mtc0_contextconfig(cpu_env, arg); /* SmartMIPS ASE */
rn = "ContextConfig";
+ goto die;
// break;
+ case 2:
+ if (env->CP0_Config3 & (1 << CP0C3_ULRI)) {
+ tcg_gen_st_tl(arg, cpu_env,
+ offsetof(CPUMIPSState, CP0_UserLocal));
+ rn = "UserLocal";
+ }
+ break;
default:
goto die;
}
@@ -9068,8 +9104,10 @@ static void gen_rdhwr(DisasContext *ctx, int rt, int rd)
gen_store_gpr(t0, rt);
break;
#else
- /* XXX: Some CPUs implement this in hardware.
- Not supported yet. */
+ save_cpu_state(ctx, 1);
+ gen_helper_rdhwr_ul(t0, cpu_env);
+ gen_store_gpr(t0, rt);
+ break;
#endif
default: /* Invalid */
MIPS_INVAL("rdhwr");
@@ -16034,6 +16072,7 @@ void cpu_state_reset(CPUMIPSState *env)
/* vectored interrupts not implemented, timer on int 7,
no performance counters. */
env->CP0_IntCtl = 0xe0000000;
+ env->CP0_UserLocal = 0;
{
int i;