Gekko: Centralize bitmasking of the FPSCR within UReg_FPSCR

Rather than introduce this handling in every system instruction that modifies
the FPSCR directly, we can instead just handle it within the data structure
instead, which avoids duplicating mask handling across instructions.

This also allows handling proper masking from the debugger register
windows themselves without duplicating masking behavior there either.
This commit is contained in:
Lioncash 2018-06-12 13:22:49 -04:00
parent 8a3679bebc
commit 0049ef3a2a
4 changed files with 41 additions and 26 deletions

View File

@ -474,8 +474,37 @@ union UReg_FPSCR
};
u32 Hex = 0;
// The FPSCR's 20th bit (11th from a little endian perspective)
// is defined as reserved and set to zero. Attempts to modify it
// are ignored by hardware, so we do the same.
static constexpr u32 mask = 0xFFFFF7FF;
UReg_FPSCR() = default;
explicit UReg_FPSCR(u32 hex_) : Hex{hex_} {}
explicit UReg_FPSCR(u32 hex_) : Hex{hex_ & mask} {}
UReg_FPSCR& operator=(u32 value)
{
Hex = value & mask;
return *this;
}
UReg_FPSCR& operator|=(u32 value)
{
Hex |= value & mask;
return *this;
}
UReg_FPSCR& operator&=(u32 value)
{
Hex &= value;
return *this;
}
UReg_FPSCR& operator^=(u32 value)
{
Hex ^= value & mask;
return *this;
}
void ClearFIFR()
{

View File

@ -62,20 +62,14 @@ void Interpreter::mtfsb0x(UGeckoInstruction inst)
void Interpreter::mtfsb1x(UGeckoInstruction inst)
{
const u32 bit = inst.CRBD;
const u32 b = 0x80000000 >> bit;
// Bit 20 in the FPSCR is reserved and defined as zero,
// so we ensure that we don't set it.
if (bit != 20)
{
const u32 b = 0x80000000 >> bit;
if (b & FPSCR_ANY_X)
SetFPException(b);
else
FPSCR |= b;
if (b & FPSCR_ANY_X)
SetFPException(b);
else
FPSCR.Hex |= b;
FPSCRtoFPUSettings(FPSCR);
}
FPSCRtoFPUSettings(FPSCR);
if (inst.Rc)
Helper_UpdateCR1();
@ -83,14 +77,12 @@ void Interpreter::mtfsb1x(UGeckoInstruction inst)
void Interpreter::mtfsfix(UGeckoInstruction inst)
{
// Bit 20 of the FPSCR is reserved and defined as zero on hardware,
// so ensure that we don't set it.
const u32 field = inst.CRFD;
const u32 pre_shifted_mask = field == 4 ? 0x70000000 : 0xF0000000;
const u32 pre_shifted_mask = 0xF0000000;
const u32 mask = (pre_shifted_mask >> (4 * field));
const u32 imm = (inst.hex << 16) & pre_shifted_mask;
FPSCR.Hex = (FPSCR.Hex & ~mask) | (imm >> (4 * field));
FPSCR = (FPSCR.Hex & ~mask) | (imm >> (4 * field));
FPSCRtoFPUSettings(FPSCR);
@ -108,13 +100,7 @@ void Interpreter::mtfsfx(UGeckoInstruction inst)
m |= (0xFU << (i * 4));
}
// Bit 20 of the FPSCR is defined as always being zero
// (bit 11 in a little endian context), so ensure that
// we don't actually set that bit.
if ((fm & 0b100) != 0)
m &= 0xFFFFF7FF;
FPSCR.Hex = (FPSCR.Hex & ~m) | (static_cast<u32>(riPS0(inst.FB)) & m);
FPSCR = (FPSCR.Hex & ~m) | (static_cast<u32>(riPS0(inst.FB)) & m);
FPSCRtoFPUSettings(FPSCR);
if (inst.Rc)

View File

@ -290,7 +290,7 @@ void RegisterWidget::PopulateTable()
// FPSCR
AddRegister(22, 5, RegisterType::fpscr, "FPSCR", [] { return PowerPC::ppcState.fpscr.Hex; },
[](u64 value) { PowerPC::ppcState.fpscr.Hex = value; });
[](u64 value) { PowerPC::ppcState.fpscr = static_cast<u32>(value); });
// MSR
AddRegister(23, 5, RegisterType::msr, "MSR", [] { return PowerPC::ppcState.msr.Hex; },

View File

@ -124,7 +124,7 @@ void SetSpecialRegValue(int reg, u32 value)
PowerPC::SetXER(UReg_XER(value));
break;
case 5:
PowerPC::ppcState.fpscr.Hex = value;
PowerPC::ppcState.fpscr = value;
break;
case 6:
PowerPC::ppcState.msr.Hex = value;