GB Memory: Add cursory cartridge open bus emulation (fixes #2032)

This commit is contained in:
Vicki Pfau 2021-06-23 20:34:11 -07:00
parent dc40ef7cb8
commit 78d3a1f17e
5 changed files with 54 additions and 21 deletions

View File

@ -7,6 +7,7 @@ Features:
- Support for combo "Super Game Boy Color" SGB + GBC ROM hacks
- Support for 64 kiB SRAM saves used in some bootlegs
Emulation fixes:
- GB Memory: Add cursory cartridge open bus emulation (fixes mgba.io/i/2032)
- GB Video: Clear VRAM on reset (fixes mgba.io/i/2152)
- GBA SIO: Add missing NORMAL8 implementation bits (fixes mgba.io/i/2172)
- GBA SIO: Fix missing interrupt on an unattached NORMAL transfer

View File

@ -181,6 +181,9 @@ struct GBMemory {
union GBMBCState mbcState;
int currentBank;
int currentBank0;
unsigned cartBusDecay;
uint16_t cartBusPc;
uint8_t cartBus;
uint8_t* wram;
uint8_t* wramBank;

View File

@ -157,9 +157,11 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
* | bit 3: IME
* | bit 4: Is HDMA active?
* | bits 5 - 7: Active RTC register
* | 0x00196 - 0x00197: Reserved (leave zero)
* | 0x00196: Cartridge bus value
* | 0x00197: Reserved (leave zero)
* 0x00198 - 0x0019F: Global cycle counter
* 0x001A0 - 0x0025F: Reserved (leave zero)
* 0x001A0 - 0x001A1: Program counter for last cartridge read
* 0x001A2 - 0x0025F: Reserved (leave zero)
* 0x00260 - 0x002FF: OAM
* 0x00300 - 0x0037F: I/O memory
* 0x00380 - 0x003FE: HRAM
@ -401,12 +403,14 @@ struct GBSerializedState {
};
GBSerializedMemoryFlags flags;
uint16_t reserved;
uint8_t cartBus;
uint8_t reserved;
} memory;
uint64_t globalCycles;
uint32_t reserved[48];
uint16_t cartBusPc;
uint16_t reserved[95];
uint8_t oam[GB_SIZE_OAM];

View File

@ -322,6 +322,7 @@ void GBMBCInit(struct GB* gb) {
}
gb->memory.mbcRead = NULL;
gb->memory.directSramAccess = true;
gb->memory.cartBusDecay = 4;
switch (gb->memory.mbcType) {
case GB_MBC_NONE:
gb->memory.mbcWrite = _GBMBCNone;
@ -442,6 +443,9 @@ void GBMBCInit(struct GB* gb) {
void GBMBCReset(struct GB* gb) {
gb->memory.currentBank0 = 0;
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
gb->memory.cartBus = 0xFF;
gb->memory.cartBusPc = 0;
gb->memory.cartBusDecay = 1;
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
GBMBCInit(gb);

View File

@ -51,12 +51,17 @@ static const uint8_t _blockedRegion[1] = { 0xFF };
static void _pristineCow(struct GB* gba);
static uint8_t GBFastLoad8(struct SM83Core* cpu, uint16_t address) {
static uint8_t GBCartLoad8(struct SM83Core* cpu, uint16_t address) {
if (UNLIKELY(address >= cpu->memory.activeRegionEnd)) {
cpu->memory.setActiveRegion(cpu, address);
return cpu->memory.cpuLoad8(cpu, address);
}
return cpu->memory.activeRegion[address & cpu->memory.activeMask];
struct GB* gb = (struct GB*) cpu->master;
struct GBMemory* memory = &gb->memory;
memory->cartBusPc = address;
uint8_t value = cpu->memory.activeRegion[address & cpu->memory.activeMask];
memory->cartBus = value;
return value;
}
static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
@ -67,7 +72,7 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
case GB_REGION_CART_BANK0 + 1:
case GB_REGION_CART_BANK0 + 2:
case GB_REGION_CART_BANK0 + 3:
cpu->memory.cpuLoad8 = GBFastLoad8;
cpu->memory.cpuLoad8 = GBCartLoad8;
cpu->memory.activeRegion = memory->romBase;
cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
@ -88,7 +93,7 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
cpu->memory.cpuLoad8 = GBLoad8;
break;
}
cpu->memory.cpuLoad8 = GBFastLoad8;
cpu->memory.cpuLoad8 = GBCartLoad8;
if (gb->memory.mbcType != GB_MBC6) {
cpu->memory.activeRegion = memory->romBank;
cpu->memory.activeRegionEnd = GB_BASE_VRAM;
@ -238,24 +243,31 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
case GB_REGION_CART_BANK0 + 2:
case GB_REGION_CART_BANK0 + 3:
if (address >= memory->romSize) {
return 0xFF;
memory->cartBus = 0xFF;
} else {
memory->cartBus = memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
}
return memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
memory->cartBusPc = cpu->pc;
return memory->cartBus;
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)];
memory->cartBus = memory->mbcState.mbc6.romBank1[address & (GB_SIZE_CART_HALFBANK - 1)];
memory->cartBusPc = cpu->pc;
return memory->cartBus;
}
// Fall through
case GB_REGION_CART_BANK1:
case GB_REGION_CART_BANK1 + 1:
if (address >= memory->romSize) {
return 0xFF;
memory->cartBus = 0xFF;
} else if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
memory->cartBus = memory->mbcRead(memory, address);
} else {
memory->cartBus = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
}
if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
return memory->mbcRead(memory, address);
}
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
memory->cartBusPc = cpu->pc;
return memory->cartBus;
case GB_REGION_VRAM:
case GB_REGION_VRAM + 1:
if (gb->video.mode != 3) {
@ -265,15 +277,18 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
case GB_REGION_EXTERNAL_RAM:
case GB_REGION_EXTERNAL_RAM + 1:
if (memory->rtcAccess) {
return memory->rtcRegs[memory->activeRtcReg];
memory->cartBus = memory->rtcRegs[memory->activeRtcReg];
} else if (memory->mbcRead) {
return memory->mbcRead(memory, address);
memory->cartBus = memory->mbcRead(memory, address);
} else if (memory->sramAccess && memory->sram) {
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
memory->cartBus = memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
} else if (memory->mbcType == GB_HuC3) {
return 0x01; // TODO: Is this supposed to be the current SRAM bank?
memory->cartBus = 0x01; // TODO: Is this supposed to be the current SRAM bank?
} else if (cpu->tMultiplier * (cpu->pc - memory->cartBusPc) >= memory->cartBusDecay) {
memory->cartBus = 0xFF;
}
return 0xFF;
memory->cartBusPc = cpu->pc;
return memory->cartBus;
case GB_REGION_WORKING_RAM_BANK0:
case GB_REGION_WORKING_RAM_BANK0 + 2:
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
@ -705,6 +720,9 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg);
STORE_16LE(flags, 0, &state->memory.flags);
state->memory.cartBus = memory->cartBus;
STORE_16LE(memory->cartBusPc, 0, &state->cartBusPc);
switch (memory->mbcType) {
case GB_MBC1:
state->memory.mbc1.mode = memory->mbcState.mbc1.mode;
@ -784,6 +802,9 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
memory->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags);
memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
memory->cartBus = state->memory.cartBus;
LOAD_16LE(memory->cartBusPc, 0, &state->cartBusPc);
switch (memory->mbcType) {
case GB_MBC1:
memory->mbcState.mbc1.mode = state->memory.mbc1.mode;