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 24KB

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