diff --git a/rpcs3/Emu/Cell/PPUInterpreter.cpp b/rpcs3/Emu/Cell/PPUInterpreter.cpp index 1347bcc08e..232fe7bb0c 100644 --- a/rpcs3/Emu/Cell/PPUInterpreter.cpp +++ b/rpcs3/Emu/Cell/PPUInterpreter.cpp @@ -1,4 +1,4 @@ -#include "stdafx.h" +#include "stdafx.h" #include "Emu/System.h" #include "PPUThread.h" #include "PPUInterpreter.h" @@ -22,7 +22,7 @@ inline void ppu_cr_set(ppu_thread& ppu, u32 field, bool le, bool gt, bool eq, bo if (UNLIKELY(g_cfg.core.ppu_debug)) { - *(u32*)(vm::g_stat_addr + ppu.cia) |= *(u32*)(u8*)(ppu.cr + field * 4); + *(u32*)(vm::g_stat_addr + ppu.cia) |= *(u32*)(ppu.cr.bits + field * 4); } } @@ -2941,7 +2941,7 @@ bool ppu_interpreter::B(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::MCRF(ppu_thread& ppu, ppu_opcode_t op) { CHECK_SIZE(ppu_thread::cr, 32); - reinterpret_cast(ppu.cr)[op.crfd] = reinterpret_cast(ppu.cr)[op.crfs]; + reinterpret_cast(+ppu.cr.bits)[op.crfd] = reinterpret_cast(+ppu.cr.bits)[op.crfs]; return true; } @@ -3237,7 +3237,7 @@ bool ppu_interpreter::MFOCRF(ppu_thread& ppu, ppu_opcode_t op) else { // MFCR - auto* lanes = reinterpret_cast*>(ppu.cr); + auto* lanes = reinterpret_cast*>(+ppu.cr.bits); const u32 mh = _mm_movemask_epi8(_mm_slli_epi64(lanes[0].value().vi, 7)); const u32 ml = _mm_movemask_epi8(_mm_slli_epi64(lanes[1].value().vi, 7)); @@ -3518,7 +3518,7 @@ bool ppu_interpreter::MTOCRF(ppu_thread& ppu, ppu_opcode_t op) const u32 n = utils::cntlz32(op.crm) & 7; const u32 p = n * 4; const u64 v = (s >> (p ^ 0x1c)) & 0xf; - *(u32*)(u8*)(ppu.cr + p) = *(u32*)(s_table + v); + *(u32*)(ppu.cr.bits + p) = *(u32*)(s_table + v); } else { @@ -3530,7 +3530,7 @@ bool ppu_interpreter::MTOCRF(ppu_thread& ppu, ppu_opcode_t op) { const u32 p = i * 4; const u64 v = (s >> (p ^ 0x1c)) & 0xf; - *(u32*)(u8*)(ppu.cr + p) = *(u32*)(s_table + v); + *(u32*)(ppu.cr.bits + p) = *(u32*)(s_table + v); } } } @@ -4673,28 +4673,46 @@ bool ppu_interpreter::FNMADDS(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::MTFSB1(ppu_thread& ppu, ppu_opcode_t op) { - LOG_WARNING(PPU, "MTFSB1"); + const u32 bit = op.crbd; + if (bit < 16 || bit > 19) LOG_WARNING(PPU, "MTFSB1(%d)", bit); + ppu.fpscr.bits[bit] = 1; if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } bool ppu_interpreter::MCRFS(ppu_thread& ppu, ppu_opcode_t op) { - LOG_WARNING(PPU, "MCRFS"); - ppu_cr_set(ppu, op.crfd, false, false, false, false); + if (op.crfs != 4) LOG_WARNING(PPU, "MCRFS(%d)", op.crfs); + reinterpret_cast(+ppu.cr.bits)[op.crfd] = reinterpret_cast(&ppu.fpscr.bits[0])[op.crfs]; return true; } bool ppu_interpreter::MTFSB0(ppu_thread& ppu, ppu_opcode_t op) { - LOG_WARNING(PPU, "MTFSB0"); + const u32 bit = op.crbd; + if (bit < 16 || bit > 19) LOG_WARNING(PPU, "MTFSB0(%d)", bit); + ppu.fpscr.bits[bit] = 0; if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } bool ppu_interpreter::MTFSFI(ppu_thread& ppu, ppu_opcode_t op) { - LOG_WARNING(PPU, "MTFSFI"); + const u32 bf = op.crfd * 4; + if (bf != 4 * 4) + { + // Do nothing on non-FPCC field (TODO) + LOG_WARNING(PPU, "MTFSFI(%d)", op.crfd); + } + else + { + u32 i = op.i; + ppu.fpscr.bits[bf + 3] = i & 1; i >>= 1; + ppu.fpscr.bits[bf + 2] = i & 1; i >>= 1; + ppu.fpscr.bits[bf + 1] = i & 1; i >>= 1; + ppu.fpscr.bits[bf + 0] = i & 1; + } + if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } @@ -4702,7 +4720,7 @@ bool ppu_interpreter::MTFSFI(ppu_thread& ppu, ppu_opcode_t op) bool ppu_interpreter::MFFS(ppu_thread& ppu, ppu_opcode_t op) { LOG_WARNING(PPU, "MFFS"); - ppu.fpr[op.frd] = 0.0; + (u64&)ppu.fpr[op.frd] = u64{ppu.fpscr.fl} << 15 | u64{ppu.fpscr.fg} << 14 | u64{ppu.fpscr.fe} << 13 | u64{ppu.fpscr.fu} << 12; if (UNLIKELY(op.rc)) ppu_cr_set(ppu, 1, ppu.fpscr.fg, ppu.fpscr.fl, ppu.fpscr.fe, ppu.fpscr.fu); return true; } @@ -4718,10 +4736,10 @@ bool ppu_interpreter::FCMPU(ppu_thread& ppu, ppu_opcode_t op) { const f64 a = ppu.fpr[op.fra]; const f64 b = ppu.fpr[op.frb]; - ppu.fpscr.fg = a > b; - ppu.fpscr.fl = a < b; - ppu.fpscr.fe = a == b; - //ppu.fpscr.fu = a != a || b != b; + u8 test_fu = ppu.fpscr.fg = a > b; + test_fu |= ppu.fpscr.fl = a < b; + test_fu |= ppu.fpscr.fe = a == b; + (u8&)ppu.fpscr.fu = test_fu ^ 1; ppu_cr_set(ppu, op.crfd, ppu.fpscr.fl, ppu.fpscr.fg, ppu.fpscr.fe, ppu.fpscr.fu); return true; } diff --git a/rpcs3/Emu/Cell/PPUThread.cpp b/rpcs3/Emu/Cell/PPUThread.cpp index bc23813dbc..e3a4c92014 100644 --- a/rpcs3/Emu/Cell/PPUThread.cpp +++ b/rpcs3/Emu/Cell/PPUThread.cpp @@ -443,7 +443,7 @@ std::string ppu_thread::dump() const for (uint i = 0; i < 32; ++i) fmt::append(ret, "FPR[%d] = %.6G\n", i, fpr[i]); for (uint i = 0; i < 32; ++i) fmt::append(ret, "VR[%d] = %s [x: %g y: %g z: %g w: %g]\n", i, vr[i], vr[i]._f[3], vr[i]._f[2], vr[i]._f[1], vr[i]._f[0]); - fmt::append(ret, "CR = 0x%08x\n", cr_pack()); + fmt::append(ret, "CR = 0x%08x\n", cr.pack()); fmt::append(ret, "LR = 0x%llx\n", lr); fmt::append(ret, "CTR = 0x%llx\n", ctr); fmt::append(ret, "VRSAVE = 0x%08x\n", vrsave); diff --git a/rpcs3/Emu/Cell/PPUThread.h b/rpcs3/Emu/Cell/PPUThread.h index a2a1f12ccb..f2ab2ed390 100644 --- a/rpcs3/Emu/Cell/PPUThread.h +++ b/rpcs3/Emu/Cell/PPUThread.h @@ -1,4 +1,4 @@ -#pragma once +#pragma once #include "Common.h" #include "../CPU/CPUThread.h" @@ -59,48 +59,65 @@ public: f64 fpr[32] = {}; // Floating Point Registers v128 vr[32] = {}; // Vector Registers - alignas(16) bool cr[32] = {}; // Condition Registers (unpacked) - - alignas(16) struct // Floating-Point Status and Control Register (unpacked) + struct cr_bits { - // TODO - bool _start[16]{}; - bool fl{}; // FPCC.FL - bool fg{}; // FPCC.FG - bool fe{}; // FPCC.FE - bool fu{}; // FPCC.FU - bool _end[12]{}; + alignas(16) u8 bits[32]; + + u8& operator [](std::size_t i) + { + return bits[i]; + } + + // Pack CR bits + u32 pack() const + { + u32 result{}; + + for (u32 bit : bits) + { + result <<= 1; + result |= bit; + } + + return result; + } + + // Unpack CR bits + void unpack(u32 value) + { + for (u8& b : bits) + { + b = value & 0x1; + value >>= 1; + } + } + }; + + cr_bits cr{}; // Condition Registers (unpacked) + + // Floating-Point Status and Control Register (unpacked) + union + { + struct + { + // TODO + bool _start[16]; + bool fl; // FPCC.FL + bool fg; // FPCC.FG + bool fe; // FPCC.FE + bool fu; // FPCC.FU + bool _end[12]; + }; + + cr_bits bits; } - fpscr; + fpscr{}; u64 lr{}; // Link Register u64 ctr{}; // Counter Register u32 vrsave{0xffffffff}; // VR Save Register u32 cia{}; // Current Instruction Address - // Pack CR bits - u32 cr_pack() const - { - u32 result{}; - - for (u32 bit : cr) - { - result = (result << 1) | bit; - } - - return result; - } - - // Unpack CR bits - void cr_unpack(u32 value) - { - for (bool& b : cr) - { - b = (value & 0x1) != 0; - value >>= 1; - } - } - // Fixed-Point Exception Register (abstract representation) struct { diff --git a/rpcs3/rpcs3qt/register_editor_dialog.cpp b/rpcs3/rpcs3qt/register_editor_dialog.cpp index bf51d76173..263d312907 100644 --- a/rpcs3/rpcs3qt/register_editor_dialog.cpp +++ b/rpcs3/rpcs3qt/register_editor_dialog.cpp @@ -1,4 +1,4 @@ - + #include "register_editor_dialog.h" constexpr auto qstr = QString::fromStdString; @@ -105,7 +105,7 @@ void register_editor_dialog::updateRegister(const QString& text) if (reg.compare(0, 3, "FPR") == 0) str = fmt::format("%016llx", ppu.fpr[reg_index]); if (reg.compare(0, 2, "VR") == 0) str = fmt::format("%016llx%016llx", ppu.vr[reg_index]._u64[1], ppu.vr[reg_index]._u64[0]); } - if (reg == "CR") str = fmt::format("%08x", ppu.cr_pack()); + if (reg == "CR") str = fmt::format("%08x", ppu.cr.pack()); if (reg == "LR") str = fmt::format("%016llx", ppu.lr); if (reg == "CTR") str = fmt::format("%016llx", ppu.ctr); } @@ -169,7 +169,7 @@ void register_editor_dialog::OnOkay(const std::shared_ptr& _cpu) if (reg == "CR") { const ullong reg_value = std::stoull(value.substr(24, 31), 0, 16); - if (reg == "CR") ppu.cr_unpack((u32)reg_value); + if (reg == "CR") ppu.cr.unpack((u32)reg_value); return; } }