3e1126549bcbcc540fde2140384f92b4cc8e34c9
[pcsx_rearmed.git] / libpcsxcore / lightrec / plugin.c
1 #include <errno.h>
2 #include <stdbool.h>
3 #include <stdio.h>
4 #include <unistd.h>
5 #include <signal.h>
6 #include <assert.h>
7
8 #if P_HAVE_MMAP
9 #include <sys/mman.h>
10 #endif
11
12 #include "lightrec.h"
13 #include "../cdrom.h"
14 #include "../gpu.h"
15 #include "../gte.h"
16 #include "../mdec.h"
17 #include "../psxdma.h"
18 #include "../psxhw.h"
19 #include "../psxmem.h"
20 #include "../r3000a.h"
21 #include "../psxinterpreter.h"
22 #include "../psxhle.h"
23 #include "../psxevents.h"
24
25 #include "../frontend/main.h"
26
27 #include "mem.h"
28 #include "plugin.h"
29
30 #if (defined(__arm__) || defined(__aarch64__)) && !defined(ALLOW_LIGHTREC_ON_ARM)
31 #error "Lightrec should not be used on ARM (please specify DYNAREC=ari64 to make)"
32 #endif
33
34 #define ARRAY_SIZE(x) (sizeof(x) ? sizeof(x) / sizeof((x)[0]) : 0)
35
36 #if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
37 #       define LE32TOH(x)       __builtin_bswap32(x)
38 #       define HTOLE32(x)       __builtin_bswap32(x)
39 #       define LE16TOH(x)       __builtin_bswap16(x)
40 #       define HTOLE16(x)       __builtin_bswap16(x)
41 #else
42 #       define LE32TOH(x)       (x)
43 #       define HTOLE32(x)       (x)
44 #       define LE16TOH(x)       (x)
45 #       define HTOLE16(x)       (x)
46 #endif
47
48 #ifdef __GNUC__
49 #       define likely(x)       __builtin_expect(!!(x),1)
50 #       define unlikely(x)     __builtin_expect(!!(x),0)
51 #else
52 #       define likely(x)       (x)
53 #       define unlikely(x)     (x)
54 #endif
55
56 #ifndef LIGHTREC_PROG_NAME
57 #  ifdef __linux__
58 #    define LIGHTREC_PROG_NAME "/proc/self/exe"
59 #  else
60 #    define LIGHTREC_PROG_NAME "retroarch.exe"
61 #  endif
62 #endif
63
64 #ifndef GPUSTATUS_POLLING_THRESHOLD
65 #  define GPUSTATUS_POLLING_THRESHOLD 0
66 #endif
67
68 psxRegisters psxRegs;
69 Rcnt rcnts[4];
70
71 void* code_buffer;
72
73 static struct lightrec_state *lightrec_state;
74
75 static bool use_lightrec_interpreter;
76 static bool block_stepping;
77 //static bool use_pcsx_interpreter;
78 #define use_pcsx_interpreter 0
79 static bool ram_disabled;
80 static bool lightrec_debug, lightrec_very_debug;
81 static u32 lightrec_begin_cycles;
82
83 extern u32 lightrec_hacks;
84
85 static void lightrec_plugin_apply_config();
86 extern void lightrec_code_inv(void *ptr, uint32_t len);
87
88 enum my_cp2_opcodes {
89         OP_CP2_RTPS             = 0x01,
90         OP_CP2_NCLIP            = 0x06,
91         OP_CP2_OP               = 0x0c,
92         OP_CP2_DPCS             = 0x10,
93         OP_CP2_INTPL            = 0x11,
94         OP_CP2_MVMVA            = 0x12,
95         OP_CP2_NCDS             = 0x13,
96         OP_CP2_CDP              = 0x14,
97         OP_CP2_NCDT             = 0x16,
98         OP_CP2_NCCS             = 0x1b,
99         OP_CP2_CC               = 0x1c,
100         OP_CP2_NCS              = 0x1e,
101         OP_CP2_NCT              = 0x20,
102         OP_CP2_SQR              = 0x28,
103         OP_CP2_DCPL             = 0x29,
104         OP_CP2_DPCT             = 0x2a,
105         OP_CP2_AVSZ3            = 0x2d,
106         OP_CP2_AVSZ4            = 0x2e,
107         OP_CP2_RTPT             = 0x30,
108         OP_CP2_GPF              = 0x3d,
109         OP_CP2_GPL              = 0x3e,
110         OP_CP2_NCCT             = 0x3f,
111 };
112
113 static void (*cp2_ops[])(struct psxCP2Regs *) = {
114         [OP_CP2_RTPS] = gteRTPS,
115         [OP_CP2_NCLIP] = gteNCLIP,
116         [OP_CP2_OP] = gteOP,
117         [OP_CP2_DPCS] = gteDPCS,
118         [OP_CP2_INTPL] = gteINTPL,
119         [OP_CP2_MVMVA] = gteMVMVA,
120         [OP_CP2_NCDS] = gteNCDS,
121         [OP_CP2_CDP] = gteCDP,
122         [OP_CP2_NCDT] = gteNCDT,
123         [OP_CP2_NCCS] = gteNCCS,
124         [OP_CP2_CC] = gteCC,
125         [OP_CP2_NCS] = gteNCS,
126         [OP_CP2_NCT] = gteNCT,
127         [OP_CP2_SQR] = gteSQR,
128         [OP_CP2_DCPL] = gteDCPL,
129         [OP_CP2_DPCT] = gteDPCT,
130         [OP_CP2_AVSZ3] = gteAVSZ3,
131         [OP_CP2_AVSZ4] = gteAVSZ4,
132         [OP_CP2_RTPT] = gteRTPT,
133         [OP_CP2_GPF] = gteGPF,
134         [OP_CP2_GPL] = gteGPL,
135         [OP_CP2_NCCT] = gteNCCT,
136 };
137
138 static char cache_buf[64 * 1024];
139
140 static void cop2_op(struct lightrec_state *state, u32 func)
141 {
142         struct lightrec_registers *regs = lightrec_get_registers(state);
143
144         psxRegs.code = func;
145
146         if (unlikely(!cp2_ops[func & 0x3f])) {
147                 fprintf(stderr, "Invalid CP2 function %u\n", func);
148         } else {
149                 /* This works because regs->cp2c comes right after regs->cp2d,
150                  * so it can be cast to a pcsxCP2Regs pointer. */
151                 cp2_ops[func & 0x3f]((psxCP2Regs *) regs->cp2d);
152         }
153 }
154
155 static bool has_interrupt(void)
156 {
157         struct lightrec_registers *regs = lightrec_get_registers(lightrec_state);
158
159         return ((psxHu32(0x1070) & psxHu32(0x1074)) &&
160                 (regs->cp0[12] & 0x401) == 0x401) ||
161                 (regs->cp0[12] & regs->cp0[13] & 0x0300);
162 }
163
164 static void lightrec_tansition_to_pcsx(struct lightrec_state *state)
165 {
166         psxRegs.cycle += lightrec_current_cycle_count(state) / 1024;
167         lightrec_reset_cycle_count(state, 0);
168 }
169
170 static void lightrec_tansition_from_pcsx(struct lightrec_state *state)
171 {
172         s32 cycles_left = psxRegs.next_interupt - psxRegs.cycle;
173
174         if (block_stepping || cycles_left <= 0 || has_interrupt())
175                 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
176         else {
177                 lightrec_set_target_cycle_count(state, cycles_left * 1024);
178         }
179 }
180
181 static void hw_write_byte(struct lightrec_state *state,
182                           u32 op, void *host, u32 mem, u32 val)
183 {
184         lightrec_tansition_to_pcsx(state);
185
186         psxHwWrite8(mem, val);
187
188         lightrec_tansition_from_pcsx(state);
189 }
190
191 static void hw_write_half(struct lightrec_state *state,
192                           u32 op, void *host, u32 mem, u32 val)
193 {
194         lightrec_tansition_to_pcsx(state);
195
196         psxHwWrite16(mem, val);
197
198         lightrec_tansition_from_pcsx(state);
199 }
200
201 static void hw_write_word(struct lightrec_state *state,
202                           u32 op, void *host, u32 mem, u32 val)
203 {
204         lightrec_tansition_to_pcsx(state);
205
206         psxHwWrite32(mem, val);
207
208         lightrec_tansition_from_pcsx(state);
209 }
210
211 static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
212 {
213         u8 val;
214
215         lightrec_tansition_to_pcsx(state);
216
217         val = psxHwRead8(mem);
218
219         lightrec_tansition_from_pcsx(state);
220
221         return val;
222 }
223
224 static u16 hw_read_half(struct lightrec_state *state,
225                         u32 op, void *host, u32 mem)
226 {
227         u16 val;
228
229         lightrec_tansition_to_pcsx(state);
230
231         val = psxHwRead16(mem);
232
233         lightrec_tansition_from_pcsx(state);
234
235         return val;
236 }
237
238 static u32 hw_read_word(struct lightrec_state *state,
239                         u32 op, void *host, u32 mem)
240 {
241         static u32 old_cycle, oldold_cycle, old_gpusr;
242         u32 val, diff;
243
244         lightrec_tansition_to_pcsx(state);
245
246         val = psxHwRead32(mem);
247
248         if (GPUSTATUS_POLLING_THRESHOLD > 0 && mem == 0x1f801814) {
249                 diff = psxRegs.cycle - old_cycle;
250
251                 if (diff > 0
252                     && diff < GPUSTATUS_POLLING_THRESHOLD
253                     && diff == old_cycle - oldold_cycle) {
254                         while (psxRegs.next_interupt > psxRegs.cycle && val == old_gpusr) {
255                                 psxRegs.cycle += diff;
256                                 val = psxHwRead32(mem);
257                         }
258                 }
259
260                 oldold_cycle = old_cycle;
261                 old_cycle = psxRegs.cycle;
262                 old_gpusr = val;
263         }
264
265         lightrec_tansition_from_pcsx(state);
266
267         return val;
268 }
269
270 static struct lightrec_mem_map_ops hw_regs_ops = {
271         .sb = hw_write_byte,
272         .sh = hw_write_half,
273         .sw = hw_write_word,
274         .lb = hw_read_byte,
275         .lh = hw_read_half,
276         .lw = hw_read_word,
277 };
278
279 static u32 cache_ctrl;
280
281 static void cache_ctrl_write_word(struct lightrec_state *state,
282                                   u32 op, void *host, u32 mem, u32 val)
283 {
284         cache_ctrl = val;
285 }
286
287 static u32 cache_ctrl_read_word(struct lightrec_state *state,
288                                 u32 op, void *host, u32 mem)
289 {
290         return cache_ctrl;
291 }
292
293 static struct lightrec_mem_map_ops cache_ctrl_ops = {
294         .sw = cache_ctrl_write_word,
295         .lw = cache_ctrl_read_word,
296 };
297
298 static struct lightrec_mem_map lightrec_map[] = {
299         [PSX_MAP_KERNEL_USER_RAM] = {
300                 /* Kernel and user memory */
301                 .pc = 0x00000000,
302                 .length = 0x200000,
303         },
304         [PSX_MAP_BIOS] = {
305                 /* BIOS */
306                 .pc = 0x1fc00000,
307                 .length = 0x80000,
308         },
309         [PSX_MAP_SCRATCH_PAD] = {
310                 /* Scratch pad */
311                 .pc = 0x1f800000,
312                 .length = 0x400,
313         },
314         [PSX_MAP_PARALLEL_PORT] = {
315                 /* Parallel port */
316                 .pc = 0x1f000000,
317                 .length = 0x10000,
318         },
319         [PSX_MAP_HW_REGISTERS] = {
320                 /* Hardware registers */
321                 .pc = 0x1f801000,
322                 .length = 0x8000,
323                 .ops = &hw_regs_ops,
324         },
325         [PSX_MAP_CACHE_CONTROL] = {
326                 /* Cache control */
327                 .pc = 0x5ffe0130,
328                 .length = 4,
329                 .ops = &cache_ctrl_ops,
330         },
331
332         /* Mirrors of the kernel/user memory */
333         [PSX_MAP_MIRROR1] = {
334                 .pc = 0x00200000,
335                 .length = 0x200000,
336                 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
337         },
338         [PSX_MAP_MIRROR2] = {
339                 .pc = 0x00400000,
340                 .length = 0x200000,
341                 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
342         },
343         [PSX_MAP_MIRROR3] = {
344                 .pc = 0x00600000,
345                 .length = 0x200000,
346                 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
347         },
348
349         /* Mirror of the parallel port. Only used by the PS2/PS3 BIOS */
350         [PSX_MAP_PPORT_MIRROR] = {
351                 .pc = 0x1fa00000,
352                 .length = 0x10000,
353                 .mirror_of = &lightrec_map[PSX_MAP_PARALLEL_PORT],
354         },
355
356         /* Code buffer */
357         [PSX_MAP_CODE_BUFFER] = {
358                 .length = CODE_BUFFER_SIZE,
359         },
360 };
361
362 static void lightrec_enable_ram(struct lightrec_state *state, bool enable)
363 {
364         if (enable)
365                 memcpy(psxM, cache_buf, sizeof(cache_buf));
366         else
367                 memcpy(cache_buf, psxM, sizeof(cache_buf));
368
369         ram_disabled = !enable;
370 }
371
372 static bool lightrec_can_hw_direct(u32 kaddr, bool is_write, u8 size)
373 {
374         if (is_write && size != 32) {
375                 // force32 so must go through handlers
376                 if (0x1f801000 <= kaddr && kaddr < 0x1f801024)
377                         return false;
378                 if ((kaddr & 0x1fffff80) == 0x1f801080) // dma
379                         return false;
380         }
381
382         switch (size) {
383         case 8:
384                 switch (kaddr) {
385                 case 0x1f801040:
386                 case 0x1f801050:
387                 case 0x1f801800:
388                 case 0x1f801801:
389                 case 0x1f801802:
390                 case 0x1f801803:
391                         return false;
392                 default:
393                         return true;
394                 }
395         case 16:
396                 switch (kaddr) {
397                 case 0x1f801040:
398                 case 0x1f801044:
399                 case 0x1f801048:
400                 case 0x1f80104a:
401                 case 0x1f80104e:
402                 case 0x1f801050:
403                 case 0x1f801054:
404                 case 0x1f80105a:
405                 case 0x1f80105e:
406                 case 0x1f801100:
407                 case 0x1f801104:
408                 case 0x1f801108:
409                 case 0x1f801110:
410                 case 0x1f801114:
411                 case 0x1f801118:
412                 case 0x1f801120:
413                 case 0x1f801124:
414                 case 0x1f801128:
415                         return false;
416                 case 0x1f801070:
417                 case 0x1f801074:
418                         return !is_write;
419                 default:
420                         return kaddr < 0x1f801c00 || kaddr >= 0x1f801e00;
421                 }
422         default:
423                 switch (kaddr) {
424                 case 0x1f801040:
425                 case 0x1f801050:
426                 case 0x1f801100:
427                 case 0x1f801104:
428                 case 0x1f801108:
429                 case 0x1f801110:
430                 case 0x1f801114:
431                 case 0x1f801118:
432                 case 0x1f801120:
433                 case 0x1f801124:
434                 case 0x1f801128:
435                 case 0x1f801810:
436                 case 0x1f801814:
437                 case 0x1f801820:
438                 case 0x1f801824:
439                         return false;
440                 case 0x1f801070:
441                 case 0x1f801074:
442                 case 0x1f801088:
443                 case 0x1f801098:
444                 case 0x1f8010a8:
445                 case 0x1f8010b8:
446                 case 0x1f8010c8:
447                 case 0x1f8010e8:
448                 case 0x1f8010f4:
449                         return !is_write;
450                 default:
451                         return !is_write || kaddr < 0x1f801c00 || kaddr >= 0x1f801e00;
452                 }
453         }
454 }
455
456 static const struct lightrec_ops lightrec_ops = {
457         .cop2_op = cop2_op,
458         .enable_ram = lightrec_enable_ram,
459         .hw_direct = lightrec_can_hw_direct,
460         .code_inv = LIGHTREC_CODE_INV ? lightrec_code_inv : NULL,
461 };
462
463 static int lightrec_plugin_init(void)
464 {
465         lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
466         lightrec_map[PSX_MAP_BIOS].address = psxR;
467         lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
468         lightrec_map[PSX_MAP_HW_REGISTERS].address = psxH + 0x1000;
469         lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
470
471         if (!LIGHTREC_CUSTOM_MAP) {
472 #if P_HAVE_MMAP
473                 code_buffer = mmap(0, CODE_BUFFER_SIZE,
474                                    PROT_EXEC | PROT_READ | PROT_WRITE,
475                                    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
476                 if (code_buffer == MAP_FAILED)
477                         return -ENOMEM;
478 #else
479                 code_buffer = malloc(CODE_BUFFER_SIZE);
480                 if (!code_buffer)
481                         return -ENOMEM;
482 #endif
483         }
484
485         if (LIGHTREC_CUSTOM_MAP) {
486                 lightrec_map[PSX_MAP_MIRROR1].address = psxM + 0x200000;
487                 lightrec_map[PSX_MAP_MIRROR2].address = psxM + 0x400000;
488                 lightrec_map[PSX_MAP_MIRROR3].address = psxM + 0x600000;
489         }
490
491         lightrec_map[PSX_MAP_CODE_BUFFER].address = code_buffer;
492
493         use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
494
495 #ifdef LIGHTREC_DEBUG
496         char *cycles = getenv("LIGHTREC_BEGIN_CYCLES");
497
498         lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
499         lightrec_debug = lightrec_very_debug || !!getenv("LIGHTREC_DEBUG");
500
501         if (cycles)
502                 lightrec_begin_cycles = (unsigned int) strtol(cycles, NULL, 0);
503 #endif
504
505         lightrec_state = lightrec_init(LIGHTREC_PROG_NAME,
506                         lightrec_map, ARRAY_SIZE(lightrec_map),
507                         &lightrec_ops);
508
509         // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
510         //              (uintptr_t) psxM,
511         //              (uintptr_t) psxP,
512         //              (uintptr_t) psxR,
513         //              (uintptr_t) psxH);
514
515 #ifndef _WIN32
516         signal(SIGPIPE, exit);
517 #endif
518         lightrec_plugin_apply_config();
519         return 0;
520 }
521
522 static u32 do_calculate_hash(const void *buffer, u32 count, u32 needle, bool le)
523 {
524         unsigned int i;
525         const u32 *data = (const u32 *) buffer;
526         u32 hash = needle;
527
528         count /= 4;
529         for(i = 0; i < count; ++i) {
530                 hash += le ? LE32TOH(data[i]) : data[i];
531                 hash += (hash << 10);
532                 hash ^= (hash >> 6);
533         }
534
535         hash += (hash << 3);
536         hash ^= (hash >> 11);
537         hash += (hash << 15);
538
539         return hash;
540 }
541
542 static u32 hash_calculate_le(const void *buffer, u32 count)
543 {
544         return do_calculate_hash(buffer, count, 0xffffffff, true);
545 }
546
547 u32 hash_calculate(const void *buffer, u32 count)
548 {
549         return do_calculate_hash(buffer, count, 0xffffffff, false);
550 }
551
552 static u32 hash_calculate_ram(const void *buffer, u32 ram_size)
553 {
554         u32 hash;
555
556         if (ram_disabled)
557                 hash = hash_calculate_le(cache_buf, sizeof(cache_buf));
558         else
559                 hash = hash_calculate_le(buffer, sizeof(cache_buf));
560
561         return do_calculate_hash(buffer + sizeof(cache_buf),
562                                  ram_size - sizeof(cache_buf),
563                                  hash, true);
564 }
565
566 static const char * const mips_regs[] = {
567         "zero",
568         "at",
569         "v0", "v1",
570         "a0", "a1", "a2", "a3",
571         "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
572         "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
573         "t8", "t9",
574         "k0", "k1",
575         "gp", "sp", "fp", "ra",
576         "lo", "hi",
577 };
578
579 static void print_for_big_ass_debugger(void)
580 {
581         struct lightrec_registers *regs;
582         unsigned int i;
583
584         regs = lightrec_get_registers(lightrec_state);
585
586         printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
587
588         if (lightrec_very_debug)
589                 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
590                                 hash_calculate_ram(psxM, 0x200000),
591                                 hash_calculate_le(psxH, 0x400),
592                                 hash_calculate_le(psxH + 0x1000, 0x2000));
593
594         printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
595                         hash_calculate(regs->cp0, sizeof(regs->cp0)),
596                         hash_calculate(regs->cp2d, sizeof(regs->cp2d)),
597                         hash_calculate(regs->cp2c, sizeof(regs->cp2c)),
598                         psxRegs.interrupt,
599                         hash_calculate(psxRegs.intCycle, sizeof(psxRegs.intCycle)),
600                         LE32TOH(HW_GPU_STATUS));
601
602         if (lightrec_very_debug) {
603                 for (i = 0; i < 32; i++)
604                         printf(" CP2D%u 0x%08x", i, regs->cp2d[i]);
605                 for (i = 0; i < 32; i++)
606                         printf(" CP2C%u 0x%08x", i, regs->cp2c[i]);
607         }
608
609         if (lightrec_very_debug)
610                 for (i = 0; i < 34; i++)
611                         printf(" %s 0x%08x", mips_regs[i], regs->gpr[i]);
612         else
613                 printf(" GPR 0x%08x",
614                        hash_calculate(regs->gpr, sizeof(regs->gpr)));
615         printf("\n");
616
617         fflush(stdout);
618 }
619
620 static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2);
621 static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2);
622
623 static void lightrec_plugin_execute_internal(bool block_only)
624 {
625         struct lightrec_registers *regs;
626         u32 flags, cycles_pcsx;
627         u32 old_pc = psxRegs.pc;
628
629         regs = lightrec_get_registers(lightrec_state);
630         gen_interupt((psxCP0Regs *)regs->cp0);
631         if (!block_only && psxRegs.stop)
632                 return;
633
634         cycles_pcsx = psxRegs.next_interupt - psxRegs.cycle;
635         assert((s32)cycles_pcsx > 0);
636
637         // step during early boot so that 0x80030000 fastboot hack works
638         block_stepping = block_only;
639         if (block_only)
640                 cycles_pcsx = 0;
641
642         if (use_pcsx_interpreter) {
643                 psxInt.ExecuteBlock(&psxRegs, 0);
644         } else {
645                 u32 cycles_lightrec = cycles_pcsx * 1024;
646                 if (unlikely(use_lightrec_interpreter)) {
647                         psxRegs.pc = lightrec_run_interpreter(lightrec_state,
648                                                               psxRegs.pc,
649                                                               cycles_lightrec);
650                 } else {
651                         psxRegs.pc = lightrec_execute(lightrec_state,
652                                                       psxRegs.pc, cycles_lightrec);
653                 }
654
655                 lightrec_tansition_to_pcsx(lightrec_state);
656
657                 flags = lightrec_exit_flags(lightrec_state);
658
659                 if (flags & LIGHTREC_EXIT_SEGFAULT) {
660                         fprintf(stderr, "Exiting at cycle 0x%08x\n",
661                                 psxRegs.cycle);
662                         if (lightrec_debug)
663                                 print_for_big_ass_debugger();
664                         exit(1);
665                 }
666
667                 if (flags & LIGHTREC_EXIT_SYSCALL)
668                         psxException(R3000E_Syscall << 2, 0, (psxCP0Regs *)regs->cp0);
669                 if (flags & LIGHTREC_EXIT_BREAK)
670                         psxException(R3000E_Bp << 2, 0, (psxCP0Regs *)regs->cp0);
671                 else if (flags & LIGHTREC_EXIT_UNKNOWN_OP) {
672                         u32 op = intFakeFetch(psxRegs.pc);
673                         u32 hlec = op & 0x03ffffff;
674                         if ((op >> 26) == 0x3b && hlec < ARRAY_SIZE(psxHLEt) && Config.HLE) {
675                                 lightrec_plugin_sync_regs_to_pcsx(0);
676                                 psxHLEt[hlec]();
677                                 lightrec_plugin_sync_regs_from_pcsx(0);
678                         }
679                         else
680                                 psxException(R3000E_RI << 2, 0, (psxCP0Regs *)regs->cp0);
681                 }
682         }
683
684         if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles && psxRegs.pc != old_pc) {
685                 print_for_big_ass_debugger();
686         }
687
688         if ((regs->cp0[13] & regs->cp0[12] & 0x300) && (regs->cp0[12] & 0x1)) {
689                 /* Handle software interrupts */
690                 regs->cp0[13] &= ~0x7c;
691                 psxException(regs->cp0[13], 0, (psxCP0Regs *)regs->cp0);
692         }
693 }
694
695 static void lightrec_plugin_execute(psxRegisters *regs)
696 {
697         while (!regs->stop)
698                 lightrec_plugin_execute_internal(lightrec_very_debug);
699 }
700
701 static void lightrec_plugin_execute_block(psxRegisters *regs,
702         enum blockExecCaller caller)
703 {
704         lightrec_plugin_execute_internal(true);
705 }
706
707 static void lightrec_plugin_clear(u32 addr, u32 size)
708 {
709         if ((addr == 0 && size == UINT32_MAX)
710             || (lightrec_hacks & LIGHTREC_OPT_INV_DMA_ONLY))
711                 lightrec_invalidate_all(lightrec_state);
712         else
713                 /* size * 4: PCSX uses DMA units */
714                 lightrec_invalidate(lightrec_state, addr, size * 4);
715 }
716
717 static void lightrec_plugin_notify(enum R3000Anote note, void *data)
718 {
719         switch (note)
720         {
721         case R3000ACPU_NOTIFY_CACHE_ISOLATED:
722         case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
723                 /* not used, lightrec calls lightrec_enable_ram() instead */
724                 break;
725         case R3000ACPU_NOTIFY_BEFORE_SAVE:
726                 /* non-null 'data' means this is HLE related sync */
727                 lightrec_plugin_sync_regs_to_pcsx(data == NULL);
728                 break;
729         case R3000ACPU_NOTIFY_AFTER_LOAD:
730                 lightrec_plugin_sync_regs_from_pcsx(data == NULL);
731                 if (data == NULL)
732                         lightrec_invalidate_all(lightrec_state);
733                 break;
734         }
735 }
736
737 static void lightrec_plugin_apply_config()
738 {
739         static u32 cycles_per_op_old;
740         u32 cycle_mult = Config.cycle_multiplier_override && Config.cycle_multiplier == CYCLE_MULT_DEFAULT
741                 ? Config.cycle_multiplier_override : Config.cycle_multiplier;
742         u32 cycles_per_op = cycle_mult * 1024 / 100;
743         assert(cycles_per_op);
744
745         if (cycles_per_op_old && cycles_per_op_old != cycles_per_op) {
746                 SysPrintf("lightrec: reinit block cache for cycles_per_op %.2f\n",
747                         cycles_per_op / 1024.f);
748         }
749         cycles_per_op_old = cycles_per_op;
750         lightrec_set_cycles_per_opcode(lightrec_state, cycles_per_op);
751
752         lightrec_set_unsafe_opt_flags(lightrec_state, lightrec_hacks);
753         intApplyConfig();
754 }
755
756 static void lightrec_plugin_shutdown(void)
757 {
758         lightrec_destroy(lightrec_state);
759
760         if (!LIGHTREC_CUSTOM_MAP) {
761 #if P_HAVE_MMAP
762                 munmap(code_buffer, CODE_BUFFER_SIZE);
763 #else
764                 free(code_buffer);
765 #endif
766         }
767 }
768
769 static void lightrec_plugin_reset(void)
770 {
771         struct lightrec_registers *regs;
772
773         regs = lightrec_get_registers(lightrec_state);
774
775         /* Invalidate all blocks */
776         lightrec_invalidate_all(lightrec_state);
777
778         /* Reset registers */
779         memset(regs, 0, sizeof(*regs));
780
781         regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
782         regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
783 }
784
785 static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2)
786 {
787         struct lightrec_registers *regs;
788
789         regs = lightrec_get_registers(lightrec_state);
790         memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
791         memcpy(regs->cp0, &psxRegs.CP0, sizeof(regs->cp0));
792         if (need_cp2)
793                 memcpy(regs->cp2d, &psxRegs.CP2, sizeof(regs->cp2d) + sizeof(regs->cp2c));
794 }
795
796 static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2)
797 {
798         struct lightrec_registers *regs;
799
800         regs = lightrec_get_registers(lightrec_state);
801         memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
802         memcpy(&psxRegs.CP0, regs->cp0, sizeof(regs->cp0));
803         if (need_cp2)
804                 memcpy(&psxRegs.CP2, regs->cp2d, sizeof(regs->cp2d) + sizeof(regs->cp2c));
805 }
806
807 R3000Acpu psxRec =
808 {
809         lightrec_plugin_init,
810         lightrec_plugin_reset,
811         lightrec_plugin_execute,
812         lightrec_plugin_execute_block,
813         lightrec_plugin_clear,
814         lightrec_plugin_notify,
815         lightrec_plugin_apply_config,
816         lightrec_plugin_shutdown,
817 };