GB MBC: Add M161 support for one Mani 4-in-1 multicart

This commit is contained in:
Vicki Pfau 2025-05-22 02:54:40 -07:00
parent 0418ae33d5
commit 30a94053c3
11 changed files with 48 additions and 1 deletions

View File

@ -45,6 +45,7 @@ Misc:
- Core: Add SHA1 hashing for ROMs
- FFmpeg: Add Ut Video option
- GB: Prevent incompatible BIOSes from being used on differing models
- GB MBC: Add M161 support for one Mani 4-in-1 multicart
- GB Serialize: Add missing savestate support for MBC6 and NT (newer)
- GBA: Improve detection of valid ELF ROMs
- GBA Audio: Remove broken XQ audio pending rewrite

View File

@ -54,6 +54,7 @@ The following mappers are fully supported:
- MBC5
- MBC5+Rumble
- MBC7
- M161
- Wisdom Tree (unlicensed)
- NT "old type" 1 and 2 (unlicensed multicart)
- NT "new type" (unlicensed MBC5-like)

View File

@ -37,6 +37,7 @@ enum GBMemoryBankControllerType {
GB_HuC3 = 0x12,
GB_POCKETCAM = 0x13,
GB_TAMA5 = 0x14,
GB_M161 = 0x15,
GB_MBC3_RTC = 0x103,
GB_MBC5_RUMBLE = 0x105,
GB_UNL_WISDOM_TREE = 0x200,

View File

@ -233,6 +233,11 @@ struct GBHuC3State {
uint8_t registers[256];
};
struct GBM161State {
bool locked;
uint8_t bank;
};
struct GBPKJDState {
uint8_t reg[2];
};
@ -276,6 +281,7 @@ union GBMBCState {
struct GBPocketCamState pocketCam;
struct GBTAMA5State tama5;
struct GBHuC3State huc3;
struct GBM161State m161;
struct GBNTOldState ntOld;
struct GBNTNewState ntNew;
struct GBPKJDState pkjd;

View File

@ -432,6 +432,10 @@ struct GBSerializedState {
uint8_t value;
uint8_t mode;
} huc3;
struct {
uint8_t bank;
uint8_t locked;
} m161;
struct {
GBSerializedNTOldFlags flags;
uint8_t baseBank;

View File

@ -110,7 +110,7 @@ static struct {
{"HUC1", GB_HuC1},
{"HUC3", GB_HuC3},
{"TAM5", GB_TAMA5},
{"M161", GB_MBC_AUTODETECT}, // TODO
{"M161", GB_M161},
{"BBD", GB_UNL_BBD},
{"HITK", GB_UNL_HITEK},
{"SNTX", GB_UNL_SINTAX},
@ -460,6 +460,9 @@ void GBMBCInit(struct GB* gb) {
gb->memory.cam->startRequestImage(gb->memory.cam, GBCAM_WIDTH, GBCAM_HEIGHT, mCOLOR_ANY);
}
break;
case GB_M161:
gb->memory.mbcWrite = _GBM161;
break;
case GB_UNL_WISDOM_TREE:
gb->memory.mbcWrite = _GBWisdomTree;
break;

View File

@ -24,6 +24,7 @@ void _GBMBC7(struct GB*, uint16_t address, uint8_t value);
void _GBMMM01(struct GB*, uint16_t address, uint8_t value);
void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
void _GBM161(struct GB* gb, uint16_t address, uint8_t value);
void _GBHuC1(struct GB*, uint16_t address, uint8_t value);
void _GBHuC3(struct GB*, uint16_t address, uint8_t value);

View File

@ -565,3 +565,19 @@ void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value) {
}
mbc7->eeprom = value;
}
void _GBM161(struct GB* gb, uint16_t address, uint8_t value) {
UNUSED(address);
struct GBM161State* m161 = &gb->memory.mbcState.m161;
if (m161->locked) {
return;
}
int bank = value & 0x7;
m161->bank = bank;
m161->locked = true;
GBMBCSwitchBank0(gb, bank * 2);
GBMBCSwitchBank(gb, bank * 2 + 1);
}

View File

@ -840,6 +840,10 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
state->memory.mmm01.locked = memory->mbcState.mmm01.locked;
state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0;
break;
case GB_M161:
state->memory.m161.locked = memory->mbcState.m161.locked;
state->memory.m161.bank = memory->mbcState.m161.bank;
break;
case GB_UNL_NT_OLD_1:
case GB_UNL_NT_OLD_2:
state->memory.ntOld.flags = GBSerializedNTOldFlagsSetSwapped(0, memory->mbcState.ntOld.swapped);
@ -1006,6 +1010,12 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
}
break;
case GB_M161:
memory->mbcState.m161.locked = state->memory.m161.locked;
memory->mbcState.m161.bank = state->memory.m161.bank & 0x7;
GBMBCSwitchBank0(gb, memory->mbcState.m161.bank * 2);
GBMBCSwitchBank(gb, memory->mbcState.m161.bank * 2 + 1);
break;
case GB_UNL_NT_OLD_1:
case GB_UNL_NT_OLD_2:
memory->mbcState.ntOld.swapped = GBSerializedNTOldFlagsGetSwapped(state->memory.ntOld.flags);

View File

@ -667,6 +667,8 @@ static const struct GBCartridgeOverride _sgbOverrides[] = {
};
static const struct GBCartridgeOverride _overrides[] = {
{ 0xA61F3EE1, GB_MODEL_AUTODETECT, GB_M161, { 0 } }, // Mani 4 in 1 - Tetris + Alleyway + Yakuman + Tennis
// Pokemon Spaceworld 1997 demo
{ 0x232A067D, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (debug)
{ 0x630ED957, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (non-debug)

View File

@ -33,6 +33,7 @@ static const QList<GBMemoryBankControllerType> s_mbcList{
GB_TAMA5,
GB_HuC1,
GB_HuC3,
GB_M161,
GB_UNL_WISDOM_TREE,
GB_UNL_PKJD,
GB_UNL_NT_OLD_1,
@ -92,6 +93,7 @@ QString GameBoy::mbcName(GBMemoryBankControllerType mbc) {
s_mbcNames[GB_HuC3] = "HuC-3";
s_mbcNames[GB_POCKETCAM] = "Pocket Cam";
s_mbcNames[GB_TAMA5] = "TAMA5";
s_mbcNames[GB_M161] = "M161";
s_mbcNames[GB_UNL_WISDOM_TREE] = "Wisdom Tree";
s_mbcNames[GB_UNL_NT_OLD_1] = tr("%1 (old 1)").arg("NT");
s_mbcNames[GB_UNL_NT_OLD_2] = tr("%1 (old 2)").arg("NT");