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