Fix way too many instruction bugs, add tests for some of the more important ones.
This commit is contained in:
parent
012fcc6c06
commit
85a8d1bb9f
21 changed files with 637 additions and 108 deletions
|
@ -25,7 +25,7 @@ namespace ARMeilleure.Decoders
|
|||
Size = 0;
|
||||
Index = (opc >> 1) & 0x7;
|
||||
}
|
||||
else if ((opc & 0b11) != 0b10)
|
||||
else if ((opc & 0b11) == 0b10)
|
||||
{
|
||||
Size = 1;
|
||||
Index = (opc >> 2) & 0x3;
|
||||
|
@ -43,6 +43,7 @@ namespace ARMeilleure.Decoders
|
|||
Vd = ((opCode >> 18) & 0x10) | ((opCode >> 12) & 0xf);
|
||||
Vm = ((opCode >> 1) & 0x10) | ((opCode >> 0) & 0xf);
|
||||
Q = (opCode & (1 << 6)) != 0;
|
||||
if (Q) RegisterSize = RegisterSize.Simd128;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,7 +21,7 @@ namespace ARMeilleure.Decoders
|
|||
Rt = (opCode >> 12) & 0xf;
|
||||
Rt2 = (opCode >> 16) & 0xf;
|
||||
|
||||
bool single = (opCode & (1 << 8)) != 0;
|
||||
bool single = (opCode & (1 << 8)) == 0;
|
||||
if (single)
|
||||
{
|
||||
Vm = ((opCode >> 5) & 0x1) | ((opCode << 1) & 0x1e);
|
||||
|
|
|
@ -22,19 +22,19 @@ namespace ARMeilleure.Decoders
|
|||
Op = ((opCode >> 20) & 0x1);
|
||||
U = ((opCode >> 23) & 1) != 0;
|
||||
|
||||
var opc = (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
||||
var opc = (((opCode >> 23) & 1) << 4) | (((opCode >> 21) & 0x3) << 2) | ((opCode >> 5) & 0x3);
|
||||
|
||||
if ((opc & 0x8) != 0)
|
||||
if ((opc & 0b01000) == 0b01000)
|
||||
{
|
||||
Size = 0;
|
||||
Index = opc & 0x7;
|
||||
}
|
||||
else if ((opc & 0x1) != 0)
|
||||
else if ((opc & 0b01001) == 0b00001)
|
||||
{
|
||||
Size = 1;
|
||||
Index = (opc >> 1) & 0x3;
|
||||
}
|
||||
else if ((opc & 0x2) == 0)
|
||||
else if ((opc & 0b11011) == 0)
|
||||
{
|
||||
Size = 2;
|
||||
Index = (opc >> 2) & 0x1;
|
||||
|
|
18
ARMeilleure/Decoders/OpCode32SimdRev.cs
Normal file
18
ARMeilleure/Decoders/OpCode32SimdRev.cs
Normal file
|
@ -0,0 +1,18 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace ARMeilleure.Decoders
|
||||
{
|
||||
class OpCode32SimdRev : OpCode32SimdCmpZ
|
||||
{
|
||||
public OpCode32SimdRev(InstDescriptor inst, ulong address, int opCode) : base(inst, address, opCode)
|
||||
{
|
||||
// Currently, this instruction is treated as though it's OPCODE is the true size.
|
||||
// which lets us deal with reversing vectors on a single element basis (eg. math magic an I64 rather than insert lots of I8s)
|
||||
int tempSize = Size;
|
||||
Size = 3 - Opc; //op 0 is 64 bit, 1 is 32 and so on.
|
||||
Opc = tempSize;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -631,6 +631,7 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("<<<<0010001xxxxxxxxxxxxxxxxxxxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluImm));
|
||||
SetA32("<<<<0000001xxxxxxxxxxxxxxxx0xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsImm));
|
||||
SetA32("<<<<0000001xxxxxxxxxxxxx0xx1xxxx", InstName.Eor, InstEmit32.Eor, typeof(OpCode32AluRsReg));
|
||||
SetA32("1111010101111111111100000110xxxx", InstName.Isb, InstEmit32.Nop, typeof(OpCode32));
|
||||
SetA32("<<<<00011001xxxxxxxx110010011111", InstName.Lda, InstEmit32.Lda, typeof(OpCode32MemLdEx));
|
||||
SetA32("<<<<00011101xxxxxxxx110010011111", InstName.Ldab, InstEmit32.Ldab, typeof(OpCode32MemLdEx));
|
||||
SetA32("<<<<00011001xxxxxxxx111010011111", InstName.Ldaex, InstEmit32.Ldaex, typeof(OpCode32MemLdEx));
|
||||
|
@ -768,20 +769,17 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("1111001x0xxxxxxxxxxx0011xxx0xxxx", InstName.Vcgt, InstEmit32.Vcgt_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x011xx0xxxx", InstName.Vcle, InstEmit32.Vcle_Z, typeof(OpCode32SimdCmpZ));
|
||||
//SetA32("111100110x0xxxxxxxxx1110xxx0xxxx", InstName.Vcle, InstEmit32.Vcle_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
//SetA32("1111001x0xxxxxxxxxxx0011xxx1xxxx", InstName.Vcle, InstEmit32.Vcle_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x100xx0xxxx", InstName.Vclt, InstEmit32.Vclt_Z, typeof(OpCode32SimdCmpZ));
|
||||
//SetA32("111100110x1xxxxxxxxx1110xxx0xxxx", InstName.Vclt, InstEmit32.Vclt_V, typeof(OpCode32SimdReg)); //note: size is 16/32 only
|
||||
//SetA32("1111001x0xxxxxxxxxxx0011xxx0xxxx", InstName.Vclt, InstEmit32.Vclt_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("<<<<11101x11010xxxxx10xx01x0xxxx", InstName.Vcmp, InstEmit32.Vcmp, typeof(OpCode32SimdS));
|
||||
SetA32("<<<<11101x11010xxxxx10xx11x0xxxx", InstName.Vcmpe,InstEmit32.Vcmpe, typeof(OpCode32SimdS));
|
||||
SetA32("111100111x11xx11xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ));
|
||||
SetA32("<<<<11101x110111xxxx101x11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FD, typeof(OpCode32SimdS));
|
||||
SetA32("<<<<11101x11110xxxxx10xx11x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("<<<<11101x111000xxxx10xxx1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_FI, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("111111101x1111xxxxxx10<<x1x0xxxx", InstName.Vcvt, InstEmit32.Vcvt_R, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("111100111x11xx11xxxx011xxxx0xxxx", InstName.Vcvt, InstEmit32.Vcvt_V, typeof(OpCode32SimdCmpZ)); // fp and integer, vector
|
||||
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("<<<<11101x111000xxxx10xxx1x0xxxx", 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("<<<<11101x00xxxxxxxx10xxx0x0xxxx", InstName.Vdiv, InstEmit32.Vdiv_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("<<<<11101xx0xxxxxxxx1011x0x10000", InstName.Vdup, InstEmit32.Vdup, typeof(OpCode32SimdVdupGP));
|
||||
SetA32("111100111x11xxxxxxxx11000xx0xxxx", InstName.Vdup, InstEmit32.Vdup_1, typeof(OpCode32SimdDupElem));
|
||||
|
@ -790,32 +788,20 @@ namespace ARMeilleure.Decoders
|
|||
|
||||
// VLD# missing single to all lanes
|
||||
|
||||
SetA32("111101001x10xxxxxxxx0000xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx0100xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1000xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1100xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle)); //all lanes
|
||||
SetA32("111101001x10xxxxxxxxxx00xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x10xxxxxxxx0111xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); //regs = 1
|
||||
SetA32("111101000x10xxxxxxxx1010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); //regs = 2
|
||||
SetA32("111101000x10xxxxxxxx0110xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); //regs = 3
|
||||
SetA32("111101000x10xxxxxxxx0010xxxxxxxx", InstName.Vld1, InstEmit32.Vld1, typeof(OpCode32SimdMemPair)); //regs = 4
|
||||
|
||||
SetA32("111101001x10xxxxxxxx0001xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx0101xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1001xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1101xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemSingle)); //all lanes
|
||||
SetA32("111101001x10xxxxxxxxxx01xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x10xxxxxxxx100xxxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemPair)); //regs = 1, inc = 1/2 (itype)
|
||||
SetA32("111101000x10xxxxxxxx0011xxxxxxxx", InstName.Vld2, InstEmit32.Vld2, typeof(OpCode32SimdMemPair)); //regs = 2, inc = 2
|
||||
|
||||
SetA32("111101001x10xxxxxxxx0010xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx0110xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1010xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1110xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemSingle)); //all lanes
|
||||
SetA32("111101001x10xxxxxxxxxx10xxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x10xxxxxxxx010xxxxxxxxx", InstName.Vld3, InstEmit32.Vld3, typeof(OpCode32SimdMemPair)); //inc = 1/2 (itype)
|
||||
|
||||
SetA32("111101001x10xxxxxxxx0011xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx0111xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1011xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x10xxxxxxxx1111xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemSingle)); //all lanes
|
||||
SetA32("111101001x10xxxxxxxxxx11xxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x10xxxxxxxx000xxxxxxxxx", InstName.Vld4, InstEmit32.Vld4, typeof(OpCode32SimdMemPair)); //inc = 1/2 (itype)
|
||||
|
||||
SetA32("<<<<11001x01xxxxxxxx1011xxxxxxx0", InstName.Vldm, InstEmit32.Vldm, typeof(OpCode32SimdMemMult));
|
||||
|
@ -834,7 +820,7 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("111100100x1xxxxxxxxx1111xxx0xxxx", InstName.Vmin, InstEmit32.Vmin_V, typeof(OpCode32SimdReg));
|
||||
SetA32("1111001x0xxxxxxxxxxx0110xxx1xxxx", InstName.Vmin, InstEmit32.Vmin_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111111101x00xxxxxxxx10xxxxx0xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("111111101x00xxxxxxxx10>>xxx0xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_S, typeof(OpCode32SimdRegS));
|
||||
SetA32("111100110xxxxxxxxxxx1111xxx1xxxx", InstName.VMMmn, InstEmit32.VmaxminNm_V, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("<<<<11100x00xxxxxxxx10xxx0x0xxxx", InstName.Vmla, InstEmit32.Vmla_S, typeof(OpCode32SimdRegS));
|
||||
|
@ -868,6 +854,10 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("1111001x0xxxxxxxxxxx1001xxx1xxxx", InstName.Vmul, InstEmit32.Vmul_I, typeof(OpCode32SimdReg));
|
||||
SetA32("1111001x1x<<xxxxxxxx100xx1x0xxxx", InstName.Vmul, InstEmit32.Vmul_1, typeof(OpCode32SimdRegElem));
|
||||
|
||||
SetA32("1111001x1x000xxxxxxx0xx00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, typeof(OpCode32SimdImm)); //d/q vector i32
|
||||
SetA32("1111001x1x000xxxxxxx10x00x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, typeof(OpCode32SimdImm));
|
||||
SetA32("1111001x1x000xxxxxxx110x0x11xxxx", InstName.Vmvn, InstEmit32.Vmvn_I, typeof(OpCode32SimdImm));
|
||||
|
||||
SetA32("111100111x11xx01xxxx0x111xx0xxxx", InstName.Vneg, InstEmit32.Vneg_V, typeof(OpCode32Simd));
|
||||
SetA32("<<<<11101x110001xxxx10xx01x0xxxx", InstName.Vneg, InstEmit32.Vneg_S, typeof(OpCode32SimdS));
|
||||
|
||||
|
@ -878,38 +868,31 @@ namespace ARMeilleure.Decoders
|
|||
SetA32("111100100x10xxxxxxxx0001xxx1xxxx", InstName.Vorr, InstEmit32.Vorr_I, typeof(OpCode32SimdBinary));
|
||||
|
||||
SetA32("111100110x0xxxxxxxxx1101xxx0xxxx", InstName.Vpadd, InstEmit32.Vpadd_V, typeof(OpCode32SimdReg));
|
||||
SetA32("1111001x0xxxxxxxxxxx1010x0x0xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, typeof(OpCode32SimdReg));
|
||||
SetA32("111100100xxxxxxxxxxx1011xxx1xxxx", InstName.Vpadd, InstEmit32.Vpadd_I, typeof(OpCode32SimdReg));
|
||||
|
||||
SetA32("111111101x1110xxxxxx10<<01x0xxxx", InstName.Vrint, InstEmit32.Vrint_R, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("111100111x11xx00xxxx000<<xx0xxxx", InstName.Vrev, InstEmit32.Vrev, typeof(OpCode32SimdRev));
|
||||
SetA32("111111101x1110xxxxxx10>>01x0xxxx", InstName.Vrint, InstEmit32.Vrint_RM, typeof(OpCode32SimdCvtFI));
|
||||
SetA32("<<<<11101x110110xxxx10xx11x0xxxx", InstName.Vrint, InstEmit32.Vrint_Z, typeof(OpCode32SimdCvtFI));
|
||||
|
||||
SetA32("111111100xxxxxxxxxxx10xxx0x0xxxx", InstName.Vsel, InstEmit32.Vsel, typeof(OpCode32SimdSel));
|
||||
SetA32("111111100xxxxxxxxxxx10>>x0x0xxxx", InstName.Vsel, InstEmit32.Vsel, typeof(OpCode32SimdSel));
|
||||
|
||||
SetA32("1111001x0xxxxxxxxxxx0100xxx0xxxx", InstName.Vshl, InstEmit32.Vshl_I, typeof(OpCode32SimdReg));
|
||||
SetA32("111100101xxxxxxxxxxx0101xxx1xxxx", InstName.Vshl, InstEmit32.Vshl, typeof(OpCode32SimdShift));
|
||||
SetA32("111100101x>>>xxxxxxx0101>xx1xxxx", InstName.Vshl, InstEmit32.Vshl, typeof(OpCode32SimdShift));
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx0100xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx1000xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx<<00xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x00xxxxxxxx0111xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemPair)); //regs = 1
|
||||
SetA32("111101000x00xxxxxxxx1010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemPair)); //regs = 2
|
||||
SetA32("111101000x00xxxxxxxx0110xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemPair)); //regs = 3
|
||||
SetA32("111101000x00xxxxxxxx0010xxxxxxxx", InstName.Vst1, InstEmit32.Vst1, typeof(OpCode32SimdMemPair)); //regs = 4
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0001xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx0101xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx1001xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx<<01xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x00xxxxxxxx100xxxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemPair)); //regs = 1, inc = 1/2 (itype)
|
||||
SetA32("111101000x00xxxxxxxx0011xxxxxxxx", InstName.Vst2, InstEmit32.Vst2, typeof(OpCode32SimdMemPair)); //regs = 2, inc = 2
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0010xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx0110xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx1010xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx<<10xxxxxxxx", InstName.Vst3, InstEmit32.Vst3, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x00xxxxxxxx010xxxxxxxxx", InstName.Vst3, InstEmit32.Vst3, typeof(OpCode32SimdMemPair)); //inc = 1/2 (itype)
|
||||
|
||||
SetA32("111101001x00xxxxxxxx0011xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx0111xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx1011xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101001x00xxxxxxxx<<11xxxxxxxx", InstName.Vst4, InstEmit32.Vst4, typeof(OpCode32SimdMemSingle));
|
||||
SetA32("111101000x00xxxxxxxx000xxxxxxxxx", InstName.Vst4, InstEmit32.Vst4, typeof(OpCode32SimdMemPair)); //inc = 1/2 (itype)
|
||||
|
||||
SetA32("<<<<11001x00xxxxxxxx1011xxxxxxx0", InstName.Vstm, InstEmit32.Vstm, typeof(OpCode32SimdMemMult));
|
||||
|
|
|
@ -367,7 +367,7 @@ namespace ARMeilleure.Instructions
|
|||
SetAluDOrZR(context, d);
|
||||
}
|
||||
|
||||
private static Operand EmitReverseBytes32_64Op(ArmEmitterContext context, Operand op)
|
||||
public static Operand EmitReverseBytes32_64Op(ArmEmitterContext context, Operand op)
|
||||
{
|
||||
Debug.Assert(op.Type == OperandType.I64);
|
||||
|
||||
|
|
|
@ -581,7 +581,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
Operand m = GetAluM(context);
|
||||
|
||||
Operand res = context.Call(new _U32_U32(System.Buffers.Binary.BinaryPrimitives.ReverseEndianness), m);
|
||||
Operand res = context.ByteSwap(m);
|
||||
|
||||
EmitAluStore(context, res);
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ using static ARMeilleure.Instructions.InstEmitSimdHelper;
|
|||
using static ARMeilleure.Instructions.InstEmitSimdHelper32;
|
||||
using static ARMeilleure.Instructions.InstEmitFlowHelper;
|
||||
using static ARMeilleure.IntermediateRepresentation.OperandHelper;
|
||||
using System.Diagnostics;
|
||||
|
||||
namespace ARMeilleure.Instructions
|
||||
{
|
||||
|
@ -86,7 +87,7 @@ namespace ARMeilleure.Instructions
|
|||
InsertScalar(context, op.Vd, insert);
|
||||
if (op.Q)
|
||||
{
|
||||
InsertScalar(context, op.Vd | 1, insert);
|
||||
InsertScalar(context, op.Vd + 1, insert);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -179,7 +180,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private static void EmitBifBit(ArmEmitterContext context, bool notRm)
|
||||
{
|
||||
OpCodeSimdReg op = (OpCodeSimdReg)context.CurrOp;
|
||||
OpCode32SimdReg op = (OpCode32SimdReg)context.CurrOp;
|
||||
|
||||
/*
|
||||
if (Optimizations.UseSse2)
|
||||
|
@ -357,7 +358,6 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
}
|
||||
|
||||
//TODO: probably important to have a fast path for these instead of calling fucking standard math min/max
|
||||
public static void VmaxminNm_S(ArmEmitterContext context)
|
||||
{
|
||||
bool max = (context.CurrOp.RawOpCode & (1 << 6)) == 0;
|
||||
|
@ -408,6 +408,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void Vmul_I(ArmEmitterContext context)
|
||||
{
|
||||
if (((context.CurrOp.RawOpCode >> 24) & 1) != 0) throw new Exception("Polynomial mode not supported");
|
||||
EmitVectorBinaryOpSx32(context, (op1, op2) => context.Multiply(op1, op2));
|
||||
}
|
||||
|
||||
|
@ -558,6 +559,52 @@ namespace ARMeilleure.Instructions
|
|||
EmitVectorPairwiseOpI32(context, (op1, op2) => context.Add(op1, op2), !op.U);
|
||||
}
|
||||
|
||||
public static void Vrev(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32Simd op = (OpCode32Simd)context.CurrOp;
|
||||
EmitVectorUnaryOpZx32(context, (op1) =>
|
||||
{
|
||||
switch (op.Opc)
|
||||
{
|
||||
case 0:
|
||||
switch (op.Size) //swap bytes
|
||||
{
|
||||
default:
|
||||
return op1;
|
||||
case 1:
|
||||
return InstEmit.EmitReverseBytes16_32Op(context, op1);
|
||||
case 2:
|
||||
case 3:
|
||||
return context.ByteSwap(op1);
|
||||
}
|
||||
case 1:
|
||||
switch (op.Size)
|
||||
{
|
||||
default:
|
||||
return op1;
|
||||
case 2:
|
||||
return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff0000)), Const(16)),
|
||||
context.ShiftLeft(context.BitwiseAnd(op1, Const(0x0000ffff)), Const(16)));
|
||||
case 3:
|
||||
return context.BitwiseOr(
|
||||
context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffff000000000000ul)), Const(48)),
|
||||
context.ShiftLeft(context.BitwiseAnd(op1, Const(0x000000000000fffful)), Const(48))),
|
||||
context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0x0000ffff00000000ul)), Const(16)),
|
||||
context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000ffff0000ul)), Const(16)))
|
||||
);
|
||||
}
|
||||
case 2:
|
||||
//swap upper and lower
|
||||
return context.BitwiseOr(context.ShiftRightUI(context.BitwiseAnd(op1, Const(0xffffffff00000000ul)), Const(32)),
|
||||
context.ShiftLeft(context.BitwiseAnd(op1, Const(0x00000000fffffffful)), Const(32)));
|
||||
|
||||
}
|
||||
return op1;
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void Vrecpe(ArmEmitterContext context)
|
||||
{
|
||||
EmitVectorUnaryOpF32(context, (op1) =>
|
||||
|
@ -593,24 +640,24 @@ namespace ARMeilleure.Instructions
|
|||
public static void Vsel(ArmEmitterContext context)
|
||||
{
|
||||
var op = (OpCode32SimdSel)context.CurrOp;
|
||||
Operand condition = null;
|
||||
switch (op.Cc)
|
||||
{
|
||||
case OpCode32SimdSelMode.Eq:
|
||||
condition = GetCondTrue(context, Condition.Eq);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Ge:
|
||||
condition = GetCondTrue(context, Condition.Ge);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Gt:
|
||||
condition = GetCondTrue(context, Condition.Gt);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Vs:
|
||||
condition = GetCondTrue(context, Condition.Vs);
|
||||
break;
|
||||
}
|
||||
EmitScalarBinaryOpI32(context, (op1, op2) =>
|
||||
{
|
||||
Operand condition = null;
|
||||
switch (op.Cc)
|
||||
{
|
||||
case OpCode32SimdSelMode.Eq:
|
||||
condition = GetCondTrue(context, Condition.Eq);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Ge:
|
||||
condition = GetCondTrue(context, Condition.Ge);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Gt:
|
||||
condition = GetCondTrue(context, Condition.Gt);
|
||||
break;
|
||||
case OpCode32SimdSelMode.Vs:
|
||||
condition = GetCondTrue(context, Condition.Vs);
|
||||
break;
|
||||
}
|
||||
return context.ConditionalSelect(condition, op1, op2);
|
||||
});
|
||||
}
|
||||
|
@ -621,11 +668,48 @@ namespace ARMeilleure.Instructions
|
|||
//IMPORTANT TODO: does shift left negative do a truncating shift right on x86?
|
||||
if (op.U)
|
||||
{
|
||||
EmitVectorBinaryOpZx32(context, (op1, op2) => context.ShiftLeft(op1, context.SignExtend8(op2.Type, op2)));
|
||||
EmitVectorBinaryOpZx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, true));
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitVectorBinaryOpSx32(context, (op1, op2) => context.ShiftLeft(op1, context.SignExtend8(op2.Type, op2)));
|
||||
EmitVectorBinaryOpSx32(context, (op1, op2) => EmitShlRegOp(context, op2, op1, op.Size, false));
|
||||
}
|
||||
}
|
||||
|
||||
private static Operand EmitShlRegOp(ArmEmitterContext context, Operand op, Operand shiftLsB, int size, bool unsigned)
|
||||
{
|
||||
if (shiftLsB.Type == OperandType.I64) shiftLsB = context.ConvertI64ToI32(shiftLsB);
|
||||
shiftLsB = context.SignExtend8(OperandType.I32, shiftLsB);
|
||||
Debug.Assert((uint)size < 4u);
|
||||
|
||||
Operand negShiftLsB = context.Negate(shiftLsB);
|
||||
|
||||
Operand isPositive = context.ICompareGreaterOrEqual(shiftLsB, Const(0));
|
||||
|
||||
Operand shl = context.ShiftLeft(op, shiftLsB);
|
||||
Operand shr = (unsigned) ? context.ShiftRightUI(op, negShiftLsB) : context.ShiftRightSI(op, negShiftLsB);
|
||||
|
||||
Operand res = context.ConditionalSelect(isPositive, shl, shr);
|
||||
|
||||
if (unsigned)
|
||||
{
|
||||
Operand isOutOfRange = context.BitwiseOr(
|
||||
context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size)),
|
||||
context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size)));
|
||||
|
||||
return context.ConditionalSelect(isOutOfRange, Const(op.Type, 0), res);
|
||||
}
|
||||
else
|
||||
{
|
||||
Operand isOutOfRange0 = context.ICompareGreaterOrEqual(shiftLsB, Const(8 << size));
|
||||
Operand isOutOfRangeN = context.ICompareGreaterOrEqual(negShiftLsB, Const(8 << size));
|
||||
|
||||
//also zero if shift is too negative, but value was positive
|
||||
isOutOfRange0 = context.BitwiseOr(isOutOfRange0, context.BitwiseAnd(isOutOfRangeN, context.ICompareGreaterOrEqual(op, Const(0))));
|
||||
|
||||
Operand min = (op.Type == OperandType.I64) ? Const(-1L) : Const(-1);
|
||||
|
||||
return context.ConditionalSelect(isOutOfRange0, Const(op.Type, 0), context.ConditionalSelect(isOutOfRangeN, min, res));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -166,7 +166,8 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
private static Operand ZerosOrOnes(ArmEmitterContext context, Operand fromBool, OperandType baseType)
|
||||
{
|
||||
return context.ConditionalSelect(fromBool, Const(baseType, -1L), Const(baseType, 0L));
|
||||
var ones = (baseType == OperandType.I64) ? Const(-1L) : Const(-1);
|
||||
return context.ConditionalSelect(fromBool, ones, Const(baseType, 0L));
|
||||
}
|
||||
|
||||
private static void EmitCmpOpI32(
|
||||
|
|
|
@ -87,7 +87,7 @@ namespace ARMeilleure.Instructions
|
|||
int vd;
|
||||
if (op.Size == 3)
|
||||
{
|
||||
vd = FlipVdBits(op.Vd, true);
|
||||
vd = FlipVdBits(op.Vd, false);
|
||||
// double to single
|
||||
Operand fp = ExtractScalar(context, OperandType.FP64, vm);
|
||||
|
||||
|
@ -99,7 +99,7 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
else
|
||||
{
|
||||
vd = FlipVdBits(op.Vd, false);
|
||||
vd = FlipVdBits(op.Vd, true);
|
||||
// single to double
|
||||
Operand fp = ExtractScalar(context, OperandType.FP32, vm);
|
||||
|
||||
|
@ -248,10 +248,10 @@ namespace ARMeilleure.Instructions
|
|||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
|
||||
break;
|
||||
case 0b10: //+infinity
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToPositiveInfinity, toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, toConvert);
|
||||
break;
|
||||
case 0b11: //negative
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToNegativeInfinity, toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, MathF.Floor, Math.Floor, toConvert);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -285,7 +285,7 @@ namespace ARMeilleure.Instructions
|
|||
}
|
||||
|
||||
|
||||
public static void Vrint_R(ArmEmitterContext context)
|
||||
public static void Vrint_RM(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdCvtFI op = (OpCode32SimdCvtFI)context.CurrOp;
|
||||
|
||||
|
@ -302,10 +302,10 @@ namespace ARMeilleure.Instructions
|
|||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToEven, toConvert);
|
||||
break;
|
||||
case 0b10: //+infinity
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToPositiveInfinity, toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, MathF.Ceiling, Math.Ceiling, toConvert);
|
||||
break;
|
||||
case 0b11: //negative
|
||||
toConvert = EmitRoundMathCall(context, MidpointRounding.ToNegativeInfinity, toConvert);
|
||||
toConvert = EmitUnaryMathCall(context, MathF.Floor, Math.Floor, toConvert);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -314,7 +314,7 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
public static void Vrint_Z(ArmEmitterContext context)
|
||||
{
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitRoundMathCall(context, MidpointRounding.ToZero, op1));
|
||||
EmitScalarUnaryOpF32(context, (op1) => EmitUnaryMathCall(context, MathF.Truncate, Math.Truncate, op1));
|
||||
}
|
||||
|
||||
private static int CastDoubleToInt32(double value)
|
||||
|
|
|
@ -230,9 +230,9 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand ne = EmitVectorExtractSx32(context, vm, index + em * elems, op.Size);
|
||||
Operand me = EmitVectorExtractSx32(context, vm, index + em * elems, op.Size);
|
||||
|
||||
res = EmitVectorInsert(context, res, emit(ne), index + ed * elems, op.Size);
|
||||
res = EmitVectorInsert(context, res, emit(me), index + ed * elems, op.Size);
|
||||
}
|
||||
|
||||
context.Copy(GetVecA32(vd), res);
|
||||
|
@ -298,9 +298,9 @@ namespace ARMeilleure.Instructions
|
|||
|
||||
for (int index = 0; index < elems; index++)
|
||||
{
|
||||
Operand ne = EmitVectorExtractZx32(context, vm, index + em * elems, op.Size);
|
||||
Operand me = EmitVectorExtractZx32(context, vm, index + em * elems, op.Size);
|
||||
|
||||
res = EmitVectorInsert(context, res, emit(ne), index + ed * elems, op.Size);
|
||||
res = EmitVectorInsert(context, res, emit(me), index + ed * elems, op.Size);
|
||||
}
|
||||
|
||||
context.Copy(GetVecA32(vd), res);
|
||||
|
@ -347,7 +347,7 @@ namespace ARMeilleure.Instructions
|
|||
Operand ne = EmitVectorExtractZx32(context, vn, index + en * elems, op.Size);
|
||||
Operand me = EmitVectorExtractZx32(context, vm, index + em * elems, op.Size);
|
||||
|
||||
res = EmitVectorInsert(context, res, emit(de, ne, me), index, op.Size);
|
||||
res = EmitVectorInsert(context, res, emit(de, ne, me), index + ed * elems, op.Size);
|
||||
}
|
||||
|
||||
context.Copy(GetVecA32(vd), res);
|
||||
|
@ -479,17 +479,21 @@ namespace ARMeilleure.Instructions
|
|||
(int vd, int ed) = GetQuadwordAndSubindex(op.Vd, op.RegisterSize);
|
||||
|
||||
Operand res = GetVecA32(vd);
|
||||
Operand mvec = GetVecA32(vm);
|
||||
Operand nvec = GetVecA32(vn);
|
||||
|
||||
for (int index = 0; index < pairs; index++)
|
||||
{
|
||||
int pairIndex = index << 1;
|
||||
Operand n1 = context.VectorExtract(type, GetVecA32(vn), pairIndex + en * elems);
|
||||
Operand n2 = context.VectorExtract(type, GetVecA32(vn), pairIndex + 1 + en * elems);
|
||||
|
||||
Operand m1 = context.VectorExtract(type, GetVecA32(vm), pairIndex + em * elems);
|
||||
Operand m2 = context.VectorExtract(type, GetVecA32(vm), pairIndex + 1 + em * elems);
|
||||
Operand n1 = context.VectorExtract(type, nvec, pairIndex + en * elems);
|
||||
Operand n2 = context.VectorExtract(type, nvec, pairIndex + 1 + en * elems);
|
||||
|
||||
res = context.VectorInsert(res, emit(n1, n2), index + ed * elems);
|
||||
|
||||
Operand m1 = context.VectorExtract(type, mvec, pairIndex + em * elems);
|
||||
Operand m2 = context.VectorExtract(type, mvec, pairIndex + 1 + em * elems);
|
||||
|
||||
res = context.VectorInsert(res, emit(m1, m2), index + pairs + ed * elems);
|
||||
}
|
||||
|
||||
|
|
|
@ -52,7 +52,7 @@ namespace ARMeilleure.Instructions
|
|||
{
|
||||
OpCode32SimdMemSingle op = (OpCode32SimdMemSingle)context.CurrOp;
|
||||
|
||||
if (op.Replicate && !load) throw new Exception("Replicate+Store is undefined for LDn");
|
||||
if (op.Replicate && !load) throw new Exception("Replicate+Store is undefined for STn");
|
||||
int eBytes = 1 << op.Size;
|
||||
|
||||
Operand n = GetIntA32(context, op.Rn);
|
||||
|
@ -81,14 +81,24 @@ namespace ARMeilleure.Instructions
|
|||
int index = ((d & 1) << (3 - op.Size)) + op.Index;
|
||||
if (load)
|
||||
{
|
||||
EmitLoadSimd(context, address, GetVecA32(d >> 1), d >> 1, index, op.Size);
|
||||
if (op.Replicate)
|
||||
{
|
||||
int limit = index + (1 << (3 - op.Size));
|
||||
while (++index < limit)
|
||||
var regs = (count > 1) ? 1 : op.Increment;
|
||||
for (int reg = 0; reg < regs; reg++)
|
||||
{
|
||||
EmitLoadSimd(context, address, GetVecA32(d >> 1), d >> 1, index, op.Size);
|
||||
int dreg = reg + d;
|
||||
int rIndex = ((dreg & 1) << (3 - op.Size));
|
||||
int limit = rIndex + (1 << (3 - op.Size));
|
||||
|
||||
while (rIndex < limit)
|
||||
{
|
||||
EmitLoadSimd(context, address, GetVecA32(dreg >> 1), dreg >> 1, rIndex++, op.Size);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
EmitLoadSimd(context, address, GetVecA32(d >> 1), d >> 1, index, op.Size);
|
||||
}
|
||||
}
|
||||
else
|
||||
|
|
|
@ -18,6 +18,11 @@ namespace ARMeilleure.Instructions
|
|||
EmitVectorImmUnaryOp32(context, (op1) => op1);
|
||||
}
|
||||
|
||||
public static void Vmvn_I(ArmEmitterContext context)
|
||||
{
|
||||
EmitVectorImmUnaryOp32(context, (op1) => context.BitwiseExclusiveOr(op1, op1));
|
||||
}
|
||||
|
||||
public static void Vmov_GS(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdMovGp op = (OpCode32SimdMovGp)context.CurrOp;
|
||||
|
@ -58,24 +63,37 @@ namespace ARMeilleure.Instructions
|
|||
public static void Vmov_G2(ArmEmitterContext context)
|
||||
{
|
||||
OpCode32SimdMovGpDouble op = (OpCode32SimdMovGpDouble)context.CurrOp;
|
||||
Operand vec = GetVecA32(op.Vm >> 1);
|
||||
Operand vec = GetVecA32(op.Vm >> 2);
|
||||
int vm1 = (op.Vm + 1);
|
||||
bool sameOwnerVec = (op.Vm >> 2) == (vm1 >> 2);
|
||||
Operand vec2 = sameOwnerVec ? vec : GetVecA32(vm1 >> 2);
|
||||
if (op.Op == 1)
|
||||
{
|
||||
// to general purpose
|
||||
Operand lowValue = context.VectorExtract(OperandType.I32, vec, (op.Vm & 1) << 1);
|
||||
Operand lowValue = context.VectorExtract(OperandType.I32, vec, op.Vm & 3);
|
||||
SetIntA32(context, op.Rt, lowValue);
|
||||
|
||||
Operand highValue = context.VectorExtract(OperandType.I32, vec, ((op.Vm & 1) << 1) | 1);
|
||||
Operand highValue = context.VectorExtract(OperandType.I32, vec2, vm1 & 3);
|
||||
SetIntA32(context, op.Rt2, highValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
// from general purpose
|
||||
Operand lowValue = GetIntA32(context, op.Rt);
|
||||
Operand resultVec = context.VectorInsert(vec, lowValue, (op.Vm & 1) << 1);
|
||||
Operand resultVec = context.VectorInsert(vec, lowValue, op.Vm & 3);
|
||||
|
||||
Operand highValue = GetIntA32(context, op.Rt2);
|
||||
context.Copy(vec, context.VectorInsert(resultVec, highValue, ((op.Vm & 1) << 1) | 1));
|
||||
|
||||
if (sameOwnerVec)
|
||||
{
|
||||
context.Copy(vec, context.VectorInsert(resultVec, highValue, vm1 & 3));
|
||||
}
|
||||
else
|
||||
{
|
||||
context.Copy(vec, resultVec);
|
||||
context.Copy(vec2, context.VectorInsert(vec2, highValue, vm1 & 3));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -551,12 +551,14 @@ namespace ARMeilleure.Instructions
|
|||
Vmrs,
|
||||
Vmsr,
|
||||
Vmul,
|
||||
Vmvn,
|
||||
Vneg,
|
||||
Vnmul,
|
||||
Vnmla,
|
||||
Vnmls,
|
||||
Vorr,
|
||||
Vpadd,
|
||||
Vrev,
|
||||
Vrint,
|
||||
Vsel,
|
||||
Vshl,
|
||||
|
|
|
@ -24,7 +24,7 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public bool ShouldRejit()
|
||||
{
|
||||
return Interlocked.Increment(ref _callCount) == MinCallsForRejit;
|
||||
return _rejit && Interlocked.Increment(ref _callCount) == MinCallsForRejit;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -87,7 +87,6 @@ namespace ARMeilleure.Translation
|
|||
|
||||
public ulong ExecuteSingle(State.ExecutionContext context, ulong address)
|
||||
{
|
||||
if (address == 0xa28b75) { }
|
||||
TranslatedFunction func = GetOrTranslate(address, context.ExecutionMode);
|
||||
|
||||
Statistics.StartTimer();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
#define Simd
|
||||
//#define Simd
|
||||
|
||||
using ARMeilleure.State;
|
||||
|
||||
|
|
116
Ryujinx.Tests/Cpu/CpuTestSimdLogical32.cs
Normal file
116
Ryujinx.Tests/Cpu/CpuTestSimdLogical32.cs
Normal file
|
@ -0,0 +1,116 @@
|
|||
#define SimdLogical32
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Text;
|
||||
|
||||
namespace Ryujinx.Tests.Cpu
|
||||
{
|
||||
[Category("SimdLogical32")]
|
||||
class CpuTestSimdLogical32 : CpuTest32
|
||||
{
|
||||
#if SimdLogical32
|
||||
|
||||
private const int RndCnt = 5;
|
||||
|
||||
private uint GenerateVectorOpcode(uint opcode, uint rd, uint rn, uint rm, bool q)
|
||||
{
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
rm <<= 1;
|
||||
rn <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
return opcode;
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VBIF {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vbif([Range(0u, 4u)] uint rd,
|
||||
[Range(0u, 4u)] uint rn,
|
||||
[Range(0u, 4u)] uint rm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = GenerateVectorOpcode(0xf3300110, rd, rn, rm, q);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VBIT {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vbit([Range(0u, 4u)] uint rd,
|
||||
[Range(0u, 4u)] uint rn,
|
||||
[Range(0u, 4u)] uint rm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = GenerateVectorOpcode(0xf3200110, rd, rn, rm, q);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VBSL {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vbsl([Range(0u, 4u)] uint rd,
|
||||
[Range(0u, 4u)] uint rn,
|
||||
[Range(0u, 4u)] uint rm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = GenerateVectorOpcode(0xf3100110, rd, rn, rm, q);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VAND {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vand([Range(0u, 4u)] uint rd,
|
||||
[Range(0u, 4u)] uint rn,
|
||||
[Range(0u, 4u)] uint rm,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = GenerateVectorOpcode(0xf2000110, rd, rn, rm, q);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
//#define SimdMem32
|
||||
#define SimdMem32
|
||||
|
||||
using ARMeilleure.State;
|
||||
using NUnit.Framework;
|
||||
|
@ -37,7 +37,7 @@ namespace Ryujinx.Tests.Cpu
|
|||
0b0001
|
||||
};
|
||||
|
||||
[Test, Combinatorial, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
[Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
public void Vldn_Single([Values(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
|
@ -67,6 +67,33 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (all lanes)")]
|
||||
public void Vldn_All([Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
|
||||
[Range(0u, 3u)] uint n,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[Values] bool t,
|
||||
[Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
|
||||
{
|
||||
var data = GenerateVectorSequence(0x1000);
|
||||
SetWorkingMemory(data);
|
||||
|
||||
uint opcode = 0xf4a00c00; // vld1.8 {d0[0]}, [r0], r0
|
||||
|
||||
opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15);
|
||||
|
||||
opcode |= ((vd & 0x10) << 18);
|
||||
opcode |= ((vd & 0xf) << 12);
|
||||
|
||||
opcode |= (n & 3) << 8; //LD1 is 0, LD2 is 1 etc
|
||||
if (t) opcode |= 1 << 5; //LD1 is 0, LD2 is 1 etc
|
||||
|
||||
SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (multiple n element structures)")]
|
||||
public void Vldn_Pair([Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
|
@ -90,7 +117,7 @@ namespace Ryujinx.Tests.Cpu
|
|||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
[Test, Pairwise, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
|
||||
public void Vstn_Single([Values(0u, 1u, 2u)] uint size,
|
||||
[Values(0u, 13u)] uint rn,
|
||||
[Values(1u, 13u, 15u)] uint rm,
|
||||
|
|
|
@ -92,14 +92,101 @@ namespace Ryujinx.Tests.Cpu
|
|||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xee000a10; // invalid
|
||||
uint opcode = 0xee000a10;
|
||||
opcode |= (vn & 1) << 7;
|
||||
opcode |= (vn & 0x1e) << 15;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
if (op) opcode |= 1 << 20;
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2)); //correct
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VMOV.<size> <Rt>, <Dn[x]>")]
|
||||
public void Mov_GP_Elem([Range(0u, 7u)] uint vn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Range(0u, 2u)] uint size,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Random(1)] uint valueRn,
|
||||
[Random(1)] ulong valueVn1,
|
||||
[Random(1)] ulong valueVn2,
|
||||
[Values] bool op,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xee000b10;
|
||||
|
||||
uint opEncode = 0b01000;
|
||||
switch (size)
|
||||
{
|
||||
case 0:
|
||||
opEncode = (0b1000) | index & 7;
|
||||
break;
|
||||
case 1:
|
||||
opEncode = (0b0001) | ((index & 3) << 1);
|
||||
break;
|
||||
case 2:
|
||||
opEncode = (index & 1) << 2;
|
||||
break;
|
||||
}
|
||||
|
||||
opcode |= ((opEncode >> 2) << 21) | ((opEncode & 3) << 5);
|
||||
|
||||
opcode |= (vn & 0x10) << 3;
|
||||
opcode |= (vn & 0xf) << 16;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
if (op) opcode |= 1 << 20;
|
||||
if (op && u && size != 2) opcode |= 1 << 23;
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2), v1: new V128(valueVn2, valueVn1));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("(VMOV <Rt>, <Rt2>, <Dm>), (VMOV <Dm>, <Rt>, <Rt2>)")]
|
||||
public void Mov_GP_D([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt2,
|
||||
[Random(RndCntImm)] uint valueRt1,
|
||||
[Random(RndCntImm)] uint valueRt2,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xec400b10;
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
opcode |= (rt2 & 0xf) << 16;
|
||||
|
||||
if (op) opcode |= 1 << 20;
|
||||
|
||||
SingleOpcode(opcode, r0: valueRt1, r1: valueRt2, r2: valueRt1, r3: valueRt2, v0: new V128(valueVn1, valueVn2));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("(VMOV <Rt>, <Rt2>, <Sm>, <Sm1>), (VMOV <Sm>, <Sm1>, <Rt>, <Rt2>)")]
|
||||
public void Mov_GP_2([Range(0u, 7u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt2,
|
||||
[Random(RndCntImm)] uint valueRt1,
|
||||
[Random(RndCntImm)] uint valueRt2,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool op)
|
||||
{
|
||||
uint opcode = 0xec400a10;
|
||||
opcode |= (vm & 1) << 5;
|
||||
opcode |= (vm & 0x1e) >> 1;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
opcode |= (rt2 & 0xf) << 16;
|
||||
|
||||
if (op) opcode |= 1 << 20;
|
||||
|
||||
SingleOpcode(opcode, r0: valueRt1, r1: valueRt2, r2: valueRt1, r3: valueRt2, v0: new V128(valueVn1, valueVn2), v1: new V128(valueVn2, valueVn1));
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
@ -239,6 +326,117 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VEXT.8 {<Vd>,} <Vn>, <Vm>, #<imm>")]
|
||||
public void Vext([Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vn,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 15u)] uint imm4,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf2b00000;
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1; vm <<= 1; vn <<= 1;
|
||||
|
||||
} else if (imm4 > 7) return; //undefined
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (vn & 0x10) << 3;
|
||||
opcode |= (vn & 0xf) << 16;
|
||||
opcode |= (imm4 & 0xf) << 8;
|
||||
|
||||
V128 v0 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3); //correct
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VDUP <Vd>, <Rt>")]
|
||||
public void Vdup_GP([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint rt,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Random(RndCntImm)] uint valueRn,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xee800b10;
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 21;
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (vd & 0x10) << 3;
|
||||
opcode |= (vd & 0xf) << 16;
|
||||
opcode |= (rt & 0xf) << 12;
|
||||
|
||||
opcode |= (size & 1) << 5; //e
|
||||
opcode |= (size & 2) << 21; //b
|
||||
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, r0: valueRn, r1: valueRn, r2: valueRn, r3: valueRn, v0: new V128(valueVn1, valueVn2), v1: v1);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VDUP.<size> <Vd>, <Dm[x]>")]
|
||||
public void Vdup_S([Values(0u, 1u, 2u, 3u)] uint vd,
|
||||
[Values(0u, 1u, 2u, 3u)] uint vm,
|
||||
[Values(0u, 1u, 2u)] uint size,
|
||||
[Range(0u, 7u)] uint index,
|
||||
[Random(RndCntImm)] ulong valueVn1,
|
||||
[Random(RndCntImm)] ulong valueVn2,
|
||||
[Values] bool q)
|
||||
{
|
||||
uint opcode = 0xf3b00c00;
|
||||
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
vd <<= 1;
|
||||
}
|
||||
|
||||
opcode |= (vd & 0x10) << 18;
|
||||
opcode |= (vd & 0xf) << 12;
|
||||
opcode |= (vm & 0x10) << 1;
|
||||
opcode |= (vm & 0xf);
|
||||
|
||||
uint imm4 = 0;
|
||||
switch (size)
|
||||
{
|
||||
case 0:
|
||||
imm4 |= 0b0100 | ((index & 1) << 3);
|
||||
break;
|
||||
case 1:
|
||||
imm4 |= 0b0010 | ((index & 3) << 2);
|
||||
break;
|
||||
case 2:
|
||||
imm4 |= 0b0001 | ((index & 7) << 1);
|
||||
break;
|
||||
}
|
||||
|
||||
opcode |= imm4 << 16;
|
||||
|
||||
V128 v1 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong());
|
||||
|
||||
SingleOpcode(opcode, v0: new V128(valueVn1, valueVn2), v1: v1, v2: v2, v3: v3);
|
||||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
|
@ -243,7 +243,8 @@ namespace Ryujinx.Tests.Cpu
|
|||
[Test, Pairwise, Description("VCMP.f<size> Vd, Vm")]
|
||||
public void Vcmp([Values(2u, 3u)] uint size,
|
||||
[ValueSource("_1S_F_")] ulong a,
|
||||
[ValueSource("_1S_F_")] ulong b)
|
||||
[ValueSource("_1S_F_")] ulong b,
|
||||
[Values] bool e)
|
||||
{
|
||||
uint opcode = 0xeeb40840;
|
||||
uint rm = 1;
|
||||
|
@ -259,6 +260,7 @@ namespace Ryujinx.Tests.Cpu
|
|||
opcode |= ((rd & 0x1e) << 11) | ((rd & 0x1) << 22);
|
||||
}
|
||||
opcode |= ((size & 3) << 8);
|
||||
if (e) opcode |= 1 << 7;
|
||||
|
||||
V128 v1 = MakeVectorE0(a);
|
||||
V128 v2 = MakeVectorE0(b);
|
||||
|
@ -274,6 +276,72 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
CompareAgainstUnicorn();
|
||||
}
|
||||
|
||||
[Test, Pairwise, Description("VSHL.<size> {<Vd>}, <Vm>, <Vn>")]
|
||||
public void Vshl([Values(0u)] uint rd,
|
||||
[Values(1u, 0u)] uint rn,
|
||||
[Values(2u, 0u)] uint rm,
|
||||
[Values(0u, 1u, 2u, 3u)] uint size,
|
||||
[Random(RndCnt)] ulong z,
|
||||
[Random(RndCnt)] ulong a,
|
||||
[Random(RndCnt)] ulong b,
|
||||
[Values] bool q,
|
||||
[Values] bool u)
|
||||
{
|
||||
uint opcode = 0xf2000400;
|
||||
if (q)
|
||||
{
|
||||
opcode |= 1 << 6;
|
||||
rm <<= 1;
|
||||
rn <<= 1;
|
||||
rd <<= 1;
|
||||
}
|
||||
|
||||
if (u) opcode |= 1 << 24;
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
V128 v0 = MakeVectorE0E1(z, z);
|
||||
V128 v1 = MakeVectorE0E1(a, z);
|
||||
V128 v2 = MakeVectorE0E1(b, z);
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsS);
|
||||
}
|
||||
|
||||
[Test, Combinatorial, Description("VPADD.f32 V0, V0, V0")]
|
||||
public void Vpadd_f32([Values(0u)] uint rd,
|
||||
[Range(0u, 7u)] uint rn,
|
||||
[Range(0u, 7u)] uint rm)
|
||||
{
|
||||
uint opcode = 0xf3000d00; // VADD.f32 D0, D0, D0
|
||||
/*
|
||||
if (q)
|
||||
{
|
||||
rm <<= 0x1e;
|
||||
rn <<= 0x1e;
|
||||
rd <<= 0x1e;
|
||||
}
|
||||
*/
|
||||
|
||||
opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1);
|
||||
opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18);
|
||||
opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3);
|
||||
|
||||
//if (q) opcode |= 1 << 6;
|
||||
|
||||
var rnd = TestContext.CurrentContext.Random;
|
||||
V128 v0 = new V128(rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue));
|
||||
V128 v1 = new V128(rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue));
|
||||
V128 v2 = new V128(rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue), rnd.NextFloat(int.MinValue, int.MaxValue));
|
||||
|
||||
SingleOpcode(opcode, v0: v0, v1: v1, v2: v2);
|
||||
|
||||
CompareAgainstUnicorn(fpTolerances: FpTolerances.UpToOneUlpsS);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue