From 6f60b1a74accf4a03e46d718606d09a89ce65817 Mon Sep 17 00:00:00 2001 From: Henrik Hautakoski Date: Sun, 28 Oct 2018 14:53:41 +0100 Subject: [PATCH] src/cpu.c: alot of refactoring, store state in a struct. and make vm.c "own" the state. --- src/cpu.c | 113 +++++++++++++++++++++++------------------------------- src/cpu.h | 27 +++++++++++-- src/vm.c | 53 +++++++++++++++++++++++-- 3 files changed, 120 insertions(+), 73 deletions(-) diff --git a/src/cpu.c b/src/cpu.c index 1cd42a4..c5b076d 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -31,9 +31,6 @@ #include "syscall.h" #include "instr.h" -// Registers r0, r15 -int16_t reg[CPU_NUM_REGS] = { 0 }; - /* Program */ unsigned char *instr_mem = NULL; unsigned long instr_cnt = 0; @@ -47,7 +44,7 @@ unsigned char cpu_flags = CPU_FLAGS_HALT; #define debug(...) fprintf(stderr, __VA_ARGS__) -static void execute(struct instr *instr) { +static void execute(struct cpu_state *state, struct instr *instr) { switch(instr->opcode) { case OP_NOOP : @@ -56,128 +53,112 @@ static void execute(struct instr *instr) { break; case OP_ADD : debug("add\tr%i r%i r%i\n", instr->r.rs, instr->r.r0, instr->r.r1); - reg[instr->r.rs] = reg[instr->r.r0] + reg[instr->r.r1]; + state->reg[instr->r.rs] = state->reg[instr->r.r0] + state->reg[instr->r.r1]; break; case OP_MOVL : debug("movl\tr%i #%i\n", instr->i.rs, instr->i.imm); - reg[instr->r.rs] = (reg[instr->r.rs] & 0xFF00) | instr->i.imm; + state->reg[instr->r.rs] = (state->reg[instr->r.rs] & 0xFF00) | instr->i.imm; break; case OP_MOVH : debug("movh\tr%i #%i\n", instr->i.rs, instr->i.imm); - reg[instr->r.rs] = (reg[instr->r.rs] & 0x00FF) | (((uint16_t) instr->i.imm) << 8); + state->reg[instr->r.rs] = (state->reg[instr->r.rs] & 0x00FF) | (((uint16_t) instr->i.imm) << 8); break; case OP_LW : debug("lw\tr%i r%i #%i\n", instr->r.rs, instr->r.r0, instr->r.r1); - reg[instr->r.rs] = mm_lw(reg[instr->r.r0] + instr->r.r1); + state->reg[instr->r.rs] = mm_lw(state->reg[instr->r.r0] + instr->r.r1); break; case OP_SW : debug("sw\tr%i r%i #%i\n", instr->r.rs, instr->r.r0, instr->r.r1); - mm_sw(reg[instr->r.rs] + instr->r.r1, reg[instr->r.r0]); + mm_sw(state->reg[instr->r.rs] + instr->r.r1, state->reg[instr->r.r0]); break; case OP_JMP : debug("jmp\t#%i\n", instr->j.addr); - cpu_set_pc(instr->j.addr); + cpu_set_pc(state, instr->j.addr); break; case OP_JR : debug("jr\tr%i(#%i)\n", instr->i.rs, instr->i.imm); - cpu_set_pc(reg[instr->r.rs] + instr->i.imm); + cpu_set_pc(state, state->reg[instr->r.rs] + instr->i.imm); break; case OP_BEQ : debug("beq\tr%i r%i #%i\n", instr->ri.rs, instr->ri.r0, instr->ri.offset); // Compare rs, r0 - if (reg[instr->ri.rs] == reg[instr->ri.r0]) - cpu_set_pc(pc + instr->ri.offset); + if (state->reg[instr->ri.rs] == state->reg[instr->ri.r0]) + cpu_set_pc(state, state->pc + instr->ri.offset); break; case OP_INT : debug("int %i(#%i)\n", instr->r.rs, instr->i.imm); - vm_syscall(instr->i.rs, instr->i.imm, reg); + vm_syscall(instr->i.rs, instr->i.imm, state->reg); break; default : fprintf(stderr, "Invalid instruction (%.2X)\n", instr->opcode); - cpu_flags |= CPU_FLAGS_HALT; + state->flags |= CPU_FLAGS_HALT; break; } } -void print_memory() { +void cpu_init(struct cpu_state *state) +{ + state->pc = 0; + state->flags = 0; + memset(state->reg, 0, sizeof(state->reg[0]) * CPU_NUM_REGS); - int i = 0; - - printf("\n"); - - for(i = 0; i < 32; i++) { - printf("%.2X ", memory[i]); - } - printf("\n"); + state->instr_mem = NULL; + state->instr_cnt = 0; } -void print_reg() { - - int i = 0; - - printf("\n"); - - for(i = 0; i < 16; i++) { - printf("r%i = %i\n", i, reg[i]); - } - printf("\n"); -} - -static unsigned char* instr_fetch() { - - if (pc + 1 >= instr_cnt >> 1) - cpu_flags |= CPU_FLAGS_HALT; - - return instr_mem + (pc++ << 1); -} - -int cpu_instr_load(void *ptr, unsigned len) { +int cpu_instr_load(struct cpu_state *state, void *ptr, unsigned len) { if (len % 2) { fprintf(stderr, "Error: Instruction length must be a multiple of 2\n"); return -1; } - instr_mem = ptr; - instr_cnt = len; + state->instr_mem = ptr; + state->instr_cnt = len; return len; } -void cpu_instr_unload() { +void cpu_instr_unload(struct cpu_state *state) { - instr_mem = NULL; - instr_cnt = 0; + state->instr_mem = NULL; + state->instr_cnt = 0; } -void cpu_set_pc(uint16_t addr) { +void cpu_set_pc(struct cpu_state *state, uint16_t addr) { if (addr > instr_cnt / 2) { fprintf(stderr, "Runtime error: Invalid instruction address %ui\n", addr); - cpu_flags |= CPU_FLAGS_HALT; + state->flags |= CPU_FLAGS_HALT; return; } - pc = addr; + state->pc = addr; } -void cpu_run() { +static unsigned char* instr_fetch(struct cpu_state *state) { - mm_init(); + if (state->pc + 1 >= state->instr_cnt >> 1) + state->flags |= CPU_FLAGS_HALT; - cpu_flags &= ~CPU_FLAGS_HALT; + return state->instr_mem + (state->pc++ << 1); +} - while(!(cpu_flags & CPU_FLAGS_HALT)) { - struct instr instr; - unsigned char* next = instr_fetch(); +int cpu_tick(struct cpu_state *state) { - // decode instruction. - instr_decode(next, &instr); + struct instr instr; + unsigned char* next; - // Execute it. - execute(&instr); + if (state->flags & CPU_FLAGS_HALT) { + return 1; } - print_reg(); - print_memory(); + // Fetch next instruction + next = instr_fetch(state); - mm_exit(); + // decode instruction. + instr_decode(next, &instr); + + // Execute it. + execute(state, &instr); + + return 0; } diff --git a/src/cpu.h b/src/cpu.h index a9b1473..2ec28ea 100644 --- a/src/cpu.h +++ b/src/cpu.h @@ -25,12 +25,31 @@ #define CPU_NUM_REGS 16 -int cpu_instr_load(void *ptr, unsigned len); +#define CPU_FLAGS_HALT (1<<0) -void cpu_instr_unload(); +struct cpu_state { + // Registers r0, r15 + int16_t reg[CPU_NUM_REGS]; -void cpu_set_pc(uint16_t addr); + // Program counter + uint16_t pc; -void cpu_run(); + // flags + unsigned char flags; + + // Instruction + unsigned char *instr_mem; + unsigned long instr_cnt; +}; + +void cpu_init(struct cpu_state *state); + +int cpu_instr_load(struct cpu_state *state, void *ptr, unsigned len); + +void cpu_instr_unload(struct cpu_state *state); + +void cpu_set_pc(struct cpu_state *state, uint16_t addr); + +int cpu_tick(struct cpu_state *state); #endif /* CPU_H */ diff --git a/src/vm.c b/src/vm.c index a9354bc..c51e2b1 100644 --- a/src/vm.c +++ b/src/vm.c @@ -25,8 +25,11 @@ #include #include #include +#include "mm.h" #include "cpu.h" +struct cpu_state state; + // Load program from file unsigned long load_program(int fd, unsigned char **buf) { @@ -46,8 +49,53 @@ unsigned long load_program(int fd, unsigned char **buf) { return rc; } +void print_memory() { + + int i = 0; + + printf("\n"); + + for(i = 0; i < 32; i++) { + printf("%.2X ", memory[i]); + } + printf("\n"); +} + +void print_regs(uint16_t *regs) { + + int i = 0; + + printf("\n"); + + for(i = 0; i < CPU_NUM_REGS; i++) { + printf("r%i = %i\n", i, regs[i]); + } + printf("\n"); +} + +void run(unsigned char *instr_ptr, unsigned instr_len) { + + int rc; + + mm_init(); + cpu_init(&state); + + cpu_instr_load(&state, instr_ptr, instr_len); + + do { + rc = cpu_tick(&state); + } while(rc == 0); + + print_regs(state.reg); + + print_memory(); + + mm_exit(); +} + int main(int argc, char **argv) { + int rc; int fd; unsigned char *instr_ptr; unsigned instr_len; @@ -70,9 +118,8 @@ int main(int argc, char **argv) { if (instr_len < 0) return 1; - cpu_instr_load(instr_ptr, instr_len); - - cpu_run(); + // Execute the program. + run(instr_ptr, instr_len); if (instr_ptr) free(instr_ptr);