diff --git a/src/gb/core.c b/src/gb/core.c index 0ca70be10..d693eeb0f 100644 --- a/src/gb/core.c +++ b/src/gb/core.c @@ -13,6 +13,7 @@ #include "lr35902/debugger/debugger.h" #include "util/memory.h" #include "util/patch.h" +#include "util/vfs.h" struct GBCore { struct mCore d; @@ -93,6 +94,16 @@ static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* conf gb->audio.masterVolume = core->opts.volume; } gb->video.frameskip = core->opts.frameskip; + +#if !defined(MINIMAL_CORE) || MINIMAL_CORE < 2 + struct VFile* bios = 0; + if (core->opts.useBios && core->opts.bios) { + bios = VFileOpen(core->opts.bios, O_RDONLY); + } + if (bios) { + GBLoadBIOS(gb, bios); + } +#endif } static void _GBCoreDesiredVideoDimensions(struct mCore* core, unsigned* width, unsigned* height) { @@ -148,11 +159,9 @@ static bool _GBCoreLoadROM(struct mCore* core, struct VFile* vf) { } static bool _GBCoreLoadBIOS(struct mCore* core, struct VFile* vf, int type) { - UNUSED(core); - UNUSED(vf); UNUSED(type); - // TODO - return false; + GBLoadBIOS(core->board, vf); + return true; } static bool _GBCoreLoadSave(struct mCore* core, struct VFile* vf) { diff --git a/src/gb/gb.c b/src/gb/gb.c index abd3f7e84..c14051a52 100644 --- a/src/gb/gb.c +++ b/src/gb/gb.c @@ -88,6 +88,7 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf) { } gb->yankedRomSize = 0; gb->memory.rom = gb->pristineRom; + gb->memory.romBase = gb->memory.rom; gb->memory.romSize = gb->pristineRomSize; gb->romCrc32 = doCrc32(gb->memory.rom, gb->memory.romSize); @@ -109,6 +110,9 @@ bool GBLoadSave(struct GB* gb, struct VFile* vf) { void GBUnloadROM(struct GB* gb) { // TODO: Share with GBAUnloadROM + if (gb->memory.rom && gb->memory.romBase != gb->memory.rom) { + free(gb->memory.romBase); + } if (gb->memory.rom && gb->pristineRom != gb->memory.rom) { if (gb->yankedRomSize) { gb->yankedRomSize = 0; @@ -135,6 +139,10 @@ void GBUnloadROM(struct GB* gb) { gb->memory.sram = 0; } +void GBLoadBIOS(struct GB* gb, struct VFile* vf) { + gb->biosVf = vf; +} + void GBApplyPatch(struct GB* gb, struct Patch* patch) { size_t patchedSize = patch->outputSize(patch, gb->memory.romSize); if (!patchedSize) { @@ -171,31 +179,71 @@ void GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) { void GBReset(struct LR35902Core* cpu) { struct GB* gb = (struct GB*) cpu->master; - const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; - if (cart->cgb & 0x80) { - gb->model = GB_MODEL_CGB; - gb->audio.style = GB_AUDIO_CGB; - cpu->a = 0x11; - cpu->f.packed = 0x80; + if (gb->biosVf) { + gb->biosVf->seek(gb->biosVf, 0, SEEK_SET); + gb->memory.romBase = malloc(GB_SIZE_CART_BANK0); + ssize_t size = gb->biosVf->read(gb->biosVf, gb->memory.romBase, GB_SIZE_CART_BANK0); + uint32_t biosCrc = doCrc32(gb->memory.romBase, size); + switch (biosCrc) { + case 0x59C8598E: + gb->model = GB_MODEL_DMG; + gb->audio.style = GB_AUDIO_DMG; + break; + case 0x41884E46: + gb->model = GB_MODEL_CGB; + gb->audio.style = GB_AUDIO_CGB; + break; + default: + free(gb->memory.romBase); + gb->memory.romBase = gb->memory.rom; + gb->biosVf = NULL; + break; + } + + memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size); + if (size > 0x100) { + memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge)); + } + + cpu->a = 0; + cpu->f.packed = 0; cpu->c = 0; - cpu->e = 0x08; + cpu->e = 0; cpu->h = 0; - cpu->l = 0x7C; - } else { - // TODO: SGB - gb->model = GB_MODEL_DMG; - gb->audio.style = GB_AUDIO_DMG; - cpu->a = 1; - cpu->f.packed = 0xB0; - cpu->c = 0x13; - cpu->e = 0xD8; - cpu->h = 1; - cpu->l = 0x4D; + cpu->l = 0; + cpu->sp = 0; + cpu->pc = 0; } + if (!gb->biosVf) { + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + if (cart->cgb & 0x80) { + gb->model = GB_MODEL_CGB; + gb->audio.style = GB_AUDIO_CGB; + cpu->a = 0x11; + cpu->f.packed = 0x80; + cpu->c = 0; + cpu->e = 0x08; + cpu->h = 0; + cpu->l = 0x7C; + } else { + // TODO: SGB + gb->model = GB_MODEL_DMG; + gb->audio.style = GB_AUDIO_DMG; + cpu->a = 1; + cpu->f.packed = 0xB0; + cpu->c = 0x13; + cpu->e = 0xD8; + cpu->h = 1; + cpu->l = 0x4D; + } + + cpu->sp = 0xFFFE; + cpu->pc = 0x100; + } + cpu->b = 0; cpu->d = 0; - cpu->sp = 0xFFFE; - cpu->pc = 0x100; + cpu->memory.setActiveRegion(cpu, cpu->pc); if (gb->yankedRomSize) { diff --git a/src/gb/gb.h b/src/gb/gb.h index e7c5ccd8a..f803a68a5 100644 --- a/src/gb/gb.h +++ b/src/gb/gb.h @@ -62,6 +62,7 @@ struct GB { size_t yankedRomSize; uint32_t romCrc32; struct VFile* romVf; + struct VFile* biosVf; struct VFile* sramVf; struct mAVStream* stream; @@ -108,6 +109,8 @@ bool GBLoadSave(struct GB* gb, struct VFile* vf); void GBYankROM(struct GB* gb); void GBUnloadROM(struct GB* gb); +void GBLoadBIOS(struct GB* gb, struct VFile* vf); + struct Patch; void GBApplyPatch(struct GB* gb, struct Patch* patch); diff --git a/src/gb/io.c b/src/gb/io.c index a6d67be0a..5eed35823 100644 --- a/src/gb/io.c +++ b/src/gb/io.c @@ -311,6 +311,12 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) { case REG_STAT: GBVideoWriteSTAT(&gb->video, value); break; + case 0x50: + if (gb->memory.romBase != gb->memory.rom) { + free(gb->memory.romBase); + gb->memory.romBase = gb->memory.rom; + } + break; case REG_IE: gb->memory.ie = value; GBUpdateIRQs(gb); diff --git a/src/gb/memory.c b/src/gb/memory.c index c5271fbb7..dbafa7dab 100644 --- a/src/gb/memory.c +++ b/src/gb/memory.c @@ -52,7 +52,7 @@ static void GBSetActiveRegion(struct LR35902Core* cpu, uint16_t address) { case GB_REGION_CART_BANK0 + 2: case GB_REGION_CART_BANK0 + 3: cpu->memory.cpuLoad8 = GBFastLoad8; - cpu->memory.activeRegion = memory->rom; + cpu->memory.activeRegion = memory->romBase; cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1; cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1; break; @@ -211,7 +211,7 @@ uint8_t GBLoad8(struct LR35902Core* cpu, uint16_t address) { case GB_REGION_CART_BANK0 + 1: case GB_REGION_CART_BANK0 + 2: case GB_REGION_CART_BANK0 + 3: - return memory->rom[address & (GB_SIZE_CART_BANK0 - 1)]; + return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)]; case GB_REGION_CART_BANK1: case GB_REGION_CART_BANK1 + 1: case GB_REGION_CART_BANK1 + 2: diff --git a/src/gb/memory.h b/src/gb/memory.h index f2f4a4d26..84fe2efd3 100644 --- a/src/gb/memory.h +++ b/src/gb/memory.h @@ -112,6 +112,7 @@ union GBMBCState { struct mRotationSource; struct GBMemory { uint8_t* rom; + uint8_t* romBase; uint8_t* romBank; enum GBMemoryBankControllerType mbcType; GBMemoryBankController mbc;