@@ -41,130 +41,15 @@ extern struct target_ops gdbstub_ops;
41
41
#define IF_rs2 (i , r ) (i->rs2 == rv_reg_##r)
42
42
#define IF_imm (i , v ) (i->imm == v)
43
43
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
-
65
44
static void rv_trap_default_handler (riscv_t * rv )
66
45
{
67
46
rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
68
47
rv -> PC = rv -> csr_mepc ; /* mret */
69
48
}
70
49
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
50
#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) */
168
53
169
54
/* wrap load/store and insn misaligned handler
170
55
* @mask_or_pc: mask for load/store and pc for insn misaligned handler.
@@ -180,8 +65,8 @@ RV_TRAP_LIST
180
65
rv->compressed = compress; \
181
66
rv->csr_cycle = cycle; \
182
67
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)); \
185
70
return false; \
186
71
}
187
72
@@ -531,8 +416,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531
416
*/
532
417
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533
418
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 ]);
536
421
}
537
422
PC += ir -> imm2 * 4 ;
538
423
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)
555
440
*/
556
441
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557
442
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 );
560
445
}
561
446
PC += ir -> imm2 * 4 ;
562
447
if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +551,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666
551
prev_ir -> next = ir ;
667
552
668
553
/* 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 );
670
555
671
556
/* decode the instruction */
672
557
if (!rv_decode (ir , insn )) {
673
558
rv -> compressed = is_compressed (insn );
674
- rv_trap_illegal_insn (rv , insn );
559
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675
560
break ;
676
561
}
677
562
ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1007,14 @@ void rv_step(void *arg)
1122
1007
}
1123
1008
1124
1009
#if RV32_HAS (SYSTEM )
1125
- static void trap_handler (riscv_t * rv )
1010
+ static void __trap_handler (riscv_t * rv )
1126
1011
{
1127
1012
rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1128
1013
assert (ir );
1129
1014
1130
- /* set to false by sret/mret implementation */
1131
- uint32_t insn ;
1015
+ /* set to false by sret implementation */
1132
1016
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 );
1134
1018
assert (insn );
1135
1019
1136
1020
rv_decode (ir , insn );
@@ -1139,12 +1023,94 @@ static void trap_handler(riscv_t *rv)
1139
1023
ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
1140
1024
}
1141
1025
}
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
+ }
1143
1109
1144
1110
void ebreak_handler (riscv_t * rv )
1145
1111
{
1146
1112
assert (rv );
1147
- rv_trap_breakpoint (rv , rv -> PC );
1113
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
1148
1114
}
1149
1115
1150
1116
void ecall_handler (riscv_t * rv )
@@ -1154,7 +1120,7 @@ void ecall_handler(riscv_t *rv)
1154
1120
syscall_handler (rv );
1155
1121
rv -> PC += 4 ;
1156
1122
#else
1157
- rv_trap_ecall_M (rv , 0 );
1123
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
1158
1124
syscall_handler (rv );
1159
1125
#endif
1160
1126
}
0 commit comments