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