mirror of
https://github.com/yuzu-emu/unicorn.git
synced 2024-12-23 13:15:31 +00:00
target/arm: Convert T16, push and pop
Backports commit 564b125fb9dec77e5bca9b4590786985ccc3d6cb from qemu
This commit is contained in:
parent
25d1de9005
commit
336d6b3625
|
@ -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
|
||||
|
|
|
@ -7665,6 +7665,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.
|
||||
*/
|
||||
|
@ -11066,7 +11076,6 @@ static void disas_thumb_insn(DisasContext *s, uint32_t insn)
|
|||
TCGContext *tcg_ctx = s->uc->tcg_ctx;
|
||||
uint32_t val, op, rm, rd, shift, cond;
|
||||
int32_t offset;
|
||||
int i;
|
||||
TCGv_i32 tmp;
|
||||
TCGv_i32 tmp2;
|
||||
TCGv_i32 addr;
|
||||
|
@ -11140,76 +11149,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(tcg_ctx, 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(tcg_ctx, tcg_ctx->cpu_env, addr);
|
||||
}
|
||||
|
||||
for (i = 0; i < 8; i++) {
|
||||
if (insn & (1 << i)) {
|
||||
if (insn & (1 << 11)) {
|
||||
/* pop */
|
||||
tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
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(tcg_ctx, tmp);
|
||||
}
|
||||
/* advance to the next address. */
|
||||
tcg_gen_addi_i32(tcg_ctx, addr, addr, 4);
|
||||
}
|
||||
}
|
||||
tmp = NULL;
|
||||
if (insn & (1 << 8)) {
|
||||
if (insn & (1 << 11)) {
|
||||
/* pop pc */
|
||||
tmp = tcg_temp_new_i32(tcg_ctx);
|
||||
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(tcg_ctx, tmp);
|
||||
}
|
||||
tcg_gen_addi_i32(tcg_ctx, addr, addr, 4);
|
||||
}
|
||||
if ((insn & (1 << 11)) == 0) {
|
||||
tcg_gen_addi_i32(tcg_ctx, 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;
|
||||
|
|
Loading…
Reference in a new issue