#include "target/mips/trace.h"
#include "trace-tcg.h"
+#include "exec/translator.h"
#include "exec/log.h"
#define MIPS_DEBUG_DISAS 0
int mem_idx;
TCGMemOp default_tcg_memop_mask;
uint32_t hflags, saved_hflags;
- int bstate;
+ DisasJumpType is_jmp;
target_ulong btarget;
bool ulri;
int kscrexist;
bool abs2008;
} DisasContext;
-enum {
- BS_NONE = 0, /* We go out of the TB without reaching a branch or an
- * exception condition */
- BS_STOP = 1, /* We want to stop translation for any reason */
- BS_BRANCH = 2, /* We reached a branch condition */
- BS_EXCP = 3, /* We reached an exception condition */
-};
+#define DISAS_STOP DISAS_TARGET_0
+#define DISAS_EXIT DISAS_TARGET_1
static const char * const regnames[] = {
"r0", "at", "v0", "v1", "a0", "a1", "a2", "a3",
gen_helper_raise_exception_err(cpu_env, texcp, terr);
tcg_temp_free_i32(terr);
tcg_temp_free_i32(texcp);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_NORETURN;
}
static inline void generate_exception(DisasContext *ctx, int excp)
gen_io_end();
}
/* Break the TB to be able to take timer interrupts immediately
- after reading count. BS_STOP isn't sufficient, we need to ensure
- we break completely out of translated code. */
+ after reading count. DISAS_STOP isn't sufficient, we need to
+ ensure we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Count";
break;
/* 6,7 are implementation dependent */
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_pagegrain(cpu_env, arg);
rn = "PageGrain";
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 2:
CP0_CHECK(ctx->sc);
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "HWREna";
break;
default:
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_status(cpu_env, arg);
- /* BS_STOP isn't good enough here, hflags may have changed. */
+ /* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "SRSMap";
break;
default:
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
- /* Stop translation as we may have triggered an interrupt. BS_STOP
- * isn't sufficient, we need to ensure we break out of translated
- * code to check for pending interrupts. */
+ /* Stop translation as we may have triggered an interrupt.
+ * DISAS_STOP isn't sufficient, we need to ensure we break out of
+ * translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Cause";
break;
default:
gen_helper_mtc0_config0(cpu_env, arg);
rn = "Config";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 1:
/* ignored, read only */
gen_helper_mtc0_config2(cpu_env, arg);
rn = "Config2";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 3:
gen_helper_mtc0_config3(cpu_env, arg);
rn = "Config3";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 4:
gen_helper_mtc0_config4(cpu_env, arg);
rn = "Config4";
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 5:
gen_helper_mtc0_config5(cpu_env, arg);
rn = "Config5";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
/* 6,7 are implementation dependent */
case 6:
switch (sel) {
case 0:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
- /* BS_STOP isn't good enough here, hflags may have changed. */
+ /* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Debug";
break;
case 1:
// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
rn = "TraceControl";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
rn = "TraceControl2";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
goto cp0_unimplemented;
case 3:
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
rn = "UserTraceData";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
goto cp0_unimplemented;
case 4:
// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "TraceBPC";
goto cp0_unimplemented;
default:
switch (sel) {
case 0:
gen_helper_mtc0_errctl(cpu_env, arg);
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "ErrCtl";
break;
default:
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) {
gen_io_end();
- /* BS_STOP isn't sufficient, we need to ensure we break out of
+ /* DISAS_STOP isn't sufficient, we need to ensure we break out of
* translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
}
return;
gen_io_end();
}
/* Break the TB to be able to take timer interrupts immediately
- after reading count. BS_STOP isn't sufficient, we need to ensure
- we break completely out of translated code. */
+ after reading count. DISAS_STOP isn't sufficient, we need to
+ ensure we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Count";
break;
/* 6,7 are implementation dependent */
case 0:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_hwrena(cpu_env, arg);
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "HWREna";
break;
default:
goto cp0_unimplemented;
}
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 10:
switch (sel) {
goto cp0_unimplemented;
}
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 12:
switch (sel) {
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_status(cpu_env, arg);
- /* BS_STOP isn't good enough here, hflags may have changed. */
+ /* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Status";
break;
case 1:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_intctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "IntCtl";
break;
case 2:
check_insn(ctx, ISA_MIPS32R2);
gen_helper_mtc0_srsctl(cpu_env, arg);
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "SRSCtl";
break;
case 3:
check_insn(ctx, ISA_MIPS32R2);
gen_mtc0_store32(arg, offsetof(CPUMIPSState, CP0_SRSMap));
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "SRSMap";
break;
default:
case 0:
save_cpu_state(ctx, 1);
gen_helper_mtc0_cause(cpu_env, arg);
- /* Stop translation as we may have triggered an intetrupt. BS_STOP
- * isn't sufficient, we need to ensure we break out of translated
- * code to check for pending interrupts. */
+ /* Stop translation as we may have triggered an interrupt.
+ * DISAS_STOP isn't sufficient, we need to ensure we break out of
+ * translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Cause";
break;
default:
gen_helper_mtc0_config0(cpu_env, arg);
rn = "Config";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 1:
/* ignored, read only */
gen_helper_mtc0_config2(cpu_env, arg);
rn = "Config2";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 3:
gen_helper_mtc0_config3(cpu_env, arg);
rn = "Config3";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case 4:
/* currently ignored */
gen_helper_mtc0_config5(cpu_env, arg);
rn = "Config5";
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
/* 6,7 are implementation dependent */
default:
switch (sel) {
case 0:
gen_helper_mtc0_debug(cpu_env, arg); /* EJTAG support */
- /* BS_STOP isn't good enough here, hflags may have changed. */
+ /* DISAS_STOP isn't good enough here, hflags may have changed. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
rn = "Debug";
break;
case 1:
// gen_helper_mtc0_tracecontrol(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "TraceControl";
goto cp0_unimplemented;
case 2:
// gen_helper_mtc0_tracecontrol2(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "TraceControl2";
goto cp0_unimplemented;
case 3:
// gen_helper_mtc0_usertracedata(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "UserTraceData";
goto cp0_unimplemented;
case 4:
// gen_helper_mtc0_tracebpc(cpu_env, arg); /* PDtrace support */
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "TraceBPC";
goto cp0_unimplemented;
default:
switch (sel) {
case 0:
gen_helper_mtc0_errctl(cpu_env, arg);
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
rn = "ErrCtl";
break;
default:
/* For simplicity assume that all writes can cause interrupts. */
if (tb_cflags(ctx->tb) & CF_USE_ICOUNT) {
gen_io_end();
- /* BS_STOP isn't sufficient, we need to ensure we break out of
+ /* DISAS_STOP isn't sufficient, we need to ensure we break out of
* translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
}
return;
tcg_temp_free_i32(fs_tmp);
}
/* Stop translation as we may have changed hflags */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
/* COP2: Not implemented. */
case 4:
check_insn(ctx, ISA_MIPS2);
gen_helper_eret(cpu_env);
}
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
}
break;
case OPC_DERET:
generate_exception_end(ctx, EXCP_RI);
} else {
gen_helper_deret(cpu_env);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
}
break;
case OPC_WAIT:
save_cpu_state(ctx, 1);
ctx->pc -= 4;
gen_helper_wait(cpu_env);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_NORETURN;
break;
default:
die:
tcg_temp_free_i32(fs_tmp);
}
/* Stop translation as we may have changed hflags */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
#if defined(TARGET_MIPS64)
case OPC_DMFC1:
}
gen_store_gpr(t0, rt);
/* Break the TB to be able to take timer interrupts immediately
- after reading count. BS_STOP isn't sufficient, we need to ensure
+ after reading count. DISAS_STOP isn't sufficient, we need to ensure
we break completely out of translated code. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
break;
case 3:
gen_helper_rdhwr_ccres(t0, cpu_env);
static inline void clear_branch_hflags(DisasContext *ctx)
{
ctx->hflags &= ~MIPS_HFLAG_BMASK;
- if (ctx->bstate == BS_NONE) {
+ if (ctx->is_jmp == DISAS_NEXT) {
save_cpu_state(ctx, 0);
} else {
/* it is not safe to save ctx->hflags as hflags may be changed
int proc_hflags = ctx->hflags & MIPS_HFLAG_BMASK;
/* Branches completion */
clear_branch_hflags(ctx);
- ctx->bstate = BS_BRANCH;
+ ctx->is_jmp = DISAS_NORETURN;
/* FIXME: Need to clear can_do_io. */
switch (proc_hflags & MIPS_HFLAG_BMASK_BASE) {
case MIPS_HFLAG_FBNSLOT:
gen_helper_di(t0, cpu_env);
gen_store_gpr(t0, rs);
/* Stop translation as we may have switched the execution mode */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
tcg_temp_free(t0);
}
break;
save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rs);
- /* BS_STOP isn't sufficient, we need to ensure we break out
+ /* DISAS_STOP isn't sufficient, we need to ensure we break out
of translated code to check for pending interrupts. */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
tcg_temp_free(t0);
}
break;
/* SYNCI */
/* Break the TB to be able to sync copied instructions
immediately */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
} else {
/* TNEI */
mips32_op = OPC_TNEI;
check_insn_opc_removed(ctx, ISA_MIPS32R6);
/* Break the TB to be able to sync copied instructions
immediately */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case BC2F:
case BC2T:
check_insn(ctx, ISA_MIPS32R2);
/* Break the TB to be able to sync copied instructions
immediately */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case OPC_BPOSGE32: /* MIPS DSP branch */
#if defined(TARGET_MIPS64)
gen_store_gpr(t0, rt);
/* Stop translation as we may have switched
the execution mode. */
- ctx->bstate = BS_STOP;
+ ctx->is_jmp = DISAS_STOP;
break;
case OPC_EI:
check_insn(ctx, ISA_MIPS32R2);
save_cpu_state(ctx, 1);
gen_helper_ei(t0, cpu_env);
gen_store_gpr(t0, rt);
- /* BS_STOP isn't sufficient, we need to ensure we break out
- of translated code to check for pending interrupts. */
+ /* DISAS_STOP isn't sufficient, we need to ensure we break
+ out of translated code to check for pending interrupts */
gen_save_pc(ctx->pc + 4);
- ctx->bstate = BS_EXCP;
+ ctx->is_jmp = DISAS_EXIT;
break;
default: /* Invalid */
MIPS_INVAL("mfmc0");
ctx.insn_flags = env->insn_flags;
ctx.CP0_Config1 = env->CP0_Config1;
ctx.tb = tb;
- ctx.bstate = BS_NONE;
+ ctx.is_jmp = DISAS_NEXT;
ctx.btarget = 0;
ctx.kscrexist = (env->CP0_Config4 >> CP0C4_KScrExist) & 0xff;
ctx.rxi = (env->CP0_Config3 >> CP0C3_RXI) & 1;
LOG_DISAS("\ntb %p idx %d hflags %04x\n", tb, ctx.mem_idx, ctx.hflags);
gen_tb_start(tb);
- while (ctx.bstate == BS_NONE) {
+ while (ctx.is_jmp == DISAS_NEXT) {
tcg_gen_insn_start(ctx.pc, ctx.hflags & MIPS_HFLAG_BMASK, ctx.btarget);
num_insns++;
if (unlikely(cpu_breakpoint_test(cs, ctx.pc, BP_ANY))) {
save_cpu_state(&ctx, 1);
- ctx.bstate = BS_BRANCH;
+ ctx.is_jmp = DISAS_NORETURN;
gen_helper_raise_exception_debug(cpu_env);
/* The address covered by the breakpoint must be included in
[tb->pc, tb->pc + tb->size) in order to for it to be
if (tb_cflags(tb) & CF_LAST_IO) {
gen_io_end();
}
- if (cs->singlestep_enabled && ctx.bstate != BS_BRANCH) {
- save_cpu_state(&ctx, ctx.bstate != BS_EXCP);
+ if (cs->singlestep_enabled && ctx.is_jmp != DISAS_NORETURN) {
+ save_cpu_state(&ctx, ctx.is_jmp != DISAS_EXIT);
gen_helper_raise_exception_debug(cpu_env);
} else {
- switch (ctx.bstate) {
- case BS_STOP:
+ switch (ctx.is_jmp) {
+ case DISAS_STOP:
gen_save_pc(ctx.pc);
tcg_gen_lookup_and_goto_ptr();
break;
- case BS_NONE:
+ case DISAS_NEXT:
save_cpu_state(&ctx, 0);
gen_goto_tb(&ctx, 0, ctx.pc);
break;
- case BS_EXCP:
+ case DISAS_EXIT:
tcg_gen_exit_tb(0);
break;
- case BS_BRANCH:
+ case DISAS_NORETURN:
default:
break;
}