diff --git a/rpcs3/Emu/Cell/PPUInterpreter.h b/rpcs3/Emu/Cell/PPUInterpreter.h index 76a9991a62..b4f308a2ee 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.h +++ b/rpcs3/Emu/Cell/PPUInterpreter.h @@ -4112,7 +4112,7 @@ private: } void MTFSB1(u32 crbd, bool rc) { - u64 mask = (1ULL << crbd); + u64 mask = (1ULL << (31 - crbd)); if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); CPU.FPSCR.FPSCR |= mask; @@ -4120,13 +4120,32 @@ private: } void MCRFS(u32 crbd, u32 crbs) { - u64 mask = (1ULL << crbd); - CPU.CR.CR &= ~mask; - CPU.CR.CR |= CPU.FPSCR.FPSCR & mask; + CPU.SetCR(crbd, (CPU.FPSCR.FPSCR >> ((7 - crbs) * 4)) & 0xf); + + switch (crbs) + { + case 0: + CPU.FPSCR.FX = CPU.FPSCR.OX = 0; + break; + case 1: + CPU.FPSCR.UX = CPU.FPSCR.ZX = CPU.FPSCR.XX = CPU.FPSCR.VXSNAN = 0; + break; + case 2: + CPU.FPSCR.VXISI = CPU.FPSCR.VXIDI = CPU.FPSCR.VXZDZ = CPU.FPSCR.VXIMZ = 0; + break; + case 3: + CPU.FPSCR.VXVC = 0; + break; + case 5: + CPU.FPSCR.VXSOFT = CPU.FPSCR.VXSQRT = CPU.FPSCR.VXCVI = 0; + break; + default: + break; + } } void MTFSB0(u32 crbd, bool rc) { - u64 mask = (1ULL << crbd); + u64 mask = (1ULL << (31 - crbd)); if ((crbd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); CPU.FPSCR.FPSCR &= ~mask; @@ -4134,17 +4153,18 @@ private: } void MTFSFI(u32 crfd, u32 i, bool rc) { - u64 mask = (0x1ULL << crfd); + u32 mask = 0xF0000000 >> (crfd * 4); + u32 val = (i & 0xF) << ((7 - crfd) * 4); - if(i) + const u32 oldNI = CPU.FPSCR.NI; + CPU.FPSCR.FPSCR &= ~mask; + CPU.FPSCR.FPSCR |= val; + if (CPU.FPSCR.NI != oldNI) { - if ((crfd == 29) && !CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode enabled"); - CPU.FPSCR.FPSCR |= mask; - } - else - { - if ((crfd == 29) && CPU.FPSCR.NI) LOG_WARNING(PPU, "Non-IEEE mode disabled"); - CPU.FPSCR.FPSCR &= ~mask; + if (oldNI) + LOG_WARNING(PPU, "Non-IEEE mode disabled"); + else + LOG_WARNING(PPU, "Non-IEEE mode enabled"); } if(rc) UNIMPLEMENTED(); diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp index b88489bc5e..042f2457f3 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.cpp @@ -4305,27 +4305,99 @@ void Compiler::STDU(u32 rs, u32 ra, s32 ds) { } void Compiler::MTFSB1(u32 crbd, bool rc) { - InterpreterCall("MTFSB1", &PPUInterpreter::MTFSB1, crbd, rc); + auto fpscr_i32 = GetFpscr(); + SetBit(fpscr_i32, crbd, m_ir_builder->getInt32(1), false); + SetFpscr(fpscr_i32); + + if (rc) { + // TODO: Implement this + CompilationError("MTFSB1."); + } } void Compiler::MCRFS(u32 crbd, u32 crbs) { - InterpreterCall("MCRFS", &PPUInterpreter::MCRFS, crbd, crbs); + auto fpscr_i32 = GetFpscr(); + auto val_i32 = GetNibble(fpscr_i32, crbs); + SetCrField(crbd, val_i32); + + switch (crbs) { + case 0: + fpscr_i32 = ClrBit(fpscr_i32, 0); + fpscr_i32 = ClrBit(fpscr_i32, 3); + break; + case 1: + fpscr_i32 = ClrNibble(fpscr_i32, 1); + break; + case 2: + fpscr_i32 = ClrNibble(fpscr_i32, 2); + break; + case 3: + fpscr_i32 = ClrBit(fpscr_i32, 12); + break; + case 5: + fpscr_i32 = ClrBit(fpscr_i32, 21); + fpscr_i32 = ClrBit(fpscr_i32, 22); + fpscr_i32 = ClrBit(fpscr_i32, 23); + break; + default: + break; + } + + SetFpscr(fpscr_i32); } void Compiler::MTFSB0(u32 crbd, bool rc) { - InterpreterCall("MTFSB0", &PPUInterpreter::MTFSB0, crbd, rc); + auto fpscr_i32 = GetFpscr(); + fpscr_i32 = ClrBit(fpscr_i32, crbd); + SetFpscr(fpscr_i32); + + if (rc) { + // TODO: Implement this + CompilationError("MTFSB0."); + } } void Compiler::MTFSFI(u32 crfd, u32 i, bool rc) { - InterpreterCall("MTFSFI", &PPUInterpreter::MTFSFI, crfd, i, rc); + auto fpscr_i32 = GetFpscr(); + fpscr_i32 = SetNibble(fpscr_i32, crfd, m_ir_builder->getInt32(i & 0xF)); + SetFpscr(fpscr_i32); + + if (rc) { + // TODO: Implement this + CompilationError("MTFSFI."); + } } void Compiler::MFFS(u32 frd, bool rc) { - InterpreterCall("MFFS", &PPUInterpreter::MFFS, frd, rc); + auto fpscr_i32 = GetFpscr(); + auto fpscr_i64 = m_ir_builder->CreateZExt(fpscr_i32, m_ir_builder->getInt64Ty()); + SetFpr(frd, fpscr_i64); + + if (rc) { + // TODO: Implement this + CompilationError("MFFS."); + } } void Compiler::MTFSF(u32 flm, u32 frb, bool rc) { - InterpreterCall("MTFSF", &PPUInterpreter::MTFSF, flm, frb, rc); + u32 mask = 0; + for(u32 i = 0; i < 8; i++) { + if (flm & (1 << i)) { + mask |= 0xF << (i * 4); + } + } + + auto rb_i32 = GetFpr(frb, 32, true); + auto fpscr_i32 = GetFpscr(); + fpscr_i32 = m_ir_builder->CreateAnd(fpscr_i32, ~mask); + rb_i32 = m_ir_builder->CreateAnd(rb_i32, mask); + fpscr_i32 = m_ir_builder->CreateOr(fpscr_i32, rb_i32); + SetFpscr(fpscr_i32); + + if (rc) { + // TODO: Implement this + CompilationError("MTFSF."); + } } void Compiler::FCMPU(u32 crfd, u32 fra, u32 frb) { @@ -4987,6 +5059,19 @@ void Compiler::SetUsprg0(Value * val_x64) { m_ir_builder->CreateAlignedStore(val_i64, usprg0_i64_ptr, 8); } +Value * Compiler::GetFpscr() { + auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPSCR)); + auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + return m_ir_builder->CreateAlignedLoad(fpscr_i32_ptr, 4); +} + +void Compiler::SetFpscr(Value * val_x32) { + auto val_i32 = m_ir_builder->CreateBitCast(val_x32, m_ir_builder->getInt32Ty()); + auto fpscr_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPSCR)); + auto fpscr_i32_ptr = m_ir_builder->CreateBitCast(fpscr_i8_ptr, m_ir_builder->getInt32Ty()->getPointerTo()); + m_ir_builder->CreateAlignedStore(val_i32, fpscr_i32_ptr, 4); +} + Value * Compiler::GetFpr(u32 r, u32 bits, bool as_int) { auto r_i8_ptr = m_ir_builder->CreateConstGEP1_32(m_state.args[CompileTaskState::Args::State], (unsigned int)offsetof(PPUThread, FPR[r])); if (!as_int) { diff --git a/rpcs3/Emu/Cell/PPULLVMRecompiler.h b/rpcs3/Emu/Cell/PPULLVMRecompiler.h index 8249da1c97..7d351638c7 100644 --- a/rpcs3/Emu/Cell/PPULLVMRecompiler.h +++ b/rpcs3/Emu/Cell/PPULLVMRecompiler.h @@ -869,6 +869,12 @@ namespace ppu_recompiler_llvm { /// Set USPRG0 void SetUsprg0(llvm::Value * val_x64); + /// Load FPSCR + llvm::Value * GetFpscr(); + + /// Set FPSCR + void SetFpscr(llvm::Value * val_x32); + /// Get FPR llvm::Value * GetFpr(u32 r, u32 bits = 64, bool as_int = false);