diff --git a/cli/CMakeLists.txt b/cli/CMakeLists.txt index b80293f..ccbf053 100644 --- a/cli/CMakeLists.txt +++ b/cli/CMakeLists.txt @@ -20,6 +20,7 @@ add_executable(gb6 ../src/instructions.c ../src/lcd.c ../src/rom.c + ../src/mbc.c emulator.c lcd_imgui.c imgui/imgui_demo.cpp diff --git a/src/cpu.c b/src/cpu.c index 7f3ffbf..fff4b21 100644 --- a/src/cpu.c +++ b/src/cpu.c @@ -453,6 +453,34 @@ static void conditional_jump(struct cpu *cpu, u8 opc, u8 neg_op, int flag) { } } +static void daa(struct cpu *cpu) +{ + // https://forums.nesdev.org/viewtopic.php?t=15944 + if (!flag_isset(cpu, FLAG_SIGN)) { + if (flag_isset(cpu, FLAG_CARRY) || cpu->a > 0x99) { + cpu->a += 0x60; + set_flag(cpu, FLAG_CARRY); + } + if (flag_isset(cpu, FLAG_HALF_CARRY) || (cpu->a & 0x0f) > 0x09) { + cpu->a += 0x6; + } + } else { + if (flag_isset(cpu, FLAG_CARRY)) { + cpu->a -= 0x60; + } + if (flag_isset(cpu, FLAG_HALF_CARRY)) { + cpu->a -= 0x6; + } + } + + if (cpu->a) { + set_flag(cpu, FLAG_ZERO); + } else { + clear_flag(cpu, FLAG_ZERO); + } + clear_flag(cpu, FLAG_HALF_CARRY); +} + static u16 handlers[] = { 0x40, 0x48, 0x50, 0x58, 0x60 }; static u16 check_interrupts(struct cpu *cpu) @@ -480,6 +508,9 @@ static u16 check_interrupts(struct cpu *cpu) return 0; } +/* +*/ + void cpu_step(struct cpu *cpu) { u8 temp; @@ -512,6 +543,9 @@ void cpu_step(struct cpu *cpu) case 0x0f: // RRCA cpu->a = rrc(cpu, cpu->a); break; + case 0x10: // STOP + cpu->pc++; + break; case 0x11: // LD DE,d16 write_de(cpu, read16(cpu, cpu->pc)); cpu->pc += 2; @@ -892,6 +926,7 @@ void cpu_step(struct cpu *cpu) case 0xff: push(cpu, cpu->pc); cpu->pc = 0x38; break; case 0x27: // DAA + daa(cpu); break; case 0x76: // HALT diff --git a/src/dmg.c b/src/dmg.c index 4541208..0fde300 100644 --- a/src/dmg.c +++ b/src/dmg.c @@ -5,6 +5,7 @@ #include "rom.h" #include "lcd.h" #include "dmg.h" +#include "mbc.h" #include "types.h" #include "bootstrap.h" @@ -54,6 +55,12 @@ static int counter; u8 dmg_read(void *_dmg, u16 address) { struct dmg *dmg = (struct dmg *) _dmg; + u8 mbc_data; + + if (mbc_read(dmg->rom->mbc, dmg, address, &mbc_data)) { + return mbc_data; + } + // if (address < 0x100) { // return dmg_boot_rom[address]; // } else if (address < 0x4000) { @@ -93,6 +100,11 @@ u8 dmg_read(void *_dmg, u16 address) void dmg_write(void *_dmg, u16 address, u8 data) { struct dmg *dmg = (struct dmg *) _dmg; + + if (mbc_write(dmg->rom->mbc, dmg, address, data)) { + return; + } + if (address < 0x4000) { printf("warning: writing 0x%04x in rom\n", address); } else if (address < 0x8000) { diff --git a/src/dmg.h b/src/dmg.h index 2ae02b0..3419fd9 100644 --- a/src/dmg.h +++ b/src/dmg.h @@ -1,9 +1,7 @@ #ifndef _DMG_H #define _DMG_H -#include "cpu.h" -#include "rom.h" -#include "lcd.h" +#include "types.h" #define FIELD_JOY 1 #define FIELD_ACTION 2 @@ -17,6 +15,10 @@ #define BUTTON_SELECT (1 << 2) #define BUTTON_START (1 << 3) +struct cpu; +struct rom; +struct lcd; + struct dmg { struct cpu *cpu; struct rom *rom; diff --git a/src/mbc.c b/src/mbc.c new file mode 100644 index 0000000..2601820 --- /dev/null +++ b/src/mbc.c @@ -0,0 +1,91 @@ +#include +#include + +#include "types.h" +#include "mbc.h" +#include "dmg.h" +#include "rom.h" + +static int mbc_noop_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data) +{ + return 0; +} + +static int mbc_noop_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data) +{ + return 0; +} + +static int mbc1_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data) +{ + if (addr >= 0x4000 && addr <= 0x7fff) { + int use_bank = mbc->rom_bank || 1; + *out_data = dmg->rom->data[0x4000 * use_bank + (addr & 0x3fff)]; + return 1; + } else if (addr >= 0xa000 && addr <= 0xbfff) { + if (mbc->ram_enabled) { + *out_data = mbc->ram[0x2000 * mbc->ram_bank + (addr & 0x1fff)]; + } else { + *out_data = 0xff; + } + return 1; + } + + return 0; +} + +static int mbc1_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data) +{ + if (addr >= 0 && addr <= 0x1fff) { + mbc->ram_enabled = (data & 0xf) == 0xa; + return 1; + } else if (addr >= 0x2000 && addr <= 0x3fff) { + mbc->rom_bank = data & 0x1f; + return 1; + } else if (addr >= 0x4000 && addr <= 0x5fff) { + mbc->ram_bank = data & 0x03; + return 1; + } else if (addr >= 0x6000 && addr <= 0x7fff) { + //printf("sel %d\n", data); + return 1; + } else if (addr >= 0xa000 && addr <= 0xbfff) { + if (mbc->ram_enabled) { + mbc->ram[0x2000 * mbc->ram_bank + (addr & 0x1fff)] = data; + return 1; + } + } + return 0; +} + +struct mbc mbc_noop = { + mbc_noop_read, + mbc_noop_write, +}; + +struct mbc mbc1 = { + mbc1_read, + mbc1_write, +}; + +struct mbc *mbc_new(int type) +{ + switch (type) { + case 0: + return &mbc_noop; + case 1: + case 2: + case 3: + return &mbc1; + } + return NULL; +} + +int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data) +{ + return mbc->read_fn(mbc, dmg, addr, out_data); +} + +int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data) +{ + return mbc->write_fn(mbc, dmg, addr, data); +} diff --git a/src/mbc.h b/src/mbc.h new file mode 100644 index 0000000..d1d429b --- /dev/null +++ b/src/mbc.h @@ -0,0 +1,22 @@ +#ifndef _MBC_H +#define _MBC_H + +#include "types.h" + +struct dmg; + +struct mbc { + int (*read_fn)(struct mbc *, struct dmg *, u16, u8 *); + int (*write_fn)(struct mbc *, struct dmg *, u16, u8); + int type; + int rom_bank; + int ram_bank; + int ram_enabled; + u8 ram[0x8000]; +}; + +struct mbc *mbc_new(int type); +int mbc_read(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 *out_data); +int mbc_write(struct mbc *mbc, struct dmg *dmg, u16 addr, u8 data); + +#endif \ No newline at end of file diff --git a/src/rom.c b/src/rom.c index 86b4349..f3d1130 100644 --- a/src/rom.c +++ b/src/rom.c @@ -17,12 +17,15 @@ int rom_load(struct rom *rom, const char *filename) len = ftell(fp); rewind(fp); - rom->type = 0; // TODO read type from cart rom->data = malloc(len); rom->length = len; if (fread(rom->data, 1, len, fp) < len) { return 0; } + rom->mbc = mbc_new(rom->data[0x147]); + if (!rom->mbc) { + return 0; + } return 1; } diff --git a/src/rom.h b/src/rom.h index 4bcb1f5..a0bf7b5 100644 --- a/src/rom.h +++ b/src/rom.h @@ -2,11 +2,12 @@ #define _ROM_H #include "types.h" +#include "mbc.h" struct rom { u32 length; - int type; u8 *data; + struct mbc *mbc; }; int rom_load(struct rom *rom, const char *filename);