OSDN Git Service

[General][CMAKE] Integrate all devices to upstream 2015-12-17.
[csp-qt/common_source_project-fm7.git] / source / src / vm / z80sio.cpp
index d960ef2..6962793 100644 (file)
@@ -9,12 +9,10 @@
 
 #include "z80sio.h"
 #include "../fifo.h"
-#include "../fileio.h"
 
 #define EVENT_SEND     2
 #define EVENT_RECV     4
 
-
 //#define SIO_DEBUG
 
 #define MONOSYNC(ch)   ((port[ch].wr[4] & 0x3c) == 0x00)
 #define BIT_SYNC1      1
 #define BIT_SYNC2      2
 
+#define REGISTER_FIRST_SEND_EVENT(ch) { \
+       if(port[ch].tx_clock != 0) { \
+               if(port[ch].send_id == -1) { \
+                       register_event(this, EVENT_SEND + ch, 1000000.0 / port[ch].tx_clock / 2.0, false, &port[ch].send_id); \
+               } \
+       } else { \
+               if(port[ch].tx_bits_x2_remain == 0) { \
+                       port[ch].tx_bits_x2_remain = 1; \
+               } \
+       } \
+}
+
 #define REGISTER_SEND_EVENT(ch) { \
        if(port[ch].tx_clock != 0) { \
                if(port[ch].send_id == -1) { \
 void Z80SIO::initialize()
 {
        for(int ch = 0; ch < 2; ch++) {
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                port[ch].send = new FIFO(16);
                port[ch].recv = new FIFO(16);
                port[ch].rtmp = new FIFO(16);
 #else
-               port[ch].send = new FIFO(2);
+               port[ch].send = new FIFO(1);
                port[ch].recv = new FIFO(4);
                port[ch].rtmp = new FIFO(8);
 #endif
@@ -101,14 +111,15 @@ void Z80SIO::reset()
                port[ch].over_flow = false;
                port[ch].under_run = false;
                port[ch].abort = false;
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                port[ch].tx_count = 0;
 #endif
-               port[ch].send_id = -1;
-               port[ch].recv_id = -1;
                port[ch].send->clear();
                port[ch].recv->clear();
                port[ch].rtmp->clear();
+               port[ch].shift_reg = -1;
+               port[ch].send_id = -1;
+               port[ch].recv_id = -1;
                memset(port[ch].wr, 0, sizeof(port[ch].wr));
                // interrupt
                port[ch].err_intr = false;
@@ -157,16 +168,11 @@ void Z80SIO::write_io8(uint32 addr, uint32 data)
        case 0:
        case 2:
                // send data
-               port[ch].send->write(data);
-#ifdef UPD7210
-               port[ch].tx_count++;
-#endif
                if(port[ch].send_intr) {
                        port[ch].send_intr = false;
                        update_intr();
                }
                // register next event
-               CANCEL_SEND_EVENT(ch);
                if(port[ch].wr[5] & 8) {
                        int tx_data_bits = 5;
                        if((data & 0xe0) == 0x00) {
@@ -184,8 +190,23 @@ void Z80SIO::write_io8(uint32 addr, uint32 data)
                                port[ch].tx_data_bits = tx_data_bits;
                                update_tx_timing(ch);
                        }
-                       REGISTER_SEND_EVENT(ch);
+                       if((port[ch].wr[4] & 0x0c) != 0 && port[ch].shift_reg == -1 && port[ch].send->empty()) {
+                               // this is the first data
+                               CANCEL_SEND_EVENT(ch);
+                               REGISTER_FIRST_SEND_EVENT(ch);
+                       } else {
+                               REGISTER_SEND_EVENT(ch);
+                       }
+               } else {
+                       CANCEL_SEND_EVENT(ch);
                }
+#ifndef HAS_UPD7201
+               port[ch].send->clear();
+#endif
+               port[ch].send->write(data);
+#ifdef HAS_UPD7201
+               port[ch].tx_count++;
+#endif
                break;
        case 1:
        case 3:
@@ -203,17 +224,19 @@ void Z80SIO::write_io8(uint32 addr, uint32 data)
                                }
                                break;
                        case 0x18:
+                               // channel reset
                                CANCEL_SEND_EVENT(ch);
                                CANCEL_RECV_EVENT(ch);
                                port[ch].nextrecv_intr = false;
                                port[ch].first_data = false;
                                port[ch].over_flow = false;
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                                port[ch].tx_count = 0;  // is this correct ???
 #endif
                                port[ch].send->clear();
                                port[ch].recv->clear();
                                port[ch].rtmp->clear();
+                               port[ch].shift_reg = -1;
                                memset(port[ch].wr, 0, sizeof(port[ch].wr));
                                // interrupt
                                if(port[ch].err_intr) {
@@ -324,7 +347,12 @@ void Z80SIO::write_io8(uint32 addr, uint32 data)
                                write_signals(&port[ch].outputs_dtr, (data & 0x80) ? 0 : 0xffffffff);
                        }
                        if(data & 8) {
-                               REGISTER_SEND_EVENT(ch);
+                               if((port[ch].wr[4] & 0x0c) != 0 && port[ch].shift_reg == -1 && !port[ch].send->empty()) {
+//                                     CANCEL_SEND_EVENT(ch);
+                                       REGISTER_FIRST_SEND_EVENT(ch);
+                               } else {
+                                       REGISTER_SEND_EVENT(ch);
+                               }
                        } else {
                                CANCEL_SEND_EVENT(ch);
                        }
@@ -405,11 +433,13 @@ uint32 Z80SIO::read_io8(uint32 addr)
                        }
                } else if(port[ch].pointer == 2) {
                        val = port[ch].vector;
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                } else if(port[ch].pointer == 3) {
                        val = port[ch].tx_count & 0xff;
+                       port[ch].tx_count_hi = port[ch].tx_count >> 8;
                } else if(port[ch].pointer == 4) {
-                       val = (port[ch].tx_count >> 8) & 0xff;
+//                     val = (port[ch].tx_count >> 8) & 0xff;
+                       val = port[ch].tx_count_hi;
 #endif
                }
                port[ch].pointer = 0;
@@ -465,7 +495,12 @@ void Z80SIO::write_signal(int id, uint32 data, uint32 mask)
                        port[ch].cts = signal;
                        if(!signal && (port[ch].wr[3] & 0x20)) {
                                // auto enables
-                               REGISTER_SEND_EVENT(ch);
+                               if((port[ch].wr[4] & 0x0c) != 0 && port[ch].shift_reg == -1 && !port[ch].send->empty()) {
+//                                     CANCEL_SEND_EVENT(ch);
+                                       REGISTER_FIRST_SEND_EVENT(ch);
+                               } else {
+                                       REGISTER_SEND_EVENT(ch);
+                               }
                                port[ch].wr[5] |= 8;
                        }
                        if(!port[ch].stat_intr) {
@@ -526,7 +561,20 @@ void Z80SIO::event_callback(int event_id, int err)
                port[ch].send_id = -1;
                port[ch].tx_bits_x2_remain = 0;
                
-               if(port[ch].send->empty()) {
+               bool under_run = true;
+               
+               if(port[ch].shift_reg != -1) {
+                       // send data in shift register
+                       write_signals(&port[ch].outputs_send, port[ch].shift_reg);
+                       port[ch].shift_reg = -1;
+                       under_run = false;
+               }
+               if(!port[ch].send->empty()) {
+                       // load data in send buffer to shift register
+                       port[ch].shift_reg = port[ch].send->read();
+                       under_run = false;
+               }
+               if(under_run) {
                        // underrun interrupt
                        if(!port[ch].under_run) {
                                port[ch].under_run = true;
@@ -535,9 +583,6 @@ void Z80SIO::event_callback(int event_id, int err)
                                        update_intr();
                                }
                        }
-               } else {
-                       uint32 data = port[ch].send->read();
-                       write_signals(&port[ch].outputs_send, data);
                }
                if(port[ch].send->empty()) {
                        // transmitter interrupt
@@ -547,7 +592,6 @@ void Z80SIO::event_callback(int event_id, int err)
                        }
                        write_signals(&port[ch].outputs_txdone, 0xffffffff);
                }
-               // register next event
                REGISTER_SEND_EVENT(ch);
        } else if(event_id & EVENT_RECV) {
                // recv
@@ -763,7 +807,7 @@ void Z80SIO::update_intr()
        
        // create vector
        if(port[1].wr[1] & 4) {
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                uint8 affect = 7;       // no interrupt pending
                for(int ch = 0; ch < 2; ch++) {
                        if(port[ch].in_service) {
@@ -864,7 +908,7 @@ void Z80SIO::intr_reti()
        }
 }
 
-#define STATE_VERSION  2
+#define STATE_VERSION  3
 
 void Z80SIO::save_state(FILEIO* state_fio)
 {
@@ -883,8 +927,9 @@ void Z80SIO::save_state(FILEIO* state_fio)
                state_fio->FputBool(port[i].abort);
                state_fio->FputBool(port[i].sync);
                state_fio->FputUint8(port[i].sync_bit);
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                state_fio->FputUint16(port[i].tx_count);
+               state_fio->FputUint8(port[i].tx_count_hi);
 #endif
                state_fio->FputDouble(port[i].tx_clock);
                state_fio->FputDouble(port[i].tx_interval);
@@ -900,6 +945,7 @@ void Z80SIO::save_state(FILEIO* state_fio)
                port[i].send->save_state((void *)state_fio);
                port[i].recv->save_state((void *)state_fio);
                port[i].rtmp->save_state((void *)state_fio);
+               state_fio->FputInt32(port[i].shift_reg);
                state_fio->FputInt32(port[i].send_id);
                state_fio->FputInt32(port[i].recv_id);
                state_fio->FputBool(port[i].err_intr);
@@ -936,8 +982,9 @@ bool Z80SIO::load_state(FILEIO* state_fio)
                port[i].abort = state_fio->FgetBool();
                port[i].sync = state_fio->FgetBool();
                port[i].sync_bit = state_fio->FgetUint8();
-#ifdef UPD7201
+#ifdef HAS_UPD7201
                port[i].tx_count = state_fio->FgetUint16();
+               port[i].tx_count_hi = state_fio->FgetUint8();
 #endif
                port[i].tx_clock = state_fio->FgetDouble();
                port[i].tx_interval = state_fio->FgetDouble();
@@ -959,6 +1006,7 @@ bool Z80SIO::load_state(FILEIO* state_fio)
                if(!port[i].rtmp->load_state((void *)state_fio)) {
                        return false;
                }
+               port[i].shift_reg = state_fio->FgetInt32();
                port[i].send_id = state_fio->FgetInt32();
                port[i].recv_id = state_fio->FgetInt32();
                port[i].err_intr = state_fio->FgetBool();