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-03 21:22:40 +0000
commit90cb0e2742b8483ef44243d3967bf3fd805e563a (patch)
treecfaac11f7906abad35f898673830b696b97651fd
parentf51bf344689b0be285d73f07ecf663af4d68ed28 (diff)
add ldp/stp vector formsa64-first-set-test-context
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 da6c742a63..6e1acff7f1 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -1259,6 +1259,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)
{
@@ -1267,10 +1270,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;
@@ -1278,6 +1281,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;
@@ -1306,9 +1320,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);
@@ -1337,6 +1359,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)
{
@@ -1345,14 +1369,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) */
@@ -1383,9 +1422,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);
@@ -1428,6 +1475,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)
{