GB MBC: Support for unlicensed Pokemon Jade/Diamond Game Boy mapper

This commit is contained in:
Vicki Pfau 2020-07-07 18:11:18 -07:00
parent 3062a6a2d7
commit cdf9105f56
10 changed files with 105 additions and 9 deletions

View File

@ -2,6 +2,7 @@
Features:
- e-Reader card scanning
- Add APNG recording
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
Emulation fixes:
- ARM: Fix ALU reading PC after shifting
- ARM: Fix STR storing PC after address calculation

View File

@ -51,6 +51,7 @@ The following mappers are fully supported:
- MBC5+Rumble
- MBC7
- Wisdom Tree (unlicensed)
- Pokémon Jade/Diamond (unlicensed)
The following mappers are partially supported:

View File

@ -34,9 +34,10 @@ enum GBMemoryBankControllerType {
GB_HuC3 = 0x12,
GB_POCKETCAM = 0x13,
GB_TAMA5 = 0x14,
GB_UNL_WISDOM_TREE = 0x20,
GB_MBC3_RTC = 0x103,
GB_MBC5_RUMBLE = 0x105
GB_MBC5_RUMBLE = 0x105,
GB_UNL_WISDOM_TREE = 0x200,
GB_UNL_PKJD = 0x203,
};
struct GBSIODriver {

View File

@ -146,6 +146,10 @@ struct GBTAMA5State {
uint8_t registers[GBTAMA5_MAX];
};
struct GBPKJDState {
uint8_t reg[2];
};
union GBMBCState {
struct GBMBC1State mbc1;
struct GBMBC6State mbc6;
@ -153,6 +157,7 @@ union GBMBCState {
struct GBMMM01State mmm01;
struct GBPocketCamState pocketCam;
struct GBTAMA5State tama5;
struct GBPKJDState pkjd;
};
struct mRotationSource;
@ -171,6 +176,7 @@ struct GBMemory {
int wramCurrentBank;
bool sramAccess;
bool directSramAccess;
uint8_t* sram;
uint8_t* sramBank;
int sramCurrentBank;

View File

@ -162,6 +162,10 @@ bool mCorePreloadVFCB(struct mCore* core, struct VFile* vf, void (cb)(size_t, si
}
}
vf->close(vf);
if (read < 0) {
vfm->close(vfm);
return false;
}
bool ret = core->loadROM(core, vfm);
if (!ret) {
vfm->close(vfm);

View File

@ -36,6 +36,7 @@ static void _GBHuC3(struct GB*, uint16_t address, uint8_t value);
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 uint8_t _GBMBC2Read(struct GBMemory*, uint16_t address);
static uint8_t _GBMBC6Read(struct GBMemory*, uint16_t address);
@ -43,6 +44,7 @@ static uint8_t _GBMBC7Read(struct GBMemory*, uint16_t address);
static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
static uint8_t _GBTAMA5Read(struct GBMemory*, uint16_t address);
static uint8_t _GBPKJDRead(struct GBMemory*, uint16_t address);
static uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
static void _GBPocketCamCapture(struct GBMemory*);
@ -273,6 +275,7 @@ void GBMBCInit(struct GB* gb) {
gb->memory.mbcType = GB_MBC_NONE;
}
gb->memory.mbcRead = NULL;
gb->memory.directSramAccess = true;
switch (gb->memory.mbcType) {
case GB_MBC_NONE:
gb->memory.mbcWrite = _GBMBCNone;
@ -288,6 +291,7 @@ void GBMBCInit(struct GB* gb) {
case GB_MBC2:
gb->memory.mbcWrite = _GBMBC2;
gb->memory.mbcRead = _GBMBC2Read;
gb->memory.directSramAccess = false;
gb->sramSize = 0x100;
break;
case GB_MBC3:
@ -300,9 +304,9 @@ void GBMBCInit(struct GB* gb) {
gb->memory.mbcWrite = _GBMBC5;
break;
case GB_MBC6:
mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6");
gb->memory.mbcWrite = _GBMBC6;
gb->memory.mbcRead = _GBMBC6Read;
gb->memory.directSramAccess = false;
break;
case GB_MBC7:
gb->memory.mbcWrite = _GBMBC7;
@ -342,6 +346,10 @@ void GBMBCInit(struct GB* gb) {
case GB_UNL_WISDOM_TREE:
gb->memory.mbcWrite = _GBWisdomTree;
break;
case GB_UNL_PKJD:
gb->memory.mbcWrite = _GBPKJD;
gb->memory.mbcRead = _GBPKJDRead;
break;
}
gb->memory.currentBank = 1;
@ -626,10 +634,10 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0:
switch (value) {
case 0:
memory->mbcState.mbc6.sramAccess = false;
memory->sramAccess = false;
break;
case 0xA:
memory->mbcState.mbc6.sramAccess = true;
memory->sramAccess = true;
break;
default:
// TODO
@ -655,7 +663,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0x29:
case 0x2A:
case 0x2B:
if (memory->mbcState.mbc6.sramAccess) {
if (memory->sramAccess) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
}
break;
@ -663,7 +671,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0x2D:
case 0x2E:
case 0x2F:
if (memory->mbcState.mbc6.sramAccess) {
if (memory->sramAccess) {
memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
}
break;
@ -674,7 +682,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
}
uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
if (!memory->mbcState.mbc6.sramAccess) {
if (!memory->sramAccess) {
return 0xFF;
}
switch (address >> 12) {
@ -1229,6 +1237,74 @@ void _GBWisdomTree(struct GB* gb, uint16_t address, uint8_t value) {
}
}
void _GBPKJD(struct GB* gb, uint16_t address, uint8_t value) {
struct GBMemory* memory = &gb->memory;
switch (address >> 13) {
case 0x2:
if (value < 8) {
memory->directSramAccess = true;
memory->activeRtcReg = 0;
} else if (value >= 0xD && value <= 0xF) {
memory->directSramAccess = false;
memory->rtcAccess = false;
memory->activeRtcReg = value - 8;
}
break;
case 0x5:
if (!memory->sramAccess) {
return;
}
switch (memory->activeRtcReg) {
case 0:
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
break;
case 5:
case 6:
memory->mbcState.pkjd.reg[memory->activeRtcReg - 5] = value;
break;
case 7:
switch (value) {
case 0x11:
memory->mbcState.pkjd.reg[0]--;
break;
case 0x12:
memory->mbcState.pkjd.reg[1]--;
break;
case 0x41:
memory->mbcState.pkjd.reg[0] += memory->mbcState.pkjd.reg[1];
break;
case 0x42:
memory->mbcState.pkjd.reg[1] += memory->mbcState.pkjd.reg[0];
break;
case 0x51:
memory->mbcState.pkjd.reg[0]++;
break;
case 0x52:
memory->mbcState.pkjd.reg[1]--;
break;
}
break;
}
return;
}
_GBMBC3(gb, address, value);
}
static uint8_t _GBPKJDRead(struct GBMemory* memory, uint16_t address) {
if (!memory->sramAccess) {
return 0xFF;
}
switch (memory->activeRtcReg) {
case 0:
return memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)];
case 5:
case 6:
return memory->mbcState.pkjd.reg[memory->activeRtcReg - 5];
default:
return 0;
}
}
void GBMBCRTCRead(struct GB* gb) {
struct GBMBCRTCSaveBuffer rtcBuffer;
struct VFile* vf = gb->sramVf;

View File

@ -361,7 +361,7 @@ void GBStore8(struct SM83Core* cpu, uint16_t address, int8_t value) {
case GB_REGION_EXTERNAL_RAM + 1:
if (memory->rtcAccess) {
memory->rtcRegs[memory->activeRtcReg] = value;
} else if (memory->sramAccess && memory->sram && memory->mbcType != GB_MBC2) {
} else if (memory->sramAccess && memory->sram && memory->directSramAccess) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
} else {
memory->mbcWrite(gb, address, value);

View File

@ -495,6 +495,7 @@ static const struct GBCartridgeOverride _overrides[] = {
{ 0x630ed957, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (non-debug)
{ 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)
{ 0, 0, 0, { 0 } }
};

View File

@ -50,6 +50,7 @@ OverrideView::OverrideView(ConfigController* config, QWidget* parent)
s_mbcList.append(GB_HuC1);
s_mbcList.append(GB_HuC3);
s_mbcList.append(GB_UNL_WISDOM_TREE);
s_mbcList.append(GB_UNL_PKJD);
}
if (s_gbModelList.isEmpty()) {
// NB: Keep in sync with OverrideView.ui

View File

@ -359,6 +359,11 @@
<string>Wisdom Tree (Unlicensed)</string>
</property>
</item>
<item>
<property name="text">
<string>Pokémon Jade/Diamond (Unlicensed)</string>
</property>
</item>
</widget>
</item>
<item row="2" column="0">