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