#define SimdMov32 using ARMeilleure.State; using NUnit.Framework; namespace Ryujinx.Tests.Cpu { [Category("SimdMov32")] public sealed class CpuTestSimdMov32 : CpuTest32 { #if SimdMov32 private const int RndCntImm = 2; [Test, Pairwise, Description("VMOV.I
, #")] public void Movi_V([Range(0u, 10u)] uint variant, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0x0u)] uint imm, [Values] bool q) { uint[] variants = { // I32 0b0000_0, 0b0010_0, 0b0100_0, 0b0110_0, // I16 0b1000_0, 0b1010_0, // DT 0b1100_0, 0b1101_0, 0b1110_0, 0b1111_0, 0b1110_1 }; uint opcode = 0xf2800010u; // VMOV.I32 D0, #0 uint cmodeOp = variants[variant]; if (q) { vd <<= 1; } opcode |= ((cmodeOp & 1) << 5) | ((cmodeOp & 0x1e) << 7); opcode |= (q ? 1u : 0u) << 6; opcode |= (imm & 0xf) | ((imm & 0x70) << 12) | ((imm & 0x80) << 16); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; SingleOpcode(opcode); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMOV.F , #")] public void Movi_S([Range(2u, 3u)] uint size, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0x0u)] uint imm) { uint opcode = 0xeeb00800u; opcode |= (size & 3) << 8; opcode |= (imm & 0xf) | ((imm & 0xf0) << 12); if (size == 2) { opcode |= ((vd & 0x1) << 22); opcode |= ((vd & 0x1e) << 11); } else { opcode |= ((vd & 0x10) << 18); opcode |= ((vd & 0xf) << 12); } SingleOpcode(opcode); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMOV , ")] public void Mov_GP([Values(0u, 1u, 2u, 3u)] uint vn, [Values(0u, 1u, 2u, 3u)] uint rt, [Random(RndCntImm)] uint valueRn, [Random(RndCntImm)] ulong valueVn1, [Random(RndCntImm)] ulong valueVn2, [Values] bool op) { uint opcode = 0xee000a10u; // VMOV S0, R0 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)); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMOV. , ")] 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 = 0xee000b10u; // VMOV.32 D0[0], R0 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 (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 , , ), (VMOV , , )")] 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 = 0xec400b10u; // VMOV D0, R0, R0 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 , , , ), (VMOV , , , )")] 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 = 0xec400a10u; // VMOV S0, S1, R0, R0 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(); } [Test, Pairwise, Description("VMOVN.
, ")] public void Movn_V([Range(0u, 1u, 2u)] uint size, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0u, 2u, 4u, 8u)] uint vm) { uint opcode = 0xf3b20200u; // VMOVN.I16 D0, Q0 opcode |= (size & 0x3) << 18; opcode |= ((vm & 0x10) << 1); opcode |= ((vm & 0xf) << 0); opcode |= ((vd & 0x10) << 18); opcode |= ((vd & 0xf) << 12); 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMOVL. , ")] public void Vmovl([Values(0u, 1u, 2u, 3u)] uint vm, [Values(0u, 2u, 4u, 6u)] uint vd, [Values(1u, 2u, 4u)] uint imm3H, [Values] bool u) { // This is not VMOVL because imm3H = 0, but once // we shift in the imm3H value it turns into VMOVL. uint opcode = 0xf2800a10u; // VMOV.I16 D0, #0 opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; opcode |= (imm3H & 0x7) << 19; if (u) { opcode |= 1 << 24; } 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMVN. , ")] public void Vmvn([Range(0u, 1u, 2u)] uint size, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0u, 2u, 4u, 8u)] uint vm, [Values] bool q) { uint opcode = 0xf3b00580u; // VMVN D0, D0 if (q) { opcode |= 1 << 6; vm <<= 1; vd <<= 1; } opcode |= (size & 0x3) << 18; opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf) << 0; opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VMVN.I
, #")] public void Mvni_V([Range(0u, 7u)] uint variant, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0x0u)] uint imm, [Values] bool q) { uint[] variants = { // I32 0b0000, 0b0010, 0b0100, 0b0110, // I16 0b1000, 0b1010, // I32 0b1100, 0b1101, }; uint opcode = 0xf2800030u; // VMVN.I32 D0, #0 uint cmodeOp = variants[variant]; if (q) { vd <<= 1; } opcode |= (cmodeOp & 0xf) << 8; opcode |= (q ? 1u : 0u) << 6; opcode |= (imm & 0xf) | ((imm & 0x70) << 12) | ((imm & 0x80) << 16); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; SingleOpcode(opcode); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VTRN. , ")] public void Vtrn([Values(0u, 1u, 2u, 3u)] uint vm, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0u, 1u, 2u)] uint size, [Values] bool q) { uint opcode = 0xf3b20080u; // VTRN.8 D0, D0 if (vm == vd) { return; // Undefined. } if (q) { opcode |= 1 << 6; vd <<= 1; vm <<= 1; } opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; opcode |= (size & 0x3) << 18; 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VZIP. , ")] public void Vzip([Values(0u, 1u, 2u, 3u)] uint vm, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0u, 1u, 2u)] uint size, [Values] bool q) { uint opcode = 0xf3b20180u; // VZIP.8 D0, D0 if (vm == vd || (size == 2 && !q)) { return; // Undefined. } if (q) { opcode |= 1 << 6; vd <<= 1; vm <<= 1; } opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; opcode |= (size & 0x3) << 18; 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VUZP. , ")] public void Vuzp([Values(0u, 1u, 2u, 3u)] uint vm, [Values(0u, 1u, 2u, 3u)] uint vd, [Values(0u, 1u, 2u)] uint size, [Values] bool q) { uint opcode = 0xf3b20100u; // VUZP.8 d0, d0 if (vm == vd || (size == 2 && !q)) { return; // Undefined. } if (q) { opcode |= 1 << 6; vd <<= 1; vm <<= 1; } opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; opcode |= (size & 0x3) << 18; 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VTBL.8
, {list}, ")] public void Vtbl([Range(0u, 6u)] uint vm, // Indices, include potentially invalid. [Range(4u, 12u)] uint vn, // Selection. [Values(0u, 1u)] uint vd, // Destinations. [Range(0u, 3u)] uint length, [Values] bool x) { uint opcode = 0xf3b00800u; // VTBL.8 D0, {D0}, D0 if (vn + length > 31) { return; // Undefined. } if (x) { opcode |= 1 << 6; } opcode |= (vm & 0x10) << 1; opcode |= (vm & 0xf); opcode |= (vd & 0x10) << 18; opcode |= (vd & 0xf) << 12; opcode |= (vn & 0x10) << 3; opcode |= (vn & 0xf) << 16; opcode |= (length & 0x3) << 8; var rnd = TestContext.CurrentContext.Random; V128 v2 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); V128 v3 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); V128 v4 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); V128 v5 = new V128(TestContext.CurrentContext.Random.NextULong(), TestContext.CurrentContext.Random.NextULong()); byte maxIndex = (byte)(length * 8 - 1); byte[] b0 = new byte[16]; byte[] b1 = new byte[16]; for (int i=0; i<16; i++) { b0[i] = rnd.NextByte(maxIndex); b1[i] = rnd.NextByte(maxIndex); } V128 v0 = new V128(b0); V128 v1 = new V128(b1); SingleOpcode(opcode, v0: v0, v1: v1, v2: v2, v3: v3, v4: v4, v5: v5); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VEXT.8 {,} , , #")] 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; // VEXT.32 D0, D0, D0, #0 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); CompareAgainstUnicorn(); } [Test, Pairwise, Description("VDUP. , ")] 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; // VDUP.32 d0, r0 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. , ")] 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 } }