GB MBC: Add MBC6 flash support (read-only currently)
This commit is contained in:
parent
2251d93938
commit
347c5f2de5
5
CHANGES
5
CHANGES
@ -5,9 +5,8 @@ Features:
|
|||||||
- Separate overrides for GBC games that can also run on SGB or regular GB
|
- Separate overrides for GBC games that can also run on SGB or regular GB
|
||||||
- Mute option in homebrew ports
|
- Mute option in homebrew ports
|
||||||
- Status indicators for fast-forward and mute in homebrew ports
|
- Status indicators for fast-forward and mute in homebrew ports
|
||||||
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
|
- Read-only support for MBC6 flash memory
|
||||||
- Support for unlicensed BBD Game Boy mapper
|
- New unlicensed GB mappers: Pokémon Jade/Diamond, BBD, and Hitek
|
||||||
- Support for unlicensed Hitek Game Boy mapper
|
|
||||||
- Stack tracing tools in ARM debugger (by ahigerd)
|
- Stack tracing tools in ARM debugger (by ahigerd)
|
||||||
- Command scripts for CLI debugger (by ahigerd)
|
- Command scripts for CLI debugger (by ahigerd)
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
|
@ -57,7 +57,7 @@ The following mappers are fully supported:
|
|||||||
|
|
||||||
The following mappers are partially supported:
|
The following mappers are partially supported:
|
||||||
|
|
||||||
- MBC6 (missing flash memory support)
|
- MBC6 (missing flash memory write support)
|
||||||
- MMM01
|
- MMM01
|
||||||
- Pocket Cam
|
- Pocket Cam
|
||||||
- TAMA5 (missing RTC support)
|
- TAMA5 (missing RTC support)
|
||||||
|
@ -61,6 +61,8 @@ enum {
|
|||||||
GB_SIZE_OAM = 0xA0,
|
GB_SIZE_OAM = 0xA0,
|
||||||
GB_SIZE_IO = 0x80,
|
GB_SIZE_IO = 0x80,
|
||||||
GB_SIZE_HRAM = 0x7F,
|
GB_SIZE_HRAM = 0x7F,
|
||||||
|
|
||||||
|
GB_SIZE_MBC6_FLASH = 0x100000,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
@ -118,6 +120,8 @@ struct GBMBC6State {
|
|||||||
bool sramAccess;
|
bool sramAccess;
|
||||||
int currentSramBank1;
|
int currentSramBank1;
|
||||||
uint8_t* sramBank1;
|
uint8_t* sramBank1;
|
||||||
|
bool flashBank0;
|
||||||
|
bool flashBank1;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBMBC7State {
|
struct GBMBC7State {
|
||||||
|
66
src/gb/mbc.c
66
src/gb/mbc.c
@ -53,6 +53,8 @@ static uint8_t _GBHitekRead(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*);
|
||||||
|
|
||||||
|
static void _GBMBC6MapChip(struct GB*, int half, uint8_t value);
|
||||||
|
|
||||||
void GBMBCSwitchBank(struct GB* gb, int bank) {
|
void GBMBCSwitchBank(struct GB* gb, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_CART_BANK0;
|
size_t bankStart = bank * GB_SIZE_CART_BANK0;
|
||||||
if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
|
if (bankStart + GB_SIZE_CART_BANK0 > gb->memory.romSize) {
|
||||||
@ -81,19 +83,37 @@ void GBMBCSwitchBank0(struct GB* gb, int bank) {
|
|||||||
|
|
||||||
void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) {
|
void GBMBCSwitchHalfBank(struct GB* gb, int half, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
|
size_t bankStart = bank * GB_SIZE_CART_HALFBANK;
|
||||||
if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) {
|
bool isFlash = half ? gb->memory.mbcState.mbc6.flashBank1 : gb->memory.mbcState.mbc6.flashBank0;
|
||||||
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
|
if (isFlash) {
|
||||||
bankStart &= (gb->memory.romSize - 1);
|
if (bankStart + GB_SIZE_CART_HALFBANK > GB_SIZE_MBC6_FLASH) {
|
||||||
bank = bankStart / GB_SIZE_CART_HALFBANK;
|
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid Flash bank: %0X", bank);
|
||||||
if (!bank) {
|
bankStart &= GB_SIZE_MBC6_FLASH - 1;
|
||||||
++bank;
|
bank = bankStart / GB_SIZE_CART_HALFBANK;
|
||||||
|
}
|
||||||
|
bankStart += gb->sramSize - GB_SIZE_MBC6_FLASH;
|
||||||
|
} else {
|
||||||
|
if (bankStart + GB_SIZE_CART_HALFBANK > gb->memory.romSize) {
|
||||||
|
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid ROM bank: %0X", bank);
|
||||||
|
bankStart &= gb->memory.romSize - 1;
|
||||||
|
bank = bankStart / GB_SIZE_CART_HALFBANK;
|
||||||
|
if (!bank) {
|
||||||
|
++bank;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!half) {
|
if (!half) {
|
||||||
gb->memory.romBank = &gb->memory.rom[bankStart];
|
if (isFlash) {
|
||||||
|
gb->memory.romBank = &gb->memory.sram[bankStart];
|
||||||
|
} else {
|
||||||
|
gb->memory.romBank = &gb->memory.rom[bankStart];
|
||||||
|
}
|
||||||
gb->memory.currentBank = bank;
|
gb->memory.currentBank = bank;
|
||||||
} else {
|
} else {
|
||||||
gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart];
|
if (isFlash) {
|
||||||
|
gb->memory.mbcState.mbc6.romBank1 = &gb->memory.sram[bankStart];
|
||||||
|
} else {
|
||||||
|
gb->memory.mbcState.mbc6.romBank1 = &gb->memory.rom[bankStart];
|
||||||
|
}
|
||||||
gb->memory.mbcState.mbc6.currentBank1 = bank;
|
gb->memory.mbcState.mbc6.currentBank1 = bank;
|
||||||
}
|
}
|
||||||
if (gb->cpu->pc < GB_BASE_VRAM) {
|
if (gb->cpu->pc < GB_BASE_VRAM) {
|
||||||
@ -187,9 +207,10 @@ void GBMBCSwitchSramBank(struct GB* gb, int bank) {
|
|||||||
|
|
||||||
void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) {
|
void GBMBCSwitchSramHalfBank(struct GB* gb, int half, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
||||||
if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > gb->sramSize) {
|
size_t sramSize = gb->sramSize - GB_SIZE_MBC6_FLASH;
|
||||||
|
if (bankStart + GB_SIZE_EXTERNAL_RAM_HALFBANK > sramSize) {
|
||||||
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank);
|
mLOG(GB_MBC, GAME_ERROR, "Attempting to switch to an invalid RAM bank: %0X", bank);
|
||||||
bankStart &= (gb->sramSize - 1);
|
bankStart &= (sramSize - 1);
|
||||||
bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
bank = bankStart / GB_SIZE_EXTERNAL_RAM_HALFBANK;
|
||||||
}
|
}
|
||||||
if (!half) {
|
if (!half) {
|
||||||
@ -334,6 +355,7 @@ void GBMBCInit(struct GB* gb) {
|
|||||||
gb->memory.mbcWrite = _GBMBC6;
|
gb->memory.mbcWrite = _GBMBC6;
|
||||||
gb->memory.mbcRead = _GBMBC6Read;
|
gb->memory.mbcRead = _GBMBC6Read;
|
||||||
gb->memory.directSramAccess = false;
|
gb->memory.directSramAccess = false;
|
||||||
|
gb->sramSize += GB_SIZE_MBC6_FLASH; // Flash is concatenated at the end
|
||||||
break;
|
break;
|
||||||
case GB_MBC7:
|
case GB_MBC7:
|
||||||
gb->memory.mbcWrite = _GBMBC7;
|
gb->memory.mbcWrite = _GBMBC7;
|
||||||
@ -689,14 +711,28 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
|
|||||||
case 0x2:
|
case 0x2:
|
||||||
GBMBCSwitchSramHalfBank(gb, 1, bank);
|
GBMBCSwitchSramHalfBank(gb, 1, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0x3:
|
||||||
|
mLOG(GB_MBC, STUB, "MBC6 unimplemented flash OE write: %04X:%02X", address, value);
|
||||||
|
break;
|
||||||
|
case 0x4:
|
||||||
|
mLOG(GB_MBC, STUB, "MBC6 unimplemented flash WE write: %04X:%02X", address, value);
|
||||||
|
break;
|
||||||
case 0x8:
|
case 0x8:
|
||||||
case 0x9:
|
case 0x9:
|
||||||
GBMBCSwitchHalfBank(gb, 0, bank);
|
GBMBCSwitchHalfBank(gb, 0, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0xA:
|
||||||
|
case 0xB:
|
||||||
|
_GBMBC6MapChip(gb, 0, value);
|
||||||
|
break;
|
||||||
case 0xC:
|
case 0xC:
|
||||||
case 0xD:
|
case 0xD:
|
||||||
GBMBCSwitchHalfBank(gb, 1, bank);
|
GBMBCSwitchHalfBank(gb, 1, bank);
|
||||||
break;
|
break;
|
||||||
|
case 0xE:
|
||||||
|
case 0xF:
|
||||||
|
_GBMBC6MapChip(gb, 1, value);
|
||||||
|
break;
|
||||||
case 0x28:
|
case 0x28:
|
||||||
case 0x29:
|
case 0x29:
|
||||||
case 0x2A:
|
case 0x2A:
|
||||||
@ -732,6 +768,16 @@ uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
|
|||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _GBMBC6MapChip(struct GB* gb, int half, uint8_t value) {
|
||||||
|
if (!half) {
|
||||||
|
gb->memory.mbcState.mbc6.flashBank0 = !!(value & 0x08);
|
||||||
|
GBMBCSwitchHalfBank(gb, half, gb->memory.currentBank);
|
||||||
|
} else {
|
||||||
|
gb->memory.mbcState.mbc6.flashBank1 = !!(value & 0x08);
|
||||||
|
GBMBCSwitchHalfBank(gb, half, gb->memory.mbcState.mbc6.currentBank1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
|
void _GBMBC7(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
int bank = value & 0x7F;
|
int bank = value & 0x7F;
|
||||||
switch (address >> 13) {
|
switch (address >> 13) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user