All of lore.kernel.org
 help / color / mirror / Atom feed
* [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer
@ 2013-12-11 22:01 Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
                   ` (7 more replies)
  0 siblings, 8 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

Here's version 2 of the third set of A64 decoder patches
(loads, stores, misc integer).

Changes v1->v2:
 * merged ldp and stp into one function/patch
 * minor cleanup as per RTH review
 * use the new tcg ops for guest load/store
 * catch the missing UNALLOCATED cases for load/store
 * add missing returns after unallocated_encoding() calls
   in vector load/store decode
 * use tcg ops for mul[su]h

thanks
-- PMM

Alex Bennée (6):
  target-arm: A64: add support for ld/st pair
  target-arm: A64: add support for ld/st unsigned imm
  target-arm: A64: add support for ld/st with reg offset
  target-arm: A64: add support for ld/st with index
  target-arm: A64: add support for add, addi, sub, subi
  target-arm: A64: add support for move wide instructions

Alexander Graf (2):
  target-arm: A64: add support for 3 src data proc insns
  target-arm: A64: implement SVC, BRK

 target-arm/translate-a64.c | 1114 +++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 1092 insertions(+), 22 deletions(-)

-- 
1.8.5

^ permalink raw reply	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-12  9:54   ` C Fontana
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 2/8] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
                   ` (6 subsequent siblings)
  7 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This patch support the basic load and store pair instructions and
includes the generic helper functions:

  * do_gpr_st()
  * do_fp_st()
  * do_gpr_ld()
  * do_fp_ld()
  * read_cpu_reg_sp()
  * gen_check_sp_alignment()

The last function gen_check_sp_alignment() is a NULL op currently but
put in place to make it easy to add SP alignment checking later.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---

Changes
  - merge ldp/stp together
  - add read_cpu_reg_sp() and use
  - only reference registers as needed
  - use common tcg ops for gpr/fp loads/store
---
 target-arm/translate-a64.c | 268 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 263 insertions(+), 5 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0a76130..018b3ee 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -99,6 +99,15 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
     cpu_fprintf(f, "\n");
 }
 
+static int get_mem_index(DisasContext *s)
+{
+#ifdef CONFIG_USER_ONLY
+    return 1;
+#else
+    return s->user;
+#endif
+}
+
 void gen_a64_set_pc_im(uint64_t val)
 {
     tcg_gen_movi_i64(cpu_pc, val);
@@ -250,6 +259,17 @@ static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
     return v;
 }
 
+static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
+{
+    TCGv_i64 v = new_tmp_a64(s);
+    if (sf) {
+        tcg_gen_mov_i64(v, cpu_X[reg]);
+    } else {
+        tcg_gen_ext32u_i64(v, cpu_X[reg]);
+    }
+    return v;
+}
+
 /* Set ZF and NF based on a 64 bit result. This is alas fiddlier
  * than the 32 bit equivalent.
  */
@@ -278,6 +298,124 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
 }
 
 /*
+ * Load/Store generators
+ */
+
+/*
+ *  Store from GPR register to memory
+ */
+static void do_gpr_st(DisasContext *s, TCGv_i64 source,
+                      TCGv_i64 tcg_addr, int size)
+{
+    g_assert(size <= 3);
+    tcg_gen_qemu_st_i64(source, tcg_addr, get_mem_index(s), MO_TE + size);
+}
+
+/*
+ * Load from memory to GPR register
+ */
+static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
+                      int size, bool is_signed, bool extend)
+{
+    TCGMemOp memop =  MO_TE + size;
+
+    g_assert(size <= 3);
+
+    if (is_signed) {
+        memop += MO_SIGN;
+    }
+
+    tcg_gen_qemu_ld_i64(dest, tcg_addr, get_mem_index(s), memop);
+
+    if (extend && is_signed) {
+        g_assert(size < 3);
+        tcg_gen_ext32u_i64(dest, dest);
+    }
+}
+
+/*
+ * Store from FP register to memory
+ */
+static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
+{
+    /* This writes the bottom N bits of a 128 bit wide vector to memory */
+    int freg_offs = offsetof(CPUARMState, vfp.regs[srcidx * 2]);
+    TCGv_i64 tmp = tcg_temp_new_i64();
+
+    if (size < 4) {
+        switch (size) {
+        case 0:
+            tcg_gen_ld8u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 1:
+            tcg_gen_ld16u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 2:
+            tcg_gen_ld32u_i64(tmp, cpu_env, freg_offs);
+            break;
+        case 3:
+            tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
+            break;
+        }
+        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
+    } else {
+        TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
+        tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
+        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
+        tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
+        tcg_gen_ld_i64(tmp, cpu_env, freg_offs + sizeof(float64));
+        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
+        tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
+        tcg_temp_free_i64(tcg_hiaddr);
+    }
+
+    tcg_temp_free_i64(tmp);
+}
+
+/* Load from memory to FP register */
+static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
+{
+    /* This always zero-extends and writes to a full 128 bit wide vector */
+    int freg_offs = offsetof(CPUARMState, vfp.regs[destidx * 2]);
+    TCGv_i64 tmplo = tcg_temp_new_i64();
+    TCGv_i64 tmphi;
+
+    if (size < 4) {
+        TCGMemOp memop =  MO_TE + size;
+        tmphi = tcg_const_i64(0);
+        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
+    } else {
+        TCGv_i64 tcg_hiaddr;
+        tmphi = tcg_temp_new_i64();
+        tcg_hiaddr = tcg_temp_new_i64();
+
+        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
+        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
+        tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
+        tcg_temp_free_i64(tcg_hiaddr);
+    }
+
+    tcg_gen_st_i64(tmplo, cpu_env, freg_offs);
+    tcg_gen_st_i64(tmphi, cpu_env, freg_offs + sizeof(float64));
+
+    tcg_temp_free_i64(tmplo);
+    tcg_temp_free_i64(tmphi);
+}
+
+static inline void gen_check_sp_alignment(DisasContext *s)
+{
+    /* The AArch64 architecture mandates that (if enabled via PSTATE
+     * or SCTLR bits) there is a check that SP is 16-aligned on every
+     * SP-relative load or store (with an exception generated if it is not).
+     * In line with general QEMU practice regarding misaligned accesses,
+     * we omit these checks for the sake of guest program performance.
+     * This function is provided as a hook so we can more easily add these
+     * checks in future (possibly as a "favour catching guest program bugs
+     * over speed" user selectable option).
+     */
+}
+
+/*
  * the instruction disassembly implemented here matches
  * the instruction encoding classifications in chapter 3 (C3)
  * of the ARM Architecture Reference Manual (DDI0487A_a)
@@ -620,10 +758,130 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
     unsupported_encoding(s, insn);
 }
 
-/* Load/store pair (all forms) */
-static void disas_ldst_pair(DisasContext *s, uint32_t insn)
-{
-    unsupported_encoding(s, insn);
+/*
+ * C5.6.81 LDP (Load Pair - non vector)
+ * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
+ * C5.6.177 STP (Store Pair - non vector)
+ * C6.3.165 LDP (Load Pair of SIMD&FP)
+ * C6.3.284 STP (Store Pair of SIMD&FP)
+ *
+ *  31 30 29   27  26 25   23  22 21   15 14   10 9    5 4    0
+ * +-----+-------+---+-------+---+-----------------------------+
+ * | opc | 1 0 1 | V | index | L |  imm7 |  Rt2  |  Rn  | Rt   |
+ * +-----+-------+---+-------+---+-------+-------+------+------+
+ *
+ * opc: LDP&STP       00 -> 32 bit, 10 -> 64 bit
+ *      LDPSW         01
+ *      LDP&STP(SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
+ *   V: 0 -> GPR, 1 -> Vector
+ * idx: 001 -> post-index, 011 -> pre-index, 010 -> signed off
+ *   L: 0 -> Store 1 -> Load
+ *
+ * Rt, Rt2 = GPR or SIMD registers to be stored
+ * Rn = general purpose register containing address
+ * imm7 = signed offset (multiple of 4 or 8 depending on size)
+ */
+static void handle_ldst_pair(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int rt2 = extract32(insn, 10, 5);
+    int64_t offset = sextract32(insn, 15, 7);
+    int index = extract32(insn, 23, 2);
+    bool is_vector = extract32(insn, 26, 1);
+    bool is_load = extract32(insn, 22, 1);
+    int opc = extract32(insn, 30, 2);
+
+    bool is_signed = false;
+    bool postindex = false;
+    bool wback = false;
+
+    TCGv_i64 tcg_addr; /* calculated address */
+    int size;
+
+    if (is_vector) {
+        if (opc == 3) {
+            unallocated_encoding(s);
+            return;
+        }
+        size = 2 + opc;
+    } else {
+        size = 2 + extract32(opc, 1, 1);
+        if (is_load) {
+            is_signed = opc & 1;
+        } else if (opc & 1) {
+            unallocated_encoding(s);
+            return;
+        }
+    }
+
+    switch (index) {
+    case 1: /* post-index */
+        postindex = true;
+        wback = true;
+        break;
+    case 2: /* signed offset, rn not updated */
+        postindex = false;
+        break;
+    case 3: /* pre-index */
+        postindex = false;
+        wback = true;
+        break;
+    default: /* Failed decoder tree? */
+        unallocated_encoding(s);
+        break;
+    }
+
+    offset <<= size;
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    if (!postindex) {
+        tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+    }
+
+    if (is_vector) {
+        if (is_load) {
+            do_fp_ld(s, rt, tcg_addr, size);
+        } else {
+            do_fp_st(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_load) {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
+        } else {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        }
+    }
+    tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
+    if (is_vector) {
+        if (is_load) {
+            do_fp_ld(s, rt2, tcg_addr, size);
+        } else {
+            do_fp_st(s, rt2, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
+        if (is_load) {
+            do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
+        } else {
+            do_gpr_st(s, tcg_rt2, tcg_addr, size);
+        }
+    }
+
+    if (wback) {
+        if (postindex) {
+            tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
+        } else {
+            tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
+        }
+        tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
+    }
 }
 
 /* Load/store register (all forms) */
@@ -656,7 +914,7 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
         break;
     case 0x28: case 0x29:
     case 0x2c: case 0x2d: /* Load/store pair (all forms) */
-        disas_ldst_pair(s, insn);
+        handle_ldst_pair(s, insn);
         break;
     case 0x38: case 0x39:
     case 0x3c: case 0x3d: /* Load/store register (all forms) */
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 2/8] target-arm: A64: add support for ld/st unsigned imm
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 3/8] target-arm: A64: add support for ld/st with reg offset Peter Maydell
                   ` (5 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex@bennee.com>

This adds support for the forms of ld/st with a 12 bit
unsigned immediate offset.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---

Changes
   - split off cpu_read_reg_sp for earlier use
---
 target-arm/translate-a64.c | 89 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 88 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 018b3ee..7d3f432 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -884,10 +884,97 @@ static void handle_ldst_pair(DisasContext *s, uint32_t insn)
     }
 }
 
+/*
+ * C3.3.13 Load/store (unsigned immediate)
+ *
+ * 31 30 29   27  26 25 24 23 22 21        10 9     5
+ * +----+-------+---+-----+-----+------------+-------+------+
+ * |size| 1 1 1 | V | 0 1 | opc |   imm12    |  Rn   |  Rt  |
+ * +----+-------+---+-----+-----+------------+-------+------+
+ *
+ * For non-vector:
+ *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
+ *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ * For vector:
+ *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
+ *   opc<0>: 0 -> store, 1 -> load
+ * Rn: base address register (inc SP)
+ * Rt: target register
+ */
+static void handle_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    unsigned int imm12 = extract32(insn, 10, 12);
+    bool is_vector = extract32(insn, 26, 1);
+    int size = extract32(insn, 30, 2);
+    int opc = extract32(insn, 22, 2);
+    unsigned int offset;
+
+    TCGv_i64 tcg_addr;
+
+    bool is_store;
+    bool is_signed = false;
+    bool is_extended = false;
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = ((opc & 1) == 0);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = opc & (1<<1);
+        is_extended = (size < 3) && (opc & 1);
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+    offset = imm12 << size;
+    tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+}
+
 /* Load/store register (all forms) */
 static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    switch (extract32(insn, 24, 2)) {
+    case 0:
+        unsupported_encoding(s, insn);
+        break;
+    case 1:
+        handle_ldst_reg_unsigned_imm(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* AdvSIMD load/store multiple structures */
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 3/8] target-arm: A64: add support for ld/st with reg offset
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 2/8] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 4/8] target-arm: A64: add support for ld/st with index Peter Maydell
                   ` (4 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex@bennee.com>

This adds support for the load/store forms using a register offset.

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 144 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 143 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7d3f432..1ea3c0e 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -402,6 +402,54 @@ static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
     tcg_temp_free_i64(tmphi);
 }
 
+/*
+ * 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.
+ */
+static void ext_and_shift_reg(TCGv_i64 tcg_out, TCGv_i64 tcg_in,
+                              int option, unsigned int shift)
+{
+    int extsize = extract32(option, 0, 2);
+    bool is_signed = extract32(option, 2, 1);
+
+    if (is_signed) {
+        switch (extsize) {
+        case 0:
+            tcg_gen_ext8s_i64(tcg_out, tcg_in);
+            break;
+        case 1:
+            tcg_gen_ext16s_i64(tcg_out, tcg_in);
+            break;
+        case 2:
+            tcg_gen_ext32s_i64(tcg_out, tcg_in);
+            break;
+        case 3:
+            tcg_gen_mov_i64(tcg_out, tcg_in);
+            break;
+        }
+    } else {
+        switch (extsize) {
+        case 0:
+            tcg_gen_ext8u_i64(tcg_out, tcg_in);
+            break;
+        case 1:
+            tcg_gen_ext16u_i64(tcg_out, tcg_in);
+            break;
+        case 2:
+            tcg_gen_ext32u_i64(tcg_out, tcg_in);
+            break;
+        case 3:
+            tcg_gen_mov_i64(tcg_out, tcg_in);
+            break;
+        }
+    }
+
+    if (shift) {
+        tcg_gen_shli_i64(tcg_out, tcg_out, shift);
+    }
+}
+
 static inline void gen_check_sp_alignment(DisasContext *s)
 {
     /* The AArch64 architecture mandates that (if enabled via PSTATE
@@ -885,6 +933,96 @@ static void handle_ldst_pair(DisasContext *s, uint32_t insn)
 }
 
 /*
+ * C3.3.10 Load/store (register offset)
+ *
+ * 31 30 29   27  26 25 24 23 22 21  20  16 15 13 12 11 10 9  5 4  0
+ * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
+ * |size| 1 1 1 | V | 0 0 | opc | 1 |  Rm  | opt | S| 1 0 | Rn | Rt |
+ * +----+-------+---+-----+-----+---+------+-----+--+-----+----+----+
+ *
+ * For non-vector:
+ *   size: 00-> byte, 01 -> 16 bit, 10 -> 32bit, 11 -> 64bit
+ *   opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ * For vector:
+ *   size is opc<1>:size<1:0> so 100 -> 128 bit; 110 and 111 unallocated
+ *   opc<0>: 0 -> store, 1 -> load
+ * V: 1 -> vector/simd
+ * opt: extend encoding (see DecodeRegExtend)
+ * S: if S=1 then scale (essentially index by sizeof(size))
+ * Rt: register to transfer into/out of
+ * Rn: address register or SP for base
+ * Rm: offset register or ZR for offset
+ */
+static void handle_ldst_reg_roffset(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int shift = extract32(insn, 12, 1);
+    int rm = extract32(insn, 16, 5);
+    int opc = extract32(insn, 22, 2);
+    int opt = extract32(insn, 13, 3);
+    int size = extract32(insn, 30, 2);
+    bool is_signed = false;
+    bool is_store = false;
+    bool is_extended = false;
+    bool is_vector = extract32(insn, 26, 1);
+
+    TCGv_i64 tcg_rm;
+    TCGv_i64 tcg_addr;
+
+    if (extract32(opt, 1, 1) == 0) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = ((opc & 1) == 0);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = opc & (1<<1);
+        is_extended = (size < 3) && (opc & 1);
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    tcg_rm = read_cpu_reg(s, rm, 1);
+    ext_and_shift_reg(tcg_rm, tcg_rm, opt, shift ? size : 0);
+
+    tcg_gen_add_i64(tcg_addr, tcg_addr, tcg_rm);
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+}
+
+/*
  * C3.3.13 Load/store (unsigned immediate)
  *
  * 31 30 29   27  26 25 24 23 22 21        10 9     5
@@ -966,7 +1104,11 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
     switch (extract32(insn, 24, 2)) {
     case 0:
-        unsupported_encoding(s, insn);
+        if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
+            handle_ldst_reg_roffset(s, insn);
+        } else {
+            unsupported_encoding(s, insn);
+        }
         break;
     case 1:
         handle_ldst_reg_unsigned_imm(s, insn);
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 4/8] target-arm: A64: add support for ld/st with index
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
                   ` (2 preceding siblings ...)
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 3/8] target-arm: A64: add support for ld/st with reg offset Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 5/8] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
                   ` (3 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex@bennee.com>

This adds support for the pre/post-index ld/st forms with immediate
offsets as well as the un-scaled immediate form (which are all
variations on the same 9-bit immediate instruction form).

Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target-arm/translate-a64.c | 125 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 124 insertions(+), 1 deletion(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 1ea3c0e..791555d 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -933,6 +933,110 @@ static void handle_ldst_pair(DisasContext *s, uint32_t insn)
 }
 
 /*
+ * C3.3.8 Load/store (immediate post-indexed)
+ * C3.3.9 Load/store (immediate pre-indexed)
+ * C3.3.12 Load/store (unscaled immediate)
+ *
+ * 31 30 29   27  26 25 24 23 22 21  20    12 11 10 9    5 4    0
+ * +----+-------+---+-----+-----+---+--------+-----+------+------+
+ * |size| 1 1 1 | V | 0 0 | opc | 0 |  imm9  | idx |  Rn  |  Rt  |
+ * +----+-------+---+-----+-----+---+--------+-----+------+------+
+ *
+ * idx = 01 -> post-indexed, 11 pre-indexed, 00 unscaled imm. (no writeback)
+ * V = 0 -> non-vector
+ * size: 00 -> 8 bit, 01 -> 16 bit, 10 -> 32 bit, 11 -> 64bit
+ * opc: 00 -> store, 01 -> loadu, 10 -> loads 64, 11 -> loads 32
+ */
+static void handle_ldst_reg_imm9(DisasContext *s, uint32_t insn)
+{
+    int rt = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm9 = sextract32(insn, 12, 9);
+    int opc = extract32(insn, 22, 2);
+    int size = extract32(insn, 30, 2);
+    int idx = extract32(insn, 10, 2);
+    bool is_signed = false;
+    bool is_store = false;
+    bool is_extended = false;
+    bool is_vector = extract32(insn, 26, 1);
+    bool post_index;
+    bool writeback;
+
+    TCGv_i64 tcg_addr;
+
+    if (is_vector) {
+        size |= (opc & 2) << 1;
+        if (size > 4) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = ((opc & 1) == 0);
+    } else {
+        if (size == 3 && opc == 2) {
+            /* PRFM - prefetch */
+            return;
+        }
+        if (opc == 3 && size > 1) {
+            unallocated_encoding(s);
+            return;
+        }
+        is_store = (opc == 0);
+        is_signed = opc & (1<<1);
+        is_extended = (size < 3) && (opc & 1);
+    }
+
+    switch (idx) {
+    case 0:
+        post_index = false;
+        writeback = false;
+        break;
+    case 1:
+        post_index = true;
+        writeback = true;
+        break;
+    case 3:
+        post_index = false;
+        writeback = true;
+        break;
+    case 2:
+        g_assert(false);
+        break;
+    }
+
+    if (rn == 31) {
+        gen_check_sp_alignment(s);
+    }
+    tcg_addr = read_cpu_reg_sp(s, rn, 1);
+
+    if (!post_index) {
+        tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
+    }
+
+    if (is_vector) {
+        if (is_store) {
+            do_fp_st(s, rt, tcg_addr, size);
+        } else {
+            do_fp_ld(s, rt, tcg_addr, size);
+        }
+    } else {
+        TCGv_i64 tcg_rt = cpu_reg(s, rt);
+        if (is_store) {
+            do_gpr_st(s, tcg_rt, tcg_addr, size);
+        } else {
+            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, is_extended);
+        }
+    }
+
+    if (writeback) {
+        TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
+        if (post_index) {
+            tcg_gen_addi_i64(tcg_addr, tcg_addr, imm9);
+        }
+        tcg_gen_mov_i64(tcg_rn, tcg_addr);
+    }
+}
+
+/*
  * C3.3.10 Load/store (register offset)
  *
  * 31 30 29   27  26 25 24 23 22 21  20  16 15 13 12 11 10 9  5 4  0
@@ -1099,6 +1203,25 @@ static void handle_ldst_reg_unsigned_imm(DisasContext *s, uint32_t insn)
     }
 }
 
+/* Load/store register (immediate forms) */
+static void disas_ldst_reg_imm(DisasContext *s, uint32_t insn)
+{
+    switch (extract32(insn, 10, 2)) {
+    case 0: case 1: case 3:
+        /* Load/store register (unscaled immediate) */
+        /* Load/store immediate pre/post-indexed */
+        handle_ldst_reg_imm9(s, insn);
+        break;
+    case 2:
+        /* Load/store register unprivileged */
+        unsupported_encoding(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
+}
+
 /* Load/store register (all forms) */
 static void disas_ldst_reg(DisasContext *s, uint32_t insn)
 {
@@ -1107,7 +1230,7 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
         if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
             handle_ldst_reg_roffset(s, insn);
         } else {
-            unsupported_encoding(s, insn);
+            disas_ldst_reg_imm(s, insn);
         }
         break;
     case 1:
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 5/8] target-arm: A64: add support for add, addi, sub, subi
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
                   ` (3 preceding siblings ...)
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 4/8] target-arm: A64: add support for ld/st with index Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 6/8] target-arm: A64: add support for move wide instructions Peter Maydell
                   ` (2 subsequent siblings)
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

Implement the non-carry forms of addition and subtraction
(immediate, extended register and shifted register).
This includes the code to calculate NZCV if the instruction
calls for setting the flags.

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>

---
Changes:
  - remove pointless mov op (we already have a copy)
---
 target-arm/translate-a64.c | 299 +++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 289 insertions(+), 10 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 791555d..59393f3 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -297,6 +297,102 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
     tcg_gen_movi_i32(cpu_VF, 0);
 }
 
+/* dest = T0 + T1; compute C, N, V and Z flags */
+static void gen_add_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    if (sf) {
+        TCGv_i64 result, flag, tmp;
+        result = tcg_temp_new_i64();
+        flag = tcg_temp_new_i64();
+        tmp = tcg_temp_new_i64();
+
+        tcg_gen_movi_i64(tmp, 0);
+        tcg_gen_add2_i64(result, flag, t0, tmp, t1, tmp);
+
+        tcg_gen_trunc_i64_i32(cpu_CF, flag);
+
+        gen_set_NZ64(result);
+
+        tcg_gen_xor_i64(flag, result, t0);
+        tcg_gen_xor_i64(tmp, t0, t1);
+        tcg_gen_andc_i64(flag, flag, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_gen_shri_i64(flag, flag, 32);
+        tcg_gen_trunc_i64_i32(cpu_VF, flag);
+
+        tcg_gen_mov_i64(dest, result);
+        tcg_temp_free_i64(result);
+        tcg_temp_free_i64(flag);
+    } else {
+        /* 32 bit arithmetic */
+        TCGv_i32 t0_32 = tcg_temp_new_i32();
+        TCGv_i32 t1_32 = tcg_temp_new_i32();
+        TCGv_i32 tmp = tcg_temp_new_i32();
+
+        tcg_gen_movi_i32(tmp, 0);
+        tcg_gen_trunc_i64_i32(t0_32, t0);
+        tcg_gen_trunc_i64_i32(t1_32, t1);
+        tcg_gen_add2_i32(cpu_NF, cpu_CF, t0_32, tmp, t1_32, tmp);
+        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
+        tcg_gen_xor_i32(tmp, t0_32, t1_32);
+        tcg_gen_andc_i32(cpu_VF, cpu_VF, tmp);
+        tcg_gen_extu_i32_i64(dest, cpu_NF);
+
+        tcg_temp_free_i32(tmp);
+        tcg_temp_free_i32(t0_32);
+        tcg_temp_free_i32(t1_32);
+    }
+}
+
+/* dest = T0 - T1; compute C, N, V and Z flags */
+static void gen_sub_CC(int sf, TCGv_i64 dest, TCGv_i64 t0, TCGv_i64 t1)
+{
+    if (sf) {
+        /* 64 bit arithmetic */
+        TCGv_i64 result, flag, tmp;
+
+        result = tcg_temp_new_i64();
+        flag = tcg_temp_new_i64();
+        tcg_gen_sub_i64(result, t0, t1);
+
+        gen_set_NZ64(result);
+
+        tcg_gen_setcond_i64(TCG_COND_GEU, flag, t0, t1);
+        tcg_gen_trunc_i64_i32(cpu_CF, flag);
+
+        tcg_gen_xor_i64(flag, result, t0);
+        tmp = tcg_temp_new_i64();
+        tcg_gen_xor_i64(tmp, t0, t1);
+        tcg_gen_and_i64(flag, flag, tmp);
+        tcg_temp_free_i64(tmp);
+        tcg_gen_shri_i64(flag, flag, 32);
+        tcg_gen_trunc_i64_i32(cpu_VF, flag);
+        tcg_gen_mov_i64(dest, result);
+        tcg_temp_free_i64(flag);
+        tcg_temp_free_i64(result);
+    } else {
+        /* 32 bit arithmetic */
+        TCGv_i32 t0_32 = tcg_temp_new_i32();
+        TCGv_i32 t1_32 = tcg_temp_new_i32();
+        TCGv_i32 tmp;
+
+        tcg_gen_trunc_i64_i32(t0_32, t0);
+        tcg_gen_trunc_i64_i32(t1_32, t1);
+        tcg_gen_sub_i32(cpu_NF, t0_32, t1_32);
+        tcg_gen_mov_i32(cpu_ZF, cpu_NF);
+        tcg_gen_setcond_i32(TCG_COND_GEU, cpu_CF, t0_32, t1_32);
+        tcg_gen_xor_i32(cpu_VF, cpu_NF, t0_32);
+        tmp = tcg_temp_new_i32();
+        tcg_gen_xor_i32(tmp, t0_32, t1_32);
+        tcg_temp_free_i32(t0_32);
+        tcg_temp_free_i32(t1_32);
+        tcg_gen_and_i32(cpu_VF, cpu_VF, tmp);
+        tcg_temp_free_i32(tmp);
+        tcg_gen_extu_i32_i64(dest, cpu_NF);
+    }
+}
+
 /*
  * Load/Store generators
  */
@@ -1311,10 +1407,67 @@ static void disas_pc_rel_adr(DisasContext *s, uint32_t insn)
     tcg_gen_movi_i64(cpu_reg(s, rd), base + offset);
 }
 
-/* Add/subtract (immediate) */
+/*
+ * C3.4.1 Add/subtract (immediate)
+ *
+ *  31 30 29 28       24 23 22 21         10 9   5 4   0
+ * +--+--+--+-----------+-----+-------------+-----+-----+
+ * |sf|op| S| 1 0 0 0 1 |shift|    imm12    |  Rn | Rd  |
+ * +--+--+--+-----------+-----+-------------+-----+-----+
+ *
+ *    sf: 0 -> 32bit, 1 -> 64bit
+ *    op: 0 -> add  , 1 -> sub
+ *     S: 1 -> set flags
+ * shift: 00 -> LSL imm by 0, 01 -> LSL imm by 12
+ */
 static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    uint64_t imm = extract32(insn, 10, 12);
+    int shift = extract32(insn, 22, 2);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool is_64bit = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rn = cpu_reg_sp(s, rn);
+    TCGv_i64 tcg_rd = setflags ? cpu_reg(s, rd) : cpu_reg_sp(s, rd);
+    TCGv_i64 tcg_result;
+
+    switch (shift) {
+    case 0x0:
+        break;
+    case 0x1:
+        imm <<= 12;
+        break;
+    default:
+        unallocated_encoding(s);
+    }
+
+    tcg_result = tcg_temp_new_i64();
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_subi_i64(tcg_result, tcg_rn, imm);
+        } else {
+            tcg_gen_addi_i64(tcg_result, tcg_rn, imm);
+        }
+    } else {
+        TCGv_i64 tcg_imm = tcg_const_i64(imm);
+        if (sub_op) {
+            gen_sub_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
+        } else {
+            gen_add_CC(is_64bit, tcg_result, tcg_rn, tcg_imm);
+        }
+        tcg_temp_free_i64(tcg_imm);
+    }
+
+    if (is_64bit) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
 /* The input should be a value in the bottom e bits (with higher
@@ -1772,16 +1925,142 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Add/subtract (extended register) */
-static void disas_add_sub_ext_reg(DisasContext *s, uint32_t insn)
+/*
+ * C3.5.1 Add/subtract (extended register)
+ *
+ *  31|30|29|28       24|23 22|21|20   16|15  13|12  10|9  5|4  0|
+ * +--+--+--+-----------+-----+--+-------+------+------+----+----+
+ * |sf|op| S| 0 1 0 1 1 | opt | 1|  Rm   |option| imm3 | Rn | Rd |
+ * +--+--+--+-----------+-----+--+-------+------+------+----+----+
+ *
+ *  sf: 0 -> 32bit, 1 -> 64bit
+ *  op: 0 -> add  , 1 -> sub
+ *   S: 1 -> set flags
+ * opt: 00
+ * option: extension type (see DecodeRegExtend)
+ * imm3: optional shift to Rm
+ *
+ * Rd = Rn + LSL(extend(Rm), amount)
+ */
+static void handle_add_sub_ext_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm3 = extract32(insn, 10, 3);
+    int option = extract32(insn, 13, 3);
+    int rm = extract32(insn, 16, 5);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool sf = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rm, tcg_rn; /* temps */
+    TCGv_i64 tcg_rd;
+    TCGv_i64 tcg_result;
+
+    if (imm3 > 4) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    /* non-flag setting ops may use SP */
+    if (!setflags) {
+        tcg_rn = read_cpu_reg_sp(s, rn, sf);
+        tcg_rd = cpu_reg_sp(s, rd);
+    } else {
+        tcg_rn = read_cpu_reg(s, rn, sf);
+        tcg_rd = cpu_reg(s, rd);
+    }
+
+    tcg_rm = read_cpu_reg(s, rm, sf);
+    ext_and_shift_reg(tcg_rm, tcg_rm, option, imm3);
+
+    tcg_result = tcg_temp_new_i64();
+
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
+        }
+    } else {
+        if (sub_op) {
+            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        } else {
+            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        }
+    }
+
+    if (sf) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
-/* Add/subtract (shifted register) */
-static void disas_add_sub_reg(DisasContext *s, uint32_t insn)
+/*
+ * C3.5.2 Add/subtract (shifted register)
+ *
+ *  31 30 29 28       24 23 22 21 20   16 15     10 9    5 4    0
+ * +--+--+--+-----------+-----+--+-------+---------+------+------+
+ * |sf|op| S| 0 1 0 1 1 |shift| 0|  Rm   |  imm6   |  Rn  |  Rd  |
+ * +--+--+--+-----------+-----+--+-------+---------+------+------+
+ *
+ *    sf: 0 -> 32bit, 1 -> 64bit
+ *    op: 0 -> add  , 1 -> sub
+ *     S: 1 -> set flags
+ * shift: 00 -> LSL, 01 -> LSR, 10 -> ASR, 11 -> RESERVED
+ *  imm6: Shift amount to apply to Rm before the add/sub
+ */
+static void handle_add_sub_reg(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int imm6 = extract32(insn, 10, 6);
+    int rm = extract32(insn, 16, 5);
+    int shift_type = extract32(insn, 22, 2);
+    bool setflags = extract32(insn, 29, 1);
+    bool sub_op = extract32(insn, 30, 1);
+    bool sf = extract32(insn, 31, 1);
+
+    TCGv_i64 tcg_rd = cpu_reg(s, rd);
+    TCGv_i64 tcg_rn, tcg_rm;
+    TCGv_i64 tcg_result;
+
+    if ((shift_type == 3) || (!sf && (imm6 > 31))) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    tcg_rn = read_cpu_reg(s, rn, sf);
+    tcg_rm = read_cpu_reg(s, rm, sf);
+
+    shift_reg_imm(tcg_rm, tcg_rm, sf, shift_type, imm6);
+
+    tcg_result = tcg_temp_new_i64();
+
+    if (!setflags) {
+        if (sub_op) {
+            tcg_gen_sub_i64(tcg_result, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_add_i64(tcg_result, tcg_rn, tcg_rm);
+        }
+    } else {
+        if (sub_op) {
+            gen_sub_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        } else {
+            gen_add_CC(sf, tcg_result, tcg_rn, tcg_rm);
+        }
+    }
+
+    if (sf) {
+        tcg_gen_mov_i64(tcg_rd, tcg_result);
+    } else {
+        tcg_gen_ext32u_i64(tcg_rd, tcg_result);
+    }
+
+    tcg_temp_free_i64(tcg_result);
 }
 
 /* Data-processing (3 source) */
@@ -2145,9 +2424,9 @@ static void disas_data_proc_reg(DisasContext *s, uint32_t insn)
         break;
     case 0x0b: /* Add/subtract */
         if (insn & (1 << 21)) { /* (extended register) */
-            disas_add_sub_ext_reg(s, insn);
+            handle_add_sub_ext_reg(s, insn);
         } else {
-            disas_add_sub_reg(s, insn);
+            handle_add_sub_reg(s, insn);
         }
         break;
     case 0x1b: /* Data-processing (3 source) */
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 6/8] target-arm: A64: add support for move wide instructions
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
                   ` (4 preceding siblings ...)
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 5/8] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 8/8] target-arm: A64: implement SVC, BRK Peter Maydell
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alex Bennée <alex.bennee@linaro.org>

This patch adds emulation for the mov wide instructions
(MOVN, MOVZ, MOVK).

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 | 51 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 59393f3..4a6252e 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1626,10 +1626,57 @@ static void disas_logic_imm(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Move wide (immediate) */
+/*
+ * C3.4.5 Move wide (immediate)
+ *
+ *  31 30 29 28         23 22 21 20             5 4    0
+ * +--+-----+-------------+-----+----------------+------+
+ * |sf| opc | 1 0 0 1 0 1 |  hw |  imm16         |  Rd  |
+ * +--+-----+-------------+-----+----------------+------+
+ *
+ * sf: 0 -> 32 bit, 1 -> 64 bit
+ * opc: 00 -> N, 10 -> Z, 11 -> K
+ * hw: shift/16 (0,16, and sf only 32, 48)
+ */
 static void disas_movw_imm(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    uint64_t imm = extract32(insn, 5, 16);
+    int sf = extract32(insn, 31, 1);
+    int opc = extract32(insn, 29, 2);
+    int pos = extract32(insn, 21, 2) << 4;
+    TCGv_i64 tcg_rd = cpu_reg(s, rd);
+    TCGv_i64 tcg_imm;
+
+    if (!sf && (pos >= 32)) {
+        unallocated_encoding(s);
+        return;
+    }
+
+    switch (opc) {
+    case 0: /* MOVN */
+    case 2: /* MOVZ */
+        imm <<= pos;
+        if (opc == 0) {
+            imm = ~imm;
+        }
+        if (!sf) {
+            imm &= 0xffffffffu;
+        }
+        tcg_gen_movi_i64(tcg_rd, imm);
+        break;
+    case 3: /* MOVK */
+        tcg_imm = tcg_const_i64(imm);
+        tcg_gen_deposit_i64(tcg_rd, tcg_rd, tcg_imm, pos, 16);
+        tcg_temp_free_i64(tcg_imm);
+        if (!sf) {
+            tcg_gen_ext32u_i64(tcg_rd, tcg_rd);
+        }
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* C3.4.2 Bitfield
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 7/8] target-arm: A64: add support for 3 src data proc insns
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
                   ` (5 preceding siblings ...)
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 6/8] target-arm: A64: add support for move wide instructions Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 8/8] target-arm: A64: implement SVC, BRK Peter Maydell
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alexander Graf <agraf@suse.de>

This patch adds emulation for the "Data-processing (3 source)"
family of instructions, namely MADD, MSUB, SMADDL, SMSUBL, SMULH,
UMADDL, UMSUBL, UMULH.

Signed-off-by: Alexander Graf <agraf@suse.de>
Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

---
Changes:
  - Use tcg ops for mul[su]h (rh comment)
---
 target-arm/translate-a64.c | 91 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 4a6252e..019a6ed 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2110,10 +2110,97 @@ static void handle_add_sub_reg(DisasContext *s, uint32_t insn)
     tcg_temp_free_i64(tcg_result);
 }
 
-/* Data-processing (3 source) */
+/* C3.5.9 Data-processing (3 source)
+
+   31 30  29 28       24 23 21  20  16  15  14  10 9    5 4    0
+  +--+------+-----------+------+------+----+------+------+------+
+  |sf| op54 | 1 1 0 1 1 | op31 |  Rm  | o0 |  Ra  |  Rn  |  Rd  |
+  +--+------+-----------+------+------+----+------+------+------+
+
+ */
 static void disas_data_proc_3src(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int rd = extract32(insn, 0, 5);
+    int rn = extract32(insn, 5, 5);
+    int ra = extract32(insn, 10, 5);
+    int rm = extract32(insn, 16, 5);
+    int op_id = (extract32(insn, 29, 3) << 4) |
+        (extract32(insn, 21, 3) << 1) |
+        extract32(insn, 15, 1);
+    bool is_32bit = !extract32(insn, 31, 1);
+    bool is_sub = extract32(op_id, 0, 1);
+    bool is_high = extract32(op_id, 2, 1);
+    bool is_signed = false;
+    TCGv_i64 tcg_op1;
+    TCGv_i64 tcg_op2;
+    TCGv_i64 tcg_tmp;
+
+    /* Note that op_id is sf:op54:op31:o0 so it includes the 32/64 size flag */
+    switch (op_id) {
+    case 0x42: /* SMADDL */
+    case 0x43: /* SMSUBL */
+    case 0x44: /* SMULH */
+        is_signed = true;
+        break;
+    case 0x0: /* MADD (32bit) */
+    case 0x1: /* MSUB (32bit) */
+    case 0x40: /* MADD (64bit) */
+    case 0x41: /* MSUB (64bit) */
+    case 0x4a: /* UMADDL */
+    case 0x4b: /* UMSUBL */
+    case 0x4c: /* UMULH */
+        break;
+    default:
+        unallocated_encoding(s);
+    }
+
+    if (is_high) {
+        TCGv_i64 low_bits = tcg_temp_new_i64(); /* low bits discarded */
+        TCGv_i64 tcg_rd = cpu_reg(s, rd);
+        TCGv_i64 tcg_rn = cpu_reg(s, rn);
+        TCGv_i64 tcg_rm = cpu_reg(s, rm);
+
+        if (is_signed) {
+            tcg_gen_muls2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
+        } else {
+            tcg_gen_mulu2_i64(low_bits, tcg_rd, tcg_rn, tcg_rm);
+        }
+
+        tcg_temp_free(low_bits);
+        return;
+    }
+
+    tcg_op1 = tcg_temp_new_i64();
+    tcg_op2 = tcg_temp_new_i64();
+    tcg_tmp = tcg_temp_new_i64();
+
+    if (op_id < 0x42) {
+        tcg_gen_mov_i64(tcg_op1, cpu_reg(s, rn));
+        tcg_gen_mov_i64(tcg_op2, cpu_reg(s, rm));
+    } else {
+        if (is_signed) {
+            tcg_gen_ext32s_i64(tcg_op1, cpu_reg(s, rn));
+            tcg_gen_ext32s_i64(tcg_op2, cpu_reg(s, rm));
+        } else {
+            tcg_gen_ext32u_i64(tcg_op1, cpu_reg(s, rn));
+            tcg_gen_ext32u_i64(tcg_op2, cpu_reg(s, rm));
+        }
+    }
+
+    tcg_gen_mul_i64(tcg_tmp, tcg_op1, tcg_op2);
+    if (is_sub) {
+        tcg_gen_sub_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+    } else {
+        tcg_gen_add_i64(cpu_reg(s, rd), cpu_reg(s, ra), tcg_tmp);
+    }
+
+    if (is_32bit) {
+        tcg_gen_ext32u_i64(cpu_reg(s, rd), cpu_reg(s, rd));
+    }
+
+    tcg_temp_free_i64(tcg_op1);
+    tcg_temp_free_i64(tcg_op2);
+    tcg_temp_free_i64(tcg_tmp);
 }
 
 /* Add/subtract (with carry) */
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [Qemu-devel] [PATCH v2 8/8] target-arm: A64: implement SVC, BRK
  2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
                   ` (6 preceding siblings ...)
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
@ 2013-12-11 22:01 ` Peter Maydell
  7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-11 22:01 UTC (permalink / raw)
  To: qemu-devel
  Cc: patches, Michael Matz, Claudio Fontana, Dirk Mueller, Will Newton,
	Laurent Desnogues, Alex Bennée, kvmarm, Christoffer Dall,
	Richard Henderson

From: Alexander Graf <agraf@suse.de>

Add decoding for the exception generating instructions, and implement
SVC (syscalls) and BRK (software breakpoint).

Signed-off-by: Alexander Graf <agraf@suse.de>
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 | 51 ++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 49 insertions(+), 2 deletions(-)

diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 019a6ed..df4409b 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -806,10 +806,57 @@ static void disas_system(DisasContext *s, uint32_t insn)
     }
 }
 
-/* Exception generation */
+/* C3.2.3 Exception generation
+ *
+ *  31             24 23 21 20                     5 4   2 1  0
+ * +-----------------+-----+------------------------+-----+----+
+ * | 1 1 0 1 0 1 0 0 | opc |          imm16         | op2 | LL |
+ * +-----------------------+------------------------+----------+
+ */
 static void disas_exc(DisasContext *s, uint32_t insn)
 {
-    unsupported_encoding(s, insn);
+    int opc = extract32(insn, 21, 3);
+    int op2_ll = extract32(insn, 0, 5);
+
+    switch (opc) {
+    case 0:
+        /* SVC, HVC, SMC; since we don't support the Virtualization
+         * or TrustZone extensions these all UNDEF except SVC.
+         */
+        if (op2_ll != 1) {
+            unallocated_encoding(s);
+            break;
+        }
+        gen_exception_insn(s, 0, EXCP_SWI);
+        break;
+    case 1:
+        if (op2_ll != 0) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* BRK */
+        gen_exception_insn(s, 0, EXCP_BKPT);
+        break;
+    case 2:
+        if (op2_ll != 0) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* HLT */
+        unsupported_encoding(s, insn);
+        break;
+    case 5:
+        if (op2_ll < 1 || op2_ll > 3) {
+            unallocated_encoding(s);
+            break;
+        }
+        /* DCPS1, DCPS2, DCPS3 */
+        unsupported_encoding(s, insn);
+        break;
+    default:
+        unallocated_encoding(s);
+        break;
+    }
 }
 
 /* C3.2.7 Unconditional branch (register)
-- 
1.8.5

^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
@ 2013-12-12  9:54   ` C Fontana
  2013-12-12 11:43     ` Alex Bennée
  0 siblings, 1 reply; 14+ messages in thread
From: C Fontana @ 2013-12-12  9:54 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Michael Matz, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée,
	kvmarm@lists.cs.columbia.edu, Christoffer Dall, Richard Henderson

Hi,

I saw a missing return below:

On 11 December 2013 23:01, Peter Maydell <peter.maydell@linaro.org> wrote:
> From: Alex Bennée <alex.bennee@linaro.org>
>
> This patch support the basic load and store pair instructions and
> includes the generic helper functions:
>
>   * do_gpr_st()
>   * do_fp_st()
>   * do_gpr_ld()
>   * do_fp_ld()
>   * read_cpu_reg_sp()
>   * gen_check_sp_alignment()
>
> The last function gen_check_sp_alignment() is a NULL op currently but
> put in place to make it easy to add SP alignment checking later.
>
> Signed-off-by: Alex Bennée <alex.bennee@linaro.org>
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
> ---
>
> Changes
>   - merge ldp/stp together
>   - add read_cpu_reg_sp() and use
>   - only reference registers as needed
>   - use common tcg ops for gpr/fp loads/store
> ---
>  target-arm/translate-a64.c | 268 ++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 263 insertions(+), 5 deletions(-)
>
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 0a76130..018b3ee 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -99,6 +99,15 @@ void aarch64_cpu_dump_state(CPUState *cs, FILE *f,
>      cpu_fprintf(f, "\n");
>  }
>
> +static int get_mem_index(DisasContext *s)
> +{
> +#ifdef CONFIG_USER_ONLY
> +    return 1;
> +#else
> +    return s->user;
> +#endif
> +}
> +
>  void gen_a64_set_pc_im(uint64_t val)
>  {
>      tcg_gen_movi_i64(cpu_pc, val);
> @@ -250,6 +259,17 @@ static TCGv_i64 read_cpu_reg(DisasContext *s, int reg, int sf)
>      return v;
>  }
>
> +static TCGv_i64 read_cpu_reg_sp(DisasContext *s, int reg, int sf)
> +{
> +    TCGv_i64 v = new_tmp_a64(s);
> +    if (sf) {
> +        tcg_gen_mov_i64(v, cpu_X[reg]);
> +    } else {
> +        tcg_gen_ext32u_i64(v, cpu_X[reg]);
> +    }
> +    return v;
> +}
> +
>  /* Set ZF and NF based on a 64 bit result. This is alas fiddlier
>   * than the 32 bit equivalent.
>   */
> @@ -278,6 +298,124 @@ static inline void gen_logic_CC(int sf, TCGv_i64 result)
>  }
>
>  /*
> + * Load/Store generators
> + */
> +
> +/*
> + *  Store from GPR register to memory
> + */
> +static void do_gpr_st(DisasContext *s, TCGv_i64 source,
> +                      TCGv_i64 tcg_addr, int size)
> +{
> +    g_assert(size <= 3);
> +    tcg_gen_qemu_st_i64(source, tcg_addr, get_mem_index(s), MO_TE + size);
> +}
> +
> +/*
> + * Load from memory to GPR register
> + */
> +static void do_gpr_ld(DisasContext *s, TCGv_i64 dest, TCGv_i64 tcg_addr,
> +                      int size, bool is_signed, bool extend)
> +{
> +    TCGMemOp memop =  MO_TE + size;
> +
> +    g_assert(size <= 3);
> +
> +    if (is_signed) {
> +        memop += MO_SIGN;
> +    }
> +
> +    tcg_gen_qemu_ld_i64(dest, tcg_addr, get_mem_index(s), memop);
> +
> +    if (extend && is_signed) {
> +        g_assert(size < 3);
> +        tcg_gen_ext32u_i64(dest, dest);
> +    }
> +}
> +
> +/*
> + * Store from FP register to memory
> + */
> +static void do_fp_st(DisasContext *s, int srcidx, TCGv_i64 tcg_addr, int size)
> +{
> +    /* This writes the bottom N bits of a 128 bit wide vector to memory */
> +    int freg_offs = offsetof(CPUARMState, vfp.regs[srcidx * 2]);
> +    TCGv_i64 tmp = tcg_temp_new_i64();
> +
> +    if (size < 4) {
> +        switch (size) {
> +        case 0:
> +            tcg_gen_ld8u_i64(tmp, cpu_env, freg_offs);
> +            break;
> +        case 1:
> +            tcg_gen_ld16u_i64(tmp, cpu_env, freg_offs);
> +            break;
> +        case 2:
> +            tcg_gen_ld32u_i64(tmp, cpu_env, freg_offs);
> +            break;
> +        case 3:
> +            tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
> +            break;
> +        }
> +        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TE + size);
> +    } else {
> +        TCGv_i64 tcg_hiaddr = tcg_temp_new_i64();
> +        tcg_gen_ld_i64(tmp, cpu_env, freg_offs);
> +        tcg_gen_qemu_st_i64(tmp, tcg_addr, get_mem_index(s), MO_TEQ);
> +        tcg_gen_qemu_st64(tmp, tcg_addr, get_mem_index(s));
> +        tcg_gen_ld_i64(tmp, cpu_env, freg_offs + sizeof(float64));
> +        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
> +        tcg_gen_qemu_st_i64(tmp, tcg_hiaddr, get_mem_index(s), MO_TEQ);
> +        tcg_temp_free_i64(tcg_hiaddr);
> +    }
> +
> +    tcg_temp_free_i64(tmp);
> +}
> +
> +/* Load from memory to FP register */
> +static void do_fp_ld(DisasContext *s, int destidx, TCGv_i64 tcg_addr, int size)
> +{
> +    /* This always zero-extends and writes to a full 128 bit wide vector */
> +    int freg_offs = offsetof(CPUARMState, vfp.regs[destidx * 2]);
> +    TCGv_i64 tmplo = tcg_temp_new_i64();
> +    TCGv_i64 tmphi;
> +
> +    if (size < 4) {
> +        TCGMemOp memop =  MO_TE + size;
> +        tmphi = tcg_const_i64(0);
> +        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), memop);
> +    } else {
> +        TCGv_i64 tcg_hiaddr;
> +        tmphi = tcg_temp_new_i64();
> +        tcg_hiaddr = tcg_temp_new_i64();
> +
> +        tcg_gen_qemu_ld_i64(tmplo, tcg_addr, get_mem_index(s), MO_TEQ);
> +        tcg_gen_addi_i64(tcg_hiaddr, tcg_addr, 8);
> +        tcg_gen_qemu_ld_i64(tmphi, tcg_hiaddr, get_mem_index(s), MO_TEQ);
> +        tcg_temp_free_i64(tcg_hiaddr);
> +    }
> +
> +    tcg_gen_st_i64(tmplo, cpu_env, freg_offs);
> +    tcg_gen_st_i64(tmphi, cpu_env, freg_offs + sizeof(float64));
> +
> +    tcg_temp_free_i64(tmplo);
> +    tcg_temp_free_i64(tmphi);
> +}
> +
> +static inline void gen_check_sp_alignment(DisasContext *s)
> +{
> +    /* The AArch64 architecture mandates that (if enabled via PSTATE
> +     * or SCTLR bits) there is a check that SP is 16-aligned on every
> +     * SP-relative load or store (with an exception generated if it is not).
> +     * In line with general QEMU practice regarding misaligned accesses,
> +     * we omit these checks for the sake of guest program performance.
> +     * This function is provided as a hook so we can more easily add these
> +     * checks in future (possibly as a "favour catching guest program bugs
> +     * over speed" user selectable option).
> +     */
> +}
> +
> +/*
>   * the instruction disassembly implemented here matches
>   * the instruction encoding classifications in chapter 3 (C3)
>   * of the ARM Architecture Reference Manual (DDI0487A_a)
> @@ -620,10 +758,130 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
>      unsupported_encoding(s, insn);
>  }
>
> -/* Load/store pair (all forms) */
> -static void disas_ldst_pair(DisasContext *s, uint32_t insn)
> -{
> -    unsupported_encoding(s, insn);
> +/*
> + * C5.6.81 LDP (Load Pair - non vector)
> + * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
> + * C5.6.177 STP (Store Pair - non vector)
> + * C6.3.165 LDP (Load Pair of SIMD&FP)
> + * C6.3.284 STP (Store Pair of SIMD&FP)
> + *
> + *  31 30 29   27  26 25   23  22 21   15 14   10 9    5 4    0
> + * +-----+-------+---+-------+---+-----------------------------+
> + * | opc | 1 0 1 | V | index | L |  imm7 |  Rt2  |  Rn  | Rt   |
> + * +-----+-------+---+-------+---+-------+-------+------+------+
> + *
> + * opc: LDP&STP       00 -> 32 bit, 10 -> 64 bit
> + *      LDPSW         01
> + *      LDP&STP(SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
> + *   V: 0 -> GPR, 1 -> Vector
> + * idx: 001 -> post-index, 011 -> pre-index, 010 -> signed off
> + *   L: 0 -> Store 1 -> Load
> + *
> + * Rt, Rt2 = GPR or SIMD registers to be stored
> + * Rn = general purpose register containing address
> + * imm7 = signed offset (multiple of 4 or 8 depending on size)
> + */
> +static void handle_ldst_pair(DisasContext *s, uint32_t insn)
> +{
> +    int rt = extract32(insn, 0, 5);
> +    int rn = extract32(insn, 5, 5);
> +    int rt2 = extract32(insn, 10, 5);
> +    int64_t offset = sextract32(insn, 15, 7);
> +    int index = extract32(insn, 23, 2);
> +    bool is_vector = extract32(insn, 26, 1);
> +    bool is_load = extract32(insn, 22, 1);
> +    int opc = extract32(insn, 30, 2);
> +
> +    bool is_signed = false;
> +    bool postindex = false;
> +    bool wback = false;
> +
> +    TCGv_i64 tcg_addr; /* calculated address */
> +    int size;
> +
> +    if (is_vector) {
> +        if (opc == 3) {
> +            unallocated_encoding(s);
> +            return;
> +        }
> +        size = 2 + opc;
> +    } else {
> +        size = 2 + extract32(opc, 1, 1);
> +        if (is_load) {
> +            is_signed = opc & 1;
> +        } else if (opc & 1) {
> +            unallocated_encoding(s);
> +            return;
> +        }
> +    }
> +
> +    switch (index) {
> +    case 1: /* post-index */
> +        postindex = true;
> +        wback = true;
> +        break;
> +    case 2: /* signed offset, rn not updated */
> +        postindex = false;
> +        break;
> +    case 3: /* pre-index */
> +        postindex = false;
> +        wback = true;
> +        break;
> +    default: /* Failed decoder tree? */
> +        unallocated_encoding(s);
> +        break;
> +    }

This doesn't seem right (break instead of return):

default:
    unallocated_encoding(s);
    return;
}

> +
> +    offset <<= size;
> +
> +    if (rn == 31) {
> +        gen_check_sp_alignment(s);
> +    }
> +
> +    tcg_addr = read_cpu_reg_sp(s, rn, 1);
> +
> +    if (!postindex) {
> +        tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
> +    }
> +
> +    if (is_vector) {
> +        if (is_load) {
> +            do_fp_ld(s, rt, tcg_addr, size);
> +        } else {
> +            do_fp_st(s, rt, tcg_addr, size);
> +        }
> +    } else {
> +        TCGv_i64 tcg_rt = cpu_reg(s, rt);
> +        if (is_load) {
> +            do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed, false);
> +        } else {
> +            do_gpr_st(s, tcg_rt, tcg_addr, size);
> +        }
> +    }
> +    tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
> +    if (is_vector) {
> +        if (is_load) {
> +            do_fp_ld(s, rt2, tcg_addr, size);
> +        } else {
> +            do_fp_st(s, rt2, tcg_addr, size);
> +        }
> +    } else {
> +        TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
> +        if (is_load) {
> +            do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed, false);
> +        } else {
> +            do_gpr_st(s, tcg_rt2, tcg_addr, size);
> +        }
> +    }
> +
> +    if (wback) {
> +        if (postindex) {
> +            tcg_gen_addi_i64(tcg_addr, tcg_addr, offset - (1 << size));
> +        } else {
> +            tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
> +        }
> +        tcg_gen_mov_i64(cpu_reg_sp(s, rn), tcg_addr);
> +    }
>  }
>
>  /* Load/store register (all forms) */
> @@ -656,7 +914,7 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
>          break;
>      case 0x28: case 0x29:
>      case 0x2c: case 0x2d: /* Load/store pair (all forms) */
> -        disas_ldst_pair(s, insn);
> +        handle_ldst_pair(s, insn);
>          break;
>      case 0x38: case 0x39:
>      case 0x3c: case 0x3d: /* Load/store register (all forms) */
> --
> 1.8.5
>

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-12  9:54   ` C Fontana
@ 2013-12-12 11:43     ` Alex Bennée
  2013-12-12 11:45       ` Peter Maydell
  0 siblings, 1 reply; 14+ messages in thread
From: Alex Bennée @ 2013-12-12 11:43 UTC (permalink / raw)
  To: C Fontana
  Cc: Peter Maydell, Patch Tracking, Michael Matz, QEMU Developers,
	Will Newton, Dirk Mueller, Laurent Desnogues,
	kvmarm@lists.cs.columbia.edu, Christoffer Dall, Richard Henderson


claudio.fontana@linaro.org writes:

> Hi,
>
> I saw a missing return below:
<snip>
>> +    default: /* Failed decoder tree? */
>> +        unallocated_encoding(s);
>> +        break;
>> +    }
>
> This doesn't seem right (break instead of return):
>
> default:
>     unallocated_encoding(s);
>     return;
> }

Good catch. I suspect it never hits though (or risu doesn't generate
enough unallocated versions).

-- 
Alex Bennée
QEMU/KVM Hacker for Linaro

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-12 11:43     ` Alex Bennée
@ 2013-12-12 11:45       ` Peter Maydell
  2013-12-12 12:14         ` C Fontana
  0 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2013-12-12 11:45 UTC (permalink / raw)
  To: Alex Bennée
  Cc: Patch Tracking, Michael Matz, QEMU Developers, C Fontana,
	Dirk Mueller, Will Newton, Laurent Desnogues,
	kvmarm@lists.cs.columbia.edu, Christoffer Dall, Richard Henderson

On 12 December 2013 11:43, Alex Bennée <alex.bennee@linaro.org> wrote:
>
> claudio.fontana@linaro.org writes:
>
>> Hi,
>>
>> I saw a missing return below:
> <snip>
>>> +    default: /* Failed decoder tree? */
>>> +        unallocated_encoding(s);
>>> +        break;
>>> +    }
>>
>> This doesn't seem right (break instead of return):
>>
>> default:
>>     unallocated_encoding(s);
>>     return;
>> }
>
> Good catch. I suspect it never hits though (or risu doesn't generate
> enough unallocated versions).

Oh, I saw that and then forgot to mention it.
Either the comment or the code is wrong -- if
the decoder tree prevents us getting to this point
with that value of index then we should be asserting,
not calling unallocated_encoding(). If the encoding
is really supposed to be unallocated then it's not
a failure of the decoder tree that we got here,
it's just another case we need to check. Which is it?

thanks
-- PMM

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-12 11:45       ` Peter Maydell
@ 2013-12-12 12:14         ` C Fontana
  2013-12-13 14:34           ` Peter Maydell
  0 siblings, 1 reply; 14+ messages in thread
From: C Fontana @ 2013-12-12 12:14 UTC (permalink / raw)
  To: Peter Maydell
  Cc: Patch Tracking, Michael Matz, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée,
	kvmarm@lists.cs.columbia.edu, Christoffer Dall, Richard Henderson

On 12 December 2013 12:45, Peter Maydell <peter.maydell@linaro.org> wrote:
> On 12 December 2013 11:43, Alex Bennée <alex.bennee@linaro.org> wrote:
>>
>> claudio.fontana@linaro.org writes:
>>
>>> Hi,
>>>
>>> I saw a missing return below:
>> <snip>
>>>> +    default: /* Failed decoder tree? */
>>>> +        unallocated_encoding(s);
>>>> +        break;
>>>> +    }
>>>
>>> This doesn't seem right (break instead of return):
>>>
>>> default:
>>>     unallocated_encoding(s);
>>>     return;
>>> }
>>
>> Good catch. I suspect it never hits though (or risu doesn't generate
>> enough unallocated versions).
>
> Oh, I saw that and then forgot to mention it.
> Either the comment or the code is wrong -- if
> the decoder tree prevents us getting to this point
> with that value of index then we should be asserting,
> not calling unallocated_encoding(). If the encoding
> is really supposed to be unallocated then it's not
> a failure of the decoder tree that we got here,
> it's just another case we need to check. Which is it?
>
> thanks
> -- PMM

I think that there is more than the missing return:

we need to handle the case 0 as well, as it's a perfectly valid form
of a load/store pair:
it's the Load/Store no-allocate pair (offset) (LDNP, STNP).

So in my view we need to add a case 0 where we handle  the load/store
no-allocate pair,
and no default case, or a default case where we assert(0) for unreachable code,
since all possible index values (2 bits) should be handled by the
switch statement.

Ref: C3.3 Loads and stores Table C3-3

Claudio

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair
  2013-12-12 12:14         ` C Fontana
@ 2013-12-13 14:34           ` Peter Maydell
  0 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 14:34 UTC (permalink / raw)
  To: C Fontana
  Cc: Patch Tracking, Michael Matz, QEMU Developers, Will Newton,
	Dirk Mueller, Laurent Desnogues, Alex Bennée,
	kvmarm@lists.cs.columbia.edu, Christoffer Dall, Richard Henderson

On 12 December 2013 12:14, C Fontana <claudio.fontana@linaro.org> wrote:
> I think that there is more than the missing return:
>
> we need to handle the case 0 as well, as it's a perfectly valid form
> of a load/store pair:
> it's the Load/Store no-allocate pair (offset) (LDNP, STNP).
>
> So in my view we need to add a case 0 where we handle  the load/store
> no-allocate pair,
> and no default case, or a default case where we assert(0) for unreachable code,
> since all possible index values (2 bits) should be handled by the
> switch statement.

Yep. I've added support for the non-temporal versions
(pretty easy since qemu doesn't care about cache allocation
hints) to my patchstack so we'll get this in the next
version of the patchset.

thanks
-- PMM

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2013-12-13 14:35 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-12-11 22:01 [Qemu-devel] [PATCH v2 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
2013-12-12  9:54   ` C Fontana
2013-12-12 11:43     ` Alex Bennée
2013-12-12 11:45       ` Peter Maydell
2013-12-12 12:14         ` C Fontana
2013-12-13 14:34           ` Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 2/8] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 3/8] target-arm: A64: add support for ld/st with reg offset Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 4/8] target-arm: A64: add support for ld/st with index Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 5/8] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 6/8] target-arm: A64: add support for move wide instructions Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
2013-12-11 22:01 ` [Qemu-devel] [PATCH v2 8/8] target-arm: A64: implement SVC, BRK Peter Maydell

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.