From feb6caa3c470a890e2ad2c24b95045f8f309f7b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Rydg=C3=A5rd?= Date: Fri, 25 Sep 2026 11:05:40 -0600 Subject: [PATCH] Implement mfic and mtic Both were no-ops, so mfic left its destination unchanged. They read and write the interrupt enable flag that sceKernelCpuSuspendIntr/ResumeIntr use. Only bit 0 counts for mtic, which also goes for sceKernelCpuResumeIntr, since on hardware it's just mtic. Adds the intr/mfic test, recorded on hardware. Co-Authored-By: Claude Opus 5.5 (1M context) --- Core/HLE/sceKernelInterrupt.cpp | 3 ++- Core/MIPS/Interpreter.cpp | 26 ++++++++++++-------------- Core/MIPS/MIPSTables.cpp | 4 ++-- pspautotests | 2 +- test.py | 1 + 5 files changed, 18 insertions(+), 18 deletions(-) diff --git a/Core/HLE/sceKernelInterrupt.cpp b/Core/HLE/sceKernelInterrupt.cpp index 4d79d764d9..db9ed3852f 100644 --- a/Core/HLE/sceKernelInterrupt.cpp +++ b/Core/HLE/sceKernelInterrupt.cpp @@ -98,7 +98,8 @@ static int sceKernelCpuSuspendIntr() static void sceKernelCpuResumeIntr(u32 enable) { VERBOSE_LOG(Log::sceIntc, "sceKernelCpuResumeIntr(%i)", enable); - if (enable) + // This is mtic a0, $0, which only looks at bit 0 (tests/intr/mfic). + if (enable & 1) { __EnableInterrupts(); hleRunInterrupts(); diff --git a/Core/MIPS/Interpreter.cpp b/Core/MIPS/Interpreter.cpp index c65e20db88..723b566a64 100644 --- a/Core/MIPS/Interpreter.cpp +++ b/Core/MIPS/Interpreter.cpp @@ -35,6 +35,7 @@ #include "Core/HLE/HLE.h" #include "Core/HLE/HLETables.h" #include "Core/HLE/ReplaceTables.h" +#include "Core/HLE/sceKernelInterrupt.h" #include "Core/HW/GpioMMIO.h" #define R(i) (mips->r[i]) @@ -1054,25 +1055,22 @@ namespace MIPSInt { PC += 4; } + // The interrupt enable flag, shared with the HLE sceKernelCpuSuspendIntr/ResumeIntr, which on + // hardware are just mfic v0, $0; mtic zero, $0 and mtic a0, $0. Only $0 exists. void Int_Special2(MIPSState *mips, MIPSOpcode op) { - static int reported = 0; + int rt = _RT; switch (op & 0x3F) { case 36: // mfic - // move from interrupt controller, not implemented - // See related report https://report.ppsspp.org/logs/kind/316 for possible locations. - // Also see https://forums.ps2dev.org/viewtopic.php?p=32700#p32700 . - // TODO: Should we actually implement this? - if (!reported) { - WARN_LOG(Log::CPU, "MFIC Disable/Enable Interrupt CPU instruction"); - reported = 1; - } + if (rt != 0) + R(rt) = __InterruptsEnabled() ? 1 : 0; break; case 38: // mtic - // move to interrupt controller, not implemented - if (!reported) { - WARN_LOG(Log::CPU, "MTIC Disable/Enable Interrupt CPU instruction"); - reported = 1; - } + // Only bit 0 counts: mtic 2 disables. Pending interrupts run at the next scheduling point, + // not right away as with sceKernelCpuResumeIntr. + if (R(rt) & 1) + __EnableInterrupts(); + else + __DisableInterrupts(); break; } PC += 4; diff --git a/Core/MIPS/MIPSTables.cpp b/Core/MIPS/MIPSTables.cpp index 093f708360..6ace0f2712 100644 --- a/Core/MIPS/MIPSTables.cpp +++ b/Core/MIPS/MIPSTables.cpp @@ -261,9 +261,9 @@ static const MIPSInstruction tableSpecial2[64] = // 011100 ..... ..... ..... ... INVALID_X_8, //32 INVALID, INVALID, INVALID, INVALID, - INSTR("mfic", JITFUNC(Comp_Generic), Dis_Generic, Int_Special2, OUT_OTHER), + INSTR("mfic", JITFUNC(Comp_Generic), Dis_Generic, Int_Special2, OUT_RT | OUT_OTHER), INVALID, - INSTR("mtic", JITFUNC(Comp_Generic), Dis_Generic, Int_Special2, OUT_OTHER), + INSTR("mtic", JITFUNC(Comp_Generic), Dis_Generic, Int_Special2, IN_RT | OUT_OTHER), INVALID, //40 INVALID_X_8, diff --git a/pspautotests b/pspautotests index 8d51020081..3dc4690e7d 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 8d510200812366931e7becb743cdbaea51174999 +Subproject commit 3dc4690e7d4f704764d23ef1ef0eb82ccc3dc30d diff --git a/test.py b/test.py index c1455dc759..df5fd93a24 100755 --- a/test.py +++ b/test.py @@ -262,6 +262,7 @@ tests_good = [ "hash/sha1ctx", "hle/check_not_used_uids", "intr/intr", + "intr/mfic", "intr/enablesub", "intr/suspended", "intr/vblank/vblank",