mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-12-16 04:09:39 +00:00
96 lines
2.6 KiB
C++
96 lines
2.6 KiB
C++
// 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,
|
|
|
|
CR_EMU_SO_BIT = 59,
|
|
CR_EMU_LT_BIT = 62,
|
|
};
|
|
|
|
// 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 59 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) << CR_EMU_SO_BIT;
|
|
cr_val |= (u64) !(value & CR_EQ);
|
|
cr_val |= (u64) !(value & CR_GT) << 63;
|
|
cr_val |= (u64) !!(value & CR_LT) << CR_EMU_LT_BIT;
|
|
|
|
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;
|
|
|
|
// LT/SO
|
|
static_assert(CR_EMU_LT_BIT - CR_EMU_SO_BIT == CR_LT_BIT - CR_SO_BIT);
|
|
ppc_cr |= (cr_val >> CR_EMU_SO_BIT) & (PowerPC::CR_LT | PowerPC::CR_SO);
|
|
// EQ
|
|
ppc_cr |= ((cr_val & 0xFFFFFFFF) == 0) << PowerPC::CR_EQ_BIT;
|
|
// GT
|
|
ppc_cr |= (static_cast<s64>(cr_val) > 0) << PowerPC::CR_GT_BIT;
|
|
|
|
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
|