aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2013-12-01 13:57:55 +0000
committerPeter Maydell <peter.maydell@linaro.org>2013-12-01 14:33:36 +0000
commit8ae1aa47f0ec7475d69de3d63e8eb9e85e1e4862 (patch)
treeb32539f6a4d2cb3117518fd79f6b99d89cf5d6fc
parentbedc64035d7f334b105817687e20b6de45330215 (diff)
downloadqemu-arm-8ae1aa47f0ec7475d69de3d63e8eb9e85e1e4862.tar.gz
add ldp/stp vector forms
ldp/stp decode wasn't checking the vector bit, so we wrote the int regs by mistake for LDP d8,d9,[sp,#96] Add support. Note to Alex: we really should fold the load and store support together better, most of the decode is the same at the bottom level. Possibly factoring out the 'if vector do_fp_st else do_gpr_st' logic as the suse patches do would also be a good plan. I've left some XXX notes about updating comments in this one. Oh yes, we should check the semantics for what happens if the second load of the pair faults -- currently we update the first register, but I have a feeling maybe we should not.
-rw-r--r--target-arm/translate-a64.c69
1 files changed, 59 insertions, 10 deletions
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index efc2288f75..161f18bb66 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1248,6 +1248,9 @@ static void handle_ld_lit(DisasContext *s, uint32_t insn)
s: 0 -> unsigned, 1 -> signed
idx: 001 -> post-index, 011 -> pre-index, 010 -> signed off
+XXX update: supports V=1
+XXX diagram above is wrong, bits 31:30 are opc
+
*/
static void handle_gpr_ldp(DisasContext *s, uint32_t insn)
{
@@ -1256,10 +1259,10 @@ static void handle_gpr_ldp(DisasContext *s, uint32_t insn)
int rt2 = extract32(insn, 10, 5);
int64_t offset = sextract32(insn, 15, 7);
int idx = extract32(insn, 23, 3);
- int is_signed = extract32(insn, 30, 1);
- int sf = extract32(insn, 31, 1);
-
- int size = sf?3:2;
+ bool is_signed = false;
+ bool is_vector = extract32(insn, 26, 1);
+ int opc = extract32(insn, 30, 2);
+ int size;
bool postindex = true;
bool wback = false;
@@ -1267,6 +1270,17 @@ static void handle_gpr_ldp(DisasContext *s, uint32_t insn)
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
TCGv_i64 tcg_addr = tcg_temp_new_i64();
+ if (opc == 3) {
+ unallocated_encoding(s);
+ return;
+ }
+ if (is_vector) {
+ size = 2 + opc;
+ } else {
+ is_signed = opc & 1;
+ size = 2 + extract32(opc, 1, 1);
+ }
+
switch (idx) {
case 1: /* post-index */
postindex = true;
@@ -1295,9 +1309,17 @@ static void handle_gpr_ldp(DisasContext *s, uint32_t insn)
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
}
- do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed);
+ if (is_vector) {
+ do_fp_ld(s, rt, tcg_addr, size);
+ } else {
+ do_gpr_ld(s, tcg_rt, tcg_addr, size, is_signed);
+ }
tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
- do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed);
+ if (is_vector) {
+ do_fp_ld(s, rt2, tcg_addr, size);
+ } else {
+ do_gpr_ld(s, tcg_rt2, tcg_addr, size, is_signed);
+ }
// XXX - this could be more optimal?
tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
@@ -1326,6 +1348,8 @@ static void handle_gpr_ldp(DisasContext *s, uint32_t insn)
Rt, Rt2 = general purpose registers to be stored
Rn = general purpose register containing address
imm7 = signed offset (multiple of 4 or 8 depending on size)
+
+XXX update comment, we accept V=1
*/
static void handle_gpr_stp(DisasContext *s, uint32_t insn)
{
@@ -1334,14 +1358,29 @@ static void handle_gpr_stp(DisasContext *s, uint32_t insn)
int rt2 = extract32(insn, 10, 5);
int64_t offset = sextract32(insn, 15, 7);
int type = extract32(insn, 23, 2);
- int is_32bit = !extract32(insn, 30, 2);
+ bool is_vector = extract32(insn, 26, 1);
+ int opc = extract32(insn, 30, 2);
TCGv_i64 tcg_rt = cpu_reg(s, rt);
TCGv_i64 tcg_rt2 = cpu_reg(s, rt2);
TCGv_i64 tcg_addr; /* calculated address */
bool postindex = false;
bool wback = false;
- int size = is_32bit ? 2 : 3;
+ int size;
+
+ if (is_vector) {
+ if (opc == 3) {
+ unallocated_encoding(s);
+ return;
+ }
+ size = 2 + opc;
+ } else {
+ size = 2 + extract32(opc, 1, 1);
+ if (opc & 1) {
+ unallocated_encoding(s);
+ return;
+ }
+ }
switch (type) {
case 1: /* STP (post-index) */
@@ -1372,9 +1411,17 @@ static void handle_gpr_stp(DisasContext *s, uint32_t insn)
tcg_gen_addi_i64(tcg_addr, tcg_addr, offset);
}
- do_gpr_st(s, tcg_rt, tcg_addr, size);
+ if (is_vector) {
+ do_fp_st(s, rt, tcg_addr, size);
+ } else {
+ do_gpr_st(s, tcg_rt, tcg_addr, size);
+ }
tcg_gen_addi_i64(tcg_addr, tcg_addr, 1 << size);
- do_gpr_st(s, tcg_rt2, tcg_addr, size);
+ if (is_vector) {
+ do_fp_st(s, rt2, tcg_addr, size);
+ } else {
+ do_gpr_st(s, tcg_rt2, tcg_addr, size);
+ }
// XXX - this could be more optimal?
tcg_gen_subi_i64(tcg_addr, tcg_addr, 1 << size);
@@ -1417,6 +1464,8 @@ static void handle_gpr_stp(DisasContext *s, uint32_t insn)
10100111 -> pre-index
10100101 -> signed offset
+XXX also handles vector forms, comment needs fixing
+
*/
static void disas_ldst_pair(DisasContext *s, uint32_t insn)
{