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