Commit 67b54c55 authored by Richard Henderson's avatar Richard Henderson Committed by Peter Maydell
Browse files

target/arm: Convert T16, long branches



Reviewed-by: default avatarPeter Maydell <peter.maydell@linaro.org>
Signed-off-by: default avatarRichard Henderson <richard.henderson@linaro.org>
Message-id: 20190904193059.26202-68-richard.henderson@linaro.org
Signed-off-by: default avatarPeter Maydell <peter.maydell@linaro.org>
parent 8d4a4dc8
Loading
Loading
Loading
Loading
+7 −0
Original line number Diff line number Diff line
@@ -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
+36 −49
Original line number Diff line number Diff line
@@ -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: