All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC
@ 2022-03-08  7:19 Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 01/33] target/nios2: Check supervisor on eret Richard Henderson
                   ` (32 more replies)
  0 siblings, 33 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Hi Amir,

I've done a bunch of cleanup which Peter and I had recommended
during review.  The major bits are:

* Note reserved bits of control registers, which may include
  the entire control register.
* Complete conversion to registerfields.h.
* Use pointer to shadow register set, akin to Sparc windows.
* Use -M 10m50-ghrd,vic=on to enable VIC.

I can test this to a point, but not the final result.
It works to a point with our existing nios2 kernels,
but of course no interrupts are received. So it verifies
that something changes, and that the init doesn't crash,
but that's about it.


r~


Amir Gonnen (5):
  target/nios2: Check supervisor on eret
  target/nios2: Add NUM_GP_REGS and NUM_CP_REGS
  target/nios2: Split out helper for eret instruction
  hw/intc: Vectored Interrupt Controller (VIC)
  hw/nios2: Machine with a Vectored Interrupt Controller

Richard Henderson (28):
  target/nios2: Stop generating code if gen_check_supervisor fails
  target/nios2: Split PC out of env->regs[]
  target/nios2: Do not create TCGv for control registers
  linux-user/nios2: Trim target_pc_regs to sp and pc
  target/nios2: Remove cpu_interrupts_enabled
  target/nios2: Split control registers away from general registers
  target/nios2: Clean up nios2_cpu_dump_state
  target/nios2: Use hw/registerfields.h for CR_STATUS fields
  target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields
  target/nios2: Use hw/registerfields.h for CR_TLBADDR fields
  target/nios2: Use hw/registerfields.h for CR_TLBACC fields
  target/nios2: Use hw/registerfields.h for CR_TLBMISC fields
  target/nios2: Move R_FOO and CR_BAR into enumerations
  target/nios2: Prevent writes to read-only or reserved control fields
  target/nios2: Implement cpuid
  target/nios2: Implement CR_STATUS.RSIE
  target/nios2: Remove CPU_INTERRUPT_NMI
  target/nios2: Use tcg_constant_tl
  target/nios2: Introduce dest_gpr
  target/nios2: Drop CR_STATUS_EH from tb->flags
  target/nios2: Introduce shadow register sets
  target/nios2: Implement rdprs, wrprs
  target/nios2: Update helper_eret for shadow registers
  target/nios2: Create EXCP_SEMIHOST for semi-hosting
  target/nios2: Clean up nios2_cpu_do_interrupt
  target/nios2: Implement EIC interrupt processing
  hw/nios2: Introduce Nios2MachineState
  hw/nios2: Move memory regions into Nios2Machine

 linux-user/nios2/target_syscall.h |  25 +-
 target/nios2/cpu.h                | 253 ++++++++++++------
 target/nios2/helper.h             |   3 +
 hw/intc/nios2_vic.c               | 341 ++++++++++++++++++++++++
 hw/nios2/10m50_devboard.c         | 118 +++++++--
 hw/nios2/boot.c                   |   8 +-
 linux-user/elfload.c              |   5 +-
 linux-user/nios2/cpu_loop.c       |  39 +--
 linux-user/nios2/signal.c         |   6 +-
 target/nios2/cpu.c                | 194 +++++++++++---
 target/nios2/helper.c             | 218 +++++++--------
 target/nios2/mmu.c                |  73 +++---
 target/nios2/nios2-semi.c         |  13 +-
 target/nios2/op_helper.c          |  39 +++
 target/nios2/translate.c          | 422 +++++++++++++++++++-----------
 hw/intc/Kconfig                   |   3 +
 hw/intc/meson.build               |   1 +
 hw/nios2/Kconfig                  |   1 +
 18 files changed, 1223 insertions(+), 539 deletions(-)
 create mode 100644 hw/intc/nios2_vic.c

-- 
2.25.1



^ permalink raw reply	[flat|nested] 77+ messages in thread

* [PATCH v4 01/33] target/nios2: Check supervisor on eret
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails Richard Henderson
                   ` (31 subsequent siblings)
  32 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

From: Amir Gonnen <amir.gonnen@neuroblade.ai>

eret instruction is only allowed in supervisor mode.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
Message-Id: <20220303153906.2024748-2-amir.gonnen@neuroblade.ai>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index f89271dbed..341f3a8273 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -384,6 +384,8 @@ static const Nios2Instruction i_type_instructions[] = {
  */
 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
+    gen_check_supervisor(dc);
+
     tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
     tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 01/33] target/nios2: Check supervisor on eret Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  9:48   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS Richard Henderson
                   ` (30 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Whether the cpu is in user-mode or not is something that we
know at translation-time.  We do not need to generate code
after having raised an exception.

Suggested-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 20 +++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 341f3a8273..1e0ab686dc 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -169,12 +169,14 @@ static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
     t_gen_helper_raise_exception(dc, flags);
 }
 
-static void gen_check_supervisor(DisasContext *dc)
+static bool gen_check_supervisor(DisasContext *dc)
 {
     if (dc->base.tb->flags & CR_STATUS_U) {
         /* CPU in user mode, privileged instruction called, stop. */
         t_gen_helper_raise_exception(dc, EXCP_SUPERI);
+        return false;
     }
+    return true;
 }
 
 /*
@@ -384,7 +386,9 @@ static const Nios2Instruction i_type_instructions[] = {
  */
 static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    gen_check_supervisor(dc);
+    if (!gen_check_supervisor(dc)) {
+        return;
+    }
 
     tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
     tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]);
@@ -447,7 +451,9 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
 
-    gen_check_supervisor(dc);
+    if (!gen_check_supervisor(dc)) {
+        return;
+    }
 
     if (unlikely(instr.c == R_ZERO)) {
         return;
@@ -474,9 +480,13 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 /* ctlN <- rA */
 static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    gen_check_supervisor(dc);
+    if (!gen_check_supervisor(dc)) {
+        return;
+    }
 
-#ifndef CONFIG_USER_ONLY
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
     R_TYPE(instr, code);
     TCGv v = load_gpr(dc, instr.a);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 01/33] target/nios2: Check supervisor on eret Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  9:49   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 04/33] target/nios2: Split PC out of env->regs[] Richard Henderson
                   ` (29 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

From: Amir Gonnen <amir.gonnen@neuroblade.ai>

Split NUM_CORE_REGS into components that can be used elsewhere.

Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
Message-Id: <20220303153906.2024748-3-amir.gonnen@neuroblade.ai>
[rth: Split out of a larger patch for shadow register sets.]
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index a00e4229ce..655a440033 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -57,9 +57,11 @@ struct Nios2CPUClass {
 #define EXCEPTION_ADDRESS     0x00000004
 #define FAST_TLB_MISS_ADDRESS 0x00000008
 
+#define NUM_GP_REGS 32
+#define NUM_CR_REGS 32
 
 /* GP regs + CR regs + PC */
-#define NUM_CORE_REGS (32 + 32 + 1)
+#define NUM_CORE_REGS (NUM_GP_REGS + NUM_CR_REGS + 1)
 
 /* General purpose register aliases */
 #define R_ZERO   0
@@ -80,7 +82,7 @@ struct Nios2CPUClass {
 #define R_RA     31
 
 /* Control register aliases */
-#define CR_BASE  32
+#define CR_BASE  NUM_GP_REGS
 #define CR_STATUS    (CR_BASE + 0)
 #define   CR_STATUS_PIE  (1 << 0)
 #define   CR_STATUS_U    (1 << 1)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 04/33] target/nios2: Split PC out of env->regs[]
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (2 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  9:51   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 05/33] target/nios2: Split out helper for eret instruction Richard Henderson
                   ` (28 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

It is cleaner to have a separate name for this variable.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h          | 10 +++-----
 linux-user/elfload.c        |  2 +-
 linux-user/nios2/cpu_loop.c | 17 ++++++-------
 linux-user/nios2/signal.c   |  6 ++---
 target/nios2/cpu.c          |  8 +++---
 target/nios2/helper.c       | 51 +++++++++++++++++--------------------
 target/nios2/translate.c    | 26 ++++++++++---------
 7 files changed, 57 insertions(+), 63 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 655a440033..727d31c427 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -60,8 +60,8 @@ struct Nios2CPUClass {
 #define NUM_GP_REGS 32
 #define NUM_CR_REGS 32
 
-/* GP regs + CR regs + PC */
-#define NUM_CORE_REGS (NUM_GP_REGS + NUM_CR_REGS + 1)
+/* GP regs + CR regs */
+#define NUM_CORE_REGS (NUM_GP_REGS + NUM_CR_REGS)
 
 /* General purpose register aliases */
 #define R_ZERO   0
@@ -131,9 +131,6 @@ struct Nios2CPUClass {
 #define CR_MPUBASE   (CR_BASE + 14)
 #define CR_MPUACC    (CR_BASE + 15)
 
-/* Other registers */
-#define R_PC         64
-
 /* Exceptions */
 #define EXCP_BREAK    0x1000
 #define EXCP_RESET    0
@@ -159,6 +156,7 @@ struct Nios2CPUClass {
 
 struct CPUNios2State {
     uint32_t regs[NUM_CORE_REGS];
+    uint32_t pc;
 
 #if !defined(CONFIG_USER_ONLY)
     Nios2MMU mmu;
@@ -242,7 +240,7 @@ typedef Nios2CPU ArchCPU;
 static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
 {
-    *pc = env->regs[R_PC];
+    *pc = env->pc;
     *cs_base = 0;
     *flags = (env->regs[CR_STATUS] & (CR_STATUS_EH | CR_STATUS_U));
 }
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 9628a38361..23ff9659a5 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1170,7 +1170,7 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs,
     (*regs)[30] = -1;    /* R_SSTATUS */
     (*regs)[31] = tswapreg(env->regs[R_RA]);
 
-    (*regs)[32] = tswapreg(env->regs[R_PC]);
+    (*regs)[32] = tswapreg(env->pc);
 
     (*regs)[33] = -1; /* R_STATUS */
     (*regs)[34] = tswapreg(env->regs[CR_ESTATUS]);
diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
index 1e93ef34e6..7b20c024db 100644
--- a/linux-user/nios2/cpu_loop.c
+++ b/linux-user/nios2/cpu_loop.c
@@ -56,25 +56,24 @@ void cpu_loop(CPUNios2State *env)
                 env->regs[2] = abs(ret);
                 /* Return value is 0..4096 */
                 env->regs[7] = ret > 0xfffff000u;
-                env->regs[R_PC] += 4;
+                env->pc += 4;
                 break;
 
             case 1:
                 qemu_log_mask(CPU_LOG_INT, "\nTrap 1\n");
-                force_sig_fault(TARGET_SIGUSR1, 0, env->regs[R_PC]);
+                force_sig_fault(TARGET_SIGUSR1, 0, env->pc);
                 break;
             case 2:
                 qemu_log_mask(CPU_LOG_INT, "\nTrap 2\n");
-                force_sig_fault(TARGET_SIGUSR2, 0, env->regs[R_PC]);
+                force_sig_fault(TARGET_SIGUSR2, 0, env->pc);
                 break;
             case 31:
                 qemu_log_mask(CPU_LOG_INT, "\nTrap 31\n");
-                force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->regs[R_PC]);
+                force_sig_fault(TARGET_SIGTRAP, TARGET_TRAP_BRKPT, env->pc);
                 break;
             default:
                 qemu_log_mask(CPU_LOG_INT, "\nTrap %d\n", env->error_code);
-                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP,
-                                env->regs[R_PC]);
+                force_sig_fault(TARGET_SIGILL, TARGET_ILL_ILLTRP, env->pc);
                 break;
 
             case 16: /* QEMU specific, for __kuser_cmpxchg */
@@ -99,7 +98,7 @@ void cpu_loop(CPUNios2State *env)
                     o = env->regs[5];
                     n = env->regs[6];
                     env->regs[2] = qatomic_cmpxchg(h, o, n) - o;
-                    env->regs[R_PC] += 4;
+                    env->pc += 4;
                 }
                 break;
             }
@@ -117,7 +116,7 @@ void cpu_loop(CPUNios2State *env)
                 info.si_errno = 0;
                 /* TODO: check env->error_code */
                 info.si_code = TARGET_SEGV_MAPERR;
-                info._sifields._sigfault._addr = env->regs[R_PC];
+                info._sifields._sigfault._addr = env->pc;
                 queue_signal(env, info.si_signo, QEMU_SI_FAULT, &info);
             }
             break;
@@ -155,6 +154,6 @@ void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
     env->regs[R_SP] = regs->sp;
     env->regs[R_GP] = regs->gp;
     env->regs[CR_ESTATUS] = regs->estatus;
-    env->regs[R_PC] = regs->ea;
+    env->pc = regs->ea;
     /* TODO: unsigned long  orig_r7; */
 }
diff --git a/linux-user/nios2/signal.c b/linux-user/nios2/signal.c
index 517cd39270..ccfaa75d3b 100644
--- a/linux-user/nios2/signal.c
+++ b/linux-user/nios2/signal.c
@@ -73,7 +73,7 @@ static void rt_setup_ucontext(struct target_ucontext *uc, CPUNios2State *env)
     __put_user(env->regs[R_RA], &gregs[23]);
     __put_user(env->regs[R_FP], &gregs[24]);
     __put_user(env->regs[R_GP], &gregs[25]);
-    __put_user(env->regs[R_PC], &gregs[27]);
+    __put_user(env->pc, &gregs[27]);
     __put_user(env->regs[R_SP], &gregs[28]);
 }
 
@@ -122,7 +122,7 @@ static int rt_restore_ucontext(CPUNios2State *env, struct target_ucontext *uc,
     __get_user(env->regs[R_GP], &gregs[25]);
     /* Not really necessary no user settable bits */
     __get_user(temp, &gregs[26]);
-    __get_user(env->regs[R_PC], &gregs[27]);
+    __get_user(env->pc, &gregs[27]);
 
     __get_user(env->regs[R_RA], &gregs[23]);
     __get_user(env->regs[R_SP], &gregs[28]);
@@ -180,7 +180,7 @@ void setup_rt_frame(int sig, struct target_sigaction *ka,
     env->regs[4] = sig;
     env->regs[5] = frame_addr + offsetof(struct target_rt_sigframe, info);
     env->regs[6] = frame_addr + offsetof(struct target_rt_sigframe, uc);
-    env->regs[R_PC] = ka->_sa_handler;
+    env->pc = ka->_sa_handler;
 
     unlock_user_struct(frame, frame_addr, 1);
 }
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 6975ae4bdb..40031c9f20 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -31,7 +31,7 @@ static void nios2_cpu_set_pc(CPUState *cs, vaddr value)
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
 
-    env->regs[R_PC] = value;
+    env->pc = value;
 }
 
 static bool nios2_cpu_has_work(CPUState *cs)
@@ -54,7 +54,7 @@ static void nios2_cpu_reset(DeviceState *dev)
     ncc->parent_reset(dev);
 
     memset(env->regs, 0, sizeof(uint32_t) * NUM_CORE_REGS);
-    env->regs[R_PC] = cpu->reset_addr;
+    env->pc = cpu->reset_addr;
 
 #if defined(CONFIG_USER_ONLY)
     /* Start in user mode with interrupts enabled. */
@@ -161,7 +161,7 @@ static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
     if (n < 32) {          /* GP regs */
         return gdb_get_reg32(mem_buf, env->regs[n]);
     } else if (n == 32) {    /* PC */
-        return gdb_get_reg32(mem_buf, env->regs[R_PC]);
+        return gdb_get_reg32(mem_buf, env->pc);
     } else if (n < 49) {     /* Status regs */
         return gdb_get_reg32(mem_buf, env->regs[n - 1]);
     }
@@ -183,7 +183,7 @@ static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     if (n < 32) {            /* GP regs */
         env->regs[n] = ldl_p(mem_buf);
     } else if (n == 32) {    /* PC */
-        env->regs[R_PC] = ldl_p(mem_buf);
+        env->pc = ldl_p(mem_buf);
     } else if (n < 49) {     /* Status regs */
         env->regs[n - 1] = ldl_p(mem_buf);
     }
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index e5c98650e1..31cec29e89 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -35,7 +35,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
     cs->exception_index = -1;
-    env->regs[R_EA] = env->regs[R_PC] + 4;
+    env->regs[R_EA] = env->pc + 4;
 }
 
 void nios2_cpu_record_sigsegv(CPUState *cs, vaddr addr,
@@ -58,7 +58,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     case EXCP_IRQ:
         assert(env->regs[CR_STATUS] & CR_STATUS_PIE);
 
-        qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->regs[R_PC]);
+        qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->pc);
 
         env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
         env->regs[CR_STATUS] |= CR_STATUS_IH;
@@ -67,14 +67,13 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
         env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
 
-        env->regs[R_EA] = env->regs[R_PC] + 4;
-        env->regs[R_PC] = cpu->exception_addr;
+        env->regs[R_EA] = env->pc + 4;
+        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_TLBD:
         if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
-            qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n",
-                          env->regs[R_PC]);
+            qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n", env->pc);
 
             /* Fast TLB miss */
             /* Variation from the spec. Table 3-35 of the cpu reference shows
@@ -90,11 +89,10 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->regs[CR_TLBMISC] &= ~CR_TLBMISC_DBL;
             env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
 
-            env->regs[R_EA] = env->regs[R_PC] + 4;
-            env->regs[R_PC] = cpu->fast_tlb_miss_addr;
+            env->regs[R_EA] = env->pc + 4;
+            env->pc = cpu->fast_tlb_miss_addr;
         } else {
-            qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n",
-                          env->regs[R_PC]);
+            qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", env->pc);
 
             /* Double TLB miss */
             env->regs[CR_STATUS] |= CR_STATUS_EH;
@@ -105,14 +103,14 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
             env->regs[CR_TLBMISC] |= CR_TLBMISC_DBL;
 
-            env->regs[R_PC] = cpu->exception_addr;
+            env->pc = cpu->exception_addr;
         }
         break;
 
     case EXCP_TLBR:
     case EXCP_TLBW:
     case EXCP_TLBX:
-        qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->regs[R_PC]);
+        qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->pc);
 
         env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
         env->regs[CR_STATUS] |= CR_STATUS_EH;
@@ -125,19 +123,18 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
         }
 
-        env->regs[R_EA] = env->regs[R_PC] + 4;
-        env->regs[R_PC] = cpu->exception_addr;
+        env->regs[R_EA] = env->pc + 4;
+        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_SUPERA:
     case EXCP_SUPERI:
     case EXCP_SUPERD:
-        qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n",
-                      env->regs[R_PC]);
+        qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n", env->pc);
 
         if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
             env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
-            env->regs[R_EA] = env->regs[R_PC] + 4;
+            env->regs[R_EA] = env->pc + 4;
         }
 
         env->regs[CR_STATUS] |= CR_STATUS_EH;
@@ -146,17 +143,16 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
         env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
 
-        env->regs[R_PC] = cpu->exception_addr;
+        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_ILLEGAL:
     case EXCP_TRAP:
-        qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n",
-                      env->regs[R_PC]);
+        qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n", env->pc);
 
         if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
             env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
-            env->regs[R_EA] = env->regs[R_PC] + 4;
+            env->regs[R_EA] = env->pc + 4;
         }
 
         env->regs[CR_STATUS] |= CR_STATUS_EH;
@@ -165,24 +161,23 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
         env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
 
-        env->regs[R_PC] = cpu->exception_addr;
+        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_BREAK:
-        qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n",
-                      env->regs[R_PC]);
+        qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", env->pc);
         /* The semihosting instruction is "break 1".  */
         if (semihosting_enabled() &&
-            cpu_ldl_code(env, env->regs[R_PC]) == 0x003da07a)  {
+            cpu_ldl_code(env, env->pc) == 0x003da07a)  {
             qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n");
-            env->regs[R_PC] += 4;
+            env->pc += 4;
             do_nios2_semihosting(env);
             break;
         }
 
         if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
             env->regs[CR_BSTATUS] = env->regs[CR_STATUS];
-            env->regs[R_BA] = env->regs[R_PC] + 4;
+            env->regs[R_BA] = env->pc + 4;
         }
 
         env->regs[CR_STATUS] |= CR_STATUS_EH;
@@ -191,7 +186,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
         env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
 
-        env->regs[R_PC] = cpu->exception_addr;
+        env->pc = cpu->exception_addr;
         break;
 
     default:
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 1e0ab686dc..7a33181c4b 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -104,6 +104,7 @@ typedef struct DisasContext {
 } DisasContext;
 
 static TCGv cpu_R[NUM_CORE_REGS];
+static TCGv cpu_pc;
 
 typedef struct Nios2Instruction {
     void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
@@ -144,7 +145,7 @@ static void t_gen_helper_raise_exception(DisasContext *dc,
 {
     TCGv_i32 tmp = tcg_const_i32(index);
 
-    tcg_gen_movi_tl(cpu_R[R_PC], dc->pc);
+    tcg_gen_movi_tl(cpu_pc, dc->pc);
     gen_helper_raise_exception(cpu_env, tmp);
     tcg_temp_free_i32(tmp);
     dc->base.is_jmp = DISAS_NORETURN;
@@ -156,10 +157,10 @@ static void gen_goto_tb(DisasContext *dc, int n, uint32_t dest)
 
     if (translator_use_goto_tb(&dc->base, dest)) {
         tcg_gen_goto_tb(n);
-        tcg_gen_movi_tl(cpu_R[R_PC], dest);
+        tcg_gen_movi_tl(cpu_pc, dest);
         tcg_gen_exit_tb(tb, n);
     } else {
-        tcg_gen_movi_tl(cpu_R[R_PC], dest);
+        tcg_gen_movi_tl(cpu_pc, dest);
         tcg_gen_exit_tb(NULL, 0);
     }
 }
@@ -391,7 +392,7 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
     }
 
     tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
-    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_EA]);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[R_EA]);
 
     dc->base.is_jmp = DISAS_JUMP;
 }
@@ -399,7 +400,7 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 /* PC <- ra */
 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_RA]);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[R_RA]);
 
     dc->base.is_jmp = DISAS_JUMP;
 }
@@ -407,7 +408,7 @@ static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 /* PC <- ba */
 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    tcg_gen_mov_tl(cpu_R[R_PC], cpu_R[R_BA]);
+    tcg_gen_mov_tl(cpu_pc, cpu_R[R_BA]);
 
     dc->base.is_jmp = DISAS_JUMP;
 }
@@ -417,7 +418,7 @@ static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
 
-    tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
+    tcg_gen_mov_tl(cpu_pc, load_gpr(dc, instr.a));
 
     dc->base.is_jmp = DISAS_JUMP;
 }
@@ -440,7 +441,7 @@ static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
 
-    tcg_gen_mov_tl(cpu_R[R_PC], load_gpr(dc, instr.a));
+    tcg_gen_mov_tl(cpu_pc, load_gpr(dc, instr.a));
     tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
 
     dc->base.is_jmp = DISAS_JUMP;
@@ -827,7 +828,7 @@ static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
     case DISAS_TOO_MANY:
     case DISAS_UPDATE:
         /* Save the current PC back into the CPU register */
-        tcg_gen_movi_tl(cpu_R[R_PC], dc->base.pc_next);
+        tcg_gen_movi_tl(cpu_pc, dc->base.pc_next);
         tcg_gen_exit_tb(NULL, 0);
         break;
 
@@ -876,8 +877,7 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         return;
     }
 
-    qemu_fprintf(f, "IN: PC=%x %s\n",
-                 env->regs[R_PC], lookup_symbol(env->regs[R_PC]));
+    qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
 
     for (i = 0; i < NUM_CORE_REGS; i++) {
         qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
@@ -903,10 +903,12 @@ void nios2_tcg_init(void)
                                       offsetof(CPUNios2State, regs[i]),
                                       regnames[i]);
     }
+    cpu_pc = tcg_global_mem_new(cpu_env,
+                                offsetof(CPUNios2State, pc), "pc");
 }
 
 void restore_state_to_opc(CPUNios2State *env, TranslationBlock *tb,
                           target_ulong *data)
 {
-    env->regs[R_PC] = data[0];
+    env->pc = data[0];
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 05/33] target/nios2: Split out helper for eret instruction
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (3 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 04/33] target/nios2: Split PC out of env->regs[] Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  9:52   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers Richard Henderson
                   ` (27 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

From: Amir Gonnen <amir.gonnen@neuroblade.ai>

The implementation of eret will become much more complex
with the introduction of shadow registers.

Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
Message-Id: <20220303153906.2024748-3-amir.gonnen@neuroblade.ai>
[rth: Split out of a larger patch for shadow register sets.
      Directly exit to the cpu loop from the helper.]
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/helper.h    |  1 +
 target/nios2/op_helper.c |  9 +++++++++
 target/nios2/translate.c | 10 ++++++----
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/target/nios2/helper.h b/target/nios2/helper.h
index a44ecfdf7a..02797c384d 100644
--- a/target/nios2/helper.h
+++ b/target/nios2/helper.h
@@ -21,6 +21,7 @@
 DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
 
 #if !defined(CONFIG_USER_ONLY)
+DEF_HELPER_2(eret, noreturn, env, i32)
 DEF_HELPER_2(mmu_write_tlbacc, void, env, i32)
 DEF_HELPER_2(mmu_write_tlbmisc, void, env, i32)
 DEF_HELPER_2(mmu_write_pteaddr, void, env, i32)
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index caa885f7b4..df48e82cc2 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -30,3 +30,12 @@ void helper_raise_exception(CPUNios2State *env, uint32_t index)
     cs->exception_index = index;
     cpu_loop_exit(cs);
 }
+
+#ifndef CONFIG_USER_ONLY
+void helper_eret(CPUNios2State *env, uint32_t new_pc)
+{
+    env->regs[CR_STATUS] = env->regs[CR_ESTATUS];
+    env->pc = new_pc;
+    cpu_loop_exit(env_cpu(env));
+}
+#endif /* !CONFIG_USER_ONLY */
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 7a33181c4b..fe21bf45af 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -391,10 +391,12 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
         return;
     }
 
-    tcg_gen_mov_tl(cpu_R[CR_STATUS], cpu_R[CR_ESTATUS]);
-    tcg_gen_mov_tl(cpu_pc, cpu_R[R_EA]);
-
-    dc->base.is_jmp = DISAS_JUMP;
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    gen_helper_eret(cpu_env, cpu_R[R_EA]);
+    dc->base.is_jmp = DISAS_NORETURN;
+#endif
 }
 
 /* PC <- ra */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (4 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 05/33] target/nios2: Split out helper for eret instruction Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  9:54   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc Richard Henderson
                   ` (26 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

We don't need to reference them often, and when we do it
is just as easy to load/store from cpu_env directly.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 21 ++++++++++++++++-----
 1 file changed, 16 insertions(+), 5 deletions(-)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index fe21bf45af..cefdcea81e 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -103,7 +103,7 @@ typedef struct DisasContext {
     int               mem_idx;
 } DisasContext;
 
-static TCGv cpu_R[NUM_CORE_REGS];
+static TCGv cpu_R[NUM_GP_REGS];
 static TCGv cpu_pc;
 
 typedef struct Nios2Instruction {
@@ -453,6 +453,7 @@ static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
+    TCGv t1, t2;
 
     if (!gen_check_supervisor(dc)) {
         return;
@@ -472,10 +473,19 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
          * must perform the AND here, and anywhere else we need the
          * guest value of ipending.
          */
-        tcg_gen_and_tl(cpu_R[instr.c], cpu_R[CR_IPENDING], cpu_R[CR_IENABLE]);
+        t1 = tcg_temp_new();
+        t2 = tcg_temp_new();
+        tcg_gen_ld_tl(t1, cpu_env,
+                      offsetof(CPUNios2State, regs[CR_IPENDING]));
+        tcg_gen_ld_tl(t2, cpu_env,
+                      offsetof(CPUNios2State, regs[CR_IENABLE]));
+        tcg_gen_and_tl(cpu_R[instr.c], t1, t2);
+        tcg_temp_free(t1);
+        tcg_temp_free(t2);
         break;
     default:
-        tcg_gen_mov_tl(cpu_R[instr.c], cpu_R[instr.imm5 + CR_BASE]);
+        tcg_gen_ld_tl(cpu_R[instr.c], cpu_env,
+                      offsetof(CPUNios2State, regs[instr.imm5 + CR_BASE]));
         break;
     }
 }
@@ -512,7 +522,8 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
         dc->base.is_jmp = DISAS_UPDATE;
         /* fall through */
     default:
-        tcg_gen_mov_tl(cpu_R[instr.imm5 + CR_BASE], v);
+        tcg_gen_st_tl(v, cpu_env,
+                      offsetof(CPUNios2State, regs[instr.imm5 + CR_BASE]));
         break;
     }
 #endif
@@ -900,7 +911,7 @@ void nios2_tcg_init(void)
 {
     int i;
 
-    for (i = 0; i < NUM_CORE_REGS; i++) {
+    for (i = 0; i < NUM_GP_REGS; i++) {
         cpu_R[i] = tcg_global_mem_new(cpu_env,
                                       offsetof(CPUNios2State, regs[i]),
                                       regnames[i]);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (5 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:00   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled Richard Henderson
                   ` (25 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

The only thing this struct is used for is passing startup values
from elfload.c to the cpu.  We do not need all registers to be
represented, we do not need the kernel internal stack slots.

The userland argc, argv, and envp values are passed on
the stack, so only SP and PC need updating.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 linux-user/nios2/target_syscall.h | 25 ++-----------------------
 linux-user/elfload.c              |  3 +--
 linux-user/nios2/cpu_loop.c       | 24 +-----------------------
 3 files changed, 4 insertions(+), 48 deletions(-)

diff --git a/linux-user/nios2/target_syscall.h b/linux-user/nios2/target_syscall.h
index 561b28d281..0999ce25fd 100644
--- a/linux-user/nios2/target_syscall.h
+++ b/linux-user/nios2/target_syscall.h
@@ -5,29 +5,8 @@
 #define UNAME_MINIMUM_RELEASE "3.19.0"
 
 struct target_pt_regs {
-    unsigned long  r8;    /* r8-r15 Caller-saved GP registers */
-    unsigned long  r9;
-    unsigned long  r10;
-    unsigned long  r11;
-    unsigned long  r12;
-    unsigned long  r13;
-    unsigned long  r14;
-    unsigned long  r15;
-    unsigned long  r1;    /* Assembler temporary */
-    unsigned long  r2;    /* Retval LS 32bits */
-    unsigned long  r3;    /* Retval MS 32bits */
-    unsigned long  r4;    /* r4-r7 Register arguments */
-    unsigned long  r5;
-    unsigned long  r6;
-    unsigned long  r7;
-    unsigned long  orig_r2;    /* Copy of r2 ?? */
-    unsigned long  ra;    /* Return address */
-    unsigned long  fp;    /* Frame pointer */
-    unsigned long  sp;    /* Stack pointer */
-    unsigned long  gp;    /* Global pointer */
-    unsigned long  estatus;
-    unsigned long  ea;    /* Exception return address (pc) */
-    unsigned long  orig_r7;
+    target_ulong sp;
+    target_ulong pc;
 };
 
 #define TARGET_MCL_CURRENT 1
diff --git a/linux-user/elfload.c b/linux-user/elfload.c
index 23ff9659a5..cb14c5f786 100644
--- a/linux-user/elfload.c
+++ b/linux-user/elfload.c
@@ -1094,9 +1094,8 @@ static void elf_core_copy_regs(target_elf_gregset_t *regs, const CPUMBState *env
 
 static void init_thread(struct target_pt_regs *regs, struct image_info *infop)
 {
-    regs->ea = infop->entry;
+    regs->pc = infop->entry;
     regs->sp = infop->start_stack;
-    regs->estatus = 0x3;
 }
 
 #define LO_COMMPAGE  TARGET_PAGE_SIZE
diff --git a/linux-user/nios2/cpu_loop.c b/linux-user/nios2/cpu_loop.c
index 7b20c024db..37e1dfecfd 100644
--- a/linux-user/nios2/cpu_loop.c
+++ b/linux-user/nios2/cpu_loop.c
@@ -132,28 +132,6 @@ void cpu_loop(CPUNios2State *env)
 
 void target_cpu_copy_regs(CPUArchState *env, struct target_pt_regs *regs)
 {
-    env->regs[0] = 0;
-    env->regs[1] = regs->r1;
-    env->regs[2] = regs->r2;
-    env->regs[3] = regs->r3;
-    env->regs[4] = regs->r4;
-    env->regs[5] = regs->r5;
-    env->regs[6] = regs->r6;
-    env->regs[7] = regs->r7;
-    env->regs[8] = regs->r8;
-    env->regs[9] = regs->r9;
-    env->regs[10] = regs->r10;
-    env->regs[11] = regs->r11;
-    env->regs[12] = regs->r12;
-    env->regs[13] = regs->r13;
-    env->regs[14] = regs->r14;
-    env->regs[15] = regs->r15;
-    /* TODO: unsigned long  orig_r2; */
-    env->regs[R_RA] = regs->ra;
-    env->regs[R_FP] = regs->fp;
     env->regs[R_SP] = regs->sp;
-    env->regs[R_GP] = regs->gp;
-    env->regs[CR_ESTATUS] = regs->estatus;
-    env->pc = regs->ea;
-    /* TODO: unsigned long  orig_r7; */
+    env->pc = regs->pc;
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (6 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:00   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 09/33] target/nios2: Split control registers away from general registers Richard Henderson
                   ` (24 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

This function is unused.  The real computation of this value
is located in nios2_cpu_exec_interrupt.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 727d31c427..14ed46959e 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -227,11 +227,6 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                         bool probe, uintptr_t retaddr);
 #endif
 
-static inline int cpu_interrupts_enabled(CPUNios2State *env)
-{
-    return env->regs[CR_STATUS] & CR_STATUS_PIE;
-}
-
 typedef CPUNios2State CPUArchState;
 typedef Nios2CPU ArchCPU;
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 09/33] target/nios2: Split control registers away from general registers
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (7 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:04   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state Richard Henderson
                   ` (23 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Place the control registers into their own array, env->ctrl[].

Use an anonymous union and struct to give the entries in the
array distinct names, so that one may write env->foo instead
of env->ctrl[CR_FOO].

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       |  64 ++++++++++++++---------
 target/nios2/cpu.c       |  19 +++----
 target/nios2/helper.c    | 106 +++++++++++++++++++--------------------
 target/nios2/mmu.c       |  26 +++++-----
 target/nios2/op_helper.c |   2 +-
 target/nios2/translate.c |  31 +++++++-----
 6 files changed, 136 insertions(+), 112 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 14ed46959e..5bc0e353b4 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -60,9 +60,6 @@ struct Nios2CPUClass {
 #define NUM_GP_REGS 32
 #define NUM_CR_REGS 32
 
-/* GP regs + CR regs */
-#define NUM_CORE_REGS (NUM_GP_REGS + NUM_CR_REGS)
-
 /* General purpose register aliases */
 #define R_ZERO   0
 #define R_AT     1
@@ -82,8 +79,7 @@ struct Nios2CPUClass {
 #define R_RA     31
 
 /* Control register aliases */
-#define CR_BASE  NUM_GP_REGS
-#define CR_STATUS    (CR_BASE + 0)
+#define CR_STATUS        0
 #define   CR_STATUS_PIE  (1 << 0)
 #define   CR_STATUS_U    (1 << 1)
 #define   CR_STATUS_EH   (1 << 2)
@@ -93,19 +89,19 @@ struct Nios2CPUClass {
 #define   CR_STATUS_PRS  (63 << 16)
 #define   CR_STATUS_NMI  (1 << 22)
 #define   CR_STATUS_RSIE (1 << 23)
-#define CR_ESTATUS   (CR_BASE + 1)
-#define CR_BSTATUS   (CR_BASE + 2)
-#define CR_IENABLE   (CR_BASE + 3)
-#define CR_IPENDING  (CR_BASE + 4)
-#define CR_CPUID     (CR_BASE + 5)
-#define CR_CTL6      (CR_BASE + 6)
-#define CR_EXCEPTION (CR_BASE + 7)
-#define CR_PTEADDR   (CR_BASE + 8)
+#define CR_ESTATUS       1
+#define CR_BSTATUS       2
+#define CR_IENABLE       3
+#define CR_IPENDING      4
+#define CR_CPUID         5
+#define CR_CTL6          6
+#define CR_EXCEPTION     7
+#define CR_PTEADDR       8
 #define   CR_PTEADDR_PTBASE_SHIFT 22
 #define   CR_PTEADDR_PTBASE_MASK  (0x3FF << CR_PTEADDR_PTBASE_SHIFT)
 #define   CR_PTEADDR_VPN_SHIFT    2
 #define   CR_PTEADDR_VPN_MASK     (0xFFFFF << CR_PTEADDR_VPN_SHIFT)
-#define CR_TLBACC    (CR_BASE + 9)
+#define CR_TLBACC        9
 #define   CR_TLBACC_IGN_SHIFT 25
 #define   CR_TLBACC_IGN_MASK  (0x7F << CR_TLBACC_IGN_SHIFT)
 #define   CR_TLBACC_C         (1 << 24)
@@ -114,7 +110,7 @@ struct Nios2CPUClass {
 #define   CR_TLBACC_X         (1 << 21)
 #define   CR_TLBACC_G         (1 << 20)
 #define   CR_TLBACC_PFN_MASK  0x000FFFFF
-#define CR_TLBMISC   (CR_BASE + 10)
+#define CR_TLBMISC       10
 #define   CR_TLBMISC_WAY_SHIFT 20
 #define   CR_TLBMISC_WAY_MASK  (0xF << CR_TLBMISC_WAY_SHIFT)
 #define   CR_TLBMISC_RD        (1 << 19)
@@ -125,11 +121,11 @@ struct Nios2CPUClass {
 #define   CR_TLBMISC_BAD       (1 << 2)
 #define   CR_TLBMISC_PERM      (1 << 1)
 #define   CR_TLBMISC_D         (1 << 0)
-#define CR_ENCINJ    (CR_BASE + 11)
-#define CR_BADADDR   (CR_BASE + 12)
-#define CR_CONFIG    (CR_BASE + 13)
-#define CR_MPUBASE   (CR_BASE + 14)
-#define CR_MPUACC    (CR_BASE + 15)
+#define CR_ENCINJ        11
+#define CR_BADADDR       12
+#define CR_CONFIG        13
+#define CR_MPUBASE       14
+#define CR_MPUACC        15
 
 /* Exceptions */
 #define EXCP_BREAK    0x1000
@@ -155,7 +151,28 @@ struct Nios2CPUClass {
 #define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
 
 struct CPUNios2State {
-    uint32_t regs[NUM_CORE_REGS];
+    uint32_t regs[NUM_GP_REGS];
+    union {
+        uint32_t ctrl[NUM_CR_REGS];
+        struct {
+            uint32_t status;
+            uint32_t estatus;
+            uint32_t bstatus;
+            uint32_t ienable;
+            uint32_t ipending;
+            uint32_t cpuid;
+            uint32_t reserved6;
+            uint32_t exception;
+            uint32_t pteaddr;
+            uint32_t tlbacc;
+            uint32_t tlbmisc;
+            uint32_t eccinj;
+            uint32_t badaddr;
+            uint32_t config;
+            uint32_t mpubase;
+            uint32_t mpuacc;
+        };
+    };
     uint32_t pc;
 
 #if !defined(CONFIG_USER_ONLY)
@@ -213,8 +230,7 @@ void do_nios2_semihosting(CPUNios2State *env);
 
 static inline int cpu_mmu_index(CPUNios2State *env, bool ifetch)
 {
-    return (env->regs[CR_STATUS] & CR_STATUS_U) ? MMU_USER_IDX :
-                                                  MMU_SUPERVISOR_IDX;
+    return (env->status & CR_STATUS_U) ? MMU_USER_IDX : MMU_SUPERVISOR_IDX;
 }
 
 #ifdef CONFIG_USER_ONLY
@@ -237,7 +253,7 @@ static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
 {
     *pc = env->pc;
     *cs_base = 0;
-    *flags = (env->regs[CR_STATUS] & (CR_STATUS_EH | CR_STATUS_U));
+    *flags = env->status & (CR_STATUS_EH | CR_STATUS_U);
 }
 
 #endif /* NIOS2_CPU_H */
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 40031c9f20..f2813d3b47 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -53,14 +53,15 @@ static void nios2_cpu_reset(DeviceState *dev)
 
     ncc->parent_reset(dev);
 
-    memset(env->regs, 0, sizeof(uint32_t) * NUM_CORE_REGS);
+    memset(env->regs, 0, sizeof(env->regs));
+    memset(env->ctrl, 0, sizeof(env->ctrl));
     env->pc = cpu->reset_addr;
 
 #if defined(CONFIG_USER_ONLY)
     /* Start in user mode with interrupts enabled. */
-    env->regs[CR_STATUS] = CR_STATUS_U | CR_STATUS_PIE;
+    env->status = CR_STATUS_U | CR_STATUS_PIE;
 #else
-    env->regs[CR_STATUS] = 0;
+    env->status = 0;
 #endif
 }
 
@@ -71,9 +72,9 @@ static void nios2_cpu_set_irq(void *opaque, int irq, int level)
     CPUNios2State *env = &cpu->env;
     CPUState *cs = CPU(cpu);
 
-    env->regs[CR_IPENDING] = deposit32(env->regs[CR_IPENDING], irq, 1, !!level);
+    env->ipending = deposit32(env->ipending, irq, 1, !!level);
 
-    if (env->regs[CR_IPENDING]) {
+    if (env->ipending) {
         cpu_interrupt(cs, CPU_INTERRUPT_HARD);
     } else {
         cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
@@ -131,8 +132,8 @@ static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
     CPUNios2State *env = &cpu->env;
 
     if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-        (env->regs[CR_STATUS] & CR_STATUS_PIE) &&
-        (env->regs[CR_IPENDING] & env->regs[CR_IENABLE])) {
+        (env->status & CR_STATUS_PIE) &&
+        (env->ipending & env->ienable)) {
         cs->exception_index = EXCP_IRQ;
         nios2_cpu_do_interrupt(cs);
         return true;
@@ -163,7 +164,7 @@ static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
     } else if (n == 32) {    /* PC */
         return gdb_get_reg32(mem_buf, env->pc);
     } else if (n < 49) {     /* Status regs */
-        return gdb_get_reg32(mem_buf, env->regs[n - 1]);
+        return gdb_get_reg32(mem_buf, env->ctrl[n - 33]);
     }
 
     /* Invalid regs */
@@ -185,7 +186,7 @@ static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     } else if (n == 32) {    /* PC */
         env->pc = ldl_p(mem_buf);
     } else if (n < 49) {     /* Status regs */
-        env->regs[n - 1] = ldl_p(mem_buf);
+        env->ctrl[n - 33] = ldl_p(mem_buf);
     }
 
     return 4;
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index 31cec29e89..3c49b0cfbf 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -56,38 +56,38 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
     switch (cs->exception_index) {
     case EXCP_IRQ:
-        assert(env->regs[CR_STATUS] & CR_STATUS_PIE);
+        assert(env->status & CR_STATUS_PIE);
 
         qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->pc);
 
-        env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
-        env->regs[CR_STATUS] |= CR_STATUS_IH;
-        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+        env->estatus = env->status;
+        env->status |= CR_STATUS_IH;
+        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+        env->exception &= ~(0x1F << 2);
+        env->exception |= (cs->exception_index & 0x1F) << 2;
 
         env->regs[R_EA] = env->pc + 4;
         env->pc = cpu->exception_addr;
         break;
 
     case EXCP_TLBD:
-        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
+        if ((env->status & CR_STATUS_EH) == 0) {
             qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n", env->pc);
 
             /* Fast TLB miss */
             /* Variation from the spec. Table 3-35 of the cpu reference shows
              * estatus not being changed for TLB miss but this appears to
              * be incorrect. */
-            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
-            env->regs[CR_STATUS] |= CR_STATUS_EH;
-            env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+            env->estatus = env->status;
+            env->status |= CR_STATUS_EH;
+            env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-            env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-            env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+            env->exception &= ~(0x1F << 2);
+            env->exception |= (cs->exception_index & 0x1F) << 2;
 
-            env->regs[CR_TLBMISC] &= ~CR_TLBMISC_DBL;
-            env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
+            env->tlbmisc &= ~CR_TLBMISC_DBL;
+            env->tlbmisc |= CR_TLBMISC_WR;
 
             env->regs[R_EA] = env->pc + 4;
             env->pc = cpu->fast_tlb_miss_addr;
@@ -95,13 +95,13 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", env->pc);
 
             /* Double TLB miss */
-            env->regs[CR_STATUS] |= CR_STATUS_EH;
-            env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+            env->status |= CR_STATUS_EH;
+            env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-            env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-            env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+            env->exception &= ~(0x1F << 2);
+            env->exception |= (cs->exception_index & 0x1F) << 2;
 
-            env->regs[CR_TLBMISC] |= CR_TLBMISC_DBL;
+            env->tlbmisc |= CR_TLBMISC_DBL;
 
             env->pc = cpu->exception_addr;
         }
@@ -112,15 +112,15 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     case EXCP_TLBX:
         qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->pc);
 
-        env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
-        env->regs[CR_STATUS] |= CR_STATUS_EH;
-        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+        env->estatus = env->status;
+        env->status |= CR_STATUS_EH;
+        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+        env->exception &= ~(0x1F << 2);
+        env->exception |= (cs->exception_index & 0x1F) << 2;
 
-        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
-            env->regs[CR_TLBMISC] |= CR_TLBMISC_WR;
+        if ((env->status & CR_STATUS_EH) == 0) {
+            env->tlbmisc |= CR_TLBMISC_WR;
         }
 
         env->regs[R_EA] = env->pc + 4;
@@ -132,16 +132,16 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     case EXCP_SUPERD:
         qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n", env->pc);
 
-        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
-            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+        if ((env->status & CR_STATUS_EH) == 0) {
+            env->estatus = env->status;
             env->regs[R_EA] = env->pc + 4;
         }
 
-        env->regs[CR_STATUS] |= CR_STATUS_EH;
-        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+        env->status |= CR_STATUS_EH;
+        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+        env->exception &= ~(0x1F << 2);
+        env->exception |= (cs->exception_index & 0x1F) << 2;
 
         env->pc = cpu->exception_addr;
         break;
@@ -150,16 +150,16 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     case EXCP_TRAP:
         qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n", env->pc);
 
-        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
-            env->regs[CR_ESTATUS] = env->regs[CR_STATUS];
+        if ((env->status & CR_STATUS_EH) == 0) {
+            env->estatus = env->status;
             env->regs[R_EA] = env->pc + 4;
         }
 
-        env->regs[CR_STATUS] |= CR_STATUS_EH;
-        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+        env->status |= CR_STATUS_EH;
+        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+        env->exception &= ~(0x1F << 2);
+        env->exception |= (cs->exception_index & 0x1F) << 2;
 
         env->pc = cpu->exception_addr;
         break;
@@ -175,16 +175,16 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             break;
         }
 
-        if ((env->regs[CR_STATUS] & CR_STATUS_EH) == 0) {
-            env->regs[CR_BSTATUS] = env->regs[CR_STATUS];
+        if ((env->status & CR_STATUS_EH) == 0) {
+            env->bstatus = env->status;
             env->regs[R_BA] = env->pc + 4;
         }
 
-        env->regs[CR_STATUS] |= CR_STATUS_EH;
-        env->regs[CR_STATUS] &= ~(CR_STATUS_PIE | CR_STATUS_U);
+        env->status |= CR_STATUS_EH;
+        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[CR_EXCEPTION] &= ~(0x1F << 2);
-        env->regs[CR_EXCEPTION] |= (cs->exception_index & 0x1F) << 2;
+        env->exception &= ~(0x1F << 2);
+        env->exception |= (cs->exception_index & 0x1F) << 2;
 
         env->pc = cpu->exception_addr;
         break;
@@ -227,8 +227,8 @@ void nios2_cpu_do_unaligned_access(CPUState *cs, vaddr addr,
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
 
-    env->regs[CR_BADADDR] = addr;
-    env->regs[CR_EXCEPTION] = EXCP_UNALIGN << 2;
+    env->badaddr = addr;
+    env->exception = EXCP_UNALIGN << 2;
     helper_raise_exception(env, EXCP_UNALIGN);
 }
 
@@ -266,7 +266,7 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
                 return false;
             }
             cs->exception_index = EXCP_SUPERA;
-            env->regs[CR_BADADDR] = address;
+            env->badaddr = address;
             cpu_loop_exit_restore(cs, retaddr);
         }
     }
@@ -295,16 +295,16 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     }
 
     if (access_type == MMU_INST_FETCH) {
-        env->regs[CR_TLBMISC] &= ~CR_TLBMISC_D;
+        env->tlbmisc &= ~CR_TLBMISC_D;
     } else {
-        env->regs[CR_TLBMISC] |= CR_TLBMISC_D;
+        env->tlbmisc |= CR_TLBMISC_D;
     }
-    env->regs[CR_PTEADDR] &= CR_PTEADDR_PTBASE_MASK;
-    env->regs[CR_PTEADDR] |= (address >> 10) & CR_PTEADDR_VPN_MASK;
-    env->mmu.pteaddr_wr = env->regs[CR_PTEADDR];
+    env->pteaddr &= CR_PTEADDR_PTBASE_MASK;
+    env->pteaddr |= (address >> 10) & CR_PTEADDR_VPN_MASK;
+    env->mmu.pteaddr_wr = env->pteaddr;
 
     cs->exception_index = excp;
-    env->regs[CR_BADADDR] = address;
+    env->badaddr = address;
     cpu_loop_exit_restore(cs, retaddr);
 }
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c
index 4daab2a7ab..382b190ae7 100644
--- a/target/nios2/mmu.c
+++ b/target/nios2/mmu.c
@@ -95,8 +95,8 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
                                  v & CR_TLBACC_PFN_MASK);
 
     /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */
-    if (env->regs[CR_TLBMISC] & CR_TLBMISC_WR) {
-        int way = (env->regs[CR_TLBMISC] >> CR_TLBMISC_WAY_SHIFT);
+    if (env->tlbmisc & CR_TLBMISC_WR) {
+        int way = (env->tlbmisc >> CR_TLBMISC_WAY_SHIFT);
         int vpn = (env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK) >> 2;
         int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4;
         int g = (v & CR_TLBACC_G) ? 1 : 0;
@@ -117,8 +117,8 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
             entry->data = newData;
         }
         /* Auto-increment tlbmisc.WAY */
-        env->regs[CR_TLBMISC] =
-            (env->regs[CR_TLBMISC] & ~CR_TLBMISC_WAY_MASK) |
+        env->tlbmisc =
+            (env->tlbmisc & ~CR_TLBMISC_WAY_MASK) |
             (((way + 1) & (cpu->tlb_num_ways - 1)) <<
              CR_TLBMISC_WAY_SHIFT);
     }
@@ -153,17 +153,17 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
             &env->mmu.tlb[(way * cpu->tlb_num_ways) +
                           (vpn & env->mmu.tlb_entry_mask)];
 
-        env->regs[CR_TLBACC] &= CR_TLBACC_IGN_MASK;
-        env->regs[CR_TLBACC] |= entry->data;
-        env->regs[CR_TLBACC] |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0;
-        env->regs[CR_TLBMISC] =
+        env->tlbacc &= CR_TLBACC_IGN_MASK;
+        env->tlbacc |= entry->data;
+        env->tlbacc |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0;
+        env->tlbmisc =
             (v & ~CR_TLBMISC_PID_MASK) |
             ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) <<
              CR_TLBMISC_PID_SHIFT);
-        env->regs[CR_PTEADDR] &= ~CR_PTEADDR_VPN_MASK;
-        env->regs[CR_PTEADDR] |= (entry->tag >> 12) << CR_PTEADDR_VPN_SHIFT;
+        env->pteaddr &= ~CR_PTEADDR_VPN_MASK;
+        env->pteaddr |= (entry->tag >> 12) << CR_PTEADDR_VPN_SHIFT;
     } else {
-        env->regs[CR_TLBMISC] = v;
+        env->tlbmisc = v;
     }
 
     env->mmu.tlbmisc_wr = v;
@@ -175,8 +175,8 @@ void helper_mmu_write_pteaddr(CPUNios2State *env, uint32_t v)
                                   (v & CR_PTEADDR_VPN_MASK) >> CR_PTEADDR_VPN_SHIFT);
 
     /* Writes to PTEADDR don't change the read-back VPN value */
-    env->regs[CR_PTEADDR] = (v & ~CR_PTEADDR_VPN_MASK) |
-                            (env->regs[CR_PTEADDR] & CR_PTEADDR_VPN_MASK);
+    env->pteaddr = (v & ~CR_PTEADDR_VPN_MASK) |
+                    (env->pteaddr & CR_PTEADDR_VPN_MASK);
     env->mmu.pteaddr_wr = v;
 }
 
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index df48e82cc2..a1554ce349 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -34,7 +34,7 @@ void helper_raise_exception(CPUNios2State *env, uint32_t index)
 #ifndef CONFIG_USER_ONLY
 void helper_eret(CPUNios2State *env, uint32_t new_pc)
 {
-    env->regs[CR_STATUS] = env->regs[CR_ESTATUS];
+    env->status = env->estatus;
     env->pc = new_pc;
     cpu_loop_exit(env_cpu(env));
 }
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index cefdcea81e..2942921724 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -463,7 +463,7 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
         return;
     }
 
-    switch (instr.imm5 + CR_BASE) {
+    switch (instr.imm5) {
     case CR_IPENDING:
         /*
          * The value of the ipending register is synthetic.
@@ -475,17 +475,15 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
          */
         t1 = tcg_temp_new();
         t2 = tcg_temp_new();
-        tcg_gen_ld_tl(t1, cpu_env,
-                      offsetof(CPUNios2State, regs[CR_IPENDING]));
-        tcg_gen_ld_tl(t2, cpu_env,
-                      offsetof(CPUNios2State, regs[CR_IENABLE]));
+        tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ipending));
+        tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ienable));
         tcg_gen_and_tl(cpu_R[instr.c], t1, t2);
         tcg_temp_free(t1);
         tcg_temp_free(t2);
         break;
     default:
         tcg_gen_ld_tl(cpu_R[instr.c], cpu_env,
-                      offsetof(CPUNios2State, regs[instr.imm5 + CR_BASE]));
+                      offsetof(CPUNios2State, ctrl[instr.imm5]));
         break;
     }
 }
@@ -503,7 +501,7 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
     R_TYPE(instr, code);
     TCGv v = load_gpr(dc, instr.a);
 
-    switch (instr.imm5 + CR_BASE) {
+    switch (instr.imm5) {
     case CR_PTEADDR:
         gen_helper_mmu_write_pteaddr(cpu_env, v);
         break;
@@ -523,7 +521,7 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
         /* fall through */
     default:
         tcg_gen_st_tl(v, cpu_env,
-                      offsetof(CPUNios2State, regs[instr.imm5 + CR_BASE]));
+                      offsetof(CPUNios2State, ctrl[instr.imm5]));
         break;
     }
 #endif
@@ -756,7 +754,7 @@ illegal_op:
     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 }
 
-static const char * const regnames[] = {
+static const char * const gr_regnames[] = {
     "zero",       "at",         "r2",         "r3",
     "r4",         "r5",         "r6",         "r7",
     "r8",         "r9",         "r10",        "r11",
@@ -765,6 +763,9 @@ static const char * const regnames[] = {
     "r20",        "r21",        "r22",        "r23",
     "et",         "bt",         "gp",         "sp",
     "fp",         "ea",         "ba",         "ra",
+};
+
+static const char * const cr_regnames[] = {
     "status",     "estatus",    "bstatus",    "ienable",
     "ipending",   "cpuid",      "reserved0",  "exception",
     "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
@@ -892,8 +893,14 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 
     qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
 
-    for (i = 0; i < NUM_CORE_REGS; i++) {
-        qemu_fprintf(f, "%9s=%8.8x ", regnames[i], env->regs[i]);
+    for (i = 0; i < NUM_GP_REGS; i++) {
+        qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
+        if ((i + 1) % 4 == 0) {
+            qemu_fprintf(f, "\n");
+        }
+    }
+    for (i = 0; i < NUM_CR_REGS; i++) {
+        qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
         if ((i + 1) % 4 == 0) {
             qemu_fprintf(f, "\n");
         }
@@ -914,7 +921,7 @@ void nios2_tcg_init(void)
     for (i = 0; i < NUM_GP_REGS; i++) {
         cpu_R[i] = tcg_global_mem_new(cpu_env,
                                       offsetof(CPUNios2State, regs[i]),
-                                      regnames[i]);
+                                      gr_regnames[i]);
     }
     cpu_pc = tcg_global_mem_new(cpu_env,
                                 offsetof(CPUNios2State, pc), "pc");
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (8 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 09/33] target/nios2: Split control registers away from general registers Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:06   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields Richard Henderson
                   ` (22 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Do not print control registers for user-only mode.
Rename reserved control registers to "resN", where
N is the control register index.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 20 +++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 2942921724..7a32e6626d 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -754,7 +754,7 @@ illegal_op:
     t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
 }
 
-static const char * const gr_regnames[] = {
+static const char * const gr_regnames[NUM_GP_REGS] = {
     "zero",       "at",         "r2",         "r3",
     "r4",         "r5",         "r6",         "r7",
     "r8",         "r9",         "r10",        "r11",
@@ -765,17 +765,18 @@ static const char * const gr_regnames[] = {
     "fp",         "ea",         "ba",         "ra",
 };
 
-static const char * const cr_regnames[] = {
+#ifndef CONFIG_USER_ONLY
+static const char * const cr_regnames[NUM_CR_REGS] = {
     "status",     "estatus",    "bstatus",    "ienable",
-    "ipending",   "cpuid",      "reserved0",  "exception",
+    "ipending",   "cpuid",      "res6",       "exception",
     "pteaddr",    "tlbacc",     "tlbmisc",    "reserved1",
     "badaddr",    "config",     "mpubase",    "mpuacc",
-    "reserved2",  "reserved3",  "reserved4",  "reserved5",
-    "reserved6",  "reserved7",  "reserved8",  "reserved9",
-    "reserved10", "reserved11", "reserved12", "reserved13",
-    "reserved14", "reserved15", "reserved16", "reserved17",
-    "rpc"
+    "res16",      "res17",      "res18",      "res19",
+    "res20",      "res21",      "res22",      "res23",
+    "res24",      "res25",      "res26",      "res27",
+    "res28",      "res29",      "res30",      "res31",
 };
+#endif
 
 #include "exec/gen-icount.h"
 
@@ -899,13 +900,14 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
             qemu_fprintf(f, "\n");
         }
     }
+
+#if !defined(CONFIG_USER_ONLY)
     for (i = 0; i < NUM_CR_REGS; i++) {
         qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
         if ((i + 1) % 4 == 0) {
             qemu_fprintf(f, "\n");
         }
     }
-#if !defined(CONFIG_USER_ONLY)
     qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
                  env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
                  (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (9 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:08   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields Richard Henderson
                   ` (21 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Add all fields; retain the helper macros for single bit fields.
So far there are no uses of the multi-bit status fields.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 27 ++++++++++++++++++---------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 5bc0e353b4..26618baa70 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -23,6 +23,7 @@
 
 #include "exec/cpu-defs.h"
 #include "hw/core/cpu.h"
+#include "hw/registerfields.h"
 #include "qom/object.h"
 
 typedef struct CPUNios2State CPUNios2State;
@@ -80,15 +81,23 @@ struct Nios2CPUClass {
 
 /* Control register aliases */
 #define CR_STATUS        0
-#define   CR_STATUS_PIE  (1 << 0)
-#define   CR_STATUS_U    (1 << 1)
-#define   CR_STATUS_EH   (1 << 2)
-#define   CR_STATUS_IH   (1 << 3)
-#define   CR_STATUS_IL   (63 << 4)
-#define   CR_STATUS_CRS  (63 << 10)
-#define   CR_STATUS_PRS  (63 << 16)
-#define   CR_STATUS_NMI  (1 << 22)
-#define   CR_STATUS_RSIE (1 << 23)
+
+FIELD(CR_STATUS, PIE, 0, 1)
+FIELD(CR_STATUS, U, 1, 1)
+FIELD(CR_STATUS, EH, 2, 1)
+FIELD(CR_STATUS, IH, 3, 1)
+FIELD(CR_STATUS, IL, 4, 6)
+FIELD(CR_STATUS, CRS, 10, 6)
+FIELD(CR_STATUS, PRS, 16, 6)
+FIELD(CR_STATUS, NMI, 22, 1)
+
+#define CR_STATUS_PIE  (1u << R_CR_STATUS_PIE_SHIFT)
+#define CR_STATUS_U    (1u << R_CR_STATUS_U_SHIFT)
+#define CR_STATUS_EH   (1u << R_CR_STATUS_EH_SHIFT)
+#define CR_STATUS_IH   (1u << R_CR_STATUS_IH_SHIFT)
+#define CR_STATUS_NMI  (1u << R_CR_STATUS_NMI_SHIFT)
+#define CR_STATUS_RSIE (1u << R_CR_STATUS_RSIE_SHIFT)
+
 #define CR_ESTATUS       1
 #define CR_BSTATUS       2
 #define CR_IENABLE       3
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (10 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:12   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields Richard Henderson
                   ` (20 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Sink the set of env->exception to the end of nios2_cpu_do_interrupt.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h    |  4 ++++
 target/nios2/helper.c | 24 +++---------------------
 2 files changed, 7 insertions(+), 21 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 26618baa70..35b4d88859 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -105,6 +105,10 @@ FIELD(CR_STATUS, NMI, 22, 1)
 #define CR_CPUID         5
 #define CR_CTL6          6
 #define CR_EXCEPTION     7
+
+FIELD(CR_EXCEPTION, CAUSE, 2, 5)
+FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
+
 #define CR_PTEADDR       8
 #define   CR_PTEADDR_PTBASE_SHIFT 22
 #define   CR_PTEADDR_PTBASE_MASK  (0x3FF << CR_PTEADDR_PTBASE_SHIFT)
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index 3c49b0cfbf..eb354f78e2 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -64,9 +64,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_IH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->exception &= ~(0x1F << 2);
-        env->exception |= (cs->exception_index & 0x1F) << 2;
-
         env->regs[R_EA] = env->pc + 4;
         env->pc = cpu->exception_addr;
         break;
@@ -83,9 +80,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->status |= CR_STATUS_EH;
             env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-            env->exception &= ~(0x1F << 2);
-            env->exception |= (cs->exception_index & 0x1F) << 2;
-
             env->tlbmisc &= ~CR_TLBMISC_DBL;
             env->tlbmisc |= CR_TLBMISC_WR;
 
@@ -98,9 +92,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->status |= CR_STATUS_EH;
             env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-            env->exception &= ~(0x1F << 2);
-            env->exception |= (cs->exception_index & 0x1F) << 2;
-
             env->tlbmisc |= CR_TLBMISC_DBL;
 
             env->pc = cpu->exception_addr;
@@ -116,9 +107,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_EH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->exception &= ~(0x1F << 2);
-        env->exception |= (cs->exception_index & 0x1F) << 2;
-
         if ((env->status & CR_STATUS_EH) == 0) {
             env->tlbmisc |= CR_TLBMISC_WR;
         }
@@ -140,9 +128,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_EH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->exception &= ~(0x1F << 2);
-        env->exception |= (cs->exception_index & 0x1F) << 2;
-
         env->pc = cpu->exception_addr;
         break;
 
@@ -158,9 +143,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_EH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->exception &= ~(0x1F << 2);
-        env->exception |= (cs->exception_index & 0x1F) << 2;
-
         env->pc = cpu->exception_addr;
         break;
 
@@ -183,9 +165,6 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_EH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->exception &= ~(0x1F << 2);
-        env->exception |= (cs->exception_index & 0x1F) << 2;
-
         env->pc = cpu->exception_addr;
         break;
 
@@ -194,6 +173,9 @@ void nios2_cpu_do_interrupt(CPUState *cs)
                   cs->exception_index);
         break;
     }
+
+    env->exception = FIELD_DP32(env->exception, CR_EXCEPTION, CAUSE,
+                                cs->exception_index);
 }
 
 hwaddr nios2_cpu_get_phys_page_debug(CPUState *cs, vaddr addr)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (11 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:14   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields Richard Henderson
                   ` (19 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       |  8 ++++----
 target/nios2/helper.c    |  4 ++--
 target/nios2/mmu.c       | 16 ++++++++--------
 target/nios2/translate.c |  2 +-
 4 files changed, 15 insertions(+), 15 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 35b4d88859..84138000fa 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -110,10 +110,10 @@ FIELD(CR_EXCEPTION, CAUSE, 2, 5)
 FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
 
 #define CR_PTEADDR       8
-#define   CR_PTEADDR_PTBASE_SHIFT 22
-#define   CR_PTEADDR_PTBASE_MASK  (0x3FF << CR_PTEADDR_PTBASE_SHIFT)
-#define   CR_PTEADDR_VPN_SHIFT    2
-#define   CR_PTEADDR_VPN_MASK     (0xFFFFF << CR_PTEADDR_VPN_SHIFT)
+
+FIELD(CR_PTEADDR, VPN, 2, 20)
+FIELD(CR_PTEADDR, PTBASE, 22, 10)
+
 #define CR_TLBACC        9
 #define   CR_TLBACC_IGN_SHIFT 25
 #define   CR_TLBACC_IGN_MASK  (0x7F << CR_TLBACC_IGN_SHIFT)
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index eb354f78e2..37fb53dadb 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -281,8 +281,8 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
     } else {
         env->tlbmisc |= CR_TLBMISC_D;
     }
-    env->pteaddr &= CR_PTEADDR_PTBASE_MASK;
-    env->pteaddr |= (address >> 10) & CR_PTEADDR_VPN_MASK;
+    env->pteaddr = FIELD_DP32(env->pteaddr, CR_PTEADDR, VPN,
+                              address >> TARGET_PAGE_BITS);
     env->mmu.pteaddr_wr = env->pteaddr;
 
     cs->exception_index = excp;
diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c
index 382b190ae7..8017f2af93 100644
--- a/target/nios2/mmu.c
+++ b/target/nios2/mmu.c
@@ -97,7 +97,7 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
     /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */
     if (env->tlbmisc & CR_TLBMISC_WR) {
         int way = (env->tlbmisc >> CR_TLBMISC_WAY_SHIFT);
-        int vpn = (env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK) >> 2;
+        int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
         int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4;
         int g = (v & CR_TLBACC_G) ? 1 : 0;
         int valid = ((vpn & CR_TLBACC_PFN_MASK) < 0xC0000) ? 1 : 0;
@@ -148,7 +148,7 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
     /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */
     if (v & CR_TLBMISC_RD) {
         int way = (v >> CR_TLBMISC_WAY_SHIFT);
-        int vpn = (env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK) >> 2;
+        int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
         Nios2TLBEntry *entry =
             &env->mmu.tlb[(way * cpu->tlb_num_ways) +
                           (vpn & env->mmu.tlb_entry_mask)];
@@ -160,8 +160,8 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
             (v & ~CR_TLBMISC_PID_MASK) |
             ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) <<
              CR_TLBMISC_PID_SHIFT);
-        env->pteaddr &= ~CR_PTEADDR_VPN_MASK;
-        env->pteaddr |= (entry->tag >> 12) << CR_PTEADDR_VPN_SHIFT;
+        env->pteaddr = FIELD_DP32(env->pteaddr, CR_PTEADDR, VPN,
+                                  entry->tag >> TARGET_PAGE_BITS);
     } else {
         env->tlbmisc = v;
     }
@@ -171,12 +171,12 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
 
 void helper_mmu_write_pteaddr(CPUNios2State *env, uint32_t v)
 {
-    trace_nios2_mmu_write_pteaddr(v >> CR_PTEADDR_PTBASE_SHIFT,
-                                  (v & CR_PTEADDR_VPN_MASK) >> CR_PTEADDR_VPN_SHIFT);
+    trace_nios2_mmu_write_pteaddr(FIELD_EX32(v, CR_PTEADDR, PTBASE),
+                                  FIELD_EX32(v, CR_PTEADDR, VPN));
 
     /* Writes to PTEADDR don't change the read-back VPN value */
-    env->pteaddr = (v & ~CR_PTEADDR_VPN_MASK) |
-                    (env->pteaddr & CR_PTEADDR_VPN_MASK);
+    env->pteaddr = (v & ~R_CR_PTEADDR_VPN_MASK) |
+                   (env->pteaddr & R_CR_PTEADDR_VPN_MASK);
     env->mmu.pteaddr_wr = v;
 }
 
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 7a32e6626d..3cdef16519 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -909,7 +909,7 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
         }
     }
     qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
-                 env->mmu.pteaddr_wr & CR_PTEADDR_VPN_MASK,
+                 env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
                  (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
                  env->mmu.tlbacc_wr);
 #endif
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (12 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:19   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields Richard Henderson
                   ` (18 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 23 +++++++++++++++--------
 target/nios2/mmu.c | 16 ++++++++--------
 2 files changed, 23 insertions(+), 16 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 84138000fa..024ef3ccc0 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -115,14 +115,21 @@ FIELD(CR_PTEADDR, VPN, 2, 20)
 FIELD(CR_PTEADDR, PTBASE, 22, 10)
 
 #define CR_TLBACC        9
-#define   CR_TLBACC_IGN_SHIFT 25
-#define   CR_TLBACC_IGN_MASK  (0x7F << CR_TLBACC_IGN_SHIFT)
-#define   CR_TLBACC_C         (1 << 24)
-#define   CR_TLBACC_R         (1 << 23)
-#define   CR_TLBACC_W         (1 << 22)
-#define   CR_TLBACC_X         (1 << 21)
-#define   CR_TLBACC_G         (1 << 20)
-#define   CR_TLBACC_PFN_MASK  0x000FFFFF
+
+FIELD(CR_TLBACC, PFN, 0, 20)
+FIELD(CR_TLBACC, G, 20, 1)
+FIELD(CR_TLBACC, X, 21, 1)
+FIELD(CR_TLBACC, W, 22, 1)
+FIELD(CR_TLBACC, R, 23, 1)
+FIELD(CR_TLBACC, C, 24, 1)
+FIELD(CR_TLBACC, IG, 25, 7)
+
+#define CR_TLBACC_C  (1u << R_CR_TLBACC_C_SHIFT)
+#define CR_TLBACC_R  (1u << R_CR_TLBACC_R_SHIFT)
+#define CR_TLBACC_W  (1u << R_CR_TLBACC_W_SHIFT)
+#define CR_TLBACC_X  (1u << R_CR_TLBACC_X_SHIFT)
+#define CR_TLBACC_G  (1u << R_CR_TLBACC_G_SHIFT)
+
 #define CR_TLBMISC       10
 #define   CR_TLBMISC_WAY_SHIFT 20
 #define   CR_TLBMISC_WAY_MASK  (0xF << CR_TLBMISC_WAY_SHIFT)
diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c
index 8017f2af93..d6221936f7 100644
--- a/target/nios2/mmu.c
+++ b/target/nios2/mmu.c
@@ -49,7 +49,7 @@ unsigned int mmu_translate(CPUNios2State *env,
         }
 
         lu->vaddr = vaddr & TARGET_PAGE_MASK;
-        lu->paddr = (entry->data & CR_TLBACC_PFN_MASK) << TARGET_PAGE_BITS;
+        lu->paddr = FIELD_EX32(entry->data, CR_TLBACC, PFN) << TARGET_PAGE_BITS;
         lu->prot = ((entry->data & CR_TLBACC_R) ? PAGE_READ : 0) |
                    ((entry->data & CR_TLBACC_W) ? PAGE_WRITE : 0) |
                    ((entry->data & CR_TLBACC_X) ? PAGE_EXEC : 0);
@@ -86,27 +86,27 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
     CPUState *cs = env_cpu(env);
     Nios2CPU *cpu = env_archcpu(env);
 
-    trace_nios2_mmu_write_tlbacc(v >> CR_TLBACC_IGN_SHIFT,
+    trace_nios2_mmu_write_tlbacc(FIELD_EX32(v, CR_TLBACC, IG),
                                  (v & CR_TLBACC_C) ? 'C' : '.',
                                  (v & CR_TLBACC_R) ? 'R' : '.',
                                  (v & CR_TLBACC_W) ? 'W' : '.',
                                  (v & CR_TLBACC_X) ? 'X' : '.',
                                  (v & CR_TLBACC_G) ? 'G' : '.',
-                                 v & CR_TLBACC_PFN_MASK);
+                                 FIELD_EX32(v, CR_TLBACC, PFN));
 
     /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */
     if (env->tlbmisc & CR_TLBMISC_WR) {
         int way = (env->tlbmisc >> CR_TLBMISC_WAY_SHIFT);
         int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
         int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4;
-        int g = (v & CR_TLBACC_G) ? 1 : 0;
-        int valid = ((vpn & CR_TLBACC_PFN_MASK) < 0xC0000) ? 1 : 0;
+        int g = FIELD_EX32(v, CR_TLBACC, G);
+        int valid = FIELD_EX32(vpn, CR_TLBACC, PFN) < 0xC0000;
         Nios2TLBEntry *entry =
             &env->mmu.tlb[(way * cpu->tlb_num_ways) +
                           (vpn & env->mmu.tlb_entry_mask)];
         uint32_t newTag = (vpn << 12) | (g << 11) | (valid << 10) | pid;
         uint32_t newData = v & (CR_TLBACC_C | CR_TLBACC_R | CR_TLBACC_W |
-                                CR_TLBACC_X | CR_TLBACC_PFN_MASK);
+                                CR_TLBACC_X | R_CR_TLBACC_PFN_MASK);
 
         if ((entry->tag != newTag) || (entry->data != newData)) {
             if (entry->tag & (1 << 10)) {
@@ -153,7 +153,7 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
             &env->mmu.tlb[(way * cpu->tlb_num_ways) +
                           (vpn & env->mmu.tlb_entry_mask)];
 
-        env->tlbacc &= CR_TLBACC_IGN_MASK;
+        env->tlbacc &= R_CR_TLBACC_IG_MASK;
         env->tlbacc |= entry->data;
         env->tlbacc |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0;
         env->tlbmisc =
@@ -207,7 +207,7 @@ void dump_mmu(CPUNios2State *env)
                     entry->tag >> 12,
                     entry->tag & ((1 << cpu->pid_num_bits) - 1),
                     (entry->tag & (1 << 11)) ? 'G' : '-',
-                    entry->data & CR_TLBACC_PFN_MASK,
+                    FIELD_EX32(entry->data, CR_TLBACC, PFN),
                     (entry->data & CR_TLBACC_C) ? 'C' : '-',
                     (entry->data & CR_TLBACC_R) ? 'R' : '-',
                     (entry->data & CR_TLBACC_W) ? 'W' : '-',
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (13 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:46   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations Richard Henderson
                   ` (17 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       | 28 ++++++++++++++++++----------
 target/nios2/helper.c    |  7 ++-----
 target/nios2/mmu.c       | 33 +++++++++++++++------------------
 target/nios2/translate.c |  2 +-
 4 files changed, 36 insertions(+), 34 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 024ef3ccc0..3857848f7c 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -131,16 +131,24 @@ FIELD(CR_TLBACC, IG, 25, 7)
 #define CR_TLBACC_G  (1u << R_CR_TLBACC_G_SHIFT)
 
 #define CR_TLBMISC       10
-#define   CR_TLBMISC_WAY_SHIFT 20
-#define   CR_TLBMISC_WAY_MASK  (0xF << CR_TLBMISC_WAY_SHIFT)
-#define   CR_TLBMISC_RD        (1 << 19)
-#define   CR_TLBMISC_WR        (1 << 18)
-#define   CR_TLBMISC_PID_SHIFT 4
-#define   CR_TLBMISC_PID_MASK  (0x3FFF << CR_TLBMISC_PID_SHIFT)
-#define   CR_TLBMISC_DBL       (1 << 3)
-#define   CR_TLBMISC_BAD       (1 << 2)
-#define   CR_TLBMISC_PERM      (1 << 1)
-#define   CR_TLBMISC_D         (1 << 0)
+
+FIELD(CR_TLBMISC, D, 0, 1)
+FIELD(CR_TLBMISC, PERM, 1, 1)
+FIELD(CR_TLBMISC, BAD, 2, 1)
+FIELD(CR_TLBMISC, DBL, 3, 1)
+FIELD(CR_TLBMISC, PID, 4, 14)
+FIELD(CR_TLBMISC, WR, 18, 1)
+FIELD(CR_TLBMISC, RD, 19, 1)
+FIELD(CR_TLBMISC, WAY, 20, 4)
+FIELD(CR_TLBMISC, EE, 24, 1)
+
+#define CR_TLBMISC_RD    (1u << R_CR_TLBMISC_RD_SHIFT)
+#define CR_TLBMISC_WR    (1u << R_CR_TLBMISC_WR_SHIFT)
+#define CR_TLBMISC_DBL   (1u << R_CR_TLBMISC_DBL_SHIFT)
+#define CR_TLBMISC_BAD   (1u << R_CR_TLBMISC_BAD_SHIFT)
+#define CR_TLBMISC_PERM  (1u << R_CR_TLBMISC_PERM_SHIFT)
+#define CR_TLBMISC_D     (1u << R_CR_TLBMISC_D_SHIFT)
+
 #define CR_ENCINJ        11
 #define CR_BADADDR       12
 #define CR_CONFIG        13
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index 37fb53dadb..93338e86f0 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -276,11 +276,8 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
         return false;
     }
 
-    if (access_type == MMU_INST_FETCH) {
-        env->tlbmisc &= ~CR_TLBMISC_D;
-    } else {
-        env->tlbmisc |= CR_TLBMISC_D;
-    }
+    env->tlbmisc = FIELD_DP32(env->tlbmisc, CR_TLBMISC, D,
+                              access_type == MMU_INST_FETCH);
     env->pteaddr = FIELD_DP32(env->pteaddr, CR_PTEADDR, VPN,
                               address >> TARGET_PAGE_BITS);
     env->mmu.pteaddr_wr = env->pteaddr;
diff --git a/target/nios2/mmu.c b/target/nios2/mmu.c
index d6221936f7..c8b74b5479 100644
--- a/target/nios2/mmu.c
+++ b/target/nios2/mmu.c
@@ -33,7 +33,7 @@ unsigned int mmu_translate(CPUNios2State *env,
                            target_ulong vaddr, int rw, int mmu_idx)
 {
     Nios2CPU *cpu = env_archcpu(env);
-    int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4;
+    int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
     int vpn = vaddr >> 12;
     int way, n_ways = cpu->tlb_num_ways;
 
@@ -96,9 +96,9 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
 
     /* if tlbmisc.WE == 1 then trigger a TLB write on writes to TLBACC */
     if (env->tlbmisc & CR_TLBMISC_WR) {
-        int way = (env->tlbmisc >> CR_TLBMISC_WAY_SHIFT);
+        int way = FIELD_EX32(env->tlbmisc, CR_TLBMISC, WAY);
         int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
-        int pid = (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4;
+        int pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
         int g = FIELD_EX32(v, CR_TLBACC, G);
         int valid = FIELD_EX32(vpn, CR_TLBACC, PFN) < 0xC0000;
         Nios2TLBEntry *entry =
@@ -117,10 +117,8 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
             entry->data = newData;
         }
         /* Auto-increment tlbmisc.WAY */
-        env->tlbmisc =
-            (env->tlbmisc & ~CR_TLBMISC_WAY_MASK) |
-            (((way + 1) & (cpu->tlb_num_ways - 1)) <<
-             CR_TLBMISC_WAY_SHIFT);
+        env->tlbmisc = FIELD_DP32(env->tlbmisc, CR_TLBMISC, WAY,
+                                  (way + 1) & (cpu->tlb_num_ways - 1));
     }
 
     /* Writes to TLBACC don't change the read-back value */
@@ -130,24 +128,25 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
 void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
 {
     Nios2CPU *cpu = env_archcpu(env);
+    uint32_t new_pid = FIELD_EX32(v, CR_TLBMISC, PID);
+    uint32_t old_pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
+    uint32_t way = FIELD_EX32(v, CR_TLBMISC, WAY);
 
-    trace_nios2_mmu_write_tlbmisc(v >> CR_TLBMISC_WAY_SHIFT,
+    trace_nios2_mmu_write_tlbmisc(way,
                                   (v & CR_TLBMISC_RD) ? 'R' : '.',
                                   (v & CR_TLBMISC_WR) ? 'W' : '.',
                                   (v & CR_TLBMISC_DBL) ? '2' : '.',
                                   (v & CR_TLBMISC_BAD) ? 'B' : '.',
                                   (v & CR_TLBMISC_PERM) ? 'P' : '.',
                                   (v & CR_TLBMISC_D) ? 'D' : '.',
-                                  (v & CR_TLBMISC_PID_MASK) >> 4);
+                                  new_pid);
 
-    if ((v & CR_TLBMISC_PID_MASK) !=
-        (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK)) {
-        mmu_flush_pid(env, (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >>
-                           CR_TLBMISC_PID_SHIFT);
+    if (new_pid != old_pid) {
+        mmu_flush_pid(env, old_pid);
     }
+
     /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */
     if (v & CR_TLBMISC_RD) {
-        int way = (v >> CR_TLBMISC_WAY_SHIFT);
         int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
         Nios2TLBEntry *entry =
             &env->mmu.tlb[(way * cpu->tlb_num_ways) +
@@ -156,10 +155,8 @@ void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
         env->tlbacc &= R_CR_TLBACC_IG_MASK;
         env->tlbacc |= entry->data;
         env->tlbacc |= (entry->tag & (1 << 11)) ? CR_TLBACC_G : 0;
-        env->tlbmisc =
-            (v & ~CR_TLBMISC_PID_MASK) |
-            ((entry->tag & ((1 << cpu->pid_num_bits) - 1)) <<
-             CR_TLBMISC_PID_SHIFT);
+        env->tlbmisc = FIELD_DP32(v, CR_TLBMISC, PID,
+                                  entry->tag & ((1 << cpu->pid_num_bits) - 1));
         env->pteaddr = FIELD_DP32(env->pteaddr, CR_PTEADDR, VPN,
                                   entry->tag >> TARGET_PAGE_BITS);
     } else {
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 3cdef16519..77b3bf05f3 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -910,7 +910,7 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     }
     qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
                  env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
-                 (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >> 4,
+                 FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
                  env->mmu.tlbacc_wr);
 #endif
     qemu_fprintf(f, "\n\n");
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (14 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:47   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields Richard Henderson
                   ` (16 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

These symbols become available to the debugger.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 72 ++++++++++++++++++++++------------------------
 1 file changed, 35 insertions(+), 37 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 3857848f7c..927c4aaa80 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -62,25 +62,43 @@ struct Nios2CPUClass {
 #define NUM_CR_REGS 32
 
 /* General purpose register aliases */
-#define R_ZERO   0
-#define R_AT     1
-#define R_RET0   2
-#define R_RET1   3
-#define R_ARG0   4
-#define R_ARG1   5
-#define R_ARG2   6
-#define R_ARG3   7
-#define R_ET     24
-#define R_BT     25
-#define R_GP     26
-#define R_SP     27
-#define R_FP     28
-#define R_EA     29
-#define R_BA     30
-#define R_RA     31
+enum {
+    R_ZERO   = 0,
+    R_AT     = 1,
+    R_RET0   = 2,
+    R_RET1   = 3,
+    R_ARG0   = 4,
+    R_ARG1   = 5,
+    R_ARG2   = 6,
+    R_ARG3   = 7,
+    R_ET     = 24,
+    R_BT     = 25,
+    R_GP     = 26,
+    R_SP     = 27,
+    R_FP     = 28,
+    R_EA     = 29,
+    R_BA     = 30,
+    R_RA     = 31,
+};
 
 /* Control register aliases */
-#define CR_STATUS        0
+enum {
+    CR_STATUS        = 0,
+    CR_ESTATUS       = 1,
+    CR_BSTATUS       = 2,
+    CR_IENABLE       = 3,
+    CR_IPENDING      = 4,
+    CR_CPUID         = 5,
+    CR_EXCEPTION     = 7,
+    CR_PTEADDR       = 8,
+    CR_TLBACC        = 9,
+    CR_TLBMISC       = 10,
+    CR_ENCINJ        = 11,
+    CR_BADADDR       = 12,
+    CR_CONFIG        = 13,
+    CR_MPUBASE       = 14,
+    CR_MPUACC        = 15,
+};
 
 FIELD(CR_STATUS, PIE, 0, 1)
 FIELD(CR_STATUS, U, 1, 1)
@@ -98,24 +116,12 @@ FIELD(CR_STATUS, NMI, 22, 1)
 #define CR_STATUS_NMI  (1u << R_CR_STATUS_NMI_SHIFT)
 #define CR_STATUS_RSIE (1u << R_CR_STATUS_RSIE_SHIFT)
 
-#define CR_ESTATUS       1
-#define CR_BSTATUS       2
-#define CR_IENABLE       3
-#define CR_IPENDING      4
-#define CR_CPUID         5
-#define CR_CTL6          6
-#define CR_EXCEPTION     7
-
 FIELD(CR_EXCEPTION, CAUSE, 2, 5)
 FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
 
-#define CR_PTEADDR       8
-
 FIELD(CR_PTEADDR, VPN, 2, 20)
 FIELD(CR_PTEADDR, PTBASE, 22, 10)
 
-#define CR_TLBACC        9
-
 FIELD(CR_TLBACC, PFN, 0, 20)
 FIELD(CR_TLBACC, G, 20, 1)
 FIELD(CR_TLBACC, X, 21, 1)
@@ -130,8 +136,6 @@ FIELD(CR_TLBACC, IG, 25, 7)
 #define CR_TLBACC_X  (1u << R_CR_TLBACC_X_SHIFT)
 #define CR_TLBACC_G  (1u << R_CR_TLBACC_G_SHIFT)
 
-#define CR_TLBMISC       10
-
 FIELD(CR_TLBMISC, D, 0, 1)
 FIELD(CR_TLBMISC, PERM, 1, 1)
 FIELD(CR_TLBMISC, BAD, 2, 1)
@@ -149,12 +153,6 @@ FIELD(CR_TLBMISC, EE, 24, 1)
 #define CR_TLBMISC_PERM  (1u << R_CR_TLBMISC_PERM_SHIFT)
 #define CR_TLBMISC_D     (1u << R_CR_TLBMISC_D_SHIFT)
 
-#define CR_ENCINJ        11
-#define CR_BADADDR       12
-#define CR_CONFIG        13
-#define CR_MPUBASE       14
-#define CR_MPUACC        15
-
 /* Exceptions */
 #define EXCP_BREAK    0x1000
 #define EXCP_RESET    0
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (15 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:57   ` Peter Maydell
  2022-03-08 20:24   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 18/33] target/nios2: Implement cpuid Richard Henderson
                   ` (15 subsequent siblings)
  32 siblings, 2 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Create an array of masks which detail the writable and readonly
bits for each control register.  Apply them when writing to
control registers.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       | 13 ++++++
 target/nios2/cpu.c       | 90 +++++++++++++++++++++++++++++++++-------
 target/nios2/translate.c | 80 ++++++++++++++++++++++++++++-------
 3 files changed, 152 insertions(+), 31 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 927c4aaa80..7faec97d77 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -207,6 +207,11 @@ struct CPUNios2State {
     int error_code;
 };
 
+typedef struct {
+    uint32_t writable;
+    uint32_t readonly;
+} ControlRegState;
+
 /**
  * Nios2CPU:
  * @env: #CPUNios2State
@@ -230,9 +235,17 @@ struct Nios2CPU {
     uint32_t reset_addr;
     uint32_t exception_addr;
     uint32_t fast_tlb_miss_addr;
+
+    /* Bits within each control register which are reserved or readonly. */
+    ControlRegState cr_state[NUM_CR_REGS];
 };
 
 
+static inline bool nios2_cr_reserved(const ControlRegState *s)
+{
+    return (s->writable | s->readonly) == 0;
+}
+
 void nios2_tcg_init(void);
 void nios2_cpu_do_interrupt(CPUState *cs);
 void dump_mmu(CPUNios2State *env);
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index f2813d3b47..189adf111c 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -88,6 +88,55 @@ static void nios2_cpu_initfn(Object *obj)
 
     cpu_set_cpustate_pointers(cpu);
 
+    /* Begin with all fields of all registers are reserved. */
+    memset(cpu->cr_state, 0, sizeof(cpu->cr_state));
+
+    /*
+     * The combination of writable and readonly is the set of all
+     * non-reserved fields.  We apply writable as a mask to bits,
+     * and merge in existing readonly bits, before storing.
+     */
+#define WR_REG(C)       cpu->cr_state[C].writable = -1
+#define RO_REG(C)       cpu->cr_state[C].readonly = -1
+#define WR_FIELD(C, F)  cpu->cr_state[C].writable |= R_##C##_##F##_MASK
+#define RO_FIELD(C, F)  cpu->cr_state[C].readonly |= R_##C##_##F##_MASK
+
+    WR_FIELD(CR_STATUS, PIE);
+    WR_REG(CR_ESTATUS);
+    WR_REG(CR_BSTATUS);
+    RO_REG(CR_CPUID);
+    WR_FIELD(CR_EXCEPTION, CAUSE);
+    WR_REG(CR_BADADDR);
+
+    /* TODO: These control registers are not present with the EIC. */
+    WR_REG(CR_IENABLE);
+    RO_REG(CR_IPENDING);
+
+    if (cpu->mmu_present) {
+        WR_FIELD(CR_STATUS, U);
+        WR_FIELD(CR_STATUS, EH);
+
+        WR_FIELD(CR_PTEADDR, VPN);
+        WR_FIELD(CR_PTEADDR, PTBASE);
+
+        RO_FIELD(CR_TLBMISC, D);
+        RO_FIELD(CR_TLBMISC, PERM);
+        RO_FIELD(CR_TLBMISC, BAD);
+        RO_FIELD(CR_TLBMISC, DBL);
+        WR_FIELD(CR_TLBMISC, WR);
+        WR_FIELD(CR_TLBMISC, RD);
+        WR_FIELD(CR_TLBMISC, WAY);
+
+        WR_REG(CR_TLBACC);
+    }
+
+    /* TODO: ECC and MPU not implemented. */
+
+#undef WR_REG
+#undef RO_REG
+#undef WR_FIELD
+#undef RO_FIELD
+
 #if !defined(CONFIG_USER_ONLY)
     mmu_init(&cpu->env);
 
@@ -152,23 +201,26 @@ static void nios2_cpu_disas_set_info(CPUState *cpu, disassemble_info *info)
 static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
-    CPUClass *cc = CPU_GET_CLASS(cs);
     CPUNios2State *env = &cpu->env;
+    uint32_t val;
 
-    if (n > cc->gdb_num_core_regs) {
+    if (n < 32) {          /* GP regs */
+        val = env->regs[n];
+    } else if (n == 32) {    /* PC */
+        val = env->pc;
+    } else if (n < 49) {     /* Status regs */
+        unsigned cr = n - 33;
+        if (nios2_cr_reserved(&cpu->cr_state[cr])) {
+            val = 0;
+        } else {
+            val = env->ctrl[n - 33];
+        }
+    } else {
+        /* Invalid regs */
         return 0;
     }
 
-    if (n < 32) {          /* GP regs */
-        return gdb_get_reg32(mem_buf, env->regs[n]);
-    } else if (n == 32) {    /* PC */
-        return gdb_get_reg32(mem_buf, env->pc);
-    } else if (n < 49) {     /* Status regs */
-        return gdb_get_reg32(mem_buf, env->ctrl[n - 33]);
-    }
-
-    /* Invalid regs */
-    return 0;
+    return gdb_get_reg32(mem_buf, val);
 }
 
 static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
@@ -176,17 +228,25 @@ static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUClass *cc = CPU_GET_CLASS(cs);
     CPUNios2State *env = &cpu->env;
+    uint32_t val;
 
     if (n > cc->gdb_num_core_regs) {
         return 0;
     }
+    val = ldl_p(mem_buf);
 
     if (n < 32) {            /* GP regs */
-        env->regs[n] = ldl_p(mem_buf);
+        env->regs[n] = val;
     } else if (n == 32) {    /* PC */
-        env->pc = ldl_p(mem_buf);
+        env->pc = val;
     } else if (n < 49) {     /* Status regs */
-        env->ctrl[n - 33] = ldl_p(mem_buf);
+        unsigned cr = n - 33;
+        /* ??? Maybe allow the debugger to write to readonly fields. */
+        val &= cpu->cr_state[cr].writable;
+        val |= cpu->cr_state[cr].readonly & env->ctrl[cr];
+        env->ctrl[cr] = val;
+    } else {
+        g_assert_not_reached();
     }
 
     return 4;
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 77b3bf05f3..38e16df459 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -101,6 +101,7 @@ typedef struct DisasContext {
     TCGv_i32          zero;
     target_ulong      pc;
     int               mem_idx;
+    const ControlRegState *cr_state;
 } DisasContext;
 
 static TCGv cpu_R[NUM_GP_REGS];
@@ -452,17 +453,26 @@ static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
 /* rC <- ctlN */
 static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    R_TYPE(instr, code);
-    TCGv t1, t2;
-
     if (!gen_check_supervisor(dc)) {
         return;
     }
 
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    R_TYPE(instr, code);
+    TCGv t1, t2;
+
     if (unlikely(instr.c == R_ZERO)) {
         return;
     }
 
+    /* Reserved registers read as zero. */
+    if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
+        tcg_gen_movi_tl(cpu_R[instr.c], 0);
+        return;
+    }
+
     switch (instr.imm5) {
     case CR_IPENDING:
         /*
@@ -486,6 +496,7 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
                       offsetof(CPUNios2State, ctrl[instr.imm5]));
         break;
     }
+#endif
 }
 
 /* ctlN <- rA */
@@ -500,6 +511,14 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 #else
     R_TYPE(instr, code);
     TCGv v = load_gpr(dc, instr.a);
+    uint32_t ofs = offsetof(CPUNios2State, ctrl[instr.imm5]);
+    uint32_t wr = dc->cr_state[instr.imm5].writable;
+    uint32_t ro = dc->cr_state[instr.imm5].readonly;
+
+    /* Skip reserved or readonly registers. */
+    if (wr == 0) {
+        return;
+    }
 
     switch (instr.imm5) {
     case CR_PTEADDR:
@@ -511,17 +530,35 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
     case CR_TLBMISC:
         gen_helper_mmu_write_tlbmisc(cpu_env, v);
         break;
-    case CR_IPENDING:
-        /* ipending is read only, writes ignored. */
-        break;
     case CR_STATUS:
     case CR_IENABLE:
         /* If interrupts were enabled using WRCTL, trigger them. */
         dc->base.is_jmp = DISAS_UPDATE;
         /* fall through */
     default:
-        tcg_gen_st_tl(v, cpu_env,
-                      offsetof(CPUNios2State, ctrl[instr.imm5]));
+        if (wr == -1) {
+            /* The register is entirely writable. */
+            tcg_gen_st_tl(v, cpu_env, ofs);
+        } else {
+            /*
+             * The register is partially read-only or reserved:
+             * merge the value.
+             */
+            TCGv n = tcg_temp_new();
+
+            tcg_gen_andi_tl(n, v, wr);
+
+            if (ro != 0) {
+                TCGv o = tcg_temp_new();
+                tcg_gen_ld_tl(o, cpu_env, ofs);
+                tcg_gen_andi_tl(o, o, ro);
+                tcg_gen_or_tl(n, n, o);
+                tcg_temp_free(o);
+            }
+
+            tcg_gen_st_tl(n, cpu_env, ofs);
+            tcg_temp_free(n);
+        }
         break;
     }
 #endif
@@ -785,9 +822,11 @@ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 {
     DisasContext *dc = container_of(dcbase, DisasContext, base);
     CPUNios2State *env = cs->env_ptr;
+    Nios2CPU *cpu = env_archcpu(env);
     int page_insns;
 
     dc->mem_idx = cpu_mmu_index(env, false);
+    dc->cr_state = cpu->cr_state;
 
     /* Bound the number of insns to execute to those left on the page.  */
     page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
@@ -902,16 +941,25 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
     }
 
 #if !defined(CONFIG_USER_ONLY)
-    for (i = 0; i < NUM_CR_REGS; i++) {
-        qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
-        if ((i + 1) % 4 == 0) {
-            qemu_fprintf(f, "\n");
+    int j;
+
+    for (i = j = 0; i < NUM_CR_REGS; i++) {
+        if (!nios2_cr_reserved(&cpu->cr_state[i])) {
+            qemu_fprintf(f, "%9s=%8.8x ", cr_regnames[i], env->ctrl[i]);
+            if (++j % 4 == 0) {
+                qemu_fprintf(f, "\n");
+            }
         }
     }
-    qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
-                 env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
-                 FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
-                 env->mmu.tlbacc_wr);
+    if (j % 4 != 0) {
+        qemu_fprintf(f, "\n");
+    }
+    if (cpu->mmu_present) {
+        qemu_fprintf(f, " mmu write: VPN=%05X PID %02X TLBACC %08X\n",
+                     env->mmu.pteaddr_wr & R_CR_PTEADDR_VPN_MASK,
+                     FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID),
+                     env->mmu.tlbacc_wr);
+    }
 #endif
     qemu_fprintf(f, "\n\n");
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 18/33] target/nios2: Implement cpuid
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (16 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:52   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE Richard Henderson
                   ` (14 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Copy the existing cpu_index into the space reserved for CR_CPUID.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 189adf111c..fbcb4da737 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -159,6 +159,7 @@ static ObjectClass *nios2_cpu_class_by_name(const char *cpu_model)
 static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
 {
     CPUState *cs = CPU(dev);
+    Nios2CPU *cpu = NIOS2_CPU(cs);
     Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev);
     Error *local_err = NULL;
 
@@ -171,6 +172,9 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
     qemu_init_vcpu(cs);
     cpu_reset(cs);
 
+    /* We have reserved storage for ctrl[CR_CPUID]; might as well use it. */
+    cpu->env.cpuid = cs->cpu_index;
+
     ncc->parent_realize(dev, errp);
 }
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (17 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 18/33] target/nios2: Implement cpuid Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:55   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI Richard Henderson
                   ` (13 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Without EIC, this bit is RES1.  So set the bit at reset,
and add it to the readonly fields of CR_STATUS.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 1 +
 target/nios2/cpu.c | 5 +++--
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 7faec97d77..b418deec4c 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -108,6 +108,7 @@ FIELD(CR_STATUS, IL, 4, 6)
 FIELD(CR_STATUS, CRS, 10, 6)
 FIELD(CR_STATUS, PRS, 16, 6)
 FIELD(CR_STATUS, NMI, 22, 1)
+FIELD(CR_STATUS, RSIE, 23, 1)
 
 #define CR_STATUS_PIE  (1u << R_CR_STATUS_PIE_SHIFT)
 #define CR_STATUS_U    (1u << R_CR_STATUS_U_SHIFT)
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index fbcb4da737..ed7b9f9459 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -59,9 +59,9 @@ static void nios2_cpu_reset(DeviceState *dev)
 
 #if defined(CONFIG_USER_ONLY)
     /* Start in user mode with interrupts enabled. */
-    env->status = CR_STATUS_U | CR_STATUS_PIE;
+    env->status = CR_STATUS_RSIE | CR_STATUS_U | CR_STATUS_PIE;
 #else
-    env->status = 0;
+    env->status = CR_STATUS_RSIE;
 #endif
 }
 
@@ -109,6 +109,7 @@ static void nios2_cpu_initfn(Object *obj)
     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);
 
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (18 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 10:56   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 21/33] target/nios2: Use tcg_constant_tl Richard Henderson
                   ` (12 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

This interrupt bit is never set, so testing it in
nios2_cpu_has_work is pointless.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 2 --
 target/nios2/cpu.c | 2 +-
 2 files changed, 1 insertion(+), 3 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index b418deec4c..f582e52aa4 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -175,8 +175,6 @@ FIELD(CR_TLBMISC, EE, 24, 1)
 #define EXCP_MPUI     16
 #define EXCP_MPUD     17
 
-#define CPU_INTERRUPT_NMI       CPU_INTERRUPT_TGT_EXT_3
-
 struct CPUNios2State {
     uint32_t regs[NUM_GP_REGS];
     union {
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index ed7b9f9459..2779650128 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -36,7 +36,7 @@ static void nios2_cpu_set_pc(CPUState *cs, vaddr value)
 
 static bool nios2_cpu_has_work(CPUState *cs)
 {
-    return cs->interrupt_request & (CPU_INTERRUPT_HARD | CPU_INTERRUPT_NMI);
+    return cs->interrupt_request & CPU_INTERRUPT_HARD;
 }
 
 static void nios2_cpu_reset(DeviceState *dev)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 21/33] target/nios2: Use tcg_constant_tl
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (19 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 11:00   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 22/33] target/nios2: Introduce dest_gpr Richard Henderson
                   ` (11 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Replace current uses of tcg_const_tl, and remove the frees.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 36 ++++++++----------------------------
 1 file changed, 8 insertions(+), 28 deletions(-)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 38e16df459..6ff9c18502 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -98,7 +98,6 @@
 
 typedef struct DisasContext {
     DisasContextBase  base;
-    TCGv_i32          zero;
     target_ulong      pc;
     int               mem_idx;
     const ControlRegState *cr_state;
@@ -124,31 +123,20 @@ static uint8_t get_opxcode(uint32_t code)
     return instr.opx;
 }
 
-static TCGv load_zero(DisasContext *dc)
+static TCGv load_gpr(DisasContext *dc, unsigned reg)
 {
-    if (!dc->zero) {
-        dc->zero = tcg_const_i32(0);
-    }
-    return dc->zero;
-}
-
-static TCGv load_gpr(DisasContext *dc, uint8_t reg)
-{
-    if (likely(reg != R_ZERO)) {
-        return cpu_R[reg];
-    } else {
-        return load_zero(dc);
+    assert(reg < NUM_GP_REGS);
+    if (unlikely(reg == R_ZERO)) {
+        return tcg_constant_tl(0);
     }
+    return cpu_R[reg];
 }
 
 static void t_gen_helper_raise_exception(DisasContext *dc,
                                          uint32_t index)
 {
-    TCGv_i32 tmp = tcg_const_i32(index);
-
     tcg_gen_movi_tl(cpu_pc, dc->pc);
-    gen_helper_raise_exception(cpu_env, tmp);
-    tcg_temp_free_i32(tmp);
+    gen_helper_raise_exception(cpu_env, tcg_constant_i32(index));
     dc->base.is_jmp = DISAS_NORETURN;
 }
 
@@ -675,8 +663,8 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
-    TCGv t2 = tcg_const_tl(0);
-    TCGv t3 = tcg_const_tl(1);
+    TCGv t2 = tcg_constant_tl(0);
+    TCGv t3 = tcg_constant_tl(1);
 
     tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
     tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
@@ -684,8 +672,6 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
     tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
     tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
 
-    tcg_temp_free(t3);
-    tcg_temp_free(t2);
     tcg_temp_free(t1);
     tcg_temp_free(t0);
 }
@@ -863,14 +849,8 @@ static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
         return;
     }
 
-    dc->zero = NULL;
-
     instr = &i_type_instructions[op];
     instr->handler(dc, code, instr->flags);
-
-    if (dc->zero) {
-        tcg_temp_free(dc->zero);
-    }
 }
 
 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 22/33] target/nios2: Introduce dest_gpr
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (20 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 21/33] target/nios2: Use tcg_constant_tl Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 11:07   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags Richard Henderson
                   ` (10 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Constrain all references to cpu_R[] to load_gpr and dest_gpr.
This will be required for supporting shadow register sets.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/translate.c | 144 +++++++++++++++------------------------
 1 file changed, 55 insertions(+), 89 deletions(-)

diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 6ff9c18502..7c2ad02685 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -100,6 +100,7 @@ typedef struct DisasContext {
     DisasContextBase  base;
     target_ulong      pc;
     int               mem_idx;
+    TCGv              sink;
     const ControlRegState *cr_state;
 } DisasContext;
 
@@ -132,6 +133,18 @@ static TCGv load_gpr(DisasContext *dc, unsigned reg)
     return cpu_R[reg];
 }
 
+static TCGv dest_gpr(DisasContext *dc, unsigned reg)
+{
+    assert(reg < NUM_GP_REGS);
+    if (unlikely(reg == R_ZERO)) {
+        if (dc->sink == NULL) {
+            dc->sink = tcg_temp_new();
+        }
+        return dc->sink;
+    }
+    return cpu_R[reg];
+}
+
 static void t_gen_helper_raise_exception(DisasContext *dc,
                                          uint32_t index)
 {
@@ -190,7 +203,7 @@ static void jmpi(DisasContext *dc, uint32_t code, uint32_t flags)
 
 static void call(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
+    tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
     jmpi(dc, code, flags);
 }
 
@@ -203,27 +216,10 @@ static void gen_ldx(DisasContext *dc, uint32_t code, uint32_t flags)
     I_TYPE(instr, code);
 
     TCGv addr = tcg_temp_new();
-    TCGv data;
-
-    /*
-     * WARNING: Loads into R_ZERO are ignored, but we must generate the
-     *          memory access itself to emulate the CPU precisely. Load
-     *          from a protected page to R_ZERO will cause SIGSEGV on
-     *          the Nios2 CPU.
-     */
-    if (likely(instr.b != R_ZERO)) {
-        data = cpu_R[instr.b];
-    } else {
-        data = tcg_temp_new();
-    }
+    TCGv data = dest_gpr(dc, instr.b);
 
     tcg_gen_addi_tl(addr, load_gpr(dc, instr.a), instr.imm16.s);
     tcg_gen_qemu_ld_tl(data, addr, dc->mem_idx, flags);
-
-    if (unlikely(instr.b == R_ZERO)) {
-        tcg_temp_free(data);
-    }
-
     tcg_temp_free(addr);
 }
 
@@ -253,7 +249,7 @@ static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
     I_TYPE(instr, code);
 
     TCGLabel *l1 = gen_new_label();
-    tcg_gen_brcond_tl(flags, cpu_R[instr.a], cpu_R[instr.b], l1);
+    tcg_gen_brcond_tl(flags, load_gpr(dc, instr.a), load_gpr(dc, instr.b), l1);
     gen_goto_tb(dc, 0, dc->base.pc_next);
     gen_set_label(l1);
     gen_goto_tb(dc, 1, dc->base.pc_next + (instr.imm16.s & -4));
@@ -261,11 +257,12 @@ static void gen_bxx(DisasContext *dc, uint32_t code, uint32_t flags)
 }
 
 /* Comparison instructions */
-#define gen_i_cmpxx(fname, op3)                                              \
-static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)         \
-{                                                                            \
-    I_TYPE(instr, (code));                                                   \
-    tcg_gen_setcondi_tl(flags, cpu_R[instr.b], cpu_R[instr.a], (op3));       \
+#define gen_i_cmpxx(fname, op3)                                         \
+static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
+{                                                                       \
+    I_TYPE(instr, (code));                                              \
+    tcg_gen_setcondi_tl(flags, dest_gpr(dc, instr.b),                   \
+                        load_gpr(dc, instr.a), (op3));                  \
 }
 
 gen_i_cmpxx(gen_cmpxxsi, instr.imm16.s)
@@ -276,13 +273,7 @@ gen_i_cmpxx(gen_cmpxxui, instr.imm16.u)
 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)        \
 {                                                                           \
     I_TYPE(instr, (code));                                                  \
-    if (unlikely(instr.b == R_ZERO)) { /* Store to R_ZERO is ignored */     \
-        return;                                                             \
-    } else if (instr.a == R_ZERO) { /* MOVxI optimizations */               \
-        tcg_gen_movi_tl(cpu_R[instr.b], (resimm) ? (op3) : 0);              \
-    } else {                                                                \
-        tcg_gen_##insn##_tl(cpu_R[instr.b], cpu_R[instr.a], (op3));         \
-    }                                                                       \
+    tcg_gen_##insn##_tl(dest_gpr(dc, instr.b), load_gpr(dc, instr.a), (op3)); \
 }
 
 gen_i_math_logic(addi,  addi, 1, instr.imm16.s)
@@ -383,7 +374,7 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 #ifdef CONFIG_USER_ONLY
     g_assert_not_reached();
 #else
-    gen_helper_eret(cpu_env, cpu_R[R_EA]);
+    gen_helper_eret(cpu_env, load_gpr(dc, R_EA));
     dc->base.is_jmp = DISAS_NORETURN;
 #endif
 }
@@ -391,16 +382,14 @@ static void eret(DisasContext *dc, uint32_t code, uint32_t flags)
 /* PC <- ra */
 static void ret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    tcg_gen_mov_tl(cpu_pc, cpu_R[R_RA]);
-
+    tcg_gen_mov_tl(cpu_pc, load_gpr(dc, R_RA));
     dc->base.is_jmp = DISAS_JUMP;
 }
 
 /* PC <- ba */
 static void bret(DisasContext *dc, uint32_t code, uint32_t flags)
 {
-    tcg_gen_mov_tl(cpu_pc, cpu_R[R_BA]);
-
+    tcg_gen_mov_tl(cpu_pc, load_gpr(dc, R_BA));
     dc->base.is_jmp = DISAS_JUMP;
 }
 
@@ -410,7 +399,6 @@ static void jmp(DisasContext *dc, uint32_t code, uint32_t flags)
     R_TYPE(instr, code);
 
     tcg_gen_mov_tl(cpu_pc, load_gpr(dc, instr.a));
-
     dc->base.is_jmp = DISAS_JUMP;
 }
 
@@ -419,9 +407,7 @@ static void nextpc(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
 
-    if (likely(instr.c != R_ZERO)) {
-        tcg_gen_movi_tl(cpu_R[instr.c], dc->base.pc_next);
-    }
+    tcg_gen_movi_tl(dest_gpr(dc, instr.c), dc->base.pc_next);
 }
 
 /*
@@ -433,7 +419,7 @@ static void callr(DisasContext *dc, uint32_t code, uint32_t flags)
     R_TYPE(instr, code);
 
     tcg_gen_mov_tl(cpu_pc, load_gpr(dc, instr.a));
-    tcg_gen_movi_tl(cpu_R[R_RA], dc->base.pc_next);
+    tcg_gen_movi_tl(dest_gpr(dc, R_RA), dc->base.pc_next);
 
     dc->base.is_jmp = DISAS_JUMP;
 }
@@ -449,15 +435,11 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
     g_assert_not_reached();
 #else
     R_TYPE(instr, code);
-    TCGv t1, t2;
-
-    if (unlikely(instr.c == R_ZERO)) {
-        return;
-    }
+    TCGv t1, t2, dest = dest_gpr(dc, instr.c);
 
     /* Reserved registers read as zero. */
     if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
-        tcg_gen_movi_tl(cpu_R[instr.c], 0);
+        tcg_gen_movi_tl(dest, 0);
         return;
     }
 
@@ -475,12 +457,12 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
         t2 = tcg_temp_new();
         tcg_gen_ld_tl(t1, cpu_env, offsetof(CPUNios2State, ipending));
         tcg_gen_ld_tl(t2, cpu_env, offsetof(CPUNios2State, ienable));
-        tcg_gen_and_tl(cpu_R[instr.c], t1, t2);
+        tcg_gen_and_tl(dest, t1, t2);
         tcg_temp_free(t1);
         tcg_temp_free(t2);
         break;
     default:
-        tcg_gen_ld_tl(cpu_R[instr.c], cpu_env,
+        tcg_gen_ld_tl(dest, cpu_env,
                       offsetof(CPUNios2State, ctrl[instr.imm5]));
         break;
     }
@@ -556,10 +538,8 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, code);
-    if (likely(instr.c != R_ZERO)) {
-        tcg_gen_setcond_tl(flags, cpu_R[instr.c], cpu_R[instr.a],
-                           cpu_R[instr.b]);
-    }
+    tcg_gen_setcond_tl(flags, dest_gpr(dc, instr.c),
+                       load_gpr(dc, instr.a), load_gpr(dc, instr.b));
 }
 
 /* Math/logic instructions */
@@ -567,9 +547,7 @@ static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
 {                                                                          \
     R_TYPE(instr, (code));                                                 \
-    if (likely(instr.c != R_ZERO)) {                                       \
-        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), (op3));    \
-    }                                                                      \
+    tcg_gen_##insn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), (op3));   \
 }
 
 gen_r_math_logic(add,  add_tl,   load_gpr(dc, instr.b))
@@ -590,28 +568,24 @@ gen_r_math_logic(roli, rotli_tl, instr.imm5)
 static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)   \
 {                                                                      \
     R_TYPE(instr, (code));                                             \
-    if (likely(instr.c != R_ZERO)) {                                   \
-        TCGv t0 = tcg_temp_new();                                      \
-        tcg_gen_##insn(t0, cpu_R[instr.c],                             \
-                       load_gpr(dc, instr.a), load_gpr(dc, instr.b));  \
-        tcg_temp_free(t0);                                             \
-    }                                                                  \
+    TCGv t0 = tcg_temp_new();                                          \
+    tcg_gen_##insn(t0, dest_gpr(dc, instr.c),                          \
+                   load_gpr(dc, instr.a), load_gpr(dc, instr.b));      \
+    tcg_temp_free(t0);                                                 \
 }
 
 gen_r_mul(mulxss, muls2_tl)
 gen_r_mul(mulxuu, mulu2_tl)
 gen_r_mul(mulxsu, mulsu2_tl)
 
-#define gen_r_shift_s(fname, insn)                                         \
-static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)       \
-{                                                                          \
-    R_TYPE(instr, (code));                                                 \
-    if (likely(instr.c != R_ZERO)) {                                       \
-        TCGv t0 = tcg_temp_new();                                          \
-        tcg_gen_andi_tl(t0, load_gpr((dc), instr.b), 31);                  \
-        tcg_gen_##insn(cpu_R[instr.c], load_gpr((dc), instr.a), t0);       \
-        tcg_temp_free(t0);                                                 \
-    }                                                                      \
+#define gen_r_shift_s(fname, insn)                                      \
+static void (fname)(DisasContext *dc, uint32_t code, uint32_t flags)    \
+{                                                                       \
+    R_TYPE(instr, (code));                                              \
+    TCGv t0 = tcg_temp_new();                                           \
+    tcg_gen_andi_tl(t0, load_gpr(dc, instr.b), 31);                     \
+    tcg_gen_##insn(dest_gpr(dc, instr.c), load_gpr(dc, instr.a), t0);   \
+    tcg_temp_free(t0);                                                  \
 }
 
 gen_r_shift_s(sra, sar_tl)
@@ -623,12 +597,6 @@ gen_r_shift_s(ror, rotr_tl)
 static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, (code));
-
-    /* Stores into R_ZERO are ignored */
-    if (unlikely(instr.c == R_ZERO)) {
-        return;
-    }
-
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
     TCGv t2 = tcg_temp_new();
@@ -643,8 +611,7 @@ static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
     tcg_gen_or_tl(t2, t2, t3);
     tcg_gen_movi_tl(t3, 0);
     tcg_gen_movcond_tl(TCG_COND_NE, t1, t2, t3, t2, t1);
-    tcg_gen_div_tl(cpu_R[instr.c], t0, t1);
-    tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
+    tcg_gen_div_tl(dest_gpr(dc, instr.c), t0, t1);
 
     tcg_temp_free(t3);
     tcg_temp_free(t2);
@@ -655,12 +622,6 @@ static void divs(DisasContext *dc, uint32_t code, uint32_t flags)
 static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
 {
     R_TYPE(instr, (code));
-
-    /* Stores into R_ZERO are ignored */
-    if (unlikely(instr.c == R_ZERO)) {
-        return;
-    }
-
     TCGv t0 = tcg_temp_new();
     TCGv t1 = tcg_temp_new();
     TCGv t2 = tcg_constant_tl(0);
@@ -669,8 +630,7 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
     tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
     tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
     tcg_gen_movcond_tl(TCG_COND_EQ, t1, t1, t2, t3, t1);
-    tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
-    tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
+    tcg_gen_divu_tl(dest_gpr(dc, instr.c), t0, t1);
 
     tcg_temp_free(t1);
     tcg_temp_free(t0);
@@ -849,8 +809,14 @@ static void nios2_tr_translate_insn(DisasContextBase *dcbase, CPUState *cs)
         return;
     }
 
+    dc->sink = NULL;
+
     instr = &i_type_instructions[op];
     instr->handler(dc, code, instr->flags);
+
+    if (dc->sink) {
+        tcg_temp_free(dc->sink);
+    }
 }
 
 static void nios2_tr_tb_stop(DisasContextBase *dcbase, CPUState *cs)
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (21 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 22/33] target/nios2: Introduce dest_gpr Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 11:08   ` Peter Maydell
  2022-03-08  7:19 ` [PATCH v4 24/33] target/nios2: Introduce shadow register sets Richard Henderson
                   ` (9 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

There's nothing about EH that affects translation,
so there's no need to include it in tb->flags.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index f582e52aa4..2a5e070960 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -291,7 +291,7 @@ static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
 {
     *pc = env->pc;
     *cs_base = 0;
-    *flags = env->status & (CR_STATUS_EH | CR_STATUS_U);
+    *flags = env->status & CR_STATUS_U;
 }
 
 #endif /* NIOS2_CPU_H */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 24/33] target/nios2: Introduce shadow register sets
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (22 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-09 14:02   ` Amir Gonnen
  2022-03-08  7:19 ` [PATCH v4 25/33] target/nios2: Implement rdprs, wrprs Richard Henderson
                   ` (8 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Do not actually enable them so far, but add all of the
plumbing to address them.  Do not enable them for user-only.

Add an env->crs pointer that handles the indirection to
the current register set.  Add a nios2_crs() function to
wrap this for normal uses, which hides the difference
between user-only and system modes.

From the notes on wrprs, which states that r0 must be initialized
before use in shadow register sets, infer that R_ZERO is *not*
hardwired to zero in shadow register sets.  Adjust load_gpr and
dest_gpr to reflect this.  At the same time we might as well
special case crs == 0 to avoid the indirection through env->crs
during translation as well.  Given that this is intended to be
the most common case for non-interrupt handlers.

Drop the zeroing of env->regs at reset, as those are undefined.
Do init env->crs at reset.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h        | 32 ++++++++++++++++++++
 hw/nios2/boot.c           |  8 ++---
 target/nios2/cpu.c        |  7 +++--
 target/nios2/helper.c     | 12 ++++----
 target/nios2/nios2-semi.c | 13 ++++----
 target/nios2/translate.c  | 62 ++++++++++++++++++++++++++-------------
 6 files changed, 95 insertions(+), 39 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 2a5e070960..f05536e04d 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -61,6 +61,11 @@ struct Nios2CPUClass {
 #define NUM_GP_REGS 32
 #define NUM_CR_REGS 32
 
+#ifndef CONFIG_USER_ONLY
+/* 63 shadow register sets; index 0 is the primary register set. */
+#define NUM_REG_SETS 64
+#endif
+
 /* General purpose register aliases */
 enum {
     R_ZERO   = 0,
@@ -176,7 +181,13 @@ FIELD(CR_TLBMISC, EE, 24, 1)
 #define EXCP_MPUD     17
 
 struct CPUNios2State {
+#ifdef CONFIG_USER_ONLY
     uint32_t regs[NUM_GP_REGS];
+#else
+    uint32_t shadow_regs[NUM_REG_SETS][NUM_GP_REGS];
+    uint32_t *crs;
+#endif
+
     union {
         uint32_t ctrl[NUM_CR_REGS];
         struct {
@@ -245,6 +256,23 @@ static inline bool nios2_cr_reserved(const ControlRegState *s)
     return (s->writable | s->readonly) == 0;
 }
 
+static inline void nios2_update_crs(CPUNios2State *env)
+{
+#ifndef CONFIG_USER_ONLY
+    unsigned crs = FIELD_EX32(env->status, CR_STATUS, CRS);
+    env->crs = env->shadow_regs[crs];
+#endif
+}
+
+static inline uint32_t *nios2_crs(CPUNios2State *env)
+{
+#ifdef CONFIG_USER_ONLY
+    return env->regs;
+#else
+    return env->crs;
+#endif
+}
+
 void nios2_tcg_init(void);
 void nios2_cpu_do_interrupt(CPUState *cs);
 void dump_mmu(CPUNios2State *env);
@@ -286,12 +314,16 @@ typedef Nios2CPU ArchCPU;
 
 #include "exec/cpu-all.h"
 
+FIELD(TBFLAGS, CRS0, 0, 1)
+FIELD(TBFLAGS, U, 1, 1)     /* Overlaps CR_STATUS_U */
+
 static inline void cpu_get_tb_cpu_state(CPUNios2State *env, target_ulong *pc,
                                         target_ulong *cs_base, uint32_t *flags)
 {
     *pc = env->pc;
     *cs_base = 0;
     *flags = env->status & CR_STATUS_U;
+    *flags |= env->status & R_CR_STATUS_CRS_MASK ? 0 : R_TBFLAGS_CRS0_MASK;
 }
 
 #endif /* NIOS2_CPU_H */
diff --git a/hw/nios2/boot.c b/hw/nios2/boot.c
index 5b3e4efed5..96896f2ec5 100644
--- a/hw/nios2/boot.c
+++ b/hw/nios2/boot.c
@@ -62,10 +62,10 @@ static void main_cpu_reset(void *opaque)
 
     cpu_reset(CPU(cpu));
 
-    env->regs[R_ARG0] = NIOS2_MAGIC;
-    env->regs[R_ARG1] = boot_info.initrd_start;
-    env->regs[R_ARG2] = boot_info.fdt;
-    env->regs[R_ARG3] = boot_info.cmdline;
+    nios2_crs(env)[R_ARG0] = NIOS2_MAGIC;
+    nios2_crs(env)[R_ARG1] = boot_info.initrd_start;
+    nios2_crs(env)[R_ARG2] = boot_info.fdt;
+    nios2_crs(env)[R_ARG3] = boot_info.cmdline;
 
     cpu_set_pc(cs, boot_info.bootstrap_pc);
     if (boot_info.machine_cpu_reset) {
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 2779650128..05f4a7a93a 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -53,7 +53,6 @@ static void nios2_cpu_reset(DeviceState *dev)
 
     ncc->parent_reset(dev);
 
-    memset(env->regs, 0, sizeof(env->regs));
     memset(env->ctrl, 0, sizeof(env->ctrl));
     env->pc = cpu->reset_addr;
 
@@ -63,6 +62,8 @@ static void nios2_cpu_reset(DeviceState *dev)
 #else
     env->status = CR_STATUS_RSIE;
 #endif
+
+    nios2_update_crs(env);
 }
 
 #ifndef CONFIG_USER_ONLY
@@ -210,7 +211,7 @@ static int nios2_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
     uint32_t val;
 
     if (n < 32) {          /* GP regs */
-        val = env->regs[n];
+        val = nios2_crs(env)[n];
     } else if (n == 32) {    /* PC */
         val = env->pc;
     } else if (n < 49) {     /* Status regs */
@@ -241,7 +242,7 @@ static int nios2_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
     val = ldl_p(mem_buf);
 
     if (n < 32) {            /* GP regs */
-        env->regs[n] = val;
+        nios2_crs(env)[n] = val;
     } else if (n == 32) {    /* PC */
         env->pc = val;
     } else if (n < 49) {     /* Status regs */
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index 93338e86f0..007496b957 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -64,7 +64,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->status |= CR_STATUS_IH;
         env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
 
-        env->regs[R_EA] = env->pc + 4;
+        nios2_crs(env)[R_EA] = env->pc + 4;
         env->pc = cpu->exception_addr;
         break;
 
@@ -83,7 +83,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->tlbmisc &= ~CR_TLBMISC_DBL;
             env->tlbmisc |= CR_TLBMISC_WR;
 
-            env->regs[R_EA] = env->pc + 4;
+            nios2_crs(env)[R_EA] = env->pc + 4;
             env->pc = cpu->fast_tlb_miss_addr;
         } else {
             qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", env->pc);
@@ -111,7 +111,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
             env->tlbmisc |= CR_TLBMISC_WR;
         }
 
-        env->regs[R_EA] = env->pc + 4;
+        nios2_crs(env)[R_EA] = env->pc + 4;
         env->pc = cpu->exception_addr;
         break;
 
@@ -122,7 +122,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
         if ((env->status & CR_STATUS_EH) == 0) {
             env->estatus = env->status;
-            env->regs[R_EA] = env->pc + 4;
+            nios2_crs(env)[R_EA] = env->pc + 4;
         }
 
         env->status |= CR_STATUS_EH;
@@ -137,7 +137,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
         if ((env->status & CR_STATUS_EH) == 0) {
             env->estatus = env->status;
-            env->regs[R_EA] = env->pc + 4;
+            nios2_crs(env)[R_EA] = env->pc + 4;
         }
 
         env->status |= CR_STATUS_EH;
@@ -159,7 +159,7 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
         if ((env->status & CR_STATUS_EH) == 0) {
             env->bstatus = env->status;
-            env->regs[R_BA] = env->pc + 4;
+            nios2_crs(env)[R_BA] = env->pc + 4;
         }
 
         env->status |= CR_STATUS_EH;
diff --git a/target/nios2/nios2-semi.c b/target/nios2/nios2-semi.c
index fe5598bae4..8495718de0 100644
--- a/target/nios2/nios2-semi.c
+++ b/target/nios2/nios2-semi.c
@@ -144,7 +144,7 @@ static bool translate_stat(CPUNios2State *env, target_ulong addr,
 static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret,
                                   uint32_t err)
 {
-    target_ulong args = env->regs[R_ARG1];
+    target_ulong args = nios2_crs(env)[R_ARG1];
     if (put_user_u32(ret, args) ||
         put_user_u32(err, args + 4)) {
         /*
@@ -160,7 +160,7 @@ static void nios2_semi_return_u32(CPUNios2State *env, uint32_t ret,
 static void nios2_semi_return_u64(CPUNios2State *env, uint64_t ret,
                                   uint32_t err)
 {
-    target_ulong args = env->regs[R_ARG1];
+    target_ulong args = nios2_crs(env)[R_ARG1];
     if (put_user_u32(ret >> 32, args) ||
         put_user_u32(ret, args + 4) ||
         put_user_u32(err, args + 8)) {
@@ -210,13 +210,14 @@ void do_nios2_semihosting(CPUNios2State *env)
     void *q;
     uint32_t len;
     uint32_t result;
+    uint32_t *crs = nios2_crs(env);
 
-    nr = env->regs[R_ARG0];
-    args = env->regs[R_ARG1];
+    nr = crs[R_ARG0];
+    args = crs[R_ARG1];
     switch (nr) {
     case HOSTED_EXIT:
-        gdb_exit(env->regs[R_ARG0]);
-        exit(env->regs[R_ARG0]);
+        gdb_exit(crs[R_ARG0]);
+        exit(crs[R_ARG0]);
     case HOSTED_OPEN:
         GET_ARG(0);
         GET_ARG(1);
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 7c2ad02685..57913da3c9 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -100,12 +100,16 @@ typedef struct DisasContext {
     DisasContextBase  base;
     target_ulong      pc;
     int               mem_idx;
+    bool              crs0;
     TCGv              sink;
     const ControlRegState *cr_state;
 } DisasContext;
 
 static TCGv cpu_R[NUM_GP_REGS];
 static TCGv cpu_pc;
+#ifndef CONFIG_USER_ONLY
+static TCGv cpu_crs_R[NUM_GP_REGS];
+#endif
 
 typedef struct Nios2Instruction {
     void     (*handler)(DisasContext *dc, uint32_t code, uint32_t flags);
@@ -127,22 +131,36 @@ static uint8_t get_opxcode(uint32_t code)
 static TCGv load_gpr(DisasContext *dc, unsigned reg)
 {
     assert(reg < NUM_GP_REGS);
-    if (unlikely(reg == R_ZERO)) {
-        return tcg_constant_tl(0);
+    if (dc->crs0) {
+        if (unlikely(reg == R_ZERO)) {
+            return tcg_constant_tl(0);
+        }
+        return cpu_R[reg];
     }
-    return cpu_R[reg];
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    return cpu_crs_R[reg];
+#endif
 }
 
 static TCGv dest_gpr(DisasContext *dc, unsigned reg)
 {
     assert(reg < NUM_GP_REGS);
-    if (unlikely(reg == R_ZERO)) {
-        if (dc->sink == NULL) {
-            dc->sink = tcg_temp_new();
+    if (dc->crs0) {
+        if (unlikely(reg == R_ZERO)) {
+            if (dc->sink == NULL) {
+                dc->sink = tcg_temp_new();
+            }
+            return dc->sink;
         }
-        return dc->sink;
+        return cpu_R[reg];
     }
-    return cpu_R[reg];
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    return cpu_crs_R[reg];
+#endif
 }
 
 static void t_gen_helper_raise_exception(DisasContext *dc,
@@ -174,7 +192,7 @@ static void gen_excp(DisasContext *dc, uint32_t code, uint32_t flags)
 
 static bool gen_check_supervisor(DisasContext *dc)
 {
-    if (dc->base.tb->flags & CR_STATUS_U) {
+    if (dc->base.tb->flags & R_TBFLAGS_U_MASK) {
         /* CPU in user mode, privileged instruction called, stop. */
         t_gen_helper_raise_exception(dc, EXCP_SUPERI);
         return false;
@@ -773,6 +791,7 @@ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 
     dc->mem_idx = cpu_mmu_index(env, false);
     dc->cr_state = cpu->cr_state;
+    dc->crs0 = FIELD_EX32(dc->base.tb->flags, TBFLAGS, CRS0);
 
     /* Bound the number of insns to execute to those left on the page.  */
     page_insns = -(dc->base.pc_first | TARGET_PAGE_MASK) / 4;
@@ -871,16 +890,13 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
+    const uint32_t *crs = nios2_crs(env);
     int i;
 
-    if (!env) {
-        return;
-    }
-
     qemu_fprintf(f, "IN: PC=%x %s\n", env->pc, lookup_symbol(env->pc));
 
     for (i = 0; i < NUM_GP_REGS; i++) {
-        qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], env->regs[i]);
+        qemu_fprintf(f, "%9s=%8.8x ", gr_regnames[i], crs[i]);
         if ((i + 1) % 4 == 0) {
             qemu_fprintf(f, "\n");
         }
@@ -912,13 +928,19 @@ void nios2_cpu_dump_state(CPUState *cs, FILE *f, int flags)
 
 void nios2_tcg_init(void)
 {
-    int i;
-
-    for (i = 0; i < NUM_GP_REGS; i++) {
-        cpu_R[i] = tcg_global_mem_new(cpu_env,
-                                      offsetof(CPUNios2State, regs[i]),
-                                      gr_regnames[i]);
+    for (int i = 0; i < NUM_GP_REGS; i++) {
+        cpu_R[i] = tcg_global_mem_new(cpu_env, 4 * i, gr_regnames[i]);
     }
+
+#ifndef CONFIG_USER_ONLY
+    TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
+                                          offsetof(CPUNios2State, crs), "crs");
+
+    for (int i = 0; i < NUM_GP_REGS; i++) {
+        cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
+    }
+#endif
+
     cpu_pc = tcg_global_mem_new(cpu_env,
                                 offsetof(CPUNios2State, pc), "pc");
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 25/33] target/nios2: Implement rdprs, wrprs
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (23 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 24/33] target/nios2: Introduce shadow register sets Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 26/33] target/nios2: Update helper_eret for shadow registers Richard Henderson
                   ` (7 subsequent siblings)
  32 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Implement these out of line, so that tcg global temps
(aka the architectural registers) are synced back to
storage as required.  This makes sure that we get the
proper results when status.PRS == status.CRS.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       |  2 ++
 target/nios2/helper.h    |  2 ++
 target/nios2/op_helper.c | 12 ++++++++++
 target/nios2/translate.c | 47 ++++++++++++++++++++++++++++++++++++++--
 4 files changed, 61 insertions(+), 2 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index f05536e04d..efaac274aa 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -237,6 +237,8 @@ struct Nios2CPU {
     CPUNios2State env;
 
     bool mmu_present;
+    bool eic_present;
+
     uint32_t pid_num_bits;
     uint32_t tlb_num_ways;
     uint32_t tlb_num_entries;
diff --git a/target/nios2/helper.h b/target/nios2/helper.h
index 02797c384d..a8edca5194 100644
--- a/target/nios2/helper.h
+++ b/target/nios2/helper.h
@@ -22,6 +22,8 @@ DEF_HELPER_FLAGS_2(raise_exception, TCG_CALL_NO_WG, noreturn, env, i32)
 
 #if !defined(CONFIG_USER_ONLY)
 DEF_HELPER_2(eret, noreturn, env, i32)
+DEF_HELPER_FLAGS_2(rdprs, TCG_CALL_NO_WG, i32, env, i32)
+DEF_HELPER_3(wrprs, void, env, i32, i32)
 DEF_HELPER_2(mmu_write_tlbacc, void, env, i32)
 DEF_HELPER_2(mmu_write_tlbmisc, void, env, i32)
 DEF_HELPER_2(mmu_write_pteaddr, void, env, i32)
diff --git a/target/nios2/op_helper.c b/target/nios2/op_helper.c
index a1554ce349..e656986e3c 100644
--- a/target/nios2/op_helper.c
+++ b/target/nios2/op_helper.c
@@ -38,4 +38,16 @@ void helper_eret(CPUNios2State *env, uint32_t new_pc)
     env->pc = new_pc;
     cpu_loop_exit(env_cpu(env));
 }
+
+uint32_t helper_rdprs(CPUNios2State *env, uint32_t regno)
+{
+    unsigned prs = FIELD_EX32(env->status, CR_STATUS, PRS);
+    return env->shadow_regs[prs][regno];
+}
+
+void helper_wrprs(CPUNios2State *env, uint32_t regno, uint32_t val)
+{
+    unsigned prs = FIELD_EX32(env->status, CR_STATUS, PRS);
+    env->shadow_regs[prs][regno] = val;
+}
 #endif /* !CONFIG_USER_ONLY */
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 57913da3c9..7730735639 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -103,6 +103,7 @@ typedef struct DisasContext {
     bool              crs0;
     TCGv              sink;
     const ControlRegState *cr_state;
+    bool              eic_present;
 } DisasContext;
 
 static TCGv cpu_R[NUM_GP_REGS];
@@ -305,6 +306,27 @@ gen_i_math_logic(andhi, andi, 0, instr.imm16.u << 16)
 gen_i_math_logic(orhi , ori,  1, instr.imm16.u << 16)
 gen_i_math_logic(xorhi, xori, 1, instr.imm16.u << 16)
 
+/* rB <- prs.rA + sigma(IMM16) */
+static void rdprs(DisasContext *dc, uint32_t code, uint32_t flags)
+{
+    if (!dc->eic_present) {
+        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
+        return;
+    }
+    if (!gen_check_supervisor(dc)) {
+        return;
+    }
+
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    I_TYPE(instr, code);
+    TCGv dest = dest_gpr(dc, instr.b);
+    gen_helper_rdprs(dest, cpu_env, tcg_constant_i32(instr.a));
+    tcg_gen_addi_tl(dest, dest, instr.imm16.s);
+#endif
+}
+
 /* Prototype only, defined below */
 static void handle_r_type_instr(DisasContext *dc, uint32_t code,
                                 uint32_t flags);
@@ -366,7 +388,7 @@ static const Nios2Instruction i_type_instructions[] = {
     INSTRUCTION_FLG(gen_stx, MO_SL),                  /* stwio */
     INSTRUCTION_FLG(gen_bxx, TCG_COND_LTU),           /* bltu */
     INSTRUCTION_FLG(gen_ldx, MO_UL),                  /* ldwio */
-    INSTRUCTION_UNIMPLEMENTED(),                      /* rdprs */
+    INSTRUCTION(rdprs),                               /* rdprs */
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION_FLG(handle_r_type_instr, 0),          /* R-Type */
     INSTRUCTION_NOP(),                                /* flushd */
@@ -552,6 +574,26 @@ static void wrctl(DisasContext *dc, uint32_t code, uint32_t flags)
 #endif
 }
 
+/* prs.rC <- rA */
+static void wrprs(DisasContext *dc, uint32_t code, uint32_t flags)
+{
+    if (!dc->eic_present) {
+        t_gen_helper_raise_exception(dc, EXCP_ILLEGAL);
+        return;
+    }
+    if (!gen_check_supervisor(dc)) {
+        return;
+    }
+
+#ifdef CONFIG_USER_ONLY
+    g_assert_not_reached();
+#else
+    R_TYPE(instr, code);
+    gen_helper_wrprs(cpu_env, tcg_constant_i32(instr.c),
+                     load_gpr(dc, instr.a));
+#endif
+}
+
 /* Comparison instructions */
 static void gen_cmpxx(DisasContext *dc, uint32_t code, uint32_t flags)
 {
@@ -690,7 +732,7 @@ static const Nios2Instruction r_type_instructions[] = {
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION(slli),                                /* slli */
     INSTRUCTION(sll),                                 /* sll */
-    INSTRUCTION_UNIMPLEMENTED(),                      /* wrprs */
+    INSTRUCTION(wrprs),                               /* wrprs */
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION(or),                                  /* or */
     INSTRUCTION(mulxsu),                              /* mulxsu */
@@ -791,6 +833,7 @@ static void nios2_tr_init_disas_context(DisasContextBase *dcbase, CPUState *cs)
 
     dc->mem_idx = cpu_mmu_index(env, false);
     dc->cr_state = cpu->cr_state;
+    dc->eic_present = cpu->eic_present;
     dc->crs0 = FIELD_EX32(dc->base.tb->flags, TBFLAGS, CRS0);
 
     /* Bound the number of insns to execute to those left on the page.  */
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 26/33] target/nios2: Update helper_eret for shadow registers
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (24 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 25/33] target/nios2: Implement rdprs, wrprs Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08  7:19 ` [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting Richard Henderson
                   ` (6 subsequent siblings)
  32 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

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 --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));
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (25 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 26/33] target/nios2: Update helper_eret for shadow registers Richard Henderson
@ 2022-03-08  7:19 ` Richard Henderson
  2022-03-08 11:24   ` Peter Maydell
  2022-03-08  7:20 ` [PATCH v4 28/33] target/nios2: Clean up nios2_cpu_do_interrupt Richard Henderson
                   ` (5 subsequent siblings)
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:19 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Decode 'break 1' during translation, rather than doing
it again during exception processing.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h       |  1 +
 target/nios2/helper.c    | 15 ++++++---------
 target/nios2/translate.c | 17 ++++++++++++++++-
 3 files changed, 23 insertions(+), 10 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index c48daa5640..13e1d49f38 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -162,6 +162,7 @@ FIELD(CR_TLBMISC, EE, 24, 1)
 
 /* Exceptions */
 #define EXCP_BREAK    0x1000
+#define EXCP_SEMIHOST 0x1001
 #define EXCP_RESET    0
 #define EXCP_PRESET   1
 #define EXCP_IRQ      2
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index 007496b957..a338d02f6b 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -146,17 +146,14 @@ void nios2_cpu_do_interrupt(CPUState *cs)
         env->pc = cpu->exception_addr;
         break;
 
+    case EXCP_SEMIHOST:
+        qemu_log_mask(CPU_LOG_INT, "BREAK semihosting at pc=%x\n", env->pc);
+        env->pc += 4;
+        do_nios2_semihosting(env);
+        return;
+
     case EXCP_BREAK:
         qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", env->pc);
-        /* The semihosting instruction is "break 1".  */
-        if (semihosting_enabled() &&
-            cpu_ldl_code(env, env->pc) == 0x003da07a)  {
-            qemu_log_mask(CPU_LOG_INT, "Entering semihosting\n");
-            env->pc += 4;
-            do_nios2_semihosting(env);
-            break;
-        }
-
         if ((env->status & CR_STATUS_EH) == 0) {
             env->bstatus = env->status;
             nios2_crs(env)[R_BA] = env->pc + 4;
diff --git a/target/nios2/translate.c b/target/nios2/translate.c
index 7730735639..f9b84e31d7 100644
--- a/target/nios2/translate.c
+++ b/target/nios2/translate.c
@@ -33,6 +33,7 @@
 #include "exec/translator.h"
 #include "qemu/qemu-print.h"
 #include "exec/gen-icount.h"
+#include "semihosting/semihost.h"
 
 /* is_jmp field values */
 #define DISAS_JUMP    DISAS_TARGET_0 /* only pc was modified dynamically */
@@ -711,6 +712,20 @@ static void trap(DisasContext *dc, uint32_t code, uint32_t flags)
     t_gen_helper_raise_exception(dc, EXCP_TRAP);
 }
 
+static void gen_break(DisasContext *dc, uint32_t code, uint32_t flags)
+{
+#ifndef CONFIG_USER_ONLY
+    /* The semihosting instruction is "break 1".  */
+    R_TYPE(instr, code);
+    if (semihosting_enabled() && instr.imm5 == 1) {
+        t_gen_helper_raise_exception(dc, EXCP_SEMIHOST);
+        return;
+    }
+#endif
+
+    t_gen_helper_raise_exception(dc, EXCP_BREAK);
+}
+
 static const Nios2Instruction r_type_instructions[] = {
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION(eret),                                /* eret */
@@ -764,7 +779,7 @@ static const Nios2Instruction r_type_instructions[] = {
     INSTRUCTION(add),                                 /* add */
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION_ILLEGAL(),
-    INSTRUCTION_FLG(gen_excp, EXCP_BREAK),            /* break */
+    INSTRUCTION(gen_break),                           /* break */
     INSTRUCTION_ILLEGAL(),
     INSTRUCTION(nop),                                 /* nop */
     INSTRUCTION_ILLEGAL(),
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 28/33] target/nios2: Clean up nios2_cpu_do_interrupt
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (26 preceding siblings ...)
  2022-03-08  7:19 ` [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  7:20 ` [PATCH v4 29/33] target/nios2: Implement EIC interrupt processing Richard Henderson
                   ` (4 subsequent siblings)
  32 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Sink the bulk of the interrupt processing to the end
of the file.  All of the internal interrupt and
non-interrupt exception code shares EH processing.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/helper.c | 100 +++++++++++-------------------------------
 1 file changed, 25 insertions(+), 75 deletions(-)

diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index a338d02f6b..ccf2634c9b 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -53,48 +53,25 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
     CPUNios2State *env = &cpu->env;
+    uint32_t exception_addr = cpu->exception_addr;
+    unsigned r_ea = R_EA;
+    unsigned cr_estatus = CR_ESTATUS;
 
     switch (cs->exception_index) {
     case EXCP_IRQ:
-        assert(env->status & CR_STATUS_PIE);
-
         qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->pc);
-
-        env->estatus = env->status;
-        env->status |= CR_STATUS_IH;
-        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-        nios2_crs(env)[R_EA] = env->pc + 4;
-        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_TLBD:
-        if ((env->status & CR_STATUS_EH) == 0) {
+        if (env->status & CR_STATUS_EH) {
+            qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", env->pc);
+            /* Double TLB miss */
+            env->tlbmisc |= CR_TLBMISC_DBL;
+        } else {
             qemu_log_mask(CPU_LOG_INT, "TLB MISS (fast) at pc=%x\n", env->pc);
-
-            /* Fast TLB miss */
-            /* Variation from the spec. Table 3-35 of the cpu reference shows
-             * estatus not being changed for TLB miss but this appears to
-             * be incorrect. */
-            env->estatus = env->status;
-            env->status |= CR_STATUS_EH;
-            env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
             env->tlbmisc &= ~CR_TLBMISC_DBL;
             env->tlbmisc |= CR_TLBMISC_WR;
-
-            nios2_crs(env)[R_EA] = env->pc + 4;
-            env->pc = cpu->fast_tlb_miss_addr;
-        } else {
-            qemu_log_mask(CPU_LOG_INT, "TLB MISS (double) at pc=%x\n", env->pc);
-
-            /* Double TLB miss */
-            env->status |= CR_STATUS_EH;
-            env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-            env->tlbmisc |= CR_TLBMISC_DBL;
-
-            env->pc = cpu->exception_addr;
+            exception_addr = cpu->fast_tlb_miss_addr;
         }
         break;
 
@@ -102,48 +79,18 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     case EXCP_TLBW:
     case EXCP_TLBX:
         qemu_log_mask(CPU_LOG_INT, "TLB PERM at pc=%x\n", env->pc);
-
-        env->estatus = env->status;
-        env->status |= CR_STATUS_EH;
-        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-        if ((env->status & CR_STATUS_EH) == 0) {
-            env->tlbmisc |= CR_TLBMISC_WR;
-        }
-
-        nios2_crs(env)[R_EA] = env->pc + 4;
-        env->pc = cpu->exception_addr;
+        env->tlbmisc |= CR_TLBMISC_WR;
         break;
 
     case EXCP_SUPERA:
     case EXCP_SUPERI:
     case EXCP_SUPERD:
         qemu_log_mask(CPU_LOG_INT, "SUPERVISOR exception at pc=%x\n", env->pc);
-
-        if ((env->status & CR_STATUS_EH) == 0) {
-            env->estatus = env->status;
-            nios2_crs(env)[R_EA] = env->pc + 4;
-        }
-
-        env->status |= CR_STATUS_EH;
-        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_ILLEGAL:
     case EXCP_TRAP:
         qemu_log_mask(CPU_LOG_INT, "TRAP exception at pc=%x\n", env->pc);
-
-        if ((env->status & CR_STATUS_EH) == 0) {
-            env->estatus = env->status;
-            nios2_crs(env)[R_EA] = env->pc + 4;
-        }
-
-        env->status |= CR_STATUS_EH;
-        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-        env->pc = cpu->exception_addr;
         break;
 
     case EXCP_SEMIHOST:
@@ -154,23 +101,26 @@ void nios2_cpu_do_interrupt(CPUState *cs)
 
     case EXCP_BREAK:
         qemu_log_mask(CPU_LOG_INT, "BREAK exception at pc=%x\n", env->pc);
-        if ((env->status & CR_STATUS_EH) == 0) {
-            env->bstatus = env->status;
-            nios2_crs(env)[R_BA] = env->pc + 4;
-        }
-
-        env->status |= CR_STATUS_EH;
-        env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
-
-        env->pc = cpu->exception_addr;
+        r_ea = R_BA;
+        cr_estatus = CR_BSTATUS;
         break;
 
     default:
-        cpu_abort(cs, "unhandled exception type=%d\n",
-                  cs->exception_index);
-        break;
+        cpu_abort(cs, "unhandled exception type=%d\n", cs->exception_index);
     }
 
+    /*
+     * Finish Internal Interrupt or Noninterrupt Exception.
+     */
+
+    if (!(env->status & CR_STATUS_EH)) {
+        env->ctrl[cr_estatus] = env->status;
+        env->crs[r_ea] = env->pc + 4;
+        env->status |= CR_STATUS_EH;
+    }
+    env->status &= ~(CR_STATUS_PIE | CR_STATUS_U);
+
+    env->pc = exception_addr;
     env->exception = FIELD_DP32(env->exception, CR_EXCEPTION, CAUSE,
                                 cs->exception_index);
 }
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 29/33] target/nios2: Implement EIC interrupt processing
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (27 preceding siblings ...)
  2022-03-08  7:20 ` [PATCH v4 28/33] target/nios2: Clean up nios2_cpu_do_interrupt Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  7:20 ` [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC) Richard Henderson
                   ` (3 subsequent siblings)
  32 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

This is the cpu side of the operation.  Register one irq line,
called EIC.  Split out the rather different processing to a
separate function.

Delay initialization of gpio irqs until realize.  We need to
provide a window after init in which the board can set eic_present.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/nios2/cpu.h    |  8 +++++
 target/nios2/cpu.c    | 75 +++++++++++++++++++++++++++++++++----------
 target/nios2/helper.c | 37 +++++++++++++++++++++
 3 files changed, 103 insertions(+), 17 deletions(-)

diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
index 13e1d49f38..89c575c26d 100644
--- a/target/nios2/cpu.h
+++ b/target/nios2/cpu.h
@@ -115,6 +115,7 @@ FIELD(CR_STATUS, CRS, 10, 6)
 FIELD(CR_STATUS, PRS, 16, 6)
 FIELD(CR_STATUS, NMI, 22, 1)
 FIELD(CR_STATUS, RSIE, 23, 1)
+FIELD(CR_STATUS, SRS, 31, 1)
 
 #define CR_STATUS_PIE  (1u << R_CR_STATUS_PIE_SHIFT)
 #define CR_STATUS_U    (1u << R_CR_STATUS_U_SHIFT)
@@ -122,6 +123,7 @@ FIELD(CR_STATUS, RSIE, 23, 1)
 #define CR_STATUS_IH   (1u << R_CR_STATUS_IH_SHIFT)
 #define CR_STATUS_NMI  (1u << R_CR_STATUS_NMI_SHIFT)
 #define CR_STATUS_RSIE (1u << R_CR_STATUS_RSIE_SHIFT)
+#define CR_STATUS_SRS  (1u << R_CR_STATUS_SRS_SHIFT)
 
 FIELD(CR_EXCEPTION, CAUSE, 2, 5)
 FIELD(CR_EXCEPTION, ECCFTL, 31, 1)
@@ -252,6 +254,12 @@ struct Nios2CPU {
 
     /* Bits within each control register which are reserved or readonly. */
     ControlRegState cr_state[NUM_CR_REGS];
+
+    /* External Interrupt Controller Interface */
+    uint32_t rha; /* Requested handler address */
+    uint32_t ril; /* Requested interrupt level */
+    uint32_t rrs; /* Requested register set */
+    bool rnmi;    /* Requested nonmaskable interrupt */
 };
 
 
diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
index 6ece92a2b8..65a900a7fb 100644
--- a/target/nios2/cpu.c
+++ b/target/nios2/cpu.c
@@ -67,7 +67,19 @@ static void nios2_cpu_reset(DeviceState *dev)
 }
 
 #ifndef CONFIG_USER_ONLY
-static void nios2_cpu_set_irq(void *opaque, int irq, int level)
+static void eic_set_irq(void *opaque, int irq, int level)
+{
+    Nios2CPU *cpu = opaque;
+    CPUState *cs = CPU(cpu);
+
+    if (level) {
+        cpu_interrupt(cs, CPU_INTERRUPT_HARD);
+    } else {
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_HARD);
+    }
+}
+
+static void iic_set_irq(void *opaque, int irq, int level)
 {
     Nios2CPU *cpu = opaque;
     CPUNios2State *env = &cpu->env;
@@ -149,15 +161,6 @@ static void nios2_cpu_initfn(Object *obj)
 
 #if !defined(CONFIG_USER_ONLY)
     mmu_init(&cpu->env);
-
-    /*
-     * These interrupt lines model the IIC (internal interrupt
-     * controller). QEMU does not currently support the EIC
-     * (external interrupt controller) -- if we did it would be
-     * a separate device in hw/intc with a custom interface to
-     * the CPU, and boards using it would not wire up these IRQ lines.
-     */
-    qdev_init_gpio_in_named(DEVICE(cpu), nios2_cpu_set_irq, "IRQ", 32);
 #endif
 }
 
@@ -173,6 +176,14 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
     Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev);
     Error *local_err = NULL;
 
+#ifndef CONFIG_USER_ONLY
+    if (cpu->eic_present) {
+        qdev_init_gpio_in_named(DEVICE(cpu), eic_set_irq, "EIC", 1);
+    } else {
+        qdev_init_gpio_in_named(DEVICE(cpu), iic_set_irq, "IRQ", 32);
+    }
+#endif
+
     cpu_exec_realizefn(cs, &local_err);
     if (local_err != NULL) {
         error_propagate(errp, local_err);
@@ -189,17 +200,47 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
 }
 
 #ifndef CONFIG_USER_ONLY
+static bool eic_take_interrupt(Nios2CPU *cpu)
+{
+    CPUNios2State *env = &cpu->env;
+
+    if (cpu->rnmi) {
+        return !(env->status & CR_STATUS_NMI);
+    }
+    if (!(env->status & CR_STATUS_PIE)) {
+        return false;
+    }
+    if (cpu->ril <= FIELD_EX32(env->status, CR_STATUS, IL)) {
+        return false;
+    }
+    if (cpu->rrs != FIELD_EX32(env->status, CR_STATUS, CRS)) {
+        return true;
+    }
+    return env->status & CR_STATUS_RSIE;
+}
+
+static bool iic_take_interrupt(Nios2CPU *cpu)
+{
+    CPUNios2State *env = &cpu->env;
+
+    if (!(env->status & CR_STATUS_PIE)) {
+        return false;
+    }
+    return env->ipending & env->ienable;
+}
+
 static bool nios2_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
-    CPUNios2State *env = &cpu->env;
 
-    if ((interrupt_request & CPU_INTERRUPT_HARD) &&
-        (env->status & CR_STATUS_PIE) &&
-        (env->ipending & env->ienable)) {
-        cs->exception_index = EXCP_IRQ;
-        nios2_cpu_do_interrupt(cs);
-        return true;
+    if (interrupt_request & CPU_INTERRUPT_HARD) {
+        if (cpu->eic_present
+            ? eic_take_interrupt(cpu)
+            : iic_take_interrupt(cpu)) {
+            cs->exception_index = EXCP_IRQ;
+            nios2_cpu_do_interrupt(cs);
+            return true;
+        }
     }
     return false;
 }
diff --git a/target/nios2/helper.c b/target/nios2/helper.c
index ccf2634c9b..11840496f7 100644
--- a/target/nios2/helper.c
+++ b/target/nios2/helper.c
@@ -49,6 +49,36 @@ void nios2_cpu_record_sigsegv(CPUState *cs, vaddr addr,
 
 #else /* !CONFIG_USER_ONLY */
 
+static void eic_do_interrupt(Nios2CPU *cpu)
+{
+    CPUNios2State *env = &cpu->env;
+    uint32_t old_status = env->status;
+    uint32_t old_rs = FIELD_EX32(old_status, CR_STATUS, CRS);
+    uint32_t new_rs = cpu->rrs;
+
+    env->status = FIELD_DP32(env->status, CR_STATUS, CRS, new_rs);
+    env->status = FIELD_DP32(env->status, CR_STATUS, IL, cpu->ril);
+    env->status = FIELD_DP32(env->status, CR_STATUS, NMI, cpu->rnmi);
+    env->status &= ~(CR_STATUS_RSIE | CR_STATUS_U);
+    env->status |= CR_STATUS_IH;
+    nios2_update_crs(env);
+
+    if (!(env->status & CR_STATUS_EH)) {
+        env->status = FIELD_DP32(env->status, CR_STATUS, PRS, old_rs);
+        if (new_rs == 0) {
+            env->estatus = old_status;
+        } else {
+            if (new_rs != old_rs) {
+                old_status |= CR_STATUS_SRS;
+            }
+            env->crs[R_SSTATUS] = old_status;
+        }
+        env->crs[R_EA] = env->pc + 4;
+    }
+
+    env->pc = cpu->rha;
+}
+
 void nios2_cpu_do_interrupt(CPUState *cs)
 {
     Nios2CPU *cpu = NIOS2_CPU(cs);
@@ -60,6 +90,10 @@ void nios2_cpu_do_interrupt(CPUState *cs)
     switch (cs->exception_index) {
     case EXCP_IRQ:
         qemu_log_mask(CPU_LOG_INT, "interrupt at pc=%x\n", env->pc);
+        if (cpu->eic_present) {
+            eic_do_interrupt(cpu);
+            return;
+        }
         break;
 
     case EXCP_TLBD:
@@ -113,6 +147,9 @@ void nios2_cpu_do_interrupt(CPUState *cs)
      * Finish Internal Interrupt or Noninterrupt Exception.
      */
 
+    env->status &= ~R_CR_STATUS_CRS_MASK;
+    nios2_update_crs(env);
+
     if (!(env->status & CR_STATUS_EH)) {
         env->ctrl[cr_estatus] = env->status;
         env->crs[r_ea] = env->pc + 4;
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC)
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (28 preceding siblings ...)
  2022-03-08  7:20 ` [PATCH v4 29/33] target/nios2: Implement EIC interrupt processing Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  8:32   ` Mark Cave-Ayland
  2022-03-08 11:27   ` Peter Maydell
  2022-03-08  7:20 ` [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState Richard Henderson
                   ` (2 subsequent siblings)
  32 siblings, 2 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

From: Amir Gonnen <amir.gonnen@neuroblade.ai>

Implement nios2 Vectored Interrupt Controller (VIC).
VIC is connected to EIC. It needs to update rha, ril, rrs and rnmi
fields on Nios2CPU before raising an IRQ.
For that purpose, VIC has a "cpu" property which should refer to the
nios2 cpu and set by the board that connects VIC.

Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
Message-Id: <20220303153906.2024748-5-amir.gonnen@neuroblade.ai>
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/intc/nios2_vic.c | 341 ++++++++++++++++++++++++++++++++++++++++++++
 hw/intc/Kconfig     |   3 +
 hw/intc/meson.build |   1 +
 3 files changed, 345 insertions(+)
 create mode 100644 hw/intc/nios2_vic.c

diff --git a/hw/intc/nios2_vic.c b/hw/intc/nios2_vic.c
new file mode 100644
index 0000000000..b59d3f6f4c
--- /dev/null
+++ b/hw/intc/nios2_vic.c
@@ -0,0 +1,341 @@
+/*
+ * Vectored Interrupt Controller for nios2 processor
+ *
+ * Copyright (c) 2022 Neuroblade
+ *
+ * Interface:
+ * QOM property "cpu": link to the Nios2 CPU (must be set)
+ * Unnamed GPIO inputs 0..NIOS2_VIC_MAX_IRQ-1: input IRQ lines
+ * IRQ should be connected to nios2 IRQ0.
+ *
+ * Reference: "Embedded Peripherals IP User Guide
+ *             for Intel® Quartus® Prime Design Suite: 21.4"
+ * Chapter 38 "Vectored Interrupt Controller Core"
+ * See: https://www.intel.com/content/www/us/en/docs/programmable/683130/21-4/vectored-interrupt-controller-core.html
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include "qemu/osdep.h"
+
+#include "hw/irq.h"
+#include "hw/qdev-properties.h"
+#include "hw/sysbus.h"
+#include "migration/vmstate.h"
+#include "qapi/error.h"
+#include "qemu/bitops.h"
+#include "qemu/log.h"
+#include "qom/object.h"
+#include "cpu.h"
+
+#define TYPE_NIOS2_VIC "nios2-vic"
+
+OBJECT_DECLARE_SIMPLE_TYPE(Nios2Vic, NIOS2_VIC)
+
+#define NIOS2_VIC_MAX_IRQ 32
+
+enum {
+    INT_CONFIG0 = 0,
+    INT_CONFIG31 = 31,
+    INT_ENABLE = 32,
+    INT_ENABLE_SET = 33,
+    INT_ENABLE_CLR = 34,
+    INT_PENDING = 35,
+    INT_RAW_STATUS = 36,
+    SW_INTERRUPT = 37,
+    SW_INTERRUPT_SET = 38,
+    SW_INTERRUPT_CLR = 39,
+    VIC_CONFIG = 40,
+    VIC_STATUS = 41,
+    VEC_TBL_BASE = 42,
+    VEC_TBL_ADDR = 43,
+    CSR_COUNT /* Last! */
+};
+
+struct Nios2Vic {
+    /*< private >*/
+    SysBusDevice parent_obj;
+
+    /*< public >*/
+    qemu_irq output_int;
+
+    /* properties */
+    CPUState *cpu;
+    MemoryRegion csr;
+
+    uint32_t int_config[32];
+    uint32_t vic_config;
+    uint32_t int_raw_status;
+    uint32_t int_enable;
+    uint32_t sw_int;
+    uint32_t vic_status;
+    uint32_t vec_tbl_base;
+    uint32_t vec_tbl_addr;
+};
+
+/* Requested interrupt level (INT_CONFIG[0:5]) */
+static inline uint32_t vic_int_config_ril(const Nios2Vic *vic, int irq_num)
+{
+    return extract32(vic->int_config[irq_num], 0, 6);
+}
+
+/* Requested NMI (INT_CONFIG[6]) */
+static inline uint32_t vic_int_config_rnmi(const Nios2Vic *vic, int irq_num)
+{
+    return extract32(vic->int_config[irq_num], 6, 1);
+}
+
+/* Requested register set (INT_CONFIG[7:12]) */
+static inline uint32_t vic_int_config_rrs(const Nios2Vic *vic, int irq_num)
+{
+    return extract32(vic->int_config[irq_num], 7, 6);
+}
+
+static inline uint32_t vic_config_vec_size(const Nios2Vic *vic)
+{
+    return 1 << (2 + extract32(vic->vic_config, 0, 3));
+}
+
+static inline uint32_t vic_int_pending(const Nios2Vic *vic)
+{
+    return (vic->int_raw_status | vic->sw_int) & vic->int_enable;
+}
+
+static void vic_update_irq(Nios2Vic *vic)
+{
+    Nios2CPU *cpu = NIOS2_CPU(vic->cpu);
+    uint32_t pending = vic_int_pending(vic);
+    int irq = -1;
+    int max_ril = 0;
+    /* Note that if RIL is 0 for an interrupt it is effectively disabled */
+
+    vic->vec_tbl_addr = 0;
+    vic->vic_status = 0;
+
+    if (pending == 0) {
+        qemu_irq_lower(vic->output_int);
+        return;
+    }
+
+    for (int i = 0; i < NIOS2_VIC_MAX_IRQ; i++) {
+        if (pending & BIT(i)) {
+            int ril = vic_int_config_ril(vic, i);
+            if (ril > max_ril) {
+                irq = i;
+                max_ril = ril;
+            }
+        }
+    }
+
+    if (irq < 0) {
+        qemu_irq_lower(vic->output_int);
+        return;
+    }
+
+    vic->vec_tbl_addr = irq * vic_config_vec_size(vic) + vic->vec_tbl_base;
+    vic->vic_status = irq | BIT(31);
+
+    /*
+     * In hardware, the interface between the VIC and the CPU is via the
+     * External Interrupt Controller interface, where the interrupt controller
+     * presents the CPU with a packet of data containing:
+     *  - Requested Handler Address (RHA): 32 bits
+     *  - Requested Register Set (RRS) : 6 bits
+     *  - Requested Interrupt Level (RIL) : 6 bits
+     *  - Requested NMI flag (RNMI) : 1 bit
+     * In our emulation, we implement this by writing the data directly to
+     * fields in the CPU object and then raising the IRQ line to tell
+     * the CPU that we've done so.
+     */
+
+    cpu->rha = vic->vec_tbl_addr;
+    cpu->ril = max_ril;
+    cpu->rrs = vic_int_config_rrs(vic, irq);
+    cpu->rnmi = vic_int_config_rnmi(vic, irq);
+
+    qemu_irq_raise(vic->output_int);
+}
+
+static void vic_set_irq(void *opaque, int irq_num, int level)
+{
+    Nios2Vic *vic = opaque;
+
+    if (level) {
+        vic->int_raw_status |= BIT(irq_num);
+    } else {
+        vic->int_raw_status &= ~BIT(irq_num);
+    }
+
+    vic_update_irq(vic);
+}
+
+static void nios2_vic_reset(DeviceState *dev)
+{
+    Nios2Vic *vic = NIOS2_VIC(dev);
+    memset(&vic->int_config, 0, sizeof(vic->int_config));
+    vic->vic_config = 0;
+    vic->int_raw_status = 0;
+    vic->int_enable = 0;
+    vic->sw_int = 0;
+    vic->vic_status = 0;
+    vic->vec_tbl_base = 0;
+    vic->vec_tbl_addr = 0;
+}
+
+static uint64_t nios2_vic_csr_read(void *opaque, hwaddr offset, unsigned size)
+{
+    Nios2Vic *vic = opaque;
+    int index = offset / 4;
+
+    switch (index) {
+    case INT_CONFIG0 ... INT_CONFIG31:
+        return vic->int_config[index - INT_CONFIG0];
+    case INT_ENABLE:
+        return vic->int_enable;
+    case INT_PENDING:
+        return vic_int_pending(vic);
+    case INT_RAW_STATUS:
+        return vic->int_raw_status;
+    case SW_INTERRUPT:
+        return vic->sw_int;
+    case VIC_CONFIG:
+        return vic->vic_config;
+    case VIC_STATUS:
+        return vic->vic_status;
+    case VEC_TBL_BASE:
+        return vic->vec_tbl_base;
+    case VEC_TBL_ADDR:
+        return vic->vec_tbl_addr;
+    default:
+        return 0;
+    }
+}
+
+static void nios2_vic_csr_write(void *opaque, hwaddr offset, uint64_t value,
+                                unsigned size)
+{
+    Nios2Vic *vic = opaque;
+    int index = offset / 4;
+
+    switch (index) {
+    case INT_CONFIG0 ... INT_CONFIG31:
+        vic->int_config[index - INT_CONFIG0] = value;
+        break;
+    case INT_ENABLE:
+        vic->int_enable = value;
+        break;
+    case INT_ENABLE_SET:
+        vic->int_enable |= value;
+        break;
+    case INT_ENABLE_CLR:
+        vic->int_enable &= ~value;
+        break;
+    case SW_INTERRUPT:
+        vic->sw_int = value;
+        break;
+    case SW_INTERRUPT_SET:
+        vic->sw_int |= value;
+        break;
+    case SW_INTERRUPT_CLR:
+        vic->sw_int &= ~value;
+        break;
+    case VIC_CONFIG:
+        vic->vic_config = value;
+        break;
+    case VEC_TBL_BASE:
+        vic->vec_tbl_base = value;
+        break;
+    default:
+        qemu_log_mask(LOG_GUEST_ERROR,
+            "nios2-vic: write to invalid CSR address 0x%x\n", (int)offset);
+    }
+
+    vic_update_irq(vic);
+}
+
+static const MemoryRegionOps nios2_vic_csr_ops = {
+    .read = nios2_vic_csr_read,
+    .write = nios2_vic_csr_write,
+    .endianness = DEVICE_LITTLE_ENDIAN,
+    .valid = { .min_access_size = 4, .max_access_size = 4 }
+};
+
+static void nios2_vic_realize(DeviceState *dev, Error **errp)
+{
+    Nios2Vic *vic = NIOS2_VIC(dev);
+
+    if (!vic->cpu) {
+        /* This is a programming error in the code using this device */
+        error_setg(errp, "nios2-vic 'cpu' link property was not set");
+        return;
+    }
+
+    sysbus_init_irq(SYS_BUS_DEVICE(dev), &vic->output_int);
+    qdev_init_gpio_in(dev, vic_set_irq, NIOS2_VIC_MAX_IRQ);
+
+    memory_region_init_io(&vic->csr, OBJECT(dev), &nios2_vic_csr_ops, vic,
+                          "nios2.vic.csr", CSR_COUNT * sizeof(uint32_t));
+    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &vic->csr);
+}
+
+static Property nios2_vic_properties[] = {
+    DEFINE_PROP_LINK("cpu", Nios2Vic, cpu, TYPE_CPU, CPUState *),
+    DEFINE_PROP_END_OF_LIST()
+};
+
+static const VMStateDescription nios2_vic_vmstate = {
+    .name = "nios2-vic",
+    .version_id = 1,
+    .minimum_version_id = 1,
+    .fields = (VMStateField[]){
+        VMSTATE_UINT32_ARRAY(int_config, Nios2Vic, 32),
+        VMSTATE_UINT32(vic_config, Nios2Vic),
+        VMSTATE_UINT32(int_raw_status, Nios2Vic),
+        VMSTATE_UINT32(int_enable, Nios2Vic),
+        VMSTATE_UINT32(sw_int, Nios2Vic),
+        VMSTATE_UINT32(vic_status, Nios2Vic),
+        VMSTATE_UINT32(vec_tbl_base, Nios2Vic),
+        VMSTATE_UINT32(vec_tbl_addr, Nios2Vic),
+        VMSTATE_END_OF_LIST()
+    },
+};
+
+static void nios2_vic_class_init(ObjectClass *klass, void *data)
+{
+    DeviceClass *dc = DEVICE_CLASS(klass);
+
+    dc->reset = nios2_vic_reset;
+    dc->realize = nios2_vic_realize;
+    dc->vmsd = &nios2_vic_vmstate;
+    device_class_set_props(dc, nios2_vic_properties);
+}
+
+static const TypeInfo nios2_vic_info = {
+    .name = TYPE_NIOS2_VIC,
+    .parent = TYPE_SYS_BUS_DEVICE,
+    .instance_size = sizeof(Nios2Vic),
+    .class_init = nios2_vic_class_init,
+};
+
+static void nios2_vic_register_types(void)
+{
+    type_register_static(&nios2_vic_info);
+}
+
+type_init(nios2_vic_register_types);
diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
index ec8d4cec29..eeb2d6f428 100644
--- a/hw/intc/Kconfig
+++ b/hw/intc/Kconfig
@@ -84,3 +84,6 @@ config GOLDFISH_PIC
 
 config M68K_IRQC
     bool
+
+config NIOS2_VIC
+    bool
diff --git a/hw/intc/meson.build b/hw/intc/meson.build
index 81ccdb0d78..167755ac64 100644
--- a/hw/intc/meson.build
+++ b/hw/intc/meson.build
@@ -62,3 +62,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
 		if_true: files('spapr_xive_kvm.c'))
 specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
 specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
+specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (29 preceding siblings ...)
  2022-03-08  7:20 ` [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC) Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  8:39   ` Mark Cave-Ayland
  2022-03-08  7:20 ` [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine Richard Henderson
  2022-03-08  7:20 ` [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller Richard Henderson
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

We want to move data from the heap into Nios2MachineState,
which is not possible with DEFINE_MACHINE.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/nios2/10m50_devboard.c | 28 +++++++++++++++++++++++++---
 1 file changed, 25 insertions(+), 3 deletions(-)

diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
index 3d1205b8bd..f245e0baa8 100644
--- a/hw/nios2/10m50_devboard.c
+++ b/hw/nios2/10m50_devboard.c
@@ -36,10 +36,18 @@
 
 #include "boot.h"
 
+struct Nios2MachineState {
+    MachineState parent_obj;
+};
+
+#define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
+OBJECT_DECLARE_TYPE(Nios2MachineState, MachineClass, NIOS2_MACHINE)
+
 #define BINARY_DEVICE_TREE_FILE    "10m50-devboard.dtb"
 
 static void nios2_10m50_ghrd_init(MachineState *machine)
 {
+    Nios2MachineState *nms = NIOS2_MACHINE(machine);
     Nios2CPU *cpu;
     DeviceState *dev;
     MemoryRegion *address_space_mem = get_system_memory();
@@ -101,15 +109,29 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
     cpu->exception_addr = 0xc8000120;
     cpu->fast_tlb_miss_addr = 0xc0000100;
 
-    nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename,
+    nios2_load_kernel(cpu, ram_base, ram_size, nms->parent_obj.initrd_filename,
                       BINARY_DEVICE_TREE_FILE, NULL);
 }
 
-static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc)
+static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
 {
+    MachineClass *mc = MACHINE_CLASS(oc);
+
     mc->desc = "Altera 10M50 GHRD Nios II design";
     mc->init = nios2_10m50_ghrd_init;
     mc->is_default = true;
 }
 
-DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init);
+static const TypeInfo nios2_10m50_ghrd_type_info = {
+    .name          = TYPE_NIOS2_MACHINE,
+    .parent        = TYPE_MACHINE,
+    .instance_size = sizeof(Nios2MachineState),
+    .class_size    = sizeof(MachineClass),
+    .class_init    = nios2_10m50_ghrd_class_init,
+};
+
+static void nios2_10m50_ghrd_type_init(void)
+{
+    type_register_static(&nios2_10m50_ghrd_type_info);
+}
+type_init(nios2_10m50_ghrd_type_init);
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (30 preceding siblings ...)
  2022-03-08  7:20 ` [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  8:39   ` Mark Cave-Ayland
  2022-03-08  7:20 ` [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller Richard Henderson
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

Convert to contiguous allocation, as much as possible so far.
The two timer objects are not exposed for subobject allocation.

Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/nios2/10m50_devboard.c | 29 +++++++++++++++--------------
 1 file changed, 15 insertions(+), 14 deletions(-)

diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
index f245e0baa8..f4931b8a67 100644
--- a/hw/nios2/10m50_devboard.c
+++ b/hw/nios2/10m50_devboard.c
@@ -38,6 +38,11 @@
 
 struct Nios2MachineState {
     MachineState parent_obj;
+
+    MemoryRegion phys_tcm;
+    MemoryRegion phys_tcm_alias;
+    MemoryRegion phys_ram;
+    MemoryRegion phys_ram_alias;
 };
 
 #define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
@@ -51,10 +56,6 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
     Nios2CPU *cpu;
     DeviceState *dev;
     MemoryRegion *address_space_mem = get_system_memory();
-    MemoryRegion *phys_tcm = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
-    MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1);
     ram_addr_t tcm_base = 0x0;
     ram_addr_t tcm_size = 0x1000;    /* 1 kiB, but QEMU limit is 4 kiB */
     ram_addr_t ram_base = 0x08000000;
@@ -63,22 +64,22 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
     int i;
 
     /* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */
-    memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size,
+    memory_region_init_ram(&nms->phys_tcm, NULL, "nios2.tcm", tcm_size,
                            &error_abort);
-    memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias",
-                             phys_tcm, 0, tcm_size);
-    memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm);
+    memory_region_init_alias(&nms->phys_tcm_alias, NULL, "nios2.tcm.alias",
+                             &nms->phys_tcm, 0, tcm_size);
+    memory_region_add_subregion(address_space_mem, tcm_base, &nms->phys_tcm);
     memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base,
-                                phys_tcm_alias);
+                                &nms->phys_tcm_alias);
 
     /* Physical DRAM with alias at 0xc0000000 */
-    memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size,
+    memory_region_init_ram(&nms->phys_ram, NULL, "nios2.ram", ram_size,
                            &error_abort);
-    memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias",
-                             phys_ram, 0, ram_size);
-    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
+    memory_region_init_alias(&nms->phys_ram_alias, NULL, "nios2.ram.alias",
+                             &nms->phys_ram, 0, ram_size);
+    memory_region_add_subregion(address_space_mem, ram_base, &nms->phys_ram);
     memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
-                                phys_ram_alias);
+                                &nms->phys_ram_alias);
 
     /* Create CPU -- FIXME */
     cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU));
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller
  2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
                   ` (31 preceding siblings ...)
  2022-03-08  7:20 ` [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine Richard Henderson
@ 2022-03-08  7:20 ` Richard Henderson
  2022-03-08  8:43   ` Mark Cave-Ayland
  32 siblings, 1 reply; 77+ messages in thread
From: Richard Henderson @ 2022-03-08  7:20 UTC (permalink / raw)
  To: qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

From: Amir Gonnen <amir.gonnen@neuroblade.ai>

Demonstrate how to use nios2 VIC on a machine.
Introduce a new machine property to attach a VIC.

When VIC is present, let the CPU know that it should use the
External Interrupt Interface instead of the Internal Interrupt Interface.
The devices on the machine are attached to the VIC and not directly to cpu.
To allow VIC update EIC fields, we set the "cpu" property of the VIC
with a reference to the nios2 cpu.

Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
Message-Id: <20220303153906.2024748-6-amir.gonnen@neuroblade.ai>
[rth: Put a property on the 10m50-ghrd machine, rather than
      create a new machine class.]
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 hw/nios2/10m50_devboard.c | 61 +++++++++++++++++++++++++++++++++------
 hw/nios2/Kconfig          |  1 +
 2 files changed, 53 insertions(+), 9 deletions(-)

diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
index f4931b8a67..bdbc6539c9 100644
--- a/hw/nios2/10m50_devboard.c
+++ b/hw/nios2/10m50_devboard.c
@@ -43,6 +43,8 @@ struct Nios2MachineState {
     MemoryRegion phys_tcm_alias;
     MemoryRegion phys_ram;
     MemoryRegion phys_ram_alias;
+
+    bool vic;
 };
 
 #define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
@@ -81,10 +83,40 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
     memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
                                 &nms->phys_ram_alias);
 
-    /* Create CPU -- FIXME */
-    cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU));
-    for (i = 0; i < 32; i++) {
-        irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i);
+    /* Create CPU.  We need to set eic_present between init and realize. */
+    cpu = NIOS2_CPU(object_new(TYPE_NIOS2_CPU));
+
+    /* Enable the External Interrupt Controller within the CPU. */
+    cpu->eic_present = nms->vic;
+
+    /* Configure new exception vectors. */
+    cpu->reset_addr = 0xd4000000;
+    cpu->exception_addr = 0xc8000120;
+    cpu->fast_tlb_miss_addr = 0xc0000100;
+
+    qdev_realize(DEVICE(cpu), NULL, &error_fatal);
+    object_unref(CPU(cpu));
+
+    if (nms->vic) {
+        DeviceState *dev = qdev_new("nios2-vic");
+        MemoryRegion *dev_mr;
+        qemu_irq cpu_irq;
+
+        object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_fatal);
+        sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
+
+        cpu_irq = qdev_get_gpio_in_named(DEVICE(cpu), "EIC", 0);
+        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq);
+        for (int i = 0; i < 32; i++) {
+            irq[i] = qdev_get_gpio_in(dev, i);
+        }
+
+        dev_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
+        memory_region_add_subregion(address_space_mem, 0x18002000, dev_mr);
+    } else {
+        for (i = 0; i < 32; i++) {
+            irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i);
+        }
     }
 
     /* Register: Altera 16550 UART */
@@ -105,15 +137,22 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
     sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880);
     sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]);
 
-    /* Configure new exception vectors and reset CPU for it to take effect. */
-    cpu->reset_addr = 0xd4000000;
-    cpu->exception_addr = 0xc8000120;
-    cpu->fast_tlb_miss_addr = 0xc0000100;
-
     nios2_load_kernel(cpu, ram_base, ram_size, nms->parent_obj.initrd_filename,
                       BINARY_DEVICE_TREE_FILE, NULL);
 }
 
+static bool get_vic(Object *obj, Error **errp)
+{
+    Nios2MachineState *nms = NIOS2_MACHINE(obj);
+    return nms->vic;
+}
+
+static void set_vic(Object *obj, bool value, Error **errp)
+{
+    Nios2MachineState *nms = NIOS2_MACHINE(obj);
+    nms->vic = value;
+}
+
 static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
 {
     MachineClass *mc = MACHINE_CLASS(oc);
@@ -121,6 +160,10 @@ static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
     mc->desc = "Altera 10M50 GHRD Nios II design";
     mc->init = nios2_10m50_ghrd_init;
     mc->is_default = true;
+
+    object_class_property_add_bool(oc, "vic", get_vic, set_vic);
+    object_class_property_set_description(oc, "vic",
+        "Set on/off to enable/disable the Vectored Interrupt Controller");
 }
 
 static const TypeInfo nios2_10m50_ghrd_type_info = {
diff --git a/hw/nios2/Kconfig b/hw/nios2/Kconfig
index b10ea640da..4748ae27b6 100644
--- a/hw/nios2/Kconfig
+++ b/hw/nios2/Kconfig
@@ -3,6 +3,7 @@ config NIOS2_10M50
     select NIOS2
     select SERIAL
     select ALTERA_TIMER
+    select NIOS2_VIC
 
 config NIOS2_GENERIC_NOMMU
     bool
-- 
2.25.1



^ permalink raw reply related	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC)
  2022-03-08  7:20 ` [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC) Richard Henderson
@ 2022-03-08  8:32   ` Mark Cave-Ayland
  2022-03-08 11:27   ` Peter Maydell
  1 sibling, 0 replies; 77+ messages in thread
From: Mark Cave-Ayland @ 2022-03-08  8:32 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 08/03/2022 07:20, Richard Henderson wrote:

> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
> 
> Implement nios2 Vectored Interrupt Controller (VIC).
> VIC is connected to EIC. It needs to update rha, ril, rrs and rnmi
> fields on Nios2CPU before raising an IRQ.
> For that purpose, VIC has a "cpu" property which should refer to the
> nios2 cpu and set by the board that connects VIC.
> 
> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
> Message-Id: <20220303153906.2024748-5-amir.gonnen@neuroblade.ai>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/intc/nios2_vic.c | 341 ++++++++++++++++++++++++++++++++++++++++++++
>   hw/intc/Kconfig     |   3 +
>   hw/intc/meson.build |   1 +
>   3 files changed, 345 insertions(+)
>   create mode 100644 hw/intc/nios2_vic.c
> 
> diff --git a/hw/intc/nios2_vic.c b/hw/intc/nios2_vic.c
> new file mode 100644
> index 0000000000..b59d3f6f4c
> --- /dev/null
> +++ b/hw/intc/nios2_vic.c
> @@ -0,0 +1,341 @@
> +/*
> + * Vectored Interrupt Controller for nios2 processor
> + *
> + * Copyright (c) 2022 Neuroblade
> + *
> + * Interface:
> + * QOM property "cpu": link to the Nios2 CPU (must be set)
> + * Unnamed GPIO inputs 0..NIOS2_VIC_MAX_IRQ-1: input IRQ lines
> + * IRQ should be connected to nios2 IRQ0.
> + *
> + * Reference: "Embedded Peripherals IP User Guide
> + *             for Intel® Quartus® Prime Design Suite: 21.4"
> + * Chapter 38 "Vectored Interrupt Controller Core"
> + * See: https://www.intel.com/content/www/us/en/docs/programmable/683130/21-4/vectored-interrupt-controller-core.html
> + *
> + * Permission is hereby granted, free of charge, to any person obtaining a copy
> + * of this software and associated documentation files (the "Software"), to deal
> + * in the Software without restriction, including without limitation the rights
> + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
> + * copies of the Software, and to permit persons to whom the Software is
> + * furnished to do so, subject to the following conditions:
> + *
> + * The above copyright notice and this permission notice shall be included in
> + * all copies or substantial portions of the Software.
> + *
> + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
> + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
> + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
> + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
> + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
> + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
> + * THE SOFTWARE.
> + */
> +
> +#include "qemu/osdep.h"
> +
> +#include "hw/irq.h"
> +#include "hw/qdev-properties.h"
> +#include "hw/sysbus.h"
> +#include "migration/vmstate.h"
> +#include "qapi/error.h"
> +#include "qemu/bitops.h"
> +#include "qemu/log.h"
> +#include "qom/object.h"
> +#include "cpu.h"
> +
> +#define TYPE_NIOS2_VIC "nios2-vic"
> +
> +OBJECT_DECLARE_SIMPLE_TYPE(Nios2Vic, NIOS2_VIC)
> +
> +#define NIOS2_VIC_MAX_IRQ 32
> +
> +enum {
> +    INT_CONFIG0 = 0,
> +    INT_CONFIG31 = 31,
> +    INT_ENABLE = 32,
> +    INT_ENABLE_SET = 33,
> +    INT_ENABLE_CLR = 34,
> +    INT_PENDING = 35,
> +    INT_RAW_STATUS = 36,
> +    SW_INTERRUPT = 37,
> +    SW_INTERRUPT_SET = 38,
> +    SW_INTERRUPT_CLR = 39,
> +    VIC_CONFIG = 40,
> +    VIC_STATUS = 41,
> +    VEC_TBL_BASE = 42,
> +    VEC_TBL_ADDR = 43,
> +    CSR_COUNT /* Last! */
> +};
> +
> +struct Nios2Vic {
> +    /*< private >*/
> +    SysBusDevice parent_obj;
> +
> +    /*< public >*/
> +    qemu_irq output_int;
> +
> +    /* properties */
> +    CPUState *cpu;
> +    MemoryRegion csr;
> +
> +    uint32_t int_config[32];

Is this NIOS2_VIC_MAX_IRQ?

> +    uint32_t vic_config;
> +    uint32_t int_raw_status;
> +    uint32_t int_enable;
> +    uint32_t sw_int;
> +    uint32_t vic_status;
> +    uint32_t vec_tbl_base;
> +    uint32_t vec_tbl_addr;
> +};

I think it's worth splitting the type section above into a separate 
include/hw/intc/nios2_vic.h header for completeness, plus it will allow you to use 
TYPE_NIOS2_VIC later in patch 33.

> +/* Requested interrupt level (INT_CONFIG[0:5]) */
> +static inline uint32_t vic_int_config_ril(const Nios2Vic *vic, int irq_num)
> +{
> +    return extract32(vic->int_config[irq_num], 0, 6);
> +}
> +
> +/* Requested NMI (INT_CONFIG[6]) */
> +static inline uint32_t vic_int_config_rnmi(const Nios2Vic *vic, int irq_num)
> +{
> +    return extract32(vic->int_config[irq_num], 6, 1);
> +}
> +
> +/* Requested register set (INT_CONFIG[7:12]) */
> +static inline uint32_t vic_int_config_rrs(const Nios2Vic *vic, int irq_num)
> +{
> +    return extract32(vic->int_config[irq_num], 7, 6);
> +}
> +
> +static inline uint32_t vic_config_vec_size(const Nios2Vic *vic)
> +{
> +    return 1 << (2 + extract32(vic->vic_config, 0, 3));
> +}
> +
> +static inline uint32_t vic_int_pending(const Nios2Vic *vic)
> +{
> +    return (vic->int_raw_status | vic->sw_int) & vic->int_enable;
> +}
> +
> +static void vic_update_irq(Nios2Vic *vic)
> +{
> +    Nios2CPU *cpu = NIOS2_CPU(vic->cpu);
> +    uint32_t pending = vic_int_pending(vic);
> +    int irq = -1;
> +    int max_ril = 0;
> +    /* Note that if RIL is 0 for an interrupt it is effectively disabled */
> +
> +    vic->vec_tbl_addr = 0;
> +    vic->vic_status = 0;
> +
> +    if (pending == 0) {
> +        qemu_irq_lower(vic->output_int);
> +        return;
> +    }
> +
> +    for (int i = 0; i < NIOS2_VIC_MAX_IRQ; i++) {
> +        if (pending & BIT(i)) {
> +            int ril = vic_int_config_ril(vic, i);
> +            if (ril > max_ril) {
> +                irq = i;
> +                max_ril = ril;
> +            }
> +        }
> +    }
> +
> +    if (irq < 0) {
> +        qemu_irq_lower(vic->output_int);
> +        return;
> +    }
> +
> +    vic->vec_tbl_addr = irq * vic_config_vec_size(vic) + vic->vec_tbl_base;
> +    vic->vic_status = irq | BIT(31);
> +
> +    /*
> +     * In hardware, the interface between the VIC and the CPU is via the
> +     * External Interrupt Controller interface, where the interrupt controller
> +     * presents the CPU with a packet of data containing:
> +     *  - Requested Handler Address (RHA): 32 bits
> +     *  - Requested Register Set (RRS) : 6 bits
> +     *  - Requested Interrupt Level (RIL) : 6 bits
> +     *  - Requested NMI flag (RNMI) : 1 bit
> +     * In our emulation, we implement this by writing the data directly to
> +     * fields in the CPU object and then raising the IRQ line to tell
> +     * the CPU that we've done so.
> +     */
> +
> +    cpu->rha = vic->vec_tbl_addr;
> +    cpu->ril = max_ril;
> +    cpu->rrs = vic_int_config_rrs(vic, irq);
> +    cpu->rnmi = vic_int_config_rnmi(vic, irq);
> +
> +    qemu_irq_raise(vic->output_int);
> +}
> +
> +static void vic_set_irq(void *opaque, int irq_num, int level)
> +{
> +    Nios2Vic *vic = opaque;
> +
> +    if (level) {
> +        vic->int_raw_status |= BIT(irq_num);
> +    } else {
> +        vic->int_raw_status &= ~BIT(irq_num);
> +    }
> +
> +    vic_update_irq(vic);
> +}
> +
> +static void nios2_vic_reset(DeviceState *dev)
> +{
> +    Nios2Vic *vic = NIOS2_VIC(dev);
> +    memset(&vic->int_config, 0, sizeof(vic->int_config));
> +    vic->vic_config = 0;
> +    vic->int_raw_status = 0;
> +    vic->int_enable = 0;
> +    vic->sw_int = 0;
> +    vic->vic_status = 0;
> +    vic->vec_tbl_base = 0;
> +    vic->vec_tbl_addr = 0;
> +}
> +
> +static uint64_t nios2_vic_csr_read(void *opaque, hwaddr offset, unsigned size)
> +{
> +    Nios2Vic *vic = opaque;
> +    int index = offset / 4;
> +
> +    switch (index) {
> +    case INT_CONFIG0 ... INT_CONFIG31:
> +        return vic->int_config[index - INT_CONFIG0];
> +    case INT_ENABLE:
> +        return vic->int_enable;
> +    case INT_PENDING:
> +        return vic_int_pending(vic);
> +    case INT_RAW_STATUS:
> +        return vic->int_raw_status;
> +    case SW_INTERRUPT:
> +        return vic->sw_int;
> +    case VIC_CONFIG:
> +        return vic->vic_config;
> +    case VIC_STATUS:
> +        return vic->vic_status;
> +    case VEC_TBL_BASE:
> +        return vic->vec_tbl_base;
> +    case VEC_TBL_ADDR:
> +        return vic->vec_tbl_addr;
> +    default:
> +        return 0;
> +    }
> +}
> +
> +static void nios2_vic_csr_write(void *opaque, hwaddr offset, uint64_t value,
> +                                unsigned size)
> +{
> +    Nios2Vic *vic = opaque;
> +    int index = offset / 4;
> +
> +    switch (index) {
> +    case INT_CONFIG0 ... INT_CONFIG31:
> +        vic->int_config[index - INT_CONFIG0] = value;
> +        break;
> +    case INT_ENABLE:
> +        vic->int_enable = value;
> +        break;
> +    case INT_ENABLE_SET:
> +        vic->int_enable |= value;
> +        break;
> +    case INT_ENABLE_CLR:
> +        vic->int_enable &= ~value;
> +        break;
> +    case SW_INTERRUPT:
> +        vic->sw_int = value;
> +        break;
> +    case SW_INTERRUPT_SET:
> +        vic->sw_int |= value;
> +        break;
> +    case SW_INTERRUPT_CLR:
> +        vic->sw_int &= ~value;
> +        break;
> +    case VIC_CONFIG:
> +        vic->vic_config = value;
> +        break;
> +    case VEC_TBL_BASE:
> +        vic->vec_tbl_base = value;
> +        break;
> +    default:
> +        qemu_log_mask(LOG_GUEST_ERROR,
> +            "nios2-vic: write to invalid CSR address 0x%x\n", (int)offset);
> +    }
> +
> +    vic_update_irq(vic);
> +}
> +
> +static const MemoryRegionOps nios2_vic_csr_ops = {
> +    .read = nios2_vic_csr_read,
> +    .write = nios2_vic_csr_write,
> +    .endianness = DEVICE_LITTLE_ENDIAN,
> +    .valid = { .min_access_size = 4, .max_access_size = 4 }
> +};
> +
> +static void nios2_vic_realize(DeviceState *dev, Error **errp)
> +{
> +    Nios2Vic *vic = NIOS2_VIC(dev);
> +
> +    if (!vic->cpu) {
> +        /* This is a programming error in the code using this device */
> +        error_setg(errp, "nios2-vic 'cpu' link property was not set");
> +        return;
> +    }
> +
> +    sysbus_init_irq(SYS_BUS_DEVICE(dev), &vic->output_int);
> +    qdev_init_gpio_in(dev, vic_set_irq, NIOS2_VIC_MAX_IRQ);
> +
> +    memory_region_init_io(&vic->csr, OBJECT(dev), &nios2_vic_csr_ops, vic,
> +                          "nios2.vic.csr", CSR_COUNT * sizeof(uint32_t));
> +    sysbus_init_mmio(SYS_BUS_DEVICE(dev), &vic->csr);
> +}
> +
> +static Property nios2_vic_properties[] = {
> +    DEFINE_PROP_LINK("cpu", Nios2Vic, cpu, TYPE_CPU, CPUState *),
> +    DEFINE_PROP_END_OF_LIST()
> +};
> +
> +static const VMStateDescription nios2_vic_vmstate = {
> +    .name = "nios2-vic",
> +    .version_id = 1,
> +    .minimum_version_id = 1,
> +    .fields = (VMStateField[]){
> +        VMSTATE_UINT32_ARRAY(int_config, Nios2Vic, 32),

And also NIOS2_VIC_MAX_IRQ here?

> +        VMSTATE_UINT32(vic_config, Nios2Vic),
> +        VMSTATE_UINT32(int_raw_status, Nios2Vic),
> +        VMSTATE_UINT32(int_enable, Nios2Vic),
> +        VMSTATE_UINT32(sw_int, Nios2Vic),
> +        VMSTATE_UINT32(vic_status, Nios2Vic),
> +        VMSTATE_UINT32(vec_tbl_base, Nios2Vic),
> +        VMSTATE_UINT32(vec_tbl_addr, Nios2Vic),
> +        VMSTATE_END_OF_LIST()
> +    },
> +};
> +
> +static void nios2_vic_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +
> +    dc->reset = nios2_vic_reset;
> +    dc->realize = nios2_vic_realize;
> +    dc->vmsd = &nios2_vic_vmstate;
> +    device_class_set_props(dc, nios2_vic_properties);
> +}
> +
> +static const TypeInfo nios2_vic_info = {
> +    .name = TYPE_NIOS2_VIC,
> +    .parent = TYPE_SYS_BUS_DEVICE,
> +    .instance_size = sizeof(Nios2Vic),
> +    .class_init = nios2_vic_class_init,
> +};
> +
> +static void nios2_vic_register_types(void)
> +{
> +    type_register_static(&nios2_vic_info);
> +}
> +
> +type_init(nios2_vic_register_types);
> diff --git a/hw/intc/Kconfig b/hw/intc/Kconfig
> index ec8d4cec29..eeb2d6f428 100644
> --- a/hw/intc/Kconfig
> +++ b/hw/intc/Kconfig
> @@ -84,3 +84,6 @@ config GOLDFISH_PIC
>   
>   config M68K_IRQC
>       bool
> +
> +config NIOS2_VIC
> +    bool
> diff --git a/hw/intc/meson.build b/hw/intc/meson.build
> index 81ccdb0d78..167755ac64 100644
> --- a/hw/intc/meson.build
> +++ b/hw/intc/meson.build
> @@ -62,3 +62,4 @@ specific_ss.add(when: ['CONFIG_KVM', 'CONFIG_XIVE'],
>   		if_true: files('spapr_xive_kvm.c'))
>   specific_ss.add(when: 'CONFIG_GOLDFISH_PIC', if_true: files('goldfish_pic.c'))
>   specific_ss.add(when: 'CONFIG_M68K_IRQC', if_true: files('m68k_irqc.c'))
> +specific_ss.add(when: 'CONFIG_NIOS2_VIC', if_true: files('nios2_vic.c'))

Otherwise seems okay to me.


ATB,

Mark.


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState
  2022-03-08  7:20 ` [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState Richard Henderson
@ 2022-03-08  8:39   ` Mark Cave-Ayland
  2022-03-08 19:55     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Mark Cave-Ayland @ 2022-03-08  8:39 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 08/03/2022 07:20, Richard Henderson wrote:

> We want to move data from the heap into Nios2MachineState,
> which is not possible with DEFINE_MACHINE.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/nios2/10m50_devboard.c | 28 +++++++++++++++++++++++++---
>   1 file changed, 25 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
> index 3d1205b8bd..f245e0baa8 100644
> --- a/hw/nios2/10m50_devboard.c
> +++ b/hw/nios2/10m50_devboard.c
> @@ -36,10 +36,18 @@
>   
>   #include "boot.h"
>   
> +struct Nios2MachineState {
> +    MachineState parent_obj;
> +};
> +
> +#define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
> +OBJECT_DECLARE_TYPE(Nios2MachineState, MachineClass, NIOS2_MACHINE)
> +
>   #define BINARY_DEVICE_TREE_FILE    "10m50-devboard.dtb"
>   
>   static void nios2_10m50_ghrd_init(MachineState *machine)
>   {
> +    Nios2MachineState *nms = NIOS2_MACHINE(machine);
>       Nios2CPU *cpu;
>       DeviceState *dev;
>       MemoryRegion *address_space_mem = get_system_memory();
> @@ -101,15 +109,29 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>       cpu->exception_addr = 0xc8000120;
>       cpu->fast_tlb_miss_addr = 0xc0000100;
>   
> -    nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename,
> +    nios2_load_kernel(cpu, ram_base, ram_size, nms->parent_obj.initrd_filename,
>                         BINARY_DEVICE_TREE_FILE, NULL);

I think you should be able to keep this as machine->initrd_filename? Certainly there 
should be no direct access to parent_obj here, and if you did need it a QOM cast 
macro would be the way to do this.

>   }
>   
> -static void nios2_10m50_ghrd_machine_init(struct MachineClass *mc)
> +static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
>   {
> +    MachineClass *mc = MACHINE_CLASS(oc);
> +
>       mc->desc = "Altera 10M50 GHRD Nios II design";
>       mc->init = nios2_10m50_ghrd_init;
>       mc->is_default = true;
>   }
>   
> -DEFINE_MACHINE("10m50-ghrd", nios2_10m50_ghrd_machine_init);
> +static const TypeInfo nios2_10m50_ghrd_type_info = {
> +    .name          = TYPE_NIOS2_MACHINE,
> +    .parent        = TYPE_MACHINE,
> +    .instance_size = sizeof(Nios2MachineState),
> +    .class_size    = sizeof(MachineClass),

Technically you can drop .class_size here since this should be inherited 
automatically from MachineClass.

> +    .class_init    = nios2_10m50_ghrd_class_init,
> +};
> +
> +static void nios2_10m50_ghrd_type_init(void)
> +{
> +    type_register_static(&nios2_10m50_ghrd_type_info);
> +}
> +type_init(nios2_10m50_ghrd_type_init);


ATB,

Mark.


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine
  2022-03-08  7:20 ` [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine Richard Henderson
@ 2022-03-08  8:39   ` Mark Cave-Ayland
  0 siblings, 0 replies; 77+ messages in thread
From: Mark Cave-Ayland @ 2022-03-08  8:39 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 08/03/2022 07:20, Richard Henderson wrote:

> Convert to contiguous allocation, as much as possible so far.
> The two timer objects are not exposed for subobject allocation.
> 
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/nios2/10m50_devboard.c | 29 +++++++++++++++--------------
>   1 file changed, 15 insertions(+), 14 deletions(-)
> 
> diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
> index f245e0baa8..f4931b8a67 100644
> --- a/hw/nios2/10m50_devboard.c
> +++ b/hw/nios2/10m50_devboard.c
> @@ -38,6 +38,11 @@
>   
>   struct Nios2MachineState {
>       MachineState parent_obj;
> +
> +    MemoryRegion phys_tcm;
> +    MemoryRegion phys_tcm_alias;
> +    MemoryRegion phys_ram;
> +    MemoryRegion phys_ram_alias;
>   };
>   
>   #define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
> @@ -51,10 +56,6 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>       Nios2CPU *cpu;
>       DeviceState *dev;
>       MemoryRegion *address_space_mem = get_system_memory();
> -    MemoryRegion *phys_tcm = g_new(MemoryRegion, 1);
> -    MemoryRegion *phys_tcm_alias = g_new(MemoryRegion, 1);
> -    MemoryRegion *phys_ram = g_new(MemoryRegion, 1);
> -    MemoryRegion *phys_ram_alias = g_new(MemoryRegion, 1);
>       ram_addr_t tcm_base = 0x0;
>       ram_addr_t tcm_size = 0x1000;    /* 1 kiB, but QEMU limit is 4 kiB */
>       ram_addr_t ram_base = 0x08000000;
> @@ -63,22 +64,22 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>       int i;
>   
>       /* Physical TCM (tb_ram_1k) with alias at 0xc0000000 */
> -    memory_region_init_ram(phys_tcm, NULL, "nios2.tcm", tcm_size,
> +    memory_region_init_ram(&nms->phys_tcm, NULL, "nios2.tcm", tcm_size,
>                              &error_abort);
> -    memory_region_init_alias(phys_tcm_alias, NULL, "nios2.tcm.alias",
> -                             phys_tcm, 0, tcm_size);
> -    memory_region_add_subregion(address_space_mem, tcm_base, phys_tcm);
> +    memory_region_init_alias(&nms->phys_tcm_alias, NULL, "nios2.tcm.alias",
> +                             &nms->phys_tcm, 0, tcm_size);
> +    memory_region_add_subregion(address_space_mem, tcm_base, &nms->phys_tcm);
>       memory_region_add_subregion(address_space_mem, 0xc0000000 + tcm_base,
> -                                phys_tcm_alias);
> +                                &nms->phys_tcm_alias);
>   
>       /* Physical DRAM with alias at 0xc0000000 */
> -    memory_region_init_ram(phys_ram, NULL, "nios2.ram", ram_size,
> +    memory_region_init_ram(&nms->phys_ram, NULL, "nios2.ram", ram_size,
>                              &error_abort);
> -    memory_region_init_alias(phys_ram_alias, NULL, "nios2.ram.alias",
> -                             phys_ram, 0, ram_size);
> -    memory_region_add_subregion(address_space_mem, ram_base, phys_ram);
> +    memory_region_init_alias(&nms->phys_ram_alias, NULL, "nios2.ram.alias",
> +                             &nms->phys_ram, 0, ram_size);
> +    memory_region_add_subregion(address_space_mem, ram_base, &nms->phys_ram);
>       memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
> -                                phys_ram_alias);
> +                                &nms->phys_ram_alias);
>   
>       /* Create CPU -- FIXME */
>       cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU));

Reviewed-by: Mark Cave-Ayland <mark.cave-ayland@ilande.co.uk>


ATB,

Mark.


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller
  2022-03-08  7:20 ` [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller Richard Henderson
@ 2022-03-08  8:43   ` Mark Cave-Ayland
  2022-03-08 19:57     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Mark Cave-Ayland @ 2022-03-08  8:43 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 08/03/2022 07:20, Richard Henderson wrote:

> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
> 
> Demonstrate how to use nios2 VIC on a machine.
> Introduce a new machine property to attach a VIC.
> 
> When VIC is present, let the CPU know that it should use the
> External Interrupt Interface instead of the Internal Interrupt Interface.
> The devices on the machine are attached to the VIC and not directly to cpu.
> To allow VIC update EIC fields, we set the "cpu" property of the VIC
> with a reference to the nios2 cpu.
> 
> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
> Message-Id: <20220303153906.2024748-6-amir.gonnen@neuroblade.ai>
> [rth: Put a property on the 10m50-ghrd machine, rather than
>        create a new machine class.]
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>   hw/nios2/10m50_devboard.c | 61 +++++++++++++++++++++++++++++++++------
>   hw/nios2/Kconfig          |  1 +
>   2 files changed, 53 insertions(+), 9 deletions(-)
> 
> diff --git a/hw/nios2/10m50_devboard.c b/hw/nios2/10m50_devboard.c
> index f4931b8a67..bdbc6539c9 100644
> --- a/hw/nios2/10m50_devboard.c
> +++ b/hw/nios2/10m50_devboard.c
> @@ -43,6 +43,8 @@ struct Nios2MachineState {
>       MemoryRegion phys_tcm_alias;
>       MemoryRegion phys_ram;
>       MemoryRegion phys_ram_alias;
> +
> +    bool vic;
>   };
>   
>   #define TYPE_NIOS2_MACHINE  MACHINE_TYPE_NAME("10m50-ghrd")
> @@ -81,10 +83,40 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>       memory_region_add_subregion(address_space_mem, 0xc0000000 + ram_base,
>                                   &nms->phys_ram_alias);
>   
> -    /* Create CPU -- FIXME */
> -    cpu = NIOS2_CPU(cpu_create(TYPE_NIOS2_CPU));
> -    for (i = 0; i < 32; i++) {
> -        irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i);
> +    /* Create CPU.  We need to set eic_present between init and realize. */
> +    cpu = NIOS2_CPU(object_new(TYPE_NIOS2_CPU));
> +
> +    /* Enable the External Interrupt Controller within the CPU. */
> +    cpu->eic_present = nms->vic;
> +
> +    /* Configure new exception vectors. */
> +    cpu->reset_addr = 0xd4000000;
> +    cpu->exception_addr = 0xc8000120;
> +    cpu->fast_tlb_miss_addr = 0xc0000100;
> +
> +    qdev_realize(DEVICE(cpu), NULL, &error_fatal);
> +    object_unref(CPU(cpu));

I believe this can be replaced with qdev_realize_and_unref()?

> +    if (nms->vic) {
> +        DeviceState *dev = qdev_new("nios2-vic");

And with a separate header for nios2_vic.h you can include that and use 
TYPE_NIOS2_VIC here instead of hard-coding the type name.

> +        MemoryRegion *dev_mr;
> +        qemu_irq cpu_irq;
> +
> +        object_property_set_link(OBJECT(dev), "cpu", OBJECT(cpu), &error_fatal);
> +        sysbus_realize_and_unref(SYS_BUS_DEVICE(dev), &error_fatal);
> +
> +        cpu_irq = qdev_get_gpio_in_named(DEVICE(cpu), "EIC", 0);
> +        sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, cpu_irq);
> +        for (int i = 0; i < 32; i++) {
> +            irq[i] = qdev_get_gpio_in(dev, i);
> +        }
> +
> +        dev_mr = sysbus_mmio_get_region(SYS_BUS_DEVICE(dev), 0);
> +        memory_region_add_subregion(address_space_mem, 0x18002000, dev_mr);
> +    } else {
> +        for (i = 0; i < 32; i++) {
> +            irq[i] = qdev_get_gpio_in_named(DEVICE(cpu), "IRQ", i);
> +        }
>       }
>   
>       /* Register: Altera 16550 UART */
> @@ -105,15 +137,22 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>       sysbus_mmio_map(SYS_BUS_DEVICE(dev), 0, 0xe0000880);
>       sysbus_connect_irq(SYS_BUS_DEVICE(dev), 0, irq[5]);
>   
> -    /* Configure new exception vectors and reset CPU for it to take effect. */
> -    cpu->reset_addr = 0xd4000000;
> -    cpu->exception_addr = 0xc8000120;
> -    cpu->fast_tlb_miss_addr = 0xc0000100;
> -
>       nios2_load_kernel(cpu, ram_base, ram_size, nms->parent_obj.initrd_filename,
>                         BINARY_DEVICE_TREE_FILE, NULL);
>   }
>   
> +static bool get_vic(Object *obj, Error **errp)
> +{
> +    Nios2MachineState *nms = NIOS2_MACHINE(obj);
> +    return nms->vic;
> +}
> +
> +static void set_vic(Object *obj, bool value, Error **errp)
> +{
> +    Nios2MachineState *nms = NIOS2_MACHINE(obj);
> +    nms->vic = value;
> +}
> +
>   static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
>   {
>       MachineClass *mc = MACHINE_CLASS(oc);
> @@ -121,6 +160,10 @@ static void nios2_10m50_ghrd_class_init(ObjectClass *oc, void *data)
>       mc->desc = "Altera 10M50 GHRD Nios II design";
>       mc->init = nios2_10m50_ghrd_init;
>       mc->is_default = true;
> +
> +    object_class_property_add_bool(oc, "vic", get_vic, set_vic);
> +    object_class_property_set_description(oc, "vic",
> +        "Set on/off to enable/disable the Vectored Interrupt Controller");
>   }
>   
>   static const TypeInfo nios2_10m50_ghrd_type_info = {
> diff --git a/hw/nios2/Kconfig b/hw/nios2/Kconfig
> index b10ea640da..4748ae27b6 100644
> --- a/hw/nios2/Kconfig
> +++ b/hw/nios2/Kconfig
> @@ -3,6 +3,7 @@ config NIOS2_10M50
>       select NIOS2
>       select SERIAL
>       select ALTERA_TIMER
> +    select NIOS2_VIC
>   
>   config NIOS2_GENERIC_NOMMU
>       bool


ATB,

Mark.


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails
  2022-03-08  7:19 ` [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails Richard Henderson
@ 2022-03-08  9:48   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08  9:48 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Whether the cpu is in user-mode or not is something that we
> know at translation-time.  We do not need to generate code
> after having raised an exception.
>
> Suggested-by: Peter Maydell <peter.maydell@linaro.org>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/translate.c | 20 +++++++++++++++-----

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS
  2022-03-08  7:19 ` [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS Richard Henderson
@ 2022-03-08  9:49   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08  9:49 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
>
> Split NUM_CORE_REGS into components that can be used elsewhere.
>
> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
> Message-Id: <20220303153906.2024748-3-amir.gonnen@neuroblade.ai>
> [rth: Split out of a larger patch for shadow register sets.]
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 04/33] target/nios2: Split PC out of env->regs[]
  2022-03-08  7:19 ` [PATCH v4 04/33] target/nios2: Split PC out of env->regs[] Richard Henderson
@ 2022-03-08  9:51   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08  9:51 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> It is cleaner to have a separate name for this variable.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h          | 10 +++-----
>  linux-user/elfload.c        |  2 +-
>  linux-user/nios2/cpu_loop.c | 17 ++++++-------
>  linux-user/nios2/signal.c   |  6 ++---
>  target/nios2/cpu.c          |  8 +++---
>  target/nios2/helper.c       | 51 +++++++++++++++++--------------------
>  target/nios2/translate.c    | 26 ++++++++++---------
>  7 files changed, 57 insertions(+), 63 deletions(-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 05/33] target/nios2: Split out helper for eret instruction
  2022-03-08  7:19 ` [PATCH v4 05/33] target/nios2: Split out helper for eret instruction Richard Henderson
@ 2022-03-08  9:52   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08  9:52 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
>
> The implementation of eret will become much more complex
> with the introduction of shadow registers.
>
> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
> Message-Id: <20220303153906.2024748-3-amir.gonnen@neuroblade.ai>
> [rth: Split out of a larger patch for shadow register sets.
>       Directly exit to the cpu loop from the helper.]
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers
  2022-03-08  7:19 ` [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers Richard Henderson
@ 2022-03-08  9:54   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08  9:54 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> We don't need to reference them often, and when we do it
> is just as easy to load/store from cpu_env directly.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/translate.c | 21 ++++++++++++++++-----
>  1 file changed, 16 insertions(+), 5 deletions(-)
>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc
  2022-03-08  7:19 ` [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc Richard Henderson
@ 2022-03-08 10:00   ` Peter Maydell
  2022-03-08 19:34     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> The only thing this struct is used for is passing startup values
> from elfload.c to the cpu.  We do not need all registers to be
> represented, we do not need the kernel internal stack slots.
>
> The userland argc, argv, and envp values are passed on
> the stack, so only SP and PC need updating.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  linux-user/nios2/target_syscall.h | 25 ++-----------------------
>  linux-user/elfload.c              |  3 +--
>  linux-user/nios2/cpu_loop.c       | 24 +-----------------------
>  3 files changed, 4 insertions(+), 48 deletions(-)

Well, I guess we're not using it for anything else currently,
but if you do this then it's not the target arch's pt_regs
struct any more. And all our other target archs seem to define
the struct to follow the kernel definition even if we don't
happen to use it all.

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled
  2022-03-08  7:19 ` [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled Richard Henderson
@ 2022-03-08 10:00   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> This function is unused.  The real computation of this value
> is located in nios2_cpu_exec_interrupt.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 5 -----
>  1 file changed, 5 deletions(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index 727d31c427..14ed46959e 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -227,11 +227,6 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>                          bool probe, uintptr_t retaddr);
>  #endif
>
> -static inline int cpu_interrupts_enabled(CPUNios2State *env)
> -{
> -    return env->regs[CR_STATUS] & CR_STATUS_PIE;
> -}
> -
>  typedef CPUNios2State CPUArchState;
>  typedef Nios2CPU ArchCPU;

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 09/33] target/nios2: Split control registers away from general registers
  2022-03-08  7:19 ` [PATCH v4 09/33] target/nios2: Split control registers away from general registers Richard Henderson
@ 2022-03-08 10:04   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:04 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Place the control registers into their own array, env->ctrl[].
>
> Use an anonymous union and struct to give the entries in the
> array distinct names, so that one may write env->foo instead
> of env->ctrl[CR_FOO].
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Not 100% sold on the union, but
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state
  2022-03-08  7:19 ` [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state Richard Henderson
@ 2022-03-08 10:06   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:06 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Do not print control registers for user-only mode.
> Rename reserved control registers to "resN", where
> N is the control register index.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields
  2022-03-08  7:19 ` [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields Richard Henderson
@ 2022-03-08 10:08   ` Peter Maydell
  2022-03-08 19:34     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:08 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Add all fields; retain the helper macros for single bit fields.
> So far there are no uses of the multi-bit status fields.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 27 ++++++++++++++++++---------
>  1 file changed, 18 insertions(+), 9 deletions(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index 5bc0e353b4..26618baa70 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -23,6 +23,7 @@
>
>  #include "exec/cpu-defs.h"
>  #include "hw/core/cpu.h"
> +#include "hw/registerfields.h"
>  #include "qom/object.h"
>
>  typedef struct CPUNios2State CPUNios2State;
> @@ -80,15 +81,23 @@ struct Nios2CPUClass {
>
>  /* Control register aliases */
>  #define CR_STATUS        0
> -#define   CR_STATUS_PIE  (1 << 0)
> -#define   CR_STATUS_U    (1 << 1)
> -#define   CR_STATUS_EH   (1 << 2)
> -#define   CR_STATUS_IH   (1 << 3)
> -#define   CR_STATUS_IL   (63 << 4)
> -#define   CR_STATUS_CRS  (63 << 10)
> -#define   CR_STATUS_PRS  (63 << 16)
> -#define   CR_STATUS_NMI  (1 << 22)
> -#define   CR_STATUS_RSIE (1 << 23)
> +
> +FIELD(CR_STATUS, PIE, 0, 1)
> +FIELD(CR_STATUS, U, 1, 1)
> +FIELD(CR_STATUS, EH, 2, 1)
> +FIELD(CR_STATUS, IH, 3, 1)
> +FIELD(CR_STATUS, IL, 4, 6)
> +FIELD(CR_STATUS, CRS, 10, 6)
> +FIELD(CR_STATUS, PRS, 16, 6)
> +FIELD(CR_STATUS, NMI, 22, 1)
> +
> +#define CR_STATUS_PIE  (1u << R_CR_STATUS_PIE_SHIFT)
> +#define CR_STATUS_U    (1u << R_CR_STATUS_U_SHIFT)
> +#define CR_STATUS_EH   (1u << R_CR_STATUS_EH_SHIFT)
> +#define CR_STATUS_IH   (1u << R_CR_STATUS_IH_SHIFT)
> +#define CR_STATUS_NMI  (1u << R_CR_STATUS_NMI_SHIFT)
> +#define CR_STATUS_RSIE (1u << R_CR_STATUS_RSIE_SHIFT)

Since these are all 1 bit fields you can use
#define CR_STATUS_PIE R_CR_STATUS_PIE_MASK
etc rather than manually shifting by the shift count.

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields
  2022-03-08  7:19 ` [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields Richard Henderson
@ 2022-03-08 10:12   ` Peter Maydell
  2022-03-08 19:36     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:12 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Sink the set of env->exception to the end of nios2_cpu_do_interrupt.

This splits the two things the patch is doing between the subject line
and the commit message body; the subject is supposed to be a summary
and the body should be able to stand alone without the subject.

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

>      }
> +
> +    env->exception = FIELD_DP32(env->exception, CR_EXCEPTION, CAUSE,
> +                                cs->exception_index);
>  }

This is a behaviour change in the semihosting case, which
previously did not change env->exception and now does.
Since that's guest visible I think it's not correct.
You could fix that by making the semihosting handling end
with 'return' rather than 'break'.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields
  2022-03-08  7:19 ` [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields Richard Henderson
@ 2022-03-08 10:14   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:14 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields
  2022-03-08  7:19 ` [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields Richard Henderson
@ 2022-03-08 10:19   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:19 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>

Empty body.

You might also mention:

"Since we're rewriting the references to CR_TLBACC_IGN_* anyway,
we correct the name of this field to IG, which is its name in the
official CPU documentation."

> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 23 +++++++++++++++--------
>  target/nios2/mmu.c | 16 ++++++++--------
>  2 files changed, 23 insertions(+), 16 deletions(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index 84138000fa..024ef3ccc0 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -115,14 +115,21 @@ FIELD(CR_PTEADDR, VPN, 2, 20)
>  FIELD(CR_PTEADDR, PTBASE, 22, 10)
>
>  #define CR_TLBACC        9
> -#define   CR_TLBACC_IGN_SHIFT 25
> -#define   CR_TLBACC_IGN_MASK  (0x7F << CR_TLBACC_IGN_SHIFT)
> -#define   CR_TLBACC_C         (1 << 24)
> -#define   CR_TLBACC_R         (1 << 23)
> -#define   CR_TLBACC_W         (1 << 22)
> -#define   CR_TLBACC_X         (1 << 21)
> -#define   CR_TLBACC_G         (1 << 20)
> -#define   CR_TLBACC_PFN_MASK  0x000FFFFF
> +
> +FIELD(CR_TLBACC, PFN, 0, 20)
> +FIELD(CR_TLBACC, G, 20, 1)
> +FIELD(CR_TLBACC, X, 21, 1)
> +FIELD(CR_TLBACC, W, 22, 1)
> +FIELD(CR_TLBACC, R, 23, 1)
> +FIELD(CR_TLBACC, C, 24, 1)
> +FIELD(CR_TLBACC, IG, 25, 7)
> +
> +#define CR_TLBACC_C  (1u << R_CR_TLBACC_C_SHIFT)
> +#define CR_TLBACC_R  (1u << R_CR_TLBACC_R_SHIFT)
> +#define CR_TLBACC_W  (1u << R_CR_TLBACC_W_SHIFT)
> +#define CR_TLBACC_X  (1u << R_CR_TLBACC_X_SHIFT)
> +#define CR_TLBACC_G  (1u << R_CR_TLBACC_G_SHIFT)

again,
#define CR_TLBACC_C R_CR_TLBACC_C_MASK
etc

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields
  2022-03-08  7:19 ` [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields Richard Henderson
@ 2022-03-08 10:46   ` Peter Maydell
  2022-03-08 19:37     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:46 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h       | 28 ++++++++++++++++++----------
>  target/nios2/helper.c    |  7 ++-----
>  target/nios2/mmu.c       | 33 +++++++++++++++------------------
>  target/nios2/translate.c |  2 +-
>  4 files changed, 36 insertions(+), 34 deletions(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index 024ef3ccc0..3857848f7c 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -131,16 +131,24 @@ FIELD(CR_TLBACC, IG, 25, 7)
>  #define CR_TLBACC_G  (1u << R_CR_TLBACC_G_SHIFT)
>
>  #define CR_TLBMISC       10
> -#define   CR_TLBMISC_WAY_SHIFT 20
> -#define   CR_TLBMISC_WAY_MASK  (0xF << CR_TLBMISC_WAY_SHIFT)
> -#define   CR_TLBMISC_RD        (1 << 19)
> -#define   CR_TLBMISC_WR        (1 << 18)
> -#define   CR_TLBMISC_PID_SHIFT 4
> -#define   CR_TLBMISC_PID_MASK  (0x3FFF << CR_TLBMISC_PID_SHIFT)
> -#define   CR_TLBMISC_DBL       (1 << 3)
> -#define   CR_TLBMISC_BAD       (1 << 2)
> -#define   CR_TLBMISC_PERM      (1 << 1)
> -#define   CR_TLBMISC_D         (1 << 0)
> +
> +FIELD(CR_TLBMISC, D, 0, 1)
> +FIELD(CR_TLBMISC, PERM, 1, 1)
> +FIELD(CR_TLBMISC, BAD, 2, 1)
> +FIELD(CR_TLBMISC, DBL, 3, 1)
> +FIELD(CR_TLBMISC, PID, 4, 14)
> +FIELD(CR_TLBMISC, WR, 18, 1)
> +FIELD(CR_TLBMISC, RD, 19, 1)
> +FIELD(CR_TLBMISC, WAY, 20, 4)
> +FIELD(CR_TLBMISC, EE, 24, 1)
> +
> +#define CR_TLBMISC_RD    (1u << R_CR_TLBMISC_RD_SHIFT)
> +#define CR_TLBMISC_WR    (1u << R_CR_TLBMISC_WR_SHIFT)
> +#define CR_TLBMISC_DBL   (1u << R_CR_TLBMISC_DBL_SHIFT)
> +#define CR_TLBMISC_BAD   (1u << R_CR_TLBMISC_BAD_SHIFT)
> +#define CR_TLBMISC_PERM  (1u << R_CR_TLBMISC_PERM_SHIFT)
> +#define CR_TLBMISC_D     (1u << R_CR_TLBMISC_D_SHIFT)

Same comment as previous patches.

> +
>  #define CR_ENCINJ        11
>  #define CR_BADADDR       12
>  #define CR_CONFIG        13
> diff --git a/target/nios2/helper.c b/target/nios2/helper.c
> index 37fb53dadb..93338e86f0 100644
> --- a/target/nios2/helper.c
> +++ b/target/nios2/helper.c
> @@ -276,11 +276,8 @@ bool nios2_cpu_tlb_fill(CPUState *cs, vaddr address, int size,
>          return false;
>      }
>
> -    if (access_type == MMU_INST_FETCH) {
> -        env->tlbmisc &= ~CR_TLBMISC_D;
> -    } else {
> -        env->tlbmisc |= CR_TLBMISC_D;
> -    }
> +    env->tlbmisc = FIELD_DP32(env->tlbmisc, CR_TLBMISC, D,
> +                              access_type == MMU_INST_FETCH);

This inverts the sense -- now we set the D bit for MMU_INST_FETCH,
which is wrong.

>      env->pteaddr = FIELD_DP32(env->pteaddr, CR_PTEADDR, VPN,
>                                address >> TARGET_PAGE_BITS);
>      env->mmu.pteaddr_wr = env->pteaddr;

> @@ -130,24 +128,25 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
>  void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
>  {
>      Nios2CPU *cpu = env_archcpu(env);
> +    uint32_t new_pid = FIELD_EX32(v, CR_TLBMISC, PID);
> +    uint32_t old_pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
> +    uint32_t way = FIELD_EX32(v, CR_TLBMISC, WAY);
>
> -    trace_nios2_mmu_write_tlbmisc(v >> CR_TLBMISC_WAY_SHIFT,
> +    trace_nios2_mmu_write_tlbmisc(way,
>                                    (v & CR_TLBMISC_RD) ? 'R' : '.',
>                                    (v & CR_TLBMISC_WR) ? 'W' : '.',
>                                    (v & CR_TLBMISC_DBL) ? '2' : '.',
>                                    (v & CR_TLBMISC_BAD) ? 'B' : '.',
>                                    (v & CR_TLBMISC_PERM) ? 'P' : '.',
>                                    (v & CR_TLBMISC_D) ? 'D' : '.',
> -                                  (v & CR_TLBMISC_PID_MASK) >> 4);
> +                                  new_pid);
>
> -    if ((v & CR_TLBMISC_PID_MASK) !=
> -        (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK)) {
> -        mmu_flush_pid(env, (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >>
> -                           CR_TLBMISC_PID_SHIFT);
> +    if (new_pid != old_pid) {
> +        mmu_flush_pid(env, old_pid);
>      }
> +
>      /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */
>      if (v & CR_TLBMISC_RD) {
> -        int way = (v >> CR_TLBMISC_WAY_SHIFT);
>          int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
>          Nios2TLBEntry *entry =
>              &env->mmu.tlb[(way * cpu->tlb_num_ways) +


Any reason for hoisting the declaration of 'way' up to the top of the
function ?

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations
  2022-03-08  7:19 ` [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations Richard Henderson
@ 2022-03-08 10:47   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:47 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> These symbols become available to the debugger.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 18/33] target/nios2: Implement cpuid
  2022-03-08  7:19 ` [PATCH v4 18/33] target/nios2: Implement cpuid Richard Henderson
@ 2022-03-08 10:52   ` Peter Maydell
  2022-03-08 19:50     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:52 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Copy the existing cpu_index into the space reserved for CR_CPUID.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.c | 4 ++++
>  1 file changed, 4 insertions(+)
>
> diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
> index 189adf111c..fbcb4da737 100644
> --- a/target/nios2/cpu.c
> +++ b/target/nios2/cpu.c
> @@ -159,6 +159,7 @@ static ObjectClass *nios2_cpu_class_by_name(const char *cpu_model)
>  static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
>  {
>      CPUState *cs = CPU(dev);
> +    Nios2CPU *cpu = NIOS2_CPU(cs);
>      Nios2CPUClass *ncc = NIOS2_CPU_GET_CLASS(dev);
>      Error *local_err = NULL;
>
> @@ -171,6 +172,9 @@ static void nios2_cpu_realizefn(DeviceState *dev, Error **errp)
>      qemu_init_vcpu(cs);
>      cpu_reset(cs);
>
> +    /* We have reserved storage for ctrl[CR_CPUID]; might as well use it. */
> +    cpu->env.cpuid = cs->cpu_index;
> +
>      ncc->parent_realize(dev, errp);
>  }

I guess. This will have no effect as all our nios2 boards are
single-CPU.

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE
  2022-03-08  7:19 ` [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE Richard Henderson
@ 2022-03-08 10:55   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:55 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Without EIC, this bit is RES1.  So set the bit at reset,
> and add it to the readonly fields of CR_STATUS.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 1 +
>  target/nios2/cpu.c | 5 +++--
>  2 files changed, 4 insertions(+), 2 deletions(-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI
  2022-03-08  7:19 ` [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI Richard Henderson
@ 2022-03-08 10:56   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:56 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> This interrupt bit is never set, so testing it in
> nios2_cpu_has_work is pointless.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 2 --
>  target/nios2/cpu.c | 2 +-
>  2 files changed, 1 insertion(+), 3 deletions(-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields
  2022-03-08  7:19 ` [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields Richard Henderson
@ 2022-03-08 10:57   ` Peter Maydell
  2022-03-08 19:49     ` Richard Henderson
  2022-03-08 20:24   ` Peter Maydell
  1 sibling, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 10:57 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Create an array of masks which detail the writable and readonly
> bits for each control register.  Apply them when writing to
> control registers.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

What's the justification for this extra machinery? Does
existing guest code rely on writes to r/o bits being ignored ?

-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 21/33] target/nios2: Use tcg_constant_tl
  2022-03-08  7:19 ` [PATCH v4 21/33] target/nios2: Use tcg_constant_tl Richard Henderson
@ 2022-03-08 11:00   ` Peter Maydell
  2022-03-08 19:51     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 11:00 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Replace current uses of tcg_const_tl, and remove the frees.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

> @@ -675,8 +663,8 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
>
>      TCGv t0 = tcg_temp_new();
>      TCGv t1 = tcg_temp_new();
> -    TCGv t2 = tcg_const_tl(0);
> -    TCGv t3 = tcg_const_tl(1);
> +    TCGv t2 = tcg_constant_tl(0);
> +    TCGv t3 = tcg_constant_tl(1);

Maybe just use tcg_constant_tl(0) and (1) in-place at
the only two uses of t2, t3 rather than retaining the TCGv
local variables ?

>
>      tcg_gen_ext32u_tl(t0, load_gpr(dc, instr.a));
>      tcg_gen_ext32u_tl(t1, load_gpr(dc, instr.b));
> @@ -684,8 +672,6 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
>      tcg_gen_divu_tl(cpu_R[instr.c], t0, t1);
>      tcg_gen_ext32s_tl(cpu_R[instr.c], cpu_R[instr.c]);
>
> -    tcg_temp_free(t3);
> -    tcg_temp_free(t2);
>      tcg_temp_free(t1);
>      tcg_temp_free(t0);
>  }

Otherwise
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 22/33] target/nios2: Introduce dest_gpr
  2022-03-08  7:19 ` [PATCH v4 22/33] target/nios2: Introduce dest_gpr Richard Henderson
@ 2022-03-08 11:07   ` Peter Maydell
  2022-03-08 20:53     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 11:07 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Constrain all references to cpu_R[] to load_gpr and dest_gpr.
> This will be required for supporting shadow register sets.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/translate.c | 144 +++++++++++++++------------------------
>  1 file changed, 55 insertions(+), 89 deletions(-)



> @@ -449,15 +435,11 @@ static void rdctl(DisasContext *dc, uint32_t code, uint32_t flags)
>      g_assert_not_reached();
>  #else
>      R_TYPE(instr, code);
> -    TCGv t1, t2;
> -
> -    if (unlikely(instr.c == R_ZERO)) {
> -        return;
> -    }
> +    TCGv t1, t2, dest = dest_gpr(dc, instr.c);
>
>      /* Reserved registers read as zero. */
>      if (nios2_cr_reserved(&dc->cr_state[instr.imm5])) {
> -        tcg_gen_movi_tl(cpu_R[instr.c], 0);
> +        tcg_gen_movi_tl(dest, 0);
>          return;
>      }

I assume the TCG dead-code elimination will mostly throw away the
write-to-R_ZERO stuff, but here for rdctl I suspect it won't.
But probably real code doesn't do that kind of silly thing.



Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags
  2022-03-08  7:19 ` [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags Richard Henderson
@ 2022-03-08 11:08   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 11:08 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> There's nothing about EH that affects translation,
> so there's no need to include it in tb->flags.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting
  2022-03-08  7:19 ` [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting Richard Henderson
@ 2022-03-08 11:24   ` Peter Maydell
  0 siblings, 0 replies; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 11:24 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Decode 'break 1' during translation, rather than doing
> it again during exception processing.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/nios2/cpu.h       |  1 +
>  target/nios2/helper.c    | 15 ++++++---------
>  target/nios2/translate.c | 17 ++++++++++++++++-
>  3 files changed, 23 insertions(+), 10 deletions(-)
>
> diff --git a/target/nios2/cpu.h b/target/nios2/cpu.h
> index c48daa5640..13e1d49f38 100644
> --- a/target/nios2/cpu.h
> +++ b/target/nios2/cpu.h
> @@ -162,6 +162,7 @@ FIELD(CR_TLBMISC, EE, 24, 1)
>
>  /* Exceptions */
>  #define EXCP_BREAK    0x1000
> +#define EXCP_SEMIHOST 0x1001
>  #define EXCP_RESET    0
>  #define EXCP_PRESET   1
>  #define EXCP_IRQ      2
> diff --git a/target/nios2/helper.c b/target/nios2/helper.c
> index 007496b957..a338d02f6b 100644
> --- a/target/nios2/helper.c
> +++ b/target/nios2/helper.c
> @@ -146,17 +146,14 @@ void nios2_cpu_do_interrupt(CPUState *cs)
>          env->pc = cpu->exception_addr;
>          break;
>
> +    case EXCP_SEMIHOST:
> +        qemu_log_mask(CPU_LOG_INT, "BREAK semihosting at pc=%x\n", env->pc);
> +        env->pc += 4;
> +        do_nios2_semihosting(env);
> +        return;

Ah, here's the "return" I asked for in the earlier patch :-)

Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC)
  2022-03-08  7:20 ` [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC) Richard Henderson
  2022-03-08  8:32   ` Mark Cave-Ayland
@ 2022-03-08 11:27   ` Peter Maydell
  2022-03-08 19:53     ` Richard Henderson
  1 sibling, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 11:27 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
>
> Implement nios2 Vectored Interrupt Controller (VIC).
> VIC is connected to EIC. It needs to update rha, ril, rrs and rnmi
> fields on Nios2CPU before raising an IRQ.
> For that purpose, VIC has a "cpu" property which should refer to the
> nios2 cpu and set by the board that connects VIC.
>
> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
> Message-Id: <20220303153906.2024748-5-amir.gonnen@neuroblade.ai>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---

I reviewed the version of this patch that was in Amir's v3 -- has
it changed, and if so how, or did you just drop the R-by by accident?

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc
  2022-03-08 10:00   ` Peter Maydell
@ 2022-03-08 19:34     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:34 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:00, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> The only thing this struct is used for is passing startup values
>> from elfload.c to the cpu.  We do not need all registers to be
>> represented, we do not need the kernel internal stack slots.
>>
>> The userland argc, argv, and envp values are passed on
>> the stack, so only SP and PC need updating.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
>>   linux-user/nios2/target_syscall.h | 25 ++-----------------------
>>   linux-user/elfload.c              |  3 +--
>>   linux-user/nios2/cpu_loop.c       | 24 +-----------------------
>>   3 files changed, 4 insertions(+), 48 deletions(-)
> 
> Well, I guess we're not using it for anything else currently,
> but if you do this then it's not the target arch's pt_regs
> struct any more. And all our other target archs seem to define
> the struct to follow the kernel definition even if we don't
> happen to use it all.

Yes, something I've meant to clean up for ages.

My real goal here was removing the reference to estatus, which then does not need to be 
converted to a different form in the coming patches.

(Assigning to estatus is unusable in user-mode, because rdctl and eret are supervisor 
insns.  This code appears to be mirroring the kernel code in which it is trying to get the 
right bits ready for the context switch to user-mode.  For qemu, we've done that for 
user-only during reset, and with proper symbolic constants, so no need to do it again here.)

I could just remove the two mentions of estatus in init_thread and copy_regs, if that 
seems better.  Leave the target_pt_regs cleanup to a larger patch set touching them all.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields
  2022-03-08 10:08   ` Peter Maydell
@ 2022-03-08 19:34     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:34 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:08, Peter Maydell wrote:
>> +#define CR_STATUS_RSIE (1u << R_CR_STATUS_RSIE_SHIFT)
> 
> Since these are all 1 bit fields you can use
> #define CR_STATUS_PIE R_CR_STATUS_PIE_MASK
> etc rather than manually shifting by the shift count.

Quite right, thanks.

r~



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields
  2022-03-08 10:12   ` Peter Maydell
@ 2022-03-08 19:36     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:36 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:12, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Sink the set of env->exception to the end of nios2_cpu_do_interrupt.
> 
> This splits the two things the patch is doing between the subject line
> and the commit message body; the subject is supposed to be a summary
> and the body should be able to stand alone without the subject.

Yea, I should merge this sink to patch 28, which does other cleanup to this function.

>> +    env->exception = FIELD_DP32(env->exception, CR_EXCEPTION, CAUSE,
>> +                                cs->exception_index);
>>   }
> 
> This is a behaviour change in the semihosting case, which
> previously did not change env->exception and now does.
> Since that's guest visible I think it's not correct.
> You could fix that by making the semihosting handling end
> with 'return' rather than 'break'.

Yea, poor patch ordering, as you discovered.


r~



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields
  2022-03-08 10:46   ` Peter Maydell
@ 2022-03-08 19:37     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:37 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:46, Peter Maydell wrote:
>> @@ -130,24 +128,25 @@ void helper_mmu_write_tlbacc(CPUNios2State *env, uint32_t v)
>>   void helper_mmu_write_tlbmisc(CPUNios2State *env, uint32_t v)
>>   {
>>       Nios2CPU *cpu = env_archcpu(env);
>> +    uint32_t new_pid = FIELD_EX32(v, CR_TLBMISC, PID);
>> +    uint32_t old_pid = FIELD_EX32(env->mmu.tlbmisc_wr, CR_TLBMISC, PID);
>> +    uint32_t way = FIELD_EX32(v, CR_TLBMISC, WAY);
>>
>> -    trace_nios2_mmu_write_tlbmisc(v >> CR_TLBMISC_WAY_SHIFT,
>> +    trace_nios2_mmu_write_tlbmisc(way,
>>                                     (v & CR_TLBMISC_RD) ? 'R' : '.',
>>                                     (v & CR_TLBMISC_WR) ? 'W' : '.',
>>                                     (v & CR_TLBMISC_DBL) ? '2' : '.',
>>                                     (v & CR_TLBMISC_BAD) ? 'B' : '.',
>>                                     (v & CR_TLBMISC_PERM) ? 'P' : '.',
>>                                     (v & CR_TLBMISC_D) ? 'D' : '.',
>> -                                  (v & CR_TLBMISC_PID_MASK) >> 4);
>> +                                  new_pid);
>>
>> -    if ((v & CR_TLBMISC_PID_MASK) !=
>> -        (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK)) {
>> -        mmu_flush_pid(env, (env->mmu.tlbmisc_wr & CR_TLBMISC_PID_MASK) >>
>> -                           CR_TLBMISC_PID_SHIFT);
>> +    if (new_pid != old_pid) {
>> +        mmu_flush_pid(env, old_pid);
>>       }
>> +
>>       /* if tlbmisc.RD == 1 then trigger a TLB read on writes to TLBMISC */
>>       if (v & CR_TLBMISC_RD) {
>> -        int way = (v >> CR_TLBMISC_WAY_SHIFT);
>>           int vpn = FIELD_EX32(env->mmu.pteaddr_wr, CR_PTEADDR, VPN);
>>           Nios2TLBEntry *entry =
>>               &env->mmu.tlb[(way * cpu->tlb_num_ways) +
> 
> 
> Any reason for hoisting the declaration of 'way' up to the top of the
> function ?

For use in the tracepoint, rather than extracting it twice.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields
  2022-03-08 10:57   ` Peter Maydell
@ 2022-03-08 19:49     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:49 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:57, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Create an array of masks which detail the writable and readonly
>> bits for each control register.  Apply them when writing to
>> control registers.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> 
> What's the justification for this extra machinery? Does
> existing guest code rely on writes to r/o bits being ignored ?

During review of a previous edition of this patch set, I asked myself: why isn't Amir 
changing the shadow register set on WRCTL to STATUS, as the CRS field could change.

The answer is that the architecture disallows this, by making the CRS field read-only from 
software.  CRS can only be modified by interrupt entry and return.

Then I looked further and found more read-only fields, and lots of fields that are 
reserved unless the appropriate cpu options are enabled.  Again thining of CRS more so to 
PRS when shadow register sets are *not* enabled -- we don't want software to put us into 
some weird state.

I probably should have put all that in the patch description.  :-)


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 18/33] target/nios2: Implement cpuid
  2022-03-08 10:52   ` Peter Maydell
@ 2022-03-08 19:50     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:50 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 00:52, Peter Maydell wrote:
> I guess. This will have no effect as all our nios2 boards are
> single-CPU.
> 
> Reviewed-by: Peter Maydell <peter.maydell@linaro.org>

Oh, fair enough.  I didn't even think of that (even though I've just spent quite a bit of 
time on interrupts, and there's no sign of an inter-processor interrupt).


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 21/33] target/nios2: Use tcg_constant_tl
  2022-03-08 11:00   ` Peter Maydell
@ 2022-03-08 19:51     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:51 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 01:00, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Replace current uses of tcg_const_tl, and remove the frees.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
> 
>> @@ -675,8 +663,8 @@ static void divu(DisasContext *dc, uint32_t code, uint32_t flags)
>>
>>       TCGv t0 = tcg_temp_new();
>>       TCGv t1 = tcg_temp_new();
>> -    TCGv t2 = tcg_const_tl(0);
>> -    TCGv t3 = tcg_const_tl(1);
>> +    TCGv t2 = tcg_constant_tl(0);
>> +    TCGv t3 = tcg_constant_tl(1);
> 
> Maybe just use tcg_constant_tl(0) and (1) in-place at
> the only two uses of t2, t3 rather than retaining the TCGv
> local variables ?

Sure.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC)
  2022-03-08 11:27   ` Peter Maydell
@ 2022-03-08 19:53     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:53 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 01:27, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> From: Amir Gonnen <amir.gonnen@neuroblade.ai>
>>
>> Implement nios2 Vectored Interrupt Controller (VIC).
>> VIC is connected to EIC. It needs to update rha, ril, rrs and rnmi
>> fields on Nios2CPU before raising an IRQ.
>> For that purpose, VIC has a "cpu" property which should refer to the
>> nios2 cpu and set by the board that connects VIC.
>>
>> Signed-off-by: Amir Gonnen <amir.gonnen@neuroblade.ai>
>> Message-Id: <20220303153906.2024748-5-amir.gonnen@neuroblade.ai>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
>> ---
> 
> I reviewed the version of this patch that was in Amir's v3 -- has
> it changed, and if so how, or did you just drop the R-by by accident?

I don't believe that anything changed in this patch. I used tooling to grab the patches + 
tags, so I'm not sure what went wrong.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState
  2022-03-08  8:39   ` Mark Cave-Ayland
@ 2022-03-08 19:55     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:55 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 3/7/22 22:39, Mark Cave-Ayland wrote:
>>   static void nios2_10m50_ghrd_init(MachineState *machine)
>>   {
>> +    Nios2MachineState *nms = NIOS2_MACHINE(machine);
>>       Nios2CPU *cpu;
>>       DeviceState *dev;
>>       MemoryRegion *address_space_mem = get_system_memory();
>> @@ -101,15 +109,29 @@ static void nios2_10m50_ghrd_init(MachineState *machine)
>>       cpu->exception_addr = 0xc8000120;
>>       cpu->fast_tlb_miss_addr = 0xc0000100;
>> -    nios2_load_kernel(cpu, ram_base, ram_size, machine->initrd_filename,
>> +    nios2_load_kernel(cpu, ram_base, ram_size, nms->parent_obj.initrd_filename,
>>                         BINARY_DEVICE_TREE_FILE, NULL);
> 
> I think you should be able to keep this as machine->initrd_filename? Certainly there 
> should be no direct access to parent_obj here, and if you did need it a QOM cast macro 
> would be the way to do this.

Ok.

>> +static const TypeInfo nios2_10m50_ghrd_type_info = {
>> +    .name          = TYPE_NIOS2_MACHINE,
>> +    .parent        = TYPE_MACHINE,
>> +    .instance_size = sizeof(Nios2MachineState),
>> +    .class_size    = sizeof(MachineClass),
> 
> Technically you can drop .class_size here since this should be inherited automatically 
> from MachineClass.

Ok.  This is a leftover from an intermediate when Nios2MachineClass existed.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller
  2022-03-08  8:43   ` Mark Cave-Ayland
@ 2022-03-08 19:57     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 19:57 UTC (permalink / raw)
  To: Mark Cave-Ayland, qemu-devel; +Cc: marex, peter.maydell, amir.gonnen

On 3/7/22 22:43, Mark Cave-Ayland wrote:
>> +    qdev_realize(DEVICE(cpu), NULL, &error_fatal);
>> +    object_unref(CPU(cpu));
> 
> I believe this can be replaced with qdev_realize_and_unref()?

Oh, nice.  I copied this from hw/arm/virt, which has code between these two points.

>> +    if (nms->vic) {
>> +        DeviceState *dev = qdev_new("nios2-vic");
> 
> And with a separate header for nios2_vic.h you can include that and use TYPE_NIOS2_VIC 
> here instead of hard-coding the type name.

Ok.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields
  2022-03-08  7:19 ` [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields Richard Henderson
  2022-03-08 10:57   ` Peter Maydell
@ 2022-03-08 20:24   ` Peter Maydell
  2022-03-08 20:45     ` Richard Henderson
  1 sibling, 1 reply; 77+ messages in thread
From: Peter Maydell @ 2022-03-08 20:24 UTC (permalink / raw)
  To: Richard Henderson; +Cc: marex, amir.gonnen, qemu-devel

On Tue, 8 Mar 2022 at 07:20, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Create an array of masks which detail the writable and readonly
> bits for each control register.  Apply them when writing to
> control registers.
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>

> diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
> index f2813d3b47..189adf111c 100644
> --- a/target/nios2/cpu.c
> +++ b/target/nios2/cpu.c
> @@ -88,6 +88,55 @@ static void nios2_cpu_initfn(Object *obj)
>
>      cpu_set_cpustate_pointers(cpu);
>
> +    /* Begin with all fields of all registers are reserved. */
> +    memset(cpu->cr_state, 0, sizeof(cpu->cr_state));
> +
> +    /*
> +     * The combination of writable and readonly is the set of all
> +     * non-reserved fields.  We apply writable as a mask to bits,
> +     * and merge in existing readonly bits, before storing.
> +     */
> +#define WR_REG(C)       cpu->cr_state[C].writable = -1
> +#define RO_REG(C)       cpu->cr_state[C].readonly = -1
> +#define WR_FIELD(C, F)  cpu->cr_state[C].writable |= R_##C##_##F##_MASK
> +#define RO_FIELD(C, F)  cpu->cr_state[C].readonly |= R_##C##_##F##_MASK
> +
> +    WR_FIELD(CR_STATUS, PIE);

I think you need to claim (CR_STATUS, RSIE) is a RO bit, because without
EIC it's should-be-one.

> +    WR_REG(CR_ESTATUS);
> +    WR_REG(CR_BSTATUS);
> +    RO_REG(CR_CPUID);
> +    WR_FIELD(CR_EXCEPTION, CAUSE);
> +    WR_REG(CR_BADADDR);
> +
> +    /* TODO: These control registers are not present with the EIC. */
> +    WR_REG(CR_IENABLE);
> +    RO_REG(CR_IPENDING);

Missing CR_CONFIG register ?

> +
> +    if (cpu->mmu_present) {
> +        WR_FIELD(CR_STATUS, U);
> +        WR_FIELD(CR_STATUS, EH);

True by the documentation, but we don't seem to prevent EH from
being set to 1 when we take an exception on the no-MMU config...

> +
> +        WR_FIELD(CR_PTEADDR, VPN);
> +        WR_FIELD(CR_PTEADDR, PTBASE);
> +
> +        RO_FIELD(CR_TLBMISC, D);
> +        RO_FIELD(CR_TLBMISC, PERM);
> +        RO_FIELD(CR_TLBMISC, BAD);
> +        RO_FIELD(CR_TLBMISC, DBL);
> +        WR_FIELD(CR_TLBMISC, WR);

(the docs call this field 'WE', incidentally)

> +        WR_FIELD(CR_TLBMISC, RD);

If you claim this bit to be writable you'll allow the gdbstub
to set it, which is probably not what you want. (Actual writes to
this register are handled via the helper function.)

> +        WR_FIELD(CR_TLBMISC, WAY);

Missing PID field ?

> +
> +        WR_REG(CR_TLBACC);

> +    }

You don't enforce the reserved/readonly bits on status when
we copy it from estatus during eret. (That change appears later,
in patch 26.)

The same *ought* to apply for bret, except that we have a bug in
our implementation of it, where we fail to copy bstatus into status...

The machinery itself looks OK.

thanks
-- PMM


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields
  2022-03-08 20:24   ` Peter Maydell
@ 2022-03-08 20:45     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 20:45 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 10:24, Peter Maydell wrote:
> On Tue, 8 Mar 2022 at 07:20, Richard Henderson
> <richard.henderson@linaro.org> wrote:
>>
>> Create an array of masks which detail the writable and readonly
>> bits for each control register.  Apply them when writing to
>> control registers.
>>
>> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> 
>> diff --git a/target/nios2/cpu.c b/target/nios2/cpu.c
>> index f2813d3b47..189adf111c 100644
>> --- a/target/nios2/cpu.c
>> +++ b/target/nios2/cpu.c
>> @@ -88,6 +88,55 @@ static void nios2_cpu_initfn(Object *obj)
>>
>>       cpu_set_cpustate_pointers(cpu);
>>
>> +    /* Begin with all fields of all registers are reserved. */
>> +    memset(cpu->cr_state, 0, sizeof(cpu->cr_state));
>> +
>> +    /*
>> +     * The combination of writable and readonly is the set of all
>> +     * non-reserved fields.  We apply writable as a mask to bits,
>> +     * and merge in existing readonly bits, before storing.
>> +     */
>> +#define WR_REG(C)       cpu->cr_state[C].writable = -1
>> +#define RO_REG(C)       cpu->cr_state[C].readonly = -1
>> +#define WR_FIELD(C, F)  cpu->cr_state[C].writable |= R_##C##_##F##_MASK
>> +#define RO_FIELD(C, F)  cpu->cr_state[C].readonly |= R_##C##_##F##_MASK
>> +
>> +    WR_FIELD(CR_STATUS, PIE);
> 
> I think you need to claim (CR_STATUS, RSIE) is a RO bit, because without
> EIC it's should-be-one.

That's patch 19.

> 
>> +    WR_REG(CR_ESTATUS);
>> +    WR_REG(CR_BSTATUS);
>> +    RO_REG(CR_CPUID);
>> +    WR_FIELD(CR_EXCEPTION, CAUSE);
>> +    WR_REG(CR_BADADDR);
>> +
>> +    /* TODO: These control registers are not present with the EIC. */
>> +    WR_REG(CR_IENABLE);
>> +    RO_REG(CR_IPENDING);
> 
> Missing CR_CONFIG register ?

Present with MPU or ECC, and we implement neither.  Perhaps these should be listed below 
with the TODO?

> 
>> +
>> +    if (cpu->mmu_present) {
>> +        WR_FIELD(CR_STATUS, U);
>> +        WR_FIELD(CR_STATUS, EH);
> 
> True by the documentation, but we don't seem to prevent EH from
> being set to 1 when we take an exception on the no-MMU config...

Yeah, I noticed this when cleaning things up in patch 28, but didn't want to change things 
too much in that patch.  I also don't have a no-mmu kernel to test against.

>> +        WR_FIELD(CR_TLBMISC, WR);
> 
> (the docs call this field 'WE', incidentally)

Yeah, noticed that and meant to fix it, but forgot.

>> +        WR_FIELD(CR_TLBMISC, RD);
> 
> If you claim this bit to be writable you'll allow the gdbstub
> to set it, which is probably not what you want. (Actual writes to
> this register are handled via the helper function.)

Mm.  Perhaps calling it reserved is the easiest way out of that.  For these mmu registers, 
we don't apply the two masks, but pass it all to the helper.  I'm open to ideas there.

>> +        WR_FIELD(CR_TLBMISC, WAY);
> 
> Missing PID field ?

Yep, thanks.

>> +        WR_REG(CR_TLBACC);
> 
>> +    }
> 
> You don't enforce the reserved/readonly bits on status when
> we copy it from estatus during eret. (That change appears later,
> in patch 26.)

Yep.  I could move the masking back to this patch, leave only the estatus/sstatus change 
to patch 26.

> The same *ought* to apply for bret, except that we have a bug in
> our implementation of it, where we fail to copy bstatus into status...

Hah, thanks, yes.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 22/33] target/nios2: Introduce dest_gpr
  2022-03-08 11:07   ` Peter Maydell
@ 2022-03-08 20:53     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-08 20:53 UTC (permalink / raw)
  To: Peter Maydell; +Cc: marex, amir.gonnen, qemu-devel

On 3/8/22 01:07, Peter Maydell wrote:
> I assume the TCG dead-code elimination will mostly throw away the
> write-to-R_ZERO stuff, but here for rdctl I suspect it won't.

I believe it will.  We don't indicate that normal load has side effects (as opposed to 
guest load), so it should all fall out of unused values.

> But probably real code doesn't do that kind of silly thing.

Indeed.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

* RE: [PATCH v4 24/33] target/nios2: Introduce shadow register sets
  2022-03-08  7:19 ` [PATCH v4 24/33] target/nios2: Introduce shadow register sets Richard Henderson
@ 2022-03-09 14:02   ` Amir Gonnen
  2022-03-09 18:01     ` Richard Henderson
  0 siblings, 1 reply; 77+ messages in thread
From: Amir Gonnen @ 2022-03-09 14:02 UTC (permalink / raw)
  To: Richard Henderson, qemu-devel; +Cc: marex, peter.maydell

Hi Richard,

How does "cpu_crs_R" work?
In your version you hold a pointer to the current register set instead of copying registers back and forth like I did, which makes sense.

But how does TCG know which set to refer to when it generates code?
It looks like it's always accessing the same cpu_crs_R, so how does it relate to the correct register set on "shadow_regs"?

In fact, I imagined it would be necessary to change "cpu_get_tb_cpu_state" and set "cs_base" or "flags" to STATUS.CRS such that different code would be generated for each shadow instance. Otherwise, each gpr access would be indirect. I'm probably missing something here.

Thanks,
Amir



^ permalink raw reply	[flat|nested] 77+ messages in thread

* Re: [PATCH v4 24/33] target/nios2: Introduce shadow register sets
  2022-03-09 14:02   ` Amir Gonnen
@ 2022-03-09 18:01     ` Richard Henderson
  0 siblings, 0 replies; 77+ messages in thread
From: Richard Henderson @ 2022-03-09 18:01 UTC (permalink / raw)
  To: Amir Gonnen, qemu-devel; +Cc: marex, peter.maydell

On 3/9/22 04:02, Amir Gonnen wrote:
> How does "cpu_crs_R" work?
...> Otherwise, each gpr access would be indirect. I'm probably missing something here.

They are indirect, but with some optimization.

> +    TCGv_ptr crs = tcg_global_mem_new_ptr(cpu_env,
> +                                          offsetof(CPUNios2State, crs), "crs");
> +
> +    for (int i = 0; i < NUM_GP_REGS; i++) {
> +        cpu_crs_R[i] = tcg_global_mem_new(crs, 4 * i, gr_regnames[i]);
> +    }

Note that the crs variable is relative to env, and then the cpu_crs_R registers are 
relative to crs.

Without an EIC-enabled kernel for testing, it's hard for me to show the nios2 code at 
work, but it is identical to what we do over in target/sparc:

>     for (i = 8; i < 32; ++i) {
>         cpu_regs[i] = tcg_global_mem_new(cpu_regwptr,
>                                          (i - 8) * sizeof(target_ulong),
>                                          gregnames[i]);
>     }

A small example of what this looks like is -d in_asm,op_ind,op_opt :

IN: __libc_start_main
0x00000000001032e8:  save  %sp, -720, %sp
0x00000000001032ec:  stx  %i0, [ %fp + 0x87f ]
0x00000000001032f0:  stx  %i1, [ %fp + 0x887 ]
0x00000000001032f4:  stx  %i2, [ %fp + 0x88f ]

OP before indirect lowering:
  ld_i32 tmp0,env,$0xfffffffffffffff8
  brcond_i32 tmp0,$0x0,lt,$L0              dead: 0 1

  ---- 00000000001032e8 00000000001032ec
  add_i64 tmp3,o6,$0xfffffffffffffd30      dead: 1 2
  call save,$0x0,$0,env                    dead: 0
  mov_i64 o6,tmp3                          sync: 0  dead: 0 1

  ---- 00000000001032ec 00000000001032f0
  add_i64 tmp2,i6,$0x87f                   dead: 2
  qemu_st_i64 i0,tmp2,beq,0                dead: 0 1

  ---- 00000000001032f0 00000000001032f4
  add_i64 tmp2,i6,$0x887                   dead: 2
  qemu_st_i64 i1,tmp2,beq,0                dead: 0 1

  ---- 00000000001032f4 00000000001032f8
  add_i64 tmp2,i6,$0x88f                   dead: 1 2
  qemu_st_i64 i2,tmp2,beq,0                dead: 0 1


You can see that early on, we optimize with the windowed registers themselves (o[0-7] and 
i[0-7] here).  But then we lower that to explicit load/store operations:


OP after optimization and liveness analysis:
  ld_i32 tmp0,env,$0xfffffffffffffff8      pref=0xffff
  brcond_i32 tmp0,$0x0,lt,$L0              dead: 0 1

  ---- 00000000001032e8 00000000001032ec
  ld_i64 tmp20,regwptr,$0x30               dead: 1  pref=0xffff
  add_i64 tmp3,tmp20,$0xfffffffffffffd30   dead: 1 2  pref=0xf038
  call save,$0x0,$0,env                    dead: 0
  st_i64 tmp3,regwptr,$0x30                dead: 0

  ---- 00000000001032ec 00000000001032f0
  ld_i64 tmp36,regwptr,$0xb0               pref=0xf038
  add_i64 tmp2,tmp36,$0x87f                dead: 2  pref=0xffff
  ld_i64 tmp30,regwptr,$0x80               pref=0xffff
  qemu_st_i64 tmp30,tmp2,beq,0             dead: 0 1

  ---- 00000000001032f0 00000000001032f4
  add_i64 tmp2,tmp36,$0x887                dead: 2  pref=0xffff
  ld_i64 tmp31,regwptr,$0x88               pref=0xffff
  qemu_st_i64 tmp31,tmp2,beq,0             dead: 0 1

  ---- 00000000001032f4 00000000001032f8
  add_i64 tmp2,tmp36,$0x88f                dead: 1 2  pref=0xffff
  ld_i64 tmp32,regwptr,$0x90               dead: 1  pref=0xffff
  qemu_st_i64 tmp32,tmp2,beq,0             dead: 0 1


You can now see the new tmpN variables, and the uses of regwptr in the loads and stores.


r~


^ permalink raw reply	[flat|nested] 77+ messages in thread

end of thread, other threads:[~2022-03-09 18:02 UTC | newest]

Thread overview: 77+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-03-08  7:19 [PATCH v4 00/33] target/nios2: Shadow register set, EIC and VIC Richard Henderson
2022-03-08  7:19 ` [PATCH v4 01/33] target/nios2: Check supervisor on eret Richard Henderson
2022-03-08  7:19 ` [PATCH v4 02/33] target/nios2: Stop generating code if gen_check_supervisor fails Richard Henderson
2022-03-08  9:48   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 03/33] target/nios2: Add NUM_GP_REGS and NUM_CP_REGS Richard Henderson
2022-03-08  9:49   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 04/33] target/nios2: Split PC out of env->regs[] Richard Henderson
2022-03-08  9:51   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 05/33] target/nios2: Split out helper for eret instruction Richard Henderson
2022-03-08  9:52   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 06/33] target/nios2: Do not create TCGv for control registers Richard Henderson
2022-03-08  9:54   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 07/33] linux-user/nios2: Trim target_pc_regs to sp and pc Richard Henderson
2022-03-08 10:00   ` Peter Maydell
2022-03-08 19:34     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 08/33] target/nios2: Remove cpu_interrupts_enabled Richard Henderson
2022-03-08 10:00   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 09/33] target/nios2: Split control registers away from general registers Richard Henderson
2022-03-08 10:04   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 10/33] target/nios2: Clean up nios2_cpu_dump_state Richard Henderson
2022-03-08 10:06   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 11/33] target/nios2: Use hw/registerfields.h for CR_STATUS fields Richard Henderson
2022-03-08 10:08   ` Peter Maydell
2022-03-08 19:34     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 12/33] target/nios2: Use hw/registerfields.h for CR_EXCEPTION fields Richard Henderson
2022-03-08 10:12   ` Peter Maydell
2022-03-08 19:36     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 13/33] target/nios2: Use hw/registerfields.h for CR_TLBADDR fields Richard Henderson
2022-03-08 10:14   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 14/33] target/nios2: Use hw/registerfields.h for CR_TLBACC fields Richard Henderson
2022-03-08 10:19   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 15/33] target/nios2: Use hw/registerfields.h for CR_TLBMISC fields Richard Henderson
2022-03-08 10:46   ` Peter Maydell
2022-03-08 19:37     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 16/33] target/nios2: Move R_FOO and CR_BAR into enumerations Richard Henderson
2022-03-08 10:47   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 17/33] target/nios2: Prevent writes to read-only or reserved control fields Richard Henderson
2022-03-08 10:57   ` Peter Maydell
2022-03-08 19:49     ` Richard Henderson
2022-03-08 20:24   ` Peter Maydell
2022-03-08 20:45     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 18/33] target/nios2: Implement cpuid Richard Henderson
2022-03-08 10:52   ` Peter Maydell
2022-03-08 19:50     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 19/33] target/nios2: Implement CR_STATUS.RSIE Richard Henderson
2022-03-08 10:55   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 20/33] target/nios2: Remove CPU_INTERRUPT_NMI Richard Henderson
2022-03-08 10:56   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 21/33] target/nios2: Use tcg_constant_tl Richard Henderson
2022-03-08 11:00   ` Peter Maydell
2022-03-08 19:51     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 22/33] target/nios2: Introduce dest_gpr Richard Henderson
2022-03-08 11:07   ` Peter Maydell
2022-03-08 20:53     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 23/33] target/nios2: Drop CR_STATUS_EH from tb->flags Richard Henderson
2022-03-08 11:08   ` Peter Maydell
2022-03-08  7:19 ` [PATCH v4 24/33] target/nios2: Introduce shadow register sets Richard Henderson
2022-03-09 14:02   ` Amir Gonnen
2022-03-09 18:01     ` Richard Henderson
2022-03-08  7:19 ` [PATCH v4 25/33] target/nios2: Implement rdprs, wrprs Richard Henderson
2022-03-08  7:19 ` [PATCH v4 26/33] target/nios2: Update helper_eret for shadow registers Richard Henderson
2022-03-08  7:19 ` [PATCH v4 27/33] target/nios2: Create EXCP_SEMIHOST for semi-hosting Richard Henderson
2022-03-08 11:24   ` Peter Maydell
2022-03-08  7:20 ` [PATCH v4 28/33] target/nios2: Clean up nios2_cpu_do_interrupt Richard Henderson
2022-03-08  7:20 ` [PATCH v4 29/33] target/nios2: Implement EIC interrupt processing Richard Henderson
2022-03-08  7:20 ` [PATCH v4 30/33] hw/intc: Vectored Interrupt Controller (VIC) Richard Henderson
2022-03-08  8:32   ` Mark Cave-Ayland
2022-03-08 11:27   ` Peter Maydell
2022-03-08 19:53     ` Richard Henderson
2022-03-08  7:20 ` [PATCH v4 31/33] hw/nios2: Introduce Nios2MachineState Richard Henderson
2022-03-08  8:39   ` Mark Cave-Ayland
2022-03-08 19:55     ` Richard Henderson
2022-03-08  7:20 ` [PATCH v4 32/33] hw/nios2: Move memory regions into Nios2Machine Richard Henderson
2022-03-08  8:39   ` Mark Cave-Ayland
2022-03-08  7:20 ` [PATCH v4 33/33] hw/nios2: Machine with a Vectored Interrupt Controller Richard Henderson
2022-03-08  8:43   ` Mark Cave-Ayland
2022-03-08 19:57     ` Richard Henderson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.