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