diff options
| author | gdkchan <gab.dark.100@gmail.com> | 2022-09-09 21:47:38 -0300 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2022-09-09 21:47:38 -0300 |
| commit | db45688aa8d0e63d3ffbe50351722ef32f8360f8 (patch) | |
| tree | 3228986398039c37546510ddeecea1600a48b933 /Ryujinx.Tests | |
| parent | c6d82209abeacd2336cde99e5a02b4596e70da83 (diff) | |
Implement VRSRA, VRSHRN, VQSHRUN, VQMOVN, VQMOVUN, VQADD, VQSUB, VRHADD, VPADDL, VSUBL, VQDMULH and VMLAL Arm32 NEON instructions (#3677)
* Implement VRSRA, VRSHRN, VQSHRUN, VQMOVN, VQMOVUN, VQADD, VQSUB, VRHADD, VPADDL, VSUBL, VQDMULH and VMLAL Arm32 NEON instructions
* PPTC version
* Fix VQADD/VQSUB
* Improve MRC/MCR handling and exception messages
In case data is being recompiled as code, we don't want to throw at emit stage, instead we should only throw if it actually tries to execute
Diffstat (limited to 'Ryujinx.Tests')
| -rw-r--r-- | Ryujinx.Tests/Cpu/CpuTestSimd32.cs | 93 | ||||
| -rw-r--r-- | Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs | 190 | ||||
| -rw-r--r-- | Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs | 68 |
3 files changed, 261 insertions, 90 deletions
diff --git a/Ryujinx.Tests/Cpu/CpuTestSimd32.cs b/Ryujinx.Tests/Cpu/CpuTestSimd32.cs index 34e94068..34173cd7 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimd32.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimd32.cs @@ -12,12 +12,22 @@ namespace Ryujinx.Tests.Cpu #if Simd32 #region "ValueSource (Opcodes)" - private static uint[] _Vabs_Vneg_V_() + private static uint[] _Vabs_Vneg_Vpaddl_I_() { return new uint[] { - 0xf3b10300u, // VABS.S8 D0, D0 - 0xf3b10380u // VNEG.S8 D0, D0 + 0xf3b10300u, // VABS.S8 D0, D0 + 0xf3b10380u, // VNEG.S8 D0, D0 + 0xf3b00200u // VPADDL.S8 D0, D0 + }; + } + + private static uint[] _Vabs_Vneg_F_() + { + return new uint[] + { + 0xf3b90700u, // VABS.F32 D0, D0 + 0xf3b90780u // VNEG.F32 D0, D0 }; } #endregion @@ -201,40 +211,43 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] - public void Vabs_Vneg_V_S8_S16_S32([ValueSource("_Vabs_Vneg_V_")] uint opcode, - [Range(0u, 3u)] uint rd, - [Range(0u, 3u)] uint rm, - [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z, - [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b, - [Values(0u, 1u, 2u)] uint size, // <S8, S16, S32> - [Values] bool q) + public void Vabs_Vneg_Vpaddl_V_I([ValueSource("_Vabs_Vneg_Vpaddl_I_")] uint opcode, + [Range(0u, 3u)] uint rd, + [Range(0u, 3u)] uint rm, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b, + [Values(0u, 1u, 2u)] uint size, // <S8, S16, S32> + [Values] bool q) { - const bool f = false; + if (q) + { + opcode |= 1 << 6; + + rd >>= 1; rd <<= 1; + rm >>= 1; rm <<= 1; + } - Vabs_Vneg_V(opcode, rd, rm, z, b, size, f, q); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + opcode |= (size & 0x3) << 18; + + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(b, ~b); + + SingleOpcode(opcode, v0: v0, v1: v1); + + CompareAgainstUnicorn(); } [Test, Pairwise] - public void Vabs_Vneg_V_F32([ValueSource("_Vabs_Vneg_V_")] uint opcode, + public void Vabs_Vneg_V_F32([ValueSource("_Vabs_Vneg_F_")] uint opcode, [Range(0u, 3u)] uint rd, [Range(0u, 3u)] uint rm, [ValueSource("_2S_F_")] ulong z, [ValueSource("_2S_F_")] ulong b, [Values] bool q) { - const uint size = 0b10; // <F32> - const bool f = true; - - Vabs_Vneg_V(opcode, rd, rm, z, b, size, f, q); - } - - private void Vabs_Vneg_V(uint opcode, uint rd, uint rm, ulong z, ulong b, uint size, bool f, bool q) - { - if (f) - { - opcode |= 1 << 10; - } - if (q) { opcode |= 1 << 6; @@ -246,8 +259,6 @@ namespace Ryujinx.Tests.Cpu opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); - opcode |= (size & 0x3) << 18; - V128 v0 = MakeVectorE0E1(z, ~z); V128 v1 = MakeVectorE0E1(b, ~b); @@ -283,6 +294,32 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise] + public void Vmovn_V([Range(0u, 3u)] uint rd, + [Range(0u, 3u)] uint rm, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S_")] [Random(RndCnt)] ulong b, + [Values(0u, 1u, 2u, 3u)] uint op, + [Values(0u, 1u, 2u)] uint size) // <S8, S16, S32> + { + rm >>= 1; rm <<= 1; + + uint opcode = 0xf3b20200u; // VMOVN.S16 D0, Q0 + + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + opcode |= (op & 0x3) << 6; + opcode |= (size & 0x3) << 18; + + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(b, ~b); + + SingleOpcode(opcode, v0: v0, v1: v1); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs b/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs index 0635d8fc..93fc658a 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdReg32.cs @@ -12,11 +12,13 @@ namespace Ryujinx.Tests.Cpu #if SimdReg32 #region "ValueSource (Opcodes)" - private static uint[] _V_Add_Sub_Wide_I_() + private static uint[] _V_Add_Sub_Long_Wide_I_() { return new uint[] { + 0xf2800000u, // VADDL.S8 Q0, D0, D0 0xf2800100u, // VADDW.S8 Q0, Q0, D0 + 0xf2800200u, // VSUBL.S8 Q0, D0, D0 0xf2800300u // VSUBW.S8 Q0, Q0, D0 }; } @@ -74,6 +76,15 @@ namespace Ryujinx.Tests.Cpu }; } + private static uint[] _Vmlal_Vmlsl_V_I_() + { + return new uint[] + { + 0xf2800800u, // VMLAL.S8 Q0, D0, D0 + 0xf2800a00u // VMLSL.S8 Q0, D0, D0 + }; + } + private static uint[] _Vp_Add_Max_Min_F_() { return new uint[] @@ -84,16 +95,30 @@ namespace Ryujinx.Tests.Cpu }; } - // VPADD does not have an unsigned flag, so we check the opcode before setting it. - private static uint VpaddI8 = 0xf2000b10u; // VPADD.I8 D0, D0, D0 + private static uint[] _Vp_Add_I_() + { + return new uint[] + { + 0xf2000b10u // VPADD.I8 D0, D0, D0 + }; + } - private static uint[] _Vp_Add_Max_Min_I_() + private static uint[] _V_Pmax_Pmin_Rhadd_I_() { return new uint[] { - VpaddI8, - 0xf2000a00u, // VPMAX.S8 D0, D0, D0 - 0xf2000a10u // VPMIN.S8 D0, D0, D0 + 0xf2000a00u, // VPMAX .S8 D0, D0, D0 + 0xf2000a10u, // VPMIN .S8 D0, D0, D0 + 0xf2000100u, // VRHADD.S8 D0, D0, D0 + }; + } + + private static uint[] _Vq_Add_Sub_I_() + { + return new uint[] + { + 0xf2000050u, // VQADD.S8 Q0, Q0, Q0 + 0xf2000250u // VQSUB.S8 Q0, Q0, Q0 }; } #endregion @@ -350,7 +375,7 @@ namespace Ryujinx.Tests.Cpu [Explicit] [Test, Pairwise, Description("VADD.f32 V0, V0, V0")] - public void Vadd_f32([Values(0u)] uint rd, + public void Vadd_F32([Values(0u)] uint rd, [Values(0u, 1u)] uint rn, [Values(0u, 2u)] uint rm, [ValueSource("_2S_F_")] ulong z0, @@ -384,15 +409,15 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] - public void V_Add_Sub_Wide_I([ValueSource("_V_Add_Sub_Wide_I_")] uint opcode, - [Range(0u, 5u)] uint rd, - [Range(0u, 5u)] uint rn, - [Range(0u, 5u)] uint rm, - [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong z, - [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong a, - [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong b, - [Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32> - [Values] bool u) // <S, U> + public void V_Add_Sub_Long_Wide_I([ValueSource("_V_Add_Sub_Long_Wide_I_")] uint opcode, + [Range(0u, 5u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong a, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong b, + [Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32> + [Values] bool u) // <S, U> { if (u) { @@ -566,18 +591,17 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } - [Test, Pairwise, Description("VMLSL.<type><size> <Vd>, <Vn>, <Vm>")] - public void Vmlsl_I([Values(0u)] uint rd, - [Values(1u, 0u)] uint rn, - [Values(2u, 0u)] uint rm, - [Values(0u, 1u, 2u)] uint size, - [Random(RndCnt)] ulong z, - [Random(RndCnt)] ulong a, - [Random(RndCnt)] ulong b, - [Values] bool u) + [Test, Pairwise] + public void Vmlal_Vmlsl_I([ValueSource(nameof(_Vmlal_Vmlsl_V_I_))] uint opcode, + [Values(0u)] uint rd, + [Values(1u, 0u)] uint rn, + [Values(2u, 0u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool u) { - uint opcode = 0xf2800a00u; // VMLSL.S8 Q0, D0, D0 - opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3); @@ -736,17 +760,42 @@ namespace Ryujinx.Tests.Cpu } [Test, Pairwise] - public void Vp_Add_Max_Min_I([ValueSource("_Vp_Add_Max_Min_I_")] uint opcode, - [Values(0u)] uint rd, - [Range(0u, 5u)] uint rn, - [Range(0u, 5u)] uint rm, - [Values(0u, 1u, 2u)] uint size, - [Random(RndCnt)] ulong z, - [Random(RndCnt)] ulong a, - [Random(RndCnt)] ulong b, - [Values] bool u) + public void Vp_Add_I([ValueSource("_Vp_Add_I_")] uint opcode, + [Values(0u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b) + { + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3); + + opcode |= size << 20; + + 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] + public void V_Pmax_Pmin_Rhadd_I([ValueSource("_V_Pmax_Pmin_Rhadd_I_")] uint opcode, + [Values(0u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool u) { - if (u && opcode != VpaddI8) + if (u) { opcode |= 1 << 24; } @@ -765,6 +814,71 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } + + [Test, Pairwise] + public void Vq_Add_Sub_I([ValueSource("_Vq_Add_Sub_I_")] uint opcode, + [Range(0u, 5u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong a, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong b, + [Values(0u, 1u, 2u)] uint size, // <SU8, SU16, SU32> + [Values] bool u) // <S, U> + { + if (u) + { + opcode |= 1 << 24; + } + + rd >>= 1; rd <<= 1; + rn >>= 1; rn <<= 1; + rm >>= 1; rm <<= 1; + + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + opcode |= (size & 0x3) << 20; + + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } + + [Test, Pairwise, Description("VQDMULH.<S16, S32> <Qd>, <Qn>, <Qm>")] + public void Vqdmulh_I([Range(0u, 5u)] uint rd, + [Range(0u, 5u)] uint rn, + [Range(0u, 5u)] uint rm, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong z, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong a, + [ValueSource("_8B4H2S1D_")] [Random(RndCnt)] ulong b, + [Values(1u, 2u)] uint size) // <S16, S32> + { + rd >>= 1; rd <<= 1; + rn >>= 1; rn <<= 1; + rm >>= 1; rm <<= 1; + + uint opcode = 0xf2100b40u & ~(3u << 20); // VQDMULH.S16 Q0, Q0, Q0 + + opcode |= ((rd & 0xf) << 12) | ((rd & 0x10) << 18); + opcode |= ((rn & 0xf) << 16) | ((rn & 0x10) << 3); + opcode |= ((rm & 0xf) << 0) | ((rm & 0x10) << 1); + + opcode |= (size & 0x3) << 20; + + V128 v0 = MakeVectorE0E1(z, ~z); + V128 v1 = MakeVectorE0E1(a, ~a); + V128 v2 = MakeVectorE0E1(b, ~b); + + SingleOpcode(opcode, v0: v0, v1: v1, v2: v2); + + CompareAgainstUnicorn(); + } #endif } } diff --git a/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs b/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs index a8c32d58..45481f85 100644 --- a/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs +++ b/Ryujinx.Tests/Cpu/CpuTestSimdShImm32.cs @@ -41,9 +41,10 @@ namespace Ryujinx.Tests.Cpu { return new uint[] { + 0xf2880010u, // VSHR.S8 D0, D0, #8 0xf2880110u, // VSRA.S8 D0, D0, #8 0xf2880210u, // VRSHR.S8 D0, D0, #8 - 0xf2880010u // VSHR.S8 D0, D0, #8 + 0xf2880310u // VRSRA.S8 D0, D0, #8 }; } @@ -51,9 +52,10 @@ namespace Ryujinx.Tests.Cpu { return new uint[] { + 0xf2900010u, // VSHR.S16 D0, D0, #16 0xf2900110u, // VSRA.S16 D0, D0, #16 0xf2900210u, // VRSHR.S16 D0, D0, #16 - 0xf2900010u // VSHR.S16 D0, D0, #16 + 0xf2900310u // VRSRA.S16 D0, D0, #16 }; } @@ -61,9 +63,10 @@ namespace Ryujinx.Tests.Cpu { return new uint[] { + 0xf2a00010u, // VSHR.S32 D0, D0, #32 0xf2a00110u, // VSRA.S32 D0, D0, #32 0xf2a00210u, // VRSHR.S32 D0, D0, #32 - 0xf2a00010u // VSHR.S32 D0, D0, #32 + 0xf2a00310u // VRSRA.S32 D0, D0, #32 }; } @@ -76,6 +79,25 @@ namespace Ryujinx.Tests.Cpu 0xf2800090u // VSHR.S64 D0, D0, #64 }; } + + private static uint[] _Vqshrn_Vqrshrn_Vrshrn_Imm_() + { + return new uint[] + { + 0xf2800910u, // VORR.I16 D0, #0 (immediate value changes it into QSHRN) + 0xf2800950u, // VORR.I16 Q0, #0 (immediate value changes it into QRSHRN) + 0xf2800850u // VMOV.I16 Q0, #0 (immediate value changes it into RSHRN) + }; + } + + private static uint[] _Vqshrun_Vqrshrun_Imm_() + { + return new uint[] + { + 0xf3800810u, // VMOV.I16 D0, #0x80 (immediate value changes it into QSHRUN) + 0xf3800850u // VMOV.I16 Q0, #0x80 (immediate value changes it into QRSHRUN) + }; + } #endregion private const int RndCnt = 2; @@ -230,18 +252,17 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(); } - [Test, Pairwise, Description("VQRSHRN.<type><size> <Vd>, <Vm>, #<imm>")] - public void Vqrshrn_Imm([Values(0u, 1u)] uint rd, - [Values(2u, 0u)] uint rm, - [Values(0u, 1u, 2u)] uint size, - [Random(RndCntShiftImm)] [Values(0u)] uint shiftImm, - [Random(RndCnt)] ulong z, - [Random(RndCnt)] ulong a, - [Random(RndCnt)] ulong b, - [Values] bool u) + [Test, Pairwise] + public void Vqshrn_Vqrshrn_Vrshrn_Imm([ValueSource("_Vqshrn_Vqrshrn_Vrshrn_Imm_")] uint opcode, + [Values(0u, 1u)] uint rd, + [Values(2u, 0u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCntShiftImm)] [Values(0u)] uint shiftImm, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b, + [Values] bool u) { - uint opcode = 0xf2800950u; // VORR.I16 Q0, #0 (immediate value changes it into QRSHRN) - uint imm = 1u << ((int)size + 3); imm |= shiftImm & (imm - 1); @@ -265,17 +286,16 @@ namespace Ryujinx.Tests.Cpu CompareAgainstUnicorn(fpsrMask: Fpsr.Qc); } - [Test, Pairwise, Description("VQRSHRUN.<type><size> <Vd>, <Vm>, #<imm>")] - public void Vqrshrun_Imm([Values(0u, 1u)] uint rd, - [Values(2u, 0u)] uint rm, - [Values(0u, 1u, 2u)] uint size, - [Random(RndCntShiftImm)] [Values(0u)] uint shiftImm, - [Random(RndCnt)] ulong z, - [Random(RndCnt)] ulong a, - [Random(RndCnt)] ulong b) + [Test, Pairwise] + public void Vqshrun_Vqrshrun_Imm([ValueSource("_Vqshrun_Vqrshrun_Imm_")] uint opcode, + [Values(0u, 1u)] uint rd, + [Values(2u, 0u)] uint rm, + [Values(0u, 1u, 2u)] uint size, + [Random(RndCntShiftImm)] [Values(0u)] uint shiftImm, + [Random(RndCnt)] ulong z, + [Random(RndCnt)] ulong a, + [Random(RndCnt)] ulong b) { - uint opcode = 0xf3800850u; // VMOV.I16 Q0, #0x80 (immediate value changes it into QRSHRUN) - uint imm = 1u << ((int)size + 3); imm |= shiftImm & (imm - 1); |
