pico_cmn.c 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350
  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 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(&PicoCpuFM68k, 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 (unlikely(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 ((PicoIn.opt&POPT_ALT_RENDERER) && !PicoIn.skipFrame && (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=PicoIn.skipFrame;
  95. Pico.t.m68c_frame_start = Pico.t.m68c_aim;
  96. pv->v_counter = Pico.m.scanline = 0;
  97. z80_resetCycles();
  98. PsndStartFrame();
  99. hint = pv->hint_cnt;
  100. pv->status |= PVS_ACTIVE;
  101. for (y = 0; ; y++)
  102. {
  103. pv->v_counter = Pico.m.scanline = y;
  104. if ((pv->reg[12]&6) == 6) { // interlace mode 2
  105. pv->v_counter <<= 1;
  106. pv->v_counter |= pv->v_counter >> 8;
  107. pv->v_counter &= 0xff;
  108. }
  109. if ((y == 224 && !(pv->reg[1] & 8)) || y == 240)
  110. break;
  111. PAD_DELAY();
  112. // H-Interrupts:
  113. if (--hint < 0)
  114. {
  115. hint = pv->reg[10]; // Reload H-Int counter
  116. do_hint(pv);
  117. }
  118. // decide if we draw this line
  119. if (!skip && (PicoIn.opt & POPT_ALT_RENDERER))
  120. {
  121. // find the right moment for frame renderer, when display is no longer blanked
  122. if ((pv->reg[1]&0x40) || y > 100) {
  123. PicoFrameFull();
  124. #ifdef DRAW_FINISH_FUNC
  125. DRAW_FINISH_FUNC();
  126. #endif
  127. skip = 1;
  128. }
  129. }
  130. // get samples from sound chips
  131. if ((y == 224 || y == line_sample) && PicoIn.sndOut)
  132. {
  133. cycles = SekCyclesDone();
  134. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
  135. PicoSyncZ80(cycles);
  136. #ifdef PICO_CD
  137. if (PicoIn.AHW & PAHW_MCD)
  138. pcd_sync_s68k(cycles, 0);
  139. #endif
  140. #ifdef PICO_32X
  141. p32x_sync_sh2s(cycles);
  142. #endif
  143. PsndGetSamples(y);
  144. }
  145. // Run scanline:
  146. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  147. do_timing_hacks_as(pv, vdp_slots);
  148. CPUS_RUN(CYCLES_M68K_LINE);
  149. if (PicoLineHook) PicoLineHook();
  150. pevt_log_m68k_o(EVT_NEXT_LINE);
  151. }
  152. lines_vis = (pv->reg[1] & 8) ? 240 : 224;
  153. if (y == lines_vis)
  154. pv->status &= ~PVS_ACTIVE;
  155. if (!skip)
  156. {
  157. if (Pico.est.DrawScanline < y)
  158. PicoDrawSync(y - 1, 0);
  159. #ifdef DRAW_FINISH_FUNC
  160. DRAW_FINISH_FUNC();
  161. #endif
  162. }
  163. // VDP FIFO
  164. pv->lwrite_cnt = 0;
  165. Pico.video.status |= SR_EMPT;
  166. memcpy(PicoIn.padInt, PicoIn.pad, sizeof(PicoIn.padInt));
  167. PAD_DELAY();
  168. // Last H-Int (normally):
  169. if (--hint < 0)
  170. {
  171. hint = pv->reg[10]; // Reload H-Int counter
  172. do_hint(pv);
  173. }
  174. pv->status |= SR_VB | PVS_VB2; // go into vblank
  175. // the following SekRun is there for several reasons:
  176. // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
  177. // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
  178. // also delay between last H-int and V-int (Golden Axe 3)
  179. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  180. do_timing_hacks_vb();
  181. CPUS_RUN(CYCLES_M68K_VINT_LAG);
  182. pv->status |= SR_F;
  183. pv->pending_ints |= 0x20;
  184. if (pv->reg[1] & 0x20) {
  185. Pico.t.m68c_aim = Pico.t.m68c_cnt + 11; // HACK
  186. SekSyncM68k();
  187. elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
  188. SekInterrupt(6);
  189. }
  190. cycles = SekCyclesDone();
  191. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80)) {
  192. PicoSyncZ80(cycles);
  193. elprintf(EL_INTS, "zint");
  194. z80_int();
  195. }
  196. #ifdef PICO_CD
  197. if (PicoIn.AHW & PAHW_MCD)
  198. pcd_sync_s68k(cycles, 0);
  199. #endif
  200. #ifdef PICO_32X
  201. p32x_sync_sh2s(cycles);
  202. p32x_start_blank();
  203. #endif
  204. // get samples from sound chips
  205. if (y == 224 && PicoIn.sndOut)
  206. PsndGetSamples(y);
  207. // Run scanline:
  208. CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
  209. if (PicoLineHook) PicoLineHook();
  210. pevt_log_m68k_o(EVT_NEXT_LINE);
  211. if (Pico.m.pal) {
  212. lines = 313;
  213. vcnt_wrap = 0x103;
  214. vcnt_adj = 57;
  215. }
  216. else {
  217. lines = 262;
  218. vcnt_wrap = 0xEB;
  219. vcnt_adj = 6;
  220. }
  221. for (y++; y < lines - 1; y++)
  222. {
  223. pv->v_counter = Pico.m.scanline = y;
  224. if (y >= vcnt_wrap)
  225. pv->v_counter -= vcnt_adj;
  226. if ((pv->reg[12]&6) == 6)
  227. pv->v_counter = (pv->v_counter << 1) | 1;
  228. pv->v_counter &= 0xff;
  229. PAD_DELAY();
  230. if (unlikely(pv->status & PVS_ACTIVE) && --hint < 0)
  231. {
  232. hint = pv->reg[10]; // Reload H-Int counter
  233. do_hint(pv);
  234. }
  235. // Run scanline:
  236. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  237. do_timing_hacks_vb();
  238. CPUS_RUN(CYCLES_M68K_LINE);
  239. if (PicoLineHook) PicoLineHook();
  240. pevt_log_m68k_o(EVT_NEXT_LINE);
  241. }
  242. if (unlikely(PicoIn.overclockM68k)) {
  243. unsigned int l = PicoIn.overclockM68k * lines / 100;
  244. while (l-- > 0) {
  245. Pico.t.m68c_cnt -= CYCLES_M68K_LINE;
  246. do_timing_hacks_vb();
  247. SekSyncM68k();
  248. }
  249. }
  250. pv->status &= ~(SR_VB | PVS_VB2);
  251. pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
  252. // last scanline
  253. Pico.m.scanline = y;
  254. pv->v_counter = 0xff;
  255. pv->lwrite_cnt = 0;
  256. PAD_DELAY();
  257. if (unlikely(pv->status & PVS_ACTIVE)) {
  258. if (--hint < 0) {
  259. hint = pv->reg[10]; // Reload H-Int counter
  260. do_hint(pv);
  261. }
  262. }
  263. else
  264. hint = pv->reg[10];
  265. // Run scanline:
  266. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  267. do_timing_hacks_as(pv, vdp_slots);
  268. CPUS_RUN(CYCLES_M68K_LINE);
  269. if (PicoLineHook) PicoLineHook();
  270. pevt_log_m68k_o(EVT_NEXT_LINE);
  271. // sync cpus
  272. cycles = SekCyclesDone();
  273. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoIn.opt&POPT_EN_Z80))
  274. PicoSyncZ80(cycles);
  275. if (PicoIn.sndOut && ym2612.dacen && Pico.snd.dac_line < lines)
  276. PsndDoDAC(lines - 1);
  277. if (PicoIn.sndOut && Pico.snd.psg_line < lines)
  278. PsndDoPSG(lines - 1);
  279. #ifdef PICO_CD
  280. if (PicoIn.AHW & PAHW_MCD)
  281. pcd_sync_s68k(cycles, 0);
  282. #endif
  283. #ifdef PICO_32X
  284. p32x_sync_sh2s(cycles);
  285. #endif
  286. timers_cycle();
  287. pv->hint_cnt = hint;
  288. return 0;
  289. }
  290. #undef PAD_DELAY
  291. #undef CPUS_RUN
  292. // vim:shiftwidth=2:ts=2:expandtab