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