Dynamically translate MIPS mtc0 instructions.
git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@2223 c046a42c-6fe2-441c-8c8c-71466251a162
This commit is contained in:
parent
873eb01234
commit
8c0fdd856c
@ -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);
|
||||
|
180
target-mips/op.c
180
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();
|
||||
}
|
||||
|
||||
|
@ -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;
|
||||
|
||||
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) {
|
||||
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 ((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)
|
||||
}
|
||||
|
||||
void do_mtc0_status_irqraise_debug(void)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
#ifdef MIPS_USES_FPU
|
||||
|
@ -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";
|
||||
|
Loading…
Reference in New Issue
Block a user