target/arm: Convert T16, long branches
Reviewed-by: Peter Maydell <peter.maydell@linaro.org> Signed-off-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20190904193059.26202-68-richard.henderson@linaro.org Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
parent
8d4a4dc849
commit
67b54c554b
|
@ -272,3 +272,10 @@ LDM_t16 1011 110 ......... \
|
|||
%imm11_0x2 0:s11 !function=times_2
|
||||
|
||||
B 11100 ........... &i imm=%imm11_0x2
|
||||
|
||||
# thumb_insn_is_16bit() ensures we won't be decoding these as
|
||||
# T16 instructions for a Thumb2 CPU, so these patterns must be
|
||||
# a Thumb1 split BL/BLX.
|
||||
BLX_suffix 11101 imm:11 &i
|
||||
BL_BLX_prefix 11110 imm:s11 &i
|
||||
BL_suffix 11111 imm:11 &i
|
||||
|
|
|
@ -10147,6 +10147,40 @@ static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool trans_BL_BLX_prefix(DisasContext *s, arg_BL_BLX_prefix *a)
|
||||
{
|
||||
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
||||
tcg_gen_movi_i32(cpu_R[14], read_pc(s) + (a->imm << 12));
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_BL_suffix(DisasContext *s, arg_BL_suffix *a)
|
||||
{
|
||||
TCGv_i32 tmp = tcg_temp_new_i32();
|
||||
|
||||
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
||||
tcg_gen_addi_i32(tmp, cpu_R[14], (a->imm << 1) | 1);
|
||||
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
|
||||
gen_bx(s, tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool trans_BLX_suffix(DisasContext *s, arg_BLX_suffix *a)
|
||||
{
|
||||
TCGv_i32 tmp;
|
||||
|
||||
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
||||
if (!ENABLE_ARCH_5) {
|
||||
return false;
|
||||
}
|
||||
tmp = tcg_temp_new_i32();
|
||||
tcg_gen_addi_i32(tmp, cpu_R[14], a->imm << 1);
|
||||
tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
|
||||
tcg_gen_movi_i32(cpu_R[14], s->base.pc_next | 1);
|
||||
gen_bx(s, tmp);
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool op_tbranch(DisasContext *s, arg_tbranch *a, bool half)
|
||||
{
|
||||
TCGv_i32 addr, tmp;
|
||||
|
@ -10736,10 +10770,6 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
|
|||
|
||||
static void disas_thumb_insn(DisasContext *s, uint32_t insn)
|
||||
{
|
||||
int32_t offset;
|
||||
TCGv_i32 tmp;
|
||||
TCGv_i32 tmp2;
|
||||
|
||||
if (disas_t16(s, insn)) {
|
||||
return;
|
||||
}
|
||||
|
@ -10758,53 +10788,10 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
|
|||
case 11: /* misc, in decodetree */
|
||||
case 12: /* load/store multiple, in decodetree */
|
||||
case 13: /* conditional branch or swi, in decodetree */
|
||||
goto illegal_op;
|
||||
|
||||
case 14:
|
||||
if (insn & (1 << 11)) {
|
||||
/* thumb_insn_is_16bit() ensures we can't get here for
|
||||
* a Thumb2 CPU, so this must be a thumb1 split BL/BLX:
|
||||
* 0b1110_1xxx_xxxx_xxxx : BLX suffix (or UNDEF)
|
||||
*/
|
||||
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
||||
ARCH(5);
|
||||
offset = ((insn & 0x7ff) << 1);
|
||||
tmp = load_reg(s, 14);
|
||||
tcg_gen_addi_i32(tmp, tmp, offset);
|
||||
tcg_gen_andi_i32(tmp, tmp, 0xfffffffc);
|
||||
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
|
||||
store_reg(s, 14, tmp2);
|
||||
gen_bx(s, tmp);
|
||||
break;
|
||||
}
|
||||
/* unconditional branch, in decodetree */
|
||||
goto illegal_op;
|
||||
|
||||
case 15:
|
||||
/* thumb_insn_is_16bit() ensures we can't get here for
|
||||
* a Thumb2 CPU, so this must be a thumb1 split BL/BLX.
|
||||
*/
|
||||
assert(!arm_dc_feature(s, ARM_FEATURE_THUMB2));
|
||||
|
||||
if (insn & (1 << 11)) {
|
||||
/* 0b1111_1xxx_xxxx_xxxx : BL suffix */
|
||||
offset = ((insn & 0x7ff) << 1) | 1;
|
||||
tmp = load_reg(s, 14);
|
||||
tcg_gen_addi_i32(tmp, tmp, offset);
|
||||
|
||||
tmp2 = tcg_temp_new_i32();
|
||||
tcg_gen_movi_i32(tmp2, s->base.pc_next | 1);
|
||||
store_reg(s, 14, tmp2);
|
||||
gen_bx(s, tmp);
|
||||
} else {
|
||||
/* 0b1111_0xxx_xxxx_xxxx : BL/BLX prefix */
|
||||
uint32_t uoffset = ((int32_t)insn << 21) >> 9;
|
||||
|
||||
tcg_gen_movi_i32(cpu_R[14], read_pc(s) + uoffset);
|
||||
}
|
||||
break;
|
||||
/* branches, in decodetree */
|
||||
goto illegal_op;
|
||||
}
|
||||
return;
|
||||
illegal_op:
|
||||
|
|
Loading…
Reference in a new issue