summaryrefslogtreecommitdiffstats
path: root/target/arm
diff options
context:
space:
mode:
authorPeter Maydell2020-02-24 18:28:46 +0100
committerPeter Maydell2020-02-28 17:14:57 +0100
commita1229109dec4375259d3fff99f362405aab7917a (patch)
treefa861ddfe41b9f6e1864945ecfc7206be3af1cb9 /target/arm
parenttarget/arm: Implement v8.3-RCPC (diff)
downloadqemu-a1229109dec4375259d3fff99f362405aab7917a.tar.gz
qemu-a1229109dec4375259d3fff99f362405aab7917a.tar.xz
qemu-a1229109dec4375259d3fff99f362405aab7917a.zip
target/arm: Implement v8.4-RCPC
The v8.4-RCPC extension implements some new instructions: * LDAPUR, LDAPURB, LDAPURH, LDAPRSB, LDAPRSH, LDAPRSW * STLUR, STLURB, STLURH These are all in a new subgroup of encodings that sits below the top-level "Loads and Stores" group in the Arm ARM. The STLUR* instructions have standard store-release semantics; the LDAPUR* have Load-AcquirePC semantics, but (as with LDAPR*) we choose to implement them as the slightly stronger Load-Acquire. Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20200224172846.13053-4-peter.maydell@linaro.org
Diffstat (limited to 'target/arm')
-rw-r--r--target/arm/cpu.h5
-rw-r--r--target/arm/cpu64.c2
-rw-r--r--target/arm/translate-a64.c90
3 files changed, 96 insertions, 1 deletions
diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index ff30985ead..ce1e2a090e 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -3779,6 +3779,11 @@ static inline bool isar_feature_aa64_rcpc_8_3(const ARMISARegisters *id)
return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) != 0;
}
+static inline bool isar_feature_aa64_rcpc_8_4(const ARMISARegisters *id)
+{
+ return FIELD_EX64(id->id_aa64isar1, ID_AA64ISAR1, LRCPC) >= 2;
+}
+
/*
* Feature tests for "does this exist in either 32-bit or 64-bit?"
*/
diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 18c7b40f98..b842e2b664 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -654,7 +654,7 @@ static void aarch64_max_initfn(Object *obj)
t = FIELD_DP64(t, ID_AA64ISAR1, SB, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, SPECRES, 1);
t = FIELD_DP64(t, ID_AA64ISAR1, FRINTTS, 1);
- t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 1); /* ARMv8.3-RCPC */
+ t = FIELD_DP64(t, ID_AA64ISAR1, LRCPC, 2); /* ARMv8.4-RCPC */
cpu->isar.id_aa64isar1 = t;
t = cpu->isar.id_aa64pfr0;
diff --git a/target/arm/translate-a64.c b/target/arm/translate-a64.c
index 7a066fb7cb..579180af0a 100644
--- a/target/arm/translate-a64.c
+++ b/target/arm/translate-a64.c
@@ -3283,6 +3283,88 @@ static void disas_ldst_pac(DisasContext *s, uint32_t insn,
}
}
+/*
+ * LDAPR/STLR (unscaled immediate)
+ *
+ * 31 30 24 22 21 12 10 5 0
+ * +------+-------------+-----+---+--------+-----+----+-----+
+ * | size | 0 1 1 0 0 1 | opc | 0 | imm9 | 0 0 | Rn | Rt |
+ * +------+-------------+-----+---+--------+-----+----+-----+
+ *
+ * Rt: source or destination register
+ * Rn: base register
+ * imm9: unscaled immediate offset
+ * opc: 00: STLUR*, 01/10/11: various LDAPUR*
+ * size: size of load/store
+ */
+static void disas_ldst_ldapr_stlr(DisasContext *s, uint32_t insn)
+{
+ int rt = extract32(insn, 0, 5);
+ int rn = extract32(insn, 5, 5);
+ int offset = sextract32(insn, 12, 9);
+ int opc = extract32(insn, 22, 2);
+ int size = extract32(insn, 30, 2);
+ TCGv_i64 clean_addr, dirty_addr;
+ bool is_store = false;
+ bool is_signed = false;
+ bool extend = false;
+ bool iss_sf;
+
+ if (!dc_isar_feature(aa64_rcpc_8_4, s)) {
+ unallocated_encoding(s);
+ return;
+ }
+
+ switch (opc) {
+ case 0: /* STLURB */
+ is_store = true;
+ break;
+ case 1: /* LDAPUR* */
+ break;
+ case 2: /* LDAPURS* 64-bit variant */
+ if (size == 3) {
+ unallocated_encoding(s);
+ return;
+ }
+ is_signed = true;
+ break;
+ case 3: /* LDAPURS* 32-bit variant */
+ if (size > 1) {
+ unallocated_encoding(s);
+ return;
+ }
+ is_signed = true;
+ extend = true; /* zero-extend 32->64 after signed load */
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ iss_sf = disas_ldst_compute_iss_sf(size, is_signed, opc);
+
+ if (rn == 31) {
+ gen_check_sp_alignment(s);
+ }
+
+ dirty_addr = read_cpu_reg_sp(s, rn, 1);
+ tcg_gen_addi_i64(dirty_addr, dirty_addr, offset);
+ clean_addr = clean_data_tbi(s, dirty_addr);
+
+ if (is_store) {
+ /* Store-Release semantics */
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_STRL);
+ do_gpr_st(s, cpu_reg(s, rt), clean_addr, size, true, rt, iss_sf, true);
+ } else {
+ /*
+ * Load-AcquirePC semantics; we implement as the slightly more
+ * restrictive Load-Acquire.
+ */
+ do_gpr_ld(s, cpu_reg(s, rt), clean_addr, size, is_signed, extend,
+ true, rt, iss_sf, true);
+ tcg_gen_mb(TCG_MO_ALL | TCG_BAR_LDAQ);
+ }
+}
+
/* Load/store register (all forms) */
static void disas_ldst_reg(DisasContext *s, uint32_t insn)
{
@@ -3634,6 +3716,14 @@ static void disas_ldst(DisasContext *s, uint32_t insn)
case 0x0d: /* AdvSIMD load/store single structure */
disas_ldst_single_struct(s, insn);
break;
+ case 0x19: /* LDAPR/STLR (unscaled immediate) */
+ if (extract32(insn, 10, 2) != 0 ||
+ extract32(insn, 21, 1) != 0) {
+ unallocated_encoding(s);
+ break;
+ }
+ disas_ldst_ldapr_stlr(s, insn);
+ break;
default:
unallocated_encoding(s);
break;