Misc: Combine some redundant functions

This commit is contained in:
Stenzek 2023-12-13 20:56:24 +10:00
parent 68d3cb5b4a
commit bc2c334370
No known key found for this signature in database
6 changed files with 326 additions and 261 deletions

View file

@ -10,11 +10,11 @@
#include "cpu_code_cache_private.h" #include "cpu_code_cache_private.h"
#include "cpu_core_private.h" #include "cpu_core_private.h"
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "cpu_pgxp.h"
#include "cpu_recompiler_thunks.h" #include "cpu_recompiler_thunks.h"
#include "gte.h" #include "gte.h"
#include "host.h" #include "host.h"
#include "pcdrv.h" #include "pcdrv.h"
#include "cpu_pgxp.h"
#include "settings.h" #include "settings.h"
#include "system.h" #include "system.h"
#include "timing_event.h" #include "timing_event.h"
@ -920,236 +920,250 @@ restart_instruction:
{ {
case InstructionFunct::sll: case InstructionFunct::sll:
{ {
const u32 new_value = ReadReg(inst.r.rt) << inst.r.shamt; const u32 rtVal = ReadReg(inst.r.rt);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rdVal = rtVal << inst.r.shamt;
PGXP::CPU_SLL(inst.bits, ReadReg(inst.r.rt)); WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLL(inst.bits, rtVal);
} }
break; break;
case InstructionFunct::srl: case InstructionFunct::srl:
{ {
const u32 new_value = ReadReg(inst.r.rt) >> inst.r.shamt; const u32 rtVal = ReadReg(inst.r.rt);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rdVal = rtVal >> inst.r.shamt;
PGXP::CPU_SRL(inst.bits, ReadReg(inst.r.rt)); WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SRL(inst.bits, rtVal);
} }
break; break;
case InstructionFunct::sra: case InstructionFunct::sra:
{ {
const u32 new_value = static_cast<u32>(static_cast<s32>(ReadReg(inst.r.rt)) >> inst.r.shamt); const u32 rtVal = ReadReg(inst.r.rt);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> inst.r.shamt);
PGXP::CPU_SRA(inst.bits, ReadReg(inst.r.rt)); WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SRA(inst.bits, rtVal);
} }
break; break;
case InstructionFunct::sllv: case InstructionFunct::sllv:
{ {
const u32 shift_amount = ReadReg(inst.r.rs) & UINT32_C(0x1F); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = ReadReg(inst.r.rt) << shift_amount; const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F);
const u32 rdVal = rtVal << shamt;
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLLV(inst.bits, ReadReg(inst.r.rt), shift_amount); PGXP::CPU_SLLV(inst.bits, rtVal, shamt);
WriteReg(inst.r.rd, new_value); WriteReg(inst.r.rd, rdVal);
} }
break; break;
case InstructionFunct::srlv: case InstructionFunct::srlv:
{ {
const u32 shift_amount = ReadReg(inst.r.rs) & UINT32_C(0x1F); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = ReadReg(inst.r.rt) >> shift_amount; const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rdVal = rtVal >> shamt;
PGXP::CPU_SRLV(inst.bits, ReadReg(inst.r.rt), shift_amount); WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SRLV(inst.bits, rtVal, shamt);
} }
break; break;
case InstructionFunct::srav: case InstructionFunct::srav:
{ {
const u32 shift_amount = ReadReg(inst.r.rs) & UINT32_C(0x1F); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = static_cast<u32>(static_cast<s32>(ReadReg(inst.r.rt)) >> shift_amount); const u32 shamt = ReadReg(inst.r.rs) & UINT32_C(0x1F);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rdVal = static_cast<u32>(static_cast<s32>(rtVal) >> shamt);
PGXP::CPU_SRAV(inst.bits, ReadReg(inst.r.rt), shift_amount); WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SRAV(inst.bits, rtVal, shamt);
} }
break; break;
case InstructionFunct::and_: case InstructionFunct::and_:
{ {
const u32 new_value = ReadReg(inst.r.rs) & ReadReg(inst.r.rt); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_AND_(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 new_value = rsVal & rtVal;
WriteReg(inst.r.rd, new_value); WriteReg(inst.r.rd, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_AND_(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::or_: case InstructionFunct::or_:
{ {
const u32 new_value = ReadReg(inst.r.rs) | ReadReg(inst.r.rt); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_OR_(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 new_value = rsVal | rtVal;
WriteReg(inst.r.rd, new_value); WriteReg(inst.r.rd, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_OR_(inst.bits, rsVal, rtVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory)
PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt);
} }
break; break;
case InstructionFunct::xor_: case InstructionFunct::xor_:
{ {
const u32 new_value = ReadReg(inst.r.rs) ^ ReadReg(inst.r.rt); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_XOR_(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 new_value = rsVal ^ rtVal;
WriteReg(inst.r.rd, new_value); WriteReg(inst.r.rd, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_XOR_(inst.bits, rsVal, rtVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory)
PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt);
} }
break; break;
case InstructionFunct::nor: case InstructionFunct::nor:
{ {
const u32 new_value = ~(ReadReg(inst.r.rs) | ReadReg(inst.r.rt)); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_NOR(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 new_value = ~(rsVal | rtVal);
WriteReg(inst.r.rd, new_value); WriteReg(inst.r.rd, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_NOR(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::add: case InstructionFunct::add:
{ {
const u32 old_value = ReadReg(inst.r.rs); const u32 rsVal = ReadReg(inst.r.rs);
const u32 add_value = ReadReg(inst.r.rt); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = old_value + add_value; const u32 rdVal = rsVal + rtVal;
if (AddOverflow(old_value, add_value, new_value)) if (AddOverflow(rsVal, rtVal, rdVal))
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
} }
WriteReg(inst.r.rd, rdVal);
if constexpr (pgxp_mode == PGXPMode::CPU) if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_ADD(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); PGXP::CPU_ADD(inst.bits, rsVal, rtVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory) else if constexpr (pgxp_mode >= PGXPMode::Memory)
{ PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt);
if (add_value == 0)
{
PGXP::CPU_MOVE((static_cast<u32>(inst.r.rd.GetValue()) << 8) | static_cast<u32>(inst.r.rs.GetValue()),
old_value);
}
}
WriteReg(inst.r.rd, new_value);
} }
break; break;
case InstructionFunct::addu: case InstructionFunct::addu:
{ {
const u32 old_value = ReadReg(inst.r.rs); const u32 rsVal = ReadReg(inst.r.rs);
const u32 add_value = ReadReg(inst.r.rt); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = old_value + add_value; const u32 rdVal = rsVal + rtVal;
WriteReg(inst.r.rd, rdVal);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_ADD(inst.bits, old_value, add_value); PGXP::CPU_ADD(inst.bits, rsVal, rtVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory) else if constexpr (pgxp_mode >= PGXPMode::Memory)
{ PGXP::TryMove(inst.r.rd, inst.r.rs, inst.r.rt);
if (add_value == 0)
{
PGXP::CPU_MOVE((static_cast<u32>(inst.r.rd.GetValue()) << 8) | static_cast<u32>(inst.r.rs.GetValue()),
old_value);
}
}
WriteReg(inst.r.rd, new_value);
} }
break; break;
case InstructionFunct::sub: case InstructionFunct::sub:
{ {
const u32 old_value = ReadReg(inst.r.rs); const u32 rsVal = ReadReg(inst.r.rs);
const u32 sub_value = ReadReg(inst.r.rt); const u32 rtVal = ReadReg(inst.r.rt);
const u32 new_value = old_value - sub_value; const u32 rdVal = rsVal - rtVal;
if (SubOverflow(old_value, sub_value, new_value)) if (SubOverflow(rsVal, rtVal, rdVal))
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
} }
if constexpr (pgxp_mode >= PGXPMode::CPU) WriteReg(inst.r.rd, rdVal);
PGXP::CPU_SUB(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt));
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SUB(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::subu: case InstructionFunct::subu:
{ {
const u32 new_value = ReadReg(inst.r.rs) - ReadReg(inst.r.rt); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_SUB(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 rdVal = rsVal - rtVal;
WriteReg(inst.r.rd, rdVal);
WriteReg(inst.r.rd, new_value); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SUB(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::slt: case InstructionFunct::slt:
{ {
const u32 result = BoolToUInt32(static_cast<s32>(ReadReg(inst.r.rs)) < static_cast<s32>(ReadReg(inst.r.rt))); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_SLT(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 result = BoolToUInt32(static_cast<s32>(rsVal) < static_cast<s32>(rtVal));
WriteReg(inst.r.rd, result); WriteReg(inst.r.rd, result);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLT(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::sltu: case InstructionFunct::sltu:
{ {
const u32 result = BoolToUInt32(ReadReg(inst.r.rs) < ReadReg(inst.r.rt)); const u32 rsVal = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 rtVal = ReadReg(inst.r.rt);
PGXP::CPU_SLTU(inst.bits, ReadReg(inst.r.rs), ReadReg(inst.r.rt)); const u32 result = BoolToUInt32(rsVal < rtVal);
WriteReg(inst.r.rd, result); WriteReg(inst.r.rd, result);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLTU(inst.bits, rsVal, rtVal);
} }
break; break;
case InstructionFunct::mfhi: case InstructionFunct::mfhi:
{ {
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 value = g_state.regs.hi;
PGXP::CPU_MFHI(inst.bits, g_state.regs.hi); WriteReg(inst.r.rd, value);
WriteReg(inst.r.rd, g_state.regs.hi); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::hi), value);
} }
break; break;
case InstructionFunct::mthi: case InstructionFunct::mthi:
{ {
const u32 value = ReadReg(inst.r.rs); const u32 value = ReadReg(inst.r.rs);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MTHI(inst.bits, value);
g_state.regs.hi = value; g_state.regs.hi = value;
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MOVE(static_cast<u32>(Reg::hi), static_cast<u32>(inst.r.rs.GetValue()), value);
} }
break; break;
case InstructionFunct::mflo: case InstructionFunct::mflo:
{ {
if constexpr (pgxp_mode >= PGXPMode::CPU) const u32 value = g_state.regs.lo;
PGXP::CPU_MFLO(inst.bits, g_state.regs.lo); WriteReg(inst.r.rd, value);
WriteReg(inst.r.rd, g_state.regs.lo); if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MOVE(static_cast<u32>(inst.r.rd.GetValue()), static_cast<u32>(Reg::lo), value);
} }
break; break;
case InstructionFunct::mtlo: case InstructionFunct::mtlo:
{ {
const u32 value = ReadReg(inst.r.rs); const u32 value = ReadReg(inst.r.rs);
if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_MTLO(inst.bits, value);
g_state.regs.lo = value; g_state.regs.lo = value;
if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_MOVE(static_cast<u32>(Reg::lo), static_cast<u32>(inst.r.rs.GetValue()), value);
} }
break; break;
@ -1174,11 +1188,11 @@ restart_instruction:
const u32 rhs = ReadReg(inst.r.rt); const u32 rhs = ReadReg(inst.r.rt);
const u64 result = ZeroExtend64(lhs) * ZeroExtend64(rhs); const u64 result = ZeroExtend64(lhs) * ZeroExtend64(rhs);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MULTU(inst.bits, lhs, rhs);
g_state.regs.hi = Truncate32(result >> 32); g_state.regs.hi = Truncate32(result >> 32);
g_state.regs.lo = Truncate32(result); g_state.regs.lo = Truncate32(result);
if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_MULTU(inst.bits, lhs, rhs);
} }
break; break;
@ -1285,103 +1299,95 @@ restart_instruction:
case InstructionOp::andi: case InstructionOp::andi:
{ {
const u32 new_value = ReadReg(inst.i.rs) & inst.i.imm_zext32(); const u32 rsVal = ReadReg(inst.i.rs);
const u32 new_value = rsVal & inst.i.imm_zext32();
WriteReg(inst.i.rt, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_ANDI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_ANDI(inst.bits, rsVal);
WriteReg(inst.i.rt, new_value);
} }
break; break;
case InstructionOp::ori: case InstructionOp::ori:
{ {
const u32 new_value = ReadReg(inst.i.rs) | inst.i.imm_zext32(); const u32 rsVal = ReadReg(inst.i.rs);
const u32 imm = inst.i.imm_zext32();
const u32 rtVal = rsVal | imm;
WriteReg(inst.i.rt, rtVal);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_ORI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_ORI(inst.bits, rsVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory)
WriteReg(inst.i.rt, new_value); PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm);
} }
break; break;
case InstructionOp::xori: case InstructionOp::xori:
{ {
const u32 new_value = ReadReg(inst.i.rs) ^ inst.i.imm_zext32(); const u32 rsVal = ReadReg(inst.i.rs);
const u32 imm = inst.i.imm_zext32();
const u32 new_value = ReadReg(inst.i.rs) ^ imm;
WriteReg(inst.i.rt, new_value);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_XORI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_XORI(inst.bits, rsVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory)
WriteReg(inst.i.rt, new_value); PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm);
} }
break; break;
case InstructionOp::addi: case InstructionOp::addi:
{ {
const u32 old_value = ReadReg(inst.i.rs); const u32 rsVal = ReadReg(inst.i.rs);
const u32 add_value = inst.i.imm_sext32(); const u32 imm = inst.i.imm_sext32();
const u32 new_value = old_value + add_value; const u32 rtVal = rsVal + imm;
if (AddOverflow(old_value, add_value, new_value)) if (AddOverflow(rsVal, imm, rtVal))
{ {
RaiseException(Exception::Ov); RaiseException(Exception::Ov);
return; return;
} }
WriteReg(inst.i.rt, rtVal);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_ADDI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_ADDI(inst.bits, rsVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory) else if constexpr (pgxp_mode >= PGXPMode::Memory)
{ PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm);
if (add_value == 0)
{
PGXP::CPU_MOVE((static_cast<u32>(inst.i.rt.GetValue()) << 8) | static_cast<u32>(inst.i.rs.GetValue()),
old_value);
}
}
WriteReg(inst.i.rt, new_value);
} }
break; break;
case InstructionOp::addiu: case InstructionOp::addiu:
{ {
const u32 old_value = ReadReg(inst.i.rs); const u32 rsVal = ReadReg(inst.i.rs);
const u32 add_value = inst.i.imm_sext32(); const u32 imm = inst.i.imm_sext32();
const u32 new_value = old_value + add_value; const u32 rtVal = rsVal + imm;
WriteReg(inst.i.rt, rtVal);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_ADDI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_ADDI(inst.bits, rsVal);
else if constexpr (pgxp_mode >= PGXPMode::Memory) else if constexpr (pgxp_mode >= PGXPMode::Memory)
{ PGXP::TryMoveImm(inst.r.rd, inst.r.rs, imm);
if (add_value == 0)
{
PGXP::CPU_MOVE((static_cast<u32>(inst.i.rt.GetValue()) << 8) | static_cast<u32>(inst.i.rs.GetValue()),
old_value);
}
}
WriteReg(inst.i.rt, new_value);
} }
break; break;
case InstructionOp::slti: case InstructionOp::slti:
{ {
const u32 result = BoolToUInt32(static_cast<s32>(ReadReg(inst.i.rs)) < static_cast<s32>(inst.i.imm_sext32())); const u32 rsVal = ReadReg(inst.i.rs);
const u32 result = BoolToUInt32(static_cast<s32>(rsVal) < static_cast<s32>(inst.i.imm_sext32()));
WriteReg(inst.i.rt, result);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLTI(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_SLTI(inst.bits, rsVal);
WriteReg(inst.i.rt, result);
} }
break; break;
case InstructionOp::sltiu: case InstructionOp::sltiu:
{ {
const u32 result = BoolToUInt32(ReadReg(inst.i.rs) < inst.i.imm_sext32()); const u32 result = BoolToUInt32(ReadReg(inst.i.rs) < inst.i.imm_sext32());
WriteReg(inst.i.rt, result);
if constexpr (pgxp_mode >= PGXPMode::CPU) if constexpr (pgxp_mode >= PGXPMode::CPU)
PGXP::CPU_SLTIU(inst.bits, ReadReg(inst.i.rs)); PGXP::CPU_SLTIU(inst.bits, ReadReg(inst.i.rs));
WriteReg(inst.i.rt, result);
} }
break; break;
@ -1671,20 +1677,20 @@ restart_instruction:
case CopCommonInstruction::mfcn: case CopCommonInstruction::mfcn:
{ {
const u32 value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())); const u32 value = ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()));
WriteRegDelayed(inst.r.rt, value);
if constexpr (pgxp_mode == PGXPMode::CPU) if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_MFC0(inst.bits, value); PGXP::CPU_MFC0(inst.bits, value);
WriteRegDelayed(inst.r.rt, value);
} }
break; break;
case CopCommonInstruction::mtcn: case CopCommonInstruction::mtcn:
{ {
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), ReadReg(inst.r.rt)); const u32 rtVal = ReadReg(inst.r.rt);
WriteCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue()), rtVal);
if constexpr (pgxp_mode == PGXPMode::CPU) if constexpr (pgxp_mode == PGXPMode::CPU)
PGXP::CPU_MTC0(inst.bits, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())), ReadReg(inst.i.rt)); PGXP::CPU_MTC0(inst.bits, ReadCop0Reg(static_cast<Cop0Reg>(inst.r.rd.GetValue())), rtVal);
} }
break; break;
@ -2380,7 +2386,6 @@ void CPU::CodeCache::InterpretUncachedBlock()
break; break;
} }
in_branch_delay_slot = branch; in_branch_delay_slot = branch;
} }
} }
@ -2930,8 +2935,7 @@ bool CPU::SafeWriteMemoryWord(VirtualMemoryAddress addr, u32 value)
if ((addr & 3) == 0) if ((addr & 3) == 0)
return DoSafeMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value); return DoSafeMemoryAccess<MemoryAccessType::Write, MemoryAccessSize::Word>(addr, value);
return SafeWriteMemoryHalfWord(addr, Truncate16(value)) && return SafeWriteMemoryHalfWord(addr, Truncate16(value)) && SafeWriteMemoryHalfWord(addr + 2, Truncate16(value >> 16));
SafeWriteMemoryHalfWord(addr + 2, Truncate16(value >> 16));
} }
void* CPU::GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks) void* CPU::GetDirectReadMemoryPointer(VirtualMemoryAddress address, MemoryAccessSize size, TickCount* read_ticks)

View file

@ -52,13 +52,13 @@ struct PGXP_value
float x; float x;
float y; float y;
float z; float z;
u32 value;
union union
{ {
u32 flags; u32 flags;
u8 compFlags[4]; u8 compFlags[4];
u16 halfFlags[2]; u16 halfFlags[2];
}; };
u32 value;
}; };
struct State struct State
@ -107,9 +107,7 @@ struct State
std::array<u8, SCRATCHPAD_SIZE> scratchpad = {}; std::array<u8, SCRATCHPAD_SIZE> scratchpad = {};
PGXP_value pgxp_gpr[32]; PGXP_value pgxp_gpr[static_cast<u8>(Reg::count)];
PGXP_value pgxp_hi;
PGXP_value pgxp_lo;
PGXP_value pgxp_cop0[32]; PGXP_value pgxp_cop0[32];
PGXP_value pgxp_gte[64]; PGXP_value pgxp_gte[64];

View file

@ -1728,8 +1728,8 @@ void CPU::NewRec::Compiler::CompileMoveRegTemplate(Reg dst, Reg src, bool pgxp_m
if (g_settings.gpu_pgxp_enable && pgxp_move) if (g_settings.gpu_pgxp_enable && pgxp_move)
{ {
// might've been renamed, so use dst here // might've been renamed, so use dst here
GeneratePGXPCallWithMIPSRegs(reinterpret_cast<const void*>(&PGXP::CPU_MOVE), GeneratePGXPCallWithMIPSRegs(reinterpret_cast<const void*>(&PGXP::CPU_MOVE_Packed), PGXP::PackMoveArgs(dst, src),
(static_cast<u32>(dst) << 8) | (static_cast<u32>(src)), dst); dst);
} }
} }

View file

@ -79,8 +79,8 @@ static void CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVal, u32 rtVal);
static void WriteMem(const PGXP_value* value, u32 addr); static void WriteMem(const PGXP_value* value, u32 addr);
static void WriteMem16(const PGXP_value* src, u32 addr); static void WriteMem16(const PGXP_value* src, u32 addr);
static const PGXP_value PGXP_value_invalid = {0.f, 0.f, 0.f, {0}, 0}; static const PGXP_value PGXP_value_invalid = {0.f, 0.f, 0.f, 0, {0}};
static const PGXP_value PGXP_value_zero = {0.f, 0.f, 0.f, {VALID_ALL}, 0}; static const PGXP_value PGXP_value_zero = {0.f, 0.f, 0.f, 0, {VALID_ALL}};
static PGXP_value* s_mem = nullptr; static PGXP_value* s_mem = nullptr;
static PGXP_value* s_vertex_cache = nullptr; static PGXP_value* s_vertex_cache = nullptr;
@ -568,11 +568,17 @@ void CPU::PGXP::CPU_SW(u32 instr, u32 addr, u32 rtVal)
WriteMem(val, addr); WriteMem(val, addr);
} }
void CPU::PGXP::CPU_MOVE(u32 rd_and_rs, u32 rsVal) void CPU::PGXP::CPU_MOVE_Packed(u32 rd_and_rs, u32 rsVal)
{ {
const u32 Rs = (rd_and_rs & 0xFFu); const u32 Rs = (rd_and_rs & 0xFFu);
const u32 Rd = (rd_and_rs >> 8);
CPU_MOVE(Rd, Rs, rsVal);
}
void CPU::PGXP::CPU_MOVE(u32 Rd, u32 Rs, u32 rsVal)
{
Validate(&g_state.pgxp_gpr[Rs], rsVal); Validate(&g_state.pgxp_gpr[Rs], rsVal);
g_state.pgxp_gpr[(rd_and_rs >> 8)] = g_state.pgxp_gpr[Rs]; g_state.pgxp_gpr[Rd] = g_state.pgxp_gpr[Rs];
} }
void CPU::PGXP::CPU_ADDI(u32 instr, u32 rsVal) void CPU::PGXP::CPU_ADDI(u32 instr, u32 rsVal)
@ -1031,9 +1037,9 @@ void CPU::PGXP::CPU_MULT(u32 instr, u32 rsVal, u32 rtVal)
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal); MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
} }
g_state.pgxp_lo = g_state.pgxp_hi = g_state.pgxp_gpr[rs(instr)]; g_state.pgxp_gpr[static_cast<u8>(Reg::lo)] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)] = g_state.pgxp_gpr[rs(instr)];
g_state.pgxp_lo.halfFlags[0] = g_state.pgxp_hi.halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].halfFlags[0] =
(g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]); (g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]);
double xx, xy, yx, yy; double xx, xy, yx, yy;
@ -1056,15 +1062,15 @@ void CPU::PGXP::CPU_MULT(u32 instr, u32 rsVal, u32 rtVal)
hy = f16Overflow(hx); hy = f16Overflow(hx);
g_state.pgxp_lo.x = (float)f16Sign(lx); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].x = (float)f16Sign(lx);
g_state.pgxp_lo.y = (float)f16Sign(ly); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].y = (float)f16Sign(ly);
g_state.pgxp_hi.x = (float)f16Sign(hx); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].x = (float)f16Sign(hx);
g_state.pgxp_hi.y = (float)f16Sign(hy); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].y = (float)f16Sign(hy);
// compute PSX value // compute PSX value
const u64 result = static_cast<u64>(static_cast<s64>(SignExtend64(rsVal)) * static_cast<s64>(SignExtend64(rtVal))); const u64 result = static_cast<u64>(static_cast<s64>(SignExtend64(rsVal)) * static_cast<s64>(SignExtend64(rtVal)));
g_state.pgxp_hi.value = Truncate32(result >> 32); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = Truncate32(result >> 32);
g_state.pgxp_lo.value = Truncate32(result); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value = Truncate32(result);
} }
void CPU::PGXP::CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal) void CPU::PGXP::CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
@ -1081,9 +1087,9 @@ void CPU::PGXP::CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal); MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
} }
g_state.pgxp_lo = g_state.pgxp_hi = g_state.pgxp_gpr[rs(instr)]; g_state.pgxp_gpr[static_cast<u8>(Reg::lo)] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)] = g_state.pgxp_gpr[rs(instr)];
g_state.pgxp_lo.halfFlags[0] = g_state.pgxp_hi.halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].halfFlags[0] =
(g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]); (g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]);
double xx, xy, yx, yy; double xx, xy, yx, yy;
@ -1106,15 +1112,15 @@ void CPU::PGXP::CPU_MULTU(u32 instr, u32 rsVal, u32 rtVal)
hy = f16Overflow(hx); hy = f16Overflow(hx);
g_state.pgxp_lo.x = (float)f16Sign(lx); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].x = (float)f16Sign(lx);
g_state.pgxp_lo.y = (float)f16Sign(ly); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].y = (float)f16Sign(ly);
g_state.pgxp_hi.x = (float)f16Sign(hx); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].x = (float)f16Sign(hx);
g_state.pgxp_hi.y = (float)f16Sign(hy); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].y = (float)f16Sign(hy);
// compute PSX value // compute PSX value
const u64 result = ZeroExtend64(rsVal) * ZeroExtend64(rtVal); const u64 result = ZeroExtend64(rsVal) * ZeroExtend64(rtVal);
g_state.pgxp_hi.value = Truncate32(result >> 32); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = Truncate32(result >> 32);
g_state.pgxp_lo.value = Truncate32(result); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value = Truncate32(result);
} }
void CPU::PGXP::CPU_DIV(u32 instr, u32 rsVal, u32 rtVal) void CPU::PGXP::CPU_DIV(u32 instr, u32 rsVal, u32 rtVal)
@ -1132,39 +1138,42 @@ void CPU::PGXP::CPU_DIV(u32 instr, u32 rsVal, u32 rtVal)
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal); MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
} }
g_state.pgxp_lo = g_state.pgxp_hi = g_state.pgxp_gpr[rs(instr)]; g_state.pgxp_gpr[static_cast<u8>(Reg::lo)] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)] = g_state.pgxp_gpr[rs(instr)];
g_state.pgxp_lo.halfFlags[0] = g_state.pgxp_hi.halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].halfFlags[0] =
(g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]); (g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]);
double vs = f16Unsign(g_state.pgxp_gpr[rs(instr)].x) + (g_state.pgxp_gpr[rs(instr)].y) * (double)(1 << 16); double vs = f16Unsign(g_state.pgxp_gpr[rs(instr)].x) + (g_state.pgxp_gpr[rs(instr)].y) * (double)(1 << 16);
double vt = f16Unsign(g_state.pgxp_gpr[rt(instr)].x) + (g_state.pgxp_gpr[rt(instr)].y) * (double)(1 << 16); double vt = f16Unsign(g_state.pgxp_gpr[rt(instr)].x) + (g_state.pgxp_gpr[rt(instr)].y) * (double)(1 << 16);
double lo = vs / vt; double lo = vs / vt;
g_state.pgxp_lo.y = (float)f16Sign(f16Overflow(lo)); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].y = (float)f16Sign(f16Overflow(lo));
g_state.pgxp_lo.x = (float)f16Sign(lo); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].x = (float)f16Sign(lo);
double hi = fmod(vs, vt); double hi = fmod(vs, vt);
g_state.pgxp_hi.y = (float)f16Sign(f16Overflow(hi)); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].y = (float)f16Sign(f16Overflow(hi));
g_state.pgxp_hi.x = (float)f16Sign(hi); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].x = (float)f16Sign(hi);
// compute PSX value // compute PSX value
if (static_cast<s32>(rtVal) == 0) if (static_cast<s32>(rtVal) == 0)
{ {
// divide by zero // divide by zero
g_state.pgxp_lo.value = (static_cast<s32>(rsVal) >= 0) ? UINT32_C(0xFFFFFFFF) : UINT32_C(1); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value =
g_state.pgxp_hi.value = static_cast<u32>(static_cast<s32>(rsVal)); (static_cast<s32>(rsVal) >= 0) ? UINT32_C(0xFFFFFFFF) : UINT32_C(1);
g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = static_cast<u32>(static_cast<s32>(rsVal));
} }
else if (rsVal == UINT32_C(0x80000000) && static_cast<s32>(rtVal) == -1) else if (rsVal == UINT32_C(0x80000000) && static_cast<s32>(rtVal) == -1)
{ {
// unrepresentable // unrepresentable
g_state.pgxp_lo.value = UINT32_C(0x80000000); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value = UINT32_C(0x80000000);
g_state.pgxp_hi.value = 0; g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = 0;
} }
else else
{ {
g_state.pgxp_lo.value = static_cast<u32>(static_cast<s32>(rsVal) / static_cast<s32>(rtVal)); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value =
g_state.pgxp_hi.value = static_cast<u32>(static_cast<s32>(rsVal) % static_cast<s32>(rtVal)); static_cast<u32>(static_cast<s32>(rsVal) / static_cast<s32>(rtVal));
g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value =
static_cast<u32>(static_cast<s32>(rsVal) % static_cast<s32>(rtVal));
} }
} }
@ -1183,32 +1192,32 @@ void CPU::PGXP::CPU_DIVU(u32 instr, u32 rsVal, u32 rtVal)
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal); MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
} }
g_state.pgxp_lo = g_state.pgxp_hi = g_state.pgxp_gpr[rs(instr)]; g_state.pgxp_gpr[static_cast<u8>(Reg::lo)] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)] = g_state.pgxp_gpr[rs(instr)];
g_state.pgxp_lo.halfFlags[0] = g_state.pgxp_hi.halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].halfFlags[0] = g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].halfFlags[0] =
(g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]); (g_state.pgxp_gpr[rs(instr)].halfFlags[0] & g_state.pgxp_gpr[rt(instr)].halfFlags[0]);
double vs = f16Unsign(g_state.pgxp_gpr[rs(instr)].x) + f16Unsign(g_state.pgxp_gpr[rs(instr)].y) * (double)(1 << 16); double vs = f16Unsign(g_state.pgxp_gpr[rs(instr)].x) + f16Unsign(g_state.pgxp_gpr[rs(instr)].y) * (double)(1 << 16);
double vt = f16Unsign(g_state.pgxp_gpr[rt(instr)].x) + f16Unsign(g_state.pgxp_gpr[rt(instr)].y) * (double)(1 << 16); double vt = f16Unsign(g_state.pgxp_gpr[rt(instr)].x) + f16Unsign(g_state.pgxp_gpr[rt(instr)].y) * (double)(1 << 16);
double lo = vs / vt; double lo = vs / vt;
g_state.pgxp_lo.y = (float)f16Sign(f16Overflow(lo)); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].y = (float)f16Sign(f16Overflow(lo));
g_state.pgxp_lo.x = (float)f16Sign(lo); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].x = (float)f16Sign(lo);
double hi = fmod(vs, vt); double hi = fmod(vs, vt);
g_state.pgxp_hi.y = (float)f16Sign(f16Overflow(hi)); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].y = (float)f16Sign(f16Overflow(hi));
g_state.pgxp_hi.x = (float)f16Sign(hi); g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].x = (float)f16Sign(hi);
if (rtVal == 0) if (rtVal == 0)
{ {
// divide by zero // divide by zero
g_state.pgxp_lo.value = UINT32_C(0xFFFFFFFF); g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value = UINT32_C(0xFFFFFFFF);
g_state.pgxp_hi.value = rsVal; g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = rsVal;
} }
else else
{ {
g_state.pgxp_lo.value = rsVal / rtVal; g_state.pgxp_gpr[static_cast<u8>(Reg::lo)].value = rsVal / rtVal;
g_state.pgxp_hi.value = rsVal % rtVal; g_state.pgxp_gpr[static_cast<u8>(Reg::hi)].value = rsVal % rtVal;
} }
} }
@ -1575,38 +1584,6 @@ void CPU::PGXP::CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal)
g_state.pgxp_gpr[rd(instr)] = ret; g_state.pgxp_gpr[rd(instr)] = ret;
} }
void CPU::PGXP::CPU_MFHI(u32 instr, u32 hiVal)
{
// Rd = Hi
Validate(&g_state.pgxp_hi, hiVal);
g_state.pgxp_gpr[rd(instr)] = g_state.pgxp_hi;
}
void CPU::PGXP::CPU_MTHI(u32 instr, u32 rsVal)
{
// Hi = Rd
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
g_state.pgxp_hi = g_state.pgxp_gpr[rd(instr)];
}
void CPU::PGXP::CPU_MFLO(u32 instr, u32 loVal)
{
// Rd = Lo
Validate(&g_state.pgxp_lo, loVal);
g_state.pgxp_gpr[rd(instr)] = g_state.pgxp_lo;
}
void CPU::PGXP::CPU_MTLO(u32 instr, u32 rsVal)
{
// Lo = Rd
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
g_state.pgxp_lo = g_state.pgxp_gpr[rd(instr)];
}
void CPU::PGXP::CPU_MFC0(u32 instr, u32 rdVal) void CPU::PGXP::CPU_MFC0(u32 instr, u32 rdVal)
{ {
// CPU[Rt] = CP0[Rd] // CPU[Rt] = CP0[Rd]

View file

@ -2,7 +2,7 @@
// SPDX-License-Identifier: GPL-2.0+ // SPDX-License-Identifier: GPL-2.0+
#pragma once #pragma once
#include "types.h" #include "cpu_core.h"
namespace CPU::PGXP { namespace CPU::PGXP {
@ -34,7 +34,13 @@ void CPU_LBx(u32 instr, u32 addr, u32 rtVal);
void CPU_SB(u32 instr, u32 addr, u32 rtVal); void CPU_SB(u32 instr, u32 addr, u32 rtVal);
void CPU_SH(u32 instr, u32 addr, u32 rtVal); void CPU_SH(u32 instr, u32 addr, u32 rtVal);
void CPU_SW(u32 instr, u32 addr, u32 rtVal); void CPU_SW(u32 instr, u32 addr, u32 rtVal);
void CPU_MOVE(u32 rd_and_rs, u32 rsVal); void CPU_MOVE(u32 Rd, u32 Rs, u32 rsVal);
ALWAYS_INLINE static u32 PackMoveArgs(Reg rd, Reg rs)
{
return (static_cast<u32>(rd) << 8) | static_cast<u32>(rs);
}
void CPU_MOVE_Packed(u32 rd_and_rs, u32 rsVal);
// Arithmetic with immediate value // Arithmetic with immediate value
void CPU_ADDI(u32 instr, u32 rsVal); void CPU_ADDI(u32 instr, u32 rsVal);
@ -73,14 +79,30 @@ void CPU_SLLV(u32 instr, u32 rtVal, u32 rsVal);
void CPU_SRLV(u32 instr, u32 rtVal, u32 rsVal); void CPU_SRLV(u32 instr, u32 rtVal, u32 rsVal);
void CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal); void CPU_SRAV(u32 instr, u32 rtVal, u32 rsVal);
// Move registers
void CPU_MFHI(u32 instr, u32 hiVal);
void CPU_MTHI(u32 instr, u32 rsVal);
void CPU_MFLO(u32 instr, u32 loVal);
void CPU_MTLO(u32 instr, u32 rsVal);
// CP0 Data transfer tracking // CP0 Data transfer tracking
void CPU_MFC0(u32 instr, u32 rdVal); void CPU_MFC0(u32 instr, u32 rdVal);
void CPU_MTC0(u32 instr, u32 rdVal, u32 rtVal); void CPU_MTC0(u32 instr, u32 rdVal, u32 rtVal);
} // namespace PGXP ALWAYS_INLINE void TryMove(Reg rd, Reg rs, Reg rt)
{
u32 src;
if (rs == Reg::zero)
src = static_cast<u32>(rt);
else if (rt == Reg::zero)
src = static_cast<u32>(rs);
else
return;
CPU_MOVE(static_cast<u32>(rd), src, g_state.regs.r[src]);
}
ALWAYS_INLINE void TryMoveImm(Reg rd, Reg rs, u32 imm)
{
if (imm == 0)
{
const u32 src = static_cast<u32>(rs);
CPU_MOVE(static_cast<u32>(rd), src, g_state.regs.r[src]);
}
}
} // namespace CPU::PGXP

View file

@ -6,8 +6,8 @@
#include "cpu_core.h" #include "cpu_core.h"
#include "cpu_core_private.h" #include "cpu_core_private.h"
#include "cpu_disasm.h" #include "cpu_disasm.h"
#include "gte.h"
#include "cpu_pgxp.h" #include "cpu_pgxp.h"
#include "gte.h"
#include "settings.h" #include "settings.h"
Log_SetChannel(CPU::Recompiler); Log_SetChannel(CPU::Recompiler);
@ -1269,6 +1269,13 @@ bool CodeGenerator::Compile_Bitwise(Instruction instruction, const CodeCache::In
result = OrValues(lhs, rhs); result = OrValues(lhs, rhs);
if (spec_lhs && spec_rhs) if (spec_lhs && spec_rhs)
spec_value = *spec_lhs | *spec_rhs; spec_value = *spec_lhs | *spec_rhs;
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu && dest != Reg::zero &&
instruction.i.rs != Reg::zero && dest != instruction.i.rs && rhs.HasConstantValue(0))
{
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(dest, instruction.i.rs)), lhs);
}
} }
break; break;
@ -1291,6 +1298,13 @@ bool CodeGenerator::Compile_Bitwise(Instruction instruction, const CodeCache::In
result = XorValues(lhs, rhs); result = XorValues(lhs, rhs);
if (spec_lhs && spec_rhs) if (spec_lhs && spec_rhs)
spec_value = *spec_lhs ^ *spec_rhs; spec_value = *spec_lhs ^ *spec_rhs;
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu && dest != Reg::zero &&
instruction.i.rs != Reg::zero && dest != instruction.i.rs && rhs.HasConstantValue(0))
{
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(dest, instruction.i.rs)), lhs);
}
} }
break; break;
@ -1306,6 +1320,16 @@ bool CodeGenerator::Compile_Bitwise(Instruction instruction, const CodeCache::In
result = OrValues(lhs, rhs); result = OrValues(lhs, rhs);
if (spec_lhs && spec_rhs) if (spec_lhs && spec_rhs)
spec_value = *spec_lhs | *spec_rhs; spec_value = *spec_lhs | *spec_rhs;
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu && dest != Reg::zero &&
((lhs.HasConstantValue(0) && instruction.r.rt != Reg::zero && dest != instruction.r.rs) ||
(rhs.HasConstantValue(0) && instruction.r.rs != Reg::zero && dest != instruction.r.rt)))
{
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(
PGXP::PackMoveArgs(dest, lhs.HasConstantValue(0) ? instruction.r.rt : instruction.r.rs)),
lhs.HasConstantValue(0) ? rhs : lhs);
}
} }
break; break;
@ -1328,6 +1352,16 @@ bool CodeGenerator::Compile_Bitwise(Instruction instruction, const CodeCache::In
result = XorValues(lhs, rhs); result = XorValues(lhs, rhs);
if (spec_lhs && spec_rhs) if (spec_lhs && spec_rhs)
spec_value = *spec_lhs ^ *spec_rhs; spec_value = *spec_lhs ^ *spec_rhs;
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu && dest != Reg::zero &&
((lhs.HasConstantValue(0) && instruction.r.rt != Reg::zero && dest != instruction.r.rs) ||
(rhs.HasConstantValue(0) && instruction.r.rs != Reg::zero && dest != instruction.r.rt)))
{
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(
PGXP::PackMoveArgs(dest, lhs.HasConstantValue(0) ? instruction.r.rt : instruction.r.rs)),
lhs.HasConstantValue(0) ? rhs : lhs);
}
} }
break; break;
@ -1787,7 +1821,10 @@ bool CodeGenerator::Compile_MoveHiLo(Instruction instruction, const CodeCache::I
{ {
Value hi = m_register_cache.ReadGuestRegister(Reg::hi); Value hi = m_register_cache.ReadGuestRegister(Reg::hi);
if (g_settings.UsingPGXPCPUMode()) if (g_settings.UsingPGXPCPUMode())
EmitFunctionCall(nullptr, &PGXP::CPU_MFHI, Value::FromConstantU32(instruction.bits), hi); {
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(instruction.r.rd, Reg::hi)), hi);
}
m_register_cache.WriteGuestRegister(instruction.r.rd, std::move(hi)); m_register_cache.WriteGuestRegister(instruction.r.rd, std::move(hi));
SpeculativeWriteReg(instruction.r.rd, std::nullopt); SpeculativeWriteReg(instruction.r.rd, std::nullopt);
@ -1798,7 +1835,10 @@ bool CodeGenerator::Compile_MoveHiLo(Instruction instruction, const CodeCache::I
{ {
Value rs = m_register_cache.ReadGuestRegister(instruction.r.rs); Value rs = m_register_cache.ReadGuestRegister(instruction.r.rs);
if (g_settings.UsingPGXPCPUMode()) if (g_settings.UsingPGXPCPUMode())
EmitFunctionCall(nullptr, &PGXP::CPU_MTHI, Value::FromConstantU32(instruction.bits), rs); {
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(Reg::hi, instruction.r.rs)), rs);
}
m_register_cache.WriteGuestRegister(Reg::hi, std::move(rs)); m_register_cache.WriteGuestRegister(Reg::hi, std::move(rs));
} }
@ -1808,7 +1848,10 @@ bool CodeGenerator::Compile_MoveHiLo(Instruction instruction, const CodeCache::I
{ {
Value lo = m_register_cache.ReadGuestRegister(Reg::lo); Value lo = m_register_cache.ReadGuestRegister(Reg::lo);
if (g_settings.UsingPGXPCPUMode()) if (g_settings.UsingPGXPCPUMode())
EmitFunctionCall(nullptr, &PGXP::CPU_MFLO, Value::FromConstantU32(instruction.bits), lo); {
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(instruction.r.rd, Reg::lo)), lo);
}
m_register_cache.WriteGuestRegister(instruction.r.rd, std::move(lo)); m_register_cache.WriteGuestRegister(instruction.r.rd, std::move(lo));
SpeculativeWriteReg(instruction.r.rd, std::nullopt); SpeculativeWriteReg(instruction.r.rd, std::nullopt);
@ -1819,7 +1862,10 @@ bool CodeGenerator::Compile_MoveHiLo(Instruction instruction, const CodeCache::I
{ {
Value rs = m_register_cache.ReadGuestRegister(instruction.r.rs); Value rs = m_register_cache.ReadGuestRegister(instruction.r.rs);
if (g_settings.UsingPGXPCPUMode()) if (g_settings.UsingPGXPCPUMode())
EmitFunctionCall(nullptr, &PGXP::CPU_MTLO, Value::FromConstantU32(instruction.bits), rs); {
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(Reg::lo, instruction.r.rs)), rs);
}
m_register_cache.WriteGuestRegister(Reg::lo, std::move(rs)); m_register_cache.WriteGuestRegister(Reg::lo, std::move(rs));
} }
@ -1842,7 +1888,6 @@ bool CodeGenerator::Compile_Add(Instruction instruction, const CodeCache::Instru
instruction.r.funct == InstructionFunct::add)); instruction.r.funct == InstructionFunct::add));
Value lhs, rhs; Value lhs, rhs;
Reg lhs_src;
SpeculativeValue lhs_spec, rhs_spec; SpeculativeValue lhs_spec, rhs_spec;
Reg dest; Reg dest;
@ -1853,7 +1898,6 @@ bool CodeGenerator::Compile_Add(Instruction instruction, const CodeCache::Instru
{ {
// rt <- rs + sext(imm) // rt <- rs + sext(imm)
dest = instruction.i.rt; dest = instruction.i.rt;
lhs_src = instruction.i.rs;
lhs = m_register_cache.ReadGuestRegister(instruction.i.rs); lhs = m_register_cache.ReadGuestRegister(instruction.i.rs);
rhs = Value::FromConstantU32(instruction.i.imm_sext32()); rhs = Value::FromConstantU32(instruction.i.imm_sext32());
@ -1866,7 +1910,6 @@ bool CodeGenerator::Compile_Add(Instruction instruction, const CodeCache::Instru
{ {
Assert(instruction.r.funct == InstructionFunct::add || instruction.r.funct == InstructionFunct::addu); Assert(instruction.r.funct == InstructionFunct::add || instruction.r.funct == InstructionFunct::addu);
dest = instruction.r.rd; dest = instruction.r.rd;
lhs_src = instruction.r.rs;
lhs = m_register_cache.ReadGuestRegister(instruction.r.rs); lhs = m_register_cache.ReadGuestRegister(instruction.r.rs);
rhs = m_register_cache.ReadGuestRegister(instruction.r.rt); rhs = m_register_cache.ReadGuestRegister(instruction.r.rt);
lhs_spec = SpeculativeReadReg(instruction.r.rs); lhs_spec = SpeculativeReadReg(instruction.r.rs);
@ -1880,17 +1923,38 @@ bool CodeGenerator::Compile_Add(Instruction instruction, const CodeCache::Instru
} }
// detect register moves and handle them for pgxp // detect register moves and handle them for pgxp
if (g_settings.gpu_pgxp_enable && rhs.HasConstantValue(0)) if (dest != Reg::zero && g_settings.gpu_pgxp_enable)
{
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE,
Value::FromConstantU32((static_cast<u32>(dest) << 8) | (static_cast<u32>(lhs_src))), lhs);
}
else if (g_settings.UsingPGXPCPUMode())
{ {
bool handled = false;
if (instruction.op != InstructionOp::funct) if (instruction.op != InstructionOp::funct)
EmitFunctionCall(nullptr, &PGXP::CPU_ADDI, Value::FromConstantU32(instruction.bits), lhs); {
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu && instruction.i.rs != Reg::zero &&
dest != instruction.i.rs && rhs.HasConstantValue(0))
{
handled = true;
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(dest, instruction.i.rs)), lhs);
}
}
else else
EmitFunctionCall(nullptr, &PGXP::CPU_ADD, Value::FromConstantU32(instruction.bits), lhs, rhs); {
if (g_settings.gpu_pgxp_enable && !g_settings.gpu_pgxp_cpu &&
((lhs.HasConstantValue(0) && instruction.r.rt != Reg::zero && dest != instruction.r.rs) ||
(rhs.HasConstantValue(0) && instruction.r.rs != Reg::zero && dest != instruction.r.rt)))
{
handled = true;
EmitFunctionCall(nullptr, &PGXP::CPU_MOVE_Packed,
Value::FromConstantU32(PGXP::PackMoveArgs(dest, instruction.i.rs)), lhs);
}
}
if (g_settings.gpu_pgxp_cpu && !handled)
{
if (instruction.op != InstructionOp::funct)
EmitFunctionCall(nullptr, &PGXP::CPU_ADDI, Value::FromConstantU32(instruction.bits), lhs);
else
EmitFunctionCall(nullptr, &PGXP::CPU_ADD, Value::FromConstantU32(instruction.bits), lhs, rhs);
}
} }
Value result = AddValues(lhs, rhs, check_overflow); Value result = AddValues(lhs, rhs, check_overflow);