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