frontend: update libpicofe, fix missed callbacks
[pcsx_rearmed.git] / libpcsxcore / lightrec / plugin.c
CommitLineData
a3c46b7f 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
397f72d9
PC
64#ifndef GPUSTATUS_POLLING_THRESHOLD
65# define GPUSTATUS_POLLING_THRESHOLD 0
66#endif
67
a3c46b7f 68psxRegisters psxRegs;
69Rcnt rcnts[4];
70
71void* code_buffer;
72
73static struct lightrec_state *lightrec_state;
74
75static bool use_lightrec_interpreter;
a3c46b7f 76static bool block_stepping;
c87406ff 77//static bool use_pcsx_interpreter;
78#define use_pcsx_interpreter 0
97fa754e
PC
79static bool ram_disabled;
80static bool lightrec_debug, lightrec_very_debug;
81static u32 lightrec_begin_cycles;
a3c46b7f 82
83extern u32 lightrec_hacks;
84
c6809aec 85static void lightrec_plugin_apply_config();
a3c46b7f 86extern void lightrec_code_inv(void *ptr, uint32_t len);
87
88enum 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
113static void (*cp2_ops[])(struct psxCP2Regs *) = {
a3c46b7f 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
138static char cache_buf[64 * 1024];
139
140static 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
155static 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
164static 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
170static void lightrec_tansition_from_pcsx(struct lightrec_state *state)
171{
c87406ff 172 s32 cycles_left = psxRegs.next_interupt - psxRegs.cycle;
a3c46b7f 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
181static 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
191static 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
201static 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
211static 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
224static 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
238static u32 hw_read_word(struct lightrec_state *state,
239 u32 op, void *host, u32 mem)
240{
397f72d9
PC
241 static u32 old_cycle, oldold_cycle, old_gpusr;
242 u32 val, diff;
a3c46b7f 243
244 lightrec_tansition_to_pcsx(state);
245
246 val = psxHwRead32(mem);
247
397f72d9
PC
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
a3c46b7f 265 lightrec_tansition_from_pcsx(state);
266
267 return val;
268}
269
270static 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
279static u32 cache_ctrl;
280
281static 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
287static u32 cache_ctrl_read_word(struct lightrec_state *state,
288 u32 op, void *host, u32 mem)
289{
290 return cache_ctrl;
291}
292
293static struct lightrec_mem_map_ops cache_ctrl_ops = {
294 .sw = cache_ctrl_write_word,
295 .lw = cache_ctrl_read_word,
296};
297
298static 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
362static 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));
97fa754e
PC
368
369 ram_disabled = !enable;
a3c46b7f 370}
371
372static 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
456static 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
463static 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
97fa754e
PC
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
a3c46b7f 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
c6809aec 518 lightrec_plugin_apply_config();
a3c46b7f 519 return 0;
520}
521
97fa754e
PC
522static 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
542static u32 hash_calculate_le(const void *buffer, u32 count)
543{
544 return do_calculate_hash(buffer, count, 0xffffffff, true);
545}
546
547u32 hash_calculate(const void *buffer, u32 count)
548{
549 return do_calculate_hash(buffer, count, 0xffffffff, false);
550}
551
552static 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
566static 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
579static 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
a3c46b7f 620static void lightrec_plugin_sync_regs_to_pcsx(bool need_cp2);
621static void lightrec_plugin_sync_regs_from_pcsx(bool need_cp2);
622
623static void lightrec_plugin_execute_internal(bool block_only)
624{
625 struct lightrec_registers *regs;
626 u32 flags, cycles_pcsx;
97fa754e 627 u32 old_pc = psxRegs.pc;
a3c46b7f 628
629 regs = lightrec_get_registers(lightrec_state);
630 gen_interupt((psxCP0Regs *)regs->cp0);
c87406ff 631 if (!block_only && psxRegs.stop)
a3c46b7f 632 return;
633
c87406ff 634 cycles_pcsx = psxRegs.next_interupt - psxRegs.cycle;
a3c46b7f 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) {
c87406ff 643 psxInt.ExecuteBlock(&psxRegs, 0);
a3c46b7f 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);
97fa754e
PC
662 if (lightrec_debug)
663 print_for_big_ass_debugger();
a3c46b7f 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
97fa754e
PC
684 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles && psxRegs.pc != old_pc) {
685 print_for_big_ass_debugger();
686 }
687
a3c46b7f 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
c87406ff 695static void lightrec_plugin_execute(psxRegisters *regs)
a3c46b7f 696{
c87406ff 697 while (!regs->stop)
97fa754e 698 lightrec_plugin_execute_internal(lightrec_very_debug);
a3c46b7f 699}
700
c87406ff 701static void lightrec_plugin_execute_block(psxRegisters *regs,
702 enum blockExecCaller caller)
a3c46b7f 703{
704 lightrec_plugin_execute_internal(true);
705}
706
707static 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
717static 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
737static 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);
c87406ff 751
c6809aec 752 lightrec_set_unsafe_opt_flags(lightrec_state, lightrec_hacks);
c87406ff 753 intApplyConfig();
a3c46b7f 754}
755
756static 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
769static 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
a3c46b7f 783}
784
785static 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
796static 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
807R3000Acpu 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};