Skip to content

Commit 9509721

Browse files
committed
Multiple changes
- Eliminate the delegation logic from TRAP_HANDLER_IMPL because we do not rely on M-mode software, such as OpenSBI for system emulation. - Apply conditional checks for SYSTEM in various locations as necessary. - Disable LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE when handling traps with the trap_handler, as the trap_handler code is not chained as a block, and the trap should be handled PC by PC. - Refine some comments
1 parent cb419d4 commit 9509721

File tree

13 files changed

+121
-84
lines changed

13 files changed

+121
-84
lines changed

Makefile

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ CFLAGS = -std=gnu99 -O2 -Wall -Wextra
1111
CFLAGS += -Wno-unused-label
1212
CFLAGS += -include src/common.h
1313

14+
ENABLE_SYSTEM ?= 0
15+
$(call set-feature, SYSTEM)
16+
1417
# Enable link-time optimization (LTO)
1518
ENABLE_LTO ?= 1
1619
ifeq ($(call has, LTO), 1)
@@ -134,7 +137,7 @@ endif
134137
ENABLE_JIT ?= 0
135138
$(call set-feature, JIT)
136139
ifeq ($(call has, JIT), 1)
137-
OBJS_EXT += jit.o
140+
OBJS_EXT += jit.o
138141
# tier-2 JIT compiler powered LLVM
139142
LLVM_CONFIG = llvm-config-17
140143
LLVM_CONFIG := $(shell which $(LLVM_CONFIG))

src/decode.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -841,9 +841,11 @@ static inline bool op_system(rv_insn_t *ir, const uint32_t insn)
841841
case 0x202: /* HRET: return from traps in H-mode */
842842
/* illegal instruction */
843843
return false;
844+
#if RV32_HAS(SYSTEM)
844845
case 0x102: /* SRET: return from traps in S-mode */
845846
ir->opcode = rv_insn_sret;
846847
break;
848+
#endif
847849
case 0x302: /* MRET */
848850
ir->opcode = rv_insn_mret;
849851
break;

src/decode.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,9 @@ enum op_field {
7878
/* RISC-V Privileged Instruction */ \
7979
_(wfi, 0, 4, 0, ENC(rs1, rd)) \
8080
_(uret, 0, 4, 0, ENC(rs1, rd)) \
81-
_(sret, 1, 4, 0, ENC(rs1, rd)) \
81+
IIF(RV32_HAS(SYSTEM))( \
82+
_(sret, 1, 4, 0, ENC(rs1, rd)) \
83+
) \
8284
_(hret, 0, 4, 0, ENC(rs1, rd)) \
8385
_(mret, 1, 4, 0, ENC(rs1, rd)) \
8486
_(sfencevma, 1, 4, 0, ENC(rs1, rs2, rd)) \

src/emulate.c

Lines changed: 45 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55

66
#include <assert.h>
7-
#include <setjmp.h>
87
#include <stdbool.h>
98
#include <stdint.h>
109
#include <stdio.h>
@@ -52,7 +51,9 @@ extern struct target_ops gdbstub_ops;
5251
_(breakpoint, 3) /* Breakpoint */ \
5352
_(load_misaligned, 4) /* Load address misaligned */ \
5453
_(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+
)
5657
/* clang-format on */
5758

5859
enum {
@@ -67,56 +68,56 @@ static void rv_trap_default_handler(riscv_t *rv)
6768
rv->PC = rv->csr_mepc; /* mret */
6869
}
6970

70-
/* Trap might occurs during block emulation. For instance, page fault.
71+
/*
72+
* Trap might occurs during block emulation. For instance, page fault.
7173
* In order to handle trap, we have to escape from block and execute
7274
* registered trap handler. This trap_handler function helps to execute
7375
* the registered trap handler, PC by PC. Once the trap is handled,
7476
* 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.
7581
*/
7682
#if RV32_HAS(SYSTEM)
7783
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) {}
8384
#endif
8485

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
8687
* 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
8889
* software can explicitly write to it. The hardware platform will define
8990
* which exceptions are required to informatively set mtval and which may
9091
* consistently set it to zero.
9192
*
9293
* When a hardware breakpoint is triggered or an exception like address
9394
* 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
9697
* 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
99100
* 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.
100104
*/
101-
static jmp_buf env;
102105
#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) \
104107
{ \
105108
/* m/stvec (Machine/Supervisor Trap-Vector Base Address Register) \
106109
* m/stvec[MXLEN-1:2]: vector base address \
107110
* 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) \
112112
* m/stval (Machine/Supervisor Trap Value Register) \
113113
* m/scause (Machine/Supervisor Cause Register): store exception code \
114114
* m/sstatus (Machine/Supervisor Status Register): keep track of and \
115115
* controls the hart’s current operating state \
116116
*/ \
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()) { \
120121
const uint32_t sstatus_sie = \
121122
(rv->csr_sstatus & SSTATUS_SIE) >> SSTATUS_SIE_SHIFT; \
122123
rv->csr_sstatus |= (sstatus_sie << SSTATUS_SPIE_SHIFT); \
@@ -126,10 +127,9 @@ static jmp_buf env;
126127
base = rv->csr_stvec & ~0x3; \
127128
mode = rv->csr_stvec & 0x3; \
128129
rv->csr_sepc = rv->PC; \
129-
rv->csr_stval = mtval; \
130+
rv->csr_stval = tval; \
130131
rv->csr_scause = code; \
131-
rv->csr_sstatus |= SSTATUS_SPP; /* set privilege mode */ \
132-
} else { /* machine */ \
132+
} else { /* machine */ \
133133
const uint32_t mstatus_mie = \
134134
(rv->csr_mstatus & MSTATUS_MIE) >> MSTATUS_MIE_SHIFT; \
135135
rv->csr_mstatus |= (mstatus_mie << MSTATUS_MPIE_SHIFT); \
@@ -139,9 +139,8 @@ static jmp_buf env;
139139
base = rv->csr_mtvec & ~0x3; \
140140
mode = rv->csr_mtvec & 0x3; \
141141
rv->csr_mepc = rv->PC; \
142-
rv->csr_mtval = mtval; \
142+
rv->csr_mtval = tval; \
143143
rv->csr_mcause = code; \
144-
rv->csr_mstatus |= MSTATUS_MPP; /* set privilege mode */ \
145144
if (!rv->csr_mtvec) { /* in case CSR is not configured */ \
146145
rv_trap_default_handler(rv); \
147146
return; \
@@ -159,14 +158,7 @@ static jmp_buf env;
159158
rv->PC = base + 4 * (code & MASK(31)); \
160159
break; \
161160
} \
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);, ) \
170162
}
171163

172164
/* RISC-V exception handlers */
@@ -188,7 +180,7 @@ RV_TRAP_LIST
188180
rv->compressed = compress; \
189181
rv->csr_cycle = cycle; \
190182
rv->PC = PC; \
191-
rv->is_trapped = true; \
183+
IIF(RV32_HAS(SYSTEM))(rv->is_trapped = true, ); \
192184
rv_trap_##type##_misaligned(rv, IIF(IO)(addr, mask_or_pc)); \
193185
return false; \
194186
}
@@ -455,9 +447,10 @@ enum {
455447
};
456448

457449
#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, ))
459452
#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, ))
461454
#endif
462455

463456
/* record whether the branch is taken or not during emulation */
@@ -643,8 +636,10 @@ FORCE_INLINE bool insn_is_unconditional_branch(uint8_t opcode)
643636
case rv_insn_ebreak:
644637
case rv_insn_jal:
645638
case rv_insn_jalr:
646-
case rv_insn_sret:
647639
case rv_insn_mret:
640+
#if RV32_HAS(SYSTEM)
641+
case rv_insn_sret:
642+
#endif
648643
#if RV32_HAS(EXT_C)
649644
case rv_insn_cj:
650645
case rv_insn_cjalr:
@@ -1132,9 +1127,12 @@ static void trap_handler(riscv_t *rv)
11321127
rv_insn_t *ir = mpool_alloc(rv->block_ir_mp);
11331128
assert(ir);
11341129

1130+
/* set to false by sret/mret implementation */
11351131
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+
11381136
rv_decode(ir, insn);
11391137
ir->impl = dispatch_table[ir->opcode];
11401138
rv->compressed = is_compressed(insn);
@@ -1152,8 +1150,13 @@ void ebreak_handler(riscv_t *rv)
11521150
void ecall_handler(riscv_t *rv)
11531151
{
11541152
assert(rv);
1153+
#if RV32_HAS(SYSTEM)
1154+
syscall_handler(rv);
1155+
rv->PC += 4;
1156+
#else
11551157
rv_trap_ecall_M(rv, 0);
11561158
syscall_handler(rv);
1159+
#endif
11571160
}
11581161

11591162
void memset_handler(riscv_t *rv)

src/riscv.c

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,6 @@ riscv_t *rv_create(riscv_user_t rv_attr)
221221
attr->mem = memory_new(attr->mem_size);
222222
assert(attr->mem);
223223

224-
/* not being trapped */
225-
rv->is_trapped = false;
226-
227224
/* reset */
228225
rv_reset(rv, 0U);
229226

@@ -306,6 +303,20 @@ riscv_t *rv_create(riscv_user_t rv_attr)
306303
#endif
307304
#endif
308305

306+
#if RV32_HAS(SYSTEM)
307+
/*
308+
* System simulation defaults to S-mode as
309+
* it does not rely on M-mode software like OpenSBI.
310+
*/
311+
rv->priv_mode = RV_PRIV_S_MODE;
312+
313+
/* not being trapped */
314+
rv->is_trapped = false;
315+
#else
316+
/* ISA simulation defaults to M-mode */
317+
rv->priv_mode = RV_PRIV_M_MODE;
318+
#endif
319+
309320
return rv;
310321
}
311322

src/riscv.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,7 @@ enum {
125125
#define MSTATUS_TW (1 << MSTATUS_TW_SHIFT)
126126
#define MSTATUS_TSR (1 << MSTATUS_TSR_SHIFT)
127127

128-
/* A restricted view of mstatus */
128+
/* sstatus, a restricted view of mstatus */
129129
#define SSTATUS_SIE_SHIFT 1
130130
#define SSTATUS_SPIE_SHIFT 5
131131
#define SSTATUS_UBE_SHIFT 6
@@ -149,6 +149,7 @@ enum {
149149
#define RV_PRIV_U_MODE 0
150150
#define RV_PRIV_S_MODE 1
151151
#define RV_PRIV_M_MODE 3
152+
#define RV_PRIV_IS_U_OR_S_MODE() (rv->priv_mode <= RV_PRIV_S_MODE)
152153

153154
/*
154155
* SBI functions must return a pair of values:

src/riscv_private.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -204,8 +204,10 @@ struct riscv_internal {
204204
bool is_interrupted;
205205
#endif
206206

207-
/* The flag to indicate the current emulation is in a trap */
207+
#if RV32_HAS(SYSTEM)
208+
/* The flag is used to indicate the current emulation is in a trap */
208209
bool is_trapped;
210+
#endif
209211
};
210212

211213
/* sign extend a 16 bit value */

src/rv32_constopt.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -374,8 +374,10 @@ CONSTOPT(wfi, {})
374374
/* URET: return from traps in U-mode */
375375
CONSTOPT(uret, {})
376376

377+
#if RV32_HAS(SYSTEM)
377378
/* SRET: return from traps in S-mode */
378379
CONSTOPT(sret, {})
380+
#endif
379381

380382
/* HRET: return from traps in H-mode */
381383
CONSTOPT(hret, {})

src/rv32_template.c

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -199,19 +199,24 @@ RVOP(
199199
#if !RV32_HAS(JIT)
200200
#define LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE() \
201201
/* lookup branch history table */ \
202-
for (int i = 0; i < HISTORY_SIZE; i++) { \
203-
if (ir->branch_table->PC[i] == PC) { \
204-
MUST_TAIL return ir->branch_table->target[i]->impl( \
205-
rv, ir->branch_table->target[i], cycle, PC); \
202+
IIF(RV32_HAS(SYSTEM)(if (!rv->is_trapped), )) \
203+
{ \
204+
for (int i = 0; i < HISTORY_SIZE; i++) { \
205+
if (ir->branch_table->PC[i] == PC) { \
206+
MUST_TAIL return ir->branch_table->target[i]->impl( \
207+
rv, ir->branch_table->target[i], cycle, PC); \
208+
} \
209+
} \
210+
block_t *block = block_find(&rv->block_map, PC); \
211+
if (block) { \
212+
/* update branch history table */ \
213+
ir->branch_table->PC[ir->branch_table->idx] = PC; \
214+
ir->branch_table->target[ir->branch_table->idx] = block->ir_head; \
215+
ir->branch_table->idx = \
216+
(ir->branch_table->idx + 1) % HISTORY_SIZE; \
217+
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, \
218+
PC); \
206219
} \
207-
} \
208-
block_t *block = block_find(&rv->block_map, PC); \
209-
if (block) { \
210-
/* update branch history table */ \
211-
ir->branch_table->PC[ir->branch_table->idx] = PC; \
212-
ir->branch_table->target[ir->branch_table->idx] = block->ir_head; \
213-
ir->branch_table->idx = (ir->branch_table->idx + 1) % HISTORY_SIZE; \
214-
MUST_TAIL return block->ir_head->impl(rv, block->ir_head, cycle, PC); \
215220
}
216221
#else
217222
#define LOOKUP_OR_UPDATE_BRANCH_HISTORY_TABLE() \
@@ -1004,12 +1009,13 @@ RVOP(
10041009
}))
10051010

10061011
/* SRET: return from traps in S-mode */
1012+
#if RV32_HAS(SYSTEM)
10071013
RVOP(
10081014
sret,
10091015
{
10101016
rv->is_trapped = false;
1011-
rv->priv_mode = (rv->csr_sstatus & MSTATUS_SPP) >> MSTATUS_SPP_SHIFT;
1012-
rv->csr_sstatus &= ~(MSTATUS_SPP);
1017+
rv->priv_mode = (rv->csr_sstatus & SSTATUS_SPP) >> SSTATUS_SPP_SHIFT;
1018+
rv->csr_sstatus &= ~(SSTATUS_SPP);
10131019

10141020
const uint32_t sstatus_spie =
10151021
(rv->csr_sstatus & SSTATUS_SPIE) >> SSTATUS_SPIE_SHIFT;
@@ -1022,6 +1028,7 @@ RVOP(
10221028
GEN({
10231029
assert; /* FIXME: Implement */
10241030
}))
1031+
#endif
10251032

10261033
/* HRET: return from traps in H-mode */
10271034
RVOP(
@@ -1038,7 +1045,6 @@ RVOP(
10381045
RVOP(
10391046
mret,
10401047
{
1041-
rv->is_trapped = false;
10421048
rv->priv_mode = (rv->csr_mstatus & MSTATUS_MPP) >> MSTATUS_MPP_SHIFT;
10431049
rv->csr_mstatus &= ~(MSTATUS_MPP);
10441050

src/t2c.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -159,8 +159,10 @@ FORCE_INLINE bool t2c_insn_is_terminal(uint8_t opcode)
159159
case rv_insn_ecall:
160160
case rv_insn_ebreak:
161161
case rv_insn_jalr:
162-
case rv_insn_sret:
163162
case rv_insn_mret:
163+
#if RV32_HAS(SYSTEM)
164+
case rv_insn_sret:
165+
#endif
164166
#if RV32_HAS(EXT_C)
165167
case rv_insn_cjalr:
166168
case rv_insn_cjr:

0 commit comments

Comments
 (0)