1 #include <lightrec.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6
7 #include "../cdrom.h"
8 #include "../gpu.h"
9 #include "../gte.h"
10 #include "../mdec.h"
11 #include "../psxdma.h"
12 #include "../psxhw.h"
13 #include "../psxmem.h"
14 #include "../r3000a.h"
15
16 #include "../frontend/main.h"
17
18 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
19
20 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
21 # define LE32TOH(x) __builtin_bswap32(x)
22 # define HTOLE32(x) __builtin_bswap32(x)
23 # define LE16TOH(x) __builtin_bswap16(x)
24 # define HTOLE16(x) __builtin_bswap16(x)
25 #else
26 # define LE32TOH(x) (x)
27 # define HTOLE32(x) (x)
28 # define LE16TOH(x) (x)
29 # define HTOLE16(x) (x)
30 #endif
31
32 #ifdef __GNUC__
33 # define likely(x) __builtin_expect(!!(x),1)
34 # define unlikely(x) __builtin_expect(!!(x),0)
35 #else
36 # define likely(x) (x)
37 # define unlikely(x) (x)
38 #endif
39
40 static struct lightrec_state *lightrec_state;
41
42 static char *name = "retroarch.exe";
43
44 static bool use_lightrec_interpreter;
45 static bool use_pcsx_interpreter;
46 static bool lightrec_debug;
47 static bool lightrec_very_debug;
48 static u32 lightrec_begin_cycles;
49
50 int stop;
51 u32 cycle_multiplier;
52 int new_dynarec_hacks;
53
54 /* Unused for now */
55 u32 event_cycles[PSXINT_COUNT];
56 u32 next_interupt;
57
new_dyna_before_save()58 void new_dyna_before_save() {}
new_dyna_after_save()59 void new_dyna_after_save() {}
new_dyna_freeze(void * f,int i)60 void new_dyna_freeze(void *f, int i) {}
61
62 enum my_cp2_opcodes {
63 OP_CP2_RTPS = 0x01,
64 OP_CP2_NCLIP = 0x06,
65 OP_CP2_OP = 0x0c,
66 OP_CP2_DPCS = 0x10,
67 OP_CP2_INTPL = 0x11,
68 OP_CP2_MVMVA = 0x12,
69 OP_CP2_NCDS = 0x13,
70 OP_CP2_CDP = 0x14,
71 OP_CP2_NCDT = 0x16,
72 OP_CP2_NCCS = 0x1b,
73 OP_CP2_CC = 0x1c,
74 OP_CP2_NCS = 0x1e,
75 OP_CP2_NCT = 0x20,
76 OP_CP2_SQR = 0x28,
77 OP_CP2_DCPL = 0x29,
78 OP_CP2_DPCT = 0x2a,
79 OP_CP2_AVSZ3 = 0x2d,
80 OP_CP2_AVSZ4 = 0x2e,
81 OP_CP2_RTPT = 0x30,
82 OP_CP2_GPF = 0x3d,
83 OP_CP2_GPL = 0x3e,
84 OP_CP2_NCCT = 0x3f,
85 };
86
87 static void (*cp2_ops[])(struct psxCP2Regs *) = {
88 [OP_CP2_RTPS] = gteRTPS,
89 [OP_CP2_RTPS] = gteRTPS,
90 [OP_CP2_NCLIP] = gteNCLIP,
91 [OP_CP2_OP] = gteOP,
92 [OP_CP2_DPCS] = gteDPCS,
93 [OP_CP2_INTPL] = gteINTPL,
94 [OP_CP2_MVMVA] = gteMVMVA,
95 [OP_CP2_NCDS] = gteNCDS,
96 [OP_CP2_CDP] = gteCDP,
97 [OP_CP2_NCDT] = gteNCDT,
98 [OP_CP2_NCCS] = gteNCCS,
99 [OP_CP2_CC] = gteCC,
100 [OP_CP2_NCS] = gteNCS,
101 [OP_CP2_NCT] = gteNCT,
102 [OP_CP2_SQR] = gteSQR,
103 [OP_CP2_DCPL] = gteDCPL,
104 [OP_CP2_DPCT] = gteDPCT,
105 [OP_CP2_AVSZ3] = gteAVSZ3,
106 [OP_CP2_AVSZ4] = gteAVSZ4,
107 [OP_CP2_RTPT] = gteRTPT,
108 [OP_CP2_GPF] = gteGPF,
109 [OP_CP2_GPL] = gteGPL,
110 [OP_CP2_NCCT] = gteNCCT,
111 };
112
113 static char cache_buf[64 * 1024];
114
cop0_mfc(struct lightrec_state * state,u32 op,u8 reg)115 static u32 cop0_mfc(struct lightrec_state *state, u32 op, u8 reg)
116 {
117 return psxRegs.CP0.r[reg];
118 }
119
cop2_mfc_cfc(struct lightrec_state * state,u8 reg,bool cfc)120 static u32 cop2_mfc_cfc(struct lightrec_state *state, u8 reg, bool cfc)
121 {
122 if (cfc)
123 return psxRegs.CP2C.r[reg];
124 else
125 return MFC2(reg);
126 }
127
cop2_mfc(struct lightrec_state * state,u32 op,u8 reg)128 static u32 cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
129 {
130 return cop2_mfc_cfc(state, reg, false);
131 }
132
cop2_cfc(struct lightrec_state * state,u32 op,u8 reg)133 static u32 cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
134 {
135 return cop2_mfc_cfc(state, reg, true);
136 }
137
cop0_mtc_ctc(struct lightrec_state * state,u8 reg,u32 value,bool ctc)138 static void cop0_mtc_ctc(struct lightrec_state *state,
139 u8 reg, u32 value, bool ctc)
140 {
141 switch (reg) {
142 case 1:
143 case 4:
144 case 8:
145 case 14:
146 case 15:
147 /* Those registers are read-only */
148 break;
149 case 12: /* Status */
150 if ((psxRegs.CP0.n.Status & ~value) & (1 << 16)) {
151 memcpy(psxM, cache_buf, sizeof(cache_buf));
152 lightrec_invalidate_all(state);
153 } else if ((~psxRegs.CP0.n.Status & value) & (1 << 16)) {
154 memcpy(cache_buf, psxM, sizeof(cache_buf));
155 }
156
157 psxRegs.CP0.n.Status = value;
158 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
159 break;
160 case 13: /* Cause */
161 psxRegs.CP0.n.Cause &= ~0x0300;
162 psxRegs.CP0.n.Cause |= value & 0x0300;
163 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
164 break;
165 default:
166 psxRegs.CP0.r[reg] = value;
167 break;
168 }
169 }
170
cop2_mtc_ctc(struct lightrec_state * state,u8 reg,u32 value,bool ctc)171 static void cop2_mtc_ctc(struct lightrec_state *state,
172 u8 reg, u32 value, bool ctc)
173 {
174 if (ctc)
175 CTC2(value, reg);
176 else
177 MTC2(value, reg);
178 }
179
cop0_mtc(struct lightrec_state * state,u32 op,u8 reg,u32 value)180 static void cop0_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
181 {
182 cop0_mtc_ctc(state, reg, value, false);
183 }
184
cop0_ctc(struct lightrec_state * state,u32 op,u8 reg,u32 value)185 static void cop0_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
186 {
187 cop0_mtc_ctc(state, reg, value, true);
188 }
189
cop2_mtc(struct lightrec_state * state,u32 op,u8 reg,u32 value)190 static void cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
191 {
192 cop2_mtc_ctc(state, reg, value, false);
193 }
194
cop2_ctc(struct lightrec_state * state,u32 op,u8 reg,u32 value)195 static void cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
196 {
197 cop2_mtc_ctc(state, reg, value, true);
198 }
199
cop0_op(struct lightrec_state * state,u32 func)200 static void cop0_op(struct lightrec_state *state, u32 func)
201 {
202 fprintf(stderr, "Invalid access to COP0\n");
203 }
204
cop2_op(struct lightrec_state * state,u32 func)205 static void cop2_op(struct lightrec_state *state, u32 func)
206 {
207 psxRegs.code = func;
208
209 if (unlikely(!cp2_ops[func & 0x3f]))
210 fprintf(stderr, "Invalid CP2 function %u\n", func);
211 else
212 cp2_ops[func & 0x3f](&psxRegs.CP2);
213 }
214
hw_write_byte(struct lightrec_state * state,u32 op,void * host,u32 mem,u8 val)215 static void hw_write_byte(struct lightrec_state *state,
216 u32 op, void *host, u32 mem, u8 val)
217 {
218 psxRegs.cycle = lightrec_current_cycle_count(state);
219
220 psxHwWrite8(mem, val);
221 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
222
223 lightrec_reset_cycle_count(state, psxRegs.cycle);
224 }
225
hw_write_half(struct lightrec_state * state,u32 op,void * host,u32 mem,u16 val)226 static void hw_write_half(struct lightrec_state *state,
227 u32 op, void *host, u32 mem, u16 val)
228 {
229 psxRegs.cycle = lightrec_current_cycle_count(state);
230
231 psxHwWrite16(mem, val);
232 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
233
234 lightrec_reset_cycle_count(state, psxRegs.cycle);
235 }
236
hw_write_word(struct lightrec_state * state,u32 op,void * host,u32 mem,u32 val)237 static void hw_write_word(struct lightrec_state *state,
238 u32 op, void *host, u32 mem, u32 val)
239 {
240 psxRegs.cycle = lightrec_current_cycle_count(state);
241
242 psxHwWrite32(mem, val);
243 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
244
245 lightrec_reset_cycle_count(state, psxRegs.cycle);
246 }
247
hw_read_byte(struct lightrec_state * state,u32 op,void * host,u32 mem)248 static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
249 {
250 u8 val;
251
252 psxRegs.cycle = lightrec_current_cycle_count(state);
253
254 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
255 val = psxHwRead8(mem);
256 lightrec_reset_cycle_count(state, psxRegs.cycle);
257
258 return val;
259 }
260
hw_read_half(struct lightrec_state * state,u32 op,void * host,u32 mem)261 static u16 hw_read_half(struct lightrec_state *state,
262 u32 op, void *host, u32 mem)
263 {
264 u16 val;
265
266 psxRegs.cycle = lightrec_current_cycle_count(state);
267
268 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
269 val = psxHwRead16(mem);
270 lightrec_reset_cycle_count(state, psxRegs.cycle);
271
272 return val;
273 }
274
hw_read_word(struct lightrec_state * state,u32 op,void * host,u32 mem)275 static u32 hw_read_word(struct lightrec_state *state,
276 u32 op, void *host, u32 mem)
277 {
278 u32 val;
279
280 psxRegs.cycle = lightrec_current_cycle_count(state);
281
282 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
283 val = psxHwRead32(mem);
284 lightrec_reset_cycle_count(state, psxRegs.cycle);
285
286 return val;
287 }
288
289 static struct lightrec_mem_map_ops hw_regs_ops = {
290 .sb = hw_write_byte,
291 .sh = hw_write_half,
292 .sw = hw_write_word,
293 .lb = hw_read_byte,
294 .lh = hw_read_half,
295 .lw = hw_read_word,
296 };
297
298 static u32 cache_ctrl;
299
cache_ctrl_write_word(struct lightrec_state * state,u32 op,void * host,u32 mem,u32 val)300 static void cache_ctrl_write_word(struct lightrec_state *state,
301 u32 op, void *host, u32 mem, u32 val)
302 {
303 cache_ctrl = val;
304 }
305
cache_ctrl_read_word(struct lightrec_state * state,u32 op,void * host,u32 mem)306 static u32 cache_ctrl_read_word(struct lightrec_state *state,
307 u32 op, void *host, u32 mem)
308 {
309 return cache_ctrl;
310 }
311
312 static struct lightrec_mem_map_ops cache_ctrl_ops = {
313 .sw = cache_ctrl_write_word,
314 .lw = cache_ctrl_read_word,
315 };
316
317 static struct lightrec_mem_map lightrec_map[] = {
318 [PSX_MAP_KERNEL_USER_RAM] = {
319 /* Kernel and user memory */
320 .pc = 0x00000000,
321 .length = 0x200000,
322 },
323 [PSX_MAP_BIOS] = {
324 /* BIOS */
325 .pc = 0x1fc00000,
326 .length = 0x80000,
327 },
328 [PSX_MAP_SCRATCH_PAD] = {
329 /* Scratch pad */
330 .pc = 0x1f800000,
331 .length = 0x400,
332 },
333 [PSX_MAP_PARALLEL_PORT] = {
334 /* Parallel port */
335 .pc = 0x1f000000,
336 .length = 0x10000,
337 },
338 [PSX_MAP_HW_REGISTERS] = {
339 /* Hardware registers */
340 .pc = 0x1f801000,
341 .length = 0x2000,
342 .ops = &hw_regs_ops,
343 },
344 [PSX_MAP_CACHE_CONTROL] = {
345 /* Cache control */
346 .pc = 0x5ffe0130,
347 .length = 4,
348 .ops = &cache_ctrl_ops,
349 },
350
351 /* Mirrors of the kernel/user memory */
352 [PSX_MAP_MIRROR1] = {
353 .pc = 0x00200000,
354 .length = 0x200000,
355 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
356 },
357 [PSX_MAP_MIRROR2] = {
358 .pc = 0x00400000,
359 .length = 0x200000,
360 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
361 },
362 [PSX_MAP_MIRROR3] = {
363 .pc = 0x00600000,
364 .length = 0x200000,
365 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
366 },
367 };
368
369 static const struct lightrec_ops lightrec_ops = {
370 .cop0_ops = {
371 .mfc = cop0_mfc,
372 .cfc = cop0_mfc,
373 .mtc = cop0_mtc,
374 .ctc = cop0_ctc,
375 .op = cop0_op,
376 },
377 .cop2_ops = {
378 .mfc = cop2_mfc,
379 .cfc = cop2_cfc,
380 .mtc = cop2_mtc,
381 .ctc = cop2_ctc,
382 .op = cop2_op,
383 },
384 };
385
lightrec_plugin_init(void)386 static int lightrec_plugin_init(void)
387 {
388 lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
389 lightrec_map[PSX_MAP_BIOS].address = psxR;
390 lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
391 lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
392
393 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
394 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
395 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
396 if (getenv("LIGHTREC_BEGIN_CYCLES"))
397 lightrec_begin_cycles = (unsigned int) strtol(
398 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
399
400 lightrec_state = lightrec_init(name,
401 lightrec_map, ARRAY_SIZE(lightrec_map),
402 &lightrec_ops);
403
404 fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
405 (uintptr_t) psxM,
406 (uintptr_t) psxP,
407 (uintptr_t) psxR,
408 (uintptr_t) psxH);
409
410 #ifndef _WIN32
411 signal(SIGPIPE, exit);
412 #endif
413 return 0;
414 }
415
hash_calculate_le(const void * buffer,u32 count)416 static u32 hash_calculate_le(const void *buffer, u32 count)
417 {
418 unsigned int i;
419 u32 *data = (u32 *) buffer;
420 u32 hash = 0xffffffff;
421
422 count /= 4;
423 for(i = 0; i < count; ++i) {
424 hash += LE32TOH(data[i]);
425 hash += (hash << 10);
426 hash ^= (hash >> 6);
427 }
428
429 hash += (hash << 3);
430 hash ^= (hash >> 11);
431 hash += (hash << 15);
432 return hash;
433 }
434
hash_calculate(const void * buffer,u32 count)435 static u32 hash_calculate(const void *buffer, u32 count)
436 {
437 unsigned int i;
438 u32 *data = (u32 *) buffer;
439 u32 hash = 0xffffffff;
440
441 count /= 4;
442 for(i = 0; i < count; ++i) {
443 hash += data[i];
444 hash += (hash << 10);
445 hash ^= (hash >> 6);
446 }
447
448 hash += (hash << 3);
449 hash ^= (hash >> 11);
450 hash += (hash << 15);
451 return hash;
452 }
453
454 static const char * const mips_regs[] = {
455 "zero",
456 "at",
457 "v0", "v1",
458 "a0", "a1", "a2", "a3",
459 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
460 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
461 "t8", "t9",
462 "k0", "k1",
463 "gp", "sp", "fp", "ra",
464 "lo", "hi",
465 };
466
print_for_big_ass_debugger(void)467 static void print_for_big_ass_debugger(void)
468 {
469 unsigned int i;
470
471 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
472
473 if (lightrec_very_debug)
474 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
475 hash_calculate_le(psxM, 0x200000),
476 hash_calculate_le(psxH, 0x400),
477 hash_calculate_le(psxH + 0x1000, 0x2000));
478
479 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
480 hash_calculate(&psxRegs.CP0.r,
481 sizeof(psxRegs.CP0.r)),
482 hash_calculate(&psxRegs.CP2D.r,
483 sizeof(psxRegs.CP2D.r)),
484 hash_calculate(&psxRegs.CP2C.r,
485 sizeof(psxRegs.CP2C.r)),
486 psxRegs.interrupt,
487 hash_calculate(psxRegs.intCycle,
488 sizeof(psxRegs.intCycle)),
489 LE32TOH(HW_GPU_STATUS));
490
491 if (lightrec_very_debug)
492 for (i = 0; i < 34; i++)
493 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
494 else
495 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
496 sizeof(psxRegs.GPR.r)));
497 printf("\n");
498 }
499
500
501 extern void intExecuteBlock();
502
503 static u32 old_cycle_counter;
504
lightrec_plugin_execute_block(void)505 static void lightrec_plugin_execute_block(void)
506 {
507 u32 old_pc = psxRegs.pc;
508 u32 flags;
509
510 if (use_pcsx_interpreter) {
511 intExecuteBlock();
512 } else {
513 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
514 lightrec_restore_registers(lightrec_state, psxRegs.GPR.r);
515
516 if (use_lightrec_interpreter)
517 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
518 psxRegs.pc);
519 else
520 psxRegs.pc = lightrec_execute_one(lightrec_state,
521 psxRegs.pc);
522
523 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
524
525 lightrec_dump_registers(lightrec_state, psxRegs.GPR.r);
526 flags = lightrec_exit_flags(lightrec_state);
527
528 if (flags & LIGHTREC_EXIT_SEGFAULT) {
529 fprintf(stderr, "Exiting at cycle 0x%08x\n",
530 psxRegs.cycle);
531 exit(1);
532 }
533
534 if (flags & LIGHTREC_EXIT_SYSCALL)
535 psxException(0x20, 0);
536 }
537
538 psxBranchTest();
539
540 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
541 && psxRegs.pc != old_pc)
542 print_for_big_ass_debugger();
543
544 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
545 (psxRegs.CP0.n.Status & 0x1)) {
546 /* Handle software interrupts */
547 psxRegs.CP0.n.Cause &= ~0x7c;
548 psxException(psxRegs.CP0.n.Cause, 0);
549 }
550
551 if ((psxRegs.cycle & ~0xfffffff) != old_cycle_counter) {
552 SysDLog("RAM usage: Lightrec %u KiB, IR %u KiB, CODE %u KiB, "
553 "MIPS %u KiB, TOTAL %u KiB, avg. IPI %f\n",
554 lightrec_get_mem_usage(MEM_FOR_LIGHTREC) / 1024,
555 lightrec_get_mem_usage(MEM_FOR_IR) / 1024,
556 lightrec_get_mem_usage(MEM_FOR_CODE) / 1024,
557 lightrec_get_mem_usage(MEM_FOR_MIPS_CODE) / 1024,
558 lightrec_get_total_mem_usage() / 1024,
559 lightrec_get_average_ipi());
560 old_cycle_counter = psxRegs.cycle & ~0xfffffff;
561 }
562 }
563
lightrec_plugin_execute(void)564 static void lightrec_plugin_execute(void)
565 {
566 extern int stop;
567
568 while (!stop)
569 lightrec_plugin_execute_block();
570 }
571
lightrec_plugin_clear(u32 addr,u32 size)572 static void lightrec_plugin_clear(u32 addr, u32 size)
573 {
574 if (addr == 0 && size == UINT32_MAX)
575 lightrec_invalidate_all(lightrec_state);
576 else
577 /* size * 4: PCSX uses DMA units */
578 lightrec_invalidate(lightrec_state, addr, size * 4);
579 }
580
lightrec_plugin_shutdown(void)581 static void lightrec_plugin_shutdown(void)
582 {
583 lightrec_destroy(lightrec_state);
584 }
585
lightrec_plugin_reset(void)586 static void lightrec_plugin_reset(void)
587 {
588 lightrec_plugin_shutdown();
589 lightrec_plugin_init();
590 }
591
592 R3000Acpu psxRec =
593 {
594 lightrec_plugin_init,
595 lightrec_plugin_reset,
596 lightrec_plugin_execute,
597 lightrec_plugin_execute_block,
598 lightrec_plugin_clear,
599 lightrec_plugin_shutdown,
600 };
601