drc: add a clock override for Super Robot Taisen Alpha
[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;
2bf88032 51static bool booting;
6f1edc3c
PC
52static u32 lightrec_begin_cycles;
53
6f1edc3c
PC
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
6b02f240 107static u32 cop0_mfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
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
6b02f240 120static u32 cop2_mfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
121{
122 return cop2_mfc_cfc(state, reg, false);
123}
124
6b02f240 125static u32 cop2_cfc(struct lightrec_state *state, u32 op, u8 reg)
6f1edc3c
PC
126{
127 return cop2_mfc_cfc(state, reg, true);
128}
129
2bf88032
PC
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
f4f9f2a4
PC
137static void lightrec_restore_state(struct lightrec_state *state)
138{
139 lightrec_reset_cycle_count(state, psxRegs.cycle);
2bf88032
PC
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);
f4f9f2a4
PC
145}
146
6f1edc3c
PC
147static void cop0_mtc_ctc(struct lightrec_state *state,
148 u8 reg, u32 value, bool ctc)
149{
2bf88032
PC
150 psxRegs.cycle = lightrec_current_cycle_count(state);
151
6f1edc3c
PC
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;
6f1edc3c
PC
169 break;
170 case 13: /* Cause */
171 psxRegs.CP0.n.Cause &= ~0x0300;
172 psxRegs.CP0.n.Cause |= value & 0x0300;
6f1edc3c
PC
173 break;
174 default:
175 psxRegs.CP0.r[reg] = value;
176 break;
177 }
f4f9f2a4
PC
178
179 lightrec_restore_state(state);
6f1edc3c
PC
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
6b02f240 191static void cop0_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
192{
193 cop0_mtc_ctc(state, reg, value, false);
194}
195
6b02f240 196static void cop0_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
197{
198 cop0_mtc_ctc(state, reg, value, true);
199}
200
6b02f240 201static void cop2_mtc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
202{
203 cop2_mtc_ctc(state, reg, value, false);
204}
205
6b02f240 206static void cop2_ctc(struct lightrec_state *state, u32 op, u8 reg, u32 value)
6f1edc3c
PC
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
6b02f240 226static void hw_write_byte(struct lightrec_state *state,
227 u32 op, void *host, u32 mem, u8 val)
6f1edc3c
PC
228{
229 psxRegs.cycle = lightrec_current_cycle_count(state);
230
231 psxHwWrite8(mem, val);
6f1edc3c 232
f4f9f2a4 233 lightrec_restore_state(state);
6f1edc3c
PC
234}
235
6b02f240 236static void hw_write_half(struct lightrec_state *state,
237 u32 op, void *host, u32 mem, u16 val)
6f1edc3c
PC
238{
239 psxRegs.cycle = lightrec_current_cycle_count(state);
240
241 psxHwWrite16(mem, val);
6f1edc3c 242
f4f9f2a4 243 lightrec_restore_state(state);
6f1edc3c
PC
244}
245
6b02f240 246static void hw_write_word(struct lightrec_state *state,
247 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
248{
249 psxRegs.cycle = lightrec_current_cycle_count(state);
250
251 psxHwWrite32(mem, val);
6f1edc3c 252
f4f9f2a4 253 lightrec_restore_state(state);
6f1edc3c
PC
254}
255
6b02f240 256static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
6f1edc3c
PC
257{
258 u8 val;
259
260 psxRegs.cycle = lightrec_current_cycle_count(state);
261
6f1edc3c 262 val = psxHwRead8(mem);
f4f9f2a4
PC
263
264 lightrec_restore_state(state);
6f1edc3c
PC
265
266 return val;
267}
268
6b02f240 269static u16 hw_read_half(struct lightrec_state *state,
270 u32 op, void *host, u32 mem)
6f1edc3c
PC
271{
272 u16 val;
273
274 psxRegs.cycle = lightrec_current_cycle_count(state);
275
6f1edc3c 276 val = psxHwRead16(mem);
f4f9f2a4
PC
277
278 lightrec_restore_state(state);
6f1edc3c
PC
279
280 return val;
281}
282
6b02f240 283static u32 hw_read_word(struct lightrec_state *state,
284 u32 op, void *host, u32 mem)
6f1edc3c
PC
285{
286 u32 val;
287
288 psxRegs.cycle = lightrec_current_cycle_count(state);
289
6f1edc3c 290 val = psxHwRead32(mem);
f4f9f2a4
PC
291
292 lightrec_restore_state(state);
6f1edc3c
PC
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
6b02f240 308static void cache_ctrl_write_word(struct lightrec_state *state,
309 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
310{
311 cache_ctrl = val;
312}
313
6b02f240 314static u32 cache_ctrl_read_word(struct lightrec_state *state,
315 u32 op, void *host, u32 mem)
6f1edc3c
PC
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
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
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
6b02f240 508
509extern void intExecuteBlock();
2bf88032 510extern void gen_interupt();
6b02f240 511
6f1edc3c
PC
512static u32 old_cycle_counter;
513
514static void lightrec_plugin_execute_block(void)
515{
516 u32 old_pc = psxRegs.pc;
517 u32 flags;
518
2bf88032
PC
519 gen_interupt();
520
6b02f240 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);
6f1edc3c 526
2bf88032 527 if (unlikely(use_lightrec_interpreter))
6b02f240 528 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
529 psxRegs.pc);
2bf88032
PC
530 // step during early boot so that 0x80030000 fastboot hack works
531 else if (unlikely(booting))
6b02f240 532 psxRegs.pc = lightrec_execute_one(lightrec_state,
533 psxRegs.pc);
2bf88032
PC
534 else
535 psxRegs.pc = lightrec_execute(lightrec_state,
536 psxRegs.pc, next_interupt);
6f1edc3c 537
6b02f240 538 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
6f1edc3c 539
6b02f240 540 lightrec_dump_registers(lightrec_state, psxRegs.GPR.r);
541 flags = lightrec_exit_flags(lightrec_state);
6f1edc3c 542
6b02f240 543 if (flags & LIGHTREC_EXIT_SEGFAULT) {
544 fprintf(stderr, "Exiting at cycle 0x%08x\n",
545 psxRegs.cycle);
546 exit(1);
547 }
6f1edc3c 548
6b02f240 549 if (flags & LIGHTREC_EXIT_SYSCALL)
550 psxException(0x20, 0);
6f1edc3c 551
2bf88032
PC
552 if (booting && (psxRegs.pc & 0xff800000) == 0x80000000)
553 booting = false;
554 }
6f1edc3c
PC
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) {
6205159e 568 SysDLog("RAM usage: Lightrec %u KiB, IR %u KiB, CODE %u KiB, "
6f1edc3c 569 "MIPS %u KiB, TOTAL %u KiB, avg. IPI %f\n",
6b02f240 570 lightrec_get_mem_usage(MEM_FOR_LIGHTREC) / 1024,
6f1edc3c
PC
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{
8c9468f1
ZC
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);
6f1edc3c
PC
595}
596
7a811716 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}
630b122b 613
614static void lightrec_plugin_apply_config()
615{
616}
7a811716 617
6f1edc3c
PC
618static void lightrec_plugin_shutdown(void)
619{
620 lightrec_destroy(lightrec_state);
621}
622
623static void lightrec_plugin_reset(void)
624{
37e4b2cc 625 lightrec_plugin_shutdown();
626 lightrec_plugin_init();
2bf88032 627 booting = true;
6f1edc3c
PC
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,
7a811716 637 lightrec_plugin_notify,
630b122b 638 lightrec_plugin_apply_config,
6f1edc3c
PC
639 lightrec_plugin_shutdown,
640};