mcd.c 9.8 KB

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