Implement Fcvtn (single->half)
This commit is contained in:
parent
7920dc1d2f
commit
a69e8a6f77
3 changed files with 95 additions and 5 deletions
|
@ -122,14 +122,14 @@ namespace ChocolArm64.Instruction
|
|||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
EmitVectorExtractF(Context, Op.Rd, Index, SizeF);
|
||||
EmitVectorExtractF(Context, Op.Rn, Index, SizeF);
|
||||
|
||||
if (SizeF == 0)
|
||||
{
|
||||
//TODO: This need the half precision floating point type,
|
||||
//that is not yet supported on .NET. We should probably
|
||||
//do our own implementation on the meantime.
|
||||
throw new NotImplementedException();
|
||||
Context.Emit(OpCodes.Ldc_I4_0);
|
||||
Context.EmitCall(typeof(ASoftFloat), nameof(ASoftFloat.ConvertSingleToHalf));
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Part + Index, 1);
|
||||
}
|
||||
else /* if (SizeF == 1) */
|
||||
{
|
||||
|
|
|
@ -231,6 +231,67 @@ namespace ChocolArm64.Instruction
|
|||
uint new_exp = (uint)((exponent + 127) & 0xFF) << 23;
|
||||
return BitConverter.Int32BitsToSingle((int)((x_sign << 31) | new_exp | (x_mantissa << 13)));
|
||||
}
|
||||
|
||||
public static ushort ConvertSingleToHalf(float op1, bool alt_hp)
|
||||
{
|
||||
uint op1_bits = (uint)BitConverter.SingleToInt32Bits(op1);
|
||||
|
||||
uint sign = (op1_bits >> 31) & 1;
|
||||
uint exp = (op1_bits >> 23) & 0xFF;
|
||||
uint mantissa = op1_bits & ((1u << 23) - 1);
|
||||
|
||||
// Convert from biased-single to biased-half precision
|
||||
int new_exp = ((int)exp - 127) + 15;
|
||||
ushort new_mantissa = (ushort)(mantissa >> 13);
|
||||
|
||||
if (exp == 0xFF && mantissa != 0)
|
||||
{
|
||||
// NaN
|
||||
if (alt_hp)
|
||||
{
|
||||
return (ushort)(sign << 15);
|
||||
}
|
||||
return (ushort)((sign << 15) | 0x7E00u | new_mantissa);
|
||||
}
|
||||
else if (exp == 0xFF && mantissa == 0)
|
||||
{
|
||||
// Infinity
|
||||
if (alt_hp)
|
||||
{
|
||||
return (ushort)((sign << 15) | 0x7FFFu);
|
||||
}
|
||||
return (ushort)((sign << 15) | 0x7C00u);
|
||||
}
|
||||
else if (exp == 0 && mantissa == 0)
|
||||
{
|
||||
// Zero
|
||||
return (ushort)(sign << 15);
|
||||
}
|
||||
|
||||
if (new_exp <= 0)
|
||||
{
|
||||
// Output a denormal
|
||||
new_mantissa |= 0x0400; // explicit leading bit
|
||||
new_mantissa >>= 1 - new_exp;
|
||||
return (ushort)((sign << 15) | new_mantissa);
|
||||
}
|
||||
|
||||
// TODO: Rounding correction
|
||||
// We currently assume truncation rounding
|
||||
|
||||
if (new_exp >= 0x1F && !alt_hp)
|
||||
{
|
||||
// Output an infinity
|
||||
return (ushort)((sign << 15) | 0x7C00u);
|
||||
}
|
||||
else if (new_exp >= 0x20 && alt_hp)
|
||||
{
|
||||
// Output a maximum value
|
||||
return (ushort)((sign << 15) | 0x7FFFu);
|
||||
}
|
||||
|
||||
return (ushort)((sign << 15) | (ushort)((uint)new_exp << 10) | new_mantissa);
|
||||
}
|
||||
}
|
||||
|
||||
static class ASoftFloat_32
|
||||
|
|
|
@ -39,5 +39,34 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[TestCase((ushort)0x0000, 0x00000000u)] // Positive Zero
|
||||
[TestCase((ushort)0x8000, 0x80000000u)] // Negative Zero
|
||||
[TestCase((ushort)0x3E00, 0x3FC00000u)] // +1.5
|
||||
[TestCase((ushort)0xBE00, 0xBFC00000u)] // -1.5
|
||||
[TestCase((ushort)0xFFFF, 0xFFFFE000u)] // -QNaN
|
||||
[TestCase((ushort)0x7C00, 0x7F800000u)] // +Inf
|
||||
[TestCase((ushort)0x3C00, 0x3F800000u)] // 1.0
|
||||
[TestCase((ushort)0xC000, 0xC0000000u)] // -2.0
|
||||
[TestCase((ushort)0x7BFF, 0x477FE000u)] // 65504.0 (Largest Normal)
|
||||
[TestCase((ushort)0x03FF, 0x387FC000u)] // 0.00006097555 (Largest Subnormal)
|
||||
[TestCase((ushort)0x0001, 0x33800000u)] // 5.96046448e-8 (Smallest Subnormal)
|
||||
public void Fcvtn_V_f16(ushort Result, uint Value)
|
||||
{
|
||||
uint Opcode = 0x0E216801; // FCVTN V1.4H, V0.4S
|
||||
|
||||
Vector128<float> V0 = Sse.StaticCast<uint, float>(Sse2.SetAllVector128(Value));
|
||||
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(Sse2.Extract(Sse.StaticCast<float, ushort>(ThreadState.V1), (byte)0), Is.EqualTo(Result));
|
||||
Assert.That(Sse2.Extract(Sse.StaticCast<float, ushort>(ThreadState.V1), (byte)1), Is.EqualTo(Result));
|
||||
Assert.That(Sse2.Extract(Sse.StaticCast<float, ushort>(ThreadState.V1), (byte)2), Is.EqualTo(Result));
|
||||
Assert.That(Sse2.Extract(Sse.StaticCast<float, ushort>(ThreadState.V1), (byte)3), Is.EqualTo(Result));
|
||||
});
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue