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,47 +45,33 @@ 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 */
48
+ /* RISC-V trap code list */
45
49
/* 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 */ \
56
63
)
57
64
/* clang-format on */
58
65
59
- enum {
60
- #define _(type, code) rv_trap_code_##type = code,
61
- RV_TRAP_LIST
62
- #undef _
63
- };
64
-
65
66
static void rv_trap_default_handler (riscv_t * rv )
66
67
{
67
68
rv -> csr_mepc += rv -> compressed ? 2 : 4 ;
68
69
rv -> PC = rv -> csr_mepc ; /* mret */
69
70
}
70
71
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
72
#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 */
85
75
86
76
/* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
87
77
* populated with exception-specific details to assist software in managing
@@ -99,11 +89,9 @@ static void trap_handler(riscv_t *rv);
99
89
* it is worth noting that a future standard could redefine how m/stval is
100
90
* handled for different types of traps.
101
91
*
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
92
*/
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) \
107
95
{ \
108
96
/* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
109
97
* m/stvec[MXLEN-1:2]: vector base address \
@@ -113,9 +101,12 @@ static void trap_handler(riscv_t *rv);
113
101
* m/scause (Machine/Supervisor Cause Register): store exception code \
114
102
* m/sstatus (Machine/Supervisor Status Register): keep track of and \
115
103
* controls the hart’s current operating state \
104
+ * \
105
+ * m/stval and m/scause are set in SET_CAUSE_AND_TVAL_THEN_TRAP \
116
106
*/ \
117
107
uint32_t base ; \
118
108
uint32_t mode ; \
109
+ uint32_t cause ; \
119
110
/* user or supervisor */ \
120
111
if (RV_PRIV_IS_U_OR_S_MODE ()) { \
121
112
const uint32_t sstatus_sie = \
@@ -126,9 +117,8 @@ static void trap_handler(riscv_t *rv);
126
117
rv -> priv_mode = RV_PRIV_S_MODE ; \
127
118
base = rv -> csr_stvec & ~0x3 ; \
128
119
mode = rv -> csr_stvec & 0x3 ; \
120
+ cause = rv -> csr_scause ; \
129
121
rv -> csr_sepc = rv -> PC ; \
130
- rv -> csr_stval = tval ; \
131
- rv -> csr_scause = code ; \
132
122
} else { /* machine */ \
133
123
const uint32_t mstatus_mie = \
134
124
(rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ; \
@@ -138,9 +128,8 @@ static void trap_handler(riscv_t *rv);
138
128
rv -> priv_mode = RV_PRIV_M_MODE ; \
139
129
base = rv -> csr_mtvec & ~0x3 ; \
140
130
mode = rv -> csr_mtvec & 0x3 ; \
131
+ cause = rv -> csr_mcause ; \
141
132
rv -> csr_mepc = rv -> PC ; \
142
- rv -> csr_mtval = tval ; \
143
- rv -> csr_mcause = code ; \
144
133
if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
145
134
rv_trap_default_handler (rv ); \
146
135
return ; \
@@ -155,14 +144,14 @@ static void trap_handler(riscv_t *rv);
155
144
case 1 : \
156
145
/* MSB of code is used to indicate whether the trap is interrupt \
157
146
* 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 )); \
159
148
break ; \
160
149
} \
161
- IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) trap_handler (rv );, ) \
150
+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) __trap_handler (rv );, ) \
162
151
}
163
152
164
153
/* RISC-V exception handlers */
165
- #define _ (type , code ) TRAP_HANDLER_IMPL(type, code )
154
+ #define _ (type ) TRAP_HANDLER_IMPL(type)
166
155
RV_TRAP_LIST
167
156
#undef _
168
157
@@ -180,8 +169,8 @@ RV_TRAP_LIST
180
169
rv->compressed = compress; \
181
170
rv->csr_cycle = cycle; \
182
171
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)); \
185
174
return false; \
186
175
}
187
176
@@ -531,8 +520,8 @@ static bool do_fuse3(riscv_t *rv, rv_insn_t *ir, uint64_t cycle, uint32_t PC)
531
520
*/
532
521
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
533
522
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 ]);
536
525
}
537
526
PC += ir -> imm2 * 4 ;
538
527
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)
555
544
*/
556
545
for (int i = 0 ; i < ir -> imm2 ; i ++ ) {
557
546
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 );
560
549
}
561
550
PC += ir -> imm2 * 4 ;
562
551
if (unlikely (RVOP_NO_NEXT (ir ))) {
@@ -666,12 +655,12 @@ static void block_translate(riscv_t *rv, block_t *block)
666
655
prev_ir -> next = ir ;
667
656
668
657
/* 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 );
670
659
671
660
/* decode the instruction */
672
661
if (!rv_decode (ir , insn )) {
673
662
rv -> compressed = is_compressed (insn );
674
- rv_trap_illegal_insn (rv , insn );
663
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ILLEGAL_INSN , insn );
675
664
break ;
676
665
}
677
666
ir -> impl = dispatch_table [ir -> opcode ];
@@ -1122,15 +1111,14 @@ void rv_step(void *arg)
1122
1111
}
1123
1112
1124
1113
#if RV32_HAS (SYSTEM )
1125
- static void trap_handler (riscv_t * rv )
1114
+ static void __trap_handler (riscv_t * rv )
1126
1115
{
1127
1116
rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1128
1117
assert (ir );
1129
1118
1130
- /* set to false by sret/mret implementation */
1131
- uint32_t insn ;
1119
+ /* set to false by sret implementation */
1132
1120
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 );
1134
1122
assert (insn );
1135
1123
1136
1124
rv_decode (ir , insn );
@@ -1139,12 +1127,62 @@ static void trap_handler(riscv_t *rv)
1139
1127
ir -> impl (rv , ir , rv -> csr_cycle , rv -> PC );
1140
1128
}
1141
1129
}
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
+ }
1143
1181
1144
1182
void ebreak_handler (riscv_t * rv )
1145
1183
{
1146
1184
assert (rv );
1147
- rv_trap_breakpoint (rv , rv -> PC );
1185
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , BREAKPOINT , rv -> PC );
1148
1186
}
1149
1187
1150
1188
void ecall_handler (riscv_t * rv )
@@ -1154,7 +1192,7 @@ void ecall_handler(riscv_t *rv)
1154
1192
syscall_handler (rv );
1155
1193
rv -> PC += 4 ;
1156
1194
#else
1157
- rv_trap_ecall_M (rv , 0 );
1195
+ SET_CAUSE_AND_TVAL_THEN_TRAP (rv , ECALL_M , 0 );
1158
1196
syscall_handler (rv );
1159
1197
#endif
1160
1198
}
0 commit comments