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