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