1 #include <cinttypes>
2 #include <cstdio>
3 #include <iomanip>
4 #include <memory>
5 #include <teakra/disassembler.h>
6 #include "../core_timing.h"
7 #include "../interpreter.h"
8 #include "../memory_interface.h"
9 #include "../shared_memory.h"
10 #include "../test.h"
11 
Flag16ToString(u16 value,const char * symbols)12 std::string Flag16ToString(u16 value, const char* symbols) {
13     std::string result = symbols;
14     for (int i = 0; i < 16; ++i) {
15         if ((value >> i & 1) == 0)
16             result[15 - i] = '-';
17     }
18     return result;
19 }
20 
main(int argc,char ** argv)21 int main(int argc, char** argv) {
22     if (argc < 2) {
23         std::fprintf(stderr, "A filename argument must be provided. Exiting...\n");
24         return -1;
25     }
26 
27     std::unique_ptr<std::FILE, decltype(&std::fclose)> file{std::fopen(argv[1], "rb"), std::fclose};
28     if (!file) {
29         std::fprintf(stderr, "Unable to open file %s. Exiting...\n", argv[1]);
30         return -2;
31     }
32 
33     Teakra::CoreTiming core_timing;
34     Teakra::SharedMemory shared_memory;
35     Teakra::MemoryInterfaceUnit miu;
36     Teakra::MemoryInterface memory_interface{shared_memory, miu};
37     Teakra::RegisterState regs;
38     Teakra::Interpreter interpreter(core_timing, regs, memory_interface);
39 
40     int i = 0;
41     int passed = 0;
42     int total = 0;
43     int skipped = 0;
44     while (true) {
45         TestCase test_case;
46         if (std::fread(&test_case, sizeof(test_case), 1, file.get()) == 0) {
47             break;
48         }
49         regs.Reset();
50         regs.a = test_case.before.a;
51         regs.b = test_case.before.b;
52         regs.p = test_case.before.p;
53         regs.r = test_case.before.r;
54         regs.x = test_case.before.x;
55         regs.y = test_case.before.y;
56         regs.stepi0 = test_case.before.stepi0;
57         regs.stepj0 = test_case.before.stepj0;
58         regs.mixp = test_case.before.mixp;
59         regs.sv = test_case.before.sv;
60         regs.repc = test_case.before.repc;
61         regs.Lc() = test_case.before.lc;
62         regs.Set<Teakra::cfgi>(test_case.before.cfgi);
63         regs.Set<Teakra::cfgj>(test_case.before.cfgj);
64         regs.Set<Teakra::stt0>(test_case.before.stt0);
65         regs.Set<Teakra::stt1>(test_case.before.stt1);
66         regs.Set<Teakra::stt2>(test_case.before.stt2);
67         regs.Set<Teakra::mod0>(test_case.before.mod0);
68         regs.Set<Teakra::mod1>(test_case.before.mod1);
69         regs.Set<Teakra::mod2>(test_case.before.mod2);
70         regs.Set<Teakra::ar0>(test_case.before.ar[0]);
71         regs.Set<Teakra::ar1>(test_case.before.ar[1]);
72         regs.Set<Teakra::arp0>(test_case.before.arp[0]);
73         regs.Set<Teakra::arp1>(test_case.before.arp[1]);
74         regs.Set<Teakra::arp2>(test_case.before.arp[2]);
75         regs.Set<Teakra::arp3>(test_case.before.arp[3]);
76 
77         for (u16 offset = 0; offset < TestSpaceSize; ++offset) {
78             memory_interface.DataWrite(TestSpaceX + offset, test_case.before.test_space_x[offset]);
79             memory_interface.DataWrite(TestSpaceY + offset, test_case.before.test_space_y[offset]);
80         }
81 
82         memory_interface.ProgramWrite(0, test_case.opcode);
83         memory_interface.ProgramWrite(1, test_case.expand);
84 
85         bool pass = true;
86         bool skip = false;
87         try {
88             interpreter.Run(1);
89             auto Check40 = [&](const char* name, u64 expected, u64 actual) {
90                 if (expected != actual) {
91                     std::printf("Mismatch: %s: %010" PRIx64 " != %010" PRIx64 "\n", name,
92                                 expected & 0xFF'FFFF'FFFF, actual & 0xFF'FFFF'FFFF);
93                     pass = false;
94                 }
95             };
96 
97             auto Check32 = [&](const char* name, u32 expected, u32 actual) {
98                 if (expected != actual) {
99                     std::printf("Mismatch: %s: %08X != %08X\n", name, expected, actual);
100                     pass = false;
101                 }
102             };
103 
104             auto Check = [&](const char* name, u16 expected, u16 actual) {
105                 if (expected != actual) {
106                     std::printf("Mismatch: %s: %04X != %04X\n", name, expected, actual);
107                     pass = false;
108                 }
109             };
110 
111             auto CheckAddress = [&](const char* name, u16 address, u16 expected, u16 actual) {
112                 if (expected != actual) {
113                     std::printf("Mismatch: %s%04X: %04X != %04X\n", name, address, expected,
114                                 actual);
115                     pass = false;
116                 }
117             };
118 
119             auto CheckFlag = [&](const char* name, u16 expected, u16 actual, const char* symbols) {
120                 if (expected != actual) {
121                     std::printf("Mismatch: %s: %s != %s\n", name,
122                                 Flag16ToString(expected, symbols).c_str(),
123                                 Flag16ToString(actual, symbols).c_str());
124                     pass = false;
125                 }
126             };
127 
128             Check40("a0", SignExtend<40>(test_case.after.a[0]), regs.a[0]);
129             Check40("a1", SignExtend<40>(test_case.after.a[1]), regs.a[1]);
130             Check40("b0", SignExtend<40>(test_case.after.b[0]), regs.b[0]);
131             Check40("b1", SignExtend<40>(test_case.after.b[1]), regs.b[1]);
132             Check32("p0", test_case.after.p[0], regs.p[0]);
133             Check32("p1", test_case.after.p[1], regs.p[1]);
134             Check("r0", test_case.after.r[0], regs.r[0]);
135             Check("r1", test_case.after.r[1], regs.r[1]);
136             Check("r2", test_case.after.r[2], regs.r[2]);
137             Check("r3", test_case.after.r[3], regs.r[3]);
138             Check("r4", test_case.after.r[4], regs.r[4]);
139             Check("r5", test_case.after.r[5], regs.r[5]);
140             Check("r6", test_case.after.r[6], regs.r[6]);
141             Check("r7", test_case.after.r[7], regs.r[7]);
142             Check("x0", test_case.after.x[0], regs.x[0]);
143             Check("x1", test_case.after.x[1], regs.x[1]);
144             Check("y0", test_case.after.y[0], regs.y[0]);
145             Check("y1", test_case.after.y[1], regs.y[1]);
146             Check("stepi0", test_case.after.stepi0, regs.stepi0);
147             Check("stepj0", test_case.after.stepj0, regs.stepj0);
148             Check("mixp", test_case.after.mixp, regs.mixp);
149             Check("sv", test_case.after.sv, regs.sv);
150             Check("repc", test_case.after.repc, regs.repc);
151             Check("lc", test_case.after.lc, regs.Lc());
152             CheckFlag("cfgi", test_case.after.cfgi, regs.Get<Teakra::cfgi>(), "mmmmmmmmmsssssss");
153             CheckFlag("cfgj", test_case.after.cfgj, regs.Get<Teakra::cfgj>(), "mmmmmmmmmsssssss");
154             CheckFlag("stt0", test_case.after.stt0, regs.Get<Teakra::stt0>(), "####C###ZMNVCELL");
155             CheckFlag("stt1", test_case.after.stt1, regs.Get<Teakra::stt1>(), "QP#########R####");
156             CheckFlag("stt2", test_case.after.stt2, regs.Get<Teakra::stt2>(), "LBBB####mm##V21I");
157             CheckFlag("mod0", test_case.after.mod0, regs.Get<Teakra::mod0>(), "#QQ#PPooSYY###SS");
158             CheckFlag("mod1", test_case.after.mod1, regs.Get<Teakra::mod1>(), "???B####pppppppp");
159             CheckFlag("mod2", test_case.after.mod2, regs.Get<Teakra::mod2>(), "7654321m7654321M");
160             CheckFlag("ar0", test_case.after.ar[0], regs.Get<Teakra::ar0>(), "RRRRRRoosssoosss");
161             CheckFlag("ar1", test_case.after.ar[1], regs.Get<Teakra::ar1>(), "RRRRRRoosssoosss");
162             CheckFlag("arp0", test_case.after.arp[0], regs.Get<Teakra::arp0>(), "#RR#RRjjjjjiiiii");
163             CheckFlag("arp1", test_case.after.arp[1], regs.Get<Teakra::arp1>(), "#RR#RRjjjjjiiiii");
164             CheckFlag("arp2", test_case.after.arp[2], regs.Get<Teakra::arp2>(), "#RR#RRjjjjjiiiii");
165             CheckFlag("arp3", test_case.after.arp[3], regs.Get<Teakra::arp3>(), "#RR#RRjjjjjiiiii");
166 
167             for (u16 offset = 0; offset < TestSpaceSize; ++offset) {
168                 CheckAddress("memory_", (TestSpaceX + offset), test_case.after.test_space_x[offset],
169                              memory_interface.DataRead(TestSpaceX + offset));
170                 CheckAddress("memory_", (TestSpaceY + offset), test_case.after.test_space_y[offset],
171                              memory_interface.DataRead(TestSpaceY + offset));
172             }
173             ++total;
174         } catch (const Teakra::UnimplementedException&) {
175             std::printf("Skipped one unimplemented case\n");
176             pass = false;
177             skip = true;
178             ++skipped;
179         }
180 
181         if (pass) {
182             ++passed;
183         } else {
184             Teakra::Disassembler::ArArpSettings ar_arp;
185             ar_arp.ar = test_case.before.ar;
186             ar_arp.arp = test_case.before.arp;
187             std::printf(
188                 "Test case %d: %04X %04X %s\n", i, test_case.opcode, test_case.expand,
189                 Teakra::Disassembler::Do(test_case.opcode, test_case.expand, ar_arp).c_str());
190             if (!skip) {
191                 std::printf("before:\n");
192                 std::printf("a0 = %010" PRIx64 "; a1 = %010" PRIx64 "\n",
193                             test_case.before.a[0] & 0xFF'FFFF'FFFF,
194                             test_case.before.a[1] & 0xFF'FFFF'FFFF);
195                 std::printf("b0 = %010" PRIx64 "; b1 = %010" PRIx64 "\n",
196                             test_case.before.b[0] & 0xFF'FFFF'FFFF,
197                             test_case.before.b[1] & 0xFF'FFFF'FFFF);
198                 std::printf("p0 = %08X; p1 = %08X\n", test_case.before.p[0], test_case.before.p[1]);
199                 std::printf("x0 = %04X; x1 = %04X\n", test_case.before.x[0], test_case.before.x[1]);
200                 std::printf("y0 = %04X; y1 = %04X\n", test_case.before.y[0], test_case.before.y[1]);
201                 std::printf("r0 = %04X; r1 = %04X; r2 = %04X; r3 = %04X\n", test_case.before.r[0],
202                             test_case.before.r[1], test_case.before.r[2], test_case.before.r[3]);
203                 std::printf("r4 = %04X; r5 = %04X; r6 = %04X; r7 = %04X\n", test_case.before.r[4],
204                             test_case.before.r[5], test_case.before.r[6], test_case.before.r[7]);
205                 std::printf("stepi0 = %04X\n", test_case.before.stepi0);
206                 std::printf("stepj0 = %04X\n", test_case.before.stepj0);
207                 std::printf("mixp = %04X\n", test_case.before.mixp);
208                 std::printf("sv = %04X\n", test_case.before.sv);
209                 std::printf("repc = %04X\n", test_case.before.repc);
210                 std::printf("lc = %04X\n", test_case.before.lc);
211                 std::printf("cfgi = %s\n",
212                             Flag16ToString(test_case.before.cfgi, "mmmmmmmmmsssssss").c_str());
213                 std::printf("cfgj = %s\n",
214                             Flag16ToString(test_case.before.cfgj, "mmmmmmmmmsssssss").c_str());
215                 std::printf("stt0 = %s\n",
216                             Flag16ToString(test_case.before.stt0, "####C###ZMNVCELL").c_str());
217                 std::printf("stt1 = %s\n",
218                             Flag16ToString(test_case.before.stt1, "QP#########R####").c_str());
219                 std::printf("stt2 = %s\n",
220                             Flag16ToString(test_case.before.stt2, "LBBB####mm##V21I").c_str());
221                 std::printf("mod0 = %s\n",
222                             Flag16ToString(test_case.before.mod0, "#QQ#PPooSYY###SS").c_str());
223                 std::printf("mod1 = %s\n",
224                             Flag16ToString(test_case.before.mod1, "jicB####pppppppp").c_str());
225                 std::printf("mod2 = %s\n",
226                             Flag16ToString(test_case.before.mod2, "7654321m7654321M").c_str());
227                 std::printf("ar0 = %s\n",
228                             Flag16ToString(test_case.before.ar[0], "RRRRRRoosssoosss").c_str());
229                 std::printf("ar1 = %s\n",
230                             Flag16ToString(test_case.before.ar[1], "RRRRRRoosssoosss").c_str());
231                 std::printf("arp0 = %s\n",
232                             Flag16ToString(test_case.before.arp[0], "#RR#RRiiiiijjjjj").c_str());
233                 std::printf("arp1 = %s\n",
234                             Flag16ToString(test_case.before.arp[1], "#RR#RRiiiiijjjjj").c_str());
235                 std::printf("arp2 = %s\n",
236                             Flag16ToString(test_case.before.arp[2], "#RR#RRiiiiijjjjj").c_str());
237                 std::printf("arp3 = %s\n",
238                             Flag16ToString(test_case.before.arp[3], "#RR#RRiiiiijjjjj").c_str());
239                 std::printf("FAILED\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n");
240             }
241         }
242 
243         ++i;
244     }
245 
246     std::printf("%d / %d passed, %d skipped\n", passed, total, skipped);
247 
248     if (passed < total) {
249         return 1;
250     }
251 
252     return 0;
253 }
254