mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Sachen MMC2 support
This commit is contained in:
parent
73f18f8049
commit
0676769b68
2
CHANGES
2
CHANGES
|
@ -13,7 +13,7 @@ Features:
|
||||||
- Additional scaling shaders
|
- Additional scaling shaders
|
||||||
- Support for GameShark Advance SP (.gsv) save file importing
|
- Support for GameShark Advance SP (.gsv) save file importing
|
||||||
- Support for multiple saves per game using .sa2, .sa3, etc.
|
- Support for multiple saves per game using .sa2, .sa3, etc.
|
||||||
- New unlicensed GB mappers: NT (newer type), Sachen (MMC1)
|
- New unlicensed GB mappers: NT (newer type), Sachen (MMC1, MMC2)
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
- ARM7: Fix unsigned multiply timing
|
- ARM7: Fix unsigned multiply timing
|
||||||
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
|
- GB: Copy logo from ROM if not running the BIOS intro (fixes mgba.io/i/2378)
|
||||||
|
|
|
@ -248,6 +248,11 @@ struct GBMemory {
|
||||||
uint8_t* wramBank;
|
uint8_t* wramBank;
|
||||||
int wramCurrentBank;
|
int wramCurrentBank;
|
||||||
|
|
||||||
|
bool mbcReadBank0;
|
||||||
|
bool mbcReadBank1;
|
||||||
|
bool mbcReadHigh;
|
||||||
|
bool mbcWriteHigh;
|
||||||
|
|
||||||
bool sramAccess;
|
bool sramAccess;
|
||||||
bool directSramAccess;
|
bool directSramAccess;
|
||||||
uint8_t* sram;
|
uint8_t* sram;
|
||||||
|
|
|
@ -636,6 +636,10 @@ void GBSkipBIOS(struct GB* gb) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (gb->memory.mbcType == GB_UNL_SACHEN_MMC2) {
|
||||||
|
gb->memory.mbcState.sachen.locked = GB_SACHEN_UNLOCKED;
|
||||||
|
}
|
||||||
|
|
||||||
cpu->sp = 0xFFFE;
|
cpu->sp = 0xFFFE;
|
||||||
cpu->pc = 0x100;
|
cpu->pc = 0x100;
|
||||||
|
|
||||||
|
@ -660,7 +664,7 @@ void GBMapBIOS(struct GB* gb) {
|
||||||
if (gb->memory.rom) {
|
if (gb->memory.rom) {
|
||||||
memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
|
memcpy(&gb->memory.romBase[size], &gb->memory.rom[size], GB_SIZE_CART_BANK0 - size);
|
||||||
if (size > 0x100) {
|
if (size > 0x100) {
|
||||||
memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], sizeof(struct GBCartridge));
|
memcpy(&gb->memory.romBase[0x100], &gb->memory.rom[0x100], 0x100);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
62
src/gb/mbc.c
62
src/gb/mbc.c
|
@ -54,6 +54,7 @@ static uint8_t _GBPKJDRead(struct GBMemory*, uint16_t address);
|
||||||
static uint8_t _GBBBDRead(struct GBMemory*, uint16_t address);
|
static uint8_t _GBBBDRead(struct GBMemory*, uint16_t address);
|
||||||
static uint8_t _GBHitekRead(struct GBMemory*, uint16_t address);
|
static uint8_t _GBHitekRead(struct GBMemory*, uint16_t address);
|
||||||
static uint8_t _GBSachenMMC1Read(struct GBMemory*, uint16_t address);
|
static uint8_t _GBSachenMMC1Read(struct GBMemory*, uint16_t address);
|
||||||
|
static uint8_t _GBSachenMMC2Read(struct GBMemory*, uint16_t address);
|
||||||
|
|
||||||
static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
|
static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
|
||||||
static void _GBPocketCamCapture(struct GBMemory*);
|
static void _GBPocketCamCapture(struct GBMemory*);
|
||||||
|
@ -204,6 +205,10 @@ static enum GBMemoryBankControllerType _detectUnlMBC(const uint8_t* mem, size_t
|
||||||
return GB_UNL_SACHEN_MMC1;
|
return GB_UNL_SACHEN_MMC1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (mem[0x184] == 0xCE && mem[0x1C4] == 0xED && mem[0x194] == 0x66) {
|
||||||
|
return GB_UNL_SACHEN_MMC2;
|
||||||
|
}
|
||||||
|
|
||||||
return GB_MBC_AUTODETECT;
|
return GB_MBC_AUTODETECT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -423,16 +428,31 @@ void GBMBCInit(struct GB* gb) {
|
||||||
case GB_UNL_BBD:
|
case GB_UNL_BBD:
|
||||||
gb->memory.mbcWrite = _GBBBD;
|
gb->memory.mbcWrite = _GBBBD;
|
||||||
gb->memory.mbcRead = _GBBBDRead;
|
gb->memory.mbcRead = _GBBBDRead;
|
||||||
|
gb->memory.mbcReadBank1 = true;
|
||||||
break;
|
break;
|
||||||
case GB_UNL_HITEK:
|
case GB_UNL_HITEK:
|
||||||
gb->memory.mbcWrite = _GBHitek;
|
gb->memory.mbcWrite = _GBHitek;
|
||||||
gb->memory.mbcRead = _GBHitekRead;
|
gb->memory.mbcRead = _GBHitekRead;
|
||||||
gb->memory.mbcState.bbd.dataSwapMode = 7;
|
gb->memory.mbcState.bbd.dataSwapMode = 7;
|
||||||
gb->memory.mbcState.bbd.bankSwapMode = 7;
|
gb->memory.mbcState.bbd.bankSwapMode = 7;
|
||||||
|
gb->memory.mbcReadBank1 = true;
|
||||||
break;
|
break;
|
||||||
case GB_UNL_SACHEN_MMC1:
|
case GB_UNL_SACHEN_MMC1:
|
||||||
gb->memory.mbcWrite = _GBSachen;
|
gb->memory.mbcWrite = _GBSachen;
|
||||||
gb->memory.mbcRead = _GBSachenMMC1Read;
|
gb->memory.mbcRead = _GBSachenMMC1Read;
|
||||||
|
gb->memory.mbcReadBank0 = true;
|
||||||
|
gb->memory.mbcReadBank1 = true;
|
||||||
|
break;
|
||||||
|
case GB_UNL_SACHEN_MMC2:
|
||||||
|
gb->memory.mbcWrite = _GBSachen;
|
||||||
|
gb->memory.mbcRead = _GBSachenMMC2Read;
|
||||||
|
gb->memory.mbcReadBank0 = true;
|
||||||
|
gb->memory.mbcReadBank1 = true;
|
||||||
|
gb->memory.mbcReadHigh = true;
|
||||||
|
gb->memory.mbcWriteHigh = true;
|
||||||
|
if (gb->sramSize) {
|
||||||
|
gb->memory.sramAccess = true;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1760,6 +1780,12 @@ void _GBSachen(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
GBMBCSwitchBank0(gb, state->baseBank & state->mask);
|
GBMBCSwitchBank0(gb, state->baseBank & state->mask);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 6:
|
||||||
|
if (gb->memory.mbcType == GB_UNL_SACHEN_MMC2 && state->locked == GB_SACHEN_LOCKED_DMG) {
|
||||||
|
state->locked = GB_SACHEN_LOCKED_CGB;
|
||||||
|
state->transition = 0;
|
||||||
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1774,12 +1800,13 @@ static uint16_t _unscrambleSachen(uint16_t address) {
|
||||||
|
|
||||||
uint8_t _GBSachenMMC1Read(struct GBMemory* memory, uint16_t address) {
|
uint8_t _GBSachenMMC1Read(struct GBMemory* memory, uint16_t address) {
|
||||||
struct GBSachenState* state = &memory->mbcState.sachen;
|
struct GBSachenState* state = &memory->mbcState.sachen;
|
||||||
if (state->locked != GB_SACHEN_UNLOCKED) {
|
if (state->locked != GB_SACHEN_UNLOCKED && (address & 0xFF00) == 0x100) {
|
||||||
++state->transition;
|
++state->transition;
|
||||||
if (state->transition == 0x31) {
|
if (state->transition == 0x31) {
|
||||||
state->locked = GB_SACHEN_UNLOCKED;
|
state->locked = GB_SACHEN_UNLOCKED;
|
||||||
|
} else {
|
||||||
|
address |= 0x80;
|
||||||
}
|
}
|
||||||
address |= 0x80;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((address & 0xFF00) == 0x0100) {
|
if ((address & 0xFF00) == 0x0100) {
|
||||||
|
@ -1795,6 +1822,37 @@ uint8_t _GBSachenMMC1Read(struct GBMemory* memory, uint16_t address) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint8_t _GBSachenMMC2Read(struct GBMemory* memory, uint16_t address) {
|
||||||
|
struct GBSachenState* state = &memory->mbcState.sachen;
|
||||||
|
if (address >= 0xC000 && state->locked == GB_SACHEN_LOCKED_DMG) {
|
||||||
|
state->transition = 0;
|
||||||
|
state->locked = GB_SACHEN_LOCKED_CGB;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (state->locked != GB_SACHEN_UNLOCKED && (address & 0x8700) == 0x0100) {
|
||||||
|
++state->transition;
|
||||||
|
if (state->transition == 0x31) {
|
||||||
|
++state->locked;
|
||||||
|
state->transition = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((address & 0xFF00) == 0x0100) {
|
||||||
|
if (state->locked == GB_SACHEN_LOCKED_CGB) {
|
||||||
|
address |= 0x80;
|
||||||
|
}
|
||||||
|
address = _unscrambleSachen(address);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (address < GB_BASE_CART_BANK1) {
|
||||||
|
return memory->romBase[address];
|
||||||
|
} else if (address < GB_BASE_VRAM) {
|
||||||
|
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
|
} else {
|
||||||
|
return 0xFF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static void _appendSaveSuffix(struct GB* gb, const void* buffer, size_t size) {
|
static void _appendSaveSuffix(struct GB* gb, const void* buffer, size_t size) {
|
||||||
struct VFile* vf = gb->sramVf;
|
struct VFile* vf = gb->sramVf;
|
||||||
if ((size_t) vf->size(vf) < gb->sramSize + size) {
|
if ((size_t) vf->size(vf) < gb->sramSize + size) {
|
||||||
|
|
|
@ -73,7 +73,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:
|
||||||
if ((gb->memory.mbcType & GB_UNL_SACHEN_MMC1) == GB_UNL_SACHEN_MMC1) {
|
if (gb->memory.mbcReadBank0) {
|
||||||
cpu->memory.cpuLoad8 = GBLoad8;
|
cpu->memory.cpuLoad8 = GBLoad8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -94,7 +94,7 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
|
||||||
case GB_REGION_CART_BANK1 + 1:
|
case GB_REGION_CART_BANK1 + 1:
|
||||||
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 ((gb->memory.mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
if (gb->memory.mbcReadBank1) {
|
||||||
cpu->memory.cpuLoad8 = GBLoad8;
|
cpu->memory.cpuLoad8 = GBLoad8;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||||
case GB_REGION_CART_BANK0 + 3:
|
case GB_REGION_CART_BANK0 + 3:
|
||||||
if (address >= memory->romSize) {
|
if (address >= memory->romSize) {
|
||||||
memory->cartBus = 0xFF;
|
memory->cartBus = 0xFF;
|
||||||
} else if ((memory->mbcType & GB_UNL_SACHEN_MMC1) == GB_UNL_SACHEN_MMC1) {
|
} else if (gb->memory.mbcReadBank0) {
|
||||||
memory->cartBus = memory->mbcRead(memory, address);
|
memory->cartBus = memory->mbcRead(memory, address);
|
||||||
} else {
|
} else {
|
||||||
memory->cartBus = memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
|
memory->cartBus = memory->romBase[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
|
@ -268,7 +268,7 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||||
case GB_REGION_CART_BANK1 + 1:
|
case GB_REGION_CART_BANK1 + 1:
|
||||||
if (address >= memory->romSize) {
|
if (address >= memory->romSize) {
|
||||||
memory->cartBus = 0xFF;
|
memory->cartBus = 0xFF;
|
||||||
} else if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
} else if (gb->memory.mbcReadBank1) {
|
||||||
memory->cartBus = memory->mbcRead(memory, address);
|
memory->cartBus = memory->mbcRead(memory, address);
|
||||||
} else {
|
} else {
|
||||||
memory->cartBus = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
memory->cartBus = memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
|
@ -298,8 +298,14 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||||
return memory->cartBus;
|
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:
|
||||||
|
if (gb->memory.mbcReadHigh) {
|
||||||
|
memory->mbcRead(memory, address);
|
||||||
|
}
|
||||||
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
return memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||||
case GB_REGION_WORKING_RAM_BANK1:
|
case GB_REGION_WORKING_RAM_BANK1:
|
||||||
|
if (gb->memory.mbcReadHigh) {
|
||||||
|
memory->mbcRead(memory, address);
|
||||||
|
}
|
||||||
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
return memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)];
|
||||||
default:
|
default:
|
||||||
if (address < GB_BASE_OAM) {
|
if (address < GB_BASE_OAM) {
|
||||||
|
@ -373,9 +379,15 @@ void GBStore8(struct SM83Core* cpu, uint16_t address, int8_t value) {
|
||||||
return;
|
return;
|
||||||
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:
|
||||||
|
if (memory->mbcWriteHigh) {
|
||||||
|
memory->mbcWrite(gb, address, value);
|
||||||
|
}
|
||||||
memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
memory->wram[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
||||||
return;
|
return;
|
||||||
case GB_REGION_WORKING_RAM_BANK1:
|
case GB_REGION_WORKING_RAM_BANK1:
|
||||||
|
if (memory->mbcWriteHigh) {
|
||||||
|
memory->mbcWrite(gb, address, value);
|
||||||
|
}
|
||||||
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
memory->wramBank[address & (GB_SIZE_WORKING_RAM_BANK0 - 1)] = value;
|
||||||
return;
|
return;
|
||||||
default:
|
default:
|
||||||
|
|
Loading…
Reference in New Issue