1 /* This file is part of the dynarmic project.
2 * Copyright (c) 2016 MerryMage
3 * SPDX-License-Identifier: 0BSD
4 */
5
6 #include <catch.hpp>
7 #include <dynarmic/A32/a32.h>
8
9 #include "A32/testenv.h"
10 #include "frontend/A32/location_descriptor.h"
11
12 using namespace Dynarmic;
13
GetUserConfig(ArmTestEnv * testenv)14 static A32::UserConfig GetUserConfig(ArmTestEnv* testenv) {
15 A32::UserConfig user_config;
16 user_config.enable_fast_dispatch = false;
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 };
84 jit.SetCpsr(0x000001d0); // User-mode
85
86 test_env.ticks_left = 6;
87 jit.Run();
88
89 REQUIRE(jit.Regs()[0] == 0x00000af1);
90 REQUIRE(jit.Regs()[1] == 0x267ea626);
91 REQUIRE(jit.Regs()[2] == 0x69debf49);
92 REQUIRE(jit.Regs()[3] == 0x8f976895);
93 REQUIRE(jit.Regs()[4] == 0xcf8a42c8);
94 REQUIRE(jit.Regs()[5] == 0xcf89b8c7);
95 REQUIRE(jit.Regs()[6] == 0xb6713f85);
96 REQUIRE(jit.Regs()[7] == 0x015e2aa5);
97 REQUIRE(jit.Regs()[8] == 0xcd14336a);
98 REQUIRE(jit.Regs()[9] == 0xafca0f3e);
99 REQUIRE(jit.Regs()[10] == 0xace2efd9);
100 REQUIRE(jit.Regs()[11] == 0x68fb82cd);
101 REQUIRE(jit.Regs()[12] == 0x775447c0);
102 REQUIRE(jit.Regs()[13] == 0xc9e1f8cd);
103 REQUIRE(jit.Regs()[14] == 0xebe0e626);
104 REQUIRE(jit.Regs()[15] == 0x00000014);
105 REQUIRE(jit.Cpsr() == 0x200001d0);
106 }
107
108 TEST_CASE( "arm: shsax (Edge-case)", "[arm][A32]" ) {
109 // This was a randomized test-case that was failing.
110 //
111 // The issue here was one of the words to be subtracted was 0x8000.
112 // When the 2s complement was calculated by (~a + 1), it was 0x8000.
113
114 ArmTestEnv test_env;
115 A32::Jit jit{GetUserConfig(&test_env)};
116 test_env.code_mem = {
117 0xe63dbf59, // shsax r11, sp, r9
118 0xeafffffe, // b +#0
119 };
120
121 jit.Regs() = {
122 0x3a3b8b18, 0x96156555, 0xffef039f, 0xafb946f2, 0x2030a69a, 0xafe09b2a, 0x896823c8, 0xabde0ded,
123 0x9825d6a6, 0x17498000, 0x999d2c95, 0x8b812a59, 0x209bdb58, 0x2f7fb1d4, 0x0f378107, 0x00000000
124 };
125 jit.SetCpsr(0x000001d0); // User-mode
126
127 test_env.ticks_left = 2;
128 jit.Run();
129
130 REQUIRE(jit.Regs()[0] == 0x3a3b8b18);
131 REQUIRE(jit.Regs()[1] == 0x96156555);
132 REQUIRE(jit.Regs()[2] == 0xffef039f);
133 REQUIRE(jit.Regs()[3] == 0xafb946f2);
134 REQUIRE(jit.Regs()[4] == 0x2030a69a);
135 REQUIRE(jit.Regs()[5] == 0xafe09b2a);
136 REQUIRE(jit.Regs()[6] == 0x896823c8);
137 REQUIRE(jit.Regs()[7] == 0xabde0ded);
138 REQUIRE(jit.Regs()[8] == 0x9825d6a6);
139 REQUIRE(jit.Regs()[9] == 0x17498000);
140 REQUIRE(jit.Regs()[10] == 0x999d2c95);
141 REQUIRE(jit.Regs()[11] == 0x57bfe48e);
142 REQUIRE(jit.Regs()[12] == 0x209bdb58);
143 REQUIRE(jit.Regs()[13] == 0x2f7fb1d4);
144 REQUIRE(jit.Regs()[14] == 0x0f378107);
145 REQUIRE(jit.Regs()[15] == 0x00000004);
146 REQUIRE(jit.Cpsr() == 0x000001d0);
147 }
148
149 TEST_CASE( "arm: uasx (Edge-case)", "[arm][A32]" ) {
150 // UASX's Rm<31:16> == 0x0000.
151 // An implementation that depends on addition overflow to detect
152 // if diff >= 0 will fail this testcase.
153
154 ArmTestEnv test_env;
155 A32::Jit jit{GetUserConfig(&test_env)};
156 test_env.code_mem = {
157 0xe6549f35, // uasx r9, r4, r5
158 0xeafffffe, // b +#0
159 };
160
161 jit.Regs()[4] = 0x8ed38f4c;
162 jit.Regs()[5] = 0x0000261d;
163 jit.Regs()[15] = 0x00000000;
164 jit.SetCpsr(0x000001d0); // User-mode
165
166 test_env.ticks_left = 2;
167 jit.Run();
168
169 REQUIRE(jit.Regs()[4] == 0x8ed38f4c);
170 REQUIRE(jit.Regs()[5] == 0x0000261d);
171 REQUIRE(jit.Regs()[9] == 0xb4f08f4c);
172 REQUIRE(jit.Regs()[15] == 0x00000004);
173 REQUIRE(jit.Cpsr() == 0x000301d0);
174 }
175
176 TEST_CASE("arm: smuad (Edge-case)", "[arm][A32]") {
177 ArmTestEnv test_env;
178 A32::Jit jit{GetUserConfig(&test_env)};
179 test_env.code_mem = {
180 0xE700F211, // smuad r0, r1, r2
181 0xeafffffe, // b +#0
182 };
183
184 jit.Regs() = {
185 0, // Rd
186 0x80008000, // Rn
187 0x80008000, // Rm
188 0,
189 0, 0, 0, 0,
190 0, 0, 0, 0,
191 0, 0, 0, 0,
192 };
193 jit.SetCpsr(0x000001d0); // User-mode
194
195 test_env.ticks_left = 2;
196 jit.Run();
197
198 REQUIRE(jit.Regs()[0] == 0x80000000);
199 REQUIRE(jit.Regs()[1] == 0x80008000);
200 REQUIRE(jit.Regs()[2] == 0x80008000);
201 REQUIRE(jit.Cpsr() == 0x080001d0);
202 }
203
204 TEST_CASE("arm: Test InvalidateCacheRange", "[arm][A32]") {
205 ArmTestEnv test_env;
206 A32::Jit jit{GetUserConfig(&test_env)};
207 test_env.code_mem = {
208 0xe3a00005, // mov r0, #5
209 0xe3a0100D, // mov r1, #13
210 0xe0812000, // add r2, r1, r0
211 0xeafffffe, // b +#0 (infinite loop)
212 };
213
214 jit.Regs() = {};
215 jit.SetCpsr(0x000001d0); // User-mode
216
217 test_env.ticks_left = 4;
218 jit.Run();
219
220 REQUIRE(jit.Regs()[0] == 5);
221 REQUIRE(jit.Regs()[1] == 13);
222 REQUIRE(jit.Regs()[2] == 18);
223 REQUIRE(jit.Regs()[15] == 0x0000000c);
224 REQUIRE(jit.Cpsr() == 0x000001d0);
225
226 // Change the code
227 test_env.code_mem[1] = 0xe3a01007; // mov r1, #7
228 jit.InvalidateCacheRange(/*start_memory_location = */ 4, /* length_in_bytes = */ 4);
229
230 // Reset position of PC
231 jit.Regs()[15] = 0;
232
233 test_env.ticks_left = 4;
234 jit.Run();
235
236 REQUIRE(jit.Regs()[0] == 5);
237 REQUIRE(jit.Regs()[1] == 7);
238 REQUIRE(jit.Regs()[2] == 12);
239 REQUIRE(jit.Regs()[15] == 0x0000000c);
240 REQUIRE(jit.Cpsr() == 0x000001d0);
241 }
242
243 TEST_CASE("arm: Step blx", "[arm]") {
244 ArmTestEnv test_env;
245 A32::UserConfig config = GetUserConfig(&test_env);
246 config.enable_fast_dispatch = true;
247 Dynarmic::A32::Jit jit{config};
248 test_env.code_mem = {
249 0xe12fff30, // blx r0
250 0xe320f000, // nop
251 0xe320f000, // nop
252 0xe320f000, // nop
253 0xe320f000, // nop
254 0xe320f000, // nop
255 0xeafffffe, // b +#0 (infinite loop)
256 };
257
258 jit.Regs()[0] = 8;
259 jit.Regs()[15] = 0; // PC = 0
260 jit.SetCpsr(0x000001d0); // User-mode
261
262 test_env.ticks_left = 10;
263 jit.Step();
264
265 REQUIRE(jit.Regs()[0] == 8);
266 REQUIRE(jit.Regs()[14] == 4);
267 REQUIRE(jit.Regs()[15] == 8);
268 REQUIRE(jit.Cpsr() == 0x000001d0);
269 }
270
271 TEST_CASE("arm: Step bx", "[arm]") {
272 ArmTestEnv test_env;
273 A32::UserConfig config = GetUserConfig(&test_env);
274 config.enable_fast_dispatch = true;
275 Dynarmic::A32::Jit jit{config};
276 test_env.code_mem = {
277 0xe12fff10, // bx r0
278 0xe320f000, // nop
279 0xe320f000, // nop
280 0xe320f000, // nop
281 0xe320f000, // nop
282 0xe320f000, // nop
283 0xeafffffe, // b +#0 (infinite loop)
284 };
285
286 jit.Regs()[0] = 8;
287 jit.Regs()[15] = 0; // PC = 0
288 jit.SetCpsr(0x000001d0); // User-mode
289
290 test_env.ticks_left = 10;
291 jit.Step();
292
293 REQUIRE(jit.Regs()[0] == 8);
294 REQUIRE(jit.Regs()[15] == 8);
295 REQUIRE(jit.Cpsr() == 0x000001d0);
296 }
297
298
299 TEST_CASE("arm: Test stepping", "[arm]") {
300 ArmTestEnv test_env;
301 Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
302 test_env.code_mem = {
303 0xe320f000, // nop
304 0xe320f000, // nop
305 0xe320f000, // nop
306 0xe320f000, // nop
307 0xe320f000, // nop
308
309 0xe320f000, // nop
310 0xe320f000, // nop
311 0xe320f000, // nop
312 0xe320f000, // nop
313 0xe320f000, // nop
314
315 0xe320f000, // nop
316 0xe320f000, // nop
317 0xe320f000, // nop
318 0xe320f000, // nop
319 0xe320f000, // nop
320
321 0xe320f000, // nop
322 0xe320f000, // nop
323 0xe320f000, // nop
324 0xe320f000, // nop
325 0xe320f000, // nop
326
327 0xeafffffe, // b +#0 (infinite loop)
328 };
329
330 jit.Regs()[0] = 8;
331 jit.Regs()[15] = 0; // PC = 0
332 jit.SetCpsr(0x000001d0); // User-mode
333
334 for (size_t i = 0; i < 5; ++i) {
335 test_env.ticks_left = 10;
336 jit.Step();
337
338 REQUIRE(jit.Regs()[15] == (i + 1) * 4);
339 REQUIRE(jit.Cpsr() == 0x000001d0);
340 }
341
342 test_env.ticks_left = 20;
343 jit.Run();
344
345 REQUIRE(jit.Regs()[15] == 80);
346 REQUIRE(jit.Cpsr() == 0x000001d0);
347 }
348
349 TEST_CASE("arm: Test stepping 2", "[arm]") {
350 ArmTestEnv test_env;
351 Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
352 test_env.code_mem = {
353 0xe12fff10, // bx r0
354 0xe320f000, // nop
355 0xe320f000, // nop
356 0xe320f000, // nop
357 0xe320f000, // nop
358
359 0xe320f000, // nop
360 0xe320f000, // nop
361 0xe320f000, // nop
362 0xe320f000, // nop
363 0xe320f000, // nop
364
365 0xe320f000, // nop
366 0xe320f000, // nop
367 0xe320f000, // nop
368 0xe320f000, // nop
369 0xe320f000, // nop
370
371 0xe320f000, // nop
372 0xe320f000, // nop
373 0xe320f000, // nop
374 0xe320f000, // nop
375 0xe320f000, // nop
376
377 0xeafffffe, // b +#0 (infinite loop)
378 };
379
380 jit.Regs()[0] = 4;
381 jit.Regs()[15] = 0; // PC = 0
382 jit.SetCpsr(0x000001d0); // User-mode
383
384 for (size_t i = 0; i < 5; ++i) {
385 test_env.ticks_left = 10;
386 jit.Step();
387
388 REQUIRE(jit.Regs()[15] == (i + 1) * 4);
389 REQUIRE(jit.Cpsr() == 0x000001d0);
390 }
391
392 test_env.ticks_left = 20;
393 jit.Run();
394
395 REQUIRE(jit.Regs()[15] == 80);
396 REQUIRE(jit.Cpsr() == 0x000001d0);
397 }
398
399 TEST_CASE("arm: Test stepping 3", "[arm]") {
400 ArmTestEnv test_env;
401 Dynarmic::A32::Jit jit{GetUserConfig(&test_env)};
402 test_env.code_mem = {
403 0xe12fff10, // bx r0
404 0xe320f000, // nop
405 0xe320f000, // nop
406 0xe320f000, // nop
407 0xe320f000, // nop
408
409 0xeafffffe, // b +#0 (infinite loop)
410 };
411
412 jit.Regs()[0] = 4;
413 jit.Regs()[15] = 0; // PC = 0
414 jit.SetCpsr(0x000001d0); // User-mode
415
416 test_env.ticks_left = 10;
417 jit.Step();
418
419 REQUIRE(jit.Regs()[15] == 4);
420 REQUIRE(jit.Cpsr() == 0x000001d0);
421
422 test_env.ticks_left = 20;
423 jit.Run();
424
425 REQUIRE(jit.Regs()[15] == 20);
426 REQUIRE(jit.Cpsr() == 0x000001d0);
427 }
428
429 TEST_CASE("arm: PackedAbsDiffSumS8", "[arm][A32]") {
430 // This was a randomized test-case that was failing.
431 // In circumstances there were cases when the upper 32 bits of an argument to psadbw were not zero.
432
433 ArmTestEnv test_env;
434 A32::Jit jit{GetUserConfig(&test_env)};
435 test_env.code_mem = {
436 0x87414354, // smlsldhi r4, r1, r4, r3
437 0xe7886412, // usad8a r8, r2, r4, r6
438 0xeafffffe, // b +#0
439 };
440
441 jit.Regs() = {
442 0xea85297c, 0x417ad918, 0x64f8b70b, 0xcca0373e, 0xbc722361, 0xc528c69e, 0xca926de8, 0xd665d210,
443 0xb5650555, 0x4a24b25b, 0xaed44144, 0xe87230b2, 0x98e391de, 0x126efc0c, 0xe591fd11, 0x00000000,
444 };
445 jit.SetCpsr(0xb0000010);
446
447 test_env.ticks_left = 3;
448 jit.Run();
449
450 REQUIRE(jit.Regs()[0] == 0xea85297c);
451 REQUIRE(jit.Regs()[1] == 0x417ad918);
452 REQUIRE(jit.Regs()[2] == 0x64f8b70b);
453 REQUIRE(jit.Regs()[3] == 0xcca0373e);
454 REQUIRE(jit.Regs()[4] == 0xb685ec9f);
455 REQUIRE(jit.Regs()[5] == 0xc528c69e);
456 REQUIRE(jit.Regs()[6] == 0xca926de8);
457 REQUIRE(jit.Regs()[7] == 0xd665d210);
458 REQUIRE(jit.Regs()[8] == 0xca926f76);
459 REQUIRE(jit.Regs()[9] == 0x4a24b25b);
460 REQUIRE(jit.Regs()[10] == 0xaed44144);
461 REQUIRE(jit.Regs()[11] == 0xe87230b2);
462 REQUIRE(jit.Regs()[12] == 0x98e391de);
463 REQUIRE(jit.Regs()[13] == 0x126efc0c);
464 REQUIRE(jit.Regs()[14] == 0xe591fd11);
465 REQUIRE(jit.Regs()[15] == 0x00000008);
466 REQUIRE(jit.Cpsr() == 0xb0000010);
467 }
468
469 TEST_CASE("arm: Cleared Q flag", "[arm][A32]") {
470 ArmTestEnv test_env;
471 A32::Jit jit{GetUserConfig(&test_env)};
472
473 // qadd r1, r0, r0
474 // msr APSR_nzcvq, #0
475 // qadd r3, r2, r2
476 // b +#0 (infinite loop)
477 test_env.code_mem = {
478 0xe1001050,
479 0xe328f000,
480 0xe1023052,
481 0xeafffffe,
482 };
483
484 jit.Regs() = {
485 0x7FFFFFFF, // R0
486 0x80008000, // R1
487 0x00008000, // R2
488 0x7f7f7f7f, // R3
489 0, 0, 0, 0,
490 0, 0, 0, 0,
491 0, 0, 0, 0,
492 };
493
494 jit.SetCpsr(0x000001d0); // User-mode
495
496 test_env.ticks_left = 4;
497 jit.Run();
498
499 REQUIRE(jit.Regs()[0] == 0x7FFFFFFF);
500 REQUIRE(jit.Regs()[1] == 0x7FFFFFFF);
501 REQUIRE(jit.Regs()[2] == 0x00008000);
502 REQUIRE(jit.Regs()[3] == 0x00010000);
503 REQUIRE(jit.Cpsr() == 0x000001d0);
504 }
505
506 TEST_CASE("arm: Cleared Q flag 2", "[arm][A32][JitA64]") {
507 ArmTestEnv test_env;
508 A32::Jit jit{GetUserConfig(&test_env)};
509
510 // Because of how we calculate the ge-flag in (A64 backend)sadd8
511 // and similar instructions, the host's Q flag may set,
512 // tainting our results in subsequent instructions.
513
514 // sadd8 r1, r0, r0
515 // qadd r3, r2, r2
516 // b +#0 (infinite loop)
517 test_env.code_mem = {
518 0xe6101f90,
519 0xe1023052,
520 0xeafffffe,
521 };
522
523 jit.Regs() = {
524 0x7F007F00, // R0
525 0x80008000, // R1
526 0x00008000, // R2
527 0x7f7f7f7f, // R3
528 0, 0, 0, 0,
529 0, 0, 0, 0,
530 0, 0, 0, 0,
531 };
532
533 jit.SetCpsr(0x000001d0); // User-mode
534
535 test_env.ticks_left = 4;
536 jit.Run();
537
538 REQUIRE((jit.Cpsr() & (1 << 27)) == 0);
539 }
540