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:
Nathan Froyd 2009-12-08 08:06:27 -08:00 committed by Aurelien Jarno
parent 662d748516
commit c960206137
1 changed files with 79 additions and 55 deletions

View File

@ -7532,6 +7532,56 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
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) */
/* MIPS16 extension to MIPS32 */
/* SmartMIPS extension to MIPS32 */
@ -7542,7 +7592,7 @@ static void gen_flt3_arith (DisasContext *ctx, uint32_t opc,
#endif
static void decode_opc (CPUState *env, DisasContext *ctx)
static void decode_opc (CPUState *env, DisasContext *ctx, int *is_branch)
{
int32_t offset;
int rs, rt, rd, sa;
@ -7557,7 +7607,7 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
}
/* 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();
MIPS_DEBUG("blikely condition (" TARGET_FMT_lx ")", ctx->pc + 4);
@ -7648,7 +7698,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
break;
case OPC_JR ... OPC_JALR:
gen_compute_branch(ctx, op1, 4, rs, rd, sa);
return;
*is_branch = 1;
break;
case OPC_TGE ... OPC_TEQ: /* Traps */
case OPC_TNE:
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_BLTZAL ... OPC_BGEZALL:
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2);
return;
*is_branch = 1;
break;
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
case OPC_TNEI:
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 */
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2;
gen_compute_branch(ctx, op, 4, rs, rt, offset);
return;
*is_branch = 1;
break;
case OPC_BEQ ... OPC_BGTZ: /* Branch */
case OPC_BEQL ... OPC_BGTZL:
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_SB ... OPC_SW:
case OPC_SWR:
@ -8121,7 +8175,8 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
case OPC_BC1:
gen_compute_branch1(env, ctx, MASK_BC1(ctx->opcode),
(rt >> 2) & 0x7, imm << 2);
return;
*is_branch = 1;
break;
case OPC_S_FMT:
case OPC_D_FMT:
case OPC_W_FMT:
@ -8226,51 +8281,6 @@ static void decode_opc (CPUState *env, DisasContext *ctx)
generate_exception(ctx, EXCP_RI);
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
@ -8284,6 +8294,8 @@ gen_intermediate_code_internal (CPUState *env, TranslationBlock *tb,
int j, lj = -1;
int num_insns;
int max_insns;
int insn_bytes;
int is_branch;
if (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))
gen_io_start();
ctx.opcode = ldl_code(ctx.pc);
decode_opc(env, &ctx);
ctx.pc += 4;
is_branch = 0;
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++;
/* Execute a branch and its delay slot as a single instruction.