aboutsummaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2006-12-06 18:19:33 +0000
committerths <ths@c046a42c-6fe2-441c-8c8c-71466251a162>2006-12-06 18:19:33 +0000
commit8c0fdd856c63eb11ec5ef955731b1b0cda51f967 (patch)
tree85bc9ea7b661628d50e742d9fa31b49ae4077b4e /target-mips
parent873eb01234e67d27f3719310f7a89892e4727546 (diff)
Dynamically translate MIPS mtc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2223 c046a42c-6fe2-441c-8c8c-71466251a162
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/exec.h3
-rw-r--r--target-mips/op.c180
-rw-r--r--target-mips/op_helper.c247
-rw-r--r--target-mips/translate.c213
4 files changed, 423 insertions, 220 deletions
diff --git a/target-mips/exec.h b/target-mips/exec.h
index bc330c0295..e39f70f872 100644
--- a/target-mips/exec.h
+++ b/target-mips/exec.h
@@ -68,7 +68,8 @@ void do_msubu (void);
#endif
void do_mfc0_random(void);
void do_mfc0_count(void);
-void do_mtc0(int reg, int sel);
+void do_mtc0_status_debug(uint32_t old, uint32_t val);
+void do_mtc0_status_irqraise_debug(void);
void do_tlbwi (void);
void do_tlbwr (void);
void do_tlbp (void);
diff --git a/target-mips/op.c b/target-mips/op.c
index 2597e2e3d3..7a57728345 100644
--- a/target-mips/op.c
+++ b/target-mips/op.c
@@ -852,9 +852,185 @@ void op_mfc0_desave (void)
RETURN();
}
-void op_mtc0 (void)
+void op_mtc0_index (void)
{
- CALL_FROM_TB2(do_mtc0, PARAM1, PARAM2);
+ env->CP0_index = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
+ RETURN();
+}
+
+void op_mtc0_entrylo0 (void)
+{
+ env->CP0_EntryLo0 = T0 & 0x3FFFFFFF;
+ RETURN();
+}
+
+void op_mtc0_entrylo1 (void)
+{
+ env->CP0_EntryLo1 = T0 & 0x3FFFFFFF;
+ RETURN();
+}
+
+void op_mtc0_context (void)
+{
+ env->CP0_Context = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
+ RETURN();
+}
+
+void op_mtc0_pagemask (void)
+{
+ env->CP0_PageMask = T0 & 0x01FFE000;
+ RETURN();
+}
+
+void op_mtc0_wired (void)
+{
+ env->CP0_Wired = T0 & 0x0000000F;
+ RETURN();
+}
+
+void op_mtc0_count (void)
+{
+ CALL_FROM_TB2(cpu_mips_store_count, env, T0);
+ RETURN();
+}
+
+void op_mtc0_entryhi (void)
+{
+ uint32_t old, val;
+
+ val = T0 & 0xFFFFE0FF;
+ old = env->CP0_EntryHi;
+ env->CP0_EntryHi = val;
+ /* If the ASID changes, flush qemu's TLB. */
+ if ((old & 0xFF) != (val & 0xFF))
+ CALL_FROM_TB2(cpu_mips_tlb_flush, env, 1);
+ RETURN();
+}
+
+void op_mtc0_compare (void)
+{
+ CALL_FROM_TB2(cpu_mips_store_compare, env, T0);
+ RETURN();
+}
+
+void op_mtc0_status (void)
+{
+ uint32_t val, old, mask;
+
+ val = T0 & 0xFA78FF01;
+ old = env->CP0_Status;
+ if (T0 & (1 << CP0St_UM))
+ env->hflags |= MIPS_HFLAG_UM;
+ else
+ env->hflags &= ~MIPS_HFLAG_UM;
+ if (T0 & (1 << CP0St_ERL))
+ env->hflags |= MIPS_HFLAG_ERL;
+ else
+ env->hflags &= ~MIPS_HFLAG_ERL;
+ if (T0 & (1 << CP0St_EXL))
+ env->hflags |= MIPS_HFLAG_EXL;
+ else
+ env->hflags &= ~MIPS_HFLAG_EXL;
+ env->CP0_Status = val;
+ /* If we unmasked an asserted IRQ, raise it */
+ mask = 0x0000FF00;
+ if (loglevel & CPU_LOG_TB_IN_ASM)
+ CALL_FROM_TB2(do_mtc0_status_debug, old, val);
+ if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
+ !(env->hflags & MIPS_HFLAG_EXL) &&
+ !(env->hflags & MIPS_HFLAG_ERL) &&
+ !(env->hflags & MIPS_HFLAG_DM) &&
+ (env->CP0_Status & env->CP0_Cause & mask)) {
+ env->interrupt_request |= CPU_INTERRUPT_HARD;
+ if (logfile)
+ CALL_FROM_TB0(do_mtc0_status_irqraise_debug);
+ } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
+ env->interrupt_request &= ~CPU_INTERRUPT_HARD;
+ }
+ RETURN();
+}
+
+void op_mtc0_cause (void)
+{
+ uint32_t val, old;
+
+ val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
+ old = env->CP0_Cause;
+ env->CP0_Cause = val;
+#if 0
+ {
+ int i, mask;
+
+ /* Check if we ever asserted a software IRQ */
+ for (i = 0; i < 2; i++) {
+ mask = 0x100 << i;
+ if ((val & mask) & !(old & mask))
+ CALL_FROM_TB1(mips_set_irq, i);
+ }
+ }
+#endif
+ RETURN();
+}
+
+void op_mtc0_epc (void)
+{
+ env->CP0_EPC = T0;
+ RETURN();
+}
+
+void op_mtc0_config0 (void)
+{
+#if defined(MIPS_USES_R4K_TLB)
+ env->CP0_Config0 = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
+#else
+ env->CP0_Config0 = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
+#endif
+ RETURN();
+}
+
+void op_mtc0_watchlo (void)
+{
+ env->CP0_WatchLo = T0;
+ RETURN();
+}
+
+void op_mtc0_watchhi (void)
+{
+ env->CP0_WatchHi = T0 & 0x40FF0FF8;
+ RETURN();
+}
+
+void op_mtc0_debug (void)
+{
+ env->CP0_Debug = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
+ if (T0 & (1 << CP0DB_DM))
+ env->hflags |= MIPS_HFLAG_DM;
+ else
+ env->hflags &= ~MIPS_HFLAG_DM;
+ RETURN();
+}
+
+void op_mtc0_depc (void)
+{
+ env->CP0_DEPC = T0;
+ RETURN();
+}
+
+void op_mtc0_taglo (void)
+{
+ env->CP0_TagLo = T0 & 0xFFFFFCF6;
+ RETURN();
+}
+
+void op_mtc0_errorepc (void)
+{
+ env->CP0_ErrorEPC = T0;
+ RETURN();
+}
+
+void op_mtc0_desave (void)
+{
+ env->CP0_DESAVE = T0;
RETURN();
}
diff --git a/target-mips/op_helper.c b/target-mips/op_helper.c
index d3959f3801..11e12c0d84 100644
--- a/target-mips/op_helper.c
+++ b/target-mips/op_helper.c
@@ -141,9 +141,24 @@ void do_mfc0_count (void)
cpu_abort(env, "mfc0 count\n");
}
-void do_mtc0 (int reg, int sel)
+void cpu_mips_store_count(CPUState *env, uint32_t value)
{
- cpu_abort(env, "mtc0 reg=%d sel=%d\n", reg, sel);
+ cpu_abort(env, "mtc0 count\n");
+}
+
+void cpu_mips_store_compare(CPUState *env, uint32_t value)
+{
+ cpu_abort(env, "mtc0 compare\n");
+}
+
+void do_mtc0_status_debug(uint32_t old, uint32_t val)
+{
+ cpu_abort(env, "mtc0 status\n");
+}
+
+void do_mtc0_status_irqraise_debug(void)
+{
+ cpu_abort(env, "mtc0 status\n");
}
void do_tlbwi (void)
@@ -166,6 +181,11 @@ void do_tlbr (void)
cpu_abort(env, "tlbr\n");
}
+void cpu_mips_tlb_flush (CPUState *env, int flush_global)
+{
+ cpu_abort(env, "mips_tlb_flush\n");
+}
+
#else
/* CP0 helpers */
@@ -179,222 +199,17 @@ void do_mfc0_count (void)
T0 = cpu_mips_get_count(env);
}
-void do_mtc0 (int reg, int sel)
+void do_mtc0_status_debug(uint32_t old, uint32_t val)
{
- const unsigned char *rn;
- uint32_t val, old, mask;
+ const uint32_t mask = 0x0000FF00;
+ fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
+ old, val, env->CP0_Cause, old & mask, val & mask,
+ env->CP0_Cause & mask);
+}
- if (sel != 0 && reg != 16 && reg != 28) {
- val = -1;
- old = -1;
- rn = "invalid";
- goto print;
- }
- switch (reg) {
- case 0:
- val = (env->CP0_index & 0x80000000) | (T0 & 0x0000000F);
- old = env->CP0_index;
- env->CP0_index = val;
- rn = "Index";
- break;
- case 2:
- val = T0 & 0x3FFFFFFF;
- old = env->CP0_EntryLo0;
- env->CP0_EntryLo0 = val;
- rn = "EntryLo0";
- break;
- case 3:
- val = T0 & 0x3FFFFFFF;
- old = env->CP0_EntryLo1;
- env->CP0_EntryLo1 = val;
- rn = "EntryLo1";
- break;
- case 4:
- val = (env->CP0_Context & 0xFF800000) | (T0 & 0x007FFFF0);
- old = env->CP0_Context;
- env->CP0_Context = val;
- rn = "Context";
- break;
- case 5:
- val = T0 & 0x01FFE000;
- old = env->CP0_PageMask;
- env->CP0_PageMask = val;
- rn = "PageMask";
- break;
- case 6:
- val = T0 & 0x0000000F;
- old = env->CP0_Wired;
- env->CP0_Wired = val;
- rn = "Wired";
- break;
- case 9:
- val = T0;
- old = cpu_mips_get_count(env);
- cpu_mips_store_count(env, val);
- rn = "Count";
- break;
- case 10:
- val = T0 & 0xFFFFE0FF;
- old = env->CP0_EntryHi;
- env->CP0_EntryHi = val;
- /* If the ASID changes, flush qemu's TLB. */
- if ((old & 0xFF) != (val & 0xFF))
- cpu_mips_tlb_flush (env, 1);
- rn = "EntryHi";
- break;
- case 11:
- val = T0;
- old = env->CP0_Compare;
- cpu_mips_store_compare(env, val);
- rn = "Compare";
- break;
- case 12:
- val = T0 & 0xFA78FF01;
- if (T0 & (1 << CP0St_UM))
- env->hflags |= MIPS_HFLAG_UM;
- else
- env->hflags &= ~MIPS_HFLAG_UM;
- if (T0 & (1 << CP0St_ERL))
- env->hflags |= MIPS_HFLAG_ERL;
- else
- env->hflags &= ~MIPS_HFLAG_ERL;
- if (T0 & (1 << CP0St_EXL))
- env->hflags |= MIPS_HFLAG_EXL;
- else
- env->hflags &= ~MIPS_HFLAG_EXL;
- old = env->CP0_Status;
- env->CP0_Status = val;
- /* If we unmasked an asserted IRQ, raise it */
- mask = 0x0000FF00;
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "Status %08x => %08x Cause %08x (%08x %08x %08x)\n",
- old, val, env->CP0_Cause, old & mask, val & mask,
- env->CP0_Cause & mask);
- }
- if ((val & (1 << CP0St_IE)) && !(old & (1 << CP0St_IE)) &&
- !(env->hflags & MIPS_HFLAG_EXL) &&
- !(env->hflags & MIPS_HFLAG_ERL) &&
- !(env->hflags & MIPS_HFLAG_DM) &&
- (env->CP0_Status & env->CP0_Cause & mask)) {
- if (logfile)
- fprintf(logfile, "Raise pending IRQs\n");
- env->interrupt_request |= CPU_INTERRUPT_HARD;
- } else if (!(val & (1 << CP0St_IE)) && (old & (1 << CP0St_IE))) {
- env->interrupt_request &= ~CPU_INTERRUPT_HARD;
- }
- rn = "Status";
- break;
- case 13:
- val = (env->CP0_Cause & 0xB000F87C) | (T0 & 0x000C00300);
- old = env->CP0_Cause;
- env->CP0_Cause = val;
-#if 0
- {
- int i;
- /* Check if we ever asserted a software IRQ */
- for (i = 0; i < 2; i++) {
- mask = 0x100 << i;
- if ((val & mask) & !(old & mask))
- mips_set_irq(i);
- }
- }
-#endif
- rn = "Cause";
- break;
- case 14:
- val = T0;
- old = env->CP0_EPC;
- env->CP0_EPC = val;
- rn = "EPC";
- break;
- case 16:
- switch (sel) {
- case 0:
-#if defined(MIPS_USES_R4K_TLB)
- val = (env->CP0_Config0 & 0x8017FF80) | (T0 & 0x7E000001);
-#else
- val = (env->CP0_Config0 & 0xFE17FF80) | (T0 & 0x00000001);
-#endif
- old = env->CP0_Config0;
- env->CP0_Config0 = val;
- rn = "Config0";
- break;
- default:
- val = -1;
- old = -1;
- rn = "bad config selector";
- break;
- }
- break;
- case 18:
- val = T0;
- old = env->CP0_WatchLo;
- env->CP0_WatchLo = val;
- rn = "WatchLo";
- break;
- case 19:
- val = T0 & 0x40FF0FF8;
- old = env->CP0_WatchHi;
- env->CP0_WatchHi = val;
- rn = "WatchHi";
- break;
- case 23:
- val = (env->CP0_Debug & 0x8C03FC1F) | (T0 & 0x13300120);
- if (T0 & (1 << CP0DB_DM))
- env->hflags |= MIPS_HFLAG_DM;
- else
- env->hflags &= ~MIPS_HFLAG_DM;
- old = env->CP0_Debug;
- env->CP0_Debug = val;
- rn = "Debug";
- break;
- case 24:
- val = T0;
- old = env->CP0_DEPC;
- env->CP0_DEPC = val;
- rn = "DEPC";
- break;
- case 28:
- switch (sel) {
- case 0:
- val = T0 & 0xFFFFFCF6;
- old = env->CP0_TagLo;
- env->CP0_TagLo = val;
- rn = "TagLo";
- break;
- default:
- val = -1;
- old = -1;
- rn = "invalid sel";
- break;
- }
- break;
- case 30:
- val = T0;
- old = env->CP0_ErrorEPC;
- env->CP0_ErrorEPC = val;
- rn = "EPC";
- break;
- case 31:
- val = T0;
- old = env->CP0_DESAVE;
- env->CP0_DESAVE = val;
- rn = "DESAVE";
- break;
- default:
- val = -1;
- old = -1;
- rn = "unknown";
- break;
- }
- print:
-#if defined MIPS_DEBUG_DISAS
- if (loglevel & CPU_LOG_TB_IN_ASM) {
- fprintf(logfile, "%08x mtc0 %s %08x => %08x (%d %d %08x)\n",
- env->PC, rn, T0, val, reg, sel, old);
- }
-#endif
- return;
+void do_mtc0_status_irqraise_debug(void)
+{
+ fprintf(logfile, "Raise pending IRQs\n");
}
#ifdef MIPS_USES_FPU
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e1c8bd4c70..6880667109 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1371,6 +1371,7 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
rn = "EntryLo0";
break;
case 3:
+ /* also CONF */
gen_op_mfc0_entrylo1();
rn = "EntryLo1";
break;
@@ -1386,6 +1387,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
gen_op_mfc0_wired();
rn = "Wired";
break;
+ case 7:
+// gen_op_mfc0_info();
+ rn = "Info";
+ break;
case 8:
gen_op_mfc0_badvaddr();
rn = "BadVaddr";
@@ -1445,6 +1450,19 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
gen_op_mfc0_watchhi();
rn = "WatchHi";
break;
+ case 20:
+ /* 64 bit only */
+// gen_op_mfc0_xcontext();
+ rn = "XContext";
+ break;
+ case 21:
+// gen_op_mfc0_framemask();
+ rn = "Framemask";
+ break;
+ case 22:
+// gen_op_mfc0_diagnostic();
+ rn = "'Diagnostic";
+ break;
case 23:
gen_op_mfc0_debug();
rn = "Debug";
@@ -1453,6 +1471,18 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
gen_op_mfc0_depc();
rn = "DEPC";
break;
+ case 25:
+// gen_op_mfc0_performance();
+ rn = "Performance";
+ break;
+ case 26:
+// gen_op_mfc0_ecc();
+ rn = "ECC";
+ break;
+ case 27:
+// gen_op_mfc0_cacheerr();
+ rn = "CacheErr";
+ break;
case 28:
switch (sel) {
case 0:
@@ -1468,6 +1498,10 @@ static void gen_mfc0 (DisasContext *ctx, int reg, int sel)
goto die;
}
break;
+ case 29:
+// gen_op_mfc0_taghi();
+ rn = "TagHi";
+ break;
case 30:
gen_op_mfc0_errorepc();
rn = "ErrorEPC";
@@ -1498,6 +1532,183 @@ die:
generate_exception(ctx, EXCP_RI);
}
+static void gen_mtc0 (DisasContext *ctx, int reg, int sel)
+{
+ const unsigned char *rn;
+ uint32_t val, old;
+
+ if (sel != 0 && reg != 16 && reg != 28) {
+ val = -1;
+ old = -1;
+ rn = "invalid";
+ goto die;
+ }
+ switch (reg) {
+ case 0:
+ gen_op_mtc0_index();
+ rn = "Index";
+ break;
+ case 1:
+// ignore or except?
+ rn = "Random";
+ break;
+ case 2:
+ gen_op_mtc0_entrylo0();
+ rn = "EntryLo0";
+ break;
+ case 3:
+ gen_op_mtc0_entrylo1();
+ rn = "EntryLo1";
+ break;
+ case 4:
+ gen_op_mtc0_context();
+ rn = "Context";
+ break;
+ case 5:
+ gen_op_mtc0_pagemask();
+ rn = "PageMask";
+ break;
+ case 6:
+ gen_op_mtc0_wired();
+ rn = "Wired";
+ break;
+ case 7:
+// ignore or except?
+ rn = "Info";
+ break;
+ case 8:
+// ignore or except?
+ rn = "BadVaddr";
+ break;
+ case 9:
+ gen_op_mtc0_count();
+ rn = "Count";
+ break;
+ case 10:
+ gen_op_mtc0_entryhi();
+ rn = "EntryHi";
+ break;
+ case 11:
+ gen_op_mtc0_compare();
+ rn = "Compare";
+ break;
+ case 12:
+ gen_op_mtc0_status();
+ rn = "Status";
+ break;
+ case 13:
+ gen_op_mtc0_cause();
+ rn = "Cause";
+ break;
+ case 14:
+ gen_op_mtc0_epc();
+ rn = "EPC";
+ break;
+ case 15:
+// ignore or except?
+ rn = "PRid";
+ break;
+ case 16:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_config0();
+ rn = "Config0";
+ break;
+ default:
+ rn = "Invalid config selector";
+ goto die;
+ }
+ break;
+ case 17:
+// ignore or except?
+ rn = "LLaddr";
+ break;
+ case 18:
+ gen_op_mtc0_watchlo();
+ rn = "WatchLo";
+ break;
+ case 19:
+ gen_op_mtc0_watchhi();
+ rn = "WatchHi";
+ break;
+ case 20:
+ /* 64 bit only */
+// gen_op_mtc0_xcontext();
+ rn = "XContext";
+ break;
+ case 21:
+// gen_op_mtc0_framemask();
+ rn = "Framemask";
+ break;
+ case 22:
+// ignore or except?
+ rn = "Diagnostic";
+ break;
+ case 23:
+ gen_op_mtc0_debug();
+ rn = "Debug";
+ break;
+ case 24:
+ gen_op_mtc0_depc();
+ rn = "DEPC";
+ break;
+ case 25:
+// ignore or except?
+ rn = "Performance";
+ break;
+ case 26:
+// ignore or except?
+ rn = "ECC";
+ break;
+ case 27:
+// ignore or except?
+ rn = "CacheErr";
+ break;
+ case 28:
+ switch (sel) {
+ case 0:
+ gen_op_mtc0_taglo();
+ rn = "TagLo";
+ break;
+ default:
+ rn = "invalid sel";
+ goto die;
+ }
+ break;
+ case 29:
+// gen_op_mtc0_taghi();
+ rn = "TagHi";
+ break;
+ case 30:
+ gen_op_mtc0_errorepc();
+ rn = "ErrorEPC";
+ break;
+ case 31:
+ gen_op_mtc0_desave();
+ rn = "DESAVE";
+ break;
+ default:
+ rn = "unknown";
+ goto die;
+ }
+#if defined MIPS_DEBUG_DISAS
+ if (loglevel & CPU_LOG_TB_IN_ASM) {
+ fprintf(logfile, "%08x mtc0 %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 mtc0 %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";
@@ -1529,7 +1740,7 @@ static void gen_cp0 (DisasContext *ctx, uint16_t opc, int rt, int rd)
save_cpu_state(ctx, 1);
ctx->pc -= 4;
GEN_LOAD_REG_TN(T0, rt);
- gen_op_mtc0(rd, ctx->opcode & 0x7);
+ gen_mtc0(ctx, rd, ctx->opcode & 0x7);
/* Stop translation as we may have switched the execution mode */
ctx->bstate = BS_STOP;
opn = "mtc0";