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