make idle loop detection a little more specific with where the load goes

This commit is contained in:
2026-06-03 21:08:36 +02:00
parent b037de4c3d
commit 61bb4fb449
3 changed files with 51 additions and 18 deletions
+24 -9
View File
@@ -1,5 +1,6 @@
#include <Core.hpp> #include <Core.hpp>
#include <Scheduler.hpp> #include <Scheduler.hpp>
#include <mem/Utils.hpp>
namespace n64 { namespace n64 {
Interpreter::Interpreter(Mem &mem, Registers &regs) : regs(regs), mem(mem) {} Interpreter::Interpreter(Mem &mem, Registers &regs) : regs(regs), mem(mem) {}
@@ -118,11 +119,18 @@ bool Interpreter::DetectIdleLoop(const std::array<Instruction, MAX_INSTR_PER_BLO
// _andi reg2, reg1, immediate // _andi reg2, reg1, immediate
auto branch = code[lastInstructionIndex - 1]; auto branch = code[lastInstructionIndex - 1];
auto load = code[lastInstructionIndex - 2]; // load auto load = code[lastInstructionIndex - 2];
bool isLoad = load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU;
if (isLoad) {
const s16 offset = load;
const u64 address = regs.Read<s64>(load.rs()) + offset;
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
panic("Failed to translate load address in DetectIdleLoop");
return (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) && return isLoad && delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -8 &&
delay.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -8 && load.rt() == delay.rs() && delay.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
load.rt() == delay.rs() && delay.rt() == branch.rs(); }
} }
if (len == 4) { if (len == 4) {
@@ -132,12 +140,19 @@ bool Interpreter::DetectIdleLoop(const std::array<Instruction, MAX_INSTR_PER_BLO
// _nop // _nop
auto branch = code[lastInstructionIndex - 1]; auto branch = code[lastInstructionIndex - 1];
auto andi = code[lastInstructionIndex - 2]; // andi auto andi = code[lastInstructionIndex - 2];
auto load = code[lastInstructionIndex - 3]; // load auto load = code[lastInstructionIndex - 3];
const s16 offset = load;
const u64 address = regs.Read<s64>(load.rs()) + offset;
bool isLoad = load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU;
if (isLoad) {
u32 paddr;
if (!regs.cop0.MapVAddr(Cop0::LOAD, address, paddr))
panic("Failed to translate load address in DetectIdleLoop");
return (load.opcode() == Instruction::LW || load.opcode() == Instruction::LWU) && return isLoad && andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -12 &&
andi.opcode() == Instruction::ANDI && branch.IsBranch() && branch.offset() == -12 && load.rt() == andi.rs() && andi.rt() == branch.rs() && IsAddressMMIOorRDRAM(paddr);
load.rt() == andi.rs() && andi.rt() == branch.rs(); }
} }
return false; return false;
+17
View File
@@ -0,0 +1,17 @@
#pragma once
#include <common.hpp>
#include <ircolib/mem_access.hpp>
#include <MemoryRegions.hpp>
namespace n64 {
static bool IsAddressMMIOorRDRAM(u32 addr) {
if (ircolib::IsInsideRange(addr, RDRAM_REGION_START, RDRAM_REGION_END))
return true;
if (ircolib::IsInsideRange(addr, MMIO_REGION_START_1, MMIO_REGION_END_1) ||
ircolib::IsInsideRange(addr, MMIO_REGION_START_2, MMIO_REGION_END_2))
return true;
return false;
}
} // namespace n64
+5 -4
View File
@@ -4,12 +4,13 @@
int main(const int argc, char **argv) { int main(const int argc, char **argv) {
KaizenGui kaizenGui; KaizenGui kaizenGui;
cflags::cflags flags; cflags::cflags flags;
flags.add_string_callback('\0', "rom", [&kaizenGui](const std::string& v) { kaizenGui.LoadROM(v); }, "Rom to launch from command-line"); flags.add_string_callback(
flags.add_string_callback('\0', "movie", [](const std::string& v) { KaizenGui::LoadTAS(v); }, "Mupen Movie to replay"); '\0', "rom", [&kaizenGui](const std::string &v) { kaizenGui.LoadROM(v); }, "Rom to launch from command-line");
flags.add_string_callback(
'\0', "movie", [](const std::string &v) { KaizenGui::LoadTAS(v); }, "Mupen Movie to replay");
if(!flags.parse(argc, argv)) { if (!flags.parse(argc, argv))
return -1; return -1;
}
kaizenGui.run(); kaizenGui.run();