rvemu

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

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:
Mdisasm.c | 30+++++++++++++++---------------
Mexec.c | 17++---------------
Mmain.c | 111++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Amem.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