drc: prevent people from using lightrec on arm
[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#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
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
44psxRegisters psxRegs;
45Rcnt rcnts[4];
46
47static struct lightrec_state *lightrec_state;
48
49static char *name = "retroarch.exe";
50
51static bool use_lightrec_interpreter;
52static bool use_pcsx_interpreter;
53static bool lightrec_debug;
54static bool lightrec_very_debug;
55static bool booting;
56static u32 lightrec_begin_cycles;
57
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
111static void cop2_op(struct lightrec_state *state, u32 func)
112{
113 struct lightrec_registers *regs = lightrec_get_registers(state);
114
115 psxRegs.code = func;
116
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 }
124}
125
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
133static void lightrec_restore_state(struct lightrec_state *state)
134{
135 lightrec_reset_cycle_count(state, psxRegs.cycle);
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);
141}
142
143static void hw_write_byte(struct lightrec_state *state,
144 u32 op, void *host, u32 mem, u8 val)
145{
146 psxRegs.cycle = lightrec_current_cycle_count(state);
147
148 psxHwWrite8(mem, val);
149
150 lightrec_restore_state(state);
151}
152
153static void hw_write_half(struct lightrec_state *state,
154 u32 op, void *host, u32 mem, u16 val)
155{
156 psxRegs.cycle = lightrec_current_cycle_count(state);
157
158 psxHwWrite16(mem, val);
159
160 lightrec_restore_state(state);
161}
162
163static void hw_write_word(struct lightrec_state *state,
164 u32 op, void *host, u32 mem, u32 val)
165{
166 psxRegs.cycle = lightrec_current_cycle_count(state);
167
168 psxHwWrite32(mem, val);
169
170 lightrec_restore_state(state);
171}
172
173static u8 hw_read_byte(struct lightrec_state *state, u32 op, void *host, u32 mem)
174{
175 u8 val;
176
177 psxRegs.cycle = lightrec_current_cycle_count(state);
178
179 val = psxHwRead8(mem);
180
181 lightrec_restore_state(state);
182
183 return val;
184}
185
186static u16 hw_read_half(struct lightrec_state *state,
187 u32 op, void *host, u32 mem)
188{
189 u16 val;
190
191 psxRegs.cycle = lightrec_current_cycle_count(state);
192
193 val = psxHwRead16(mem);
194
195 lightrec_restore_state(state);
196
197 return val;
198}
199
200static u32 hw_read_word(struct lightrec_state *state,
201 u32 op, void *host, u32 mem)
202{
203 u32 val;
204
205 psxRegs.cycle = lightrec_current_cycle_count(state);
206
207 val = psxHwRead32(mem);
208
209 lightrec_restore_state(state);
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
225static void cache_ctrl_write_word(struct lightrec_state *state,
226 u32 op, void *host, u32 mem, u32 val)
227{
228 cache_ctrl = val;
229}
230
231static u32 cache_ctrl_read_word(struct lightrec_state *state,
232 u32 op, void *host, u32 mem)
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
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
302static const struct lightrec_ops lightrec_ops = {
303 .cop2_op = cop2_op,
304 .enable_ram = lightrec_enable_ram,
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
314 lightrec_debug = !!getenv("LIGHTREC_DEBUG");
315 lightrec_very_debug = !!getenv("LIGHTREC_VERY_DEBUG");
316 use_lightrec_interpreter = !!getenv("LIGHTREC_INTERPRETER");
317 if (getenv("LIGHTREC_BEGIN_CYCLES"))
318 lightrec_begin_cycles = (unsigned int) strtol(
319 getenv("LIGHTREC_BEGIN_CYCLES"), NULL, 0);
320
321 lightrec_state = lightrec_init(name,
322 lightrec_map, ARRAY_SIZE(lightrec_map),
323 &lightrec_ops);
324
325 // fprintf(stderr, "M=0x%lx, P=0x%lx, R=0x%lx, H=0x%lx\n",
326 // (uintptr_t) psxM,
327 // (uintptr_t) psxP,
328 // (uintptr_t) psxR,
329 // (uintptr_t) psxH);
330
331#ifndef _WIN32
332 signal(SIGPIPE, exit);
333#endif
334 return 0;
335}
336
337static u32 hash_calculate_le(const void *buffer, u32 count)
338{
339 unsigned int i;
340 u32 *data = (u32 *) buffer;
341 u32 hash = 0xffffffff;
342
343 count /= 4;
344 for(i = 0; i < count; ++i) {
345 hash += LE32TOH(data[i]);
346 hash += (hash << 10);
347 hash ^= (hash >> 6);
348 }
349
350 hash += (hash << 3);
351 hash ^= (hash >> 11);
352 hash += (hash << 15);
353 return hash;
354}
355
356static u32 hash_calculate(const void *buffer, u32 count)
357{
358 unsigned int i;
359 u32 *data = (u32 *) buffer;
360 u32 hash = 0xffffffff;
361
362 count /= 4;
363 for(i = 0; i < count; ++i) {
364 hash += data[i];
365 hash += (hash << 10);
366 hash ^= (hash >> 6);
367 }
368
369 hash += (hash << 3);
370 hash ^= (hash >> 11);
371 hash += (hash << 15);
372 return hash;
373}
374
375static const char * const mips_regs[] = {
376 "zero",
377 "at",
378 "v0", "v1",
379 "a0", "a1", "a2", "a3",
380 "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7",
381 "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7",
382 "t8", "t9",
383 "k0", "k1",
384 "gp", "sp", "fp", "ra",
385 "lo", "hi",
386};
387
388static void print_for_big_ass_debugger(void)
389{
390 unsigned int i;
391
392 printf("CYCLE 0x%08x PC 0x%08x", psxRegs.cycle, psxRegs.pc);
393
394 if (lightrec_very_debug)
395 printf(" RAM 0x%08x SCRATCH 0x%08x HW 0x%08x",
396 hash_calculate_le(psxM, 0x200000),
397 hash_calculate_le(psxH, 0x400),
398 hash_calculate_le(psxH + 0x1000, 0x2000));
399
400 printf(" CP0 0x%08x CP2D 0x%08x CP2C 0x%08x INT 0x%04x INTCYCLE 0x%08x GPU 0x%08x",
401 hash_calculate(&psxRegs.CP0.r,
402 sizeof(psxRegs.CP0.r)),
403 hash_calculate(&psxRegs.CP2D.r,
404 sizeof(psxRegs.CP2D.r)),
405 hash_calculate(&psxRegs.CP2C.r,
406 sizeof(psxRegs.CP2C.r)),
407 psxRegs.interrupt,
408 hash_calculate(psxRegs.intCycle,
409 sizeof(psxRegs.intCycle)),
410 LE32TOH(HW_GPU_STATUS));
411
412 if (lightrec_very_debug)
413 for (i = 0; i < 34; i++)
414 printf(" %s 0x%08x", mips_regs[i], psxRegs.GPR.r[i]);
415 else
416 printf(" GPR 0x%08x", hash_calculate(&psxRegs.GPR.r,
417 sizeof(psxRegs.GPR.r)));
418 printf("\n");
419}
420
421static void lightrec_dump_regs(struct lightrec_state *state)
422{
423 struct lightrec_registers *regs = lightrec_get_registers(state);
424
425 if (unlikely(booting))
426 memcpy(&psxRegs.GPR, regs->gpr, sizeof(regs->gpr));
427 psxRegs.CP0.n.Status = regs->cp0[12];
428 psxRegs.CP0.n.Cause = regs->cp0[13];
429}
430
431static void lightrec_restore_regs(struct lightrec_state *state)
432{
433 struct lightrec_registers *regs = lightrec_get_registers(state);
434
435 if (unlikely(booting))
436 memcpy(regs->gpr, &psxRegs.GPR, sizeof(regs->gpr));
437 regs->cp0[12] = psxRegs.CP0.n.Status;
438 regs->cp0[13] = psxRegs.CP0.n.Cause;
439 regs->cp0[14] = psxRegs.CP0.n.EPC;
440}
441
442extern void intExecuteBlock();
443extern void gen_interupt();
444
445static void lightrec_plugin_execute_block(void)
446{
447 u32 old_pc = psxRegs.pc;
448 u32 flags;
449
450 gen_interupt();
451
452 if (use_pcsx_interpreter) {
453 intExecuteBlock();
454 } else {
455 lightrec_reset_cycle_count(lightrec_state, psxRegs.cycle);
456 lightrec_restore_regs(lightrec_state);
457
458 if (unlikely(use_lightrec_interpreter))
459 psxRegs.pc = lightrec_run_interpreter(lightrec_state,
460 psxRegs.pc);
461 // step during early boot so that 0x80030000 fastboot hack works
462 else if (unlikely(booting || lightrec_debug))
463 psxRegs.pc = lightrec_execute_one(lightrec_state,
464 psxRegs.pc);
465 else
466 psxRegs.pc = lightrec_execute(lightrec_state,
467 psxRegs.pc, next_interupt);
468
469 psxRegs.cycle = lightrec_current_cycle_count(lightrec_state);
470
471 lightrec_dump_regs(lightrec_state);
472 flags = lightrec_exit_flags(lightrec_state);
473
474 if (flags & LIGHTREC_EXIT_SEGFAULT) {
475 fprintf(stderr, "Exiting at cycle 0x%08x\n",
476 psxRegs.cycle);
477 exit(1);
478 }
479
480 if (flags & LIGHTREC_EXIT_SYSCALL)
481 psxException(0x20, 0);
482
483 if (booting && (psxRegs.pc & 0xff800000) == 0x80000000)
484 booting = false;
485 }
486
487 if (lightrec_debug && psxRegs.cycle >= lightrec_begin_cycles
488 && psxRegs.pc != old_pc)
489 print_for_big_ass_debugger();
490
491 if ((psxRegs.CP0.n.Cause & psxRegs.CP0.n.Status & 0x300) &&
492 (psxRegs.CP0.n.Status & 0x1)) {
493 /* Handle software interrupts */
494 psxRegs.CP0.n.Cause &= ~0x7c;
495 psxException(psxRegs.CP0.n.Cause, 0);
496 }
497}
498
499static void lightrec_plugin_execute(void)
500{
501 extern int stop;
502
503 while (!stop)
504 lightrec_plugin_execute_block();
505}
506
507static void lightrec_plugin_clear(u32 addr, u32 size)
508{
509 if (addr == 0 && size == UINT32_MAX)
510 lightrec_invalidate_all(lightrec_state);
511 else
512 /* size * 4: PCSX uses DMA units */
513 lightrec_invalidate(lightrec_state, addr, size * 4);
514}
515
516static void lightrec_plugin_notify(int note, void *data)
517{
518 /*
519 To change once proper icache emulation is emulated
520 switch (note)
521 {
522 case R3000ACPU_NOTIFY_CACHE_UNISOLATED:
523 lightrec_plugin_clear(0, 0x200000/4);
524 break;
525 case R3000ACPU_NOTIFY_CACHE_ISOLATED:
526 // Sent from psxDma3().
527 case R3000ACPU_NOTIFY_DMA3_EXE_LOAD:
528 default:
529 break;
530 }*/
531}
532
533static void lightrec_plugin_apply_config()
534{
535}
536
537static void lightrec_plugin_shutdown(void)
538{
539 lightrec_destroy(lightrec_state);
540}
541
542static void lightrec_plugin_reset(void)
543{
544 struct lightrec_registers *regs;
545
546 lightrec_plugin_shutdown();
547 lightrec_plugin_init();
548
549 regs = lightrec_get_registers(lightrec_state);
550
551 regs->cp0[12] = 0x10900000; // COP0 enabled | BEV = 1 | TS = 1
552 regs->cp0[15] = 0x00000002; // PRevID = Revision ID, same as R3000A
553
554 booting = true;
555}
556
557R3000Acpu psxRec =
558{
559 lightrec_plugin_init,
560 lightrec_plugin_reset,
561 lightrec_plugin_execute,
562 lightrec_plugin_execute_block,
563 lightrec_plugin_clear,
564 lightrec_plugin_notify,
565 lightrec_plugin_apply_config,
566 lightrec_plugin_shutdown,
567};