GB MBC: Fix MBC1 mode changing behavior
Vicki Pfau vi@endrift.com
Tue, 16 Jun 2020 20:00:44 -0700
7 files changed,
38 insertions(+),
20 deletions(-)
M
CHANGES
→
CHANGES
@@ -5,6 +5,7 @@ - Add APNG recording
Emulation fixes: - ARM: Fix ALU reading PC after shifting - ARM: Fix STR storing PC after address calculation + - GB MBC: Fix MBC1 mode changing behavior - GB Video: Fix state after skipping BIOS (fixes mgba.io/i/1715 and mgba.io/i/1716) - GBA: Fix timing advancing too quickly in rare cases - GBA BIOS: Implement dummy sound driver calls
M
include/mgba/internal/gb/memory.h
→
include/mgba/internal/gb/memory.h
@@ -108,6 +108,8 @@
struct GBMBC1State { int mode; int multicartStride; + uint8_t bankLo; + uint8_t bankHi; }; struct GBMBC6State {
M
include/mgba/internal/gb/serialize.h
→
include/mgba/internal/gb/serialize.h
@@ -362,6 +362,8 @@ union {
struct { uint8_t mode; uint8_t multicartStride; + uint8_t bankLo; + uint8_t bankHi; } mbc1; struct { uint64_t lastLatch;
M
src/gb/mbc.c
→
src/gb/mbc.c
@@ -419,10 +419,27 @@ rtcRegs[4] |= 0x80;
} } +static void _GBMBC1Update(struct GB* gb) { + struct GBMBC1State* state = &gb->memory.mbcState.mbc1; + int bank = state->bankLo; + bank &= (1 << state->multicartStride) - 1; + bank |= state->bankHi << state->multicartStride; + if (state->mode) { + GBMBCSwitchBank0(gb, state->bankHi << state->multicartStride); + GBMBCSwitchSramBank(gb, state->bankHi & 3); + } else { + GBMBCSwitchBank0(gb, 0); + GBMBCSwitchSramBank(gb, 0); + } + if (!(state->bankLo & 0x1F)) { + ++bank; + } + GBMBCSwitchBank(gb, bank); +} + void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) { struct GBMemory* memory = &gb->memory; int bank = value & 0x1F; - int stride = 1 << memory->mbcState.mbc1.multicartStride; switch (address >> 13) { case 0x0: switch (value) {@@ -440,28 +457,17 @@ break;
} break; case 0x1: - if (!bank) { - ++bank; - } - bank &= stride - 1; - GBMBCSwitchBank(gb, bank | (memory->currentBank & (3 * stride))); + memory->mbcState.mbc1.bankLo = bank; + _GBMBC1Update(gb); break; case 0x2: bank &= 3; - if (memory->mbcState.mbc1.mode) { - GBMBCSwitchBank0(gb, bank << gb->memory.mbcState.mbc1.multicartStride); - GBMBCSwitchSramBank(gb, bank); - } - GBMBCSwitchBank(gb, (bank << memory->mbcState.mbc1.multicartStride) | (memory->currentBank & (stride - 1))); + memory->mbcState.mbc1.bankHi = bank; + _GBMBC1Update(gb); break; case 0x3: memory->mbcState.mbc1.mode = value & 1; - if (memory->mbcState.mbc1.mode) { - GBMBCSwitchBank0(gb, memory->currentBank & ~((1 << memory->mbcState.mbc1.multicartStride) - 1)); - } else { - GBMBCSwitchBank0(gb, 0); - GBMBCSwitchSramBank(gb, 0); - } + _GBMBC1Update(gb); break; default: // TODO
M
src/gb/memory.c
→
src/gb/memory.c
@@ -733,6 +733,8 @@ switch (memory->mbcType) {
case GB_MBC1: state->memory.mbc1.mode = memory->mbcState.mbc1.mode; state->memory.mbc1.multicartStride = memory->mbcState.mbc1.multicartStride; + state->memory.mbc1.bankLo = memory->mbcState.mbc1.bankLo; + state->memory.mbc1.bankHi = memory->mbcState.mbc1.bankHi; break; case GB_MBC3_RTC: STORE_64LE(gb->memory.rtcLastLatch, 0, &state->memory.rtc.lastLatch);@@ -801,8 +803,15 @@ switch (memory->mbcType) {
case GB_MBC1: memory->mbcState.mbc1.mode = state->memory.mbc1.mode; memory->mbcState.mbc1.multicartStride = state->memory.mbc1.multicartStride; + memory->mbcState.mbc1.bankLo = state->memory.mbc1.bankLo; + memory->mbcState.mbc1.bankHi = state->memory.mbc1.bankHi; + if (!(memory->mbcState.mbc1.bankLo || memory->mbcState.mbc1.bankHi)) { + // Backwards compat + memory->mbcState.mbc1.bankLo = memory->currentBank & ((1 << memory->mbcState.mbc1.multicartStride) - 1); + memory->mbcState.mbc1.bankHi = memory->currentBank >> memory->mbcState.mbc1.multicartStride; + } if (memory->mbcState.mbc1.mode) { - GBMBCSwitchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride); + GBMBCSwitchBank0(gb, memory->mbcState.mbc1.bankHi); } break; case GB_MBC3_RTC: