commit 4f7fe64aa5cbd2fb181c3fece01a0b806fc885a1
parent 2cc43400b091dc7d16b7d8880ba4e2d47f2702ad
Author: Michail Konstantinos Dimopoulos <mk@mcdim.xyz>
Date: Fri, 4 Sep 2026 21:20:17 +0300
Improved debugger output and added running mode
Diffstat:
| M | disasm.c | | | 30 | +++++++++++++++--------------- |
| M | exec.c | | | 17 | ++--------------- |
| M | main.c | | | 111 | ++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------- |
| A | mem.h | | | 15 | +++++++++++++++ |
4 files changed, 102 insertions(+), 71 deletions(-)
diff --git a/disasm.c b/disasm.c
@@ -19,7 +19,7 @@ static void disasm_itype(uint32_t inst) {
if (i.funct7 == 0x00) {
printf("slli");
} else {
- printf("Illegal funct7\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
break;
@@ -41,7 +41,7 @@ static void disasm_itype(uint32_t inst) {
printf("srai");
break;
default:
- printf("Illegal funct7\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
break;
@@ -52,10 +52,10 @@ static void disasm_itype(uint32_t inst) {
printf("andi");
break;
default:
- printf("Illegal funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
- printf(" x%d, %" PRIu8 ", %" PRId32 "\n", i.rd, i.rs1, i.imm);
+ printf(" x%d, x%" PRIu8 ", %" PRId32 "\n", i.rd, i.rs1, i.imm);
}
static void disasm_rtype(uint32_t inst) {
@@ -72,7 +72,7 @@ static void disasm_rtype(uint32_t inst) {
printf("sub x%d, x%d\n", r.rs1, r.rs2);
break;
default:
- printf("Illegal funct7\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
break;
@@ -97,7 +97,7 @@ static void disasm_rtype(uint32_t inst) {
printf("sra x%d, x%d\n", r.rs1, r.rs2);
break;
default:
- printf("Illegal funct7\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
break;
@@ -108,7 +108,7 @@ static void disasm_rtype(uint32_t inst) {
printf("and x%d, x%d\n", r.rs1, r.rs2);
break;
default:
- printf("Illegal funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
}
@@ -134,7 +134,7 @@ static void disasm_itype_loads(uint32_t inst) {
printf("lhu");
break;
default:
- printf("Illegal funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -157,7 +157,7 @@ static void disasm_stype(uint32_t inst) {
printf("sw");
break;
default:
- printf("Illegal funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -189,7 +189,7 @@ static void disasm_btype(uint32_t inst) {
printf("bgeu");
break;
default:
- printf("Illegal funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -204,7 +204,7 @@ static void disasm_itype_jalr(uint32_t inst) {
decode_itype(&i, inst);
if (i.funct3 != 0x0u) {
- fprintf(stderr, "Illegal JALR funct3\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -243,7 +243,7 @@ disasm_itype_control(uint32_t inst)
decode_itype(&i, inst);
if (i.funct3 != 0x0) {
- puts("Illegal instruction");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -254,7 +254,7 @@ disasm_itype_control(uint32_t inst)
puts("ebreak");
return;
} else {
- puts("Illegal instruction");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
}
@@ -266,7 +266,7 @@ disasm_itype_fence(uint32_t inst)
decode_itype(&i, inst);
if (i.funct3 != 0x0) {
- puts("Illegal instruction");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
@@ -299,7 +299,7 @@ void disassemble_instruction(uint32_t inst) {
uint16_t opcode = inst & 0x7f;
disasm_fn fn = opcode_table[opcode];
if (!fn) {
- fprintf(stderr, "Illegal opcode\n");
+ printf(".word 0x%08" PRIx32 "\n", inst);
return;
}
fn(inst);
diff --git a/exec.c b/exec.c
@@ -5,11 +5,11 @@
#include <string.h>
#include "exec.h"
+#include "mem.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');
@@ -463,18 +463,6 @@ exec_itype_fence(cpu_state_t *cpu, uint32_t inst, uint8_t *mem)
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);
@@ -496,8 +484,7 @@ static exec_fn opcode_table[128] = {
void
cpu_step(cpu_state_t *cpu, uint8_t *mem)
{
- uint32_t inst = make_instruction(mem, cpu->pc);
- disassemble_instruction(inst);
+ uint32_t inst = load_u32_le(mem, cpu->pc); /* load little endian */
/* decode opcode */
uint16_t opcode = inst & 127;
diff --git a/main.c b/main.c
@@ -4,8 +4,15 @@
#include <stdlib.h>
#include <string.h>
-#include "disasm.h"
+//#include "disasm.h"
#include "exec.h"
+#include "mem.h"
+#include "disasm.h"
+
+typedef enum {
+ MODE_RUN,
+ MODE_STEP
+} emu_mode_t;
static void
load_program(uint8_t *mem)
@@ -62,14 +69,13 @@ load_program(uint8_t *mem)
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)
@@ -89,6 +95,7 @@ load_program(uint8_t *mem)
0x0085a503, //lw a0,8(a1)
0x00000593, //li a1,0
0x00100073 //ebreak
+*/
};
size_t len = sizeof(arr) / sizeof(arr[0]);
@@ -105,15 +112,15 @@ load_program(uint8_t *mem)
}
}
-
-void
+static emu_mode_t
trap_handler(cpu_state_t *cpu)
{
if (cpu->status == CPU_TRAPPED) {
printf("CPU trapped\n");
- switch(cpu.trap.cause) {
+ switch(cpu->trap.cause) {
case TRAP_EBREAK:
printf("Code reached breakpoint\n");
+ return MODE_STEP;
break;
case TRAP_ECALL:
printf("Code ECALL\n");
@@ -132,8 +139,59 @@ trap_handler(cpu_state_t *cpu)
break;
}
}
+ return MODE_RUN;
}
+static emu_mode_t
+debugger(cpu_state_t *cpu, uint8_t *mem)
+{
+ printf("PC 0x%x>", cpu->pc);
+ char line[256];
+ if (!fgets(line, sizeof(line), stdin)) {
+ fprintf(stderr, "Error reading"
+ "interactive input\n");
+ }
+
+ if (strncmp(line, "s", 1) == 0 ||
+ strncmp(line, "step", 4) == 0 ||
+ strncmp(line, "n", 1) == 0 ||
+ strncmp(line, "next", 4) == 0) {
+
+ uint32_t inst = load_u32_le(mem, cpu->pc); /* load little endian */
+ disassemble_instruction(inst);
+ cpu_step(cpu, mem);
+
+ trap_handler(cpu);
+
+ } else if (strncmp(line, "r", 1) == 0 ||
+ strncmp(line, "registers", 9) == 0) {
+ printf("Registers:\n");
+ for (int i=0; i<32; i++) {
+ printf("0x%x: 0x%x\n", i, cpu->x[i]);
+ }
+ } else if (strncmp(line, "m", 1) == 0 ||
+ strncmp(line, "memory", 6) == 0) {
+ printf("Memory:\n");
+ for (int i=0; i<128; i+=4) {
+ if (cpu->pc == i) {
+ printf("-> ");
+ } else {
+ printf(" ");
+ }
+ printf("0x%.8x: 0x%.2x 0x%.2x 0x%.2x 0x%.2x ",
+ i, mem[i], mem[i+1], mem[i+2], mem[i+3]);
+ disassemble_instruction(load_u32_le(mem,i));
+ }
+ } else if (strncmp(line, "ip", 2) == 0 ||
+ strncmp(line, "pc", 2) == 0) {
+ printf("Instruction poiter:\n");
+ printf("PC: %" PRIu32 "\n", cpu->pc);
+ } else if (strncmp(line, "e", 1) == 0) {
+ return MODE_RUN;
+ }
+
+ return MODE_STEP;
+}
int
main()
@@ -145,43 +203,14 @@ main()
load_program(mem);
/* fetch & run */
- while (1) {
- printf("PC 0x%x>", cpu.pc);
- char line[256];
- if (!fgets(line, sizeof(line), stdin)) {
- fprintf(stderr, "Error reading"
- "interactive input\n");
- }
-
- if (strncmp(line, "s", 1) == 0 ||
- strncmp(line, "step", 4) == 0 ||
- strncmp(line, "n", 1) == 0 ||
- strncmp(line, "next", 4) == 0) {
+ emu_mode_t mode = MODE_STEP;
+ while (1) {
+ if (mode == MODE_RUN) {
cpu_step(&cpu, mem);
-
- trap_handler(&cpu);
-
- } else if (strncmp(line, "r", 1) == 0 ||
- strncmp(line, "registers", 9) == 0) {
- printf("Registers:\n");
- for (int i=0; i<32; i++) {
- printf("0x%x: 0x%x\n", i, cpu.x[i]);
- }
- } else if (strncmp(line, "m", 1) == 0 ||
- strncmp(line, "memory", 6) == 0) {
- printf("Memory:\n");
- 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");
- printf("PC: %" PRIu32 "\n", cpu.pc);
+ mode = trap_handler(&cpu);
+ } else {
+ mode = debugger(&cpu, mem);
}
}
diff --git a/mem.h b/mem.h
@@ -0,0 +1,15 @@
+#ifndef MEMORY_H
+#define MEMORY_H
+
+static inline uint32_t
+load_u32_le(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;
+}
+
+#endif