14
14
#include <emscripten.h>
15
15
#endif
16
16
17
+ #if RV32_HAS (SYSTEM )
18
+ #include "system.h"
19
+ #endif /* RV32_HAS(SYSTEM) */
20
+
17
21
#if RV32_HAS (EXT_F )
18
22
#include <math.h>
19
23
#include "softfloat.h"
@@ -41,130 +45,15 @@ extern struct target_ops gdbstub_ops;
41
45
#define IF_rs2 (i , r ) (i->rs2 == rv_reg_##r)
42
46
#define IF_imm (i , v ) (i->imm == v)
43
47
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
48
static void rv_trap_default_handler (riscv_t * rv )
66
49
{
67
50
rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
68
51
rv -> PC = rv -> csr_mepc ; /* mret */
69
52
}
70
53
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
54
#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 */
168
57
169
58
/* wrap load/store and insn misaligned handler
170
59
* @mask_or_pc: mask for load/store and pc for insn misaligned handler.
@@ -180,8 +69,8 @@ RV_TRAP_LIST
180
69
rv->compressed = compress; \
181
70
rv->csr_cycle = cycle; \
182
71
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)); \
185
74
return false; \
186
75
}
187
76
@@ -531,8 +420,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531
420
*/
532
421
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533
422
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 ]);
536
425
}
537
426
PC += ir -> imm2 * 4 ;
538
427
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)
555
444
*/
556
445
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557
446
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 );
560
449
}
561
450
PC += ir -> imm2 * 4 ;
562
451
if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +555,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666
555
prev_ir -> next = ir ;
667
556
668
557
/* 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 );
670
559
671
560
/* decode the instruction */
672
561
if (!rv_decode (ir , insn )) {
673
562
rv -> compressed = is_compressed (insn );
674
- rv_trap_illegal_insn (rv , insn );
563
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675
564
break ;
676
565
}
677
566
ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1011,14 @@ void rv_step(void *arg)
1122
1011
}
1123
1012
1124
1013
#if RV32_HAS (SYSTEM )
1125
- static void trap_handler (riscv_t * rv )
1014
+ static void __trap_handler (riscv_t * rv )
1126
1015
{
1127
1016
rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1128
1017
assert (ir );
1129
1018
1130
- /* set to false by sret/mret implementation */
1131
- uint32_t insn ;
1019
+ /* set to false by sret implementation */
1132
1020
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 );
1134
1022
assert (insn );
1135
1023
1136
1024
rv_decode (ir , insn );
@@ -1139,12 +1027,94 @@ static void trap_handler(riscv_t *rv)
1139
1027
ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
1140
1028
}
1141
1029
}
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
+ }
1143
1113
1144
1114
void ebreak_handler (riscv_t * rv )
1145
1115
{
1146
1116
assert (rv );
1147
- rv_trap_breakpoint (rv , rv -> PC );
1117
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
1148
1118
}
1149
1119
1150
1120
void ecall_handler (riscv_t * rv )
@@ -1154,7 +1124,7 @@ void ecall_handler(riscv_t *rv)
1154
1124
syscall_handler (rv );
1155
1125
rv -> PC += 4 ;
1156
1126
#else
1157
- rv_trap_ecall_M (rv , 0 );
1127
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
1158
1128
syscall_handler (rv );
1159
1129
#endif
1160
1130
}
0 commit comments