GB MBC: Add MBC6 flash support (read-only currently)
Vicki Pfau vi@endrift.com
Thu, 03 Sep 2020 23:43:47 -0700
4 files changed,
63 insertions(+),
14 deletions(-)
M
CHANGES
→
CHANGES
@@ -5,9 +5,8 @@ - WebP and APNG recording
- Separate overrides for GBC games that can also run on SGB or regular GB - Mute option in homebrew ports - Status indicators for fast-forward and mute in homebrew ports - - Support for unlicensed Pokemon Jade/Diamond Game Boy mapper - - Support for unlicensed BBD Game Boy mapper - - Support for unlicensed Hitek Game Boy mapper + - Read-only support for MBC6 flash memory + - New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek - Stack tracing tools in ARM debugger (by ahigerd) - Command scripts for CLI debugger (by ahigerd) Emulation fixes:
M
include/mgba/internal/gb/memory.h
→
include/mgba/internal/gb/memory.h
@@ -61,6 +61,8 @@ GB_SIZE_WORKING_RAM_BANK0 = 0x1000,
GB_SIZE_OAM = 0xA0, GB_SIZE_IO = 0x80, GB_SIZE_HRAM = 0x7F, + + GB_SIZE_MBC6_FLASH = 0x100000, }; enum {@@ -118,6 +120,8 @@ uint8_t* romBank1;
bool sramAccess; int currentSramBank1; uint8_t* sramBank1; + bool flashBank0; + bool flashBank1; }; struct GBMBC7State {
M
src/gb/mbc.c
→
src/gb/mbc.c
@@ -53,6 +53,8 @@
static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address); static void _GBPocketCamCapture(struct GBMemory*); +static void _GBMBC6MapChip(struct GB*, int half, uint8_t value); + void GBMBCSwitchBank(struct GB* gb, int bank) { size_t bankStart = bank * GB_SIZE_CART_BANK0; if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {@@ -81,19 +83,37 @@ }
void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) { size_t bankStart = bank * GB_SIZE_CART_HALFBANK; - if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) { - mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); - bankStart &= (gb->memory.romSize - 1); - bank = bankStart / GB_SIZE_CART_HALFBANK; - if (!bank) { - ++bank; + bool isFlash = half ? gb->memory.mbcState.mbc6.flashBank1 : gb->memory.mbcState.mbc6.flashBank0; + if (isFlash) { + if (bankStart + GB_SIZE_CART_HALFBANK > GB_SIZE_MBC6_FLASH) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid Flash bank: %0X", bank); + bankStart &= GB_SIZE_MBC6_FLASH - 1; + bank = bankStart / GB_SIZE_CART_HALFBANK; + } + bankStart += gb->sramSize - GB_SIZE_MBC6_FLASH; + } else { + if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank); + bankStart &= gb->memory.romSize - 1; + bank = bankStart / GB_SIZE_CART_HALFBANK; + if (!bank) { + ++bank; + } } } if (!half) { - gb->memory.romBank = &gb->memory.rom[bankStart]; + if (isFlash) { + gb->memory.romBank = &gb->memory.sram[bankStart]; + } else { + gb->memory.romBank = &gb->memory.rom[bankStart]; + } gb->memory.currentBank = bank; } else { - gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart]; + if (isFlash) { + gb->memory.mbcState.mbc6.romBank1 = &gb->memory.sram[bankStart]; + } else { + gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart]; + } gb->memory.mbcState.mbc6.currentBank1 = bank; } if (gb->cpu->pc < GB_BASE_VRAM) {@@ -187,9 +207,10 @@ }
void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) { size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK; - if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > gb->sramSize) { + size_t sramSize = gb->sramSize - GB_SIZE_MBC6_FLASH; + if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > sramSize) { mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank); - bankStart &= (gb->sramSize - 1); + bankStart &= (sramSize - 1); bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK; } if (!half) {@@ -334,6 +355,7 @@ case GB_MBC6:
gb->memory.mbcWrite = _GBMBC6; gb->memory.mbcRead = _GBMBC6Read; gb->memory.directSramAccess = false; + gb->sramSize += GB_SIZE_MBC6_FLASH; // Flash is concatenated at the end break; case GB_MBC7: gb->memory.mbcWrite = _GBMBC7;@@ -689,13 +711,27 @@ break;
case 0x2: GBMBCSwitchSramHalfBank(gb, 1, bank); break; + case 0x3: + mLOG(GB_MBC, STUB, "MBC6 unimplemented flash OE write: %04X:%02X", address, value); + break; + case 0x4: + mLOG(GB_MBC, STUB, "MBC6 unimplemented flash WE write: %04X:%02X", address, value); + break; case 0x8: case 0x9: GBMBCSwitchHalfBank(gb, 0, bank); break; + case 0xA: + case 0xB: + _GBMBC6MapChip(gb, 0, value); + break; case 0xC: case 0xD: GBMBCSwitchHalfBank(gb, 1, bank); + break; + case 0xE: + case 0xF: + _GBMBC6MapChip(gb, 1, value); break; case 0x28: case 0x29:@@ -730,6 +766,16 @@ case 0xB:
return memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)]; } return 0xFF; +} + +static void _GBMBC6MapChip(struct GB* gb, int half, uint8_t value) { + if (!half) { + gb->memory.mbcState.mbc6.flashBank0 = !!(value & 0x08); + GBMBCSwitchHalfBank(gb, half, gb->memory.currentBank); + } else { + gb->memory.mbcState.mbc6.flashBank1 = !!(value & 0x08); + GBMBCSwitchHalfBank(gb, half, gb->memory.mbcState.mbc6.currentBank1); + } } void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {