CpuTestSimdMemory32.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332
  1. #define SimdMemory32
  2. using ARMeilleure.State;
  3. using NUnit.Framework;
  4. using System;
  5. namespace Ryujinx.Tests.Cpu
  6. {
  7. [Category("SimdMemory32")]
  8. public sealed class CpuTestSimdMemory32 : CpuTest32
  9. {
  10. #if SimdMemory32
  11. private const int RndCntImm = 2;
  12. private uint[] _ldStModes =
  13. {
  14. // LD1
  15. 0b0111,
  16. 0b1010,
  17. 0b0110,
  18. 0b0010,
  19. // LD2
  20. 0b1000,
  21. 0b1001,
  22. 0b0011,
  23. // LD3
  24. 0b0100,
  25. 0b0101,
  26. // LD4
  27. 0b0000,
  28. 0b0001
  29. };
  30. [Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
  31. public void Vldn_Single([Values(0u, 1u, 2u)] uint size,
  32. [Values(0u, 13u)] uint rn,
  33. [Values(1u, 13u, 15u)] uint rm,
  34. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  35. [Range(0u, 7u)] uint index,
  36. [Range(0u, 3u)] uint n,
  37. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
  38. {
  39. var data = GenerateVectorSequence(0x1000);
  40. SetWorkingMemory(0, data);
  41. uint opcode = 0xf4a00000u; // VLD1.8 {D0[0]}, [R0], R0
  42. opcode |= ((size & 3) << 10) | ((rn & 15) << 16) | (rm & 15);
  43. uint index_align = (index << (int)(1 + size)) & 15;
  44. opcode |= (index_align) << 4;
  45. opcode |= ((vd & 0x10) << 18);
  46. opcode |= ((vd & 0xf) << 12);
  47. opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
  48. SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
  49. CompareAgainstUnicorn();
  50. }
  51. [Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (all lanes)")]
  52. public void Vldn_All([Values(0u, 13u)] uint rn,
  53. [Values(1u, 13u, 15u)] uint rm,
  54. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  55. [Range(0u, 3u)] uint n,
  56. [Range(0u, 2u)] uint size,
  57. [Values] bool t,
  58. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
  59. {
  60. var data = GenerateVectorSequence(0x1000);
  61. SetWorkingMemory(0, data);
  62. uint opcode = 0xf4a00c00u; // VLD1.8 {D0[0]}, [R0], R0
  63. opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15);
  64. opcode |= ((vd & 0x10) << 18);
  65. opcode |= ((vd & 0xf) << 12);
  66. opcode |= (n & 3) << 8; // LD1 is 0, LD2 is 1 etc.
  67. if (t) opcode |= 1 << 5;
  68. SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
  69. CompareAgainstUnicorn();
  70. }
  71. [Test, Pairwise, Description("VLDn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (multiple n element structures)")]
  72. public void Vldn_Pair([Values(0u, 1u, 2u, 3u)] uint size,
  73. [Values(0u, 13u)] uint rn,
  74. [Values(1u, 13u, 15u)] uint rm,
  75. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  76. [Range(0u, 10u)] uint mode,
  77. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
  78. {
  79. var data = GenerateVectorSequence(0x1000);
  80. SetWorkingMemory(0, data);
  81. uint opcode = 0xf4200000u; // VLD4.8 {D0, D1, D2, D3}, [R0], R0
  82. if (mode > 3 && size == 3)
  83. {
  84. // A size of 3 is only valid for VLD1.
  85. size = 2;
  86. }
  87. opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15) | (_ldStModes[mode] << 8);
  88. opcode |= ((vd & 0x10) << 18);
  89. opcode |= ((vd & 0xf) << 12);
  90. SingleOpcode(opcode, r0: 0x2500, r1: offset, sp: 0x2500);
  91. CompareAgainstUnicorn();
  92. }
  93. [Test, Pairwise, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (single n element structure)")]
  94. public void Vstn_Single([Values(0u, 1u, 2u)] uint size,
  95. [Values(0u, 13u)] uint rn,
  96. [Values(1u, 13u, 15u)] uint rm,
  97. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  98. [Range(0u, 7u)] uint index,
  99. [Range(0u, 3u)] uint n,
  100. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
  101. {
  102. var data = GenerateVectorSequence(0x1000);
  103. SetWorkingMemory(0, data);
  104. (V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
  105. uint opcode = 0xf4800000u; // VST1.8 {D0[0]}, [R0], R0
  106. opcode |= ((size & 3) << 10) | ((rn & 15) << 16) | (rm & 15);
  107. uint index_align = (index << (int)(1 + size)) & 15;
  108. opcode |= (index_align) << 4;
  109. opcode |= ((vd & 0x10) << 18);
  110. opcode |= ((vd & 0xf) << 12);
  111. opcode |= (n & 3) << 8; // ST1 is 0, ST2 is 1 etc.
  112. SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
  113. CompareAgainstUnicorn();
  114. }
  115. [Test, Pairwise, Description("VSTn.<size> <list>, [<Rn> {:<align>}]{ /!/, <Rm>} (multiple n element structures)")]
  116. public void Vstn_Pair([Values(0u, 1u, 2u, 3u)] uint size,
  117. [Values(0u, 13u)] uint rn,
  118. [Values(1u, 13u, 15u)] uint rm,
  119. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  120. [Range(0u, 10u)] uint mode,
  121. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint offset)
  122. {
  123. var data = GenerateVectorSequence(0x1000);
  124. SetWorkingMemory(0, data);
  125. (V128 vec1, V128 vec2, V128 vec3, V128 vec4) = GenerateTestVectors();
  126. uint opcode = 0xf4000000u; // VST4.8 {D0, D1, D2, D3}, [R0], R0
  127. if (mode > 3 && size == 3)
  128. {
  129. // A size of 3 is only valid for VST1.
  130. size = 2;
  131. }
  132. opcode |= ((size & 3) << 6) | ((rn & 15) << 16) | (rm & 15) | (_ldStModes[mode] << 8);
  133. opcode |= ((vd & 0x10) << 18);
  134. opcode |= ((vd & 0xf) << 12);
  135. SingleOpcode(opcode, r0: 0x2500, r1: offset, v1: vec1, v2: vec2, v3: vec3, v4: vec4, sp: 0x2500);
  136. CompareAgainstUnicorn();
  137. }
  138. [Test, Pairwise, Description("VLDM.<size> <Rn>{!}, <d/sreglist>")]
  139. public void Vldm([Values(0u, 13u)] uint rn,
  140. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint vd,
  141. [Range(0u, 2u)] uint mode,
  142. [Values(0x1u, 0x32u)] [Random(2u, 31u, RndCntImm)] uint regs,
  143. [Values] bool single)
  144. {
  145. var data = GenerateVectorSequence(0x1000);
  146. SetWorkingMemory(0, data);
  147. uint opcode = 0xec100a00u; // VST4.8 {D0, D1, D2, D3}, [R0], R0
  148. uint[] vldmModes =
  149. {
  150. // Note: 3rd 0 leaves a space for "D".
  151. 0b0100, // Increment after.
  152. 0b0101, // Increment after. (!)
  153. 0b1001 // Decrement before. (!)
  154. };
  155. opcode |= ((vldmModes[mode] & 15) << 21);
  156. opcode |= ((rn & 15) << 16);
  157. opcode |= ((vd & 0x10) << 18);
  158. opcode |= ((vd & 0xf) << 12);
  159. opcode |= ((uint)(single ? 0 : 1) << 8);
  160. if (!single) regs = (regs << 1); // Low bit must be 0 - must be even number of registers.
  161. uint regSize = single ? 1u : 2u;
  162. if (vd + (regs / regSize) > 32) // Can't address further than S31 or D31.
  163. {
  164. regs -= (vd + (regs / regSize)) - 32;
  165. }
  166. if (regs / regSize > 16) // Can't do more than 16 registers at a time.
  167. {
  168. regs = 16 * regSize;
  169. }
  170. opcode |= regs & 0xff;
  171. SingleOpcode(opcode, r0: 0x2500, sp: 0x2500);
  172. CompareAgainstUnicorn();
  173. }
  174. [Test, Pairwise, Description("VLDR.<size> <Sd>, [<Rn> {, #{+/-}<imm>}]")]
  175. public void Vldr([Values(2u, 3u)] uint size, // FP16 is not supported for now
  176. [Values(0u)] uint rn,
  177. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
  178. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint imm,
  179. [Values] bool sub)
  180. {
  181. var data = GenerateVectorSequence(0x1000);
  182. SetWorkingMemory(0, data);
  183. uint opcode = 0xed900a00u; // VLDR.32 S0, [R0, #0]
  184. opcode |= ((size & 3) << 8) | ((rn & 15) << 16);
  185. if (sub)
  186. {
  187. opcode &= ~(uint)(1 << 23);
  188. }
  189. if (size == 2)
  190. {
  191. opcode |= ((sd & 0x1) << 22);
  192. opcode |= ((sd & 0x1e) << 11);
  193. }
  194. else
  195. {
  196. opcode |= ((sd & 0x10) << 18);
  197. opcode |= ((sd & 0xf) << 12);
  198. }
  199. opcode |= imm & 0xff;
  200. SingleOpcode(opcode, r0: 0x2500);
  201. CompareAgainstUnicorn();
  202. }
  203. [Test, Pairwise, Description("VSTR.<size> <Sd>, [<Rn> {, #{+/-}<imm>}]")]
  204. public void Vstr([Values(2u, 3u)] uint size, // FP16 is not supported for now
  205. [Values(0u)] uint rn,
  206. [Values(0u, 1u, 2u, 3u, 4u, 5u, 6u, 7u)] uint sd,
  207. [Values(0x0u)] [Random(0u, 0xffu, RndCntImm)] uint imm,
  208. [Values] bool sub)
  209. {
  210. var data = GenerateVectorSequence(0x1000);
  211. SetWorkingMemory(0, data);
  212. uint opcode = 0xed800a00u; // VSTR.32 S0, [R0, #0]
  213. opcode |= ((size & 3) << 8) | ((rn & 15) << 16);
  214. if (sub)
  215. {
  216. opcode &= ~(uint)(1 << 23);
  217. }
  218. if (size == 2)
  219. {
  220. opcode |= ((sd & 0x1) << 22);
  221. opcode |= ((sd & 0x1e) << 11);
  222. }
  223. else
  224. {
  225. opcode |= ((sd & 0x10) << 18);
  226. opcode |= ((sd & 0xf) << 12);
  227. }
  228. opcode |= imm & 0xff;
  229. (V128 vec1, V128 vec2, _, _) = GenerateTestVectors();
  230. SingleOpcode(opcode, r0: 0x2500, v0: vec1, v1: vec2);
  231. CompareAgainstUnicorn();
  232. }
  233. private (V128, V128, V128, V128) GenerateTestVectors()
  234. {
  235. return (
  236. new V128(-12.43f, 1872.23f, 4456.23f, -5622.2f),
  237. new V128(0.0f, float.NaN, float.PositiveInfinity, float.NegativeInfinity),
  238. new V128(1.23e10f, -0.0f, -0.123f, 0.123f),
  239. new V128(float.Epsilon, 3.5f, 925.23f, -104.9f)
  240. );
  241. }
  242. private byte[] GenerateVectorSequence(int length)
  243. {
  244. int floatLength = length >> 2;
  245. float[] data = new float[floatLength];
  246. for (int i = 0; i < floatLength; i++)
  247. {
  248. data[i] = i + (i / 9f);
  249. }
  250. var result = new byte[length];
  251. Buffer.BlockCopy(data, 0, result, 0, result.Length);
  252. return result;
  253. }
  254. #endif
  255. }
  256. }