pico_cmn.c 7.5 KB

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