pico_cmn.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327
  1. /*
  2. * common code for base/cd/32x
  3. * (C) notaz, 2007-2009,2013
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #define CYCLES_M68K_LINE 488 // suitable for both PAL/NTSC
  9. #define CYCLES_M68K_VINT_LAG 112
  10. // pad delay (for 6 button pads)
  11. #define PAD_DELAY() { \
  12. if(Pico.m.padDelay[0]++ > 25) Pico.m.padTHPhase[0]=0; \
  13. if(Pico.m.padDelay[1]++ > 25) Pico.m.padTHPhase[1]=0; \
  14. }
  15. // CPUS_RUN
  16. #ifndef CPUS_RUN
  17. #define CPUS_RUN(m68k_cycles) \
  18. SekRunM68k(m68k_cycles)
  19. #endif
  20. // sync m68k to Pico.t.m68c_aim
  21. static void SekExecM68k(int cyc_do)
  22. {
  23. Pico.t.m68c_cnt += cyc_do;
  24. #if defined(EMU_C68K)
  25. PicoCpuCM68k.cycles = cyc_do;
  26. CycloneRun(&PicoCpuCM68k);
  27. Pico.t.m68c_cnt -= PicoCpuCM68k.cycles;
  28. #elif defined(EMU_M68K)
  29. Pico.t.m68c_cnt += m68k_execute(cyc_do) - cyc_do;
  30. #elif defined(EMU_F68K)
  31. Pico.t.m68c_cnt += fm68k_emulate(&PicoCpuFM68k, cyc_do, 0) - cyc_do;
  32. #endif
  33. SekCyclesLeft = 0;
  34. }
  35. static void SekSyncM68k(void)
  36. {
  37. int cyc_do;
  38. pprof_start(m68k);
  39. pevt_log_m68k_o(EVT_RUN_START);
  40. while ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0)
  41. SekExecM68k(cyc_do);
  42. SekTrace(0);
  43. pevt_log_m68k_o(EVT_RUN_END);
  44. pprof_end(m68k);
  45. }
  46. static __inline void SekRunM68k(int cyc)
  47. {
  48. Pico.t.m68c_aim += cyc;
  49. Pico.t.m68c_cnt += cyc >> 6; // refresh slowdowns
  50. cyc = Pico.t.m68c_aim - Pico.t.m68c_cnt;
  51. if (cyc <= 0)
  52. return;
  53. SekSyncM68k();
  54. }
  55. static void do_hint(struct PicoVideo *pv)
  56. {
  57. pv->pending_ints |= 0x10;
  58. if (pv->reg[0] & 0x10) {
  59. elprintf(EL_INTS, "hint: @ %06x [%u]", SekPc, SekCyclesDone());
  60. if (SekIrqLevel < 4)
  61. SekInterrupt(4);
  62. }
  63. }
  64. static void do_timing_hacks_end(struct PicoVideo *pv)
  65. {
  66. PicoVideoFIFOSync(488);
  67. }
  68. static void do_timing_hacks_start(struct PicoVideo *pv)
  69. {
  70. SekCyclesBurn(PicoVideoFIFOHint()); // prolong cpu HOLD if necessary
  71. }
  72. static int PicoFrameHints(void)
  73. {
  74. struct PicoVideo *pv = &Pico.video;
  75. int lines, y, lines_vis, skip;
  76. int vcnt_wrap, vcnt_adj;
  77. unsigned int cycles;
  78. int hint; // Hint counter
  79. pevt_log_m68k_o(EVT_FRAME_START);
  80. if ((PicoIn.opt&POPT_ALT_RENDERER) && !PicoIn.skipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
  81. // draw a frame just after vblank in alternative render mode
  82. // yes, this will cause 1 frame lag, but this is inaccurate mode anyway.
  83. PicoFrameFull();
  84. #ifdef DRAW_FINISH_FUNC
  85. DRAW_FINISH_FUNC();
  86. #endif
  87. skip = 1;
  88. }
  89. else skip=PicoIn.skipFrame;
  90. Pico.t.m68c_frame_start = Pico.t.m68c_aim;
  91. pv->v_counter = Pico.m.scanline = 0;
  92. z80_resetCycles();
  93. PsndStartFrame();
  94. hint = pv->hint_cnt;
  95. pv->status |= PVS_ACTIVE;
  96. for (y = 0; ; y++)
  97. {
  98. pv->v_counter = Pico.m.scanline = y;
  99. if ((pv->reg[12]&6) == 6) { // interlace mode 2
  100. pv->v_counter <<= 1;
  101. pv->v_counter |= pv->v_counter >> 8;
  102. pv->v_counter &= 0xff;
  103. }
  104. if ((y == 224 && !(pv->reg[1] & 8)) || y == 240)
  105. break;
  106. PAD_DELAY();
  107. // H-Interrupts:
  108. if (--hint < 0)
  109. {
  110. hint = pv->reg[10]; // Reload H-Int counter
  111. do_hint(pv);
  112. }
  113. // decide if we draw this line
  114. if (!skip && (PicoIn.opt & POPT_ALT_RENDERER))
  115. {
  116. // find the right moment for frame renderer, when display is no longer blanked
  117. if ((pv->reg[1]&0x40) || y > 100) {
  118. PicoFrameFull();
  119. #ifdef DRAW_FINISH_FUNC
  120. DRAW_FINISH_FUNC();
  121. #endif
  122. skip = 1;
  123. }
  124. }
  125. // Run scanline:
  126. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  127. do_timing_hacks_start(pv);
  128. CPUS_RUN(CYCLES_M68K_LINE);
  129. do_timing_hacks_end(pv);
  130. if (PicoLineHook) PicoLineHook();
  131. pevt_log_m68k_o(EVT_NEXT_LINE);
  132. }
  133. lines_vis = (pv->reg[1] & 8) ? 240 : 224;
  134. if (y == lines_vis)
  135. pv->status &= ~PVS_ACTIVE;
  136. if (!skip)
  137. {
  138. if (Pico.est.DrawScanline < y)
  139. PicoDrawSync(y - 1, 0);
  140. #ifdef DRAW_FINISH_FUNC
  141. DRAW_FINISH_FUNC();
  142. #endif
  143. }
  144. memcpy(PicoIn.padInt, PicoIn.pad, sizeof(PicoIn.padInt));
  145. PAD_DELAY();
  146. // Last H-Int (normally):
  147. if (--hint < 0)
  148. {
  149. hint = pv->reg[10]; // Reload H-Int counter
  150. do_hint(pv);
  151. }
  152. pv->status |= SR_VB | PVS_VB2; // go into vblank
  153. // the following SekRun is there for several reasons:
  154. // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
  155. // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
  156. // also delay between last H-int and V-int (Golden Axe 3)
  157. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  158. PicoVideoFIFOMode(pv->reg[1]&0x40, pv->reg[12]&1);
  159. do_timing_hacks_start(pv);
  160. CPUS_RUN(CYCLES_M68K_VINT_LAG);
  161. pv->status |= SR_F;
  162. pv->pending_ints |= 0x20;
  163. if (pv->reg[1] & 0x20) {
  164. if (Pico.t.m68c_cnt - Pico.t.m68c_aim < 60) // CPU blocked?
  165. SekExecM68k(11); // HACK
  166. elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
  167. SekInterrupt(6);
  168. }
  169. cycles = Pico.t.m68c_aim;
  170. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
  171. PicoSyncZ80(cycles);
  172. elprintf(EL_INTS, "zint");
  173. z80_int();
  174. }
  175. #ifdef PICO_CD
  176. if (PicoIn.AHW & PAHW_MCD)
  177. pcd_sync_s68k(cycles, 0);
  178. #endif
  179. #ifdef PICO_32X
  180. p32x_sync_sh2s(cycles);
  181. p32x_start_blank();
  182. #endif
  183. // Run scanline:
  184. CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
  185. do_timing_hacks_end(pv);
  186. if (PicoLineHook) PicoLineHook();
  187. pevt_log_m68k_o(EVT_NEXT_LINE);
  188. if (Pico.m.pal) {
  189. lines = 313;
  190. vcnt_wrap = 0x103;
  191. vcnt_adj = 57;
  192. }
  193. else {
  194. lines = 262;
  195. vcnt_wrap = 0xEB;
  196. vcnt_adj = 6;
  197. }
  198. for (y++; y < lines - 1; y++)
  199. {
  200. pv->v_counter = Pico.m.scanline = y;
  201. if (y >= vcnt_wrap)
  202. pv->v_counter -= vcnt_adj;
  203. if ((pv->reg[12]&6) == 6)
  204. pv->v_counter = (pv->v_counter << 1) | 1;
  205. pv->v_counter &= 0xff;
  206. PAD_DELAY();
  207. if (unlikely(pv->status & PVS_ACTIVE) && --hint < 0)
  208. {
  209. hint = pv->reg[10]; // Reload H-Int counter
  210. do_hint(pv);
  211. }
  212. // Run scanline:
  213. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  214. do_timing_hacks_start(pv);
  215. CPUS_RUN(CYCLES_M68K_LINE);
  216. do_timing_hacks_end(pv);
  217. if (PicoLineHook) PicoLineHook();
  218. pevt_log_m68k_o(EVT_NEXT_LINE);
  219. }
  220. if (unlikely(PicoIn.overclockM68k)) {
  221. unsigned int l = PicoIn.overclockM68k * lines / 100;
  222. while (l-- > 0) {
  223. Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
  224. do_timing_hacks_start(pv);
  225. SekSyncM68k();
  226. do_timing_hacks_end(pv);
  227. }
  228. }
  229. pv->status &= ~(SR_VB | PVS_VB2);
  230. pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
  231. // last scanline
  232. Pico.m.scanline = y++;
  233. pv->v_counter = 0xff;
  234. PAD_DELAY();
  235. if (unlikely(pv->status & PVS_ACTIVE)) {
  236. if (--hint < 0) {
  237. hint = pv->reg[10]; // Reload H-Int counter
  238. do_hint(pv);
  239. }
  240. }
  241. else
  242. hint = pv->reg[10];
  243. // Run scanline:
  244. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  245. PicoVideoFIFOMode(pv->reg[1]&0x40, pv->reg[12]&1);
  246. do_timing_hacks_start(pv);
  247. CPUS_RUN(CYCLES_M68K_LINE);
  248. do_timing_hacks_end(pv);
  249. if (PicoLineHook) PicoLineHook();
  250. pevt_log_m68k_o(EVT_NEXT_LINE);
  251. // sync cpus
  252. cycles = Pico.t.m68c_aim;
  253. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
  254. PicoSyncZ80(cycles);
  255. #ifdef PICO_CD
  256. if (PicoIn.AHW & PAHW_MCD)
  257. pcd_sync_s68k(cycles, 0);
  258. #endif
  259. #ifdef PICO_32X
  260. p32x_sync_sh2s(cycles);
  261. #endif
  262. // get samples from sound chips
  263. if (PicoIn.sndOut)
  264. PsndGetSamples(y);
  265. timers_cycle();
  266. pv->hint_cnt = hint;
  267. return 0;
  268. }
  269. #undef PAD_DELAY
  270. #undef CPUS_RUN
  271. // vim:shiftwidth=2:ts=2:expandtab