From: Peter Maydell <peter.maydell@linaro.org>
To: Anthony Liguori <aliguori@amazon.com>
Cc: Blue Swirl <blauwirbel@gmail.com>,
qemu-devel@nongnu.org, Aurelien Jarno <aurelien@aurel32.net>
Subject: [Qemu-devel] [PULL 01/38] target-arm: A64: Add SIMD ld/st multiple
Date: Wed, 29 Jan 2014 13:39:28 +0000 [thread overview]
Message-ID: <1391002805-26596-2-git-send-email-peter.maydell@linaro.org> (raw)
In-Reply-To: <1391002805-26596-1-git-send-email-peter.maydell@linaro.org>
From: Alex Bennée <alex.bennee@linaro.org>
This adds support support for the SIMD load/store
multiple category of instructions.
This also brings in a couple of helper functions for manipulating
sections of the SIMD registers:
* do_vec_get - fetch value from a slice of a vector register
* do_vec_set - set a slice of a vector register
which use vec_reg_offset for consistent processing of offsets in an
endian aware manner. There are also additional helpers:
* do_vec_ld - load value into SIMD
* do_vec_st - store value from SIMD
which load or store a slice of a vector register to memory.
These don't zero extend like the fp variants.
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
target-arm/translate-a64.c | 250 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 248 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index cf80c46..e4fdf00 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -308,6 +308,28 @@ static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
return v;
}
+/* Return the offset into CPUARMState of an element of specified
+ * size, 'element' places in from the least significant end of
+ * the FP/vector register Qn.
+ */
+static inline int vec_reg_offset(int regno, int element, TCGMemOp size)
+{
+ int offs = offsetof(CPUARMState, vfp.regs[regno * 2]);
+#ifdef HOST_WORDS_BIGENDIAN
+ /* This is complicated slightly because vfp.regs[2n] is
+ * still the low half and vfp.regs[2n+1] the high half
+ * of the 128 bit vector, even on big endian systems.
+ * Calculate the offset assuming a fully bigendian 128 bits,
+ * then XOR to account for the order of the two 64 bit halves.
+ */
+ offs += (16 - ((element + 1) * (1 << size)));
+ offs ^= 8;
+#else
+ offs += element * (1 << size);
+#endif
+ return offs;
+}
+
/* Return the offset into CPUARMState of a slice (from
* the least significant end) of FP register Qn (ie
* Dn, Sn, Hn or Bn).
@@ -661,6 +683,108 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
}
/*
+ * Vector load/store helpers.
+ *
+ * The principal difference between this and a FP load is that we don't
+ * zero extend as we are filling a partial chunk of the vector register.
+ * These functions don't support 128 bit loads/stores, which would be
+ * normal load/store operations.
+ */
+
+/* Get value of an element within a vector register */
+static void read_vec_element(DisasContext *s, TCGv_i64 tcg_dest, int srcidx,
+ int element, TCGMemOp memop)
+{
+ int vect_off = vec_reg_offset(srcidx, element, memop & MO_SIZE);
+ switch (memop) {
+ case MO_8:
+ tcg_gen_ld8u_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_16:
+ tcg_gen_ld16u_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_32:
+ tcg_gen_ld32u_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_8|MO_SIGN:
+ tcg_gen_ld8s_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_16|MO_SIGN:
+ tcg_gen_ld16s_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_32|MO_SIGN:
+ tcg_gen_ld32s_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ case MO_64:
+ case MO_64|MO_SIGN:
+ tcg_gen_ld_i64(tcg_dest, cpu_env, vect_off);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+/* Set value of an element within a vector register */
+static void write_vec_element(DisasContext *s, TCGv_i64 tcg_src, int destidx,
+ int element, TCGMemOp memop)
+{
+ int vect_off = vec_reg_offset(destidx, element, memop & MO_SIZE);
+ switch (memop) {
+ case MO_8:
+ tcg_gen_st8_i64(tcg_src, cpu_env, vect_off);
+ break;
+ case MO_16:
+ tcg_gen_st16_i64(tcg_src, cpu_env, vect_off);
+ break;
+ case MO_32:
+ tcg_gen_st32_i64(tcg_src, cpu_env, vect_off);
+ break;
+ case MO_64:
+ tcg_gen_st_i64(tcg_src, cpu_env, vect_off);
+ break;
+ default:
+ g_assert_not_reached();
+ }
+}
+
+/* Clear the high 64 bits of a 128 bit vector (in general non-quad
+ * vector ops all need to do this).
+ */
+static void clear_vec_high(DisasContext *s, int rd)
+{
+ TCGv_i64 tcg_zero = tcg_const_i64(0);
+
+ write_vec_element(s, tcg_zero, rd, 1, MO_64);
+ tcg_temp_free_i64(tcg_zero);
+}
+
+/* Store from vector register to memory */
+static void do_vec_st(DisasContext *s, int srcidx, int element,
+ TCGv_i64 tcg_addr, int size)
+{
+ TCGMemOp memop = MO_TE + size;
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+
+ read_vec_element(s, tcg_tmp, srcidx, element, size);
+ tcg_gen_qemu_st_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
+
+ tcg_temp_free_i64(tcg_tmp);
+}
+
+/* Load from memory to vector register */
+static void do_vec_ld(DisasContext *s, int destidx, int element,
+ TCGv_i64 tcg_addr, int size)
+{
+ TCGMemOp memop = MO_TE + size;
+ TCGv_i64 tcg_tmp = tcg_temp_new_i64();
+
+ tcg_gen_qemu_ld_i64(tcg_tmp, tcg_addr, get_mem_index(s), memop);
+ write_vec_element(s, tcg_tmp, destidx, element, size);
+
+ tcg_temp_free_i64(tcg_tmp);
+}
+
+/*
* This utility function is for doing register extension with an
* optional shift. You will likely want to pass a temporary for the
* destination register. See DecodeRegExtend() in the ARM ARM.
@@ -1835,10 +1959,132 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
}
}
-/* AdvSIMD load/store multiple structures */
+/* C3.3.1 AdvSIMD load/store multiple structures
+ *
+ * 31 30 29 23 22 21 16 15 12 11 10 9 5 4 0
+ * +---+---+---------------+---+-------------+--------+------+------+------+
+ * | 0 | Q | 0 0 1 1 0 0 0 | L | 0 0 0 0 0 0 | opcode | size | Rn | Rt |
+ * +---+---+---------------+---+-------------+--------+------+------+------+
+ *
+ * C3.3.2 AdvSIMD load/store multiple structures (post-indexed)
+ *
+ * 31 30 29 23 22 21 20 16 15 12 11 10 9 5 4 0
+ * +---+---+---------------+---+---+---------+--------+------+------+------+
+ * | 0 | Q | 0 0 1 1 0 0 1 | L | 0 | Rm | opcode | size | Rn | Rt |
+ * +---+---+---------------+---+---+---------+--------+------+------+------+
+ *
+ * Rt: first (or only) SIMD&FP register to be transferred
+ * Rn: base address or SP
+ * Rm (post-index only): post-index register (when !31) or size dependent #imm
+ */
static void disas_ldst_multiple_struct(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, insn);
+ int rt = extract32(insn, 0, 5);
+ int rn = extract32(insn, 5, 5);
+ int size = extract32(insn, 10, 2);
+ int opcode = extract32(insn, 12, 4);
+ bool is_store = !extract32(insn, 22, 1);
+ bool is_postidx = extract32(insn, 23, 1);
+ bool is_q = extract32(insn, 30, 1);
+ TCGv_i64 tcg_addr, tcg_rn;
+
+ int ebytes = 1 << size;
+ int elements = (is_q ? 128 : 64) / (8 << size);
+ int rpt; /* num iterations */
+ int selem; /* structure elements */
+ int r;
+
+ if (extract32(insn, 31, 1) || extract32(insn, 21, 1)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ /* From the shared decode logic */
+ 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);
+ return;
+ }
+
+ if (rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+
+ tcg_rn = cpu_reg_sp(s, rn);
+ tcg_addr = tcg_temp_new_i64();
+ tcg_gen_mov_i64(tcg_addr, tcg_rn);
+
+ for (r = 0; r < rpt; r++) {
+ int e;
+ for (e = 0; e < elements; e++) {
+ int tt = (rt + r) % 32;
+ int xs;
+ for (xs = 0; xs < selem; xs++) {
+ if (is_store) {
+ do_vec_st(s, tt, e, tcg_addr, size);
+ } else {
+ do_vec_ld(s, tt, e, tcg_addr, size);
+
+ /* For non-quad operations, setting a slice of the low
+ * 64 bits of the register clears the high 64 bits (in
+ * the ARM ARM pseudocode this is implicit in the fact
+ * that 'rval' is a 64 bit wide variable). We optimize
+ * by noticing that we only need to do this the first
+ * time we touch a register.
+ */
+ if (!is_q && e == 0 && (r == 0 || xs == selem - 1)) {
+ clear_vec_high(s, tt);
+ }
+ }
+ tcg_gen_addi_i64(tcg_addr, tcg_addr, ebytes);
+ tt = (tt + 1) % 32;
+ }
+ }
+ }
+
+ if (is_postidx) {
+ int rm = extract32(insn, 16, 5);
+ if (rm == 31) {
+ tcg_gen_mov_i64(tcg_rn, tcg_addr);
+ } else {
+ tcg_gen_add_i64(tcg_rn, tcg_rn, cpu_reg(s, rm));
+ }
+ }
+ tcg_temp_free_i64(tcg_addr);
}
/* AdvSIMD load/store single structure */
--
1.8.5
next prev parent reply other threads:[~2014-01-29 13:40 UTC|newest]
Thread overview: 40+ messages / expand[flat|nested] mbox.gz Atom feed top
2014-01-29 13:39 [Qemu-devel] [PULL 00/38] target-arm queue Peter Maydell
2014-01-29 13:39 ` Peter Maydell [this message]
2014-01-29 13:39 ` [Qemu-devel] [PULL 02/38] target-arm: A64: Add SIMD ld/st single Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 03/38] target-arm: A64: Add decode skeleton for SIMD data processing insns Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 04/38] target-arm: A64: Add SIMD EXT Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 05/38] target-arm: A64: Add SIMD TBL/TBLX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 06/38] target-arm: A64: Add SIMD ZIP/UZP/TRN Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 07/38] target-arm: A64: Add SIMD across-lanes instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 08/38] target-arm: A64: Add SIMD copy operations Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 09/38] target-arm: A64: Add SIMD modified immediate group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 10/38] target-arm: A64: Add SIMD scalar copy instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 11/38] hw/arm/boot: Don't set up ATAGS for autogenerated dtb booting Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 12/38] ARM: Convert MIDR to a property Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 13/38] ZYNQ: Implement board MIDR control for Zynq Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 14/38] display: avoid multi-statement macro Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 15/38] target-arm: Move arm_rmode_to_sf to a shared location Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 16/38] target-arm: Add AArch32 FP VRINTA, VRINTN, VRINTP and VRINTM Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 17/38] target-arm: Add support for AArch32 FP VRINTR Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 18/38] target-arm: Add support for AArch32 FP VRINTZ Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 19/38] target-arm: Add support for AArch32 FP VRINTX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 20/38] target-arm: Add support for AArch32 SIMD VRINTX Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 21/38] target-arm: Add set_neon_rmode helper Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 22/38] target-arm: Add AArch32 SIMD VRINTA, VRINTN, VRINTP, VRINTM, VRINTZ Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 23/38] target-arm: Add AArch32 FP VCVTA, VCVTN, VCVTP and VCVTM Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 24/38] target-arm: Add AArch32 SIMD " Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 25/38] target-arm: A64: Add SIMD three-different multiply accumulate insns Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 26/38] target-arm: A64: Add SIMD three-different ABDL instructions Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 27/38] target-arm: A64: Add SIMD scalar 3 same add, sub and compare ops Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 28/38] target-arm: A64: Add top level decode for SIMD 3-same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 29/38] target-arm: A64: Add logic ops from SIMD 3 same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 30/38] target-arm: A64: Add integer ops from SIMD 3-same group Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 31/38] target-arm: A64: Add simple SIMD 3-same floating point ops Peter Maydell
2014-01-29 13:39 ` [Qemu-devel] [PULL 32/38] target-arm: A64: Add SIMD shift by immediate Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 33/38] linux-headers: Update from Linus' master ba635f8 Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 34/38] kvm: Introduce kvm_arch_irqchip_create Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 35/38] kvm: Common device control API functions Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 36/38] arm: vgic device control api support Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 37/38] arm_gic: Introduce define for GIC_NR_SGIS Peter Maydell
2014-01-29 13:40 ` [Qemu-devel] [PULL 38/38] arm_gic: Fix GICD_ICPENDR and GICD_ISPENDR writes Peter Maydell
2014-01-31 14:36 ` [Qemu-devel] [PULL 00/38] target-arm queue Peter Maydell
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1391002805-26596-2-git-send-email-peter.maydell@linaro.org \
--to=peter.maydell@linaro.org \
--cc=aliguori@amazon.com \
--cc=aurelien@aurel32.net \
--cc=blauwirbel@gmail.com \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).