all repos — mgba @ eb4b53a7c4dc292e71e2796c19cdb59b828367b6

mGBA Game Boy Advance Emulator

GB: Initial BIOS support
Jeffrey Pfau jeffrey@endrift.com
Thu, 19 May 2016 22:31:13 -0700
commit

eb4b53a7c4dc292e71e2796c19cdb59b828367b6

parent

2f33cd70f601c06809c34ee58bf4ca964cec7318

6 files changed, 93 insertions(+), 26 deletions(-)

jump to
M src/gb/core.csrc/gb/core.c

@@ -13,6 +13,7 @@ #include "gb/renderers/software.h"

#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 @@ } else {

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 @@ return GBLoadROM(core->board, 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) {
M src/gb/gb.csrc/gb/gb.c

@@ -88,6 +88,7 @@ return false;

} 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 @@ }

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 @@ }

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 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) {
M src/gb/gb.hsrc/gb/gb.h

@@ -62,6 +62,7 @@ size_t pristineRomSize;

size_t yankedRomSize; uint32_t romCrc32; struct VFile* romVf; + struct VFile* biosVf; struct VFile* sramVf; struct mAVStream* stream;

@@ -107,6 +108,8 @@ bool GBLoadROM(struct GB* gb, struct VFile* vf);

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);
M src/gb/io.csrc/gb/io.c

@@ -311,6 +311,12 @@ break;

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);
M src/gb/memory.csrc/gb/memory.c

@@ -52,7 +52,7 @@ case GB_REGION_CART_BANK0 + 1:

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 @@ case GB_REGION_CART_BANK0:

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:
M src/gb/memory.hsrc/gb/memory.h

@@ -112,6 +112,7 @@

struct mRotationSource; struct GBMemory { uint8_t* rom; + uint8_t* romBase; uint8_t* romBank; enum GBMemoryBankControllerType mbcType; GBMemoryBankController mbc;