1 #ifdef PARALLEL_RSP_DEBUG_JIT
2 #include "debug_rsp.hpp"
3 #endif
4 #include "rsp_jit.hpp"
5 #include <stdio.h>
6 #include <vector>
7
8 using namespace std;
9
flip_endian(uint32_t v)10 static inline uint32_t flip_endian(uint32_t v)
11 {
12 return (v >> 24) | (v << 24) | ((v >> 8) & 0x0000ff00) | ((v << 8) & 0x00ff0000);
13 }
14
read_binary(const char * path,bool flip)15 static vector<uint32_t> read_binary(const char *path, bool flip)
16 {
17 FILE *f = fopen(path, "rb");
18 if (!f)
19 return {};
20
21 fseek(f, 0, SEEK_END);
22 long len = ftell(f);
23 rewind(f);
24
25 vector<uint32_t> v(len / 4);
26 fread(v.data(), sizeof(uint32_t), v.size(), f);
27 fclose(f);
28
29 if (flip)
30 for (auto &value : v)
31 value = flip_endian(value);
32 return v;
33 }
34
35 #if 0
36 static bool read_tag_validate(FILE *file, const char *tag)
37 {
38 char tmp[9] = {};
39 if (fread(tmp, 1, 8, file) != 8)
40 throw runtime_error("Failed to read tag.");
41
42 if (strcmp(tmp, "EOF ") == 0)
43 return false;
44
45 if (strcmp(tmp, tag))
46 throw runtime_error("Unexpected tag.");
47
48 return true;
49 }
50
51 static bool read_block(FILE *file, const char *tag, void *buffer, size_t size)
52 {
53 if (!read_tag_validate(file, tag))
54 return false;
55
56 uint32_t block_size;
57 if (fread(&block_size, sizeof(block_size), 1, file) != 1)
58 throw runtime_error("EOF");
59
60 if (size != block_size)
61 throw runtime_error("Unexpected size");
62
63 if (fread(buffer, size, 1, file) != 1)
64 throw runtime_error("EOF");
65
66 return true;
67 }
68
69 static bool read_poke(FILE *file, RSP::CPU &cpu)
70 {
71 char tmp[9] = {};
72 if (fread(tmp, 1, 8, file) != 8)
73 throw runtime_error("Failed to read tag.");
74
75 if (strcmp(tmp, "ENDDMA ") == 0)
76 return false;
77
78 if (strcmp(tmp, "POKE "))
79 throw runtime_error("Unexpected tag.");
80
81 uint32_t offset;
82 uint32_t len;
83
84 if (fread(&offset, sizeof(offset), 1, file) != 1)
85 throw runtime_error("Wrong EOF");
86 if (fread(&len, sizeof(len), 1, file) != 1)
87 throw runtime_error("Wrong EOF");
88
89 if (offset >= 0x1000)
90 {
91 if (fread(reinterpret_cast<uint8_t *>(cpu.get_state().imem) + offset - 0x1000, len, 1, file) != 1)
92 throw runtime_error("Wrong EOF");
93 }
94 else
95 {
96 if (fread(reinterpret_cast<uint8_t *>(cpu.get_state().dmem) + offset, len, 1, file) != 1)
97 throw runtime_error("Wrong EOF");
98 }
99
100 return true;
101 }
102
103 static void validate_trace(RSP::CPU &cpu, const char *path)
104 {
105 auto &state = cpu.get_state();
106 uint32_t dmem[1024];
107 uint32_t imem[1024];
108 cpu.set_dmem(dmem);
109 cpu.set_imem(imem);
110
111 FILE *file = fopen(path, "rb");
112 if (!file)
113 throw runtime_error("Failed to load trace.");
114
115 try
116 {
117 read_tag_validate(file, "RSPDUMP1");
118
119 unsigned index = 0;
120
121 while (read_tag_validate(file, "BEGIN "))
122 {
123 read_block(file, "DMEM ", state.dmem, 0x1000);
124 read_block(file, "IMEM ", state.imem, 0x1000);
125 read_block(file, "SR32 ", state.sr, sizeof(state.sr));
126 read_block(file, "VR32 ", state.cp2.regs, sizeof(state.cp2.regs));
127 read_block(file, "VLO ", state.cp2.acc.e + RSP::RSP_ACC_LO, sizeof(uint16_t) * 8);
128 read_block(file, "VMD ", state.cp2.acc.e + RSP::RSP_ACC_MD, sizeof(uint16_t) * 8);
129 read_block(file, "VHI ", state.cp2.acc.e + RSP::RSP_ACC_HI, sizeof(uint16_t) * 8);
130 read_block(file, "PC ", &state.pc, sizeof(state.pc));
131
132 int16_t VCO, VCC, VCE;
133 read_block(file, "VCO ", &VCO, sizeof(VCO));
134 read_block(file, "VCC ", &VCC, sizeof(VCC));
135 read_block(file, "VCE ", &VCE, sizeof(VCE));
136
137 rsp_set_flags(state.cp2.flags[RSP::RSP_VCO].e, VCO);
138 rsp_set_flags(state.cp2.flags[RSP::RSP_VCC].e, VCC);
139 rsp_set_flags(state.cp2.flags[RSP::RSP_VCE].e, VCE);
140
141 RSP::ReturnMode mode = RSP::MODE_CONTINUE;
142 do
143 {
144 *state.cp0.cr[RSP::CP0_REGISTER_SP_STATUS] = 0;
145 cpu.invalidate_imem();
146
147 // Run till break.
148 mode = cpu.run();
149 if (mode == RSP::MODE_DMA_READ)
150 {
151 if (!read_tag_validate(file, "BEGINDMA"))
152 throw runtime_error("Expected BEGINDMA.");
153 while (read_poke(file, cpu))
154 ;
155 }
156 } while (mode != RSP::MODE_BREAK);
157
158 uint32_t dmem[0x1000 >> 2];
159 uint32_t imem[0x1000 >> 2];
160 uint32_t sr[32];
161 uint16_t vr[32 * 8];
162 uint16_t vlo[8];
163 uint16_t vmd[8];
164 uint16_t vhi[8];
165
166 read_block(file, "DMEM END", dmem, sizeof(dmem));
167 read_block(file, "IMEM END", imem, sizeof(imem));
168 read_block(file, "SR32 END", sr, sizeof(sr));
169 read_block(file, "VR32 END", vr, sizeof(vr));
170 read_block(file, "VLO END", vlo, sizeof(vlo));
171 read_block(file, "VMD END", vmd, sizeof(vmd));
172 read_block(file, "VHI END", vhi, sizeof(vhi));
173 read_block(file, "VCO END", &VCO, sizeof(VCO));
174 read_block(file, "VCC END", &VCC, sizeof(VCC));
175 read_block(file, "VCE END", &VCE, sizeof(VCE));
176
177 unsigned errors = 0;
178
179 fprintf(stderr, "==== Trace #%u ====\n", index);
180
181 // Validate DMEM
182 for (unsigned i = 0; i < (0x1000 >> 2); i++)
183 {
184 if (state.dmem[i] != dmem[i])
185 {
186 fprintf(stderr, "DMEM32[0x%03x] fault. Expected 0x%08x, got 0x%08x!\n", i, dmem[i], state.dmem[i]);
187 errors++;
188 }
189 }
190
191 // Validate IMEM (in case of DMA)
192 for (unsigned i = 0; i < (0x1000 >> 2); i++)
193 {
194 if (state.imem[i] != imem[i])
195 {
196 fprintf(stderr, "IMEM32[0x%03x] fault. Expected 0x%08x, got 0x%08x!\n", i, dmem[i], state.dmem[i]);
197 errors++;
198 }
199 }
200
201 // Validate SR
202 for (unsigned i = 0; i < 32; i++)
203 {
204 if (sr[i] != state.sr[i])
205 {
206 fprintf(stderr, "SR[%02u] fault. Expected 0x%08x, got 0x%08x!\n", i, sr[i], state.sr[i]);
207 errors++;
208 }
209 }
210
211 // Validate VR
212 for (unsigned i = 0; i < 16 * 8; i++)
213 {
214 if (vr[i] != state.cp2.regs[i >> 3].e[i & 7])
215 {
216 fprintf(stderr, "VR[%02u][%u] fault. Expected 0x%04x, got 0x%04x!\n", i >> 3, i & 7, vr[i],
217 state.cp2.regs[i >> 3].e[i & 7]);
218 errors++;
219 }
220 }
221
222 // Validate VLO
223 for (unsigned i = 0; i < 8; i++)
224 {
225 if (vlo[i] != state.cp2.acc.e[RSP::RSP_ACC_LO + i])
226 {
227 fprintf(stderr, "VLO[%u] fault. Expected 0x%04x, got 0x%04x!\n", i, vlo[i],
228 state.cp2.acc.e[RSP::RSP_ACC_LO + i]);
229 errors++;
230 }
231 }
232
233 // Validate VMD
234 for (unsigned i = 0; i < 8; i++)
235 {
236 if (vmd[i] != state.cp2.acc.e[RSP::RSP_ACC_MD + i])
237 {
238 fprintf(stderr, "VMD[%u] fault. Expected 0x%04x, got 0x%04x!\n", i, vmd[i],
239 state.cp2.acc.e[RSP::RSP_ACC_MD + i]);
240 errors++;
241 }
242 }
243
244 // Validate VHI
245 for (unsigned i = 0; i < 8; i++)
246 {
247 if (vhi[i] != state.cp2.acc.e[RSP::RSP_ACC_HI + i])
248 {
249 fprintf(stderr, "VHI[%u] fault. Expected 0x%04x, got 0x%04x!\n", i, vhi[i],
250 state.cp2.acc.e[RSP::RSP_ACC_HI + i]);
251 errors++;
252 }
253 }
254
255 // Validate flags
256 if (VCO != rsp_get_flags(state.cp2.flags[RSP::RSP_VCO].e))
257 {
258 fprintf(stderr, "VCO fault. Expected 0x%04x, got 0x%04x!\n", VCO,
259 rsp_get_flags(state.cp2.flags[RSP::RSP_VCO].e));
260 errors++;
261 }
262
263 if (VCC != rsp_get_flags(state.cp2.flags[RSP::RSP_VCC].e))
264 {
265 fprintf(stderr, "VCC fault. Expected 0x%04x, got 0x%04x!\n", VCC,
266 rsp_get_flags(state.cp2.flags[RSP::RSP_VCC].e));
267 errors++;
268 }
269
270 if (VCE != rsp_get_flags(state.cp2.flags[RSP::RSP_VCE].e))
271 {
272 fprintf(stderr, "VCE fault. Expected 0x%04x, got 0x%04x!\n", VCE,
273 rsp_get_flags(state.cp2.flags[RSP::RSP_VCE].e));
274 errors++;
275 }
276
277 read_tag_validate(file, "END ");
278
279 if (errors == 0)
280 fprintf(stderr, "SUCCESS! :D\n");
281 else
282 fprintf(stderr, "%u ERRORS! :{\n", errors);
283 fprintf(stderr, "======================\n\n");
284
285 index++;
286 }
287 }
288 catch (const std::exception &e)
289 {
290 fprintf(stderr, "Exception: %s\n", e.what());
291 }
292
293 fclose(file);
294 }
295 #endif
296
main(int argc,char * argv[])297 int main(int argc, char *argv[])
298 {
299 RSP::JIT::CPU cpu;
300 auto &state = cpu.get_state();
301 #ifdef PARALLEL_RSP_DEBUG_JIT
302 RSP::CPU reference_cpu;
303 auto &reference_state = reference_cpu.get_state();
304 #endif
305
306 uint32_t cr[16] = {};
307 for (unsigned i = 0; i < 16; i++)
308 state.cp0.cr[i] = &cr[i];
309
310 #ifdef PARALLEL_RSP_DEBUG_JIT
311 uint32_t reference_cr[16] = {};
312 for (unsigned i = 0; i < 16; i++)
313 reference_state.cp0.cr[i] = &reference_cr[i];
314 #endif
315
316 if (argc == 3)
317 {
318 auto dmem = read_binary(argv[1], true);
319 auto imem = read_binary(argv[2], true);
320 if (imem.empty())
321 return 1;
322
323 dmem.resize(0x1000);
324 imem.resize(0x1000);
325 #ifdef PARALLEL_RSP_DEBUG_JIT
326 auto reference_dmem = dmem;
327 auto reference_imem = imem;
328 #endif
329
330 cpu.set_dmem(dmem.data());
331 cpu.set_imem(imem.data());
332 #ifdef PARALLEL_RSP_DEBUG_JIT
333 reference_cpu.set_dmem(reference_dmem.data());
334 reference_cpu.set_imem(reference_imem.data());
335 #endif
336
337 printf("=== Running Lightning CPU ===\n");
338 fflush(stdout);
339 fflush(stderr);
340 cpu.invalidate_imem();
341 cpu.run();
342 fflush(stdout);
343 fflush(stderr);
344
345 #ifdef PARALLEL_RSP_DEBUG_JIT
346 printf("=== Running reference CPU ===\n");
347 reference_cpu.invalidate_imem();
348 reference_cpu.run();
349 fflush(stdout);
350 fflush(stderr);
351
352 bool mismatch = false;
353
354 for (unsigned i = 0; i < 32; i++)
355 {
356 if (state.sr[i] != reference_state.sr[i])
357 {
358 fprintf(stderr, "SR[%u] mismatch (got 0x%x, reference 0x%x)!\n", i, state.sr[i], reference_state.sr[i]);
359 mismatch = true;
360 }
361 }
362
363 if (state.pc != reference_state.pc)
364 {
365 fprintf(stderr, "PC mismatch (got 0x%x, reference 0x%x)!\n", state.pc, reference_state.pc);
366 mismatch = true;
367 }
368
369 for (unsigned i = 0; i < 16; i++)
370 {
371 if (cr[i] != reference_cr[i])
372 {
373 fprintf(stderr, "COP0 CR [%u] mismatch (got %u, reference %u)!\n", i, cr[i], reference_cr[i]);
374 mismatch = true;
375 }
376 }
377
378 for (unsigned i = 0; i < 0x1000; i++)
379 {
380 if (dmem[i] != reference_dmem[i])
381 {
382 fprintf(stderr, "DMEM[0x%03x] mismatch (got 0x%02x, reference 0x%02x)!\n", i, dmem[i], reference_dmem[i]);
383 mismatch = true;
384 }
385 }
386
387 if (memcmp(&state.cp2, &reference_state.cp2, sizeof(state.cp2)) != 0)
388 {
389 fprintf(stderr, "CP2 register state mismatch.\n");
390 mismatch = true;
391 }
392
393 if (mismatch)
394 return EXIT_FAILURE;
395 #endif
396 }
397 #if 0
398 else if (argc == 2)
399 validate_trace(cpu, argv[1]);
400 #endif
401 else
402 return 1;
403 }
404