commit 3e264da356ccbd3878d552f6de1006448ae9a1b9 Author: Matt Laux Date: Tue Apr 16 01:25:00 2019 -0500 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..1377554 --- /dev/null +++ b/.gitignore @@ -0,0 +1 @@ +*.swp diff --git a/src/cpu.c b/src/cpu.c new file mode 100644 index 0000000..21b682a --- /dev/null +++ b/src/cpu.c @@ -0,0 +1,80 @@ +#include +#include + +#include "cpu.h" +#include "types.h" + +void cpu_bind_mem_model( + struct cpu *cpu, + void *mem_model, + u8 (*mem_read)(void *, u16), + void (*mem_write)(void *, u16, u8) +) { + cpu->mem_model = mem_model; + cpu->mem_read = mem_read; + cpu->mem_write = mem_write; +} + +static inline u16 read_af(struct cpu *cpu) +{ + return cpu->a << 8 | cpu->f; +} + +static inline u16 read_bc(struct cpu *cpu) +{ + return cpu->b << 8 | cpu->c; +} + +static inline u16 read_de(struct cpu *cpu) +{ + return cpu->d << 8 | cpu->e; +} + +static inline u16 read_hl(struct cpu *cpu) +{ + return cpu->h << 8 | cpu->l; +} + +static inline void write_af(struct cpu *cpu, int value) +{ + cpu->a = value >> 8; + cpu->f = value & 0xff; +} + +static inline void write_bc(struct cpu *cpu, int value) +{ + cpu->b = value >> 8; + cpu->c = value & 0xff; +} + +static inline void write_de(struct cpu *cpu, int value) +{ + cpu->d = value >> 8; + cpu->e = value & 0xff; +} + +static inline void write_hl(struct cpu *cpu, int value) +{ + cpu->h = value >> 8; + cpu->l = value & 0xff; +} + +void cpu_panic(struct cpu *cpu) +{ + printf("a=%02x f=%02x b=%02x c=%02x\n", cpu->a, cpu->f, cpu->b, cpu->c); + printf("d=%02x e=%02x h=%02x l=%02x\n", cpu->d, cpu->e, cpu->h, cpu->l); + exit(0); +} + +void cpu_step(struct cpu *cpu) +{ + u8 opc = cpu->mem_read(cpu->mem_model, cpu->pc); + switch (opc) { + case 0: // NOP + cpu->pc++; + break; + default: + printf("unknown opcode %02x\n", opc); + cpu_panic(cpu); + } +} diff --git a/src/cpu.h b/src/cpu.h new file mode 100644 index 0000000..a565d73 --- /dev/null +++ b/src/cpu.h @@ -0,0 +1,38 @@ +#ifndef _CPU_H +#define _CPU_H + +#include "types.h" + +struct cpu +{ + u8 a; + u8 f; + u8 b; + u8 c; + u8 d; + u8 e; + u8 h; + u8 l; + u16 sp; + u16 pc; + + u8 (*mem_read)(void *, u16); + void (*mem_write)(void *, u16, u8); + void *mem_model; +}; + +void cpu_bind_mem_model( + struct cpu *cpu, + void *mem_model, + u8 (*mem_read)(void *, u16), + void (*mem_write)(void *, u16, u8) +); + +void cpu_step(struct cpu *cpu); + +#define FLAG_Z(cpu) ((cpu)->f >> 7 & 1) +#define FLAG_N(cpu) ((cpu)->f >> 6 & 1) +#define FLAG_H(cpu) ((cpu)->f >> 5 & 1) +#define FLAG_C(cpu) ((cpu)->f >> 4 & 1) + +#endif diff --git a/src/dmg.c b/src/dmg.c new file mode 100644 index 0000000..c3c9bb6 --- /dev/null +++ b/src/dmg.c @@ -0,0 +1,36 @@ +#include "cpu.h" +#include "rom.h" +#include "dmg.h" +#include "types.h" + +void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom) +{ + dmg->cpu = cpu; + dmg->rom = rom; +} + +u8 dmg_read(void *_dmg, u16 address) +{ + struct dmg *dmg = (struct dmg *) _dmg; + if (address < 0x4000) { + return dmg->rom->data[address]; + } else if (address < 0x8000) { + // TODO switchable rom bank + return dmg->rom->data[address]; + } else if (address < 0xa000) { + return dmg->video_ram[address - 0x8000]; + } else if (address < 0xc000) { + // TODO switchable ram bank + return 0; + } else if (address < 0xe000) { + return dmg->main_ram[address - 0xc000]; + } else { + // not sure about any of this yet + return 0; + } +} + +void dmg_write(void *_dmg, u16 address, u8 data) +{ + struct dmg *dmg = (struct dmg *) _dmg; +} diff --git a/src/dmg.h b/src/dmg.h new file mode 100644 index 0000000..2070a48 --- /dev/null +++ b/src/dmg.h @@ -0,0 +1,19 @@ +#ifndef _DMG_H +#define _DMG_H + +#include "cpu.h" +#include "rom.h" + +struct dmg { + struct cpu *cpu; + struct rom *rom; + u8 main_ram[0x2000]; + u8 video_ram[0x2000]; +}; + +void dmg_new(struct dmg *dmg, struct cpu *cpu, struct rom *rom); + +u8 dmg_read(void *dmg, u16 address); +void dmg_write(void *dmg, u16 address, u8 data); + +#endif diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..997bb6a --- /dev/null +++ b/src/main.c @@ -0,0 +1,37 @@ +#include + +#include "dmg.h" +#include "cpu.h" +#include "rom.h" + +int main(int argc, char *argv[]) +{ + struct cpu cpu; + struct rom rom; + struct dmg dmg; + + if (argc < 2) { + printf("no rom specified\n"); + return 1; + } + + if (!rom_load(&rom, argv[1])) { + printf("error loading rom\n"); + return 1; + } + + // this might be too much abstraction but it'll let me + // test the cpu, rom, and dmg independently and use the cpu + // for other non-GB stuff + dmg_new(&dmg, &cpu, &rom); + cpu_bind_mem_model(&cpu, &dmg, dmg_read, dmg_write); + + cpu.pc = 0x100; + + while (1) { + cpu_step(&cpu); + } + + rom_free(&rom); + return 0; +} diff --git a/src/rom.c b/src/rom.c new file mode 100644 index 0000000..7eaa1e2 --- /dev/null +++ b/src/rom.c @@ -0,0 +1,32 @@ +#include +#include +#include "rom.h" +#include "types.h" + +int rom_load(struct rom *rom, const char *filename) +{ + FILE *fp; + int len; + + fp = fopen(filename, "r"); + if (!fp) { + return 0; + } + + fseek(fp, 0, SEEK_END); + len = ftell(fp); + rewind(fp); + + rom->type = 0; // TODO read type from cart + rom->data = malloc(len); + if (fread(rom->data, 1, len, fp) < len) { + return 0; + } + + return 1; +} + +void rom_free(struct rom *rom) +{ + free(rom->data); +} diff --git a/src/rom.h b/src/rom.h new file mode 100644 index 0000000..97e1cfc --- /dev/null +++ b/src/rom.h @@ -0,0 +1,16 @@ +#ifndef _ROM_H +#define _ROM_H + +#include "types.h" + +struct rom { + int type; + u8 *data; +}; + + +int rom_load(struct rom *rom, const char *filename); + +void rom_free(struct rom *rom); + +#endif diff --git a/src/types.h b/src/types.h new file mode 100644 index 0000000..0404438 --- /dev/null +++ b/src/types.h @@ -0,0 +1,7 @@ +#ifndef _TYPES_H +#define _TYPES_H + +typedef unsigned char u8; +typedef unsigned short u16; + +#endif