lightrec: Update to latest Lightrec API
[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
0733c3ab 107static void cop2_op(struct lightrec_state *state, u32 func)
6f1edc3c 108{
0733c3ab 109 struct lightrec_registers *regs = lightrec_get_registers(state);
6f1edc3c 110
0733c3ab 111 psxRegs.code = func;
6f1edc3c 112
0733c3ab
PC
113 if (unlikely(!cp2_ops[func & 0x3f])) {
114 fprintf(stderr, "Invalid CP2 function %u\n", func);
115 } else {
116 /* This works because regs->cp2c comes right after regs->cp2d,
117 * so it can be cast to a pcsxCP2Regs pointer. */
118 cp2_ops[func & 0x3f]((psxCP2Regs *) regs->cp2d);
119 }
6f1edc3c
PC
120}
121
2bf88032
PC
122static bool has_interrupt(void)
123{
124 return ((psxHu32(0x1070) & psxHu32(0x1074)) &&
125 (psxRegs.CP0.n.Status & 0x401) == 0x401) ||
126 (psxRegs.CP0.n.Status & psxRegs.CP0.n.Cause & 0x0300);
127}
128
f4f9f2a4
PC
129static void lightrec_restore_state(struct lightrec_state *state)
130{
131 lightrec_reset_cycle_count(state, psxRegs.cycle);
2bf88032
PC
132
133 if (booting || has_interrupt())
134 lightrec_set_exit_flags(state, LIGHTREC_EXIT_CHECK_INTERRUPT);
135 else
136 lightrec_set_target_cycle_count(state, next_interupt);
f4f9f2a4
PC
137}
138
6b02f240 139static void hw_write_byte(struct lightrec_state *state,
140 u32 op, void *host, u32 mem, u8 val)
6f1edc3c
PC
141{
142 psxRegs.cycle = lightrec_current_cycle_count(state);
143
144 psxHwWrite8(mem, val);
6f1edc3c 145
f4f9f2a4 146 lightrec_restore_state(state);
6f1edc3c
PC
147}
148
6b02f240 149static void hw_write_half(struct lightrec_state *state,
150 u32 op, void *host, u32 mem, u16 val)
6f1edc3c
PC
151{
152 psxRegs.cycle = lightrec_current_cycle_count(state);
153
154 psxHwWrite16(mem, val);
6f1edc3c 155
f4f9f2a4 156 lightrec_restore_state(state);
6f1edc3c
PC
157}
158
6b02f240 159static void hw_write_word(struct lightrec_state *state,
160 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
161{
162 psxRegs.cycle = lightrec_current_cycle_count(state);
163
164 psxHwWrite32(mem, val);
6f1edc3c 165
f4f9f2a4 166 lightrec_restore_state(state);
6f1edc3c
PC
167}
168
6b02f240 169static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
6f1edc3c
PC
170{
171 u8 val;
172
173 psxRegs.cycle = lightrec_current_cycle_count(state);
174
6f1edc3c 175 val = psxHwRead8(mem);
f4f9f2a4
PC
176
177 lightrec_restore_state(state);
6f1edc3c
PC
178
179 return val;
180}
181
6b02f240 182static u16 hw_read_half(struct lightrec_state *state,
183 u32 op, void *host, u32 mem)
6f1edc3c
PC
184{
185 u16 val;
186
187 psxRegs.cycle = lightrec_current_cycle_count(state);
188
6f1edc3c 189 val = psxHwRead16(mem);
f4f9f2a4
PC
190
191 lightrec_restore_state(state);
6f1edc3c
PC
192
193 return val;
194}
195
6b02f240 196static u32 hw_read_word(struct lightrec_state *state,
197 u32 op, void *host, u32 mem)
6f1edc3c
PC
198{
199 u32 val;
200
201 psxRegs.cycle = lightrec_current_cycle_count(state);
202
6f1edc3c 203 val = psxHwRead32(mem);
f4f9f2a4
PC
204
205 lightrec_restore_state(state);
6f1edc3c
PC
206
207 return val;
208}
209
210static struct lightrec_mem_map_ops hw_regs_ops = {
211 .sb = hw_write_byte,
212 .sh = hw_write_half,
213 .sw = hw_write_word,
214 .lb = hw_read_byte,
215 .lh = hw_read_half,
216 .lw = hw_read_word,
217};
218
219static u32 cache_ctrl;
220
6b02f240 221static void cache_ctrl_write_word(struct lightrec_state *state,
222 u32 op, void *host, u32 mem, u32 val)
6f1edc3c
PC
223{
224 cache_ctrl = val;
225}
226
6b02f240 227static u32 cache_ctrl_read_word(struct lightrec_state *state,
228 u32 op, void *host, u32 mem)
6f1edc3c
PC
229{
230 return cache_ctrl;
231}
232
233static struct lightrec_mem_map_ops cache_ctrl_ops = {
234 .sw = cache_ctrl_write_word,
235 .lw = cache_ctrl_read_word,
236};
237
238static struct lightrec_mem_map lightrec_map[] = {
239 [PSX_MAP_KERNEL_USER_RAM] = {
240 /* Kernel and user memory */
241 .pc = 0x00000000,
242 .length = 0x200000,
243 },
244 [PSX_MAP_BIOS] = {
245 /* BIOS */
246 .pc = 0x1fc00000,
247 .length = 0x80000,
248 },
249 [PSX_MAP_SCRATCH_PAD] = {
250 /* Scratch pad */
251 .pc = 0x1f800000,
252 .length = 0x400,
253 },
254 [PSX_MAP_PARALLEL_PORT] = {
255 /* Parallel port */
256 .pc = 0x1f000000,
257 .length = 0x10000,
258 },
259 [PSX_MAP_HW_REGISTERS] = {
260 /* Hardware registers */
261 .pc = 0x1f801000,
262 .length = 0x2000,
263 .ops = &hw_regs_ops,
264 },
265 [PSX_MAP_CACHE_CONTROL] = {
266 /* Cache control */
267 .pc = 0x5ffe0130,
268 .length = 4,
269 .ops = &cache_ctrl_ops,
270 },
271
272 /* Mirrors of the kernel/user memory */
273 [PSX_MAP_MIRROR1] = {
274 .pc = 0x00200000,
275 .length = 0x200000,
276 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
277 },
278 [PSX_MAP_MIRROR2] = {
279 .pc = 0x00400000,
280 .length = 0x200000,
281 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
282 },
283 [PSX_MAP_MIRROR3] = {
284 .pc = 0x00600000,
285 .length = 0x200000,
286 .mirror_of = &lightrec_map[PSX_MAP_KERNEL_USER_RAM],
287 },
288};
289
0733c3ab
PC
290static void lightrec_enable_ram(struct lightrec_state *state, bool enable)
291{
292 if (enable)
293 memcpy(psxM, cache_buf, sizeof(cache_buf));
294 else
295 memcpy(cache_buf, psxM, sizeof(cache_buf));
296}
297
6f1edc3c 298static const struct lightrec_ops lightrec_ops = {
0733c3ab
PC
299 .cop2_op = cop2_op,
300 .enable_ram = lightrec_enable_ram,
6f1edc3c
PC
301};
302
303static int lightrec_plugin_init(void)
304{
305 lightrec_map[PSX_MAP_KERNEL_USER_RAM].address = psxM;
306 lightrec_map[PSX_MAP_BIOS].address = psxR;
307 lightrec_map[PSX_MAP_SCRATCH_PAD].address = psxH;
308 lightrec_map[PSX_MAP_PARALLEL_PORT].address = psxP;
309
310 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
311 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
312 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
313 if (getenv("LIGHTREC_BEGIN_CYCLES"))
314 lightrec_begin_cycles = (unsigned int) strtol(
315 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
316
317 lightrec_state = lightrec_init(name,
318 lightrec_map, ARRAY_SIZE(lightrec_map),
319 &lightrec_ops);
320
9361a5aa
EC
321 // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
322 // (uintptr_t) psxM,
323 // (uintptr_t) psxP,
324 // (uintptr_t) psxR,
325 // (uintptr_t) psxH);
6f1edc3c
PC
326
327#ifndef _WIN32
328 signal(SIGPIPE, exit);
329#endif
330 return 0;
331}
332
333static u32 hash_calculate_le(const void *buffer, u32 count)
334{
335 unsigned int i;
336 u32 *data = (u32 *) buffer;
337 u32 hash = 0xffffffff;
338
339 count /= 4;
340 for(i = 0; i < count; ++i) {
341 hash += LE32TOH(data[i]);
342 hash += (hash << 10);
343 hash ^= (hash >> 6);
344 }
345
346 hash += (hash << 3);
347 hash ^= (hash >> 11);
348 hash += (hash << 15);
349 return hash;
350}
351
352static u32 hash_calculate(const void *buffer, u32 count)
353{
354 unsigned int i;
355 u32 *data = (u32 *) buffer;
356 u32 hash = 0xffffffff;
357
358 count /= 4;
359 for(i = 0; i < count; ++i) {
360 hash += data[i];
361 hash += (hash << 10);
362 hash ^= (hash >> 6);
363 }
364
365 hash += (hash << 3);
366 hash ^= (hash >> 11);
367 hash += (hash << 15);
368 return hash;
369}
370
371static const char * const mips_regs[] = {
372 "zero",
373 "at",
374 "v0", "v1",
375 "a0", "a1", "a2", "a3",
376 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
377 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
378 "t8", "t9",
379 "k0", "k1",
380 "gp", "sp", "fp", "ra",
381 "lo", "hi",
382};
383
384static void print_for_big_ass_debugger(void)
385{
386 unsigned int i;
387
388 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
389
390 if (lightrec_very_debug)
391 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
392 hash_calculate_le(psxM, 0x200000),
393 hash_calculate_le(psxH, 0x400),
394 hash_calculate_le(psxH + 0x1000, 0x2000));
395
396 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
397 hash_calculate(&psxRegs.CP0.r,
398 sizeof(psxRegs.CP0.r)),
399 hash_calculate(&psxRegs.CP2D.r,
400 sizeof(psxRegs.CP2D.r)),
401 hash_calculate(&psxRegs.CP2C.r,
402 sizeof(psxRegs.CP2C.r)),
403 psxRegs.interrupt,
404 hash_calculate(psxRegs.intCycle,
405 sizeof(psxRegs.intCycle)),
406 LE32TOH(HW_GPU_STATUS));
407
408 if (lightrec_very_debug)
409 for (i = 0; i < 34; i++)
410 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
411 else
412 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
413 sizeof(psxRegs.GPR.r)));
414 printf("\n");
415}
416
0733c3ab
PC
417static void lightrec_dump_regs(struct lightrec_state *state)
418{
419 struct lightrec_registers *regs = lightrec_get_registers(state);
420
421 if (unlikely(booting))
422 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
423 psxRegs.CP0.n.Status = regs->cp0[12];
424 psxRegs.CP0.n.Cause = regs->cp0[13];
425}
426
427static void lightrec_restore_regs(struct lightrec_state *state)
428{
429 struct lightrec_registers *regs = lightrec_get_registers(state);
430
431 if (unlikely(booting))
432 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
433 regs->cp0[12] = psxRegs.CP0.n.Status;
434 regs->cp0[13] = psxRegs.CP0.n.Cause;
435 regs->cp0[14] = psxRegs.CP0.n.EPC;
436}
6b02f240 437
438extern void intExecuteBlock();
2bf88032 439extern void gen_interupt();
6b02f240 440
6f1edc3c
PC
441static void lightrec_plugin_execute_block(void)
442{
443 u32 old_pc = psxRegs.pc;
444 u32 flags;
445
2bf88032
PC
446 gen_interupt();
447
6b02f240 448 if (use_pcsx_interpreter) {
449 intExecuteBlock();
450 } else {
451 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
0733c3ab 452 lightrec_restore_regs(lightrec_state);
6f1edc3c 453
2bf88032 454 if (unlikely(use_lightrec_interpreter))
6b02f240 455 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
456 psxRegs.pc);
2bf88032 457 // step during early boot so that 0x80030000 fastboot hack works
0733c3ab 458 else if (unlikely(booting || lightrec_debug))
6b02f240 459 psxRegs.pc = lightrec_execute_one(lightrec_state,
460 psxRegs.pc);
2bf88032
PC
461 else
462 psxRegs.pc = lightrec_execute(lightrec_state,
463 psxRegs.pc, next_interupt);
6f1edc3c 464
6b02f240 465 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
6f1edc3c 466
0733c3ab 467 lightrec_dump_regs(lightrec_state);
6b02f240 468 flags = lightrec_exit_flags(lightrec_state);
6f1edc3c 469
6b02f240 470 if (flags & LIGHTREC_EXIT_SEGFAULT) {
471 fprintf(stderr, "Exiting at cycle 0x%08x\n",
472 psxRegs.cycle);
473 exit(1);
474 }
6f1edc3c 475
6b02f240 476 if (flags & LIGHTREC_EXIT_SYSCALL)
477 psxException(0x20, 0);
6f1edc3c 478
2bf88032
PC
479 if (booting && (psxRegs.pc & 0xff800000) == 0x80000000)
480 booting = false;
481 }
6f1edc3c
PC
482
483 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
484 && psxRegs.pc != old_pc)
485 print_for_big_ass_debugger();
486
487 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
488 (psxRegs.CP0.n.Status & 0x1)) {
489 /* Handle software interrupts */
490 psxRegs.CP0.n.Cause &= ~0x7c;
491 psxException(psxRegs.CP0.n.Cause, 0);
492 }
6f1edc3c
PC
493}
494
495static void lightrec_plugin_execute(void)
496{
497 extern int stop;
498
499 while (!stop)
500 lightrec_plugin_execute_block();
501}
502
503static void lightrec_plugin_clear(u32 addr, u32 size)
504{
8c9468f1
ZC
505 if (addr == 0 && size == UINT32_MAX)
506 lightrec_invalidate_all(lightrec_state);
507 else
508 /* size * 4: PCSX uses DMA units */
509 lightrec_invalidate(lightrec_state, addr, size * 4);
6f1edc3c
PC
510}
511
7a811716 512static void lightrec_plugin_notify(int note, void *data)
513{
514 /*
515 To change once proper icache emulation is emulated
516 switch (note)
517 {
518 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
519 lightrec_plugin_clear(0, 0x200000/4);
520 break;
521 case R3000ACPU_NOTIFY_CACHE_ISOLATED:
522 // Sent from psxDma3().
523 case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
524 default:
525 break;
526 }*/
527}
630b122b 528
529static void lightrec_plugin_apply_config()
530{
531}
7a811716 532
6f1edc3c
PC
533static void lightrec_plugin_shutdown(void)
534{
535 lightrec_destroy(lightrec_state);
536}
537
538static void lightrec_plugin_reset(void)
539{
0733c3ab
PC
540 struct lightrec_registers *regs;
541
37e4b2cc 542 lightrec_plugin_shutdown();
543 lightrec_plugin_init();
0733c3ab
PC
544
545 regs = lightrec_get_registers(lightrec_state);
546
547 regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
548 regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
549
2bf88032 550 booting = true;
6f1edc3c
PC
551}
552
553R3000Acpu psxRec =
554{
555 lightrec_plugin_init,
556 lightrec_plugin_reset,
557 lightrec_plugin_execute,
558 lightrec_plugin_execute_block,
559 lightrec_plugin_clear,
7a811716 560 lightrec_plugin_notify,
630b122b 561 lightrec_plugin_apply_config,
6f1edc3c
PC
562 lightrec_plugin_shutdown,
563};