summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
-rw-r--r--src/devices/machine/z80sio.cpp179
-rw-r--r--src/devices/machine/z80sio.h37
-rw-r--r--src/mame/drivers/apricot.cpp5
-rw-r--r--src/mame/machine/kay_kbd.cpp29
-rw-r--r--src/mame/machine/kay_kbd.h3
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;