GB: Add overrides

This commit is contained in:
Jeffrey Pfau 2016-09-09 16:29:52 -07:00
parent d8a6d940ed
commit 38e3858852
9 changed files with 322 additions and 86 deletions

View File

@ -10,9 +10,11 @@
#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 GBCore {
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 @@ static bool _GBCoreInit(struct mCore* core) {
}
core->cpu = cpu;
core->board = gb;
gbcore->overrides = NULL;
gbcore->debuggerPlatform = NULL;
gbcore->cheatDevice = NULL;
@ -107,6 +111,8 @@ static void _GBCoreLoadConfig(struct mCore* core, const struct mCoreConfig* conf
if (bios) {
GBLoadBIOS(gb, bios);
}
struct GBCore* gbcore = (struct GBCore*) core;
gbcore->overrides = mCoreConfigGetOverridesConst(config);
#endif
}
@ -200,6 +206,16 @@ static void _GBCoreReset(struct mCore* core) {
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);
}

View File

@ -115,6 +115,10 @@ static void GBSramDeinit(struct GB* gb) {
}
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 GBInterruptHandlerInit(struct LR35902InterruptHandler* irqh) {
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,36 +278,41 @@ void GBReset(struct LR35902Core* cpu) {
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;
@ -339,6 +332,50 @@ void GBReset(struct LR35902Core* cpu) {
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) {
int irqs = gb->memory.ie & gb->memory.io[REG_IF];
if (!irqs) {

View File

@ -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);

View File

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

View File

@ -64,62 +64,100 @@ void GBMBCInit(struct GB* gb) {
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:
gb->memory.mbc = _GBMBC1;
gb->memory.mbcType = GB_MBC1;
break;
case 5:
case 6:
case GB_MBC1:
gb->memory.mbc = _GBMBC1;
break;
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:
case GB_MBC5:
gb->memory.mbc = _GBMBC5;
gb->memory.mbcType = GB_MBC5;
break;
case 0x1C:
case 0x1D:
case 0x1E:
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;
}

View File

@ -69,7 +69,7 @@ void GBMemoryInit(struct GB* gb) {
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;

View File

@ -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);
@ -55,20 +55,6 @@ enum {
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;
typedef void (*GBMemoryBankController)(struct GB*, uint16_t address, uint8_t value);

114
src/gb/overrides.c Normal file
View File

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

27
src/gb/overrides.h Normal file
View File

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