GB: Add overrides
Jeffrey Pfau jeffrey@endrift.com
Fri, 09 Sep 2016 16:29:52 -0700
9 files changed,
321 insertions(+),
85 deletions(-)
M
src/gb/core.c
→
src/gb/core.c
@@ -10,9 +10,11 @@ #include "gb/cheats.h"
#include "gb/cli.h" #include "gb/gb.h" #include "gb/mbc.h" +#include "gb/overrides.h" #include "gb/renderers/software.h" #include "gb/serialize.h" #include "lr35902/debugger/debugger.h" +#include "util/crc32.h" #include "util/memory.h" #include "util/patch.h" #include "util/vfs.h"@@ -22,6 +24,7 @@ struct mCore d;
struct GBVideoSoftwareRenderer renderer; uint8_t keys; struct mCPUComponent* components[CPU_COMPONENT_MAX]; + const struct Configuration* overrides; struct mDebuggerPlatform* debuggerPlatform; struct mCheatDevice* cheatDevice; };@@ -38,6 +41,7 @@ return false;
} core->cpu = cpu; core->board = gb; + gbcore->overrides = NULL; gbcore->debuggerPlatform = NULL; gbcore->cheatDevice = NULL;@@ -107,6 +111,8 @@ }
if (bios) { GBLoadBIOS(gb, bios); } + struct GBCore* gbcore = (struct GBCore*) core; + gbcore->overrides = mCoreConfigGetOverridesConst(config); #endif }@@ -200,6 +206,16 @@ struct GB* gb = (struct GB*) core->board;
if (gbcore->renderer.outputBuffer) { GBVideoAssociateRenderer(&gb->video, &gbcore->renderer.d); } + + struct GBCartridgeOverride override; + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + if (cart) { + override.headerCrc32 = doCrc32(cart, sizeof(*cart)); + if (GBOverrideFind(gbcore->overrides, &override)) { + GBOverrideApply(gb, &override); + } + } + LR35902Reset(core->cpu); }
M
src/gb/gb.c
→
src/gb/gb.c
@@ -115,6 +115,10 @@ gb->memory.sram = 0;
} void GBResizeSram(struct GB* gb, size_t size) { + if (gb->memory.sram && size <= gb->sramSize) { + return; + } + mLOG(GB, INFO, "Resizing SRAM to %"PRIz"u bytes", size); struct VFile* vf = gb->sramVf; if (vf) { if (vf == gb->sramRealVf) {@@ -254,27 +258,11 @@ }
void GBReset(struct LR35902Core* cpu) { struct GB* gb = (struct GB*) cpu->master; - + GBDetectModel(gb); 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) {@@ -290,35 +278,40 @@ cpu->l = 0;
cpu->sp = 0; cpu->pc = 0; } + + cpu->b = 0; + cpu->d = 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 { + switch (gb->model) { + case GB_MODEL_DMG: // TODO: SGB + case GB_MODEL_SGB: + case GB_MODEL_AUTODETECT: // Silence warnings 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; + break; + case GB_MODEL_CGB: + cpu->b = 1; + // Fall through + case GB_MODEL_AGB: // Silence warnings + cpu->a = 0x11; + cpu->f.packed = 0x80; + cpu->c = 0; + cpu->e = 0x08; + cpu->h = 0; + cpu->l = 0x7C; + break; } cpu->sp = 0xFFFE; cpu->pc = 0x100; } - - cpu->b = 0; - cpu->d = 0; gb->eiPending = INT_MAX; gb->doubleSpeed = 0;@@ -337,6 +330,50 @@ GBAudioReset(&gb->audio);
GBSIOReset(&gb->sio); GBSavedataUnmask(gb); +} + +void GBDetectModel(struct GB* gb) { + if (gb->model != GB_MODEL_AUTODETECT) { + return; + } + if (gb->biosVf) { + gb->biosVf->seek(gb->biosVf, 0, SEEK_SET); + void* bios = malloc(GB_SIZE_CART_BANK0); + ssize_t size = gb->biosVf->read(gb->biosVf, bios, GB_SIZE_CART_BANK0); + uint32_t biosCrc = doCrc32(gb->memory.romBase, size); + switch (biosCrc) { + case 0x59C8598E: + gb->model = GB_MODEL_DMG; + break; + case 0x41884E46: + gb->model = GB_MODEL_CGB; + break; + default: + gb->biosVf->close(gb->biosVf); + gb->biosVf = NULL; + } + free(bios); + } + if (gb->model == GB_MODEL_AUTODETECT && gb->memory.rom) { + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + if (cart->cgb & 0x80) { + gb->model = GB_MODEL_CGB; + } else { + gb->model = GB_MODEL_DMG; + } + } + + switch (gb->model) { + case GB_MODEL_DMG: + case GB_MODEL_SGB: + case GB_MODEL_AUTODETECT: //Silence warnings + gb->audio.style = GB_AUDIO_DMG; + break; + case GB_MODEL_AGB: + case GB_MODEL_CGB: + gb->audio.style = GB_AUDIO_CGB; + break; + } } void GBUpdateIRQs(struct GB* gb) {
M
src/gb/gb.h
→
src/gb/gb.h
@@ -103,6 +103,7 @@ void GBCreate(struct GB* gb);
void GBDestroy(struct GB* gb); void GBReset(struct LR35902Core* cpu); +void GBDetectModel(struct GB* gb); void GBUpdateIRQs(struct GB* gb); void GBHalt(struct LR35902Core* cpu);
M
src/gb/interface.h
→
src/gb/interface.h
@@ -9,10 +9,27 @@
#include "util/common.h" enum GBModel { + GB_MODEL_AUTODETECT = 0xFF, GB_MODEL_DMG = 0x00, GB_MODEL_SGB = 0x40, GB_MODEL_CGB = 0x80, GB_MODEL_AGB = 0xC0 +}; + +enum GBMemoryBankControllerType { + GB_MBC_AUTODETECT = -1, + GB_MBC_NONE = 0, + GB_MBC1 = 1, + GB_MBC2 = 2, + GB_MBC3 = 3, + GB_MBC5 = 5, + GB_MBC6 = 6, + GB_MBC7 = 7, + GB_MMM01 = 0x10, + GB_HuC1 = 0x11, + GB_HuC3 = 0x12, + GB_MBC3_RTC = 0x103, + GB_MBC5_RUMBLE = 0x105 }; #endif
M
src/gb/mbc.c
→
src/gb/mbc.c
@@ -64,62 +64,100 @@ gb->sramSize = 0x8000;
break; } - switch (cart->type) { - case 0: - case 8: - case 9: + if (gb->memory.mbcType == GB_MBC_AUTODETECT) { + const struct GBCartridge* cart = (const struct GBCartridge*) &gb->memory.rom[0x100]; + switch (cart->type) { + case 0: + case 8: + case 9: + gb->memory.mbcType = GB_MBC_NONE; + break; + case 1: + case 2: + case 3: + gb->memory.mbcType = GB_MBC1; + break; + case 5: + case 6: + gb->memory.mbcType = GB_MBC2; + break; + case 0x0F: + case 0x10: + gb->memory.mbcType = GB_MBC3_RTC; + break; + case 0x11: + case 0x12: + case 0x13: + gb->memory.mbcType = GB_MBC3; + break; + default: + mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type); + // Fall through + case 0x19: + case 0x1A: + case 0x1B: + gb->memory.mbcType = GB_MBC5; + break; + case 0x1C: + case 0x1D: + case 0x1E: + gb->memory.mbcType = GB_MBC5_RUMBLE; + break; + case 0x20: + gb->memory.mbcType = GB_MBC6; + break; + case 0x22: + gb->memory.mbcType = GB_MBC7; + break; + case 0xFE: + gb->memory.mbcType = GB_HuC3; + break; + } + } + switch (gb->memory.mbcType) { + case GB_MBC_NONE: gb->memory.mbc = _GBMBCNone; - gb->memory.mbcType = GB_MBC_NONE; - return; - case 1: - case 2: - case 3: + break; + case GB_MBC1: gb->memory.mbc = _GBMBC1; - gb->memory.mbcType = GB_MBC1; break; - case 5: - case 6: + case GB_MBC2: gb->memory.mbc = _GBMBC2; - gb->memory.mbcType = GB_MBC2; gb->sramSize = 0x200; break; - case 0x0F: - case 0x10: - case 0x11: - case 0x12: - case 0x13: + case GB_MBC3: gb->memory.mbc = _GBMBC3; - gb->memory.mbcType = GB_MBC3; gb->sramSize += 0x48; break; default: mLOG(GB_MBC, WARN, "Unknown MBC type: %02X", cart->type); // Fall through - case 0x19: - case 0x1A: - case 0x1B: - gb->memory.mbc = _GBMBC5; - gb->memory.mbcType = GB_MBC5; - break; - case 0x1C: - case 0x1D: - case 0x1E: + case GB_MBC5: gb->memory.mbc = _GBMBC5; - gb->memory.mbcType = GB_MBC5_RUMBLE; break; - case 0x20: + case GB_MBC6: + mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6"); gb->memory.mbc = _GBMBC6; - gb->memory.mbcType = GB_MBC6; - gb->sramSize = 0; // TODO break; - case 0x22: + case GB_MBC7: gb->memory.mbc = _GBMBC7; - gb->memory.mbcType = GB_MBC7; - gb->sramSize = 0x2000; break; - case 0xFE: + case GB_MMM01: + mLOG(GB_MBC, WARN, "unimplemented MBC: MMM01"); + gb->memory.mbc = _GBMBC1; + break; + case GB_HuC1: + mLOG(GB_MBC, WARN, "unimplemented MBC: HuC-1"); + gb->memory.mbc = _GBMBC1; + break; + case GB_HuC3: gb->memory.mbc = _GBHuC3; - gb->memory.mbcType = GB_HuC3; + break; + case GB_MBC3_RTC: + gb->memory.mbc = _GBMBC3; + break; + case GB_MBC5_RUMBLE: + gb->memory.mbc = _GBMBC5; break; }
M
src/gb/memory.c
→
src/gb/memory.c
@@ -69,7 +69,7 @@ gb->memory.rom = 0;
gb->memory.romBank = 0; gb->memory.romSize = 0; gb->memory.sram = 0; - gb->memory.mbcType = GB_MBC_NONE; + gb->memory.mbcType = GB_MBC_AUTODETECT; gb->memory.mbc = 0; gb->memory.rtc = NULL;
M
src/gb/memory.h
→
src/gb/memory.h
@@ -9,7 +9,7 @@
#include "util/common.h" #include "core/log.h" - +#include "gb/interface.h" #include "lr35902/lr35902.h" mLOG_DECLARE_CATEGORY(GB_MBC);@@ -53,20 +53,6 @@ GB_SIZE_WORKING_RAM_BANK0 = 0x1000,
GB_SIZE_OAM = 0xA0, GB_SIZE_IO = 0x80, GB_SIZE_HRAM = 0x7F, -}; - -enum GBMemoryBankControllerType { - GB_MBC_NONE = 0, - GB_MBC1 = 1, - GB_MBC2 = 2, - GB_MBC3 = 3, - GB_MBC5 = 5, - GB_MBC6 = 6, - GB_MBC7 = 7, - GB_MMM01 = 0x10, - GB_HuC1 = 0x11, - GB_HuC3 = 0x12, - GB_MBC5_RUMBLE = 0x105 }; struct GBMemory;
A
src/gb/overrides.c
@@ -0,0 +1,114 @@
+/* Copyright (c) 2013-2015 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#include "overrides.h" + +#include "gb/gb.h" + +#include "util/configuration.h" +#include "util/crc32.h" + +static const struct GBCartridgeOverride _overrides[] = { + // None yet + { 0, 0, 0 } +}; + +bool GBOverrideFind(const struct Configuration* config, struct GBCartridgeOverride* override) { + override->model = GB_MODEL_AUTODETECT; + override->mbc = GB_MBC_AUTODETECT; + bool found = false; + + int i; + for (i = 0; _overrides[i].headerCrc32; ++i) { + if (override->headerCrc32 == _overrides[i].headerCrc32) { + *override = _overrides[i]; + found = true; + break; + } + } + + if (config) { + char sectionName[24] = ""; + snprintf(sectionName, sizeof(sectionName), "gb.override.%08X", override->headerCrc32); + const char* model = ConfigurationGetValue(config, sectionName, "model"); + const char* mbc = ConfigurationGetValue(config, sectionName, "mbc"); + + if (model) { + if (strcasecmp(model, "DMG") == 0) { + found = true; + override->model = GB_MODEL_DMG; + } else if (strcasecmp(model, "CGB") == 0) { + found = true; + override->model = GB_MODEL_CGB; + } else if (strcasecmp(model, "AGB") == 0) { + found = true; + override->model = GB_MODEL_AGB; + } else if (strcasecmp(model, "SGB") == 0) { + found = true; + override->model = GB_MODEL_DMG; // TODO + } else if (strcasecmp(model, "MGB") == 0) { + found = true; + override->model = GB_MODEL_DMG; // TODO + } + } + + if (mbc) { + char* end; + long type = strtoul(mbc, &end, 0); + if (end && !*end) { + override->mbc = type; + found = true; + } + } + } + return found; +} + +void GBOverrideSave(struct Configuration* config, const struct GBCartridgeOverride* override) { + char sectionName[24] = ""; + snprintf(sectionName, sizeof(sectionName), "gb.override.%08X", override->headerCrc32); + const char* model = 0; + switch (override->model) { + case GB_MODEL_DMG: + model = "DMG"; + break; + case GB_MODEL_SGB: + model = "SGB"; + break; + case GB_MODEL_CGB: + model = "CGB"; + break; + case GB_MODEL_AGB: + model = "AGB"; + break; + case GB_MODEL_AUTODETECT: + break; + } + ConfigurationSetValue(config, sectionName, "model", model); + + if (override->mbc != GB_MBC_AUTODETECT) { + ConfigurationSetIntValue(config, sectionName, "mbc", override->mbc); + } else { + ConfigurationClearValue(config, sectionName, "mbc"); + } +} + +void GBOverrideApply(struct GB* gb, const struct GBCartridgeOverride* override) { + if (override->model != GB_MODEL_AUTODETECT) { + gb->model = override->model; + } + + if (override->mbc != GB_MBC_AUTODETECT) { + gb->memory.mbcType = override->mbc; + } +} + +void GBOverrideApplyDefaults(struct GB* gb) { + struct GBCartridgeOverride override; + override.headerCrc32 = doCrc32(&gb->memory.rom[0x100], sizeof(struct GBCartridge)); + if (GBOverrideFind(0, &override)) { + GBOverrideApply(gb, &override); + } +}
A
src/gb/overrides.h
@@ -0,0 +1,27 @@
+/* Copyright (c) 2013-2016 Jeffrey Pfau + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +#ifndef GB_OVERRIDES_H +#define GB_OVERRIDES_H + +#include "util/common.h" + +#include "gb/interface.h" + +struct GBCartridgeOverride { + int headerCrc32; + enum GBModel model; + enum GBMemoryBankControllerType mbc; +}; + +struct Configuration; +bool GBOverrideFind(const struct Configuration*, struct GBCartridgeOverride* override); +void GBOverrideSave(struct Configuration*, const struct GBCartridgeOverride* override); + +struct GB; +void GBOverrideApply(struct GB*, const struct GBCartridgeOverride*); +void GBOverrideApplyDefaults(struct GB*); + +#endif