mcd.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440
  1. /*
  2. * PicoDrive
  3. * (C) notaz, 2007,2013
  4. *
  5. * This work is licensed under the terms of MAME license.
  6. * See COPYING file in the top-level directory.
  7. */
  8. #include "../pico_int.h"
  9. #include "../sound/ym2612.h"
  10. extern unsigned char formatted_bram[4*0x10];
  11. static unsigned int mcd_m68k_cycle_mult;
  12. static unsigned int mcd_s68k_cycle_mult;
  13. static unsigned int mcd_m68k_cycle_base;
  14. static unsigned int mcd_s68k_cycle_base;
  15. PICO_INTERNAL void PicoInitMCD(void)
  16. {
  17. SekInitS68k();
  18. }
  19. PICO_INTERNAL void PicoExitMCD(void)
  20. {
  21. cdd_unload();
  22. }
  23. PICO_INTERNAL void PicoPowerMCD(void)
  24. {
  25. int fmt_size;
  26. SekCycleCntS68k = SekCycleAimS68k = 0;
  27. fmt_size = sizeof(formatted_bram);
  28. memset(Pico_mcd->prg_ram, 0, sizeof(Pico_mcd->prg_ram));
  29. memset(Pico_mcd->word_ram2M, 0, sizeof(Pico_mcd->word_ram2M));
  30. memset(Pico_mcd->pcm_ram, 0, sizeof(Pico_mcd->pcm_ram));
  31. memset(Pico_mcd->bram, 0, sizeof(Pico_mcd->bram));
  32. memcpy(Pico_mcd->bram + sizeof(Pico_mcd->bram) - fmt_size,
  33. formatted_bram, fmt_size);
  34. memset(Pico_mcd->s68k_regs, 0, sizeof(Pico_mcd->s68k_regs));
  35. memset(&Pico_mcd->pcm, 0, sizeof(Pico_mcd->pcm));
  36. memset(&Pico_mcd->m, 0, sizeof(Pico_mcd->m));
  37. cdc_init();
  38. gfx_init();
  39. // cold reset state (tested)
  40. Pico_mcd->m.state_flags = PCD_ST_S68K_RST;
  41. Pico_mcd->m.busreq = 2; // busreq on, s68k in reset
  42. Pico_mcd->s68k_regs[3] = 1; // 2M word RAM mode, m68k access
  43. memset(Pico_mcd->bios + 0x70, 0xff, 4);
  44. }
  45. void pcd_soft_reset(void)
  46. {
  47. elprintf(EL_CD, "cd: soft reset");
  48. Pico_mcd->m.s68k_pend_ints = 0;
  49. cdc_reset();
  50. cdd_reset();
  51. #ifdef _ASM_CD_MEMORY_C
  52. //PicoMemResetCDdecode(1); // don't have to call this in 2M mode
  53. #endif
  54. memset(&Pico_mcd->s68k_regs[0x38], 0, 9);
  55. Pico_mcd->s68k_regs[0x38+9] = 0x0f; // default checksum
  56. pcd_event_schedule_s68k(PCD_EVENT_CDC, 12500000/75);
  57. // TODO: test if register state/timers change
  58. }
  59. PICO_INTERNAL int PicoResetMCD(void)
  60. {
  61. // reset button doesn't affect MCD hardware
  62. // use Pico.sv.data for RAM cart
  63. if (PicoIn.opt & POPT_EN_MCD_RAMCART) {
  64. if (Pico.sv.data == NULL)
  65. Pico.sv.data = calloc(1, 0x12000);
  66. }
  67. else if (Pico.sv.data != NULL) {
  68. free(Pico.sv.data);
  69. Pico.sv.data = NULL;
  70. }
  71. Pico.sv.start = Pico.sv.end = 0; // unused
  72. return 0;
  73. }
  74. static void SekRunM68kOnce(void)
  75. {
  76. int cyc_do;
  77. pevt_log_m68k_o(EVT_RUN_START);
  78. if ((cyc_do = Pico.t.m68c_aim - Pico.t.m68c_cnt) > 0) {
  79. Pico.t.m68c_cnt += cyc_do;
  80. #if defined(EMU_C68K)
  81. PicoCpuCM68k.cycles = cyc_do;
  82. CycloneRun(&PicoCpuCM68k);
  83. Pico.t.m68c_cnt -= PicoCpuCM68k.cycles;
  84. #elif defined(EMU_M68K)
  85. Pico.t.m68c_cnt += m68k_execute(cyc_do) - cyc_do;
  86. #elif defined(EMU_F68K)
  87. Pico.t.m68c_cnt += fm68k_emulate(&PicoCpuFM68k, cyc_do, 0) - cyc_do;
  88. #endif
  89. }
  90. SekCyclesLeft = 0;
  91. SekTrace(0);
  92. pevt_log_m68k_o(EVT_RUN_END);
  93. }
  94. static void SekRunS68k(unsigned int to)
  95. {
  96. int cyc_do;
  97. SekCycleAimS68k = to;
  98. if ((cyc_do = SekCycleAimS68k - SekCycleCntS68k) <= 0)
  99. return;
  100. pprof_start(s68k);
  101. SekCycleCntS68k += cyc_do;
  102. #if defined(EMU_C68K)
  103. PicoCpuCS68k.cycles = cyc_do;
  104. CycloneRun(&PicoCpuCS68k);
  105. SekCycleCntS68k -= PicoCpuCS68k.cycles;
  106. #elif defined(EMU_M68K)
  107. m68k_set_context(&PicoCpuMS68k);
  108. SekCycleCntS68k += m68k_execute(cyc_do) - cyc_do;
  109. m68k_set_context(&PicoCpuMM68k);
  110. #elif defined(EMU_F68K)
  111. SekCycleCntS68k += fm68k_emulate(&PicoCpuFS68k, cyc_do, 0) - cyc_do;
  112. #endif
  113. SekCyclesLeftS68k = 0;
  114. pprof_end(s68k);
  115. }
  116. static void pcd_set_cycle_mult(void)
  117. {
  118. unsigned int div;
  119. if (Pico.m.pal)
  120. div = 50*313*488;
  121. else
  122. div = 60*262*488;
  123. // ~1.63 for NTSC, ~1.645 for PAL; round to nearest, x/y+0.5 -> (x+y/2)/y
  124. mcd_m68k_cycle_mult = ((12500000ull << 16) + div/2) / div;
  125. mcd_s68k_cycle_mult = ((1ull*div << 16) + 6250000) / 12500000;
  126. }
  127. unsigned int pcd_cycles_m68k_to_s68k(unsigned int c)
  128. {
  129. return (long long)c * mcd_m68k_cycle_mult >> 16;
  130. }
  131. /* events */
  132. static void pcd_cdc_event(unsigned int now)
  133. {
  134. // 75Hz CDC update
  135. cdd_update();
  136. /* check if a new CDD command has been processed */
  137. if (!(Pico_mcd->s68k_regs[0x4b] & 0xf0))
  138. {
  139. /* reset CDD command wait flag */
  140. Pico_mcd->s68k_regs[0x4b] = 0xf0;
  141. if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN4) {
  142. elprintf(EL_INTS|EL_CD, "s68k: cdd irq 4");
  143. pcd_irq_s68k(4, 1);
  144. }
  145. }
  146. pcd_event_schedule(now, PCD_EVENT_CDC, 12500000/75);
  147. }
  148. static void pcd_int3_timer_event(unsigned int now)
  149. {
  150. if (Pico_mcd->s68k_regs[0x33] & PCDS_IEN3) {
  151. elprintf(EL_INTS|EL_CD, "s68k: timer irq 3");
  152. pcd_irq_s68k(3, 1);
  153. }
  154. if (Pico_mcd->s68k_regs[0x31] != 0)
  155. pcd_event_schedule(now, PCD_EVENT_TIMER3,
  156. Pico_mcd->s68k_regs[0x31] * 384);
  157. }
  158. static void pcd_dma_event(unsigned int now)
  159. {
  160. cdc_dma_update();
  161. }
  162. typedef void (event_cb)(unsigned int now);
  163. /* times are in s68k (12.5MHz) cycles */
  164. unsigned int pcd_event_times[PCD_EVENT_COUNT];
  165. static unsigned int event_time_next;
  166. static event_cb *pcd_event_cbs[PCD_EVENT_COUNT] = {
  167. pcd_cdc_event, // PCD_EVENT_CDC
  168. pcd_int3_timer_event, // PCD_EVENT_TIMER3
  169. gfx_update, // PCD_EVENT_GFX
  170. pcd_dma_event, // PCD_EVENT_DMA
  171. };
  172. void pcd_event_schedule(unsigned int now, enum pcd_event event, int after)
  173. {
  174. unsigned int when;
  175. when = now + after;
  176. if (when == 0) {
  177. // event cancelled
  178. pcd_event_times[event] = 0;
  179. return;
  180. }
  181. when |= 1;
  182. elprintf(EL_CD, "cd: new event #%u %u->%u", event, now, when);
  183. pcd_event_times[event] = when;
  184. if (event_time_next == 0 || CYCLES_GT(event_time_next, when))
  185. event_time_next = when;
  186. }
  187. void pcd_event_schedule_s68k(enum pcd_event event, int after)
  188. {
  189. if (SekCyclesLeftS68k > after)
  190. SekEndRunS68k(after);
  191. pcd_event_schedule(SekCyclesDoneS68k(), event, after);
  192. }
  193. static void pcd_run_events(unsigned int until)
  194. {
  195. int oldest, oldest_diff, time;
  196. int i, diff;
  197. while (1) {
  198. oldest = -1, oldest_diff = 0x7fffffff;
  199. for (i = 0; i < PCD_EVENT_COUNT; i++) {
  200. if (pcd_event_times[i]) {
  201. diff = pcd_event_times[i] - until;
  202. if (diff < oldest_diff) {
  203. oldest_diff = diff;
  204. oldest = i;
  205. }
  206. }
  207. }
  208. if (oldest_diff <= 0) {
  209. time = pcd_event_times[oldest];
  210. pcd_event_times[oldest] = 0;
  211. elprintf(EL_CD, "cd: run event #%d %u", oldest, time);
  212. pcd_event_cbs[oldest](time);
  213. }
  214. else if (oldest_diff < 0x7fffffff) {
  215. event_time_next = pcd_event_times[oldest];
  216. break;
  217. }
  218. else {
  219. event_time_next = 0;
  220. break;
  221. }
  222. }
  223. if (oldest != -1)
  224. elprintf(EL_CD, "cd: next event #%d at %u",
  225. oldest, event_time_next);
  226. }
  227. void pcd_irq_s68k(int irq, int state)
  228. {
  229. if (state) {
  230. SekInterruptS68k(irq);
  231. SekSetStopS68k(0);
  232. Pico_mcd->m.s68k_poll_a = 0;
  233. } else
  234. SekInterruptClearS68k(irq);
  235. }
  236. int pcd_sync_s68k(unsigned int m68k_target, int m68k_poll_sync)
  237. {
  238. #define now SekCycleCntS68k
  239. unsigned int s68k_target;
  240. unsigned int target;
  241. target = m68k_target - mcd_m68k_cycle_base;
  242. s68k_target = mcd_s68k_cycle_base +
  243. ((unsigned long long)target * mcd_m68k_cycle_mult >> 16);
  244. elprintf(EL_CD, "s68k sync to %u, %u->%u",
  245. m68k_target, now, s68k_target);
  246. if (Pico_mcd->m.busreq != 1) { /* busreq/reset */
  247. SekCycleCntS68k = SekCycleAimS68k = s68k_target;
  248. pcd_run_events(s68k_target);
  249. return 0;
  250. }
  251. while (CYCLES_GT(s68k_target, now)) {
  252. if (event_time_next && CYCLES_GE(now, event_time_next))
  253. pcd_run_events(now);
  254. target = s68k_target;
  255. if (event_time_next && CYCLES_GT(target, event_time_next))
  256. target = event_time_next;
  257. if (SekIsStoppedS68k())
  258. SekCycleCntS68k = SekCycleAimS68k = target;
  259. else
  260. SekRunS68k(target);
  261. if (m68k_poll_sync && Pico_mcd->m.m68k_poll_cnt == 0)
  262. break;
  263. }
  264. return s68k_target - now;
  265. #undef now
  266. }
  267. #define pcd_run_cpus_normal pcd_run_cpus
  268. //#define pcd_run_cpus_lockstep pcd_run_cpus
  269. static void SekSyncM68k(void);
  270. void pcd_run_cpus_normal(int m68k_cycles)
  271. {
  272. Pico.t.m68c_aim += m68k_cycles;
  273. while (CYCLES_GT(Pico.t.m68c_aim, Pico.t.m68c_cnt)) {
  274. if (SekShouldInterrupt())
  275. Pico_mcd->m.m68k_poll_cnt = 0;
  276. #ifdef USE_POLL_DETECT
  277. if (Pico_mcd->m.m68k_poll_cnt >= 16) {
  278. // main CPU is polling, (wake and) run sub only
  279. SekSetStopS68k(0);
  280. pcd_sync_s68k(Pico.t.m68c_aim, 1);
  281. Pico.t.m68c_cnt = Pico.t.m68c_aim;
  282. if (SekIsStoppedS68k()) {
  283. // slave has stopped, wake master to avoid lockups
  284. Pico_mcd->m.m68k_poll_cnt = 0;
  285. }
  286. elprintf(EL_CDPOLL, "m68k poll [%02x] x%d @%06x",
  287. Pico_mcd->m.m68k_poll_a, Pico_mcd->m.m68k_poll_cnt, SekPc);
  288. }
  289. #endif
  290. SekRunM68kOnce();
  291. if (Pico_mcd->m.need_sync) {
  292. Pico_mcd->m.need_sync = 0;
  293. pcd_sync_s68k(Pico.t.m68c_cnt, 0);
  294. }
  295. }
  296. }
  297. void pcd_run_cpus_lockstep(int m68k_cycles)
  298. {
  299. unsigned int target = Pico.t.m68c_aim + m68k_cycles;
  300. do {
  301. Pico.t.m68c_aim += 8;
  302. SekSyncM68k();
  303. pcd_sync_s68k(Pico.t.m68c_aim, 0);
  304. } while (CYCLES_GT(target, Pico.t.m68c_aim));
  305. Pico.t.m68c_aim = target;
  306. }
  307. #define PICO_CD
  308. #define CPUS_RUN(m68k_cycles) \
  309. pcd_run_cpus(m68k_cycles)
  310. #include "../pico_cmn.c"
  311. void pcd_prepare_frame(void)
  312. {
  313. pcd_set_cycle_mult();
  314. // need this because we can't have direct mapping between
  315. // master<->slave cycle counters because of overflows
  316. mcd_m68k_cycle_base = Pico.t.m68c_aim;
  317. mcd_s68k_cycle_base = SekCycleAimS68k;
  318. }
  319. PICO_INTERNAL void PicoFrameMCD(void)
  320. {
  321. PicoFrameStart();
  322. pcd_prepare_frame();
  323. PicoFrameHints();
  324. }
  325. void pcd_state_loaded(void)
  326. {
  327. unsigned int cycles;
  328. int diff;
  329. pcd_set_cycle_mult();
  330. pcd_state_loaded_mem();
  331. memset(Pico_mcd->pcm_mixbuf, 0, sizeof(Pico_mcd->pcm_mixbuf));
  332. Pico_mcd->pcm_mixbuf_dirty = 0;
  333. Pico_mcd->pcm_mixpos = 0;
  334. Pico_mcd->pcm_regs_dirty = 1;
  335. // old savestates..
  336. cycles = pcd_cycles_m68k_to_s68k(Pico.t.m68c_aim);
  337. diff = cycles - SekCycleAimS68k;
  338. if (diff < -1000 || diff > 1000) {
  339. SekCycleCntS68k = SekCycleAimS68k = cycles;
  340. }
  341. if (pcd_event_times[PCD_EVENT_CDC] == 0) {
  342. pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_CDC, 12500000/75);
  343. if (Pico_mcd->s68k_regs[0x31])
  344. pcd_event_schedule(SekCycleAimS68k, PCD_EVENT_TIMER3,
  345. Pico_mcd->s68k_regs[0x31] * 384);
  346. }
  347. diff = cycles - Pico_mcd->pcm.update_cycles;
  348. if ((unsigned int)diff > 12500000/50)
  349. Pico_mcd->pcm.update_cycles = cycles;
  350. // reschedule
  351. event_time_next = 0;
  352. pcd_run_events(SekCycleCntS68k);
  353. }
  354. // vim:shiftwidth=2:ts=2:expandtab