summaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2006-12-06 17:59:07 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2006-12-06 17:59:07 +0000
commit873eb01234e67d27f3719310f7a89892e4727546 (patch)
tree873f375b652021d13f983208c0b2648771446f45 /target-mips
parent6ae817752b72a7c9c3bb031afa7e7cc0e4d10eaf (diff)
downloadqemu-873eb01234e67d27f3719310f7a89892e4727546.tar.gz
Dynamically translate MIPS mfc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2222 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/exec.h3
-rw-r--r--target-mips/op.c162
-rw-r--r--target-mips/op_helper.c158
-rw-r--r--target-mips/translate.c151
4 files changed, 327 insertions, 147 deletions
diff --git a/target-mips/exec.h b/target-mips/exec.h
index a1cf685a16..bc330c0295 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -66,7 +66,8 @@ void do_maddu (void);
void do_msub (void);
void do_msubu (void);
#endif
-void do_mfc0(int reg, int sel);
+void do_mfc0_random(void);
+void do_mfc0_count(void);
void do_mtc0(int reg, int sel);
void do_tlbwi (void);
void do_tlbwr (void);
diff --git a/target-mips/op.c b/target-mips/op.c
index 534c90e51f..2597e2e3d3 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -688,9 +688,167 @@ void op_jnz_T2 (void)
}
/* CP0 functions */
-void op_mfc0 (void)
+void op_mfc0_index (void)
{
- CALL_FROM_TB2(do_mfc0, PARAM1, PARAM2);
+ T0 = env->CP0_index;
+ RETURN();
+}
+
+void op_mfc0_random (void)
+{
+ CALL_FROM_TB0(do_mfc0_random);
+ RETURN();
+}
+
+void op_mfc0_entrylo0 (void)
+{
+ T0 = env->CP0_EntryLo0;
+ RETURN();
+}
+
+void op_mfc0_entrylo1 (void)
+{
+ T0 = env->CP0_EntryLo1;
+ RETURN();
+}
+
+void op_mfc0_context (void)
+{
+ T0 = env->CP0_Context;
+ RETURN();
+}
+
+void op_mfc0_pagemask (void)
+{
+ T0 = env->CP0_PageMask;
+ RETURN();
+}
+
+void op_mfc0_wired (void)
+{
+ T0 = env->CP0_Wired;
+ RETURN();
+}
+
+void op_mfc0_badvaddr (void)
+{
+ T0 = env->CP0_BadVAddr;
+ RETURN();
+}
+
+void op_mfc0_count (void)
+{
+ CALL_FROM_TB0(do_mfc0_count);
+ RETURN();
+}
+
+void op_mfc0_entryhi (void)
+{
+ T0 = env->CP0_EntryHi;
+ RETURN();
+}
+
+void op_mfc0_compare (void)
+{
+ T0 = env->CP0_Compare;
+ RETURN();
+}
+
+void op_mfc0_status (void)
+{
+ T0 = env->CP0_Status;
+ if (env->hflags & MIPS_HFLAG_UM)
+ T0 |= (1 << CP0St_UM);
+ if (env->hflags & MIPS_HFLAG_ERL)
+ T0 |= (1 << CP0St_ERL);
+ if (env->hflags & MIPS_HFLAG_EXL)
+ T0 |= (1 << CP0St_EXL);
+ RETURN();
+}
+
+void op_mfc0_cause (void)
+{
+ T0 = env->CP0_Cause;
+ RETURN();
+}
+
+void op_mfc0_epc (void)
+{
+ T0 = env->CP0_EPC;
+ RETURN();
+}
+
+void op_mfc0_prid (void)
+{
+ T0 = env->CP0_PRid;
+ RETURN();
+}
+
+void op_mfc0_config0 (void)
+{
+ T0 = env->CP0_Config0;
+ RETURN();
+}
+
+void op_mfc0_config1 (void)
+{
+ T0 = env->CP0_Config1;
+ RETURN();
+}
+
+void op_mfc0_lladdr (void)
+{
+ T0 = env->CP0_LLAddr >> 4;
+ RETURN();
+}
+
+void op_mfc0_watchlo (void)
+{
+ T0 = env->CP0_WatchLo;
+ RETURN();
+}
+
+void op_mfc0_watchhi (void)
+{
+ T0 = env->CP0_WatchHi;
+ RETURN();
+}
+
+void op_mfc0_debug (void)
+{
+ T0 = env->CP0_Debug;
+ if (env->hflags & MIPS_HFLAG_DM)
+ T0 |= 1 << CP0DB_DM;
+ RETURN();
+}
+
+void op_mfc0_depc (void)
+{
+ T0 = env->CP0_DEPC;
+ RETURN();
+}
+
+void op_mfc0_taglo (void)
+{
+ T0 = env->CP0_TagLo;
+ RETURN();
+}
+
+void op_mfc0_datalo (void)
+{
+ T0 = env->CP0_DataLo;
+ RETURN();
+}
+
+void op_mfc0_errorepc (void)
+{
+ T0 = env->CP0_ErrorEPC;
+ RETURN();
+}
+
+void op_mfc0_desave (void)
+{
+ T0 = env->CP0_DESAVE;
RETURN();
}
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index c7d86d0167..d3959f3801 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -131,10 +131,16 @@ void do_msubu (void)
#endif
#if defined(CONFIG_USER_ONLY)
-void do_mfc0 (int reg, int sel)
+void do_mfc0_random (void)
{
- cpu_abort(env, "mfc0 reg=%d sel=%d\n", reg, sel);
+ cpu_abort(env, "mfc0 random\n");
}
+
+void do_mfc0_count (void)
+{
+ cpu_abort(env, "mfc0 count\n");
+}
+
void do_mtc0 (int reg, int sel)
{
cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
@@ -159,152 +165,18 @@ void do_tlbr (void)
{
cpu_abort(env, "tlbr\n");
}
+
#else
/* CP0 helpers */
-void do_mfc0 (int reg, int sel)
+void do_mfc0_random (void)
{
- const unsigned char *rn;
+ T0 = cpu_mips_get_random(env);
+}
- if (sel != 0 && reg != 16 && reg != 28) {
- rn = "invalid";
- goto print;
- }
- switch (reg) {
- case 0:
- T0 = env->CP0_index;
- rn = "Index";
- break;
- case 1:
- T0 = cpu_mips_get_random(env);
- rn = "Random";
- break;
- case 2:
- T0 = env->CP0_EntryLo0;
- rn = "EntryLo0";
- break;
- case 3:
- T0 = env->CP0_EntryLo1;
- rn = "EntryLo1";
- break;
- case 4:
- T0 = env->CP0_Context;
- rn = "Context";
- break;
- case 5:
- T0 = env->CP0_PageMask;
- rn = "PageMask";
- break;
- case 6:
- T0 = env->CP0_Wired;
- rn = "Wired";
- break;
- case 8:
- T0 = env->CP0_BadVAddr;
- rn = "BadVaddr";
- break;
- case 9:
- T0 = cpu_mips_get_count(env);
- rn = "Count";
- break;
- case 10:
- T0 = env->CP0_EntryHi;
- rn = "EntryHi";
- break;
- case 11:
- T0 = env->CP0_Compare;
- rn = "Compare";
- break;
- case 12:
- T0 = env->CP0_Status;
- if (env->hflags & MIPS_HFLAG_UM)
- T0 |= (1 << CP0St_UM);
- rn = "Status";
- break;
- case 13:
- T0 = env->CP0_Cause;
- rn = "Cause";
- break;
- case 14:
- T0 = env->CP0_EPC;
- rn = "EPC";
- break;
- case 15:
- T0 = env->CP0_PRid;
- rn = "PRid";
- break;
- case 16:
- switch (sel) {
- case 0:
- T0 = env->CP0_Config0;
- rn = "Config";
- break;
- case 1:
- T0 = env->CP0_Config1;
- rn = "Config1";
- break;
- default:
- rn = "Unknown config register";
- break;
- }
- break;
- case 17:
- T0 = env->CP0_LLAddr >> 4;
- rn = "LLAddr";
- break;
- case 18:
- T0 = env->CP0_WatchLo;
- rn = "WatchLo";
- break;
- case 19:
- T0 = env->CP0_WatchHi;
- rn = "WatchHi";
- break;
- case 23:
- T0 = env->CP0_Debug;
- if (env->hflags & MIPS_HFLAG_DM)
- T0 |= 1 << CP0DB_DM;
- rn = "Debug";
- break;
- case 24:
- T0 = env->CP0_DEPC;
- rn = "DEPC";
- break;
- case 28:
- switch (sel) {
- case 0:
- T0 = env->CP0_TagLo;
- rn = "TagLo";
- break;
- case 1:
- T0 = env->CP0_DataLo;
- rn = "DataLo";
- break;
- default:
- rn = "unknown sel";
- break;
- }
- break;
- case 30:
- T0 = env->CP0_ErrorEPC;
- rn = "ErrorEPC";
- break;
- case 31:
- T0 = env->CP0_DESAVE;
- rn = "DESAVE";
- break;
- default:
- rn = "unknown";
- break;
- }
- print:
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
- env->PC, rn, T0, reg, sel);
- }
-#endif
- return;
+void do_mfc0_count (void)
+{
+ T0 = cpu_mips_get_count(env);
}
void do_mtc0 (int reg, int sel)
diff --git a/target-mips/translate.c b/target-mips/translate.c
index 07725b3445..e1c8bd4c70 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1349,6 +1349,155 @@ static void gen_compute_branch (DisasContext *ctx, uint16_t opc,
}
/* CP0 (MMU and control) */
+static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
+{
+ const unsigned char *rn;
+
+ if (sel != 0 && reg != 16 && reg != 28) {
+ rn = "invalid";
+ goto die;
+ }
+ switch (reg) {
+ case 0:
+ gen_op_mfc0_index();
+ rn = "Index";
+ break;
+ case 1:
+ gen_op_mfc0_random();
+ rn = "Random";
+ break;
+ case 2:
+ gen_op_mfc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 3:
+ gen_op_mfc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ case 4:
+ gen_op_mfc0_context();
+ rn = "Context";
+ break;
+ case 5:
+ gen_op_mfc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 6:
+ gen_op_mfc0_wired();
+ rn = "Wired";
+ break;
+ case 8:
+ gen_op_mfc0_badvaddr();
+ rn = "BadVaddr";
+ break;
+ case 9:
+ gen_op_mfc0_count();
+ rn = "Count";
+ break;
+ case 10:
+ gen_op_mfc0_entryhi();
+ rn = "EntryHi";
+ break;
+ case 11:
+ gen_op_mfc0_compare();
+ rn = "Compare";
+ break;
+ case 12:
+ gen_op_mfc0_status();
+ rn = "Status";
+ break;
+ case 13:
+ gen_op_mfc0_cause();
+ rn = "Cause";
+ break;
+ case 14:
+ gen_op_mfc0_epc();
+ rn = "EPC";
+ break;
+ case 15:
+ gen_op_mfc0_prid();
+ rn = "PRid";
+ break;
+ case 16:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_config0();
+ rn = "Config";
+ break;
+ case 1:
+ gen_op_mfc0_config1();
+ rn = "Config1";
+ break;
+ default:
+ rn = "Unknown config register";
+ goto die;
+ }
+ break;
+ case 17:
+ gen_op_mfc0_lladdr();
+ rn = "LLAddr";
+ break;
+ case 18:
+ gen_op_mfc0_watchlo();
+ rn = "WatchLo";
+ break;
+ case 19:
+ gen_op_mfc0_watchhi();
+ rn = "WatchHi";
+ break;
+ case 23:
+ gen_op_mfc0_debug();
+ rn = "Debug";
+ break;
+ case 24:
+ gen_op_mfc0_depc();
+ rn = "DEPC";
+ break;
+ case 28:
+ switch (sel) {
+ case 0:
+ gen_op_mfc0_taglo();
+ rn = "TagLo";
+ break;
+ case 1:
+ gen_op_mfc0_datalo();
+ rn = "DataLo";
+ break;
+ default:
+ rn = "unknown sel";
+ goto die;
+ }
+ break;
+ case 30:
+ gen_op_mfc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ case 31:
+ gen_op_mfc0_desave();
+ rn = "DESAVE";
+ break;
+ default:
+ rn = "unknown";
+ goto die;
+ }
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
+ env->PC, rn, T0, reg, sel);
+ }
+#endif
+ return;
+
+die:
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "%08x mfc0 %s => %08x (%d %d)\n",
+ env->PC, rn, T0, reg, sel);
+ }
+#endif
+ generate_exception(ctx, EXCP_RI);
+}
+
static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
{
const unsigned char *opn = "unk";
@@ -1370,7 +1519,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
/* Treat as NOP */
return;
}
- gen_op_mfc0(rd, ctx->opcode & 0x7);
+ gen_mfc0(ctx, rd, ctx->opcode & 0x7);
gen_op_store_T0_gpr(rt);
opn = "mfc0";
break;