test_arm_instructions.cpp 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705
  1. /* This file is part of the dynarmic project.
  2. * Copyright (c) 2016 MerryMage
  3. * SPDX-License-Identifier: 0BSD
  4. */
  5. #include <catch2/catch_test_macros.hpp>
  6. #include "./testenv.h"
  7. #include "dynarmic/frontend/A32/a32_location_descriptor.h"
  8. #include "dynarmic/interface/A32/a32.h"
  9. using namespace Dynarmic;
  10. static A32::UserConfig GetUserConfig(ArmTestEnv* testenv) {
  11. A32::UserConfig user_config;
  12. user_config.optimizations &= ~OptimizationFlag::FastDispatch;
  13. user_config.callbacks = testenv;
  14. return user_config;
  15. }
  16. TEST_CASE("arm: Opt Failure: Const folding in MostSignificantWord", "[arm][A32]") {
  17. // This was a randomized test-case that was failing.
  18. // This was due to constant folding for MostSignificantWord
  19. // failing to take into account an associated GetCarryFromOp
  20. // pseudoinstruction.
  21. ArmTestEnv test_env;
  22. A32::Jit jit{GetUserConfig(&test_env)};
  23. test_env.code_mem = {
  24. 0xe30ad071, // movw, sp, #41073
  25. 0xe75efd3d, // smmulr lr, sp, sp
  26. 0xa637af1e, // shadd16ge r10, r7, lr
  27. 0xf57ff01f, // clrex
  28. 0x86b98879, // sxtahhi r8, r9, r9, ror #16
  29. 0xeafffffe, // b +#0
  30. };
  31. jit.SetCpsr(0x000001d0); // User-mode
  32. test_env.ticks_left = 6;
  33. jit.Run();
  34. // If we don't trigger the GetCarryFromOp ASSERT, we're fine.
  35. }
  36. TEST_CASE("arm: Unintended modification in SetCFlag", "[arm][A32]") {
  37. // This was a randomized test-case that was failing.
  38. //
  39. // IR produced for location {12, !T, !E} was:
  40. // %0 = GetRegister r1
  41. // %1 = SubWithCarry %0, #0x3e80000, #1
  42. // %2 = GetCarryFromOp %1
  43. // %3 = GetOverflowFromOp %1
  44. // %4 = MostSignificantBit %1
  45. // SetNFlag %4
  46. // %6 = IsZero %1
  47. // SetZFlag %6
  48. // SetCFlag %2
  49. // SetVFlag %3
  50. // %10 = GetRegister r5
  51. // %11 = AddWithCarry %10, #0x8a00, %2
  52. // SetRegister r4, %11
  53. //
  54. // The reference to %2 in instruction %11 was the issue, because instruction %8
  55. // told the register allocator it was a Use but then modified the value.
  56. // Changing the EmitSet*Flag instruction to declare their arguments as UseScratch
  57. // solved this bug.
  58. ArmTestEnv test_env;
  59. A32::Jit jit{GetUserConfig(&test_env)};
  60. test_env.code_mem = {
  61. 0xe35f0cd9, // cmp pc, #55552
  62. 0xe11c0474, // tst r12, r4, ror r4
  63. 0xe1a006a7, // mov r0, r7, lsr #13
  64. 0xe35107fa, // cmp r1, #0x3E80000
  65. 0xe2a54c8a, // adc r4, r5, #35328
  66. 0xeafffffe, // b +#0
  67. };
  68. jit.Regs() = {
  69. 0x6973b6bb, 0x267ea626, 0x69debf49, 0x8f976895, 0x4ecd2d0d, 0xcf89b8c7, 0xb6713f85, 0x15e2aa5,
  70. 0xcd14336a, 0xafca0f3e, 0xace2efd9, 0x68fb82cd, 0x775447c0, 0xc9e1f8cd, 0xebe0e626, 0x0};
  71. jit.SetCpsr(0x000001d0); // User-mode
  72. test_env.ticks_left = 6;
  73. jit.Run();
  74. REQUIRE(jit.Regs()[0] == 0x00000af1);
  75. REQUIRE(jit.Regs()[1] == 0x267ea626);
  76. REQUIRE(jit.Regs()[2] == 0x69debf49);
  77. REQUIRE(jit.Regs()[3] == 0x8f976895);
  78. REQUIRE(jit.Regs()[4] == 0xcf8a42c8);
  79. REQUIRE(jit.Regs()[5] == 0xcf89b8c7);
  80. REQUIRE(jit.Regs()[6] == 0xb6713f85);
  81. REQUIRE(jit.Regs()[7] == 0x015e2aa5);
  82. REQUIRE(jit.Regs()[8] == 0xcd14336a);
  83. REQUIRE(jit.Regs()[9] == 0xafca0f3e);
  84. REQUIRE(jit.Regs()[10] == 0xace2efd9);
  85. REQUIRE(jit.Regs()[11] == 0x68fb82cd);
  86. REQUIRE(jit.Regs()[12] == 0x775447c0);
  87. REQUIRE(jit.Regs()[13] == 0xc9e1f8cd);
  88. REQUIRE(jit.Regs()[14] == 0xebe0e626);
  89. REQUIRE(jit.Regs()[15] == 0x00000014);
  90. REQUIRE(jit.Cpsr() == 0x200001d0);
  91. }
  92. TEST_CASE("arm: shsax (Edge-case)", "[arm][A32]") {
  93. // This was a randomized test-case that was failing.
  94. //
  95. // The issue here was one of the words to be subtracted was 0x8000.
  96. // When the 2s complement was calculated by (~a + 1), it was 0x8000.
  97. ArmTestEnv test_env;
  98. A32::Jit jit{GetUserConfig(&test_env)};
  99. test_env.code_mem = {
  100. 0xe63dbf59, // shsax r11, sp, r9
  101. 0xeafffffe, // b +#0
  102. };
  103. jit.Regs() = {
  104. 0x3a3b8b18, 0x96156555, 0xffef039f, 0xafb946f2, 0x2030a69a, 0xafe09b2a, 0x896823c8, 0xabde0ded,
  105. 0x9825d6a6, 0x17498000, 0x999d2c95, 0x8b812a59, 0x209bdb58, 0x2f7fb1d4, 0x0f378107, 0x00000000};
  106. jit.SetCpsr(0x000001d0); // User-mode
  107. test_env.ticks_left = 2;
  108. jit.Run();
  109. REQUIRE(jit.Regs()[0] == 0x3a3b8b18);
  110. REQUIRE(jit.Regs()[1] == 0x96156555);
  111. REQUIRE(jit.Regs()[2] == 0xffef039f);
  112. REQUIRE(jit.Regs()[3] == 0xafb946f2);
  113. REQUIRE(jit.Regs()[4] == 0x2030a69a);
  114. REQUIRE(jit.Regs()[5] == 0xafe09b2a);
  115. REQUIRE(jit.Regs()[6] == 0x896823c8);
  116. REQUIRE(jit.Regs()[7] == 0xabde0ded);
  117. REQUIRE(jit.Regs()[8] == 0x9825d6a6);
  118. REQUIRE(jit.Regs()[9] == 0x17498000);
  119. REQUIRE(jit.Regs()[10] == 0x999d2c95);
  120. REQUIRE(jit.Regs()[11] == 0x57bfe48e);
  121. REQUIRE(jit.Regs()[12] == 0x209bdb58);
  122. REQUIRE(jit.Regs()[13] == 0x2f7fb1d4);
  123. REQUIRE(jit.Regs()[14] == 0x0f378107);
  124. REQUIRE(jit.Regs()[15] == 0x00000004);
  125. REQUIRE(jit.Cpsr() == 0x000001d0);
  126. }
  127. TEST_CASE("arm: uasx (Edge-case)", "[arm][A32]") {
  128. // UASX's Rm<31:16> == 0x0000.
  129. // An implementation that depends on addition overflow to detect
  130. // if diff >= 0 will fail this testcase.
  131. ArmTestEnv test_env;
  132. A32::Jit jit{GetUserConfig(&test_env)};
  133. test_env.code_mem = {
  134. 0xe6549f35, // uasx r9, r4, r5
  135. 0xeafffffe, // b +#0
  136. };
  137. jit.Regs()[4] = 0x8ed38f4c;
  138. jit.Regs()[5] = 0x0000261d;
  139. jit.Regs()[15] = 0x00000000;
  140. jit.SetCpsr(0x000001d0); // User-mode
  141. test_env.ticks_left = 2;
  142. jit.Run();
  143. REQUIRE(jit.Regs()[4] == 0x8ed38f4c);
  144. REQUIRE(jit.Regs()[5] == 0x0000261d);
  145. REQUIRE(jit.Regs()[9] == 0xb4f08f4c);
  146. REQUIRE(jit.Regs()[15] == 0x00000004);
  147. REQUIRE(jit.Cpsr() == 0x000301d0);
  148. }
  149. TEST_CASE("arm: smuad (Edge-case)", "[arm][A32]") {
  150. ArmTestEnv test_env;
  151. A32::Jit jit{GetUserConfig(&test_env)};
  152. test_env.code_mem = {
  153. 0xE700F211, // smuad r0, r1, r2
  154. 0xeafffffe, // b +#0
  155. };
  156. jit.Regs() = {
  157. 0, // Rd
  158. 0x80008000, // Rn
  159. 0x80008000, // Rm
  160. 0,
  161. 0,
  162. 0,
  163. 0,
  164. 0,
  165. 0,
  166. 0,
  167. 0,
  168. 0,
  169. 0,
  170. 0,
  171. 0,
  172. 0,
  173. };
  174. jit.SetCpsr(0x000001d0); // User-mode
  175. test_env.ticks_left = 2;
  176. jit.Run();
  177. REQUIRE(jit.Regs()[0] == 0x80000000);
  178. REQUIRE(jit.Regs()[1] == 0x80008000);
  179. REQUIRE(jit.Regs()[2] == 0x80008000);
  180. REQUIRE(jit.Cpsr() == 0x080001d0);
  181. }
  182. TEST_CASE("arm: Test InvalidateCacheRange", "[arm][A32]") {
  183. ArmTestEnv test_env;
  184. A32::Jit jit{GetUserConfig(&test_env)};
  185. test_env.code_mem = {
  186. 0xe3a00005, // mov r0, #5
  187. 0xe3a0100D, // mov r1, #13
  188. 0xe0812000, // add r2, r1, r0
  189. 0xeafffffe, // b +#0 (infinite loop)
  190. };
  191. jit.Regs() = {};
  192. jit.SetCpsr(0x000001d0); // User-mode
  193. test_env.ticks_left = 4;
  194. jit.Run();
  195. REQUIRE(jit.Regs()[0] == 5);
  196. REQUIRE(jit.Regs()[1] == 13);
  197. REQUIRE(jit.Regs()[2] == 18);
  198. REQUIRE(jit.Regs()[15] == 0x0000000c);
  199. REQUIRE(jit.Cpsr() == 0x000001d0);
  200. // Change the code
  201. test_env.code_mem[1] = 0xe3a01007; // mov r1, #7
  202. jit.InvalidateCacheRange(/*start_memory_location = */ 4, /* length_in_bytes = */ 4);
  203. // Reset position of PC
  204. jit.Regs()[15] = 0;
  205. test_env.ticks_left = 4;
  206. jit.Run();
  207. jit.Run();
  208. REQUIRE(jit.Regs()[0] == 5);
  209. REQUIRE(jit.Regs()[1] == 7);
  210. REQUIRE(jit.Regs()[2] == 12);
  211. REQUIRE(jit.Regs()[15] == 0x0000000c);
  212. REQUIRE(jit.Cpsr() == 0x000001d0);
  213. }
  214. TEST_CASE("arm: Step blx", "[arm]") {
  215. ArmTestEnv test_env;
  216. A32::UserConfig config = GetUserConfig(&test_env);
  217. config.optimizations |= OptimizationFlag::FastDispatch;
  218. Dynarmic::A32::Jit jit{config};
  219. test_env.code_mem = {
  220. 0xe12fff30, // blx r0
  221. 0xe320f000, // nop
  222. 0xe320f000, // nop
  223. 0xe320f000, // nop
  224. 0xe320f000, // nop
  225. 0xe320f000, // nop
  226. 0xeafffffe, // b +#0 (infinite loop)
  227. };
  228. jit.Regs()[0] = 8;
  229. jit.Regs()[15] = 0; // PC = 0
  230. jit.SetCpsr(0x000001d0); // User-mode
  231. test_env.ticks_left = 10;
  232. jit.Step();
  233. REQUIRE(jit.Regs()[0] == 8);
  234. REQUIRE(jit.Regs()[14] == 4);
  235. REQUIRE(jit.Regs()[15] == 8);
  236. REQUIRE(jit.Cpsr() == 0x000001d0);
  237. }
  238. TEST_CASE("arm: Step bx", "[arm]") {
  239. ArmTestEnv test_env;
  240. A32::UserConfig config = GetUserConfig(&test_env);
  241. config.optimizations |= OptimizationFlag::FastDispatch;
  242. Dynarmic::A32::Jit jit{config};
  243. test_env.code_mem = {
  244. 0xe12fff10, // bx r0
  245. 0xe320f000, // nop
  246. 0xe320f000, // nop
  247. 0xe320f000, // nop
  248. 0xe320f000, // nop
  249. 0xe320f000, // nop
  250. 0xeafffffe, // b +#0 (infinite loop)
  251. };
  252. jit.Regs()[0] = 8;
  253. jit.Regs()[15] = 0; // PC = 0
  254. jit.SetCpsr(0x000001d0); // User-mode
  255. test_env.ticks_left = 10;
  256. jit.Step();
  257. REQUIRE(jit.Regs()[0] == 8);
  258. REQUIRE(jit.Regs()[15] == 8);
  259. REQUIRE(jit.Cpsr() == 0x000001d0);
  260. }
  261. TEST_CASE("arm: Test stepping", "[arm]") {
  262. ArmTestEnv test_env;
  263. Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
  264. test_env.code_mem = {
  265. 0xe320f000, // nop
  266. 0xe320f000, // nop
  267. 0xe320f000, // nop
  268. 0xe320f000, // nop
  269. 0xe320f000, // nop
  270. 0xe320f000, // nop
  271. 0xe320f000, // nop
  272. 0xe320f000, // nop
  273. 0xe320f000, // nop
  274. 0xe320f000, // nop
  275. 0xe320f000, // nop
  276. 0xe320f000, // nop
  277. 0xe320f000, // nop
  278. 0xe320f000, // nop
  279. 0xe320f000, // nop
  280. 0xe320f000, // nop
  281. 0xe320f000, // nop
  282. 0xe320f000, // nop
  283. 0xe320f000, // nop
  284. 0xe320f000, // nop
  285. 0xeafffffe, // b +#0 (infinite loop)
  286. };
  287. jit.Regs()[0] = 8;
  288. jit.Regs()[15] = 0; // PC = 0
  289. jit.SetCpsr(0x000001d0); // User-mode
  290. for (size_t i = 0; i < 5; ++i) {
  291. test_env.ticks_left = 10;
  292. jit.Step();
  293. REQUIRE(jit.Regs()[15] == (i + 1) * 4);
  294. REQUIRE(jit.Cpsr() == 0x000001d0);
  295. }
  296. test_env.ticks_left = 20;
  297. jit.Run();
  298. REQUIRE(jit.Regs()[15] == 80);
  299. REQUIRE(jit.Cpsr() == 0x000001d0);
  300. }
  301. TEST_CASE("arm: Test stepping 2", "[arm]") {
  302. ArmTestEnv test_env;
  303. Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
  304. test_env.code_mem = {
  305. 0xe12fff10, // bx r0
  306. 0xe320f000, // nop
  307. 0xe320f000, // nop
  308. 0xe320f000, // nop
  309. 0xe320f000, // nop
  310. 0xe320f000, // nop
  311. 0xe320f000, // nop
  312. 0xe320f000, // nop
  313. 0xe320f000, // nop
  314. 0xe320f000, // nop
  315. 0xe320f000, // nop
  316. 0xe320f000, // nop
  317. 0xe320f000, // nop
  318. 0xe320f000, // nop
  319. 0xe320f000, // nop
  320. 0xe320f000, // nop
  321. 0xe320f000, // nop
  322. 0xe320f000, // nop
  323. 0xe320f000, // nop
  324. 0xe320f000, // nop
  325. 0xeafffffe, // b +#0 (infinite loop)
  326. };
  327. jit.Regs()[0] = 4;
  328. jit.Regs()[15] = 0; // PC = 0
  329. jit.SetCpsr(0x000001d0); // User-mode
  330. for (size_t i = 0; i < 5; ++i) {
  331. test_env.ticks_left = 10;
  332. jit.Step();
  333. REQUIRE(jit.Regs()[15] == (i + 1) * 4);
  334. REQUIRE(jit.Cpsr() == 0x000001d0);
  335. }
  336. test_env.ticks_left = 20;
  337. jit.Run();
  338. REQUIRE(jit.Regs()[15] == 80);
  339. REQUIRE(jit.Cpsr() == 0x000001d0);
  340. }
  341. TEST_CASE("arm: Test stepping 3", "[arm]") {
  342. ArmTestEnv test_env;
  343. Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
  344. test_env.code_mem = {
  345. 0xe12fff10, // bx r0
  346. 0xe320f000, // nop
  347. 0xe320f000, // nop
  348. 0xe320f000, // nop
  349. 0xe320f000, // nop
  350. 0xeafffffe, // b +#0 (infinite loop)
  351. };
  352. jit.Regs()[0] = 4;
  353. jit.Regs()[15] = 0; // PC = 0
  354. jit.SetCpsr(0x000001d0); // User-mode
  355. test_env.ticks_left = 10;
  356. jit.Step();
  357. REQUIRE(jit.Regs()[15] == 4);
  358. REQUIRE(jit.Cpsr() == 0x000001d0);
  359. test_env.ticks_left = 20;
  360. jit.Run();
  361. REQUIRE(jit.Regs()[15] == 20);
  362. REQUIRE(jit.Cpsr() == 0x000001d0);
  363. }
  364. TEST_CASE("arm: PackedAbsDiffSumS8", "[arm][A32]") {
  365. // This was a randomized test-case that was failing.
  366. // In circumstances there were cases when the upper 32 bits of an argument to psadbw were not zero.
  367. ArmTestEnv test_env;
  368. A32::Jit jit{GetUserConfig(&test_env)};
  369. test_env.code_mem = {
  370. 0x87414354, // smlsldhi r4, r1, r4, r3
  371. 0xe7886412, // usad8a r8, r2, r4, r6
  372. 0xeafffffe, // b +#0
  373. };
  374. jit.Regs() = {
  375. 0xea85297c,
  376. 0x417ad918,
  377. 0x64f8b70b,
  378. 0xcca0373e,
  379. 0xbc722361,
  380. 0xc528c69e,
  381. 0xca926de8,
  382. 0xd665d210,
  383. 0xb5650555,
  384. 0x4a24b25b,
  385. 0xaed44144,
  386. 0xe87230b2,
  387. 0x98e391de,
  388. 0x126efc0c,
  389. 0xe591fd11,
  390. 0x00000000,
  391. };
  392. jit.SetCpsr(0xb0000010);
  393. test_env.ticks_left = 3;
  394. jit.Run();
  395. REQUIRE(jit.Regs()[0] == 0xea85297c);
  396. REQUIRE(jit.Regs()[1] == 0x417ad918);
  397. REQUIRE(jit.Regs()[2] == 0x64f8b70b);
  398. REQUIRE(jit.Regs()[3] == 0xcca0373e);
  399. REQUIRE(jit.Regs()[4] == 0xb685ec9f);
  400. REQUIRE(jit.Regs()[5] == 0xc528c69e);
  401. REQUIRE(jit.Regs()[6] == 0xca926de8);
  402. REQUIRE(jit.Regs()[7] == 0xd665d210);
  403. REQUIRE(jit.Regs()[8] == 0xca926f76);
  404. REQUIRE(jit.Regs()[9] == 0x4a24b25b);
  405. REQUIRE(jit.Regs()[10] == 0xaed44144);
  406. REQUIRE(jit.Regs()[11] == 0xe87230b2);
  407. REQUIRE(jit.Regs()[12] == 0x98e391de);
  408. REQUIRE(jit.Regs()[13] == 0x126efc0c);
  409. REQUIRE(jit.Regs()[14] == 0xe591fd11);
  410. REQUIRE(jit.Regs()[15] == 0x00000008);
  411. REQUIRE(jit.Cpsr() == 0xb0000010);
  412. }
  413. TEST_CASE("arm: vclt.f32 with zero", "[arm][A32]") {
  414. ArmTestEnv test_env;
  415. A32::Jit jit{GetUserConfig(&test_env)};
  416. test_env.code_mem = {
  417. 0xf3b93628, // vclt.f32 d3, d24, #0
  418. 0xeafffffe, // b +#0
  419. };
  420. jit.ExtRegs()[48] = 0x3a87d9f1;
  421. jit.ExtRegs()[49] = 0x80796dc0;
  422. jit.SetCpsr(0x000001d0); // User-mode
  423. test_env.ticks_left = 2;
  424. jit.Run();
  425. REQUIRE(jit.ExtRegs()[6] == 0x00000000);
  426. REQUIRE(jit.ExtRegs()[7] == 0x00000000);
  427. }
  428. TEST_CASE("arm: vcvt.s16.f64", "[arm][A32]") {
  429. ArmTestEnv test_env;
  430. A32::Jit jit{GetUserConfig(&test_env)};
  431. test_env.code_mem = {
  432. 0xeebe8b45, // vcvt.s16.f64 d8, d8, #6
  433. 0xeafffffe, // b +#0
  434. };
  435. jit.ExtRegs()[16] = 0x9a7110b0;
  436. jit.ExtRegs()[17] = 0xcd78f4e7;
  437. jit.SetCpsr(0x000001d0); // User-mode
  438. test_env.ticks_left = 2;
  439. jit.Run();
  440. REQUIRE(jit.ExtRegs()[16] == 0xffff8000);
  441. REQUIRE(jit.ExtRegs()[17] == 0xffffffff);
  442. }
  443. TEST_CASE("arm: Memory access (fastmem)", "[arm][A32]") {
  444. constexpr size_t address_width = 12;
  445. constexpr size_t memory_size = 1ull << address_width; // 4K
  446. constexpr size_t page_size = 4 * 1024;
  447. constexpr size_t buffer_size = 2 * page_size;
  448. char buffer[buffer_size];
  449. void* buffer_ptr = reinterpret_cast<void*>(buffer);
  450. size_t buffer_size_nconst = buffer_size;
  451. char* backing_memory = reinterpret_cast<char*>(std::align(page_size, memory_size, buffer_ptr, buffer_size_nconst));
  452. A32FastmemTestEnv env{backing_memory};
  453. Dynarmic::A32::UserConfig config{&env};
  454. config.fastmem_pointer = reinterpret_cast<uintptr_t>(backing_memory);
  455. config.recompile_on_fastmem_failure = false;
  456. config.processor_id = 0;
  457. Dynarmic::A32::Jit jit{config};
  458. memset(backing_memory, 0, memory_size);
  459. memcpy(backing_memory + 0x100, "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", 57);
  460. env.MemoryWrite32(0, 0xE5904000); // LDR R4, [R0]
  461. env.MemoryWrite32(4, 0xE5814000); // STR R4, [R1]
  462. env.MemoryWrite32(8, 0xEAFFFFFE); // B .
  463. jit.Regs()[0] = 0x100;
  464. jit.Regs()[1] = 0x1F0;
  465. jit.Regs()[15] = 0; // PC = 0
  466. jit.SetCpsr(0x000001d0); // User-mode
  467. env.ticks_left = 3;
  468. jit.Run();
  469. REQUIRE(strncmp(backing_memory + 0x100, backing_memory + 0x1F0, 4) == 0);
  470. }
  471. TEST_CASE("arm: vmsr, vcmp, vmrs", "[arm][A32]") {
  472. ArmTestEnv test_env;
  473. A32::Jit jit{GetUserConfig(&test_env)};
  474. test_env.code_mem = {
  475. 0xeee10a10, // vmsr fpscr, r0
  476. 0xeeb48a4a, // vcmp.f32 s16, s20
  477. 0xeef1fa10, // vmrs apsr_nzcv, fpscr
  478. 0xe12fff1e, // bx lr
  479. };
  480. jit.ExtRegs()[16] = 0xFF7FFFFF;
  481. jit.ExtRegs()[20] = 0xFF7FFFFF;
  482. jit.Regs()[0] = 0x60000000;
  483. jit.SetFpscr(0x3ee22ac0);
  484. jit.SetCpsr(0x60000000); // User-mode
  485. test_env.ticks_left = 4;
  486. jit.Run();
  487. }
  488. TEST_CASE("arm: sdiv maximally", "[arm][A32]") {
  489. ArmTestEnv test_env;
  490. A32::Jit jit{GetUserConfig(&test_env)};
  491. test_env.code_mem = {
  492. 0xe712f011, // sdiv r2, r1, r0
  493. 0xeafffffe, // b +#0
  494. };
  495. jit.Regs()[1] = 0x80000000;
  496. jit.Regs()[0] = 0xffffffff;
  497. jit.SetCpsr(0x000001d0); // User-mode
  498. test_env.ticks_left = 2;
  499. jit.Run();
  500. REQUIRE(jit.Regs()[2] == 0x80000000);
  501. }
  502. TEST_CASE("arm: tbl", "[arm][A32]") {
  503. ArmTestEnv test_env;
  504. A32::Jit jit{GetUserConfig(&test_env)};
  505. test_env.code_mem.emplace_back(0xf3f408a0); // vtbl.8 d16, {d20 }, d16
  506. test_env.code_mem.emplace_back(0xf3f419a1); // vtbl.8 d17, {d20, d21 }, d17
  507. test_env.code_mem.emplace_back(0xf3f42aa2); // vtbl.8 d18, {d20, d21, d22 }, d18
  508. test_env.code_mem.emplace_back(0xf3f43ba3); // vtbl.8 d19, {d20, d21, d22, d23}, d19
  509. test_env.code_mem.emplace_back(0xeafffffe); // b +#0
  510. // Indices
  511. jit.ExtRegs()[16 * 2 + 0] = 0x05'02'01'00;
  512. jit.ExtRegs()[16 * 2 + 1] = 0x20'1F'10'0F;
  513. jit.ExtRegs()[17 * 2 + 0] = 0x05'02'01'00;
  514. jit.ExtRegs()[17 * 2 + 1] = 0x20'1F'10'0F;
  515. jit.ExtRegs()[18 * 2 + 0] = 0x05'02'01'00;
  516. jit.ExtRegs()[18 * 2 + 1] = 0x20'1F'10'0F;
  517. jit.ExtRegs()[19 * 2 + 0] = 0x05'02'01'00;
  518. jit.ExtRegs()[19 * 2 + 1] = 0x20'1F'10'0F;
  519. // Table
  520. jit.ExtRegs()[20 * 2 + 0] = 0x03'02'01'00;
  521. jit.ExtRegs()[20 * 2 + 1] = 0x07'06'05'04;
  522. jit.ExtRegs()[21 * 2 + 0] = 0x0B'0A'09'08;
  523. jit.ExtRegs()[21 * 2 + 1] = 0x0F'0E'0D'0C;
  524. jit.ExtRegs()[22 * 2 + 0] = 0x13'12'11'10;
  525. jit.ExtRegs()[22 * 2 + 1] = 0x17'16'15'14;
  526. jit.ExtRegs()[23 * 2 + 0] = 0x1B'1A'19'18;
  527. jit.ExtRegs()[23 * 2 + 1] = 0x1F'1E'1D'1C;
  528. test_env.ticks_left = 5;
  529. jit.Run();
  530. REQUIRE(jit.ExtRegs()[16 * 2 + 0] == 0x05'02'01'00);
  531. REQUIRE(jit.ExtRegs()[16 * 2 + 1] == 0x00'00'00'00);
  532. REQUIRE(jit.ExtRegs()[17 * 2 + 0] == 0x05'02'01'00);
  533. REQUIRE(jit.ExtRegs()[17 * 2 + 1] == 0x00'00'00'0F);
  534. REQUIRE(jit.ExtRegs()[18 * 2 + 0] == 0x05'02'01'00);
  535. REQUIRE(jit.ExtRegs()[18 * 2 + 1] == 0x00'00'10'0F);
  536. REQUIRE(jit.ExtRegs()[19 * 2 + 0] == 0x05'02'01'00);
  537. REQUIRE(jit.ExtRegs()[19 * 2 + 1] == 0x00'1F'10'0F);
  538. }
  539. TEST_CASE("arm: tbx", "[arm][A32]") {
  540. ArmTestEnv test_env;
  541. A32::Jit jit{GetUserConfig(&test_env)};
  542. test_env.code_mem.emplace_back(0xf3f408e0); // vtbx.8 d16, {d20 }, d16
  543. test_env.code_mem.emplace_back(0xf3f419e1); // vtbx.8 d17, {d20, d21 }, d17
  544. test_env.code_mem.emplace_back(0xf3f42ae2); // vtbx.8 d18, {d20, d21, d22 }, d18
  545. test_env.code_mem.emplace_back(0xf3f43be3); // vtbx.8 d19, {d20, d21, d22, d23}, d19
  546. test_env.code_mem.emplace_back(0xeafffffe); // b +#0
  547. // Indices
  548. jit.ExtRegs()[16 * 2 + 0] = 0x05'02'01'00;
  549. jit.ExtRegs()[16 * 2 + 1] = 0x20'1F'10'0F;
  550. jit.ExtRegs()[17 * 2 + 0] = 0x05'02'01'00;
  551. jit.ExtRegs()[17 * 2 + 1] = 0x20'1F'10'0F;
  552. jit.ExtRegs()[18 * 2 + 0] = 0x05'02'01'00;
  553. jit.ExtRegs()[18 * 2 + 1] = 0x20'1F'10'0F;
  554. jit.ExtRegs()[19 * 2 + 0] = 0x05'02'01'00;
  555. jit.ExtRegs()[19 * 2 + 1] = 0x20'1F'10'0F;
  556. // Table
  557. jit.ExtRegs()[20 * 2 + 0] = 0x03'02'01'00;
  558. jit.ExtRegs()[20 * 2 + 1] = 0x07'06'05'04;
  559. jit.ExtRegs()[21 * 2 + 0] = 0x0B'0A'09'08;
  560. jit.ExtRegs()[21 * 2 + 1] = 0x0F'0E'0D'0C;
  561. jit.ExtRegs()[22 * 2 + 0] = 0x13'12'11'10;
  562. jit.ExtRegs()[22 * 2 + 1] = 0x17'16'15'14;
  563. jit.ExtRegs()[23 * 2 + 0] = 0x1B'1A'19'18;
  564. jit.ExtRegs()[23 * 2 + 1] = 0x1F'1E'1D'1C;
  565. test_env.ticks_left = 5;
  566. jit.Run();
  567. REQUIRE(jit.ExtRegs()[16 * 2 + 0] == 0x05'02'01'00);
  568. REQUIRE(jit.ExtRegs()[16 * 2 + 1] == 0x20'1F'10'0F);
  569. REQUIRE(jit.ExtRegs()[17 * 2 + 0] == 0x05'02'01'00);
  570. REQUIRE(jit.ExtRegs()[17 * 2 + 1] == 0x20'1F'10'0F);
  571. REQUIRE(jit.ExtRegs()[18 * 2 + 0] == 0x05'02'01'00);
  572. REQUIRE(jit.ExtRegs()[18 * 2 + 1] == 0x20'1F'10'0F);
  573. REQUIRE(jit.ExtRegs()[19 * 2 + 0] == 0x05'02'01'00);
  574. REQUIRE(jit.ExtRegs()[19 * 2 + 1] == 0x20'1F'10'0F);
  575. }