OSDN Git Service

[VM][FMTOWNS][WIP] Implementing CDROM.Still not buildable.
authorK.Ohta <whatisthis.sowhat@gmail.com>
Thu, 7 Feb 2019 08:18:12 +0000 (17:18 +0900)
committerK.Ohta <whatisthis.sowhat@gmail.com>
Thu, 7 Feb 2019 08:18:12 +0000 (17:18 +0900)
source/src/vm/fmtowns/cdc.cpp
source/src/vm/fmtowns/towns_cdrom.cpp

index b0720ea..6d7413c 100644 (file)
@@ -3,8 +3,38 @@
 
 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)
@@ -20,28 +50,28 @@ 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;
                }
@@ -90,6 +120,116 @@ uint32_t CDC::read_io8(uint32_t address)
                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) {
@@ -179,6 +319,7 @@ void CDC::read_cdrom(bool req_reply)
                        write_status(0x22, 0x00, 0x00, 0x00);
                }
        }
+       dma_fifo->clear(); // OK?
        d_cdrom->start_command();
 }      
 
@@ -209,21 +350,187 @@ void CDC::play_cdda(bool req_reply)
                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
+}
+
+
+}
index b666fee..81fd3c6 100644 (file)
@@ -38,11 +38,141 @@ void TOWNS_CDROM::reset()
 
 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);
 }