Message ID | 1404232985-63404-1-git-send-email-yongbok.kim@imgtec.com |
---|---|
State | New |
Headers | show |
On Tue, Jul 01, 2014 at 05:43:05PM +0100, Yongbok Kim wrote: > Commit 240ce26a broke MIPS16 and microMIPS support as it didn't > care those branches and jumps don't have delay slot in > MIPS16 and microMIPS. > > This patch introduces a new argument delayslot_size to the > gen_compute_branch() indicating size of delay slot {0, 2, 4}. > And the information is used to call handle_delay_slot() forcingly > when no delay slot is required. > > There are some microMIPS branch and jump instructions that requires > exact size of instruction in the delay slot. For indicating > these instructions, MIPS_HFLAG_BDS_STRICT flag is introduced. > > Those fictional branch opcodes defined to support MIPS16 and > microMIPS are no longer needed. > > Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com> Jonas hit this problem too with a mips16 enabled userland, and has confirmed that this patch fixes it: Tested-by: Jonas Gorski <jogo@openwrt.org> Cheers James > --- > v2: > * correct MIPS_HFLAG_TMASK > --- > target-mips/cpu.h | 13 +- > target-mips/translate.c | 284 ++++++++++++++++++----------------------------- > 2 files changed, 117 insertions(+), 180 deletions(-) > > diff --git a/target-mips/cpu.h b/target-mips/cpu.h > index 8b9a92e..c81dfac 100644 > --- a/target-mips/cpu.h > +++ b/target-mips/cpu.h > @@ -431,7 +431,7 @@ struct CPUMIPSState { > int error_code; > uint32_t hflags; /* CPU State */ > /* TMASK defines different execution modes */ > -#define MIPS_HFLAG_TMASK 0xC07FF > +#define MIPS_HFLAG_TMASK 0x1807FF > #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ > /* The KSU flags must be the lowest bits in hflags. The flag order > must be the same as defined for CP0 Status. This allows to use > @@ -463,17 +463,18 @@ struct CPUMIPSState { > #define MIPS_HFLAG_BL 0x01800 /* Likely branch */ > #define MIPS_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ > /* Extra flags about the current pending branch. */ > -#define MIPS_HFLAG_BMASK_EXT 0x3C000 > +#define MIPS_HFLAG_BMASK_EXT 0x7C000 > #define MIPS_HFLAG_B16 0x04000 /* branch instruction was 16 bits */ > #define MIPS_HFLAG_BDS16 0x08000 /* branch requires 16-bit delay slot */ > #define MIPS_HFLAG_BDS32 0x10000 /* branch requires 32-bit delay slot */ > -#define MIPS_HFLAG_BX 0x20000 /* branch exchanges execution mode */ > +#define MIPS_HFLAG_BDS_STRICT 0x20000 /* Strict delay slot size */ > +#define MIPS_HFLAG_BX 0x40000 /* branch exchanges execution mode */ > #define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT) > /* MIPS DSP resources access. */ > -#define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */ > -#define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */ > +#define MIPS_HFLAG_DSP 0x080000 /* Enable access to MIPS DSP resources. */ > +#define MIPS_HFLAG_DSPR2 0x100000 /* Enable access to MIPS DSPR2 resources. */ > /* Extra flag about HWREna register. */ > -#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */ > +#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ > target_ulong btarget; /* Jump / branch target */ > target_ulong bcond; /* Branch condition (if needed) */ > > diff --git a/target-mips/translate.c b/target-mips/translate.c > index 2f91959..a654ae8 100644 > --- a/target-mips/translate.c > +++ b/target-mips/translate.c > @@ -61,7 +61,6 @@ enum { > /* Jump and branches */ > OPC_J = (0x02 << 26), > OPC_JAL = (0x03 << 26), > - OPC_JALS = OPC_JAL | 0x5, > OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ > OPC_BEQL = (0x14 << 26), > OPC_BNE = (0x05 << 26), > @@ -70,8 +69,7 @@ enum { > OPC_BLEZL = (0x16 << 26), > OPC_BGTZ = (0x07 << 26), > OPC_BGTZL = (0x17 << 26), > - OPC_JALX = (0x1D << 26), /* MIPS 16 only */ > - OPC_JALXS = OPC_JALX | 0x5, > + OPC_JALX = (0x1D << 26), > /* Load and stores */ > OPC_LDL = (0x1A << 26), > OPC_LDR = (0x1B << 26), > @@ -171,8 +169,6 @@ enum { > /* Jumps */ > OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ > OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ > - OPC_JALRC = OPC_JALR | (0x5 << 6), > - OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6), > /* Traps */ > OPC_TGE = 0x30 | OPC_SPECIAL, > OPC_TGEU = 0x31 | OPC_SPECIAL, > @@ -236,10 +232,8 @@ enum { > OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, > OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, > OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, > - OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */ > OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, > OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, > - OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */ > OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, > OPC_TGEI = (0x08 << 16) | OPC_REGIMM, > OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, > @@ -3597,7 +3591,8 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) > /* Branches (before delay slot) */ > static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > int insn_bytes, > - int rs, int rt, int32_t offset) > + int rs, int rt, int32_t offset, > + int delayslot_size) > { > target_ulong btgt = -1; > int blink = 0; > @@ -3629,7 +3624,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > break; > case OPC_BGEZ: > case OPC_BGEZAL: > - case OPC_BGEZALS: > case OPC_BGEZALL: > case OPC_BGEZL: > case OPC_BGTZ: > @@ -3638,7 +3632,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > case OPC_BLEZL: > case OPC_BLTZ: > case OPC_BLTZAL: > - case OPC_BLTZALS: > case OPC_BLTZALL: > case OPC_BLTZL: > /* Compare to zero */ > @@ -3661,15 +3654,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > case OPC_J: > case OPC_JAL: > case OPC_JALX: > - case OPC_JALS: > - case OPC_JALXS: > /* Jump to immediate */ > btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; > break; > case OPC_JR: > case OPC_JALR: > - case OPC_JALRC: > - case OPC_JALRS: > /* Jump to register */ > if (offset != 0 && offset != 16) { > /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the > @@ -3698,12 +3687,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > ctx->hflags |= MIPS_HFLAG_B; > MIPS_DEBUG("balways"); > break; > - case OPC_BGEZALS: > case OPC_BGEZAL: /* 0 >= 0 */ > case OPC_BGEZALL: /* 0 >= 0 likely */ > - ctx->hflags |= (opc == OPC_BGEZALS > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > /* Always take and link */ > blink = 31; > ctx->hflags |= MIPS_HFLAG_B; > @@ -3715,15 +3700,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > /* Treat as NOP. */ > MIPS_DEBUG("bnever (NOP)"); > goto out; > - case OPC_BLTZALS: > case OPC_BLTZAL: /* 0 < 0 */ > - ctx->hflags |= (opc == OPC_BLTZALS > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > /* Handle as an unconditional branch to get correct delay > slot checking. */ > blink = 31; > - btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8); > + btgt = ctx->pc + insn_bytes + delayslot_size; > ctx->hflags |= MIPS_HFLAG_B; > MIPS_DEBUG("bnever and link"); > break; > @@ -3744,33 +3725,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > ctx->hflags |= MIPS_HFLAG_B; > MIPS_DEBUG("j " TARGET_FMT_lx, btgt); > break; > - case OPC_JALXS: > case OPC_JALX: > ctx->hflags |= MIPS_HFLAG_BX; > /* Fallthrough */ > - case OPC_JALS: > case OPC_JAL: > blink = 31; > ctx->hflags |= MIPS_HFLAG_B; > - ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS) > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); > break; > case OPC_JR: > ctx->hflags |= MIPS_HFLAG_BR; > - if (insn_bytes == 4) > - ctx->hflags |= MIPS_HFLAG_BDS32; > MIPS_DEBUG("jr %s", regnames[rs]); > break; > - case OPC_JALRS: > case OPC_JALR: > - case OPC_JALRC: > blink = rt; > ctx->hflags |= MIPS_HFLAG_BR; > - ctx->hflags |= (opc == OPC_JALRS > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); > break; > default: > @@ -3808,11 +3777,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); > MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); > goto likely; > - case OPC_BGEZALS: > case OPC_BGEZAL: > - ctx->hflags |= (opc == OPC_BGEZALS > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); > MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); > blink = 31; > @@ -3856,11 +3821,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt); > goto not_likely; > #endif > - case OPC_BLTZALS: > case OPC_BLTZAL: > - ctx->hflags |= (opc == OPC_BLTZALS > - ? MIPS_HFLAG_BDS16 > - : MIPS_HFLAG_BDS32); > tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); > blink = 31; > MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); > @@ -3884,13 +3845,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, > blink, ctx->hflags, btgt); > > ctx->btarget = btgt; > + > + switch (delayslot_size) { > + case 2: > + ctx->hflags |= MIPS_HFLAG_BDS16; > + break; > + case 4: > + ctx->hflags |= MIPS_HFLAG_BDS32; > + break; > + } > + > if (blink > 0) { > int post_delay = insn_bytes; > int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); > > - if (opc != OPC_JALRC) > - post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); > - > + post_delay += delayslot_size; > tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); > } > > @@ -7124,7 +7093,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, > MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, > ctx->hflags, btarget); > ctx->btarget = btarget; > - > + ctx->hflags |= MIPS_HFLAG_BDS32; > out: > tcg_temp_free_i32(t0); > } > @@ -9667,15 +9636,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > gen_addiupc(ctx, rx, imm, 0, 1); > break; > case M16_OPC_B: > - gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1); > + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_BEQZ: > - gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1); > + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_BNEQZ: > - gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1); > + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_SHIFT: > @@ -9733,10 +9702,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > case M16_OPC_I8: > switch (funct) { > case I8_BTEQZ: > - gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1); > + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0); > break; > case I8_BTNEZ: > - gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1); > + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0); > break; > case I8_SWRASP: > gen_st(ctx, OPC_SW, 31, 29, imm); > @@ -9864,7 +9833,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > case M16_OPC_B: > offset = (ctx->opcode & 0x7ff) << 1; > offset = (int16_t)(offset << 4) >> 4; > - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset); > + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_JAL: > @@ -9872,16 +9841,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > offset = (((ctx->opcode & 0x1f) << 21) > | ((ctx->opcode >> 5) & 0x1f) << 16 > | offset) << 2; > - op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; > - gen_compute_branch(ctx, op, 4, rx, ry, offset); > + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; > + gen_compute_branch(ctx, op, 4, rx, ry, offset, 2); > n_bytes = 4; > break; > case M16_OPC_BEQZ: > - gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); > + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, > + ((int8_t)ctx->opcode) << 1, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_BNEQZ: > - gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1); > + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, > + ((int8_t)ctx->opcode) << 1, 0); > /* No delay slot, so just process as a normal instruction */ > break; > case M16_OPC_SHIFT: > @@ -9954,11 +9925,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > switch (funct) { > case I8_BTEQZ: > gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, > - ((int8_t)ctx->opcode) << 1); > + ((int8_t)ctx->opcode) << 1, 0); > break; > case I8_BTNEZ: > gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, > - ((int8_t)ctx->opcode) << 1); > + ((int8_t)ctx->opcode) << 1, 0); > break; > case I8_SWRASP: > gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); > @@ -10107,12 +10078,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) > int ra = (ctx->opcode >> 5) & 0x1; > > if (link) { > - op = nd ? OPC_JALRC : OPC_JALRS; > + op = OPC_JALR; > } else { > op = OPC_JR; > } > > - gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); > + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0, > + (nd ? 0 : 2)); > } > break; > case RR_SDBBP: > @@ -10870,7 +10842,6 @@ static void gen_pool16c_insn(DisasContext *ctx) > { > int rd = mmreg((ctx->opcode >> 3) & 0x7); > int rs = mmreg(ctx->opcode & 0x7); > - int opc; > > switch (((ctx->opcode) >> 4) & 0x3f) { > case NOT16 + 0: > @@ -10926,32 +10897,27 @@ static void gen_pool16c_insn(DisasContext *ctx) > { > int reg = ctx->opcode & 0x1f; > > - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); > + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); > } > break; > case JRC16 + 0: > case JRC16 + 1: > { > int reg = ctx->opcode & 0x1f; > - > - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); > + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); > /* Let normal delay slot handling in our caller take us > to the branch target. */ > } > break; > case JALR16 + 0: > case JALR16 + 1: > - opc = OPC_JALR; > - goto do_jalr; > + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > + break; > case JALR16S + 0: > case JALR16S + 1: > - opc = OPC_JALRS; > - do_jalr: > - { > - int reg = ctx->opcode & 0x1f; > - > - gen_compute_branch(ctx, opc, 2, reg, 31, 0); > - } > + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > case MFHI16 + 0: > case MFHI16 + 1: > @@ -10979,8 +10945,7 @@ static void gen_pool16c_insn(DisasContext *ctx) > case JRADDIUSP + 1: > { > int imm = ZIMM(ctx->opcode, 0, 5); > - > - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0); > + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); > gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); > /* Let normal delay slot handling in our caller take us > to the branch target. */ > @@ -11237,11 +11202,13 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) > switch (minor) { > case JALR: > case JALR_HB: > - gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); > + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > case JALRS: > case JALRS_HB: > - gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); > + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > default: > goto pool32axf_invalid; > @@ -12131,30 +12098,32 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, > minor = (ctx->opcode >> 21) & 0x1f; > switch (minor) { > case BLTZ: > - mips32_op = OPC_BLTZ; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); > + break; > case BLTZAL: > - mips32_op = OPC_BLTZAL; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > + break; > case BLTZALS: > - mips32_op = OPC_BLTZALS; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > + break; > case BGEZ: > - mips32_op = OPC_BGEZ; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); > + break; > case BGEZAL: > - mips32_op = OPC_BGEZAL; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > + break; > case BGEZALS: > - mips32_op = OPC_BGEZALS; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > + break; > case BLEZ: > - mips32_op = OPC_BLEZ; > - goto do_branch; > + gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); > + break; > case BGTZ: > - mips32_op = OPC_BGTZ; > - do_branch: > - gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); > + gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); > break; > > /* Traps */ > @@ -12182,7 +12151,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, > case BNEZC: > case BEQZC: > gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, > - 4, rs, 0, imm << 1); > + 4, rs, 0, imm << 1, 0); > /* Compact branches don't have a delay slot, so just let > the normal delay slot handling take us to the branch > target. */ > @@ -12320,25 +12289,28 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, > break; > case JALX32: > offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; > - gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); > + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > case JALS32: > offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; > - gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); > + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > case BEQ32: > - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); > + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); > break; > case BNE32: > - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); > + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); > break; > case J32: > gen_compute_branch(ctx, OPC_J, 4, rt, rs, > - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); > + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); > break; > case JAL32: > gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, > - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); > + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); > + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; > break; > /* Floating point (COP1) */ > case LWC132: > @@ -12422,84 +12394,41 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) > > op = (ctx->opcode >> 10) & 0x3f; > /* Enforce properly-sized instructions in a delay slot */ > - if (ctx->hflags & MIPS_HFLAG_BMASK) { > - int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT; > - > - switch (op) { > - case POOL32A: > - case POOL32B: > - case POOL32I: > - case POOL32C: > - case ADDI32: > - case ADDIU32: > - case ORI32: > - case XORI32: > - case SLTI32: > - case SLTIU32: > - case ANDI32: > - case JALX32: > - case LBU32: > - case LHU32: > - case POOL32F: > - case JALS32: > - case BEQ32: > - case BNE32: > - case J32: > - case JAL32: > - case SB32: > - case SH32: > - case POOL32S: > - case ADDIUPC: > - case SWC132: > - case SDC132: > - case SD32: > - case SW32: > - case LB32: > - case LH32: > - case DADDIU32: > - case LWC132: > - case LDC132: > - case LD32: > - case LW32: > - if (bits & MIPS_HFLAG_BDS16) { > + if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { > + switch (op & 0x7) { /* MSB-3..MSB-5 */ > + case 0: > + /* POOL31A, POOL32B, POOL32I, POOL32C */ > + case 4: > + /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ > + case 5: > + /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ > + case 6: > + /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ > + case 7: > + /* LB32, LH32, LWC132, LDC132, LW32 */ > + if (ctx->hflags & MIPS_HFLAG_BDS16) { > generate_exception(ctx, EXCP_RI); > /* Just stop translation; the user is confused. */ > ctx->bstate = BS_STOP; > return 2; > } > break; > - case POOL16A: > - case POOL16B: > - case POOL16C: > - case LWGP16: > - case POOL16F: > - case LBU16: > - case LHU16: > - case LWSP16: > - case LW16: > - case SB16: > - case SH16: > - case SWSP16: > - case SW16: > - case MOVE16: > - case ANDI16: > - case POOL16D: > - case POOL16E: > - case BEQZ16: > - case BNEZ16: > - case B16: > - case LI16: > - if (bits & MIPS_HFLAG_BDS32) { > + case 1: > + /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ > + case 2: > + /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ > + case 3: > + /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ > + if (ctx->hflags & MIPS_HFLAG_BDS32) { > generate_exception(ctx, EXCP_RI); > /* Just stop translation; the user is confused. */ > ctx->bstate = BS_STOP; > return 2; > } > break; > - default: > - break; > } > } > + > switch (op) { > case POOL16A: > { > @@ -12680,13 +12609,13 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) > break; > case B16: > gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, > - SIMM(ctx->opcode, 0, 10) << 1); > + SIMM(ctx->opcode, 0, 10) << 1, 4); > break; > case BNEZ16: > case BEQZ16: > gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, > mmreg(uMIPS_RD(ctx->opcode)), > - 0, SIMM(ctx->opcode, 0, 7) << 1); > + 0, SIMM(ctx->opcode, 0, 7) << 1, 4); > break; > case LI16: > { > @@ -14556,7 +14485,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > gen_muldiv(ctx, op1, 0, rs, rt); > break; > case OPC_JR ... OPC_JALR: > - gen_compute_branch(ctx, op1, 4, rs, rd, sa); > + gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4); > break; > case OPC_TGE ... OPC_TEQ: /* Traps */ > case OPC_TNE: > @@ -15322,7 +15251,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > switch (op1) { > case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ > 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, 4); > break; > case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ > case OPC_TNEI: > @@ -15337,7 +15266,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > case OPC_BPOSGE64: > #endif > check_dsp(ctx); > - gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); > + gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2, 4); > break; > default: /* Invalid */ > MIPS_INVAL("regimm"); > @@ -15448,11 +15377,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > break; > case OPC_J ... OPC_JAL: /* Jump */ > 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, 4); > break; > case OPC_BEQ ... OPC_BGTZ: /* Branch */ > 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, 4); > break; > case OPC_LB ... OPC_LWR: /* Load and stores */ > case OPC_LL: > @@ -15617,7 +15546,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) > case OPC_JALX: > check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); > 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, 4); > break; > case OPC_MDMX: > check_insn(ctx, ASE_MDMX); > @@ -15719,6 +15648,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, > ctx.bstate = BS_STOP; > break; > } > + if (ctx.hflags & MIPS_HFLAG_BMASK) { > + if (!(ctx.hflags & MIPS_HFLAG_BDS16) && > + !(ctx.hflags & MIPS_HFLAG_BDS32)) { > + is_delay = 1; > + /* force to generate branch as no delay slot is required */ > + } > + } > if (is_delay) { > handle_delay_slot(&ctx, insn_bytes); > } > -- > 1.7.4 > >
diff --git a/target-mips/cpu.h b/target-mips/cpu.h index 8b9a92e..c81dfac 100644 --- a/target-mips/cpu.h +++ b/target-mips/cpu.h @@ -431,7 +431,7 @@ struct CPUMIPSState { int error_code; uint32_t hflags; /* CPU State */ /* TMASK defines different execution modes */ -#define MIPS_HFLAG_TMASK 0xC07FF +#define MIPS_HFLAG_TMASK 0x1807FF #define MIPS_HFLAG_MODE 0x00007 /* execution modes */ /* The KSU flags must be the lowest bits in hflags. The flag order must be the same as defined for CP0 Status. This allows to use @@ -463,17 +463,18 @@ struct CPUMIPSState { #define MIPS_HFLAG_BL 0x01800 /* Likely branch */ #define MIPS_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ /* Extra flags about the current pending branch. */ -#define MIPS_HFLAG_BMASK_EXT 0x3C000 +#define MIPS_HFLAG_BMASK_EXT 0x7C000 #define MIPS_HFLAG_B16 0x04000 /* branch instruction was 16 bits */ #define MIPS_HFLAG_BDS16 0x08000 /* branch requires 16-bit delay slot */ #define MIPS_HFLAG_BDS32 0x10000 /* branch requires 32-bit delay slot */ -#define MIPS_HFLAG_BX 0x20000 /* branch exchanges execution mode */ +#define MIPS_HFLAG_BDS_STRICT 0x20000 /* Strict delay slot size */ +#define MIPS_HFLAG_BX 0x40000 /* branch exchanges execution mode */ #define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT) /* MIPS DSP resources access. */ -#define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */ -#define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */ +#define MIPS_HFLAG_DSP 0x080000 /* Enable access to MIPS DSP resources. */ +#define MIPS_HFLAG_DSPR2 0x100000 /* Enable access to MIPS DSPR2 resources. */ /* Extra flag about HWREna register. */ -#define MIPS_HFLAG_HWRENA_ULR 0x100000 /* ULR bit from HWREna is set. */ +#define MIPS_HFLAG_HWRENA_ULR 0x200000 /* ULR bit from HWREna is set. */ target_ulong btarget; /* Jump / branch target */ target_ulong bcond; /* Branch condition (if needed) */ diff --git a/target-mips/translate.c b/target-mips/translate.c index 2f91959..a654ae8 100644 --- a/target-mips/translate.c +++ b/target-mips/translate.c @@ -61,7 +61,6 @@ enum { /* Jump and branches */ OPC_J = (0x02 << 26), OPC_JAL = (0x03 << 26), - OPC_JALS = OPC_JAL | 0x5, OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ OPC_BEQL = (0x14 << 26), OPC_BNE = (0x05 << 26), @@ -70,8 +69,7 @@ enum { OPC_BLEZL = (0x16 << 26), OPC_BGTZ = (0x07 << 26), OPC_BGTZL = (0x17 << 26), - OPC_JALX = (0x1D << 26), /* MIPS 16 only */ - OPC_JALXS = OPC_JALX | 0x5, + OPC_JALX = (0x1D << 26), /* Load and stores */ OPC_LDL = (0x1A << 26), OPC_LDR = (0x1B << 26), @@ -171,8 +169,6 @@ enum { /* Jumps */ OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ - OPC_JALRC = OPC_JALR | (0x5 << 6), - OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6), /* Traps */ OPC_TGE = 0x30 | OPC_SPECIAL, OPC_TGEU = 0x31 | OPC_SPECIAL, @@ -236,10 +232,8 @@ enum { OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, - OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */ OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, - OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */ OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, OPC_TGEI = (0x08 << 16) | OPC_REGIMM, OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, @@ -3597,7 +3591,8 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest) /* Branches (before delay slot) */ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, int insn_bytes, - int rs, int rt, int32_t offset) + int rs, int rt, int32_t offset, + int delayslot_size) { target_ulong btgt = -1; int blink = 0; @@ -3629,7 +3624,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, break; case OPC_BGEZ: case OPC_BGEZAL: - case OPC_BGEZALS: case OPC_BGEZALL: case OPC_BGEZL: case OPC_BGTZ: @@ -3638,7 +3632,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_BLEZL: case OPC_BLTZ: case OPC_BLTZAL: - case OPC_BLTZALS: case OPC_BLTZALL: case OPC_BLTZL: /* Compare to zero */ @@ -3661,15 +3654,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, case OPC_J: case OPC_JAL: case OPC_JALX: - case OPC_JALS: - case OPC_JALXS: /* Jump to immediate */ btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; break; case OPC_JR: case OPC_JALR: - case OPC_JALRC: - case OPC_JALRS: /* Jump to register */ if (offset != 0 && offset != 16) { /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the @@ -3698,12 +3687,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("balways"); break; - case OPC_BGEZALS: case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZALL: /* 0 >= 0 likely */ - ctx->hflags |= (opc == OPC_BGEZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); /* Always take and link */ blink = 31; ctx->hflags |= MIPS_HFLAG_B; @@ -3715,15 +3700,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, /* Treat as NOP. */ MIPS_DEBUG("bnever (NOP)"); goto out; - case OPC_BLTZALS: case OPC_BLTZAL: /* 0 < 0 */ - ctx->hflags |= (opc == OPC_BLTZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); /* Handle as an unconditional branch to get correct delay slot checking. */ blink = 31; - btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8); + btgt = ctx->pc + insn_bytes + delayslot_size; ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("bnever and link"); break; @@ -3744,33 +3725,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, ctx->hflags |= MIPS_HFLAG_B; MIPS_DEBUG("j " TARGET_FMT_lx, btgt); break; - case OPC_JALXS: case OPC_JALX: ctx->hflags |= MIPS_HFLAG_BX; /* Fallthrough */ - case OPC_JALS: case OPC_JAL: blink = 31; ctx->hflags |= MIPS_HFLAG_B; - ctx->hflags |= ((opc == OPC_JALS || opc == OPC_JALXS) - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); MIPS_DEBUG("jal " TARGET_FMT_lx, btgt); break; case OPC_JR: ctx->hflags |= MIPS_HFLAG_BR; - if (insn_bytes == 4) - ctx->hflags |= MIPS_HFLAG_BDS32; MIPS_DEBUG("jr %s", regnames[rs]); break; - case OPC_JALRS: case OPC_JALR: - case OPC_JALRC: blink = rt; ctx->hflags |= MIPS_HFLAG_BR; - ctx->hflags |= (opc == OPC_JALRS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]); break; default: @@ -3808,11 +3777,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); goto likely; - case OPC_BGEZALS: case OPC_BGEZAL: - ctx->hflags |= (opc == OPC_BGEZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); blink = 31; @@ -3856,11 +3821,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt); goto not_likely; #endif - case OPC_BLTZALS: case OPC_BLTZAL: - ctx->hflags |= (opc == OPC_BLTZALS - ? MIPS_HFLAG_BDS16 - : MIPS_HFLAG_BDS32); tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); blink = 31; MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); @@ -3884,13 +3845,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc, blink, ctx->hflags, btgt); ctx->btarget = btgt; + + switch (delayslot_size) { + case 2: + ctx->hflags |= MIPS_HFLAG_BDS16; + break; + case 4: + ctx->hflags |= MIPS_HFLAG_BDS32; + break; + } + if (blink > 0) { int post_delay = insn_bytes; int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16); - if (opc != OPC_JALRC) - post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); - + post_delay += delayslot_size; tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); } @@ -7124,7 +7093,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op, MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, ctx->hflags, btarget); ctx->btarget = btarget; - + ctx->hflags |= MIPS_HFLAG_BDS32; out: tcg_temp_free_i32(t0); } @@ -9667,15 +9636,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) gen_addiupc(ctx, rx, imm, 0, 1); break; case M16_OPC_B: - gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, 0, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, rx, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1); + gen_compute_branch(ctx, OPC_BNE, 4, rx, 0, offset << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_SHIFT: @@ -9733,10 +9702,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case M16_OPC_I8: switch (funct) { case I8_BTEQZ: - gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, 24, 0, offset << 1, 0); break; case I8_BTNEZ: - gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1); + gen_compute_branch(ctx, OPC_BNE, 4, 24, 0, offset << 1, 0); break; case I8_SWRASP: gen_st(ctx, OPC_SW, 31, 29, imm); @@ -9864,7 +9833,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) case M16_OPC_B: offset = (ctx->opcode & 0x7ff) << 1; offset = (int16_t)(offset << 4) >> 4; - gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset); + gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, offset, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_JAL: @@ -9872,16 +9841,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) offset = (((ctx->opcode & 0x1f) << 21) | ((ctx->opcode >> 5) & 0x1f) << 16 | offset) << 2; - op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; - gen_compute_branch(ctx, op, 4, rx, ry, offset); + op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL; + gen_compute_branch(ctx, op, 4, rx, ry, offset, 2); n_bytes = 4; break; case M16_OPC_BEQZ: - gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + gen_compute_branch(ctx, OPC_BEQ, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_BNEQZ: - gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, ((int8_t)ctx->opcode) << 1); + gen_compute_branch(ctx, OPC_BNE, 2, rx, 0, + ((int8_t)ctx->opcode) << 1, 0); /* No delay slot, so just process as a normal instruction */ break; case M16_OPC_SHIFT: @@ -9954,11 +9925,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) switch (funct) { case I8_BTEQZ: gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, - ((int8_t)ctx->opcode) << 1); + ((int8_t)ctx->opcode) << 1, 0); break; case I8_BTNEZ: gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, - ((int8_t)ctx->opcode) << 1); + ((int8_t)ctx->opcode) << 1, 0); break; case I8_SWRASP: gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); @@ -10107,12 +10078,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx) int ra = (ctx->opcode >> 5) & 0x1; if (link) { - op = nd ? OPC_JALRC : OPC_JALRS; + op = OPC_JALR; } else { op = OPC_JR; } - gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0); + gen_compute_branch(ctx, op, 2, ra ? 31 : rx, 31, 0, + (nd ? 0 : 2)); } break; case RR_SDBBP: @@ -10870,7 +10842,6 @@ static void gen_pool16c_insn(DisasContext *ctx) { int rd = mmreg((ctx->opcode >> 3) & 0x7); int rs = mmreg(ctx->opcode & 0x7); - int opc; switch (((ctx->opcode) >> 4) & 0x3f) { case NOT16 + 0: @@ -10926,32 +10897,27 @@ static void gen_pool16c_insn(DisasContext *ctx) { int reg = ctx->opcode & 0x1f; - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 4); } break; case JRC16 + 0: case JRC16 + 1: { int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0); /* Let normal delay slot handling in our caller take us to the branch target. */ } break; case JALR16 + 0: case JALR16 + 1: - opc = OPC_JALR; - goto do_jalr; + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case JALR16S + 0: case JALR16S + 1: - opc = OPC_JALRS; - do_jalr: - { - int reg = ctx->opcode & 0x1f; - - gen_compute_branch(ctx, opc, 2, reg, 31, 0); - } + gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case MFHI16 + 0: case MFHI16 + 1: @@ -10979,8 +10945,7 @@ static void gen_pool16c_insn(DisasContext *ctx) case JRADDIUSP + 1: { int imm = ZIMM(ctx->opcode, 0, 5); - - gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0); + gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0); gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); /* Let normal delay slot handling in our caller take us to the branch target. */ @@ -11237,11 +11202,13 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs) switch (minor) { case JALR: case JALR_HB: - gen_compute_branch (ctx, OPC_JALR, 4, rs, rt, 0); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case JALRS: case JALRS_HB: - gen_compute_branch (ctx, OPC_JALRS, 4, rs, rt, 0); + gen_compute_branch(ctx, OPC_JALR, 4, rs, rt, 0, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; default: goto pool32axf_invalid; @@ -12131,30 +12098,32 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, minor = (ctx->opcode >> 21) & 0x1f; switch (minor) { case BLTZ: - mips32_op = OPC_BLTZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4); + break; case BLTZAL: - mips32_op = OPC_BLTZAL; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BLTZALS: - mips32_op = OPC_BLTZALS; - goto do_branch; + gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BGEZ: - mips32_op = OPC_BGEZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4); + break; case BGEZAL: - mips32_op = OPC_BGEZAL; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BGEZALS: - mips32_op = OPC_BGEZALS; - goto do_branch; + gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; + break; case BLEZ: - mips32_op = OPC_BLEZ; - goto do_branch; + gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4); + break; case BGTZ: - mips32_op = OPC_BGTZ; - do_branch: - gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1); + gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4); break; /* Traps */ @@ -12182,7 +12151,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, case BNEZC: case BEQZC: gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, - 4, rs, 0, imm << 1); + 4, rs, 0, imm << 1, 0); /* Compact branches don't have a delay slot, so just let the normal delay slot handling take us to the branch target. */ @@ -12320,25 +12289,28 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx, break; case JALX32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; - gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset); + gen_compute_branch(ctx, OPC_JALX, 4, rt, rs, offset, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case JALS32: offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; - gen_compute_branch(ctx, OPC_JALS, 4, rt, rs, offset); + gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, offset, 2); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; case BEQ32: - gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1); + gen_compute_branch(ctx, OPC_BEQ, 4, rt, rs, imm << 1, 4); break; case BNE32: - gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1); + gen_compute_branch(ctx, OPC_BNE, 4, rt, rs, imm << 1, 4); break; case J32: gen_compute_branch(ctx, OPC_J, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); break; case JAL32: gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, - (int32_t)(ctx->opcode & 0x3FFFFFF) << 1); + (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4); + ctx->hflags |= MIPS_HFLAG_BDS_STRICT; break; /* Floating point (COP1) */ case LWC132: @@ -12422,84 +12394,41 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) op = (ctx->opcode >> 10) & 0x3f; /* Enforce properly-sized instructions in a delay slot */ - if (ctx->hflags & MIPS_HFLAG_BMASK) { - int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT; - - switch (op) { - case POOL32A: - case POOL32B: - case POOL32I: - case POOL32C: - case ADDI32: - case ADDIU32: - case ORI32: - case XORI32: - case SLTI32: - case SLTIU32: - case ANDI32: - case JALX32: - case LBU32: - case LHU32: - case POOL32F: - case JALS32: - case BEQ32: - case BNE32: - case J32: - case JAL32: - case SB32: - case SH32: - case POOL32S: - case ADDIUPC: - case SWC132: - case SDC132: - case SD32: - case SW32: - case LB32: - case LH32: - case DADDIU32: - case LWC132: - case LDC132: - case LD32: - case LW32: - if (bits & MIPS_HFLAG_BDS16) { + if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) { + switch (op & 0x7) { /* MSB-3..MSB-5 */ + case 0: + /* POOL31A, POOL32B, POOL32I, POOL32C */ + case 4: + /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */ + case 5: + /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */ + case 6: + /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */ + case 7: + /* LB32, LH32, LWC132, LDC132, LW32 */ + if (ctx->hflags & MIPS_HFLAG_BDS16) { generate_exception(ctx, EXCP_RI); /* Just stop translation; the user is confused. */ ctx->bstate = BS_STOP; return 2; } break; - case POOL16A: - case POOL16B: - case POOL16C: - case LWGP16: - case POOL16F: - case LBU16: - case LHU16: - case LWSP16: - case LW16: - case SB16: - case SH16: - case SWSP16: - case SW16: - case MOVE16: - case ANDI16: - case POOL16D: - case POOL16E: - case BEQZ16: - case BNEZ16: - case B16: - case LI16: - if (bits & MIPS_HFLAG_BDS32) { + case 1: + /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */ + case 2: + /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */ + case 3: + /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */ + if (ctx->hflags & MIPS_HFLAG_BDS32) { generate_exception(ctx, EXCP_RI); /* Just stop translation; the user is confused. */ ctx->bstate = BS_STOP; return 2; } break; - default: - break; } } + switch (op) { case POOL16A: { @@ -12680,13 +12609,13 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx) break; case B16: gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, - SIMM(ctx->opcode, 0, 10) << 1); + SIMM(ctx->opcode, 0, 10) << 1, 4); break; case BNEZ16: case BEQZ16: gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, mmreg(uMIPS_RD(ctx->opcode)), - 0, SIMM(ctx->opcode, 0, 7) << 1); + 0, SIMM(ctx->opcode, 0, 7) << 1, 4); break; case LI16: { @@ -14556,7 +14485,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) gen_muldiv(ctx, op1, 0, rs, rt); break; case OPC_JR ... OPC_JALR: - gen_compute_branch(ctx, op1, 4, rs, rd, sa); + gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4); break; case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TNE: @@ -15322,7 +15251,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) switch (op1) { case OPC_BLTZ ... OPC_BGEZL: /* REGIMM branches */ 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, 4); break; case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TNEI: @@ -15337,7 +15266,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_BPOSGE64: #endif check_dsp(ctx); - gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2); + gen_compute_branch(ctx, op1, 4, -1, -2, (int32_t)imm << 2, 4); break; default: /* Invalid */ MIPS_INVAL("regimm"); @@ -15448,11 +15377,11 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) break; case OPC_J ... OPC_JAL: /* Jump */ 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, 4); break; case OPC_BEQ ... OPC_BGTZ: /* Branch */ 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, 4); break; case OPC_LB ... OPC_LWR: /* Load and stores */ case OPC_LL: @@ -15617,7 +15546,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx) case OPC_JALX: check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); 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, 4); break; case OPC_MDMX: check_insn(ctx, ASE_MDMX); @@ -15719,6 +15648,13 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb, ctx.bstate = BS_STOP; break; } + if (ctx.hflags & MIPS_HFLAG_BMASK) { + if (!(ctx.hflags & MIPS_HFLAG_BDS16) && + !(ctx.hflags & MIPS_HFLAG_BDS32)) { + is_delay = 1; + /* force to generate branch as no delay slot is required */ + } + } if (is_delay) { handle_delay_slot(&ctx, insn_bytes); }
Commit 240ce26a broke MIPS16 and microMIPS support as it didn't care those branches and jumps don't have delay slot in MIPS16 and microMIPS. This patch introduces a new argument delayslot_size to the gen_compute_branch() indicating size of delay slot {0, 2, 4}. And the information is used to call handle_delay_slot() forcingly when no delay slot is required. There are some microMIPS branch and jump instructions that requires exact size of instruction in the delay slot. For indicating these instructions, MIPS_HFLAG_BDS_STRICT flag is introduced. Those fictional branch opcodes defined to support MIPS16 and microMIPS are no longer needed. Signed-off-by: Yongbok Kim <yongbok.kim@imgtec.com> --- v2: * correct MIPS_HFLAG_TMASK --- target-mips/cpu.h | 13 +- target-mips/translate.c | 284 ++++++++++++++++++----------------------------- 2 files changed, 117 insertions(+), 180 deletions(-)