target-mips: fix broken MIPS16 and microMIPS

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>
Tested-by: Jonas Gorski <jogo@openwrt.org>
Reviewed-by: Leon Alrae <leon.alrae@imgtec.com>
[leon.alrae@imgtec.com: cosmetic changes]
Signed-off-by: Leon Alrae <leon.alrae@imgtec.com>
master
Yongbok Kim 2014-07-01 17:43:05 +01:00 committed by Leon Alrae
parent a83bddd60d
commit b231c103af
2 changed files with 124 additions and 189 deletions

View File

@ -431,7 +431,7 @@ struct CPUMIPSState {
int error_code; int error_code;
uint32_t hflags; /* CPU State */ uint32_t hflags; /* CPU State */
/* TMASK defines different execution modes */ /* TMASK defines different execution modes */
#define MIPS_HFLAG_TMASK 0xC07FF #define MIPS_HFLAG_TMASK 0x1807FF
#define MIPS_HFLAG_MODE 0x00007 /* execution modes */ #define MIPS_HFLAG_MODE 0x00007 /* execution modes */
/* The KSU flags must be the lowest bits in hflags. The flag order /* 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 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_BL 0x01800 /* Likely branch */
#define MIPS_HFLAG_BR 0x02000 /* branch to register (can't link TB) */ #define MIPS_HFLAG_BR 0x02000 /* branch to register (can't link TB) */
/* Extra flags about the current pending branch. */ /* 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_B16 0x04000 /* branch instruction was 16 bits */
#define MIPS_HFLAG_BDS16 0x08000 /* branch requires 16-bit delay slot */ #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_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) #define MIPS_HFLAG_BMASK (MIPS_HFLAG_BMASK_BASE | MIPS_HFLAG_BMASK_EXT)
/* MIPS DSP resources access. */ /* MIPS DSP resources access. */
#define MIPS_HFLAG_DSP 0x40000 /* Enable access to MIPS DSP resources. */ #define MIPS_HFLAG_DSP 0x080000 /* Enable access to MIPS DSP resources. */
#define MIPS_HFLAG_DSPR2 0x80000 /* Enable access to MIPS DSPR2 resources. */ #define MIPS_HFLAG_DSPR2 0x100000 /* Enable access to MIPS DSPR2 resources. */
/* Extra flag about HWREna register. */ /* 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 btarget; /* Jump / branch target */
target_ulong bcond; /* Branch condition (if needed) */ target_ulong bcond; /* Branch condition (if needed) */

View File

@ -65,7 +65,6 @@ enum {
/* Jump and branches */ /* Jump and branches */
OPC_J = (0x02 << 26), OPC_J = (0x02 << 26),
OPC_JAL = (0x03 << 26), OPC_JAL = (0x03 << 26),
OPC_JALS = OPC_JAL | 0x5,
OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */ OPC_BEQ = (0x04 << 26), /* Unconditional if rs = rt = 0 (B) */
OPC_BEQL = (0x14 << 26), OPC_BEQL = (0x14 << 26),
OPC_BNE = (0x05 << 26), OPC_BNE = (0x05 << 26),
@ -74,9 +73,8 @@ enum {
OPC_BLEZL = (0x16 << 26), OPC_BLEZL = (0x16 << 26),
OPC_BGTZ = (0x07 << 26), OPC_BGTZ = (0x07 << 26),
OPC_BGTZL = (0x17 << 26), OPC_BGTZL = (0x17 << 26),
OPC_JALX = (0x1D << 26), /* MIPS 16 only */ OPC_JALX = (0x1D << 26),
OPC_DAUI = (0x1D << 26), OPC_DAUI = (0x1D << 26),
OPC_JALXS = OPC_JALX | 0x5,
/* Load and stores */ /* Load and stores */
OPC_LDL = (0x1A << 26), OPC_LDL = (0x1A << 26),
OPC_LDR = (0x1B << 26), OPC_LDR = (0x1B << 26),
@ -219,8 +217,6 @@ enum {
/* Jumps */ /* Jumps */
OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */ OPC_JR = 0x08 | OPC_SPECIAL, /* Also JR.HB */
OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */ OPC_JALR = 0x09 | OPC_SPECIAL, /* Also JALR.HB */
OPC_JALRC = OPC_JALR | (0x5 << 6),
OPC_JALRS = 0x10 | OPC_SPECIAL | (0x5 << 6),
/* Traps */ /* Traps */
OPC_TGE = 0x30 | OPC_SPECIAL, OPC_TGE = 0x30 | OPC_SPECIAL,
OPC_TGEU = 0x31 | OPC_SPECIAL, OPC_TGEU = 0x31 | OPC_SPECIAL,
@ -317,10 +313,8 @@ enum {
OPC_BGEZ = (0x01 << 16) | OPC_REGIMM, OPC_BGEZ = (0x01 << 16) | OPC_REGIMM,
OPC_BGEZL = (0x03 << 16) | OPC_REGIMM, OPC_BGEZL = (0x03 << 16) | OPC_REGIMM,
OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM, OPC_BLTZAL = (0x10 << 16) | OPC_REGIMM,
OPC_BLTZALS = OPC_BLTZAL | 0x5, /* microMIPS */
OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM, OPC_BLTZALL = (0x12 << 16) | OPC_REGIMM,
OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM, OPC_BGEZAL = (0x11 << 16) | OPC_REGIMM,
OPC_BGEZALS = OPC_BGEZAL | 0x5, /* microMIPS */
OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM, OPC_BGEZALL = (0x13 << 16) | OPC_REGIMM,
OPC_TGEI = (0x08 << 16) | OPC_REGIMM, OPC_TGEI = (0x08 << 16) | OPC_REGIMM,
OPC_TGEIU = (0x09 << 16) | OPC_REGIMM, OPC_TGEIU = (0x09 << 16) | OPC_REGIMM,
@ -4137,7 +4131,8 @@ static inline void gen_goto_tb(DisasContext *ctx, int n, target_ulong dest)
/* Branches (before delay slot) */ /* Branches (before delay slot) */
static void gen_compute_branch (DisasContext *ctx, uint32_t opc, static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
int insn_bytes, int insn_bytes,
int rs, int rt, int32_t offset) int rs, int rt, int32_t offset,
int delayslot_size)
{ {
target_ulong btgt = -1; target_ulong btgt = -1;
int blink = 0; int blink = 0;
@ -4169,7 +4164,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
break; break;
case OPC_BGEZ: case OPC_BGEZ:
case OPC_BGEZAL: case OPC_BGEZAL:
case OPC_BGEZALS:
case OPC_BGEZALL: case OPC_BGEZALL:
case OPC_BGEZL: case OPC_BGEZL:
case OPC_BGTZ: case OPC_BGTZ:
@ -4178,7 +4172,6 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_BLEZL: case OPC_BLEZL:
case OPC_BLTZ: case OPC_BLTZ:
case OPC_BLTZAL: case OPC_BLTZAL:
case OPC_BLTZALS:
case OPC_BLTZALL: case OPC_BLTZALL:
case OPC_BLTZL: case OPC_BLTZL:
/* Compare to zero */ /* Compare to zero */
@ -4201,15 +4194,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
case OPC_J: case OPC_J:
case OPC_JAL: case OPC_JAL:
case OPC_JALX: case OPC_JALX:
case OPC_JALS:
case OPC_JALXS:
/* Jump to immediate */ /* Jump to immediate */
btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset; btgt = ((ctx->pc + insn_bytes) & (int32_t)0xF0000000) | (uint32_t)offset;
break; break;
case OPC_JR: case OPC_JR:
case OPC_JALR: case OPC_JALR:
case OPC_JALRC:
case OPC_JALRS:
/* Jump to register */ /* Jump to register */
if (offset != 0 && offset != 16) { if (offset != 0 && offset != 16) {
/* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the /* Hint = 0 is JR/JALR, hint 16 is JR.HB/JALR.HB, the
@ -4238,12 +4227,8 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->hflags |= MIPS_HFLAG_B; ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("balways"); MIPS_DEBUG("balways");
break; break;
case OPC_BGEZALS:
case OPC_BGEZAL: /* 0 >= 0 */ case OPC_BGEZAL: /* 0 >= 0 */
case OPC_BGEZALL: /* 0 >= 0 likely */ case OPC_BGEZALL: /* 0 >= 0 likely */
ctx->hflags |= (opc == OPC_BGEZALS
? MIPS_HFLAG_BDS16
: MIPS_HFLAG_BDS32);
/* Always take and link */ /* Always take and link */
blink = 31; blink = 31;
ctx->hflags |= MIPS_HFLAG_B; ctx->hflags |= MIPS_HFLAG_B;
@ -4255,15 +4240,11 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
/* Treat as NOP. */ /* Treat as NOP. */
MIPS_DEBUG("bnever (NOP)"); MIPS_DEBUG("bnever (NOP)");
goto out; goto out;
case OPC_BLTZALS:
case OPC_BLTZAL: /* 0 < 0 */ 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 /* Handle as an unconditional branch to get correct delay
slot checking. */ slot checking. */
blink = 31; blink = 31;
btgt = ctx->pc + (opc == OPC_BLTZALS ? 6 : 8); btgt = ctx->pc + insn_bytes + delayslot_size;
ctx->hflags |= MIPS_HFLAG_B; ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("bnever and link"); MIPS_DEBUG("bnever and link");
break; break;
@ -4284,33 +4265,21 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
ctx->hflags |= MIPS_HFLAG_B; ctx->hflags |= MIPS_HFLAG_B;
MIPS_DEBUG("j " TARGET_FMT_lx, btgt); MIPS_DEBUG("j " TARGET_FMT_lx, btgt);
break; break;
case OPC_JALXS:
case OPC_JALX: case OPC_JALX:
ctx->hflags |= MIPS_HFLAG_BX; ctx->hflags |= MIPS_HFLAG_BX;
/* Fallthrough */ /* Fallthrough */
case OPC_JALS:
case OPC_JAL: case OPC_JAL:
blink = 31; blink = 31;
ctx->hflags |= MIPS_HFLAG_B; 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); MIPS_DEBUG("jal " TARGET_FMT_lx, btgt);
break; break;
case OPC_JR: case OPC_JR:
ctx->hflags |= MIPS_HFLAG_BR; ctx->hflags |= MIPS_HFLAG_BR;
if (insn_bytes == 4)
ctx->hflags |= MIPS_HFLAG_BDS32;
MIPS_DEBUG("jr %s", regnames[rs]); MIPS_DEBUG("jr %s", regnames[rs]);
break; break;
case OPC_JALRS:
case OPC_JALR: case OPC_JALR:
case OPC_JALRC:
blink = rt; blink = rt;
ctx->hflags |= MIPS_HFLAG_BR; 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]); MIPS_DEBUG("jalr %s, %s", regnames[rt], regnames[rs]);
break; break;
default: default:
@ -4348,11 +4317,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt); MIPS_DEBUG("bgezl %s, " TARGET_FMT_lx, regnames[rs], btgt);
goto likely; goto likely;
case OPC_BGEZALS:
case OPC_BGEZAL: case OPC_BGEZAL:
ctx->hflags |= (opc == OPC_BGEZALS
? MIPS_HFLAG_BDS16
: MIPS_HFLAG_BDS32);
tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0); tcg_gen_setcondi_tl(TCG_COND_GE, bcond, t0, 0);
MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt); MIPS_DEBUG("bgezal %s, " TARGET_FMT_lx, regnames[rs], btgt);
blink = 31; blink = 31;
@ -4396,11 +4361,7 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt); MIPS_DEBUG("bposge64 " TARGET_FMT_lx, btgt);
goto not_likely; goto not_likely;
#endif #endif
case OPC_BLTZALS:
case OPC_BLTZAL: case OPC_BLTZAL:
ctx->hflags |= (opc == OPC_BLTZALS
? MIPS_HFLAG_BDS16
: MIPS_HFLAG_BDS32);
tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0); tcg_gen_setcondi_tl(TCG_COND_LT, bcond, t0, 0);
blink = 31; blink = 31;
MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt); MIPS_DEBUG("bltzal %s, " TARGET_FMT_lx, regnames[rs], btgt);
@ -4424,12 +4385,19 @@ static void gen_compute_branch (DisasContext *ctx, uint32_t opc,
blink, ctx->hflags, btgt); blink, ctx->hflags, btgt);
ctx->btarget = btgt; ctx->btarget = btgt;
if (blink > 0) {
int post_delay = insn_bytes;
int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);
if (opc != OPC_JALRC) switch (delayslot_size) {
post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4); case 2:
ctx->hflags |= MIPS_HFLAG_BDS16;
break;
case 4:
ctx->hflags |= MIPS_HFLAG_BDS32;
break;
}
if (blink > 0) {
int post_delay = insn_bytes + delayslot_size;
int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);
tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit); tcg_gen_movi_tl(cpu_gpr[blink], ctx->pc + post_delay + lowbit);
} }
@ -7664,7 +7632,7 @@ static void gen_compute_branch1(DisasContext *ctx, uint32_t op,
MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn, MIPS_DEBUG("%s: cond %02x target " TARGET_FMT_lx, opn,
ctx->hflags, btarget); ctx->hflags, btarget);
ctx->btarget = btarget; ctx->btarget = btarget;
ctx->hflags |= MIPS_HFLAG_BDS32;
out: out:
tcg_temp_free_i32(t0); tcg_temp_free_i32(t0);
} }
@ -10666,15 +10634,15 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
gen_addiupc(ctx, rx, imm, 0, 1); gen_addiupc(ctx, rx, imm, 0, 1);
break; break;
case M16_OPC_B: 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_BEQZ: 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_BNEQZ: 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_SHIFT: case M16_OPC_SHIFT:
@ -10732,10 +10700,10 @@ static int decode_extended_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
case M16_OPC_I8: case M16_OPC_I8:
switch (funct) { switch (funct) {
case I8_BTEQZ: 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; break;
case I8_BTNEZ: 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; break;
case I8_SWRASP: case I8_SWRASP:
gen_st(ctx, OPC_SW, 31, 29, imm); gen_st(ctx, OPC_SW, 31, 29, imm);
@ -10863,7 +10831,7 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
case M16_OPC_B: case M16_OPC_B:
offset = (ctx->opcode & 0x7ff) << 1; offset = (ctx->opcode & 0x7ff) << 1;
offset = (int16_t)(offset << 4) >> 4; 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_JAL: case M16_OPC_JAL:
@ -10871,16 +10839,18 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
offset = (((ctx->opcode & 0x1f) << 21) offset = (((ctx->opcode & 0x1f) << 21)
| ((ctx->opcode >> 5) & 0x1f) << 16 | ((ctx->opcode >> 5) & 0x1f) << 16
| offset) << 2; | offset) << 2;
op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALXS : OPC_JALS; op = ((ctx->opcode >> 10) & 0x1) ? OPC_JALX : OPC_JAL;
gen_compute_branch(ctx, op, 4, rx, ry, offset); gen_compute_branch(ctx, op, 4, rx, ry, offset, 2);
n_bytes = 4; n_bytes = 4;
break; break;
case M16_OPC_BEQZ: 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_BNEQZ: 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 */ /* No delay slot, so just process as a normal instruction */
break; break;
case M16_OPC_SHIFT: case M16_OPC_SHIFT:
@ -10953,11 +10923,11 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
switch (funct) { switch (funct) {
case I8_BTEQZ: case I8_BTEQZ:
gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0, gen_compute_branch(ctx, OPC_BEQ, 2, 24, 0,
((int8_t)ctx->opcode) << 1); ((int8_t)ctx->opcode) << 1, 0);
break; break;
case I8_BTNEZ: case I8_BTNEZ:
gen_compute_branch(ctx, OPC_BNE, 2, 24, 0, gen_compute_branch(ctx, OPC_BNE, 2, 24, 0,
((int8_t)ctx->opcode) << 1); ((int8_t)ctx->opcode) << 1, 0);
break; break;
case I8_SWRASP: case I8_SWRASP:
gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2); gen_st(ctx, OPC_SW, 31, 29, (ctx->opcode & 0xff) << 2);
@ -11106,12 +11076,13 @@ static int decode_mips16_opc (CPUMIPSState *env, DisasContext *ctx)
int ra = (ctx->opcode >> 5) & 0x1; int ra = (ctx->opcode >> 5) & 0x1;
if (link) { if (link) {
op = nd ? OPC_JALRC : OPC_JALRS; op = OPC_JALR;
} else { } else {
op = OPC_JR; 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; break;
case RR_SDBBP: case RR_SDBBP:
@ -11869,7 +11840,6 @@ static void gen_pool16c_insn(DisasContext *ctx)
{ {
int rd = mmreg((ctx->opcode >> 3) & 0x7); int rd = mmreg((ctx->opcode >> 3) & 0x7);
int rs = mmreg(ctx->opcode & 0x7); int rs = mmreg(ctx->opcode & 0x7);
int opc;
switch (((ctx->opcode) >> 4) & 0x3f) { switch (((ctx->opcode) >> 4) & 0x3f) {
case NOT16 + 0: case NOT16 + 0:
@ -11925,32 +11895,27 @@ static void gen_pool16c_insn(DisasContext *ctx)
{ {
int reg = ctx->opcode & 0x1f; 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; break;
case JRC16 + 0: case JRC16 + 0:
case JRC16 + 1: case JRC16 + 1:
{ {
int reg = ctx->opcode & 0x1f; int reg = ctx->opcode & 0x1f;
gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0, 0);
gen_compute_branch(ctx, OPC_JR, 2, reg, 0, 0);
/* Let normal delay slot handling in our caller take us /* Let normal delay slot handling in our caller take us
to the branch target. */ to the branch target. */
} }
break; break;
case JALR16 + 0: case JALR16 + 0:
case JALR16 + 1: case JALR16 + 1:
opc = OPC_JALR; gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 4);
goto do_jalr; ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
break;
case JALR16S + 0: case JALR16S + 0:
case JALR16S + 1: case JALR16S + 1:
opc = OPC_JALRS; gen_compute_branch(ctx, OPC_JALR, 2, ctx->opcode & 0x1f, 31, 0, 2);
do_jalr: ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
{
int reg = ctx->opcode & 0x1f;
gen_compute_branch(ctx, opc, 2, reg, 31, 0);
}
break; break;
case MFHI16 + 0: case MFHI16 + 0:
case MFHI16 + 1: case MFHI16 + 1:
@ -11978,8 +11943,7 @@ static void gen_pool16c_insn(DisasContext *ctx)
case JRADDIUSP + 1: case JRADDIUSP + 1:
{ {
int imm = ZIMM(ctx->opcode, 0, 5); int imm = ZIMM(ctx->opcode, 0, 5);
gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0, 0);
gen_compute_branch(ctx, OPC_JR, 2, 31, 0, 0);
gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2); gen_arith_imm(ctx, OPC_ADDIU, 29, 29, imm << 2);
/* Let normal delay slot handling in our caller take us /* Let normal delay slot handling in our caller take us
to the branch target. */ to the branch target. */
@ -12236,11 +12200,13 @@ static void gen_pool32axf (CPUMIPSState *env, DisasContext *ctx, int rt, int rs)
switch (minor) { switch (minor) {
case JALR: case JALR:
case JALR_HB: 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; break;
case JALRS: case JALRS:
case JALRS_HB: 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; break;
default: default:
goto pool32axf_invalid; goto pool32axf_invalid;
@ -13130,30 +13096,32 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
minor = (ctx->opcode >> 21) & 0x1f; minor = (ctx->opcode >> 21) & 0x1f;
switch (minor) { switch (minor) {
case BLTZ: case BLTZ:
mips32_op = OPC_BLTZ; gen_compute_branch(ctx, OPC_BLTZ, 4, rs, -1, imm << 1, 4);
goto do_branch; break;
case BLTZAL: case BLTZAL:
mips32_op = OPC_BLTZAL; gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 4);
goto do_branch; ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
break;
case BLTZALS: case BLTZALS:
mips32_op = OPC_BLTZALS; gen_compute_branch(ctx, OPC_BLTZAL, 4, rs, -1, imm << 1, 2);
goto do_branch; ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
break;
case BGEZ: case BGEZ:
mips32_op = OPC_BGEZ; gen_compute_branch(ctx, OPC_BGEZ, 4, rs, -1, imm << 1, 4);
goto do_branch; break;
case BGEZAL: case BGEZAL:
mips32_op = OPC_BGEZAL; gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 4);
goto do_branch; ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
break;
case BGEZALS: case BGEZALS:
mips32_op = OPC_BGEZALS; gen_compute_branch(ctx, OPC_BGEZAL, 4, rs, -1, imm << 1, 2);
goto do_branch; ctx->hflags |= MIPS_HFLAG_BDS_STRICT;
break;
case BLEZ: case BLEZ:
mips32_op = OPC_BLEZ; gen_compute_branch(ctx, OPC_BLEZ, 4, rs, -1, imm << 1, 4);
goto do_branch; break;
case BGTZ: case BGTZ:
mips32_op = OPC_BGTZ; gen_compute_branch(ctx, OPC_BGTZ, 4, rs, -1, imm << 1, 4);
do_branch:
gen_compute_branch(ctx, mips32_op, 4, rs, -1, imm << 1);
break; break;
/* Traps */ /* Traps */
@ -13181,7 +13149,7 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
case BNEZC: case BNEZC:
case BEQZC: case BEQZC:
gen_compute_branch(ctx, minor == BNEZC ? OPC_BNE : OPC_BEQ, 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 /* Compact branches don't have a delay slot, so just let
the normal delay slot handling take us to the branch the normal delay slot handling take us to the branch
target. */ target. */
@ -13322,25 +13290,28 @@ static void decode_micromips32_opc (CPUMIPSState *env, DisasContext *ctx,
break; break;
case JALX32: case JALX32:
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 2; 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; break;
case JALS32: case JALS32:
offset = (int32_t)(ctx->opcode & 0x3FFFFFF) << 1; 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; break;
case BEQ32: 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; break;
case BNE32: 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; break;
case J32: case J32:
gen_compute_branch(ctx, OPC_J, 4, rt, rs, gen_compute_branch(ctx, OPC_J, 4, rt, rs,
(int32_t)(ctx->opcode & 0x3FFFFFF) << 1); (int32_t)(ctx->opcode & 0x3FFFFFF) << 1, 4);
break; break;
case JAL32: case JAL32:
gen_compute_branch(ctx, OPC_JAL, 4, rt, rs, 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; break;
/* Floating point (COP1) */ /* Floating point (COP1) */
case LWC132: case LWC132:
@ -13424,84 +13395,41 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx)
op = (ctx->opcode >> 10) & 0x3f; op = (ctx->opcode >> 10) & 0x3f;
/* Enforce properly-sized instructions in a delay slot */ /* Enforce properly-sized instructions in a delay slot */
if (ctx->hflags & MIPS_HFLAG_BMASK) { if (ctx->hflags & MIPS_HFLAG_BDS_STRICT) {
int bits = ctx->hflags & MIPS_HFLAG_BMASK_EXT; switch (op & 0x7) { /* MSB-3..MSB-5 */
case 0:
switch (op) { /* POOL32A, POOL32B, POOL32I, POOL32C */
case POOL32A: case 4:
case POOL32B: /* ADDI32, ADDIU32, ORI32, XORI32, SLTI32, SLTIU32, ANDI32, JALX32 */
case POOL32I: case 5:
case POOL32C: /* LBU32, LHU32, POOL32F, JALS32, BEQ32, BNE32, J32, JAL32 */
case ADDI32: case 6:
case ADDIU32: /* SB32, SH32, ADDIUPC, SWC132, SDC132, SW32 */
case ORI32: case 7:
case XORI32: /* LB32, LH32, LWC132, LDC132, LW32 */
case SLTI32: if (ctx->hflags & MIPS_HFLAG_BDS16) {
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) {
generate_exception(ctx, EXCP_RI); generate_exception(ctx, EXCP_RI);
/* Just stop translation; the user is confused. */ /* Just stop translation; the user is confused. */
ctx->bstate = BS_STOP; ctx->bstate = BS_STOP;
return 2; return 2;
} }
break; break;
case POOL16A: case 1:
case POOL16B: /* POOL16A, POOL16B, POOL16C, LWGP16, POOL16F */
case POOL16C: case 2:
case LWGP16: /* LBU16, LHU16, LWSP16, LW16, SB16, SH16, SWSP16, SW16 */
case POOL16F: case 3:
case LBU16: /* MOVE16, ANDI16, POOL16D, POOL16E, BEQZ16, BNEZ16, B16, LI16 */
case LHU16: if (ctx->hflags & MIPS_HFLAG_BDS32) {
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) {
generate_exception(ctx, EXCP_RI); generate_exception(ctx, EXCP_RI);
/* Just stop translation; the user is confused. */ /* Just stop translation; the user is confused. */
ctx->bstate = BS_STOP; ctx->bstate = BS_STOP;
return 2; return 2;
} }
break; break;
default:
break;
} }
} }
switch (op) { switch (op) {
case POOL16A: case POOL16A:
{ {
@ -13682,13 +13610,13 @@ static int decode_micromips_opc (CPUMIPSState *env, DisasContext *ctx)
break; break;
case B16: case B16:
gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0, gen_compute_branch(ctx, OPC_BEQ, 2, 0, 0,
SIMM(ctx->opcode, 0, 10) << 1); SIMM(ctx->opcode, 0, 10) << 1, 4);
break; break;
case BNEZ16: case BNEZ16:
case BEQZ16: case BEQZ16:
gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2, gen_compute_branch(ctx, op == BNEZ16 ? OPC_BNE : OPC_BEQ, 2,
mmreg(uMIPS_RD(ctx->opcode)), mmreg(uMIPS_RD(ctx->opcode)),
0, SIMM(ctx->opcode, 0, 7) << 1); 0, SIMM(ctx->opcode, 0, 7) << 1, 4);
break; break;
case LI16: case LI16:
{ {
@ -15855,7 +15783,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
break; break;
#endif #endif
case OPC_JR: case OPC_JR:
gen_compute_branch(ctx, op1, 4, rs, rd, sa); gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4);
break; break;
case OPC_SPIM: case OPC_SPIM:
#ifdef MIPS_STRICT_STANDARD #ifdef MIPS_STRICT_STANDARD
@ -15940,7 +15868,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
gen_logic(ctx, op1, rd, rs, rt); gen_logic(ctx, op1, rd, rs, rt);
break; break;
case OPC_JALR: case OPC_JALR:
gen_compute_branch(ctx, op1, 4, rs, rd, sa); gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4);
break; break;
case OPC_TGE ... OPC_TEQ: /* Traps */ case OPC_TGE ... OPC_TEQ: /* Traps */
case OPC_TNE: case OPC_TNE:
@ -16909,19 +16837,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn_opc_removed(ctx, ISA_MIPS32R6);
case OPC_BLTZ: case OPC_BLTZ:
case OPC_BGEZ: case OPC_BGEZ:
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4);
break; break;
case OPC_BLTZAL: case OPC_BLTZAL:
case OPC_BGEZAL: case OPC_BGEZAL:
if (ctx->insn_flags & ISA_MIPS32R6) { if (ctx->insn_flags & ISA_MIPS32R6) {
if (rs == 0) { if (rs == 0) {
/* OPC_NAL, OPC_BAL */ /* OPC_NAL, OPC_BAL */
gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2); gen_compute_branch(ctx, op1, 4, 0, -1, imm << 2, 4);
} else { } else {
generate_exception(ctx, EXCP_RI); generate_exception(ctx, EXCP_RI);
} }
} else { } else {
gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2); gen_compute_branch(ctx, op1, 4, rs, -1, imm << 2, 4);
} }
break; break;
case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */ case OPC_TGEI ... OPC_TEQI: /* REGIMM traps */
@ -16940,7 +16868,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
case OPC_BPOSGE64: case OPC_BPOSGE64:
#endif #endif
check_dsp(ctx); 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; break;
#if defined(TARGET_MIPS64) #if defined(TARGET_MIPS64)
case OPC_DAHI: case OPC_DAHI:
@ -17079,7 +17007,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
break; break;
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, 4);
break; break;
/* Branch */ /* Branch */
case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */ case OPC_BLEZC: /* OPC_BGEZC, OPC_BGEC, OPC_BLEZL */
@ -17092,7 +17020,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
} else { } else {
/* OPC_BLEZL */ /* OPC_BLEZL */
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} }
break; break;
case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */ case OPC_BGTZC: /* OPC_BLTZC, OPC_BLTC, OPC_BGTZL */
@ -17105,13 +17033,13 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
gen_compute_compact_branch(ctx, op, rs, rt, imm << 2); gen_compute_compact_branch(ctx, op, rs, rt, imm << 2);
} else { } else {
/* OPC_BGTZL */ /* OPC_BGTZL */
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} }
break; break;
case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */ case OPC_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */
if (rt == 0) { if (rt == 0) {
/* OPC_BLEZ */ /* OPC_BLEZ */
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} else { } else {
check_insn(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS32R6);
/* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */ /* OPC_BLEZALC, OPC_BGEZALC, OPC_BGEUC */
@ -17121,7 +17049,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */ case OPC_BGTZALC: /* OPC_BLTZALC, OPC_BLTUC, OPC_BGTZ */
if (rt == 0) { if (rt == 0) {
/* OPC_BGTZ */ /* OPC_BGTZ */
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} else { } else {
check_insn(ctx, ISA_MIPS32R6); check_insn(ctx, ISA_MIPS32R6);
/* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */ /* OPC_BGTZALC, OPC_BLTZALC, OPC_BLTUC */
@ -17133,7 +17061,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6); check_insn_opc_removed(ctx, ISA_MIPS32R6);
case OPC_BEQ: case OPC_BEQ:
case OPC_BNE: case OPC_BNE:
gen_compute_branch(ctx, op, 4, rs, rt, imm << 2); gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
break; break;
case OPC_LWL: /* Load and stores */ case OPC_LWL: /* Load and stores */
case OPC_LWR: case OPC_LWR:
@ -17453,7 +17381,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
/* OPC_JALX */ /* OPC_JALX */
check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS); check_insn(ctx, ASE_MIPS16 | ASE_MICROMIPS);
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, 4);
} }
break; break;
case OPC_MDMX: case OPC_MDMX:
@ -17562,6 +17490,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
break; break;
} }
if (ctx.hflags & MIPS_HFLAG_BMASK) {
if (!(ctx.hflags & (MIPS_HFLAG_BDS16 | MIPS_HFLAG_BDS32))) {
is_delay = 1;
/* force to generate branch as no delay slot is required */
}
}
if (is_delay) { if (is_delay) {
gen_branch(&ctx, insn_bytes); gen_branch(&ctx, insn_bytes);
} }