mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Add MBC1-M support with basic heuristic
This commit is contained in:
parent
7de5b33554
commit
f84af91173
1
CHANGES
1
CHANGES
|
@ -20,6 +20,7 @@ Features:
|
||||||
- Library view
|
- Library view
|
||||||
- Debugger: Segment/bank support
|
- Debugger: Segment/bank support
|
||||||
- GB: Symbol table support
|
- GB: Symbol table support
|
||||||
|
- GB MBC: Add MBC1 multicart support
|
||||||
Bugfixes:
|
Bugfixes:
|
||||||
- LR35902: Fix core never exiting with certain event patterns
|
- LR35902: Fix core never exiting with certain event patterns
|
||||||
- GB Timer: Improve DIV reset behavior
|
- GB Timer: Improve DIV reset behavior
|
||||||
|
|
|
@ -85,6 +85,7 @@ enum GBMBC7MachineState {
|
||||||
|
|
||||||
struct GBMBC1State {
|
struct GBMBC1State {
|
||||||
int mode;
|
int mode;
|
||||||
|
int multicartStride;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBMBC7State {
|
struct GBMBC7State {
|
||||||
|
|
|
@ -385,7 +385,9 @@ bool GBIsBIOS(struct VFile* vf) {
|
||||||
|
|
||||||
void GBReset(struct LR35902Core* cpu) {
|
void GBReset(struct LR35902Core* cpu) {
|
||||||
struct GB* gb = (struct GB*) cpu->master;
|
struct GB* gb = (struct GB*) cpu->master;
|
||||||
|
gb->memory.romBase = gb->memory.rom;
|
||||||
GBDetectModel(gb);
|
GBDetectModel(gb);
|
||||||
|
|
||||||
if (gb->biosVf) {
|
if (gb->biosVf) {
|
||||||
if (!GBIsBIOS(gb->biosVf)) {
|
if (!GBIsBIOS(gb->biosVf)) {
|
||||||
gb->biosVf->close(gb->biosVf);
|
gb->biosVf->close(gb->biosVf);
|
||||||
|
|
|
@ -382,7 +382,7 @@ void GBIOWrite(struct GB* gb, unsigned address, uint8_t value) {
|
||||||
value = gb->video.stat;
|
value = gb->video.stat;
|
||||||
break;
|
break;
|
||||||
case 0x50:
|
case 0x50:
|
||||||
if (gb->memory.romBase != gb->memory.rom) {
|
if (gb->memory.romBase < gb->memory.rom && gb->memory.romBase > &gb->memory.rom[gb->memory.romSize - 1]) {
|
||||||
free(gb->memory.romBase);
|
free(gb->memory.romBase);
|
||||||
gb->memory.romBase = gb->memory.rom;
|
gb->memory.romBase = gb->memory.rom;
|
||||||
}
|
}
|
||||||
|
|
45
src/gb/mbc.c
45
src/gb/mbc.c
|
@ -46,6 +46,33 @@ void GBMBCSwitchBank(struct GB* gb, int bank) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _switchBank0(struct GB* gb, int bank) {
|
||||||
|
size_t bankStart = bank * GB_SIZE_CART_BANK0 << gb->memory.mbcState.mbc1.multicartStride;
|
||||||
|
if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
|
||||||
|
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
|
||||||
|
bankStart &= (gb->memory.romSize - 1);
|
||||||
|
}
|
||||||
|
gb->memory.romBase = &gb->memory.rom[bankStart];
|
||||||
|
if (gb->cpu->pc < GB_SIZE_CART_BANK0) {
|
||||||
|
gb->cpu->memory.setActiveRegion(gb->cpu, gb->cpu->pc);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool _isMulticart(const uint8_t* mem) {
|
||||||
|
bool success = true;
|
||||||
|
struct VFile* vf;
|
||||||
|
|
||||||
|
vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x10], 1024);
|
||||||
|
success = success && GBIsROM(vf);
|
||||||
|
vf->close(vf);
|
||||||
|
|
||||||
|
vf = VFileFromConstMemory(&mem[GB_SIZE_CART_BANK0 * 0x20], 1024);
|
||||||
|
success = success && GBIsROM(vf);
|
||||||
|
vf->close(vf);
|
||||||
|
|
||||||
|
return success;
|
||||||
|
}
|
||||||
|
|
||||||
void GBMBCSwitchSramBank(struct GB* gb, int bank) {
|
void GBMBCSwitchSramBank(struct GB* gb, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
|
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
|
||||||
GBResizeSram(gb, (bank + 1) * GB_SIZE_EXTERNAL_RAM);
|
GBResizeSram(gb, (bank + 1) * GB_SIZE_EXTERNAL_RAM);
|
||||||
|
@ -83,6 +110,11 @@ void GBMBCInit(struct GB* gb) {
|
||||||
case 2:
|
case 2:
|
||||||
case 3:
|
case 3:
|
||||||
gb->memory.mbcType = GB_MBC1;
|
gb->memory.mbcType = GB_MBC1;
|
||||||
|
if (gb->memory.romSize >= GB_SIZE_CART_BANK0 * 0x31 && _isMulticart(gb->memory.rom)) {
|
||||||
|
gb->memory.mbcState.mbc1.multicartStride = 4;
|
||||||
|
} else {
|
||||||
|
gb->memory.mbcState.mbc1.multicartStride = 5;
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
case 6:
|
case 6:
|
||||||
|
@ -233,6 +265,7 @@ static void _latchRtc(struct mRTCSource* rtc, uint8_t* rtcRegs, time_t* rtcLastL
|
||||||
void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
|
void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
struct GBMemory* memory = &gb->memory;
|
struct GBMemory* memory = &gb->memory;
|
||||||
int bank = value & 0x1F;
|
int bank = value & 0x1F;
|
||||||
|
int stride = 1 << memory->mbcState.mbc1.multicartStride;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
case 0x0:
|
case 0x0:
|
||||||
switch (value) {
|
switch (value) {
|
||||||
|
@ -253,21 +286,23 @@ void _GBMBC1(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
if (!bank) {
|
if (!bank) {
|
||||||
++bank;
|
++bank;
|
||||||
}
|
}
|
||||||
GBMBCSwitchBank(gb, bank | (memory->currentBank & 0x60));
|
bank &= stride - 1;
|
||||||
|
GBMBCSwitchBank(gb, bank | (memory->currentBank & (3 * stride)));
|
||||||
break;
|
break;
|
||||||
case 0x2:
|
case 0x2:
|
||||||
bank &= 3;
|
bank &= 3;
|
||||||
if (!memory->mbcState.mbc1.mode) {
|
if (memory->mbcState.mbc1.mode) {
|
||||||
GBMBCSwitchBank(gb, (bank << 5) | (memory->currentBank & 0x1F));
|
_switchBank0(gb, bank);
|
||||||
} else {
|
|
||||||
GBMBCSwitchSramBank(gb, bank);
|
GBMBCSwitchSramBank(gb, bank);
|
||||||
}
|
}
|
||||||
|
GBMBCSwitchBank(gb, (bank << memory->mbcState.mbc1.multicartStride) | (memory->currentBank & (stride - 1)));
|
||||||
break;
|
break;
|
||||||
case 0x3:
|
case 0x3:
|
||||||
memory->mbcState.mbc1.mode = value & 1;
|
memory->mbcState.mbc1.mode = value & 1;
|
||||||
if (memory->mbcState.mbc1.mode) {
|
if (memory->mbcState.mbc1.mode) {
|
||||||
GBMBCSwitchBank(gb, memory->currentBank & 0x1F);
|
_switchBank0(gb, memory->currentBank >> memory->mbcState.mbc1.multicartStride);
|
||||||
} else {
|
} else {
|
||||||
|
_switchBank0(gb, 0);
|
||||||
GBMBCSwitchSramBank(gb, 0);
|
GBMBCSwitchSramBank(gb, 0);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -165,7 +165,13 @@ void GBMemoryReset(struct GB* gb) {
|
||||||
memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
|
memset(&gb->memory.rtcRegs, 0, sizeof(gb->memory.rtcRegs));
|
||||||
|
|
||||||
memset(&gb->memory.hram, 0, sizeof(gb->memory.hram));
|
memset(&gb->memory.hram, 0, sizeof(gb->memory.hram));
|
||||||
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
|
switch (gb->memory.mbcType) {
|
||||||
|
case GB_MBC1:
|
||||||
|
gb->memory.mbcState.mbc1.mode = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
memset(&gb->memory.mbcState, 0, sizeof(gb->memory.mbcState));
|
||||||
|
}
|
||||||
|
|
||||||
GBMBCInit(gb);
|
GBMBCInit(gb);
|
||||||
gb->memory.sramBank = gb->memory.sram;
|
gb->memory.sramBank = gb->memory.sram;
|
||||||
|
|
Loading…
Reference in New Issue