1
0
mirror of https://github.com/RPCS3/rpcs3.git synced 2025-01-31 20:41:45 +01:00

ppu interpreter: Improve FPCC field handling

This commit is contained in:
eladash 2019-03-19 10:20:02 +02:00 committed by Ivan
parent aa44ef1f44
commit e21504d52d
4 changed files with 90 additions and 55 deletions

View File

@ -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<u32*>(ppu.cr)[op.crfd] = reinterpret_cast<u32*>(ppu.cr)[op.crfs];
reinterpret_cast<u32*>(+ppu.cr.bits)[op.crfd] = reinterpret_cast<u32*>(+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<be_t<v128>*>(ppu.cr);
auto* lanes = reinterpret_cast<be_t<v128>*>(+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<u32*>(+ppu.cr.bits)[op.crfd] = reinterpret_cast<u32*>(&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;
}

View File

@ -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);

View File

@ -1,4 +1,4 @@
#pragma once
#pragma once
#include "Common.h"
#include "../CPU/CPUThread.h"
@ -59,47 +59,64 @@ 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]{};
}
fpscr;
alignas(16) u8 bits[32];
u64 lr{}; // Link Register
u64 ctr{}; // Counter Register
u32 vrsave{0xffffffff}; // VR Save Register
u32 cia{}; // Current Instruction Address
u8& operator [](std::size_t i)
{
return bits[i];
}
// Pack CR bits
u32 cr_pack() const
u32 pack() const
{
u32 result{};
for (u32 bit : cr)
for (u32 bit : bits)
{
result = (result << 1) | bit;
result <<= 1;
result |= bit;
}
return result;
}
// Unpack CR bits
void cr_unpack(u32 value)
void unpack(u32 value)
{
for (bool& b : cr)
for (u8& b : bits)
{
b = (value & 0x1) != 0;
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{};
u64 lr{}; // Link Register
u64 ctr{}; // Counter Register
u32 vrsave{0xffffffff}; // VR Save Register
u32 cia{}; // Current Instruction Address
// Fixed-Point Exception Register (abstract representation)
struct

View File

@ -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_thread>& _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;
}
}