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

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190904193059.26202-33-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
master
Richard Henderson 2019-09-04 12:30:22 -07:00 committed by Peter Maydell
parent b0e382b8cf
commit 360144f3b9
4 changed files with 123 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,47 +284,55 @@ 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.
{ {
YIELD 1111 0011 1010 1111 1000 0000 0000 0001 # Hints
WFE 1111 0011 1010 1111 1000 0000 0000 0010 {
WFI 1111 0011 1010 1111 1000 0000 0000 0011 YIELD 1111 0011 1010 1111 1000 0000 0000 0001
WFE 1111 0011 1010 1111 1000 0000 0000 0010
WFI 1111 0011 1010 1111 1000 0000 0000 0011
# TODO: Implement SEV, SEVL; may help SMP performance. # TODO: Implement SEV, SEVL; may help SMP performance.
# SEV 1111 0011 1010 1111 1000 0000 0000 0100 # SEV 1111 0011 1010 1111 1000 0000 0000 0100
# SEVL 1111 0011 1010 1111 1000 0000 0000 0101 # SEVL 1111 0011 1010 1111 1000 0000 0000 0101
# The canonical nop ends in 0000 0000, but the whole rest # The canonical nop ends in 0000 0000, but the whole rest
# of the space is "reserved hint, behaves as nop". # of the space is "reserved hint, behaves as nop".
NOP 1111 0011 1010 1111 1000 0000 ---- ---- NOP 1111 0011 1010 1111 1000 0000 ---- ----
} }
# Note that the v7m insn overlaps both the normal and banked insn. # Note that the v7m insn overlaps both the normal and banked insn.
{ {
MRS_bank 1111 0011 111 r:1 .... 1000 rd:4 001. 0000 \ MRS_bank 1111 0011 111 r:1 .... 1000 rd:4 001. 0000 \
&mrs_bank sysm=%mrs_sysm &mrs_bank sysm=%mrs_sysm
MRS_reg 1111 0011 111 r:1 1111 1000 rd:4 0000 0000 &mrs_reg MRS_reg 1111 0011 111 r:1 1111 1000 rd:4 0000 0000 &mrs_reg
MRS_v7m 1111 0011 111 0 1111 1000 rd:4 sysm:8 MRS_v7m 1111 0011 111 0 1111 1000 rd:4 sysm:8
} }
{ {
MSR_bank 1111 0011 100 r:1 rn:4 1000 .... 001. 0000 \ MSR_bank 1111 0011 100 r:1 rn:4 1000 .... 001. 0000 \
&msr_bank sysm=%msr_sysm &msr_bank sysm=%msr_sysm
MSR_reg 1111 0011 100 r:1 rn:4 1000 mask:4 0000 0000 &msr_reg MSR_reg 1111 0011 100 r:1 rn:4 1000 mask:4 0000 0000 &msr_reg
MSR_v7m 1111 0011 100 0 rn:4 1000 mask:2 00 sysm:8 MSR_v7m 1111 0011 100 0 rn:4 1000 mask:2 00 sysm:8
} }
BXJ 1111 0011 1100 rm:4 1000 1111 0000 0000 &r BXJ 1111 0011 1100 rm:4 1000 1111 0000 0000 &r
{ {
# At v6T2, this is the T5 encoding of SUBS PC, LR, #IMM, and works as for # At v6T2, this is the T5 encoding of SUBS PC, LR, #IMM, and works as for
# every other encoding of SUBS. With v7VE, IMM=0 is redefined as ERET. # every other encoding of SUBS. With v7VE, IMM=0 is redefined as ERET.
# The distinction between the two only matters for Hyp mode. # The distinction between the two only matters for Hyp mode.
ERET 1111 0011 1101 1110 1000 1111 0000 0000 ERET 1111 0011 1101 1110 1000 1111 0000 0000
SUB_rri 1111 0011 1101 1110 1000 1111 imm:8 \ SUB_rri 1111 0011 1101 1110 1000 1111 imm:8 \
&s_rri_rot rot=0 s=1 rd=15 rn=14 &s_rri_rot rot=0 s=1 rd=15 rn=14
} }
SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i SMC 1111 0111 1111 imm:4 1000 0000 0000 0000 &i
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

@ -7545,6 +7545,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.
*/ */
@ -10030,13 +10038,56 @@ 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)
{
tcg_gen_movi_i32(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)
{
/* 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(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.
*/ */
static void disas_arm_insn(DisasContext *s, unsigned int insn) static void disas_arm_insn(DisasContext *s, unsigned int insn)
{ {
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;
@ -10204,21 +10255,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_gen_movi_i32(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. */
@ -10310,23 +10346,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_gen_movi_i32(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:
@ -10693,32 +10716,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(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))
@ -10804,24 +10803,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 {
/* /*