pico_cmn.c 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340
  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(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 = Pico.t.m68c_aim;
  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 = Pico.t.m68c_aim;
  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 | PVS_VB2; // go into vblank
  176. // the following SekRun is there for several reasons:
  177. // there must be a delay after vblank bit is set and irq is asserted (Mazin Saga)
  178. // also delay between F bit (bit 7) is set in SR and IRQ happens (Ex-Mutants)
  179. // also delay between last H-int and V-int (Golden Axe 3)
  180. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  181. do_timing_hacks_vb();
  182. CPUS_RUN(CYCLES_M68K_VINT_LAG);
  183. pv->status |= SR_F;
  184. pv->pending_ints |= 0x20;
  185. if (pv->reg[1] & 0x20) {
  186. Pico.t.m68c_aim = Pico.t.m68c_cnt + 11; // HACK
  187. SekSyncM68k();
  188. elprintf(EL_INTS, "vint: @ %06x [%u]", SekPc, SekCyclesDone());
  189. SekInterrupt(6);
  190. }
  191. cycles = SekCyclesDone();
  192. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80)) {
  193. PicoSyncZ80(cycles);
  194. elprintf(EL_INTS, "zint");
  195. z80_int();
  196. }
  197. #ifdef PICO_CD
  198. if (PicoAHW & PAHW_MCD)
  199. pcd_sync_s68k(cycles, 0);
  200. #endif
  201. #ifdef PICO_32X
  202. p32x_sync_sh2s(cycles);
  203. p32x_start_blank();
  204. #endif
  205. // get samples from sound chips
  206. if (y == 224 && PsndOut)
  207. PsndGetSamples(y);
  208. // Run scanline:
  209. CPUS_RUN(CYCLES_M68K_LINE - CYCLES_M68K_VINT_LAG);
  210. if (PicoLineHook) PicoLineHook();
  211. pevt_log_m68k_o(EVT_NEXT_LINE);
  212. if (Pico.m.pal) {
  213. lines = 313;
  214. vcnt_wrap = 0x103;
  215. vcnt_adj = 57;
  216. }
  217. else {
  218. lines = 262;
  219. vcnt_wrap = 0xEB;
  220. vcnt_adj = 6;
  221. }
  222. for (y++; y < lines - 1; y++)
  223. {
  224. pv->v_counter = Pico.m.scanline = y;
  225. if (y >= vcnt_wrap)
  226. pv->v_counter -= vcnt_adj;
  227. if ((pv->reg[12]&6) == 6)
  228. pv->v_counter = (pv->v_counter << 1) | 1;
  229. pv->v_counter &= 0xff;
  230. PAD_DELAY();
  231. if ((pv->status & PVS_ACTIVE) && --hint < 0)
  232. {
  233. hint = pv->reg[10]; // Reload H-Int counter
  234. do_hint(pv);
  235. }
  236. // Run scanline:
  237. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  238. do_timing_hacks_vb();
  239. CPUS_RUN(CYCLES_M68K_LINE);
  240. if (PicoLineHook) PicoLineHook();
  241. pevt_log_m68k_o(EVT_NEXT_LINE);
  242. }
  243. pv->status &= ~(SR_VB | PVS_VB2);
  244. pv->status |= ((pv->reg[1] >> 3) ^ SR_VB) & SR_VB; // forced blanking
  245. // last scanline
  246. Pico.m.scanline = y;
  247. pv->v_counter = 0xff;
  248. pv->lwrite_cnt = 0;
  249. PAD_DELAY();
  250. if ((pv->status & PVS_ACTIVE) && --hint < 0)
  251. {
  252. hint = pv->reg[10]; // Reload H-Int counter
  253. do_hint(pv);
  254. }
  255. // Run scanline:
  256. Pico.t.m68c_line_start = Pico.t.m68c_aim;
  257. do_timing_hacks_as(pv, vdp_slots);
  258. CPUS_RUN(CYCLES_M68K_LINE);
  259. if (PicoLineHook) PicoLineHook();
  260. pevt_log_m68k_o(EVT_NEXT_LINE);
  261. // sync cpus
  262. cycles = SekCyclesDone();
  263. if (Pico.m.z80Run && !Pico.m.z80_reset && (PicoOpt&POPT_EN_Z80))
  264. PicoSyncZ80(cycles);
  265. if (PsndOut && ym2612.dacen && PsndDacLine < lines)
  266. PsndDoDAC(lines - 1);
  267. if (PsndOut && PsndPsgLine < lines)
  268. PsndDoPSG(lines - 1);
  269. #ifdef PICO_CD
  270. if (PicoAHW & PAHW_MCD)
  271. pcd_sync_s68k(cycles, 0);
  272. #endif
  273. #ifdef PICO_32X
  274. p32x_sync_sh2s(cycles);
  275. #endif
  276. timers_cycle();
  277. pv->hint_cnt = hint;
  278. return 0;
  279. }
  280. #undef PAD_DELAY
  281. #undef CPUS_RUN
  282. // vim:shiftwidth=2:ts=2:expandtab