all repos — mgba @ 4a10ea2f699d0d2bade8df17d513ba5f90bef949

mGBA Game Boy Advance Emulator

GB MBC: Add MBC6 SRAM support
Vicki Pfau vi@endrift.com
Wed, 18 Apr 2018 18:26:50 -0700
commit

4a10ea2f699d0d2bade8df17d513ba5f90bef949

parent

f23f221d49b82007aeb030babadec6071da40f8b

4 files changed, 65 insertions(+), 3 deletions(-)

jump to
M include/mgba/internal/gb/mbc.hinclude/mgba/internal/gb/mbc.h

@@ -21,6 +21,7 @@ void GBMBCSwitchBank(struct GB* gb, int bank);

void GBMBCSwitchBank0(struct GB* gb, int bank); void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank); void GBMBCSwitchSramBank(struct GB* gb, int bank); +void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank); enum GBCam { GBCAM_WIDTH = 128,
M include/mgba/internal/gb/memory.hinclude/mgba/internal/gb/memory.h

@@ -26,6 +26,8 @@ GB_BASE_CART_HALFBANK1 = 0x4000,

GB_BASE_CART_HALFBANK2 = 0x6000, GB_BASE_VRAM = 0x8000, GB_BASE_EXTERNAL_RAM = 0xA000, + GB_BASE_EXTERNAL_RAM_HALFBANK0 = 0xA000, + GB_BASE_EXTERNAL_RAM_HALFBANK1 = 0xB000, GB_BASE_WORKING_RAM_BANK0 = 0xC000, GB_BASE_WORKING_RAM_BANK1 = 0xD000, GB_BASE_OAM = 0xFE00,

@@ -53,6 +55,7 @@ GB_SIZE_CART_MAX = 0x800000,

GB_SIZE_VRAM = 0x4000, GB_SIZE_VRAM_BANK0 = 0x2000, GB_SIZE_EXTERNAL_RAM = 0x2000, + GB_SIZE_EXTERNAL_RAM_HALFBANK = 0x1000, GB_SIZE_WORKING_RAM = 0x8000, GB_SIZE_WORKING_RAM_BANK0 = 0x1000, GB_SIZE_OAM = 0xA0,

@@ -110,6 +113,9 @@

struct GBMBC6State { int currentBank1; uint8_t* romBank1; + bool sramAccess; + int currentSramBank1; + uint8_t* sramBank1; }; struct GBMBC7State {
M src/gb/mbc.csrc/gb/mbc.c

@@ -32,6 +32,7 @@ static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);

static void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value); static uint8_t _GBMBC2Read(struct GBMemory*, uint16_t address); +static uint8_t _GBMBC6Read(struct GBMemory*, uint16_t address); static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address); static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);

@@ -112,6 +113,22 @@ bank = bankStart / GB_SIZE_EXTERNAL_RAM;

} gb->memory.sramBank = &gb->memory.sram[bankStart]; gb->memory.sramCurrentBank = 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) { + mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank); + bankStart &= (gb->sramSize - 1); + bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK; + } + if (!half) { + gb->memory.sramBank = &gb->memory.sram[bankStart]; + gb->memory.sramCurrentBank = bank; + } else { + gb->memory.mbcState.mbc6.sramBank1 = &gb->memory.sram[bankStart]; + gb->memory.mbcState.mbc6.currentSramBank1 = bank; + } } void GBMBCInit(struct GB* gb) {

@@ -230,6 +247,7 @@ break;

case GB_MBC6: mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6"); gb->memory.mbcWrite = _GBMBC6; + gb->memory.mbcRead = _GBMBC6Read; break; case GB_MBC7: gb->memory.mbcWrite = _GBMBC7;

@@ -536,11 +554,10 @@ switch (address >> 10) {

case 0: switch (value) { case 0: - memory->sramAccess = false; + memory->mbcState.mbc6.sramAccess = false; break; case 0xA: - memory->sramAccess = true; - GBMBCSwitchSramBank(gb, memory->sramCurrentBank); + memory->mbcState.mbc6.sramAccess = true; break; default: // TODO

@@ -548,6 +565,12 @@ mLOG(GB_MBC, STUB, "MBC6 unknown value %02X", value);

break; } break; + case 0x1: + GBMBCSwitchSramHalfBank(gb, 0, bank); + break; + case 0x2: + GBMBCSwitchSramHalfBank(gb, 1, bank); + break; case 0x8: case 0x9: GBMBCSwitchHalfBank(gb, 0, bank);

@@ -556,10 +579,39 @@ case 0xC:

case 0xD: GBMBCSwitchHalfBank(gb, 1, bank); break; + case 0x28: + case 0x29: + case 0x2A: + case 0x2B: + if (memory->mbcState.mbc6.sramAccess) { + memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value; + } + break; + case 0x2C: + case 0x2D: + case 0x2E: + case 0x2F: + if (memory->mbcState.mbc6.sramAccess) { + memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value; + } + break; default: mLOG(GB_MBC, STUB, "MBC6 unknown address: %04X:%02X", address, value); break; } +} + +uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) { + if (!memory->mbcState.mbc6.sramAccess) { + return 0xFF; + } + switch (address >> 12) { + case 0xA: + return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)]; + case 0xB: + return memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)]; + } + return 0xFF; } void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
M src/gb/memory.csrc/gb/memory.c

@@ -183,6 +183,9 @@ break;

case GB_MBC6: GBMBCSwitchHalfBank(gb, 0, 2); GBMBCSwitchHalfBank(gb, 1, 3); + gb->memory.mbcState.mbc6.sramAccess = false; + GBMBCSwitchSramHalfBank(gb, 0, 0); + GBMBCSwitchSramHalfBank(gb, 0, 1); break; default: memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));