GB MBC: Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
@@ -34,9 +34,10 @@ GB_HuC1 = 0x11,
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 {
@@ -146,6 +146,10 @@ uint8_t reg;
uint8_t registers[GBTAMA5_MAX]; }; +struct GBPKJDState { + uint8_t reg[2]; +}; + union GBMBCState { struct GBMBC1State mbc1; struct GBMBC6State mbc6;@@ -153,6 +157,7 @@ struct GBMBC7State mbc7;
struct GBMMM01State mmm01; struct GBPocketCamState pocketCam; struct GBTAMA5State tama5; + struct GBPKJDState pkjd; }; struct mRotationSource;@@ -171,6 +176,7 @@ uint8_t* wramBank;
int wramCurrentBank; bool sramAccess; + bool directSramAccess; uint8_t* sram; uint8_t* sramBank; int sramCurrentBank;
@@ -162,6 +162,10 @@ cb(total, size, context);
} } vf->close(vf); + if (read < 0) { + vfm->close(vfm); + return false; + } bool ret = core->loadROM(core, vfm); if (!ret) { vfm->close(vfm);
@@ -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 @@ } else {
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 @@ break;
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 @@ case GB_MBC5:
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 @@ break;
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 @@ switch (address >> 10) {
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 @@ case 0x28:
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 @@ case 0x2C:
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 @@ }
} uint8_t _GBMBC6Read(struct GBMemory* memory, uint16_t address) { - if (!memory->mbcState.mbc6.sramAccess) { + if (!memory->sramAccess) { return 0xFF; } switch (address >> 12) {@@ -1226,6 +1234,74 @@ default:
// TODO mLOG(GB_MBC, STUB, "Wisdom Tree unknown address: %04X:%02X", address, value); break; + } +} + +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; } }
@@ -361,7 +361,7 @@ case GB_REGION_EXTERNAL_RAM:
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);
@@ -495,6 +495,7 @@ { 0x232a067d, GB_MODEL_AUTODETECT, GB_MBC3_RTC, { 0 } }, // Gold (debug)
{ 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 } } };
@@ -50,6 +50,7 @@ s_mbcList.append(GB_TAMA5);
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
@@ -359,6 +359,11 @@ <property name="text">
<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">