This patch adds support for the SIMD load/store multiple (post-indexed) category of instructions.
Signed-off-by: Alexander Graf <[email protected]> --- target-arm/translate-a64.c | 91 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 91 insertions(+) diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index a0df55c..a864a90 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -748,6 +748,91 @@ static void handle_add(DisasContext *s, uint32_t insn) tcg_temp_free_i64(tcg_result); } +/* SIMD load/store multiple (post-indexed) */ +static void handle_simdldstm(DisasContext *s, uint32_t insn, bool is_wback) +{ + int rd = get_bits(insn, 0, 5); + int rn = get_bits(insn, 5, 5); + int rm = get_bits(insn, 16, 5); + int size = get_bits(insn, 10, 2); + int opcode = get_bits(insn, 12, 4); + bool is_store = !get_bits(insn, 22, 1); + bool is_q = get_bits(insn, 30, 1); + TCGv_i64 tcg_tmp = tcg_temp_new_i64(); + TCGv_i64 tcg_addr = tcg_temp_new_i64(); + int r, e, xs, tt, rpt, selem; + int ebytes = 1 << size; + int elements = (is_q ? 128 : 64) / (8 << size); + + tcg_gen_mov_i64(tcg_addr, cpu_reg_sp(rn)); + + switch (opcode) { + case 0x0: + rpt = 1; + selem = 4; + break; + case 0x2: + rpt = 4; + selem = 1; + break; + case 0x4: + rpt = 1; + selem = 3; + break; + case 0x6: + rpt = 3; + selem = 1; + break; + case 0x7: + rpt = 1; + selem = 1; + break; + case 0x8: + rpt = 1; + selem = 2; + break; + case 0xa: + rpt = 2; + selem = 1; + break; + default: + unallocated_encoding(s); + return; + } + + if (size == 3 && !is_q && selem != 1) { + /* reserved */ + unallocated_encoding(s); + } + + /* XXX check SP alignment on Rn */ + + for (r = 0; r < rpt; r++) { + for (e = 0; e < elements; e++) { + tt = (rd + r) % 32; + for (xs = 0; xs < selem; xs++) { + int freg_offs = offsetof(CPUARMState, vfp.regs[tt * 2]) + + (e * ebytes); + + ldst_do_vec_int(s, freg_offs, tcg_addr, size, is_store); + tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes); + tt = (tt + 1) % 32; + } + } + } + + if (is_wback) { + if (rm == 31) { + tcg_gen_mov_i64(cpu_reg_sp(rn), tcg_addr); + } else { + tcg_gen_add_i64(cpu_reg_sp(rn), cpu_reg(rn), cpu_reg(rm)); + } + } + + tcg_temp_free_i64(tcg_tmp); + tcg_temp_free_i64(tcg_addr); +} + void disas_a64_insn(CPUARMState *env, DisasContext *s) { uint32_t insn; @@ -789,6 +874,12 @@ void disas_a64_insn(CPUARMState *env, DisasContext *s) case 0x0c: if (get_bits(insn, 29, 1)) { handle_stp(s, insn); + } else if (!get_bits(insn, 31, 1) && get_bits(insn, 23, 1) && + !get_bits(insn, 21, 1)) { + handle_simdldstm(s, insn, true); + } else if (!get_bits(insn, 31, 1) && !get_bits(insn, 29, 1) && + !get_bits(insn, 23, 1) && !get_bits(insn, 16, 6)) { + handle_simdldstm(s, insn, false); } else { unallocated_encoding(s); } -- 1.7.12.4
