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: Features:
- e-Reader card scanning - e-Reader card scanning
- Add APNG recording - Add APNG recording
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
Emulation fixes: Emulation fixes:
- ARM: Fix ALU reading PC after shifting - ARM: Fix ALU reading PC after shifting
- ARM: Fix STR storing PC after address calculation - ARM: Fix STR storing PC after address calculation

View File

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

View File

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

View File

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

View File

@ -162,6 +162,10 @@ bool mCorePreloadVFCB(struct mCore* core, struct VFile* vf, void (cb)(size_t, si
} }
} }
vf->close(vf); vf->close(vf);
if (read < 0) {
vfm->close(vfm);
return false;
}
bool ret = core->loadROM(core, vfm); bool ret = core->loadROM(core, vfm);
if (!ret) { if (!ret) {
vfm->close(vfm); 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 _GBPocketCam(struct GB* gb, uint16_t address, uint8_t value);
static void _GBTAMA5(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 _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 _GBMBC2Read(struct GBMemory*, uint16_t address);
static uint8_t _GBMBC6Read(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 void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t value);
static uint8_t _GBTAMA5Read(struct GBMemory*, uint16_t address); 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 uint8_t _GBPocketCamRead(struct GBMemory*, uint16_t address);
static void _GBPocketCamCapture(struct GBMemory*); static void _GBPocketCamCapture(struct GBMemory*);
@ -273,6 +275,7 @@ void GBMBCInit(struct GB* gb) {
gb->memory.mbcType = GB_MBC_NONE; gb->memory.mbcType = GB_MBC_NONE;
} }
gb->memory.mbcRead = NULL; gb->memory.mbcRead = NULL;
gb->memory.directSramAccess = true;
switch (gb->memory.mbcType) { switch (gb->memory.mbcType) {
case GB_MBC_NONE: case GB_MBC_NONE:
gb->memory.mbcWrite = _GBMBCNone; gb->memory.mbcWrite = _GBMBCNone;
@ -288,6 +291,7 @@ void GBMBCInit(struct GB* gb) {
case GB_MBC2: case GB_MBC2:
gb->memory.mbcWrite = _GBMBC2; gb->memory.mbcWrite = _GBMBC2;
gb->memory.mbcRead = _GBMBC2Read; gb->memory.mbcRead = _GBMBC2Read;
gb->memory.directSramAccess = false;
gb->sramSize = 0x100; gb->sramSize = 0x100;
break; break;
case GB_MBC3: case GB_MBC3:
@ -300,9 +304,9 @@ void GBMBCInit(struct GB* gb) {
gb->memory.mbcWrite = _GBMBC5; gb->memory.mbcWrite = _GBMBC5;
break; break;
case GB_MBC6: case GB_MBC6:
mLOG(GB_MBC, WARN, "unimplemented MBC: MBC6");
gb->memory.mbcWrite = _GBMBC6; gb->memory.mbcWrite = _GBMBC6;
gb->memory.mbcRead = _GBMBC6Read; gb->memory.mbcRead = _GBMBC6Read;
gb->memory.directSramAccess = false;
break; break;
case GB_MBC7: case GB_MBC7:
gb->memory.mbcWrite = _GBMBC7; gb->memory.mbcWrite = _GBMBC7;
@ -342,6 +346,10 @@ void GBMBCInit(struct GB* gb) {
case GB_UNL_WISDOM_TREE: case GB_UNL_WISDOM_TREE:
gb->memory.mbcWrite = _GBWisdomTree; gb->memory.mbcWrite = _GBWisdomTree;
break; break;
case GB_UNL_PKJD:
gb->memory.mbcWrite = _GBPKJD;
gb->memory.mbcRead = _GBPKJDRead;
break;
} }
gb->memory.currentBank = 1; gb->memory.currentBank = 1;
@ -626,10 +634,10 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0: case 0:
switch (value) { switch (value) {
case 0: case 0:
memory->mbcState.mbc6.sramAccess = false; memory->sramAccess = false;
break; break;
case 0xA: case 0xA:
memory->mbcState.mbc6.sramAccess = true; memory->sramAccess = true;
break; break;
default: default:
// TODO // TODO
@ -655,7 +663,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0x29: case 0x29:
case 0x2A: case 0x2A:
case 0x2B: case 0x2B:
if (memory->mbcState.mbc6.sramAccess) { if (memory->sramAccess) {
memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value; memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
} }
break; break;
@ -663,7 +671,7 @@ void _GBMBC6(struct GB* gb, uint16_t address, uint8_t value) {
case 0x2D: case 0x2D:
case 0x2E: case 0x2E:
case 0x2F: case 0x2F:
if (memory->mbcState.mbc6.sramAccess) { if (memory->sramAccess) {
memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value; memory->mbcState.mbc6.sramBank1[address & (GB_SIZE_EXTERNAL_RAM_HALFBANK - 1)] = value;
} }
break; 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) { uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) {
if (!memory->mbcState.mbc6.sramAccess) { if (!memory->sramAccess) {
return 0xFF; return 0xFF;
} }
switch (address >> 12) { 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) { void GBMBCRTCRead(struct GB* gb) {
struct GBMBCRTCSaveBuffer rtcBuffer; struct GBMBCRTCSaveBuffer rtcBuffer;
struct VFile* vf = gb->sramVf; 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: case GB_REGION_EXTERNAL_RAM + 1:
if (memory->rtcAccess) { if (memory->rtcAccess) {
memory->rtcRegs[memory->activeRtcReg] = value; 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; memory->sramBank[address & (GB_SIZE_EXTERNAL_RAM - 1)] = value;
} else { } else {
memory->mbcWrite(gb, address, value); 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) { 0x630ed957, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (non-debug)
{ 0x5aff0038, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (debug) { 0x5aff0038, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (debug)
{ 0xa61856bd, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Silver (non-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 } } { 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_HuC1);
s_mbcList.append(GB_HuC3); s_mbcList.append(GB_HuC3);
s_mbcList.append(GB_UNL_WISDOM_TREE); s_mbcList.append(GB_UNL_WISDOM_TREE);
s_mbcList.append(GB_UNL_PKJD);
} }
if (s_gbModelList.isEmpty()) { if (s_gbModelList.isEmpty()) {
// NB: Keep in sync with OverrideView.ui // NB: Keep in sync with OverrideView.ui

View File

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