@@ -41,130 +41,15 @@ extern struct target_ops gdbstub_ops;
4141#define IF_rs2 (i , r ) (i->rs2 == rv_reg_##r)
4242#define IF_imm (i , v ) (i->imm == v)
4343
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-
6544static void rv_trap_default_handler (riscv_t * rv )
6645{
6746 rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
6847 rv -> PC = rv -> csr_mepc ; /* mret */
6948}
7049
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- */
8250#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 _
51+ static void __trap_handler (riscv_t * rv );
52+ #endif /* RV32_HAS(SYSTEM) */
16853
16954/* wrap load/store and insn misaligned handler
17055 * @mask_or_pc: mask for load/store and pc for insn misaligned handler.
@@ -180,8 +65,8 @@ RV_TRAP_LIST
18065 rv->compressed = compress; \
18166 rv->csr_cycle = cycle; \
18267 rv->PC = PC; \
183- IIF(RV32_HAS(SYSTEM))(rv->is_trapped = true, ); \
184- rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
68+ SET_CAUSE_AND_TVAL_THEN_TRAP(rv, type##_MISALIGNED, \
69+ IIF(IO)(addr, mask_or_pc)); \
18570 return false; \
18671 }
18772
@@ -531,8 +416,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531416 */
532417 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533418 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 ]);
419+ RV_EXC_MISALIGN_HANDLER (3 , STORE , false, 1 );
420+ rv -> io .mem_write_w (rv , addr , rv -> X [fuse [i ].rs2 ]);
536421 }
537422 PC += ir -> imm2 * 4 ;
538423 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -555,8 +440,8 @@ static bool do_fuse4(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
555440 */
556441 for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557442 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 );
443+ RV_EXC_MISALIGN_HANDLER (3 , LOAD , false, 1 );
444+ rv -> X [fuse [i ].rd ] = rv -> io .mem_read_w (rv , addr );
560445 }
561446 PC += ir -> imm2 * 4 ;
562447 if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +551,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666551 prev_ir -> next = ir ;
667552
668553 /* fetch the next instruction */
669- const uint32_t insn = rv -> io .mem_ifetch (block -> pc_end );
554+ const uint32_t insn = rv -> io .mem_ifetch (rv , block -> pc_end );
670555
671556 /* decode the instruction */
672557 if (!rv_decode (ir , insn )) {
673558 rv -> compressed = is_compressed (insn );
674- rv_trap_illegal_insn (rv , insn );
559+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675560 break ;
676561 }
677562 ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1007,14 @@ void rv_step(void *arg)
11221007}
11231008
11241009#if RV32_HAS (SYSTEM )
1125- static void trap_handler (riscv_t * rv )
1010+ static void __trap_handler (riscv_t * rv )
11261011{
11271012 rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
11281013 assert (ir );
11291014
1130- /* set to false by sret/mret implementation */
1131- uint32_t insn ;
1015+ /* set to false by sret implementation */
11321016 while (rv -> is_trapped && !rv_has_halted (rv )) {
1133- insn = rv -> io .mem_ifetch (rv -> PC );
1017+ uint32_t insn = rv -> io .mem_ifetch (rv , rv -> PC );
11341018 assert (insn );
11351019
11361020 rv_decode (ir , insn );
@@ -1139,12 +1023,94 @@ static void trap_handler(riscv_t *rv)
11391023 ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
11401024 }
11411025}
1142- #endif
1026+ #endif /* RV32_HAS(SYSTEM) */
1027+
1028+ /* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
1029+ * populated with exception-specific details to assist software in managing
1030+ * the trap. Otherwise, the implementation never modifies m/stval, although
1031+ * software can explicitly write to it. The hardware platform will define
1032+ * which exceptions are required to informatively set mtval and which may
1033+ * consistently set it to zero.
1034+ *
1035+ * When a hardware breakpoint is triggered or an exception like address
1036+ * misalignment, access fault, or page fault occurs during an instruction
1037+ * fetch, load, or store operation, m/stval is updated with the virtual address
1038+ * that caused the fault. In the case of an illegal instruction trap, m/stval
1039+ * might be updated with the first XLEN or ILEN bits of the offending
1040+ * instruction. For all other traps, m/stval is simply set to zero. However,
1041+ * it is worth noting that a future standard could redefine how m/stval is
1042+ * handled for different types of traps.
1043+ *
1044+ */
1045+ static void _trap_handler (riscv_t * rv )
1046+ {
1047+ /* m/stvec (Machine/Supervisor Trap-Vector Base Address Register)
1048+ * m/stvec[MXLEN-1:2]: vector base address
1049+ * m/stvec[1:0] : vector mode
1050+ * m/sepc (Machine/Supervisor Exception Program Counter)
1051+ * m/stval (Machine/Supervisor Trap Value Register)
1052+ * m/scause (Machine/Supervisor Cause Register): store exception code
1053+ * m/sstatus (Machine/Supervisor Status Register): keep track of and
1054+ * controls the hart’s current operating state
1055+ *
1056+ * m/stval and m/scause are set in SET_CAUSE_AND_TVAL_THEN_TRAP
1057+ */
1058+ uint32_t base ;
1059+ uint32_t mode ;
1060+ uint32_t cause ;
1061+ /* user or supervisor */
1062+ if (RV_PRIV_IS_U_OR_S_MODE ()) {
1063+ const uint32_t sstatus_sie =
1064+ (rv -> csr_sstatus & SSTATUS_SIE ) >> SSTATUS_SIE_SHIFT ;
1065+ rv -> csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT );
1066+ rv -> csr_sstatus &= ~(SSTATUS_SIE );
1067+ rv -> csr_sstatus |= (rv -> priv_mode << SSTATUS_SPP_SHIFT );
1068+ rv -> priv_mode = RV_PRIV_S_MODE ;
1069+ base = rv -> csr_stvec & ~0x3 ;
1070+ mode = rv -> csr_stvec & 0x3 ;
1071+ cause = rv -> csr_scause ;
1072+ rv -> csr_sepc = rv -> PC ;
1073+ } else { /* machine */
1074+ const uint32_t mstatus_mie =
1075+ (rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ;
1076+ rv -> csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT );
1077+ rv -> csr_mstatus &= ~(MSTATUS_MIE );
1078+ rv -> csr_mstatus |= (rv -> priv_mode << MSTATUS_MPP_SHIFT );
1079+ rv -> priv_mode = RV_PRIV_M_MODE ;
1080+ base = rv -> csr_mtvec & ~0x3 ;
1081+ mode = rv -> csr_mtvec & 0x3 ;
1082+ cause = rv -> csr_mcause ;
1083+ rv -> csr_mepc = rv -> PC ;
1084+ if (!rv -> csr_mtvec ) { /* in case CSR is not configured */
1085+ rv_trap_default_handler (rv );
1086+ return ;
1087+ }
1088+ }
1089+ switch (mode ) {
1090+ /* DIRECT: All traps set PC to base */
1091+ case 0 :
1092+ rv -> PC = base ;
1093+ break ;
1094+ /* VECTORED: Asynchronous traps set PC to base + 4 * code */
1095+ case 1 :
1096+ /* MSB of code is used to indicate whether the trap is interrupt
1097+ * or exception, so it is not considered as the 'real' code */
1098+ rv -> PC = base + 4 * (cause & MASK (31 ));
1099+ break ;
1100+ }
1101+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) __trap_handler (rv );, )
1102+ }
1103+
1104+ void trap_handler (riscv_t * rv )
1105+ {
1106+ assert (rv );
1107+ _trap_handler (rv );
1108+ }
11431109
11441110void ebreak_handler (riscv_t * rv )
11451111{
11461112 assert (rv );
1147- rv_trap_breakpoint (rv , rv -> PC );
1113+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
11481114}
11491115
11501116void ecall_handler (riscv_t * rv )
@@ -1154,7 +1120,7 @@ void ecall_handler(riscv_t *rv)
11541120 syscall_handler (rv );
11551121 rv -> PC += 4 ;
11561122#else
1157- rv_trap_ecall_M (rv , 0 );
1123+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
11581124 syscall_handler (rv );
11591125#endif
11601126}
0 commit comments