GB MBC: Add MBC6 flash support (read-only currently)

This commit is contained in:
Vicki Pfau 2020-09-03 23:43:47 -07:00
parent 2251d93938
commit 347c5f2de5
4 changed files with 63 additions and 14 deletions

View File

@ -5,9 +5,8 @@ Features:
- 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:

View File

@ -57,7 +57,7 @@ The following mappers are fully supported:
The following mappers are partially supported:
- MBC6 (missing flash memory support)
- MBC6 (missing flash memory write support)
- MMM01
- Pocket Cam
- TAMA5 (missing RTC support)

View File

@ -61,6 +61,8 @@ enum {
GB_SIZE_OAM = 0xA0,
GB_SIZE_IO = 0x80,
GB_SIZE_HRAM = 0x7F,
GB_SIZE_MBC6_FLASH = 0x100000,
};
enum {
@ -118,6 +120,8 @@ struct GBMBC6State {
bool sramAccess;
int currentSramBank1;
uint8_t* sramBank1;
bool flashBank0;
bool flashBank1;
};
struct GBMBC7State {

View File

@ -53,6 +53,8 @@ static uint8_t _GBHitekRead(struct GBMemory*, uint16_t address);
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 GBMBCSwitchBank0(struct GB* gb, int bank) {
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 GBMBCSwitchSramBank(struct GB* gb, int bank) {
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 @@ void GBMBCInit(struct GB* gb) {
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,14 +711,28 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
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:
case 0x2A:
@ -732,6 +768,16 @@ uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
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) {
int bank = value & 0x7F;
switch (address >> 13) {