mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
This commit is contained in:
parent
3062a6a2d7
commit
cdf9105f56
1
CHANGES
1
CHANGES
|
@ -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
|
||||
|
|
|
@ -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:
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
88
src/gb/mbc.c
88
src/gb/mbc.c
|
@ -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;
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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 } }
|
||||
};
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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">
|
||||
|
|
Loading…
Reference in New Issue