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 }