working on debug menu
This commit is contained in:
2
.vscode/launch.json
vendored
2
.vscode/launch.json
vendored
@ -9,7 +9,7 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug",
|
"name": "Debug",
|
||||||
"program": "${workspaceFolder}/build/gbemu/Debug/gbemu.exe",
|
"program": "${workspaceFolder}/build/gbemu/Debug/gbemu.exe",
|
||||||
"args": [ "C:\\Users\\piwalker\\Downloads\\mts-20240926-1737-443f6e1\\mts-20240926-1737-443f6e1\\emulator-only\\mbc2\\ram.gb" ],
|
"args": [ "C:\\Users\\piwalker\\Downloads\\mts-20240926-1737-443f6e1\\emulator-only\\mbc2\\ram.gb" ],
|
||||||
"cwd": "${workspaceFolder}"
|
"cwd": "${workspaceFolder}"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
@ -33,6 +33,7 @@ typedef struct {
|
|||||||
bool enabling_ime;
|
bool enabling_ime;
|
||||||
u8 ie_register;
|
u8 ie_register;
|
||||||
u8 int_flags;
|
u8 int_flags;
|
||||||
|
u16 inst_pc;
|
||||||
} cpu_context;
|
} cpu_context;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
@ -42,6 +43,8 @@ typedef struct {
|
|||||||
void cpu_save_state(cpu_state*);
|
void cpu_save_state(cpu_state*);
|
||||||
void cpu_load_state(const cpu_state*);
|
void cpu_load_state(const cpu_state*);
|
||||||
|
|
||||||
|
void fetch_instruction(cpu_context *ctx);
|
||||||
|
|
||||||
void cpu_init();
|
void cpu_init();
|
||||||
bool cpu_step();
|
bool cpu_step();
|
||||||
|
|
||||||
|
19
include/debug.h
Normal file
19
include/debug.h
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <common.h>
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
DS_MAIN,
|
||||||
|
DS_DISASSEMBLE
|
||||||
|
} debug_state;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
debug_state state;
|
||||||
|
u16 dissasembly_scroll;
|
||||||
|
u16 dissasembly_target;
|
||||||
|
u16 dissasembly_pc;
|
||||||
|
} debug_context;
|
||||||
|
|
||||||
|
void debug_update();
|
||||||
|
debug_context *debug_get_context();
|
||||||
|
void debug_init();
|
@ -9,6 +9,8 @@ typedef struct {
|
|||||||
u64 ticks;
|
u64 ticks;
|
||||||
const char *app_path;
|
const char *app_path;
|
||||||
bool fast_forward;
|
bool fast_forward;
|
||||||
|
bool debug;
|
||||||
|
u8 step;
|
||||||
} emu_context;
|
} emu_context;
|
||||||
|
|
||||||
int emu_run(int, char**);
|
int emu_run(int, char**);
|
||||||
|
23
lib/cpu.c
23
lib/cpu.c
@ -7,7 +7,7 @@
|
|||||||
#include <timer.h>
|
#include <timer.h>
|
||||||
#include <memory.h>
|
#include <memory.h>
|
||||||
|
|
||||||
cpu_context ctx = {0};
|
static cpu_context ctx = {0};
|
||||||
#define CPU_DEBUG 1
|
#define CPU_DEBUG 1
|
||||||
#define FILE_LOG 0
|
#define FILE_LOG 0
|
||||||
|
|
||||||
@ -37,9 +37,9 @@ void cpu_init() {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
static void fetch_instruction() {
|
void fetch_instruction(cpu_context *ctx) {
|
||||||
ctx.cur_opcode = bus_read(ctx.regs.pc++);
|
ctx->cur_opcode = bus_read(ctx->regs.pc++);
|
||||||
ctx.cur_inst = instruction_by_opcode(ctx.cur_opcode);
|
ctx->cur_inst = instruction_by_opcode(ctx->cur_opcode);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void execute() {
|
static void execute() {
|
||||||
@ -57,15 +57,26 @@ bool cpu_step() {
|
|||||||
|
|
||||||
if(!ctx.halted) {
|
if(!ctx.halted) {
|
||||||
u16 pc = ctx.regs.pc;
|
u16 pc = ctx.regs.pc;
|
||||||
fetch_instruction();
|
ctx.inst_pc = pc;
|
||||||
|
fetch_instruction(&ctx);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
|
|
||||||
#if FILE_LOG == 1
|
#if FILE_LOG == 1
|
||||||
fprintf(log, "A:%02X F:%02X B:%02X C:%02X D:%02X E:%02X H:%02X L:%02X SP:%04X PC:%04X PCMEM:%02X,%02X,%02X,%02X\n",
|
fprintf(log, "A:%02X F:%02X B:%02X C:%02X D:%02X E:%02X H:%02X L:%02X SP:%04X PC:%04X PCMEM:%02X,%02X,%02X,%02X\n",
|
||||||
ctx.regs.a, ctx.regs.f, ctx.regs.b, ctx.regs.c, ctx.regs.d, ctx.regs.e, ctx.regs.h, ctx.regs.l, ctx.regs.sp, pc,
|
ctx.regs.a, ctx.regs.f, ctx.regs.b, ctx.regs.c, ctx.regs.d, ctx.regs.e, ctx.regs.h, ctx.regs.l, ctx.regs.sp, pc,
|
||||||
bus_read(pc), bus_read(pc+1), bus_read(pc+2), bus_read(pc+3)
|
bus_read(pc), bus_read(pc+1), bus_read(pc+2), bus_read(pc+3)
|
||||||
);
|
);
|
||||||
#endif
|
#endif
|
||||||
fetch_data();
|
fetch_data(&ctx);
|
||||||
|
while(emu_get_context()->paused && !emu_get_context()->step)
|
||||||
|
delay(10);
|
||||||
|
if(emu_get_context()->paused) {
|
||||||
|
emu_get_context()->step--;
|
||||||
|
if(emu_get_context()->step == 0) {
|
||||||
|
printf("debug!\n");
|
||||||
|
emu_get_context()->debug = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
#if CPU_DEBUG == 1
|
#if CPU_DEBUG == 1
|
||||||
char flags[16];
|
char flags[16];
|
||||||
sprintf(flags, "%c%c%c%c",
|
sprintf(flags, "%c%c%c%c",
|
||||||
|
116
lib/cpu_fetch.c
116
lib/cpu_fetch.c
@ -2,138 +2,136 @@
|
|||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
#include <emu.h>
|
#include <emu.h>
|
||||||
|
|
||||||
extern cpu_context ctx;
|
void fetch_data(cpu_context *ctx) {
|
||||||
|
ctx->mem_dest = 0;
|
||||||
|
ctx->dest_is_mem = false;
|
||||||
|
|
||||||
void fetch_data() {
|
if(ctx->cur_inst == NULL) return;
|
||||||
ctx.mem_dest = 0;
|
|
||||||
ctx.dest_is_mem = false;
|
|
||||||
|
|
||||||
if(ctx.cur_inst == NULL) return;
|
switch(ctx->cur_inst->mode) {
|
||||||
|
|
||||||
switch(ctx.cur_inst->mode) {
|
|
||||||
case AM_IMP: return;
|
case AM_IMP: return;
|
||||||
case AM_R:
|
case AM_R:
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
return;
|
return;
|
||||||
case AM_R_R:
|
case AM_R_R:
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
return;
|
return;
|
||||||
case AM_R_D8:
|
case AM_R_D8:
|
||||||
ctx.fetched_data = bus_read(ctx.regs.pc);
|
ctx->fetched_data = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
return;
|
return;
|
||||||
case AM_R_D16:
|
case AM_R_D16:
|
||||||
case AM_D16: {
|
case AM_D16: {
|
||||||
u16 lo = bus_read(ctx.regs.pc);
|
u16 lo = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
u16 hi = bus_read(ctx.regs.pc+1);
|
u16 hi = bus_read(ctx->regs.pc+1);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.fetched_data = lo | (hi << 8);
|
ctx->fetched_data = lo | (hi << 8);
|
||||||
ctx.regs.pc += 2;
|
ctx->regs.pc += 2;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AM_MR_R:
|
case AM_MR_R:
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->mem_dest = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
|
|
||||||
if (ctx.cur_inst->reg_1 == RT_C) {
|
if (ctx->cur_inst->reg_1 == RT_C) {
|
||||||
ctx.mem_dest |= 0xFF00;
|
ctx->mem_dest |= 0xFF00;
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
case AM_R_MR: {
|
case AM_R_MR: {
|
||||||
u16 addr = cpu_read_reg(ctx.cur_inst->reg_2);
|
u16 addr = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
if(ctx.cur_inst->reg_2 == RT_C) {
|
if(ctx->cur_inst->reg_2 == RT_C) {
|
||||||
addr |= 0xFF00;
|
addr |= 0xFF00;
|
||||||
}
|
}
|
||||||
ctx.fetched_data = bus_read(addr);
|
ctx->fetched_data = bus_read(addr);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case AM_R_HLI:
|
case AM_R_HLI:
|
||||||
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_2));
|
ctx->fetched_data = bus_read(cpu_read_reg(ctx->cur_inst->reg_2));
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
||||||
return;
|
return;
|
||||||
case AM_R_HLD:
|
case AM_R_HLD:
|
||||||
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_2));
|
ctx->fetched_data = bus_read(cpu_read_reg(ctx->cur_inst->reg_2));
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
||||||
return;
|
return;
|
||||||
case AM_HLI_R:
|
case AM_HLI_R:
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->mem_dest = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)+1);
|
||||||
return;
|
return;
|
||||||
case AM_HLD_R:
|
case AM_HLD_R:
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->mem_dest = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
cpu_set_reg(RT_HL, cpu_read_reg(RT_HL)-1);
|
||||||
return;
|
return;
|
||||||
case AM_R_A8:
|
case AM_R_A8:
|
||||||
u16 addr = bus_read(ctx.regs.pc) | 0xFF00;
|
u16 addr = bus_read(ctx->regs.pc) | 0xFF00;
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.fetched_data = bus_read(addr);
|
ctx->fetched_data = bus_read(addr);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
return;
|
return;
|
||||||
case AM_A8_R:
|
case AM_A8_R:
|
||||||
ctx.mem_dest = bus_read(ctx.regs.pc) | 0xFF00;
|
ctx->mem_dest = bus_read(ctx->regs.pc) | 0xFF00;
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
return;
|
return;
|
||||||
case AM_HL_SPR:
|
case AM_HL_SPR:
|
||||||
ctx.fetched_data = bus_read(ctx.regs.pc);
|
ctx->fetched_data = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
return;
|
return;
|
||||||
case AM_D8:
|
case AM_D8:
|
||||||
ctx.fetched_data = bus_read(ctx.regs.pc);
|
ctx->fetched_data = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
return;
|
return;
|
||||||
case AM_A16_R:
|
case AM_A16_R:
|
||||||
case AM_D16_R: {
|
case AM_D16_R: {
|
||||||
u16 lo = bus_read(ctx.regs.pc);
|
u16 lo = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
u16 hi = bus_read(ctx.regs.pc+1);
|
u16 hi = bus_read(ctx->regs.pc+1);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.mem_dest = lo | (hi << 8);
|
ctx->mem_dest = lo | (hi << 8);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
ctx.regs.pc += 2;
|
ctx->regs.pc += 2;
|
||||||
ctx.fetched_data = cpu_read_reg(ctx.cur_inst->reg_2);
|
ctx->fetched_data = cpu_read_reg(ctx->cur_inst->reg_2);
|
||||||
} return;
|
} return;
|
||||||
|
|
||||||
case AM_MR_D8:
|
case AM_MR_D8:
|
||||||
ctx.fetched_data = bus_read(ctx.regs.pc);
|
ctx->fetched_data = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc++;
|
ctx->regs.pc++;
|
||||||
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->mem_dest = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case AM_MR:
|
case AM_MR:
|
||||||
ctx.mem_dest = cpu_read_reg(ctx.cur_inst->reg_1);
|
ctx->mem_dest = cpu_read_reg(ctx->cur_inst->reg_1);
|
||||||
ctx.dest_is_mem = true;
|
ctx->dest_is_mem = true;
|
||||||
ctx.fetched_data = bus_read(cpu_read_reg(ctx.cur_inst->reg_1));
|
ctx->fetched_data = bus_read(cpu_read_reg(ctx->cur_inst->reg_1));
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
return;
|
return;
|
||||||
|
|
||||||
case AM_R_A16: {
|
case AM_R_A16: {
|
||||||
u16 lo = bus_read(ctx.regs.pc);
|
u16 lo = bus_read(ctx->regs.pc);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
u16 hi = bus_read(ctx.regs.pc+1);
|
u16 hi = bus_read(ctx->regs.pc+1);
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.fetched_data = bus_read(lo | (hi << 8));
|
ctx->fetched_data = bus_read(lo | (hi << 8));
|
||||||
emu_cycles(1);
|
emu_cycles(1);
|
||||||
ctx.regs.pc += 2;
|
ctx->regs.pc += 2;
|
||||||
} return;
|
} return;
|
||||||
default:
|
default:
|
||||||
printf("Unknown Addressing Mode! %d (%02X)\n", ctx.cur_inst->mode, ctx.cur_opcode);
|
printf("Unknown Addressing Mode! %d (%02X)\n", ctx->cur_inst->mode, ctx->cur_opcode);
|
||||||
exit(-7);
|
exit(-7);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -1,66 +1,64 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <bus.h>
|
#include <bus.h>
|
||||||
|
|
||||||
extern cpu_context ctx;
|
|
||||||
|
|
||||||
u16 reverse(u16 n) {
|
u16 reverse(u16 n) {
|
||||||
return ((n & 0XFF00) >> 8) | ((n & 0x00FF) << 8);
|
return ((n & 0XFF00) >> 8) | ((n & 0x00FF) << 8);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 cpu_read_reg(reg_type rt) {
|
u16 cpu_read_reg(reg_type rt) {
|
||||||
switch(rt) {
|
switch(rt) {
|
||||||
case RT_A: return ctx.regs.a;
|
case RT_A: return cpu_get_context()->regs.a;
|
||||||
case RT_F: return ctx.regs.f;
|
case RT_F: return cpu_get_context()->regs.f;
|
||||||
case RT_B: return ctx.regs.b;
|
case RT_B: return cpu_get_context()->regs.b;
|
||||||
case RT_C: return ctx.regs.c;
|
case RT_C: return cpu_get_context()->regs.c;
|
||||||
case RT_D: return ctx.regs.d;
|
case RT_D: return cpu_get_context()->regs.d;
|
||||||
case RT_E: return ctx.regs.e;
|
case RT_E: return cpu_get_context()->regs.e;
|
||||||
case RT_H: return ctx.regs.h;
|
case RT_H: return cpu_get_context()->regs.h;
|
||||||
case RT_L: return ctx.regs.l;
|
case RT_L: return cpu_get_context()->regs.l;
|
||||||
|
|
||||||
case RT_AF: return reverse(*((u16 *)&ctx.regs.a));
|
case RT_AF: return reverse(*((u16 *)&cpu_get_context()->regs.a));
|
||||||
case RT_BC: return reverse(*((u16 *)&ctx.regs.b));
|
case RT_BC: return reverse(*((u16 *)&cpu_get_context()->regs.b));
|
||||||
case RT_DE: return reverse(*((u16 *)&ctx.regs.d));
|
case RT_DE: return reverse(*((u16 *)&cpu_get_context()->regs.d));
|
||||||
case RT_HL: return reverse(*((u16 *)&ctx.regs.h));
|
case RT_HL: return reverse(*((u16 *)&cpu_get_context()->regs.h));
|
||||||
|
|
||||||
case RT_PC: return ctx.regs.pc;
|
case RT_PC: return cpu_get_context()->regs.pc;
|
||||||
case RT_SP: return ctx.regs.sp;
|
case RT_SP: return cpu_get_context()->regs.sp;
|
||||||
default: return 0;
|
default: return 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_set_reg(reg_type rt, u16 val) {
|
void cpu_set_reg(reg_type rt, u16 val) {
|
||||||
switch(rt) {
|
switch(rt) {
|
||||||
case RT_A: ctx.regs.a = val & 0XFF; break;
|
case RT_A: cpu_get_context()->regs.a = val & 0XFF; break;
|
||||||
case RT_F: ctx.regs.f = val & 0XFF; break;
|
case RT_F: cpu_get_context()->regs.f = val & 0XFF; break;
|
||||||
case RT_B: ctx.regs.b = val & 0XFF; break;
|
case RT_B: cpu_get_context()->regs.b = val & 0XFF; break;
|
||||||
case RT_C: ctx.regs.c = val & 0XFF; break;
|
case RT_C: cpu_get_context()->regs.c = val & 0XFF; break;
|
||||||
case RT_D: ctx.regs.d = val & 0XFF; break;
|
case RT_D: cpu_get_context()->regs.d = val & 0XFF; break;
|
||||||
case RT_E: ctx.regs.e = val & 0XFF; break;
|
case RT_E: cpu_get_context()->regs.e = val & 0XFF; break;
|
||||||
case RT_H: ctx.regs.h = val & 0XFF; break;
|
case RT_H: cpu_get_context()->regs.h = val & 0XFF; break;
|
||||||
case RT_L: ctx.regs.l = val & 0XFF; break;
|
case RT_L: cpu_get_context()->regs.l = val & 0XFF; break;
|
||||||
|
|
||||||
case RT_AF: *((u16 *)&ctx.regs.a) = reverse(val); break;
|
case RT_AF: *((u16 *)&cpu_get_context()->regs.a) = reverse(val); break;
|
||||||
case RT_BC: *((u16 *)&ctx.regs.b) = reverse(val); break;
|
case RT_BC: *((u16 *)&cpu_get_context()->regs.b) = reverse(val); break;
|
||||||
case RT_DE: *((u16 *)&ctx.regs.d) = reverse(val); break;
|
case RT_DE: *((u16 *)&cpu_get_context()->regs.d) = reverse(val); break;
|
||||||
case RT_HL: *((u16 *)&ctx.regs.h) = reverse(val); break;
|
case RT_HL: *((u16 *)&cpu_get_context()->regs.h) = reverse(val); break;
|
||||||
|
|
||||||
case RT_PC: ctx.regs.pc = val; break;
|
case RT_PC: cpu_get_context()->regs.pc = val; break;
|
||||||
case RT_SP: ctx.regs.sp = val; break;
|
case RT_SP: cpu_get_context()->regs.sp = val; break;
|
||||||
case RT_NONE: break;
|
case RT_NONE: break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 cpu_read_reg8(reg_type rt) {
|
u8 cpu_read_reg8(reg_type rt) {
|
||||||
switch(rt) {
|
switch(rt) {
|
||||||
case RT_A: return ctx.regs.a;
|
case RT_A: return cpu_get_context()->regs.a;
|
||||||
case RT_F: return ctx.regs.f;
|
case RT_F: return cpu_get_context()->regs.f;
|
||||||
case RT_B: return ctx.regs.b;
|
case RT_B: return cpu_get_context()->regs.b;
|
||||||
case RT_C: return ctx.regs.c;
|
case RT_C: return cpu_get_context()->regs.c;
|
||||||
case RT_D: return ctx.regs.d;
|
case RT_D: return cpu_get_context()->regs.d;
|
||||||
case RT_E: return ctx.regs.e;
|
case RT_E: return cpu_get_context()->regs.e;
|
||||||
case RT_H: return ctx.regs.h;
|
case RT_H: return cpu_get_context()->regs.h;
|
||||||
case RT_L: return ctx.regs.l;
|
case RT_L: return cpu_get_context()->regs.l;
|
||||||
|
|
||||||
case RT_HL: {
|
case RT_HL: {
|
||||||
return bus_read(cpu_read_reg(RT_HL));
|
return bus_read(cpu_read_reg(RT_HL));
|
||||||
@ -73,14 +71,14 @@ u8 cpu_read_reg8(reg_type rt) {
|
|||||||
|
|
||||||
void cpu_set_reg8(reg_type rt, u8 val) {
|
void cpu_set_reg8(reg_type rt, u8 val) {
|
||||||
switch(rt) {
|
switch(rt) {
|
||||||
case RT_A: ctx.regs.a = val & 0xFF; break;
|
case RT_A: cpu_get_context()->regs.a = val & 0xFF; break;
|
||||||
case RT_F: ctx.regs.f = val & 0xFF; break;
|
case RT_F: cpu_get_context()->regs.f = val & 0xFF; break;
|
||||||
case RT_B: ctx.regs.b = val & 0xFF; break;
|
case RT_B: cpu_get_context()->regs.b = val & 0xFF; break;
|
||||||
case RT_C: ctx.regs.c = val & 0xFF; break;
|
case RT_C: cpu_get_context()->regs.c = val & 0xFF; break;
|
||||||
case RT_D: ctx.regs.d = val & 0xFF; break;
|
case RT_D: cpu_get_context()->regs.d = val & 0xFF; break;
|
||||||
case RT_E: ctx.regs.e = val & 0xFF; break;
|
case RT_E: cpu_get_context()->regs.e = val & 0xFF; break;
|
||||||
case RT_H: ctx.regs.h = val & 0xFF; break;
|
case RT_H: cpu_get_context()->regs.h = val & 0xFF; break;
|
||||||
case RT_L: ctx.regs.l = val & 0xFF; break;
|
case RT_L: cpu_get_context()->regs.l = val & 0xFF; break;
|
||||||
|
|
||||||
case RT_HL: bus_write(cpu_read_reg(RT_HL), val); break;
|
case RT_HL: bus_write(cpu_read_reg(RT_HL), val); break;
|
||||||
|
|
||||||
@ -91,13 +89,13 @@ void cpu_set_reg8(reg_type rt, u8 val) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
cpu_registers *cpu_get_regs() {
|
cpu_registers *cpu_get_regs() {
|
||||||
return &ctx.regs;
|
return &cpu_get_context()->regs;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 cpu_get_int_flags(){
|
u8 cpu_get_int_flags(){
|
||||||
return ctx.int_flags;
|
return cpu_get_context()->int_flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cpu_set_int_flags(u8 value){
|
void cpu_set_int_flags(u8 value){
|
||||||
ctx.int_flags = value;
|
cpu_get_context()->int_flags = value;
|
||||||
}
|
}
|
92
lib/debug.c
Normal file
92
lib/debug.c
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
#include <debug.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <cpu.h>
|
||||||
|
#include <emu.h>
|
||||||
|
#include <bus.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
static debug_context ctx;
|
||||||
|
|
||||||
|
debug_context *debug_get_context() {
|
||||||
|
return &ctx;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char **dissasembly;
|
||||||
|
|
||||||
|
void debug_init() {
|
||||||
|
dissasembly = malloc(sizeof(char*) * 0x10000);
|
||||||
|
for(int i = 0; i < 0x10000; i++) {
|
||||||
|
dissasembly[i] = malloc(sizeof(char) * 100);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void debug_update() {
|
||||||
|
switch(ctx.state) {
|
||||||
|
case DS_MAIN:
|
||||||
|
char flags[16];
|
||||||
|
sprintf(flags, "%c%c%c%c",
|
||||||
|
cpu_get_context()->regs.f & (1 << 7) ? 'Z' : '-',
|
||||||
|
cpu_get_context()->regs.f & (1 << 6) ? 'N' : '-',
|
||||||
|
cpu_get_context()->regs.f & (1 << 5) ? 'H' : '-',
|
||||||
|
cpu_get_context()->regs.f & (1 << 4) ? 'C' : '-'
|
||||||
|
);
|
||||||
|
|
||||||
|
char inst[16];
|
||||||
|
inst_to_str(cpu_get_context(), inst);
|
||||||
|
printf("%08lX - %04X: %-12s (%02X %02X %02X) A: %02X F: %s BC: %02X%02X DE: %02X%02X HL: %02X%02X SP: %04X PC: %04X\n", emu_get_context()->ticks, cpu_get_context()->inst_pc, inst, cpu_get_context()->cur_opcode, bus_read(cpu_get_context()->inst_pc+1), bus_read(cpu_get_context()->inst_pc+2), cpu_get_context()->regs.a, flags, cpu_get_context()->regs.b, cpu_get_context()->regs.c, cpu_get_context()->regs.d, cpu_get_context()->regs.e, cpu_get_context()->regs.h, cpu_get_context()->regs.l, cpu_get_context()->regs.sp, cpu_get_context()->regs.pc);
|
||||||
|
printf("> ");
|
||||||
|
char cmd[128];
|
||||||
|
scanf("%s", cmd);
|
||||||
|
if(!strcmp(cmd, "q")) {
|
||||||
|
emu_get_context()->die = true;
|
||||||
|
emu_get_context()->debug = false;
|
||||||
|
emu_get_context()->paused = false;
|
||||||
|
emu_stop();
|
||||||
|
} else if(!strcmp(cmd, "r")) {
|
||||||
|
emu_get_context()->debug = false;
|
||||||
|
emu_get_context()->paused = false;
|
||||||
|
} else if(!strcmp(cmd, "d")) {
|
||||||
|
ctx.dissasembly_target = cpu_get_context()->inst_pc;
|
||||||
|
ctx.state = DS_DISASSEMBLE;
|
||||||
|
} else if(!strcmp(cmd, "da")) {
|
||||||
|
scanf("%d", &ctx.dissasembly_target);
|
||||||
|
ctx.state = DS_DISASSEMBLE;
|
||||||
|
} else if(!strcmp(cmd, "du")) {
|
||||||
|
ctx.dissasembly_target--;
|
||||||
|
ctx.state = DS_DISASSEMBLE;
|
||||||
|
} else if(!strcmp(cmd, "dd")) {
|
||||||
|
scanf("%d", &ctx.dissasembly_target);
|
||||||
|
ctx.state = DS_DISASSEMBLE;
|
||||||
|
} else if(cmd[0] == 's') {
|
||||||
|
int steps;
|
||||||
|
scanf("%d", &steps);
|
||||||
|
printf("adding %d steps\n", steps);
|
||||||
|
emu_get_context()->step += steps;
|
||||||
|
emu_get_context()->debug = false;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case DS_DISASSEMBLE:
|
||||||
|
cpu_context cpu_ctx = {0};
|
||||||
|
u16 i = 0;
|
||||||
|
while (cpu_ctx.regs.pc <= 0xFFFF) {
|
||||||
|
u16 pc = cpu_ctx.regs.pc;
|
||||||
|
fetch_instruction(&cpu_ctx);
|
||||||
|
fetch_data(&cpu_ctx);
|
||||||
|
char inst[16];
|
||||||
|
inst_to_str(cpu_get_context(), inst);
|
||||||
|
sprintf(dissasembly[i], "%04X: %s", pc, inst);
|
||||||
|
if(pc == cpu_get_context()->inst_pc) {
|
||||||
|
ctx.dissasembly_scroll = i - 5;
|
||||||
|
ctx.dissasembly_pc = i;
|
||||||
|
}
|
||||||
|
i++;
|
||||||
|
if(cpu_ctx.regs.pc < pc)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
for(int j = ctx.dissasembly_scroll; j < ctx.dissasembly_pc+6; j++) {
|
||||||
|
printf("%c %s\n", j == ctx.dissasembly_pc ? '>' : ' ', dissasembly[j]);
|
||||||
|
}
|
||||||
|
ctx.state = DS_MAIN;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
14
lib/emu.c
14
lib/emu.c
@ -8,6 +8,7 @@
|
|||||||
#include <ppu.h>
|
#include <ppu.h>
|
||||||
#include <audio.h>
|
#include <audio.h>
|
||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
@ -34,10 +35,10 @@ void *cpu_run(void *p) {
|
|||||||
ctx.ticks = 0;
|
ctx.ticks = 0;
|
||||||
|
|
||||||
while (ctx.running) {
|
while (ctx.running) {
|
||||||
if (ctx.paused) {
|
//if (ctx.paused) {
|
||||||
delay(10);
|
// delay(10);
|
||||||
continue;
|
// continue;
|
||||||
}
|
//}
|
||||||
|
|
||||||
if (!cpu_step()) {
|
if (!cpu_step()) {
|
||||||
printf("CPU stopped\n");
|
printf("CPU stopped\n");
|
||||||
@ -113,7 +114,7 @@ int emu_run(int argc, char **argv) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
u32 prev_frame = 0;
|
u32 prev_frame = 0;
|
||||||
|
debug_init();
|
||||||
while(!ctx.die) {
|
while(!ctx.die) {
|
||||||
sleep_ms(1);
|
sleep_ms(1);
|
||||||
ui_handle_events();
|
ui_handle_events();
|
||||||
@ -121,6 +122,9 @@ int emu_run(int argc, char **argv) {
|
|||||||
ui_update();
|
ui_update();
|
||||||
//}
|
//}
|
||||||
//prev_frame = ppu_get_context()->current_frame;
|
//prev_frame = ppu_get_context()->current_frame;
|
||||||
|
if(ctx.debug) {
|
||||||
|
debug_update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
10
lib/ui.c
10
lib/ui.c
@ -9,6 +9,7 @@
|
|||||||
#include <cpu.h>
|
#include <cpu.h>
|
||||||
#include <cart.h>
|
#include <cart.h>
|
||||||
#include <state.h>
|
#include <state.h>
|
||||||
|
#include <debug.h>
|
||||||
|
|
||||||
#include <SDL.h>
|
#include <SDL.h>
|
||||||
#include <SDL_ttf.h>
|
#include <SDL_ttf.h>
|
||||||
@ -353,12 +354,9 @@ void ui_on_key(bool down, u32 key_code) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if(key_code == SDLK_d && down == true) {
|
if(key_code == SDLK_d && down == true) {
|
||||||
ppu_get_context()->debug = !ppu_get_context()->debug;
|
emu_get_context()->debug = true;
|
||||||
if(ppu_get_context()->debug) {
|
debug_get_context()->state = DS_MAIN;
|
||||||
printf("PPU Debug Enabled\n");
|
emu_get_context()->paused = true;
|
||||||
} else {
|
|
||||||
printf("PPU Debug Disabled\n");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if(key_code == SDLK_r && down == true) {
|
if(key_code == SDLK_r && down == true) {
|
||||||
emu_stop();
|
emu_stop();
|
||||||
|
Reference in New Issue
Block a user