4
4
*/
5
5
6
6
#include <assert.h>
7
- #include <setjmp.h>
8
7
#include <stdbool.h>
9
8
#include <stdint.h>
10
9
#include <stdio.h>
@@ -52,7 +51,9 @@ extern struct target_ops gdbstub_ops;
52
51
_(breakpoint, 3) /* Breakpoint */ \
53
52
_ (load_misaligned , 4 ) /* Load address misaligned */ \
54
53
_ (store_misaligned , 6 ) /* Store/AMO address misaligned */ \
55
- _ (ecall_M , 11 ) /* Environment call from M-mode */
54
+ IIF (RV32_HAS (SYSTEM ))(, \
55
+ _ (ecall_M , 11 ) /* Environment call from M-mode */ \
56
+ )
56
57
/* clang-format on */
57
58
58
59
enum {
@@ -67,56 +68,56 @@ static void rv_trap_default_handler(riscv_t *rv)
67
68
rv -> PC = rv -> csr_mepc ; /* mret */
68
69
}
69
70
70
- /* Trap might occurs during block emulation. For instance, page fault.
71
+ /*
72
+ * Trap might occurs during block emulation. For instance, page fault.
71
73
* In order to handle trap, we have to escape from block and execute
72
74
* registered trap handler. This trap_handler function helps to execute
73
75
* the registered trap handler, PC by PC. Once the trap is handled,
74
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.
75
81
*/
76
82
#if RV32_HAS (SYSTEM )
77
83
static void trap_handler (riscv_t * rv );
78
- #else
79
- /* should not be called in non-SYSTEM mode since default trap handler is capable
80
- * to handle traps
81
- */
82
- static void trap_handler (riscv_t * rv UNUSED ) {}
83
84
#endif
84
85
85
- /* When a trap occurs in M-mode, mtval is either initialized to zero or
86
+ /* When a trap occurs in M-mode/S-mode, m/stval is either initialized to zero or
86
87
* populated with exception-specific details to assist software in managing
87
- * the trap. Otherwise, the implementation never modifies mtval , although
88
+ * the trap. Otherwise, the implementation never modifies m/stval , although
88
89
* software can explicitly write to it. The hardware platform will define
89
90
* which exceptions are required to informatively set mtval and which may
90
91
* consistently set it to zero.
91
92
*
92
93
* When a hardware breakpoint is triggered or an exception like address
93
94
* misalignment, access fault, or page fault occurs during an instruction
94
- * fetch, load, or store operation, mtval is updated with the virtual address
95
- * that caused the fault. In the case of an illegal instruction trap, mtval
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
96
97
* might be updated with the first XLEN or ILEN bits of the offending
97
- * instruction. For all other traps, mtval is simply set to zero. However,
98
- * it is worth noting that a future standard could redefine how mtval is
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
99
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.
100
104
*/
101
- static jmp_buf env ;
102
105
#define TRAP_HANDLER_IMPL (type , code ) \
103
- static void rv_trap_##type(riscv_t *rv, uint32_t mtval) \
106
+ static void rv_trap_##type(riscv_t *rv, uint32_t tval) \
104
107
{ \
105
108
/* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
106
109
* m/stvec[MXLEN-1:2]: vector base address \
107
110
* m/stvec[1:0] : vector mode \
108
- */ \
109
- uint32_t base ; \
110
- uint32_t mode ; \
111
- /* m/sepc (Machine/Supervisor Exception Program Counter) \
111
+ * m/sepc (Machine/Supervisor Exception Program Counter) \
112
112
* m/stval (Machine/Supervisor Trap Value Register) \
113
113
* m/scause (Machine/Supervisor Cause Register): store exception code \
114
114
* m/sstatus (Machine/Supervisor Status Register): keep track of and \
115
115
* controls the hart’s current operating state \
116
116
*/ \
117
- /* supervisor */ \
118
- if (rv -> csr_medeleg & (1U << code ) || \
119
- rv -> csr_mideleg & (1U << code )) { \
117
+ uint32_t base ; \
118
+ uint32_t mode ; \
119
+ /* user or supervisor */ \
120
+ if (RV_PRIV_IS_U_OR_S_MODE ()) { \
120
121
const uint32_t sstatus_sie = \
121
122
(rv -> csr_sstatus & SSTATUS_SIE ) >> SSTATUS_SIE_SHIFT ; \
122
123
rv -> csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT ); \
@@ -126,10 +127,9 @@ static jmp_buf env;
126
127
base = rv -> csr_stvec & ~0x3 ; \
127
128
mode = rv -> csr_stvec & 0x3 ; \
128
129
rv -> csr_sepc = rv -> PC ; \
129
- rv -> csr_stval = mtval ; \
130
+ rv -> csr_stval = tval ; \
130
131
rv -> csr_scause = code ; \
131
- rv -> csr_sstatus |= SSTATUS_SPP ; /* set privilege mode */ \
132
- } else { /* machine */ \
132
+ } else { /* machine */ \
133
133
const uint32_t mstatus_mie = \
134
134
(rv -> csr_mstatus & MSTATUS_MIE ) >> MSTATUS_MIE_SHIFT ; \
135
135
rv -> csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT ); \
@@ -139,9 +139,8 @@ static jmp_buf env;
139
139
base = rv -> csr_mtvec & ~0x3 ; \
140
140
mode = rv -> csr_mtvec & 0x3 ; \
141
141
rv -> csr_mepc = rv -> PC ; \
142
- rv -> csr_mtval = mtval ; \
142
+ rv -> csr_mtval = tval ; \
143
143
rv -> csr_mcause = code ; \
144
- rv -> csr_mstatus |= MSTATUS_MPP ; /* set privilege mode */ \
145
144
if (!rv -> csr_mtvec ) { /* in case CSR is not configured */ \
146
145
rv_trap_default_handler (rv ); \
147
146
return ; \
@@ -159,14 +158,7 @@ static jmp_buf env;
159
158
rv -> PC = base + 4 * (code & MASK (31 )); \
160
159
break ; \
161
160
} \
162
- /* block escaping for trap handling */ \
163
- if (rv -> is_trapped ) { \
164
- if (setjmp (env ) == 0 ) { \
165
- trap_handler (rv ); \
166
- } else { \
167
- fprintf (stderr , "setjmp failed" ); \
168
- } \
169
- } \
161
+ IIF (RV32_HAS (SYSTEM ))(if (rv -> is_trapped ) trap_handler (rv );, ) \
170
162
}
171
163
172
164
/* RISC-V exception handlers */
@@ -188,7 +180,7 @@ RV_TRAP_LIST
188
180
rv->compressed = compress; \
189
181
rv->csr_cycle = cycle; \
190
182
rv->PC = PC; \
191
- rv->is_trapped = true; \
183
+ IIF(RV32_HAS(SYSTEM))( rv->is_trapped = true, ); \
192
184
rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
193
185
return false; \
194
186
}
@@ -455,9 +447,10 @@ enum {
455
447
};
456
448
457
449
#if RV32_HAS (GDBSTUB )
458
- #define RVOP_NO_NEXT (ir ) (!ir->next | rv->debug_mode | rv->is_trapped)
450
+ #define RVOP_NO_NEXT (ir ) \
451
+ (!ir->next | rv->debug_mode IIF(RV32_HAS(SYSTEM))(| rv->is_trapped, ))
459
452
#else
460
- #define RVOP_NO_NEXT (ir ) (!ir->next | rv->is_trapped)
453
+ #define RVOP_NO_NEXT (ir ) (!ir->next IIF(RV32_HAS(SYSTEM))( | rv->is_trapped, ) )
461
454
#endif
462
455
463
456
/* record whether the branch is taken or not during emulation */
@@ -643,8 +636,10 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)
643
636
case rv_insn_ebreak :
644
637
case rv_insn_jal :
645
638
case rv_insn_jalr :
646
- case rv_insn_sret :
647
639
case rv_insn_mret :
640
+ #if RV32_HAS (SYSTEM )
641
+ case rv_insn_sret :
642
+ #endif
648
643
#if RV32_HAS (EXT_C )
649
644
case rv_insn_cj :
650
645
case rv_insn_cjalr :
@@ -1132,9 +1127,12 @@ static void trap_handler(riscv_t *rv)
1132
1127
rv_insn_t * ir = mpool_alloc (rv -> block_ir_mp );
1133
1128
assert (ir );
1134
1129
1130
+ /* set to false by sret/mret implementation */
1135
1131
uint32_t insn ;
1136
- while (rv -> is_trapped ) { /* set to false by sret/mret implementation */
1137
- insn = rv -> io .mem_ifetch (rv , rv -> PC );
1132
+ while (rv -> is_trapped && !rv_has_halted (rv )) {
1133
+ insn = rv -> io .mem_ifetch (rv -> PC );
1134
+ assert (insn );
1135
+
1138
1136
rv_decode (ir , insn );
1139
1137
ir -> impl = dispatch_table [ir -> opcode ];
1140
1138
rv -> compressed = is_compressed (insn );
@@ -1152,8 +1150,13 @@ void ebreak_handler(riscv_t *rv)
1152
1150
void ecall_handler (riscv_t * rv )
1153
1151
{
1154
1152
assert (rv );
1153
+ #if RV32_HAS (SYSTEM )
1154
+ syscall_handler (rv );
1155
+ rv -> PC += 4 ;
1156
+ #else
1155
1157
rv_trap_ecall_M (rv , 0 );
1156
1158
syscall_handler (rv );
1159
+ #endif
1157
1160
}
1158
1161
1159
1162
void memset_handler (riscv_t * rv )
0 commit comments