mirror of
https://github.com/ARMSX2/ARMSX2.git
synced 2026-08-24 16:50:16 -07:00
Allows users to use the leshort, leword, and ledouble datatypes inside their patches. Using these datatypes ensures that values in the memory view appear the same as the values in the patch. This was made with easing patch development in mind as now developers can make patches without having to reverse endianness. This is especially useful when using programs like ghidra who display an instructions bytes in little endian.
488 lines
12 KiB
C++
488 lines
12 KiB
C++
/* PCSX2 - PS2 Emulator for PCs
|
|
* Copyright (C) 2002-2010 PCSX2 Dev Team
|
|
*
|
|
* PCSX2 is free software: you can redistribute it and/or modify it under the terms
|
|
* of the GNU Lesser General Public License as published by the Free Software Found-
|
|
* ation, either version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* PCSX2 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
|
|
* without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
|
|
* PURPOSE. See the GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License along with PCSX2.
|
|
* If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "PrecompiledHeader.h"
|
|
|
|
#define _PC_ // disables MIPS opcode macros.
|
|
|
|
#include "IopCommon.h"
|
|
#include "Patch.h"
|
|
|
|
u32 SkipCount = 0, IterationCount = 0;
|
|
u32 IterationIncrement = 0, ValueIncrement = 0;
|
|
u32 PrevCheatType = 0, PrevCheatAddr = 0, LastType = 0;
|
|
|
|
void writeCheat()
|
|
{
|
|
switch (LastType)
|
|
{
|
|
case 0x0:
|
|
memWrite8(PrevCheatAddr, IterationIncrement & 0xFF);
|
|
break;
|
|
case 0x1:
|
|
memWrite16(PrevCheatAddr, IterationIncrement & 0xFFFF);
|
|
break;
|
|
case 0x2:
|
|
memWrite32(PrevCheatAddr, IterationIncrement);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
void handle_extended_t(IniPatch *p)
|
|
{
|
|
if (SkipCount > 0)
|
|
{
|
|
SkipCount--;
|
|
}
|
|
else switch (PrevCheatType)
|
|
{
|
|
case 0x3040: // vvvvvvvv 00000000 Inc
|
|
{
|
|
u32 mem = memRead32(PrevCheatAddr);
|
|
memWrite32(PrevCheatAddr, mem + (p->addr));
|
|
PrevCheatType = 0;
|
|
break;
|
|
}
|
|
|
|
case 0x3050: // vvvvvvvv 00000000 Dec
|
|
{
|
|
u32 mem = memRead32(PrevCheatAddr);
|
|
memWrite32(PrevCheatAddr, mem - (p->addr));
|
|
PrevCheatType = 0;
|
|
break;
|
|
}
|
|
|
|
case 0x4000: // vvvvvvvv iiiiiiii
|
|
for (u32 i = 0; i < IterationCount; i++)
|
|
{
|
|
memWrite32((u32)(PrevCheatAddr + (i * IterationIncrement)), (u32)(p->addr + ((u32)p->data * i)));
|
|
}
|
|
PrevCheatType = 0;
|
|
break;
|
|
|
|
case 0x5000: // bbbbbbbb 00000000
|
|
for (u32 i = 0; i < IterationCount; i++)
|
|
{
|
|
u8 mem = memRead8(PrevCheatAddr + i);
|
|
memWrite8((p->addr + i) & 0x0FFFFFFF, mem);
|
|
}
|
|
PrevCheatType = 0;
|
|
break;
|
|
|
|
case 0x6000: // 000Xnnnn iiiiiiii
|
|
{
|
|
// Get Number of pointers
|
|
if (((u32)p->addr & 0x0000FFFF) == 0)
|
|
IterationCount = 1;
|
|
else
|
|
IterationCount = (u32)p->addr & 0x0000FFFF;
|
|
|
|
// Read first pointer
|
|
LastType = ((u32)p->addr & 0x000F0000) >> 16;
|
|
u32 mem = memRead32(PrevCheatAddr);
|
|
|
|
PrevCheatAddr = mem + (u32)p->data;
|
|
IterationCount--;
|
|
|
|
// Check if needed to read another pointer
|
|
if (IterationCount == 0)
|
|
{
|
|
PrevCheatType = 0;
|
|
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
}
|
|
else
|
|
{
|
|
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) == 0)
|
|
PrevCheatType = 0;
|
|
else
|
|
PrevCheatType = 0x6001;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case 0x6001: // 000Xnnnn iiiiiiii
|
|
{
|
|
// Read first pointer
|
|
u32 mem = memRead32(PrevCheatAddr & 0x0FFFFFFF);
|
|
|
|
PrevCheatAddr = mem + (u32)p->addr;
|
|
IterationCount--;
|
|
|
|
// Check if needed to read another pointer
|
|
if (IterationCount == 0)
|
|
{
|
|
PrevCheatType = 0;
|
|
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
}
|
|
else
|
|
{
|
|
mem = memRead32(PrevCheatAddr);
|
|
|
|
PrevCheatAddr = mem + (u32)p->data;
|
|
IterationCount--;
|
|
if (IterationCount == 0)
|
|
{
|
|
PrevCheatType = 0;
|
|
if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) != 0) writeCheat();
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
default:
|
|
if ((p->addr & 0xF0000000) == 0x00000000) // 0aaaaaaa 0000000vv
|
|
{
|
|
memWrite8(p->addr & 0x0FFFFFFF, (u8)p->data & 0x000000FF);
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x10000000) // 1aaaaaaa 0000vvvv
|
|
{
|
|
memWrite16(p->addr & 0x0FFFFFFF, (u16)p->data & 0x0000FFFF);
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x20000000) // 2aaaaaaa vvvvvvvv
|
|
{
|
|
memWrite32(p->addr & 0x0FFFFFFF, (u32)p->data);
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30000000) // 300000vv 0aaaaaaa Inc
|
|
{
|
|
u8 mem = memRead8((u32)p->data);
|
|
memWrite8((u32)p->data, mem + (p->addr & 0x000000FF));
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30100000) // 301000vv 0aaaaaaa Dec
|
|
{
|
|
u8 mem = memRead8((u32)p->data);
|
|
memWrite8((u32)p->data, mem - (p->addr & 0x000000FF));
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30200000) // 3020vvvv 0aaaaaaa Inc
|
|
{
|
|
u16 mem = memRead16((u32)p->data);
|
|
memWrite16((u32)p->data, mem + (p->addr & 0x0000FFFF));
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30300000) // 3030vvvv 0aaaaaaa Dec
|
|
{
|
|
u16 mem = memRead16((u32)p->data);
|
|
memWrite16((u32)p->data, mem - (p->addr & 0x0000FFFF));
|
|
PrevCheatType = 0;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30400000) // 30400000 0aaaaaaa Inc + Another line
|
|
{
|
|
PrevCheatType = 0x3040;
|
|
PrevCheatAddr = (u32)p->data;
|
|
}
|
|
else if ((p->addr & 0xFFFF0000) == 0x30500000) // 30500000 0aaaaaaa Inc + Another line
|
|
{
|
|
PrevCheatType = 0x3050;
|
|
PrevCheatAddr = (u32)p->data;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x40000000) // 4aaaaaaa nnnnssss + Another line
|
|
{
|
|
IterationCount = ((u32)p->data & 0xFFFF0000) / 0x10000;
|
|
IterationIncrement = ((u32)p->data & 0x0000FFFF) * 4;
|
|
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
PrevCheatType = 0x4000;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x50000000) // 5sssssss nnnnnnnn + Another line
|
|
{
|
|
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
IterationCount = ((u32)p->data);
|
|
PrevCheatType = 0x5000;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x60000000) // 6aaaaaaa 000000vv + Another line/s
|
|
{
|
|
PrevCheatAddr = (u32)p->addr & 0x0FFFFFFF;
|
|
IterationIncrement = ((u32)p->data);
|
|
IterationCount = 0;
|
|
PrevCheatType = 0x6000;
|
|
}
|
|
else if ((p->addr & 0xF0000000) == 0x70000000)
|
|
{
|
|
if ((p->data & 0x00F00000) == 0x00000000) // 7aaaaaaa 000000vv
|
|
{
|
|
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem | (p->data & 0x000000FF)));
|
|
}
|
|
else if ((p->data & 0x00F00000) == 0x00100000) // 7aaaaaaa 0010vvvv
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem | (p->data & 0x0000FFFF)));
|
|
}
|
|
else if ((p->data & 0x00F00000) == 0x00200000) // 7aaaaaaa 002000vv
|
|
{
|
|
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem & (p->data & 0x000000FF)));
|
|
}
|
|
else if ((p->data & 0x00F00000) == 0x00300000) // 7aaaaaaa 0030vvvv
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem & (p->data & 0x0000FFFF)));
|
|
}
|
|
else if ((p->data & 0x00F00000) == 0x00400000) // 7aaaaaaa 004000vv
|
|
{
|
|
u8 mem = memRead8((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite8((u32)p->addr & 0x0FFFFFFF, (u8)(mem ^ (p->data & 0x000000FF)));
|
|
}
|
|
else if ((p->data & 0x00F00000) == 0x00500000) // 7aaaaaaa 0050vvvv
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
memWrite16((u32)p->addr & 0x0FFFFFFF, (u16)(mem ^ (p->data & 0x0000FFFF)));
|
|
}
|
|
}
|
|
else if (p->addr < 0xE0000000)
|
|
{
|
|
if (((u32)p->data & 0xFFFF0000) == 0x00000000) // Daaaaaaa 0000dddd
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
if (mem != (0x0000FFFF & (u32)p->data))
|
|
{
|
|
SkipCount = 1;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (((u32)p->data & 0xFFFF0000) == 0x00100000) // Daaaaaaa 0010dddd
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
if (mem == (0x0000FFFF & (u32)p->data))
|
|
{
|
|
SkipCount = 1;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (((u32)p->data & 0xFFFF0000) == 0x00200000) // Daaaaaaa 0020dddd
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
if (mem >= (0x0000FFFF & (u32)p->data))
|
|
{
|
|
SkipCount = 1;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (((u32)p->data & 0xFFFF0000) == 0x00300000) // Daaaaaaa 0030dddd
|
|
{
|
|
u16 mem = memRead16((u32)p->addr & 0x0FFFFFFF);
|
|
if (mem <= (0x0000FFFF & (u32)p->data))
|
|
{
|
|
SkipCount = 1;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
}
|
|
else if (p->addr < 0xF0000000)
|
|
{
|
|
if (((u32)p->data & 0xF0000000) == 0x00000000) // Ezyyvvvv 0aaaaaaa
|
|
{
|
|
u8 z = ((u32)p->addr & 0x0F000000) / 0x01000000;
|
|
|
|
if (z == 0) // E0yyvvvv 0aaaaaaa
|
|
{
|
|
u16 mem = memRead16((u32)p->data & 0x0FFFFFFF);
|
|
if (mem != (0x0000FFFF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (z == 1) // E1yy00vv 0aaaaaaa
|
|
{
|
|
u8 mem = memRead8((u32)p->data & 0x0FFFFFFF);
|
|
if (mem != (0x000000FF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
}
|
|
else if (((u32)p->data & 0xF0000000) == 0x10000000) // Ezyyvvvv 1aaaaaaa
|
|
{
|
|
u8 z = ((u32)p->addr & 0x0F000000) / 0x01000000;
|
|
|
|
if (z == 0) // E0yyvvvv 1aaaaaaa
|
|
{
|
|
u16 mem = memRead16((u32)p->data & 0x0FFFFFFF);
|
|
if (mem == (0x0000FFFF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (z == 1) // E1yy00vv 1aaaaaaa
|
|
{
|
|
u8 mem = memRead8((u32)p->data & 0x0FFFFFFF);
|
|
if (mem == (0x000000FF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
}
|
|
else if (((u32)p->data & 0xF0000000) == 0x20000000) // Ezyyvvvv 2aaaaaaa
|
|
{
|
|
u8 z = ((u32)p->addr & 0x0F000000) / 0x01000000;
|
|
|
|
if (z == 0) // E0yyvvvv 2aaaaaaa
|
|
{
|
|
u16 mem = memRead16((u32)p->data & 0x0FFFFFFF);
|
|
if (mem >= (0x0000FFFF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (z == 1) // E1yy00vv 2aaaaaaa
|
|
{
|
|
u8 mem = memRead8((u32)p->data & 0x0FFFFFFF);
|
|
if (mem >= (0x000000FF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
}
|
|
else if (((u32)p->data & 0xF0000000) == 0x30000000) // Ezyyvvvv 3aaaaaaa
|
|
{
|
|
u8 z = ((u32)p->addr & 0x0F000000) / 0x01000000;
|
|
|
|
if (z == 0) // E0yyvvvv 3aaaaaaa
|
|
{
|
|
u16 mem = memRead16((u32)p->data & 0x0FFFFFFF);
|
|
if (mem <= (0x0000FFFF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
else if (z == 1) // E1yy00vv 3aaaaaaa
|
|
{
|
|
u8 mem = memRead8((u32)p->data & 0x0FFFFFFF);
|
|
if (mem <= (0x000000FF & (u32)p->addr))
|
|
{
|
|
SkipCount = ((u32)p->addr & 0x00FF0000) / 0x10000;
|
|
}
|
|
PrevCheatType = 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Only used from Patch.cpp and we don't export this in any h file.
|
|
// Patch.cpp itself declares this prototype, so make sure to keep in sync.
|
|
void _ApplyPatch(IniPatch *p)
|
|
{
|
|
u64 mem = 0;
|
|
u64 ledata = 0;
|
|
|
|
if (p->enabled == 0) return;
|
|
|
|
switch (p->cpu)
|
|
{
|
|
case CPU_EE:
|
|
switch (p->type)
|
|
{
|
|
case BYTE_T:
|
|
if (memRead8(p->addr) != (u8)p->data)
|
|
memWrite8(p->addr, (u8)p->data);
|
|
break;
|
|
|
|
case SHORT_T:
|
|
if (memRead16(p->addr) != (u16)p->data)
|
|
memWrite16(p->addr, (u16)p->data);
|
|
break;
|
|
|
|
case WORD_T:
|
|
if (memRead32(p->addr) != (u32)p->data)
|
|
memWrite32(p->addr, (u32)p->data);
|
|
break;
|
|
|
|
case DOUBLE_T:
|
|
memRead64(p->addr, &mem);
|
|
if (mem != p->data)
|
|
memWrite64(p->addr, &p->data);
|
|
break;
|
|
|
|
case EXTENDED_T:
|
|
handle_extended_t(p);
|
|
break;
|
|
|
|
case SHORT_LE_T:
|
|
ledata = SwapEndian(p->data, 16);
|
|
if (memRead16(p->addr) != (u16)ledata)
|
|
memWrite16(p->addr, (u16)ledata);
|
|
break;
|
|
|
|
case WORD_LE_T:
|
|
ledata = SwapEndian(p->data, 32);
|
|
if (memRead32(p->addr) != (u32)ledata)
|
|
memWrite32(p->addr, (u32)ledata);
|
|
break;
|
|
|
|
case DOUBLE_LE_T:
|
|
ledata = SwapEndian(p->data, 64);
|
|
memRead64(p->addr, &mem);
|
|
if (mem != ledata)
|
|
memWrite64(p->addr, ledata);
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case CPU_IOP:
|
|
switch (p->type)
|
|
{
|
|
case BYTE_T:
|
|
if (iopMemRead8(p->addr) != (u8)p->data)
|
|
iopMemWrite8(p->addr, (u8)p->data);
|
|
break;
|
|
case SHORT_T:
|
|
if (iopMemRead16(p->addr) != (u16)p->data)
|
|
iopMemWrite16(p->addr, (u16)p->data);
|
|
break;
|
|
case WORD_T:
|
|
if (iopMemRead32(p->addr) != (u32)p->data)
|
|
iopMemWrite32(p->addr, (u32)p->data);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
u64 SwapEndian(u64 InputNum, u8 BitLength)
|
|
{
|
|
if (BitLength == 64) // DOUBLE_LE_T
|
|
{
|
|
InputNum = (InputNum & 0x00000000FFFFFFFF) << 32 | (InputNum & 0xFFFFFFFF00000000) >> 32; //Swaps 4 bytes
|
|
}
|
|
if ((BitLength == 32)||(BitLength==64)) // WORD_LE_T
|
|
{
|
|
InputNum = (InputNum & 0x0000FFFF0000FFFF) << 16 | (InputNum & 0xFFFF0000FFFF0000) >> 16; // Swaps 2 bytes
|
|
}
|
|
InputNum = (InputNum & 0x00FF00FF00FF00FF) << 8 | (InputNum & 0xFF00FF00FF00FF00) >> 8; // Swaps 1 byte
|
|
return InputNum;
|
|
}
|
|
|