diff --git a/src/core-tests/cpu_execution_tests.cpp b/src/core-tests/cpu_execution_tests.cpp index 334978b9f..b5438a58a 100644 --- a/src/core-tests/cpu_execution_tests.cpp +++ b/src/core-tests/cpu_execution_tests.cpp @@ -205,6 +205,30 @@ TEST_P(CPUExecution, PGXPIgnoresWritesToZero) CPU::CodeCache::Reset(); } +TEST_P(CPUExecution, PGXPMTC0KeepsSourceValid) +{ + // mtc0 validates its source register, which must not lose its flags. + g_settings.gpu_pgxp_enable = true; + g_settings.gpu_pgxp_cpu = true; + CPU::PGXP::Initialize(); + CPU::CodeCache::Reset(); + const CPU::PGXPValue zero = CPU::g_state.pgxp_gpr[0]; + + Program prog; + prog.LoadImmediate(Reg::T0, 0x12345678u); + prog.Emit(mtc0(Reg::T0, 3)); + prog.Emit(mtc0(Reg::R0, 3)); + prog.Run(); + + EXPECT_EQ(CPU::g_state.pgxp_gpr[static_cast(Reg::T0)].flags & CPU::PGXP::VALID_XY, CPU::PGXP::VALID_XY); + EXPECT_EQ(std::memcmp(&CPU::g_state.pgxp_gpr[0], &zero, sizeof(zero)), 0); + + CPU::PGXP::Shutdown(); + g_settings.gpu_pgxp_enable = false; + g_settings.gpu_pgxp_cpu = false; + CPU::CodeCache::Reset(); +} + TEST_P(CPUExecution, PGXPMemoryModeMovesWithZeroImmediate) { // addiu/ori/xori with a zero immediate are moves, which memory mode PGXP keeps the value through. diff --git a/src/core/cpu_core.cpp b/src/core/cpu_core.cpp index 5402fe78c..017115b61 100644 --- a/src/core/cpu_core.cpp +++ b/src/core/cpu_core.cpp @@ -1987,7 +1987,7 @@ restart_instruction: } if constexpr (pgxp_mode == PGXPMode::CPU) - PGXP::CPU_MTC0(inst, value, orig_value); + PGXP::CPU_MTC0(inst, orig_value); } break; diff --git a/src/core/cpu_pgxp.cpp b/src/core/cpu_pgxp.cpp index 4c05e7615..3095409ea 100644 --- a/src/core/cpu_pgxp.cpp +++ b/src/core/cpu_pgxp.cpp @@ -1923,7 +1923,7 @@ void CPU::PGXP::CPU_MFC0(Instruction instr, u32 rdVal) prtVal.value = rdVal; } -void CPU::PGXP::CPU_MTC0(Instruction instr, u32 rdVal, u32 rtVal) +void CPU::PGXP::CPU_MTC0(Instruction instr, u32 rtVal) { LOG_VALUES_C1(instr.r.rt.GetValue(), rtVal); @@ -1931,5 +1931,5 @@ void CPU::PGXP::CPU_MTC0(Instruction instr, u32 rdVal, u32 rtVal) PGXPValue& prtVal = ValidateAndGetRtValue(instr, rtVal); PGXPValue& prdVal = g_state.pgxp_cop0[static_cast(instr.r.rd.GetValue())]; prdVal = prtVal; - prdVal.value = rdVal; + prdVal.value = rtVal; } diff --git a/src/core/cpu_pgxp.h b/src/core/cpu_pgxp.h index dcfb466a5..4230f1cbf 100644 --- a/src/core/cpu_pgxp.h +++ b/src/core/cpu_pgxp.h @@ -89,7 +89,7 @@ void CPU_SLLV(Instruction instr, u32 rsVal, u32 rtVal); void CPU_SRLV(Instruction instr, u32 rsVal, u32 rtVal); void CPU_SRAV(Instruction instr, u32 rsVal, u32 rtVal); void CPU_MFC0(Instruction instr, u32 rdVal); -void CPU_MTC0(Instruction instr, u32 rdVal, u32 rtVal); +void CPU_MTC0(Instruction instr, u32 rtVal); // Utility functions.