target/arm: Convert T16, push and pop

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Message-id: 20190904193059.26202-62-richard.henderson@linaro.org
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
This commit is contained in:
Richard Henderson 2019-09-04 12:30:51 -07:00 committed by Peter Maydell
parent 279de61a21
commit 564b125fb9
2 changed files with 22 additions and 71 deletions

View file

@ -221,3 +221,13 @@ REVSH 1011 1010 11 ... ... @rdm
# rest of the space is a reserved hint, behaves as nop.
NOP 1011 1111 ---- 0000
}
# Push and Pop
%push_list 0:9 !function=t16_push_list
%pop_list 0:9 !function=t16_pop_list
STM 1011 010 ......... \
&ldst_block i=0 b=1 u=0 w=1 rn=13 list=%push_list
LDM_t16 1011 110 ......... \
&ldst_block i=1 b=0 u=0 w=1 rn=13 list=%pop_list

View file

@ -7516,6 +7516,16 @@ static int t16_setflags(DisasContext *s)
return s->condexec_mask == 0;
}
static int t16_push_list(DisasContext *s, int x)
{
return (x & 0xff) | (x & 0x100) << (14 - 8);
}
static int t16_pop_list(DisasContext *s, int x)
{
return (x & 0xff) | (x & 0x100) << (15 - 8);
}
/*
* Include the generated decoders.
*/
@ -10713,7 +10723,6 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
{
uint32_t val, op, rm, rd, shift, cond;
int32_t offset;
int i;
TCGv_i32 tmp;
TCGv_i32 tmp2;
TCGv_i32 addr;
@ -10786,76 +10795,8 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
goto illegal_op;
case 4: case 5: case 0xc: case 0xd:
/*
* 0b1011_x10x_xxxx_xxxx
* - push/pop
*/
addr = load_reg(s, 13);
if (insn & (1 << 8))
offset = 4;
else
offset = 0;
for (i = 0; i < 8; i++) {
if (insn & (1 << i))
offset += 4;
}
if ((insn & (1 << 11)) == 0) {
tcg_gen_addi_i32(addr, addr, -offset);
}
if (s->v8m_stackcheck) {
/*
* Here 'addr' is the lower of "old SP" and "new SP";
* if this is a pop that starts below the limit and ends
* above it, it is UNKNOWN whether the limit check triggers;
* we choose to trigger.
*/
gen_helper_v8m_stackcheck(cpu_env, addr);
}
for (i = 0; i < 8; i++) {
if (insn & (1 << i)) {
if (insn & (1 << 11)) {
/* pop */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
store_reg(s, i, tmp);
} else {
/* push */
tmp = load_reg(s, i);
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
tcg_temp_free_i32(tmp);
}
/* advance to the next address. */
tcg_gen_addi_i32(addr, addr, 4);
}
}
tmp = NULL;
if (insn & (1 << 8)) {
if (insn & (1 << 11)) {
/* pop pc */
tmp = tcg_temp_new_i32();
gen_aa32_ld32u(s, tmp, addr, get_mem_index(s));
/* don't set the pc until the rest of the instruction
has completed */
} else {
/* push lr */
tmp = load_reg(s, 14);
gen_aa32_st32(s, tmp, addr, get_mem_index(s));
tcg_temp_free_i32(tmp);
}
tcg_gen_addi_i32(addr, addr, 4);
}
if ((insn & (1 << 11)) == 0) {
tcg_gen_addi_i32(addr, addr, -offset);
}
/* write back the new stack pointer */
store_reg(s, 13, addr);
/* set the new PC value */
if ((insn & 0x0900) == 0x0900) {
store_reg_from_load(s, 15, tmp);
}
break;
/* push/pop, in decodetree */
goto illegal_op;
case 1: case 3: case 9: case 11: /* czb */
rm = insn & 7;