Loading target-mips/exec.h +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading target-mips/op.c +178 −2 Original line number Diff line number Diff line Loading @@ -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(); } Loading target-mips/op_helper.c +31 −216 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 */ Loading @@ -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) 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 void do_mtc0_status_irqraise_debug(void) { 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; fprintf(logfile, "Raise pending IRQs\n"); } #ifdef MIPS_USES_FPU Loading target-mips/translate.c +212 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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"; Loading @@ -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: Loading @@ -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"; Loading Loading @@ -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"; Loading Loading @@ -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 Loading
target-mips/exec.h +2 −1 Original line number Diff line number Diff line Loading @@ -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); Loading
target-mips/op.c +178 −2 Original line number Diff line number Diff line Loading @@ -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(); } Loading
target-mips/op_helper.c +31 −216 Original line number Diff line number Diff line Loading @@ -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) Loading @@ -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 */ Loading @@ -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) 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 void do_mtc0_status_irqraise_debug(void) { 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; fprintf(logfile, "Raise pending IRQs\n"); } #ifdef MIPS_USES_FPU Loading
target-mips/translate.c +212 −1 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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"; Loading Loading @@ -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"; Loading @@ -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: Loading @@ -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"; Loading Loading @@ -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"; Loading Loading @@ -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