Human68k CUI emulator with sound.
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

v68periph.c 22KB

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