target/arm: Convert B, BL, BLX (immediate)

Backports commit 360144f3b99f9a626ffcc6b9d76537e3a3e0e708 from qemu
This commit is contained in:
Richard Henderson 2019-11-20 11:27:43 -05:00 committed by Lioncash
parent ed9b8ad2ea
commit a119870e57
No known key found for this signature in database
GPG key ID: 4E3C3CC1031BA9C7
4 changed files with 125 additions and 107 deletions

View file

@ -21,3 +21,11 @@
# All insns that have 0xf in insn[31:28] are decoded here. # All insns that have 0xf in insn[31:28] are decoded here.
# All of those that have a COND field in insn[31:28] are in a32.decode # All of those that have a COND field in insn[31:28] are in a32.decode
# #
&i !extern imm
# Branch with Link and Exchange
%imm24h 0:s24 24:1 !function=times_2
BLX_i 1111 101 . ........................ &i imm=%imm24h

View file

@ -520,3 +520,11 @@ SMMLSR .... 0111 0101 .... .... .... 1111 .... @rdamn
STM ---- 100 b:1 i:1 u:1 w:1 0 rn:4 list:16 &ldst_block STM ---- 100 b:1 i:1 u:1 w:1 0 rn:4 list:16 &ldst_block
LDM_a32 ---- 100 b:1 i:1 u:1 w:1 1 rn:4 list:16 &ldst_block LDM_a32 ---- 100 b:1 i:1 u:1 w:1 1 rn:4 list:16 &ldst_block
# Branch, branch with link
%imm26 0:s24 !function=times_4
@branch ---- .... ........................ &i imm=%imm26
B .... 1010 ........................ @branch
BL .... 1011 ........................ @branch

View file

@ -284,8 +284,14 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
%msr_sysm 4:1 8:4 %msr_sysm 4:1 8:4
%mrs_sysm 4:1 16:4 %mrs_sysm 4:1 16:4
%imm16_16_0 16:4 0:12 %imm16_16_0 16:4 0:12
%imm21 26:s1 11:1 13:1 16:6 0:11 !function=times_2
&ci cond imm
{ {
# Group insn[25:23] = 111, which is cond=111x for the branch below,
# or unconditional, which would be illegal for the branch.
{
# Hints
{ {
YIELD 1111 0011 1010 1111 1000 0000 0000 0001 YIELD 1111 0011 1010 1111 1000 0000 0000 0001
WFE 1111 0011 1010 1111 1000 0000 0000 0010 WFE 1111 0011 1010 1111 1000 0000 0000 0010
@ -325,6 +331,8 @@ CLZ 1111 1010 1011 ---- 1111 .... 1000 .... @rdm
HVC 1111 0111 1110 .... 1000 .... .... .... \ HVC 1111 0111 1110 .... 1000 .... .... .... \
&i imm=%imm16_16_0 &i imm=%imm16_16_0
UDF 1111 0111 1111 ---- 1010 ---- ---- ---- UDF 1111 0111 1111 ---- 1010 ---- ---- ----
}
B_cond_thumb 1111 0. cond:4 ...... 10.0 ............ &ci imm=%imm21
} }
# Load/store (register, immediate, literal) # Load/store (register, immediate, literal)
@ -573,3 +581,12 @@ STM_t32 1110 1000 10.0 .... ................ @ldstm i=1 b=0
STM_t32 1110 1001 00.0 .... ................ @ldstm i=0 b=1 STM_t32 1110 1001 00.0 .... ................ @ldstm i=0 b=1
LDM_t32 1110 1000 10.1 .... ................ @ldstm i=1 b=0 LDM_t32 1110 1000 10.1 .... ................ @ldstm i=1 b=0
LDM_t32 1110 1001 00.1 .... ................ @ldstm i=0 b=1 LDM_t32 1110 1001 00.1 .... ................ @ldstm i=0 b=1
# Branches
%imm24 26:s1 13:1 11:1 16:10 0:11 !function=t32_branch24
@branch24 ................................ &i imm=%imm24
B 1111 0. .......... 10.1 ............ @branch24
BL 1111 0. .......... 11.1 ............ @branch24
BLX_i 1111 0. .......... 11.0 ............ @branch24

View file

@ -7695,6 +7695,14 @@ static int t32_expandimm_imm(DisasContext *s, int x)
return imm; return imm;
} }
static int t32_branch24(DisasContext *s, int x)
{
/* Convert J1:J2 at x[22:21] to I2:I1, which involves I=J^~S. */
x ^= !(x < 0) * (3 << 21);
/* Append the final zero. */
return x << 1;
}
/* /*
* Include the generated decoders. * Include the generated decoders.
*/ */
@ -10364,6 +10372,51 @@ static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a)
return do_ldm(s, a, 2); return do_ldm(s, a, 2);
} }
/*
* Branch, branch with link
*/
static bool trans_B(DisasContext *s, arg_i *a)
{
gen_jmp(s, read_pc(s) + a->imm);
return true;
}
static bool trans_B_cond_thumb(DisasContext *s, arg_ci *a)
{
/* This has cond from encoding, required to be outside IT block. */
if (a->cond >= 0xe) {
return false;
}
if (s->condexec_mask) {
unallocated_encoding(s);
return true;
}
arm_skip_unless(s, a->cond);
gen_jmp(s, read_pc(s) + a->imm);
return true;
}
static bool trans_BL(DisasContext *s, arg_i *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], s->base.pc_next | s->thumb);
gen_jmp(s, read_pc(s) + a->imm);
return true;
}
static bool trans_BLX_i(DisasContext *s, arg_BLX_i *a)
{
TCGContext *tcg_ctx = s->uc->tcg_ctx;
/* For A32, ARCH(5) is checked near the start of the uncond block. */
if (s->thumb && (a->imm & 2)) {
return false;
}
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], s->base.pc_next | s->thumb);
gen_bx_im(s, (read_pc(s) & ~3) + a->imm + !s->thumb);
return true;
}
/* /*
* Legacy decoder. * Legacy decoder.
*/ */
@ -10371,7 +10424,7 @@ static bool trans_LDM_t32(DisasContext *s, arg_ldst_block *a)
static void disas_arm_insn(DisasContext *s, unsigned int insn) static void disas_arm_insn(DisasContext *s, unsigned int insn)
{ {
TCGContext *tcg_ctx = s->uc->tcg_ctx; TCGContext *tcg_ctx = s->uc->tcg_ctx;
unsigned int cond, val, op1, i, rn; unsigned int cond, op1, i, rn;
TCGv_i32 tmp; TCGv_i32 tmp;
TCGv_i32 tmp2; TCGv_i32 tmp2;
TCGv_i32 addr; TCGv_i32 addr;
@ -10547,21 +10600,6 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
} }
gen_rfe(s, tmp, tmp2); gen_rfe(s, tmp, tmp2);
return; return;
} else if ((insn & 0x0e000000) == 0x0a000000) {
/* branch link and change to thumb (blx <offset>) */
int32_t offset;
tmp = tcg_temp_new_i32(tcg_ctx);
tcg_gen_movi_i32(tcg_ctx, tmp, s->base.pc_next);
store_reg(s, 14, tmp);
/* Sign-extend the 24-bit offset */
offset = (((int32_t)insn) << 8) >> 8;
val = read_pc(s);
/* offset * 4 + bit24 * 2 + (thumb bit) */
val += (offset << 2) | ((insn >> 23) & 2) | 1;
/* protected by ARCH(5); above, near the start of uncond block */
gen_bx_im(s, val);
return;
} else if ((insn & 0x0e000f00) == 0x0c000100) { } else if ((insn & 0x0e000f00) == 0x0c000100) {
if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) { if (arm_dc_feature(s, ARM_FEATURE_IWMMXT)) {
/* iWMMXt register transfer. */ /* iWMMXt register transfer. */
@ -10655,23 +10693,10 @@ static void disas_arm_insn(DisasContext *s, unsigned int insn)
case 0x7: case 0x7:
case 0x08: case 0x08:
case 0x09: case 0x09:
/* All done in decodetree. Reach here for illegal ops. */
goto illegal_op;
case 0xa: case 0xa:
case 0xb: case 0xb:
{ /* All done in decodetree. Reach here for illegal ops. */
int32_t offset; goto illegal_op;
/* branch (and link) */
if (insn & (1 << 24)) {
tmp = tcg_temp_new_i32(tcg_ctx);
tcg_gen_movi_i32(tcg_ctx, tmp, s->base.pc_next);
store_reg(s, 14, tmp);
}
offset = sextract32(insn << 2, 0, 26);
gen_jmp(s, read_pc(s) + offset);
}
break;
case 0xc: case 0xc:
case 0xd: case 0xd:
case 0xe: case 0xe:
@ -11040,32 +11065,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
if (insn & (1 << 15)) { if (insn & (1 << 15)) {
/* Branches, misc control. */ /* Branches, misc control. */
if (insn & 0x5000) { if (insn & 0x5000) {
/* Unconditional branch. */ /* Unconditional branch, in decodetree */
/* signextend(hw1[10:0]) -> offset[:12]. */ goto illegal_op;
offset = ((int32_t)insn << 5) >> 9 & ~(int32_t)0xfff;
/* hw1[10:0] -> offset[11:1]. */
offset |= (insn & 0x7ff) << 1;
/* (~hw2[13, 11] ^ offset[24]) -> offset[23,22]
offset[24:22] already have the same value because of the
sign extension above. */
offset ^= ((~insn) & (1 << 13)) << 10;
offset ^= ((~insn) & (1 << 11)) << 11;
if (insn & (1 << 14)) {
/* Branch and link. */
tcg_gen_movi_i32(tcg_ctx, tcg_ctx->cpu_R[14], s->base.pc_next | 1);
}
offset += read_pc(s);
if (insn & (1 << 12)) {
/* b/bl */
gen_jmp(s, offset);
} else {
/* blx */
offset &= ~(uint32_t)2;
/* thumb2 bx, no need to check */
gen_bx_im(s, offset);
}
} else if (((insn >> 23) & 7) == 7) { } else if (((insn >> 23) & 7) == 7) {
/* Misc control */ /* Misc control */
if (insn & (1 << 13)) if (insn & (1 << 13))
@ -11151,24 +11152,8 @@ static void disas_thumb2_insn(DisasContext *s, uint32_t insn)
} }
} }
} else { } else {
/* Conditional branch. */ /* Conditional branch, in decodetree */
op = (insn >> 22) & 0xf; goto illegal_op;
/* Generate a conditional jump to next instruction. */
arm_skip_unless(s, op);
/* offset[11:1] = insn[10:0] */
offset = (insn & 0x7ff) << 1;
/* offset[17:12] = insn[21:16]. */
offset |= (insn & 0x003f0000) >> 4;
/* offset[31:20] = insn[26]. */
offset |= ((int32_t)((insn << 5) & 0x80000000)) >> 11;
/* offset[18] = insn[13]. */
offset |= (insn & (1 << 13)) << 5;
/* offset[19] = insn[11]. */
offset |= (insn & (1 << 11)) << 8;
/* jump to the offset */
gen_jmp(s, read_pc(s) + offset);
} }
} else { } else {
/* /*