2 FUJITSU FM Towns Emulator 'eFMTowns'
4 Author : Kyuma.Ohta <whatisthis.sowhat _at_ gmail.com>
7 [FM-Towns CD-ROM based on SCSI CDROM]
11 * Note: Re-Write CD-ROM from SCSI_CDROM, but not related from SCSI_DEV.
16 #include "../../../fifo.h"
17 #include "../../../ringbuffer.h"
18 #include "../../../fileio.h"
19 #include "../../debugger.h"
20 #include "../../types/util_sound.h"
25 // SAME AS SCSI_CDROM::
27 #define CDDA_PLAYING 1
31 // 0-99 is reserved for SCSI_DEV class
32 #define EVENT_CDDA 100
33 #define EVENT_CDDA_DELAY_PLAY 101
34 #define EVENT_CDROM_SEEK 102
35 #define EVENT_CDROM_DELAY_INTERRUPT_ON 103
36 #define EVENT_CDROM_DELAY_INTERRUPT_OFF 104
37 #define EVENT_CDDA_DELAY_STOP 105
38 #define EVENT_CDROM_READY_TO_READ 106
39 #define EVENT_CDROM_DRQ 107
40 #define EVENT_CDROM_NEXT_SECTOR 108
41 #define EVENT_CDROM_DELAY_READY 109
42 #define EVENT_CDROM_DELAY_NOT_READY 110
44 #define EVENT_CDROM_DELAY_START_DRQ 111
45 #define EVENT_CDROM_DELAY_EOT_PIO 112
47 #define EVENT_CDROM_RESTORE 113
48 #define EVENT_CDROM_WAIT 114
49 #define EVENT_CDROM_TIMEOUT 115
50 #define EVENT_CDROM_READY_EOT 116
51 #define EVENT_CDROM_READY_CDDAREPLY 117
52 #define EVENT_CDROM_CDDA_PLAY_STATUS 118
53 #define EVENT_CDDA_REPEAT 119
54 #define EVENT_CDROM_READ_PRE_SEEK 120
56 #define EVENT_CDROM_DELAY_COMMAND 128
57 #define EVENT_CDROM_DELAY_READY_FORCEINT 129
58 #define EVENT_CDROM_DELAY_NOT_READY_FORCEINT 130
59 #define EVENT_CDROM_READY_EOT_FORCEINT 136
61 //#define _CDROM_DEBUG_LOG
64 // crc table from vm/disk.cpp
65 const uint16_t TOWNS_CDROM::crc_table[256] = {
66 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
67 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
68 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
69 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
70 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
71 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
72 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
73 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
74 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
75 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
76 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
77 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
78 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
79 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
80 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
81 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
85 uint16_t TOWNS_CDROM::calc_subc_crc16(uint8_t *databuf, int bytes, uint16_t initval)
87 uint16_t crc16 = initval;
88 for(int i = 0; i < bytes ; i++) {
89 crc16 = (uint16_t)((crc16 << 8) ^ crc_table[(uint8_t)(crc16 >> 8) ^ databuf[i]]);
94 void TOWNS_CDROM::cdrom_debug_log(const char *fmt, ...)
99 vsnprintf(strbuf, 4095, fmt, ap);
100 out_debug_log_with_switch(((__CDROM_DEBUG_LOG) || (force_logging)),
106 void TOWNS_CDROM::initialize()
108 DEVICE::initialize();
109 __CDROM_DEBUG_LOG = osd->check_feature(_T("_CDROM_DEBUG_LOG"));
110 __CDROM_DEBUG_LOG = true;
111 _USE_CDROM_PREFETCH = osd->check_feature(_T("USE_CDROM_PREFETCH"));
112 force_logging = false;
114 subq_overrun = false;
115 memset(subq_bytes, 0x00, sizeof(subq_bytes));
116 memset(subq_snapshot, 0x00, sizeof(subq_snapshot));
117 memset(subq_buffer, 0x00, sizeof(subq_buffer));
121 //status_queue = new FIFO(4 * (6 + 100 + 2)); // With PAD
122 status_queue = new FIFO(4); // With PAD
123 param_queue = new RINGBUFFER(8);
124 // ToDo: MasterDevice::initialize()
125 fio_img = new FILEIO();
127 memset(img_file_path_bak, 0x00, sizeof(img_file_path_bak));
128 media_changed = false;
129 media_ejected = false;
131 //if(44100 % emu->get_sound_rate() == 0) {
132 // mix_loop_num = 44100 / emu->get_sound_rate();
138 event_cdda_delay_play = -1;
139 event_delay_interrupt = -1;
142 event_next_sector = -1;
144 event_delay_ready = -1;
145 event_cdda_delay_stop = -1;
149 // ToDo: larger buffer for later VMs.
150 max_fifo_length = ((machine_id == 0x0700) || (machine_id >= 0x0900)) ? 65536 : 8192;
152 // fifo_length = 65536;
153 databuffer = new FIFO(max_fifo_length);
155 cdda_status = CDDA_OFF;
162 for(int i = 0; i < 99; i++) {
163 memset(track_data_path[i], 0x00, _MAX_PATH * sizeof(_TCHAR));
166 @note values related muting/voluming are set by electric volume,
167 not inside of CD-ROM DRIVE.
174 memset(w_regs, 0x00, sizeof(w_regs));
177 void TOWNS_CDROM::release()
179 if(fio_img != NULL) {
180 if(fio_img->IsOpened()) {
186 if(databuffer != NULL) {
187 databuffer->release();
191 if(status_queue != NULL) {
192 status_queue->release();
196 if(param_queue != NULL) {
197 param_queue->release();
204 void TOWNS_CDROM::reset()
206 cdrom_debug_log("RESET");
210 // Interrupt masks must set after device reset : From Tsugaru.
211 mcu_intr_mask = false;
212 dma_intr_mask = false;
213 write_mcuint_signals(false);
214 // Q: Does not seek to track 0? 20181118 K.O
217 void TOWNS_CDROM::reset_device()
219 uint8_t reg4c0 = w_regs[0];
220 memset(w_regs, 0x00, sizeof(w_regs));
224 clear_event(this, event_execute);
225 clear_event(this, event_cdda);
226 clear_event(this, event_cdda_delay_play);
227 clear_event(this, event_cdda_delay_stop);
228 clear_event(this, event_delay_interrupt);
229 clear_event(this, event_next_sector);
231 clear_event(this, event_seek);
232 clear_event(this, event_delay_ready);
233 clear_event(this, event_time_out);
234 clear_event(this, event_eot);
235 clear_event(this, event_drq);
237 // Around internal variables.
238 // if(44100 % emu->get_sound_rate() == 0) {
239 // mix_loop_num = 44100 / emu->get_sound_rate();
246 cdda_status = CDDA_OFF;
247 cdda_repeat_count = -1;
249 cdda_start_frame = 0;
250 cdda_end_frame = 150;
251 cdda_playing_frame = 0;
255 media_changed = false;
256 media_ejected = false;
257 cdrom_prefetch = false;
265 get_track_by_track_num(0); // HEAD OF track 1
267 stat_track = current_track;
268 // Note: Reorder sequence.
270 // Around Register 4C0h:R
275 command_execute_phase = false;
277 // Around Register 4C2h:R
278 status_queue->clear();
281 // Around Register 4C2h:W
282 command_received = false;
284 stat_reply_intr = false;
287 // Around Register 4C4h:R
291 // Around Register 4C4h:W
292 reserved_command = 0x00;
293 param_queue->clear();
295 latest_command = 0x00;
296 memset(exec_params, 0x00, sizeof(exec_params));
298 memset(prev_params, 0x00, sizeof(prev_params));
300 // Around Register 4C6h:W
301 dma_transfer = false;
302 pio_transfer = false;
303 dma_transfer_phase = false;
304 pio_transfer_phase = false;
306 // Around Register 4CCh:R and 4CDh:R
309 subq_overrun = false;
311 memcpy(subq_snapshot, subq_bytes, sizeof(subq_snapshot));
314 dmac_running = (d_dmac->read_signal(SIG_TOWNS_DMAC_MASK_CH3) != 0) ? true : false;
316 dmac_running = false;
318 // Maybe not need to reset interrupt from I/O 04C0h:bit7 .
319 // write_mcuint_signals(false);
323 void TOWNS_CDROM::set_dma_intr(bool val)
325 // cdrom_debug_log(_T("set_dma_intr(%s) MASK=%s stat_reply_intr = %s"),
326 // (val) ? _T("true ") : _T("false"),
327 // (dma_intr_mask) ? _T("ON ") : _T("OFF"),
328 // (stat_reply_intr) ? _T("ON ") : _T("OFF"));
329 // At least, DMA interrupt mask is needed (by TownsOS v.1.1) 20200511 K.O
330 if(!(dma_intr_mask) /*&& (val)*/) { // ∑(゚Д゚)!! from Tsugaru 20231001
331 write_mcuint_signals(true);
333 // Interrupt flag may set after interrupt happened ?? (;´Д`) From Tsugaru.
338 void TOWNS_CDROM::set_mcu_intr(bool val)
340 // cdrom_debug_log(_T("set_mcu_intr(%s) MASK=%s stat_reply_intr = %s"),
341 // (val) ? _T("true ") : _T("false"),
342 // (mcu_intr_mask) ? _T("ON ") : _T("OFF"),
343 // (stat_reply_intr) ? _T("ON ") : _T("OFF"));
344 if(!(mcu_intr_mask) /*&& (val)*/) { // ∑(゚Д゚)!! from Tsugaru 20231001
345 write_mcuint_signals(true);
351 void TOWNS_CDROM::start_time_out()
354 // TIMEOUT = 1000msec = 1sec.
355 if(event_time_out < 0) {
356 register_event(this, EVENT_CDROM_TIMEOUT, 100.0e3, false, &event_time_out);
360 void TOWNS_CDROM::stop_time_out()
362 clear_event(this, event_time_out);
365 void TOWNS_CDROM::do_drq()
367 // Note: EMULATE NONE BUFFER. 20230531 K.O
368 if((dma_transfer_phase) && (dma_transfer)) {
369 __LIKELY_IF(!(databuffer->empty())) {
370 __LIKELY_IF(dmac_running) {
371 write_signals(&outputs_drq, 0xffffffff);
374 if(read_length <= 0) {
375 dma_transfer_epilogue(); // Remove Duplicate calling.
381 void TOWNS_CDROM::stop_drq()
383 clear_event(this, event_drq);
386 void TOWNS_CDROM::start_drq(const double usec)
389 dmac_running = (d_dmac->read_signal(SIG_TOWNS_DMAC_MASK_CH3) != 0) ? true : false;
391 dmac_running = false;
394 register_event(this, EVENT_CDROM_DELAY_START_DRQ,
400 void TOWNS_CDROM::clear_status_queue(const bool is_clear_extra)
406 __UNLIKELY_IF(status_queue == NULL) {
409 status_queue->clear();
412 void TOWNS_CDROM::push_status_queue(uint8_t s0, uint8_t s1, uint8_t s2, uint8_t s3)
414 __UNLIKELY_IF(status_queue == NULL) {
418 status_queue->write(s0);
419 status_queue->write(s1);
420 status_queue->write(s2);
421 status_queue->write(s3);
425 void TOWNS_CDROM::write_signal(int id, uint32_t data, uint32_t mask)
427 bool _b = ((data & mask) != 0);
430 case SIG_TOWNS_CDROM_CDDA_STOP:
431 if(cdda_status != CDDA_OFF) {
432 if(_b) set_cdda_status(CDDA_OFF);
435 case SIG_TOWNS_CDROM_CDDA_PLAY:
436 if(cdda_status != CDDA_PLAYING) {
437 if(_b) set_cdda_status(CDDA_PLAYING);
440 case SIG_TOWNS_CDROM_CDDA_PAUSE:
441 if(cdda_status != CDDA_PAUSED) {
442 if(_b) set_cdda_status(CDDA_PAUSED);
445 case SIG_TOWNS_CDROM_SET_TRACK:
446 if(((data < 100) && (data >= 0)) || (data == 0xaa)) {
450 case SIG_TOWNS_CDROM_RESET:
451 if((data & mask) != 0) {
455 case SIG_TOWNS_CDROM_MUTE_L:
456 mute_left = ((data & mask) != 0) ? true : false;
458 case SIG_TOWNS_CDROM_MUTE_R:
459 mute_right = ((data & mask) != 0) ? true : false;
461 case SIG_TOWNS_CDROM_MUTE_ALL:
462 mute_left = ((data & mask) != 0) ? true : false;
463 mute_right = mute_left;
465 // By DMA/TC, EOT.This means ABORTing request from EXTERNAL BUS.
466 case SIG_TOWNS_CDROM_DMAINT:
467 if((data & mask) != 0) {
468 // This seems to be aborting to transfer?
469 if(dma_transfer_phase) {
470 //if(databuffer->empty()) {
471 dma_transfer_epilogue();
472 // ToDo: Abort Sequence.
477 case SIG_TOWNS_CDROM_DMAMASK:
478 dmac_running = ((data & mask) != 0) ? true : false;
481 // ToDo: Implement master devices.
487 bool TOWNS_CDROM::status_media_changed_or_not_ready(const bool force_interrupt)
489 if(status_not_ready(force_interrupt)) {
490 media_changed = false;
493 if(status_media_changed(force_interrupt)) {
499 bool TOWNS_CDROM::status_not_ready(const bool force_interrupt)
501 bool _b = (mounted()) ? false : true;
503 cdrom_debug_log(_T("CMD (%02X) BUT DISC NOT ACTIVE"), latest_command);
504 command_execute_phase = false;
505 set_status_immediate(req_status, force_interrupt, 0,
506 TOWNS_CD_STATUS_CMD_ABEND, TOWNS_CD_ABEND_DRIVE_NOT_READY, 0, 0);
511 bool TOWNS_CDROM::status_media_changed(const bool force_interrupt)
513 bool _b = media_changed;
514 media_changed = false;
516 command_execute_phase = false;
517 set_status_immediate(req_status, force_interrupt, 0,
518 TOWNS_CD_STATUS_CMD_ABEND, TOWNS_CD_ABEND_MEDIA_CHANGED, 0, 0);
523 void TOWNS_CDROM::status_hardware_error(const bool force_interrupt)
525 command_execute_phase = false; // OK?
526 set_status_immediate(req_status, force_interrupt, 0,
527 TOWNS_CD_STATUS_CMD_ABEND, TOWNS_CD_ABEND_HARDWARE_ERROR_04, 0, 0);
530 void TOWNS_CDROM::status_parameter_error(const bool force_interrupt)
532 command_execute_phase = false;
533 set_status_immediate(req_status, force_interrupt, 0,
534 TOWNS_CD_STATUS_CMD_ABEND, TOWNS_CD_ABEND_PARAMETER_ERROR, 0, 0);
537 void TOWNS_CDROM::status_time_out(const bool force_interrupt)
540 //clear_event(this, event_execute); // OK?
541 //clear_event(this, event_cdda); // OK?
542 clear_event(this, event_cdda_delay_play);
543 clear_event(this, event_cdda_delay_stop);
544 //clear_event(this, event_delay_interrupt); // OK?
545 clear_event(this, event_next_sector);
547 clear_event(this, event_seek);
548 clear_event(this, event_delay_ready); // OK?
549 clear_event(this, event_eot);
550 //clear_event(this, event_time_out);
551 command_execute_phase = false;
553 set_status_immediate(true, force_interrupt, 0, TOWNS_CD_STATUS_CMD_ABEND, TOWNS_CD_ABEND_RETRY, 0x00, 0x00);
554 // Backport from Tsugaru, 2023-10-01
556 dma_transfer_phase = false;
557 pio_transfer_phase = false;
561 void TOWNS_CDROM::status_read_done(const bool force_interrupt)
564 clear_status_queue(true);
565 command_execute_phase = false;
566 push_status_queue(TOWNS_CD_STATUS_READ_DONE, 0x00, 0x00, 0x00);
569 bool i_enabled = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
570 if((stat_reply_intr) && (i_enabled)) { // Without MASK.
571 write_mcuint_signals(true);
578 void TOWNS_CDROM::status_data_ready(const bool force_interrupt)
580 clear_status_queue(true);
582 push_status_queue(TOWNS_CD_STATUS_DATA_DMA, 0x00, 0x00, 0x00);
585 bool i_enabled = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
586 if((stat_reply_intr) && (i_enabled)) { // Without MASK.
587 write_mcuint_signals(true);
596 void TOWNS_CDROM::status_illegal_lba(int extra, uint8_t s1, uint8_t s2, uint8_t s3)
598 cdrom_debug_log(_T("Error on reading (ILLGLBLKADDR): EXTRA=%d s1=%02X s2=%02X s3=%02X LBA=%d\n"), extra, s1, s2, s3, read_sector);
599 command_execute_phase = false;
600 set_status(req_status, extra, TOWNS_CD_STATUS_CMD_ABEND, s1, s2, s3, false);
603 void TOWNS_CDROM::status_accept(int extra, uint8_t s2, uint8_t s3, bool immediate_interrupt, const bool force_interrupt)
605 if(immediate_interrupt) {
606 status_accept2(force_interrupt, extra, s2, s3);
608 status_accept3(extra, s2, s3);
609 set_delay_ready(force_interrupt);
614 void TOWNS_CDROM::status_accept2(const bool force_interrupt, int extra, uint8_t s2, uint8_t s3)
616 status_accept3(extra, s2, s3);
618 bool i_enabled = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
619 if((stat_reply_intr) && (i_enabled)) { // Without MASK.
620 write_mcuint_signals(true);
626 void TOWNS_CDROM::status_accept3(int extra, uint8_t s2, uint8_t s3)
628 // Note: 2020-05-29 K.O
629 // Second byte (ARG s1) may below value (Thanks to Soji Yamakawa-San).
630 // 00h : NOT PLAYING CDDA
631 // 01h : DATA TRACK? (from Towns Linux)
632 // 03h : PLAYING CDDA
633 // 09h : MEDIA CHANGED? (from Towns Linux)
634 // 0Dh : After STOPPING CD-DA.Will clear.
635 // 01h and 09h maybe incorrect.
637 //uint8_t playcode = TOWNS_CD_ACCEPT_DATA_TRACK; // OK?
638 uint8_t playcode = TOWNS_CD_ACCEPT_NOERROR; // OK?
639 if(cdda_status == CDDA_PAUSED) {
640 playcode = TOWNS_CD_ACCEPT_CDDA_PAUSED;
641 } else if(cdda_status == CDDA_PLAYING) {
642 playcode = TOWNS_CD_ACCEPT_CDDA_PLAYING;
644 #if 0 // TRY 20230530 K.O
645 if(((latest_command & 0xb0) == 0xa0) ||
646 ((prev_command & 0xb0) == 0xa0)) {
647 switch(exec_params[0]) {
649 playcode = TOWNS_CD_ACCEPT_04H_FOR_CMD_A0H;
652 playcode = TOWNS_CD_ACCEPT_08H_FOR_CMD_A0H;
653 //playcode = TOWNS_CD_ACCEPT_NOERROR;
659 clear_status_queue(true);
662 extra_status = extra;
664 push_status_queue(TOWNS_CD_STATUS_ACCEPT, playcode, s2, s3);
669 void TOWNS_CDROM::send_mcu_ready()
672 if(stat_reply_intr) {
677 void TOWNS_CDROM::set_delay_ready(const bool force_interrupt)
679 // From Towns Linux 2.2
680 // But, some software (i.e. Star Cruiser II) failes to loading at 300uS.
681 // May need *at least* 1000uS. - 20200517 K.O
682 int evnum = (force_interrupt) ? EVENT_CDROM_DELAY_READY_FORCEINT : EVENT_CDROM_DELAY_READY;
683 force_register_event(this, evnum, 1000.0, false, event_delay_ready);
687 void TOWNS_CDROM::set_delay_ready_eot(const bool force_interrupt)
689 int evnum = (force_interrupt) ? EVENT_CDROM_READY_EOT_FORCEINT : EVENT_CDROM_READY_EOT;
690 force_register_event(this, evnum, 1000.0, false, event_delay_ready);
693 void TOWNS_CDROM::status_not_accept(int extra, uint8_t s1, uint8_t s2, uint8_t s3, bool immediate_interrupt, const bool force_interrupt)
695 clear_status_queue(true);
698 extra_status = extra;
700 push_status_queue(TOWNS_CD_STATUS_NOT_ACCEPT, s1, s2, s3);
702 command_execute_phase = false;
704 if(immediate_interrupt) {
706 bool i_enabled = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
707 if((stat_reply_intr) && (i_enabled)) { // Without MASK.
708 write_mcuint_signals(true);
713 set_delay_ready(force_interrupt);
717 const _TCHAR* TOWNS_CDROM::get_cdda_status_name(int _status)
719 const _TCHAR *playstatus = _T("UNKNOWN");
722 playstatus = _T("OFF ");
725 playstatus = _T("PLAY ");
728 playstatus = _T("PAUSE ");
731 playstatus = _T("ENDED ");
737 const _TCHAR* TOWNS_CDROM::get_command_name_from_command(uint8_t cmd)
739 const _TCHAR *cmdname = _T("UNKNOWN");
741 case CDROM_COMMAND_SEEK: // 00h
742 cmdname = _T("CDROM SEEK/RESTORE");
744 case CDROM_COMMAND_READ_MODE2: // 01h
745 cmdname = _T("CDROM READ MODE2");
747 case CDROM_COMMAND_READ_MODE1: // 02h
748 cmdname = _T("CDROM READ MODE1");
750 case CDROM_COMMAND_READ_RAW: // 03h
751 cmdname = _T("CDROM READ RAW");
753 case CDROM_COMMAND_PLAY_TRACK: // 04h
754 cmdname = _T("CDROM PLAY TRACK");
756 case CDROM_COMMAND_READ_TOC: // 05h
757 cmdname = _T("CDROM READ TOC");
759 case CDROM_COMMAND_READ_CDDA_STATE: // 06h
760 cmdname = _T("CDROM READ CDDA STATE (SUBQ)");
762 case CDROM_COMMAND_1F:
763 cmdname = _T("CDROM UNKNOWN CMD 1Fh");
765 case CDROM_COMMAND_SET_STATE: // 80h
766 cmdname = _T("CDROM SET STATE");
768 case CDROM_COMMAND_SET_CDDASET: // 81h
769 cmdname = _T("CDROM SET CDDA STATUS");
771 case CDROM_COMMAND_STOP_CDDA: // 84h
772 cmdname = _T("CDROM STOP CDDA");
774 case CDROM_COMMAND_PAUSE_CDDA: // 85h
775 cmdname = _T("CDROM PAUSE CDDA");
777 case CDROM_COMMAND_RESUME_CDDA: // 87h
778 cmdname = _T("CDROM RESUME CDDA");
784 * @brief Execute CD-ROM command.
785 * @arg command CD-ROM command.
786 * @note structure of comman is below:
787 * @note Bit7 and Bit4-0 : command code
788 * @note Bit6 : Interrupt on status at '1'
789 * @note Bit5 : Require status (must read from queue)..
791 void TOWNS_CDROM::execute_command(uint8_t command)
793 stat_reply_intr = ((command & 0x40) != 0) ? true : false;
794 req_status = ((command & 0x20) != 0) ? true : false;
795 latest_command = command;
797 for(int i = 0; i < 8; i++) {
798 exec_params[i] = param_queue->read();
800 param_queue->clear();
803 //command_received = false;
805 // if(!(is_device_ready()) && ((command & 0xb0) != 0xa0)) { // From MAME 0.254 20230530 K.O
806 // command_execute_phase = false;
807 // set_status(req_status, 0, TOWNS_CD_STATUS_DISC_NOT_READY, 0, 0, 0, false);
812 switch(command & 0x9f) {
813 case CDROM_COMMAND_SEEK: // 00h (RESTORE?)
815 // set_cdda_status(CDDA_OFF);
817 m = FROM_BCD(exec_params[0]);
818 s = FROM_BCD(exec_params[1]);
819 f = FROM_BCD(exec_params[2]);
820 int32_t lba = ((m * (60 * 75)) + (s * 75) + f) - 150;
823 cdrom_debug_log(_T("CMD SEEK(%02X) M/S/F = %d/%d/%d M2/S2/F2 = %d/%d/%d LBA=%d"), command,
824 TO_BCD(m), TO_BCD(s), TO_BCD(f),
825 TO_BCD(exec_params[3]), TO_BCD(exec_params[4]), TO_BCD(exec_params[5]),
828 double usec = 50.0e3; // From Tsugaru.
830 //double usec = get_seek_time(0); // At first, seek to track 0.
831 //if(usec < 1.0e3) usec = 1.0e3;
834 // At first, SEEK to LBA0.
835 // Next, SEEK TO ARG's LBA.
836 // Then, If set status to queue if (CMD & 20h) == 20h.
837 // Last, *FORCE TO MAKE* interrupt even (CMD & 20h) != 20h..
838 // See event_callback(EVENT_CDROM_RESTORE, foo).
841 force_register_event(this,
843 usec, false, event_seek);
846 case CDROM_COMMAND_READ_MODE2: // 01h
847 cdrom_debug_log(_T("CMD READ MODE2(%02X)"), command);
848 read_mode = CDROM_READ_MODE2;
851 case CDROM_COMMAND_READ_MODE1: // 02h
852 cdrom_debug_log(_T("CMD READ MODE1(%02X)"), command);
853 read_mode = CDROM_READ_MODE1;
856 case CDROM_COMMAND_READ_RAW: // 03h
857 cdrom_debug_log(_T("CMD READ RAW(%02X)"), command);
858 read_mode = CDROM_READ_RAW;
861 case CDROM_COMMAND_PLAY_TRACK: // 04h
862 cdrom_debug_log(_T("CMD PLAY TRACK(%02X)"), command);
863 play_cdda_from_cmd(); // ToDo : Re-Implement.
865 case CDROM_COMMAND_READ_TOC: // 05h
866 cdrom_debug_log(_T("CMD READ TOC(%02X)"), command);
868 if(status_media_changed_or_not_ready(false)) {
871 status_accept(1, 0x00, 0x00, true, false);
873 set_status(true, 2, TOWNS_CD_STATUS_TOC_ADDR, 0, 0xa0, 0, false);
877 case CDROM_COMMAND_READ_CDDA_STATE: // 06h
878 // ToDo: Some softwares check via this command, strongly to be fixed.
880 command_execute_phase = false;
882 if(status_media_changed_or_not_ready(false)) {
885 memcpy(subq_snapshot, subq_bytes, sizeof(subq_snapshot));
886 set_status(true, 1, TOWNS_CD_STATUS_ACCEPT, TOWNS_CD_ACCEPT_NOERROR, 0x00, 0x00, false);
891 case CDROM_COMMAND_1F:
892 cdrom_debug_log(_T("CMD UNKNOWN 1F(%02X)"), command);
893 command_execute_phase = false;
895 if(status_media_changed_or_not_ready(false)) {
898 status_accept(0, 0, 0, true, true); // Say reply.
901 //set_delay_ready(false); // OK? 20230127 K.O
904 case CDROM_COMMAND_SET_STATE: // 80h
905 cdrom_debug_log(_T("CMD SET STATE(%02X) PARAM=%02X %02X %02X %02X %02X %02X %02X %02X"),
916 command_execute_phase = false; // OK?
919 if(status_media_changed_or_not_ready(false)) {
923 uint8_t __s1 = TOWNS_CD_ACCEPT_NOERROR;
924 clear_status_queue(true);
926 // @note In SUPER REAL MAHJONG PIV, maybe check below.
927 // @note 20201110 K.O
928 __s1 = (toc_table[current_track].is_audio) ? TOWNS_CD_ACCEPT_WAIT : TOWNS_CD_ACCEPT_DATA_TRACK;
931 push_status_queue(TOWNS_CD_STATUS_ACCEPT, __s1, 0x00, 0x00);
933 status_accept(0, 0x00, 0x00, true, false); // Push queue Immediately
935 if(cdda_status == CDDA_ENDED) {
936 // From Tsugaru 95afde8c :
938 // Vain Dream crashes when CD BIOS Call AX=53C0H returns an error because the BIOS is expecting
939 // status 00 00 00 00, but this PushStatusCDDAPlayEnded() pushes 07 00 00 00.
940 // The retry code jumps to 4600:0084
941 // 4600:0084 1E PUSH DS
942 // 4600:0085 8CC8 MOV AX,CS
943 // However, it should really jump to 4600:0085. By jumping to 4600:0084, PUSH DS moves SP
944 // by two bytes, and the subsequent RETF fails to return to the correct address.
946 // Vain Dream runs by commenting out PushStatusCDDAPlayEnded() below. But,
947 // in the past I saw something (presumably one version of CD-ROM BIOS) was expecting
948 // 07 00 00 00 status after CDDA is done, but I cannot find it
950 // Maybe subsequent to CDDA Stop command?
952 // PushStatusCDDAPlayEnded();
953 set_cdda_status(CDDA_OFF);
955 if(stat_reply_intr) {
957 write_mcuint_signals(true);
962 case CDROM_COMMAND_SET_CDDASET: // 81h
963 cdrom_debug_log(_T("%s(%02X)"), get_command_name_from_command(command), command);
964 command_execute_phase = false;
967 // I don't know what to do with this command.
968 // CDROM BIOS AH=52H fires command 0xA1 with parameters {07 FF 00 00 00 00 00 00}
969 if(!(status_media_changed_or_not_ready(false))) {
970 //status_accept(0, 0x00, 0x00, true, true); // OK?
971 status_accept(0, 0x00, 0x00, true, false); // OK?
976 case CDROM_COMMAND_STOP_CDDA: // 84h
977 cdrom_debug_log(_T("CMD STOP CDDA(%02X)"), command);
978 ///@note From Tsugaru : 20200530 K.O
979 // clear_event(this, event_drq);
980 // write_signals(&outputs_drq, 0x00000000); // CLEAR DRQ
982 if(cdda_status == CDDA_PLAYING) {
983 force_register_event(this, EVENT_CDDA_DELAY_STOP, 1000.0, false, event_cdda_delay_stop);
985 clear_event(this, event_cdda_delay_stop);
986 stop_cdda_from_cmd();
989 case CDROM_COMMAND_PAUSE_CDDA: // 85h
990 cdrom_debug_log(_T("CMD PAUSE CDDA2(%02X)"), command);
991 pause_cdda_from_cmd(); // ToDo : Re-Implement.
993 case CDROM_COMMAND_RESUME_CDDA: // 87h
994 cdrom_debug_log(_T("CMD RESUME CDDA(%02X)"), command);
995 unpause_cdda_from_cmd();
997 case CDROM_COMMAND_86: // 86h
998 cdrom_debug_log(_T("CMD UNKNOWN 86(%02X)"), command);
999 status_not_accept(0, 0x00, 0x00, 0x00, false, true); // ToDo: Will implement
1001 case CDROM_COMMAND_9F: // 9Fh
1002 cdrom_debug_log(_T("CMD UNKNOWN 9F(%02X)"), command);
1003 command_execute_phase = false;
1004 clear_status_queue(true);
1005 push_status_queue(TOWNS_CD_STATUS_CMD_ABEND, 0x00, 0x00, 0x00); // OK?
1007 //set_delay_ready(false); // OK? 20230127 K.O
1010 cdrom_debug_log(_T("CMD Illegal(%02X)"), command);
1011 command_execute_phase = false;
1012 status_not_accept(0, 0x00, 0x00, 0x00, false, true); // ToDo: Will implement
1017 void TOWNS_CDROM::set_extra_status_values(uint8_t s0, uint8_t s1, uint8_t s2, uint8_t s3, const bool is_immediate, const bool force_interrupt)
1019 clear_status_queue(false);
1020 push_status_queue(s0, s1, s2, s3);
1021 // cdrom_debug_log(_T("SET EXTRA STATUS %02x: %02x %02x %02x %02x EXTRA COUNT=%d"), latest_command, s0, s1, s2, s3, extra_status);
1025 bool i_enable = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
1026 if((stat_reply_intr) && (i_enable)) { // From Tsugaru, 20231001
1030 set_delay_ready(force_interrupt);
1034 void TOWNS_CDROM::set_status_extra_toc_addr(uint8_t s1, uint8_t s2, uint8_t s3)
1036 set_extra_status_values(TOWNS_CD_STATUS_TOC_ADDR, s1, s2, s3, false, false); // OK?
1040 void TOWNS_CDROM::set_status_extra_toc_data(uint8_t s1, uint8_t s2, uint8_t s3)
1042 set_extra_status_values(TOWNS_CD_STATUS_TOC_DATA, s1, s2, s3, false, false); // OK?
1046 uint8_t TOWNS_CDROM::read_status()
1049 if(status_queue->empty()) {
1053 val = status_queue->read();
1054 has_status = (status_queue->empty()) ? false : true;
1056 if((status_queue->empty()) && (extra_status > 0)) {
1063 void TOWNS_CDROM::dma_transfer_epilogue()
1067 // ToDo: CD-ROM with cache.
1070 dma_transfer_phase = false;
1071 pio_transfer_phase = false;
1072 //dma_transfer = false;
1073 //pio_transfer = false;
1074 write_signals(&outputs_drq, 0x00000000); // CLEAR DRQ
1076 if(read_length <= 0) {
1077 clear_event(this, event_next_sector);
1078 dma_transfer = false;
1079 pio_transfer = false;
1080 status_seek = false;
1081 cdrom_debug_log(_T("DMA: EOT by READ COMPLETED"));
1082 write_signals(&outputs_eot, 0xffffffff);
1083 status_read_done(false);
1085 // Call to read next sector. -> Move to READING EVENT.
1091 void TOWNS_CDROM::pio_transfer_epilogue()
1094 // ToDo: CD-ROM with cache.
1098 dma_transfer_phase = false;
1099 pio_transfer_phase = false;
1100 //dma_transfer = false;
1101 //pio_transfer = false;
1102 write_signals(&outputs_drq, 0x00000000); // CLEAR DRQ
1104 if(read_length <= 0) {
1105 status_seek = false;
1106 dma_transfer = false;
1107 pio_transfer = false;
1108 clear_event(this, event_next_sector);
1109 cdrom_debug_log(_T("PIO: EOT by READ COMPLETED"));
1110 //write_signals(&outputs_eot, 0xffffffff);
1111 status_read_done(false);
1113 // Call to read next sector
1116 int physical_size = physical_block_size();
1117 int l = physical_size - logical_block_size();
1119 register_event(this, EVENT_CDROM_READY_TO_READ,
1120 (1.0e6 / ((double)transfer_speed * 150.0e3)) *
1123 &event_next_sector);
1124 //cdrom_debug_log(_T("PIO: NEXT SECTOR LEFT=%d"), read_length);
1127 // set_dma_intr(true);
1130 uint32_t TOWNS_CDROM::read_dma_io8w(uint32_t addr, int *wait)
1132 __LIKELY_IF(wait != NULL) {
1133 *wait = 0; // Temporally.
1135 __UNLIKELY_IF(!(dmac_running) && (dma_transfer_phase) && (dma_transfer)) { // Fallthrough
1138 bool is_empty = databuffer->empty();
1140 __UNLIKELY_IF(!(dma_transfer_phase) && !(pio_transfer_phase)) {
1143 __UNLIKELY_IF(is_empty) {
1144 data_reg.b.h = data_reg.b.l;
1145 data_reg.b.l = 0x00;
1149 __LIKELY_IF(dma_transfer_phase) {
1150 write_signals(&outputs_drq, 0x0);
1151 } else if(pio_transfer_phase) {
1152 if(!(is_empty) && (databuffer->empty())) {
1153 cancel_event(this, event_delay_ready);
1154 pio_transfer_epilogue();
1155 //register_event(this, EVENT_CDROM_DELAY_EOT_PIO,
1156 // 1.0, // Temporally
1158 // &event_delay_ready);
1161 return data_reg.b.l;
1164 void TOWNS_CDROM::write_dma_io8w(uint32_t addr, uint32_t data, int *wait)
1166 *wait = 0; // Temporally.
1171 uint32_t TOWNS_CDROM::read_dma_io16w(uint32_t addr, int *wait)
1173 __LIKELY_IF(wait != NULL) {
1174 *wait = 0; // Temporally.
1176 __UNLIKELY_IF(!(dmac_running) && (dma_transfer_phase) && (dma_transfer)) { // Fallthrough
1179 bool is_empty = databuffer->empty();
1181 __UNLIKELY_IF(!(dma_transfer_phase) && !(pio_transfer_phase)) {
1184 __UNLIKELY_IF(is_empty) {
1185 data_reg.w = 0x0000;
1189 __LIKELY_IF(dma_transfer_phase) {
1190 write_signals(&outputs_drq, 0x0);
1191 } else if(pio_transfer_phase) {
1192 if(!(is_empty) && (databuffer->empty())) {
1193 cancel_event(this, event_delay_ready);
1194 pio_transfer_epilogue();
1195 //register_event(this, EVENT_CDROM_DELAY_EOT_PIO,
1196 // 1.0, // Temporally
1198 // &event_delay_ready);
1204 void TOWNS_CDROM::write_dma_io16w(uint32_t addr, uint32_t data, int *wait)
1206 *wait = 0; // Temporally.
1211 void TOWNS_CDROM::read_cdrom()
1214 if((cdda_status != CDDA_OFF) && (cdda_status != CDDA_ENDED)) {
1215 // @note In SUPER REAL MAHJONG PIV, use PAUSE (A5h) command before reading.
1216 // @note 20201110 K.O
1217 set_cdda_status(CDDA_ENDED);
1219 set_cdda_status(CDDA_OFF);
1221 if(status_media_changed_or_not_ready(false)) {
1228 // uint8_t pad1, dcmd;
1230 m1 = FROM_BCD(exec_params[0]);
1231 s1 = FROM_BCD(exec_params[1]);
1232 f1 = FROM_BCD(exec_params[2]);
1234 m2 = FROM_BCD(exec_params[3]);
1235 s2 = FROM_BCD(exec_params[4]);
1236 f2 = FROM_BCD(exec_params[5]);
1237 uint8_t pad1 = exec_params[6];
1238 uint8_t dcmd = exec_params[7];
1240 int32_t lba1 = ((m1 * (60 * 75)) + (s1 * 75) + f1) - 150;
1241 int32_t lba2 = ((m2 * (60 * 75)) + (s2 * 75) + f2) - 150;
1248 cdrom_debug_log(_T("READ_CDROM LBA1=%d LBA2=%d M1/S1/F1=%02X/%02X/%02X M2/S2/F2=%02X/%02X/%02X PAD=%02X DCMD=%02X"), lba1, lba2,
1249 exec_params[0], exec_params[1], exec_params[2],
1250 exec_params[3], exec_params[4], exec_params[5],
1252 uint32_t cur_lba = get_image_cur_position();
1255 if((lba1 > lba2) || (lba1 < 0) || (lba2 < 0)) { // NOOP?
1256 status_parameter_error(false);
1260 track = get_track(lba1);
1261 //track = get_track_noop(lba1);
1262 if((track <= 0) || (track >= track_num)) {
1263 status_parameter_error(false);
1266 __remain = (lba2 - lba1 + 1);
1267 read_length = __remain * logical_block_size();
1269 current_track = track;
1270 dma_transfer_phase = false;
1271 pio_transfer_phase = false;
1275 //clear_event(this, event_drq);
1276 clear_event(this, event_next_sector);
1281 databuffer->clear();
1283 //double usec = get_seek_time(lba1);
1284 next_seek_lba = lba1;
1287 clear_event(this, event_next_sector);
1288 clear_event(this, event_seek);
1290 write_signals(&outputs_drq, 0x00000000); // CLEAR DRQ
1291 register_event(this, EVENT_CDROM_READY_TO_READ, usec, false, &event_next_sector);
1294 status_accept(0, 0, 0, true, false);
1299 void TOWNS_CDROM::set_status(const bool push_status, int extra, uint8_t s0, uint8_t s1, uint8_t s2, uint8_t s3, const bool force_interrupt)
1301 cdrom_debug_log(_T("SET STATUS: %02X %02X %02X %02X, EXTRA=%d REQ_STATUS=%s"),
1304 (push_status) ? _T("Yes"): _T("No")
1306 clear_status_queue(true);
1307 if(!(push_status) || (extra <= 0)) {
1308 command_execute_phase = false;
1311 if(extra > 0) extra_status = extra;
1312 push_status_queue(s0, s1, s2, s3);
1314 set_delay_ready(force_interrupt);
1317 void TOWNS_CDROM::set_status_read_done(bool push_status, int extra, uint8_t s0, uint8_t s1, uint8_t s2, uint8_t s3)
1319 cdrom_debug_log(_T("SET STATUS(READ DONE): %02X %02X %02X %02X, EXTRA=%d REQ_STATUS=%s"),
1322 (push_status) ? _T("Yes"): _T("No")
1324 clear_status_queue(true);
1326 extra_status = extra;
1328 command_execute_phase = false;
1329 push_status_queue(s0, s1, s2, s3);
1330 set_delay_ready_eot(false);
1333 void TOWNS_CDROM::set_status_cddareply(const bool force_interrupt, int extra, uint8_t s2, uint8_t s3)
1335 cdrom_debug_log(_T("SET STATUS(CDDA REPLY): %02X %02X, EXTRA=%d REQ_STATUS=%s, FORCE_INTERRUPT=%s"),
1338 (req_status) ? _T("Yes"): _T("No"),
1339 (force_interrupt) ? _T("Yes"): _T("No")
1341 clear_status_queue(true);
1343 if(!(req_status) || (extra <= 0)) {
1344 command_execute_phase = false;
1347 if(status_media_changed_or_not_ready(force_interrupt)) {
1351 status_accept(extra, s2, s3, true, force_interrupt);
1355 void TOWNS_CDROM::set_status_immediate(const bool push_status, const bool force_interrupt, int extra, uint8_t s0, uint8_t s1, uint8_t s2, uint8_t s3)
1357 cdrom_debug_log(_T("SET STATUS(IMMEDIATE): %02X %02X %02X %02X, EXTRA=%d FORCE_INTERRUPT=%s, PUSH_STATUS=%s"),
1360 (force_interrupt) ? _T("Yes"): _T("No"),
1361 (push_status) ? _T("Yes"): _T("No")
1363 clear_status_queue(true);
1364 if(!(push_status) || (extra <= 0)) {
1365 command_execute_phase = false;
1369 extra_status = extra;
1371 push_status_queue(s0, s1, s2, s3);
1375 bool i_enable = (!(mcu_intr_mask) || (force_interrupt)) ? true : false;
1376 if((stat_reply_intr) && (req_status) && (i_enable)) { // From Tsugaru, 20231001
1381 void TOWNS_CDROM::set_extra_status()
1383 switch(latest_command & 0x9f) {
1384 //switch(prev_command & 0x9f) {
1385 case CDROM_COMMAND_SEEK:
1386 if(extra_status > 0) {
1387 set_extra_status_values(TOWNS_CD_STATUS_SEEK_COMPLETED, 0x00, 0x00, 0x00, false, false);
1390 command_execute_phase = false;
1392 case CDROM_COMMAND_READ_MODE1:
1393 case CDROM_COMMAND_READ_MODE2:
1394 case CDROM_COMMAND_READ_RAW:
1395 //if(extra_status == 2) {
1396 // status_data_ready(false);
1398 command_execute_phase = false;
1401 case CDROM_COMMAND_PLAY_TRACK: // PLAY CDDA
1402 // From MAME 0.254. 20230530 K.O
1403 if(cdda_status != CDDA_PLAYING) {
1404 set_extra_status_values(TOWNS_CD_STATUS_PLAY_DONE, 0, 0, 0, false, false);
1406 set_extra_status_values(TOWNS_CD_STATUS_ACCEPT, 0, TOWNS_CD_ACCEPT_CDDA_PLAYING, 0, false, false); // OK?
1408 command_execute_phase = false;
1411 case CDROM_COMMAND_READ_TOC: // 0x05
1412 switch(extra_status) {
1414 set_status_extra_toc_addr(0x00, 0xa0, 0x00);
1416 case 2: // st1 = first_track_number
1417 set_status_extra_toc_data(TO_BCD(0x01), 0x00, 0x00);
1420 set_status_extra_toc_addr(0x00, 0xa1, 0x00);
1423 set_status_extra_toc_data(TO_BCD(track_num - 1), 0x00, 0x00); // OK?
1426 set_status_extra_toc_addr(0x00, 0xa2, 0x00);
1431 msf.d= read_signal(SIG_TOWNS_CDROM_START_MSF_AA);
1432 set_status_extra_toc_data(msf.b.h2, msf.b.h, msf.b.l); // OK?
1437 if((extra_status & 0x01) != 0) {
1438 // stat_track = (extra_status - 2) >> 1;
1439 uint32_t adr_control = cdrom_get_adr(stat_track);
1440 set_status_extra_toc_addr(((adr_control & 0x0f) << 4) | ((adr_control >> 4) & 0x0f), TO_BCD((extra_status / 2) - 2), 0x00);
1443 msf.d = read_signal(SIG_TOWNS_CDROM_START_MSF);
1444 cdrom_debug_log(_T("TRACK=%d M:S:F=%02X:%02X:%02X"), stat_track - 1, msf.b.h2, msf.b.h, msf.b.l);
1445 set_status_extra_toc_data(msf.b.h2, msf.b.h, msf.b.l); // OK?
1446 if((track_num <= 0) || (stat_track >= track_num)) {
1447 command_execute_phase = false; // OK?
1448 extra_status = 0; // It's end.
1454 case CDROM_COMMAND_READ_CDDA_STATE: // 06h
1455 switch(extra_status) {
1458 set_extra_status_values(TOWNS_CD_STATUS_SUBQ_READ1, 0x00, subq_snapshot[2], 0x00, false, false);
1463 set_extra_status_values(TOWNS_CD_STATUS_SUBQ_READ2, subq_snapshot[7], subq_snapshot[8], subq_snapshot[9], false, false);
1468 set_extra_status_values(TOWNS_CD_STATUS_SUBQ_READ3, 0x00, subq_snapshot[3], subq_snapshot[4], false, false);
1473 set_extra_status_values(TOWNS_CD_STATUS_SUBQ_READ4, 0x00, subq_snapshot[5], 0x00, false, false);
1474 command_execute_phase = false;
1478 command_execute_phase = false;
1483 case CDROM_COMMAND_SET_STATE: // 80h Thank to Yamakawa-San.20200626 K.O
1484 if(extra_status > 0) {
1485 set_extra_status_values(TOWNS_CD_STATUS_PLAY_DONE, 0x00, 0x00, 0x00, false, false);
1488 command_execute_phase = false;
1490 case CDROM_COMMAND_STOP_CDDA:
1491 switch(extra_status) {
1493 set_extra_status_values(TOWNS_CD_STATUS_STOP_DONE, 0x00, 0x00, 0x00, false, false);
1495 //extra_status = 0; // OK? 20230530 K.O from MAME 0.254
1498 set_extra_status_values(0x00, TOWNS_CD_ACCEPT_WAIT, 0x00, 0x00, false, false);
1500 command_execute_phase = false;
1504 command_execute_phase = false;
1508 case CDROM_COMMAND_PAUSE_CDDA:
1509 if(extra_status == 1) {
1510 set_extra_status_values(TOWNS_CD_STATUS_PAUSE_DONE, 0x00, 0x00, 0x00, false, false);
1513 command_execute_phase = false;
1515 case CDROM_COMMAND_RESUME_CDDA:
1516 if(extra_status == 1) {
1517 set_extra_status_values(TOWNS_CD_STATUS_RESUME_DONE, 0, 0x00, 0x00, false, false); // From Tsugaru
1520 command_execute_phase = false;
1524 command_execute_phase = false;
1529 uint32_t TOWNS_CDROM::read_signal(int id)
1532 case SIG_TOWNS_CDROM_READ_DATA:
1535 case SIG_TOWNS_CDROM_PLAYING:
1536 return (cdda_status == CDDA_PLAYING && cdda_interrupt) ? 0xffffffff : 0;
1538 case SIG_TOWNS_CDROM_SAMPLE_L:
1539 return (uint32_t)abs(cdda_sample_l);
1541 case SIG_TOWNS_CDROM_SAMPLE_R:
1542 return (uint32_t)abs(cdda_sample_r);
1544 case SIG_TOWNS_CDROM_IS_MEDIA_INSERTED:
1545 return ((is_device_ready()) ? 0xffffffff : 0x00000000);
1547 case SIG_TOWNS_CDROM_MAX_TRACK:
1548 if(track_num <= 0) {
1549 return (uint32_t)(TO_BCD(0x00));
1551 return (uint32_t)(TO_BCD(track_num));
1555 case SIG_TOWNS_CDROM_REACHED_MAX_TRACK:
1556 if(track_num <= 0) {
1559 if(current_track >= track_num) {
1567 case SIG_TOWNS_CDROM_CURRENT_TRACK:
1568 if(current_track >= track_num) {
1571 return TO_BCD(current_track);
1574 case SIG_TOWNS_CDROM_START_MSF:
1576 int trk = stat_track;
1583 int index0 = toc_table[trk].index0;
1584 int index1 = toc_table[trk].index1;
1585 int pregap = toc_table[trk].pregap;
1586 //if(pregap > 0) index0 = index0 + pregap;
1587 //if(index0 < 150) index0 = 150;
1588 uint32_t lba = (uint32_t)index0;
1589 uint32_t msf = lba_to_msf(lba); // Q:lba + 150?
1594 case SIG_TOWNS_CDROM_START_MSF_AA:
1596 int trk = track_num;
1597 int index0 = toc_table[trk].index0;
1598 int index1 = toc_table[trk].index1;
1599 int pregap = toc_table[trk].pregap;
1600 uint32_t lba = (uint32_t)index0;
1601 if(pregap > 0) lba = lba + pregap;
1602 if(lba < 150) lba = 150;
1603 uint32_t msf = lba_to_msf(lba); // Q:lba + 150?
1607 case SIG_TOWNS_CDROM_RELATIVE_MSF:
1608 if(!(is_device_ready())) {
1611 if((current_track <= 0) || (current_track >= track_num)) {
1614 if(toc_table[current_track].is_audio) {
1615 // uint32_t index1 = toc_table[current_track].index1;
1616 uint32_t index1 = cdda_start_frame;
1617 if(cdda_playing_frame <= cdda_start_frame) {
1620 if(cdda_end_frame <= cdda_start_frame) {
1624 uint32_t lba = cdda_playing_frame;
1625 __UNLIKELY_IF(lba >= cdda_end_frame) {
1626 if(cdda_repeat_count == 0) {
1629 if(cdda_end_frame > index1) {
1630 lba = cdda_end_frame;
1639 return lba_to_msf(n);
1642 uint32_t index1 = toc_table[current_track].index1;
1643 uint32_t lba = get_image_cur_position();
1648 return lba_to_msf(n);
1651 case SIG_TOWNS_CDROM_ABSOLUTE_MSF:
1652 if(!(is_device_ready())) {
1655 if((current_track <= 0) || (current_track >= track_num)) {
1660 if(toc_table[current_track].is_audio) {
1661 if((cdda_status == CDDA_PLAYING) || (cdda_status == CDDA_PAUSED)) {
1662 if(cdda_playing_frame >= max_logical_block) {
1663 lba = max_logical_block;
1665 lba = cdda_playing_frame;
1668 lba = cdda_end_frame;
1671 lba = get_image_cur_position();
1672 if(lba > max_logical_block) {
1673 lba = max_logical_block;
1676 return lba_to_msf(lba + 75 * 2);
1679 case SIG_TOWNS_CDROM_GET_ADR:
1680 return cdrom_get_adr(stat_track);
1683 // ToDo: Implement master DEV
1684 //return SCSI_DEV::read_signal(id);
1687 return 0; // END TRAM
1690 uint32_t TOWNS_CDROM::cdrom_get_adr(int trk)
1692 if(!(is_device_ready())) {
1693 return 0xffffffff; // OK?
1696 return 0x10; // AUDIO SUBQ
1698 if(trk > track_num) {
1699 return 0xffffffff; // OK?
1701 if(toc_table[trk].is_audio) {
1704 return 0x14; // return as data
1707 const int TOWNS_CDROM::physical_block_size()
1709 if(current_track <= 0) return 2352; // PAD
1710 if(!mounted()) return 2352; // PAD
1711 if(is_iso) return 2352;
1712 switch(toc_table[current_track].type) {
1715 case MODE_MODE1_2048:
1717 case MODE_MODE1_2352:
1718 case MODE_MODE2_2352:
1721 case MODE_MODE2_2336:
1733 const int TOWNS_CDROM::logical_block_size()
1735 if(current_track <= 0) return 2352; // PAD
1736 if(!mounted()) return 2352; // PAD
1737 if(is_iso) return 2048;
1738 switch(toc_table[current_track].type) {
1741 case MODE_MODE1_2048:
1742 case MODE_MODE1_2352:
1744 case MODE_MODE2_2336:
1745 case MODE_MODE2_2352:
1758 bool TOWNS_CDROM::start_to_play_cdda()
1760 status_seek = false;
1764 databuffer->clear();
1765 current_track = get_track(cdda_start_frame);
1766 set_subq(cdda_start_frame);
1768 if((current_track <= 0) || (current_track >= track_num)) {
1769 set_cdda_status(CDDA_OFF);
1770 return false; // SEEK ERROR;
1772 if(!(toc_table[current_track].is_audio)) {
1774 set_cdda_status(CDDA_OFF);
1778 cdda_playing_frame = cdda_start_frame;
1779 read_sector = cdda_start_frame;
1780 seek_relative_frame_in_image(cdda_playing_frame);
1781 //if(cdda_status != CDDA_PLAYING) {
1782 set_cdda_status(CDDA_PLAYING);
1784 if(prefetch_audio_sectors(1) < 1) {
1785 set_cdda_status(CDDA_OFF);
1786 return false; // READ ERROR
1791 void TOWNS_CDROM::event_callback(int event_id, int err)
1794 case EVENT_CDROM_DELAY_COMMAND:
1795 if((command_execute_phase) /*|| !(mcu_ready)*/) {
1798 clear_event(this, event_execute);
1799 // Backup previous command.
1800 prev_command = latest_command;
1801 for(int i = 0; i < 8; i++) {
1802 prev_params[i] = exec_params[i];
1804 command_execute_phase = true;
1805 execute_command(reserved_command);
1807 case EVENT_CDROM_DELAY_INTERRUPT_ON: // DELAY INTERRUPT ON
1808 event_delay_interrupt = -1;
1812 case EVENT_CDROM_DELAY_INTERRUPT_OFF: // DELAY INTERRUPT OFF
1813 event_delay_interrupt = -1;
1815 set_mcu_intr(false);
1817 case EVENT_CDROM_DELAY_READY: // CALL READY TO ACCEPT COMMAND WITH STATUS
1818 event_delay_ready = -1;
1819 media_changed = false;
1820 media_ejected = false;
1822 send_mcu_ready(); // OK? 20230127 K.O
1824 case EVENT_CDROM_DELAY_READY_FORCEINT: // CALL READY TO ACCEPT COMMAND WITH STATUS
1825 event_delay_ready = -1;
1826 media_changed = false;
1827 media_ejected = false;
1831 //stat_reply_intr = false;
1833 case EVENT_CDROM_DELAY_NOT_READY: // CALL READY TO ACCEPT COMMAND WITH STATUS
1834 event_delay_ready = -1;
1836 media_changed = false;
1837 media_ejected = false;
1838 command_execute_phase = false;
1840 if(stat_reply_intr) {
1844 case EVENT_CDROM_DELAY_NOT_READY_FORCEINT: // CALL READY TO ACCEPT COMMAND WITH STATUS
1845 event_delay_ready = -1;
1847 media_changed = false;
1848 media_ejected = false;
1849 command_execute_phase = false;
1853 case EVENT_CDROM_READY_EOT: // CALL END-OF-TRANSFER FROM CDC.
1854 event_delay_ready = -1;
1857 media_changed = false;
1858 media_ejected = false;
1859 command_execute_phase = false;
1862 if(stat_reply_intr) {
1867 case EVENT_CDROM_READY_EOT_FORCEINT: // CALL END-OF-TRANSFER FROM CDC.
1868 event_delay_ready = -1;
1871 media_changed = false;
1872 media_ejected = false;
1873 command_execute_phase = false;
1879 case EVENT_CDROM_DELAY_EOT_PIO:
1880 event_delay_ready = -1;
1881 media_changed = false;
1882 media_ejected = false;
1883 command_execute_phase = false;
1884 pio_transfer_epilogue();
1886 case EVENT_CDDA_DELAY_PLAY: // DELAY STARTING TO PLAY CDDA
1887 event_cdda_delay_play = -1;
1888 start_to_play_cdda();
1890 * @note This may solve halt incident of Kyukyoku Tiger, but something are wrong.
1891 * @note 20201113 K.O
1893 set_status_cddareply(false, 1, 0x00, 0x00);
1895 case EVENT_CDDA_REPEAT: // DELAY STARTING TO PLAY CDDA
1896 event_cdda_delay_play = -1;
1897 clear_event(this, event_cdda);
1898 if(cdda_status != CDDA_PLAYING) {
1902 cdda_buffer_ptr = 0;
1904 int track = get_track(cdda_start_frame);
1905 if((track > 0) && (track < track_num)) {
1906 cdda_playing_frame = cdda_start_frame;
1907 read_sector = cdda_playing_frame;
1908 current_track = track;
1909 seek_relative_frame_in_image(cdda_playing_frame);
1910 cdda_stopped = false;
1911 if(prefetch_audio_sectors(1) < 1) {
1912 //set_cdda_status(CDDA_OFF);
1913 return; // READ ERROR
1917 current_track = get_track(0);
1918 cdda_playing_frame = 0;
1920 cdda_start_frame = 0;
1922 cdda_stopped = true;
1923 //set_cdda_status(CDDA_OFF);
1926 if(mix_loop_num == 0) {
1927 if(event_cdda < 0) {
1928 register_event(this, EVENT_CDDA, 1.0e6 / 44100.0, true, &event_cdda);
1932 set_realtime_render(this, true);
1933 const _TCHAR *pp = get_cdda_status_name(cdda_status);
1934 cdrom_debug_log(_T("REPEAT CDDA from %s.\n"), pp);
1937 case EVENT_CDROM_CDDA_PLAY_STATUS: // READY TO ACCEPT A COMMAND FROM CDC.
1938 event_delay_ready = -1;
1939 send_mcu_ready(); // OK? 20230127 K.O
1941 case EVENT_CDDA: // READ A PAIR OF CDDA SAMPLE
1942 read_a_cdda_sample();
1945 case EVENT_CDDA_DELAY_STOP: // DELAY STOP
1946 event_cdda_delay_stop = -1;
1947 stop_cdda_from_cmd();
1949 case EVENT_CDROM_RESTORE: // Restore to LBA 0.
1952 // 20231001 Backport from Tsugaru.
1954 //status_accept(0, 0, 0, true, true); // Say reply.
1957 current_track = get_track(0);
1958 //if(next_seek_lba == 0) { // Inside of pregap
1959 // event_callback(EVENT_CDROM_SEEK, 0);
1962 double usec = 50.0e3; // From Tsugaru.
1964 //double usec = get_seek_time(next_seek_lba);
1965 //if(usec < 1.0e3) usec = 1.0e3;
1966 cdrom_debug_log(_T("RESTORE to SECTOR 0: NEXT is %d after %f"), next_seek_lba, usec);
1968 register_event(this,
1970 usec, false, &event_seek);
1973 case EVENT_CDROM_SEEK: // SEEK TO TARGET LBA (only for command 00h)
1975 status_seek = false;
1976 current_track = get_track(next_seek_lba);
1977 set_subq(next_seek_lba);
1978 cdrom_debug_log(_T("SEEK COMPLETED to SECTOR %d"), next_seek_lba);
1980 command_execute_phase = false;
1981 status_accept(1, 0, 0, false, true); // Say reply. Force to interrupt.
1983 case EVENT_CDROM_TIMEOUT: // CDC TIMEOUT (mostly READ BUFFER OVERRUN)
1984 event_time_out = -1;
1985 status_time_out(false);
1986 cdrom_debug_log(_T("READ TIME OUT"));
1988 case EVENT_CDROM_READ_PRE_SEEK:
1990 current_track = get_track(next_seek_lba);
1991 read_sector = next_seek_lba;
1992 set_subq(next_seek_lba);
1993 status_seek = false;
1994 if((read_length > 0) && (current_track > 0) && (current_track < track_num)) {
1996 event_callback(EVENT_CDROM_READY_TO_READ, 1);
1998 status_illegal_lba(0, TOWNS_CD_ABEND_PARAMETER_ERROR, 0, 0); // OK?
2001 case EVENT_CDROM_READY_TO_READ: // SEEK TO TARGET LBA FOR READING (A) SECTOR(S)
2002 event_next_sector = -1;
2004 status_seek = false;
2005 // ToDo: Prefetch 20201116
2006 if(read_length > 0) {
2008 //status_seek = true;
2009 // cdrom_debug_log(_T("READ DATA SIZE=%d BUFFER COUNT=%d"), logical_block_size(), databuffer->count());
2010 /// Below has already resolved! Issue of DMAC.20201114 K.O
2011 // Note: Still error with reading D000h at TownsOS v1.1L30.
2012 // Maybe data has changed to 1Fh from 8Eh.
2014 // ToDo: Prefetch Sectors.
2015 int logical_size = logical_block_size();
2016 //if(databuffer->left() < logical_size) {
2017 if(!(databuffer->empty())) { // ToDO: CACHING.
2018 // BE RETRY WHEN BUFFER FULL.
2019 register_event(this, EVENT_CDROM_READY_TO_READ,
2020 (1.0e6 / ((double)transfer_speed * 150.0e3)) *
2023 &event_next_sector);
2026 set_subq(read_sector);
2027 stat = read_buffer(1);
2030 // Note: EMULATE NONE BUFFER, move belows from EVENT_CDROM_NEXT_SECTOR. 20230531 K.O
2031 //status_data_ready(true);
2032 //set_dma_intr(true);
2033 register_event(this, EVENT_CDROM_NEXT_SECTOR,
2034 (1.0e6 / ((double)transfer_speed * 150.0e3)) *
2035 (double)logical_size *
2037 false, &event_next_sector);
2042 case EVENT_CDROM_NEXT_SECTOR: // READY TO READ (A) NEXT SECTOR(S).
2043 event_next_sector = -1;
2044 // BIOS FDDFCh(0FC0h:01FCh)-
2045 status_seek = false;
2046 // Workaround for dma_interrupt hasn't cleared.
2047 // This is from Tsugaru, commit 95afde8c, "Support CD-ROM CPU Data Transfer." .
2048 status_data_ready(false);
2050 if(read_length > 0) {
2052 int physical_size = physical_block_size();
2053 int l = physical_size - logical_block_size();
2055 register_event(this, EVENT_CDROM_READY_TO_READ,
2056 (1.0e6 / ((double)transfer_speed * 150.0e3)) *
2059 &event_next_sector);
2062 case EVENT_CDROM_DELAY_START_DRQ: // DELAY START DRQ
2063 do_drq(); // First, may (sould) delay from rise up.
2066 // ToDo: Another events.
2067 //SCSI_DEV::event_callback(event_id, err);
2072 int TOWNS_CDROM::read_sectors_image(int sectors, uint32_t& transferred_bytes)
2075 cdimage_buffer_t tmpbuf;
2076 size_t _read_size; //!< read size from image file.
2077 size_t _transfer_size; //!< transfer size to data buffer.
2078 size_t _offset = sizeof(cd_data_head_t); //!< Data offset from head of sector.
2083 transferred_bytes = 0;
2086 case CDROM_READ_MODE1:
2087 _transfer_size = 2048;
2090 startp = &(tmpbuf.mode1.data[0]);
2093 startp = (uint8_t*)(&tmpbuf);
2095 datap = &(tmpbuf.mode1.data[0]);
2097 case CDROM_READ_MODE2:
2098 _transfer_size = 2336;
2101 startp = &(tmpbuf.mode2.data[0]);
2104 startp = (uint8_t*)(&tmpbuf);
2106 datap = &(tmpbuf.mode2.data[0]);
2108 case CDROM_READ_RAW:
2109 case CDROM_READ_AUDIO:
2112 _transfer_size = 2352;
2113 startp = (uint8_t*)(&tmpbuf);
2114 datap = (uint8_t*)(&tmpbuf);
2117 // ToDo: Implement for unexpected type.
2118 return -1; // None sectors.
2122 while(sectors > 0) {
2123 //cdrom_debug_log(_T("TRY TO READ SECTOR:LBA=%d"), read_sector);
2124 memset(&tmpbuf, 0x00, sizeof(tmpbuf));
2125 int _trk = check_cdda_track_boundary(read_sector);
2126 if(_trk <= 0) { // END
2127 status_illegal_lba(0, 0x00, 0x00, 0x00);
2130 if(_trk != current_track) { // END
2131 get_track_by_track_num(_trk);
2133 if(!(seek_relative_frame_in_image(read_sector))) {
2134 status_illegal_lba(0, 0x00, 0x00, 0x00);
2137 // Phase 1: Check whether buffer remains.
2138 // Phase 2: Read data from image.
2139 if(!(fio_img->IsOpened())) {
2140 status_illegal_lba(0, 0x00, 0x00, 0x00); //<! OK? Maybe read error.
2143 // Read data from Image, maybe includes (or doed not include) header and footer.
2144 if(fio_img->Fread(startp, _read_size, 1) != 1) {
2145 status_illegal_lba(0, 0x00, 0x00, 0x00);
2148 // ToDo: Make pseudo header for ISO images.
2149 // ToDo: Read or Make sub-channel field.
2151 // Phase 3: Transfer main data to buffers.
2152 __UNLIKELY_IF(read_length < _transfer_size) {
2154 status_illegal_lba(0, 0x00, 0x00, 0x00);
2157 uint32_t tbytes_bak = transferred_bytes;
2158 int rlen_bak = read_length;
2160 for(int i = 0; i < _transfer_size; i++) {
2161 __UNLIKELY_IF(databuffer->full()) {
2163 // ToDo: Re-Scheduling data transfer.
2165 transferred_bytes = tbytes_bak;
2166 read_length = rlen_bak;
2168 for(int j = 0; j < i; j++) {
2169 _dummy = databuffer->read();
2171 if(!(seek_relative_frame_in_image(read_sector))) {
2172 // Try to restore before sector.
2173 status_illegal_lba(0, 0x00, 0x00, 0x00);
2177 write_a_byte(datap[i]);
2178 transferred_bytes++;
2181 read_sector++; // ToDo: Check boundary.
2185 return seccount; // OK.
2188 bool TOWNS_CDROM::read_buffer(int sectors)
2190 if(status_media_changed_or_not_ready(false)) {
2191 // @note ToDo: Make status interrupted.
2196 uint32_t nbytes; // transferred_bytes
2197 int rsectors = read_sectors_image(sectors, nbytes);
2203 if(rsectors != sectors) {
2204 // ToDo: Partly reading error.
2211 int TOWNS_CDROM::dequeue_audio_data(pair16_t& left, pair16_t& right)
2214 if(databuffer->count() < 4) {
2220 for(int i = 0; i < 4; i++) {
2221 data[i] = (uint8_t)(databuffer->read() & 0xff);
2223 __UNLIKELY_IF(config.swap_audio_byteorder[0]) {
2224 left.read_2bytes_be_from(&(data[0]));
2225 right.read_2bytes_be_from(&(data[2]));
2227 left.read_2bytes_le_from(&(data[0]));
2228 right.read_2bytes_le_from(&(data[2]));
2233 void TOWNS_CDROM::read_a_cdda_sample()
2235 __UNLIKELY_IF(event_cdda_delay_play > -1) {
2237 if(((cdda_buffer_ptr % 2352) == 0) && (cdda_status == CDDA_PLAYING)) {
2238 //set_subq(cdda_start_frame);
2239 // return; // WAIT for SEEK COMPLETED
2241 return; // WAIT for SEEK COMPLETED
2243 // read 16bit 2ch samples in the cd-da buffer, called 44100 times/sec
2244 pair16_t sample_l, sample_r;
2245 int rlen = dequeue_audio_data(sample_l, sample_r);
2247 __UNLIKELY_IF(rlen != 4) {
2248 // May recover buffer.
2249 if(rlen <= 0) return; // None dequeued.
2250 // ToDo: Recover queue.
2254 cdda_sample_l = sample_l.sw;
2255 cdda_sample_r = sample_r.sw;
2256 cdda_buffer_ptr = cdda_buffer_ptr + 4;
2257 bool force_seek = false;
2258 __UNLIKELY_IF((cdda_buffer_ptr % 2352) == 0) {
2259 // one frame finished
2260 set_subq(cdda_playing_frame); // First
2261 cdda_playing_frame++;
2262 cdda_buffer_ptr = 0;
2264 __UNLIKELY_IF(cdda_playing_frame > cdda_end_frame) {
2265 clear_event(this, event_cdda);
2266 if(cdda_repeat_count < 0) {
2267 // Infinity Loop (from Towns Linux v2.2.26)
2269 } else if(cdda_repeat_count == 0) {
2270 status_seek = false;
2271 set_cdda_status(CDDA_ENDED);
2276 cdda_repeat_count--;
2277 if(cdda_repeat_count == 0) {
2278 set_cdda_status(CDDA_ENDED);
2280 status_seek = false;
2285 /* int _ntrk = _ntrk = check_cdda_track_boundary(read_sector);
2286 __UNLIKELY_IF((_ntrk != current_track) && (_ntrk < track_num) && (_ntrk > 0)) {
2287 current_track = get_track(read_sector);
2288 seek_relative_frame_in_image(read_sector);
2289 } else */if(force_seek) {
2290 double usec = get_seek_time(cdda_start_frame);
2291 if(usec < 10.0) usec = 10.0;
2292 force_register_event(this, EVENT_CDDA_REPEAT, usec, false, event_cdda_delay_play);
2297 if(databuffer->count() <= sizeof(cd_audio_sector_t)) {
2299 //(event_next_sector < 0) {
2300 // TMP: prefetch 2 sectors
2301 prefetch_audio_sectors(2);
2305 prefetch_audio_sectors(1);
2310 // -1 = End of sector.
2311 int TOWNS_CDROM::prefetch_audio_sectors(int sectors)
2316 if(status_media_changed_or_not_ready(false)) {
2317 // @note ToDo: Make status interrupted.
2320 uint8_t tmpbuf[sectors * 2448 + 8];
2321 if((read_sector > cdda_end_frame) || (read_sector >= max_logical_block)) {
2324 if((current_track >= track_num) || (current_track <= 0)) {
2327 int track = get_track_noop(read_sector);
2328 if(track != current_track) {
2329 // BEYOND BOUNDARY OF TRACK.
2330 if((track >= track_num) || (track <= 0)) {
2331 status_parameter_error(false); // OK?
2334 if(!(toc_table[track].is_audio)) {
2335 status_parameter_error(false); // OK?
2338 current_track = get_track(read_sector);
2339 seek_relative_frame_in_image(read_sector);
2341 if((read_sector + sectors) > cdda_end_frame) {
2342 sectors = cdda_end_frame - read_sector + 1;
2344 if((read_sector + sectors) > max_logical_block) {
2345 sectors = max_logical_block - read_sector;
2348 __UNLIKELY_IF(databuffer->left() < read_length) {
2349 int tl = databuffer->left();
2350 if(tl < sizeof(cd_audio_sector_t)) return 0; // Pending
2351 int _s = tl / sizeof(cd_audio_sector_t);
2352 if(_s < 1) return 0; // Pending
2357 if(get_track_noop(read_sector + sectors) != current_track) {
2358 sectors = toc_table[current_track].index0 - read_sector;
2364 read_length = sectors * sizeof(cd_audio_sector_t); // Hack.
2365 read_mode = CDROM_READ_AUDIO;
2367 uint32_t nbytes; // transferred_bytes
2369 while(sectors > 0) {
2370 int rsectors = read_sectors_image(sectors, nbytes);
2371 //cdrom_debug_log(_T("READ AUDIO SECTOR(s) LBA=%d SECTORS=%d -> %d bytes=%d"),
2372 // read_sector, sectors, rsectors, nbytes);
2375 //set_cdda_status(CDDA_ENDED);
2377 return _sectors; // OK?
2379 sectors -= rsectors;
2380 _sectors += rsectors;
2385 void TOWNS_CDROM::set_cdda_status(uint8_t status)
2387 if(status == CDDA_PLAYING) {
2388 if(mix_loop_num == 0) {
2389 if(event_cdda < 0) {
2390 register_event(this, EVENT_CDDA, 1.0e6 / 44100.0, true, &event_cdda);
2393 if(cdda_status != CDDA_PLAYING) {
2394 //// Notify to release bus.
2395 write_mcuint_signals(false);
2396 if((cdda_status == CDDA_OFF) || (cdda_status == CDDA_ENDED)) {
2397 //get_track_by_track_num(current_track); // Re-Play
2398 int track = get_track(cdda_start_frame);
2399 if((track > 0) && (track < track_num)) {
2400 cdda_playing_frame = cdda_start_frame;
2401 read_sector = cdda_playing_frame;
2402 current_track = track;
2403 seek_relative_frame_in_image(cdda_playing_frame);
2404 cdda_stopped = false;
2407 current_track = get_track(0);
2408 cdda_playing_frame = 0;
2410 cdda_start_frame = 0;
2412 cdda_stopped = true;
2414 cdda_buffer_ptr = 0;
2416 } else if(cdda_status == CDDA_PAUSED) {
2419 cdda_stopped = false;
2421 cdda_stopped = false;
2424 set_realtime_render(this, true);
2425 const _TCHAR *pp = get_cdda_status_name(cdda_status);
2426 cdrom_debug_log(_T("Play CDDA from %s.\n"), pp);
2429 //clear_event(this, event_cdda);
2430 // if((cdda_status == CDDA_PLAYING) || (cdda_status == CDDA_ENDED)) {
2431 if(cdda_status != status) {
2432 // Notify to release bus.
2433 write_mcuint_signals(false);
2434 if(status == CDDA_OFF) {
2435 databuffer->clear();
2436 cdda_buffer_ptr = 0;
2437 cdda_repeat_count = -1; // OK?
2439 if((current_track <= 0) || (current_track >= track_num)) {
2440 current_track = get_track(0);
2442 cdda_start_frame = 0;
2444 cdda_playing_frame = 0;
2446 read_sector = toc_table[current_track].index0;
2447 cdda_start_frame = read_sector;
2448 cdda_playing_frame = read_sector;
2449 cdda_end_frame = toc_table[current_track + 1].index0 - 1; // ToDo.
2453 get_track_by_track_num(0);
2455 cdda_stopped = true;
2458 set_realtime_render(this, false);
2459 const _TCHAR *sp = get_cdda_status_name(status);
2460 const _TCHAR *pp = get_cdda_status_name(cdda_status);
2461 cdrom_debug_log(_T("Change CDDA status: %s->%s"), pp, sp);
2464 cdda_status = status;
2468 bool TOWNS_CDROM::is_device_ready()
2474 void TOWNS_CDROM::get_track_by_track_num(int track)
2476 if((track <= 0) || (track >= track_num)) {
2478 if(fio_img->IsOpened()) fio_img->Fclose();
2484 // ToDo: Apply audio with some codecs.
2485 if((current_track != track) || !(fio_img->IsOpened())){
2486 if(fio_img->IsOpened()) {
2489 cdrom_debug_log(_T("LOAD TRK #%02d from %s\n"), track, track_data_path[track - 1]);
2491 if((track > 0) && (track < 100) && (track < track_num)) {
2492 if((strlen(track_data_path[track - 1]) <= 0) ||
2493 !(fio_img->Fopen(track_data_path[track - 1], FILEIO_READ_BINARY))) {
2501 current_track = track;
2504 // Detect only track num.
2505 int TOWNS_CDROM::get_track_noop(uint32_t lba)
2508 for(int i = 0; i < track_num; i++) {
2509 if(lba >= toc_table[i].index0) {
2518 int TOWNS_CDROM::get_track(uint32_t lba)
2521 track = get_track_noop(lba);
2522 get_track_by_track_num(track);
2526 double TOWNS_CDROM::get_seek_time(uint32_t lba)
2528 uint32_t cur_lba = get_image_cur_position();
2530 if(lba > max_logical_block) lba = max_logical_block;
2532 distance = lba - cur_lba;
2534 distance = cur_lba - lba;
2536 if((cur_lba < 150) && (lba < 150)) {
2537 // Seek not effective.
2540 double _seek = (double)distance / 333000.0 ; // 333000: sectors in media
2541 _seek = 400.0e3 * _seek;
2545 uint32_t TOWNS_CDROM::lba_to_msf(uint32_t lba)
2547 uint8_t m = lba / (60 * 75);
2548 lba -= m * (60 * 75);
2549 uint8_t s = lba / 75;
2550 uint8_t f = lba % 75;
2552 return ((m / 10) << 20) | ((m % 10) << 16) | ((s / 10) << 12) | ((s % 10) << 8) | ((f / 10) << 4) | ((f % 10) << 0);
2555 uint32_t TOWNS_CDROM::get_image_cur_position()
2558 int track = current_track;
2559 if(is_device_ready()) {
2560 if(fio_img->IsOpened()) {
2561 uint32_t cur_position = (uint32_t)(fio_img->Ftell());
2562 frame = (cur_position / ((is_iso) ? 2048 : physical_block_size()));
2564 frame = frame + toc_table[track].lba_offset;
2572 uint32_t TOWNS_CDROM::lba_to_msf_alt(uint32_t lba)
2575 ret |= ((lba / (60 * 75)) & 0xff) << 16;
2576 ret |= (((lba / 75) % 60) & 0xff) << 8;
2577 ret |= ((lba % 75) & 0xff) << 0;
2581 void TOWNS_CDROM::pause_cdda_from_cmd()
2583 set_cdda_status(CDDA_PAUSED);
2585 * @note This may solve halt incident of Kyukyoku Tiger, but something are wrong.
2586 * @note 20201113 K.O
2588 set_subq(cdda_playing_frame); // First
2589 if(!(status_media_changed_or_not_ready(false))) {
2590 set_status(req_status, 1, TOWNS_CD_STATUS_ACCEPT, TOWNS_CD_ACCEPT_CDDA_PAUSED, 0x00, 0x00, true);
2594 void TOWNS_CDROM::unpause_cdda_from_cmd()
2596 set_cdda_status(CDDA_PLAYING);
2598 * @note This may solve halt incident of Kyukyoku Tiger, but something are wrong.
2599 * @note 20201113 K.O
2601 set_subq(cdda_playing_frame); // First
2602 if(!(status_media_changed_or_not_ready(false))) {
2603 set_status(req_status, 1, TOWNS_CD_STATUS_ACCEPT, TOWNS_CD_ACCEPT_NOERROR, 0x00, 0x00, true);
2607 void TOWNS_CDROM::stop_cdda_from_cmd()
2609 /// @note Even make additional status even stop.Workaround for RANCEIII.
2610 /// @note - 20201110 K.O
2611 set_cdda_status(CDDA_ENDED);
2612 set_subq(cdda_playing_frame); // First
2613 if(!(status_media_changed_or_not_ready(false))) {
2614 set_status(req_status, 1, TOWNS_CD_STATUS_ACCEPT, TOWNS_CD_ACCEPT_NOERROR, 0x00, 0x00, true);
2620 bool TOWNS_CDROM::seek_relative_frame_in_image(uint32_t frame_no)
2622 int phys_size = (is_iso) ? 2048 : physical_block_size();
2623 if(frame_no >= toc_table[current_track].lba_offset) {
2624 if(fio_img->IsOpened()) {
2626 (frame_no - toc_table[current_track].lba_offset) * phys_size,
2627 FILEIO_SEEK_SET) != 0) {
2637 int TOWNS_CDROM::check_cdda_track_boundary(uint32_t frame_no)
2639 if((frame_no >= toc_table[current_track + 1].index0) ||
2640 (frame_no < toc_table[current_track].index0)) {
2641 int trk = get_track_noop(frame_no);
2642 if((trk <= 0) || (trk >= track_num)) {
2643 cdrom_debug_log(_T("CDDA: BEYOND OF TRACK BOUNDARY AND TO THE END, FRAME=%d"), frame_no);
2646 cdrom_debug_log(_T("CDDA: BEYOND OF TRACK BOUNDARY, FRAME=%d"), frame_no);
2647 //if(frame_no < toc_table[current_track].index0) {
2648 // frame_no = toc_table[current_track].index0;
2652 return current_track;
2655 void TOWNS_CDROM::play_cdda_from_cmd()
2657 uint8_t m_start = exec_params[0];
2658 uint8_t s_start = exec_params[1];
2659 uint8_t f_start = exec_params[2];
2660 uint8_t m_end = exec_params[3];
2661 uint8_t s_end = exec_params[4];
2662 uint8_t f_end = exec_params[5];
2663 uint8_t is_repeat = exec_params[6]; // From Towns Linux v1.1/towns_cd.c
2664 uint8_t repeat_count = exec_params[7];
2666 cdda_repeat_count = -1;
2667 uint32_t start_tmp = FROM_BCD(f_start) + (FROM_BCD(s_start) + FROM_BCD(m_start) * 60) * 75;
2668 uint32_t end_tmp = FROM_BCD(f_end) + (FROM_BCD(s_end) + FROM_BCD(m_end) * 60) * 75;
2670 * @note Workaround for command SPAM, i.e. Puyo Puyo.
2671 * @note 20201115 K.O
2675 track = get_track_noop(start_tmp);
2676 if(start_tmp >= toc_table[track].pregap) {
2677 start_tmp -= toc_table[track].pregap;
2679 if(start_tmp < toc_table[track].index1) {
2680 start_tmp = toc_table[track].index1; // don't play pregap
2681 } else if(start_tmp >= max_logical_block) {
2682 start_tmp = max_logical_block - 1;
2684 /* if(end_tmp >= toc_table[track + 1].index0) {
2685 end_tmp = toc_table[track + 1].index0 - 1;
2686 } else */if(end_tmp >= max_logical_block) {
2687 end_tmp = max_logical_block - 1;
2688 } else if(end_tmp == 0) { //! Workaround of Puyo Puyo 20201116 K.O
2689 end_tmp = toc_table[track + 1].index0 - 1;
2691 if(cdda_status == CDDA_PLAYING) {
2692 int track_tmp_s = get_track_noop(start_tmp);
2693 int track_tmp_e = get_track_noop(end_tmp);
2694 if((start_tmp == cdda_start_frame) && (end_tmp == cdda_end_frame)) {
2696 set_status_cddareply(false, 1, 0x00, 0x00);
2699 // Workaround for Puyo Puyo, Interval stage.
2700 if((track_tmp_s != current_track) || (track_tmp_e != current_track)) {
2701 if(cdda_status == CDDA_PLAYING) {
2702 set_cdda_status(CDDA_OFF);
2704 if(!(toc_table[track_tmp_s].is_audio)) {
2705 // If target LBA is not CDDA, reject command.
2706 set_status_cddareply(false, 1, 0x00, 0x00);
2711 cdda_start_frame = start_tmp;
2712 cdda_end_frame = end_tmp;
2713 // Check target track is *not* audio.
2714 int track2 = get_track_noop(cdda_start_frame);
2715 if(!(toc_table[track2].is_audio)) {
2716 //if(cdda_status == CDDA_PLAYING) {
2717 set_cdda_status(CDDA_OFF);
2719 status_hardware_error(false); // OK?
2722 if(is_repeat == 1) {
2723 cdda_repeat_count = -1;
2725 // Maybe is_repeat == 9
2726 cdda_repeat_count = repeat_count;
2727 cdda_repeat_count++;
2729 uint32_t cur_lba = get_image_cur_position();
2731 //cdda_playing_frame = cdda_start_frame;
2732 //read_sector = cdda_start_frame;
2734 //seek_relative_frame_in_image(cdda_playing_frame);
2735 cdrom_debug_log(_T("PLAY_CDROM TRACK=%d START=%02X:%02X:%02X(%d) END=%02X:%02X:%02X(%d) IS_REPEAT=%d REPEAT_COUNT=%d"),
2737 m_start, s_start, f_start, cdda_start_frame,
2738 m_end, s_end, f_end, cdda_end_frame,
2739 is_repeat, repeat_count);
2740 double usec = get_seek_time(cdda_start_frame);
2741 //get_track(cdda_playing_frame);
2742 if(usec < 10.0) usec = 10.0;
2744 //set_cdda_status(CDDA_PLAYING);
2745 force_register_event(this, EVENT_CDDA_DELAY_PLAY, usec, false, event_cdda_delay_play);
2749 * @note This may solve halt incident of Kyukyoku Tiger, but something are wrong.
2750 * @note 20201113 K.O
2752 set_status_cddareply(false, 1, 0x00, 0x00);
2755 void TOWNS_CDROM::make_bitslice_subc_q(uint8_t *data, int bitwidth)
2758 if(bitwidth > (sizeof(subq_buffer) / sizeof(SUBC_t))) {
2759 bitwidth = (sizeof(subq_buffer) / sizeof(SUBC_t));
2760 } else if(bitwidth < 0) {
2764 // Q: IS set SYNC CODE?.
2765 for(int bp = 0; bp < bitwidth; bp++) {
2766 subq_buffer[bp].bit.Q =
2767 ((data[nbit >> 3] & (1 << (7 - (nbit & 7)))) != 0) ? 1 : 0;
2772 void TOWNS_CDROM::set_subq(uint32_t lba)
2774 memset(subq_bytes, 0x00, sizeof(subq_bytes));
2775 if(subq_bitptr < subq_bitwidth) {
2776 subq_overrun = true;
2778 int track = get_track_noop(lba);
2779 if((is_device_ready()) && (track > 0) && (track < track_num)) {
2780 // create track info
2784 // ToDo: Process when Foo.sub (for Foo.cue or Foo.ccd), this may be sub-channel data.
2785 if(toc_table[track].is_audio) { // OK? (or force ERROR) 20181120 K.O
2786 frame = ((cdda_status == CDDA_OFF) || (cdda_status == CDDA_ENDED)) ? toc_table[track].index0 : lba;
2790 if(frame > toc_table[track].index1) {
2791 msf_rel = lba_to_msf_alt(frame - toc_table[track].index1);
2793 msf_rel = lba_to_msf_alt(0);
2795 msf_abs = lba_to_msf_alt(frame + 75 * 2); // OK?
2797 // ToDo: POINT=0xA0-0xA2
2799 subq_bytes[0] = ((toc_table[track].is_audio) ? 0x40 : 0x00) | 0x01; // (CNT << 4) | ADR
2800 subq_bytes[1] = 0x00; // TNO
2801 subq_bytes[2] = TO_BCD(track); // POINT(Track)
2802 subq_bytes[3] = TO_BCD((msf_abs >> 16) & 0xff); // M (absolute)
2803 subq_bytes[4] = TO_BCD((msf_abs >> 8) & 0xff); // S (absolute)
2804 subq_bytes[5] = TO_BCD((msf_abs >> 0) & 0xff); // F (absolute)
2805 subq_bytes[6] = 0x00; // Zero
2806 subq_bytes[7] = TO_BCD((msf_rel >> 16) & 0xff); // M (relative)
2807 subq_bytes[8] = TO_BCD((msf_rel >> 8) & 0xff); // S (relative)
2808 subq_bytes[9] = TO_BCD((msf_rel >> 0) & 0xff); // F (relative)
2811 // Post Process1: Calculate CRC16
2812 uint16_t crc = calc_subc_crc16(subq_bytes, 10, 0xffff); // OK?
2813 subq_bytes[10] = (crc >> 8) & 0xff;
2814 subq_bytes[11] = (crc >> 0) & 0xff;
2815 // Post process 2: push bytes to Bit slice
2816 memset(subq_buffer, 0x00, sizeof(subq_buffer));
2820 make_bitslice_subc_q(subq_bytes, 96);
2821 // ToDo: R-W field (a.k.a. CD-TEXT/CD-G);
2822 // mcu_ready = true;
2826 uint8_t TOWNS_CDROM::get_subq_status()
2829 val = val | ((subq_bitwidth > 0) ? 0x01 : 0x00);
2830 val = val | ((subq_overrun) ? 0x02 : 0x00);
2834 uint8_t TOWNS_CDROM::read_subq()
2837 if(subq_bitptr < subq_bitwidth) {
2838 val = subq_buffer[subq_bitptr].byte;
2844 int TOWNS_CDROM::get_frames_from_msf(const char *s)
2846 const char *ptr = s;
2847 int frames[3] = {0};
2851 if(*ptr >= '0' && *ptr <= '9') {
2852 frames[index] = frames[index] * 10 + (*ptr - '0');
2853 } else if(*ptr == ':') {
2858 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
2864 return (frames[0] * 60 + frames[1]) * 75 + frames[2]; // 75frames/sec
2867 int64_t TOWNS_CDROM::hexatoi(const char *s)
2869 const char *ptr = s;
2873 if(*ptr >= '0' && *ptr <= '9') {
2874 value = value * 16 + (*ptr - '0');
2875 } else if(*ptr >= 'a' && *ptr <= 'f') {
2876 value = value * 16 + (*ptr - 'a' + 10);
2877 } else if(*ptr >= 'A' && *ptr <= 'F') {
2878 value = value * 16 + (*ptr - 'A' + 10);
2879 } else if(*ptr == '\r' || *ptr == '\n' || *ptr == '\0') {
2890 int64_t TOWNS_CDROM::string_to_numeric(std::string s)
2896 head = s.substr(0, 2);
2897 } catch (std::out_of_range &e) {
2900 std::transform(head.begin(), head.end(), head.begin(),
2901 [](unsigned char c) -> unsigned char{ return std::toupper(c); });
2906 __val = s.substr(2, s.size());
2907 } catch (std::out_of_range &e) {
2910 _ret = hexatoi(__val.c_str());
2912 _ret = atoll(s.c_str());
2919 void TOWNS_CDROM::open(const _TCHAR* file_path)
2921 open_from_cmd(file_path);
2924 void TOWNS_CDROM::open_from_cmd(const _TCHAR* file_path)
2926 _TCHAR img_file_path[_MAX_PATH] = {0};
2927 memset(img_file_path_bak, 0x00, sizeof(img_file_path_bak));
2932 if(check_file_extension(file_path, _T(".cue"))) {
2935 if(open_cue_file(file_path)) {
2936 strncpy(img_file_path_bak, file_path, _MAX_PATH - 1);
2938 } else if(check_file_extension(file_path, _T(".iso"))) {
2941 if(open_iso_file(file_path)) {
2942 strncpy(img_file_path, file_path, _MAX_PATH - 1);
2943 strncpy(img_file_path_bak, file_path, _MAX_PATH - 1);
2945 if(fio_img->Fopen(img_file_path, FILEIO_READ_BINARY)) {
2950 } else if(check_file_extension(file_path, _T(".ccd"))) {
2951 // get image file name
2952 if(open_ccd_file(file_path, img_file_path)) {
2953 strncpy(img_file_path_bak, img_file_path, _MAX_PATH - 1);
2954 // strncpy(img_file_path_bak, file_path, _MAX_PATH - 1);
2959 media_changed = true;
2960 media_ejected = false;
2961 // Temporally answer value.
2962 // TOWNS_CD_STATUS_DOOR_CLOSE_DONE ?
2964 /* if(__SCSI_DEBUG_LOG)*/ {
2965 for(int i = 1; i < track_num + 1; i++) {
2966 uint32_t idx0_msf = lba_to_msf(toc_table[i].index0);
2967 uint32_t idx1_msf = lba_to_msf(toc_table[i].index1);
2968 uint32_t pgap_msf = lba_to_msf(toc_table[i].pregap);
2969 cdrom_debug_log(_T("Track%02d: Index0=%02x:%02x:%02x Index1=%02x:%02x:%02x PreGap=%02x:%02x:%02x\n"), i,
2970 (idx0_msf >> 16) & 0xff, (idx0_msf >> 8) & 0xff, idx0_msf & 0xff,
2971 (idx1_msf >> 16) & 0xff, (idx1_msf >> 8) & 0xff, idx1_msf & 0xff,
2972 (pgap_msf >> 16) & 0xff, (pgap_msf >> 8) & 0xff, pgap_msf & 0xff);
2978 void TOWNS_CDROM::close()
2983 void TOWNS_CDROM::close_from_cmd()
2985 bool _b = mounted();
2987 media_ejected = true;
2989 if(fio_img->IsOpened()) {
2994 memset(toc_table, 0, sizeof(toc_table));
2995 memset(img_file_path_bak, 0x00, sizeof(img_file_path_bak));
2998 status_seek = false;
2999 media_changed = false;
3001 read_mode = CDROM_READ_NONE;
3011 databuffer->clear();
3013 cdda_start_frame = 0;
3014 cdda_end_frame = 150;
3015 cdda_playing_frame = 0;
3016 cdda_buffer_ptr = 0;
3018 cdda_repeat_count = -1; // OK?
3020 cdda_stopped = true;
3021 cdda_status = CDDA_OFF;
3024 set_realtime_render(this, false);
3027 if(command_execute_phase) {
3028 command_execute_phase = false;
3029 // Temporally answer value.
3030 // TOWNS_CD_STATUS_DOOR_OPEN_DONE ?
3031 set_status_immediate(req_status, false, 0,
3032 TOWNS_CD_STATUS_CMD_ABEND,
3033 TOWNS_CD_ABEND_DRIVE_NOT_READY, 0, 0);
3038 bool TOWNS_CDROM::mounted()
3040 __LIKELY_IF((is_cue) || (fio_img->IsOpened())) {
3041 __UNLIKELY_IF(track_num <= 0) {
3049 bool TOWNS_CDROM::accessed()
3051 bool value = access;
3056 void TOWNS_CDROM::mix(int32_t* buffer, int cnt)
3058 if(cdda_status == CDDA_PLAYING) {
3059 if(mix_loop_num != 0) {
3060 int tmp_l = 0, tmp_r = 0;
3061 for(int i = 0; i < mix_loop_num; i++) {
3062 event_callback(EVENT_CDDA, 0);
3063 tmp_l += cdda_sample_l;
3064 tmp_r += cdda_sample_r;
3066 cdda_sample_l = tmp_l / mix_loop_num;
3067 cdda_sample_r = tmp_r / mix_loop_num;
3069 // int32_t val_l = apply_volume(apply_volume(cdda_sample_l, volume_m), volume_l);
3070 // int32_t val_r = apply_volume(apply_volume(cdda_sample_r, volume_m), volume_r);
3071 int32_t val_l = (mute_left) ? 0 : apply_volume(cdda_sample_l, volume_l);
3072 int32_t val_r = (mute_right) ? 0 : apply_volume(cdda_sample_r, volume_r);
3074 for(int i = 0; i < cnt; i++) {
3075 *buffer++ += val_l; // L
3076 *buffer++ += val_r; // R
3081 void TOWNS_CDROM::set_volume(int ch, int decibel_l, int decibel_r)
3083 _decibel_l = decibel_l;
3084 _decibel_r = decibel_r;
3085 volume_l = decibel_to_volume(_decibel_l + 6.0);
3086 volume_r = decibel_to_volume(_decibel_r + 6.0);
3089 void TOWNS_CDROM::get_volume(int ch, int& decibel_l, int& decibel_r)
3091 decibel_l = _decibel_l;
3092 decibel_r = _decibel_r;
3093 // decibel_l = volume_l;
3094 // decibel_r = volume_r;
3097 uint32_t TOWNS_CDROM::read_io16(uint32_t addr)
3099 if((addr & 0x0e) == 0x04) {
3100 if((pio_transfer_phase) /*|| (dma_transfer_phase) */) {
3104 n.b.l = read_dma_io8w(0, &dummywait);
3109 return read_io8(addr);
3113 uint32_t TOWNS_CDROM::read_io8(uint32_t addr)
3116 * 04C0h : Master status
3117 * 04C2h : CDC status
3120 * 04CDh : SUBQ STATUS
3122 uint32_t val = 0xff;
3123 switch(addr & 0x0f) {
3126 val = val | ((mcu_intr) ? 0x80 : 0x00);
3127 val = val | ((dma_intr) ? 0x40 : 0x00);
3128 val = val | ((pio_transfer_phase) ? 0x20 : 0x00);
3129 val = val | ((dma_transfer_phase) ? 0x10 : 0x00); // USING DMAC ch.3
3130 // ToDo: FIX to lack queueing status with some commands
3132 // val = val | ((status_queue->full()) ? 0x02 : 0x00);
3133 val = val | ((has_status) ? 0x02 : 0x00);
3134 val = val | ((mcu_ready) ? 0x01 : 0x00);
3137 val = read_status();
3142 if((pio_transfer_phase) /*|| (dma_transfer_phase) */) {
3144 val = read_dma_io8w(0, &dummywait);
3147 case 0x0c: // Subq code
3148 //val = read_subq();
3151 case 0x0d: // Subq status
3152 //val = get_subq_status();
3156 //cdrom_debug_log(_T("READ IO8: %04X %02X"), addr, val);
3160 uint32_t TOWNS_CDROM::read_io16(uint32_t addr)
3164 v.b.l = read_io8(addr & 0xfffe);
3168 void TOWNS_CDROM::write_io8(uint32_t addr, uint32_t data)
3171 * 04C0h : Master control register
3172 * 04C2h : Command register
3173 * 04C4h : Parameter register
3174 * 04C6h : Transfer control register.
3176 //cdrom_debug_log(_T("WRITE IO8: %04X %02X"), addr, data);
3177 w_regs[addr & 0x0f] = data;
3178 switch(addr & 0x0f) {
3179 case 0x00: // Master control register
3180 // Note: Sync with TSUGARU.
3182 //cdrom_debug_log(_T("PORT 04C0h <- %02X"), data);
3183 if((data & 0xc0) != 0) {
3184 if((data & 0x80) != 0) {
3187 write_mcuint_signals(false); // Reset interrupt request to PIC.
3190 if((data & 0x40) != 0) {
3193 write_mcuint_signals(false); // Reset interrupt request to PIC.
3197 if((data & 0x04) != 0) {
3198 cdrom_debug_log(_T("RESET FROM CMDREG: 04C0h"));
3201 mcu_intr_mask = ((data & 0x02) == 0) ? true : false;
3202 dma_intr_mask = ((data & 0x01) == 0) ? true : false;
3204 case 0x02: // Command
3205 //cdrom_debug_log(_T("PORT 04C2h <- %02X"), data);
3206 // Note: Sync with TSUGARU.
3209 // data = data | (latest_command & 0x60); // For FRACTAL ENGINE DEMO (from TSUGARU).
3211 //dma_transfer_phase = false;
3212 //pio_transfer_phase = false;
3213 //if(stat_reply_intr) {
3214 // data |= (latest_command & 0x60);
3216 command_received = true;
3217 reserved_command = data;
3220 param_queue->write(data);
3223 dma_transfer = ((data & 0x10) != 0) ? true : false;
3224 pio_transfer = ((data & 0x08) != 0) ? true : false;
3226 pio_transfer = false;
3227 pio_transfer_phase = false;
3228 write_signals(&outputs_drq, 0x0);
3229 double usec = 1.0e6 / ((double)transfer_speed * 150.0e3 * 2.0);
3231 dma_transfer_phase = true;
3232 } else if(pio_transfer) {
3233 dma_transfer = false;
3234 dma_transfer_phase = false;
3236 if(!(pio_transfer_phase)) {
3237 pio_transfer_phase = true;
3240 // cdrom_debug_log(_T("SET TRANSFER MODE to %02X"), data);
3241 // cdrom_debug_log(_T("SET TRANSFER MODE to %02X"), data);
3245 if((command_received) && (param_queue->full()) && (((addr & 0x0f) == 0x04) || ((addr & 0x0f) == 0x02)) && (event_execute < 0) && (mcu_ready)) {
3246 command_received = false;
3248 for(int i = 0; i < 8; i++) {
3249 exec_params[i] = param_queue->read();
3251 param_queue->clear();
3253 //prev_command = latest_command;
3254 //execute_command(reserved_command);
3255 // From Tsugaru 2023-08-21
3257 register_event(this, EVENT_CDROM_DELAY_COMMAND, 50.0, true, &event_execute);
3261 void TOWNS_CDROM::write_io16(uint32_t addr, uint32_t data)
3265 write_io8w(addr & 0xfffe, v.b.l)
3268 void TOWNS_CDROM::write_debug_data8(uint32_t addr, uint32_t data)
3270 databuffer->write_not_push(addr % max_fifo_length, data & 0xff);
3273 uint32_t TOWNS_CDROM::read_debug_data8(uint32_t addr)
3275 return databuffer->read_not_remove(addr % max_fifo_length) & 0xff;
3279 bool TOWNS_CDROM::write_debug_reg(const _TCHAR *reg, uint32_t data)
3285 bool TOWNS_CDROM::get_debug_regs_info(_TCHAR *buffer, size_t buffer_len)
3287 if(buffer == NULL) return false;
3288 _TCHAR regs[256] = {0};
3289 for(int i = 0; i < 16; i += 2) {
3290 _TCHAR tmps[16] = {0};
3291 my_stprintf_s(tmps, 16, _T("%02X "), w_regs[i]);
3292 my_tcscat_s(regs, sizeof(regs) / sizeof(_TCHAR), tmps);
3294 _TCHAR stat[256] = {0};
3295 for(int i = 0; i < 4; i++) {
3296 _TCHAR tmps[16] = {0};
3297 my_stprintf_s(tmps, 16, _T("%02X "), status_queue->read_not_remove(i) & 0xff);
3298 my_tcscat_s(stat, sizeof(regs) / sizeof(_TCHAR), tmps);
3300 _TCHAR s_param[256] = {0};
3301 _TCHAR s_prev_param[256] = {0};
3302 for(int i = 0; i < 8; i++) {
3303 _TCHAR tmps[16] = {0};
3304 my_stprintf_s(tmps, 16, _T("%02X "), exec_params[i]);
3305 my_tcscat_s(s_param, sizeof(s_param) / sizeof(_TCHAR), tmps);
3307 for(int i = 0; i < 8; i++) {
3308 _TCHAR tmps[16] = {0};
3309 my_stprintf_s(tmps, 16, _T("%02X "), prev_params[i]);
3310 my_tcscat_s(s_prev_param, sizeof(s_prev_param) / sizeof(_TCHAR), tmps);
3312 bool is_audio = false;
3313 bool in_track = ((current_track > 0) && (current_track < track_num));
3314 uint32_t index0 = 0;
3315 uint32_t index1 = 0;
3316 uint32_t lba_size = 0;
3317 uint32_t lba_offset = 0;
3318 uint32_t pregap = 150;
3320 is_audio = toc_table[current_track].is_audio;
3321 index0 = toc_table[current_track].index0;
3322 index1 = toc_table[current_track].index1;
3323 pregap = toc_table[current_track].pregap;
3324 lba_size = toc_table[current_track].lba_size;
3325 lba_offset = toc_table[current_track].lba_offset;
3327 _TCHAR moreinfo[512] = {0};
3329 const _TCHAR* playstatus = get_cdda_status_name(cdda_status);
3330 my_stprintf_s(moreinfo, sizeof(moreinfo) - 1,
3331 _T("TYPE=AUDIO: \n")
3332 _T("STATUS=%s LOOP COUNT=%d \n")
3333 _T("START=%d END=%d CURRENT_PLAY=%d NEXT_READ=%d \n")
3335 playstatus, cdda_repeat_count,
3336 cdda_start_frame, cdda_end_frame,
3337 cdda_playing_frame, read_sector
3340 my_stprintf_s(moreinfo, sizeof(moreinfo) - 1,
3341 _T("TYPE=DATA: TRANSFER MODE=%s %s\n")
3342 , (pio_transfer) ? _T("PIO") : _T(" ")
3343 , (dma_transfer) ? _T("DMA") : _T(" ")
3346 const _TCHAR* cmdname = get_command_name_from_command(latest_command);
3347 const _TCHAR* prev_cmdname = get_command_name_from_command(prev_command);
3348 my_stprintf_s(buffer, buffer_len,
3350 _T("MCU INT=%s DMA INT=%s TRANSFER PHASE:%s %s HAS_STATUS=%s MCU=%s\n")
3351 _T("TRACK=%d INDEX0=%d INDEX1=%d PREGAP=%d LBA_OFFSET=%d LBA_SIZE=%d\n")
3352 _T("LBA=%d READ LENGTH=%d DATA QUEUE=%d\n")
3353 _T("CMD=%02X(%s) PARAM=%s\n")
3354 _T("PREV_COMMAND=%02X(%s) PARAM=%s\n")
3355 _T("EXTRA STATUS=%d STATUS COUNT=%d QUEUE_VALUE=%s\n")
3356 _T("REGS RAW VALUES=%s\n")
3358 , (mcu_intr) ? _T("ON ") : _T("OFF"), (dma_intr) ? _T("ON ") : _T("OFF")
3359 , (pio_transfer_phase) ? _T("PIO") : _T(" ")
3360 , (dma_transfer_phase) ? _T("DMA") : _T(" ")
3361 , (has_status) ? _T("ON ") : _T("OFF"), (mcu_ready) ? _T("ON ") : _T("OFF")
3362 , current_track, index0, index1, pregap, lba_size, lba_offset
3363 , read_sector, read_length, databuffer->count()
3364 , latest_command, cmdname, s_param
3365 , prev_command, prev_cmdname, s_prev_param
3366 , extra_status, status_queue->count(), stat
3374 * Note: 20200428 K.O: DO NOT USE STATE SAVE, STILL don't implement completely yet.
3376 #define STATE_VERSION 36
3378 bool TOWNS_CDROM::process_state(FILEIO* state_fio, bool loading)
3380 if(!state_fio->StateCheckUint32(STATE_VERSION)) {
3383 if(!state_fio->StateCheckInt32(this_device_id)) {
3386 if(!(databuffer->process_state((void *)state_fio, loading))) {
3389 if(!(status_queue->process_state((void *)state_fio, loading))) {
3392 state_fio->StateArray(w_regs, sizeof(w_regs), 1);
3394 state_fio->StateValue(machine_id);
3395 state_fio->StateValue(cpu_id);
3396 state_fio->StateValue(max_fifo_length);
3397 state_fio->StateValue(fifo_length);
3399 state_fio->StateValue(data_reg);
3400 state_fio->StateValue(req_status);
3401 state_fio->StateValue(stat_reply_intr);
3403 state_fio->StateValue(mcu_intr);
3404 state_fio->StateValue(dma_intr);
3405 state_fio->StateValue(pio_transfer_phase);
3406 state_fio->StateValue(dma_transfer_phase);
3408 state_fio->StateValue(mcu_ready);
3409 state_fio->StateValue(command_execute_phase);
3411 state_fio->StateValue(mcu_intr_mask);
3412 state_fio->StateValue(dma_intr_mask);
3413 state_fio->StateValue(transfer_speed);
3414 state_fio->StateValue(read_length);
3416 state_fio->StateValue(next_seek_lba);
3417 state_fio->StateValue(pio_transfer);
3418 state_fio->StateValue(dma_transfer);
3419 state_fio->StateValue(dmac_running);
3421 state_fio->StateValue(reserved_command);
3422 if(!(param_queue->process_state((void *)state_fio, loading))) {
3426 state_fio->StateValue(prev_command);
3427 state_fio->StateArray(prev_params, sizeof(prev_params), 1);
3429 state_fio->StateValue(latest_command);
3430 state_fio->StateArray(exec_params, sizeof(exec_params), 1);
3432 state_fio->StateValue(extra_status);
3434 state_fio->StateValue(subq_bitwidth);
3435 state_fio->StateValue(subq_bitptr);
3436 state_fio->StateValue(subq_overrun);
3438 state_fio->StateArray(subq_bytes, sizeof(subq_bytes), 1);
3439 state_fio->StateArray(subq_snapshot, sizeof(subq_snapshot), 1);
3441 state_fio->StateValue(stat_track);
3442 state_fio->StateValue(media_ejected);
3443 state_fio->StateValue(media_changed);
3444 state_fio->StateValue(command_received);
3447 state_fio->StateValue(force_logging);
3449 uint32_t offset = 0;
3450 state_fio->StateValue(read_sector);
3451 state_fio->StateValue(mix_loop_num);
3453 state_fio->StateArray(img_file_path_bak, sizeof(img_file_path_bak), 1);
3454 state_fio->StateValue(is_cue);
3455 state_fio->StateValue(current_track);
3456 state_fio->StateValue(track_num);
3457 state_fio->StateValue(status_seek);
3459 state_fio->StateValue(cdrom_prefetch);
3461 state_fio->StateValue(cdda_start_frame);
3462 state_fio->StateValue(cdda_end_frame);
3463 state_fio->StateValue(cdda_playing_frame);
3464 state_fio->StateValue(cdda_status);
3465 state_fio->StateValue(cdda_repeat_count);
3466 state_fio->StateValue(cdda_interrupt);
3467 state_fio->StateValue(cdda_buffer_ptr);
3468 state_fio->StateValue(cdda_sample_l);
3469 state_fio->StateValue(cdda_sample_r);
3470 state_fio->StateValue(cdda_stopped);
3472 state_fio->StateValue(_decibel_l);
3473 state_fio->StateValue(_decibel_r);
3475 state_fio->StateValue(mute_left);
3476 state_fio->StateValue(mute_right);
3479 offset = state_fio->FgetUint32_LE();
3481 if(fio_img->IsOpened()) {
3482 offset = fio_img->Ftell();
3484 state_fio->FputUint32_LE(offset);
3486 // ToDo: Re-Open Image.20181118 K.O
3489 if(status_queue != NULL) {
3490 has_status = (status_queue->empty()) ? false : true;
3494 if(fio_img->IsOpened()) {
3497 bool is_cue_bak = is_cue;
3498 int track_num_bak = track_num;
3499 if(strlen(img_file_path_bak) > 0) {
3500 open_from_cmd(img_file_path_bak);
3502 if((is_cue_bak == is_cue) && (track_num_bak == track_num)) {
3503 if((current_track > 0) && (current_track < 100)) {
3504 get_track_by_track_num(current_track); // Re-Play
3506 if(fio_img->IsOpened()) {
3507 fio_img->Fseek(offset, FILEIO_SEEK_SET);
3514 make_bitslice_subc_q(subq_bytes, 96);
3516 volume_l = decibel_to_volume(_decibel_l + 6.0);
3517 volume_r = decibel_to_volume(_decibel_r + 6.0);
3520 state_fio->StateValue(event_execute);
3521 state_fio->StateValue(event_seek);
3522 state_fio->StateValue(event_cdda);
3523 state_fio->StateValue(event_cdda_delay_play);
3524 state_fio->StateValue(event_delay_interrupt);
3525 state_fio->StateValue(event_drq);
3526 state_fio->StateValue(event_next_sector);
3527 state_fio->StateValue(event_delay_ready);
3528 state_fio->StateValue(event_time_out);
3529 state_fio->StateValue(event_eot);