dfxvideo: remove unneeded double division in line code
[pcsx_rearmed.git] / libpcsxcore / new_dynarec / emu_if.c
... / ...
CommitLineData
1/*
2 * (C) GraÅžvydas "notaz" Ignotas, 2010-2011
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
8#include <stdio.h>
9
10#include "emu_if.h"
11#include "pcsxmem.h"
12#include "../psxhle.h"
13#include "../r3000a.h"
14#include "../cdrom.h"
15#include "../psxdma.h"
16#include "../mdec.h"
17#include "../gte_arm.h"
18#include "../gte_neon.h"
19#define FLAGLESS
20#include "../gte.h"
21
22#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
23
24//#define evprintf printf
25#define evprintf(...)
26
27char invalid_code[0x100000];
28u32 event_cycles[PSXINT_COUNT];
29
30static void schedule_timeslice(void)
31{
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}
56
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,
66 [PSXINT_MDECINDMA] = mdec0Interrupt,
67 [PSXINT_GPUOTCDMA] = gpuotcInterrupt,
68 [PSXINT_CDRDMA] = cdrDmaInterrupt,
69 [PSXINT_CDRLID] = cdrLidSeekInterrupt,
70 [PSXINT_CDRPLAY] = cdrPlayInterrupt,
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
102void gen_interupt()
103{
104 evprintf(" +ge %08x, %u->%u\n", psxRegs.pc, psxRegs.cycle, next_interupt);
105
106 irq_test();
107 //psxBranchTest();
108 //pending_exception = 1;
109
110 schedule_timeslice();
111
112 evprintf(" -ge %08x, %u->%u (%d)\n", psxRegs.pc, psxRegs.cycle,
113 next_interupt, next_interupt - psxRegs.cycle);
114}
115
116// from interpreter
117extern void MTC0(int reg, u32 val);
118
119void pcsx_mtc0(u32 reg)
120{
121 evprintf("MTC0 %d #%x @%08x %u\n", reg, readmem_word, psxRegs.pc, psxRegs.cycle);
122 MTC0(reg, readmem_word);
123 gen_interupt();
124}
125
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);
130}
131
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;
140 for (i = 0; i < PSXINT_COUNT; i++)
141 event_cycles[i] = psxRegs.intCycle[i].sCycle + psxRegs.intCycle[i].cycle;
142}
143
144void *gte_handlers[64];
145
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
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
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};
176
177static int ari64_init()
178{
179 extern void (*psxCP2[64])();
180 extern void psxNULL();
181 size_t i;
182
183 new_dynarec_init();
184 new_dyna_pcsx_mem_init();
185
186 for (i = 0; i < ARRAY_SIZE(gte_handlers); i++)
187 if (psxCP2[i] != psxNULL)
188 gte_handlers[i] = psxCP2[i];
189
190#if !defined(DRC_DBG) && !defined(PCNT)
191#ifdef __arm__
192 gte_handlers[0x06] = gteNCLIP_arm;
193#endif
194#ifdef __ARM_NEON__
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;
199#endif
200#endif
201 psxH_ptr = psxH;
202
203 return 0;
204}
205
206static void ari64_reset()
207{
208 printf("ari64_reset\n");
209 new_dyna_pcsx_mem_reset();
210 invalidate_all_pages();
211 new_dyna_restore();
212 pending_exception = 1;
213}
214
215// execute until predefined leave points
216// (HLE softcall exit and BIOS fastboot end)
217static void ari64_execute_until()
218{
219 schedule_timeslice();
220
221 evprintf("ari64_execute %08x, %u->%u (%d)\n", psxRegs.pc,
222 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
223
224 new_dyna_start();
225
226 evprintf("ari64_execute end %08x, %u->%u (%d)\n", psxRegs.pc,
227 psxRegs.cycle, next_interupt, next_interupt - psxRegs.cycle);
228}
229
230static void ari64_execute()
231{
232 while (!stop) {
233 ari64_execute_until();
234 evprintf("drc left @%08x\n", psxRegs.pc);
235 }
236}
237
238static void ari64_clear(u32 addr, u32 size)
239{
240 u32 start, end, main_ram;
241
242 size *= 4; /* PCSX uses DMA units */
243
244 evprintf("ari64_clear %08x %04x\n", addr, size);
245
246 /* check for RAM mirrors */
247 main_ram = (addr & 0xffe00000) == 0x80000000;
248
249 start = addr >> 12;
250 end = (addr + size) >> 12;
251
252 for (; start <= end; start++)
253 if (!main_ram || !invalid_code[start])
254 invalidate_block(start);
255}
256
257static void ari64_shutdown()
258{
259 new_dynarec_cleanup();
260}
261
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
271R3000Acpu psxRec = {
272 ari64_init,
273 ari64_reset,
274#if defined(__arm__)
275 ari64_execute,
276 ari64_execute_until,
277#else
278 intExecuteT,
279 intExecuteBlockT,
280#endif
281 ari64_clear,
282 ari64_shutdown
283};
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;
295int pending_exception, stop;
296unsigned int next_interupt;
297void *psxH_ptr;
298void new_dynarec_init() {}
299void new_dyna_start() {}
300void new_dynarec_cleanup() {}
301void new_dynarec_clear_full() {}
302void invalidate_all_pages() {}
303void invalidate_block(unsigned int block) {}
304void new_dyna_pcsx_mem_init(void) {}
305void new_dyna_pcsx_mem_reset(void) {}
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");
317 if (f1 == NULL)
318 f1 = fopen(strrchr(fname, '/') + 1, "wb");
319 fwrite(mem, 1, size, f1);
320 fclose(f1);
321}
322
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
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;
345 u32 io_data;
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 }
367 io_data = memcheck_read(last_io_addr);
368 if (old_io_data != io_data) {
369 byte = 0xfe;
370 fwrite(&byte, 1, 1, f);
371 fwrite(&io_data, 1, 4, f);
372 old_io_data = io_data;
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
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
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
472 psxRegs.cycle = rregs.cycle;
473 psxRegs.CP0.r[9] = rregs.CP0.r[9]; // Count
474
475//if (psxRegs.cycle == 166172) breakme();
476
477 if (memcmp(&psxRegs, &rregs, offsetof(psxRegisters, intCycle)) == 0 &&
478 mem_val == memcheck_read(mem_addr)
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]) {
486 miss_log_add(i, allregs_p[i], allregs_e[i], psxRegs.pc, psxRegs.cycle);
487 bad++;
488 }
489 }
490
491 if (mem_val != memcheck_read(mem_addr)) {
492 printf("bad mem @%08x: %08x %08x\n", mem_addr, memcheck_read(mem_addr), mem_val);
493 goto end;
494 }
495
496 if (psxRegs.pc == rregs.pc && bad < 6 && failcount < 32) {
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 }
502 failcount++;
503 goto ok;
504 }
505
506end:
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],
514 i+8, allregs_p[i+8], i+16, allregs_p[i+16], i+24, allregs_p[i+24]);
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