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