mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Add NT (old 1) support
This commit is contained in:
parent
47e704d257
commit
0bd4ad034e
2
CHANGES
2
CHANGES
|
@ -1,4 +1,6 @@
|
|||
0.11.0: (Future)
|
||||
Features:
|
||||
- New unlicensed GB mapper: NT (older type 1)
|
||||
Other fixes:
|
||||
- Qt: Manually split filename to avoid overzealous splitting (fixes mgba.io/i/2681)
|
||||
- Qt: Expand criteria for tag branch names (fixes mgba.io/i/2679)
|
||||
|
|
|
@ -41,6 +41,7 @@ enum GBMemoryBankControllerType {
|
|||
GB_MBC5_RUMBLE = 0x105,
|
||||
GB_UNL_WISDOM_TREE = 0x200,
|
||||
GB_UNL_PKJD = 0x203,
|
||||
GB_UNL_NT_OLD_1 = 0x210,
|
||||
GB_UNL_NT_NEW = 0x212,
|
||||
GB_UNL_BBD = 0x220, // Also used as a mask for MBCs that need special read behavior
|
||||
GB_UNL_HITEK = 0x221,
|
||||
|
|
|
@ -238,6 +238,12 @@ struct GBPKJDState {
|
|||
uint8_t reg[2];
|
||||
};
|
||||
|
||||
struct GBNTOld1State {
|
||||
bool swapped;
|
||||
uint8_t baseBank;
|
||||
uint8_t bankCount;
|
||||
};
|
||||
|
||||
struct GBNTNewState {
|
||||
bool splitMode;
|
||||
};
|
||||
|
@ -263,6 +269,7 @@ union GBMBCState {
|
|||
struct GBPocketCamState pocketCam;
|
||||
struct GBTAMA5State tama5;
|
||||
struct GBHuC3State huc3;
|
||||
struct GBNTOld1State ntOld1;
|
||||
struct GBNTNewState ntNew;
|
||||
struct GBPKJDState pkjd;
|
||||
struct GBBBDState bbd;
|
||||
|
|
|
@ -416,6 +416,11 @@ struct GBSerializedState {
|
|||
uint8_t value;
|
||||
uint8_t mode;
|
||||
} huc3;
|
||||
struct {
|
||||
uint8_t swapped;
|
||||
uint8_t baseBank;
|
||||
uint8_t bankCount;
|
||||
} ntOld1;
|
||||
struct {
|
||||
uint8_t dataSwapMode;
|
||||
uint8_t bankSwapMode;
|
||||
|
|
112
src/gb/mbc.c
112
src/gb/mbc.c
|
@ -45,6 +45,7 @@ static void _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
|
|||
static void _GBTAMA5(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBNTOld1(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBNTNew(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBBBD(struct GB* gb, uint16_t address, uint8_t value);
|
||||
static void _GBHitek(struct GB* gb, uint16_t address, uint8_t value);
|
||||
|
@ -159,7 +160,7 @@ static struct {
|
|||
{"BBD", GB_UNL_BBD},
|
||||
{"HITK", GB_UNL_HITEK},
|
||||
{"SNTX", GB_MBC_AUTODETECT}, // TODO
|
||||
{"NTO1", GB_MBC_AUTODETECT}, // TODO
|
||||
{"NTO1", GB_UNL_NT_OLD_1},
|
||||
{"NTO2", GB_MBC_AUTODETECT}, // TODO
|
||||
{"NTN", GB_UNL_NT_NEW},
|
||||
{"LICH", GB_MBC_AUTODETECT}, // TODO
|
||||
|
@ -486,6 +487,9 @@ void GBMBCInit(struct GB* gb) {
|
|||
case GB_UNL_WISDOM_TREE:
|
||||
gb->memory.mbcWrite = _GBWisdomTree;
|
||||
break;
|
||||
case GB_UNL_NT_OLD_1:
|
||||
gb->memory.mbcWrite = _GBNTOld1;
|
||||
break;
|
||||
case GB_UNL_NT_NEW:
|
||||
gb->memory.mbcWrite = _GBNTNew;
|
||||
break;
|
||||
|
@ -1963,6 +1967,100 @@ static uint8_t _GBPKJDRead(struct GBMemory* memory, uint16_t address) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
static uint8_t _reorderBits(uint8_t input, const uint8_t* reorder) {
|
||||
uint8_t newbyte = 0;
|
||||
int i;
|
||||
for(i = 0; i < 8; ++i) {
|
||||
int oldbit = reorder[i];
|
||||
int newbit = i;
|
||||
newbyte += ((input >> oldbit) & 1) << newbit;
|
||||
}
|
||||
|
||||
return newbyte;
|
||||
}
|
||||
|
||||
static const uint8_t _ntOld1Reorder[8] = {
|
||||
0, 2, 1, 4, 3, 5, 6, 7
|
||||
};
|
||||
|
||||
void _GBNTOld1(struct GB* gb, uint16_t address, uint8_t value) {
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
struct GBNTOld1State* mbcState = &memory->mbcState.ntOld1;
|
||||
int bank = value;
|
||||
|
||||
switch (address >> 12) {
|
||||
case 0x0:
|
||||
case 0x1:
|
||||
_GBMBC3(gb, address, value);
|
||||
break;
|
||||
case 0x2:
|
||||
case 0x3:
|
||||
bank &= 0x1F;
|
||||
if (!bank) {
|
||||
bank = 1;
|
||||
}
|
||||
if (mbcState->swapped) {
|
||||
bank = _reorderBits(bank, _ntOld1Reorder);
|
||||
}
|
||||
if (mbcState->bankCount) {
|
||||
bank &= mbcState->bankCount - 1;
|
||||
}
|
||||
GBMBCSwitchBank(gb, bank + mbcState->baseBank);
|
||||
return;
|
||||
case 0x5:
|
||||
switch (address & 3) {
|
||||
case 0:
|
||||
mLOG(GB_MBC, STUB, "Unimplemented NT Old 1 address 0");
|
||||
break;
|
||||
case 1:
|
||||
value &= 0x3F;
|
||||
mbcState->baseBank = value * 2;
|
||||
if (mbcState->baseBank) {
|
||||
GBMBCSwitchBank0(gb, mbcState->baseBank);
|
||||
GBMBCSwitchBank(gb, mbcState->baseBank + 1);
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if ((value & 0xF0) == 0xE0) {
|
||||
gb->sramSize = 0x2000;
|
||||
GBResizeSram(gb, gb->sramSize);
|
||||
}
|
||||
switch (value & 0xF) {
|
||||
case 0x00:
|
||||
mbcState->bankCount = 32;
|
||||
break;
|
||||
case 0x08:
|
||||
mbcState->bankCount = 16;
|
||||
break;
|
||||
case 0xC:
|
||||
mbcState->bankCount = 8;
|
||||
break;
|
||||
case 0xE:
|
||||
mbcState->bankCount = 4;
|
||||
break;
|
||||
case 0xF:
|
||||
mbcState->bankCount = 2;
|
||||
break;
|
||||
default:
|
||||
mbcState->bankCount = 32;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
mbcState->swapped = !!(value & 0x10);
|
||||
|
||||
bank = memory->currentBank;
|
||||
if (mbcState->swapped) {
|
||||
bank = _reorderBits(bank, _ntOld1Reorder);
|
||||
}
|
||||
GBMBCSwitchBank(gb, bank);
|
||||
break;
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void _GBNTNew(struct GB* gb, uint16_t address, uint8_t value) {
|
||||
struct GBMemory* memory = &gb->memory;
|
||||
if (address >> 8 == 0x14) {
|
||||
|
@ -1986,18 +2084,6 @@ void _GBNTNew(struct GB* gb, uint16_t address, uint8_t value) {
|
|||
_GBMBC5(gb, address, value);
|
||||
}
|
||||
|
||||
static uint8_t _reorderBits(uint8_t input, const uint8_t* reorder) {
|
||||
uint8_t newbyte = 0;
|
||||
int i;
|
||||
for(i = 0; i < 8; ++i) {
|
||||
int oldbit = reorder[i];
|
||||
int newbit = i;
|
||||
newbyte += ((input >> oldbit) & 1) << newbit;
|
||||
}
|
||||
|
||||
return newbyte;
|
||||
}
|
||||
|
||||
static const uint8_t _bbdDataReordering[8][8] = {
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
|
||||
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
|
||||
|
|
|
@ -797,6 +797,11 @@ 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_UNL_NT_OLD_1:
|
||||
state->memory.ntOld1.swapped = memory->mbcState.ntOld1.swapped;
|
||||
state->memory.ntOld1.baseBank = memory->mbcState.ntOld1.baseBank;
|
||||
state->memory.ntOld1.bankCount = memory->mbcState.ntOld1.bankCount;
|
||||
break;
|
||||
case GB_UNL_BBD:
|
||||
case GB_UNL_HITEK:
|
||||
state->memory.bbd.dataSwapMode = memory->mbcState.bbd.dataSwapMode;
|
||||
|
@ -929,6 +934,12 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
|||
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
|
||||
}
|
||||
break;
|
||||
case GB_UNL_NT_OLD_1:
|
||||
memory->mbcState.ntOld1.swapped = state->memory.ntOld1.swapped;
|
||||
memory->mbcState.ntOld1.baseBank = state->memory.ntOld1.baseBank;
|
||||
memory->mbcState.ntOld1.bankCount = state->memory.ntOld1.bankCount;
|
||||
GBMBCSwitchBank0(gb, memory->mbcState.ntOld1.baseBank);
|
||||
break;
|
||||
case GB_UNL_BBD:
|
||||
case GB_UNL_HITEK:
|
||||
memory->mbcState.bbd.dataSwapMode = state->memory.bbd.dataSwapMode & 0x7;
|
||||
|
|
|
@ -673,6 +673,8 @@ static const struct GBCartridgeOverride _overrides[] = {
|
|||
{ 0x5AFF0038, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (debug)
|
||||
{ 0xA61856BD, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (non-debug)
|
||||
{ 0x30F8F86C, GB_MODEL_AUTODETECT, GB_UNL_PKJD, { 0 } }, // Pokemon Jade Version (Telefang Speed bootleg)
|
||||
{ 0xE1147E75, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_1, { 0 } }, // Rockman 8
|
||||
{ 0xEFF88FAA, GB_MODEL_AUTODETECT, GB_UNL_NT_OLD_1, { 0 } }, // True Color 25 in 1 (NT-9920)
|
||||
{ 0xB289D95A, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Capcom vs SNK - Millennium Fight 2001
|
||||
{ 0x688D6713, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Digimon 02 4
|
||||
{ 0x8931A272, GB_MODEL_AUTODETECT, GB_UNL_NT_NEW, { 0 } }, // Digimon 2
|
||||
|
|
|
@ -35,6 +35,7 @@ static const QList<GBMemoryBankControllerType> s_mbcList{
|
|||
GB_HuC3,
|
||||
GB_UNL_WISDOM_TREE,
|
||||
GB_UNL_PKJD,
|
||||
GB_UNL_NT_OLD_1,
|
||||
GB_UNL_NT_NEW,
|
||||
GB_UNL_BBD,
|
||||
GB_UNL_HITEK,
|
||||
|
@ -87,6 +88,7 @@ QString GameBoy::mbcName(GBMemoryBankControllerType mbc) {
|
|||
s_mbcNames[GB_POCKETCAM] = tr("Pocket Cam");
|
||||
s_mbcNames[GB_TAMA5] = tr("TAMA5");
|
||||
s_mbcNames[GB_UNL_WISDOM_TREE] = tr("Wisdom Tree");
|
||||
s_mbcNames[GB_UNL_NT_OLD_1] = tr("NT (old 1)");
|
||||
s_mbcNames[GB_UNL_NT_NEW] = tr("NT (new)");
|
||||
s_mbcNames[GB_UNL_PKJD] = tr("Pokémon Jade/Diamond");
|
||||
s_mbcNames[GB_UNL_BBD] = tr("BBD");
|
||||
|
|
Loading…
Reference in New Issue