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