Add Sqxtn_S, Sqxtn_V, Uqxtn_S, Uqxtn_V instructions and Tests (6). (#110)
* Update ILGeneratorEx.cs * Update AOpCodeTable.cs * Update AInstEmitSimdArithmetic.cs * Update CpuTestSimd.cs * Update CpuTestSimdReg.cs * Update CpuTest.cs * Update Pseudocode.cs * Update Instructions.cs * Update AInstEmitSimdArithmetic.cs * Update AInstEmitSimdArithmetic.cs * Update AInstEmitSimdArithmetic.cs
This commit is contained in:
parent
071754aaeb
commit
7cda630aba
8 changed files with 673 additions and 43 deletions
|
@ -337,6 +337,8 @@ namespace ChocolArm64
|
|||
Set("0x001110<<1xxxxx011011xxxxxxxxxx", AInstEmit.Smin_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<1xxxxx100000xxxxxxxxxx", AInstEmit.Smlal_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Smull_V, typeof(AOpCodeSimdReg));
|
||||
Set("01011110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_S, typeof(AOpCodeSimd));
|
||||
Set("0x001110<<100001010010xxxxxxxxxx", AInstEmit.Sqxtn_V, typeof(AOpCodeSimd));
|
||||
Set("0>001110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Sshl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x00111100>>>xxx101001xxxxxxxxxx", AInstEmit.Sshll_V, typeof(AOpCodeSimdShImm));
|
||||
Set("010111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Sshr_S, typeof(AOpCodeSimdShImm));
|
||||
|
@ -370,6 +372,8 @@ namespace ChocolArm64
|
|||
Set("0x101110<<1xxxxx000001xxxxxxxxxx", AInstEmit.Uhadd_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x001110000xxxxx001111xxxxxxxxxx", AInstEmit.Umov_S, typeof(AOpCodeSimdIns));
|
||||
Set("0x101110<<1xxxxx110000xxxxxxxxxx", AInstEmit.Umull_V, typeof(AOpCodeSimdReg));
|
||||
Set("01111110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_S, typeof(AOpCodeSimd));
|
||||
Set("0x101110<<100001010010xxxxxxxxxx", AInstEmit.Uqxtn_V, typeof(AOpCodeSimd));
|
||||
Set("0>101110<<1xxxxx010001xxxxxxxxxx", AInstEmit.Ushl_V, typeof(AOpCodeSimdReg));
|
||||
Set("0x10111100>>>xxx101001xxxxxxxxxx", AInstEmit.Ushll_V, typeof(AOpCodeSimdShImm));
|
||||
Set("011111110>>>>xxx000001xxxxxxxxxx", AInstEmit.Ushr_S, typeof(AOpCodeSimdShImm));
|
||||
|
|
|
@ -205,6 +205,84 @@ namespace ChocolArm64.Instruction
|
|||
}
|
||||
}
|
||||
|
||||
private static void EmitQxtn(AILEmitterCtx Context, bool Signed, bool Scalar)
|
||||
{
|
||||
AOpCodeSimd Op = (AOpCodeSimd)Context.CurrOp;
|
||||
|
||||
int Elems = (!Scalar ? 8 >> Op.Size : 1);
|
||||
int ESize = 8 << Op.Size;
|
||||
|
||||
int TMaxValue = (Signed ? (1 << (ESize - 1)) - 1 : (int)((1L << ESize) - 1L));
|
||||
int TMinValue = (Signed ? -((1 << (ESize - 1))) : 0);
|
||||
|
||||
int Part = (!Scalar & (Op.RegisterSize == ARegisterSize.SIMD128) ? Elems : 0);
|
||||
|
||||
Context.EmitLdc_I8(0L);
|
||||
Context.EmitSttmp();
|
||||
|
||||
for (int Index = 0; Index < Elems; Index++)
|
||||
{
|
||||
AILLabel LblLe = new AILLabel();
|
||||
AILLabel LblGeEnd = new AILLabel();
|
||||
|
||||
EmitVectorExtract(Context, Op.Rn, Index, Op.Size + 1, Signed);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitLdc_I4(TMaxValue);
|
||||
Context.Emit(OpCodes.Conv_U8);
|
||||
|
||||
Context.Emit(Signed ? OpCodes.Ble_S : OpCodes.Ble_Un_S, LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I4(TMaxValue);
|
||||
|
||||
Context.EmitLdc_I8(0x8000000L);
|
||||
Context.EmitSttmp();
|
||||
|
||||
Context.Emit(OpCodes.Br_S, LblGeEnd);
|
||||
|
||||
Context.MarkLabel(LblLe);
|
||||
|
||||
Context.Emit(OpCodes.Dup);
|
||||
|
||||
Context.EmitLdc_I4(TMinValue);
|
||||
Context.Emit(OpCodes.Conv_I8);
|
||||
|
||||
Context.Emit(Signed ? OpCodes.Bge_S : OpCodes.Bge_Un_S, LblGeEnd);
|
||||
|
||||
Context.Emit(OpCodes.Pop);
|
||||
|
||||
Context.EmitLdc_I4(TMinValue);
|
||||
|
||||
Context.EmitLdc_I8(0x8000000L);
|
||||
Context.EmitSttmp();
|
||||
|
||||
Context.MarkLabel(LblGeEnd);
|
||||
|
||||
if (Scalar)
|
||||
{
|
||||
EmitVectorZeroLower(Context, Op.Rd);
|
||||
}
|
||||
|
||||
EmitVectorInsert(Context, Op.Rd, Part + Index, Op.Size);
|
||||
}
|
||||
|
||||
if (Part == 0)
|
||||
{
|
||||
EmitVectorZeroUpper(Context, Op.Rd);
|
||||
}
|
||||
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitLdarg(ATranslatedSub.StateArgIdx);
|
||||
Context.EmitCallPropGet(typeof(AThreadState), nameof(AThreadState.Fpsr));
|
||||
Context.EmitLdtmp();
|
||||
Context.Emit(OpCodes.Conv_I4);
|
||||
Context.Emit(OpCodes.Or);
|
||||
Context.EmitCallPropSet(typeof(AThreadState), nameof(AThreadState.Fpsr));
|
||||
}
|
||||
|
||||
public static void Fabd_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpF(Context, () =>
|
||||
|
@ -971,6 +1049,16 @@ namespace ChocolArm64.Instruction
|
|||
EmitVectorWidenRnRmBinaryOpSx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Sqxtn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitQxtn(Context, Signed: true, Scalar: true);
|
||||
}
|
||||
|
||||
public static void Sqxtn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitQxtn(Context, Signed: true, Scalar: false);
|
||||
}
|
||||
|
||||
public static void Sub_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitScalarBinaryOpZx(Context, () => Context.Emit(OpCodes.Sub));
|
||||
|
@ -1049,5 +1137,15 @@ namespace ChocolArm64.Instruction
|
|||
{
|
||||
EmitVectorWidenRnRmBinaryOpZx(Context, () => Context.Emit(OpCodes.Mul));
|
||||
}
|
||||
|
||||
public static void Uqxtn_S(AILEmitterCtx Context)
|
||||
{
|
||||
EmitQxtn(Context, Signed: false, Scalar: true);
|
||||
}
|
||||
|
||||
public static void Uqxtn_V(AILEmitterCtx Context)
|
||||
{
|
||||
EmitQxtn(Context, Signed: false, Scalar: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,7 +6,7 @@ namespace ChocolArm64
|
|||
|
||||
static class ILGeneratorEx
|
||||
{
|
||||
public static void EmitLdc_I4(this ILGenerator Generator,int Value)
|
||||
public static void EmitLdc_I4(this ILGenerator Generator, int Value)
|
||||
{
|
||||
switch (Value)
|
||||
{
|
||||
|
|
|
@ -55,7 +55,8 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
protected void SetThreadState(ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X3 = 0, ulong X31 = 0,
|
||||
AVec V0 = default(AVec), AVec V1 = default(AVec), AVec V2 = default(AVec),
|
||||
bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0)
|
||||
bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false,
|
||||
int Fpcr = 0x0, int Fpsr = 0x0)
|
||||
{
|
||||
Thread.ThreadState.X0 = X0;
|
||||
Thread.ThreadState.X1 = X1;
|
||||
|
@ -70,6 +71,7 @@ namespace Ryujinx.Tests.Cpu
|
|||
Thread.ThreadState.Zero = Zero;
|
||||
Thread.ThreadState.Negative = Negative;
|
||||
Thread.ThreadState.Fpcr = Fpcr;
|
||||
Thread.ThreadState.Fpsr = Fpsr;
|
||||
}
|
||||
|
||||
protected void ExecuteOpcodes()
|
||||
|
@ -92,12 +94,13 @@ namespace Ryujinx.Tests.Cpu
|
|||
protected AThreadState SingleOpcode(uint Opcode,
|
||||
ulong X0 = 0, ulong X1 = 0, ulong X2 = 0, ulong X3 = 0, ulong X31 = 0,
|
||||
AVec V0 = default(AVec), AVec V1 = default(AVec), AVec V2 = default(AVec),
|
||||
bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false, int Fpcr = 0x0)
|
||||
bool Overflow = false, bool Carry = false, bool Zero = false, bool Negative = false,
|
||||
int Fpcr = 0x0, int Fpsr = 0x0)
|
||||
{
|
||||
this.Opcode(Opcode);
|
||||
this.Opcode(0xD4200000); // BRK #0
|
||||
this.Opcode(0xD65F03C0); // RET
|
||||
SetThreadState(X0, X1, X2, X3, X31, V0, V1, V2, Overflow, Carry, Zero, Negative, Fpcr);
|
||||
SetThreadState(X0, X1, X2, X3, X31, V0, V1, V2, Overflow, Carry, Zero, Negative, Fpcr, Fpsr);
|
||||
ExecuteOpcodes();
|
||||
|
||||
return GetThreadState();
|
||||
|
|
|
@ -26,6 +26,23 @@ namespace Ryujinx.Tests.Cpu
|
|||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _1H1S1D_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x0000000000007FFFul,
|
||||
0x0000000000008000ul, 0x000000000000FFFFul,
|
||||
0x000000007FFFFFFFul, 0x0000000080000000ul,
|
||||
0x00000000FFFFFFFFul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _4H2S1D_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7FFF7FFF7FFF7FFFul,
|
||||
0x8000800080008000ul, 0x7FFFFFFF7FFFFFFFul,
|
||||
0x8000000080000000ul, 0x7FFFFFFFFFFFFFFFul,
|
||||
0x8000000000000000ul, 0xFFFFFFFFFFFFFFFFul };
|
||||
}
|
||||
|
||||
private static ulong[] _8B4H_()
|
||||
{
|
||||
return new ulong[] { 0x0000000000000000ul, 0x7F7F7F7F7F7F7F7Ful,
|
||||
|
@ -64,8 +81,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Abs_S(Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Description("ABS <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -83,8 +103,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Abs_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ABS <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -149,8 +172,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Addv_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDV <V><d>, <Vn>.<T>")]
|
||||
|
@ -194,8 +220,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Cls_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CLS <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -236,8 +265,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Clz_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("CLZ <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -276,8 +308,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Neg_S(Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Description("NEG <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -295,8 +330,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Neg_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("NEG <Vd>.<T>, <Vn>.<T>")]
|
||||
|
@ -321,6 +359,158 @@ namespace Ryujinx.Tests.Cpu
|
|||
Assert.That(ThreadState.V0.X1, Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Description("SQXTN <Vb><d>, <Va><n>")]
|
||||
public void Sqxtn_S_HB_SH_DS([ValueSource("_1H1S1D_")] [Random(1)] ulong A,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <HB, SH, DS>
|
||||
{
|
||||
uint Opcode = 0x5E214820; // SQXTN B0, H1
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
AVec V0 = new AVec { X0 = TestContext.CurrentContext.Random.NextULong(),
|
||||
X1 = TestContext.CurrentContext.Random.NextULong() };
|
||||
AVec V1 = new AVec { X0 = A };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(0, 0, new Bits(TestContext.CurrentContext.Random.NextULong()));
|
||||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Sqxtn_S(Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
|
||||
public void Sqxtn_V_8H8B_4S4H_2D2S([ValueSource("_4H2S1D_")] [Random(1)] ulong A0,
|
||||
[ValueSource("_4H2S1D_")] [Random(1)] ulong A1,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <8H8B, 4S4H, 2D2S>
|
||||
{
|
||||
uint Opcode = 0x0E214820; // SQXTN V0.8B, V1.8H
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
AVec V0 = new AVec { X1 = TestContext.CurrentContext.Random.NextULong() };
|
||||
AVec V1 = new AVec { X0 = A0, X1 = A1 };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(1, 0, new Bits(A0));
|
||||
AArch64.Vpart(1, 1, new Bits(A1));
|
||||
SimdFp.Sqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
|
||||
public void Sqxtn_V_8H16B_4S8H_2D4S([ValueSource("_4H2S1D_")] [Random(1)] ulong A0,
|
||||
[ValueSource("_4H2S1D_")] [Random(1)] ulong A1,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <8H16B, 4S8H, 2D4S>
|
||||
{
|
||||
uint Opcode = 0x4E214820; // SQXTN2 V0.16B, V1.8H
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
ulong _X0 = TestContext.CurrentContext.Random.NextULong();
|
||||
AVec V0 = new AVec { X0 = _X0 };
|
||||
AVec V1 = new AVec { X0 = A0, X1 = A1 };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(1, 0, new Bits(A0));
|
||||
AArch64.Vpart(1, 1, new Bits(A1));
|
||||
SimdFp.Sqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(_X0));
|
||||
Assert.That(ThreadState.V0.X1, Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
[Test, Description("UQXTN <Vb><d>, <Va><n>")]
|
||||
public void Uqxtn_S_HB_SH_DS([ValueSource("_1H1S1D_")] [Random(1)] ulong A,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <HB, SH, DS>
|
||||
{
|
||||
uint Opcode = 0x7E214820; // UQXTN B0, H1
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
AVec V0 = new AVec { X0 = TestContext.CurrentContext.Random.NextULong(),
|
||||
X1 = TestContext.CurrentContext.Random.NextULong() };
|
||||
AVec V1 = new AVec { X0 = A };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(0, 0, new Bits(TestContext.CurrentContext.Random.NextULong()));
|
||||
AArch64.V(1, new Bits(A));
|
||||
SimdFp.Uqxtn_S(Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
|
||||
public void Uqxtn_V_8H8B_4S4H_2D2S([ValueSource("_4H2S1D_")] [Random(1)] ulong A0,
|
||||
[ValueSource("_4H2S1D_")] [Random(1)] ulong A1,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <8H8B, 4S4H, 2D2S>
|
||||
{
|
||||
uint Opcode = 0x2E214820; // UQXTN V0.8B, V1.8H
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
AVec V0 = new AVec { X1 = TestContext.CurrentContext.Random.NextULong() };
|
||||
AVec V1 = new AVec { X0 = A0, X1 = A1 };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(1, 0, new Bits(A0));
|
||||
AArch64.Vpart(1, 1, new Bits(A1));
|
||||
SimdFp.Uqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("UQXTN{2} <Vd>.<Tb>, <Vn>.<Ta>")]
|
||||
public void Uqxtn_V_8H16B_4S8H_2D4S([ValueSource("_4H2S1D_")] [Random(1)] ulong A0,
|
||||
[ValueSource("_4H2S1D_")] [Random(1)] ulong A1,
|
||||
[Values(0b00u, 0b01u, 0b10u)] uint size) // <8H16B, 4S8H, 2D4S>
|
||||
{
|
||||
uint Opcode = 0x6E214820; // UQXTN2 V0.16B, V1.8H
|
||||
Opcode |= ((size & 3) << 22);
|
||||
Bits Op = new Bits(Opcode);
|
||||
|
||||
ulong _X0 = TestContext.CurrentContext.Random.NextULong();
|
||||
AVec V0 = new AVec { X0 = _X0 };
|
||||
AVec V1 = new AVec { X0 = A0, X1 = A1 };
|
||||
AThreadState ThreadState = SingleOpcode(Opcode, V0: V0, V1: V1);
|
||||
|
||||
AArch64.Vpart(1, 0, new Bits(A0));
|
||||
AArch64.Vpart(1, 1, new Bits(A1));
|
||||
SimdFp.Uqxtn_V(Op[30], Op[23, 22], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(_X0));
|
||||
Assert.That(ThreadState.V0.X1, Is.EqualTo(AArch64.Vpart(64, 0, 1).ToUInt64()));
|
||||
});
|
||||
Assert.That(((ThreadState.Fpsr >> 27) & 1) != 0, Is.EqualTo(Shared.FPSR[27])); // FIXME: Temporary solution.
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -74,8 +74,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Add_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Description("ADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -96,8 +99,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Add_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADD <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -205,8 +211,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Addp_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ADDP <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -253,8 +262,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.And_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("AND <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -299,8 +311,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Bic_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BIC <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -347,8 +362,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Bif_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BIF <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -400,8 +418,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Bit_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BIT <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -453,8 +474,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Bsl_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("BSL <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -504,8 +528,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Orn_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORN <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -550,8 +577,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Orr_V(Op[30], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("ORR <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -714,8 +744,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Sub_S(Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Description("SUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
@ -736,8 +769,11 @@ namespace Ryujinx.Tests.Cpu
|
|||
AArch64.V(2, new Bits(B));
|
||||
SimdFp.Sub_V(Op[30], Op[23, 22], Op[20, 16], Op[9, 5], Op[4, 0]);
|
||||
|
||||
Assert.Multiple(() =>
|
||||
{
|
||||
Assert.That(ThreadState.V0.X0, Is.EqualTo(AArch64.V(64, 0).ToUInt64()));
|
||||
Assert.That(ThreadState.V0.X1, Is.Zero);
|
||||
});
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("SUB <Vd>.<T>, <Vn>.<T>, <Vm>.<T>")]
|
||||
|
|
|
@ -21,6 +21,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -37,6 +38,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -53,6 +55,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -75,6 +78,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
int container_size = 16;
|
||||
|
@ -113,6 +117,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
int container_size = 32;
|
||||
|
@ -187,6 +192,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -225,6 +231,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -259,6 +266,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -288,6 +296,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -312,6 +321,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -341,6 +351,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -370,6 +381,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -409,6 +421,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits imm;
|
||||
|
@ -447,6 +460,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -466,6 +480,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -488,6 +503,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if shift == '11' then ReservedValue(); */
|
||||
|
@ -513,6 +529,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if shift == '11' then ReservedValue(); */
|
||||
|
@ -541,6 +558,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -564,6 +582,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -591,6 +610,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ShiftType shift_type = DecodeShift(op2);
|
||||
|
@ -610,6 +630,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -635,6 +656,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -716,6 +738,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -741,6 +764,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -764,6 +788,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if N != sf then UnallocatedEncoding(); */
|
||||
|
@ -790,6 +815,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ShiftType shift_type = DecodeShift(op2);
|
||||
|
@ -811,6 +837,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ShiftType shift_type = DecodeShift(op2);
|
||||
|
@ -830,6 +857,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -855,6 +883,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && imm6<5> == '1' then ReservedValue(); */
|
||||
|
@ -880,6 +909,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ShiftType shift_type = DecodeShift(op2);
|
||||
|
@ -899,6 +929,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -920,6 +951,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -944,6 +976,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -970,6 +1003,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if shift == '11' then ReservedValue(); */
|
||||
|
@ -997,6 +1031,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if shift == '11' then ReservedValue(); */
|
||||
|
@ -1027,6 +1062,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1055,6 +1091,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ExtendType extend_type = DecodeRegExtend(option);
|
||||
|
@ -1086,6 +1123,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ExtendType extend_type = DecodeRegExtend(option);
|
||||
|
@ -1113,6 +1151,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ExtendType extend_type = DecodeRegExtend(option);
|
||||
|
@ -1146,6 +1185,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
ExtendType extend_type = DecodeRegExtend(option);
|
||||
|
@ -1176,6 +1216,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
int R;
|
||||
|
@ -1205,6 +1246,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
int R;
|
||||
|
@ -1238,6 +1280,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
int R;
|
||||
|
@ -1267,6 +1310,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
{
|
||||
/* Decode */
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits flags = nzcv;
|
||||
|
@ -1288,6 +1332,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
{
|
||||
/* Decode */
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits flags = nzcv;
|
||||
|
@ -1314,6 +1359,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits flags = nzcv;
|
||||
|
@ -1336,6 +1382,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
/* Decode */
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
Bits flags = nzcv;
|
||||
|
@ -1362,6 +1409,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1388,6 +1436,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1414,6 +1463,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1440,6 +1490,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1467,6 +1518,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
{
|
||||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && hw<1> == '1' then UnallocatedEncoding(); */
|
||||
|
@ -1486,6 +1538,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
{
|
||||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && hw<1> == '1' then UnallocatedEncoding(); */
|
||||
|
@ -1506,6 +1559,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
{
|
||||
/* Decode */
|
||||
int d = (int)UInt(Rd);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* if sf == '0' && hw<1> == '1' then UnallocatedEncoding(); */
|
||||
|
@ -1530,6 +1584,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
int a = (int)UInt(Ra);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1550,6 +1605,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
int n = (int)UInt(Rn);
|
||||
int m = (int)UInt(Rm);
|
||||
int a = (int)UInt(Ra);
|
||||
|
||||
int datasize = (sf ? 64 : 32);
|
||||
|
||||
/* Operation */
|
||||
|
@ -1983,6 +2039,182 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
|
||||
V(d, result);
|
||||
}
|
||||
|
||||
// https://meriac.github.io/archex/A64_v83A_ISA/sqxtn_advsimd.xml#SQXTN_asisdmisc_N
|
||||
public static void Sqxtn_S(Bits size, Bits Rn, Bits Rd)
|
||||
{
|
||||
bool U = false;
|
||||
|
||||
/* Decode Scalar */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
/* if size == '11' then ReservedValue(); */
|
||||
|
||||
int esize = 8 << (int)UInt(size);
|
||||
int datasize = esize;
|
||||
int part = 0;
|
||||
int elements = 1;
|
||||
|
||||
bool unsigned = (U == true);
|
||||
|
||||
/* Operation */
|
||||
/* CheckFPAdvSIMDEnabled64(); */
|
||||
|
||||
Bits result = new Bits(datasize);
|
||||
Bits operand = V(2 * datasize, n);
|
||||
Bits element;
|
||||
bool sat;
|
||||
|
||||
for (int e = 0; e <= elements - 1; e++)
|
||||
{
|
||||
element = Elem(operand, e, 2 * esize);
|
||||
|
||||
(Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
|
||||
Elem(result, e, esize, _result);
|
||||
sat = _sat;
|
||||
|
||||
if (sat)
|
||||
{
|
||||
/* FPSR.QC = '1'; */
|
||||
FPSR[27] = true; // FIXME: Temporary solution.
|
||||
}
|
||||
}
|
||||
|
||||
Vpart(d, part, result);
|
||||
}
|
||||
|
||||
// https://meriac.github.io/archex/A64_v83A_ISA/sqxtn_advsimd.xml#SQXTN_asimdmisc_N
|
||||
public static void Sqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
|
||||
{
|
||||
bool U = false;
|
||||
|
||||
/* Decode Vector */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
/* if size == '11' then ReservedValue(); */
|
||||
|
||||
int esize = 8 << (int)UInt(size);
|
||||
int datasize = 64;
|
||||
int part = (int)UInt(Q);
|
||||
int elements = datasize / esize;
|
||||
|
||||
bool unsigned = (U == true);
|
||||
|
||||
/* Operation */
|
||||
/* CheckFPAdvSIMDEnabled64(); */
|
||||
|
||||
Bits result = new Bits(datasize);
|
||||
Bits operand = V(2 * datasize, n);
|
||||
Bits element;
|
||||
bool sat;
|
||||
|
||||
for (int e = 0; e <= elements - 1; e++)
|
||||
{
|
||||
element = Elem(operand, e, 2 * esize);
|
||||
|
||||
(Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
|
||||
Elem(result, e, esize, _result);
|
||||
sat = _sat;
|
||||
|
||||
if (sat)
|
||||
{
|
||||
/* FPSR.QC = '1'; */
|
||||
FPSR[27] = true; // FIXME: Temporary solution.
|
||||
}
|
||||
}
|
||||
|
||||
Vpart(d, part, result);
|
||||
}
|
||||
|
||||
// https://meriac.github.io/archex/A64_v83A_ISA/uqxtn_advsimd.xml#UQXTN_asisdmisc_N
|
||||
public static void Uqxtn_S(Bits size, Bits Rn, Bits Rd)
|
||||
{
|
||||
bool U = true;
|
||||
|
||||
/* Decode Scalar */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
/* if size == '11' then ReservedValue(); */
|
||||
|
||||
int esize = 8 << (int)UInt(size);
|
||||
int datasize = esize;
|
||||
int part = 0;
|
||||
int elements = 1;
|
||||
|
||||
bool unsigned = (U == true);
|
||||
|
||||
/* Operation */
|
||||
/* CheckFPAdvSIMDEnabled64(); */
|
||||
|
||||
Bits result = new Bits(datasize);
|
||||
Bits operand = V(2 * datasize, n);
|
||||
Bits element;
|
||||
bool sat;
|
||||
|
||||
for (int e = 0; e <= elements - 1; e++)
|
||||
{
|
||||
element = Elem(operand, e, 2 * esize);
|
||||
|
||||
(Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
|
||||
Elem(result, e, esize, _result);
|
||||
sat = _sat;
|
||||
|
||||
if (sat)
|
||||
{
|
||||
/* FPSR.QC = '1'; */
|
||||
FPSR[27] = true; // FIXME: Temporary solution.
|
||||
}
|
||||
}
|
||||
|
||||
Vpart(d, part, result);
|
||||
}
|
||||
|
||||
// https://meriac.github.io/archex/A64_v83A_ISA/uqxtn_advsimd.xml#UQXTN_asimdmisc_N
|
||||
public static void Uqxtn_V(bool Q, Bits size, Bits Rn, Bits Rd)
|
||||
{
|
||||
bool U = true;
|
||||
|
||||
/* Decode Vector */
|
||||
int d = (int)UInt(Rd);
|
||||
int n = (int)UInt(Rn);
|
||||
|
||||
/* if size == '11' then ReservedValue(); */
|
||||
|
||||
int esize = 8 << (int)UInt(size);
|
||||
int datasize = 64;
|
||||
int part = (int)UInt(Q);
|
||||
int elements = datasize / esize;
|
||||
|
||||
bool unsigned = (U == true);
|
||||
|
||||
/* Operation */
|
||||
/* CheckFPAdvSIMDEnabled64(); */
|
||||
|
||||
Bits result = new Bits(datasize);
|
||||
Bits operand = V(2 * datasize, n);
|
||||
Bits element;
|
||||
bool sat;
|
||||
|
||||
for (int e = 0; e <= elements - 1; e++)
|
||||
{
|
||||
element = Elem(operand, e, 2 * esize);
|
||||
|
||||
(Bits _result, bool _sat) = SatQ(Int(element, unsigned), esize, unsigned);
|
||||
Elem(result, e, esize, _result);
|
||||
sat = _sat;
|
||||
|
||||
if (sat)
|
||||
{
|
||||
/* FPSR.QC = '1'; */
|
||||
FPSR[27] = true; // FIXME: Temporary solution.
|
||||
}
|
||||
}
|
||||
|
||||
Vpart(d, part, result);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "SimdReg"
|
||||
|
|
|
@ -104,6 +104,8 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
SP_EL0.SetAll(false);
|
||||
/* SP_EL1 = bits(64) UNKNOWN; */
|
||||
SP_EL1.SetAll(false);
|
||||
|
||||
FPSR.SetAll(false); // FIXME: Temporary solution.
|
||||
}
|
||||
|
||||
// #impl-aarch64.SP.write.0
|
||||
|
@ -518,6 +520,8 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
SP_EL0 = new Bits(64, false);
|
||||
SP_EL1 = new Bits(64, false);
|
||||
|
||||
FPSR = new Bits(32, false); // FIXME: Temporary solution.
|
||||
|
||||
PSTATE.N = false;
|
||||
PSTATE.Z = false;
|
||||
PSTATE.C = false;
|
||||
|
@ -1016,6 +1020,8 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
|
||||
public static Bits SP_EL0;
|
||||
public static Bits SP_EL1;
|
||||
|
||||
public static Bits FPSR; // FIXME: Temporary solution.
|
||||
#endregion
|
||||
|
||||
#region "functions/system/"
|
||||
|
@ -1081,6 +1087,7 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
return true; // EL1 and EL0 must exist
|
||||
}
|
||||
|
||||
/* return boolean IMPLEMENTATION_DEFINED; */
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -1113,5 +1120,65 @@ namespace Ryujinx.Tests.Cpu.Tester
|
|||
public bool SP; // Stack pointer select: 0=SP0, 1=SPx [AArch64 only]
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region "functions/vector/"
|
||||
// #impl-shared.SatQ.3
|
||||
public static (Bits, bool) SatQ(BigInteger i, int N, bool unsigned)
|
||||
{
|
||||
(Bits result, bool sat) = (unsigned ? UnsignedSatQ(i, N) : SignedSatQ(i, N));
|
||||
|
||||
return (result, sat);
|
||||
}
|
||||
|
||||
// #impl-shared.SignedSatQ.2
|
||||
public static (Bits, bool) SignedSatQ(BigInteger i, int N)
|
||||
{
|
||||
BigInteger result;
|
||||
bool saturated;
|
||||
|
||||
if (i > BigInteger.Pow(2, N - 1) - 1)
|
||||
{
|
||||
result = BigInteger.Pow(2, N - 1) - 1;
|
||||
saturated = true;
|
||||
}
|
||||
else if (i < -(BigInteger.Pow(2, N - 1)))
|
||||
{
|
||||
result = -(BigInteger.Pow(2, N - 1));
|
||||
saturated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = i;
|
||||
saturated = false;
|
||||
}
|
||||
|
||||
return (result.SubBigInteger(N - 1, 0), saturated);
|
||||
}
|
||||
|
||||
// #impl-shared.UnsignedSatQ.2
|
||||
public static (Bits, bool) UnsignedSatQ(BigInteger i, int N)
|
||||
{
|
||||
BigInteger result;
|
||||
bool saturated;
|
||||
|
||||
if (i > BigInteger.Pow(2, N) - 1)
|
||||
{
|
||||
result = BigInteger.Pow(2, N) - 1;
|
||||
saturated = true;
|
||||
}
|
||||
else if (i < 0)
|
||||
{
|
||||
result = 0;
|
||||
saturated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = i;
|
||||
saturated = false;
|
||||
}
|
||||
|
||||
return (result.SubBigInteger(N - 1, 0), saturated);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue