* [Qemu-devel] [PATCH v3 1/8] target-arm: A64: add support for ld/st pair
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
@ 2013-12-13 19:17 ` Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 2/8] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
` (6 subsequent siblings)
7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 19:17 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>
---
target-arm/translate-a64.c | 277 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 275 insertions(+), 2 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 0a76130..e4ce038 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,145 @@ static void disas_ld_lit(DisasContext *s, uint32_t insn)
unsupported_encoding(s, insn);
}
-/* Load/store pair (all forms) */
+/*
+ * C5.6.80 LDNP (Load Pair - non-temporal hint)
+ * C5.6.81 LDP (Load Pair - non vector)
+ * C5.6.82 LDPSW (Load Pair Signed Word - non vector)
+ * C5.6.176 STNP (Store Pair - non-temporal hint)
+ * C5.6.177 STP (Store Pair - non vector)
+ * C6.3.165 LDNP (Load Pair of SIMD&FP - non-temporal hint)
+ * C6.3.165 LDP (Load Pair of SIMD&FP)
+ * C6.3.284 STNP (Store Pair of SIMD&FP - non-temporal hint)
+ * C6.3.284 STP (Store Pair of SIMD&FP)
+ *
+ * 31 30 29 27 26 25 24 23 22 21 15 14 10 9 5 4 0
+ * +-----+-------+---+---+-------+---+-----------------------------+
+ * | opc | 1 0 1 | V | 0 | index | L | imm7 | Rt2 | Rn | Rt |
+ * +-----+-------+---+---+-------+---+-------+-------+------+------+
+ *
+ * opc: LDP/STP/LDNP/STNP 00 -> 32 bit, 10 -> 64 bit
+ * LDPSW 01
+ * LDP/STP/LDNP/STNP (SIMD) 00 -> 32 bit, 01 -> 64 bit, 10 -> 128 bit
+ * V: 0 -> GPR, 1 -> Vector
+ * idx: 00 -> signed offset with non-temporal hint, 01 -> post-index,
+ * 10 -> signed offset, 11 -> pre-index
+ * 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 disas_ldst_pair(DisasContext *s, uint32_t insn)
{
- unsupported_encoding(s, 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 0:
+ /* signed offset with "non-temporal" hint. Since we don't emulate
+ * caches we don't care about hints to the cache system about
+ * data access patterns, and handle this identically to plain
+ * signed offset.
+ */
+ if (is_signed) {
+ /* There is no non-temporal-hint version of LDPSW */
+ unallocated_encoding(s);
+ return;
+ }
+ postindex = false;
+ break;
+ case 2: /* signed offset, rn not updated */
+ postindex = false;
+ break;
+ case 3: /* pre-index */
+ postindex = false;
+ wback = true;
+ 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) */
--
1.8.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v3 2/8] target-arm: A64: add support for ld/st unsigned imm
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
@ 2013-12-13 19:17 ` Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 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-13 19:17 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>
---
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 e4ce038..3712a6d 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -899,10 +899,97 @@ static void disas_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 disas_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:
+ disas_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 v3 3/8] target-arm: A64: add support for ld/st with reg offset
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 1/8] target-arm: A64: add support for ld/st pair Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 2/8] target-arm: A64: add support for ld/st unsigned imm Peter Maydell
@ 2013-12-13 19:17 ` Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 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-13 19:17 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 3712a6d..742c714 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
@@ -900,6 +948,96 @@ static void disas_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 disas_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
@@ -981,7 +1119,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) {
+ disas_ldst_reg_roffset(s, insn);
+ } else {
+ unsupported_encoding(s, insn);
+ }
break;
case 1:
disas_ldst_reg_unsigned_imm(s, insn);
--
1.8.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v3 4/8] target-arm: A64: add support for ld/st with index
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
` (2 preceding siblings ...)
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 3/8] target-arm: A64: add support for ld/st with reg offset Peter Maydell
@ 2013-12-13 19:17 ` Peter Maydell
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 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-13 19:17 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 742c714..1b34a98 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -948,6 +948,110 @@ static void disas_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 disas_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
@@ -1114,6 +1218,25 @@ static void disas_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 */
+ disas_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)
{
@@ -1122,7 +1245,7 @@ static void disas_ldst_reg(DisasContext *s, uint32_t insn)
if (extract32(insn, 21, 1) == 1 && extract32(insn, 10, 2) == 2) {
disas_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 v3 5/8] target-arm: A64: add support for add, addi, sub, subi
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
` (3 preceding siblings ...)
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 4/8] target-arm: A64: add support for ld/st with index Peter Maydell
@ 2013-12-13 19:17 ` Peter Maydell
2013-12-16 10:11 ` C Fontana
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 6/8] target-arm: A64: add support for move wide instructions Peter Maydell
` (2 subsequent siblings)
7 siblings, 1 reply; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 19:17 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>
---
target-arm/translate-a64.c | 291 ++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 285 insertions(+), 6 deletions(-)
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 1b34a98..00dd369 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
*/
@@ -1326,10 +1422,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
@@ -1787,16 +1940,142 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn)
}
}
-/* Add/subtract (extended register) */
+/*
+ * 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 disas_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) */
+/*
+ * 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 disas_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) */
--
1.8.5
^ permalink raw reply related [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v3 5/8] target-arm: A64: add support for add, addi, sub, subi
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 5/8] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
@ 2013-12-16 10:11 ` C Fontana
2013-12-16 10:48 ` Peter Maydell
0 siblings, 1 reply; 14+ messages in thread
From: C Fontana @ 2013-12-16 10:11 UTC (permalink / raw)
To: Peter Maydell
Cc: Patch Tracking, Michael Matz, QEMU Developers, Will Newton,
Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
Christoffer Dall, Richard Henderson
Sorry for noticing only now,
but there is a missing return here as well I think:
On 13 December 2013 20:17, Peter Maydell <peter.maydell@linaro.org> wrote:
> 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>
> ---
> target-arm/translate-a64.c | 291 ++++++++++++++++++++++++++++++++++++++++++++-
> 1 file changed, 285 insertions(+), 6 deletions(-)
>
> diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
> index 1b34a98..00dd369 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
> */
> @@ -1326,10 +1422,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);
should return; here I think.
> + }
> +
> + 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
> @@ -1787,16 +1940,142 @@ static void disas_logic_reg(DisasContext *s, uint32_t insn)
> }
> }
>
> -/* Add/subtract (extended register) */
> +/*
> + * 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 disas_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) */
> +/*
> + * 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 disas_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) */
> --
> 1.8.5
>
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v3 5/8] target-arm: A64: add support for add, addi, sub, subi
2013-12-16 10:11 ` C Fontana
@ 2013-12-16 10:48 ` Peter Maydell
0 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-16 10:48 UTC (permalink / raw)
To: C Fontana
Cc: Patch Tracking, Michael Matz, QEMU Developers, Will Newton,
Dirk Mueller, Laurent Desnogues, Alex Bennée, kvmarm,
Christoffer Dall, Richard Henderson
On 16 December 2013 10:11, C Fontana <claudio.fontana@linaro.org> wrote:
> Sorry for noticing only now,
> but there is a missing return here as well I think:
>
>> static void disas_add_sub_imm(DisasContext *s, uint32_t insn)
>> + default:
>> + unallocated_encoding(s);
>
> should return; here I think.
Yes, fixed.
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v3 6/8] target-arm: A64: add support for move wide instructions
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
` (4 preceding siblings ...)
2013-12-13 19:17 ` [Qemu-devel] [PATCH v3 5/8] target-arm: A64: add support for add, addi, sub, subi Peter Maydell
@ 2013-12-13 19:18 ` Peter Maydell
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 8/8] target-arm: A64: implement SVC, BRK Peter Maydell
7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 19:18 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 00dd369..a6f1945 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1641,10 +1641,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 v3 7/8] target-arm: A64: add support for 3 src data proc insns
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
` (5 preceding siblings ...)
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 6/8] target-arm: A64: add support for move wide instructions Peter Maydell
@ 2013-12-13 19:18 ` Peter Maydell
2013-12-16 8:54 ` Claudio Fontana
2013-12-16 10:49 ` Peter Maydell
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 8/8] target-arm: A64: implement SVC, BRK Peter Maydell
7 siblings, 2 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 19:18 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>
---
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 a6f1945..b3e9449 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -2125,10 +2125,97 @@ static void disas_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
* Re: [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
@ 2013-12-16 8:54 ` Claudio Fontana
2013-12-16 9:36 ` Peter Maydell
2013-12-16 10:49 ` Peter Maydell
1 sibling, 1 reply; 14+ messages in thread
From: Claudio Fontana @ 2013-12-16 8:54 UTC (permalink / raw)
To: Peter Maydell, qemu-devel
Cc: Laurent Desnogues, patches, Michael Matz, Claudio Fontana,
Dirk Mueller, Will Newton, Alex Bennée, kvmarm,
Christoffer Dall, Richard Henderson
Hello Peter,
On 13.12.2013 20:18, Peter Maydell wrote:
> 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>
> ---
> 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 a6f1945..b3e9449 100644
> --- a/target-arm/translate-a64.c
> +++ b/target-arm/translate-a64.c
> @@ -2125,10 +2125,97 @@ static void disas_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);
we have used "sf" everywhere else..
> + 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);
should this be tcg_temp_free_i64()?
> + 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) */
>
Ciao,
Claudio
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns
2013-12-16 8:54 ` Claudio Fontana
@ 2013-12-16 9:36 ` Peter Maydell
0 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-16 9:36 UTC (permalink / raw)
To: Claudio Fontana
Cc: Laurent Desnogues, Patch Tracking, Michael Matz, QEMU Developers,
Claudio Fontana, Dirk Mueller, Will Newton, Alex Bennée,
kvmarm, Christoffer Dall, Richard Henderson
On 16 December 2013 08:54, Claudio Fontana <claudio.fontana@huawei.com> wrote:
> Hello Peter,
>
> On 13.12.2013 20:18, Peter Maydell wrote:
>> 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>
>> ---
>> 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 a6f1945..b3e9449 100644
>> --- a/target-arm/translate-a64.c
>> +++ b/target-arm/translate-a64.c
>> @@ -2125,10 +2125,97 @@ static void disas_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);
>
> we have used "sf" everywhere else..
Yes, might as well be consistent.
>> + tcg_temp_free(low_bits);
>
> should this be tcg_temp_free_i64()?
Yes, since we're preferring to be explicit about i32 vs i64
temps. (We know we're always building a 64 bit binary for
translate-a64.c so in fact we can guarantee that tcg_temp_free
is always tcg_temp_free_i64; but consistency with the 32 bit
decoder is nice.)
Fixed these nits in my working tree.
thanks
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* Re: [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
2013-12-16 8:54 ` Claudio Fontana
@ 2013-12-16 10:49 ` Peter Maydell
1 sibling, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-16 10:49 UTC (permalink / raw)
To: QEMU Developers
Cc: Laurent Desnogues, Patch Tracking, Michael Matz, Claudio Fontana,
Dirk Mueller, Will Newton, kvmarm, Richard Henderson
On 13 December 2013 19:18, Peter Maydell <peter.maydell@linaro.org> wrote:
> 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);
> + }
Missing 'return' after unallocated_encoding(), fixed in my
working tree.
thanks
-- PMM
^ permalink raw reply [flat|nested] 14+ messages in thread
* [Qemu-devel] [PATCH v3 8/8] target-arm: A64: implement SVC, BRK
2013-12-13 19:17 [Qemu-devel] [PATCH v3 0/8] target-arm: A64 decoder set 3: loads, stores, misc integer Peter Maydell
` (6 preceding siblings ...)
2013-12-13 19:18 ` [Qemu-devel] [PATCH v3 7/8] target-arm: A64: add support for 3 src data proc insns Peter Maydell
@ 2013-12-13 19:18 ` Peter Maydell
7 siblings, 0 replies; 14+ messages in thread
From: Peter Maydell @ 2013-12-13 19:18 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 b3e9449..56d1616 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