mirror of https://github.com/xemu-project/xemu.git
target-mips: split out delay slot handling
Move delay slot handling to common code whose invocation can be controlled from gen_intermediate_code_internal. Signed-off-by: Nathan Froyd <froydnj@codesourcery.com> Signed-off-by: Aurelien Jarno <aurelien@aurel32.net>
This commit is contained in:
parent
662d748516
commit
c960206137
|
@ -7532,6 +7532,56 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
|
||||||
fregnames[fs], fregnames[ft]);
|
fregnames[fs], fregnames[ft]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void handle_delay_slot (CPUState *env, DisasContext *ctx,
|
||||||
|
int insn_bytes)
|
||||||
|
{
|
||||||
|
if (ctx->hflags & MIPS_HFLAG_BMASK) {
|
||||||
|
int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
|
||||||
|
/* Branches completion */
|
||||||
|
ctx->hflags &= ~MIPS_HFLAG_BMASK;
|
||||||
|
ctx->bstate = BS_BRANCH;
|
||||||
|
save_cpu_state(ctx, 0);
|
||||||
|
/* FIXME: Need to clear can_do_io. */
|
||||||
|
switch (hflags) {
|
||||||
|
case MIPS_HFLAG_B:
|
||||||
|
/* unconditional branch */
|
||||||
|
MIPS_DEBUG("unconditional branch");
|
||||||
|
gen_goto_tb(ctx, 0, ctx->btarget);
|
||||||
|
break;
|
||||||
|
case MIPS_HFLAG_BL:
|
||||||
|
/* blikely taken case */
|
||||||
|
MIPS_DEBUG("blikely branch taken");
|
||||||
|
gen_goto_tb(ctx, 0, ctx->btarget);
|
||||||
|
break;
|
||||||
|
case MIPS_HFLAG_BC:
|
||||||
|
/* Conditional branch */
|
||||||
|
MIPS_DEBUG("conditional branch");
|
||||||
|
{
|
||||||
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
|
tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
|
||||||
|
gen_goto_tb(ctx, 1, ctx->pc + insn_bytes);
|
||||||
|
gen_set_label(l1);
|
||||||
|
gen_goto_tb(ctx, 0, ctx->btarget);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case MIPS_HFLAG_BR:
|
||||||
|
/* unconditional branch to register */
|
||||||
|
MIPS_DEBUG("branch to register");
|
||||||
|
tcg_gen_mov_tl(cpu_PC, btarget);
|
||||||
|
if (ctx->singlestep_enabled) {
|
||||||
|
save_cpu_state(ctx, 0);
|
||||||
|
gen_helper_0i(raise_exception, EXCP_DEBUG);
|
||||||
|
}
|
||||||
|
tcg_gen_exit_tb(0);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
MIPS_DEBUG("unknown branch");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* ISA extensions (ASEs) */
|
/* ISA extensions (ASEs) */
|
||||||
/* MIPS16 extension to MIPS32 */
|
/* MIPS16 extension to MIPS32 */
|
||||||
/* SmartMIPS extension to MIPS32 */
|
/* SmartMIPS extension to MIPS32 */
|
||||||
|
@ -7542,7 +7592,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static void decode_opc (CPUState *env, DisasContext *ctx)
|
static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
|
||||||
{
|
{
|
||||||
int32_t offset;
|
int32_t offset;
|
||||||
int rs, rt, rd, sa;
|
int rs, rt, rd, sa;
|
||||||
|
@ -7557,7 +7607,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle blikely not taken case */
|
/* Handle blikely not taken case */
|
||||||
if ((ctx->hflags & MIPS_HFLAG_BMASK) == MIPS_HFLAG_BL) {
|
if ((ctx->hflags & MIPS_HFLAG_BMASK_BASE) == MIPS_HFLAG_BL) {
|
||||||
int l1 = gen_new_label();
|
int l1 = gen_new_label();
|
||||||
|
|
||||||
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
|
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
|
||||||
|
@ -7648,7 +7698,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
break;
|
break;
|
||||||
case OPC_JR ... OPC_JALR:
|
case OPC_JR ... OPC_JALR:
|
||||||
gen_compute_branch(ctx, op1, 4, rs, rd, sa);
|
gen_compute_branch(ctx, op1, 4, rs, rd, sa);
|
||||||
return;
|
*is_branch = 1;
|
||||||
|
break;
|
||||||
case OPC_TGE ... OPC_TEQ: /* Traps */
|
case OPC_TGE ... OPC_TEQ: /* Traps */
|
||||||
case OPC_TNE:
|
case OPC_TNE:
|
||||||
gen_trap(ctx, op1, rs, rt, -1);
|
gen_trap(ctx, op1, rs, rt, -1);
|
||||||
|
@ -7937,7 +7988,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
|
case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */
|
||||||
case OPC_BLTZAL ... OPC_BGEZALL:
|
case OPC_BLTZAL ... OPC_BGEZALL:
|
||||||
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
|
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
|
||||||
return;
|
*is_branch = 1;
|
||||||
|
break;
|
||||||
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
|
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
|
||||||
case OPC_TNEI:
|
case OPC_TNEI:
|
||||||
gen_trap(ctx, op1, rs, -1, imm);
|
gen_trap(ctx, op1, rs, -1, imm);
|
||||||
|
@ -8056,11 +8108,13 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
case OPC_J ... OPC_JAL: /* Jump */
|
case OPC_J ... OPC_JAL: /* Jump */
|
||||||
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
|
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
|
||||||
gen_compute_branch(ctx, op, 4, rs, rt, offset);
|
gen_compute_branch(ctx, op, 4, rs, rt, offset);
|
||||||
return;
|
*is_branch = 1;
|
||||||
|
break;
|
||||||
case OPC_BEQ ... OPC_BGTZ: /* Branch */
|
case OPC_BEQ ... OPC_BGTZ: /* Branch */
|
||||||
case OPC_BEQL ... OPC_BGTZL:
|
case OPC_BEQL ... OPC_BGTZL:
|
||||||
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
|
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
|
||||||
return;
|
*is_branch = 1;
|
||||||
|
break;
|
||||||
case OPC_LB ... OPC_LWR: /* Load and stores */
|
case OPC_LB ... OPC_LWR: /* Load and stores */
|
||||||
case OPC_SB ... OPC_SW:
|
case OPC_SB ... OPC_SW:
|
||||||
case OPC_SWR:
|
case OPC_SWR:
|
||||||
|
@ -8121,7 +8175,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
case OPC_BC1:
|
case OPC_BC1:
|
||||||
gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
|
gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
|
||||||
(rt >> 2) & 0x7, imm << 2);
|
(rt >> 2) & 0x7, imm << 2);
|
||||||
return;
|
*is_branch = 1;
|
||||||
|
break;
|
||||||
case OPC_S_FMT:
|
case OPC_S_FMT:
|
||||||
case OPC_D_FMT:
|
case OPC_D_FMT:
|
||||||
case OPC_W_FMT:
|
case OPC_W_FMT:
|
||||||
|
@ -8226,51 +8281,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
|
||||||
generate_exception(ctx, EXCP_RI);
|
generate_exception(ctx, EXCP_RI);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (ctx->hflags & MIPS_HFLAG_BMASK) {
|
|
||||||
int hflags = ctx->hflags & MIPS_HFLAG_BMASK;
|
|
||||||
/* Branches completion */
|
|
||||||
ctx->hflags &= ~MIPS_HFLAG_BMASK;
|
|
||||||
ctx->bstate = BS_BRANCH;
|
|
||||||
save_cpu_state(ctx, 0);
|
|
||||||
/* FIXME: Need to clear can_do_io. */
|
|
||||||
switch (hflags) {
|
|
||||||
case MIPS_HFLAG_B:
|
|
||||||
/* unconditional branch */
|
|
||||||
MIPS_DEBUG("unconditional branch");
|
|
||||||
gen_goto_tb(ctx, 0, ctx->btarget);
|
|
||||||
break;
|
|
||||||
case MIPS_HFLAG_BL:
|
|
||||||
/* blikely taken case */
|
|
||||||
MIPS_DEBUG("blikely branch taken");
|
|
||||||
gen_goto_tb(ctx, 0, ctx->btarget);
|
|
||||||
break;
|
|
||||||
case MIPS_HFLAG_BC:
|
|
||||||
/* Conditional branch */
|
|
||||||
MIPS_DEBUG("conditional branch");
|
|
||||||
{
|
|
||||||
int l1 = gen_new_label();
|
|
||||||
|
|
||||||
tcg_gen_brcondi_tl(TCG_COND_NE, bcond, 0, l1);
|
|
||||||
gen_goto_tb(ctx, 1, ctx->pc + 4);
|
|
||||||
gen_set_label(l1);
|
|
||||||
gen_goto_tb(ctx, 0, ctx->btarget);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case MIPS_HFLAG_BR:
|
|
||||||
/* unconditional branch to register */
|
|
||||||
MIPS_DEBUG("branch to register");
|
|
||||||
tcg_gen_mov_tl(cpu_PC, btarget);
|
|
||||||
if (ctx->singlestep_enabled) {
|
|
||||||
save_cpu_state(ctx, 0);
|
|
||||||
gen_helper_0i(raise_exception, EXCP_DEBUG);
|
|
||||||
}
|
|
||||||
tcg_gen_exit_tb(0);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
MIPS_DEBUG("unknown branch");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
|
@ -8284,6 +8294,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
|
||||||
int j, lj = -1;
|
int j, lj = -1;
|
||||||
int num_insns;
|
int num_insns;
|
||||||
int max_insns;
|
int max_insns;
|
||||||
|
int insn_bytes;
|
||||||
|
int is_branch;
|
||||||
|
|
||||||
if (search_pc)
|
if (search_pc)
|
||||||
qemu_log("search pc %d\n", search_pc);
|
qemu_log("search pc %d\n", search_pc);
|
||||||
|
@ -8343,9 +8355,21 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
|
||||||
}
|
}
|
||||||
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
|
if (num_insns + 1 == max_insns && (tb->cflags & CF_LAST_IO))
|
||||||
gen_io_start();
|
gen_io_start();
|
||||||
ctx.opcode = ldl_code(ctx.pc);
|
|
||||||
decode_opc(env, &ctx);
|
is_branch = 0;
|
||||||
ctx.pc += 4;
|
if (ctx.isa_mode == 0) {
|
||||||
|
ctx.opcode = ldl_code(ctx.pc);
|
||||||
|
insn_bytes = 4;
|
||||||
|
decode_opc(env, &ctx, &is_branch);
|
||||||
|
} else {
|
||||||
|
generate_exception(&ctx, EXCP_RI);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (!is_branch) {
|
||||||
|
handle_delay_slot(env, &ctx, insn_bytes);
|
||||||
|
}
|
||||||
|
ctx.pc += insn_bytes;
|
||||||
|
|
||||||
num_insns++;
|
num_insns++;
|
||||||
|
|
||||||
/* Execute a branch and its delay slot as a single instruction.
|
/* Execute a branch and its delay slot as a single instruction.
|
||||||
|
|
Loading…
Reference in New Issue