rvemu

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

commit feb123c9c5c8b0cdcee6cb11bcf14344a44adf98
parent 2960ee19a669a70430c0ccdb7b21ec3b2f4f5729
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date:   Sat,  5 Sep 2026 23:09:56 +0300

Added store/load checks and traps

Diffstat:
Mexec.c | 63+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----
Mexec.h | 2+-
Mmain.c | 12++++++++++++
Mtrap.h | 2--
4 files changed, 72 insertions(+), 7 deletions(-)

diff --git a/exec.c b/exec.c @@ -216,13 +216,38 @@ static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { uint32_t x; switch(i.funct3) { case 0x0: + if (addr > MEMSIZE - 1) { + raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); + return; + } + x = (uint32_t)(int32_t)(int8_t)mem[addr]; break; case 0x1: + if ((addr & UINT32_C(0x1)) != 0) { + raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); + return; + } + + if (addr + 1 > MEMSIZE - 1) { + raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); + return; + } + uint16_t half = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8); x = (uint32_t)(int32_t)(int16_t)half; break; case 0x2: + if ((addr & UINT32_C(0x3)) != 0) { + raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); + return; + } + + if (addr + 3 > MEMSIZE - 1) { + raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); + return; + } + /* TODO: clean up */ x = (uint32_t)(int32_t)( ((uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8)) @@ -232,9 +257,24 @@ static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { ); break; case 0x4: + if (addr > MEMSIZE - 1) { + raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); + return; + } + x = (uint32_t)(uint8_t)mem[addr]; break; case 0x5: + if ((addr & UINT32_C(0x1)) != 0) { + raise_trap(cpu, TRAP_LOAD_MISALIGNED, inst); + return; + } + + if (addr + 1 > MEMSIZE - 1) { + raise_trap(cpu, TRAP_LOAD_ACCESS_FAULT, inst); + return; + } + uint16_t uhalf = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8); x = (uint32_t)uhalf; break; @@ -258,11 +298,21 @@ static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { /* TODO: helpers, better checks */ switch(s.funct3) { case 0x0: + if (addr > MEMSIZE - 1) { + raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); + return; + } + mem[addr] = cpu->x[s.rs2] & 255; break; case 0x1: - if (addr+1 > MEMSIZE-1) { - fprintf(stderr, "Illegal addr\n"); + if ((addr & UINT32_C(0x1)) != 0) { + raise_trap(cpu, TRAP_STORE_MISALIGNED, inst); + return; + } + + if (addr + 1 > MEMSIZE - 1) { + raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); return; } @@ -272,8 +322,13 @@ static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) { } break; case 0x2: - if (addr+3 > MEMSIZE-1) { - fprintf(stderr, "Illegal addr\n"); + if ((addr & UINT32_C(0x3)) != 0) { + raise_trap(cpu, TRAP_STORE_MISALIGNED, inst); + return; + } + + if (addr + 3 > MEMSIZE - 1) { + raise_trap(cpu, TRAP_STORE_ACCESS_FAULT, inst); return; } if (addr % 4 == 0) { diff --git a/exec.h b/exec.h @@ -3,7 +3,7 @@ #include "trap.h" -#define MEMSIZE 4128 +#define MEMSIZE 4096 typedef enum { CPU_RUNNING = 0, diff --git a/main.c b/main.c @@ -75,6 +75,18 @@ trap_handler(cpu_state_t *cpu) case TRAP_INSTRUCTION_ACCESS_FAULT: printf("Instruction access fault\n"); break; + case TRAP_LOAD_MISALIGNED: + printf("Load misaligned\n"); + break; + case TRAP_LOAD_ACCESS_FAULT: + printf("Load access fault\n"); + break; + case TRAP_STORE_MISALIGNED: + printf("Store misaligned\n"); + break; + case TRAP_STORE_ACCESS_FAULT: + printf("Store access fault\n"); + break; case TRAP_NONE: printf("No trap cause\n"); break; diff --git a/trap.h b/trap.h @@ -8,12 +8,10 @@ typedef enum { TRAP_ILLEGAL_INSTRUCTION, TRAP_INSTRUCTION_MISALIGNED, TRAP_INSTRUCTION_ACCESS_FAULT, -/* TRAP_LOAD_MISALIGNED, TRAP_LOAD_ACCESS_FAULT, TRAP_STORE_MISALIGNED, TRAP_STORE_ACCESS_FAULT -*/ } trap_cause_t; typedef struct {