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,130 +45,15 @@ 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 */
45- /* 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 */ \
56- )
57- /* clang-format on */
58-
59- enum {
60- #define _(type, code) rv_trap_code_##type = code,
61- RV_TRAP_LIST
62- #undef _
63- };
64-
6548static void rv_trap_default_handler (riscv_t * rv )
6649{
6750 rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
6851 rv -> PC = rv -> csr_mepc ; /* mret */
6952}
7053
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- */
8254#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
87- * populated with exception-specific details to assist software in managing
88- * the trap. Otherwise, the implementation never modifies m/stval, although
89- * software can explicitly write to it. The hardware platform will define
90- * which exceptions are required to informatively set mtval and which may
91- * consistently set it to zero.
92- *
93- * When a hardware breakpoint is triggered or an exception like address
94- * misalignment, access fault, or page fault occurs during an instruction
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
97- * might be updated with the first XLEN or ILEN bits of the offending
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
100- * 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.
104- */
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 );, ) \
162- }
163-
164- /* RISC-V exception handlers */
165- #define _ (type , code ) TRAP_HANDLER_IMPL(type, code)
166- RV_TRAP_LIST
167- #undef _
55+ static void __trap_handler (riscv_t * rv );
56+ #endif /* SYSTEM */
16857
16958/* wrap load/store and insn misaligned handler
17059 * @mask_or_pc: mask for load/store and pc for insn misaligned handler.
@@ -180,8 +69,8 @@ RV_TRAP_LIST
18069 rv->compressed = compress; \
18170 rv->csr_cycle = cycle; \
18271 rv->PC = PC; \
183- IIF(RV32_HAS(SYSTEM))(rv->is_trapped = true, ); \
184- rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
72+ SET_CAUSE_AND_TVAL_THEN_TRAP(rv, type##_MISALIGNED, \
73+ IIF(IO)(addr, mask_or_pc)); \
18574 return false; \
18675 }
18776
@@ -531,8 +420,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531420 */
532421 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533422 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 ]);
423+ RV_EXC_MISALIGN_HANDLER (3 , STORE , false, 1 );
424+ rv -> io .mem_write_w (rv , addr , rv -> X [fuse [i ].rs2 ]);
536425 }
537426 PC += ir -> imm2 * 4 ;
538427 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -555,8 +444,8 @@ static bool do_fuse4(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
555444 */
556445 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557446 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 );
447+ RV_EXC_MISALIGN_HANDLER (3 , LOAD , false, 1 );
448+ rv -> X [fuse [i ].rd ] = rv -> io .mem_read_w (rv , addr );
560449 }
561450 PC += ir -> imm2 * 4 ;
562451 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +555,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666555 prev_ir -> next = ir ;
667556
668557 /* fetch the next instruction */
669- const uint32_t insn = rv -> io .mem_ifetch (block -> pc_end );
558+ const uint32_t insn = rv -> io .mem_ifetch (rv , block -> pc_end );
670559
671560 /* decode the instruction */
672561 if (!rv_decode (ir , insn )) {
673562 rv -> compressed = is_compressed (insn );
674- rv_trap_illegal_insn (rv , insn );
563+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675564 break ;
676565 }
677566 ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1011,14 @@ void rv_step(void *arg)
11221011}
11231012
11241013#if RV32_HAS (SYSTEM )
1125- static void trap_handler (riscv_t * rv )
1014+ static void __trap_handler (riscv_t * rv )
11261015{
11271016 rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
11281017 assert (ir );
11291018
1130- /* set to false by sret/mret implementation */
1131- uint32_t insn ;
1019+ /* set to false by sret implementation */
11321020 while (rv -> is_trapped && !rv_has_halted (rv )) {
1133- insn = rv -> io .mem_ifetch (rv -> PC );
1021+ uint32_t insn = rv -> io .mem_ifetch (rv , rv -> PC );
11341022 assert (insn );
11351023
11361024 rv_decode (ir , insn );
@@ -1139,12 +1027,94 @@ static void trap_handler(riscv_t *rv)
11391027 ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
11401028 }
11411029}
1142- #endif
1030+ #endif /* SYSTEM */
1031+
1032+ /* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
1033+ * populated with exception-specific details to assist software in managing
1034+ * the trap. Otherwise, the implementation never modifies m/stval, although
1035+ * software can explicitly write to it. The hardware platform will define
1036+ * which exceptions are required to informatively set mtval and which may
1037+ * consistently set it to zero.
1038+ *
1039+ * When a hardware breakpoint is triggered or an exception like address
1040+ * misalignment, access fault, or page fault occurs during an instruction
1041+ * fetch, load, or store operation, m/stval is updated with the virtual address
1042+ * that caused the fault. In the case of an illegal instruction trap, m/stval
1043+ * might be updated with the first XLEN or ILEN bits of the offending
1044+ * instruction. For all other traps, m/stval is simply set to zero. However,
1045+ * it is worth noting that a future standard could redefine how m/stval is
1046+ * handled for different types of traps.
1047+ *
1048+ */
1049+ static void _trap_handler (riscv_t * rv )
1050+ {
1051+ /* m/stvec (Machine/Supervisor Trap-Vector Base Address Register)
1052+ * m/stvec[MXLEN-1:2]: vector base address
1053+ * m/stvec[1:0] : vector mode
1054+ * m/sepc (Machine/Supervisor Exception Program Counter)
1055+ * m/stval (Machine/Supervisor Trap Value Register)
1056+ * m/scause (Machine/Supervisor Cause Register): store exception code
1057+ * m/sstatus (Machine/Supervisor Status Register): keep track of and
1058+ * controls the hart’s current operating state
1059+ *
1060+ * m/stval and m/scause are set in SET_CAUSE_AND_TVAL_THEN_TRAP
1061+ */
1062+ uint32_t base ;
1063+ uint32_t mode ;
1064+ uint32_t cause ;
1065+ /* user or supervisor */
1066+ if (RV_PRIV_IS_U_OR_S_MODE ()) {
1067+ const uint32_t sstatus_sie =
1068+ (rv -> csr_sstatus & SSTATUS_SIE ) >> SSTATUS_SIE_SHIFT ;
1069+ rv -> csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT );
1070+ rv -> csr_sstatus &= ~(SSTATUS_SIE );
1071+ rv -> csr_sstatus |= (rv -> priv_mode << SSTATUS_SPP_SHIFT );
1072+ rv -> priv_mode = RV_PRIV_S_MODE ;
1073+ base = rv -> csr_stvec & ~0x3 ;
1074+ mode = rv -> csr_stvec & 0x3 ;
1075+ cause = rv -> csr_scause ;
1076+ rv -> csr_sepc = rv -> PC ;
1077+ } else { /* machine */
1078+ const uint32_t mstatus_mie =
1079+ (rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ;
1080+ rv -> csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT );
1081+ rv -> csr_mstatus &= ~(MSTATUS_MIE );
1082+ rv -> csr_mstatus |= (rv -> priv_mode << MSTATUS_MPP_SHIFT );
1083+ rv -> priv_mode = RV_PRIV_M_MODE ;
1084+ base = rv -> csr_mtvec & ~0x3 ;
1085+ mode = rv -> csr_mtvec & 0x3 ;
1086+ cause = rv -> csr_mcause ;
1087+ rv -> csr_mepc = rv -> PC ;
1088+ if (!rv -> csr_mtvec ) { /* in case CSR is not configured */
1089+ rv_trap_default_handler (rv );
1090+ return ;
1091+ }
1092+ }
1093+ switch (mode ) {
1094+ /* DIRECT: All traps set PC to base */
1095+ case 0 :
1096+ rv -> PC = base ;
1097+ break ;
1098+ /* VECTORED: Asynchronous traps set PC to base + 4 * code */
1099+ case 1 :
1100+ /* MSB of code is used to indicate whether the trap is interrupt
1101+ * or exception, so it is not considered as the 'real' code */
1102+ rv -> PC = base + 4 * (cause & MASK (31 ));
1103+ break ;
1104+ }
1105+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) __trap_handler (rv );, )
1106+ }
1107+
1108+ void trap_handler (riscv_t * rv )
1109+ {
1110+ assert (rv );
1111+ _trap_handler (rv );
1112+ }
11431113
11441114void ebreak_handler (riscv_t * rv )
11451115{
11461116 assert (rv );
1147- rv_trap_breakpoint (rv , rv -> PC );
1117+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
11481118}
11491119
11501120void ecall_handler (riscv_t * rv )
@@ -1154,7 +1124,7 @@ void ecall_handler(riscv_t *rv)
11541124 syscall_handler (rv );
11551125 rv -> PC += 4 ;
11561126#else
1157- rv_trap_ecall_M (rv , 0 );
1127+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
11581128 syscall_handler (rv );
11591129#endif
11601130}
0 commit comments