diff mbox series

[v4,26/33] target/nios2: Update helper_eret for shadow registers

Message ID 20220308072005.307955-27-richard.henderson@linaro.org
State New
Headers show
Series target/nios2: Shadow register set, EIC and VIC | expand

Commit Message

Richard Henderson March 8, 2022, 7:19 a.m. UTC
When CRS = 0, we restore from estatus; otherwise from sstatus.
Do not allow reserved status bits to be set via this restore.
Add the fields defined for EIC to status.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       |  1 +
 target/nios2/cpu.c       | 16 ++++++++++++----
 target/nios2/op_helper.c | 20 +++++++++++++++++++-
 3 files changed, 32 insertions(+), 5 deletions(-)
diff mbox series

Patch

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index efaac274aa..c48daa5640 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -83,6 +83,7 @@  enum {
     R_FP     = 28,
     R_EA     = 29,
     R_BA     = 30,
+    R_SSTATUS = 30,
     R_RA     = 31,
 };
 
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 05f4a7a93a..6ece92a2b8 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -109,10 +109,18 @@  static void nios2_cpu_initfn(Object *obj)
     WR_FIELD(CR_EXCEPTION, CAUSE);
     WR_REG(CR_BADADDR);
 
-    /* TODO: These control registers are not present with the EIC. */
-    RO_FIELD(CR_STATUS, RSIE);
-    WR_REG(CR_IENABLE);
-    RO_REG(CR_IPENDING);
+    if (cpu->eic_present) {
+        WR_FIELD(CR_STATUS, RSIE);
+        RO_FIELD(CR_STATUS, NMI);
+        WR_FIELD(CR_STATUS, PRS);
+        RO_FIELD(CR_STATUS, CRS);
+        WR_FIELD(CR_STATUS, IL);
+        WR_FIELD(CR_STATUS, IH);
+    } else {
+        RO_FIELD(CR_STATUS, RSIE);
+        WR_REG(CR_IENABLE);
+        RO_REG(CR_IPENDING);
+    }
 
     if (cpu->mmu_present) {
         WR_FIELD(CR_STATUS, U);
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index e656986e3c..42342f007f 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -34,7 +34,25 @@  void helper_raise_exception(CPUNios2State *env, uint32_t index)
 #ifndef CONFIG_USER_ONLY
 void helper_eret(CPUNios2State *env, uint32_t new_pc)
 {
-    env->status = env->estatus;
+    Nios2CPU *cpu = env_archcpu(env);
+    unsigned crs = FIELD_EX32(env->status, CR_STATUS, CRS);
+    uint32_t val;
+
+    if (crs == 0) {
+        val = env->estatus;
+    } else {
+        val = env->shadow_regs[crs][R_SSTATUS];
+    }
+
+    /*
+     * Both estatus and sstatus have no constraints on write;
+     * do not allow reserved fields in status to be set.
+     */
+    val &= (cpu->cr_state[CR_STATUS].writable |
+            cpu->cr_state[CR_STATUS].readonly);
+    env->status = val;
+    nios2_update_crs(env);
+
     env->pc = new_pc;
     cpu_loop_exit(env_cpu(env));
 }