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