mirror of
https://github.com/sanni/cartreader.git
synced 2024-11-27 23:14:14 +01:00
Patching header for some games
(No affect on rom file dumping)
This commit is contained in:
parent
92c7a41c97
commit
5e77331912
@ -20,10 +20,22 @@ static const char wsMenuItem3[] PROGMEM = "Write Save";
|
|||||||
static const char wsMenuItem4[] PROGMEM = "Reset";
|
static const char wsMenuItem4[] PROGMEM = "Reset";
|
||||||
static const char* const menuOptionsWS[] PROGMEM = {wsMenuItem1, wsMenuItem2, wsMenuItem3, wsMenuItem4};
|
static const char* const menuOptionsWS[] PROGMEM = {wsMenuItem1, wsMenuItem2, wsMenuItem3, wsMenuItem4};
|
||||||
|
|
||||||
|
/******************************************
|
||||||
|
* Developer Name
|
||||||
|
*****************************************/
|
||||||
|
static const char wsDevNameXX[] PROGMEM = "XXX";
|
||||||
|
static const char wsDevName01[] PROGMEM = "BAN";
|
||||||
|
static const char wsDevName12[] PROGMEM = "KNM";
|
||||||
|
static const char wsDevName18[] PROGMEM = "KGT";
|
||||||
|
static const char wsDevName1D[] PROGMEM = "BEC";
|
||||||
|
static const char wsDevName24[] PROGMEM = "0MN";
|
||||||
|
static const char wsDevName28[] PROGMEM = "SQR";
|
||||||
|
static const char wsDevName31[] PROGMEM = "VGD";
|
||||||
|
|
||||||
static uint8_t wsGameOrientation = 0;
|
static uint8_t wsGameOrientation = 0;
|
||||||
static uint8_t wsGameHasRTC = 0;
|
static uint8_t wsGameHasRTC = 0;
|
||||||
static uint16_t wsGameChecksum = 0;
|
static uint16_t wsGameChecksum = 0;
|
||||||
static uint8_t wsEepromShiftReg[5];
|
static uint8_t wsEepromShiftReg[2];
|
||||||
|
|
||||||
void setup_WS()
|
void setup_WS()
|
||||||
{
|
{
|
||||||
@ -140,18 +152,93 @@ uint8_t getCartInfo_WS()
|
|||||||
for (uint32_t i = 0; i < 16; i += 2)
|
for (uint32_t i = 0; i < 16; i += 2)
|
||||||
*((uint16_t*)(sdBuffer + i)) = readWord_WS(0xffff0 + i);
|
*((uint16_t*)(sdBuffer + i)) = readWord_WS(0xffff0 + i);
|
||||||
|
|
||||||
// developer and cartID
|
wsGameChecksum = *(uint16_t*)(sdBuffer + 14);
|
||||||
snprintf(cartID, 5, "%02X%02X", sdBuffer[6], sdBuffer[8]);
|
|
||||||
|
// some game has wrong info in header
|
||||||
|
// patch here
|
||||||
|
switch (wsGameChecksum)
|
||||||
|
{
|
||||||
|
// games with 256kbits SRAM installed
|
||||||
|
case 0xe600: // BAN007
|
||||||
|
case 0x8eed: // BANC16
|
||||||
|
{
|
||||||
|
sdBuffer[11] = 0x02;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// games missing 'COLOR' flag
|
||||||
|
case 0x26db: // SQRC01
|
||||||
|
{
|
||||||
|
sdBuffer[7] = 0x01;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x7f73: // BAN030
|
||||||
|
{
|
||||||
|
// missing developerId and cartId
|
||||||
|
sdBuffer[6] = 0x01;
|
||||||
|
sdBuffer[8] = 0x30;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 0x0000:
|
||||||
|
{
|
||||||
|
// developerId/cartId/checksum are all filled with 0x00 in wonderwitch based games
|
||||||
|
if (readWord_WS(0xf0000) == 0x4c45 && readWord_WS(0xf0002) == 0x5349 && readWord_WS(0xf0004) == 0x0041)
|
||||||
|
{
|
||||||
|
// looking for "<Ini" string
|
||||||
|
if (readWord_WS(0xec456) == 0x493c && readWord_WS(0xec458) == 0x696e)
|
||||||
|
{
|
||||||
|
// wonderwitch SWJ-7AC003
|
||||||
|
sdBuffer[6] = 0x7a;
|
||||||
|
sdBuffer[8] = 0xc3;
|
||||||
|
// TODO check OS version and fill into version field
|
||||||
|
}
|
||||||
|
// looking for "<Ini" string
|
||||||
|
else if (readWord_WS(0x839d8) == 0x493c && readWord_WS(0x839da) == 0x696e)
|
||||||
|
{
|
||||||
|
if (readWord_WS(0x93246) == 0x4a2f && readWord_WS(0x93248) == 0x5353 && readWord_WS(0x9324a) == 0x2e32)
|
||||||
|
{
|
||||||
|
// jss2
|
||||||
|
// TODO check jss version
|
||||||
|
sdBuffer[6] = 0xff; // WWGP
|
||||||
|
sdBuffer[8] = 0x1a; // 2001A
|
||||||
|
sdBuffer[7] = 0x01; // color only
|
||||||
|
|
||||||
|
if (readWord_WS(0x93e9c) == 0x4648 && readWord_WS(0x93e9e) == 0x0050)
|
||||||
|
{
|
||||||
|
// WWGP2001A3 -> HFP Version
|
||||||
|
sdBuffer[9] = 0x03;
|
||||||
|
wsGameChecksum = 0x4870;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// TODO other version
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (readWord_WS(0xe4260) == 0x6b64 && readWord_WS(0xe4262) == 0x696e)
|
||||||
|
{
|
||||||
|
// dknight
|
||||||
|
sdBuffer[6] = 0xff; // WWGP
|
||||||
|
sdBuffer[8] = 0x2b; // 2002B
|
||||||
|
sdBuffer[7] = 0x01; // color only
|
||||||
|
sdBuffer[9] = 0x00;
|
||||||
|
wsGameChecksum = 0x8b1c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
romType = sdBuffer[7]; // wsc only = 1
|
romType = sdBuffer[7]; // wsc only = 1
|
||||||
romVersion = sdBuffer[9];
|
romVersion = sdBuffer[9];
|
||||||
romSize = sdBuffer[10];
|
romSize = sdBuffer[10];
|
||||||
sramSize = sdBuffer[11];
|
sramSize = sdBuffer[11];
|
||||||
wsGameOrientation = (sdBuffer[12] & 0x01);
|
wsGameOrientation = (sdBuffer[12] & 0x01);
|
||||||
wsGameHasRTC = (sdBuffer[13] & 0x01);
|
wsGameHasRTC = (sdBuffer[13] & 0x01);
|
||||||
wsGameChecksum = *(uint16_t*)(sdBuffer + 14);
|
|
||||||
snprintf(checksumStr, 5, "%04X", wsGameChecksum);
|
|
||||||
|
|
||||||
strncpy(romName, cartID, sizeof(romName) - 1);
|
snprintf(vendorID, 4, "%02X", sdBuffer[6]);
|
||||||
|
snprintf(cartID, 4, "%c%02X", ((romType & 0x01) ? 'C' : '0'), sdBuffer[8]);
|
||||||
|
snprintf(checksumStr, 5, "%04X", wsGameChecksum);
|
||||||
|
snprintf(romName, 17, "%s%s", vendorID, cartID);
|
||||||
|
|
||||||
switch (romSize)
|
switch (romSize)
|
||||||
{
|
{
|
||||||
@ -194,7 +281,7 @@ void showCartInfo_WS()
|
|||||||
println_Msg(F("WonderSwan Cart Info"));
|
println_Msg(F("WonderSwan Cart Info"));
|
||||||
|
|
||||||
print_Msg(F("Game: "));
|
print_Msg(F("Game: "));
|
||||||
println_Msg(cartID);
|
println_Msg(romName);
|
||||||
|
|
||||||
print_Msg(F("Rom Size: "));
|
print_Msg(F("Rom Size: "));
|
||||||
if (cartSize == 0x00)
|
if (cartSize == 0x00)
|
||||||
@ -307,7 +394,7 @@ void readSRAM_WS()
|
|||||||
uint32_t bank_size = (sramSize << 7);
|
uint32_t bank_size = (sramSize << 7);
|
||||||
uint16_t end_bank = (bank_size >> 16); // 64KB per bank
|
uint16_t end_bank = (bank_size >> 16); // 64KB per bank
|
||||||
|
|
||||||
if (end_bank > 0)
|
if (bank_size > 0x10000)
|
||||||
bank_size = 0x10000;
|
bank_size = 0x10000;
|
||||||
|
|
||||||
uint16_t bank = 0;
|
uint16_t bank = 0;
|
||||||
@ -349,7 +436,7 @@ void verifySRAM_WS()
|
|||||||
uint16_t bank = 0;
|
uint16_t bank = 0;
|
||||||
uint32_t write_errors = 0;
|
uint32_t write_errors = 0;
|
||||||
|
|
||||||
if (end_bank > 0)
|
if (bank_size > 0x10000)
|
||||||
bank_size = 0x10000;
|
bank_size = 0x10000;
|
||||||
|
|
||||||
do
|
do
|
||||||
@ -410,7 +497,7 @@ void writeSRAM_WS()
|
|||||||
uint32_t bank_size = (sramSize << 7);
|
uint32_t bank_size = (sramSize << 7);
|
||||||
uint16_t end_bank = (bank_size >> 16); // 64KB per bank
|
uint16_t end_bank = (bank_size >> 16); // 64KB per bank
|
||||||
|
|
||||||
if (end_bank > 0)
|
if (bank_size > 0x10000)
|
||||||
bank_size = 0x10000;
|
bank_size = 0x10000;
|
||||||
|
|
||||||
uint16_t bank = 0;
|
uint16_t bank = 0;
|
||||||
@ -478,12 +565,12 @@ void readEEPROM_WS()
|
|||||||
if ((j & 0x1f) == 0x00)
|
if ((j & 0x1f) == 0x00)
|
||||||
PORTB ^= (1 << 4);
|
PORTB ^= (1 << 4);
|
||||||
|
|
||||||
generateEepromInstruction_WS(wsEepromShiftReg, 0x2, ((i + j) >> 1), 0x00, 0x00);
|
generateEepromInstruction_WS(wsEepromShiftReg, 0x2, ((i + j) >> 1));
|
||||||
|
|
||||||
dataOut_WS();
|
dataOut_WS();
|
||||||
writeByte_WSPort(0xc6, wsEepromShiftReg[2]);
|
writeByte_WSPort(0xc6, wsEepromShiftReg[0]);
|
||||||
writeByte_WSPort(0xc7, wsEepromShiftReg[3]);
|
writeByte_WSPort(0xc7, wsEepromShiftReg[1]);
|
||||||
writeByte_WSPort(0xc8, wsEepromShiftReg[4]);
|
writeByte_WSPort(0xc8, 0x10);
|
||||||
|
|
||||||
// MMC will shift out from port 0xc7 to 0xc6
|
// MMC will shift out from port 0xc7 to 0xc6
|
||||||
// and shift in 16bits into port 0xc5 to 0xc4
|
// and shift in 16bits into port 0xc5 to 0xc4
|
||||||
@ -522,12 +609,12 @@ void verifyEEPROM_WS()
|
|||||||
if ((j & 0x1f) == 0x00)
|
if ((j & 0x1f) == 0x00)
|
||||||
PORTB ^= (1 << 4);
|
PORTB ^= (1 << 4);
|
||||||
|
|
||||||
generateEepromInstruction_WS(wsEepromShiftReg, 0x2, ((i + j) >> 1), 0x00, 0x00);
|
generateEepromInstruction_WS(wsEepromShiftReg, 0x2, ((i + j) >> 1));
|
||||||
|
|
||||||
dataOut_WS();
|
dataOut_WS();
|
||||||
writeByte_WSPort(0xc6, wsEepromShiftReg[2]);
|
writeByte_WSPort(0xc6, wsEepromShiftReg[0]);
|
||||||
writeByte_WSPort(0xc7, wsEepromShiftReg[3]);
|
writeByte_WSPort(0xc7, wsEepromShiftReg[1]);
|
||||||
writeByte_WSPort(0xc8, wsEepromShiftReg[4]);
|
writeByte_WSPort(0xc8, 0x10);
|
||||||
|
|
||||||
// MMC will shift out from port 0xc7 to 0xc6
|
// MMC will shift out from port 0xc7 to 0xc6
|
||||||
// and shift in 16bits into port 0xc5 to 0xc4
|
// and shift in 16bits into port 0xc5 to 0xc4
|
||||||
@ -591,14 +678,14 @@ void writeEEPROM_WS()
|
|||||||
if ((j & 0x1f) == 0x00)
|
if ((j & 0x1f) == 0x00)
|
||||||
PORTB ^= (1 << 4);
|
PORTB ^= (1 << 4);
|
||||||
|
|
||||||
generateEepromInstruction_WS(wsEepromShiftReg, 0x1, ((i + j) >> 1), sdBuffer[j], sdBuffer[j + 1]);
|
generateEepromInstruction_WS(wsEepromShiftReg, 0x1, ((i + j) >> 1));
|
||||||
|
|
||||||
dataOut_WS();
|
dataOut_WS();
|
||||||
writeByte_WSPort(0xc6, wsEepromShiftReg[2]);
|
writeByte_WSPort(0xc6, wsEepromShiftReg[0]);
|
||||||
writeByte_WSPort(0xc7, wsEepromShiftReg[3]);
|
writeByte_WSPort(0xc7, wsEepromShiftReg[1]);
|
||||||
writeByte_WSPort(0xc4, wsEepromShiftReg[0]);
|
writeByte_WSPort(0xc4, sdBuffer[j]);
|
||||||
writeByte_WSPort(0xc5, wsEepromShiftReg[1]);
|
writeByte_WSPort(0xc5, sdBuffer[j + 1]);
|
||||||
writeByte_WSPort(0xc8, wsEepromShiftReg[4]);
|
writeByte_WSPort(0xc8, 0x20);
|
||||||
|
|
||||||
// MMC will shift out from port 0xc7 to 0xc4
|
// MMC will shift out from port 0xc7 to 0xc4
|
||||||
pulseCLK_WS(1 + 32 + 3);
|
pulseCLK_WS(1 + 32 + 3);
|
||||||
@ -651,7 +738,7 @@ boolean compareChecksum_WS(const char *wsFilePath)
|
|||||||
myFile.close();
|
myFile.close();
|
||||||
|
|
||||||
checksum &= 0x0000ffff;
|
checksum &= 0x0000ffff;
|
||||||
calLength = *((uint16_t*)(sdBuffer + 512 - 2));
|
calLength = wsGameChecksum;
|
||||||
|
|
||||||
// don't know why formating string "%04X(%04X)" always output "xxxx(0000)"
|
// don't know why formating string "%04X(%04X)" always output "xxxx(0000)"
|
||||||
// so split into two snprintf
|
// so split into two snprintf
|
||||||
@ -758,68 +845,42 @@ uint16_t readWord_WS(uint32_t addr)
|
|||||||
|
|
||||||
void unprotectEEPROM()
|
void unprotectEEPROM()
|
||||||
{
|
{
|
||||||
generateEepromInstruction_WS(wsEepromShiftReg, 0x0, 0x3, 0x00, 0x00);
|
generateEepromInstruction_WS(wsEepromShiftReg, 0x0, 0x3);
|
||||||
|
|
||||||
dataOut_WS();
|
dataOut_WS();
|
||||||
writeByte_WSPort(0xc6, wsEepromShiftReg[2]);
|
writeByte_WSPort(0xc6, wsEepromShiftReg[0]);
|
||||||
writeByte_WSPort(0xc7, wsEepromShiftReg[3]);
|
writeByte_WSPort(0xc7, wsEepromShiftReg[1]);
|
||||||
writeByte_WSPort(0xc8, wsEepromShiftReg[4]);
|
writeByte_WSPort(0xc8, 0x40);
|
||||||
|
|
||||||
// MMC will shift out port 0xc7 to 0xc6 to EEPROM
|
// MMC will shift out port 0xc7 to 0xc6 to EEPROM
|
||||||
pulseCLK_WS(1 + 16 + 3);
|
pulseCLK_WS(1 + 16 + 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
// generate data for port 0xc4 to 0xc8
|
// generate data for port 0xc6 to 0xc7
|
||||||
// number of CLK pulses needed for each instruction is 1 + (16 or 32) + 3
|
// number of CLK pulses needed for each instruction is 1 + (16 or 32) + 3
|
||||||
void generateEepromInstruction_WS(uint8_t *instruction, uint8_t opcode, uint16_t addr, uint8_t l_data, uint8_t h_data)
|
void generateEepromInstruction_WS(uint8_t *instruction, uint8_t opcode, uint16_t addr)
|
||||||
{
|
{
|
||||||
uint32_t *ptr = (uint32_t*)instruction;
|
|
||||||
uint8_t addr_bits = (sramSize > 1 ? 10 : 6);
|
uint8_t addr_bits = (sramSize > 1 ? 10 : 6);
|
||||||
*ptr = 0x00000001; // initial with a start bit
|
uint16_t *ptr = (uint16_t*)instruction;
|
||||||
|
*ptr = 0x0001; // initial with a start bit
|
||||||
|
|
||||||
switch (opcode)
|
if (opcode == 0)
|
||||||
{
|
{
|
||||||
case 0x00:
|
// 2bits opcode = 0x00
|
||||||
{
|
*ptr <<= 2;
|
||||||
addr &= 0x0003;
|
// 2bits ext cmd (from addr)
|
||||||
*ptr <<= 2; // opcode = 0x0
|
*ptr <<= 2;
|
||||||
*ptr = ((*ptr << 2) | addr);
|
*ptr |= (addr & 0x0003);
|
||||||
*ptr <<= (addr_bits - 2);
|
*ptr <<= (addr_bits - 2);
|
||||||
*ptr <<= 16;
|
|
||||||
|
|
||||||
if (addr == 0x01)
|
|
||||||
{
|
|
||||||
// WRAL: fill every byte in eeprom with same data
|
|
||||||
instruction[0] = l_data;
|
|
||||||
instruction[1] = h_data;
|
|
||||||
instruction[4] = 0x20;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
instruction[4] = 0x40;
|
// 2bits opcode
|
||||||
}
|
*ptr <<= 2;
|
||||||
|
*ptr |= (opcode & 0x03);
|
||||||
break;
|
// address bits
|
||||||
}
|
*ptr <<= addr_bits;
|
||||||
case 1: // WRITE
|
*ptr |= (addr & ((1 << addr_bits) - 1));
|
||||||
{
|
|
||||||
*ptr = ((*ptr << 2) | opcode); // 2bits opcode
|
|
||||||
*ptr = ((*ptr << addr_bits) | addr); // address bits
|
|
||||||
*ptr <<= 16;
|
|
||||||
instruction[0] = l_data;
|
|
||||||
instruction[1] = h_data;
|
|
||||||
instruction[4] = 0x20;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case 2: // READ
|
|
||||||
case 3: // ERASE
|
|
||||||
{
|
|
||||||
*ptr = ((*ptr << 2) | opcode); // 2bits opcode
|
|
||||||
*ptr = ((*ptr << addr_bits) | addr); // address bits
|
|
||||||
*ptr <<= 16;
|
|
||||||
instruction[4] = (opcode == 2 ? 0x10 : 0x20);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user