qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 08/12] target-mips: add BadInstr and BadInstrP suppo


From: Leon Alrae
Subject: [Qemu-devel] [PATCH 08/12] target-mips: add BadInstr and BadInstrP support
Date: Thu, 19 Jun 2014 15:45:39 +0100

BadInstr Register (CP0 Register 8, Select 1)
The BadInstr register is a read-only register that capture the most recent
instruction which caused an exception.

BadInstrP Register (CP0 Register 8, Select 2)
The BadInstrP register contains the prior branch instruction, when the
faulting instruction is in a branch delay slot.

The BadInstr and BadInstrP registers are provided to allow acceleration of
instruction emulation.

Signed-off-by: Leon Alrae <address@hidden>
---
 target-mips/cpu.h       |    6 +++
 target-mips/helper.c    |   23 +++++++++++
 target-mips/translate.c |  102 ++++++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 125 insertions(+), 6 deletions(-)

diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 14edf57..785a29b 100644
--- a/target-mips/cpu.h
+++ b/target-mips/cpu.h
@@ -177,6 +177,10 @@ struct TCState {
     target_ulong CP0_TCScheFBack;
     int32_t CP0_Debug_tcstatus;
     target_ulong CP0_UserLocal;
+    uint32_t last_instr;
+    uint32_t CP0_BadInstr;
+    uint32_t last_branch;
+    uint32_t CP0_BadInstrP;
 };
 
 typedef struct CPUMIPSState CPUMIPSState;
@@ -383,6 +387,8 @@ struct CPUMIPSState {
 #define CP0C2_SA   0
     int32_t CP0_Config3;
 #define CP0C3_M    31
+#define CP0C3_BP 27
+#define CP0C3_BI 26
 #define CP0C3_ISA_ON_EXC 16
 #define CP0C3_ULRI 13
 #define CP0C3_RXI  12
diff --git a/target-mips/helper.c b/target-mips/helper.c
index ab9217f..1a3a6af 100644
--- a/target-mips/helper.c
+++ b/target-mips/helper.c
@@ -439,6 +439,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
 #if !defined(CONFIG_USER_ONLY)
     MIPSCPU *cpu = MIPS_CPU(cs);
     CPUMIPSState *env = &cpu->env;
+    int update_badinstr = 0;
     target_ulong offset;
     int cause = -1;
     const char *name;
@@ -547,9 +548,11 @@ void mips_cpu_do_interrupt(CPUState *cs)
         goto set_EPC;
     case EXCP_LTLBL:
         cause = 1;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_TLBL:
         cause = 2;
+        update_badinstr = 1;
         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
 #if defined(TARGET_MIPS64)
             int R = env->CP0_BadVAddr >> 62;
@@ -567,6 +570,7 @@ void mips_cpu_do_interrupt(CPUState *cs)
         goto set_EPC;
     case EXCP_TLBS:
         cause = 3;
+        update_badinstr = 1;
         if (env->error_code == 1 && !(env->CP0_Status & (1 << CP0St_EXL))) {
 #if defined(TARGET_MIPS64)
             int R = env->CP0_BadVAddr >> 62;
@@ -584,9 +588,11 @@ void mips_cpu_do_interrupt(CPUState *cs)
         goto set_EPC;
     case EXCP_AdEL:
         cause = 4;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_AdES:
         cause = 5;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_IBE:
         cause = 6;
@@ -596,35 +602,44 @@ void mips_cpu_do_interrupt(CPUState *cs)
         goto set_EPC;
     case EXCP_SYSCALL:
         cause = 8;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_BREAK:
         cause = 9;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_RI:
         cause = 10;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_CpU:
         cause = 11;
+        update_badinstr = 1;
         env->CP0_Cause = (env->CP0_Cause & ~(0x3 << CP0Ca_CE)) |
                          (env->error_code << CP0Ca_CE);
         goto set_EPC;
     case EXCP_OVERFLOW:
         cause = 12;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_TRAP:
         cause = 13;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_FPE:
         cause = 15;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_C2E:
         cause = 18;
         goto set_EPC;
     case EXCP_TLBRI:
         cause = 19;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_TLBXI:
         cause = 20;
+        update_badinstr = 1;
         goto set_EPC;
     case EXCP_MDMX:
         cause = 22;
@@ -650,6 +665,14 @@ void mips_cpu_do_interrupt(CPUState *cs)
             offset = 0x20000100;
         }
  set_EPC:
+        if (env->CP0_Config3 & (1 << CP0C3_BI) && update_badinstr) {
+            env->active_tc.CP0_BadInstr = env->active_tc.last_instr;
+        }
+        if (env->CP0_Config3 & (1 << CP0C3_BP) && update_badinstr &&
+            env->hflags & MIPS_HFLAG_BMASK) {
+            env->active_tc.CP0_BadInstrP = env->active_tc.last_branch;
+        }
+
         if (!(env->CP0_Status & (1 << CP0St_EXL))) {
             env->CP0_EPC = exception_resume_pc(env);
             if (env->hflags & MIPS_HFLAG_BMASK) {
diff --git a/target-mips/translate.c b/target-mips/translate.c
index e511c75..b27d22e 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -1116,6 +1116,8 @@ static TCGv cpu_dspctrl, btarget, bcond;
 static TCGv_i32 hflags;
 static TCGv_i32 fpu_fcr0, fpu_fcr31;
 static TCGv_i64 fpu_f64[32];
+static TCGv_i32 last_instr;
+static TCGv_i32 last_branch;
 
 static uint32_t gen_opc_hflags[OPC_BUF_SIZE];
 static target_ulong gen_opc_btarget[OPC_BUF_SIZE];
@@ -1167,7 +1169,8 @@ static target_ulong gen_opc_btarget[OPC_BUF_SIZE];
 typedef struct DisasContext {
     struct TranslationBlock *tb;
     target_ulong pc, saved_pc;
-    uint32_t opcode;
+    uint32_t opcode, saved_opcode;
+    uint32_t opcode_branch, saved_opcode_branch;
     int singlestep_enabled;
     int insn_flags;
     /* Routine used to access memory */
@@ -1179,6 +1182,8 @@ typedef struct DisasContext {
     int32_t kscrexist;
     bool rxi;
     bool ie;
+    bool bi;
+    bool bp;
 } DisasContext;
 
 enum {
@@ -1391,6 +1396,15 @@ static inline void save_cpu_state (DisasContext *ctx, 
int do_save_pc)
         gen_save_pc(ctx->pc);
         ctx->saved_pc = ctx->pc;
     }
+    if (ctx->bi && ctx->opcode != ctx->saved_opcode) {
+        tcg_gen_movi_i32(last_instr, ctx->opcode);
+        ctx->saved_opcode = ctx->opcode;
+    }
+    if (ctx->bp && ctx->hflags & MIPS_HFLAG_BMASK &&
+        ctx->opcode_branch != ctx->saved_opcode_branch) {
+        tcg_gen_movi_i32(last_branch, ctx->opcode_branch);
+        ctx->saved_opcode_branch = ctx->opcode_branch;
+    }
     if (ctx->hflags != ctx->saved_hflags) {
         tcg_gen_movi_i32(hflags, ctx->hflags);
         ctx->saved_hflags = ctx->hflags;
@@ -4160,6 +4174,9 @@ static void gen_compute_branch (DisasContext *ctx, 
uint32_t opc,
 #endif
         generate_exception(ctx, EXCP_RI);
         goto out;
+    } else {
+        /* capture branch opcode prior to delay slot */
+        ctx->opcode_branch = ctx->opcode;
     }
 
     /* Load needed operands */
@@ -4868,9 +4885,19 @@ static void gen_mfc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
             tcg_gen_ext32s_tl(arg, arg);
             rn = "BadVAddr";
             break;
+        case 1:
+            gen_mfc0_load32(arg, offsetof(CPUMIPSState,
+                                          active_tc.CP0_BadInstr));
+            rn = "BadInstr";
+            break;
+        case 2:
+            gen_mfc0_load32(arg, offsetof(CPUMIPSState,
+                                          active_tc.CP0_BadInstrP));
+            rn = "BadInstrP";
+            break;
         default:
             goto die;
-       }
+        }
         break;
     case 9:
         switch (sel) {
@@ -5464,8 +5491,22 @@ static void gen_mtc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
         }
         break;
     case 8:
-        /* ignored */
-        rn = "BadVAddr";
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "BadVAddr";
+            break;
+        case 1:
+            /* ignored */
+            rn = "BadInstr";
+            break;
+        case 2:
+            /* ignored */
+            rn = "BadInstrP";
+            break;
+        default:
+            goto die;
+        }
         break;
     case 9:
         switch (sel) {
@@ -6090,6 +6131,16 @@ static void gen_dmfc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
             tcg_gen_ld_tl(arg, cpu_env, offsetof(CPUMIPSState, CP0_BadVAddr));
             rn = "BadVAddr";
             break;
+        case 1:
+            gen_mfc0_load32(arg, offsetof(CPUMIPSState,
+                                          active_tc.CP0_BadInstr));
+            rn = "BadInstr";
+            break;
+        case 2:
+            gen_mfc0_load32(arg, offsetof(CPUMIPSState,
+                                          active_tc.CP0_BadInstrP));
+            rn = "BadInstrP";
+            break;
         default:
             goto die;
         }
@@ -6671,8 +6722,22 @@ static void gen_dmtc0(DisasContext *ctx, TCGv arg, int 
reg, int sel)
         }
         break;
     case 8:
-        /* ignored */
-        rn = "BadVAddr";
+        switch (sel) {
+        case 0:
+            /* ignored */
+            rn = "BadVAddr";
+            break;
+        case 1:
+            /* ignored */
+            rn = "BadInstr";
+            break;
+        case 2:
+            /* ignored */
+            rn = "BadInstrP";
+            break;
+        default:
+            goto die;
+        }
         break;
     case 9:
         switch (sel) {
@@ -7633,6 +7698,11 @@ static void gen_compute_branch1(DisasContext *ctx, 
uint32_t op,
     const char *opn = "cp1 cond branch";
     TCGv_i32 t0 = tcg_temp_new_i32();
 
+    if (!(ctx->hflags & MIPS_HFLAG_BMASK)) {
+        /* capture branch opcode prior to delay slot */
+        ctx->opcode_branch = ctx->opcode;
+    }
+
     if (cc != 0)
         check_insn(ctx, ISA_MIPS4 | ISA_MIPS32);
 
@@ -7747,6 +7817,12 @@ static void gen_compute_branch1_r6(DisasContext *ctx, 
uint32_t op,
     const char *opn = "cp1 cond branch";
 
     TCGv_i64 t0 = tcg_temp_new_i64();
+
+    if (!(ctx->hflags & MIPS_HFLAG_BMASK)) {
+        /* capture branch opcode prior to delay slot */
+        ctx->opcode_branch = ctx->opcode;
+    }
+
     gen_load_fpr64(ctx, t0, ft);
     tcg_gen_andi_i64(t0, t0, 1);
 
@@ -17568,6 +17644,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, 
TranslationBlock *tb,
     ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff;
     ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1;
     ctx.ie = (env->CP0_Config4 >> CP0C4_IE) & 1;
+    ctx.bi = (env->CP0_Config3 >> CP0C3_BI) & 1;
+    ctx.bp = (env->CP0_Config3 >> CP0C3_BP) & 1;
+    ctx.opcode = 0;
+    ctx.saved_opcode = 0;
+    ctx.opcode_branch = 0;
+    ctx.saved_opcode_branch = 0;
     /* Restore delay slot state from the tb context.  */
     ctx.hflags = (uint32_t)tb->flags; /* FIXME: maybe use 64 bits here? */
     ctx.ulri = env->CP0_Config3 & (1 << CP0C3_ULRI);
@@ -17869,6 +17951,14 @@ void mips_tcg_init(void)
     fpu_fcr31 = tcg_global_mem_new_i32(TCG_AREG0,
                                        offsetof(CPUMIPSState, 
active_fpu.fcr31),
                                        "fcr31");
+    last_instr = tcg_global_mem_new_i32(TCG_AREG0,
+                                        offsetof(CPUMIPSState,
+                                                 active_tc.last_instr),
+                                        "last_instr");
+    last_branch = tcg_global_mem_new_i32(TCG_AREG0,
+                                         offsetof(CPUMIPSState,
+                                                  active_tc.last_branch),
+                                         "last_branch");
 
     inited = 1;
 }
-- 
1.7.5.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]