@@ -107,22 +107,22 @@ 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)
{
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)
@@ -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)
@@ -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,15 +587,15 @@ 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));
}
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)
@@ -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,27 +95,27 @@ 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)
{
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,27 +154,27 @@ 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)
{
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)
@@ -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
@@ -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)
{
@@ -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)
@@ -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)
@@ -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)
@@ -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();
@@ -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;
@@ -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;
}
@@ -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; },