From 5c7632d99bdbcfee97ec52d8dc5a9dc5487ef8de Mon Sep 17 00:00:00 2001 From: Rularia Date: Sun, 1 Nov 2026 22:08:57 +0800 Subject: [PATCH 1/4] Update MIPSAnalyst.cpp --- Core/MIPS/MIPSAnalyst.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index a261e32164..8c9efe2264 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -125,6 +125,8 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x11624abe9542fb01, 180, "everybodysgolf_copy_portrait", }, // Everybody's Golf (EUR) { 0x1252e902d0b49bfb, 44, "vector_sub_q_2", }, { 0x12df3d33a58d0298, 52, "sceVfpuMatrix3Unit", }, + { 0x63efd322d02c32c1ULL, 108, "amagoushi_ice_download_frame", }, // Koori no Bohyou (NPJH50186 / ULJS00247) + { 0xbd015888f2167ac9ULL, 532, "amagoushi_ice_download_frame_core", }, // Koori no Bohyou (NPJH50186 / ULJS00247) { 0x12feef7b017d3431, 700, "memmove", }, { 0x1322c7e3fe6dff4d, 784, "_free_r", }, { 0x1376c115d5f1d90c, 36, "strlen", }, From 70ab07755dd0b6e6e8016516d681fb8960e078ce Mon Sep 17 00:00:00 2001 From: Rularia Date: Sun, 1 Nov 2026 22:10:23 +0800 Subject: [PATCH 2/4] Update ReplaceTables.cpp --- Core/HLE/ReplaceTables.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 8398564c68..eec5c79670 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -996,12 +996,13 @@ static int Hook_soranokiseki_sc_download_frame(MIPSState *mips) { return 0; } -static int Hook_bokunonatsuyasumi4_download_frame(MIPSState *mips) { - const u32 fb_address = mips->r[MIPS_REG_A3]; - if (Memory::IsVRAMAddress(fb_address)) { - gpu->PerformReadbackToMemory(fb_address, 0x00044000); - NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00044000, "bokunonatsuyasumi4_download_frame"); - } +static int Hook_amagoushi_download_frame(MIPSState *mips) { + // Amagoushi no Yakata series (ULJS00216, ULJS00230, NPJH50186, ULJS00247) + // Offscreen picking pass renders to 0x04000000, 0x04044000, or 0x04080000. + gpu->PerformReadbackToMemory(0x04000000, 0x00044000); + gpu->PerformReadbackToMemory(0x04044000, 0x00044000); + gpu->PerformReadbackToMemory(0x04080000, 0x00044000); + NotifyMemInfo(MemBlockFlags::WRITE, 0x04000000, 0x00044000, "amagoushi_download_frame"); return 0; } @@ -2116,6 +2117,9 @@ static const ReplacementTableEntry entries[] = { { "kagaku_no_ensemble_download_frame", &Hook_kagaku_no_ensemble_download_frame, 0, REPFLAG_HOOKENTER, 0x38 }, { "soranokiseki_fc_download_frame", &Hook_soranokiseki_fc_download_frame, 0, REPFLAG_HOOKENTER, 0x180 }, { "soranokiseki_sc_download_frame", &Hook_soranokiseki_sc_download_frame, 0, REPFLAG_HOOKENTER, }, + { "amagoushi_download_frame", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, + { "amagoushi_ice_download_frame", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, + { "amagoushi_ice_download_frame_core", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, { "bokunonatsuyasumi4_download_frame", &Hook_bokunonatsuyasumi4_download_frame, 0, REPFLAG_HOOKENTER, 0x8C }, { "danganronpa2_1_download_frame", &Hook_danganronpa2_1_download_frame, 0, REPFLAG_HOOKENTER, 0x68 }, { "danganronpa2_2_download_frame", &Hook_danganronpa2_2_download_frame, 0, REPFLAG_HOOKENTER, 0x94 }, From 906fc161701f2ba7592ad338fb556a4ce323998e Mon Sep 17 00:00:00 2001 From: Rularia Date: Sun, 1 Nov 2026 22:42:55 +0800 Subject: [PATCH 3/4] Update ReplaceTables.cpp --- Core/HLE/ReplaceTables.cpp | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index eec5c79670..6b7529a18a 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -1006,6 +1006,15 @@ static int Hook_amagoushi_download_frame(MIPSState *mips) { return 0; } +static int Hook_bokunonatsuyasumi4_download_frame(MIPSState *mips) { + const u32 fb_address = mips->r[MIPS_REG_A3]; + if (Memory::IsVRAMAddress(fb_address)) { + gpu->PerformReadbackToMemory(fb_address, 0x00044000); + NotifyMemInfo(MemBlockFlags::WRITE, fb_address, 0x00044000, "bokunonatsuyasumi4_download_frame"); + } + return 0; +} + static int Hook_danganronpa2_1_download_frame(MIPSState *mips) { const u32 fb_base = mips->r[MIPS_REG_V0]; const u32 fb_offset = mips->r[MIPS_REG_V1]; From cc99fb01a195d8ac12c943579b04210ed65fcfb6 Mon Sep 17 00:00:00 2001 From: Rularia Date: Mon, 2 Nov 2026 00:14:34 +0800 Subject: [PATCH 4/4] Koori: rsingle source-buffer readback --- Core/HLE/ReplaceTables.cpp | 32 +++++++++++++++++++------------- Core/MIPS/MIPSAnalyst.cpp | 3 +-- assets/compat.ini | 2 +- 3 files changed, 21 insertions(+), 16 deletions(-) diff --git a/Core/HLE/ReplaceTables.cpp b/Core/HLE/ReplaceTables.cpp index 6b7529a18a..fdecda051d 100644 --- a/Core/HLE/ReplaceTables.cpp +++ b/Core/HLE/ReplaceTables.cpp @@ -996,16 +996,6 @@ static int Hook_soranokiseki_sc_download_frame(MIPSState *mips) { return 0; } -static int Hook_amagoushi_download_frame(MIPSState *mips) { - // Amagoushi no Yakata series (ULJS00216, ULJS00230, NPJH50186, ULJS00247) - // Offscreen picking pass renders to 0x04000000, 0x04044000, or 0x04080000. - gpu->PerformReadbackToMemory(0x04000000, 0x00044000); - gpu->PerformReadbackToMemory(0x04044000, 0x00044000); - gpu->PerformReadbackToMemory(0x04080000, 0x00044000); - NotifyMemInfo(MemBlockFlags::WRITE, 0x04000000, 0x00044000, "amagoushi_download_frame"); - return 0; -} - static int Hook_bokunonatsuyasumi4_download_frame(MIPSState *mips) { const u32 fb_address = mips->r[MIPS_REG_A3]; if (Memory::IsVRAMAddress(fb_address)) { @@ -1367,6 +1357,24 @@ static int Hook_infinity_download_frame(MIPSState *mips) { return 0; } +static int Hook_koori_download_frame(MIPSState *mips) { + u32 stateAddress; + // The matched CPU copy reads its source from this renderer state. + if (!GetMIPSStaticAddress(mips, stateAddress, 0x0C, 0x10) || !Memory::IsValidRange(stateAddress, 4)) { + return 0; + } + const u32 state = Memory::ReadUnchecked_U32(stateAddress); + if (!Memory::IsValidRange(state, 0x54)) { + return 0; + } + const u32 fb = (Memory::ReadUnchecked_U32(state + 0x24) + Memory::ReadUnchecked_U32(state + 0x50)) & 0x3FFFFFFF; + if (fb == 0x04000000 || fb == 0x04080000) { + gpu->PerformReadbackToMemory(fb, 0x00044000); + NotifyMemInfo(MemBlockFlags::WRITE, fb, 0x00044000, "koori_download_frame"); + } + return 0; +} + static int Hook_takuyo_download_frame(MIPSState *mips) { gpu->PerformReadbackToMemory(0x04088000, 0x00088000); // The offset is hardcoded. NotifyMemInfo(MemBlockFlags::WRITE, 0x04088000, 0x00088000, "takuyo_download_frame"); @@ -2126,9 +2134,6 @@ static const ReplacementTableEntry entries[] = { { "kagaku_no_ensemble_download_frame", &Hook_kagaku_no_ensemble_download_frame, 0, REPFLAG_HOOKENTER, 0x38 }, { "soranokiseki_fc_download_frame", &Hook_soranokiseki_fc_download_frame, 0, REPFLAG_HOOKENTER, 0x180 }, { "soranokiseki_sc_download_frame", &Hook_soranokiseki_sc_download_frame, 0, REPFLAG_HOOKENTER, }, - { "amagoushi_download_frame", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, - { "amagoushi_ice_download_frame", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, - { "amagoushi_ice_download_frame_core", &Hook_amagoushi_download_frame, 0, REPFLAG_HOOKENTER }, { "bokunonatsuyasumi4_download_frame", &Hook_bokunonatsuyasumi4_download_frame, 0, REPFLAG_HOOKENTER, 0x8C }, { "danganronpa2_1_download_frame", &Hook_danganronpa2_1_download_frame, 0, REPFLAG_HOOKENTER, 0x68 }, { "danganronpa2_2_download_frame", &Hook_danganronpa2_2_download_frame, 0, REPFLAG_HOOKENTER, 0x94 }, @@ -2191,6 +2196,7 @@ static const ReplacementTableEntry entries[] = { { "persona2_download_frame", &Hook_persona_download_frame, 0, REPFLAG_HOOKENTER, 0 }, { "steinsgate_download_frame", &Hook_steinsgate_download_frame, 0, REPFLAG_HOOKENTER, 0 }, { "infinity_download_frame", &Hook_infinity_download_frame, 0, REPFLAG_HOOKENTER, 0 }, + { "koori_download_frame", &Hook_koori_download_frame, 0, REPFLAG_HOOKENTER, 0 }, { "takuyo_1_download_frame", &Hook_takuyo_download_frame, 0, REPFLAG_HOOKENTER, 0}, { "takuyo_2_download_frame", &Hook_takuyo_download_frame, 0, REPFLAG_HOOKENTER, 0}, { "takuyo_3_download_frame", &Hook_takuyo_download_frame, 0, REPFLAG_HOOKENTER, 0}, diff --git a/Core/MIPS/MIPSAnalyst.cpp b/Core/MIPS/MIPSAnalyst.cpp index 8c9efe2264..05a8cfb582 100644 --- a/Core/MIPS/MIPSAnalyst.cpp +++ b/Core/MIPS/MIPSAnalyst.cpp @@ -125,8 +125,6 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0x11624abe9542fb01, 180, "everybodysgolf_copy_portrait", }, // Everybody's Golf (EUR) { 0x1252e902d0b49bfb, 44, "vector_sub_q_2", }, { 0x12df3d33a58d0298, 52, "sceVfpuMatrix3Unit", }, - { 0x63efd322d02c32c1ULL, 108, "amagoushi_ice_download_frame", }, // Koori no Bohyou (NPJH50186 / ULJS00247) - { 0xbd015888f2167ac9ULL, 532, "amagoushi_ice_download_frame_core", }, // Koori no Bohyou (NPJH50186 / ULJS00247) { 0x12feef7b017d3431, 700, "memmove", }, { 0x1322c7e3fe6dff4d, 784, "_free_r", }, { 0x1376c115d5f1d90c, 36, "strlen", }, @@ -425,6 +423,7 @@ static const HardHashTableEntry hardcodedHashes[] = { { 0xba76a8e853426baa, 544, "soranokiseki_fc_download_frame", }, // Sora no kiseki FC { 0xbb3c6592ed319ba4, 132, "sceGuFog", }, { 0xbb7d7c93e4c08577, 124, "__truncdfsf2", }, + { 0xbd015888f2167ac9, 532, "koori_download_frame", }, // Koori no Bohyou (NPJH50186) { 0xbdf54d66079afb96, 200, "sceGuBoneMatrix", }, { 0xbe773f78afd1a70f, 128, "rand", }, { 0xbf5d02ccb8514881, 108, "strcmp", }, diff --git a/assets/compat.ini b/assets/compat.ini index 13ec14f43d..b9b215d854 100644 --- a/assets/compat.ini +++ b/assets/compat.ini @@ -2252,7 +2252,7 @@ NPJH50518 = true ULJS00216 = true ULJS00230 = true ULJS00247 = true -NPJH50186 = true +# NPJH50186 uses koori_download_frame before the CPU copy instead. [FixedFramebuffer] # A framebuffer always kept at one size, as "address,width,height" (address in hex), and also read and