Skip to content

Commit c54dcde

Browse files
committed
Implement environment call properly
Implement ecall instruction with control and status registers (CSRs). However, there may occur the situation that the elf file doesn't contain any csr instruction. It will make pc point to wrong address. To resolve this, using 0 as the initial value of mtvec. By default, the emulator executes default exception handler when an exception occurs and mtvec stores 0.
1 parent 247aa03 commit c54dcde

File tree

5 files changed

+57
-44
lines changed

5 files changed

+57
-44
lines changed

README.md

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -84,10 +84,7 @@ Current progress of this emulator in riscv-arch-test(RV32):
8484
- `M`: Standard Extension for Integer Multiplication and Division
8585
- `C`: Standard Extension for Compressed Instruction
8686
- `Zifencei`: Instruction-Fetch Fence
87-
* Failed Tests
8887
- `privilege`: RISCV Privileged Specification
89-
+ 1 system calls
90-
* `ecall`
9188
* Unsupported tests (runnable but incomplete)
9289
- `F` Standard Extension for Single-Precision Floating-Point
9390

src/emulate.c

Lines changed: 53 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -32,53 +32,59 @@ extern struct target_ops gdbstub_ops;
3232
#include "riscv_private.h"
3333

3434
/* RISC-V exception code list */
35-
#define GET_EXCEPTION_CODE(type) rv_exception_code_##type
36-
#define RV_EXCEPTION_LIST \
37-
_(insn_misaligned) /* Instruction address misaligned */ \
38-
_(insn_fault) /* Instruction access fault */ \
39-
_(illegal_insn) /* Illegal instruction */ \
40-
_(breakpoint) /* Breakpoint */ \
41-
_(load_misaligned) /* Load address misaligned */ \
42-
_(load_fault) /* Load access fault */ \
43-
_(store_misaligned) /* Store/AMO address misaligned */
35+
#define RV_EXCEPTION_LIST \
36+
_(insn_misaligned, 0) /* Instruction address misaligned */ \
37+
_(illegal_insn, 2) /* Illegal instruction */ \
38+
_(breakpoint, 3) /* Breakpoint */ \
39+
_(load_misaligned, 4) /* Load address misaligned */ \
40+
_(store_misaligned, 6) /* Store/AMO address misaligned */ \
41+
_(ecall_M, 11) /* Environment call from M-mode */
4442

4543
enum {
46-
#define _(type) GET_EXCEPTION_CODE(type),
44+
#define _(type, code) rv_exception_code##type = code,
4745
RV_EXCEPTION_LIST
4846
#undef _
4947
};
5048

51-
#define EXCEPTION_HANDLER_IMPL(type) \
52-
UNUSED static void rv_except_##type(struct riscv_t *rv, uint32_t mtval) \
53-
{ \
54-
/* mtvec (Machine Trap-Vector Base Address Register) \
55-
* mtvec[MXLEN-1:2]: vector base address \
56-
* mtvec[1:0] : vector mode \
57-
*/ \
58-
const uint32_t base = rv->csr_mtvec & ~0x3; \
59-
const uint32_t mode = rv->csr_mtvec & 0x3; \
60-
/* Exception Code */ \
61-
const uint32_t code = GET_EXCEPTION_CODE(type); \
62-
/* mepc (Machine Exception Program Counter) \
63-
* mtval (Machine Trap Value Register) \
64-
*/ \
65-
rv->csr_mepc = rv->PC; \
66-
rv->csr_mtval = mtval; \
67-
switch (mode) { \
68-
case 0: /* DIRECT: All exceptions set PC to base */ \
69-
rv->PC = base; \
70-
break; \
71-
/* VECTORED: Asynchronous interrupts set PC to base + 4 * code */ \
72-
case 1: \
73-
rv->PC = base + 4 * code; \
74-
break; \
75-
} \
76-
/* mcause (Machine Cause Register): store exception code */ \
77-
rv->csr_mcause = code; \
49+
static void rv_exception_default_handler(struct riscv_t *rv)
50+
{
51+
rv->csr_mepc += rv->insn_len;
52+
rv->PC = rv->csr_mepc; /* mret */
53+
}
54+
55+
#define EXCEPTION_HANDLER_IMPL(type, code) \
56+
static void rv_except_##type(struct riscv_t *rv, uint32_t mtval) \
57+
{ \
58+
/* mtvec (Machine Trap-Vector Base Address Register) \
59+
* mtvec[MXLEN-1:2]: vector base address \
60+
* mtvec[1:0] : vector mode \
61+
*/ \
62+
const uint32_t base = rv->csr_mtvec & ~0x3; \
63+
const uint32_t mode = rv->csr_mtvec & 0x3; \
64+
/* mepc (Machine Exception Program Counter) \
65+
* mtval (Machine Trap Value Register) \
66+
* mcause (Machine Cause Register): store exception code \
67+
*/ \
68+
rv->csr_mepc = rv->PC; \
69+
rv->csr_mtval = mtval; \
70+
rv->csr_mcause = code; \
71+
if (!rv->csr_mtvec) { /* in case CSR is not configured */ \
72+
rv_exception_default_handler(rv); \
73+
return; \
74+
} \
75+
switch (mode) { \
76+
case 0: /* DIRECT: All exceptions set PC to base */ \
77+
rv->PC = base; \
78+
break; \
79+
/* VECTORED: Asynchronous interrupts set PC to base + 4 * code */ \
80+
case 1: \
81+
rv->PC = base + 4 * code; \
82+
break; \
83+
} \
7884
}
7985

8086
/* RISC-V exception handlers */
81-
#define _(type) EXCEPTION_HANDLER_IMPL(type)
87+
#define _(type, code) EXCEPTION_HANDLER_IMPL(type, code)
8288
RV_EXCEPTION_LIST
8389
#undef _
8490

@@ -775,7 +781,7 @@ static inline bool op_system(struct riscv_t *rv, uint32_t insn)
775781
switch (funct12) { /* dispatch from imm field */
776782
case 0: /* ECALL: Environment Call */
777783
rv->io.on_ecall(rv);
778-
break;
784+
return true;
779785
case 1: /* EBREAK: Environment Break */
780786
rv->io.on_ebreak(rv);
781787
return true;
@@ -2118,6 +2124,7 @@ void rv_reset(struct riscv_t *rv, riscv_word_t pc)
21182124
rv->X[rv_reg_sp] = DEFAULT_STACK_ADDR;
21192125

21202126
/* reset the csrs */
2127+
rv->csr_mtvec = 0;
21212128
rv->csr_cycle = 0;
21222129
rv->csr_mstatus = 0;
21232130

@@ -2141,3 +2148,10 @@ void ebreak_handler(struct riscv_t *rv)
21412148
assert(rv);
21422149
rv_except_breakpoint(rv, rv->PC);
21432150
}
2151+
2152+
void ecall_handler(struct riscv_t *rv)
2153+
{
2154+
assert(rv);
2155+
rv_except_ecall_M(rv, 0);
2156+
syscall_handler(rv);
2157+
}

src/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -199,7 +199,7 @@ int main(int argc, char **args)
199199
.mem_write_b = MEMIO(write_b),
200200

201201
/* system */
202-
.on_ecall = syscall_handler,
202+
.on_ecall = ecall_handler,
203203
.on_ebreak = ebreak_handler,
204204
};
205205

src/riscv.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ riscv_word_t rv_get_reg(struct riscv_t *, uint32_t reg);
130130
/* system call handler */
131131
void syscall_handler(struct riscv_t *rv);
132132

133+
/* environment call handler */
134+
void ecall_handler(struct riscv_t *rv);
135+
133136
/* breakpoint exception handler */
134137
void ebreak_handler(struct riscv_t *rv);
135138

src/syscall.c

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,7 +336,6 @@ void syscall_handler(struct riscv_t *rv)
336336
#undef _
337337
default:
338338
fprintf(stderr, "unknown syscall %d\n", (int) syscall);
339-
rv_halt(rv);
340339
break;
341340
}
342341
}

0 commit comments

Comments
 (0)