CPU/PGXP: Purge psx_value from first half of instructions
This commit is contained in:
parent
9a6de196a3
commit
302652df22
|
@ -55,6 +55,11 @@ enum : u32
|
||||||
VALID_ALL = (VALID_X | VALID_Y | VALID_Z),
|
VALID_ALL = (VALID_X | VALID_Y | VALID_Z),
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define LOWORD_U16(val) (static_cast<u16>(val))
|
||||||
|
#define HIWORD_U16(val) (static_cast<u16>(static_cast<u32>(val) >> 16))
|
||||||
|
#define LOWORD_S16(val) (static_cast<s16>(static_cast<u16>(val)))
|
||||||
|
#define HIWORD_S16(val) (static_cast<s16>(static_cast<u16>(static_cast<u32>(val) >> 16)))
|
||||||
|
|
||||||
union psx_value
|
union psx_value
|
||||||
{
|
{
|
||||||
u32 d;
|
u32 d;
|
||||||
|
@ -104,7 +109,7 @@ static void WriteMem(u32 addr, const PGXP_value& value);
|
||||||
static void WriteMem16(u32 addr, const PGXP_value& value);
|
static void WriteMem16(u32 addr, const PGXP_value& value);
|
||||||
|
|
||||||
static void CopyZIfMissing(PGXP_value& dst, const PGXP_value& src);
|
static void CopyZIfMissing(PGXP_value& dst, const PGXP_value& src);
|
||||||
static void SelectZ(PGXP_value& dst, const PGXP_value& src1, const PGXP_value& src2);
|
static void SelectZ(float& dst_z, u32& dst_flags, const PGXP_value& src1, const PGXP_value& src2);
|
||||||
|
|
||||||
#ifdef LOG_VALUES
|
#ifdef LOG_VALUES
|
||||||
static void LogInstruction(u32 pc, Instruction instr);
|
static void LogInstruction(u32 pc, Instruction instr);
|
||||||
|
@ -418,14 +423,15 @@ ALWAYS_INLINE_RELEASE void CPU::PGXP::CopyZIfMissing(PGXP_value& dst, const PGXP
|
||||||
dst.flags |= (src.flags & VALID_Z);
|
dst.flags |= (src.flags & VALID_Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
ALWAYS_INLINE_RELEASE void CPU::PGXP::SelectZ(PGXP_value& dst, const PGXP_value& src1, const PGXP_value& src2)
|
ALWAYS_INLINE_RELEASE void CPU::PGXP::SelectZ(float& dst_z, u32& dst_flags, const PGXP_value& src1,
|
||||||
|
const PGXP_value& src2)
|
||||||
{
|
{
|
||||||
// Prefer src2 if src1 is missing Z, or is potentially an imprecise value, when src2 is precise.
|
// Prefer src2 if src1 is missing Z, or is potentially an imprecise value, when src2 is precise.
|
||||||
dst.z = (!(src1.flags & VALID_Z) ||
|
dst_z = (!(src1.flags & VALID_Z) ||
|
||||||
(src1.flags & VALID_TAINTED_Z && (src2.flags & (VALID_Z | VALID_TAINTED_Z)) == VALID_Z)) ?
|
(src1.flags & VALID_TAINTED_Z && (src2.flags & (VALID_Z | VALID_TAINTED_Z)) == VALID_Z)) ?
|
||||||
src2.z :
|
src2.z :
|
||||||
src1.z;
|
src1.z;
|
||||||
dst.flags |= ((src1.flags | src2.flags) & VALID_Z);
|
dst_flags |= ((src1.flags | src2.flags) & VALID_Z);
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef LOG_VALUES
|
#ifdef LOG_VALUES
|
||||||
|
@ -767,38 +773,37 @@ void CPU::PGXP::CPU_ADDI(Instruction instr, u32 rsVal)
|
||||||
// Rt = Rs + Imm (signed)
|
// Rt = Rs + Imm (signed)
|
||||||
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
||||||
|
|
||||||
psx_value imm;
|
const u32 immVal = instr.i.imm_sext32();
|
||||||
imm.d = instr.i.imm_sext32();
|
|
||||||
|
|
||||||
PGXP_value& prtVal = GetRtValue(instr);
|
PGXP_value& prtVal = GetRtValue(instr);
|
||||||
prtVal = prsVal;
|
prtVal = prsVal;
|
||||||
|
|
||||||
if (imm.d == 0)
|
if (immVal == 0)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (rsVal == 0)
|
if (rsVal == 0)
|
||||||
{
|
{
|
||||||
// x is low precision value
|
// x is low precision value
|
||||||
prtVal.x = static_cast<float>(imm.sw.l);
|
prtVal.x = static_cast<float>(LOWORD_S16(immVal));
|
||||||
prtVal.y = static_cast<float>(imm.sw.h);
|
prtVal.y = static_cast<float>(HIWORD_S16(immVal));
|
||||||
prtVal.flags |= VALID_X | VALID_Y | VALID_TAINTED_Z;
|
prtVal.flags |= VALID_X | VALID_Y | VALID_TAINTED_Z;
|
||||||
prtVal.value = imm.d;
|
prtVal.value = immVal;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
prtVal.x = (float)f16Unsign(prtVal.x);
|
prtVal.x = static_cast<float>(f16Unsign(prtVal.x));
|
||||||
prtVal.x += (float)imm.w.l;
|
prtVal.x += static_cast<float>(LOWORD_U16(immVal));
|
||||||
|
|
||||||
// carry on over/underflow
|
// carry on over/underflow
|
||||||
float of = (prtVal.x > USHRT_MAX) ? 1.f : (prtVal.x < 0) ? -1.f : 0.f;
|
float of = (prtVal.x > USHRT_MAX) ? 1.f : (prtVal.x < 0) ? -1.f : 0.f;
|
||||||
prtVal.x = (float)f16Sign(prtVal.x);
|
prtVal.x = static_cast<float>(f16Sign(prtVal.x));
|
||||||
// ret.x -= of * (USHRT_MAX + 1);
|
// ret.x -= of * (USHRT_MAX + 1);
|
||||||
prtVal.y += imm.sw.h + of;
|
prtVal.y += HIWORD_S16(immVal) + of;
|
||||||
|
|
||||||
// truncate on overflow/underflow
|
// truncate on overflow/underflow
|
||||||
prtVal.y += (prtVal.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (prtVal.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
prtVal.y += (prtVal.y > SHRT_MAX) ? -(USHRT_MAX + 1) : (prtVal.y < SHRT_MIN) ? USHRT_MAX + 1 : 0.f;
|
||||||
|
|
||||||
prtVal.value = rsVal + imm.d;
|
prtVal.value = rsVal + immVal;
|
||||||
|
|
||||||
prtVal.flags |= VALID_TAINTED_Z;
|
prtVal.flags |= VALID_TAINTED_Z;
|
||||||
}
|
}
|
||||||
|
@ -811,33 +816,37 @@ void CPU::PGXP::CPU_ANDI(Instruction instr, u32 rsVal)
|
||||||
const u32 imm = instr.i.imm_zext32();
|
const u32 imm = instr.i.imm_zext32();
|
||||||
const u32 rtVal = rsVal & imm;
|
const u32 rtVal = rsVal & imm;
|
||||||
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
||||||
|
|
||||||
psx_value vRt;
|
|
||||||
vRt.d = rtVal;
|
|
||||||
|
|
||||||
PGXP_value& prtVal = GetRtValue(instr);
|
PGXP_value& prtVal = GetRtValue(instr);
|
||||||
prtVal = prsVal;
|
|
||||||
|
|
||||||
|
prtVal.y = 0.0f; // remove upper 16-bits
|
||||||
|
prtVal.z = prsVal.z;
|
||||||
prtVal.value = rtVal;
|
prtVal.value = rtVal;
|
||||||
prtVal.y = 0.f; // remove upper 16-bits
|
prtVal.flags = prsVal.flags | VALID_Y | VALID_TAINTED_Z;
|
||||||
prtVal.SetValid(COMP_Y);
|
|
||||||
prtVal.flags |= VALID_TAINTED_Z;
|
|
||||||
|
|
||||||
switch (imm)
|
switch (imm)
|
||||||
{
|
{
|
||||||
case 0:
|
case 0:
|
||||||
|
{
|
||||||
// if 0 then x == 0
|
// if 0 then x == 0
|
||||||
prtVal.x = 0.0f;
|
prtVal.x = 0.0f;
|
||||||
prtVal.SetValid(COMP_X);
|
prtVal.SetValid(COMP_X);
|
||||||
break;
|
}
|
||||||
case 0xFFFF:
|
break;
|
||||||
|
|
||||||
|
case 0xFFFFu:
|
||||||
|
{
|
||||||
// if saturated then x == x
|
// if saturated then x == x
|
||||||
break;
|
prtVal.x = prsVal.x;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
{
|
||||||
// otherwise x is low precision value
|
// otherwise x is low precision value
|
||||||
prtVal.x = vRt.sw.l;
|
prtVal.x = static_cast<float>(LOWORD_S16(rtVal));
|
||||||
prtVal.SetValid(COMP_X);
|
prtVal.SetValid(COMP_X);
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -854,20 +863,15 @@ void CPU::PGXP::CPU_ORI(Instruction instr, u32 rsVal)
|
||||||
pRtVal = pRsVal;
|
pRtVal = pRsVal;
|
||||||
pRtVal.value = rtVal;
|
pRtVal.value = rtVal;
|
||||||
|
|
||||||
psx_value vRt;
|
if (imm == 0) [[unlikely]]
|
||||||
vRt.d = rtVal;
|
|
||||||
|
|
||||||
switch (imm)
|
|
||||||
{
|
{
|
||||||
case 0:
|
// if 0 then x == x
|
||||||
// if 0 then x == x
|
}
|
||||||
break;
|
else
|
||||||
default:
|
{
|
||||||
// otherwise x is low precision value
|
// otherwise x is low precision value
|
||||||
pRtVal.x = vRt.sw.l;
|
pRtVal.x = static_cast<float>(LOWORD_S16(rtVal));
|
||||||
pRtVal.SetValid(COMP_X);
|
pRtVal.flags |= VALID_X | VALID_TAINTED_Z;
|
||||||
pRtVal.flags |= VALID_TAINTED_Z;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -884,20 +888,15 @@ void CPU::PGXP::CPU_XORI(Instruction instr, u32 rsVal)
|
||||||
pRtVal = pRsVal;
|
pRtVal = pRsVal;
|
||||||
pRtVal.value = rtVal;
|
pRtVal.value = rtVal;
|
||||||
|
|
||||||
psx_value vRt;
|
if (imm == 0) [[unlikely]]
|
||||||
vRt.d = rtVal;
|
|
||||||
|
|
||||||
switch (imm)
|
|
||||||
{
|
{
|
||||||
case 0:
|
// if 0 then x == x
|
||||||
// if 0 then x == x
|
}
|
||||||
break;
|
else
|
||||||
default:
|
{
|
||||||
// otherwise x is low precision value
|
// otherwise x is low precision value
|
||||||
pRtVal.x = vRt.sw.l;
|
pRtVal.x = static_cast<float>(LOWORD_S16(rtVal));
|
||||||
pRtVal.SetValid(COMP_X);
|
pRtVal.flags |= VALID_X | VALID_TAINTED_Z;
|
||||||
pRtVal.flags |= VALID_TAINTED_Z;
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -996,7 +995,7 @@ void CPU::PGXP::CPU_ADD(Instruction instr, u32 rsVal, u32 rtVal)
|
||||||
// valid x/y only if one side had a valid x/y
|
// valid x/y only if one side had a valid x/y
|
||||||
prdVal.flags = prsVal.flags | (prtVal.flags & VALID_XY) | VALID_TAINTED_Z;
|
prdVal.flags = prsVal.flags | (prtVal.flags & VALID_XY) | VALID_TAINTED_Z;
|
||||||
|
|
||||||
SelectZ(prdVal, prsVal, prtVal);
|
SelectZ(prdVal.z, prdVal.flags, prsVal, prtVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1032,7 +1031,7 @@ void CPU::PGXP::CPU_SUB(Instruction instr, u32 rsVal, u32 rtVal)
|
||||||
// valid x/y only if one side had a valid x/y
|
// valid x/y only if one side had a valid x/y
|
||||||
prdVal.flags = prsVal.flags | (prtVal.flags & VALID_XY) | VALID_TAINTED_Z;
|
prdVal.flags = prsVal.flags | (prtVal.flags & VALID_XY) | VALID_TAINTED_Z;
|
||||||
|
|
||||||
SelectZ(prdVal, prsVal, prtVal);
|
SelectZ(prdVal.z, prdVal.flags, prsVal, prtVal);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1042,36 +1041,33 @@ ALWAYS_INLINE_RELEASE void CPU::PGXP::CPU_BITWISE(Instruction instr, u32 rdVal,
|
||||||
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
PGXP_value& prsVal = ValidateAndGetRsValue(instr, rsVal);
|
||||||
PGXP_value& prtVal = ValidateAndGetRtValue(instr, rtVal);
|
PGXP_value& prtVal = ValidateAndGetRtValue(instr, rtVal);
|
||||||
|
|
||||||
psx_value vald, vals, valt;
|
float x, y;
|
||||||
vald.d = rdVal;
|
if (LOWORD_U16(rdVal) == 0)
|
||||||
vals.d = rsVal;
|
x = 0.0f;
|
||||||
valt.d = rtVal;
|
else if (LOWORD_U16(rdVal) == LOWORD_U16(rsVal))
|
||||||
|
x = prsVal.GetValidX(rsVal);
|
||||||
PGXP_value ret;
|
else if (LOWORD_U16(rdVal) == LOWORD_U16(rtVal))
|
||||||
ret.flags = ((prsVal.flags | prtVal.flags) & VALID_XY) ? (VALID_XY | VALID_TAINTED_Z) : 0;
|
x = prtVal.GetValidX(rtVal);
|
||||||
|
|
||||||
if (vald.w.l == 0)
|
|
||||||
ret.x = 0.f;
|
|
||||||
else if (vald.w.l == vals.w.l)
|
|
||||||
ret.x = prsVal.GetValidX(rsVal);
|
|
||||||
else if (vald.w.l == valt.w.l)
|
|
||||||
ret.x = prtVal.GetValidX(rtVal);
|
|
||||||
else
|
else
|
||||||
ret.x = static_cast<float>(vald.sw.l);
|
x = static_cast<float>(LOWORD_S16(rdVal));
|
||||||
|
|
||||||
if (vald.w.h == 0)
|
if (HIWORD_U16(rdVal) == 0)
|
||||||
ret.y = 0.f;
|
y = 0.0f;
|
||||||
else if (vald.w.h == vals.w.h)
|
else if (HIWORD_U16(rdVal) == HIWORD_U16(rsVal))
|
||||||
ret.y = prsVal.GetValidY(rsVal);
|
y = prsVal.GetValidY(rsVal);
|
||||||
else if (vald.w.h == valt.w.h)
|
else if (HIWORD_U16(rdVal) == HIWORD_U16(rtVal))
|
||||||
ret.y = prtVal.GetValidY(rtVal);
|
y = prtVal.GetValidY(rtVal);
|
||||||
else
|
else
|
||||||
ret.y = static_cast<float>(vald.sw.h);
|
y = static_cast<float>(HIWORD_S16(rdVal));
|
||||||
|
|
||||||
SelectZ(ret, prsVal, prtVal);
|
// Why not write directly to prdVal? Because it might be the same as the source.
|
||||||
|
u32 flags = ((prsVal.flags | prtVal.flags) & VALID_XY) ? (VALID_XY | VALID_TAINTED_Z) : 0;
|
||||||
ret.value = rdVal;
|
PGXP_value& prdVal = GetRdValue(instr);
|
||||||
GetRdValue(instr) = ret;
|
SelectZ(prdVal.z, flags, prsVal, prtVal);
|
||||||
|
prdVal.x = x;
|
||||||
|
prdVal.y = y;
|
||||||
|
prdVal.flags = flags;
|
||||||
|
prdVal.value = rdVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
void CPU::PGXP::CPU_AND_(Instruction instr, u32 rsVal, u32 rtVal)
|
void CPU::PGXP::CPU_AND_(Instruction instr, u32 rsVal, u32 rtVal)
|
||||||
|
|
Loading…
Reference in New Issue