mirror of https://github.com/mgba-emu/mgba.git
GB MBC: Add Hitek and BBD mappers
This commit is contained in:
parent
3b363bb2c1
commit
bf16c7b6bf
2
CHANGES
2
CHANGES
|
@ -3,6 +3,8 @@ Features:
|
||||||
- e-Reader card scanning
|
- e-Reader card scanning
|
||||||
- Add WebP and APNG recording
|
- Add WebP and APNG recording
|
||||||
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
|
- Support for unlicensed Pokemon Jade/Diamond Game Boy mapper
|
||||||
|
- Support for unlicensed BBD Game Boy mapper
|
||||||
|
- Support for unlicensed Hitek Game Boy mapper
|
||||||
- Stack tracing tools in ARM debugger (by ahigerd)
|
- Stack tracing tools in ARM debugger (by ahigerd)
|
||||||
- Command scripts for CLI debugger (by ahigerd)
|
- Command scripts for CLI debugger (by ahigerd)
|
||||||
Emulation fixes:
|
Emulation fixes:
|
||||||
|
|
|
@ -38,6 +38,8 @@ enum GBMemoryBankControllerType {
|
||||||
GB_MBC5_RUMBLE = 0x105,
|
GB_MBC5_RUMBLE = 0x105,
|
||||||
GB_UNL_WISDOM_TREE = 0x200,
|
GB_UNL_WISDOM_TREE = 0x200,
|
||||||
GB_UNL_PKJD = 0x203,
|
GB_UNL_PKJD = 0x203,
|
||||||
|
GB_UNL_BBD = 0x220, // Also used as a mask for MBCs that need special read behavior
|
||||||
|
GB_UNL_HITEK = 0x221,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct GBSIODriver {
|
struct GBSIODriver {
|
||||||
|
|
|
@ -150,6 +150,11 @@ struct GBPKJDState {
|
||||||
uint8_t reg[2];
|
uint8_t reg[2];
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct GBBBDState {
|
||||||
|
int dataSwapMode;
|
||||||
|
int bankSwapMode;
|
||||||
|
};
|
||||||
|
|
||||||
union GBMBCState {
|
union GBMBCState {
|
||||||
struct GBMBC1State mbc1;
|
struct GBMBC1State mbc1;
|
||||||
struct GBMBC6State mbc6;
|
struct GBMBC6State mbc6;
|
||||||
|
@ -158,6 +163,7 @@ union GBMBCState {
|
||||||
struct GBPocketCamState pocketCam;
|
struct GBPocketCamState pocketCam;
|
||||||
struct GBTAMA5State tama5;
|
struct GBTAMA5State tama5;
|
||||||
struct GBPKJDState pkjd;
|
struct GBPKJDState pkjd;
|
||||||
|
struct GBBBDState bbd;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct mRotationSource;
|
struct mRotationSource;
|
||||||
|
|
|
@ -391,6 +391,10 @@ struct GBSerializedState {
|
||||||
uint8_t locked;
|
uint8_t locked;
|
||||||
uint8_t bank0;
|
uint8_t bank0;
|
||||||
} mmm01;
|
} mmm01;
|
||||||
|
struct {
|
||||||
|
uint8_t dataSwapMode;
|
||||||
|
uint8_t bankSwapMode;
|
||||||
|
} bbd;
|
||||||
struct {
|
struct {
|
||||||
uint8_t reserved[16];
|
uint8_t reserved[16];
|
||||||
} padding;
|
} padding;
|
||||||
|
|
164
src/gb/mbc.c
164
src/gb/mbc.c
|
@ -37,6 +37,8 @@ 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 void _GBPKJD(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);
|
||||||
|
|
||||||
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);
|
||||||
|
@ -45,6 +47,8 @@ static void _GBMBC7Write(struct GBMemory* memory, uint16_t address, uint8_t valu
|
||||||
|
|
||||||
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 _GBPKJDRead(struct GBMemory*, uint16_t address);
|
||||||
|
static uint8_t _GBBBDRead(struct GBMemory*, uint16_t address);
|
||||||
|
static uint8_t _GBHitekRead(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*);
|
||||||
|
@ -145,6 +149,31 @@ static bool _isWisdomTree(const uint8_t* mem, size_t size) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static enum GBMemoryBankControllerType _detectUnlMBC(const uint8_t* mem, size_t size) {
|
||||||
|
const struct GBCartridge* cart = (const struct GBCartridge*) &mem[0x100];
|
||||||
|
|
||||||
|
switch (cart->type) {
|
||||||
|
case 0:
|
||||||
|
if (_isWisdomTree(mem, size)) {
|
||||||
|
return GB_UNL_WISDOM_TREE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t secondaryLogo = doCrc32(&mem[0x184], 0x30);
|
||||||
|
switch (secondaryLogo) {
|
||||||
|
case 0x4fdab691:
|
||||||
|
return GB_UNL_HITEK;
|
||||||
|
case 0xc7d8c1df:
|
||||||
|
case 0x6d1ea662: // Garou
|
||||||
|
if (mem[0x7FFF] != 0x01) { // Make sure we're not using a "fixed" version
|
||||||
|
return GB_UNL_BBD;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return GB_MBC_AUTODETECT;
|
||||||
|
}
|
||||||
|
|
||||||
void GBMBCSwitchSramBank(struct GB* gb, int bank) {
|
void GBMBCSwitchSramBank(struct GB* gb, int bank) {
|
||||||
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
|
size_t bankStart = bank * GB_SIZE_EXTERNAL_RAM;
|
||||||
if (bankStart + GB_SIZE_EXTERNAL_RAM > gb->sramSize) {
|
if (bankStart + GB_SIZE_EXTERNAL_RAM > gb->sramSize) {
|
||||||
|
@ -202,15 +231,13 @@ void GBMBCInit(struct GB* gb) {
|
||||||
gb->sramSize = 0x10000;
|
gb->sramSize = 0x10000;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
|
||||||
|
gb->memory.mbcType = _detectUnlMBC(gb->memory.rom, gb->memory.romSize);
|
||||||
|
}
|
||||||
|
|
||||||
if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
|
if (gb->memory.mbcType == GB_MBC_AUTODETECT) {
|
||||||
switch (cart->type) {
|
switch (cart->type) {
|
||||||
case 0:
|
case 0:
|
||||||
if (_isWisdomTree(gb->memory.rom, gb->memory.romSize)) {
|
|
||||||
gb->memory.mbcType = GB_UNL_WISDOM_TREE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
// Fall through
|
|
||||||
case 8:
|
case 8:
|
||||||
case 9:
|
case 9:
|
||||||
gb->memory.mbcType = GB_MBC_NONE;
|
gb->memory.mbcType = GB_MBC_NONE;
|
||||||
|
@ -346,6 +373,16 @@ 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_BBD:
|
||||||
|
gb->memory.mbcWrite = _GBBBD;
|
||||||
|
gb->memory.mbcRead = _GBBBDRead;
|
||||||
|
break;
|
||||||
|
case GB_UNL_HITEK:
|
||||||
|
gb->memory.mbcWrite = _GBHitek;
|
||||||
|
gb->memory.mbcRead = _GBHitekRead;
|
||||||
|
gb->memory.mbcState.bbd.dataSwapMode = 7;
|
||||||
|
gb->memory.mbcState.bbd.bankSwapMode = 7;
|
||||||
|
break;
|
||||||
case GB_UNL_PKJD:
|
case GB_UNL_PKJD:
|
||||||
gb->memory.mbcWrite = _GBPKJD;
|
gb->memory.mbcWrite = _GBPKJD;
|
||||||
gb->memory.mbcRead = _GBPKJDRead;
|
gb->memory.mbcRead = _GBPKJDRead;
|
||||||
|
@ -1306,6 +1343,123 @@ 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 _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
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 03 - NOT KNOWN YET
|
||||||
|
{ 0, 5, 1, 3, 4, 2, 6, 7 }, // 04 - Garou
|
||||||
|
{ 0, 4, 2, 3, 1, 5, 6, 7 }, // 05 - Harry
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
|
||||||
|
{ 0, 1, 5, 3, 4, 2, 6, 7 }, // 07 - Digimon
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t _bbdBankReordering[8][8] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 00 - Normal
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 01 - NOT KNOWN YET
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 02 - NOT KNOWN YET
|
||||||
|
{ 3, 4, 2, 0, 1, 5, 6, 7 }, // 03 - 0,1 unconfirmed. Digimon/Garou
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 04 - NOT KNOWN YET
|
||||||
|
{ 1, 2, 3, 4, 0, 5, 6, 7 }, // 05 - 0,1 unconfirmed. Harry
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 06 - NOT KNOWN YET
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 }, // 07 - NOT KNOWN YET
|
||||||
|
};
|
||||||
|
|
||||||
|
void _GBBBD(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
|
struct GBMemory* memory = &gb->memory;
|
||||||
|
switch (address & 0xF0FF) {
|
||||||
|
case 0x2000:
|
||||||
|
value = _reorderBits(value, _bbdBankReordering[memory->mbcState.bbd.bankSwapMode]);
|
||||||
|
break;
|
||||||
|
case 0x2001:
|
||||||
|
memory->mbcState.bbd.dataSwapMode = value & 0x07;
|
||||||
|
if (!(memory->mbcState.bbd.dataSwapMode == 0x07 || memory->mbcState.bbd.dataSwapMode == 0x05 || memory->mbcState.bbd.dataSwapMode == 0x04 || memory->mbcState.bbd.dataSwapMode == 0x00)) {
|
||||||
|
mLOG(GB_MBC, STUB, "Bitswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case 0x2080:
|
||||||
|
memory->mbcState.bbd.bankSwapMode = value & 0x07;
|
||||||
|
if (!(memory->mbcState.bbd.bankSwapMode == 0x03 || memory->mbcState.bbd.bankSwapMode == 0x05 || memory->mbcState.bbd.bankSwapMode == 0x00)) {
|
||||||
|
mLOG(GB_MBC, STUB, "Bankswap mode unsupported: %X", memory->mbcState.bbd.dataSwapMode);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
_GBMBC5(gb, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t _GBBBDRead(struct GBMemory* memory, uint16_t address) {
|
||||||
|
switch (address >> 14) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
|
case 1:
|
||||||
|
return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _bbdDataReordering[memory->mbcState.bbd.dataSwapMode]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static const uint8_t _hitekDataReordering[8][8] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||||
|
{ 0, 6, 5, 3, 4, 1, 2, 7 },
|
||||||
|
{ 0, 5, 6, 3, 4, 2, 1, 7 },
|
||||||
|
{ 0, 6, 2, 3, 4, 5, 1, 7 },
|
||||||
|
{ 0, 6, 1, 3, 4, 5, 2, 7 },
|
||||||
|
{ 0, 1, 6, 3, 4, 5, 2, 7 },
|
||||||
|
{ 0, 2, 6, 3, 4, 1, 5, 7 },
|
||||||
|
{ 0, 6, 2, 3, 4, 1, 5, 7 },
|
||||||
|
};
|
||||||
|
|
||||||
|
static const uint8_t _hitekBankReordering[8][8] = {
|
||||||
|
{ 0, 1, 2, 3, 4, 5, 6, 7 },
|
||||||
|
{ 3, 2, 1, 0, 4, 5, 6, 7 },
|
||||||
|
{ 2, 1, 0, 3, 4, 5, 6, 7 },
|
||||||
|
{ 1, 0, 3, 2, 4, 5, 6, 7 },
|
||||||
|
{ 0, 3, 2, 1, 4, 5, 6, 7 },
|
||||||
|
{ 2, 3, 0, 1, 4, 5, 6, 7 },
|
||||||
|
{ 3, 0, 1, 2, 4, 5, 6, 7 },
|
||||||
|
{ 2, 0, 3, 1, 4, 5, 6, 7 },
|
||||||
|
};
|
||||||
|
|
||||||
|
void _GBHitek(struct GB* gb, uint16_t address, uint8_t value) {
|
||||||
|
struct GBMemory* memory = &gb->memory;
|
||||||
|
switch (address & 0xF0FF) {
|
||||||
|
case 0x2000:
|
||||||
|
value = _reorderBits(value, _hitekBankReordering[memory->mbcState.bbd.bankSwapMode]);
|
||||||
|
break;
|
||||||
|
case 0x2001:
|
||||||
|
memory->mbcState.bbd.dataSwapMode = value & 0x07;
|
||||||
|
break;
|
||||||
|
case 0x2080:
|
||||||
|
memory->mbcState.bbd.bankSwapMode = value & 0x07;
|
||||||
|
break;
|
||||||
|
case 0x300:
|
||||||
|
// See hhugboy src/memory/mbc/MbcUnlHitek.cpp for commentary on this return
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
_GBMBC5(gb, address, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint8_t _GBHitekRead(struct GBMemory* memory, uint16_t address) {
|
||||||
|
switch (address >> 14) {
|
||||||
|
case 0:
|
||||||
|
default:
|
||||||
|
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
|
case 1:
|
||||||
|
return _reorderBits(memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)], _hitekDataReordering[memory->mbcState.bbd.dataSwapMode]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
|
|
@ -84,6 +84,10 @@ static void GBSetActiveRegion(struct SM83Core* cpu, uint16_t address) {
|
||||||
case GB_REGION_CART_BANK1 + 1:
|
case GB_REGION_CART_BANK1 + 1:
|
||||||
case GB_REGION_CART_BANK1 + 2:
|
case GB_REGION_CART_BANK1 + 2:
|
||||||
case GB_REGION_CART_BANK1 + 3:
|
case GB_REGION_CART_BANK1 + 3:
|
||||||
|
if ((gb->memory.mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
||||||
|
cpu->memory.cpuLoad8 = GBLoad8;
|
||||||
|
break;
|
||||||
|
}
|
||||||
cpu->memory.cpuLoad8 = GBFastLoad8;
|
cpu->memory.cpuLoad8 = GBFastLoad8;
|
||||||
if (gb->memory.mbcType != GB_MBC6) {
|
if (gb->memory.mbcType != GB_MBC6) {
|
||||||
cpu->memory.activeRegion = memory->romBank;
|
cpu->memory.activeRegion = memory->romBank;
|
||||||
|
@ -277,6 +281,9 @@ uint8_t GBLoad8(struct SM83Core* cpu, uint16_t address) {
|
||||||
if (address >= memory->romSize) {
|
if (address >= memory->romSize) {
|
||||||
return 0xFF;
|
return 0xFF;
|
||||||
}
|
}
|
||||||
|
if ((memory->mbcType & GB_UNL_BBD) == GB_UNL_BBD) {
|
||||||
|
return memory->mbcRead(memory, address);
|
||||||
|
}
|
||||||
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
return memory->romBank[address & (GB_SIZE_CART_BANK0 - 1)];
|
||||||
case GB_REGION_VRAM:
|
case GB_REGION_VRAM:
|
||||||
case GB_REGION_VRAM + 1:
|
case GB_REGION_VRAM + 1:
|
||||||
|
@ -754,6 +761,11 @@ void GBMemorySerialize(const struct GB* gb, struct GBSerializedState* state) {
|
||||||
state->memory.mmm01.locked = memory->mbcState.mmm01.locked;
|
state->memory.mmm01.locked = memory->mbcState.mmm01.locked;
|
||||||
state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0;
|
state->memory.mmm01.bank0 = memory->mbcState.mmm01.currentBank0;
|
||||||
break;
|
break;
|
||||||
|
case GB_UNL_BBD:
|
||||||
|
case GB_UNL_HITEK:
|
||||||
|
state->memory.bbd.dataSwapMode = memory->mbcState.bbd.dataSwapMode;
|
||||||
|
state->memory.bbd.bankSwapMode = memory->mbcState.bbd.bankSwapMode;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -841,6 +853,11 @@ void GBMemoryDeserialize(struct GB* gb, const struct GBSerializedState* state) {
|
||||||
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
|
GBMBCSwitchBank0(gb, gb->memory.romSize / GB_SIZE_CART_BANK0 - 2);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case GB_UNL_BBD:
|
||||||
|
case GB_UNL_HITEK:
|
||||||
|
memory->mbcState.bbd.dataSwapMode = state->memory.bbd.dataSwapMode & 0x7;
|
||||||
|
memory->mbcState.bbd.bankSwapMode = state->memory.bbd.bankSwapMode & 0x7;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -50,6 +50,8 @@ 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_BBD);
|
||||||
|
s_mbcList.append(GB_UNL_HITEK);
|
||||||
s_mbcList.append(GB_UNL_PKJD);
|
s_mbcList.append(GB_UNL_PKJD);
|
||||||
}
|
}
|
||||||
if (s_gbModelList.isEmpty()) {
|
if (s_gbModelList.isEmpty()) {
|
||||||
|
|
|
@ -359,6 +359,16 @@
|
||||||
<string>Wisdom Tree (Unlicensed)</string>
|
<string>Wisdom Tree (Unlicensed)</string>
|
||||||
</property>
|
</property>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>BBD (Unlicensed)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<property name="text">
|
||||||
|
<string>Hitek (Unlicensed)</string>
|
||||||
|
</property>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<property name="text">
|
<property name="text">
|
||||||
<string>Pokémon Jade/Diamond (Unlicensed)</string>
|
<string>Pokémon Jade/Diamond (Unlicensed)</string>
|
||||||
|
|
Loading…
Reference in New Issue