1 /*
2 * PicoDrive
3 * (c) Copyright Dave, 2004
4 * (C) notaz, 2006-2009
5 *
6 * This work is licensed under the terms of MAME license.
7 * See COPYING file in the top-level directory.
8 */
9
10 #include "pico_int.h"
11 #include "memory.h"
12
13 #ifdef USE_LIBRETRO_VFS
14 #include "file_stream_transforms.h"
15 #endif
16
17 /* context */
18 // Cyclone 68000
19 #ifdef EMU_C68K
20 struct Cyclone PicoCpuCM68k;
21 #endif
22 // MUSASHI 68000
23 #ifdef EMU_M68K
24 m68ki_cpu_core PicoCpuMM68k;
25 #endif
26 // FAME 68000
27 #ifdef EMU_F68K
28 M68K_CONTEXT PicoCpuFM68k;
29 #endif
30
31
do_ack(int level)32 static int do_ack(int level)
33 {
34 struct PicoVideo *pv = &Pico.video;
35
36 elprintf(EL_INTS, "%cack: @ %06x [%u], p=%02x",
37 level == 6 ? 'v' : 'h', SekPc, SekCyclesDone(), pv->pending_ints);
38 // the VDP doesn't look at the 68k level
39 if (pv->pending_ints & pv->reg[1] & 0x20) {
40 pv->pending_ints &= ~0x20;
41 pv->status &= ~SR_F;
42 return (pv->reg[0] & pv->pending_ints & 0x10) >> 2;
43 }
44 else if (pv->pending_ints & pv->reg[0] & 0x10)
45 pv->pending_ints &= ~0x10;
46
47 return 0;
48 }
49
50 /* callbacks */
51 #ifdef EMU_C68K
52 // interrupt acknowledgment
SekIntAck(int level)53 static int SekIntAck(int level)
54 {
55 PicoCpuCM68k.irq = do_ack(level);
56 return CYCLONE_INT_ACK_AUTOVECTOR;
57 }
58
SekResetAck(void)59 static void SekResetAck(void)
60 {
61 elprintf(EL_ANOMALY, "Reset encountered @ %06x", SekPc);
62 }
63
SekUnrecognizedOpcode()64 static int SekUnrecognizedOpcode()
65 {
66 unsigned int pc;
67 pc = SekPc;
68 elprintf(EL_ANOMALY, "Unrecognized Opcode @ %06x", pc);
69 // see if we are still in a mapped region
70 pc &= 0x00ffffff;
71 if (map_flag_set(m68k_read16_map[pc >> M68K_MEM_SHIFT])) {
72 elprintf(EL_STATUS|EL_ANOMALY, "m68k crash @%06x", pc);
73 PicoCpuCM68k.cycles = 0;
74 PicoCpuCM68k.state_flags |= 1;
75 return 1;
76 }
77 // happened once - may happen again
78 SekFinishIdleDet();
79 #ifdef EMU_M68K // debugging cyclone
80 {
81 extern int have_illegal;
82 have_illegal = 1;
83 }
84 #endif
85 return 0;
86 }
87 #endif
88
89
90 #ifdef EMU_M68K
SekIntAckM68K(int level)91 static int SekIntAckM68K(int level)
92 {
93 CPU_INT_LEVEL = do_ack(level) << 8;
94 return M68K_INT_ACK_AUTOVECTOR;
95 }
96
SekTasCallback(void)97 static int SekTasCallback(void)
98 {
99 return 0; // no writeback
100 }
101 #endif
102
103
104 #ifdef EMU_F68K
SekIntAckF68K(unsigned level)105 static void SekIntAckF68K(unsigned level)
106 {
107 PicoCpuFM68k.interrupts[0] = do_ack(level);
108 }
109 #endif
110
111
SekInit(void)112 PICO_INTERNAL void SekInit(void)
113 {
114 #ifdef EMU_C68K
115 CycloneInit();
116 memset(&PicoCpuCM68k,0,sizeof(PicoCpuCM68k));
117 PicoCpuCM68k.IrqCallback=SekIntAck;
118 PicoCpuCM68k.ResetCallback=SekResetAck;
119 PicoCpuCM68k.UnrecognizedCallback=SekUnrecognizedOpcode;
120 PicoCpuCM68k.flags=4; // Z set
121 #endif
122 #ifdef EMU_M68K
123 {
124 void *oldcontext = m68ki_cpu_p;
125 m68k_set_context(&PicoCpuMM68k);
126 m68k_set_cpu_type(M68K_CPU_TYPE_68000);
127 m68k_init();
128 m68k_set_int_ack_callback(SekIntAckM68K);
129 m68k_set_tas_instr_callback(SekTasCallback);
130 //m68k_pulse_reset();
131 m68k_set_context(oldcontext);
132 }
133 #endif
134 #ifdef EMU_F68K
135 memset(&PicoCpuFM68k, 0, sizeof(PicoCpuFM68k));
136 fm68k_init();
137 PicoCpuFM68k.iack_handler = SekIntAckF68K;
138 PicoCpuFM68k.sr = 0x2704; // Z flag
139 #endif
140 }
141
142
143 // Reset the 68000:
SekReset(void)144 PICO_INTERNAL int SekReset(void)
145 {
146 if (Pico.rom==NULL) return 1;
147
148 #ifdef EMU_C68K
149 CycloneReset(&PicoCpuCM68k);
150 #endif
151 #ifdef EMU_M68K
152 m68k_set_context(&PicoCpuMM68k); // if we ever reset m68k, we always need it's context to be set
153 m68ki_cpu.sp[0]=0;
154 m68k_set_irq(0);
155 m68k_pulse_reset();
156 REG_USP = 0; // ?
157 #endif
158 #ifdef EMU_F68K
159 fm68k_reset(&PicoCpuFM68k);
160 #endif
161
162 return 0;
163 }
164
SekStepM68k(void)165 void SekStepM68k(void)
166 {
167 Pico.t.m68c_aim = Pico.t.m68c_cnt + 1;
168 #if defined(EMU_CORE_DEBUG)
169 Pico.t.m68c_cnt += CM_compareRun(1, 0);
170 #elif defined(EMU_C68K)
171 PicoCpuCM68k.cycles=1;
172 CycloneRun(&PicoCpuCM68k);
173 Pico.t.m68c_cnt += 1 - PicoCpuCM68k.cycles;
174 #elif defined(EMU_M68K)
175 Pico.t.m68c_cnt += m68k_execute(1);
176 #elif defined(EMU_F68K)
177 Pico.t.m68c_cnt += fm68k_emulate(&PicoCpuFM68k, 1, 0);
178 #endif
179 }
180
SekSetRealTAS(int use_real)181 PICO_INTERNAL void SekSetRealTAS(int use_real)
182 {
183 #ifdef EMU_C68K
184 CycloneSetRealTAS(use_real);
185 #endif
186 #ifdef EMU_F68K
187 // TODO
188 #endif
189 }
190
191 // Pack the cpu into a common format:
192 // XXX: rename
SekPackCpu(unsigned char * cpu,int is_sub)193 PICO_INTERNAL void SekPackCpu(unsigned char *cpu, int is_sub)
194 {
195 unsigned int pc=0;
196
197 #if defined(EMU_C68K)
198 struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
199 memcpy(cpu,context->d,0x40);
200 pc=context->pc-context->membase;
201 *(unsigned int *)(cpu+0x44)=CycloneGetSr(context);
202 *(unsigned int *)(cpu+0x48)=context->osp;
203 cpu[0x4c] = context->irq;
204 cpu[0x4d] = context->state_flags & 1;
205 #elif defined(EMU_M68K)
206 void *oldcontext = m68ki_cpu_p;
207 m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
208 memcpy(cpu,m68ki_cpu_p->dar,0x40);
209 pc=m68ki_cpu_p->pc;
210 *(unsigned int *)(cpu+0x44)=m68k_get_reg(NULL, M68K_REG_SR);
211 *(unsigned int *)(cpu+0x48)=m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET];
212 cpu[0x4c] = CPU_INT_LEVEL>>8;
213 cpu[0x4d] = CPU_STOPPED;
214 m68k_set_context(oldcontext);
215 #elif defined(EMU_F68K)
216 M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
217 memcpy(cpu,context->dreg,0x40);
218 pc=context->pc;
219 *(unsigned int *)(cpu+0x44)=context->sr;
220 *(unsigned int *)(cpu+0x48)=context->asp;
221 cpu[0x4c] = context->interrupts[0];
222 cpu[0x4d] = (context->execinfo & FM68K_HALTED) ? 1 : 0;
223 #endif
224
225 *(unsigned int *)(cpu+0x40) = pc;
226 *(unsigned int *)(cpu+0x50) =
227 is_sub ? SekCycleCntS68k : Pico.t.m68c_cnt;
228 }
229
SekUnpackCpu(const unsigned char * cpu,int is_sub)230 PICO_INTERNAL void SekUnpackCpu(const unsigned char *cpu, int is_sub)
231 {
232 #if defined(EMU_C68K)
233 struct Cyclone *context = is_sub ? &PicoCpuCS68k : &PicoCpuCM68k;
234 CycloneSetSr(context, *(unsigned int *)(cpu+0x44));
235 context->osp=*(unsigned int *)(cpu+0x48);
236 memcpy(context->d,cpu,0x40);
237 context->membase = 0;
238 context->pc = *(unsigned int *)(cpu+0x40);
239 CycloneUnpack(context, NULL); // rebase PC
240 context->irq = cpu[0x4c];
241 context->state_flags = 0;
242 if (cpu[0x4d])
243 context->state_flags |= 1;
244 #elif defined(EMU_M68K)
245 void *oldcontext = m68ki_cpu_p;
246 m68k_set_context(is_sub ? &PicoCpuMS68k : &PicoCpuMM68k);
247 m68k_set_reg(M68K_REG_SR, *(unsigned int *)(cpu+0x44));
248 memcpy(m68ki_cpu_p->dar,cpu,0x40);
249 m68ki_cpu_p->pc=*(unsigned int *)(cpu+0x40);
250 m68ki_cpu_p->sp[m68ki_cpu_p->s_flag^SFLAG_SET]=*(unsigned int *)(cpu+0x48);
251 CPU_INT_LEVEL = cpu[0x4c] << 8;
252 CPU_STOPPED = cpu[0x4d];
253 m68k_set_context(oldcontext);
254 #elif defined(EMU_F68K)
255 M68K_CONTEXT *context = is_sub ? &PicoCpuFS68k : &PicoCpuFM68k;
256 memcpy(context->dreg,cpu,0x40);
257 context->pc =*(unsigned int *)(cpu+0x40);
258 context->sr =*(unsigned int *)(cpu+0x44);
259 context->asp=*(unsigned int *)(cpu+0x48);
260 context->interrupts[0] = cpu[0x4c];
261 context->execinfo &= ~FM68K_HALTED;
262 if (cpu[0x4d]&1) context->execinfo |= FM68K_HALTED;
263 #endif
264 if (is_sub)
265 SekCycleCntS68k = *(unsigned int *)(cpu+0x50);
266 else
267 Pico.t.m68c_cnt = *(unsigned int *)(cpu+0x50);
268 }
269
270
271 /* idle loop detection, not to be used in CD mode */
272 #ifdef EMU_C68K
273 #include "cpu/cyclone/tools/idle.h"
274 #endif
275
276 static unsigned short **idledet_ptrs = NULL;
277 static int idledet_count = 0, idledet_bads = 0;
278 static int idledet_start_frame = 0;
279
280 #if 0
281 #define IDLE_STATS 1
282 unsigned int idlehit_addrs[128], idlehit_counts[128];
283
284 void SekRegisterIdleHit(unsigned int pc)
285 {
286 int i;
287 for (i = 0; i < 127 && idlehit_addrs[i]; i++) {
288 if (idlehit_addrs[i] == pc) {
289 idlehit_counts[i]++;
290 return;
291 }
292 }
293 idlehit_addrs[i] = pc;
294 idlehit_counts[i] = 1;
295 idlehit_addrs[i+1] = 0;
296 }
297 #endif
298
SekInitIdleDet(void)299 void SekInitIdleDet(void)
300 {
301 unsigned short **tmp;
302 tmp = realloc(idledet_ptrs, 0x200 * sizeof(tmp[0]));
303 if (tmp == NULL) {
304 free(idledet_ptrs);
305 idledet_ptrs = NULL;
306 }
307 else
308 idledet_ptrs = tmp;
309 idledet_count = idledet_bads = 0;
310 idledet_start_frame = Pico.m.frame_count + 360;
311 #ifdef IDLE_STATS
312 idlehit_addrs[0] = 0;
313 #endif
314
315 #ifdef EMU_C68K
316 CycloneInitIdle();
317 #endif
318 #ifdef EMU_F68K
319 fm68k_idle_install();
320 #endif
321 }
322
SekIsIdleReady(void)323 int SekIsIdleReady(void)
324 {
325 return (Pico.m.frame_count >= idledet_start_frame);
326 }
327
SekIsIdleCode(unsigned short * dst,int bytes)328 int SekIsIdleCode(unsigned short *dst, int bytes)
329 {
330 // printf("SekIsIdleCode %04x %i\n", *dst, bytes);
331 switch (bytes)
332 {
333 case 2:
334 if ((*dst & 0xf000) != 0x6000) // not another branch
335 return 1;
336 break;
337 case 4:
338 if ( (*dst & 0xff3f) == 0x4a38 || // tst.x ($xxxx.w); tas ($xxxx.w)
339 (*dst & 0xc1ff) == 0x0038 || // move.x ($xxxx.w), dX
340 (*dst & 0xf13f) == 0xb038) // cmp.x ($xxxx.w), dX
341 return 1;
342 if (PicoIn.AHW & (PAHW_MCD|PAHW_32X))
343 break;
344 // with no addons, there should be no need to wait
345 // for byte change anywhere
346 if ( (*dst & 0xfff8) == 0x4a10 || // tst.b ($aX)
347 (*dst & 0xfff8) == 0x4a28) // tst.b ($xxxx,a0)
348 return 1;
349 break;
350 case 6:
351 if ( ((dst[1] & 0xe0) == 0xe0 && ( // RAM and
352 *dst == 0x4a39 || // tst.b ($xxxxxxxx)
353 *dst == 0x4a79 || // tst.w ($xxxxxxxx)
354 *dst == 0x4ab9 || // tst.l ($xxxxxxxx)
355 (*dst & 0xc1ff) == 0x0039 || // move.x ($xxxxxxxx), dX
356 (*dst & 0xf13f) == 0xb039))||// cmp.x ($xxxxxxxx), dX
357 *dst == 0x0838 || // btst $X, ($xxxx.w) [6 byte op]
358 (*dst & 0xffbf) == 0x0c38) // cmpi.{b,w} $X, ($xxxx.w)
359 return 1;
360 break;
361 case 8:
362 if ( ((dst[2] & 0xe0) == 0xe0 && ( // RAM and
363 *dst == 0x0839 || // btst $X, ($xxxxxxxx.w) [8 byte op]
364 (*dst & 0xffbf) == 0x0c39))||// cmpi.{b,w} $X, ($xxxxxxxx)
365 *dst == 0x0cb8) // cmpi.l $X, ($xxxx.w)
366 return 1;
367 break;
368 case 12:
369 if (PicoIn.AHW & (PAHW_MCD|PAHW_32X))
370 break;
371 if ( (*dst & 0xf1f8) == 0x3010 && // move.w (aX), dX
372 (dst[1]&0xf100) == 0x0000 && // arithmetic
373 (dst[3]&0xf100) == 0x0000) // arithmetic
374 return 1;
375 break;
376 }
377
378 return 0;
379 }
380
SekRegisterIdlePatch(unsigned int pc,int oldop,int newop,void * ctx)381 int SekRegisterIdlePatch(unsigned int pc, int oldop, int newop, void *ctx)
382 {
383 int is_main68k = 1;
384 u16 *target;
385 uptr v;
386
387 #if defined(EMU_C68K)
388 struct Cyclone *cyc = ctx;
389 is_main68k = cyc == &PicoCpuCM68k;
390 pc -= cyc->membase;
391 #elif defined(EMU_F68K)
392 is_main68k = ctx == &PicoCpuFM68k;
393 #endif
394 pc &= ~0xff000000;
395 if (!(newop&0x200))
396 elprintf(EL_IDLE, "idle: patch %06x %04x %04x %c %c #%i", pc, oldop, newop,
397 (newop&0x200)?'n':'y', is_main68k?'m':'s', idledet_count);
398
399 // XXX: probably shouldn't patch RAM too
400 v = m68k_read16_map[pc >> M68K_MEM_SHIFT];
401 if (!(v & 0x80000000))
402 target = (u16 *)((v << 1) + pc);
403 else {
404 if (++idledet_bads > 128)
405 return 2; // remove detector
406 return 1; // don't patch
407 }
408
409 if (idledet_count >= 0x200 && (idledet_count & 0x1ff) == 0) {
410 unsigned short **tmp;
411 tmp = realloc(idledet_ptrs, (idledet_count+0x200) * sizeof(tmp[0]));
412 if (tmp == NULL)
413 return 1;
414 idledet_ptrs = tmp;
415 }
416
417 idledet_ptrs[idledet_count++] = target;
418
419 return 0;
420 }
421
SekFinishIdleDet(void)422 void SekFinishIdleDet(void)
423 {
424 if (idledet_count < 0)
425 return;
426 #ifdef EMU_C68K
427 CycloneFinishIdle();
428 #endif
429 #ifdef EMU_F68K
430 fm68k_idle_remove();
431 #endif
432 while (idledet_count > 0)
433 {
434 unsigned short *op = idledet_ptrs[--idledet_count];
435 if ((*op & 0xfd00) == 0x7100)
436 *op &= 0xff, *op |= 0x6600;
437 else if ((*op & 0xfd00) == 0x7500)
438 *op &= 0xff, *op |= 0x6700;
439 else if ((*op & 0xfd00) == 0x7d00)
440 *op &= 0xff, *op |= 0x6000;
441 else
442 elprintf(EL_STATUS|EL_IDLE, "idle: don't know how to restore %04x", *op);
443 }
444 idledet_count = -1;
445 }
446
447
448 #if defined(CPU_CMP_R) || defined(CPU_CMP_W)
449 #include "debug.h"
450
451 struct ref_68k {
452 u32 dar[16];
453 u32 pc;
454 u32 sr;
455 u32 cycles;
456 u32 pc_prev;
457 };
458 struct ref_68k ref_68ks[2];
459 static int current_68k;
460
SekTrace(int is_s68k)461 void SekTrace(int is_s68k)
462 {
463 struct ref_68k *x68k = &ref_68ks[is_s68k];
464 u32 pc = is_s68k ? SekPcS68k : SekPc;
465 u32 sr = is_s68k ? SekSrS68k : SekSr;
466 u32 cycles = is_s68k ? SekCycleCntS68k : Pico.t.m68c_cnt;
467 u32 r;
468 u8 cmd;
469 #ifdef CPU_CMP_W
470 int i;
471
472 if (is_s68k != current_68k) {
473 current_68k = is_s68k;
474 cmd = CTL_68K_SLAVE | current_68k;
475 tl_write(&cmd, sizeof(cmd));
476 }
477 if (pc != x68k->pc) {
478 x68k->pc = pc;
479 tl_write_uint(CTL_68K_PC, x68k->pc);
480 }
481 if (sr != x68k->sr) {
482 x68k->sr = sr;
483 tl_write_uint(CTL_68K_SR, x68k->sr);
484 }
485 for (i = 0; i < 16; i++) {
486 r = is_s68k ? SekDarS68k(i) : SekDar(i);
487 if (r != x68k->dar[i]) {
488 x68k->dar[i] = r;
489 tl_write_uint(CTL_68K_R + i, r);
490 }
491 }
492 tl_write_uint(CTL_68K_CYCLES, cycles);
493 #else
494 int i, bad = 0;
495
496 while (1)
497 {
498 int ret = tl_read(&cmd, sizeof(cmd));
499 if (ret == 0) {
500 elprintf(EL_STATUS, "EOF");
501 exit(1);
502 }
503 switch (cmd) {
504 case CTL_68K_SLAVE:
505 case CTL_68K_SLAVE + 1:
506 current_68k = cmd & 1;
507 break;
508 case CTL_68K_PC:
509 tl_read_uint(&x68k->pc);
510 break;
511 case CTL_68K_SR:
512 tl_read_uint(&x68k->sr);
513 break;
514 case CTL_68K_CYCLES:
515 tl_read_uint(&x68k->cycles);
516 goto breakloop;
517 default:
518 if (CTL_68K_R <= cmd && cmd < CTL_68K_R + 0x10)
519 tl_read_uint(&x68k->dar[cmd - CTL_68K_R]);
520 else
521 elprintf(EL_STATUS, "invalid cmd: %02x", cmd);
522 }
523 }
524
525 breakloop:
526 if (is_s68k != current_68k) {
527 printf("bad 68k: %d %d\n", is_s68k, current_68k);
528 bad = 1;
529 }
530 if (cycles != x68k->cycles) {
531 printf("bad cycles: %u %u\n", cycles, x68k->cycles);
532 bad = 1;
533 }
534 if ((pc ^ x68k->pc) & 0xffffff) {
535 printf("bad PC: %08x %08x\n", pc, x68k->pc);
536 bad = 1;
537 }
538 if (sr != x68k->sr) {
539 printf("bad SR: %03x %03x\n", sr, x68k->sr);
540 bad = 1;
541 }
542 for (i = 0; i < 16; i++) {
543 r = is_s68k ? SekDarS68k(i) : SekDar(i);
544 if (r != x68k->dar[i]) {
545 printf("bad %c%d: %08x %08x\n", i < 8 ? 'D' : 'A', i & 7,
546 r, x68k->dar[i]);
547 bad = 1;
548 }
549 }
550 if (bad) {
551 for (i = 0; i < 8; i++)
552 printf("D%d: %08x A%d: %08x\n", i, x68k->dar[i],
553 i, x68k->dar[i + 8]);
554 printf("PC: %08x, %08x\n", x68k->pc, x68k->pc_prev);
555 printf("SR: %04x\n", x68k->sr);
556
557 PDebugDumpMem();
558 exit(1);
559 }
560 x68k->pc_prev = x68k->pc;
561 #endif
562 }
563 #endif // CPU_CMP_*
564
565 #if defined(EMU_M68K) && M68K_INSTRUCTION_HOOK == OPT_SPECIFY_HANDLER
566 static unsigned char op_flags[0x400000/2] = { 0, };
567 static int atexit_set = 0;
568
make_idc(void)569 static void make_idc(void)
570 {
571 FILE *f = fopen("idc.idc", "w");
572 int i;
573 if (!f) return;
574 fprintf(f, "#include <idc.idc>\nstatic main() {\n");
575 for (i = 0; i < 0x400000/2; i++)
576 if (op_flags[i] != 0)
577 fprintf(f, " MakeCode(0x%06x);\n", i*2);
578 fprintf(f, "}\n");
579 fclose(f);
580 }
581
instruction_hook(void)582 void instruction_hook(void)
583 {
584 if (!atexit_set) {
585 atexit(make_idc);
586 atexit_set = 1;
587 }
588 if (REG_PC < 0x400000)
589 op_flags[REG_PC/2] = 1;
590 }
591 #endif
592
593 // vim:shiftwidth=2:ts=2:expandtab
594