memory: separate the memory-related code into it's own file
After doing a little reading about the way the memory banks are mapped, it looks like this code is going to grow. Separate it into it's own file. While we're at it, make gb_mem_read() a proper function instead of a callback. Because these functions are used so frequently, this corresponds to a ~10-20% performance benefit (due to LTO).
This commit is contained in:
131
src/apps/gbdb.c
131
src/apps/gbdb.c
@@ -20,8 +20,6 @@
|
||||
|
||||
#define INPUT_MAX_LEN 512
|
||||
#define MAX_BREAKPTS 16 /* Should be plenty for anyone */
|
||||
#define MAX_RAM_LEN (1 << 20) /* Up to 8Mb Cartridge */
|
||||
#define UNMAP_BOOTROM_ADDR 0xff50
|
||||
|
||||
typedef void (gbdb_cmd)(char *arg_string);
|
||||
|
||||
@@ -29,7 +27,6 @@ static void breakpoint_addr_hit(uint16_t id);
|
||||
static void breakpoint_cb(struct lr35902_state *lr);
|
||||
static void reset_breakpoints(void);
|
||||
|
||||
static uint8_t ram[MAX_RAM_LEN];
|
||||
static const char prompt[] = "gbdb >";
|
||||
static const char usage[] =
|
||||
"Available commands:\n"
|
||||
@@ -44,11 +41,7 @@ static const char usage[] =
|
||||
static struct lr35902_ops cpu_ops;
|
||||
static struct lr35902_state cpu;
|
||||
static struct gb_video video;
|
||||
|
||||
static unsigned char bootrom[0x100] = {0};
|
||||
static unsigned char cart_low[0x100] = {0};
|
||||
|
||||
static int bootrom_mapped = 1;
|
||||
static void *memory = NULL;
|
||||
|
||||
static int paused_breakpoint = 0;
|
||||
static volatile sig_atomic_t paused_signal = 0;
|
||||
@@ -90,76 +83,13 @@ static void strip_newline(char *string)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* ram_{read,write} work easily because the cartridge is mapped to 0x0000
|
||||
*
|
||||
*/
|
||||
static uint8_t mem_read(struct lr35902_state *cpu, uint16_t addr)
|
||||
{
|
||||
|
||||
switch (addr) {
|
||||
case 0xFF40 ... 0xFF4B:
|
||||
return gb_video_mem_read(&video, addr);
|
||||
default:
|
||||
return ram[addr];
|
||||
}
|
||||
}
|
||||
|
||||
static void mem_write(struct lr35902_state *cpu, uint16_t addr, uint8_t val)
|
||||
{
|
||||
|
||||
switch (addr) {
|
||||
case UNMAP_BOOTROM_ADDR:
|
||||
if (val == 1) {
|
||||
bootrom_mapped = 0;
|
||||
memcpy(ram, cart_low, sizeof(cart_low));
|
||||
gb_log("bootrom unmapped\n");
|
||||
}
|
||||
break;
|
||||
case 0xFF40 ... 0xFF4B:
|
||||
gb_video_mem_write(&video, addr, val);
|
||||
break;
|
||||
case 0 ... 0x100:
|
||||
if (bootrom_mapped) {
|
||||
break;
|
||||
}
|
||||
/* Intentional fall-through */
|
||||
default:
|
||||
ram[addr] = val;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void mem_dump(char *filename)
|
||||
{
|
||||
//TODO: Check error codes like a real programmer :P
|
||||
FILE* dump_file;
|
||||
char *token = strtok(filename, " ");
|
||||
|
||||
if (token == NULL) {
|
||||
gb_log("usage: load <file>\n");
|
||||
return;
|
||||
}
|
||||
strip_newline(token);
|
||||
dump_file = fopen(token, "w");
|
||||
if(dump_file == NULL) {
|
||||
gb_log("Failed to open mem dump file: %d\n", errno);
|
||||
return;
|
||||
}
|
||||
fwrite(ram, MAX_RAM_LEN, 1, dump_file);
|
||||
fclose(dump_file);
|
||||
}
|
||||
|
||||
static void init(void)
|
||||
{
|
||||
cpu_ops.mem_read = mem_read;
|
||||
cpu_ops.mem_write = mem_write;
|
||||
cpu_ops.undef_d3 = breakpoint_cb;
|
||||
|
||||
lr35902_init(&cpu, &cpu_ops);
|
||||
lr35902_init(&cpu, memory, &cpu_ops);
|
||||
gb_video_init(&video);
|
||||
memset(&ram, 0, MAX_RAM_LEN);
|
||||
bootrom_mapped = 1;
|
||||
gb_mem_init(memory, &video);
|
||||
}
|
||||
|
||||
static void cycle()
|
||||
@@ -255,7 +185,7 @@ static void regs(char *arg_list)
|
||||
static void peek(char *arg_list)
|
||||
{
|
||||
uint16_t pc = lr35902_get_reg_16(&cpu, LR35902_REG_PC);
|
||||
uint8_t byte = mem_read(&cpu, pc);
|
||||
uint8_t byte = gb_mem_read(memory, pc);
|
||||
printf("0x%04x:%s\n", pc, gb_byte_to_opcode(byte));
|
||||
}
|
||||
|
||||
@@ -400,7 +330,7 @@ static void mem(char *arg_list)
|
||||
|
||||
for (i = 0; i < bytes; i++) {
|
||||
//TODO: Make sure this has no side effects
|
||||
int val = mem_read(&cpu, addr + i);
|
||||
uint8_t val = gb_mem_read(memory, addr + i);
|
||||
|
||||
if (token != NULL && token[0] == 'i') {
|
||||
printf("0x%04x:%s\n", addr + i, gb_byte_to_opcode(val));
|
||||
@@ -413,29 +343,6 @@ static void mem(char *arg_list)
|
||||
|
||||
}
|
||||
|
||||
static void load_file_to_buffer(char *filename, uint8_t *buffer, size_t size)
|
||||
{
|
||||
//TODO: Check error codes like a real programmer :P
|
||||
FILE* prog_file;
|
||||
long filesize;
|
||||
|
||||
prog_file = fopen(filename, "r");
|
||||
if(prog_file < 0) {
|
||||
printf("Failed to load game file: %d\n", errno);
|
||||
return;
|
||||
}
|
||||
|
||||
fseek(prog_file, 0, SEEK_END);
|
||||
filesize = ftell(prog_file);
|
||||
fseek(prog_file, 0, SEEK_SET);
|
||||
|
||||
if (fread(buffer, MIN(filesize, size), 1, prog_file) < 0) {
|
||||
printf("Failed to read filed: %d\n", errno);
|
||||
}
|
||||
fclose(prog_file);
|
||||
|
||||
}
|
||||
|
||||
static void load(char *arg_list)
|
||||
{
|
||||
char *token = strtok(arg_list, " ");
|
||||
@@ -445,9 +352,8 @@ static void load(char *arg_list)
|
||||
}
|
||||
|
||||
strip_newline(token);
|
||||
load_file_to_buffer(token, ram, sizeof(ram));
|
||||
load_file_to_buffer(token, cart_low, sizeof(cart_low));
|
||||
|
||||
gb_memory_load_file(memory, GB_MEMORY_CART, token);
|
||||
}
|
||||
|
||||
static void load_bootrom(char *arg_list)
|
||||
@@ -459,8 +365,8 @@ static void load_bootrom(char *arg_list)
|
||||
}
|
||||
|
||||
strip_newline(token);
|
||||
load_file_to_buffer(token, bootrom, sizeof(bootrom));
|
||||
load_file_to_buffer(token, ram, sizeof(bootrom));
|
||||
|
||||
gb_memory_load_file(memory, GB_MEMORY_BOOTROM, token);
|
||||
}
|
||||
|
||||
|
||||
@@ -469,7 +375,7 @@ static void quit(char *arg_list)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
static void do_run(void) {
|
||||
static __attribute__((hot)) void do_run(void) {
|
||||
paused = 0;
|
||||
signal(SIGINT, break_execution_handler);
|
||||
|
||||
@@ -501,7 +407,6 @@ static struct breakpoint {
|
||||
int id;
|
||||
bool temp;
|
||||
uint8_t op;
|
||||
uint8_t *ptr;
|
||||
} breakpoints[MAX_BREAKPTS];
|
||||
|
||||
static int num_breakpoints = 0;
|
||||
@@ -525,7 +430,7 @@ static void reset_breakpoints(void)
|
||||
|
||||
for (i = 0; i < num_breakpoints; i++) {
|
||||
struct breakpoint *bkpt = &breakpoints[i];
|
||||
*bkpt->ptr = 0xd3;
|
||||
gb_mem_force_write(memory, bkpt->addr, 0xd3);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,15 +440,10 @@ static int do_set_breakpoint(uint16_t addr, bool temp)
|
||||
|
||||
if (num_breakpoints < ARRAY_SIZE(breakpoints)) {
|
||||
breakpoints[num_breakpoints].addr = addr;
|
||||
breakpoints[num_breakpoints].op = mem_read(NULL, addr);
|
||||
if (bootrom_mapped && addr < 0x100) {
|
||||
breakpoints[num_breakpoints].ptr = &bootrom[addr];
|
||||
} else {
|
||||
breakpoints[num_breakpoints].ptr = &ram[addr];
|
||||
}
|
||||
*breakpoints[num_breakpoints].ptr = 0xd3;
|
||||
breakpoints[num_breakpoints].op = gb_mem_read(memory, addr);
|
||||
breakpoints[num_breakpoints].id = id++;
|
||||
breakpoints[num_breakpoints].temp = temp;
|
||||
gb_mem_force_write(memory, addr, 0xd3);
|
||||
num_breakpoints++;
|
||||
} else {
|
||||
printf("maximum number of breakpoints reached\n");
|
||||
@@ -593,8 +493,8 @@ static int do_delete_breakpoint(int id)
|
||||
return -1;
|
||||
}
|
||||
|
||||
*bkpt->ptr = bkpt->op;
|
||||
|
||||
gb_mem_force_write(memory, bkpt->addr, bkpt->op);
|
||||
|
||||
index = bkpt - breakpoints;
|
||||
memmove(&breakpoints[index], &breakpoints[index + 1],
|
||||
num_breakpoints - index - 1);
|
||||
@@ -816,7 +716,8 @@ int main(int argc, char **argv)
|
||||
tri_add_string(&commands, "load", load);
|
||||
tri_add_string(&commands, "bootrom", load_bootrom);
|
||||
tri_add_string(&commands, "mem", mem);
|
||||
tri_add_string(&commands, "dump", mem_dump);
|
||||
/* FIXME */
|
||||
/* tri_add_string(&commands, "dump", mem_dump); */
|
||||
tri_add_string(&commands, "peek", peek);
|
||||
tri_add_string(&commands, "help", help);
|
||||
tri_add_string(&commands, "?", help);
|
||||
|
||||
Reference in New Issue
Block a user