@@ -43,82 +43,127 @@ extern struct target_ops gdbstub_ops;
4343
4444/* RISC-V exception code list */
4545/* clang-format off */
46- #define RV_EXCEPTION_LIST \
46+ #define RV_TRAP_LIST \
4747 IIF(RV32_HAS(EXT_C))(, \
4848 _(insn_misaligned, 0) /* Instruction address misaligned */ \
4949 ) \
5050 _ (illegal_insn , 2 ) /* Illegal instruction */ \
5151 _(breakpoint, 3) /* Breakpoint */ \
5252 _ (load_misaligned , 4 ) /* Load address misaligned */ \
5353 _ (store_misaligned , 6 ) /* Store/AMO address misaligned */ \
54- _ (ecall_M , 11 ) /* Environment call from M-mode */
54+ IIF (RV32_HAS (SYSTEM ))(, \
55+ _ (ecall_M , 11 ) /* Environment call from M-mode */ \
56+ )
5557/* clang-format on */
5658
5759enum {
58- #define _(type, code) rv_exception_code ##type = code,
59- RV_EXCEPTION_LIST
60+ #define _(type, code) rv_trap_code_ ##type = code,
61+ RV_TRAP_LIST
6062#undef _
6163};
6264
63- static void rv_exception_default_handler (riscv_t * rv )
65+ static void rv_trap_default_handler (riscv_t * rv )
6466{
6567 rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
6668 rv -> PC = rv -> csr_mepc ; /* mret */
6769}
6870
69- /* When a trap occurs in M-mode, mtval is either initialized to zero or
71+ /*
72+ * Trap might occurs during block emulation. For instance, page fault.
73+ * In order to handle trap, we have to escape from block and execute
74+ * registered trap handler. This trap_handler function helps to execute
75+ * the registered trap handler, PC by PC. Once the trap is handled,
76+ * resume the previous execution flow where cause the trap.
77+ *
78+ * Since the system emulation has not yet included in rv32emu, the page
79+ * fault is not practical in current test suite. Instead, we try to
80+ * emulate the misaligned handling in the test suite.
81+ */
82+ #if RV32_HAS (SYSTEM )
83+ static void trap_handler (riscv_t * rv );
84+ #endif
85+
86+ /* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
7087 * populated with exception-specific details to assist software in managing
71- * the trap. Otherwise, the implementation never modifies mtval , although
88+ * the trap. Otherwise, the implementation never modifies m/stval , although
7289 * software can explicitly write to it. The hardware platform will define
7390 * which exceptions are required to informatively set mtval and which may
7491 * consistently set it to zero.
7592 *
7693 * When a hardware breakpoint is triggered or an exception like address
7794 * misalignment, access fault, or page fault occurs during an instruction
78- * fetch, load, or store operation, mtval is updated with the virtual address
79- * that caused the fault. In the case of an illegal instruction trap, mtval
95+ * fetch, load, or store operation, m/stval is updated with the virtual address
96+ * that caused the fault. In the case of an illegal instruction trap, m/stval
8097 * might be updated with the first XLEN or ILEN bits of the offending
81- * instruction. For all other traps, mtval is simply set to zero. However,
82- * it is worth noting that a future standard could redefine how mtval is
98+ * instruction. For all other traps, m/stval is simply set to zero. However,
99+ * it is worth noting that a future standard could redefine how m/stval is
83100 * handled for different types of traps.
101+ *
102+ * For simplicity and clarity, abstracting stval and mtval into a single
103+ * identifier called tval, as both are handled by TRAP_HANDLER_IMPL.
84104 */
85- #define EXCEPTION_HANDLER_IMPL (type , code ) \
86- static void rv_except_##type(riscv_t *rv, uint32_t mtval) \
87- { \
88- /* mtvec (Machine Trap-Vector Base Address Register) \
89- * mtvec[MXLEN-1:2]: vector base address \
90- * mtvec[1:0] : vector mode \
91- */ \
92- const uint32_t base = rv -> csr_mtvec & ~0x3 ; \
93- const uint32_t mode = rv -> csr_mtvec & 0x3 ; \
94- /* mepc (Machine Exception Program Counter) \
95- * mtval (Machine Trap Value Register) \
96- * mcause (Machine Cause Register): store exception code \
97- * mstatus (Machine Status Register): keep track of and controls the \
98- * hart’s current operating state \
99- */ \
100- rv -> csr_mepc = rv -> PC ; \
101- rv -> csr_mtval = mtval ; \
102- rv -> csr_mcause = code ; \
103- rv -> csr_mstatus = MSTATUS_MPP ; /* set privilege mode */ \
104- if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
105- rv_exception_default_handler (rv ); \
106- return ; \
107- } \
108- switch (mode ) { \
109- case 0 : /* DIRECT: All exceptions set PC to base */ \
110- rv -> PC = base ; \
111- break ; \
112- /* VECTORED: Asynchronous interrupts set PC to base + 4 * code */ \
113- case 1 : \
114- rv -> PC = base + 4 * code ; \
115- break ; \
116- } \
105+ #define TRAP_HANDLER_IMPL (type , code ) \
106+ static void rv_trap_##type(riscv_t *rv, uint32_t tval) \
107+ { \
108+ /* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
109+ * m/stvec[MXLEN-1:2]: vector base address \
110+ * m/stvec[1:0] : vector mode \
111+ * m/sepc (Machine/Supervisor Exception Program Counter) \
112+ * m/stval (Machine/Supervisor Trap Value Register) \
113+ * m/scause (Machine/Supervisor Cause Register): store exception code \
114+ * m/sstatus (Machine/Supervisor Status Register): keep track of and \
115+ * controls the hart’s current operating state \
116+ */ \
117+ uint32_t base ; \
118+ uint32_t mode ; \
119+ /* user or supervisor */ \
120+ if (RV_PRIV_IS_U_OR_S_MODE ()) { \
121+ const uint32_t sstatus_sie = \
122+ (rv -> csr_sstatus & SSTATUS_SIE ) >> SSTATUS_SIE_SHIFT ; \
123+ rv -> csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT ); \
124+ rv -> csr_sstatus &= ~(SSTATUS_SIE ); \
125+ rv -> csr_sstatus |= (rv -> priv_mode << SSTATUS_SPP_SHIFT ); \
126+ rv -> priv_mode = RV_PRIV_S_MODE ; \
127+ base = rv -> csr_stvec & ~0x3 ; \
128+ mode = rv -> csr_stvec & 0x3 ; \
129+ rv -> csr_sepc = rv -> PC ; \
130+ rv -> csr_stval = tval ; \
131+ rv -> csr_scause = code ; \
132+ } else { /* machine */ \
133+ const uint32_t mstatus_mie = \
134+ (rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ; \
135+ rv -> csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT ); \
136+ rv -> csr_mstatus &= ~(MSTATUS_MIE ); \
137+ rv -> csr_mstatus |= (rv -> priv_mode << MSTATUS_MPP_SHIFT ); \
138+ rv -> priv_mode = RV_PRIV_M_MODE ; \
139+ base = rv -> csr_mtvec & ~0x3 ; \
140+ mode = rv -> csr_mtvec & 0x3 ; \
141+ rv -> csr_mepc = rv -> PC ; \
142+ rv -> csr_mtval = tval ; \
143+ rv -> csr_mcause = code ; \
144+ if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
145+ rv_trap_default_handler (rv ); \
146+ return ; \
147+ } \
148+ } \
149+ switch (mode ) { \
150+ /* DIRECT: All traps set PC to base */ \
151+ case 0 : \
152+ rv -> PC = base ; \
153+ break ; \
154+ /* VECTORED: Asynchronous traps set PC to base + 4 * code */ \
155+ case 1 : \
156+ /* MSB of code is used to indicate whether the trap is interrupt \
157+ * or exception, so it is not considered as the 'real' code */ \
158+ rv -> PC = base + 4 * (code & MASK (31 )); \
159+ break ; \
160+ } \
161+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) trap_handler (rv );, ) \
117162 }
118163
119164/* RISC-V exception handlers */
120- #define _ (type , code ) EXCEPTION_HANDLER_IMPL (type, code)
121- RV_EXCEPTION_LIST
165+ #define _ (type , code ) TRAP_HANDLER_IMPL (type, code)
166+ RV_TRAP_LIST
122167#undef _
123168
124169/* wrap load/store and insn misaligned handler
@@ -135,7 +180,8 @@ RV_EXCEPTION_LIST
135180 rv->compressed = compress; \
136181 rv->csr_cycle = cycle; \
137182 rv->PC = PC; \
138- rv_except_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
183+ IIF(RV32_HAS(SYSTEM))(rv->is_trapped = true, ); \
184+ rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
139185 return false; \
140186 }
141187
@@ -164,6 +210,10 @@ static uint32_t *csr_get_ptr(riscv_t *rv, uint32_t csr)
164210 return (uint32_t * ) (& rv -> csr_misa );
165211
166212 /* Machine Trap Handling */
213+ case CSR_MEDELEG : /* Machine Exception Delegation Register */
214+ return (uint32_t * ) (& rv -> csr_medeleg );
215+ case CSR_MIDELEG : /* Machine Interrupt Delegation Register */
216+ return (uint32_t * ) (& rv -> csr_mideleg );
167217 case CSR_MSCRATCH : /* Machine Scratch Register */
168218 return (uint32_t * ) (& rv -> csr_mscratch );
169219 case CSR_MEPC : /* Machine Exception Program Counter */
@@ -196,6 +246,26 @@ static uint32_t *csr_get_ptr(riscv_t *rv, uint32_t csr)
196246 case CSR_FCSR :
197247 return (uint32_t * ) (& rv -> csr_fcsr );
198248#endif
249+ case CSR_SSTATUS :
250+ return (uint32_t * ) (& rv -> csr_sstatus );
251+ case CSR_SIE :
252+ return (uint32_t * ) (& rv -> csr_sie );
253+ case CSR_STVEC :
254+ return (uint32_t * ) (& rv -> csr_stvec );
255+ case CSR_SCOUNTEREN :
256+ return (uint32_t * ) (& rv -> csr_scounteren );
257+ case CSR_SSCRATCH :
258+ return (uint32_t * ) (& rv -> csr_sscratch );
259+ case CSR_SEPC :
260+ return (uint32_t * ) (& rv -> csr_sepc );
261+ case CSR_SCAUSE :
262+ return (uint32_t * ) (& rv -> csr_scause );
263+ case CSR_STVAL :
264+ return (uint32_t * ) (& rv -> csr_stval );
265+ case CSR_SIP :
266+ return (uint32_t * ) (& rv -> csr_sip );
267+ case CSR_SATP :
268+ return (uint32_t * ) (& rv -> csr_satp );
199269 default :
200270 return NULL ;
201271 }
@@ -377,9 +447,10 @@ enum {
377447};
378448
379449#if RV32_HAS (GDBSTUB )
380- #define RVOP_NO_NEXT (ir ) (!ir->next | rv->debug_mode)
450+ #define RVOP_NO_NEXT (ir ) \
451+ (!ir->next | rv->debug_mode IIF(RV32_HAS(SYSTEM))(| rv->is_trapped, ))
381452#else
382- #define RVOP_NO_NEXT (ir ) (!ir->next)
453+ #define RVOP_NO_NEXT (ir ) (!ir->next IIF(RV32_HAS(SYSTEM))(| rv->is_trapped, ) )
383454#endif
384455
385456/* record whether the branch is taken or not during emulation */
@@ -565,8 +636,10 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)
565636 case rv_insn_ebreak :
566637 case rv_insn_jal :
567638 case rv_insn_jalr :
568- case rv_insn_sret :
569639 case rv_insn_mret :
640+ #if RV32_HAS (SYSTEM )
641+ case rv_insn_sret :
642+ #endif
570643#if RV32_HAS (EXT_C )
571644 case rv_insn_cj :
572645 case rv_insn_cjalr :
@@ -598,7 +671,7 @@ static void block_translate(riscv_t *rv, block_t *block)
598671 /* decode the instruction */
599672 if (!rv_decode (ir , insn )) {
600673 rv -> compressed = is_compressed (insn );
601- rv_except_illegal_insn (rv , insn );
674+ rv_trap_illegal_insn (rv , insn );
602675 break ;
603676 }
604677 ir -> impl = dispatch_table [ir -> opcode ];
@@ -1048,17 +1121,42 @@ void rv_step(void *arg)
10481121#endif
10491122}
10501123
1124+ #if RV32_HAS (SYSTEM )
1125+ static void trap_handler (riscv_t * rv )
1126+ {
1127+ rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1128+ assert (ir );
1129+
1130+ /* set to false by sret/mret implementation */
1131+ uint32_t insn ;
1132+ while (rv -> is_trapped && !rv_has_halted (rv )) {
1133+ insn = rv -> io .mem_ifetch (rv -> PC );
1134+ assert (insn );
1135+
1136+ rv_decode (ir , insn );
1137+ ir -> impl = dispatch_table [ir -> opcode ];
1138+ rv -> compressed = is_compressed (insn );
1139+ ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
1140+ }
1141+ }
1142+ #endif
1143+
10511144void ebreak_handler (riscv_t * rv )
10521145{
10531146 assert (rv );
1054- rv_except_breakpoint (rv , rv -> PC );
1147+ rv_trap_breakpoint (rv , rv -> PC );
10551148}
10561149
10571150void ecall_handler (riscv_t * rv )
10581151{
10591152 assert (rv );
1060- rv_except_ecall_M ( rv , 0 );
1153+ #if RV32_HAS ( SYSTEM )
10611154 syscall_handler (rv );
1155+ rv -> PC += 4 ;
1156+ #else
1157+ rv_trap_ecall_M (rv , 0 );
1158+ syscall_handler (rv );
1159+ #endif
10621160}
10631161
10641162void memset_handler (riscv_t * rv )
0 commit comments