rvemu

RISC-V RV32I execution engine
git clone git://mcdim.xyz/revemu.git
Log | Files | Refs

commit 823377596d6d32a2f8eb7326c21d7da6bcbba945
parent e437d30c7b412e620c272575563a12a2a9a7d868
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date:   Thu,  3 Sep 2026 06:23:42 +0300

Trap handling

Diffstat:
Mdisasm.c | 20+-------------------
Mmain.c | 146+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
2 files changed, 95 insertions(+), 71 deletions(-)

diff --git a/disasm.c b/disasm.c @@ -7,24 +7,6 @@ #include "decode.h" #include "disasm.h" -#define MEMSIZE 2052 - - -typedef struct { - uint32_t x[32]; /* general purpose registers */ - uint32_t pc; -} cpu_state_t; - -/* -static inline int32_t get_branch_target(uint32_t pc, int32_t offset) { - return (int32_t)((int64_t)pc + (int64_t)offset); -} - -static inline int32_t get_jalr_target(uint32_t base, int32_t offset) { - return (int32_t)(((int64_t)base + (int64_t)offset) & ~INT64_C(1)); -} -*/ - static void disasm_itype(uint32_t inst) { itype_t i; decode_itype(&i, inst); @@ -278,7 +260,7 @@ void disassemble_instruction(uint32_t inst) { disasm_fn fn = opcode_table[opcode]; if (!fn) { fprintf(stderr, "Illegal opcode\n"); - exit(EXIT_FAILURE); + return; } fn(inst); } diff --git a/main.c b/main.c @@ -6,13 +6,21 @@ #include "decode.h" #include "disasm.h" +#include "trap.h" #define MEMSIZE 2052 +typedef enum { + CPU_RUNNING = 0, + CPU_TRAPPED, + CPU_HALTED +} cpu_status_t; typedef struct { uint32_t x[32]; /* general purpose registers */ uint32_t pc; + trap_info_t trap; + cpu_status_t status; } cpu_state_t; static inline void print_bin16(uint16_t x) { @@ -34,42 +42,52 @@ static inline void print_binless(uint32_t x, int a) { } } -static inline int is_instruction_address_valid(int64_t addr) +static void +raise_trap(cpu_state_t *cpu, trap_cause_t trapinfo, uint32_t tval) { - if (addr < 0) - return 0; + cpu->status = CPU_TRAPPED; + cpu->trap.cause = trapinfo; + cpu->trap.pc = cpu->pc; + cpu->trap.tval = tval; + return; +} - if (addr > (int64_t)MEMSIZE-4) - return 0; +static inline trap_cause_t +validate_instruction_address(int64_t addr) +{ + if (addr < 0 || addr > (int64_t)MEMSIZE - INT64_C(4)) + return TRAP_INSTRUCTION_ACCESS_FAULT; - if ((addr & 0x3) != 0) - return 0; - - return 1; + if ((addr & INT64_C(3)) != 0) + return TRAP_INSTRUCTION_MISALIGNED; + + return TRAP_NONE; } -static int32_t get_valid_branch_target(uint32_t pc, int32_t offset, - uint32_t *target) +static trap_cause_t +get_valid_branch_target(uint32_t pc, int32_t offset, uint32_t *target) { int64_t candidate = (int64_t)pc + (int64_t)offset; - if (!is_instruction_address_valid(candidate)) - return 1; - *target = (uint32_t)candidate; + trap_cause_t valid = validate_instruction_address(candidate); + if (valid != TRAP_NONE) + return valid; - return 0; + *target = (uint32_t)candidate; + return valid; } -static int32_t get_valid_jalr_target(uint32_t base, int32_t offset, - uint32_t *target) +static trap_cause_t +get_valid_jalr_target(uint32_t base, int32_t offset, uint32_t *target) { int64_t candidate = ((int64_t)base + (int64_t)offset) & ~INT64_C(1); - if (!is_instruction_address_valid(candidate)) - return 1; - + trap_cause_t valid = validate_instruction_address(candidate); + if (valid != TRAP_NONE) + return valid; + *target = (uint32_t)candidate; - return 0; + return valid; } static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { @@ -87,7 +105,7 @@ static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { shamt = i.imm & 31; x = cpu->x[i.rs1] << shamt; } else { - fprintf(stderr, "Illegal funct7\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } break; @@ -111,7 +129,7 @@ static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = (uint32_t)((int32_t)cpu->x[i.rs1] >> shamt); break; default: - fprintf(stderr, "Illegal funct7\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } break; @@ -122,7 +140,7 @@ static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = cpu->x[i.rs1]&i.imm; break; default: - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } @@ -150,7 +168,7 @@ static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = cpu->x[r.rs1]-cpu->x[r.rs2]; break; default: - fprintf(stderr, "Illegal funct7\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } break; @@ -178,7 +196,7 @@ static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = (uint32_t)((int32_t)cpu->x[r.rs1] >> shamt); break; default: - fprintf(stderr, "Illegal funct7\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } break; @@ -189,7 +207,7 @@ static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = cpu->x[r.rs1]&cpu->x[r.rs2]; break; default: - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } @@ -235,7 +253,7 @@ static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { x = (uint32_t)(int32_t)uhalf; break; default: - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } @@ -280,7 +298,7 @@ static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { } break; default: - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } @@ -319,17 +337,17 @@ static void exec_btype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { jump = 1; break; default: - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } if (jump == 1) { uint32_t target; - if (get_valid_branch_target(cpu->pc, b.imm, &target) != 0) - { - fprintf(stderr, "Illegal branch target: pc=%" - PRIu32 ", offset=%" PRId32 "\n", - cpu->pc, b.imm); + trap_cause_t cause = get_valid_branch_target(cpu->pc, + b.imm, + &target); + if (cause != TRAP_NONE) { + raise_trap(cpu, cause, inst); return; } cpu->pc = target; @@ -346,22 +364,22 @@ static void exec_itype_jalr(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { uint32_t x; if (i.funct3 != 0x0) { - fprintf(stderr, "Illegal funct3\n"); + raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst); return; } x = cpu->pc + 4; uint32_t target; - if (get_valid_jalr_target(cpu->x[i.rs1], i.imm, &target) == 0) { - cpu->pc = target; - } else { - fprintf(stderr, "Illegal branch target: base=%" - PRIu32 ", offset=%" PRId32 "\n", - cpu->x[i.rs1], i.imm); + trap_cause_t cause = get_valid_jalr_target(cpu->x[i.rs1], i.imm, + &target); + if (cause != TRAP_NONE) { + raise_trap(cpu, cause, inst); return; } + cpu->pc = target; + if (i.rd != 0) { cpu->x[i.rd] = x; } @@ -377,15 +395,16 @@ static void exec_jtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { cpu->pc += j.imm; uint32_t target; - if (get_valid_branch_target(cpu->pc, (int32_t)j.imm, &target) == 0) { - cpu->pc = target; - } else { - fprintf(stderr, "Illegal branch target: base=%" - PRIu32 ", offset=%" PRId32 "\n", - cpu->pc, j.imm); + trap_cause_t cause = get_valid_branch_target(cpu->pc, + (int32_t)j.imm, + &target); + if (cause != TRAP_NONE) { + raise_trap(cpu, cause, inst); return; } + cpu->pc = target; + if (j.rd != 0) { cpu->x[j.rd] = x; } @@ -482,8 +501,7 @@ int main() { /* fetch & run */ while (1) { - - printf("\n>"); + printf("PC 0x%x>", cpu.pc); char line[256]; if (!fgets(line, sizeof(line), stdin)) { fprintf(stderr, "Error reading" @@ -504,8 +522,32 @@ int main() { exec_fn fn = opcode_table[opcode]; if (!fn) { - //illegal(NULL, inst); - fprintf(stderr, "Illegal opcode\n"); + raise_trap(&cpu, TRAP_ILLEGAL_INSTRUCTION, inst); + } + + if (cpu.status == CPU_TRAPPED) { + printf("CPU trapped\n"); + switch(cpu.trap.cause) { + case TRAP_BREAKPOINT: + printf("Code reached breakpoint\n"); + break; + case TRAP_ECALL: + printf("Code ECALL\n"); + break; + case TRAP_ILLEGAL_INSTRUCTION: + printf("Illegal instruction\n"); + break; + case TRAP_INSTRUCTION_MISALIGNED: + printf("Instruction misaligned\n"); + break; + case TRAP_INSTRUCTION_ACCESS_FAULT: + printf("Instruction access fault\n"); + break; + case TRAP_NONE: + printf("No trap cause\n"); + break; + + } return EXIT_FAILURE; }