commit 823377596d6d32a2f8eb7326c21d7da6bcbba945
parent e437d30c7b412e620c272575563a12a2a9a7d868
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date: Thu, 3 Sep 2026 06:23:42 +0300
Trap handling
Diffstat:
| M | disasm.c | | | 20 | +------------------- |
| M | main.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;
}