CPU/Recompiler: Implement lwl/lwr/swl/swr
This commit is contained in:
parent
7566c45f64
commit
51eff82eb6
|
@ -88,6 +88,16 @@ bool CodeGenerator::CompileInstruction(const CodeBlockInstruction& cbi)
|
||||||
result = Compile_Load(cbi);
|
result = Compile_Load(cbi);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::lwl:
|
||||||
|
case InstructionOp::lwr:
|
||||||
|
result = Compile_LoadLeftRight(cbi);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InstructionOp::swl:
|
||||||
|
case InstructionOp::swr:
|
||||||
|
result = Compile_StoreLeftRight(cbi);
|
||||||
|
break;
|
||||||
|
|
||||||
case InstructionOp::sb:
|
case InstructionOp::sb:
|
||||||
case InstructionOp::sh:
|
case InstructionOp::sh:
|
||||||
case InstructionOp::sw:
|
case InstructionOp::sw:
|
||||||
|
@ -1263,6 +1273,100 @@ bool CodeGenerator::Compile_Store(const CodeBlockInstruction& cbi)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CodeGenerator::Compile_LoadLeftRight(const CodeBlockInstruction& cbi)
|
||||||
|
{
|
||||||
|
InstructionPrologue(cbi, 1);
|
||||||
|
|
||||||
|
Value base = m_register_cache.ReadGuestRegister(cbi.instruction.i.rs);
|
||||||
|
Value offset = Value::FromConstantU32(cbi.instruction.i.imm_sext32());
|
||||||
|
Value address = AddValues(base, offset, false);
|
||||||
|
base.ReleaseAndClear();
|
||||||
|
|
||||||
|
Value shift = ShlValues(AndValues(address, Value::FromConstantU32(3)), Value::FromConstantU32(3)); // * 8
|
||||||
|
address = AndValues(address, Value::FromConstantU32(~u32(3)));
|
||||||
|
|
||||||
|
Value mem = EmitLoadGuestMemory(cbi, address, RegSize_32);
|
||||||
|
|
||||||
|
// hack to bypass load delays
|
||||||
|
Value value;
|
||||||
|
if (cbi.instruction.i.rt == m_register_cache.GetLoadDelayRegister())
|
||||||
|
{
|
||||||
|
const Value& ld_value = m_register_cache.GetLoadDelayValue();
|
||||||
|
if (ld_value.IsInHostRegister())
|
||||||
|
value.SetHostReg(&m_register_cache, ld_value.GetHostRegister(), ld_value.size);
|
||||||
|
else
|
||||||
|
value = ld_value;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
value = m_register_cache.ReadGuestRegister(cbi.instruction.i.rt, true, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cbi.instruction.op == InstructionOp::lwl)
|
||||||
|
{
|
||||||
|
Value lhs = AndValues(value, ShrValues(Value::FromConstantU32(0x00FFFFFF), shift));
|
||||||
|
mem = ShlValues(mem, SubValues(Value::FromConstantU32(24), shift, false));
|
||||||
|
EmitOr(mem.GetHostRegister(), mem.GetHostRegister(), lhs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Value lhs = AndValues(
|
||||||
|
value, ShlValues(Value::FromConstantU32(0xFFFFFF00), SubValues(Value::FromConstantU32(24), shift, false)));
|
||||||
|
EmitShr(mem.GetHostRegister(), mem.GetHostRegister(), RegSize_32, shift);
|
||||||
|
EmitOr(mem.GetHostRegister(), mem.GetHostRegister(), lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift.ReleaseAndClear();
|
||||||
|
|
||||||
|
if (g_settings.gpu_pgxp_enable)
|
||||||
|
EmitFunctionCall(nullptr, PGXP::CPU_LW, Value::FromConstantU32(cbi.instruction.bits), mem, address);
|
||||||
|
|
||||||
|
m_register_cache.WriteGuestRegisterDelayed(cbi.instruction.i.rt, std::move(mem));
|
||||||
|
|
||||||
|
InstructionEpilogue(cbi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CodeGenerator::Compile_StoreLeftRight(const CodeBlockInstruction& cbi)
|
||||||
|
{
|
||||||
|
InstructionPrologue(cbi, 1);
|
||||||
|
|
||||||
|
Value base = m_register_cache.ReadGuestRegister(cbi.instruction.i.rs);
|
||||||
|
Value offset = Value::FromConstantU32(cbi.instruction.i.imm_sext32());
|
||||||
|
Value address = AddValues(base, offset, false);
|
||||||
|
base.ReleaseAndClear();
|
||||||
|
|
||||||
|
Value shift = ShlValues(AndValues(address, Value::FromConstantU32(3)), Value::FromConstantU32(3)); // * 8
|
||||||
|
address = AndValues(address, Value::FromConstantU32(~u32(3)));
|
||||||
|
|
||||||
|
Value mem = EmitLoadGuestMemory(cbi, address, RegSize_32);
|
||||||
|
|
||||||
|
Value reg = m_register_cache.ReadGuestRegister(cbi.instruction.r.rt);
|
||||||
|
|
||||||
|
if (cbi.instruction.op == InstructionOp::swl)
|
||||||
|
{
|
||||||
|
Value lhs = ShrValues(reg, SubValues(Value::FromConstantU32(24), shift, false));
|
||||||
|
EmitAnd(mem.GetHostRegister(), mem.GetHostRegister(), ShlValues(Value::FromConstantU32(0xFFFFFF00), shift));
|
||||||
|
EmitOr(mem.GetHostRegister(), mem.GetHostRegister(), lhs);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Value lhs = ShlValues(reg, shift);
|
||||||
|
mem = AndValues(mem,
|
||||||
|
ShrValues(Value::FromConstantU32(0x00FFFFFF), SubValues(Value::FromConstantU32(24), shift, false)));
|
||||||
|
EmitOr(mem.GetHostRegister(), mem.GetHostRegister(), lhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
shift.ReleaseAndClear();
|
||||||
|
|
||||||
|
EmitStoreGuestMemory(cbi, address, mem);
|
||||||
|
if (g_settings.gpu_pgxp_enable)
|
||||||
|
EmitFunctionCall(nullptr, PGXP::CPU_SW, Value::FromConstantU32(cbi.instruction.bits), mem, address);
|
||||||
|
|
||||||
|
InstructionEpilogue(cbi);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
bool CodeGenerator::Compile_MoveHiLo(const CodeBlockInstruction& cbi)
|
bool CodeGenerator::Compile_MoveHiLo(const CodeBlockInstruction& cbi)
|
||||||
{
|
{
|
||||||
InstructionPrologue(cbi, 1);
|
InstructionPrologue(cbi, 1);
|
||||||
|
|
|
@ -201,6 +201,8 @@ private:
|
||||||
bool Compile_Shift(const CodeBlockInstruction& cbi);
|
bool Compile_Shift(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Load(const CodeBlockInstruction& cbi);
|
bool Compile_Load(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Store(const CodeBlockInstruction& cbi);
|
bool Compile_Store(const CodeBlockInstruction& cbi);
|
||||||
|
bool Compile_LoadLeftRight(const CodeBlockInstruction& cbi);
|
||||||
|
bool Compile_StoreLeftRight(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_MoveHiLo(const CodeBlockInstruction& cbi);
|
bool Compile_MoveHiLo(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Add(const CodeBlockInstruction& cbi);
|
bool Compile_Add(const CodeBlockInstruction& cbi);
|
||||||
bool Compile_Subtract(const CodeBlockInstruction& cbi);
|
bool Compile_Subtract(const CodeBlockInstruction& cbi);
|
||||||
|
|
|
@ -308,6 +308,10 @@ public:
|
||||||
/// Stores the specified value to the guest register after the next instruction (load delay).
|
/// Stores the specified value to the guest register after the next instruction (load delay).
|
||||||
void WriteGuestRegisterDelayed(Reg guest_reg, Value&& value);
|
void WriteGuestRegisterDelayed(Reg guest_reg, Value&& value);
|
||||||
|
|
||||||
|
/// Returns the current target for a load delay, or Reg::count.
|
||||||
|
Reg GetLoadDelayRegister() const { return m_state.load_delay_register; }
|
||||||
|
const Value& GetLoadDelayValue() const { return m_state.load_delay_value; }
|
||||||
|
|
||||||
/// Moves load delay to the next load delay, and writes any previous load delay to the destination register.
|
/// Moves load delay to the next load delay, and writes any previous load delay to the destination register.
|
||||||
void UpdateLoadDelay();
|
void UpdateLoadDelay();
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue