namespace FMTOWNS {
+void CDC::reset()
+{
+ dma_fifo->clear();
+ param_fifo->clear();
+ stat_fifo->clear();
+
+ has_status = false;
+ extra_status = 0;
+ submpu_ready = true;
+ software_transfer_phase = false;
+
+ write_signals(&output_submpu_intr, 0x00000000);
+ write_signals(&output_dma_intr, 0x00000000);
+
+ dma_intr = false;
+ submpu_intr = false;
+
+}
+
void CDC::initialize()
{
+ dma_fifo->clear();
+ param_fifo->clear();
+ stat_fifo->clear();
+
+ subq_fifo->clear();
+ submpu_ready = true;
+
+ submpu_intr_mask = false;
+ dma_intr_mask = false;
+ memset(w_regs, 0x00, sizeof(w_regs));
+
}
void CDC::write_io8(uint32_t address, uint32_t data)
case 0x00: // Master control register
{
if((data & 0x80) != 0) {
- if(submpu_intr) output_signals(&output_submpu_intr, 0x00000000);
+ if(submpu_intr) write_signals(&output_submpu_intr, 0x00000000);
submpu_intr = false;
}
if((data & 0x40) != 0) {
- if(dma_intr) output_signals(&output_dma_intr, 0x00000000);
+ if(dma_intr) write_signals(&output_dma_intr, 0x00000000);
dma_intr = false;
}
+ if((data & 0x04) != 0) this->reset();
submpu_intr_mask = ((data & 0x02) != 0) ? true : false;
dma_intr_mask = ((data & 0x01) != 0) ? true : false;
- if((data & 0x04) != 0) this->reset();
w_regs[address & 0x0f] = data;
}
break;
case 0x02: // Command register
{
- command_type_play = ((data & 0x80) != 0) ? true : false; // false = status command
+ command_type_play = ((data & 0x80) != 0) ? false : true; // false = status command
stat_reply_intr = ((data & 0x40) != 0) ? true : false;
req_status = ((data & 0x20) != 0) ? true : false;
if(command_type_play) {
- enqueue_command_play(data & 0x1f);
+ enqueue_command_play(data);
} else {
- enqueue_command_status(data & 0x1f);
+ enqueue_command_status(data);
}
w_regs[address & 0x0f] = data;
}
break;
case 0x2: // Status register
val = (uint32_t)(stat_fifo->read() & 0xff);
+ if(stat_fifo->empty()) {
+ has_status = false;
+ if(extra_status != 0) {
+ uint8_t cmd = w_regs[0x02];
+ switch(cmd & 0x9f) {
+ case 0x00: // Seek
+ write_status(0x04, 0x00, 0x00, 0x00);
+ extra_status = 0;
+ break;
+ case 0x02: // Read
+ if(extra_status == 2) {
+ write_status(0x22, 0x00, 0x00, 0x00);
+ }
+ extra_status = 0;
+ break;
+ case 0x04: // PLAY CDDA
+ write_status(0x07, 0x00, 0x00, 0x00);
+ has_status = false;
+ extra_status = 0;
+ break;
+ case 0x05:
+ {
+ switch(extra_status) {
+ case 1:
+ write_status(0x16, 0x00, 0xa0, 0x00);
+ extra_status++;
+ break;
+ case 2: // st1 = first_track_number
+ write_status(0x17, TO_BCD(0x01), 0x00, 0x00);
+ extra_status++;
+ break;
+ case 3:
+ write_status(0x16, 0x00, 0xa1, 0x00);
+ extra_status++;
+ break;
+ case 4:
+ write_status(0x17, d_cdrom->read_signal(SIG_TOWNS_CDROM_MAX_TRACK), 0x00, 0x00);
+ extra_status++;
+ break;
+ case 5:
+ write_status(0x16, 0x00, 0xa2, 0x00);
+ extra_status++;
+ break;
+ case 6:
+ uint32_t msf = d_cdrom->read_signal
+ {
+ uint32_t msf = d_cdrom->read_signal(SIG_TOWNS_CDROM_START_MSF_AA);
+ write_status(0x17, (msf & 0x00ff0000) >> 16, (msf & 0x0000ff00) >> 8, msf & 0x000000ff);
+ exra_status++;
+ }
+ break;
+ default:
+ if(extra_status == 7) {
+ d_cdrom->write_signal(SIG_TOWNS_CDROM_SET_STAT_TRACK, 0x01, 0x01);
+ }
+ if((extra_status & 0x01) != 0) {
+ uint32_t adr_control = d_cdrom->read_signal(SIG_TOWNS_CDROM_GET_ADR);
+ write_status(0x16, ((adr_control & 0x0f) << 4) | ((adr_control >> 4) & 0x0f), TO_BCD((extra_status / 2) - 2), 0x00);
+ extra_status++;
+ } else {
+ uint32_t msf = d_cdrom->read_signal(SIG_TOWNS_CDROM_START_MSF);
+ write_status(0x17, (msf & 0x00ff0000) >> 16, (msf & 0x0000ff00) >> 8, msf & 0x000000ff);
+ if(d_cdrom->read_signal(SIG_TOWNS_CDROM_REACHED_MAX_TRACK) == 0){
+ extra_status++;
+ } else {
+ extra_status = 0;
+ }
+ }
+ break;
+ }
+ }
+ case 0x06: // CDDA status
+ {
+ switch(extra_status) {
+ case 1: // Get current track
+ write_status(0x18, 0x00, d_cdrom->read_signal(SIG_TOWNS_CDROM_CURRENT_TRACK), 0x00);
+ extra_status++;
+ break;
+ case 2: // Get current position
+ {
+ uint32_t msf = d_cdrom->read_signal(SIG_TOWNS_CDROM_RELATIVE_MSF);
+ write_status(0x19, (msf >> 16) & 0xff, (msf >> 8) & 0xff, msf & 0xff);
+ extra_status++;
+ }
+ break;
+ case 3: // Current_msf
+ {
+ uint32_t msf = d_cdrom->read_signal(SIG_TOWNS_CDROM_ABSOLUTE_MSF);
+ write_status(0x19, 0x00, (msf >> 16) & 0xff, (msf >> 8) & 0xff);
+ extra_status++;
+ }
+ break;
+ case 4:
+ {
+ uint32_t msf = d_cdrom->read_signal(SIG_TOWNS_CDROM_ABSOLUTE_MSF);
+ write_status(0x19, msf & 0xff, 0x00, 0x00);
+ extra_status = 0;
+ }
+ break;
+ }
+ break;
+
+ }
+ case 0x84:
+ write_status(0x11, 0x00, 0x00, 0x00);
+ extra_status = 0;
+ break;
+ }
+ }
+ }
break;
case 0x4: //
if(pio_transfer) {
write_status(0x22, 0x00, 0x00, 0x00);
}
}
+ dma_fifo->clear(); // OK?
d_cdrom->start_command();
}
extra_status = 1;
write_status(0x00, 0x03, 0x00, 0x00);
}
+ dma_fifo->clear(); // OK?
d_cdrom->start_command();
}
void CDC::write_status(uint8_t a, uint8_t b, uint8_t c, uint8_t d)
{
- status_fifo->clear();
- status_fifo->write(a);
- status_fifo->write(b);
- status_fifo->write(c);
- status_fifo->write(d);
+ has_status = true;
+ stat_fifo->clear();
+ stat_fifo->write(a);
+ stat_fifo->write(b);
+ stat_fifo->write(c);
+ stat_fifo->write(d);
if(stat_reply_intr) {
if(!(submpu_intr_mask)) {
- output_signals(&output_submpu_intr, 0xffffffff);
+ write_signals(&output_submpu_intr, 0xffffffff);
}
submpu_intr = true;
}
}
+
+void CDC::enqueue_command_play(uint8_t cmd)
+{
+ //write_signals(&output_submpu_intr, 0x00000000);
+ if((d_cdrom->read_signal(SIG_TOWNS_CDROM_IS_MEDIA_INSERTED) == 0x00000000) && (cmd != 0xa0)) { // Not Inserted
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x10, 0x00, 0x00, 0x00);
+ }
+ } else {
+ has_status = false;
+ switch(cmd & 0x1f) {
+ case 0x00: // SEEK
+ if(req_status) {
+ extra_status = 1;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ }
+ // ToDo: REAL SEEK
+ break;
+ case 0x01: // Unknown (from MAME)
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x00, 0xff, 0xff, 0xff);
+ }
+ break;
+ case 0x02: // READ (Mode1)
+ read_cdrom(req_status);
+ break;
+ case 0x04: // PLAY CDDA
+ play_cdda(req_status);
+ break;
+ case 0x05: // Read TOC
+ if(req_status) {
+ extra_status = 1;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ } else {
+ extra_status = 2;
+ write_status(0x16, 0x00, 0xa0, 0x00);
+ }
+ break;
+ case 0x06: // CD-DA Stats (?)
+ extra_status = 1;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ break;
+ case 0x1f: // ??
+ extra_status = 0;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ break;
+ default: // Illegal command
+ extra_status = 0;
+ write_status(0x10, 0x00, 0x00, 0x00);
+ break;
+ }
+ }
+}
+
+void CDC::enqueue_command_status(uint8_t cmd)
+{
+ //write_signals(&output_submpu_intr, 0x00000000);
+ if((d_cdrom->read_signal(SIG_TOWNS_CDROM_IS_MEDIA_INSERTED) == 0x00000000) && (cmd != 0xa0)) { // Not Inserted
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x10, 0x00, 0x00, 0x00);
+ }
+ } else {
+ has_status = false;
+ switch(cmd & 0x1f) {
+ case 0x00: // set state
+ if(req_status) {
+ extra_status = 0;
+ if(d_cdrom->read_signal(SIG_SCSI_CDROM_PLAYING) != 0) { // Active() && !(paused)
+ write_status(0x00, 0x03, 0x00, 0x00);
+ } else {
+ write_status(0x00, 0x01, 0x00, 0x00);
+ }
+ }
+ break;
+ case 0x01: // set state (CDDASET)
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ }
+ break;
+ case 0x04: // STOP CDDA
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ }
+ d_cdrom->write_signal(SIG_SCSI_CDROM_CDDA_STOP, 0xffffffff, 0xffffffff);
+ break;
+ case 0x05: // STOP CDDA (Difference from $84?)
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x00, 0x00, 0x00, 0x00);
+ }
+ d_cdrom->write_signal(SIG_SCSI_CDROM_CDDA_PAUSE, 0xffffffff, 0xffffffff);
+ break;
+ case 0x07: // UNPAUSE CDDA
+ if(req_status) {
+ extra_status = 0;
+ write_status(0x00, 0x03, 0x00, 0x00);
+ }
+ d_cdrom->write_signal(SIG_SCSI_CDROM_CDDA_PAUSE, 0x00000000, 0xffffffff);
+ break;
+ default: // Illegal command
+ extra_status = 0;
+ write_status(0x10, 0x00, 0x00, 0x00);
+ break;
+ }
+ }
+}
+
+void CDC::write_signal(int ch, uint32_t data, uint32_t mask)
+{
+ switch(ch) {
+ case SIG_TOWNS_CDC_SET_DATA:
+ data_reg = data;
+ if(dma_fifo->full()) {
+ dma_fifo->read();
+ }
+ dma_fifo->write(data & 0xff);
+ break;
+ case SIG_TOWNS_CDC_DMA_DONE:
+ dma_intr = (data & mask) != 0) ? true : false;
+ if(!(dma_intr_mask)) {
+ write_signals(&output_dma_intr, (dma_intr) ? 0xffffffff : 0x00000000);
+ }
+ break;
+ case SIG_TOWNS_CDC_RESET_FIFO:
+ dma_fifo->reset();
+ break;
+ case SIG_TOWNS_CDC_SET_SUBQ:
+ if(subq_fifo->full()) {
+ subq_fifo->read();
+ }
+ subq_fifo->write(data & 0xff);
+ break;
+ case SIG_TOWNS_CDC_CLEAR_SUBQ:
+ subq_fifo->clear();
+ break;
+ }
+}
+
+uint32_t CDC::read_dma_io8(uint32_t addr)
+{
+ if((addr & 0x01) == 0) {
+ return (uint32_t)(dma_fifo->read() & 0xff);
+ }
+ return 0xff; // Noop
+}
+
+uint32_t CDC::read_dma_io16(uint32_t addr)
+{
+ if((addr & 0x01) == 0) {
+ pair16_t d;
+ d.b.l = dma_fifo->read() & 0xff;
+ d.b.h = dma_fifo->read() & 0xff;
+ return (uint32_t)(d.u16);
+ }
+ return 0xffff; // Noop
+}
+
+
+}
void TOWNS_CDROM::write_signal(int id, uint32_t data, uint32_t mask)
{
+ if(id == SIG_TOWNS_CDROM_SET_TRACK) {
+ if(((data < 100) && (data >= 0)) || (data == 0xaa)) {
+ stat_track = data;
+ }
+ return;
+ }
SCSI_CDROM::write_signal(id, data, mask);
}
uint32_t TOWNS_CDROM::read_signal(int id)
{
+ if(id == SIG_TOWNS_CDROM_IS_MEDIA_INSERTED) {
+ return ((is_device_ready()) ? 0xffffffff : 0x00000000);
+ } else if(id == SIG_TOWNS_CDROM_MAX_TRACK) {
+ if(track_num <= 0) {
+ return (uint32_t)(TO_BCD(0x00));
+ } else {
+ return (uint32_t)(TO_BCD(track_num));
+ }
+ } else if(id == SIG_TOWNS_CDROM_REACHED_MAX_TRACK) {
+ if(track_num <= 0) {
+ return 0xffffffff;
+ } else {
+ if(current_track >= track_num) {
+ return 0xffffffff;
+ } else {
+ return 0x00000000;
+ }
+ }
+ } else if(id == SIG_TOWNS_CDROM_CURRENT_TRACK) {
+ if(current_track > track_num) {
+ return 0x00000000;
+ } else {
+ return TO_BCD(current_track);
+ }
+ } else if(id == SIG_TOWNS_CDROM_START_MSF) {
+ int trk = stat_track;
+ if(trk <= 0) {
+ return 0xffffffff;
+ }
+ if(trk == 0xaa) {
+ trk = track_num;
+ }
+ int index0 = toc_table[trk].index0;
+ int index1 = toc_table[trk].index1
+ int pregap = toc_table[trk].pregap
+ uint32_t lba = (uint32_t)index0;
+ if(pregap > 0) lba = lba - pregap;
+ if(lba < 150) lba = 150;
+ uint32_t msf = lba_to_msf(lba); // Q:lba + 150?
+ stat_track++;
+ return msf;
+ } eise if(id == SIG_TOWNS_CDROM_START_MSF_AA) {
+ trk = track_num;
+ int index0 = toc_table[trk].index0;
+ int index1 = toc_table[trk].index1
+ int pregap = toc_table[trk].pregap
+ uint32_t lba = (uint32_t)index0;
+ if(pregap > 0) lba = lba - pregap;
+ if(lba < 150) lba = 150;
+ uint32_t msf = lba_to_msf(lba); // Q:lba + 150?
+ return msf;
+ } else if(id == SIG_TOWNS_CDROM_RELATIVE_MSF) {
+ if(toc_table[current_track].is_audio) {
+ if(!(is_device_ready())) {
+ return 0;
+ }
+ if(cdda_playing_frame <= cdda_start_frame) {
+ return 0;
+ }
+ uint32_t msf;
+ if(cdda_playing_frame >= cdda_end_frame) {
+ if(cdda_repeat) {
+ return 0;
+ } else {
+ msf = lba_to_msf(cdda_end_frame - cdda_start_frame);
+ return msf;
+ }
+ }
+ msf = lba_to_msf(cdda_playing_frame - cdda_start_frame);
+ return msf;
+ } else {
+ if(!(is_device_ready())) {
+ return 0;
+ }
+ if(fio_img->IsOpened()) {
+ uint32_t cur_position = (uint32_t)fio_img->Ftell();
+ cur_position = cur_position / logical_block_size();
+ if(cur_position >= max_logical_block) {
+ cur_position = max_logical_block;
+ }
+ uint32_t msf = lba_to_msf(cur_position);
+ return msf;
+ }
+ return 0;
+ }
+ } else if(id == SIG_TOWNS_CDROM_ABSOLUTE_MSF) {
+ if(toc_table[current_track].is_audio) {
+ if(!(is_device_ready())) {
+ return 0;
+ }
+ uint32_t msf;
+ msf = lba_to_msf(cdda_playing_frame);
+ return msf;
+ } else {
+ if(!(is_device_ready())) {
+ return 0;
+ }
+ if(fio_img->IsOpened()) {
+ uint32_t cur_position = (uint32_t)fio_img->Ftell();
+ cur_position = cur_position / logical_block_size();
+ if(cur_position >= max_logical_block) {
+ cur_position = max_logical_block;
+ }
+ uint32_t msf = lba_to_msf(cur_position + toc_table[current_track].lba_offset);
+ return msf;
+ }
+ return 0;
+ }
+ } else if(id == SIG_TOWNS_CDROM_GET_ADR) {
+ int trk = stat_track;
+ if(!(is_device_ready())) {
+ return 0xffffffff; // OK?
+ }
+ if(trk == 0xaa) {
+ return 0x10; // AUDIO SUBQ
+ }
+ if(trk > track_num) {
+ return 0xffffffff; // OK?
+ }
+ if(toc_table[trk].is_audio) {
+ return 0x10;
+ }
+ return 0x14; // return as data
+ }
return SCSI_CDROM::read_signal(id);
}