Merge pull request #7637 from CrystalGamma/pr-crhelpers
PowerPC: Factor out CR helpers into POD class
This commit is contained in:
commit
7b354fa7ac
|
@ -215,6 +215,7 @@ add_library(core
|
||||||
PowerPC/JitInterface.cpp
|
PowerPC/JitInterface.cpp
|
||||||
PowerPC/CachedInterpreter/CachedInterpreter.cpp
|
PowerPC/CachedInterpreter/CachedInterpreter.cpp
|
||||||
PowerPC/CachedInterpreter/InterpreterBlockCache.cpp
|
PowerPC/CachedInterpreter/InterpreterBlockCache.cpp
|
||||||
|
PowerPC/ConditionRegister.cpp
|
||||||
PowerPC/Interpreter/Interpreter_Branch.cpp
|
PowerPC/Interpreter/Interpreter_Branch.cpp
|
||||||
PowerPC/Interpreter/Interpreter.cpp
|
PowerPC/Interpreter/Interpreter.cpp
|
||||||
PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
|
PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
|
||||||
|
|
|
@ -257,6 +257,7 @@
|
||||||
<ClCompile Include="PowerPC\BreakPoints.cpp" />
|
<ClCompile Include="PowerPC\BreakPoints.cpp" />
|
||||||
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp" />
|
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp" />
|
||||||
<ClCompile Include="PowerPC\CachedInterpreter\InterpreterBlockCache.cpp" />
|
<ClCompile Include="PowerPC\CachedInterpreter\InterpreterBlockCache.cpp" />
|
||||||
|
<ClCompile Include="PowerPC\ConditionRegister.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter_Branch.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter_Branch.cpp" />
|
||||||
<ClCompile Include="PowerPC\Interpreter\Interpreter_FloatingPoint.cpp" />
|
<ClCompile Include="PowerPC\Interpreter\Interpreter_FloatingPoint.cpp" />
|
||||||
|
@ -520,6 +521,7 @@
|
||||||
<ClInclude Include="PowerPC\Gekko.h" />
|
<ClInclude Include="PowerPC\Gekko.h" />
|
||||||
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h" />
|
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h" />
|
||||||
<ClInclude Include="PowerPC\CachedInterpreter\InterpreterBlockCache.h" />
|
<ClInclude Include="PowerPC\CachedInterpreter\InterpreterBlockCache.h" />
|
||||||
|
<ClInclude Include="PowerPC\ConditionRegister.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\ExceptionUtils.h" />
|
<ClInclude Include="PowerPC\Interpreter\ExceptionUtils.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
|
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
|
||||||
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />
|
||||||
|
|
|
@ -268,7 +268,7 @@ void RunCodeHandler()
|
||||||
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
|
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
|
||||||
PowerPC::HostWrite_U32(PC, SP + 12);
|
PowerPC::HostWrite_U32(PC, SP + 12);
|
||||||
PowerPC::HostWrite_U32(LR, SP + 16);
|
PowerPC::HostWrite_U32(LR, SP + 16);
|
||||||
PowerPC::HostWrite_U32(PowerPC::CompactCR(), SP + 20);
|
PowerPC::HostWrite_U32(PowerPC::ppcState.cr.Get(), SP + 20);
|
||||||
// Registers FPR0->13 are volatile
|
// Registers FPR0->13 are volatile
|
||||||
for (int i = 0; i < 14; ++i)
|
for (int i = 0; i < 14; ++i)
|
||||||
{
|
{
|
||||||
|
|
|
@ -61,7 +61,7 @@ void GeckoReturnTrampoline()
|
||||||
GPR(1) = PowerPC::HostRead_U32(SP + 8);
|
GPR(1) = PowerPC::HostRead_U32(SP + 8);
|
||||||
NPC = PowerPC::HostRead_U32(SP + 12);
|
NPC = PowerPC::HostRead_U32(SP + 12);
|
||||||
LR = PowerPC::HostRead_U32(SP + 16);
|
LR = PowerPC::HostRead_U32(SP + 16);
|
||||||
PowerPC::ExpandCR(PowerPC::HostRead_U32(SP + 20));
|
PowerPC::ppcState.cr.Set(PowerPC::HostRead_U32(SP + 20));
|
||||||
for (int i = 0; i < 14; ++i)
|
for (int i = 0; i < 14; ++i)
|
||||||
{
|
{
|
||||||
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
|
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),
|
||||||
|
|
|
@ -21,7 +21,7 @@ double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const
|
||||||
HLE::SystemVABI::VAListStruct::VAListStruct(u32 address)
|
HLE::SystemVABI::VAListStruct::VAListStruct(u32 address)
|
||||||
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
|
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
|
||||||
PowerPC::HostRead_U32(address + 4), PowerPC::HostRead_U32(address + 8)},
|
PowerPC::HostRead_U32(address + 4), PowerPC::HostRead_U32(address + 8)},
|
||||||
m_address(address), m_has_fpr_area(PowerPC::GetCRBit(6) == 1)
|
m_address(address), m_has_fpr_area(PowerPC::ppcState.cr.GetBit(6) == 1)
|
||||||
{
|
{
|
||||||
m_stack = m_va_list.overflow_arg_area;
|
m_stack = m_va_list.overflow_arg_area;
|
||||||
m_gpr += m_va_list.gpr;
|
m_gpr += m_va_list.gpr;
|
||||||
|
|
|
@ -0,0 +1,46 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#include "Core/PowerPC/ConditionRegister.h"
|
||||||
|
|
||||||
|
namespace PowerPC
|
||||||
|
{
|
||||||
|
const std::array<u64, 16> ConditionRegister::s_crTable = {{
|
||||||
|
ConditionRegister::PPCToInternal(0x0),
|
||||||
|
ConditionRegister::PPCToInternal(0x1),
|
||||||
|
ConditionRegister::PPCToInternal(0x2),
|
||||||
|
ConditionRegister::PPCToInternal(0x3),
|
||||||
|
ConditionRegister::PPCToInternal(0x4),
|
||||||
|
ConditionRegister::PPCToInternal(0x5),
|
||||||
|
ConditionRegister::PPCToInternal(0x6),
|
||||||
|
ConditionRegister::PPCToInternal(0x7),
|
||||||
|
ConditionRegister::PPCToInternal(0x8),
|
||||||
|
ConditionRegister::PPCToInternal(0x9),
|
||||||
|
ConditionRegister::PPCToInternal(0xA),
|
||||||
|
ConditionRegister::PPCToInternal(0xB),
|
||||||
|
ConditionRegister::PPCToInternal(0xC),
|
||||||
|
ConditionRegister::PPCToInternal(0xD),
|
||||||
|
ConditionRegister::PPCToInternal(0xE),
|
||||||
|
ConditionRegister::PPCToInternal(0xF),
|
||||||
|
}};
|
||||||
|
|
||||||
|
u32 ConditionRegister::Get() const
|
||||||
|
{
|
||||||
|
u32 new_cr = 0;
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
new_cr |= GetField(i) << (28 - i * 4);
|
||||||
|
}
|
||||||
|
return new_cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConditionRegister::Set(u32 cr)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < 8; i++)
|
||||||
|
{
|
||||||
|
SetField(i, (cr >> (28 - i * 4)) & 0xF);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace PowerPC
|
|
@ -0,0 +1,93 @@
|
||||||
|
// Copyright 2018 Dolphin Emulator Project
|
||||||
|
// Licensed under GPLv2+
|
||||||
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include "Common/CommonTypes.h"
|
||||||
|
|
||||||
|
namespace PowerPC
|
||||||
|
{
|
||||||
|
enum CRBits
|
||||||
|
{
|
||||||
|
CR_SO = 1,
|
||||||
|
CR_EQ = 2,
|
||||||
|
CR_GT = 4,
|
||||||
|
CR_LT = 8,
|
||||||
|
|
||||||
|
CR_SO_BIT = 0,
|
||||||
|
CR_EQ_BIT = 1,
|
||||||
|
CR_GT_BIT = 2,
|
||||||
|
CR_LT_BIT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Optimized CR implementation. Instead of storing CR in its PowerPC format
|
||||||
|
// (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of
|
||||||
|
// the 8 CR register parts. This 64 bit value follows this format:
|
||||||
|
// - SO iff. bit 61 is set
|
||||||
|
// - EQ iff. lower 32 bits == 0
|
||||||
|
// - GT iff. (s64)cr_val > 0
|
||||||
|
// - LT iff. bit 62 is set
|
||||||
|
//
|
||||||
|
// This has the interesting property that sign-extending the result of an
|
||||||
|
// operation from 32 to 64 bits results in a 64 bit value that works as a
|
||||||
|
// CR value. Checking each part of CR is also fast, as it is equivalent to
|
||||||
|
// testing one bit or the low 32 bit part of a register. And CR can still
|
||||||
|
// be manipulated bit by bit fairly easily.
|
||||||
|
struct ConditionRegister
|
||||||
|
{
|
||||||
|
// convert flags into 64-bit CR values with a lookup table
|
||||||
|
static const std::array<u64, 16> s_crTable;
|
||||||
|
|
||||||
|
u64 fields[8];
|
||||||
|
|
||||||
|
// Convert between PPC and internal representation of CR.
|
||||||
|
static u64 PPCToInternal(u8 value)
|
||||||
|
{
|
||||||
|
u64 cr_val = 0x100000000;
|
||||||
|
cr_val |= (u64) !!(value & CR_SO) << 61;
|
||||||
|
cr_val |= (u64) !(value & CR_EQ);
|
||||||
|
cr_val |= (u64) !(value & CR_GT) << 63;
|
||||||
|
cr_val |= (u64) !!(value & CR_LT) << 62;
|
||||||
|
|
||||||
|
return cr_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Warning: these CR operations are fairly slow since they need to convert from
|
||||||
|
// PowerPC format (4 bit) to our internal 64 bit format.
|
||||||
|
void SetField(u32 cr_field, u32 value) { fields[cr_field] = s_crTable[value]; }
|
||||||
|
|
||||||
|
u32 GetField(u32 cr_field) const
|
||||||
|
{
|
||||||
|
const u64 cr_val = fields[cr_field];
|
||||||
|
u32 ppc_cr = 0;
|
||||||
|
|
||||||
|
// SO
|
||||||
|
ppc_cr |= !!(cr_val & (1ull << 61));
|
||||||
|
// EQ
|
||||||
|
ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << 1;
|
||||||
|
// GT
|
||||||
|
ppc_cr |= (static_cast<s64>(cr_val) > 0) << 2;
|
||||||
|
// LT
|
||||||
|
ppc_cr |= !!(cr_val & (1ull << 62)) << 3;
|
||||||
|
|
||||||
|
return ppc_cr;
|
||||||
|
}
|
||||||
|
|
||||||
|
u32 GetBit(u32 bit) const { return (GetField(bit >> 2) >> (3 - (bit & 3))) & 1; }
|
||||||
|
|
||||||
|
void SetBit(u32 bit, u32 value)
|
||||||
|
{
|
||||||
|
if (value & 1)
|
||||||
|
SetField(bit >> 2, GetField(bit >> 2) | (0x8 >> (bit & 3)));
|
||||||
|
else
|
||||||
|
SetField(bit >> 2, GetField(bit >> 2) & ~(0x8 >> (bit & 3)));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set and Get are fairly slow. Should be avoided if possible.
|
||||||
|
void Set(u32 new_cr);
|
||||||
|
u32 Get() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
} // namespace PowerPC
|
|
@ -449,7 +449,7 @@ static void gdb_read_register()
|
||||||
wbe32hex(reply, MSR.Hex);
|
wbe32hex(reply, MSR.Hex);
|
||||||
break;
|
break;
|
||||||
case 66:
|
case 66:
|
||||||
wbe32hex(reply, PowerPC::GetCR());
|
wbe32hex(reply, PowerPC::ppcState.cr.Get());
|
||||||
break;
|
break;
|
||||||
case 67:
|
case 67:
|
||||||
wbe32hex(reply, LR);
|
wbe32hex(reply, LR);
|
||||||
|
@ -534,7 +534,7 @@ static void gdb_write_register()
|
||||||
MSR.Hex = re32hex(bufptr);
|
MSR.Hex = re32hex(bufptr);
|
||||||
break;
|
break;
|
||||||
case 66:
|
case 66:
|
||||||
PowerPC::SetCR(re32hex(bufptr));
|
PowerPC::ppcState.cr.Set(re32hex(bufptr));
|
||||||
break;
|
break;
|
||||||
case 67:
|
case 67:
|
||||||
LR = re32hex(bufptr);
|
LR = re32hex(bufptr);
|
||||||
|
|
|
@ -135,7 +135,7 @@ static void Trace(UGeckoInstruction& inst)
|
||||||
DEBUG_LOG(POWERPC,
|
DEBUG_LOG(POWERPC,
|
||||||
"INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016" PRIx64 " FPSCR: %08x MSR: %08x LR: "
|
"INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016" PRIx64 " FPSCR: %08x MSR: %08x LR: "
|
||||||
"%08x %s %08x %s",
|
"%08x %s %08x %s",
|
||||||
PC, SRR0, SRR1, PowerPC::ppcState.cr_val[0], FPSCR.Hex, MSR.Hex,
|
PC, SRR0, SRR1, PowerPC::ppcState.cr.fields[0], FPSCR.Hex, MSR.Hex,
|
||||||
PowerPC::ppcState.spr[8], regs.c_str(), inst.hex, ppc_inst.c_str());
|
PowerPC::ppcState.spr[8], regs.c_str(), inst.hex, ppc_inst.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -41,7 +41,8 @@ void Interpreter::bcx(UGeckoInstruction inst)
|
||||||
const bool only_condition_check = ((inst.BO >> 2) & 1);
|
const bool only_condition_check = ((inst.BO >> 2) & 1);
|
||||||
const u32 ctr_check = ((CTR != 0) ^ (inst.BO >> 1)) & 1;
|
const u32 ctr_check = ((CTR != 0) ^ (inst.BO >> 1)) & 1;
|
||||||
const bool counter = only_condition_check || ctr_check;
|
const bool counter = only_condition_check || ctr_check;
|
||||||
const bool condition = only_counter_check || (PowerPC::GetCRBit(inst.BI) == u32(true_false));
|
const bool condition =
|
||||||
|
only_counter_check || (PowerPC::ppcState.cr.GetBit(inst.BI) == u32(true_false));
|
||||||
|
|
||||||
if (counter && condition)
|
if (counter && condition)
|
||||||
{
|
{
|
||||||
|
@ -81,7 +82,7 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
|
||||||
"bcctrx with decrement and test CTR option is invalid!");
|
"bcctrx with decrement and test CTR option is invalid!");
|
||||||
|
|
||||||
const u32 condition =
|
const u32 condition =
|
||||||
((inst.BO_2 >> 4) | (PowerPC::GetCRBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
|
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
|
||||||
|
|
||||||
if (condition)
|
if (condition)
|
||||||
{
|
{
|
||||||
|
@ -100,7 +101,7 @@ void Interpreter::bclrx(UGeckoInstruction inst)
|
||||||
|
|
||||||
const u32 counter = ((inst.BO_2 >> 2) | ((CTR != 0) ^ (inst.BO_2 >> 1))) & 1;
|
const u32 counter = ((inst.BO_2 >> 2) | ((CTR != 0) ^ (inst.BO_2 >> 1))) & 1;
|
||||||
const u32 condition =
|
const u32 condition =
|
||||||
((inst.BO_2 >> 4) | (PowerPC::GetCRBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
|
((inst.BO_2 >> 4) | (PowerPC::ppcState.cr.GetBit(inst.BI_2) == ((inst.BO_2 >> 3) & 1))) & 1;
|
||||||
|
|
||||||
if (counter & condition)
|
if (counter & condition)
|
||||||
{
|
{
|
||||||
|
|
|
@ -54,7 +54,7 @@ inline void UpdateFPSCR()
|
||||||
|
|
||||||
inline void Helper_UpdateCR1()
|
inline void Helper_UpdateCR1()
|
||||||
{
|
{
|
||||||
PowerPC::SetCRField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
|
PowerPC::ppcState.cr.SetField(1, (FPSCR.FX << 3) | (FPSCR.FEX << 2) | (FPSCR.VX << 1) | FPSCR.OX);
|
||||||
}
|
}
|
||||||
|
|
||||||
inline double ForceSingle(double value)
|
inline double ForceSingle(double value)
|
||||||
|
|
|
@ -161,7 +161,7 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
|
||||||
// Clear and set the FPCC bits accordingly.
|
// Clear and set the FPCC bits accordingly.
|
||||||
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
|
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, compare_value);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa, double fb)
|
void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa, double fb)
|
||||||
|
@ -195,7 +195,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
|
||||||
// Clear and set the FPCC bits accordingly.
|
// Clear and set the FPCC bits accordingly.
|
||||||
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
|
FPSCR.FPRF = (FPSCR.FPRF & ~0xF) | compare_value;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, compare_value);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, compare_value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::fcmpo(UGeckoInstruction inst)
|
void Interpreter::fcmpo(UGeckoInstruction inst)
|
||||||
|
|
|
@ -15,7 +15,7 @@ void Interpreter::Helper_UpdateCR0(u32 value)
|
||||||
u64 cr_val = (u64)sign_extended;
|
u64 cr_val = (u64)sign_extended;
|
||||||
cr_val = (cr_val & ~(1ull << 61)) | ((u64)PowerPC::GetXER_SO() << 61);
|
cr_val = (cr_val & ~(1ull << 61)) | ((u64)PowerPC::GetXER_SO() << 61);
|
||||||
|
|
||||||
PowerPC::ppcState.cr_val[0] = cr_val;
|
PowerPC::ppcState.cr.fields[0] = cr_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
|
u32 Interpreter::Helper_Carry(u32 value1, u32 value2)
|
||||||
|
@ -82,7 +82,7 @@ void Interpreter::cmpi(UGeckoInstruction inst)
|
||||||
if (PowerPC::GetXER_SO())
|
if (PowerPC::GetXER_SO())
|
||||||
f |= 0x1;
|
f |= 0x1;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, f);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::cmpli(UGeckoInstruction inst)
|
void Interpreter::cmpli(UGeckoInstruction inst)
|
||||||
|
@ -101,7 +101,7 @@ void Interpreter::cmpli(UGeckoInstruction inst)
|
||||||
if (PowerPC::GetXER_SO())
|
if (PowerPC::GetXER_SO())
|
||||||
f |= 0x1;
|
f |= 0x1;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, f);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mulli(UGeckoInstruction inst)
|
void Interpreter::mulli(UGeckoInstruction inst)
|
||||||
|
@ -212,7 +212,7 @@ void Interpreter::cmp(UGeckoInstruction inst)
|
||||||
if (PowerPC::GetXER_SO())
|
if (PowerPC::GetXER_SO())
|
||||||
temp |= 0x1;
|
temp |= 0x1;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, temp);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::cmpl(UGeckoInstruction inst)
|
void Interpreter::cmpl(UGeckoInstruction inst)
|
||||||
|
@ -231,7 +231,7 @@ void Interpreter::cmpl(UGeckoInstruction inst)
|
||||||
if (PowerPC::GetXER_SO())
|
if (PowerPC::GetXER_SO())
|
||||||
temp |= 0x1;
|
temp |= 0x1;
|
||||||
|
|
||||||
PowerPC::SetCRField(inst.CRFD, temp);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::cntlzwx(UGeckoInstruction inst)
|
void Interpreter::cntlzwx(UGeckoInstruction inst)
|
||||||
|
|
|
@ -1017,13 +1017,13 @@ void Interpreter::stwcxd(UGeckoInstruction inst)
|
||||||
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
|
||||||
{
|
{
|
||||||
m_reserve = false;
|
m_reserve = false;
|
||||||
PowerPC::SetCRField(0, 2 | PowerPC::GetXER_SO());
|
PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::GetXER_SO());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::SetCRField(0, PowerPC::GetXER_SO());
|
PowerPC::ppcState.cr.SetField(0, PowerPC::GetXER_SO());
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::stwux(UGeckoInstruction inst)
|
void Interpreter::stwux(UGeckoInstruction inst)
|
||||||
|
|
|
@ -107,14 +107,14 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
|
||||||
|
|
||||||
void Interpreter::mcrxr(UGeckoInstruction inst)
|
void Interpreter::mcrxr(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRField(inst.CRFD, PowerPC::GetXER().Hex >> 28);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, PowerPC::GetXER().Hex >> 28);
|
||||||
PowerPC::ppcState.xer_ca = 0;
|
PowerPC::ppcState.xer_ca = 0;
|
||||||
PowerPC::ppcState.xer_so_ov = 0;
|
PowerPC::ppcState.xer_so_ov = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mfcr(UGeckoInstruction inst)
|
void Interpreter::mfcr(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
rGPR[inst.RD] = PowerPC::GetCR();
|
rGPR[inst.RD] = PowerPC::ppcState.cr.Get();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mtcrf(UGeckoInstruction inst)
|
void Interpreter::mtcrf(UGeckoInstruction inst)
|
||||||
|
@ -122,7 +122,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
|
||||||
const u32 crm = inst.CRM;
|
const u32 crm = inst.CRM;
|
||||||
if (crm == 0xFF)
|
if (crm == 0xFF)
|
||||||
{
|
{
|
||||||
PowerPC::SetCR(rGPR[inst.RS]);
|
PowerPC::ppcState.cr.Set(rGPR[inst.RS]);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -134,7 +134,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
|
||||||
mask |= 0xFU << (i * 4);
|
mask |= 0xFU << (i * 4);
|
||||||
}
|
}
|
||||||
|
|
||||||
PowerPC::SetCR((PowerPC::GetCR() & ~mask) | (rGPR[inst.RS] & mask));
|
PowerPC::ppcState.cr.Set((PowerPC::ppcState.cr.Get() & ~mask) | (rGPR[inst.RS] & mask));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -464,48 +464,56 @@ void Interpreter::mtspr(UGeckoInstruction inst)
|
||||||
|
|
||||||
void Interpreter::crand(UGeckoInstruction inst)
|
void Interpreter::crand(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, PowerPC::GetCRBit(inst.CRBA) & PowerPC::GetCRBit(inst.CRBB));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, PowerPC::ppcState.cr.GetBit(inst.CRBA) &
|
||||||
|
PowerPC::ppcState.cr.GetBit(inst.CRBB));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crandc(UGeckoInstruction inst)
|
void Interpreter::crandc(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, PowerPC::GetCRBit(inst.CRBA) & (1 ^ PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, PowerPC::ppcState.cr.GetBit(inst.CRBA) &
|
||||||
|
(1 ^ PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::creqv(UGeckoInstruction inst)
|
void Interpreter::creqv(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, 1 ^ (PowerPC::GetCRBit(inst.CRBA) ^ PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (PowerPC::ppcState.cr.GetBit(inst.CRBA) ^
|
||||||
|
PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crnand(UGeckoInstruction inst)
|
void Interpreter::crnand(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, 1 ^ (PowerPC::GetCRBit(inst.CRBA) & PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (PowerPC::ppcState.cr.GetBit(inst.CRBA) &
|
||||||
|
PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crnor(UGeckoInstruction inst)
|
void Interpreter::crnor(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, 1 ^ (PowerPC::GetCRBit(inst.CRBA) | PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, 1 ^ (PowerPC::ppcState.cr.GetBit(inst.CRBA) |
|
||||||
|
PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::cror(UGeckoInstruction inst)
|
void Interpreter::cror(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, (PowerPC::GetCRBit(inst.CRBA) | PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(
|
||||||
|
inst.CRBD, (PowerPC::ppcState.cr.GetBit(inst.CRBA) | PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crorc(UGeckoInstruction inst)
|
void Interpreter::crorc(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, (PowerPC::GetCRBit(inst.CRBA) | (1 ^ PowerPC::GetCRBit(inst.CRBB))));
|
PowerPC::ppcState.cr.SetBit(inst.CRBD, (PowerPC::ppcState.cr.GetBit(inst.CRBA) |
|
||||||
|
(1 ^ PowerPC::ppcState.cr.GetBit(inst.CRBB))));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::crxor(UGeckoInstruction inst)
|
void Interpreter::crxor(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
PowerPC::SetCRBit(inst.CRBD, (PowerPC::GetCRBit(inst.CRBA) ^ PowerPC::GetCRBit(inst.CRBB)));
|
PowerPC::ppcState.cr.SetBit(
|
||||||
|
inst.CRBD, (PowerPC::ppcState.cr.GetBit(inst.CRBA) ^ PowerPC::ppcState.cr.GetBit(inst.CRBB)));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mcrf(UGeckoInstruction inst)
|
void Interpreter::mcrf(UGeckoInstruction inst)
|
||||||
{
|
{
|
||||||
const u32 cr_f = PowerPC::GetCRField(inst.CRFS);
|
const u32 cr_f = PowerPC::ppcState.cr.GetField(inst.CRFS);
|
||||||
PowerPC::SetCRField(inst.CRFD, cr_f);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_f);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::isync(UGeckoInstruction inst)
|
void Interpreter::isync(UGeckoInstruction inst)
|
||||||
|
@ -546,7 +554,7 @@ void Interpreter::mcrfs(UGeckoInstruction inst)
|
||||||
FPSCR.VXCVI = 0;
|
FPSCR.VXCVI = 0;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
PowerPC::SetCRField(inst.CRFD, fpflags);
|
PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Interpreter::mffsx(UGeckoInstruction inst)
|
void Interpreter::mffsx(UGeckoInstruction inst)
|
||||||
|
|
|
@ -550,14 +550,16 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
|
||||||
pGreater = J_CC(CC_B);
|
pGreater = J_CC(CC_B);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOV(64, R(RSCRATCH), Imm64(PowerPC::PPCCRToInternal(output[PowerPC::CR_EQ_BIT])));
|
MOV(64, R(RSCRATCH),
|
||||||
|
Imm64(PowerPC::ConditionRegister::PPCToInternal(output[PowerPC::CR_EQ_BIT])));
|
||||||
if (fprf)
|
if (fprf)
|
||||||
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_EQ << FPRF_SHIFT));
|
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_EQ << FPRF_SHIFT));
|
||||||
|
|
||||||
continue1 = J();
|
continue1 = J();
|
||||||
|
|
||||||
SetJumpTarget(pNaN);
|
SetJumpTarget(pNaN);
|
||||||
MOV(64, R(RSCRATCH), Imm64(PowerPC::PPCCRToInternal(output[PowerPC::CR_SO_BIT])));
|
MOV(64, R(RSCRATCH),
|
||||||
|
Imm64(PowerPC::ConditionRegister::PPCToInternal(output[PowerPC::CR_SO_BIT])));
|
||||||
if (fprf)
|
if (fprf)
|
||||||
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_SO << FPRF_SHIFT));
|
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_SO << FPRF_SHIFT));
|
||||||
|
|
||||||
|
@ -566,13 +568,15 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
|
||||||
continue2 = J();
|
continue2 = J();
|
||||||
|
|
||||||
SetJumpTarget(pGreater);
|
SetJumpTarget(pGreater);
|
||||||
MOV(64, R(RSCRATCH), Imm64(PowerPC::PPCCRToInternal(output[PowerPC::CR_GT_BIT])));
|
MOV(64, R(RSCRATCH),
|
||||||
|
Imm64(PowerPC::ConditionRegister::PPCToInternal(output[PowerPC::CR_GT_BIT])));
|
||||||
if (fprf)
|
if (fprf)
|
||||||
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_GT << FPRF_SHIFT));
|
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_GT << FPRF_SHIFT));
|
||||||
continue3 = J();
|
continue3 = J();
|
||||||
|
|
||||||
SetJumpTarget(pLesser);
|
SetJumpTarget(pLesser);
|
||||||
MOV(64, R(RSCRATCH), Imm64(PowerPC::PPCCRToInternal(output[PowerPC::CR_LT_BIT])));
|
MOV(64, R(RSCRATCH),
|
||||||
|
Imm64(PowerPC::ConditionRegister::PPCToInternal(output[PowerPC::CR_LT_BIT])));
|
||||||
if (fprf)
|
if (fprf)
|
||||||
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_LT << FPRF_SHIFT));
|
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_LT << FPRF_SHIFT));
|
||||||
}
|
}
|
||||||
|
@ -584,7 +588,7 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
|
||||||
SetJumpTarget(continue3);
|
SetJumpTarget(continue3);
|
||||||
}
|
}
|
||||||
|
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH));
|
MOV(64, PPCSTATE(cr.fields[crf]), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::fcmpX(UGeckoInstruction inst)
|
void Jit64::fcmpX(UGeckoInstruction inst)
|
||||||
|
|
|
@ -148,16 +148,16 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext)
|
||||||
|
|
||||||
if (arg.IsImm())
|
if (arg.IsImm())
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr_val[0]), Imm32(arg.SImm32()));
|
MOV(64, PPCSTATE(cr.fields[0]), Imm32(arg.SImm32()));
|
||||||
}
|
}
|
||||||
else if (needs_sext)
|
else if (needs_sext)
|
||||||
{
|
{
|
||||||
MOVSX(64, 32, RSCRATCH, arg);
|
MOVSX(64, 32, RSCRATCH, arg);
|
||||||
MOV(64, PPCSTATE(cr_val[0]), R(RSCRATCH));
|
MOV(64, PPCSTATE(cr.fields[0]), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr_val[0]), arg);
|
MOV(64, PPCSTATE(cr.fields[0]), arg);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (CheckMergedBranch(0))
|
if (CheckMergedBranch(0))
|
||||||
|
@ -517,12 +517,12 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
(u64)gpr.Imm32(a) - (u64)comparand.Imm32();
|
(u64)gpr.Imm32(a) - (u64)comparand.Imm32();
|
||||||
if (compareResult == (s32)compareResult)
|
if (compareResult == (s32)compareResult)
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), Imm32((u32)compareResult));
|
MOV(64, PPCSTATE(cr.fields[crf]), Imm32((u32)compareResult));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH), Imm64(compareResult));
|
MOV(64, R(RSCRATCH), Imm64(compareResult));
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH));
|
MOV(64, PPCSTATE(cr.fields[crf]), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
|
@ -539,7 +539,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
|
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
|
||||||
RegCache::Realize(Ra);
|
RegCache::Realize(Ra);
|
||||||
|
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), Ra);
|
MOV(64, PPCSTATE(cr.fields[crf]), Ra);
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
{
|
{
|
||||||
TEST(64, Ra, Ra);
|
TEST(64, Ra, Ra);
|
||||||
|
@ -587,7 +587,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
|
|
||||||
if (comparand.IsImm() && comparand.Imm32() == 0)
|
if (comparand.IsImm() && comparand.Imm32() == 0)
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), R(input));
|
MOV(64, PPCSTATE(cr.fields[crf]), R(input));
|
||||||
// Place the comparison next to the branch for macro-op fusion
|
// Place the comparison next to the branch for macro-op fusion
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
TEST(64, R(input), R(input));
|
TEST(64, R(input), R(input));
|
||||||
|
@ -595,7 +595,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
SUB(64, R(input), comparand);
|
SUB(64, R(input), comparand);
|
||||||
MOV(64, PPCSTATE(cr_val[crf]), R(input));
|
MOV(64, PPCSTATE(cr.fields[crf]), R(input));
|
||||||
}
|
}
|
||||||
|
|
||||||
if (merge_branch)
|
if (merge_branch)
|
||||||
|
|
|
@ -15,27 +15,32 @@
|
||||||
|
|
||||||
using namespace Gen;
|
using namespace Gen;
|
||||||
|
|
||||||
|
static OpArg CROffset(int field)
|
||||||
|
{
|
||||||
|
return PPCSTATE(cr.fields[field]);
|
||||||
|
}
|
||||||
|
|
||||||
void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
|
void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
|
||||||
{
|
{
|
||||||
switch (bit)
|
switch (bit)
|
||||||
{
|
{
|
||||||
case PowerPC::CR_SO_BIT: // check bit 61 set
|
case PowerPC::CR_SO_BIT: // check bit 61 set
|
||||||
BT(64, PPCSTATE(cr_val[field]), Imm8(61));
|
BT(64, CROffset(field), Imm8(61));
|
||||||
SETcc(negate ? CC_NC : CC_C, R(out));
|
SETcc(negate ? CC_NC : CC_C, R(out));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
|
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
|
||||||
CMP(32, PPCSTATE(cr_val[field]), Imm8(0));
|
CMP(32, CROffset(field), Imm8(0));
|
||||||
SETcc(negate ? CC_NZ : CC_Z, R(out));
|
SETcc(negate ? CC_NZ : CC_Z, R(out));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_GT_BIT: // check val > 0
|
case PowerPC::CR_GT_BIT: // check val > 0
|
||||||
CMP(64, PPCSTATE(cr_val[field]), Imm8(0));
|
CMP(64, CROffset(field), Imm8(0));
|
||||||
SETcc(negate ? CC_NG : CC_G, R(out));
|
SETcc(negate ? CC_NG : CC_G, R(out));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_LT_BIT: // check bit 62 set
|
case PowerPC::CR_LT_BIT: // check bit 62 set
|
||||||
BT(64, PPCSTATE(cr_val[field]), Imm8(62));
|
BT(64, CROffset(field), Imm8(62));
|
||||||
SETcc(negate ? CC_NC : CC_C, R(out));
|
SETcc(negate ? CC_NC : CC_C, R(out));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -46,7 +51,7 @@ void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
|
||||||
|
|
||||||
void Jit64::SetCRFieldBit(int field, int bit, X64Reg in)
|
void Jit64::SetCRFieldBit(int field, int bit, X64Reg in)
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field]));
|
MOV(64, R(RSCRATCH2), CROffset(field));
|
||||||
MOVZX(32, 8, in, R(in));
|
MOVZX(32, 8, in, R(in));
|
||||||
|
|
||||||
// Gross but necessary; if the input is totally zero and we set SO or LT,
|
// Gross but necessary; if the input is totally zero and we set SO or LT,
|
||||||
|
@ -90,7 +95,7 @@ void Jit64::SetCRFieldBit(int field, int bit, X64Reg in)
|
||||||
}
|
}
|
||||||
|
|
||||||
BTS(64, R(RSCRATCH2), Imm8(32));
|
BTS(64, R(RSCRATCH2), Imm8(32));
|
||||||
MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH2));
|
MOV(64, CROffset(field), R(RSCRATCH2));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::ClearCRFieldBit(int field, int bit)
|
void Jit64::ClearCRFieldBit(int field, int bit)
|
||||||
|
@ -98,19 +103,19 @@ void Jit64::ClearCRFieldBit(int field, int bit)
|
||||||
switch (bit)
|
switch (bit)
|
||||||
{
|
{
|
||||||
case PowerPC::CR_SO_BIT:
|
case PowerPC::CR_SO_BIT:
|
||||||
BTR(64, PPCSTATE(cr_val[field]), Imm8(61));
|
BTR(64, CROffset(field), Imm8(61));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_EQ_BIT:
|
case PowerPC::CR_EQ_BIT:
|
||||||
OR(64, PPCSTATE(cr_val[field]), Imm8(1));
|
OR(64, CROffset(field), Imm8(1));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_GT_BIT:
|
case PowerPC::CR_GT_BIT:
|
||||||
BTS(64, PPCSTATE(cr_val[field]), Imm8(63));
|
BTS(64, CROffset(field), Imm8(63));
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case PowerPC::CR_LT_BIT:
|
case PowerPC::CR_LT_BIT:
|
||||||
BTR(64, PPCSTATE(cr_val[field]), Imm8(62));
|
BTR(64, CROffset(field), Imm8(62));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
// We don't need to set bit 32; the cases where that's needed only come up when setting bits, not
|
// We don't need to set bit 32; the cases where that's needed only come up when setting bits, not
|
||||||
|
@ -119,7 +124,7 @@ void Jit64::ClearCRFieldBit(int field, int bit)
|
||||||
|
|
||||||
void Jit64::SetCRFieldBit(int field, int bit)
|
void Jit64::SetCRFieldBit(int field, int bit)
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH), PPCSTATE(cr_val[field]));
|
MOV(64, R(RSCRATCH), CROffset(field));
|
||||||
if (bit != PowerPC::CR_GT_BIT)
|
if (bit != PowerPC::CR_GT_BIT)
|
||||||
{
|
{
|
||||||
TEST(64, R(RSCRATCH), R(RSCRATCH));
|
TEST(64, R(RSCRATCH), R(RSCRATCH));
|
||||||
|
@ -149,7 +154,7 @@ void Jit64::SetCRFieldBit(int field, int bit)
|
||||||
}
|
}
|
||||||
|
|
||||||
BTS(64, R(RSCRATCH), Imm8(32));
|
BTS(64, R(RSCRATCH), Imm8(32));
|
||||||
MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH));
|
MOV(64, CROffset(field), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
|
FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
|
||||||
|
@ -157,19 +162,19 @@ FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
|
||||||
switch (bit)
|
switch (bit)
|
||||||
{
|
{
|
||||||
case PowerPC::CR_SO_BIT: // check bit 61 set
|
case PowerPC::CR_SO_BIT: // check bit 61 set
|
||||||
BT(64, PPCSTATE(cr_val[field]), Imm8(61));
|
BT(64, CROffset(field), Imm8(61));
|
||||||
return J_CC(jump_if_set ? CC_C : CC_NC, true);
|
return J_CC(jump_if_set ? CC_C : CC_NC, true);
|
||||||
|
|
||||||
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
|
case PowerPC::CR_EQ_BIT: // check bits 31-0 == 0
|
||||||
CMP(32, PPCSTATE(cr_val[field]), Imm8(0));
|
CMP(32, CROffset(field), Imm8(0));
|
||||||
return J_CC(jump_if_set ? CC_Z : CC_NZ, true);
|
return J_CC(jump_if_set ? CC_Z : CC_NZ, true);
|
||||||
|
|
||||||
case PowerPC::CR_GT_BIT: // check val > 0
|
case PowerPC::CR_GT_BIT: // check val > 0
|
||||||
CMP(64, PPCSTATE(cr_val[field]), Imm8(0));
|
CMP(64, CROffset(field), Imm8(0));
|
||||||
return J_CC(jump_if_set ? CC_G : CC_LE, true);
|
return J_CC(jump_if_set ? CC_G : CC_LE, true);
|
||||||
|
|
||||||
case PowerPC::CR_LT_BIT: // check bit 62 set
|
case PowerPC::CR_LT_BIT: // check bit 62 set
|
||||||
BT(64, PPCSTATE(cr_val[field]), Imm8(62));
|
BT(64, CROffset(field), Imm8(62));
|
||||||
return J_CC(jump_if_set ? CC_C : CC_NC, true);
|
return J_CC(jump_if_set ? CC_C : CC_NC, true);
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -476,22 +481,22 @@ void Jit64::mtcrf(UGeckoInstruction inst)
|
||||||
if ((crm & (0x80 >> i)) != 0)
|
if ((crm & (0x80 >> i)) != 0)
|
||||||
{
|
{
|
||||||
u8 newcr = (gpr.Imm32(inst.RS) >> (28 - (i * 4))) & 0xF;
|
u8 newcr = (gpr.Imm32(inst.RS) >> (28 - (i * 4))) & 0xF;
|
||||||
u64 newcrval = PowerPC::PPCCRToInternal(newcr);
|
u64 newcrval = PowerPC::ConditionRegister::PPCToInternal(newcr);
|
||||||
if ((s64)newcrval == (s32)newcrval)
|
if ((s64)newcrval == (s32)newcrval)
|
||||||
{
|
{
|
||||||
MOV(64, PPCSTATE(cr_val[i]), Imm32((s32)newcrval));
|
MOV(64, CROffset(i), Imm32((s32)newcrval));
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH), Imm64(newcrval));
|
MOV(64, R(RSCRATCH), Imm64(newcrval));
|
||||||
MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH));
|
MOV(64, CROffset(i), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH2), ImmPtr(PowerPC::m_crTable.data()));
|
MOV(64, R(RSCRATCH2), ImmPtr(PowerPC::ConditionRegister::s_crTable.data()));
|
||||||
RCX64Reg Rs = gpr.Bind(inst.RS, RCMode::Read);
|
RCX64Reg Rs = gpr.Bind(inst.RS, RCMode::Read);
|
||||||
RegCache::Realize(Rs);
|
RegCache::Realize(Rs);
|
||||||
for (int i = 0; i < 8; i++)
|
for (int i = 0; i < 8; i++)
|
||||||
|
@ -504,7 +509,7 @@ void Jit64::mtcrf(UGeckoInstruction inst)
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
AND(32, R(RSCRATCH), Imm8(0xF));
|
AND(32, R(RSCRATCH), Imm8(0xF));
|
||||||
MOV(64, R(RSCRATCH), MComplex(RSCRATCH2, RSCRATCH, SCALE_8, 0));
|
MOV(64, R(RSCRATCH), MComplex(RSCRATCH2, RSCRATCH, SCALE_8, 0));
|
||||||
MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH));
|
MOV(64, CROffset(i), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -519,8 +524,8 @@ void Jit64::mcrf(UGeckoInstruction inst)
|
||||||
// USES_CR
|
// USES_CR
|
||||||
if (inst.CRFS != inst.CRFD)
|
if (inst.CRFS != inst.CRFD)
|
||||||
{
|
{
|
||||||
MOV(64, R(RSCRATCH), PPCSTATE(cr_val[inst.CRFS]));
|
MOV(64, R(RSCRATCH), CROffset(inst.CRFS));
|
||||||
MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
|
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -537,9 +542,9 @@ void Jit64::mcrxr(UGeckoInstruction inst)
|
||||||
// [SO OV CA 0] << 3
|
// [SO OV CA 0] << 3
|
||||||
SHL(32, R(RSCRATCH), Imm8(4));
|
SHL(32, R(RSCRATCH), Imm8(4));
|
||||||
|
|
||||||
MOV(64, R(RSCRATCH2), ImmPtr(PowerPC::m_crTable.data()));
|
MOV(64, R(RSCRATCH2), ImmPtr(PowerPC::ConditionRegister::s_crTable.data()));
|
||||||
MOV(64, R(RSCRATCH), MRegSum(RSCRATCH, RSCRATCH2));
|
MOV(64, R(RSCRATCH), MRegSum(RSCRATCH, RSCRATCH2));
|
||||||
MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
|
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
|
||||||
|
|
||||||
// Clear XER[0-3]
|
// Clear XER[0-3]
|
||||||
MOV(8, PPCSTATE(xer_ca), Imm8(0));
|
MOV(8, PPCSTATE(xer_ca), Imm8(0));
|
||||||
|
@ -646,9 +651,9 @@ void Jit64::mcrfs(UGeckoInstruction inst)
|
||||||
}
|
}
|
||||||
AND(32, R(RSCRATCH), Imm32(mask));
|
AND(32, R(RSCRATCH), Imm32(mask));
|
||||||
MOV(32, PPCSTATE(fpscr), R(RSCRATCH));
|
MOV(32, PPCSTATE(fpscr), R(RSCRATCH));
|
||||||
LEA(64, RSCRATCH, MConst(PowerPC::m_crTable));
|
LEA(64, RSCRATCH, MConst(PowerPC::ConditionRegister::s_crTable));
|
||||||
MOV(64, R(RSCRATCH), MComplex(RSCRATCH, RSCRATCH2, SCALE_8, 0));
|
MOV(64, R(RSCRATCH), MComplex(RSCRATCH, RSCRATCH2, SCALE_8, 0));
|
||||||
MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
|
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Jit64::mffsx(UGeckoInstruction inst)
|
void Jit64::mffsx(UGeckoInstruction inst)
|
||||||
|
|
|
@ -216,7 +216,7 @@ void CommonAsmRoutines::GenMfcr()
|
||||||
if (i != 0)
|
if (i != 0)
|
||||||
SHL(32, R(dst), Imm8(4));
|
SHL(32, R(dst), Imm8(4));
|
||||||
|
|
||||||
MOV(64, R(cr_val), PPCSTATE(cr_val[i]));
|
MOV(64, R(cr_val), PPCSTATE(cr.fields[i]));
|
||||||
|
|
||||||
// Upper bits of tmp need to be zeroed.
|
// Upper bits of tmp need to be zeroed.
|
||||||
// Note: tmp is used later for address calculations and thus
|
// Note: tmp is used later for address calculations and thus
|
||||||
|
|
|
@ -293,7 +293,7 @@ void JitArm64::fcmpX(UGeckoInstruction inst)
|
||||||
|
|
||||||
SetJumpTarget(pNaN);
|
SetJumpTarget(pNaN);
|
||||||
|
|
||||||
MOVI2R(XA, PowerPC::PPCCRToInternal(PowerPC::CR_SO));
|
MOVI2R(XA, PowerPC::ConditionRegister::PPCToInternal(PowerPC::CR_SO));
|
||||||
|
|
||||||
if (a != b)
|
if (a != b)
|
||||||
{
|
{
|
||||||
|
|
|
@ -139,7 +139,7 @@ Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestGPR(size_t preg)
|
||||||
Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestCR(size_t preg)
|
Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestCR(size_t preg)
|
||||||
{
|
{
|
||||||
ASSERT(preg < GUEST_CR_COUNT);
|
ASSERT(preg < GUEST_CR_COUNT);
|
||||||
return {64, PPCSTATE_OFF(cr_val[preg]), m_guest_registers[GUEST_CR_OFFSET + preg]};
|
return {64, PPCSTATE_OFF(cr.fields[preg]), m_guest_registers[GUEST_CR_OFFSET + preg]};
|
||||||
}
|
}
|
||||||
|
|
||||||
Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestByIndex(size_t index)
|
Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestByIndex(size_t index)
|
||||||
|
|
|
@ -94,7 +94,7 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
|
||||||
// [SO OV CA 0] << 3
|
// [SO OV CA 0] << 3
|
||||||
LSL(WA, WA, 4);
|
LSL(WA, WA, 4);
|
||||||
|
|
||||||
MOVP2R(XB, PowerPC::m_crTable.data());
|
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
|
||||||
LDR(XB, XB, XA);
|
LDR(XB, XB, XA);
|
||||||
|
|
||||||
// Clear XER[0-3]
|
// Clear XER[0-3]
|
||||||
|
@ -664,7 +664,7 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
|
||||||
ARM64Reg RS = gpr.R(inst.RS);
|
ARM64Reg RS = gpr.R(inst.RS);
|
||||||
ARM64Reg WB = gpr.GetReg();
|
ARM64Reg WB = gpr.GetReg();
|
||||||
ARM64Reg XB = EncodeRegTo64(WB);
|
ARM64Reg XB = EncodeRegTo64(WB);
|
||||||
MOVP2R(XB, PowerPC::m_crTable.data());
|
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
|
||||||
for (int i = 0; i < 8; ++i)
|
for (int i = 0; i < 8; ++i)
|
||||||
{
|
{
|
||||||
if ((crm & (0x80 >> i)) != 0)
|
if ((crm & (0x80 >> i)) != 0)
|
||||||
|
|
|
@ -31,28 +31,6 @@ std::array<GekkoOPInfo*, 1024> m_infoTable63;
|
||||||
std::array<GekkoOPInfo*, 512> m_allInstructions;
|
std::array<GekkoOPInfo*, 512> m_allInstructions;
|
||||||
size_t m_numInstructions;
|
size_t m_numInstructions;
|
||||||
|
|
||||||
namespace PowerPC
|
|
||||||
{
|
|
||||||
const std::array<u64, 16> m_crTable = {{
|
|
||||||
PPCCRToInternal(0x0),
|
|
||||||
PPCCRToInternal(0x1),
|
|
||||||
PPCCRToInternal(0x2),
|
|
||||||
PPCCRToInternal(0x3),
|
|
||||||
PPCCRToInternal(0x4),
|
|
||||||
PPCCRToInternal(0x5),
|
|
||||||
PPCCRToInternal(0x6),
|
|
||||||
PPCCRToInternal(0x7),
|
|
||||||
PPCCRToInternal(0x8),
|
|
||||||
PPCCRToInternal(0x9),
|
|
||||||
PPCCRToInternal(0xA),
|
|
||||||
PPCCRToInternal(0xB),
|
|
||||||
PPCCRToInternal(0xC),
|
|
||||||
PPCCRToInternal(0xD),
|
|
||||||
PPCCRToInternal(0xE),
|
|
||||||
PPCCRToInternal(0xF),
|
|
||||||
}};
|
|
||||||
} // namespace PowerPC
|
|
||||||
|
|
||||||
namespace PPCTables
|
namespace PPCTables
|
||||||
{
|
{
|
||||||
GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)
|
||||||
|
|
|
@ -94,24 +94,6 @@ std::ostream& operator<<(std::ostream& os, CPUCore core)
|
||||||
return os;
|
return os;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CompactCR()
|
|
||||||
{
|
|
||||||
u32 new_cr = 0;
|
|
||||||
for (u32 i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
new_cr |= GetCRField(i) << (28 - i * 4);
|
|
||||||
}
|
|
||||||
return new_cr;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ExpandCR(u32 cr)
|
|
||||||
{
|
|
||||||
for (u32 i = 0; i < 8; i++)
|
|
||||||
{
|
|
||||||
SetCRField(i, (cr >> (28 - i * 4)) & 0xF);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void DoState(PointerWrap& p)
|
void DoState(PointerWrap& p)
|
||||||
{
|
{
|
||||||
// some of this code has been disabled, because
|
// some of this code has been disabled, because
|
||||||
|
@ -127,7 +109,7 @@ void DoState(PointerWrap& p)
|
||||||
p.DoArray(ppcState.gpr);
|
p.DoArray(ppcState.gpr);
|
||||||
p.Do(ppcState.pc);
|
p.Do(ppcState.pc);
|
||||||
p.Do(ppcState.npc);
|
p.Do(ppcState.npc);
|
||||||
p.DoArray(ppcState.cr_val);
|
p.DoArray(ppcState.cr.fields);
|
||||||
p.Do(ppcState.msr);
|
p.Do(ppcState.msr);
|
||||||
p.Do(ppcState.fpscr);
|
p.Do(ppcState.fpscr);
|
||||||
p.Do(ppcState.Exceptions);
|
p.Do(ppcState.Exceptions);
|
||||||
|
@ -183,8 +165,10 @@ static void ResetRegisters()
|
||||||
ppcState.pc = 0;
|
ppcState.pc = 0;
|
||||||
ppcState.npc = 0;
|
ppcState.npc = 0;
|
||||||
ppcState.Exceptions = 0;
|
ppcState.Exceptions = 0;
|
||||||
for (auto& v : ppcState.cr_val)
|
for (auto& v : ppcState.cr.fields)
|
||||||
|
{
|
||||||
v = 0x8000000000000001;
|
v = 0x8000000000000001;
|
||||||
|
}
|
||||||
|
|
||||||
DBATUpdated();
|
DBATUpdated();
|
||||||
IBATUpdated();
|
IBATUpdated();
|
||||||
|
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <array>
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <iosfwd>
|
#include <iosfwd>
|
||||||
#include <tuple>
|
#include <tuple>
|
||||||
|
@ -15,6 +14,7 @@
|
||||||
|
|
||||||
#include "Core/Debugger/PPCDebugInterface.h"
|
#include "Core/Debugger/PPCDebugInterface.h"
|
||||||
#include "Core/PowerPC/BreakPoints.h"
|
#include "Core/PowerPC/BreakPoints.h"
|
||||||
|
#include "Core/PowerPC/ConditionRegister.h"
|
||||||
#include "Core/PowerPC/Gekko.h"
|
#include "Core/PowerPC/Gekko.h"
|
||||||
#include "Core/PowerPC/PPCCache.h"
|
#include "Core/PowerPC/PPCCache.h"
|
||||||
|
|
||||||
|
@ -103,20 +103,7 @@ struct PowerPCState
|
||||||
u32 pc; // program counter
|
u32 pc; // program counter
|
||||||
u32 npc;
|
u32 npc;
|
||||||
|
|
||||||
// Optimized CR implementation. Instead of storing CR in its PowerPC format
|
ConditionRegister cr;
|
||||||
// (4 bit value, SO/EQ/LT/GT), we store instead a 64 bit value for each of
|
|
||||||
// the 8 CR register parts. This 64 bit value follows this format:
|
|
||||||
// - SO iff. bit 61 is set
|
|
||||||
// - EQ iff. lower 32 bits == 0
|
|
||||||
// - GT iff. (s64)cr_val > 0
|
|
||||||
// - LT iff. bit 62 is set
|
|
||||||
//
|
|
||||||
// This has the interesting property that sign-extending the result of an
|
|
||||||
// operation from 32 to 64 bits results in a 64 bit value that works as a
|
|
||||||
// CR value. Checking each part of CR is also fast, as it is equivalent to
|
|
||||||
// testing one bit or the low 32 bit part of a register. And CR can still
|
|
||||||
// be manipulated bit by bit fairly easily.
|
|
||||||
u64 cr_val[8];
|
|
||||||
|
|
||||||
UReg_MSR msr; // machine state register
|
UReg_MSR msr; // machine state register
|
||||||
UReg_FPSCR fpscr; // floating point flags/status bits
|
UReg_FPSCR fpscr; // floating point flags/status bits
|
||||||
|
@ -213,9 +200,6 @@ void CheckExternalExceptions();
|
||||||
void CheckBreakPoints();
|
void CheckBreakPoints();
|
||||||
void RunLoop();
|
void RunLoop();
|
||||||
|
|
||||||
u32 CompactCR();
|
|
||||||
void ExpandCR(u32 cr);
|
|
||||||
|
|
||||||
u64 ReadFullTimeBaseValue();
|
u64 ReadFullTimeBaseValue();
|
||||||
void WriteFullTimeBaseValue(u64 value);
|
void WriteFullTimeBaseValue(u64 value);
|
||||||
|
|
||||||
|
@ -252,83 +236,6 @@ void UpdatePerformanceMonitor(u32 cycles, u32 num_load_stores, u32 num_fp_inst);
|
||||||
|
|
||||||
#define rPS(i) (PowerPC::ppcState.ps[(i)])
|
#define rPS(i) (PowerPC::ppcState.ps[(i)])
|
||||||
|
|
||||||
enum CRBits
|
|
||||||
{
|
|
||||||
CR_SO = 1,
|
|
||||||
CR_EQ = 2,
|
|
||||||
CR_GT = 4,
|
|
||||||
CR_LT = 8,
|
|
||||||
|
|
||||||
CR_SO_BIT = 0,
|
|
||||||
CR_EQ_BIT = 1,
|
|
||||||
CR_GT_BIT = 2,
|
|
||||||
CR_LT_BIT = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Convert between PPC and internal representation of CR.
|
|
||||||
inline u64 PPCCRToInternal(u8 value)
|
|
||||||
{
|
|
||||||
u64 cr_val = 0x100000000;
|
|
||||||
cr_val |= (u64) !!(value & CR_SO) << 61;
|
|
||||||
cr_val |= (u64) !(value & CR_EQ);
|
|
||||||
cr_val |= (u64) !(value & CR_GT) << 63;
|
|
||||||
cr_val |= (u64) !!(value & CR_LT) << 62;
|
|
||||||
|
|
||||||
return cr_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
// convert flags into 64-bit CR values with a lookup table
|
|
||||||
extern const std::array<u64, 16> m_crTable;
|
|
||||||
|
|
||||||
// Warning: these CR operations are fairly slow since they need to convert from
|
|
||||||
// PowerPC format (4 bit) to our internal 64 bit format. See the definition of
|
|
||||||
// ppcState.cr_val for more explanations.
|
|
||||||
inline void SetCRField(u32 cr_field, u32 value)
|
|
||||||
{
|
|
||||||
PowerPC::ppcState.cr_val[cr_field] = m_crTable[value];
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 GetCRField(u32 cr_field)
|
|
||||||
{
|
|
||||||
const u64 cr_val = PowerPC::ppcState.cr_val[cr_field];
|
|
||||||
u32 ppc_cr = 0;
|
|
||||||
|
|
||||||
// SO
|
|
||||||
ppc_cr |= !!(cr_val & (1ull << 61));
|
|
||||||
// EQ
|
|
||||||
ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << 1;
|
|
||||||
// GT
|
|
||||||
ppc_cr |= (static_cast<s64>(cr_val) > 0) << 2;
|
|
||||||
// LT
|
|
||||||
ppc_cr |= !!(cr_val & (1ull << 62)) << 3;
|
|
||||||
|
|
||||||
return ppc_cr;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 GetCRBit(u32 bit)
|
|
||||||
{
|
|
||||||
return (GetCRField(bit >> 2) >> (3 - (bit & 3))) & 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetCRBit(u32 bit, u32 value)
|
|
||||||
{
|
|
||||||
if (value & 1)
|
|
||||||
SetCRField(bit >> 2, GetCRField(bit >> 2) | (0x8 >> (bit & 3)));
|
|
||||||
else
|
|
||||||
SetCRField(bit >> 2, GetCRField(bit >> 2) & ~(0x8 >> (bit & 3)));
|
|
||||||
}
|
|
||||||
|
|
||||||
// SetCR and GetCR are fairly slow. Should be avoided if possible.
|
|
||||||
inline void SetCR(u32 new_cr)
|
|
||||||
{
|
|
||||||
PowerPC::ExpandCR(new_cr);
|
|
||||||
}
|
|
||||||
|
|
||||||
inline u32 GetCR()
|
|
||||||
{
|
|
||||||
return PowerPC::CompactCR();
|
|
||||||
}
|
|
||||||
|
|
||||||
inline void SetCarry(u32 ca)
|
inline void SetCarry(u32 ca)
|
||||||
{
|
{
|
||||||
PowerPC::ppcState.xer_ca = ca;
|
PowerPC::ppcState.xer_ca = ca;
|
||||||
|
|
|
@ -416,7 +416,8 @@ static bool WillInstructionReturn(UGeckoInstruction inst)
|
||||||
if (inst.hex == 0x4C000064u)
|
if (inst.hex == 0x4C000064u)
|
||||||
return true;
|
return true;
|
||||||
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0);
|
bool counter = (inst.BO_2 >> 2 & 1) != 0 || (CTR != 0) != ((inst.BO_2 >> 1 & 1) != 0);
|
||||||
bool condition = inst.BO_2 >> 4 != 0 || PowerPC::GetCRBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
|
bool condition =
|
||||||
|
inst.BO_2 >> 4 != 0 || PowerPC::ppcState.cr.GetBit(inst.BI_2) == (inst.BO_2 >> 3 & 1);
|
||||||
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
|
bool isBclr = inst.OPCD_7 == 0b010011 && (inst.hex >> 1 & 0b10000) != 0;
|
||||||
return isBclr && counter && condition && !inst.LK_3;
|
return isBclr && counter && condition && !inst.LK_3;
|
||||||
}
|
}
|
||||||
|
|
|
@ -280,8 +280,8 @@ void RegisterWidget::PopulateTable()
|
||||||
[](u64 value) { PowerPC::ppcState.spr[SPR_CTR] = value; });
|
[](u64 value) { PowerPC::ppcState.spr[SPR_CTR] = value; });
|
||||||
|
|
||||||
// CR
|
// CR
|
||||||
AddRegister(20, 5, RegisterType::cr, "CR", [] { return PowerPC::GetCR(); },
|
AddRegister(20, 5, RegisterType::cr, "CR", [] { return PowerPC::ppcState.cr.Get(); },
|
||||||
[](u64 value) { PowerPC::SetCR(value); });
|
[](u64 value) { PowerPC::ppcState.cr.Set(value); });
|
||||||
|
|
||||||
// XER
|
// XER
|
||||||
AddRegister(21, 5, RegisterType::xer, "XER", [] { return PowerPC::GetXER().Hex; },
|
AddRegister(21, 5, RegisterType::xer, "XER", [] { return PowerPC::GetXER().Hex; },
|
||||||
|
|
Loading…
Reference in New Issue