Skip to content
Permalink
Browse files

PowerPC: Factor out CR helpers into POD class

  • Loading branch information...
CrystalGamma
CrystalGamma committed Dec 22, 2018
1 parent f6b856d commit e3075f38346d53d98d316a71b55b14fa10ac4210
Showing with 249 additions and 219 deletions.
  1. +1 −0 Source/Core/Core/CMakeLists.txt
  2. +2 −0 Source/Core/Core/Core.vcxproj
  3. +1 −1 Source/Core/Core/GeckoCode.cpp
  4. +1 −1 Source/Core/Core/HLE/HLE_Misc.cpp
  5. +1 −1 Source/Core/Core/HLE/HLE_VarArgs.cpp
  6. +46 −0 Source/Core/Core/PowerPC/ConditionRegister.cpp
  7. +93 −0 Source/Core/Core/PowerPC/ConditionRegister.h
  8. +2 −2 Source/Core/Core/PowerPC/GDBStub.cpp
  9. +1 −1 Source/Core/Core/PowerPC/Interpreter/Interpreter.cpp
  10. +4 −3 Source/Core/Core/PowerPC/Interpreter/Interpreter_Branch.cpp
  11. +1 −1 Source/Core/Core/PowerPC/Interpreter/Interpreter_FPUtils.h
  12. +2 −2 Source/Core/Core/PowerPC/Interpreter/Interpreter_FloatingPoint.cpp
  13. +5 −5 Source/Core/Core/PowerPC/Interpreter/Interpreter_Integer.cpp
  14. +2 −2 Source/Core/Core/PowerPC/Interpreter/Interpreter_LoadStore.cpp
  15. +23 −15 Source/Core/Core/PowerPC/Interpreter/Interpreter_SystemRegisters.cpp
  16. +9 −5 Source/Core/Core/PowerPC/Jit64/Jit_FloatingPoint.cpp
  17. +8 −8 Source/Core/Core/PowerPC/Jit64/Jit_Integer.cpp
  18. +32 −27 Source/Core/Core/PowerPC/Jit64/Jit_SystemRegisters.cpp
  19. +1 −1 Source/Core/Core/PowerPC/Jit64Common/Jit64AsmCommon.cpp
  20. +1 −1 Source/Core/Core/PowerPC/JitArm64/JitArm64_FloatingPoint.cpp
  21. +1 −1 Source/Core/Core/PowerPC/JitArm64/JitArm64_RegCache.cpp
  22. +2 −2 Source/Core/Core/PowerPC/JitArm64/JitArm64_SystemRegisters.cpp
  23. +0 −22 Source/Core/Core/PowerPC/PPCTables.cpp
  24. +4 −20 Source/Core/Core/PowerPC/PowerPC.cpp
  25. +2 −95 Source/Core/Core/PowerPC/PowerPC.h
  26. +2 −1 Source/Core/DolphinQt/Debugger/CodeWidget.cpp
  27. +2 −2 Source/Core/DolphinQt/Debugger/RegisterWidget.cpp
@@ -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
@@ -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" />
@@ -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)
{
@@ -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)),
@@ -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;
@@ -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);
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);
@@ -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());
}

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

0 comments on commit e3075f3

Please sign in to comment.
You can’t perform that action at this time.