dfxvideo: remove unneeded double division in line code
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
CommitLineData
7e605697 1/*
009faf24 2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
7e605697 3 *
4 * This work is licensed under the terms of GNU GPL version 2 or later.
5 * See the COPYING file in the top-level directory.
6 */
7
f95a77f7 8#include <stdio.h>
9
10#include "emu_if.h"
7e605697 11#include "pcsxmem.h"
7139f3c8 12#include "../psxhle.h"
d28b54b1 13#include "../r3000a.h"
52082bc1 14#include "../cdrom.h"
15#include "../psxdma.h"
16#include "../mdec.h"
59774ed0 17#include "../gte_arm.h"
009faf24 18#include "../gte_neon.h"
59774ed0 19#define FLAGLESS
20#include "../gte.h"
7139f3c8 21
ae602c19 22#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
23
7139f3c8 24//#define evprintf printf
25#define evprintf(...)
26
f95a77f7 27char invalid_code[0x100000];
d28b54b1 28u32 event_cycles[PSXINT_COUNT];
f95a77f7 29
654e8cfb 30static void schedule_timeslice(void)
f95a77f7 31{
654e8cfb 32 u32 i, c = psxRegs.cycle;
33 s32 min, dif;
34
35 min = psxNextsCounter + psxNextCounter - c;
36 for (i = 0; i < ARRAY_SIZE(event_cycles); i++) {
37 dif = event_cycles[i] - c;
38 //evprintf(" ev %d\n", dif);
39 if (0 < dif && dif < min)
40 min = dif;
41 }
42 next_interupt = c + min;
43
44#if 0
45 static u32 cnt, last_cycle;
46 static u64 sum;
47 if (last_cycle) {
48 cnt++;
49 sum += psxRegs.cycle - last_cycle;
50 if ((cnt & 0xff) == 0)
51 printf("%u\n", (u32)(sum / cnt));
52 }
53 last_cycle = psxRegs.cycle;
54#endif
55}
ae602c19 56
52082bc1 57typedef void (irq_func)();
58
59static irq_func * const irq_funcs[] = {
60 [PSXINT_SIO] = sioInterrupt,
61 [PSXINT_CDR] = cdrInterrupt,
62 [PSXINT_CDREAD] = cdrReadInterrupt,
63 [PSXINT_GPUDMA] = gpuInterrupt,
64 [PSXINT_MDECOUTDMA] = mdec1Interrupt,
65 [PSXINT_SPUDMA] = spuInterrupt,
528ad661 66 [PSXINT_MDECINDMA] = mdec0Interrupt,
57a757ce 67 [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
9f8b032d 68 [PSXINT_CDRDMA] = cdrDmaInterrupt,
69 [PSXINT_CDRLID] = cdrLidSeekInterrupt,
7f457614 70 [PSXINT_CDRPLAY] = cdrPlayInterrupt,
52082bc1 71};
72
73/* local dupe of psxBranchTest, using event_cycles */
74static void irq_test(void)
75{
76 u32 irqs = psxRegs.interrupt;
77 u32 cycle = psxRegs.cycle;
78 u32 irq, irq_bits;
79
80 if ((psxRegs.cycle - psxNextsCounter) >= psxNextCounter)
81 psxRcntUpdate();
82
83 // irq_funcs() may queue more irqs
84 psxRegs.interrupt = 0;
85
86 for (irq = 0, irq_bits = irqs; irq_bits != 0; irq++, irq_bits >>= 1) {
87 if (!(irq_bits & 1))
88 continue;
89 if ((s32)(cycle - event_cycles[irq]) >= 0) {
90 irqs &= ~(1 << irq);
91 irq_funcs[irq]();
92 }
93 }
94 psxRegs.interrupt |= irqs;
95
96 if ((psxHu32(0x1070) & psxHu32(0x1074)) && (Status & 0x401) == 0x401) {
97 psxException(0x400, 0);
98 pending_exception = 1;
99 }
100}
101
654e8cfb 102void gen_interupt()
103{
654e8cfb 104 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
7139f3c8 105
52082bc1 106 irq_test();
107 //psxBranchTest();
108 //pending_exception = 1;
7139f3c8 109
654e8cfb 110 schedule_timeslice();
ae602c19 111
654e8cfb 112 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
113 next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 114}
115
fca1aef2 116// from interpreter
117extern void MTC0(int reg, u32 val);
118
119void pcsx_mtc0(u32 reg)
28bc5688 120{
fca1aef2 121 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
122 MTC0(reg, readmem_word);
123 gen_interupt();
124}
28bc5688 125
fca1aef2 126void pcsx_mtc0_ds(u32 reg)
127{
128 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
129 MTC0(reg, readmem_word);
28bc5688 130}
131
52082bc1 132void new_dyna_save(void)
133{
134 // psxRegs.intCycle is always maintained, no need to convert
135}
136
137void new_dyna_restore(void)
138{
139 int i;
9f8b032d 140 for (i = 0; i < PSXINT_COUNT; i++)
52082bc1 141 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
142}
143
b9b61529 144void *gte_handlers[64];
145
59774ed0 146void *gte_handlers_nf[64] = {
147 NULL , gteRTPS_nf , NULL , NULL , NULL , NULL , gteNCLIP_nf, NULL , // 00
148 NULL , NULL , NULL , NULL , gteOP_nf , NULL , NULL , NULL , // 08
149 gteDPCS_nf, gteINTPL_nf, gteMVMVA_nf, gteNCDS_nf, gteCDP_nf, NULL , gteNCDT_nf , NULL , // 10
150 NULL , NULL , NULL , gteNCCS_nf, gteCC_nf , NULL , gteNCS_nf , NULL , // 18
151 gteNCT_nf , NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 20
152 gteSQR_nf , gteDCPL_nf , gteDPCT_nf , NULL , NULL , gteAVSZ3_nf, gteAVSZ4_nf, NULL , // 28
153 gteRTPT_nf, NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 30
154 NULL , NULL , NULL , NULL , NULL , gteGPF_nf , gteGPL_nf , gteNCCT_nf, // 38
155};
156
bedfea38 157const char *gte_regnames[64] = {
158 NULL , "RTPS" , NULL , NULL , NULL , NULL , "NCLIP", NULL , // 00
159 NULL , NULL , NULL , NULL , "OP" , NULL , NULL , NULL , // 08
160 "DPCS", "INTPL", "MVMVA", "NCDS", "CDP", NULL , "NCDT" , NULL , // 10
161 NULL , NULL , NULL , "NCCS", "CC" , NULL , "NCS" , NULL , // 18
162 "NCT" , NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 20
163 "SQR" , "DCPL" , "DPCT" , NULL , NULL , "AVSZ3", "AVSZ4", NULL , // 28
164 "RTPT", NULL , NULL , NULL , NULL , NULL , NULL , NULL , // 30
165 NULL , NULL , NULL , NULL , NULL , "GPF" , "GPL" , "NCCT", // 38
166};
167
b9b61529 168/* from gte.txt.. not sure if this is any good. */
169const char gte_cycletab[64] = {
170 /* 1 2 3 4 5 6 7 8 9 a b c d e f */
171 0, 15, 0, 0, 0, 0, 8, 0, 0, 0, 0, 0, 6, 0, 0, 0,
172 8, 8, 8, 19, 13, 0, 44, 0, 0, 0, 0, 17, 11, 0, 14, 0,
173 30, 0, 0, 0, 0, 0, 0, 0, 5, 8, 17, 0, 0, 5, 6, 0,
174 23, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 5, 39,
175};
f95a77f7 176
177static int ari64_init()
178{
b9b61529 179 extern void (*psxCP2[64])();
180 extern void psxNULL();
f95a77f7 181 size_t i;
b9b61529 182
f95a77f7 183 new_dynarec_init();
7e605697 184 new_dyna_pcsx_mem_init();
7139f3c8 185
ae602c19 186 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
b9b61529 187 if (psxCP2[i] != psxNULL)
188 gte_handlers[i] = psxCP2[i];
59774ed0 189
190#if !defined(DRC_DBG) && !defined(PCNT)
191#ifdef __arm__
192 gte_handlers[0x06] = gteNCLIP_arm;
193#endif
a80ae4a0 194#ifdef __ARM_NEON__
59774ed0 195 // compiler's _nf version is still a lot slower then neon
196 gte_handlers[0x01] = gte_handlers_nf[0x01] = gteRTPS_neon;
197 gte_handlers[0x30] = gte_handlers_nf[0x30] = gteRTPT_neon;
198 gte_handlers[0x12] = gte_handlers_nf[0x12] = gteMVMVA_neon;
a80ae4a0 199#endif
009faf24 200#endif
7e605697 201 psxH_ptr = psxH;
202
b9b61529 203 return 0;
f95a77f7 204}
205
206static void ari64_reset()
207{
f95a77f7 208 printf("ari64_reset\n");
7e605697 209 new_dyna_pcsx_mem_reset();
4b421010 210 invalidate_all_pages();
7f457614 211 new_dyna_restore();
4b421010 212 pending_exception = 1;
f95a77f7 213}
214
e4eb18c1 215// execute until predefined leave points
216// (HLE softcall exit and BIOS fastboot end)
217static void ari64_execute_until()
f95a77f7 218{
654e8cfb 219 schedule_timeslice();
220
221 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
222 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
7139f3c8 223
b9b61529 224 new_dyna_start();
654e8cfb 225
226 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
227 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
f95a77f7 228}
229
e4eb18c1 230static void ari64_execute()
231{
232 while (!stop) {
233 ari64_execute_until();
234 evprintf("drc left @%08x\n", psxRegs.pc);
235 }
236}
237
4b421010 238static void ari64_clear(u32 addr, u32 size)
f95a77f7 239{
0ce47d46 240 u32 start, end, main_ram;
4b421010 241
76739a08 242 size *= 4; /* PCSX uses DMA units */
243
4b421010 244 evprintf("ari64_clear %08x %04x\n", addr, size);
245
246 /* check for RAM mirrors */
0ce47d46 247 main_ram = (addr & 0xffe00000) == 0x80000000;
4b421010 248
249 start = addr >> 12;
250 end = (addr + size) >> 12;
251
252 for (; start <= end; start++)
0ce47d46 253 if (!main_ram || !invalid_code[start])
4b421010 254 invalidate_block(start);
f95a77f7 255}
256
257static void ari64_shutdown()
258{
259 new_dynarec_cleanup();
260}
261
7139f3c8 262extern void intExecute();
263extern void intExecuteT();
264extern void intExecuteBlock();
265extern void intExecuteBlockT();
266#ifndef DRC_DBG
267#define intExecuteT intExecute
268#define intExecuteBlockT intExecuteBlock
269#endif
270
f95a77f7 271R3000Acpu psxRec = {
272 ari64_init,
273 ari64_reset,
2185e39b 274#if defined(__arm__)
f95a77f7 275 ari64_execute,
e4eb18c1 276 ari64_execute_until,
7139f3c8 277#else
278 intExecuteT,
279 intExecuteBlockT,
280#endif
f95a77f7 281 ari64_clear,
282 ari64_shutdown
283};
7139f3c8 284
285// TODO: rm
286#ifndef DRC_DBG
287void do_insn_trace() {}
288void do_insn_cmp() {}
289#endif
290
291#if defined(__x86_64__) || defined(__i386__)
292unsigned int address, readmem_word, word;
293unsigned short hword;
294unsigned char byte;
ccf51908 295int pending_exception, stop;
7139f3c8 296unsigned int next_interupt;
7e605697 297void *psxH_ptr;
7139f3c8 298void new_dynarec_init() {}
3eb78778 299void new_dyna_start() {}
7139f3c8 300void new_dynarec_cleanup() {}
2c886904 301void new_dynarec_clear_full() {}
ccf51908 302void invalidate_all_pages() {}
303void invalidate_block(unsigned int block) {}
7e605697 304void new_dyna_pcsx_mem_init(void) {}
305void new_dyna_pcsx_mem_reset(void) {}
7139f3c8 306#endif
307
308#ifdef DRC_DBG
309
310#include <stddef.h>
311static FILE *f;
312extern u32 last_io_addr;
313
314static void dump_mem(const char *fname, void *mem, size_t size)
315{
316 FILE *f1 = fopen(fname, "wb");
3eb78778 317 if (f1 == NULL)
318 f1 = fopen(strrchr(fname, '/') + 1, "wb");
7139f3c8 319 fwrite(mem, 1, size, f1);
320 fclose(f1);
321}
322
2185e39b 323static u32 memcheck_read(u32 a)
324{
325 if ((a >> 16) == 0x1f80)
326 // scratchpad/IO
327 return *(u32 *)(psxH + (a & 0xfffc));
328
329 if ((a >> 16) == 0x1f00)
330 // parallel
331 return *(u32 *)(psxP + (a & 0xfffc));
332
333// if ((a & ~0xe0600000) < 0x200000)
334 // RAM
335 return *(u32 *)(psxM + (a & 0x1ffffc));
336}
337
7139f3c8 338void do_insn_trace(void)
339{
340 static psxRegisters oldregs;
341 static u32 old_io_addr = (u32)-1;
342 static u32 old_io_data = 0xbad0c0de;
343 u32 *allregs_p = (void *)&psxRegs;
344 u32 *allregs_o = (void *)&oldregs;
2185e39b 345 u32 io_data;
7139f3c8 346 int i;
347 u8 byte;
348
349//last_io_addr = 0x5e2c8;
350 if (f == NULL)
351 f = fopen("tracelog", "wb");
352
353 oldregs.code = psxRegs.code; // don't care
354 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
355 if (allregs_p[i] != allregs_o[i]) {
356 fwrite(&i, 1, 1, f);
357 fwrite(&allregs_p[i], 1, 4, f);
358 allregs_o[i] = allregs_p[i];
359 }
360 }
361 if (old_io_addr != last_io_addr) {
362 byte = 0xfd;
363 fwrite(&byte, 1, 1, f);
364 fwrite(&last_io_addr, 1, 4, f);
365 old_io_addr = last_io_addr;
366 }
2185e39b 367 io_data = memcheck_read(last_io_addr);
368 if (old_io_data != io_data) {
7139f3c8 369 byte = 0xfe;
370 fwrite(&byte, 1, 1, f);
2185e39b 371 fwrite(&io_data, 1, 4, f);
372 old_io_data = io_data;
7139f3c8 373 }
374 byte = 0xff;
375 fwrite(&byte, 1, 1, f);
376
377#if 0
378 if (psxRegs.cycle == 190230) {
379 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram_i.dump", psxM, 0x200000);
380 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs_i.dump", psxH, 0x10000);
381 printf("dumped\n");
382 exit(1);
383 }
384#endif
385}
386
387static const char *regnames[offsetof(psxRegisters, intCycle) / 4] = {
388 "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7",
389 "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
390 "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
391 "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
392 "lo", "hi",
393 "C0_0", "C0_1", "C0_2", "C0_3", "C0_4", "C0_5", "C0_6", "C0_7",
394 "C0_8", "C0_9", "C0_10", "C0_11", "C0_12", "C0_13", "C0_14", "C0_15",
395 "C0_16", "C0_17", "C0_18", "C0_19", "C0_20", "C0_21", "C0_22", "C0_23",
396 "C0_24", "C0_25", "C0_26", "C0_27", "C0_28", "C0_29", "C0_30", "C0_31",
397
398 "C2D0", "C2D1", "C2D2", "C2D3", "C2D4", "C2D5", "C2D6", "C2D7",
399 "C2D8", "C2D9", "C2D10", "C2D11", "C2D12", "C2D13", "C2D14", "C2D15",
400 "C2D16", "C2D17", "C2D18", "C2D19", "C2D20", "C2D21", "C2D22", "C2D23",
401 "C2D24", "C2D25", "C2D26", "C2D27", "C2D28", "C2D29", "C2D30", "C2D31",
402
403 "C2C0", "C2C1", "C2C2", "C2C3", "C2C4", "C2C5", "C2C6", "C2C7",
404 "C2C8", "C2C9", "C2C10", "C2C11", "C2C12", "C2C13", "C2C14", "C2C15",
405 "C2C16", "C2C17", "C2C18", "C2C19", "C2C20", "C2C21", "C2C22", "C2C23",
406 "C2C24", "C2C25", "C2C26", "C2C27", "C2C28", "C2C29", "C2C30", "C2C31",
407
408 "PC", "code", "cycle", "interrupt",
409};
410
3eb78778 411static struct {
412 int reg;
413 u32 val, val_expect;
414 u32 pc, cycle;
415} miss_log[64];
416static int miss_log_i;
417#define miss_log_len (sizeof(miss_log)/sizeof(miss_log[0]))
418#define miss_log_mask (miss_log_len-1)
419
420static void miss_log_add(int reg, u32 val, u32 val_expect, u32 pc, u32 cycle)
421{
422 miss_log[miss_log_i].reg = reg;
423 miss_log[miss_log_i].val = val;
424 miss_log[miss_log_i].val_expect = val_expect;
425 miss_log[miss_log_i].pc = pc;
426 miss_log[miss_log_i].cycle = cycle;
427 miss_log_i = (miss_log_i + 1) & miss_log_mask;
428}
429
7139f3c8 430void breakme() {}
431
432void do_insn_cmp(void)
433{
434 static psxRegisters rregs;
435 static u32 mem_addr, mem_val;
436 u32 *allregs_p = (void *)&psxRegs;
437 u32 *allregs_e = (void *)&rregs;
438 static u32 ppc, failcount;
439 int i, ret, bad = 0;
440 u8 code;
441
442 if (f == NULL)
443 f = fopen("tracelog", "rb");
444
445 while (1) {
446 if ((ret = fread(&code, 1, 1, f)) <= 0)
447 break;
448 if (ret <= 0)
449 break;
450 if (code == 0xff)
451 break;
452 if (code == 0xfd) {
453 if ((ret = fread(&mem_addr, 1, 4, f)) <= 0)
454 break;
455 continue;
456 }
457 if (code == 0xfe) {
458 if ((ret = fread(&mem_val, 1, 4, f)) <= 0)
459 break;
460 continue;
461 }
462 if ((ret = fread(&allregs_e[code], 1, 4, f)) <= 0)
463 break;
464 }
465
466 if (ret <= 0) {
467 printf("EOF?\n");
468 goto end;
469 }
470
471 psxRegs.code = rregs.code; // don't care
2185e39b 472 psxRegs.cycle = rregs.cycle;
473 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
7139f3c8 474
475//if (psxRegs.cycle == 166172) breakme();
7139f3c8 476
477 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
2185e39b 478 mem_val == memcheck_read(mem_addr)
7139f3c8 479 ) {
480 failcount = 0;
481 goto ok;
482 }
483
484 for (i = 0; i < offsetof(psxRegisters, intCycle) / 4; i++) {
485 if (allregs_p[i] != allregs_e[i]) {
3eb78778 486 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
7139f3c8 487 bad++;
488 }
489 }
490
2185e39b 491 if (mem_val != memcheck_read(mem_addr)) {
492 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
7139f3c8 493 goto end;
494 }
495
496 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
3eb78778 497 static int last_mcycle;
498 if (last_mcycle != psxRegs.cycle >> 20) {
499 printf("%u\n", psxRegs.cycle);
500 last_mcycle = psxRegs.cycle >> 20;
501 }
7139f3c8 502 failcount++;
503 goto ok;
504 }
505
506end:
3eb78778 507 for (i = 0; i < miss_log_len; i++, miss_log_i = (miss_log_i + 1) & miss_log_mask)
508 printf("bad %5s: %08x %08x, pc=%08x, cycle %u\n",
509 regnames[miss_log[miss_log_i].reg], miss_log[miss_log_i].val,
510 miss_log[miss_log_i].val_expect, miss_log[miss_log_i].pc, miss_log[miss_log_i].cycle);
511 printf("-- %d\n", bad);
512 for (i = 0; i < 8; i++)
513 printf("r%d=%08x r%2d=%08x r%2d=%08x r%2d=%08x\n", i, allregs_p[i],
87c06e51 514 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
7139f3c8 515 printf("PC: %08x/%08x, cycle %u\n", psxRegs.pc, ppc, psxRegs.cycle);
516 dump_mem("/mnt/ntz/dev/pnd/tmp/psxram.dump", psxM, 0x200000);
517 dump_mem("/mnt/ntz/dev/pnd/tmp/psxregs.dump", psxH, 0x10000);
518 exit(1);
519ok:
520 psxRegs.cycle = rregs.cycle + 2; // sync timing
521 ppc = psxRegs.pc;
522}
523
524#endif