diff --git a/pcsx2/Patch.cpp b/pcsx2/Patch.cpp index e285d96611..3d42f58736 100644 --- a/pcsx2/Patch.cpp +++ b/pcsx2/Patch.cpp @@ -67,6 +67,7 @@ namespace Patch u32 prev_cheat_type = 0; u32 prev_cheat_addr = 0; u32 last_type = 0; + bool null_pointer_encountered = false; }; namespace PatchFunc @@ -1266,6 +1267,8 @@ void Patch::handle_extended_t(const PatchCommand* p, Memory& memory, ExtendedSta case 0x6000: // 000Xnnnn iiiiiiii { + state.null_pointer_encountered = false; + // Get Number of pointers if (((u32)p->addr & 0x0000FFFF) == 0) state.iteration_count = 1; @@ -1288,10 +1291,9 @@ void Patch::handle_extended_t(const PatchCommand* p, Memory& memory, ExtendedSta } else { + state.prev_cheat_type = 0x6001; if (((mem & 0x0FFFFFFF) & 0x3FFFFFFC) == 0) - state.prev_cheat_type = 0; - else - state.prev_cheat_type = 0x6001; + state.null_pointer_encountered = true; } } break; @@ -1299,7 +1301,9 @@ void Patch::handle_extended_t(const PatchCommand* p, Memory& memory, ExtendedSta case 0x6001: // 000Xnnnn iiiiiiii { // Read first pointer - u32 mem = memory.Read32(state.prev_cheat_addr & 0x0FFFFFFF); + u32 mem = 0; + if (!state.null_pointer_encountered) + mem = memory.Read32(state.prev_cheat_addr & 0x0FFFFFFF); state.prev_cheat_addr = mem + (u32)p->addr; state.iteration_count--; @@ -1313,7 +1317,10 @@ void Patch::handle_extended_t(const PatchCommand* p, Memory& memory, ExtendedSta } else { - mem = memory.Read32(state.prev_cheat_addr); + if (!state.null_pointer_encountered) + mem = memory.Read32(state.prev_cheat_addr); + else + mem = 0; state.prev_cheat_addr = mem + (u32)p->data; state.iteration_count--; diff --git a/tests/ctest/core/patch_tests.cpp b/tests/ctest/core/patch_tests.cpp index f8cb1ffe56..2a2e2d61b4 100644 --- a/tests/ctest/core/patch_tests.cpp +++ b/tests/ctest/core/patch_tests.cpp @@ -399,6 +399,44 @@ PATCH_TEST(ExtendedPointerWriteLastNull, ee.ExpectRead32(0x00300008, 0x00000000); } +PATCH_TEST(ExtendedPointerWriteSkipsNullSingle, + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x60100000, Patch::EXTENDED_T, 0x0fffffff), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x00020001, Patch::EXTENDED_T, 0x0fffffff), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20200000, Patch::EXTENDED_T, 0x12345678), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20300000, Patch::EXTENDED_T, 0x12345678)) +{ + ee.ExpectRead32(0x00100000, 0); + ee.ExpectIdempotentWrite32(0x00200000, 0, 0x12345678); + ee.ExpectIdempotentWrite32(0x00300000, 0, 0x12345678); +} + +// There was previously a bug where if the pointer write command was split over +// three lines or more, if the first pointer was null it would interpret the +// middle of the pointer write command as the start of a new command. +PATCH_TEST(ExtendedPointerWriteSkipsFirstNullMultiEven, + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x60100000, Patch::EXTENDED_T, 0x0fffffff), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x00020002, Patch::EXTENDED_T, 0x00000004), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x0fffffff, Patch::EXTENDED_T, 0x00000000), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20200000, Patch::EXTENDED_T, 0x12345678), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20300000, Patch::EXTENDED_T, 0x12345678)) +{ + ee.ExpectRead32(0x00100000, 0); + ee.ExpectIdempotentWrite32(0x00200000, 0, 0x12345678); + ee.ExpectIdempotentWrite32(0x00300000, 0, 0x12345678); +} + +PATCH_TEST(ExtendedPointerWriteSkipsFirstNullMultiOdd, + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x60100000, Patch::EXTENDED_T, 0x0fffffff), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x00020003, Patch::EXTENDED_T, 0x00000004), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x00000008, Patch::EXTENDED_T, 0x0fffffff), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20200000, Patch::EXTENDED_T, 0x12345678), + BuildPatchCommand(Patch::PPT_ONCE_ON_LOAD, Patch::CPU_EE, 0x20300000, Patch::EXTENDED_T, 0x12345678)) +{ + ee.ExpectRead32(0x00100000, 0); + ee.ExpectIdempotentWrite32(0x00200000, 0, 0x12345678); + ee.ExpectIdempotentWrite32(0x00300000, 0, 0x12345678); +} + // ***************************************************************************** // Boolean operation (Extended) // *****************************************************************************