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 combo "Super Game Boy Color" SGB + GBC ROM hacks
|
||||||
- Support for 64 kiB SRAM saves used in some bootlegs
|
- Support for 64 kiB SRAM saves used in some bootlegs
|
||||||
Emulation fixes:
|
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)
|
- 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: Add missing NORMAL8 implementation bits (fixes mgba.io/i/2172)
|
||||||
- GBA SIO: Fix missing interrupt on an unattached NORMAL transfer
|
- GBA SIO: Fix missing interrupt on an unattached NORMAL transfer
|
||||||
|
|
|
@ -181,6 +181,9 @@ struct GBMemory {
|
||||||
union GBMBCState mbcState;
|
union GBMBCState mbcState;
|
||||||
int currentBank;
|
int currentBank;
|
||||||
int currentBank0;
|
int currentBank0;
|
||||||
|
unsigned cartBusDecay;
|
||||||
|
uint16_t cartBusPc;
|
||||||
|
uint8_t cartBus;
|
||||||
|
|
||||||
uint8_t* wram;
|
uint8_t* wram;
|
||||||
uint8_t* wramBank;
|
uint8_t* wramBank;
|
||||||
|
|
|
@ -157,9 +157,11 @@ mLOG_DECLARE_CATEGORY(GB_STATE);
|
||||||
* | bit 3: IME
|
* | bit 3: IME
|
||||||
* | bit 4: Is HDMA active?
|
* | bit 4: Is HDMA active?
|
||||||
* | bits 5 - 7: Active RTC register
|
* | bits 5 - 7: Active RTC register
|
||||||
* | 0x00196 - 0x00197: Reserved (leave zero)
|
* | 0x00196: Cartridge bus value
|
||||||
|
* | 0x00197: Reserved (leave zero)
|
||||||
* 0x00198 - 0x0019F: Global cycle counter
|
* 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
|
* 0x00260 - 0x002FF: OAM
|
||||||
* 0x00300 - 0x0037F: I/O memory
|
* 0x00300 - 0x0037F: I/O memory
|
||||||
* 0x00380 - 0x003FE: HRAM
|
* 0x00380 - 0x003FE: HRAM
|
||||||
|
@ -401,12 +403,14 @@ struct GBSerializedState {
|
||||||
};
|
};
|
||||||
|
|
||||||
GBSerializedMemoryFlags flags;
|
GBSerializedMemoryFlags flags;
|
||||||
uint16_t reserved;
|
uint8_t cartBus;
|
||||||
|
uint8_t reserved;
|
||||||
} memory;
|
} memory;
|
||||||
|
|
||||||
uint64_t globalCycles;
|
uint64_t globalCycles;
|
||||||
|
|
||||||
uint32_t reserved[48];
|
uint16_t cartBusPc;
|
||||||
|
uint16_t reserved[95];
|
||||||
|
|
||||||
uint8_t oam[GB_SIZE_OAM];
|
uint8_t oam[GB_SIZE_OAM];
|
||||||
|
|
||||||
|
|
|
@ -322,6 +322,7 @@ void GBMBCInit(struct GB* gb) {
|
||||||
}
|
}
|
||||||
gb->memory.mbcRead = NULL;
|
gb->memory.mbcRead = NULL;
|
||||||
gb->memory.directSramAccess = true;
|
gb->memory.directSramAccess = true;
|
||||||
|
gb->memory.cartBusDecay = 4;
|
||||||
switch (gb->memory.mbcType) {
|
switch (gb->memory.mbcType) {
|
||||||
case GB_MBC_NONE:
|
case GB_MBC_NONE:
|
||||||
gb->memory.mbcWrite = _GBMBCNone;
|
gb->memory.mbcWrite = _GBMBCNone;
|
||||||
|
@ -442,6 +443,9 @@ void GBMBCInit(struct GB* gb) {
|
||||||
void GBMBCReset(struct GB* gb) {
|
void GBMBCReset(struct GB* gb) {
|
||||||
gb->memory.currentBank0 = 0;
|
gb->memory.currentBank0 = 0;
|
||||||
gb->memory.romBank = &gb->memory.rom[GB_SIZE_CART_BANK0];
|
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));
|
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
|
||||||
GBMBCInit(gb);
|
GBMBCInit(gb);
|
||||||
|
|
|
@ -51,12 +51,17 @@ static const uint8_t _blockedRegion[1] = { 0xFF };
|
||||||
|
|
||||||
static void _pristineCow(struct GB* gba);
|
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)) {
|
if (UNLIKELY(address >= cpu->memory.activeRegionEnd)) {
|
||||||
cpu->memory.setActiveRegion(cpu, address);
|
cpu->memory.setActiveRegion(cpu, address);
|
||||||
return cpu->memory.cpuLoad8(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) {
|
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 + 1:
|
||||||
case GB_REGION_CART_BANK0 + 2:
|
case GB_REGION_CART_BANK0 + 2:
|
||||||
case GB_REGION_CART_BANK0 + 3:
|
case GB_REGION_CART_BANK0 + 3:
|
||||||
cpu->memory.cpuLoad8 = GBFastLoad8;
|
cpu->memory.cpuLoad8 = GBCartLoad8;
|
||||||
cpu->memory.activeRegion = memory->romBase;
|
cpu->memory.activeRegion = memory->romBase;
|
||||||
cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
|
cpu->memory.activeRegionEnd = GB_BASE_CART_BANK1;
|
||||||
cpu->memory.activeMask = GB_SIZE_CART_BANK0 - 1;
|
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;
|
cpu->memory.cpuLoad8 = GBLoad8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
cpu->memory.cpuLoad8 = GBFastLoad8;
|
cpu->memory.cpuLoad8 = GBCartLoad8;
|
||||||
if (gb->memory.mbcType != GB_MBC6) {
|
if (gb->memory.mbcType != GB_MBC6) {
|
||||||
cpu->memory.activeRegion = memory->romBank;
|
cpu->memory.activeRegion = memory->romBank;
|
||||||
cpu->memory.activeRegionEnd = GB_BASE_VRAM;
|
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 + 2:
|
||||||
case GB_REGION_CART_BANK0 + 3:
|
case GB_REGION_CART_BANK0 + 3:
|
||||||
if (address >= memory->romSize) {
|
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 + 2:
|
||||||
case GB_REGION_CART_BANK1 + 3:
|
case GB_REGION_CART_BANK1 + 3:
|
||||||
if (memory->mbcType == GB_MBC6) {
|
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
|
// Fall through
|
||||||
case GB_REGION_CART_BANK1:
|
case GB_REGION_CART_BANK1:
|
||||||
case GB_REGION_CART_BANK1 + 1:
|
case GB_REGION_CART_BANK1 + 1:
|
||||||
if (address >= memory->romSize) {
|
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) {
|
memory->cartBusPc = cpu->pc;
|
||||||
return memory->mbcRead(memory, address);
|
return memory->cartBus;
|
||||||
}
|
|
||||||
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
|
||||||
case GB_REGION_VRAM:
|
case GB_REGION_VRAM:
|
||||||
case GB_REGION_VRAM + 1:
|
case GB_REGION_VRAM + 1:
|
||||||
if (gb->video.mode != 3) {
|
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:
|
||||||
case GB_REGION_EXTERNAL_RAM + 1:
|
case GB_REGION_EXTERNAL_RAM + 1:
|
||||||
if (memory->rtcAccess) {
|
if (memory->rtcAccess) {
|
||||||
return memory->rtcRegs[memory->activeRtcReg];
|
memory->cartBus = memory->rtcRegs[memory->activeRtcReg];
|
||||||
} else if (memory->mbcRead) {
|
} else if (memory->mbcRead) {
|
||||||
return memory->mbcRead(memory, address);
|
memory->cartBus = memory->mbcRead(memory, address);
|
||||||
} else if (memory->sramAccess && memory->sram) {
|
} 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) {
|
} 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:
|
||||||
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
case GB_REGION_WORKING_RAM_BANK0 + 2:
|
||||||
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
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);
|
flags = GBSerializedMemoryFlagsSetActiveRtcReg(flags, memory->activeRtcReg);
|
||||||
STORE_16LE(flags, 0, &state->memory.flags);
|
STORE_16LE(flags, 0, &state->memory.flags);
|
||||||
|
|
||||||
|
state->memory.cartBus = memory->cartBus;
|
||||||
|
STORE_16LE(memory->cartBusPc, 0, &state->cartBusPc);
|
||||||
|
|
||||||
switch (memory->mbcType) {
|
switch (memory->mbcType) {
|
||||||
case GB_MBC1:
|
case GB_MBC1:
|
||||||
state->memory.mbc1.mode = memory->mbcState.mbc1.mode;
|
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->isHdma = GBSerializedMemoryFlagsGetIsHdma(flags);
|
||||||
memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
|
memory->activeRtcReg = GBSerializedMemoryFlagsGetActiveRtcReg(flags);
|
||||||
|
|
||||||
|
memory->cartBus = state->memory.cartBus;
|
||||||
|
LOAD_16LE(memory->cartBusPc, 0, &state->cartBusPc);
|
||||||
|
|
||||||
switch (memory->mbcType) {
|
switch (memory->mbcType) {
|
||||||
case GB_MBC1:
|
case GB_MBC1:
|
||||||
memory->mbcState.mbc1.mode = state->memory.mbc1.mode;
|
memory->mbcState.mbc1.mode = state->memory.mbc1.mode;
|
||||||
|
|
Loading…
Reference in New Issue