Add waitstate patching from ArcheyChen loader, SRAM patch not working

This commit is contained in:
Metroid Maniac 2024-02-04 10:43:58 +00:00
parent d2c9722f25
commit 15e8930321
11 changed files with 1376 additions and 0 deletions

View File

@ -0,0 +1,191 @@
#include "find.h"
#include "Save.h"
#include "EepromSave.h"
extern u32 romSize;
//todo: Moero!! Jaleco Collection (Japan) reports EEPROM_V124, but the signatures below don't work!
static const u8 sReadEepromDwordV111Sig[0x10] =
{0xB0, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88};
static const u8 sReadEepromDwordV120Sig[0x10] =
{0x70, 0xB5, 0xA2, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x03, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88};
static const u8 sProgramEepromDwordV111Sig[0x10] =
{0x80, 0xB5, 0xAA, 0xB0, 0x6F, 0x46, 0x79, 0x60, 0x39, 0x1C, 0x08, 0x80, 0x38, 0x1C, 0x01, 0x88};
//changed in EEPROM_V124
static const u8 sProgramEepromDwordV120Sig[0x10] =
{0x30, 0xB5, 0xA9, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x04, 0x0C, 0x03, 0x48, 0x00, 0x68, 0x80, 0x88};
//changed in EEPROM_V126
static const u8 sProgramEepromDwordV124Sig[0x10] =
{0xF0, 0xB5, 0xAC, 0xB0, 0x0D, 0x1C, 0x00, 0x04, 0x01, 0x0C, 0x12, 0x06, 0x17, 0x0E, 0x03, 0x48};
static const u8 sProgramEepromDwordV126Sig[0x10] =
{0xF0, 0xB5, 0x47, 0x46, 0x80, 0xB4, 0xAC, 0xB0, 0x0E, 0x1C, 0x00, 0x04, 0x05, 0x0C, 0x12, 0x06};
//not in EEPROM_V111
//could be used to identify the eeprom size, but not strictly needed
/*static u16 identifyEeprom(u16 kbitSize)
{
return 0;
}*/
const u8 patch_eeprom_1[]=
{
0x00,0x04, // LSL R0, R0, #0x10
0x0a,0x1c, // ADD R2, R1, #0
0x40,0x0b, // LSR R0, R0, #0xD
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
0x41,0x18, // ADD R1, R0, R1
0x07,0x31, // ADD R1, #7
0x00,0x23, // MOV R3, #0
//l1:
0x08,0x78, // LDRB R0, [R1]
0x10,0x70, // STRB R0, [R2]
0x01,0x33, // ADD R3, #1
0x01,0x32, // ADD R2, #1
0x01,0x39, // SUB R1, #1
0x07,0x2b, // CMP R3, #7
0xf8,0xd9, // BLS l1
0x00,0x20, // MOV R0, #0
0x70,0x47 // BX LR
};
const u8 patch_eeprom_2[]=
{
0x00,0x04, // LSL R0, R0, #0x10
0x0a,0x1c, // ADD R2, R1, #0
0x40,0x0b, // LSR R0, R0, #0xD
0xe0,0x21,0x09,0x05, // MOVL R1, 0xE000000
0x41,0x18, // ADD R1, R0, R1
0x07,0x31, // ADD R1, #7
0x00,0x23, // MOV R3, #0
//l1:
0x10,0x78, // LDRB R0, [R2]
0x08,0x70, // STRB R0, [R1]
0x01,0x33, // ADD R3, #1
0x01,0x32, // ADD R2, #1
0x01,0x39, // SUB R1, #1
0x07,0x2b, // CMP R3, #7
0xf8,0xd9, // BLS l1
0x00,0x20, // MOV R0, #0
0x70,0x47 // BX LR
};
bool eeprom_patchV111(const struct save_type* type)
{
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV111Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV111Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
return true;
}
bool eeprom_patchV120(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 3; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2-3 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV120Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
}
return true;
}
bool eeprom_patchV124(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 2; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* readFunc = memsearch8((u8*)romPos, curRomSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)romPos, curRomSize, sProgramEepromDwordV124Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
}
return true;
}
bool eeprom_patchV126(const struct save_type* type)
{
u8* readFunc = memsearch8((u8*)0x08000000, romSize, sReadEepromDwordV120Sig, 0x10, true);
if (!readFunc)
return false;
twoByteCpy((u16*)readFunc, (const u16*)patch_eeprom_1, sizeof(patch_eeprom_1));
u8* progFunc = memsearch8((u8*)0x08000000, romSize, sProgramEepromDwordV126Sig, 0x10, true);
if (!progFunc)
return false;
twoByteCpy((u16*)progFunc, (const u16*)patch_eeprom_2, sizeof(patch_eeprom_2));
return true;
}

View File

@ -0,0 +1,7 @@
#pragma once
#include "Save.h"
bool eeprom_patchV111(const struct save_type* type);
bool eeprom_patchV120(const struct save_type* type);
bool eeprom_patchV124(const struct save_type* type);
bool eeprom_patchV126(const struct save_type* type);

View File

@ -0,0 +1,358 @@
#include "find.h"
#include "Save.h"
#include "FlashSave.h"
extern u32 romSize;
static const u8 flash1M_V102_find1[48] = {
0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,0xe0,0x21,
0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x30,0xb5,
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20
};
static const u8 flash1M_V102_replace1[136] = {
0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,0xc3,0x02,
0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,0x30,0xb5,
0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,0xaa,0x20,
0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,0x03,0x4a,
0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,0x20,0x4e,
0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,0x0c,0x48,
0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,0x62,0x20,
0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,0x55,0x20,
0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find2[24] = {
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
};
static const u8 flash1M_V102_replace2[24] = {
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find3[22] = {
0xaa,0x25,0x0d,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
0x1a,0x70,0x30,0x20,0x20,0x70
};
static const u8 flash1M_V102_replace3[22] = {
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V102_find4[12] = {
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
};
static const u8 flash1M_V102_replace4[12] = {
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
};
static const u8 flash1M_V103_find1[98] = {
0x05,0x4b,0xaa,0x21,0x19,0x70,0x05,0x4a,0x55,0x21,0x11,0x70,0xb0,0x21,0x19,0x70,
0xe0,0x21,0x09,0x05,0x08,0x70,0x70,0x47,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
0xaa,0x20,0x10,0x70,0x05,0x49,0x55,0x20,0x08,0x70,0x90,0x20,0x10,0x70,0x10,0xa9,
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
0x0c,0x48
};
static const u8 flash1M_V103_replace1[138] = {
0x05,0x4b,0x80,0x21,0x09,0x02,0x09,0x22,0x12,0x06,0x9f,0x44,0x11,0x80,0x03,0x49,
0xc3,0x02,0xc9,0x18,0x11,0x80,0x70,0x47,0xfe,0xff,0xff,0x01,0x00,0x00,0x00,0x00,
0x30,0xb5,0x91,0xb0,0x68,0x46,0x00,0xf0,0xf3,0xf8,0x6d,0x46,0x01,0x35,0x06,0x4a,
0xaa,0x20,0x00,0x00,0x05,0x49,0x55,0x20,0x00,0x00,0x90,0x20,0x00,0x00,0x10,0xa9,
0x03,0x4a,0x10,0x1c,0x08,0xe0,0x00,0x00,0x55,0x55,0x00,0x0e,0xaa,0x2a,0x00,0x0e,
0x20,0x4e,0x00,0x00,0x08,0x88,0x01,0x38,0x08,0x80,0x08,0x88,0x00,0x28,0xf9,0xd1,
0x0c,0x48,0x13,0x20,0x13,0x20,0x00,0x06,0x04,0x0c,0xe0,0x20,0x00,0x05,0x62,0x20,
0x62,0x20,0x00,0x06,0x00,0x0e,0x04,0x43,0x07,0x49,0xaa,0x20,0x00,0x00,0x07,0x4a,
0x55,0x20,0x00,0x00,0xf0,0x20,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find2[24] = {
0x14,0x49,0xaa,0x24,0x0c,0x70,0x13,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,
0x0c,0x70,0x1a,0x70,0x10,0x20,0x08,0x70
};
static const u8 flash1M_V103_replace2[24] = {
0x0e,0x21,0x09,0x06,0xff,0x24,0x80,0x22,0x13,0x4b,0x52,0x02,0x01,0x3a,0x8c,0x54,
0xfc,0xd1,0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find3[22] = {
0xaa,0x25,0x0d,0x70,0x14,0x4b,0x55,0x22,0x1a,0x70,0x80,0x20,0x08,0x70,0x0d,0x70,
0x1a,0x70,0x30,0x20,0x20,0x70
};
static const u8 flash1M_V103_replace3[22] = {
0xff,0x25,0x08,0x22,0x00,0x00,0x52,0x02,0x01,0x3a,0xa5,0x54,0xfc,0xd1,0x00,0x00,
0x00,0x00,0x00,0x00,0x00,0x00
};
static const u8 flash1M_V103_find4[12] = {
0x10,0x70,0x0b,0x49,0x55,0x20,0x08,0x70,0xa0,0x20,0x10,0x70
};
static const u8 flash1M_V103_replace4[12] = {
0x00,0x00,0x0b,0x49,0x55,0x20,0x00,0x00,0xa0,0x20,0x00,0x00
};
static const u8 flash1M_V103_find5[12] = {
0x22,0x70,0x09,0x4b,0x55,0x22,0x1a,0x70,0xa0,0x22,0x22,0x70
};
static const u8 flash1M_V103_replace5[12] = {
0x00,0x00,0x09,0x4b,0x55,0x22,0x00,0x00,0xa0,0x22,0x00,0x00
};
// FLASH512_V130, V131, and V133 have all the same patches.
// Patches are from gbatemp thread, but gbata doesn't actually support V133.
static const u8 flash512_V13X_find1[38] = {
0xf0,0xb5,0xa0,0xb0,0x0d,0x1c,0x16,0x1c,0x1f,0x1c,0x03,0x04,0x1c,0x0c,0x0f,0x4a,
0x10,0x88,0x0f,0x49,0x08,0x40,0x03,0x21,0x08,0x43,0x10,0x80,0x0d,0x48,0x00,0x68,
0x01,0x68,0x80,0x20,0x80,0x02
};
static const u8 flash512_V13X_replace1[38] = {
0x70,0xb5,0xa0,0xb0,0x00,0x03,0x40,0x18,0xe0,0x21,0x09,0x05,0x09,0x18,0x08,0x78,
0x10,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,0x20,0xb0,
0x70,0xbc,0x02,0xbc,0x08,0x47
};
static const u8 flash512_V13X_find2[8] = {
0xff,0xf7,0x88,0xfd,0x00,0x04,0x03,0x0c
};
static const u8 flash512_V13X_replace2[8] = {
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
};
static const u8 flash512_V13X_find3[8] = {
0x70,0xb5,0x90,0xb0,0x15,0x4d,0x29,0x88
};
static const u8 flash512_V13X_find4[8] = {
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0
};
static const u8 flash512_V13X_replace3_4[8] = {
0x00,0xb5,0x00,0x20,0x02,0xbc,0x08,0x47
};
static const u8 flash512_V13X_find5[24] = {
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x03,0x48,0x00,0x68,0x40,0x89,
0x84,0x42,0x05,0xd3,0x01,0x48,0x41,0xe0
};
static const u8 flash512_V13X_replace5[42] = {
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x02,0xbc,0x08,0x47
};
// Encompasses FLASH_V120 and V121.
static const u8 flash_V12X_find1[12] = {
0x90,0xb5,0x93,0xb0,0x6f,0x46,0x39,0x1d,0x08,0x1c,0x00,0xf0
};
static const u8 flash_V12X_replace1[14] = {
0x00,0xb5,0x3d,0x20,0x00,0x02,0x1f,0x21,0x08,0x43,0x02,0xbc,0x08,0x47
};
static const u8 flash_V12X_find2[35] = {
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,0x0f,0x29,
0x04,0xd9,0x01,0x48,0x56,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x23,0x48,0x23,0x49,
0x0a,0x88,0x23
};
static const u8 flash_V12X_replace2[36] = {
0x7c,0xb5,0x00,0x07,0x00,0x0c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,0x1b,0x03,
0xff,0x20,0x08,0x70,0x01,0x3b,0x01,0x31,0x00,0x2b,0xfa,0xd1,0x00,0x20,0x7c,0xbc,
0x02,0xbc,0x08,0x47
};
static const u8 flash_V12X_find3[42] = {
0x80,0xb5,0x94,0xb0,0x6f,0x46,0x79,0x60,0x39,0x1c,0x08,0x80,0x38,0x1c,0x01,0x88,
0x0f,0x29,0x03,0xd9,0x00,0x48,0x73,0xe0,0xff,0x80,0x00,0x00,0x38,0x1c,0x01,0x88,
0x08,0x1c,0xff,0xf7,0x21,0xfe,0x39,0x1c,0x0c,0x31
};
static const u8 flash_V12X_replace3[42] = {
0x7c,0xb5,0x90,0xb0,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x09,0x18,0x01,0x23,
0x1b,0x03,0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,
0x00,0x20,0x10,0xb0,0x7c,0xbc,0x08,0xbc,0x08,0x47
};
// Encompasses FLASH_V123, V124, V125, and V126.
// FIXME for FLASH_V125 and FLASH_V126: Medabots/Metarot and Super Monkey Ball Jr. (U) don't patch 1:1 with gbata.
static const u8 flash_V12Y_find1[8] = {
0xff,0xf7,0xaa,0xff,0x00,0x04,0x03,0x0c
};
static const u8 flash_V12Y_replace1[8] = {
0x1b,0x23,0x1b,0x02,0x32,0x20,0x03,0x43
};
static const u8 flash_V12Y_find2[6] = {
0x70,0xb5,0x90,0xb0,0x15,0x4d
};
static const u8 flash_V12Y_replace2[4] = {
0x00,0x20,0x70,0x47/*,0x15,0x4d*/
};
// Patch 3 differs from GBATemp tutorial.
// The added bytes at the end have significance.
static const u8 flash_V12Y_find3[9] = {
0x70,0xb5,0x46,0x46,0x40,0xb4,0x90,0xb0,0x00
};
static const u8 flash_V12Y_replace3[4] = {
0x00,0x20,0x70,0x47/*,0x40,0xb4,0x90,0xb0,0x00*/
};
static const u8 flash_V12Y_find4[38] = {
0xf0,0xb5,0x90,0xb0,0x0f,0x1c,0x00,0x04,0x04,0x0c,0x0f,0x2c,0x04,0xd9,0x01,0x48,
0x40,0xe0,0x00,0x00,0xff,0x80,0x00,0x00,0x20,0x1c,0xff,0xf7,0xd7,0xfe,0x00,0x04,
0x05,0x0c,0x00,0x2d,0x35,0xd1
};
static const u8 flash_V12Y_replace4[38] = {
0x70,0xb5,0x00,0x03,0x0a,0x1c,0xe0,0x21,0x09,0x05,0x41,0x18,0x01,0x23,0x1b,0x03,
0x10,0x78,0x08,0x70,0x01,0x3b,0x01,0x32,0x01,0x31,0x00,0x2b,0xf8,0xd1,0x00,0x20,
0x70,0xbc,0x02,0xbc,0x08,0x47
};
bool flash_patchV120(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find1, sizeof(flash_V12X_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash_V12X_replace1, sizeof(flash_V12X_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find2, sizeof(flash_V12X_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash_V12X_replace2, sizeof(flash_V12X_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12X_find3, sizeof(flash_V12X_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash_V12X_replace3, sizeof(flash_V12X_replace3));
return true;
}
bool flash_patchV123(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find1, sizeof(flash_V12Y_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash_V12Y_replace1, sizeof(flash_V12Y_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find2, sizeof(flash_V12Y_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash_V12Y_replace2, sizeof(flash_V12Y_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find3, sizeof(flash_V12Y_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash_V12Y_replace3, sizeof(flash_V12Y_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash_V12Y_find4, sizeof(flash_V12Y_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash_V12Y_replace4, sizeof(flash_V12Y_replace4));
return true;
}
/*bool flash_patchV126(const struct save_type* type)
{
}*/
bool flash_patch512V130(const struct save_type* type)
{
u32* romPos = (u32*)0x08000000;
u32 curRomSize = romSize;
u32 startSig[4] = {0};
startSig[0] = *(u32*)0x08000000;
startSig[1] = *(u32*)0x08000004;
startSig[2] = *(u32*)0x08000008;
startSig[3] = *(u32*)0x0800000C;
for (int i = 0; i < 2; i++) {
if (i != 0) {
while (romPos < romPos+romSize) {
// Look for another ROM in 2 in 1 game packs
romPos += 0x100000;
curRomSize -= 0x100000;
if (curRomSize <= 0) break;
if (romPos[0] == startSig[0]
&& romPos[1] == startSig[1]
&& romPos[2] == startSig[2]
&& romPos[3] == startSig[3]) {
break;
}
}
if (romPos >= romPos+romSize) break;
}
u8* func1 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find1, sizeof(flash512_V13X_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash512_V13X_replace1, sizeof(flash512_V13X_replace1));
u8* func2 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find2, sizeof(flash512_V13X_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash512_V13X_replace2, sizeof(flash512_V13X_replace2));
u8* func3 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find3, sizeof(flash512_V13X_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
u8* func4 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find4, sizeof(flash512_V13X_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash512_V13X_replace3_4, sizeof(flash512_V13X_replace3_4));
u8* func5 = memsearch8((u8*)romPos, curRomSize, flash512_V13X_find5, sizeof(flash512_V13X_find5), true);
if (!func5)
return false;
twoByteCpy((u16*)func5, (const u16*)flash512_V13X_replace5, sizeof(flash512_V13X_replace5));
}
return true;
}
bool flash_patch1MV102(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find1, sizeof(flash1M_V102_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash1M_V102_replace1, sizeof(flash1M_V102_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find2, sizeof(flash1M_V102_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash1M_V102_replace2, sizeof(flash1M_V102_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find3, sizeof(flash1M_V102_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash1M_V102_replace3, sizeof(flash1M_V102_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V102_find4, sizeof(flash1M_V102_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash1M_V102_replace4, sizeof(flash1M_V102_replace4));
return true;
}
bool flash_patch1MV103(const struct save_type* type)
{
u8* func1 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find1, sizeof(flash1M_V103_find1), true);
if (!func1)
return false;
twoByteCpy((u16*)func1, (const u16*)flash1M_V103_replace1, sizeof(flash1M_V103_replace1));
u8* func2 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find2, sizeof(flash1M_V103_find2), true);
if (!func2)
return false;
twoByteCpy((u16*)func2, (const u16*)flash1M_V103_replace2, sizeof(flash1M_V103_replace2));
u8* func3 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find3, sizeof(flash1M_V103_find3), true);
if (!func3)
return false;
twoByteCpy((u16*)func3, (const u16*)flash1M_V103_replace3, sizeof(flash1M_V103_replace3));
u8* func4 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find4, sizeof(flash1M_V103_find4), true);
if (!func4)
return false;
twoByteCpy((u16*)func4, (const u16*)flash1M_V103_replace4, sizeof(flash1M_V103_replace4));
u8* func5 = memsearch8((u8*)0x08000000, romSize, flash1M_V103_find5, sizeof(flash1M_V103_find5), true);
if (!func5)
return false;
twoByteCpy((u16*)func5, (const u16*)flash1M_V103_replace5, sizeof(flash1M_V103_replace5));
return true;
}

View File

@ -0,0 +1,9 @@
#pragma once
#include "Save.h"
bool flash_patchV120(const struct save_type* type);
bool flash_patchV123(const struct save_type* type);
bool flash_patchV126(const struct save_type* type);
bool flash_patch512V130(const struct save_type* type);
bool flash_patch1MV102(const struct save_type* type);
bool flash_patch1MV103(const struct save_type* type);

View File

@ -0,0 +1,86 @@
#include <gba.h>
#include "EepromSave.h"
#include "FlashSave.h"
#include "Save.h"
#include "string.h"
u32 romSize;
#define SAVE_TYPE_COUNT 25
static const struct save_type sSaveTypes[SAVE_TYPE_COUNT] =
{
{"EEPROM_V111", 12, SAVE_TYPE_EEPROM_V111, 512, eeprom_patchV111},
{"EEPROM_V120", 12, SAVE_TYPE_EEPROM_V120, 8 * 1024, eeprom_patchV120},
{"EEPROM_V121", 12, SAVE_TYPE_EEPROM_V121, 8 * 1024, eeprom_patchV120},
{"EEPROM_V122", 12, SAVE_TYPE_EEPROM_V122, 8 * 1024, eeprom_patchV120},
{"EEPROM_V124", 12, SAVE_TYPE_EEPROM_V124, 8 * 1024, eeprom_patchV124},
{"EEPROM_V125", 12, SAVE_TYPE_EEPROM_V125, 8 * 1024, eeprom_patchV124},
{"EEPROM_V126", 12, SAVE_TYPE_EEPROM_V126, 8 * 1024, eeprom_patchV126},
{"FLASH_V120", 11, SAVE_TYPE_FLASH_V120, 64 * 1024, flash_patchV120},
{"FLASH_V121", 11, SAVE_TYPE_FLASH_V121, 64 * 1024, flash_patchV120},
{"FLASH_V123", 11, SAVE_TYPE_FLASH_V123, 64 * 1024, flash_patchV123},
{"FLASH_V124", 11, SAVE_TYPE_FLASH_V124, 64 * 1024, flash_patchV123},
{"FLASH_V125", 11, SAVE_TYPE_FLASH_V125, 64 * 1024, flash_patchV123},
{"FLASH_V126", 11, SAVE_TYPE_FLASH_V126, 64 * 1024, /*flash_patchV126*/ flash_patchV123},
{"FLASH512_V130", 14, SAVE_TYPE_FLASH512_V130, 64 * 1024, flash_patch512V130},
{"FLASH512_V131", 14, SAVE_TYPE_FLASH512_V131, 64 * 1024, flash_patch512V130},
{"FLASH512_V133", 14, SAVE_TYPE_FLASH512_V133, 64 * 1024, flash_patch512V130},
{"FLASH1M_V102", 13, SAVE_TYPE_FLASH1M_V102, 128 * 1024, flash_patch1MV102},
{"FLASH1M_V103", 13, SAVE_TYPE_FLASH1M_V103, 128 * 1024, flash_patch1MV103},
//sram does not require patching
{"SRAM_F_V100", 12, SAVE_TYPE_SRAM_F_V100, 32 * 1024, NULL},
{"SRAM_F_V102", 12, SAVE_TYPE_SRAM_F_V102, 32 * 1024, NULL},
{"SRAM_F_V103", 12, SAVE_TYPE_SRAM_F_V103, 32 * 1024, NULL},
{"SRAM_V110", 10, SAVE_TYPE_SRAM_V110, 32 * 1024, NULL},
{"SRAM_V111", 10, SAVE_TYPE_SRAM_V111, 32 * 1024, NULL},
{"SRAM_V112", 10, SAVE_TYPE_SRAM_V112, 32 * 1024, NULL},
{"SRAM_V113", 10, SAVE_TYPE_SRAM_V113, 32 * 1024, NULL},
};
const struct save_type* save_findTag()
{
u32 curAddr = 0x080000C0;
char saveTag[16];
while (curAddr < 0x08000000+romSize) {
u32 fst = *(u32*)curAddr;
// tonccpy(&saveTag, (u8*)curAddr, 16);
((u32*)saveTag)[0] = ((u32*)curAddr)[0];
((u32*)saveTag)[1] = ((u32*)curAddr)[1];
((u32*)saveTag)[2] = ((u32*)curAddr)[2];
((u32*)saveTag)[3] = ((u32*)curAddr)[3];
enum SaveType type = SAVE_TYPE_NONE;
if (fst == 0x53414C46 && (saveTag[5] == '_' || saveTag[5] == '5' || saveTag[5] == '1')) {
//FLAS
type = SAVE_TYPE_FLASH;
} else if (fst == 0x4D415253) {
//SRAM
type = SAVE_TYPE_SRAM;
} else if (fst == 0x52504545 && saveTag[6] == '_') {
//EEPR
type = SAVE_TYPE_EEPROM;
}
if (type != SAVE_TYPE_NONE) {
for (int i = 0; i < SAVE_TYPE_COUNT; i++) {
if (strncmp(saveTag, sSaveTypes[i].tag, sSaveTypes[i].tagLength) != 0)
continue;
return &sSaveTypes[i];
}
}
curAddr += 4;
}
return NULL;
}
void twoByteCpy(u16 *dst, const u16 *src, u32 size){
size >>= 1;
while(size--){
*dst = *src;
dst++;
src++;
}
}

View File

@ -0,0 +1,63 @@
#pragma once
// #ifdef __cplusplus
// extern "C" {
// #endif
enum SaveType
{
SAVE_TYPE_NONE = 0,
SAVE_TYPE_EEPROM = (1 << 14),
SAVE_TYPE_EEPROM_V111,
SAVE_TYPE_EEPROM_V120,
SAVE_TYPE_EEPROM_V121,
SAVE_TYPE_EEPROM_V122,
SAVE_TYPE_EEPROM_V124,
SAVE_TYPE_EEPROM_V125,
SAVE_TYPE_EEPROM_V126,
SAVE_TYPE_FLASH = (2 << 14),
SAVE_TYPE_FLASH512 = SAVE_TYPE_FLASH | (0 << 13),
SAVE_TYPE_FLASH_V120,
SAVE_TYPE_FLASH_V121,
SAVE_TYPE_FLASH_V123,
SAVE_TYPE_FLASH_V124,
SAVE_TYPE_FLASH_V125,
SAVE_TYPE_FLASH_V126,
SAVE_TYPE_FLASH512_V130,
SAVE_TYPE_FLASH512_V131,
SAVE_TYPE_FLASH512_V133,
SAVE_TYPE_FLASH1M = SAVE_TYPE_FLASH | (1 << 13),
SAVE_TYPE_FLASH1M_V102,
SAVE_TYPE_FLASH1M_V103,
SAVE_TYPE_SRAM = (3 << 14),
SAVE_TYPE_SRAM_F_V100,
SAVE_TYPE_SRAM_F_V102,
SAVE_TYPE_SRAM_F_V103,
SAVE_TYPE_SRAM_V110,
SAVE_TYPE_SRAM_V111,
SAVE_TYPE_SRAM_V112,
SAVE_TYPE_SRAM_V113,
SAVE_TYPE_TYPE_MASK = (3 << 14)
};
struct save_type
{
char tag[16];
u16 tagLength;
u16 type;
u32 size;
bool (* patchFunc)(const struct save_type* type);
};
extern u32 romSize;
const struct save_type* save_findTag();
void twoByteCpy(u16 *dst, const u16 *src, u32 size);
// #ifdef __cplusplus
// }
// #endif

View File

@ -0,0 +1,487 @@
#include "gba.h"
#include "Save.h"
extern u32 romSize;
extern bool savingAllowed;
u32 prefetchPatch[8] = {
0xE59F000C, // LDR R0, =0x4000204
0xE59F100C, // LDR R1, =0x4000
0xE4A01000, // STRT R1, [R0]
0xE59F0008, // LDR R0, =0x80000C0 (this changes, depending on the ROM)
0xE1A0F000, // MOV PC, R0
0x04000204,
0x00004000,
0x080000C0
};
static const u8 sDbzLoGUPatch1[0x24] =
{0x0A, 0x1C, 0x40, 0x0B, 0xE0, 0x21, 0x09, 0x05, 0x41, 0x18, 0x07, 0x31, 0x00, 0x23, 0x08, 0x78,
0x10, 0x70, 0x01, 0x33, 0x01, 0x32, 0x01, 0x39, 0x07, 0x2B, 0xF8, 0xD9, 0x00, 0x20, 0x70, 0xBC,
0x02, 0xBC, 0x08, 0x47
};
static const u8 sDbzLoGUPatch2[0x28] =
{0x70, 0xB5, 0x00, 0x04, 0x0A, 0x1C, 0x40, 0x0B, 0xE0, 0x21, 0x09, 0x05, 0x41, 0x18, 0x07, 0x31,
0x00, 0x23, 0x10, 0x78, 0x08, 0x70, 0x01, 0x33, 0x01, 0x32, 0x01, 0x39, 0x07, 0x2B, 0xF8, 0xD9,
0x00, 0x20, 0x70, 0xBC, 0x02, 0xBC, 0x08, 0x47
};
static const u8 wwTwistedPatch[0xF0] =
{
0x1F, 0x24, 0x1F, 0xB4, 0x33, 0x48, 0x01, 0x21, 0x01, 0x60, 0x33, 0x48, 0x01, 0x21, 0x01, 0x60,
0x32, 0x49, 0x0A, 0x68, 0x10, 0x23, 0x1A, 0x40, 0x1E, 0xD1, 0x30, 0x49, 0x0A, 0x68, 0x02, 0x23,
0x1A, 0x40, 0x0D, 0xD0, 0x2E, 0x48, 0x01, 0x68, 0x01, 0x22, 0x91, 0x42, 0x02, 0xDB, 0x09, 0x19,
0x01, 0x60, 0x38, 0xE0, 0x2A, 0x48, 0x01, 0x22, 0x02, 0x60, 0x12, 0x19, 0x02, 0x60, 0x32, 0xE0,
0x27, 0x48, 0x01, 0x68, 0x01, 0x22, 0x91, 0x42, 0x00, 0xDB, 0x01, 0xE0, 0x02, 0x60, 0x11, 0x1C,
0x24, 0x4B, 0xC9, 0x18, 0x01, 0x60, 0x26, 0xE0, 0x20, 0x49, 0x0A, 0x68, 0x20, 0x23, 0x1A, 0x40,
0x1E, 0xD1, 0x1E, 0x49, 0x0A, 0x68, 0x02, 0x23, 0x1A, 0x40, 0x0D, 0xD0, 0x1C, 0x48, 0x01, 0x68,
0x1D, 0x4A, 0x91, 0x42, 0x02, 0xDC, 0x09, 0x1B, 0x01, 0x60, 0x14, 0xE0, 0x18, 0x48, 0x1A, 0x4A,
0x02, 0x60, 0x12, 0x1B, 0x02, 0x60, 0x0E, 0xE0, 0x15, 0x48, 0x01, 0x68, 0x16, 0x4A, 0x91, 0x42,
0x00, 0xDC, 0x01, 0xE0, 0x02, 0x60, 0x11, 0x1C, 0x12, 0x4B, 0xC9, 0x1A, 0x01, 0x60, 0x02, 0xE0,
0x0F, 0x48, 0x01, 0x21, 0x01, 0x60, 0x1F, 0xBC, 0x0C, 0x48, 0x00, 0x88, 0x0F, 0x4A, 0x10, 0x47,
0x00, 0x7F, 0x00, 0x03, 0xA0, 0x7F, 0x00, 0x03, 0x30, 0x01, 0x00, 0x04, 0x4B, 0x13, 0x00, 0x08,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x00, 0x03, 0x98, 0x0F, 0x00, 0x03, 0x30, 0x01, 0x00, 0x04,
0x30, 0x10, 0x00, 0x03, 0x20, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x4B, 0x13, 0x00, 0x08
};
static const u8 yoshiTopsyTurvyPatch[0x18C] =
{
0x0C, 0x20, 0x9F, 0xE5, 0x80, 0x30, 0xA0, 0xE3, 0x00, 0x30, 0xE2, 0xE4, 0x04, 0x30, 0x9F, 0xE5,
0x13, 0xFF, 0x2F, 0xE1, 0xE0, 0x7F, 0x00, 0x03, 0x69, 0x51, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
0xFF, 0xB5, 0x01, 0x4F, 0x00, 0x00, 0x09, 0xE0, 0xE0, 0x7F, 0x00, 0x03, 0x02, 0x49, 0x09, 0x88,
0x01, 0x23, 0x08, 0x40, 0x70, 0x47, 0x00, 0x00, 0x30, 0x01, 0x00, 0x04, 0x3D, 0x78, 0x7F, 0x1C,
0x80, 0x26, 0x35, 0x42, 0x24, 0xD0, 0x33, 0x48, 0x00, 0x21, 0x00, 0x88, 0x88, 0x42, 0x04, 0xD1,
0x31, 0x49, 0x20, 0x20, 0x00, 0x02, 0x02, 0x30, 0x08, 0x80, 0x30, 0x48, 0x03, 0x21, 0x00, 0x88,
0x88, 0x42, 0x04, 0xD1, 0x2E, 0x49, 0x20, 0x20, 0x00, 0x02, 0x02, 0x30, 0x08, 0x80, 0x02, 0x20,
0x00, 0x02, 0x00, 0x30, 0xFF, 0xF7, 0xDA, 0xFF, 0x02, 0xD1, 0x2A, 0x49, 0x00, 0x20, 0x08, 0x80,
0x01, 0x20, 0xFF, 0x30, 0xFF, 0xF7, 0xD2, 0xFF, 0x02, 0xD1, 0x27, 0x49, 0x03, 0x20, 0x08, 0x80,
0x76, 0x08, 0x35, 0x42, 0x02, 0xD0, 0x25, 0x49, 0x63, 0x20, 0x08, 0x70, 0x76, 0x08, 0x35, 0x42,
0x04, 0xD0, 0x23, 0x49, 0x27, 0x20, 0x00, 0x02, 0x0F, 0x30, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42,
0x02, 0xD0, 0x20, 0x49, 0x03, 0x20, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42, 0x22, 0xD0, 0x1E, 0x49,
0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x1C, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30,
0x08, 0x80, 0x1B, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x19, 0x49, 0xAA, 0x20,
0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x18, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80,
0x16, 0x49, 0xAA, 0x20, 0x00, 0x02, 0xAA, 0x30, 0x08, 0x80, 0x15, 0x49, 0xAA, 0x20, 0x00, 0x02,
0xAA, 0x30, 0x08, 0x80, 0x76, 0x08, 0x35, 0x42, 0x02, 0xD0, 0x12, 0x49, 0x0A, 0x20, 0x08, 0x80,
0x00, 0x00, 0x21, 0xE0, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03,
0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xE0, 0x1D, 0x00, 0x03, 0xD8, 0x03, 0x00, 0x03,
0xF8, 0x03, 0x00, 0x03, 0x00, 0x05, 0x00, 0x03, 0xDA, 0x03, 0x00, 0x03, 0xDC, 0x03, 0x00, 0x03,
0xDE, 0x03, 0x00, 0x03, 0xE0, 0x03, 0x00, 0x03, 0xE2, 0x03, 0x00, 0x03, 0xE4, 0x03, 0x00, 0x03,
0xE6, 0x03, 0x00, 0x03, 0x48, 0x29, 0x00, 0x02, 0xFF, 0xBD, 0x00, 0x00, 0x00, 0xB5, 0x03, 0x48,
0xFE, 0x46, 0x00, 0x47, 0x01, 0xBC, 0x86, 0x46, 0x01, 0xBC, 0x01, 0xE0, 0x01, 0x9C, 0x7B, 0x08,
0x02, 0x48, 0x00, 0x88, 0xC0, 0x43, 0x80, 0x05, 0x81, 0x0D, 0x01, 0xE0, 0x30, 0x01, 0x00, 0x04,
0x03, 0xB4, 0x01, 0x48, 0x01, 0x90, 0x01, 0xBD, 0x18, 0x1A, 0x00, 0x08
};
void patchGeneralWhiteScreen()
{
u32 entryPoint = *(u32*)0x08000000;
entryPoint -= 0xEA000000;
entryPoint += 2;
prefetchPatch[7] = 0x08000000+(entryPoint*4);
u32 patchOffset = 0x01FFFFDC;
{
vu32 *patchAddr = (vu32*)(0x08000000+patchOffset);
for(int i=0;i<8;i++){
patchAddr[i] = prefetchPatch[i];
}
}
u32 branchCode = 0xEA000000+(patchOffset/sizeof(u32))-2;
*(vu32*)0x08000000 = branchCode;
u32 searchRange = 0x08000000+romSize;
if (romSize > 0x01FFFFDC) searchRange = 0x09FFFFDC;
// General fix for white screen crash
// Patch out wait states
for (u32 addr = 0x080000C0; addr < searchRange; addr+=4) {
if (*(u32*)addr == 0x04000204 &&
(*(u8*)(addr-1) == 0x00 || *(u8*)(addr-1) == 0x03 || *(u8*)(addr-1) == 0x04 || *(u8*)(addr+7) == 0x04
|| *(u8*)(addr-1) == 0x08 || *(u8*)(addr-1) == 0x09
|| *(u8*)(addr-1) == 0x47 || *(u8*)(addr-1) == 0x81 || *(u8*)(addr-1) == 0x85
|| *(u8*)(addr-1) == 0xE0 || *(u8*)(addr-1) == 0xE7 || *(u16*)(addr-2) == 0xFFFE))
{
*(vu32*)addr = 0;
}
}
// Also check at 0x410
if (*(u32*)0x08000410 == 0x04000204) {
*(vu32*)0x08000410 = 0;
}
}
void patchSpecificGame(){
u32 nop = 0xE1A00000;
u32 gameCode = *(u32*)(0x080000AC);
if (gameCode == 0x50584C42) {
//Astreix & Obelix XXL (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x50118) == 0x4014)
*(u16*)(0x08000000 + 0x50118) = 0x4000;
} else if (gameCode == 0x454D4441) {
//Doom (USA)
//Fix black screen crash
if (*(u16*)(0x08000000 + 0x51C) == 0x45B6)
*(u16*)(0x08000000 + 0x51C) = 0x4002;
} else if (gameCode == 0x45443941 || gameCode == 0x50443941) {
//Doom II (USA/Europe)
//Fix black screen crash
if (*(u16*)(0x08000000 + 0x2856) == 0x5281)
*(u16*)(0x08000000 + 0x2856) = 0x46C0;
} else if (gameCode == 0x45474C41) {
//Dragon Ball Z - The Legacy of Goku (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x96E8) == 0x80A8)
*(u16*)(0x08000000 + 0x96E8) = 0x46C0;
//Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x356) == 0x7002)
*(u16*)(0x08000000 + 0x356) = 0;
if (*(u16*)(0x08000000 + 0x35E) == 0x7043)
*(u16*)(0x08000000 + 0x35E) = 0;
if (*(u16*)(0x08000000 + 0x37E) == 0x7001)
*(u16*)(0x08000000 + 0x37E) = 0;
if (*(u16*)(0x08000000 + 0x382) == 0x7041)
*(u16*)(0x08000000 + 0x382) = 0;
if (*(u16*)(0x08000000 + 0xE27E) == 0xB0A2) {
*(u16*)(0x08000000 + 0xE27E) = 0x400;
for (int i = 0; i < (int)sizeof(sDbzLoGUPatch1); i += 2)
*(u16*)(0x08000000 + 0xE280 + i) = *(u16*)&sDbzLoGUPatch1[i];
for (int i = 0; i < (int)sizeof(sDbzLoGUPatch2); i += 2)
*(u16*)(0x08000000 + 0xE32C + i) = *(u16*)&sDbzLoGUPatch2[i];
}
} else if (gameCode == 0x50474C41) {
//Dragon Ball Z - The Legacy of Goku (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x9948) == 0x80B0)
*(u16*)(0x08000000 + 0x9948) = 0x46C0;
//Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x33C) == 0x7119)
*(u16*)(0x08000000 + 0x33C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x340) == 0x7159)
*(u16*)(0x08000000 + 0x340) = 0x46C0;
if (*(u16*)(0x08000000 + 0x356) == 0x705A)
*(u16*)(0x08000000 + 0x356) = 0x46C0;
if (*(u16*)(0x08000000 + 0x35A) == 0x7002)
*(u16*)(0x08000000 + 0x35A) = 0x46C0;
if (*(u16*)(0x08000000 + 0x35E) == 0x7042)
*(u16*)(0x08000000 + 0x35E) = 0x46C0;
if (*(u16*)(0x08000000 + 0x384) == 0x7001)
*(u16*)(0x08000000 + 0x384) = 0x46C0;
if (*(u16*)(0x08000000 + 0x388) == 0x7041)
*(u16*)(0x08000000 + 0x388) = 0x46C0;
if (*(u16*)(0x08000000 + 0x494C) == 0x7002)
*(u16*)(0x08000000 + 0x494C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x4950) == 0x7042)
*(u16*)(0x08000000 + 0x4950) = 0x46C0;
if (*(u16*)(0x08000000 + 0x4978) == 0x7001)
*(u16*)(0x08000000 + 0x4978) = 0x46C0;
if (*(u16*)(0x08000000 + 0x497C) == 0x7041)
*(u16*)(0x08000000 + 0x497C) = 0x46C0;
if (*(u16*)(0x08000000 + 0x988E) == 0x7028)
*(u16*)(0x08000000 + 0x988E) = 0x46C0;
if (*(u16*)(0x08000000 + 0x9992) == 0x7068)
*(u16*)(0x08000000 + 0x9992) = 0x46C0;
} else if (gameCode == 0x45464C41) {
//Dragon Ball Z - The Legacy of Goku II (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x3B8E9E) == 0x1102)
*(u16*)(0x08000000 + 0x3B8E9E) = 0x1001;
if (*(u16*)(0x08000000 + 0x3B8EAE) == 0x0003)
*(u16*)(0x08000000 + 0x3B8EAE) = 0;
} else if (gameCode == 0x4A464C41) {
//Dragon Ball Z - The Legacy of Goku II International (Japan)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x3FC8F6) == 0x1102)
*(u16*)(0x08000000 + 0x3FC8F6) = 0x1001;
if (*(u16*)(0x08000000 + 0x3FC906) == 0x0003)
*(u16*)(0x08000000 + 0x3FC906) = 0;
} else if (gameCode == 0x50464C41) {
//Dragon Ball Z - The Legacy of Goku II (Europe)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0x6F42B2) == 0x1102)
*(u16*)(0x08000000 + 0x6F42B2) = 0x1001;
if (*(u16*)(0x08000000 + 0x6F42C2) == 0x0003)
*(u16*)(0x08000000 + 0x6F42C2) = 0;
} else if (gameCode == 0x45464C42) {
//2 Games in 1 - Dragon Ball Z - The Legacy of Goku I & II (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
if (*(u16*)(0x08000000 + 0x49840) == 0x80A8)
*(u16*)(0x08000000 + 0x49840) = 0x46C0;
// tonccpy((u16*)0x088000E0, &nop, sizeof(u32));
*((u32*)0x080000E0) = nop;
//LoG1: Fix "game cannot be played on hardware found" error
if (*(u16*)(0x08000000 + 0x40356) == 0x7002)
*(u16*)(0x08000000 + 0x40356) = 0;
if (*(u16*)(0x08000000 + 0x4035E) == 0x7043)
*(u16*)(0x08000000 + 0x4035E) = 0;
if (*(u16*)(0x08000000 + 0x4037E) == 0x7001)
*(u16*)(0x08000000 + 0x4037E) = 0;
if (*(u16*)(0x08000000 + 0x40382) == 0x7041)
*(u16*)(0x08000000 + 0x40382) = 0;
//Do we need this?
/*if (*(u16*)(0x08000000 + 0x4E316) == 0xB0A2) {
*(u16*)(0x08000000 + 0x4E316) = 0x400;
for (int i = 0; i < sizeof(sDbzLoGUPatch1); i += 2)
*(u16*)(0x08000000 + 0x4E318 + i) = *(u16*)&sDbzLoGUPatch1[i];
for (int i = 0; i < sizeof(sDbzLoGUPatch2); i += 2)
*(u16*)(0x08000000 + 0x????? + i) = *(u16*)&sDbzLoGUPatch2[i];
}*/
//LoG2: Fix "game will not run on the hardware found" error
if (*(u16*)(0x08000000 + 0xBB9016) == 0x1102)
*(u16*)(0x08000000 + 0xBB9016) = 0x1001;
if (*(u16*)(0x08000000 + 0xBB9026) == 0x0003)
*(u16*)(0x08000000 + 0xBB9026) = 0;
} else if (gameCode == 0x45424442) {
//Dragon Ball Z - Taiketsu (USA)
//Fix "game cannot be played on this hardware" error
if (*(u16*)(0x08000000 + 0x2BD54) == 0x7818)
*(u16*)(0x08000000 + 0x2BD54) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BD60) == 0x7810)
*(u16*)(0x08000000 + 0x2BD60) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BD80) == 0x703A)
*(u16*)(0x08000000 + 0x2BD80) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BD82) == 0x7839)
*(u16*)(0x08000000 + 0x2BD82) = 0x2100;
if (*(u16*)(0x08000000 + 0x2BD8C) == 0x7030)
*(u16*)(0x08000000 + 0x2BD8C) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BD8E) == 0x7830)
*(u16*)(0x08000000 + 0x2BD8E) = 0x2000;
if (*(u16*)(0x08000000 + 0x2BDAC) == 0x7008)
*(u16*)(0x08000000 + 0x2BDAC) = 0x1C00;
if (*(u16*)(0x08000000 + 0x2BDB2) == 0x7008)
*(u16*)(0x08000000 + 0x2BDB2) = 0x1C00;
} else if (gameCode == 0x50424442) {
//Dragon Ball Z - Taiketsu (Europe)
//Fix "game cannot be played on this hardware" error
if (*(u16*)(0x08000000 + 0x3FE08) == 0x7818)
*(u16*)(0x08000000 + 0x3FE08) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE14) == 0x7810)
*(u16*)(0x08000000 + 0x3FE14) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE34) == 0x703A)
*(u16*)(0x08000000 + 0x3FE34) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE36) == 0x7839)
*(u16*)(0x08000000 + 0x3FE36) = 0x2100;
if (*(u16*)(0x08000000 + 0x3FE40) == 0x7030)
*(u16*)(0x08000000 + 0x3FE40) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE42) == 0x7830)
*(u16*)(0x08000000 + 0x3FE42) = 0x2000;
if (*(u16*)(0x08000000 + 0x3FE58) == 0x7008)
*(u16*)(0x08000000 + 0x3FE58) = 0x1C00;
if (*(u16*)(0x08000000 + 0x3FE66) == 0x7008)
*(u16*)(0x08000000 + 0x3FE66) = 0x1C00;
} else if (gameCode == 0x45334742) {
//Dragon Ball Z - Buu's Fury (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
//Fix "game will not run on this hardware" error
if (*(u16*)(0x08000000 + 0x8B66) == 0x7032)
*(u16*)(0x08000000 + 0x8B66) = 0;
if (*(u16*)(0x08000000 + 0x8B6A) == 0x7072)
*(u16*)(0x08000000 + 0x8B6A) = 0;
if (*(u16*)(0x08000000 + 0x8B86) == 0x7008)
*(u16*)(0x08000000 + 0x8B86) = 0;
if (*(u16*)(0x08000000 + 0x8B8C) == 0x7031)
*(u16*)(0x08000000 + 0x8B8C) = 0;
if (*(u16*)(0x08000000 + 0x8B90) == 0x7071)
*(u16*)(0x08000000 + 0x8B90) = 0;
} else if (gameCode == 0x45345442) {
//Dragon Ball GT - Transformation (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
} else if (gameCode == 0x45465542) {
//2 Games in 1 - Dragon Ball Z - Buu's Fury & Dragon Ball GT - Transformation (USA)
*((u32*)0x080000E0) = nop;
//tonccpy((u16*)0x080000E0, &nop, sizeof(u32)); // Fix white screen crash
*((u32*)0x080300E0) = nop;
*((u32*)0x088000E0) = nop;
// tonccpy((u16*)0x080300E0, &nop, sizeof(u32));
// tonccpy((u16*)0x088000E0, &nop, sizeof(u32));
//DBZ BF: Fix "game will not run on this hardware" error
if (*(u16*)(0x08000000 + 0x38B66) == 0x7032)
*(u16*)(0x08000000 + 0x38B66) = 0;
if (*(u16*)(0x08000000 + 0x38B6A) == 0x7072)
*(u16*)(0x08000000 + 0x38B6A) = 0;
if (*(u16*)(0x08000000 + 0x38B86) == 0x7008)
*(u16*)(0x08000000 + 0x38B86) = 0;
if (*(u16*)(0x08000000 + 0x38B8C) == 0x7031)
*(u16*)(0x08000000 + 0x38B8C) = 0;
if (*(u16*)(0x08000000 + 0x38B90) == 0x7071)
*(u16*)(0x08000000 + 0x38B90) = 0;
} else if (gameCode == 0x45564442) {
//Dragon Ball - Advanced Adventure (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10C240) == 0x8008)
*(u16*)(0x08000000 + 0x10C240) = 0x46C0;
} else if (gameCode == 0x50564442) {
//Dragon Ball - Advanced Adventure (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10CE3C) == 0x8008)
*(u16*)(0x08000000 + 0x10CE3C) = 0x46C0;
} else if (gameCode == 0x4A564442) {
//Dragon Ball - Advanced Adventure (Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x10B078) == 0x8008)
*(u16*)(0x08000000 + 0x10B078) = 0x46C0;
} else if (gameCode == 0x454B3842) {
//Kirby and the Amazing Mirror (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x1515A4) == 0x8008)
*(u16*)(0x08000000 + 0x1515A4) = 0x46C0;
} else if (gameCode == 0x504B3842) {
//Kirby and the Amazing Mirror (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x151EE0) == 0x8008)
*(u16*)(0x08000000 + 0x151EE0) = 0x46C0;
} else if (gameCode == 0x4A4B3842) {
//Hoshi no Kirby - Kagami no Daimeikyuu (Japan) (V1.1)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x151564) == 0x8008)
*(u16*)(0x08000000 + 0x151564) = 0x46C0;
} else if (gameCode == 0x45533342) {
//Sonic Advance 3 (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBB67C) == 0x8008)
*(u16*)(0x08000000 + 0xBB67C) = 0x46C0;
} else if (gameCode == 0x50533342) {
//Sonic Advance 3 (Europe)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBBA04) == 0x8008)
*(u16*)(0x08000000 + 0xBBA04) = 0x46C0;
} else if (gameCode == 0x4A533342) {
//Sonic Advance 3 (Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xBB9F8) == 0x8008)
*(u16*)(0x08000000 + 0xBB9F8) = 0x46C0;
} else if (gameCode == 0x45593241) {
//Top Gun - Combat Zones (USA)
//Fix softlock when attempting to save (original cartridge does not have a save chip)
if (*(u16*)(0x08000000 + 0x88816) == 0x3501)
*(u16*)(0x08000000 + 0x88816) = 0x3401;
savingAllowed = false;
} else if (gameCode == 0x45415741 || gameCode == 0x4A415741) {
//Wario Land 4/Advance (USA/Europe/Japan)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x726) == 0x8008)
*(u16*)(0x08000000 + 0x726) = 0x46C0;
} else if (gameCode == 0x43415741) {
//Wario Land Advance (iQue)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0xE92) == 0x8008)
*(u16*)(0x08000000 + 0xE92) = 0x46C0;
} else if (gameCode == 0x45575A52) {
//WarioWare: Twisted! (USA)
//Patch out tilt controls
if (*(u16*)(0x08000000 + 0x1348) == 0x8800)
*(u16*)(0x08000000 + 0x1348) = 0x4700;
if (*(u16*)(0x08000000 + 0x1376) == 0x0400 && *(u16*)(0x08000000 + 0x1374) == 0x0130) {
*(u16*)(0x08000000 + 0x1376) = 0x08E9;
*(u16*)(0x08000000 + 0x1374) = 0x3C6D;
// tonccpy((u8*)0x08E93C6C, &wwTwistedPatch, 0xF0);
twoByteCpy((u16*)0x08E93C6C,(const u16*)wwTwistedPatch,0xF0);
}
} else if (gameCode == 0x4547594B) {
//Yoshi Topsy-Turvy (USA)
//Fix white screen crash
if (*(u16*)(0x08000000 + 0x16E4) == 0x8008)
*(u16*)(0x08000000 + 0x16E4) = 0x46C0;
//Patch out tilt controls
if (*(u16*)(0x08000000 + 0x1F2) == 0x0802 && *(u16*)(0x08000000 + 0x1F0) == 0x5169) {
*(u16*)(0x08000000 + 0x1F2) = 0x087B;
*(u16*)(0x08000000 + 0x1F0) = 0x9BE0;
// tonccpy((u8*)0x087B9BE0, &yoshiTopsyTurvyPatch, 0x18C);
twoByteCpy((u16*)0x087B9BE0,(const u16*)yoshiTopsyTurvyPatch,0x18C);
}
if (*(u16*)(0x08000000 + 0x1A0E) == 0x4808)
*(u16*)(0x08000000 + 0x1A0E) = 0xB401;
if (*(u16*)(0x08000000 + 0x1A10) == 0x8800)
*(u16*)(0x08000000 + 0x1A10) = 0x4800;
if (*(u16*)(0x08000000 + 0x1A12) == 0x43C0)
*(u16*)(0x08000000 + 0x1A12) = 0x4700;
if (*(u16*)(0x08000000 + 0x1A14) == 0x0580)
*(u16*)(0x08000000 + 0x1A14) = 0x9D3D;
if (*(u16*)(0x08000000 + 0x1A16) == 0x0D81)
*(u16*)(0x08000000 + 0x1A16) = 0x087B;
}
}

View File

@ -0,0 +1,5 @@
#pragma once
void patchGeneralWhiteScreen();
void patchSpecificGame();

View File

@ -0,0 +1,20 @@
#ifndef FIND_H
#define FIND_H
#include <gba.h>
// #ifdef __cplusplus
// extern "C" {
// #endif
// COMMON
//u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize);
u32* memsearch32(const u32* start, u32 dataSize, const u32* find, u32 findSize, bool forward);
u16* memsearch16(const u16* start, u32 dataSize, const u16* find, u32 findSize, bool forward);
u8* memsearch8(const u8* start, u32 dataSize, const u8* find, u32 findSize, bool forward);
// #ifdef __cplusplus
// }
// #endif
#endif // FIND_H

View File

@ -0,0 +1,130 @@
//#include <string.h> // memcmp
#include <stddef.h> // NULL
#include <gba.h>
//#include <limits.h>
// (memcmp is slower)
//#define memcmp __builtin_memcmp
//#define TABLE_SIZE (UCHAR_MAX + 1) // 256
/*
* Look for @find and return the position of it.
* Brute Force algorithm
*/
u32* memsearch32(const u32* start, u32 dataSize, const u32* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u32);
u32 findLen = findSize/sizeof(u32);
const u32* end = forward ? (start + dataLen) : (start - dataLen);
for (u32* addr = (u32*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u32*)addr;
}
}
return NULL;
}
u16* memsearch16(const u16* start, u32 dataSize, const u16* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u16);
u32 findLen = findSize/sizeof(u16);
const u16* end = forward ? (start + dataLen) : (start - dataLen);
for (u16* addr = (u16*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u16*)addr;
}
}
return NULL;
}
u8* memsearch8(const u8* start, u32 dataSize, const u8* find, u32 findSize, bool forward) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
const u8* end = forward ? (start + dataLen) : (start - dataLen);
for (u8* addr = (u8*)start; addr != end; forward ? ++addr : --addr) {
bool found = true;
for (u32 j = 0; j < findLen; ++j) {
if (addr[j] != find[j]) {
found = false;
break;
}
}
if (found) {
return (u8*)addr;
}
}
return NULL;
}
/*
* Boyer-Moore Horspool algorithm
*/
/*u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
u32 table[TABLE_SIZE];
// Preprocessing
for (u32 i = 0; i < TABLE_SIZE; ++i) {
table[i] = findLen;
}
for (u32 i = 0; i < findLen - 1; ++i) {
table[find[i]] = findLen - i - 1;
}
// Searching
u32 j = 0;
while (j <= dataLen - findLen) {
u8 c = start[j + findLen - 1];
if (find[findLen - 1] == c && memcmp(find, start + j, findLen - 1) == 0) {
return (u8*)start + j;
}
j += table[c];
}
return NULL;
}*/
/*
* Quick Search algorithm
*/
/*u8* memsearch(const u8* start, u32 dataSize, const u8* find, u32 findSize) {
u32 dataLen = dataSize/sizeof(u8);
u32 findLen = findSize/sizeof(u8);
u32 table[TABLE_SIZE];
// Preprocessing
for (u32 i = 0; i < TABLE_SIZE; ++i) {
table[i] = findLen + 1;
}
for (u32 i = 0; i < findLen; ++i) {
table[find[i]] = findLen - i;
}
// Searching
u32 j = 0;
while (j <= dataLen - findLen) {
if (memcmp(find, start + j, findLen) == 0) {
return (u8*)start + j;
}
j += table[start[j + findLen]];
}
return NULL;
}*/

View File

@ -7,6 +7,9 @@
#include <limits.h>
#include <dirent.h>
#include "Save.h"
#include "WhiteScreenPatch.h"
char *stpcpy(char*, char*);
void tryAgain() {
@ -76,6 +79,7 @@ void sc_mode(u32 mode)
EWRAM_DATA u8 filebuf[0x4000];
u32 pressed;
bool savingAllowed;
void setLastPlayed(char *path) {
/*
@ -146,6 +150,22 @@ void selectFile(char *path) {
fclose(lastSaved);
}
iprintf("Applying patches...\n");
sc_mode(SC_RAM_RW);
patchGeneralWhiteScreen();
patchSpecificGame();
printf("White Screen patch done!\nNow patching Save\n");
const struct save_type* saveType = savingAllowed ? save_findTag() : NULL;
if (saveType != NULL && saveType->patchFunc != NULL){
bool done = saveType->patchFunc(saveType);
if(!done)
printf("Save Type Patch Error\n");
}else{
printf("No need to patch\n");
}
iprintf("Let's go.\n");
setLastPlayed(path);