Human68k CUI emulator with sound.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

v68periph.c 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. #include "platform.h"
  2. #include "v68.h"
  3. #include "v68periph.h"
  4. #include "v68doscall.h"
  5. #include "v68fecall.h"
  6. #include "v68iocscall.h"
  7. #include "musashi/m68kcpu.h"
  8. #include "tools.h"
  9. /* YM2151 OPM */
  10. #define OPM_CLOCK 4000000
  11. static uint32_t v68_opm_calc_timera(void);
  12. static uint32_t v68_opm_calc_timerb(void);
  13. unsigned int v68_read_periph_32(unsigned int addr);
  14. unsigned int v68_read_periph_16(unsigned int addr);
  15. unsigned int v68_read_periph_8(unsigned int addr);
  16. void v68_write_periph_32(unsigned int addr, unsigned int data);
  17. void v68_write_periph_16(unsigned int addr, unsigned int data);
  18. void v68_write_periph_8(unsigned int addr, unsigned int data);
  19. void v68_opm_write_8(uint32_t addr, uint8_t data);
  20. uint8_t v68_opm_read_8(uint32_t addr);
  21. void v68_mfp_write_8(uint32_t addr, uint8_t value);
  22. uint8_t v68_mfp_read_8(uint32_t addr);
  23. void v68_adpcm_write_8(uint32_t addr, uint8_t value);
  24. uint8_t v68_adpcm_read_8(uint32_t addr);
  25. void v68_ppi_write_8(uint32_t addr, uint8_t value);
  26. uint8_t v68_ppi_read_8(uint32_t addr);
  27. void v68_emu_write_16(uint32_t addr, uint16_t data);
  28. void v68_periph_init() {
  29. verbose1("v68_periph_init\n");
  30. // for mapping $ff0000 at $000000 at startup
  31. v68.reset_pulsed = 0;
  32. ym2151_init(&v68.opm, OPM_CLOCK, v68.sample_rate);
  33. ym2151_reset_chip(&v68.opm);
  34. v68.opm_clka = 0;
  35. v68.opm_clkb = 0;
  36. v68.opm_addr_latch = 0;
  37. v68.opm_timera_counter = 0;
  38. v68.opm_timerb_counter = 0;
  39. v68.opm_timera_cycles = v68_opm_calc_timera();
  40. v68.opm_timerb_cycles = v68_opm_calc_timerb();
  41. v68.opm_flags = 0;
  42. okim6258_init(&v68.oki, 8000000, FOSC_DIV_BY_512, TYPE_4BITS, OUTPUT_12BITS);
  43. okim6258_reset(&v68.oki);
  44. v68.oki_freq = 15625;
  45. v68.oki_sample_counter = 0;
  46. v68.oki_sample_cycles = v68.cpu_clock * 2 / 15625; /* it's actually clock / (sample rate / 2), 1 byte contains 2 samples */
  47. v68.oki_prev_sample[0] = v68.oki_prev_sample[1] = 0;
  48. dmac_init();
  49. dmac_write_16(0xd4, 0xe92003 >> 16, 0xffff);
  50. dmac_write_16(0xd6, 0xe92003 & 0xffff, 0xffff);
  51. dmac_write_16(0xc6, 0x0400, 0xffff);
  52. }
  53. void v68_periph_end() {
  54. okim6258_stop(&v68.oki);
  55. }
  56. uint32_t v68_int_ack_handler(int int_level) {
  57. verbose1("v68_int_ack_handler int_level=%d int_vec=0x%02x\n", int_level, v68.int_vec);
  58. if(int_level == 6) { /* MFP */
  59. CPU_INT_LEVEL = 0;
  60. int vec = v68.int_vec;
  61. if(vec) {
  62. verbose2("v68_int_ack_handler MFP int ack vec=0x%04x vector address at 0x%08x points to 0x%08x)\n", v68.int_vec, v68.int_vec * 4, m68k_read_memory_32(v68.int_vec * 4));
  63. v68.int_vec = 0;
  64. return vec;
  65. }
  66. } else if(int_level == 3) { /* DMAC */
  67. CPU_INT_LEVEL = 0;
  68. int vec = v68.int_vec;
  69. if(vec) {
  70. verbose2("v68_int_ack_handler DMAC int ack vec=0x%04x vector address at 0x%08x points to 0x%08x)\n", v68.int_vec, v68.int_vec * 4, m68k_read_memory_32(v68.int_vec * 4));
  71. v68.int_vec = 0;
  72. return vec;
  73. }
  74. }
  75. return M68K_INT_ACK_SPURIOUS;
  76. }
  77. void v68_periph_render_sample(int16_t *l, int16_t *r) {
  78. verbose1("v68_periph_render_sample\n");
  79. #ifndef __EMSCRIPTEN__
  80. if(v68.logger) {
  81. vgm_logger_wait(v68.logger, 1);
  82. }
  83. #endif
  84. int16_t *buf[2] = { l, r };
  85. ym2151_update_one(&v68.opm, buf, 1);
  86. int prev_oki_remainder = v68.oki_resample_remainder;
  87. int x = v68.oki_freq + v68.oki_resample_remainder;
  88. int oki_samples = x / v68.sample_rate;
  89. v68.oki_resample_remainder = x - oki_samples * v68.sample_rate;
  90. verbose2("v68_periph_render_samples oki_samples=%d\n", oki_samples);
  91. if(oki_samples) {
  92. int16_t tl, tr;
  93. buf[0] = &tl;
  94. buf[1] = &tr;
  95. okim6258_update(&v68.oki, buf, oki_samples);
  96. v68.oki_prev_sample[0] = tl;
  97. v68.oki_prev_sample[1] = tr;
  98. int j = 0;
  99. int x = v68.oki_freq + prev_oki_remainder;
  100. int s = x / v68.sample_rate;
  101. prev_oki_remainder = x - s * v68.sample_rate;
  102. if(s > 0 && j < oki_samples - 1)
  103. j++;
  104. *l += tl;
  105. *r += tr;
  106. } else {
  107. *l += v68.oki_prev_sample[0];
  108. *r += v68.oki_prev_sample[1];
  109. }
  110. }
  111. void v68_periph_advance(uint32_t cycles) {
  112. verbose1("v68_periph_advance cycles=%d\n", cycles);
  113. verbose2("v68_periph_advance opm_timera_counter=%d opm_timera_cycles=%d\n", v68.opm_timera_counter, v68.opm_timera_cycles);
  114. verbose2("v68_periph_advance opm_timerb_counter=%d opm_timerb_cycles=%d\n", v68.opm_timerb_counter, v68.opm_timerb_cycles);
  115. verbose2("v68_periph_advance oki_sample_counter=%d oki_sample_cycles=%d\n", v68.oki_sample_counter, v68.oki_sample_cycles);
  116. /* If timer A enabled */
  117. if((v68.opm_flags & 0x01) && v68.opm_timera_counter < v68.opm_timera_cycles) {
  118. v68.opm_timera_counter += cycles;
  119. if(v68.opm_timera_counter >= v68.opm_timera_cycles && (v68.opm_flags & 0x04)) {
  120. v68.int_vec = 0x43;
  121. verbose2("v68_periph_advance generating IRQ 6 Timer A\n");
  122. m68k_set_irq(6);
  123. }
  124. }
  125. /* If timer B enabled */
  126. if((v68.opm_flags & 0x02) && v68.opm_timerb_counter < v68.opm_timerb_cycles) {
  127. v68.opm_timerb_counter += cycles;
  128. if(v68.opm_timerb_counter >= v68.opm_timerb_cycles && (v68.opm_flags & 0x08)) {
  129. v68.int_vec = 0x43;
  130. verbose2("v68_periph_advance generating IRQ 6 Timer B\n");
  131. m68k_set_irq(6);
  132. }
  133. }
  134. /* If OKI is playing, trigger a DMA transfer */
  135. if(v68.oki.status & 0x02) {
  136. v68.oki_sample_counter += cycles;
  137. while(v68.oki_sample_counter >= v68.oki_sample_cycles) {
  138. verbose2("v68_periph_advance DMA Tick oki_sample_counter=%d oki_sample_cycles=%d\n", v68.oki_sample_counter, v68.oki_sample_cycles);
  139. v68.oki_sample_counter -= v68.oki_sample_cycles;
  140. // Trigger transfer
  141. dmac_tick(3);
  142. }
  143. }
  144. verbose2("v68_periph_advance done\n");
  145. }
  146. static void v68_periph_before_write(uint32_t addr) {
  147. /* Check if sound is touched */
  148. if(!v68.sound_touched) {
  149. if(addr == 0xe92001 || addr == 0xe92003 || addr == 0xe90003) {
  150. verbose1("sound touched\n");
  151. v68.sound_touched = 1;
  152. }
  153. }
  154. }
  155. unsigned int v68_read_periph_32(unsigned int addr) {
  156. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  157. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  158. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  159. return (dmac_read_16(addr & 0xfe, 0xffff) << 16) | dmac_read_16((addr & 0xfe) + 2, 0xffff);
  160. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  161. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  162. return
  163. (v68_mfp_read_8((addr & 0xff) + 0) << 24) |
  164. (v68_mfp_read_8((addr & 0xff) + 1) << 16) |
  165. (v68_mfp_read_8((addr & 0xff) + 2) << 8) |
  166. (v68_mfp_read_8((addr & 0xff) + 3) );
  167. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  168. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  169. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  170. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  171. return
  172. (v68_opm_read_8((addr & 0xff) + 0) << 24) |
  173. (v68_opm_read_8((addr & 0xff) + 1) << 16) |
  174. (v68_opm_read_8((addr & 0xff) + 2) << 8) |
  175. (v68_opm_read_8((addr & 0xff) + 3) );
  176. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  177. return
  178. (v68_adpcm_read_8((addr & 0xff) + 0) << 24) |
  179. (v68_adpcm_read_8((addr & 0xff) + 1) << 16) |
  180. (v68_adpcm_read_8((addr & 0xff) + 2) << 8) |
  181. (v68_adpcm_read_8((addr & 0xff) + 3) );
  182. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  183. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  184. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  185. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  186. return
  187. (v68_ppi_read_8((addr & 0xff) + 0) << 24) |
  188. (v68_ppi_read_8((addr & 0xff) + 1) << 16) |
  189. (v68_ppi_read_8((addr & 0xff) + 2) << 8) |
  190. (v68_ppi_read_8((addr & 0xff) + 3) );
  191. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  192. }
  193. return 0xffffffff;
  194. }
  195. unsigned int v68_read_periph_16(unsigned int addr) {
  196. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  197. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  198. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  199. return dmac_read_16(addr & 0xfe, 0xffff);
  200. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  201. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  202. return
  203. (v68_mfp_read_8((addr & 0xff) + 0) << 8) |
  204. (v68_mfp_read_8((addr & 0xff) + 1) );
  205. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  206. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  207. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  208. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  209. return
  210. (v68_opm_read_8((addr & 0xff) + 0) << 8) |
  211. (v68_opm_read_8((addr & 0xff) + 1) );
  212. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  213. return
  214. (v68_adpcm_read_8((addr & 0xff) + 0) << 8) |
  215. (v68_adpcm_read_8((addr & 0xff) + 1) );
  216. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  217. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  218. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  219. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  220. return
  221. (v68_ppi_read_8((addr & 0xff) + 0) << 8) |
  222. (v68_ppi_read_8((addr & 0xff) + 1) );
  223. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  224. }
  225. return 0xffff;
  226. }
  227. unsigned int v68_read_periph_8(unsigned int addr) {
  228. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  229. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  230. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  231. return dmac_read_16(addr & 0xfe, (addr & 1) ? 0x00ff : 0xff00);
  232. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  233. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  234. return v68_mfp_read_8(addr & 0xff);
  235. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  236. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  237. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  238. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  239. return v68_opm_read_8(addr & 0xff);
  240. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  241. return v68_adpcm_read_8(addr & 0xff);
  242. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  243. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  244. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  245. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  246. return v68_ppi_read_8(addr & 0xff);
  247. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  248. }
  249. return 0xff;
  250. }
  251. void v68_write_periph_32(unsigned int addr, unsigned int data) {
  252. verbose2("write_periph_32 addr=0x%08x data=0x%08x cycles=%d remaining=%d\n", addr, data, m68k_cycles_run(), m68k_cycles_remaining());
  253. v68_periph_before_write(addr);
  254. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  255. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  256. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  257. dmac_write_16((addr & 0x0fff) + 0, data >> 16, 0xffff);
  258. dmac_write_16((addr & 0x0fff) + 2, data, 0xffff);
  259. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  260. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  261. v68_mfp_write_8((addr & 0xff) + 0, (data >> 24) & 0xff);
  262. v68_mfp_write_8((addr & 0xff) + 1, (data >> 16) & 0xff);
  263. v68_mfp_write_8((addr & 0xff) + 2, (data >> 8) & 0xff);
  264. v68_mfp_write_8((addr & 0xff) + 3, (data ) & 0xff);
  265. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  266. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  267. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  268. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  269. v68_opm_write_8((addr & 0xff) + 0, (data >> 24) & 0xff);
  270. v68_opm_write_8((addr & 0xff) + 1, (data >> 16) & 0xff);
  271. v68_opm_write_8((addr & 0xff) + 2, (data >> 8) & 0xff);
  272. v68_opm_write_8((addr & 0xff) + 3, (data ) & 0xff);
  273. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  274. v68_adpcm_write_8((addr & 0xff) + 0, (data >> 24) & 0xff);
  275. v68_adpcm_write_8((addr & 0xff) + 1, (data >> 16) & 0xff);
  276. v68_adpcm_write_8((addr & 0xff) + 2, (data >> 8) & 0xff);
  277. v68_adpcm_write_8((addr & 0xff) + 3, (data ) & 0xff);
  278. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  279. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  280. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  281. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  282. v68_ppi_write_8((addr & 0xff) + 0, (data >> 24) & 0xff);
  283. v68_ppi_write_8((addr & 0xff) + 1, (data >> 16) & 0xff);
  284. v68_ppi_write_8((addr & 0xff) + 2, (data >> 8) & 0xff);
  285. v68_ppi_write_8((addr & 0xff) + 3, (data ) & 0xff);
  286. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  287. }
  288. }
  289. void v68_write_periph_16(unsigned int addr, unsigned int data) {
  290. verbose2("write_periph_16 addr=0x%08x data=0x%04x cycles=%d remaining=%d\n", addr, data, m68k_cycles_run(), m68k_cycles_remaining());
  291. v68_periph_before_write(addr);
  292. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  293. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  294. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  295. dmac_write_16(addr & 0xff, data, 0xffff);
  296. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  297. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  298. v68_mfp_write_8((addr & 0xff) + 0, (data >> 8) & 0xff);
  299. v68_mfp_write_8((addr & 0xff) + 1, (data ) & 0xff);
  300. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  301. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  302. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  303. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  304. v68_opm_write_8((addr & 0xff) + 0, (data >> 8) & 0xff);
  305. v68_opm_write_8((addr & 0xff) + 1, (data ) & 0xff);
  306. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  307. v68_adpcm_write_8((addr & 0xff) + 0, (data >> 8) & 0xff);
  308. v68_adpcm_write_8((addr & 0xff) + 1, (data ) & 0xff);
  309. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  310. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  311. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  312. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  313. v68_ppi_write_8((addr & 0xff) + 0, (data >> 8) & 0xff);
  314. v68_ppi_write_8((addr & 0xff) + 1, (data ) & 0xff);
  315. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  316. } else if(addr < 0xeb0000) { /* Emulator port */
  317. v68_emu_write_16(addr, data);
  318. }
  319. }
  320. void v68_write_periph_8(unsigned int addr, unsigned int data) {
  321. verbose1("v68_write_periph_8 addr=0x%08x data=0x%02x cycles=%d remaining=%d\n", addr, data, m68k_cycles_run(), m68k_cycles_remaining());
  322. v68_periph_before_write(addr);
  323. if(addr < 0xe82000) { /* CRTコントローラ ◆ CRT controller */
  324. } else if(addr < 0xe84000) { /* ビデオコントローラ ◆ Video controller */
  325. } else if(addr < 0xe86000) { /* DMAC ◆ DMA controller */
  326. dmac_write_16(addr & 0xfe, (addr & 1) ? data : (data << 8), (addr & 1) ? 0x00ff : 0xff00);
  327. } else if(addr < 0xe88000) { /* エリアセット ◆ Area set */
  328. } else if(addr < 0xe8a000) { /* MFP ◆ Multi-function peripheral */
  329. v68_mfp_write_8(addr & 0xff, data);
  330. } else if(addr < 0xe8c000) { /* RTC ◆ Realtime clock */
  331. } else if(addr < 0xe8e000) { /* プリンタ ◆ Printer */
  332. } else if(addr < 0xe90000) { /* システムポート ◆ System port */
  333. } else if(addr < 0xe92000) { /* FM音源 ◆ FM sound source (OPM) */
  334. v68_opm_write_8(addr & 0xff, data);
  335. } else if(addr < 0xe94000) { /* ADPCM ◆ OKI M6258 ADPCM */
  336. v68_adpcm_write_8(addr & 0xff, data);
  337. } else if(addr < 0xe96000) { /* FDC ◆ Floppy drive controller */
  338. } else if(addr < 0xe98000) { /* HDC ◆ Hard disk controller */
  339. } else if(addr < 0xe9a000) { /* SCC ◆ Serial communications */
  340. } else if(addr < 0xe9C000) { /* i8255 ◆ Programmable peripheral interface */
  341. v68_ppi_write_8(addr & 0xff, data);
  342. } else if(addr < 0xe9e000) { /* I/O コントローラ ◆ I/O controller */
  343. }
  344. }
  345. /* FM音源 ◆ FM sound source (OPM) */
  346. static uint32_t v68_opm_calc_timera() {
  347. uint64_t x = 1024 * v68.opm_clka;
  348. x *= v68.cpu_clock;
  349. x /= 62500;
  350. return x;
  351. }
  352. static uint32_t v68_opm_calc_timerb() {
  353. uint64_t x = 1024 * (256 - v68.opm_clkb);
  354. x *= v68.cpu_clock;
  355. x /= 4000000;
  356. return x;
  357. }
  358. void v68_opm_write_8(uint32_t addr, uint8_t data) {
  359. verbose1("v68_opm_write_8 0x%08x 0x%02x\n", addr, data);
  360. switch(addr) {
  361. case 0x01:
  362. v68.opm_addr_latch = data;
  363. break;
  364. case 0x03: {
  365. verbose2("v68_opm_write_8 DATA opm_addr_latch=0x%02x data=0x%02x\n", v68.opm_addr_latch, data);
  366. ym2151_write_reg(&v68.opm, v68.opm_addr_latch, data);
  367. #ifndef __EMSCRIPTEN__
  368. if(v68.logger)
  369. vgm_logger_write_ym2151(v68.logger, v68.opm_addr_latch, data);
  370. #endif
  371. int clka = v68.opm_clka, clkb = v68.opm_clkb;
  372. switch(v68.opm_addr_latch) {
  373. case 0x10:
  374. clka &= 0x0003;
  375. clka |= data << 2;
  376. if(v68.opm_clka != clka) {
  377. v68.opm_clka = clka;
  378. v68.opm_timera_cycles = v68_opm_calc_timera();
  379. }
  380. break;
  381. case 0x11:
  382. clka &= 0x03fc;
  383. clka |= data & 0x03;
  384. if(v68.opm_clka != clka) {
  385. v68.opm_clka = clka;
  386. v68.opm_timera_cycles = v68_opm_calc_timera();
  387. }
  388. break;
  389. case 0x12:
  390. clkb = data;
  391. if(v68.opm_clkb != clkb) {
  392. v68.opm_clkb = clkb;
  393. v68.opm_timerb_cycles = v68_opm_calc_timerb();
  394. }
  395. break;
  396. case 0x14: {
  397. v68.opm_flags = data & 0x0f;
  398. /* Check for reset */
  399. if(data & 0x10) {
  400. v68.opm_timera_counter = 0;
  401. }
  402. if(data & 0x20) {
  403. v68.opm_timerb_counter = 0;
  404. }
  405. }
  406. break;
  407. case 0x1b: {
  408. v68.opm_ct = data & 0xc0;
  409. }
  410. break;
  411. }
  412. }
  413. break;
  414. }
  415. }
  416. uint8_t v68_opm_read_8(uint32_t addr) {
  417. verbose1("v68_opm_read_8 addr=0x%08x\n", addr);
  418. switch(addr) {
  419. case 0x03: {
  420. uint8_t ret = 0;
  421. if(v68.opm_timera_counter >= v68.opm_timera_cycles) ret |= 0x01;
  422. if(v68.opm_timerb_counter >= v68.opm_timerb_cycles) ret |= 0x02;
  423. return ret;
  424. }
  425. }
  426. return 0x00;
  427. }
  428. /* MFP ◆ Multi-function peripheral */
  429. void v68_mfp_write_8(uint32_t addr, uint8_t value) {
  430. verbose2("v68_mfp_write_8 0x%08x = 0x%02x\n", addr, value);
  431. }
  432. uint8_t v68_mfp_read_8(uint32_t addr) {
  433. verbose2("v68_mfp_read_8 %08x\n", addr);
  434. return 0x00;
  435. }
  436. /* ADPCM ◆ OKI M6258 ADPCM */
  437. void v68_adpcm_write_8(uint32_t addr, uint8_t value) {
  438. verbose1("v68_adpcm_write_8 addr=0x%08x value=0x%02x\n", addr, value);
  439. switch(addr) {
  440. case 0x01: /* 0xe92001 ADPCM command */
  441. okim6258_write(&v68.oki, 0x00, value);
  442. #ifndef __EMSCRIPTEN__
  443. if(v68.logger)
  444. vgm_logger_write_okim6258(v68.logger, 0x00, value);
  445. #endif
  446. if(value & 0x02) {
  447. v68.oki_freq = 15625;
  448. v68.oki_sample_cycles = v68.cpu_clock * 2 / v68.oki_freq;
  449. }
  450. break;
  451. case 0x03: /* 0xe92003 Data input / output */
  452. okim6258_write(&v68.oki, 0x01, value);
  453. #ifndef __EMSCRIPTEN__
  454. if(v68.logger)
  455. vgm_logger_write_okim6258(v68.logger, 0x01, value);
  456. #endif
  457. break;
  458. }
  459. }
  460. uint8_t v68_adpcm_read_8(uint32_t addr) {
  461. verbose1("v68_adpcm_read_8 0x%08x\n", addr);
  462. return 0x00;
  463. }
  464. /* i8255 ◆ Programmable peripheral interface */
  465. void v68_ppi_write_8(uint32_t addr, uint8_t value) {
  466. verbose2("v68_ppi_write_8 0x%08x = 0x%02x\n", addr, value);
  467. }
  468. uint8_t v68_ppi_read_8(uint32_t addr) {
  469. verbose2("v68_ppi_read_8 0x%08x\n", addr);
  470. return 0x00;
  471. }
  472. /* Emulator specific ports */
  473. void v68_emu_write_16(uint32_t addr, uint16_t data) {
  474. verbose1("v68_emu_write_16 addr=0x%08x data=0x%04x\n", addr, data);
  475. if(addr == 0xea0000) {
  476. if((data & 0xff00) == 0xff00)
  477. v68_dos_call(data);
  478. else if((data & 0xff00) == 0xfe00)
  479. v68_fe_call(data);
  480. } else if(addr == 0xea0004) {
  481. v68_iocs_call(data);
  482. } else if(addr == 0xea0008) {
  483. v68_queue_next_command();
  484. }
  485. }