GB MBC: MBC6 skeleton
Vicki Pfau vi@endrift.com
Fri, 11 Aug 2017 18:19:31 -0700
4 files changed,
66 insertions(+),
7 deletions(-)
M
include/mgba/internal/gb/mbc.h
→
include/mgba/internal/gb/mbc.h
@@ -19,6 +19,7 @@ struct GBMemory;
void GBMBCInit(struct GB* gb); 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); enum GBCam {
M
include/mgba/internal/gb/memory.h
→
include/mgba/internal/gb/memory.h
@@ -22,6 +22,8 @@
enum { GB_BASE_CART_BANK0 = 0x0000, GB_BASE_CART_BANK1 = 0x4000, + GB_BASE_CART_HALFBANK1 = 0x4000, + GB_BASE_CART_HALFBANK2 = 0x6000, GB_BASE_VRAM = 0x8000, GB_BASE_EXTERNAL_RAM = 0xA000, GB_BASE_WORKING_RAM_BANK0 = 0xC000,@@ -46,6 +48,7 @@ };
enum { GB_SIZE_CART_BANK0 = 0x4000, + GB_SIZE_CART_HALFBANK = 0x2000, GB_SIZE_CART_MAX = 0x800000, GB_SIZE_VRAM = 0x4000, GB_SIZE_VRAM_BANK0 = 0x2000,@@ -104,6 +107,11 @@ int mode;
int multicartStride; }; +struct GBMBC6State { + int currentBank1; + uint8_t* romBank1; +}; + struct GBMBC7State { enum GBMBC7MachineState state; uint16_t sr;@@ -127,6 +135,7 @@ };
union GBMBCState { struct GBMBC1State mbc1; + struct GBMBC6State mbc6; struct GBMBC7State mbc7; struct GBPocketCamState pocketCam; struct GBTAMA5State tama5;
M
src/gb/mbc.c
→
src/gb/mbc.c
@@ -68,6 +68,28 @@ gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
} } +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; + } + } + if (!half) { + gb->memory.romBank = &gb->memory.rom[bankStart]; + gb->memory.currentBank = bank; + } else { + gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart]; + gb->memory.mbcState.mbc6.currentBank1 = bank; + } + if (gb->cpu->pc < GB_BASE_VRAM) { + gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc); + } +} + static bool _isMulticart(const uint8_t* mem) { bool success = true; struct VFile* vf;@@ -496,11 +518,34 @@ }
} void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) { - // TODO - mLOG(GB_MBC, STUB, "MBC6 unimplemented"); - UNUSED(gb); - UNUSED(address); - UNUSED(value); + struct GBMemory* memory = &gb->memory; + int bank = value & 0x7F; + switch (address >> 10) { + case 0: + switch (value) { + case 0: + memory->sramAccess = false; + break; + case 0xA: + memory->sramAccess = true; + GBMBCSwitchSramBank(gb, memory->sramCurrentBank); + break; + default: + // TODO + mLOG(GB_MBC, STUB, "MBC6 unknown value %02X", value); + break; + } + break; + case 0x9: + GBMBCSwitchHalfBank(gb, 0, bank); + break; + case 0xD: + GBMBCSwitchHalfBank(gb, 1, bank); + break; + default: + mLOG(GB_MBC, STUB, "MBC6 unknown address: %04X:%02X", address, value); + break; + } } void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
M
src/gb/memory.c
→
src/gb/memory.c
@@ -207,10 +207,14 @@ case GB_REGION_CART_BANK0 + 1:
case GB_REGION_CART_BANK0 + 2: case GB_REGION_CART_BANK0 + 3: return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)]; - case GB_REGION_CART_BANK1: - case GB_REGION_CART_BANK1 + 1: case GB_REGION_CART_BANK1 + 2: case GB_REGION_CART_BANK1 + 3: + if (memory->mbcType == GB_MBC6) { + return memory->mbcState.mbc6.romBank1[address & (GB_SIZE_CART_HALFBANK - 1)]; + } + // Fall through + case GB_REGION_CART_BANK1: + case GB_REGION_CART_BANK1 + 1: return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)]; case GB_REGION_VRAM: case GB_REGION_VRAM + 1: