diff --git a/ps2xRecomp/src/lib/fpu_translator.cpp b/ps2xRecomp/src/lib/fpu_translator.cpp index 435db3aa9..00e455c81 100644 --- a/ps2xRecomp/src/lib/fpu_translator.cpp +++ b/ps2xRecomp/src/lib/fpu_translator.cpp @@ -58,7 +58,8 @@ namespace ps2recomp "ctx->f[{}] = FPU_DIV_S(ctx->f[{}], ctx->f[{}]); }}", ft, fd, fs, ft); case COP1_S_SQRT: - return fmt::format("ctx->f[{}] = FPU_SQRT_S(ctx->f[{}]);", fd, fs); + // SQRT.S fd, ft reads the ft field; fs is 0 in the encoding. + return fmt::format("ctx->f[{}] = FPU_SQRT_S(ctx->f[{}]);", fd, ft); case COP1_S_ABS: return fmt::format("ctx->f[{}] = FPU_ABS_S(ctx->f[{}]);", fd, fs); case COP1_S_MOV: diff --git a/ps2xTest/src/code_generator_tests.cpp b/ps2xTest/src/code_generator_tests.cpp index 463b6cff1..6bc6b01f1 100644 --- a/ps2xTest/src/code_generator_tests.cpp +++ b/ps2xTest/src/code_generator_tests.cpp @@ -1020,6 +1020,26 @@ void register_code_generator_tests() t.IsTrue(ctc1Code.find("ignored") == std::string::npos, "CTC1 FCR31 should not be ignored"); }); + tc.Run("SQRT.S reads the ft operand", [](TestCase &t) { + CodeGenerator gen({}, {}); + + // sqrt.s $f2, $f2 (0x46020084): fs field is 0, the source is ft + Instruction sqrtS{}; + sqrtS.raw = 0x46020084; + sqrtS.opcode = OPCODE_COP1; + sqrtS.rs = COP1_S; + sqrtS.rt = 2; + sqrtS.rd = 0; + sqrtS.sa = 2; + sqrtS.function = COP1_S_SQRT; + + std::string sqrtCode = gen.translateInstruction(sqrtS); + printGeneratedCode("SQRT.S reads the ft operand", sqrtCode); + t.IsTrue(sqrtCode.find("ctx->f[2] = FPU_SQRT_S(ctx->f[2])") != std::string::npos, + "SQRT.S should take the square root of ft"); + t.IsTrue(sqrtCode.find("ctx->f[0]") == std::string::npos, "SQRT.S must not read fs"); + }); + tc.Run("VU CFC2/CTC2 access VI registers directly", [](TestCase& t) { CodeGenerator gen({}, {});