pico_cmn.c 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326
  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. SekInterrupt(4);
  61. }
  62. }
  63. static void do_timing_hacks_end(struct PicoVideo *pv)
  64. {
  65. PicoVideoFIFOSync(488);
  66. }
  67. static void do_timing_hacks_start(struct PicoVideo *pv)
  68. {
  69. SekCyclesBurn(PicoVideoFIFOHint()); // prolong cpu HOLD if necessary
  70. }
  71. static int PicoFrameHints(void)
  72. {
  73. struct PicoVideo *pv = &Pico.video;
  74. int lines, y, lines_vis, skip;
  75. int vcnt_wrap, vcnt_adj;
  76. unsigned int cycles;
  77. int hint; // Hint counter
  78. pevt_log_m68k_o(EVT_FRAME_START);
  79. if ((PicoIn.opt&POPT_ALT_RENDERER) && !PicoIn.skipFrame && (pv->reg[1]&0x40)) { // fast rend., display enabled
  80. // draw a frame just after vblank in alternative render mode
  81. // yes, this will cause 1 frame lag, but this is inaccurate mode anyway.
  82. PicoFrameFull();
  83. #ifdef DRAW_FINISH_FUNC
  84. DRAW_FINISH_FUNC();
  85. #endif
  86. skip = 1;
  87. }
  88. else skip=PicoIn.skipFrame;
  89. Pico.t.m68c_frame_start = Pico.t.m68c_aim;
  90. pv->v_counter = Pico.m.scanline = 0;
  91. z80_resetCycles();
  92. PsndStartFrame();
  93. hint = pv->hint_cnt;
  94. pv->status |= PVS_ACTIVE;
  95. for (y = 0; ; y++)
  96. {
  97. pv->v_counter = Pico.m.scanline = y;
  98. if ((pv->reg[12]&6) == 6) { // interlace mode 2
  99. pv->v_counter <<= 1;
  100. pv->v_counter |= pv->v_counter >> 8;
  101. pv->v_counter &= 0xff;
  102. }
  103. if ((y == 224 && !(pv->reg[1] & 8)) || y == 240)
  104. break;
  105. PAD_DELAY();
  106. // H-Interrupts:
  107. if (--hint < 0)
  108. {
  109. hint = pv->reg[10]; // Reload H-Int counter
  110. do_hint(pv);
  111. }
  112. // decide if we draw this line
  113. if (!skip && (PicoIn.opt & POPT_ALT_RENDERER))
  114. {
  115. // find the right moment for frame renderer, when display is no longer blanked
  116. if ((pv->reg[1]&0x40) || y > 100) {
  117. PicoFrameFull();
  118. #ifdef DRAW_FINISH_FUNC
  119. DRAW_FINISH_FUNC();
  120. #endif
  121. skip = 1;
  122. }
  123. }
  124. // Run scanline:
  125. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  126. do_timing_hacks_start(pv);
  127. CPUS_RUN(CYCLES_M68K_LINE);
  128. do_timing_hacks_end(pv);
  129. if (PicoLineHook) PicoLineHook();
  130. pevt_log_m68k_o(EVT_NEXT_LINE);
  131. }
  132. lines_vis = (pv->reg[1] & 8) ? 240 : 224;
  133. if (y == lines_vis)
  134. pv->status &= ~PVS_ACTIVE;
  135. if (!skip)
  136. {
  137. if (Pico.est.DrawScanline < y)
  138. PicoDrawSync(y - 1, 0);
  139. #ifdef DRAW_FINISH_FUNC
  140. DRAW_FINISH_FUNC();
  141. #endif
  142. }
  143. memcpy(PicoIn.padInt, PicoIn.pad, sizeof(PicoIn.padInt));
  144. PAD_DELAY();
  145. // Last H-Int (normally):
  146. if (--hint < 0)
  147. {
  148. hint = pv->reg[10]; // Reload H-Int counter
  149. do_hint(pv);
  150. }
  151. pv->status |= SR_VB | PVS_VB2; // go into vblank
  152. // the following SekRun is there for several reasons:
  153. // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
  154. // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
  155. // also delay between last H-int and V-int (Golden Axe 3)
  156. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  157. PicoVideoFIFOMode(pv->reg[1]&0x40, pv->reg[12]&1);
  158. do_timing_hacks_start(pv);
  159. CPUS_RUN(CYCLES_M68K_VINT_LAG);
  160. pv->status |= SR_F;
  161. pv->pending_ints |= 0x20;
  162. if (pv->reg[1] & 0x20) {
  163. if (Pico.t.m68c_cnt - Pico.t.m68c_aim < 60) // CPU blocked?
  164. SekExecM68k(11); // HACK
  165. elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
  166. SekInterrupt(6);
  167. }
  168. cycles = Pico.t.m68c_aim;
  169. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
  170. PicoSyncZ80(cycles);
  171. elprintf(EL_INTS, "zint");
  172. z80_int();
  173. }
  174. #ifdef PICO_CD
  175. if (PicoIn.AHW & PAHW_MCD)
  176. pcd_sync_s68k(cycles, 0);
  177. #endif
  178. #ifdef PICO_32X
  179. p32x_sync_sh2s(cycles);
  180. p32x_start_blank();
  181. #endif
  182. // Run scanline:
  183. CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
  184. do_timing_hacks_end(pv);
  185. if (PicoLineHook) PicoLineHook();
  186. pevt_log_m68k_o(EVT_NEXT_LINE);
  187. if (Pico.m.pal) {
  188. lines = 313;
  189. vcnt_wrap = 0x103;
  190. vcnt_adj = 57;
  191. }
  192. else {
  193. lines = 262;
  194. vcnt_wrap = 0xEB;
  195. vcnt_adj = 6;
  196. }
  197. for (y++; y < lines - 1; y++)
  198. {
  199. pv->v_counter = Pico.m.scanline = y;
  200. if (y >= vcnt_wrap)
  201. pv->v_counter -= vcnt_adj;
  202. if ((pv->reg[12]&6) == 6)
  203. pv->v_counter = (pv->v_counter << 1) | 1;
  204. pv->v_counter &= 0xff;
  205. PAD_DELAY();
  206. if (unlikely(pv->status & PVS_ACTIVE) && --hint < 0)
  207. {
  208. hint = pv->reg[10]; // Reload H-Int counter
  209. do_hint(pv);
  210. }
  211. // Run scanline:
  212. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  213. do_timing_hacks_start(pv);
  214. CPUS_RUN(CYCLES_M68K_LINE);
  215. do_timing_hacks_end(pv);
  216. if (PicoLineHook) PicoLineHook();
  217. pevt_log_m68k_o(EVT_NEXT_LINE);
  218. }
  219. if (unlikely(PicoIn.overclockM68k)) {
  220. unsigned int l = PicoIn.overclockM68k * lines / 100;
  221. while (l-- > 0) {
  222. Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
  223. do_timing_hacks_start(pv);
  224. SekSyncM68k();
  225. do_timing_hacks_end(pv);
  226. }
  227. }
  228. pv->status &= ~(SR_VB | PVS_VB2);
  229. pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
  230. // last scanline
  231. Pico.m.scanline = y++;
  232. pv->v_counter = 0xff;
  233. PAD_DELAY();
  234. if (unlikely(pv->status & PVS_ACTIVE)) {
  235. if (--hint < 0) {
  236. hint = pv->reg[10]; // Reload H-Int counter
  237. do_hint(pv);
  238. }
  239. }
  240. else
  241. hint = pv->reg[10];
  242. // Run scanline:
  243. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  244. PicoVideoFIFOMode(pv->reg[1]&0x40, pv->reg[12]&1);
  245. do_timing_hacks_start(pv);
  246. CPUS_RUN(CYCLES_M68K_LINE);
  247. do_timing_hacks_end(pv);
  248. if (PicoLineHook) PicoLineHook();
  249. pevt_log_m68k_o(EVT_NEXT_LINE);
  250. // sync cpus
  251. cycles = Pico.t.m68c_aim;
  252. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
  253. PicoSyncZ80(cycles);
  254. #ifdef PICO_CD
  255. if (PicoIn.AHW & PAHW_MCD)
  256. pcd_sync_s68k(cycles, 0);
  257. #endif
  258. #ifdef PICO_32X
  259. p32x_sync_sh2s(cycles);
  260. #endif
  261. // get samples from sound chips
  262. if (PicoIn.sndOut)
  263. PsndGetSamples(y);
  264. timers_cycle();
  265. pv->hint_cnt = hint;
  266. return 0;
  267. }
  268. #undef PAD_DELAY
  269. #undef CPUS_RUN
  270. // vim:shiftwidth=2:ts=2:expandtab