diff mbox

[v2,15/25] target-arm: A64: Implement minimal set of EL0-visible sysregs

Message ID 1387752607-23755-16-git-send-email-peter.maydell@linaro.org
State Accepted
Commit b0d2b7d0f084f6b33acf7c722790da683916fee3
Headers show

Commit Message

Peter Maydell Dec. 22, 2013, 10:49 p.m. UTC
Implement an initial minimal set of EL0-visible system registers:
 * NZCV
 * FPCR
 * FPSR
 * CTR_EL0
 * DCZID_EL0

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <rth@twiddle.net>
---
 target-arm/cpu.h           |  3 ++-
 target-arm/helper.c        | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 target-arm/translate-a64.c | 52 +++++++++++++++++++++++++++++++++++++++
 3 files changed, 115 insertions(+), 1 deletion(-)

Comments

Peter Maydell Jan. 4, 2014, 11:35 a.m. UTC | #1
On 4 January 2014 02:34, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +static const ARMCPRegInfo v8_cp_reginfo[] = {
>> +    /* Minimal set of EL0-visible registers. This will need to be expanded
>> +     * significantly for system emulation of AArch64 CPUs.
>> +     */
>> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>> +      .access = PL0_RW, .type = ARM_CP_NZCV },
>> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
>
> Indentation and spacing looks inconsistent.

So it does (I didn't even know it was syntactically valid to leave
a space after the '.' like that...) . Will fix.

Do you mind if I don't do a respin just for this?

thanks
-- PMM
Peter Maydell Jan. 4, 2014, 2:11 p.m. UTC | #2
On 4 January 2014 13:32, Peter Crosthwaite <peter.crosthwaite@xilinx.com> wrote:
> On Mon, Dec 23, 2013 at 8:49 AM, Peter Maydell <peter.maydell@linaro.org> wrote:
>> +static const ARMCPRegInfo v8_cp_reginfo[] = {
>> +    /* Minimal set of EL0-visible registers. This will need to be expanded
>> +     * significantly for system emulation of AArch64 CPUs.
>> +     */
>> +    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
>> +      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
>> +      .access = PL0_RW, .type = ARM_CP_NZCV },
>> +    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
>> +    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
>> +     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
>> +     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
>> +    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
>> +     * It will eventually need to have a CPU-specified reset value.
>> +     */
>
> Not sure why this can't be solved short term as there is already the
> ctr field in cpu state struct as used by 32.

I hadn't noticed that the register was aliased to the CTR AArch32 register.
NB that we can't just share a single reginfo for AArch64 and AArch32
though -- the permissions are different since in AArch32 this is accessible
only in EL1 and above.

My aim here was mostly to set out a framework for how the system
register integration will work with system emulation, but just to
provide low-effort implementations of the EL0-visible regs for
the initial user-emulation patchset. (In the SuSE patchset these are
actually just all implemented as special cases inline in translate-a64.c,
so to some extent this array is just those special cases converted over
to reginfo.)

thanks
-- PMM
diff mbox

Patch

diff --git a/target-arm/cpu.h b/target-arm/cpu.h
index 66490ce..1e0800e 100644
--- a/target-arm/cpu.h
+++ b/target-arm/cpu.h
@@ -660,7 +660,8 @@  static inline uint64_t cpreg_to_kvm_id(uint32_t cpregid)
 #define ARM_CP_IO 64
 #define ARM_CP_NOP (ARM_CP_SPECIAL | (1 << 8))
 #define ARM_CP_WFI (ARM_CP_SPECIAL | (2 << 8))
-#define ARM_LAST_SPECIAL ARM_CP_WFI
+#define ARM_CP_NZCV (ARM_CP_SPECIAL | (3 << 8))
+#define ARM_LAST_SPECIAL ARM_CP_NZCV
 /* Used only as a terminator for ARMCPRegInfo lists */
 #define ARM_CP_SENTINEL 0xffff
 /* Mask of only the flag bits in a type field */
diff --git a/target-arm/helper.c b/target-arm/helper.c
index 66214293..ca27c8e 100644
--- a/target-arm/helper.c
+++ b/target-arm/helper.c
@@ -1560,6 +1560,64 @@  static const ARMCPRegInfo lpae_cp_reginfo[] = {
     REGINFO_SENTINEL
 };
 
+static int aa64_fpcr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpcr(env);
+    return 0;
+}
+
+static int aa64_fpcr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpcr(env, value);
+    return 0;
+}
+
+static int aa64_fpsr_read(CPUARMState *env, const ARMCPRegInfo *ri,
+                          uint64_t *value)
+{
+    *value = vfp_get_fpsr(env);
+    return 0;
+}
+
+static int aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri,
+                           uint64_t value)
+{
+    vfp_set_fpsr(env, value);
+    return 0;
+}
+
+static const ARMCPRegInfo v8_cp_reginfo[] = {
+    /* Minimal set of EL0-visible registers. This will need to be expanded
+     * significantly for system emulation of AArch64 CPUs.
+     */
+    { .name = "NZCV", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 2,
+      .access = PL0_RW, .type = ARM_CP_NZCV },
+    {. name = "FPCR", .state = ARM_CP_STATE_AA64,
+     .opc0 = 3, .opc1 = 3, .opc2 = 0, .crn = 4, .crm = 4,
+     .access = PL0_RW, .readfn = aa64_fpcr_read, .writefn = aa64_fpcr_write },
+    {. name = "FPSR", .state = ARM_CP_STATE_AA64,
+     .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 4, .crm = 4,
+     .access = PL0_RW, .readfn = aa64_fpsr_read, .writefn = aa64_fpsr_write },
+    /* This claims a 32 byte cacheline size for icache and dcache, VIPT icache.
+     * It will eventually need to have a CPU-specified reset value.
+     */
+    { .name = "CTR_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 1, .crn = 0, .crm = 0,
+      .access = PL0_R, .type = ARM_CP_CONST,
+      .resetvalue = 0x80030003 },
+    /* Prohibit use of DC ZVA. OPTME: implement DC ZVA and allow its use.
+     * For system mode the DZP bit here will need to be computed, not constant.
+     */
+    { .name = "DCZID_EL0", .state = ARM_CP_STATE_AA64,
+      .opc0 = 3, .opc1 = 3, .opc2 = 7, .crn = 0, .crm = 0,
+      .access = PL0_R, .type = ARM_CP_CONST,
+      .resetvalue = 0x10 },
+    REGINFO_SENTINEL
+};
+
 static int sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value)
 {
     env->cp15.c1_sys = value;
@@ -1662,6 +1720,9 @@  void register_cp_regs_for_features(ARMCPU *cpu)
     } else {
         define_arm_cp_regs(cpu, not_v7_cp_reginfo);
     }
+    if (arm_feature(env, ARM_FEATURE_V8)) {
+        define_arm_cp_regs(cpu, v8_cp_reginfo);
+    }
     if (arm_feature(env, ARM_FEATURE_MPU)) {
         /* These are the MPU registers prior to PMSAv6. Any new
          * PMSA core later than the ARM946 will require that we
diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c
index 7a9ee82..c8ed799 100644
--- a/target-arm/translate-a64.c
+++ b/target-arm/translate-a64.c
@@ -733,6 +733,50 @@  static void handle_msr_i(DisasContext *s, uint32_t insn,
     unsupported_encoding(s, insn);
 }
 
+static void gen_get_nzcv(TCGv_i64 tcg_rt)
+{
+    TCGv_i32 tmp = tcg_temp_new_i32();
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* build bit 31, N */
+    tcg_gen_andi_i32(nzcv, cpu_NF, (1 << 31));
+    /* build bit 30, Z */
+    tcg_gen_setcondi_i32(TCG_COND_EQ, tmp, cpu_ZF, 0);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 30, 1);
+    /* build bit 29, C */
+    tcg_gen_deposit_i32(nzcv, nzcv, cpu_CF, 29, 1);
+    /* build bit 28, V */
+    tcg_gen_shri_i32(tmp, cpu_VF, 31);
+    tcg_gen_deposit_i32(nzcv, nzcv, tmp, 28, 1);
+    /* generate result */
+    tcg_gen_extu_i32_i64(tcg_rt, nzcv);
+
+    tcg_temp_free_i32(nzcv);
+    tcg_temp_free_i32(tmp);
+}
+
+static void gen_set_nzcv(TCGv_i64 tcg_rt)
+
+{
+    TCGv_i32 nzcv = tcg_temp_new_i32();
+
+    /* take NZCV from R[t] */
+    tcg_gen_trunc_i64_i32(nzcv, tcg_rt);
+
+    /* bit 31, N */
+    tcg_gen_andi_i32(cpu_NF, nzcv, (1 << 31));
+    /* bit 30, Z */
+    tcg_gen_andi_i32(cpu_ZF, nzcv, (1 << 30));
+    tcg_gen_setcondi_i32(TCG_COND_EQ, cpu_ZF, cpu_ZF, 0);
+    /* bit 29, C */
+    tcg_gen_andi_i32(cpu_CF, nzcv, (1 << 29));
+    tcg_gen_shri_i32(cpu_CF, cpu_CF, 29);
+    /* bit 28, V */
+    tcg_gen_andi_i32(cpu_VF, nzcv, (1 << 28));
+    tcg_gen_shli_i32(cpu_VF, cpu_VF, 3);
+    tcg_temp_free_i32(nzcv);
+}
+
 /* C5.6.129 MRS - move from system register
  * C5.6.131 MSR (register) - move to system register
  * C5.6.204 SYS
@@ -767,6 +811,14 @@  static void handle_sys(DisasContext *s, uint32_t insn, bool isread,
     switch (ri->type & ~(ARM_CP_FLAG_MASK & ~ARM_CP_SPECIAL)) {
     case ARM_CP_NOP:
         return;
+    case ARM_CP_NZCV:
+        tcg_rt = cpu_reg(s, rt);
+        if (isread) {
+            gen_get_nzcv(tcg_rt);
+        } else {
+            gen_set_nzcv(tcg_rt);
+        }
+        return;
     default:
         break;
     }