[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
- [Qemu-devel] [PATCH 00/12] implement features required in MIPS64 Release 6, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 01/12] target-mips: add KScratch registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 02/12] target-mips: update cpu_save/cpu_load to support KScratch registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 03/12] target-mips: distinguish between data load and instruction fetch, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 04/12] target-mips: add RI and XI fields to TLB entry, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 05/12] target-mips: update PageGrain and m{t, f}c0 EntryLo{0, 1}, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 08/12] target-mips: add BadInstr and BadInstrP support,
Leon Alrae <=
- [Qemu-devel] [PATCH 07/12] target-mips: add TLBINV support, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 06/12] target-mips: add new Read-Inhibit and Execute-Inhibit exceptions, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 09/12] target-mips: save cpu state if instruction can cause an exception, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 10/12] target-mips: update cpu_save/cpu_load to support BadInstr registers, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 11/12] target-mips: enable features in MIPS32R5-generic core, Leon Alrae, 2014/06/19
- [Qemu-devel] [PATCH 12/12] target-mips: enable features in MIPS64R6-generic core, Leon Alrae, 2014/06/19