commit 2cc43400b091dc7d16b7d8880ba4e2d47f2702ad
parent 4e256a9cea6be3e08d06d1c63ab90e9cd4dd1824
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date: Fri, 4 Sep 2026 18:04:00 +0300
Separated execution from driver
Diffstat:
| M | Makefile | | | 2 | +- |
| M | disasm.c | | | 4 | ++-- |
| A | exec.c | | | 512 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
| A | exec.h | | | 23 | +++++++++++++++++++++++ |
| M | main.c | | | 667 | ++++++++++++------------------------------------------------------------------- |
5 files changed, 635 insertions(+), 573 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,5 +1,5 @@
all:
- gcc -g main.c disasm.c \
+ gcc -g main.c exec.c disasm.c \
-Wall -Wextra -Wpedantic \
-Wconversion -Wsign-conversion \
-Wshadow -Wstrict-prototypes \
diff --git a/disasm.c b/disasm.c
@@ -138,7 +138,7 @@ static void disasm_itype_loads(uint32_t inst) {
return;
}
- printf(" x%" PRIu32 ", %" PRId32 "(x%" PRIu32 ")",
+ printf(" x%" PRIu32 ", %" PRId32 "(x%" PRIu32 ")\n",
i.rd, i.imm, i.rs1);
}
@@ -161,7 +161,7 @@ static void disasm_stype(uint32_t inst) {
return;
}
- printf(" x%" PRIu32 ", %" PRId32 "(x%" PRIu32 ")",
+ printf(" x%" PRIu32 ", %" PRId32 "(x%" PRIu32 ")\n",
s.rs2, (int32_t)(int16_t)s.imm, s.rs1);
}
diff --git a/exec.c b/exec.c
@@ -0,0 +1,512 @@
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "exec.h"
+#include "decode.h"
+#include "disasm.h"
+#include "trap.h"
+
+
+static inline void print_bin16(uint16_t x) {
+ for (int i = 15; i >= 0; i--) {
+ putchar((x >> i) & 1 ? '1' : '0');
+ /*if (i % 4 == 0) putchar(' '); grouping */
+ }
+}
+
+static inline void print_bin32(uint32_t x) {
+ for (int i = 31; i >= 0; i--) {
+ putchar((x >> i) & 1 ? '1' : '0');
+ }
+}
+
+static inline void print_binless(uint32_t x, int a) {
+ for (int i = a-1; i >= 0; i--) {
+ putchar((x >> i) & 1 ? '1' : '0');
+ }
+}
+
+static void
+raise_trap(cpu_state_t *cpu, trap_cause_t trapinfo, uint32_t tval)
+{
+ cpu->status = CPU_TRAPPED;
+ cpu->trap.cause = trapinfo;
+ cpu->trap.pc = cpu->pc;
+ cpu->trap.tval = tval;
+ return;
+}
+
+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 & INT64_C(3)) != 0)
+ return TRAP_INSTRUCTION_MISALIGNED;
+
+ return TRAP_NONE;
+}
+
+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;
+
+ trap_cause_t valid = validate_instruction_address(candidate);
+ if (valid != TRAP_NONE)
+ return valid;
+
+ *target = (uint32_t)candidate;
+ return valid;
+}
+
+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);
+ trap_cause_t valid = validate_instruction_address(candidate);
+ if (valid != TRAP_NONE)
+ return valid;
+
+ *target = (uint32_t)candidate;
+ return valid;
+}
+
+static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ (void)mem; /* suppressing unused parameters warning */
+ itype_t i;
+ decode_itype(&i, inst);
+
+ uint32_t x; uint32_t shamt;
+ uint32_t uimm = (uint32_t)i.imm;
+ switch(i.funct3) {
+ case 0x0:
+ x = cpu->x[i.rs1]+uimm;
+ break;
+ case 0x1:
+ if (i.funct7 == 0x00) {
+ shamt = i.imm & 31;
+ x = cpu->x[i.rs1] << shamt;
+ } else {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+ break;
+ case 0x2:
+ x = ((int32_t)cpu->x[i.rs1] < (int32_t)i.imm) ? 1 : 0;
+ break;
+ case 0x3:
+ x = (cpu->x[i.rs1] < uimm) ? 1 : 0;
+ break;
+ case 0x4:
+ x = cpu->x[i.rs1]^uimm;
+ break;
+ case 0x5:
+ shamt = i.imm & 31;
+ switch(i.funct7) {
+ case 0x00:
+ x = cpu->x[i.rs1] >> shamt;
+ break;
+ case 0x20:
+ x = (uint32_t)((int32_t)cpu->x[i.rs1] >> shamt);
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+ break;
+ case 0x6:
+ x = cpu->x[i.rs1]|uimm;
+ break;
+ case 0x7:
+ x = cpu->x[i.rs1]&uimm;
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ if (i.rd != 0) {
+ cpu->x[i.rd] = x;
+ }
+
+ cpu->pc += 4;
+}
+
+static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ (void)mem; /* suppressing unused parameters warning */
+ rtype_t r;
+ decode_rtype(&r, inst);
+
+ uint32_t x;
+ uint32_t shamt;
+ switch(r.funct3) {
+ case 0x0:
+ switch(r.funct7) {
+ case 0x00:
+ x = cpu->x[r.rs1]+cpu->x[r.rs2];
+ break;
+ case 0x20:
+ x = cpu->x[r.rs1]-cpu->x[r.rs2];
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+ break;
+ case 0x1:
+ shamt = cpu->x[r.rs2] & 31;
+ x = cpu->x[r.rs1] << shamt;
+ break;
+ case 0x2:
+ x = ((int32_t)cpu->x[r.rs1] < (int32_t)cpu->x[r.rs2]) ? 1 : 0;
+ break;
+ case 0x3:
+ x = (cpu->x[r.rs1] < cpu->x[r.rs2]) ? 1 : 0;
+ break;
+ case 0x4:
+ x = cpu->x[r.rs1]^cpu->x[r.rs2];
+ break;
+ case 0x5:
+ switch(r.funct7) {
+ case 0x00:
+ shamt = cpu->x[r.rs2] & 31;
+ x = cpu->x[r.rs1] >> shamt;
+ break;
+ case 0x20:
+ shamt = cpu->x[r.rs2] & 31;
+ x = (uint32_t)((int32_t)cpu->x[r.rs1] >> shamt);
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+ break;
+ case 0x6:
+ x = cpu->x[r.rs1]|cpu->x[r.rs2];
+ break;
+ case 0x7:
+ x = cpu->x[r.rs1]&cpu->x[r.rs2];
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ if (r.rd != 0) {
+ cpu->x[r.rd] = x;
+ }
+
+ cpu->pc += 4;
+}
+
+static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ itype_t i;
+ decode_itype(&i, inst);
+
+ uint32_t addr = (uint32_t)i.imm + cpu->x[i.rs1];
+
+ /* TODO: do I need to check before loading halves and words */
+
+ uint32_t x;
+ switch(i.funct3) {
+ case 0x0:
+ x = (uint32_t)(int32_t)(int8_t)mem[addr];
+ break;
+ case 0x1:
+ uint16_t half = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8);
+ x = (uint32_t)(int32_t)(int16_t)half;
+ break;
+ case 0x2:
+ /* TODO: clean up */
+ x = (uint32_t)(int32_t)(
+ ((uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8))
+ |
+ (((uint16_t)mem[addr+2] | ((uint16_t)mem[addr+3] << 8))
+ << 16)
+ );
+ break;
+ case 0x4:
+ x = (uint32_t)(uint8_t)mem[addr];
+ break;
+
+ case 0x5:
+ int16_t uhalf = (int16_t)mem[addr] | ((int16_t)mem[addr+1] << 8);
+ x = (uint32_t)(int32_t)uhalf;
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ if (i.rd != 0) {
+ cpu->x[i.rd] = x;
+ }
+ cpu->pc += 4;
+}
+
+static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ stype_t s;
+ decode_stype(&s, inst);
+
+ uint32_t addr = s.imm + cpu->x[s.rs1];
+
+ /* TODO: helpers, better checks */
+ switch(s.funct3) {
+ case 0x0:
+ mem[addr] = cpu->x[s.rs2] & 255;
+ break;
+ case 0x1:
+ if (addr+1 > MEMSIZE-1) {
+ fprintf(stderr, "Illegal addr\n");
+ return;
+ }
+
+ if (addr % 2 == 0) {
+ mem[addr] = (uint8_t)cpu->x[s.rs2];
+ mem[addr+1] = (uint8_t)cpu->x[s.rs2] >> 8;
+ }
+ break;
+ case 0x2:
+ if (addr+3 > MEMSIZE-1) {
+ fprintf(stderr, "Illegal addr\n");
+ return;
+ }
+ if (addr % 4 == 0) {
+ mem[addr] = (uint8_t)cpu->x[s.rs2];
+ mem[addr+1] = (uint8_t)cpu->x[s.rs2] >> 8;
+ mem[addr+2] = (uint8_t)cpu->x[s.rs2] >> 16;
+ mem[addr+3] = (uint8_t)cpu->x[s.rs2] >> 24;
+ }
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ cpu->pc += 4;
+}
+
+static void exec_btype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ (void)mem; /* suppressing unused parameters warning */
+ btype_t b;
+ decode_btype(&b, inst);
+
+ int jump = 0;
+ switch (b.funct3) {
+ case 0x0:
+ if (cpu->x[b.rs1] == cpu->x[b.rs2])
+ jump = 1;
+ break;
+ case 0x1:
+ if (cpu->x[b.rs1] != cpu->x[b.rs2])
+ jump = 1;
+ break;
+ case 0x4:
+ if ((int32_t)cpu->x[b.rs1] < (int32_t)cpu->x[b.rs2])
+ jump = 1;
+ break;
+ case 0x5:
+ if ((int32_t)cpu->x[b.rs1] >= (int32_t)cpu->x[b.rs2])
+ jump = 1;
+ break;
+ case 0x6:
+ if (cpu->x[b.rs1] < cpu->x[b.rs2])
+ jump = 1;
+ break;
+ case 0x7:
+ if (cpu->x[b.rs1] >= cpu->x[b.rs2])
+ jump = 1;
+ break;
+ default:
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ if (jump == 1) {
+ uint32_t target;
+ 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;
+ } else {
+ cpu->pc += 4;
+ }
+
+}
+
+static void exec_itype_jalr(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ (void)mem; /* suppressing unused parameters warning */
+ itype_t i;
+ decode_itype(&i, inst);
+
+ uint32_t x;
+ if (i.funct3 != 0x0) {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ x = cpu->pc + 4;
+
+ uint32_t target;
+ 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;
+ }
+}
+
+static void exec_jtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
+ (void)mem; /* suppressing unused parameters warning */
+ jtype_t j;
+ decode_jtype(&j, inst);
+
+ uint32_t x;
+ x = cpu->pc + 4;
+ cpu->pc += j.imm;
+
+ uint32_t target;
+ 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;
+ }
+}
+
+static void
+exec_utype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
+{
+ (void)mem; /* suppressing unused parameters warning */
+ utype_t u;
+ decode_utype(&u, inst);
+
+ if (u.rd != 0)
+ cpu->x[u.rd] = u.imm << 12;
+
+ cpu->pc += 4;
+}
+
+static void
+exec_utype_auipc(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
+{
+ (void)mem; /* suppressing unused parameters warning */
+ utype_t u;
+ decode_utype(&u, inst);
+
+ if (u.rd != 0)
+ cpu->x[u.rd] = cpu->pc + (u.imm << 12);
+
+ cpu->pc += 4;
+}
+
+static void
+exec_itype_control(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
+{
+ (void)mem; /* suppressing unused parameters warning */
+ itype_t i;
+ decode_itype(&i, inst);
+
+ if (i.funct3 != 0x0) {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ if (i.imm == 0x0) {
+ raise_trap(cpu, TRAP_ECALL, inst);
+ return;
+ } else if (i.imm == 0x1) {
+ raise_trap(cpu, TRAP_EBREAK, inst);
+ return;
+ } else {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+}
+
+static void
+exec_itype_fence(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
+{
+ (void)mem; /* suppressing unused parameters warning */
+ itype_t i;
+ decode_itype(&i, inst);
+
+ if (i.funct3 != 0x0) {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ return;
+ }
+
+ cpu->pc += 4;
+}
+
+static inline uint32_t
+make_instruction(uint8_t *mem, uint32_t index)
+{
+ uint32_t inst = 0;
+ inst |= (uint32_t)(mem[index+0]) << 0;
+ inst |= (uint32_t)(mem[index+1]) << 8;
+ inst |= (uint32_t)(mem[index+2]) << 16;
+ inst |= (uint32_t)(mem[index+3]) << 24;
+ return inst;
+
+}
+
+/* Function pointer dispatch */
+typedef void (*exec_fn)(cpu_state_t *, uint32_t inst, uint8_t *mem);
+
+static exec_fn opcode_table[128] = {
+ [0x33] = exec_rtype,
+ [0x13] = exec_itype,
+ [0x03] = exec_itype_loads,
+ [0x67] = exec_itype_jalr,
+ [0x73] = exec_itype_control,
+ [0x0f] = exec_itype_fence,
+ [0x23] = exec_stype,
+ [0x63] = exec_btype,
+ [0x6f] = exec_jtype,
+ [0x37] = exec_utype,
+ [0x17] = exec_utype_auipc
+};
+/***/
+
+void
+cpu_step(cpu_state_t *cpu, uint8_t *mem)
+{
+ uint32_t inst = make_instruction(mem, cpu->pc);
+ disassemble_instruction(inst);
+
+ /* decode opcode */
+ uint16_t opcode = inst & 127;
+
+ exec_fn fn = opcode_table[opcode];
+
+ if (!fn) {
+ raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
+ }
+
+ fn(cpu,inst,mem);
+}
diff --git a/exec.h b/exec.h
@@ -0,0 +1,23 @@
+#ifndef EXEC_H
+#define EXEC_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;
+
+void cpu_step(cpu_state_t *cpu, uint8_t *mem);
+
+#endif
diff --git a/main.c b/main.c
@@ -4,482 +4,13 @@
#include <stdlib.h>
#include <string.h>
-#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) {
- for (int i = 15; i >= 0; i--) {
- putchar((x >> i) & 1 ? '1' : '0');
- /*if (i % 4 == 0) putchar(' '); grouping */
- }
-}
-
-static inline void print_bin32(uint32_t x) {
- for (int i = 31; i >= 0; i--) {
- putchar((x >> i) & 1 ? '1' : '0');
- }
-}
-
-static inline void print_binless(uint32_t x, int a) {
- for (int i = a-1; i >= 0; i--) {
- putchar((x >> i) & 1 ? '1' : '0');
- }
-}
-
-static void
-raise_trap(cpu_state_t *cpu, trap_cause_t trapinfo, uint32_t tval)
-{
- cpu->status = CPU_TRAPPED;
- cpu->trap.cause = trapinfo;
- cpu->trap.pc = cpu->pc;
- cpu->trap.tval = tval;
- return;
-}
-
-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 & INT64_C(3)) != 0)
- return TRAP_INSTRUCTION_MISALIGNED;
-
- return TRAP_NONE;
-}
-
-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;
-
- trap_cause_t valid = validate_instruction_address(candidate);
- if (valid != TRAP_NONE)
- return valid;
-
- *target = (uint32_t)candidate;
- return valid;
-}
-
-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);
- trap_cause_t valid = validate_instruction_address(candidate);
- if (valid != TRAP_NONE)
- return valid;
-
- *target = (uint32_t)candidate;
- return valid;
-}
-
-static void exec_itype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- (void)mem; /* suppressing unused parameters warning */
- itype_t i;
- decode_itype(&i, inst);
-
- uint32_t x; uint32_t shamt;
- uint32_t uimm = (uint32_t)i.imm;
- switch(i.funct3) {
- case 0x0:
- x = cpu->x[i.rs1]+uimm;
- break;
- case 0x1:
- if (i.funct7 == 0x00) {
- shamt = i.imm & 31;
- x = cpu->x[i.rs1] << shamt;
- } else {
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
- break;
- case 0x2:
- x = ((int32_t)cpu->x[i.rs1] < (int32_t)i.imm) ? 1 : 0;
- break;
- case 0x3:
- x = (cpu->x[i.rs1] < uimm) ? 1 : 0;
- break;
- case 0x4:
- x = cpu->x[i.rs1]^uimm;
- break;
- case 0x5:
- shamt = i.imm & 31;
- switch(i.funct7) {
- case 0x00:
- x = cpu->x[i.rs1] >> shamt;
- break;
- case 0x20:
- x = (uint32_t)((int32_t)cpu->x[i.rs1] >> shamt);
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
- break;
- case 0x6:
- x = cpu->x[i.rs1]|uimm;
- break;
- case 0x7:
- x = cpu->x[i.rs1]&uimm;
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- if (i.rd != 0) {
- cpu->x[i.rd] = x;
- }
-
- cpu->pc += 4;
-}
-
-static void exec_rtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- (void)mem; /* suppressing unused parameters warning */
- rtype_t r;
- decode_rtype(&r, inst);
-
- uint32_t x;
- uint32_t shamt;
- switch(r.funct3) {
- case 0x0:
- switch(r.funct7) {
- case 0x00:
- x = cpu->x[r.rs1]+cpu->x[r.rs2];
- break;
- case 0x20:
- x = cpu->x[r.rs1]-cpu->x[r.rs2];
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
- break;
- case 0x1:
- shamt = cpu->x[r.rs2] & 31;
- x = cpu->x[r.rs1] << shamt;
- break;
- case 0x2:
- x = ((int32_t)cpu->x[r.rs1] < (int32_t)cpu->x[r.rs2]) ? 1 : 0;
- break;
- case 0x3:
- x = (cpu->x[r.rs1] < cpu->x[r.rs2]) ? 1 : 0;
- break;
- case 0x4:
- x = cpu->x[r.rs1]^cpu->x[r.rs2];
- break;
- case 0x5:
- switch(r.funct7) {
- case 0x00:
- shamt = cpu->x[r.rs2] & 31;
- x = cpu->x[r.rs1] >> shamt;
- break;
- case 0x20:
- shamt = cpu->x[r.rs2] & 31;
- x = (uint32_t)((int32_t)cpu->x[r.rs1] >> shamt);
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
- break;
- case 0x6:
- x = cpu->x[r.rs1]|cpu->x[r.rs2];
- break;
- case 0x7:
- x = cpu->x[r.rs1]&cpu->x[r.rs2];
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- if (r.rd != 0) {
- cpu->x[r.rd] = x;
- }
-
- cpu->pc += 4;
-}
-
-static void exec_itype_loads(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- itype_t i;
- decode_itype(&i, inst);
-
- uint32_t addr = (uint32_t)i.imm + cpu->x[i.rs1];
-
- /* TODO: do I need to check before loading halves and words */
-
- uint32_t x;
- switch(i.funct3) {
- case 0x0:
- x = (uint32_t)(int32_t)(int8_t)mem[addr];
- break;
- case 0x1:
- uint16_t half = (uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8);
- x = (uint32_t)(int32_t)(int16_t)half;
- break;
- case 0x2:
- /* TODO: clean up */
- x = (uint32_t)(int32_t)(
- ((uint16_t)mem[addr] | ((uint16_t)mem[addr+1] << 8))
- |
- (((uint16_t)mem[addr+2] | ((uint16_t)mem[addr+3] << 8))
- << 16)
- );
- break;
- case 0x4:
- x = (uint32_t)(uint8_t)mem[addr];
- break;
-
- case 0x5:
- int16_t uhalf = (int16_t)mem[addr] | ((int16_t)mem[addr+1] << 8);
- x = (uint32_t)(int32_t)uhalf;
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- if (i.rd != 0) {
- cpu->x[i.rd] = x;
- }
- cpu->pc += 4;
-}
-
-static void exec_stype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- stype_t s;
- decode_stype(&s, inst);
-
- uint32_t addr = s.imm + cpu->x[s.rs1];
-
- /* TODO: helpers, better checks */
- switch(s.funct3) {
- case 0x0:
- mem[addr] = cpu->x[s.rs2] & 255;
- break;
- case 0x1:
- if (addr+1 > MEMSIZE-1) {
- fprintf(stderr, "Illegal addr\n");
- return;
- }
-
- if (addr % 2 == 0) {
- mem[addr] = (uint8_t)cpu->x[s.rs2];
- mem[addr+1] = (uint8_t)cpu->x[s.rs2] >> 8;
- }
- break;
- case 0x2:
- if (addr+3 > MEMSIZE-1) {
- fprintf(stderr, "Illegal addr\n");
- return;
- }
- if (addr % 4 == 0) {
- mem[addr] = (uint8_t)cpu->x[s.rs2];
- mem[addr+1] = (uint8_t)cpu->x[s.rs2] >> 8;
- mem[addr+2] = (uint8_t)cpu->x[s.rs2] >> 16;
- mem[addr+3] = (uint8_t)cpu->x[s.rs2] >> 24;
- }
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- cpu->pc += 4;
-}
-
-static void exec_btype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- (void)mem; /* suppressing unused parameters warning */
- btype_t b;
- decode_btype(&b, inst);
-
- int jump = 0;
- switch (b.funct3) {
- case 0x0:
- if (cpu->x[b.rs1] == cpu->x[b.rs2])
- jump = 1;
- break;
- case 0x1:
- if (cpu->x[b.rs1] != cpu->x[b.rs2])
- jump = 1;
- break;
- case 0x4:
- if ((int32_t)cpu->x[b.rs1] < (int32_t)cpu->x[b.rs2])
- jump = 1;
- break;
- case 0x5:
- if ((int32_t)cpu->x[b.rs1] >= (int32_t)cpu->x[b.rs2])
- jump = 1;
- break;
- case 0x6:
- if (cpu->x[b.rs1] < cpu->x[b.rs2])
- jump = 1;
- break;
- case 0x7:
- if (cpu->x[b.rs1] >= cpu->x[b.rs2])
- jump = 1;
- break;
- default:
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- if (jump == 1) {
- uint32_t target;
- 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;
- } else {
- cpu->pc += 4;
- }
-
-}
-
-static void exec_itype_jalr(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- (void)mem; /* suppressing unused parameters warning */
- itype_t i;
- decode_itype(&i, inst);
-
- uint32_t x;
- if (i.funct3 != 0x0) {
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- x = cpu->pc + 4;
-
- uint32_t target;
- 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;
- }
-}
-
-static void exec_jtype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem) {
- (void)mem; /* suppressing unused parameters warning */
- jtype_t j;
- decode_jtype(&j, inst);
-
- uint32_t x;
- x = cpu->pc + 4;
- cpu->pc += j.imm;
-
- uint32_t target;
- 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;
- }
-}
-
-static void
-exec_utype(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
-{
- (void)mem; /* suppressing unused parameters warning */
- utype_t u;
- decode_utype(&u, inst);
-
- if (u.rd != 0)
- cpu->x[u.rd] = u.imm << 12;
-
- cpu->pc += 4;
-}
-
-static void
-exec_utype_auipc(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
-{
- (void)mem; /* suppressing unused parameters warning */
- utype_t u;
- decode_utype(&u, inst);
-
- if (u.rd != 0)
- cpu->x[u.rd] = cpu->pc + (u.imm << 12);
-
- cpu->pc += 4;
-}
-
-static void
-exec_itype_control(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
-{
- (void)mem; /* suppressing unused parameters warning */
- itype_t i;
- decode_itype(&i, inst);
-
- if (i.funct3 != 0x0) {
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- if (i.imm == 0x0) {
- raise_trap(cpu, TRAP_ECALL, inst);
- return;
- } else if (i.imm == 0x1) {
- raise_trap(cpu, TRAP_EBREAK, inst);
- return;
- } else {
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
-}
-
-static void
-exec_itype_fence(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
-{
- (void)mem; /* suppressing unused parameters warning */
- itype_t i;
- decode_itype(&i, inst);
-
- if (i.funct3 != 0x0) {
- raise_trap(cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- return;
- }
-
- cpu->pc += 4;
-}
+#include "exec.h"
static void
load_program(uint8_t *mem)
{
- /* PROGRAM */
+ /* program */
uint32_t arr[] = {
/*
0x00500193, // addi x3, x0, 5
@@ -490,13 +21,76 @@ load_program(uint8_t *mem)
0x0ff0000f, // fence
0x00100073, // ebreak
*/
+/*
0xfff00093, // addi x1, x0, -1
0xfff04113, // xori x2, x0, -1
0xfff06193, // ori x3, x0, -1
0xfff17213, // andi x4, x2, -1
0xfff02293, // slti x5, x0, -1
0xfff03313 // sltiu x6, x0, -1
+*/
+/*
+ 0xfff00093, // li ra,-1
+ 0xfff04113, // not sp,zero
+ 0xfff06193, // ori gp,zero,-1
+ 0xfff17213, // andi tp,sp,-1
+ 0xfff02293, // slti t0,zero,-1
+ 0xfff03313, // sltiu t1,zero,-1
+ 0x00100073 // ebreak
+*/
+/*
+0x00a00093, //li ra,10
+0x00000113, //li sp,0
+0x00100193, //li gp,1
+0x00310133, //add sp,sp,gp
+0x00118193, //addi gp,gp,1
+0xfff08093, //addi ra,ra,-1
+0xfe009ae3, //bnez ra,c <loop>
+0x10000513, //li a0,256
+0x00252023, //sw sp,0(a0)
+0x00350223, //sb gp,4(a0)
+0x00052203, //lw tp,0(a0)
+0x00450283, //lb t0,4(a0)
+0x00121313, //slli t1,tp,0x1
+0x004343b3, //xor t2,t1,tp
+0x03822413, //slti s0,tp,56
+0xfff23493, //sltiu s1,tp,-1
+0x00c005ef, //jal a1,4c <subroutine>
+0x00c52423, //sw a2,8(a0)
+0x00100073, //ebreak
+0x00720613, //addi a2,tp,7 # 7 <_start+0x7>
+0x00058067 //jr a1
+*/
+
+/*
+ 0x00700513, // addi x10, x0, 7
+ 0x00451513, // slli x10, x10, 4
+ 0x00d50513, // addi x10, x10, 13
+ 0x05554513, // xori x10, x10, 0x55
+ 0xff750513, // addi x10, x10, -9
+ 0x00100073 // ebreak
+*/
+0x10000593, //li a1,256
+0xfff00513, //li a0,-1
+0x00a58023, //sb a0,0(a1)
+0x0005c503, //lbu a0,0(a1)
+0x00150513, //addi a0,a0,1
+0x00a59123, //sh a0,2(a1)
+0x00259503, //lh a0,2(a1)
+0xeff50513, //addi a0,a0,-257
+0x00a58223, //sb a0,4(a1)
+0x00458503, //lb a0,4(a1)
+0x00a59323, //sh a0,6(a1)
+0x00659503, //lh a0,6(a1)
+0x0065d503, //lhu a0,6(a1)
+0x00150513, //addi a0,a0,1
+0x00a5a423, //sw a0,8(a1)
+0x00000513, //li a0,0
+0x0085a503, //lw a0,8(a1)
+0x00000593, //li a1,0
+0x00100073 //ebreak
};
+
size_t len = sizeof(arr) / sizeof(arr[0]);
int b = 0; /*byte*/
@@ -511,45 +105,39 @@ load_program(uint8_t *mem)
}
}
-static inline uint32_t
-make_instruction(uint8_t *mem, uint32_t index)
-{
- uint32_t inst = 0;
- inst |= (uint32_t)(mem[index+0]) << 0;
- inst |= (uint32_t)(mem[index+1]) << 8;
- inst |= (uint32_t)(mem[index+2]) << 16;
- inst |= (uint32_t)(mem[index+3]) << 24;
- return inst;
-
-}
-
-/* Function pointer dispatch */
-typedef void (*exec_fn)(cpu_state_t *, uint32_t inst, uint8_t *mem);
-
-static exec_fn opcode_table[128];
-static void
-init_opcode_table(void)
+void
+trap_handler(cpu_state_t *cpu)
{
- opcode_table[0x33] = exec_rtype;
- opcode_table[0x13] = exec_itype;
- opcode_table[0x03] = exec_itype_loads;
- opcode_table[0x67] = exec_itype_jalr;
- opcode_table[0x73] = exec_itype_control;
- opcode_table[0x0f] = exec_itype_fence;
- opcode_table[0x23] = exec_stype;
- opcode_table[0x63] = exec_btype;
- opcode_table[0x6f] = exec_jtype;
- opcode_table[0x37] = exec_utype;
- opcode_table[0x17] = exec_utype_auipc;
+ if (cpu->status == CPU_TRAPPED) {
+ printf("CPU trapped\n");
+ switch(cpu.trap.cause) {
+ case TRAP_EBREAK:
+ 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;
+ }
+ }
}
-/***/
+
int
main()
{
- init_opcode_table();
-
cpu_state_t cpu = {0};
uint8_t mem[MEMSIZE] = {0};
@@ -570,45 +158,9 @@ main()
strncmp(line, "n", 1) == 0 ||
strncmp(line, "next", 4) == 0) {
- uint32_t inst = make_instruction(mem, cpu.pc);
- disassemble_instruction(inst);
-
- /* decode opcode */
- uint16_t opcode = inst & 127;
-
- exec_fn fn = opcode_table[opcode];
-
- if (!fn) {
- raise_trap(&cpu, TRAP_ILLEGAL_INSTRUCTION, inst);
- }
-
- fn(&cpu,inst,mem);
-
- if (cpu.status == CPU_TRAPPED) {
- printf("CPU trapped\n");
- switch(cpu.trap.cause) {
- case TRAP_EBREAK:
- 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;
- }
+ cpu_step(&cpu, mem);
+ trap_handler(&cpu);
} else if (strncmp(line, "r", 1) == 0 ||
strncmp(line, "registers", 9) == 0) {
@@ -622,6 +174,10 @@ main()
for (int i=0; i<32; i++) {
printf("0x%x: 0x%x\n", i, mem[i]);
}
+ printf("\n");
+ for (int i=256; i<268; i++) {
+ printf("0x%x: 0x%x\n", i, mem[i]);
+ }
} else if (strncmp(line, "ip", 2) == 0 ||
strncmp(line, "pc", 2) == 0) {
printf("Instruction poiter:\n");
@@ -631,32 +187,3 @@ main()
return 0;
}
-
-/*
-int main() {
- init_opcode_table();
-
- cpu_state_t cpu = {0};
-
- uint8_t mem[MEMSIZE] = {0};
-
- load_program(mem);
-
- while (1) {
- uint32_t inst = make_instruction(mem, cpu.pc);
-
- uint16_t opcode = inst & 127;
- exec_fn fn = opcode_table[opcode];
-
- if (!fn) {
- //illegal(NULL, inst);
- fprintf(stderr, "Illegal opcode\n");
- return EXIT_FAILURE;
- }
-
- fn(&cpu,inst,mem);
- }
-
- return 0;
-}
-*/