aboutsummaryrefslogtreecommitdiff
path: root/target-mips
diff options
context:
space:
mode:
authorYongbok Kim <yongbok.kim@imgtec.com>2014-07-01 17:43:05 +0100
committerLeon Alrae <leon.alrae@imgtec.com>2014-10-14 13:29:14 +0100
commitb231c103afced2eb27af9b6a771ab4b250afb93f (patch)
treee8219a3252ed2746beabc1bb96b865269b88b0e1 /target-mips
parenta83bddd60de0dfdbc04c6683c2701682073af5cf (diff)
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>
Diffstat (limited to 'target-mips')
-rw-r--r--target-mips/cpu.h13
-rw-r--r--target-mips/translate.c298
2 files changed, 123 insertions, 188 deletions
diff --git a/target-mips/cpu.h b/target-mips/cpu.h
index 51a83318bd..26e7894eaf 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 7b9e8cd374..8b62e66ca6 100644
--- a/target-mips/translate.c
+++ b/target-mips/translate.c
@@ -65,7 +65,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),
@@ -74,9 +73,8 @@ enum {
OPC_BLEZL = (0x16 << 26),
OPC_BGTZ = (0x07 << 26),
OPC_BGTZL = (0x17 << 26),
- OPC_JALX = (0x1D << 26), /* MIPS 16 only */
+ OPC_JALX = (0x1D << 26),
OPC_DAUI = (0x1D << 26),
- OPC_JALXS = OPC_JALX | 0x5,
/* Load and stores */
OPC_LDL = (0x1A << 26),
OPC_LDR = (0x1B << 26),
@@ -219,8 +217,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,
@@ -317,10 +313,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,
@@ -4137,7 +4131,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;
@@ -4169,7 +4164,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:
@@ -4178,7 +4172,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 */
@@ -4201,15 +4194,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
@@ -4238,12 +4227,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;
@@ -4255,15 +4240,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;
@@ -4284,33 +4265,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:
@@ -4348,11 +4317,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;
@@ -4396,11 +4361,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);
@@ -4424,13 +4385,20 @@ 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 post_delay = insn_bytes + delayslot_size;
int lowbit = !!(ctx->hflags & MIPS_HFLAG_M16);
- if (opc != OPC_JALRC)
- post_delay += ((ctx->hflags & MIPS_HFLAG_BDS16) ? 2 : 4);
-
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,
ctx->hflags, btarget);
ctx->btarget = btarget;
-
+ ctx->hflags |= MIPS_HFLAG_BDS32;
out:
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);
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:
@@ -10732,10 +10700,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);
@@ -10863,7 +10831,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:
@@ -10871,16 +10839,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:
@@ -10953,11 +10923,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);
@@ -11106,12 +11076,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:
@@ -11869,7 +11840,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:
@@ -11925,32 +11895,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:
@@ -11978,8 +11943,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. */
@@ -12236,11 +12200,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;
@@ -13130,30 +13096,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 */
@@ -13181,7 +13149,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. */
@@ -13322,25 +13290,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:
@@ -13424,84 +13395,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:
+ /* POOL32A, 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:
{
@@ -13682,13 +13610,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:
{
@@ -15855,7 +15783,7 @@ static void decode_opc_special_legacy(CPUMIPSState *env, DisasContext *ctx)
break;
#endif
case OPC_JR:
- gen_compute_branch(ctx, op1, 4, rs, rd, sa);
+ gen_compute_branch(ctx, op1, 4, rs, rd, sa, 4);
break;
case OPC_SPIM:
#ifdef MIPS_STRICT_STANDARD
@@ -15940,7 +15868,7 @@ static void decode_opc_special(CPUMIPSState *env, DisasContext *ctx)
gen_logic(ctx, op1, rd, rs, rt);
break;
case 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:
@@ -16909,19 +16837,19 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
check_insn_opc_removed(ctx, ISA_MIPS32R6);
case OPC_BLTZ:
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;
case OPC_BLTZAL:
case OPC_BGEZAL:
if (ctx->insn_flags & ISA_MIPS32R6) {
if (rs == 0) {
/* 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 {
generate_exception(ctx, EXCP_RI);
}
} else {
- 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 */
@@ -16940,7 +16868,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;
#if defined(TARGET_MIPS64)
case OPC_DAHI:
@@ -17079,7 +17007,7 @@ 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;
/* Branch */
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);
} else {
/* OPC_BLEZL */
- gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+ gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
}
break;
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);
} else {
/* 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_BLEZALC: /* OPC_BGEZALC, OPC_BGEUC, OPC_BLEZ */
if (rt == 0) {
/* OPC_BLEZ */
- gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+ gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} else {
check_insn(ctx, ISA_MIPS32R6);
/* 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 */
if (rt == 0) {
/* OPC_BGTZ */
- gen_compute_branch(ctx, op, 4, rs, rt, imm << 2);
+ gen_compute_branch(ctx, op, 4, rs, rt, imm << 2, 4);
} else {
check_insn(ctx, ISA_MIPS32R6);
/* 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);
case OPC_BEQ:
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;
case OPC_LWL: /* Load and stores */
case OPC_LWR:
@@ -17453,7 +17381,7 @@ static void decode_opc (CPUMIPSState *env, DisasContext *ctx)
/* 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:
@@ -17562,6 +17490,12 @@ gen_intermediate_code_internal(MIPSCPU *cpu, TranslationBlock *tb,
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) {
gen_branch(&ctx, insn_bytes);
}