From b73c5754189948969b947abefd7411f1be389a41 Mon Sep 17 00:00:00 2001 From: "Unknown W. Brackets" Date: Mon, 26 May 2014 16:49:32 -0700 Subject: [PATCH] Support swizzled framebuffer downloads. Used in God Eater 2 when showing the load save screen. --- Core/HLE/ReplaceTables.cpp | 37 +++++++++++++++++++++++++++++++++++++ Core/MIPS/MIPSAnalyst.cpp | 26 ++++++++++++++++++++++++++ assets/knownfuncs.ini | 1 + 3 files changed, 64 insertions(+) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index d886f343a..df3039b39 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -142,6 +142,42 @@ static int Replace_memcpy16() { return 10 + bytes / 4; // approximation } +static int Replace_memcpy_swizzled() { + u32 destPtr = PARAM(0); + u32 srcPtr = PARAM(1); + u32 pitch = PARAM(2); + u32 h = PARAM(4); + if (Memory::IsVRAMAddress(srcPtr)) { + // Cheat a bit to force a download of the framebuffer. + // VRAM + 0x00400000 is simply a VRAM mirror. + gpu->UpdateMemory(srcPtr ^ 0x00400000, srcPtr, pitch * h); + } + u8 *dstp = Memory::GetPointerUnchecked(destPtr); + const u8 *srcp = Memory::GetPointerUnchecked(srcPtr); + + const u8 *ysrcp = srcp; + for (u32 y = 0; y < h; y += 8) { + const u8 *xsrcp = ysrcp; + for (u32 x = 0; x < pitch; x += 16) { + const u8 *src = xsrcp; + for (int n = 0; n < 8; ++n) { + memcpy(dstp, src, 16); + src += pitch; + dstp += 16; + } + xsrcp += 16; + } + ysrcp += 8 * pitch; + } + + RETURN(0); +#ifndef MOBILE_DEVICE + CBreakPoints::ExecMemCheck(srcPtr, false, pitch * h, currentMIPS->pc); + CBreakPoints::ExecMemCheck(destPtr, true, pitch * h, currentMIPS->pc); +#endif + return 10 + (pitch * h) / 4; // approximation +} + static int Replace_memmove() { u32 destPtr = PARAM(0); u32 srcPtr = PARAM(1); @@ -420,6 +456,7 @@ static const ReplacementTableEntry entries[] = { { "ceilf", &Replace_ceilf, 0, 0}, { "memcpy", &Replace_memcpy, 0, 0}, { "memcpy16", &Replace_memcpy16, 0, 0}, + { "memcpy_swizzled", &Replace_memcpy_swizzled, 0, 0}, { "memmove", &Replace_memmove, 0, 0}, { "memset", &Replace_memset, 0, 0}, { "strlen", &Replace_strlen, 0, 0}, diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 7b413ee78..942e22ca3 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -220,6 +220,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x6301fa5149bd973a, 120, "wcscat", }, { 0x658b07240a690dbd, 36, "strlen", }, { 0x66122f0ab50b2ef9, 296, "dl_write_dither_matrix_5", }, + { 0x66f7f1beccbc104a, 256, "memcpy_swizzled", }, // God Eater 2 { 0x679e647e34ecf7f1, 132, "roundf", }, { 0x67afe74d9ec72f52, 4380, "_strtod_r", }, { 0x68b22c2aa4b8b915, 400, "sqrt", }, @@ -738,6 +739,7 @@ skip: bool looking = false; bool end = false; bool isStraightLeaf = true; + bool decreasedSp = false; u32 addr; u32 addrNextSym = 0; @@ -761,6 +763,8 @@ skip: furthestBranch = 0; looking = false; end = false; + isStraightLeaf = false; + decreasedSp = false; continue; } @@ -771,6 +775,7 @@ skip: if (target > furthestBranch) { furthestBranch = target; } + // j X } else if ((op & 0xFC000000) == 0x08000000) { u32 sureTarget = GetJumpTarget(addr); // Check for a tail call. Might not even have a jr ra. @@ -782,6 +787,18 @@ skip: end = true; } } else if (sureTarget != INVALIDTARGET && sureTarget > addr && sureTarget > furthestBranch) { + static const u32 MAX_JUMP_FORWARD = 128; + // If it's a nearby forward jump, and not a stackless leaf, assume not a tail call. + if (sureTarget <= addr + MAX_JUMP_FORWARD && decreasedSp) { + // But let's check the delay slot. + MIPSOpcode op = Memory::Read_Instruction(addr + 4); + // addiu sp, sp, +X + if ((op & 0xFFFF8000) != 0x27BD0000) { + furthestBranch = sureTarget; + continue; + } + } + // A jump later. Probably tail, but let's check if it jumps back. u32 knownEnd = furthestBranch == 0 ? addr : furthestBranch; u32 jumpback = ScanAheadForJumpback(sureTarget, currentFunction.start, knownEnd); @@ -806,6 +823,14 @@ skip: end = true; } } + // addiu sp, sp, -X + if ((op & 0xFFFF8000) == 0x27BD8000) { + decreasedSp = true; + } + // addiu sp, sp, +X + if ((op & 0xFFFF8000) == 0x27BD0000) { + decreasedSp = false; + } if (looking) { if (addr >= furthestBranch) { @@ -838,6 +863,7 @@ skip: looking = false; end = false; isStraightLeaf = true; + decreasedSp = false; currentFunction.start = addr+4; } } diff --git a/assets/knownfuncs.ini b/assets/knownfuncs.ini index 2ab8fa7fa..4dd2e379e 100644 --- a/assets/knownfuncs.ini +++ b/assets/knownfuncs.ini @@ -140,6 +140,7 @@ 6301fa5149bd973a:120 = wcscat 658b07240a690dbd:36 = strlen 66122f0ab50b2ef9:296 = dl_write_dither_matrix_5 +66f7f1beccbc104a:256 = memcpy_swizzled 679e647e34ecf7f1:132 = roundf 67afe74d9ec72f52:4380 = _strtod_r 68b22c2aa4b8b915:400 = sqrt