CPU/PGXP: Don't force inputs to valid on add/sub
This commit is contained in:
parent
f5cc70923b
commit
b6f7420018
|
@ -65,6 +65,14 @@ struct PGXP_value
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE bool HasValid(u32 comp) const { return ConvertToBoolUnchecked((flags >> comp) & 1); }
|
ALWAYS_INLINE bool HasValid(u32 comp) const { return ConvertToBoolUnchecked((flags >> comp) & 1); }
|
||||||
|
ALWAYS_INLINE float GetValidX(u32 psxval) const
|
||||||
|
{
|
||||||
|
return (flags & 1) ? x : static_cast<float>(static_cast<s16>(psxval));
|
||||||
|
}
|
||||||
|
ALWAYS_INLINE float GetValidY(u32 psxval) const
|
||||||
|
{
|
||||||
|
return (flags & 2) ? y : static_cast<float>(static_cast<s16>(psxval >> 16));
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct State
|
struct State
|
||||||
|
|
|
@ -21,6 +21,7 @@ Log_SetChannel(CPU::PGXP);
|
||||||
// #define LOG_LOOKUPS 1
|
// #define LOG_LOOKUPS 1
|
||||||
|
|
||||||
// TODO: Get rid of all the rs/rt subscripting.
|
// TODO: Get rid of all the rs/rt subscripting.
|
||||||
|
// TODO: Don't update flags on Validate(), instead return it.
|
||||||
|
|
||||||
namespace CPU::PGXP {
|
namespace CPU::PGXP {
|
||||||
namespace {
|
namespace {
|
||||||
|
@ -932,46 +933,43 @@ void CPU::PGXP::CPU_ADD(u32 instr, u32 rsVal, u32 rtVal)
|
||||||
{
|
{
|
||||||
LOG_VALUES_C2(rs(instr), rsVal, rt(instr), rtVal);
|
LOG_VALUES_C2(rs(instr), rsVal, rt(instr), rtVal);
|
||||||
|
|
||||||
|
PGXP_value& rsv = g_state.pgxp_gpr[rs(instr)];
|
||||||
|
PGXP_value& rtv = g_state.pgxp_gpr[rt(instr)];
|
||||||
|
|
||||||
// Rd = Rs + Rt (signed)
|
// Rd = Rs + Rt (signed)
|
||||||
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
Validate(&rsv, rsVal);
|
||||||
Validate(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
Validate(&rtv, rtVal);
|
||||||
|
|
||||||
PGXP_value ret;
|
PGXP_value ret;
|
||||||
if (rtVal == 0)
|
if (rtVal == 0)
|
||||||
{
|
{
|
||||||
ret = g_state.pgxp_gpr[rs(instr)];
|
ret = rsv;
|
||||||
CopyZIfMissing(ret, g_state.pgxp_gpr[rt(instr)]);
|
CopyZIfMissing(ret, rtv);
|
||||||
}
|
}
|
||||||
else if (rsVal == 0)
|
else if (rsVal == 0)
|
||||||
{
|
{
|
||||||
ret = g_state.pgxp_gpr[rt(instr)];
|
ret = rtv;
|
||||||
CopyZIfMissing(ret, g_state.pgxp_gpr[rs(instr)]);
|
CopyZIfMissing(ret, rsv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// iCB: Only require one valid input
|
ret = rsv;
|
||||||
if (((g_state.pgxp_gpr[rt(instr)].flags & VALID_XY) != VALID_XY) !=
|
ret.x = (float)f16Unsign(rsv.GetValidX(rsVal));
|
||||||
((g_state.pgxp_gpr[rs(instr)].flags & VALID_XY) != VALID_XY))
|
ret.x += (float)f16Unsign(rtv.GetValidX(rtVal));
|
||||||
{
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = g_state.pgxp_gpr[rs(instr)];
|
|
||||||
|
|
||||||
ret.x = (float)f16Unsign(ret.x);
|
|
||||||
ret.x += (float)f16Unsign(g_state.pgxp_gpr[rt(instr)].x);
|
|
||||||
|
|
||||||
// carry on over/underflow
|
// carry on over/underflow
|
||||||
float of = (ret.x > USHRT_MAX) ? 1.f : (ret.x < 0) ? -1.f : 0.f;
|
float of = (ret.x > USHRT_MAX) ? 1.f : (ret.x < 0) ? -1.f : 0.f;
|
||||||
ret.x = (float)f16Sign(ret.x);
|
ret.x = (float)f16Sign(ret.x);
|
||||||
// ret.x -= of * (USHRT_MAX + 1);
|
// ret.x -= of * (USHRT_MAX + 1);
|
||||||
ret.y += g_state.pgxp_gpr[rt(instr)].y + of;
|
ret.y += rtv.GetValidY(rtVal) + of;
|
||||||
|
|
||||||
// truncate on overflow/underflow
|
// truncate on overflow/underflow
|
||||||
ret.y += (ret.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (ret.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
ret.y += (ret.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (ret.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
||||||
|
|
||||||
SelectZ(ret, ret, g_state.pgxp_gpr[rt(instr)]);
|
// valid x/y only if one side had a valid x/y
|
||||||
|
ret.flags |= (rtv.flags & VALID_XY);
|
||||||
|
|
||||||
|
SelectZ(ret, ret, rtv);
|
||||||
ret.flags |= VALID_TAINTED_Z;
|
ret.flags |= VALID_TAINTED_Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -984,40 +982,38 @@ void CPU::PGXP::CPU_SUB(u32 instr, u32 rsVal, u32 rtVal)
|
||||||
{
|
{
|
||||||
LOG_VALUES_C2(rs(instr), rsVal, rt(instr), rtVal);
|
LOG_VALUES_C2(rs(instr), rsVal, rt(instr), rtVal);
|
||||||
|
|
||||||
|
PGXP_value& rsv = g_state.pgxp_gpr[rs(instr)];
|
||||||
|
PGXP_value& rtv = g_state.pgxp_gpr[rt(instr)];
|
||||||
|
|
||||||
// Rd = Rs - Rt (signed)
|
// Rd = Rs - Rt (signed)
|
||||||
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
Validate(&rsv, rsVal);
|
||||||
Validate(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
Validate(&rtv, rtVal);
|
||||||
|
|
||||||
PGXP_value ret;
|
PGXP_value ret;
|
||||||
if (rtVal == 0)
|
if (rtVal == 0)
|
||||||
{
|
{
|
||||||
ret = g_state.pgxp_gpr[rs(instr)];
|
ret = rsv;
|
||||||
CopyZIfMissing(ret, g_state.pgxp_gpr[rs(instr)]);
|
CopyZIfMissing(ret, rtv);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// iCB: Only require one valid input
|
ret = rsv;
|
||||||
if (((g_state.pgxp_gpr[rt(instr)].flags & VALID_XY) != VALID_XY) !=
|
ret.x = (float)f16Unsign(rsv.GetValidX(rsVal));
|
||||||
((g_state.pgxp_gpr[rs(instr)].flags & VALID_XY) != VALID_XY))
|
ret.x -= (float)f16Unsign(rtv.GetValidX(rtVal));
|
||||||
{
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
ret = g_state.pgxp_gpr[rs(instr)];
|
|
||||||
ret.x = (float)f16Unsign(ret.x);
|
|
||||||
ret.x -= (float)f16Unsign(g_state.pgxp_gpr[rt(instr)].x);
|
|
||||||
|
|
||||||
// carry on over/underflow
|
// carry on over/underflow
|
||||||
float of = (ret.x > USHRT_MAX) ? 1.f : (ret.x < 0) ? -1.f : 0.f;
|
float of = (ret.x > USHRT_MAX) ? 1.f : (ret.x < 0) ? -1.f : 0.f;
|
||||||
ret.x = (float)f16Sign(ret.x);
|
ret.x = (float)f16Sign(ret.x);
|
||||||
// ret.x -= of * (USHRT_MAX + 1);
|
// ret.x -= of * (USHRT_MAX + 1);
|
||||||
ret.y -= g_state.pgxp_gpr[rt(instr)].y - of;
|
ret.y -= rtv.GetValidY(rtVal) - of;
|
||||||
|
|
||||||
// truncate on overflow/underflow
|
// truncate on overflow/underflow
|
||||||
ret.y += (ret.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (ret.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
ret.y += (ret.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (ret.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
||||||
|
|
||||||
SelectZ(ret, ret, g_state.pgxp_gpr[rt(instr)]);
|
// valid x/y only if one side had a valid x/y
|
||||||
|
ret.flags |= (rtv.flags & VALID_XY);
|
||||||
|
|
||||||
|
SelectZ(ret, ret, rtv);
|
||||||
ret.flags |= VALID_TAINTED_Z;
|
ret.flags |= VALID_TAINTED_Z;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1035,14 +1031,6 @@ ALWAYS_INLINE_RELEASE void CPU::PGXP::CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVa
|
||||||
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
Validate(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
||||||
Validate(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
Validate(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
||||||
|
|
||||||
// iCB: Only require one valid input
|
|
||||||
if (((g_state.pgxp_gpr[rt(instr)].flags & VALID_XY) != VALID_XY) !=
|
|
||||||
((g_state.pgxp_gpr[rs(instr)].flags & VALID_XY) != VALID_XY))
|
|
||||||
{
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rs(instr)], rsVal);
|
|
||||||
MakeValid(&g_state.pgxp_gpr[rt(instr)], rtVal);
|
|
||||||
}
|
|
||||||
|
|
||||||
psx_value vald, vals, valt;
|
psx_value vald, vals, valt;
|
||||||
vald.d = rdVal;
|
vald.d = rdVal;
|
||||||
vals.d = rsVal;
|
vals.d = rsVal;
|
||||||
|
@ -1091,11 +1079,6 @@ ALWAYS_INLINE_RELEASE void CPU::PGXP::CPU_BITWISE(u32 instr, u32 rdVal, u32 rsVa
|
||||||
ret.SetValid(COMP_Y);
|
ret.SetValid(COMP_Y);
|
||||||
}
|
}
|
||||||
|
|
||||||
// iCB Hack: Force validity if even one half is valid
|
|
||||||
// if ((ret.hFlags & VALID_HALF) || (ret.lFlags & VALID_HALF))
|
|
||||||
// ret.valid = 1;
|
|
||||||
// /iCB Hack
|
|
||||||
|
|
||||||
// Get a valid W
|
// Get a valid W
|
||||||
if (g_state.pgxp_gpr[rs(instr)].HasValid(COMP_Z))
|
if (g_state.pgxp_gpr[rs(instr)].HasValid(COMP_Z))
|
||||||
{
|
{
|
||||||
|
|
Loading…
Reference in New Issue