PowerPC: Factor out CR helpers into POD class

This commit is contained in:
CrystalGamma 2018-12-22 16:09:44 +01:00
parent f6b856d01e
commit e3075f3834
27 changed files with 249 additions and 219 deletions

View File

@ -215,6 +215,7 @@ add_library(core
PowerPC/JitInterface.cpp
PowerPC/CachedInterpreter/CachedInterpreter.cpp
PowerPC/CachedInterpreter/InterpreterBlockCache.cpp
PowerPC/ConditionRegister.cpp
PowerPC/Interpreter/Interpreter_Branch.cpp
PowerPC/Interpreter/Interpreter.cpp
PowerPC/Interpreter/Interpreter_FloatingPoint.cpp

View File

@ -257,6 +257,7 @@
<ClCompile Include="PowerPC\BreakPoints.cpp" />
<ClCompile Include="PowerPC\CachedInterpreter\CachedInterpreter.cpp" />
<ClCompile Include="PowerPC\CachedInterpreter\InterpreterBlockCache.cpp" />
<ClCompile Include="PowerPC\ConditionRegister.cpp" />
<ClCompile Include="PowerPC\Interpreter\Interpreter.cpp" />
<ClCompile Include="PowerPC\Interpreter\Interpreter_Branch.cpp" />
<ClCompile Include="PowerPC\Interpreter\Interpreter_FloatingPoint.cpp" />
@ -520,6 +521,7 @@
<ClInclude Include="PowerPC\Gekko.h" />
<ClInclude Include="PowerPC\CachedInterpreter\CachedInterpreter.h" />
<ClInclude Include="PowerPC\CachedInterpreter\InterpreterBlockCache.h" />
<ClInclude Include="PowerPC\ConditionRegister.h" />
<ClInclude Include="PowerPC\Interpreter\ExceptionUtils.h" />
<ClInclude Include="PowerPC\Interpreter\Interpreter.h" />
<ClInclude Include="PowerPC\Interpreter\Interpreter_FPUtils.h" />

View File

@ -268,7 +268,7 @@ void RunCodeHandler()
PowerPC::HostWrite_U32(SFP, SP + 8); // Real stack frame
PowerPC::HostWrite_U32(PC, SP + 12);
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
for (int i = 0; i < 14; ++i)
{

View File

@ -61,7 +61,7 @@ void GeckoReturnTrampoline()
GPR(1) = PowerPC::HostRead_U32(SP + 8);
NPC = PowerPC::HostRead_U32(SP + 12);
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)
{
rPS(i).SetBoth(PowerPC::HostRead_U64(SP + 24 + 2 * i * sizeof(u64)),

View File

@ -21,7 +21,7 @@ double HLE::SystemVABI::VAList::GetFPR(u32 fpr) const
HLE::SystemVABI::VAListStruct::VAListStruct(u32 address)
: VAList(0), m_va_list{PowerPC::HostRead_U8(address), PowerPC::HostRead_U8(address + 1),
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_gpr += m_va_list.gpr;

View File

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

View File

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

View File

@ -449,7 +449,7 @@ static void gdb_read_register()
wbe32hex(reply, MSR.Hex);
break;
case 66:
wbe32hex(reply, PowerPC::GetCR());
wbe32hex(reply, PowerPC::ppcState.cr.Get());
break;
case 67:
wbe32hex(reply, LR);
@ -534,7 +534,7 @@ static void gdb_write_register()
MSR.Hex = re32hex(bufptr);
break;
case 66:
PowerPC::SetCR(re32hex(bufptr));
PowerPC::ppcState.cr.Set(re32hex(bufptr));
break;
case 67:
LR = re32hex(bufptr);

View File

@ -135,7 +135,7 @@ static void Trace(UGeckoInstruction& inst)
DEBUG_LOG(POWERPC,
"INTER PC: %08x SRR0: %08x SRR1: %08x CRval: %016" PRIx64 " FPSCR: %08x MSR: %08x LR: "
"%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());
}

View File

@ -41,7 +41,8 @@ void Interpreter::bcx(UGeckoInstruction inst)
const bool only_condition_check = ((inst.BO >> 2) & 1);
const u32 ctr_check = ((CTR != 0) ^ (inst.BO >> 1)) & 1;
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)
{
@ -81,7 +82,7 @@ void Interpreter::bcctrx(UGeckoInstruction inst)
"bcctrx with decrement and test CTR option is invalid!");
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)
{
@ -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 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)
{

View File

@ -54,7 +54,7 @@ inline void UpdateFPSCR()
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)

View File

@ -161,7 +161,7 @@ void Interpreter::Helper_FloatCompareOrdered(UGeckoInstruction inst, double fa,
// Clear and set the FPCC bits accordingly.
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)
@ -195,7 +195,7 @@ void Interpreter::Helper_FloatCompareUnordered(UGeckoInstruction inst, double fa
// Clear and set the FPCC bits accordingly.
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)

View File

@ -15,7 +15,7 @@ void Interpreter::Helper_UpdateCR0(u32 value)
u64 cr_val = (u64)sign_extended;
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)
@ -82,7 +82,7 @@ void Interpreter::cmpi(UGeckoInstruction inst)
if (PowerPC::GetXER_SO())
f |= 0x1;
PowerPC::SetCRField(inst.CRFD, f);
PowerPC::ppcState.cr.SetField(inst.CRFD, f);
}
void Interpreter::cmpli(UGeckoInstruction inst)
@ -101,7 +101,7 @@ void Interpreter::cmpli(UGeckoInstruction inst)
if (PowerPC::GetXER_SO())
f |= 0x1;
PowerPC::SetCRField(inst.CRFD, f);
PowerPC::ppcState.cr.SetField(inst.CRFD, f);
}
void Interpreter::mulli(UGeckoInstruction inst)
@ -212,7 +212,7 @@ void Interpreter::cmp(UGeckoInstruction inst)
if (PowerPC::GetXER_SO())
temp |= 0x1;
PowerPC::SetCRField(inst.CRFD, temp);
PowerPC::ppcState.cr.SetField(inst.CRFD, temp);
}
void Interpreter::cmpl(UGeckoInstruction inst)
@ -231,7 +231,7 @@ void Interpreter::cmpl(UGeckoInstruction inst)
if (PowerPC::GetXER_SO())
temp |= 0x1;
PowerPC::SetCRField(inst.CRFD, temp);
PowerPC::ppcState.cr.SetField(inst.CRFD, temp);
}
void Interpreter::cntlzwx(UGeckoInstruction inst)

View File

@ -1017,13 +1017,13 @@ void Interpreter::stwcxd(UGeckoInstruction inst)
if (!(PowerPC::ppcState.Exceptions & EXCEPTION_DSI))
{
m_reserve = false;
PowerPC::SetCRField(0, 2 | PowerPC::GetXER_SO());
PowerPC::ppcState.cr.SetField(0, 2 | PowerPC::GetXER_SO());
return;
}
}
}
PowerPC::SetCRField(0, PowerPC::GetXER_SO());
PowerPC::ppcState.cr.SetField(0, PowerPC::GetXER_SO());
}
void Interpreter::stwux(UGeckoInstruction inst)

View File

@ -107,14 +107,14 @@ void Interpreter::mtfsfx(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_so_ov = 0;
}
void Interpreter::mfcr(UGeckoInstruction inst)
{
rGPR[inst.RD] = PowerPC::GetCR();
rGPR[inst.RD] = PowerPC::ppcState.cr.Get();
}
void Interpreter::mtcrf(UGeckoInstruction inst)
@ -122,7 +122,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
const u32 crm = inst.CRM;
if (crm == 0xFF)
{
PowerPC::SetCR(rGPR[inst.RS]);
PowerPC::ppcState.cr.Set(rGPR[inst.RS]);
}
else
{
@ -134,7 +134,7 @@ void Interpreter::mtcrf(UGeckoInstruction inst)
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
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)
{
const u32 cr_f = PowerPC::GetCRField(inst.CRFS);
PowerPC::SetCRField(inst.CRFD, cr_f);
const u32 cr_f = PowerPC::ppcState.cr.GetField(inst.CRFS);
PowerPC::ppcState.cr.SetField(inst.CRFD, cr_f);
}
void Interpreter::isync(UGeckoInstruction inst)
@ -546,7 +554,7 @@ void Interpreter::mcrfs(UGeckoInstruction inst)
FPSCR.VXCVI = 0;
break;
}
PowerPC::SetCRField(inst.CRFD, fpflags);
PowerPC::ppcState.cr.SetField(inst.CRFD, fpflags);
}
void Interpreter::mffsx(UGeckoInstruction inst)

View File

@ -550,14 +550,16 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
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)
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_EQ << FPRF_SHIFT));
continue1 = J();
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)
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_SO << FPRF_SHIFT));
@ -566,13 +568,15 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
continue2 = J();
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)
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_GT << FPRF_SHIFT));
continue3 = J();
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)
OR(32, PPCSTATE(fpscr), Imm32(PowerPC::CR_LT << FPRF_SHIFT));
}
@ -584,7 +588,7 @@ void Jit64::FloatCompare(UGeckoInstruction inst, bool upper)
SetJumpTarget(continue3);
}
MOV(64, PPCSTATE(cr_val[crf]), R(RSCRATCH));
MOV(64, PPCSTATE(cr.fields[crf]), R(RSCRATCH));
}
void Jit64::fcmpX(UGeckoInstruction inst)

View File

@ -148,16 +148,16 @@ void Jit64::ComputeRC(preg_t preg, bool needs_test, bool needs_sext)
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)
{
MOVSX(64, 32, RSCRATCH, arg);
MOV(64, PPCSTATE(cr_val[0]), R(RSCRATCH));
MOV(64, PPCSTATE(cr.fields[0]), R(RSCRATCH));
}
else
{
MOV(64, PPCSTATE(cr_val[0]), arg);
MOV(64, PPCSTATE(cr.fields[0]), arg);
}
if (CheckMergedBranch(0))
@ -517,12 +517,12 @@ void Jit64::cmpXX(UGeckoInstruction inst)
(u64)gpr.Imm32(a) - (u64)comparand.Imm32();
if (compareResult == (s32)compareResult)
{
MOV(64, PPCSTATE(cr_val[crf]), Imm32((u32)compareResult));
MOV(64, PPCSTATE(cr.fields[crf]), Imm32((u32)compareResult));
}
else
{
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)
@ -539,7 +539,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
RCX64Reg Ra = gpr.Bind(a, RCMode::Read);
RegCache::Realize(Ra);
MOV(64, PPCSTATE(cr_val[crf]), Ra);
MOV(64, PPCSTATE(cr.fields[crf]), Ra);
if (merge_branch)
{
TEST(64, Ra, Ra);
@ -587,7 +587,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
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
if (merge_branch)
TEST(64, R(input), R(input));
@ -595,7 +595,7 @@ void Jit64::cmpXX(UGeckoInstruction inst)
else
{
SUB(64, R(input), comparand);
MOV(64, PPCSTATE(cr_val[crf]), R(input));
MOV(64, PPCSTATE(cr.fields[crf]), R(input));
}
if (merge_branch)

View File

@ -15,27 +15,32 @@
using namespace Gen;
static OpArg CROffset(int field)
{
return PPCSTATE(cr.fields[field]);
}
void Jit64::GetCRFieldBit(int field, int bit, X64Reg out, bool negate)
{
switch (bit)
{
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));
break;
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));
break;
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));
break;
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));
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)
{
MOV(64, R(RSCRATCH2), PPCSTATE(cr_val[field]));
MOV(64, R(RSCRATCH2), CROffset(field));
MOVZX(32, 8, in, R(in));
// 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));
MOV(64, PPCSTATE(cr_val[field]), R(RSCRATCH2));
MOV(64, CROffset(field), R(RSCRATCH2));
}
void Jit64::ClearCRFieldBit(int field, int bit)
@ -98,19 +103,19 @@ void Jit64::ClearCRFieldBit(int field, int bit)
switch (bit)
{
case PowerPC::CR_SO_BIT:
BTR(64, PPCSTATE(cr_val[field]), Imm8(61));
BTR(64, CROffset(field), Imm8(61));
break;
case PowerPC::CR_EQ_BIT:
OR(64, PPCSTATE(cr_val[field]), Imm8(1));
OR(64, CROffset(field), Imm8(1));
break;
case PowerPC::CR_GT_BIT:
BTS(64, PPCSTATE(cr_val[field]), Imm8(63));
BTS(64, CROffset(field), Imm8(63));
break;
case PowerPC::CR_LT_BIT:
BTR(64, PPCSTATE(cr_val[field]), Imm8(62));
BTR(64, CROffset(field), Imm8(62));
break;
}
// 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)
{
MOV(64, R(RSCRATCH), PPCSTATE(cr_val[field]));
MOV(64, R(RSCRATCH), CROffset(field));
if (bit != PowerPC::CR_GT_BIT)
{
TEST(64, R(RSCRATCH), R(RSCRATCH));
@ -149,7 +154,7 @@ void Jit64::SetCRFieldBit(int field, int bit)
}
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)
@ -157,19 +162,19 @@ FixupBranch Jit64::JumpIfCRFieldBit(int field, int bit, bool jump_if_set)
switch (bit)
{
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);
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);
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);
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);
default:
@ -476,22 +481,22 @@ void Jit64::mtcrf(UGeckoInstruction inst)
if ((crm & (0x80 >> i)) != 0)
{
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)
{
MOV(64, PPCSTATE(cr_val[i]), Imm32((s32)newcrval));
MOV(64, CROffset(i), Imm32((s32)newcrval));
}
else
{
MOV(64, R(RSCRATCH), Imm64(newcrval));
MOV(64, PPCSTATE(cr_val[i]), R(RSCRATCH));
MOV(64, CROffset(i), R(RSCRATCH));
}
}
}
}
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);
RegCache::Realize(Rs);
for (int i = 0; i < 8; i++)
@ -504,7 +509,7 @@ void Jit64::mtcrf(UGeckoInstruction inst)
if (i != 0)
AND(32, R(RSCRATCH), Imm8(0xF));
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
if (inst.CRFS != inst.CRFD)
{
MOV(64, R(RSCRATCH), PPCSTATE(cr_val[inst.CRFS]));
MOV(64, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
MOV(64, R(RSCRATCH), CROffset(inst.CRFS));
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
}
}
@ -537,9 +542,9 @@ void Jit64::mcrxr(UGeckoInstruction inst)
// [SO OV CA 0] << 3
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, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
// Clear XER[0-3]
MOV(8, PPCSTATE(xer_ca), Imm8(0));
@ -646,9 +651,9 @@ void Jit64::mcrfs(UGeckoInstruction inst)
}
AND(32, R(RSCRATCH), Imm32(mask));
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, PPCSTATE(cr_val[inst.CRFD]), R(RSCRATCH));
MOV(64, CROffset(inst.CRFD), R(RSCRATCH));
}
void Jit64::mffsx(UGeckoInstruction inst)

View File

@ -216,7 +216,7 @@ void CommonAsmRoutines::GenMfcr()
if (i != 0)
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.
// Note: tmp is used later for address calculations and thus

View File

@ -293,7 +293,7 @@ void JitArm64::fcmpX(UGeckoInstruction inst)
SetJumpTarget(pNaN);
MOVI2R(XA, PowerPC::PPCCRToInternal(PowerPC::CR_SO));
MOVI2R(XA, PowerPC::ConditionRegister::PPCToInternal(PowerPC::CR_SO));
if (a != b)
{

View File

@ -139,7 +139,7 @@ Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestGPR(size_t preg)
Arm64GPRCache::GuestRegInfo Arm64GPRCache::GetGuestCR(size_t preg)
{
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)

View File

@ -94,7 +94,7 @@ void JitArm64::mcrxr(UGeckoInstruction inst)
// [SO OV CA 0] << 3
LSL(WA, WA, 4);
MOVP2R(XB, PowerPC::m_crTable.data());
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
LDR(XB, XB, XA);
// Clear XER[0-3]
@ -664,7 +664,7 @@ void JitArm64::mtcrf(UGeckoInstruction inst)
ARM64Reg RS = gpr.R(inst.RS);
ARM64Reg WB = gpr.GetReg();
ARM64Reg XB = EncodeRegTo64(WB);
MOVP2R(XB, PowerPC::m_crTable.data());
MOVP2R(XB, PowerPC::ConditionRegister::s_crTable.data());
for (int i = 0; i < 8; ++i)
{
if ((crm & (0x80 >> i)) != 0)

View File

@ -31,28 +31,6 @@ std::array<GekkoOPInfo*, 1024> m_infoTable63;
std::array<GekkoOPInfo*, 512> m_allInstructions;
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
{
GekkoOPInfo* GetOpInfo(UGeckoInstruction inst)

View File

@ -94,24 +94,6 @@ std::ostream& operator<<(std::ostream& os, CPUCore core)
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)
{
// some of this code has been disabled, because
@ -127,7 +109,7 @@ void DoState(PointerWrap& p)
p.DoArray(ppcState.gpr);
p.Do(ppcState.pc);
p.Do(ppcState.npc);
p.DoArray(ppcState.cr_val);
p.DoArray(ppcState.cr.fields);
p.Do(ppcState.msr);
p.Do(ppcState.fpscr);
p.Do(ppcState.Exceptions);
@ -183,8 +165,10 @@ static void ResetRegisters()
ppcState.pc = 0;
ppcState.npc = 0;
ppcState.Exceptions = 0;
for (auto& v : ppcState.cr_val)
for (auto& v : ppcState.cr.fields)
{
v = 0x8000000000000001;
}
DBATUpdated();
IBATUpdated();

View File

@ -4,7 +4,6 @@
#pragma once
#include <array>
#include <cstddef>
#include <iosfwd>
#include <tuple>
@ -15,6 +14,7 @@
#include "Core/Debugger/PPCDebugInterface.h"
#include "Core/PowerPC/BreakPoints.h"
#include "Core/PowerPC/ConditionRegister.h"
#include "Core/PowerPC/Gekko.h"
#include "Core/PowerPC/PPCCache.h"
@ -103,20 +103,7 @@ struct PowerPCState
u32 pc; // program counter
u32 npc;
// 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.
u64 cr_val[8];
ConditionRegister cr;
UReg_MSR msr; // machine state register
UReg_FPSCR fpscr; // floating point flags/status bits
@ -213,9 +200,6 @@ void CheckExternalExceptions();
void CheckBreakPoints();
void RunLoop();
u32 CompactCR();
void ExpandCR(u32 cr);
u64 ReadFullTimeBaseValue();
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)])
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)
{
PowerPC::ppcState.xer_ca = ca;

View File

@ -416,7 +416,8 @@ static bool WillInstructionReturn(UGeckoInstruction inst)
if (inst.hex == 0x4C000064u)
return true;
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;
return isBclr && counter && condition && !inst.LK_3;
}

View File

@ -280,8 +280,8 @@ void RegisterWidget::PopulateTable()
[](u64 value) { PowerPC::ppcState.spr[SPR_CTR] = value; });
// CR
AddRegister(20, 5, RegisterType::cr, "CR", [] { return PowerPC::GetCR(); },
[](u64 value) { PowerPC::SetCR(value); });
AddRegister(20, 5, RegisterType::cr, "CR", [] { return PowerPC::ppcState.cr.Get(); },
[](u64 value) { PowerPC::ppcState.cr.Set(value); });
// XER
AddRegister(21, 5, RegisterType::xer, "XER", [] { return PowerPC::GetXER().Hex; },