1414#include <emscripten.h>
1515#endif
1616
17+ #if RV32_HAS (SYSTEM )
18+ #include "system.h"
19+ #endif /* RV32_HAS(SYSTEM) */
20+
1721#if RV32_HAS (EXT_F )
1822#include <math.h>
1923#include "softfloat.h"
@@ -41,47 +45,33 @@ extern struct target_ops gdbstub_ops;
4145#define IF_rs2 (i , r ) (i->rs2 == rv_reg_##r)
4246#define IF_imm (i , v ) (i->imm == v)
4347
44- /* RISC-V exception code list */
48+ /* RISC-V trap code list */
4549/* clang-format off */
46- #define RV_TRAP_LIST \
47- IIF(RV32_HAS(EXT_C))(, \
48- _(insn_misaligned, 0) /* Instruction address misaligned */ \
49- ) \
50- _ (illegal_insn , 2 ) /* Illegal instruction */ \
51- _(breakpoint, 3) /* Breakpoint */ \
52- _ (load_misaligned , 4 ) /* Load address misaligned */ \
53- _ (store_misaligned , 6 ) /* Store/AMO address misaligned */ \
54- IIF (RV32_HAS (SYSTEM ))(, \
55- _ (ecall_M , 11 ) /* Environment call from M-mode */ \
50+ #define RV_TRAP_LIST \
51+ IIF(RV32_HAS(EXT_C))(, \
52+ _(insn_misaligned) /* Instruction address misaligned */ \
53+ ) \
54+ _ (illegal_insn ) /* Illegal instruction */ \
55+ _(breakpoint) /* Breakpoint */ \
56+ _ (load_misaligned ) /* Load address misaligned */ \
57+ _ (store_misaligned ) /* Store/AMO address misaligned */ \
58+ IIF (RV32_HAS (SYSTEM ))( \
59+ _ (pagefault_insn ) /* Instruction page fault */ \
60+ _ (pagefault_load ) /* Load page fault */ \
61+ _ (pagefault_store ), /* Store page fault */ \
62+ _ (ecall_M ) /* Environment call from M-mode */ \
5663 )
5764/* clang-format on */
5865
59- enum {
60- #define _(type, code) rv_trap_code_##type = code,
61- RV_TRAP_LIST
62- #undef _
63- };
64-
6566static void rv_trap_default_handler (riscv_t * rv )
6667{
6768 rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
6869 rv -> PC = rv -> csr_mepc ; /* mret */
6970}
7071
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- */
8272#if RV32_HAS (SYSTEM )
83- static void trap_handler (riscv_t * rv );
84- #endif
73+ static void __trap_handler (riscv_t * rv );
74+ #endif /* SYSTEM */
8575
8676/* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
8777 * populated with exception-specific details to assist software in managing
@@ -99,11 +89,9 @@ static void trap_handler(riscv_t *rv);
9989 * it is worth noting that a future standard could redefine how m/stval is
10090 * handled for different types of traps.
10191 *
102- * For simplicity and clarity, abstracting stval and mtval into a single
103- * identifier called tval, as both are handled by TRAP_HANDLER_IMPL.
10492 */
105- #define TRAP_HANDLER_IMPL (type , code ) \
106- static void rv_trap_##type(riscv_t *rv, uint32_t tval) \
93+ #define TRAP_HANDLER_IMPL (type ) \
94+ static void rv_trap_##type(riscv_t *rv) \
10795 { \
10896 /* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
10997 * m/stvec[MXLEN-1:2]: vector base address \
@@ -113,9 +101,12 @@ static void trap_handler(riscv_t *rv);
113101 * m/scause (Machine/Supervisor Cause Register): store exception code \
114102 * m/sstatus (Machine/Supervisor Status Register): keep track of and \
115103 * controls the hart’s current operating state \
104+ * \
105+ * m/stval and m/scause are set in SET_CAUSE_AND_TVAL_THEN_TRAP \
116106 */ \
117107 uint32_t base ; \
118108 uint32_t mode ; \
109+ uint32_t cause ; \
119110 /* user or supervisor */ \
120111 if (RV_PRIV_IS_U_OR_S_MODE ()) { \
121112 const uint32_t sstatus_sie = \
@@ -126,9 +117,8 @@ static void trap_handler(riscv_t *rv);
126117 rv -> priv_mode = RV_PRIV_S_MODE ; \
127118 base = rv -> csr_stvec & ~0x3 ; \
128119 mode = rv -> csr_stvec & 0x3 ; \
120+ cause = rv -> csr_scause ; \
129121 rv -> csr_sepc = rv -> PC ; \
130- rv -> csr_stval = tval ; \
131- rv -> csr_scause = code ; \
132122 } else { /* machine */ \
133123 const uint32_t mstatus_mie = \
134124 (rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ; \
@@ -138,9 +128,8 @@ static void trap_handler(riscv_t *rv);
138128 rv -> priv_mode = RV_PRIV_M_MODE ; \
139129 base = rv -> csr_mtvec & ~0x3 ; \
140130 mode = rv -> csr_mtvec & 0x3 ; \
131+ cause = rv -> csr_mcause ; \
141132 rv -> csr_mepc = rv -> PC ; \
142- rv -> csr_mtval = tval ; \
143- rv -> csr_mcause = code ; \
144133 if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
145134 rv_trap_default_handler (rv ); \
146135 return ; \
@@ -155,14 +144,14 @@ static void trap_handler(riscv_t *rv);
155144 case 1 : \
156145 /* MSB of code is used to indicate whether the trap is interrupt \
157146 * or exception, so it is not considered as the 'real' code */ \
158- rv -> PC = base + 4 * (code & MASK (31 )); \
147+ rv -> PC = base + 4 * (cause & MASK (31 )); \
159148 break ; \
160149 } \
161- IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) trap_handler (rv );, ) \
150+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) __trap_handler (rv );, ) \
162151 }
163152
164153/* RISC-V exception handlers */
165- #define _ (type , code ) TRAP_HANDLER_IMPL(type, code )
154+ #define _ (type ) TRAP_HANDLER_IMPL(type)
166155RV_TRAP_LIST
167156#undef _
168157
@@ -180,8 +169,8 @@ RV_TRAP_LIST
180169 rv->compressed = compress; \
181170 rv->csr_cycle = cycle; \
182171 rv->PC = PC; \
183- IIF(RV32_HAS(SYSTEM))(rv->is_trapped = true, ); \
184- rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
172+ SET_CAUSE_AND_TVAL_THEN_TRAP(rv, type##_MISALIGNED, \
173+ IIF(IO)(addr, mask_or_pc)); \
185174 return false; \
186175 }
187176
@@ -531,8 +520,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531520 */
532521 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533522 uint32_t addr = rv -> X [fuse [i ].rs1 ] + fuse [i ].imm ;
534- RV_EXC_MISALIGN_HANDLER (3 , store , false, 1 );
535- rv -> io .mem_write_w (addr , rv -> X [fuse [i ].rs2 ]);
523+ RV_EXC_MISALIGN_HANDLER (3 , STORE , false, 1 );
524+ rv -> io .mem_write_w (rv , addr , rv -> X [fuse [i ].rs2 ]);
536525 }
537526 PC += ir -> imm2 * 4 ;
538527 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -555,8 +544,8 @@ static bool do_fuse4(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
555544 */
556545 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557546 uint32_t addr = rv -> X [fuse [i ].rs1 ] + fuse [i ].imm ;
558- RV_EXC_MISALIGN_HANDLER (3 , load , false, 1 );
559- rv -> X [fuse [i ].rd ] = rv -> io .mem_read_w (addr );
547+ RV_EXC_MISALIGN_HANDLER (3 , LOAD , false, 1 );
548+ rv -> X [fuse [i ].rd ] = rv -> io .mem_read_w (rv , addr );
560549 }
561550 PC += ir -> imm2 * 4 ;
562551 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +655,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666655 prev_ir -> next = ir ;
667656
668657 /* fetch the next instruction */
669- const uint32_t insn = rv -> io .mem_ifetch (block -> pc_end );
658+ const uint32_t insn = rv -> io .mem_ifetch (rv , block -> pc_end );
670659
671660 /* decode the instruction */
672661 if (!rv_decode (ir , insn )) {
673662 rv -> compressed = is_compressed (insn );
674- rv_trap_illegal_insn (rv , insn );
663+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675664 break ;
676665 }
677666 ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1111,14 @@ void rv_step(void *arg)
11221111}
11231112
11241113#if RV32_HAS (SYSTEM )
1125- static void trap_handler (riscv_t * rv )
1114+ static void __trap_handler (riscv_t * rv )
11261115{
11271116 rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
11281117 assert (ir );
11291118
1130- /* set to false by sret/mret implementation */
1131- uint32_t insn ;
1119+ /* set to false by sret implementation */
11321120 while (rv -> is_trapped && !rv_has_halted (rv )) {
1133- insn = rv -> io .mem_ifetch (rv -> PC );
1121+ uint32_t insn = rv -> io .mem_ifetch (rv , rv -> PC );
11341122 assert (insn );
11351123
11361124 rv_decode (ir , insn );
@@ -1139,12 +1127,62 @@ static void trap_handler(riscv_t *rv)
11391127 ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
11401128 }
11411129}
1142- #endif
1130+ #endif /* SYSTEM */
1131+
1132+ static void _trap_handler (riscv_t * rv )
1133+ {
1134+ uint32_t cause = RV_PRIV_IS_U_OR_S_MODE () ? rv -> csr_scause : rv -> csr_mcause ;
1135+
1136+ switch (cause ) {
1137+ #if !RV32_HAS (EXT_C )
1138+ case INSN_MISALIGNED :
1139+ rv_trap_insn_misaligned (rv );
1140+ break ;
1141+ #endif /* EXT_C */
1142+ case ILLEGAL_INSN :
1143+ rv_trap_illegal_insn (rv );
1144+ break ;
1145+ case BREAKPOINT :
1146+ rv_trap_breakpoint (rv );
1147+ break ;
1148+ case LOAD_MISALIGNED :
1149+ rv_trap_load_misaligned (rv );
1150+ break ;
1151+ case STORE_MISALIGNED :
1152+ rv_trap_store_misaligned (rv );
1153+ break ;
1154+ #if RV32_HAS (SYSTEM )
1155+ case PAGEFAULT_INSN :
1156+ rv_trap_pagefault_insn (rv );
1157+ break ;
1158+ case PAGEFAULT_LOAD :
1159+ rv_trap_pagefault_load (rv );
1160+ break ;
1161+ case PAGEFAULT_STORE :
1162+ rv_trap_pagefault_store (rv );
1163+ break ;
1164+ #endif /* SYSTEM */
1165+ #if !RV32_HAS (SYSTEM )
1166+ case ECALL_M :
1167+ rv_trap_ecall_M (rv );
1168+ break ;
1169+ #endif /* SYSTEM */
1170+ default :
1171+ __UNREACHABLE ;
1172+ break ;
1173+ }
1174+ }
1175+
1176+ void trap_handler (riscv_t * rv )
1177+ {
1178+ assert (rv );
1179+ _trap_handler (rv );
1180+ }
11431181
11441182void ebreak_handler (riscv_t * rv )
11451183{
11461184 assert (rv );
1147- rv_trap_breakpoint (rv , rv -> PC );
1185+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
11481186}
11491187
11501188void ecall_handler (riscv_t * rv )
@@ -1154,7 +1192,7 @@ void ecall_handler(riscv_t *rv)
11541192 syscall_handler (rv );
11551193 rv -> PC += 4 ;
11561194#else
1157- rv_trap_ecall_M (rv , 0 );
1195+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
11581196 syscall_handler (rv );
11591197#endif
11601198}
0 commit comments