mirror of https://github.com/mgba-emu/mgba.git
GB Memory: Add cursory cartridge open bus emulation (fixes #2032)
This commit is contained in:
parent
dc40ef7cb8
commit
78d3a1f17e
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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];
|
||||
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue