diff options
-rw-r--r-- | src/devices/machine/z80sio.cpp | 179 | ||||
-rw-r--r-- | src/devices/machine/z80sio.h | 37 | ||||
-rw-r--r-- | src/mame/drivers/apricot.cpp | 5 | ||||
-rw-r--r-- | src/mame/machine/kay_kbd.cpp | 29 | ||||
-rw-r--r-- | src/mame/machine/kay_kbd.h | 3 |
5 files changed, 138 insertions, 115 deletions
diff --git a/src/devices/machine/z80sio.cpp b/src/devices/machine/z80sio.cpp index 8cf9169c6b2..e17d7c83fa9 100644 --- a/src/devices/machine/z80sio.cpp +++ b/src/devices/machine/z80sio.cpp @@ -122,10 +122,6 @@ z80sio_device::z80sio_device(const machine_config &mconfig, device_type type, co device_z80daisy_interface(mconfig, *this), m_chanA(*this, CHANA_TAG), m_chanB(*this, CHANB_TAG), - m_rxca(0), - m_txca(0), - m_rxcb(0), - m_txcb(0), m_out_txda_cb(*this), m_out_dtra_cb(*this), m_out_rtsa_cb(*this), @@ -195,14 +191,6 @@ void z80sio_device::device_start() { LOG("%s\n", FUNCNAME); - // configure channel A - m_chanA->m_rxc = m_rxca; - m_chanA->m_txc = m_txca; - - // configure channel B - m_chanB->m_rxc = m_rxcb; - m_chanB->m_txc = m_txcb; - // state saving save_item(NAME(m_int_state)); save_item(NAME(m_int_source)); @@ -523,8 +511,10 @@ WRITE8_MEMBER( z80sio_device::ba_cd_w ) z80sio_channel::z80sio_channel(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, Z80SIO_CHANNEL, tag, owner, clock) , device_serial_interface(mconfig, *this) - , m_rx_error(0) , m_rx_clock(0) + , m_rx_count(0) + , m_rx_bit(0) + , m_rx_sr(0) , m_rx_first(0) , m_rx_break(0) , m_rx_rr0_latch(0) @@ -576,8 +566,10 @@ void z80sio_channel::device_start() save_item(NAME(m_wr5)); save_item(NAME(m_wr6)); save_item(NAME(m_wr7)); - save_item(NAME(m_rx_error)); save_item(NAME(m_rx_clock)); + save_item(NAME(m_rx_count)); + save_item(NAME(m_rx_bit)); + save_item(NAME(m_rx_sr)); save_item(NAME(m_rx_first)); save_item(NAME(m_rx_break)); save_item(NAME(m_rx_rr0_latch)); @@ -601,7 +593,7 @@ void z80sio_channel::device_reset() LOG("%s\n", FUNCNAME); // Reset RS232 emulation - receive_register_reset(); + receive_reset(); transmit_register_reset(); // disable receiver @@ -717,33 +709,6 @@ void z80sio_channel::tra_complete() //------------------------------------------------- -// rcv_callback - -//------------------------------------------------- -void z80sio_channel::rcv_callback() -{ - if (m_wr3 & WR3_RX_ENABLE) - { - LOGBIT("%s() \"%s \"Channel %c Received Data Bit %d\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_rxd); - receive_register_update_bit(m_rxd); - } -} - - -//------------------------------------------------- -// rcv_complete - -//------------------------------------------------- -void z80sio_channel::rcv_complete() -{ - uint8_t data; - - receive_register_extract(); - data = get_received_char(); - LOGRCV("%s() \"%s \"Channel %c Received Data %02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, data); - receive_data(data); -} - - -//------------------------------------------------- // get_clock_mode - get clock divisor //------------------------------------------------- int z80sio_channel::get_clock_mode() @@ -1205,7 +1170,7 @@ uint8_t z80sio_channel::data_read() data = m_rx_data_fifo.dequeue(); // load error status from the FIFO - m_rr1 = (m_rr1 & ~(RR1_CRC_FRAMING_ERROR | RR1_RX_OVERRUN_ERROR | RR1_PARITY_ERROR)) | m_rx_error_fifo.dequeue(); + m_rr1 = (m_rr1 & ~RR1_CRC_FRAMING_ERROR) | m_rx_error_fifo.dequeue(); if (m_rx_data_fifo.empty()) { @@ -1250,17 +1215,28 @@ void z80sio_channel::data_write(uint8_t data) //------------------------------------------------- +// receive_reset - reset receive state +//------------------------------------------------- +void z80sio_channel::receive_reset() +{ + m_rx_count = (get_clock_mode() - 1) / 2; + m_rx_bit = 0; +} + +//------------------------------------------------- // receive_data - receive data word //------------------------------------------------- -void z80sio_channel::receive_data(uint8_t data) +void z80sio_channel::receive_data() { - LOGRCV("%s(%02x) %s:%c\n",FUNCNAME, data, tag(), 'A' + m_index); + LOGRCV("%s(%04x) %s:%c\n",FUNCNAME, m_rx_sr, tag(), 'A' + m_index); if (m_rx_data_fifo.full()) { + // FIXME: this should overwrite the tail of the FIFO and store the overrun error + LOG(" Overrun detected\n"); // receive overrun error detected - m_rx_error |= RR1_RX_OVERRUN_ERROR; + //uint8_t rx_error |= RR1_RX_OVERRUN_ERROR; switch (m_wr1 & WR1_RX_INT_MODE_MASK) { @@ -1279,9 +1255,24 @@ void z80sio_channel::receive_data(uint8_t data) } else { + // check for parity and framing errors + int const word_length = get_rx_word_length(); + bool const parity = 0U != (m_wr4 & WR4_PARITY_ENABLE); + uint16_t const stop_bit = uint16_t(1U) << (word_length + (parity ? 1 : 0)); + uint8_t rx_error = (m_rx_sr & stop_bit) ? 0U : RR1_CRC_FRAMING_ERROR; + m_rx_sr |= stop_bit; + if (parity) + { + uint16_t par(m_rx_sr); + for (int i = 1; word_length >= i; ++i) + par ^= BIT(par, i); + if (bool(BIT(par, 0)) == bool(m_wr4 & WR4_PARITY_EVEN)) + rx_error |= RR1_PARITY_ERROR; + } + // store received character and error status into FIFO - m_rx_data_fifo.enqueue(data); - m_rx_error_fifo.enqueue(m_rx_error); + m_rx_data_fifo.enqueue(uint8_t(m_rx_sr & 0xffU)); + m_rx_error_fifo.enqueue(rx_error); } m_rr0 |= RR0_RX_CHAR_AVAILABLE; @@ -1301,9 +1292,9 @@ void z80sio_channel::receive_data(uint8_t data) case WR1_RX_INT_ALL: m_uart->trigger_interrupt(m_index, INT_RECEIVE); break; + default: LOG("No interrupt triggered\n"); - } } @@ -1421,18 +1412,62 @@ WRITE_LINE_MEMBER( z80sio_channel::sync_w ) WRITE_LINE_MEMBER( z80sio_channel::rxc_w ) { //LOG("Z80SIO \"%s\" Channel %c : Receiver Clock Pulse\n", owner()->tag(), m_index + 'A'); - int clocks = get_clock_mode(); - if (clocks == 1) - rx_clock_w(state); - else if(state) + if ((m_wr3 & WR3_RX_ENABLE) && state && !m_rx_clock) { - rx_clock_w(m_rx_clock < clocks/2); + // RxD sampled on rising edge + int const clocks = get_clock_mode() - 1; - m_rx_clock++; - if (m_rx_clock == clocks) - m_rx_clock = 0; + if (!m_rx_bit) + { + // look for start bit + if (m_rxd) + { + // line idle + m_rx_count = (std::max)(m_rx_count, (clocks / 2) + 1) - 1; + } + else if (!m_rx_count) + { + // half a bit period expired, start shifting bits + m_rx_count = clocks; + ++m_rx_bit; + m_rx_sr = ~uint16_t(0U); + } + else + { + // ensure start bit lasts long enough + --m_rx_count; + } + } + else if (!m_rx_count) + { + // sample a data/parity/stop bit + if (!m_rxd) + m_rx_sr &= ~uint16_t(1U << (m_rx_bit - 1)); + + if ((get_rx_word_length() + ((m_wr4 & WR4_PARITY_ENABLE) ? 1 : 0) + 1) == m_rx_bit) + { + // this is the stop bit - framing error adds a half bit period + LOGBIT("%s() \"%s \"Channel %c Received Data Bit %d\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_rxd); + m_rx_count = m_rxd ? 0 : clocks; + m_rx_bit = 0; + LOGRCV("%s() \"%s \"Channel %c Received Data %02x\n", FUNCNAME, owner()->tag(), 'A' + m_index, m_rx_sr & 0xff); + receive_data(); + } + else + { + // wait a whole bit period for the next bit + m_rx_count = clocks; + ++m_rx_bit; + } + } + else + { + // bit period hasn't expired + --m_rx_count; + } } + m_rx_clock = state; } @@ -1462,8 +1497,8 @@ WRITE_LINE_MEMBER( z80sio_channel::txc_w ) //------------------------------------------------- void z80sio_channel::update_serial() { - int data_bit_count = get_rx_word_length(); - stop_bits_t stop_bits = get_stop_bits(); + int const data_bit_count = get_rx_word_length(); + stop_bits_t const stop_bits = get_stop_bits(); parity_t parity; LOG("%s\n", FUNCNAME); @@ -1481,20 +1516,7 @@ void z80sio_channel::update_serial() set_data_frame(1, data_bit_count, parity, stop_bits); - int clocks = get_clock_mode(); - - if (m_rxc > 0) - { - LOG("- RxC:%d/%d = %d\n", m_rxc, clocks, m_rxc / clocks); - set_rcv_rate(m_rxc / clocks); - } - - if (m_txc > 0) - { - LOG("- TxC:%d/%d = %d\n", m_txc, clocks, m_txc / clocks); - set_tra_rate(m_txc / clocks); - } - receive_register_reset(); // if stop bits is changed from 0, receive register has to be reset + receive_reset(); // if stop bits is changed from 0, receive register has to be reset } @@ -1511,14 +1533,3 @@ void z80sio_channel::set_dtr(int state) else m_uart->m_out_dtrb_cb(m_dtr); } - -//------------------------------------------------- -// write_rx - -//------------------------------------------------- -WRITE_LINE_MEMBER(z80sio_channel::write_rx) -{ - m_rxd = state; - //only use rx_w when self-clocked - if(m_rxc) - device_serial_interface::rx_w(state); -} diff --git a/src/devices/machine/z80sio.h b/src/devices/machine/z80sio.h index 55803b7e427..dfe33c4068b 100644 --- a/src/devices/machine/z80sio.h +++ b/src/devices/machine/z80sio.h @@ -67,9 +67,6 @@ #define SIO_CHANB_TAG "chb" /* Generic macros */ -#define MCFG_Z80SIO_OFFSETS(_rxa, _txa, _rxb, _txb) \ - z80sio_device::configure_channels(*device, _rxa, _txa, _rxb, _txb); - #define MCFG_Z80SIO_OUT_INT_CB(_devcb) \ devcb = &z80sio_device::set_out_int_callback(*device, DEVCB_##_devcb); @@ -129,8 +126,7 @@ class z80sio_device; -class z80sio_channel : public device_t, - public device_serial_interface +class z80sio_channel : public device_t, public device_serial_interface { friend class z80sio_device; @@ -140,8 +136,6 @@ public: // device_serial_interface overrides virtual void tra_callback() override; virtual void tra_complete() override; - virtual void rcv_callback() override; - virtual void rcv_complete() override; // read register handlers uint8_t do_sioreg_rr0(); @@ -165,18 +159,16 @@ public: uint8_t data_read(); void data_write(uint8_t data); - void receive_data(uint8_t data); + void receive_reset(); + void receive_data(); - DECLARE_WRITE_LINE_MEMBER( write_rx ); + DECLARE_WRITE_LINE_MEMBER( write_rx ) { m_rxd = state; } DECLARE_WRITE_LINE_MEMBER( cts_w ); DECLARE_WRITE_LINE_MEMBER( dcd_w ); DECLARE_WRITE_LINE_MEMBER( rxc_w ); DECLARE_WRITE_LINE_MEMBER( txc_w ); DECLARE_WRITE_LINE_MEMBER( sync_w ); - int m_rxc; - int m_txc; - // Register state // read registers enum uint8_t m_rr0; // REG_RR0_STATUS @@ -380,9 +372,12 @@ protected: // receiver state util::fifo<uint8_t, 3> m_rx_data_fifo; util::fifo<uint8_t, 3> m_rx_error_fifo; - uint8_t m_rx_error; // current receive error - int m_rx_clock; // receive clock pulse count + int m_rx_clock; // receive clock line state + int m_rx_count; // clocks until next sample + int m_rx_bit; // receive data bit (0 = start bit, 1 = LSB, etc.) + uint16_t m_rx_sr; // receive shift register + int m_rx_first; // first character received int m_rx_break; // receive break condition uint8_t m_rx_rr0_latch; // read register 0 latched @@ -440,15 +435,6 @@ public: dev.m_cputag = tag; } - static void configure_channels(device_t &device, int rxa, int txa, int rxb, int txb) - { - z80sio_device &dev = downcast<z80sio_device &>(device); - dev.m_rxca = rxa; - dev.m_txca = txa; - dev.m_rxcb = rxb; - dev.m_txcb = txb; - } - DECLARE_READ8_MEMBER( cd_ba_r ); DECLARE_WRITE8_MEMBER( cd_ba_w ); DECLARE_READ8_MEMBER( ba_cd_r ); @@ -521,11 +507,6 @@ protected: required_device<z80sio_channel> m_chanB; // internal state - int m_rxca; - int m_txca; - int m_rxcb; - int m_txcb; - devcb_write_line m_out_txda_cb; devcb_write_line m_out_dtra_cb; devcb_write_line m_out_rtsa_cb; diff --git a/src/mame/drivers/apricot.cpp b/src/mame/drivers/apricot.cpp index 964b2484555..7a2b1d67716 100644 --- a/src/mame/drivers/apricot.cpp +++ b/src/mame/drivers/apricot.cpp @@ -20,6 +20,7 @@ #include "cpu/i8089/i8089.h" #include "formats/apridisk.h" #include "imagedev/flopdrv.h" +#include "machine/clock.h" #include "machine/ram.h" #include "machine/74153.h" #include "machine/i8255.h" @@ -412,8 +413,10 @@ static MACHINE_CONFIG_START( apricot ) MCFG_TTL153_ZA_CB(DEVWRITELINE("ic15", z80sio_device, rxca_w)) MCFG_TTL153_ZB_CB(DEVWRITELINE("ic15", z80sio_device, txca_w)) + MCFG_CLOCK_ADD("ic15_rxtxcb", XTAL_4MHz / 16) + MCFG_CLOCK_SIGNAL_HANDLER(DEVWRITELINE("ic15", z80sio_device, rxtxcb_w)) + MCFG_DEVICE_ADD("ic15", Z80SIO, XTAL_15MHz / 6) - MCFG_Z80SIO_OFFSETS(0, 0, XTAL_4MHz / 16, XTAL_4MHz / 16) MCFG_Z80SIO_CPU("ic91") MCFG_Z80SIO_OUT_TXDA_CB(DEVWRITELINE("rs232", rs232_port_device, write_txd)) MCFG_Z80SIO_OUT_DTRA_CB(DEVWRITELINE("rs232", rs232_port_device, write_dtr)) diff --git a/src/mame/machine/kay_kbd.cpp b/src/mame/machine/kay_kbd.cpp index de2ee0935fc..29baed6184e 100644 --- a/src/mame/machine/kay_kbd.cpp +++ b/src/mame/machine/kay_kbd.cpp @@ -11,6 +11,14 @@ #include "emu.h" #include "machine/kay_kbd.h" +#define LOG_GENERAL (1U << 0) +#define LOG_TXD (1U << 1) + +//#define VERBOSE (LOG_GENERAL | LOG_TXD) +#include "logmacro.h" + +#define LOGTXD(...) LOGMASKED(LOG_TXD, __VA_ARGS__) + /* * The KAYPRO keyboard has roughly the following layout: @@ -323,8 +331,9 @@ kaypro_10_keyboard_device::kaypro_10_keyboard_device( machine_config const &mconfig, char const *tag, device_t *owner, - uint32_t clock) + std::uint32_t clock) : device_t(mconfig, KAYPRO_10_KEYBOARD, tag, owner, clock) + , m_mcu(*this, "mcu") , m_bell(*this, "bell") , m_matrix(*this, "ROW.%X", 0) , m_modifiers(*this, "MOD") @@ -379,6 +388,24 @@ READ8_MEMBER(kaypro_10_keyboard_device::p2_r) WRITE8_MEMBER(kaypro_10_keyboard_device::p2_w) { + if ((VERBOSE & LOG_TXD) && (0x0014U >= static_cast<device_state_interface *>(m_mcu)->safe_pc())) + { + auto const suppressor(machine().disable_side_effect()); + address_space &mcu_ram(m_mcu->space(AS_DATA)); + std::uint8_t const txd_time(mcu_ram.read_byte(0x1cU)); + std::uint8_t const serial_flags(mcu_ram.read_byte(0x1eU)); + bool const txd_active(BIT(serial_flags, 6)); + if ((21U == txd_time) && txd_active) + { + std::uint8_t const txd_bit(mcu_ram.read_byte(0x1bU)); + LOGTXD( + (9U == txd_bit) ? "serial transmit: start bit = %1$u (cycles = %3$u)\n" : "serial transmit: bit %2$u = %1$u (cycles = %3$u)\n", + BIT(data, 7), + 8U - txd_bit, + m_mcu->total_cycles()); + } + } + m_bell->level_w(BIT(data, 6)); m_rxd_cb(BIT(data, 7)); } diff --git a/src/mame/machine/kay_kbd.h b/src/mame/machine/kay_kbd.h index 22edbaf207b..9bed953824d 100644 --- a/src/mame/machine/kay_kbd.h +++ b/src/mame/machine/kay_kbd.h @@ -19,7 +19,7 @@ public: machine_config const &mconfig, char const *tag, device_t *owner, - uint32_t clock); + std::uint32_t clock); template <class Object> static devcb_base &set_rxd_cb(device_t &device, Object &&cb) { return downcast<kaypro_10_keyboard_device &>(device).m_rxd_cb.set_callback(std::forward<Object>(cb)); } @@ -40,6 +40,7 @@ protected: DECLARE_WRITE8_MEMBER(bus_w); private: + required_device<cpu_device> m_mcu; required_device<speaker_sound_device> m_bell; required_ioport_array<16> m_matrix; required_ioport m_modifiers; |