forked from Mirror/Ryujinx
Fix Vcvt_FI & Vcvt_RM; Add Vfma_S & Vfms_S. Add Tests. (#1471)
* Fix Vcvt_FI & Vcvt_RM; Add Vfma_S & Vfms_S. Add Tests. * Address PR feedback & Nit.
This commit is contained in:
parent
1ad9045c6b
commit
6938988427
15 changed files with 309 additions and 31 deletions
|
@ -2,12 +2,20 @@
|
||||||
{
|
{
|
||||||
class OpCode32SimdCvtFI : OpCode32SimdS
|
class OpCode32SimdCvtFI : OpCode32SimdS
|
||||||
{
|
{
|
||||||
public int Opc2 { get; private set; }
|
|
||||||
|
|
||||||
public OpCode32SimdCvtFI(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdCvtFI(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Opc2 = (opCode >> 16) & 0x7;
|
|
||||||
Opc = (opCode >> 7) & 0x1;
|
Opc = (opCode >> 7) & 0x1;
|
||||||
|
|
||||||
|
bool toInteger = (Opc2 & 0b100) != 0;
|
||||||
|
|
||||||
|
if (toInteger)
|
||||||
|
{
|
||||||
|
Vd = ((opCode >> 22) & 0x1) | ((opCode >> 11) & 0x1e);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,14 +2,17 @@
|
||||||
{
|
{
|
||||||
class OpCode32SimdS : OpCode32, IOpCode32Simd
|
class OpCode32SimdS : OpCode32, IOpCode32Simd
|
||||||
{
|
{
|
||||||
public int Vd { get; private set; }
|
public int Vd { get; protected set; }
|
||||||
public int Vm { get; private set; }
|
public int Vm { get; protected set; }
|
||||||
public int Opc { get; protected set; }
|
public int Opc { get; protected set; } // "with_zero" (Opc<1>) [Vcmp, Vcmpe].
|
||||||
|
public int Opc2 { get; private set; } // opc2 or RM (opc2<1:0>) [Vcvt, Vrint].
|
||||||
public int Size { get; protected set; }
|
public int Size { get; protected set; }
|
||||||
|
|
||||||
public OpCode32SimdS(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
public OpCode32SimdS(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||||
{
|
{
|
||||||
Opc = (opCode >> 15) & 0x3;
|
Opc = (opCode >> 15) & 0x3;
|
||||||
|
Opc2 = (opCode >> 16) & 0x7;
|
||||||
|
|
||||||
Size = (opCode >> 8) & 0x3;
|
Size = (opCode >> 8) & 0x3;
|
||||||
|
|
||||||
bool single = Size != 3;
|
bool single = Size != 3;
|
||||||
|
|
|
@ -825,15 +825,17 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS));
|
SetA32("<<<<11101x11010xxxxx101x01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
SetA32("<<<<11101x11010xxxxx101x11x0xxxx", InstName.Vcmpe, InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS)); // FP 32 and 64, scalar.
|
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS)); // FP 32 and 64, scalar.
|
||||||
SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // FP32 to int.
|
SetA32("<<<<11101x11110xxxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // FP32 to int.
|
||||||
SetA32("<<<<11101x111000xxxx10xxx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // Int to FP32.
|
SetA32("<<<<11101x111000xxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI)); // Int to FP32.
|
||||||
SetA32("111111101x1111xxxxxx10>>x1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_R, typeof(OpCode32SimdCvtFI)); // The many FP32 to int encodings (fp).
|
SetA32("111111101x1111xxxxxx101xx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_RM, typeof(OpCode32SimdCvtFI)); // The many FP32 to int encodings (fp).
|
||||||
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ)); // FP and integer, vector.
|
SetA32("111100111x111011xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ)); // FP and integer, vector.
|
||||||
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, typeof(OpCode32SimdRegS));
|
SetA32("<<<<11101x00xxxxxxxx101xx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, typeof(OpCode32SimdRegS));
|
||||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, typeof(OpCode32SimdDupGP));
|
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, typeof(OpCode32SimdDupGP));
|
||||||
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, typeof(OpCode32SimdDupElem));
|
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, typeof(OpCode32SimdDupElem));
|
||||||
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, typeof(OpCode32SimdBinary));
|
SetA32("111100110x00xxxxxxxx0001xxx1xxxx", InstName.Veor, InstEmit32.Veor_I, typeof(OpCode32SimdBinary));
|
||||||
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, typeof(OpCode32SimdExt));
|
SetA32("111100101x11xxxxxxxxxxxxxxx0xxxx", InstName.Vext, InstEmit32.Vext, typeof(OpCode32SimdExt));
|
||||||
|
SetA32("<<<<11101x10xxxxxxxx101xx0x0xxxx", InstName.Vfma, InstEmit32.Vfma_S, typeof(OpCode32SimdRegS));
|
||||||
|
SetA32("<<<<11101x10xxxxxxxx101xx1x0xxxx", InstName.Vfms, InstEmit32.Vfms_S, typeof(OpCode32SimdRegS));
|
||||||
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
||||||
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); // Regs = 1.
|
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); // Regs = 1.
|
||||||
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); // Regs = 2.
|
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); // Regs = 2.
|
||||||
|
@ -918,8 +920,8 @@ namespace ARMeilleure.Decoders
|
||||||
SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, typeof(OpCode32SimdSqrte));
|
SetA32("111100111x111011xxxx010x0xx0xxxx", InstName.Vrecpe, InstEmit32.Vrecpe, typeof(OpCode32SimdSqrte));
|
||||||
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, typeof(OpCode32SimdReg));
|
SetA32("111100100x00xxxxxxxx1111xxx1xxxx", InstName.Vrecps, InstEmit32.Vrecps, typeof(OpCode32SimdReg));
|
||||||
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, typeof(OpCode32SimdRev));
|
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, typeof(OpCode32SimdRev));
|
||||||
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, typeof(OpCode32SimdCvtFI));
|
SetA32("111111101x1110xxxxxx101x01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, typeof(OpCode32SimdS));
|
||||||
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, typeof(OpCode32SimdCvtFI));
|
SetA32("<<<<11101x110110xxxx101x11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, typeof(OpCode32SimdS));
|
||||||
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, typeof(OpCode32SimdShImm));
|
SetA32("1111001x1x>>>xxxxxxx0010>xx1xxxx", InstName.Vrshr, InstEmit32.Vrshr, typeof(OpCode32SimdShImm));
|
||||||
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, typeof(OpCode32SimdSqrte));
|
SetA32("111100111x111011xxxx010x1xx0xxxx", InstName.Vrsqrte, InstEmit32.Vrsqrte, typeof(OpCode32SimdSqrte));
|
||||||
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, typeof(OpCode32SimdReg));
|
SetA32("111100100x10xxxxxxxx1111xxx1xxxx", InstName.Vrsqrts, InstEmit32.Vrsqrts, typeof(OpCode32SimdReg));
|
||||||
|
|
|
@ -231,6 +231,38 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void Vfma_S(ArmEmitterContext context) // Fused.
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
// TODO: Use FMA instruction set.
|
||||||
|
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Addss, Intrinsic.X86Addsd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||||
|
{
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Vfms_S(ArmEmitterContext context) // Fused.
|
||||||
|
{
|
||||||
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
{
|
||||||
|
// TODO: Use FMA instruction set.
|
||||||
|
EmitScalarTernaryOpF32(context, Intrinsic.X86Mulss, Intrinsic.X86Mulsd, Intrinsic.X86Subss, Intrinsic.X86Subsd);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||||
|
{
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static void Vmov_S(ArmEmitterContext context)
|
public static void Vmov_S(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
if (Optimizations.FastFP && Optimizations.UseSse2)
|
if (Optimizations.FastFP && Optimizations.UseSse2)
|
||||||
|
@ -586,7 +618,8 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||||
{
|
{
|
||||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulAdd), op1, op2, op3);
|
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPAdd), op1, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -657,7 +690,8 @@ namespace ARMeilleure.Instructions
|
||||||
{
|
{
|
||||||
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
EmitScalarTernaryOpF32(context, (op1, op2, op3) =>
|
||||||
{
|
{
|
||||||
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPMulSub), op1, op2, op3);
|
Operand res = EmitSoftFloatCall(context, nameof(SoftFloat32.FPMul), op2, op3);
|
||||||
|
return EmitSoftFloatCall(context, nameof(SoftFloat32.FPSub), op1, res);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -139,6 +139,7 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VCVT (floating-point to integer, floating-point) | VCVT (integer to floating-point, floating-point).
|
||||||
public static void Vcvt_FI(ArmEmitterContext context)
|
public static void Vcvt_FI(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
||||||
|
@ -236,13 +237,14 @@ namespace ARMeilleure.Instructions
|
||||||
return roundMode;
|
return roundMode;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Vcvt_R(ArmEmitterContext context)
|
// VCVTA/M/N/P (floating-point).
|
||||||
|
public static void Vcvt_RM(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp; // toInteger == true (opCode<18> == 1 => Opc2<2> == 1).
|
||||||
|
|
||||||
OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;
|
OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;
|
||||||
|
|
||||||
bool unsigned = (op.Opc & 1) == 0;
|
bool unsigned = op.Opc == 0;
|
||||||
int rm = op.Opc2 & 3;
|
int rm = op.Opc2 & 3;
|
||||||
|
|
||||||
if (Optimizations.UseSse41 && rm != 0b00)
|
if (Optimizations.UseSse41 && rm != 0b00)
|
||||||
|
@ -277,9 +279,10 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VRINTA/M/N/P (floating-point).
|
||||||
public static void Vrint_RM(ArmEmitterContext context)
|
public static void Vrint_RM(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||||
|
|
||||||
OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;
|
OperandType floatSize = op.RegisterSize == RegisterSize.Int64 ? OperandType.FP64 : OperandType.FP32;
|
||||||
|
|
||||||
|
@ -320,9 +323,10 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// VRINTZ (floating-point).
|
||||||
public static void Vrint_Z(ArmEmitterContext context)
|
public static void Vrint_Z(ArmEmitterContext context)
|
||||||
{
|
{
|
||||||
IOpCodeSimd op = (IOpCodeSimd)context.CurrOp;
|
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
||||||
|
|
||||||
if (Optimizations.UseSse2)
|
if (Optimizations.UseSse2)
|
||||||
{
|
{
|
||||||
|
@ -355,7 +359,7 @@ namespace ARMeilleure.Instructions
|
||||||
private static void EmitSse41ConvertInt32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed)
|
private static void EmitSse41ConvertInt32(ArmEmitterContext context, FPRoundingMode roundMode, bool signed)
|
||||||
{
|
{
|
||||||
// A port of the similar round function in InstEmitSimdCvt.
|
// A port of the similar round function in InstEmitSimdCvt.
|
||||||
OpCode32SimdS op = (OpCode32SimdS)context.CurrOp;
|
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
||||||
|
|
||||||
bool doubleSize = (op.Size & 1) != 0;
|
bool doubleSize = (op.Size & 1) != 0;
|
||||||
int shift = doubleSize ? 1 : 2;
|
int shift = doubleSize ? 1 : 2;
|
||||||
|
|
|
@ -906,7 +906,7 @@ namespace ARMeilleure.Instructions
|
||||||
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
OpCode32SimdRegS op = (OpCode32SimdRegS)context.CurrOp;
|
||||||
|
|
||||||
bool doubleSize = (op.Size & 1) != 0;
|
bool doubleSize = (op.Size & 1) != 0;
|
||||||
int shift = doubleSize ? 1 : 2;
|
|
||||||
Intrinsic inst1 = doubleSize ? inst64pt1 : inst32pt1;
|
Intrinsic inst1 = doubleSize ? inst64pt1 : inst32pt1;
|
||||||
Intrinsic inst2 = doubleSize ? inst64pt2 : inst32pt2;
|
Intrinsic inst2 = doubleSize ? inst64pt2 : inst32pt2;
|
||||||
|
|
||||||
|
|
|
@ -559,7 +559,7 @@ namespace ARMeilleure.Instructions
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void EmitVectorShuffleOpSimd32(ArmEmitterContext context, Func<Operand, Operand, (Operand, Operand)> shuffleFunc)
|
private static void EmitVectorShuffleOpSimd32(ArmEmitterContext context, Func<Operand, Operand, (Operand, Operand)> shuffleFunc)
|
||||||
{
|
{
|
||||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||||
|
|
||||||
|
|
|
@ -563,6 +563,8 @@ namespace ARMeilleure.Instructions
|
||||||
Vdup,
|
Vdup,
|
||||||
Veor,
|
Veor,
|
||||||
Vext,
|
Vext,
|
||||||
|
Vfma,
|
||||||
|
Vfms,
|
||||||
Vld1,
|
Vld1,
|
||||||
Vld2,
|
Vld2,
|
||||||
Vld3,
|
Vld3,
|
||||||
|
|
|
@ -20,7 +20,7 @@ namespace ARMeilleure.Translation.PTC
|
||||||
{
|
{
|
||||||
private const string HeaderMagic = "PTChd";
|
private const string HeaderMagic = "PTChd";
|
||||||
|
|
||||||
private const int InternalVersion = 20; //! To be incremented manually for each change to the ARMeilleure project.
|
private const int InternalVersion = 1471; //! To be incremented manually for each change to the ARMeilleure project.
|
||||||
|
|
||||||
private const string BaseDir = "Ryujinx";
|
private const string BaseDir = "Ryujinx";
|
||||||
|
|
||||||
|
|
|
@ -7,9 +7,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="nunit" Version="3.12.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.15.1" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.2.0" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
|
@ -22,8 +22,4 @@
|
||||||
<Optimize>false</Optimize>
|
<Optimize>false</Optimize>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
</Project>
|
||||||
|
|
|
@ -205,7 +205,9 @@ namespace Ryujinx.Tests.Cpu
|
||||||
{
|
{
|
||||||
if (Ignore_FpcrFz_FpcrDn)
|
if (Ignore_FpcrFz_FpcrDn)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CS0162
|
||||||
fpcr &= ~((1 << (int)Fpcr.Fz) | (1 << (int)Fpcr.Dn));
|
fpcr &= ~((1 << (int)Fpcr.Fz) | (1 << (int)Fpcr.Dn));
|
||||||
|
#pragma warning restore CS0162
|
||||||
}
|
}
|
||||||
|
|
||||||
Opcode(opcode);
|
Opcode(opcode);
|
||||||
|
@ -319,7 +321,9 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
if (IgnoreAllExcept_FpsrQc)
|
if (IgnoreAllExcept_FpsrQc)
|
||||||
{
|
{
|
||||||
|
#pragma warning disable CS0162
|
||||||
fpsrMask &= Fpsr.Qc;
|
fpsrMask &= Fpsr.Qc;
|
||||||
|
#pragma warning restore CS0162
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fpSkips != FpSkips.None)
|
if (fpSkips != FpSkips.None)
|
||||||
|
|
|
@ -470,6 +470,11 @@ namespace Ryujinx.Tests.Cpu
|
||||||
|
|
||||||
protected static V128 MakeVectorE0E1(ulong e0, ulong e1) => new V128(e0, e1);
|
protected static V128 MakeVectorE0E1(ulong e0, ulong e1) => new V128(e0, e1);
|
||||||
|
|
||||||
|
protected static V128 MakeVectorE0E1E2E3(uint e0, uint e1, uint e2, uint e3)
|
||||||
|
{
|
||||||
|
return new V128(e0, e1, e2, e3);
|
||||||
|
}
|
||||||
|
|
||||||
protected static ulong GetVectorE0(V128 vector) => vector.Extract<ulong>(0);
|
protected static ulong GetVectorE0(V128 vector) => vector.Extract<ulong>(0);
|
||||||
protected static ulong GetVectorE1(V128 vector) => vector.Extract<ulong>(1);
|
protected static ulong GetVectorE1(V128 vector) => vector.Extract<ulong>(1);
|
||||||
|
|
||||||
|
|
220
Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs
Normal file
220
Ryujinx.Tests/Cpu/CpuTestSimdCvt32.cs
Normal file
|
@ -0,0 +1,220 @@
|
||||||
|
#define SimdCvt32
|
||||||
|
|
||||||
|
using ARMeilleure.State;
|
||||||
|
using NUnit.Framework;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
|
||||||
|
namespace Ryujinx.Tests.Cpu
|
||||||
|
{
|
||||||
|
[Category("SimdCvt32")]
|
||||||
|
public sealed class CpuTestSimdCvt32 : CpuTest32
|
||||||
|
{
|
||||||
|
#if SimdCvt32
|
||||||
|
|
||||||
|
#region "ValueSource (Opcodes)"
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region "ValueSource (Types)"
|
||||||
|
private static uint[] _1S_()
|
||||||
|
{
|
||||||
|
return new uint[] { 0x00000000u, 0x7FFFFFFFu,
|
||||||
|
0x80000000u, 0xFFFFFFFFu };
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<uint> _1S_F_()
|
||||||
|
{
|
||||||
|
yield return 0xFF7FFFFFu; // -Max Normal (float.MinValue)
|
||||||
|
yield return 0x80800000u; // -Min Normal
|
||||||
|
yield return 0x807FFFFFu; // -Max Subnormal
|
||||||
|
yield return 0x80000001u; // -Min Subnormal (-float.Epsilon)
|
||||||
|
yield return 0x7F7FFFFFu; // +Max Normal (float.MaxValue)
|
||||||
|
yield return 0x00800000u; // +Min Normal
|
||||||
|
yield return 0x007FFFFFu; // +Max Subnormal
|
||||||
|
yield return 0x00000001u; // +Min Subnormal (float.Epsilon)
|
||||||
|
|
||||||
|
if (!NoZeros)
|
||||||
|
{
|
||||||
|
yield return 0x80000000u; // -Zero
|
||||||
|
yield return 0x00000000u; // +Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoInfs)
|
||||||
|
{
|
||||||
|
yield return 0xFF800000u; // -Infinity
|
||||||
|
yield return 0x7F800000u; // +Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoNaNs)
|
||||||
|
{
|
||||||
|
yield return 0xFFC00000u; // -QNaN (all zeros payload) (float.NaN)
|
||||||
|
yield return 0xFFBFFFFFu; // -SNaN (all ones payload)
|
||||||
|
yield return 0x7FC00000u; // +QNaN (all zeros payload) (-float.NaN) (DefaultNaN)
|
||||||
|
yield return 0x7FBFFFFFu; // +SNaN (all ones payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||||
|
{
|
||||||
|
yield return GenNormalS();
|
||||||
|
yield return GenSubnormalS();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static IEnumerable<ulong> _1D_F_()
|
||||||
|
{
|
||||||
|
yield return 0xFFEFFFFFFFFFFFFFul; // -Max Normal (double.MinValue)
|
||||||
|
yield return 0x8010000000000000ul; // -Min Normal
|
||||||
|
yield return 0x800FFFFFFFFFFFFFul; // -Max Subnormal
|
||||||
|
yield return 0x8000000000000001ul; // -Min Subnormal (-double.Epsilon)
|
||||||
|
yield return 0x7FEFFFFFFFFFFFFFul; // +Max Normal (double.MaxValue)
|
||||||
|
yield return 0x0010000000000000ul; // +Min Normal
|
||||||
|
yield return 0x000FFFFFFFFFFFFFul; // +Max Subnormal
|
||||||
|
yield return 0x0000000000000001ul; // +Min Subnormal (double.Epsilon)
|
||||||
|
|
||||||
|
if (!NoZeros)
|
||||||
|
{
|
||||||
|
yield return 0x8000000000000000ul; // -Zero
|
||||||
|
yield return 0x0000000000000000ul; // +Zero
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoInfs)
|
||||||
|
{
|
||||||
|
yield return 0xFFF0000000000000ul; // -Infinity
|
||||||
|
yield return 0x7FF0000000000000ul; // +Infinity
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!NoNaNs)
|
||||||
|
{
|
||||||
|
yield return 0xFFF8000000000000ul; // -QNaN (all zeros payload) (double.NaN)
|
||||||
|
yield return 0xFFF7FFFFFFFFFFFFul; // -SNaN (all ones payload)
|
||||||
|
yield return 0x7FF8000000000000ul; // +QNaN (all zeros payload) (-double.NaN) (DefaultNaN)
|
||||||
|
yield return 0x7FF7FFFFFFFFFFFFul; // +SNaN (all ones payload)
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int cnt = 1; cnt <= RndCnt; cnt++)
|
||||||
|
{
|
||||||
|
yield return GenNormalD();
|
||||||
|
yield return GenSubnormalD();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
private const int RndCnt = 2;
|
||||||
|
|
||||||
|
private static readonly bool NoZeros = false;
|
||||||
|
private static readonly bool NoInfs = false;
|
||||||
|
private static readonly bool NoNaNs = false;
|
||||||
|
|
||||||
|
[Explicit]
|
||||||
|
[Test, Pairwise, Description("VCVT.<dt>.F32 <Sd>, <Sm>")]
|
||||||
|
public void Vcvt_F32_I32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||||
|
[ValueSource(nameof(_1S_F_))] uint s0,
|
||||||
|
[ValueSource(nameof(_1S_F_))] uint s1,
|
||||||
|
[ValueSource(nameof(_1S_F_))] uint s2,
|
||||||
|
[ValueSource(nameof(_1S_F_))] uint s3,
|
||||||
|
[Values] bool unsigned) // <U32, S32>
|
||||||
|
{
|
||||||
|
uint opcode = 0xeebc0ac0u; // VCVT.U32.F32 S0, S0
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 16; // opc2<0>
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||||
|
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Explicit]
|
||||||
|
[Test, Pairwise, Description("VCVT.<dt>.F64 <Sd>, <Dm>")]
|
||||||
|
public void Vcvt_F64_I32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||||
|
[Values(0u, 1u)] uint rm,
|
||||||
|
[ValueSource(nameof(_1D_F_))] ulong d0,
|
||||||
|
[ValueSource(nameof(_1D_F_))] ulong d1,
|
||||||
|
[Values] bool unsigned) // <U32, S32>
|
||||||
|
{
|
||||||
|
uint opcode = 0xeebc0bc0u; // VCVT.U32.F64 S0, D0
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 16; // opc2<0>
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||||
|
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1(d0, d1);
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Explicit]
|
||||||
|
[Test, Pairwise, Description("VCVT.F32.<dt> <Sd>, <Sm>")]
|
||||||
|
public void Vcvt_I32_F32([Values(0u, 1u, 2u, 3u)] uint rd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
|
||||||
|
[Values] bool unsigned, // <U32, S32>
|
||||||
|
[Values(RMode.Rn)] RMode rMode)
|
||||||
|
{
|
||||||
|
uint opcode = 0xeeb80a40u; // VCVT.F32.U32 S0, S0
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 7; // op
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||||
|
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||||
|
|
||||||
|
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0, fpscr: fpscr);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
|
||||||
|
[Explicit]
|
||||||
|
[Test, Pairwise, Description("VCVT.F64.<dt> <Dd>, <Sm>")]
|
||||||
|
public void Vcvt_I32_F64([Values(0u, 1u)] uint rd,
|
||||||
|
[Values(0u, 1u, 2u, 3u)] uint rm,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s0,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s1,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s2,
|
||||||
|
[ValueSource(nameof(_1S_))] [Random(RndCnt)] uint s3,
|
||||||
|
[Values] bool unsigned, // <U32, S32>
|
||||||
|
[Values(RMode.Rn)] RMode rMode)
|
||||||
|
{
|
||||||
|
uint opcode = 0xeeb80b40u; // VCVT.F64.U32 D0, S0
|
||||||
|
|
||||||
|
if (!unsigned)
|
||||||
|
{
|
||||||
|
opcode |= 1 << 7; // op
|
||||||
|
}
|
||||||
|
|
||||||
|
opcode |= ((rm & 0x1e) >> 1) | ((rm & 0x1) << 5);
|
||||||
|
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||||
|
|
||||||
|
V128 v0 = MakeVectorE0E1E2E3(s0, s1, s2, s3);
|
||||||
|
|
||||||
|
int fpscr = (int)rMode << (int)Fpcr.RMode;
|
||||||
|
|
||||||
|
SingleOpcode(opcode, v0: v0, fpscr: fpscr);
|
||||||
|
|
||||||
|
CompareAgainstUnicorn();
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
|
@ -28,9 +28,9 @@
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.5.0" />
|
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.7.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="NUnit3TestAdapter" Version="3.16.1" />
|
<PackageReference Include="NUnit3TestAdapter" Version="3.17.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
|
|
Loading…
Reference in a new issue