mirror of
https://github.com/holub/mame
synced 2025-04-21 07:52:35 +03:00
Improve DL11 emulation (maintenance mode, break rx/tx) and add support for (#13184)
1801VP1-065 variant. Passes ZDLDH0 test and works with TU58 driver (DD.SYS).
This commit is contained in:
parent
fadf2b06b4
commit
2c539b6791
@ -2,11 +2,24 @@
|
||||
// copyright-holders:Sergey Svishchev
|
||||
/***************************************************************************
|
||||
|
||||
DEC DL11-type SLU (serial line unit).
|
||||
DEC DL11-type SLU (serial line unit) and compatible devices.
|
||||
|
||||
Frame format is not software-configurable; hardcoded to 8N1 for now.
|
||||
|
||||
dl11_device implements all features of DL11-D Unibus device.
|
||||
|
||||
1801VP1-065 is a single chip implementation used in Soviet clones:
|
||||
- error bits are in RCSR, not RBUF, and are not cleared by new data
|
||||
- on overflow, RBUF keeps first received byte
|
||||
- reading TBUF returns transmit interrupt vector
|
||||
- writing to RBUF does nothing
|
||||
- INIT does not set DONE in TCSR
|
||||
- supports RTS/CTS flow control
|
||||
- always sends 2 stop bits
|
||||
|
||||
http://www.ibiblio.org/pub/academic/computer-science/history/pdp-11/hardware/micronotes/numerical/micronote33.txt
|
||||
bitsavers://pdf/dec/unibus/EK-DL11-TM-003_DL11_Asynchronous_Line_Interface_Manual_Sep75.pdf
|
||||
https://github.com/1801BM1/k1801/blob/master/065/
|
||||
|
||||
***************************************************************************/
|
||||
|
||||
@ -19,7 +32,8 @@
|
||||
//**************************************************************************
|
||||
|
||||
// device type definition
|
||||
DEFINE_DEVICE_TYPE(DL11, dl11_device, "dl11", "DEC DL11-type SLU")
|
||||
DEFINE_DEVICE_TYPE(DL11, dl11_device, "dl11", "DEC DL11-D SLU")
|
||||
DEFINE_DEVICE_TYPE(K1801VP065, k1801vp065_device, "1801vp1_065", "1801VP1-065")
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
@ -42,10 +56,11 @@ enum
|
||||
// dl11_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
dl11_device::dl11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, DL11, tag, owner, clock)
|
||||
dl11_device::dl11_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock)
|
||||
: device_t(mconfig, type, tag, owner, clock)
|
||||
, device_serial_interface(mconfig, *this)
|
||||
, device_z80daisy_interface(mconfig, *this)
|
||||
, m_installed(false)
|
||||
, m_write_txd(*this)
|
||||
, m_write_rxrdy(*this)
|
||||
, m_write_txrdy(*this)
|
||||
@ -56,6 +71,11 @@ dl11_device::dl11_device(const machine_config &mconfig, const char *tag, device_
|
||||
{
|
||||
}
|
||||
|
||||
dl11_device::dl11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: dl11_device(mconfig, DL11, tag, owner, clock)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_start - device-specific startup
|
||||
@ -68,8 +88,9 @@ void dl11_device::device_start()
|
||||
save_item(NAME(m_rbuf));
|
||||
save_item(NAME(m_tcsr));
|
||||
save_item(NAME(m_tbuf));
|
||||
}
|
||||
|
||||
m_installed = false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// device_reset - device-specific reset
|
||||
@ -77,22 +98,34 @@ void dl11_device::device_start()
|
||||
|
||||
void dl11_device::device_reset()
|
||||
{
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
||||
if (!m_installed)
|
||||
{
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
||||
|
||||
// create the timers
|
||||
if (m_rxc > 0)
|
||||
set_rcv_rate(m_rxc);
|
||||
// create the timers
|
||||
if (m_rxc > 0)
|
||||
set_rcv_rate(m_rxc);
|
||||
|
||||
if (m_txc > 0)
|
||||
set_tra_rate(m_txc);
|
||||
if (m_txc > 0)
|
||||
set_tra_rate(m_txc);
|
||||
|
||||
m_rcsr = m_rbuf = m_tbuf = 0;
|
||||
m_tcsr = CSR_DONE;
|
||||
m_rxrdy = m_txrdy = CLEAR_LINE;
|
||||
m_rcsr = m_rbuf = m_tbuf = 0;
|
||||
m_tcsr = CSR_DONE;
|
||||
m_rxrdy = m_txrdy = CLEAR_LINE;
|
||||
|
||||
m_write_txd(1);
|
||||
m_write_rxrdy(m_rxrdy);
|
||||
m_write_txrdy(m_txrdy);
|
||||
m_write_txd(1);
|
||||
|
||||
m_installed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rbuf &= 255; // clear error bits
|
||||
m_rcsr &= ~(CSR_IE | CSR_DONE | DLRCSR_ACT);
|
||||
m_tcsr &= ~(DLTCSR_XBRK | DLTCSR_MAINT | CSR_IE);
|
||||
m_tcsr |= CSR_DONE;
|
||||
clear_virq(m_write_rxrdy, 1, 1, m_rxrdy);
|
||||
clear_virq(m_write_txrdy, 1, 1, m_txrdy);
|
||||
}
|
||||
}
|
||||
|
||||
int dl11_device::z80daisy_irq_state()
|
||||
@ -134,11 +167,18 @@ void dl11_device::tra_callback()
|
||||
{
|
||||
if (m_tcsr & DLTCSR_XBRK)
|
||||
{
|
||||
m_write_txd(0);
|
||||
transmit_register_get_data_bit();
|
||||
if (m_tcsr & DLTCSR_MAINT)
|
||||
rx_w(0);
|
||||
else
|
||||
m_write_txd(0);
|
||||
}
|
||||
else if (!is_transmit_register_empty())
|
||||
{
|
||||
m_write_txd(transmit_register_get_data_bit());
|
||||
if (m_tcsr & DLTCSR_MAINT)
|
||||
rx_w(transmit_register_get_data_bit());
|
||||
else
|
||||
m_write_txd(transmit_register_get_data_bit());
|
||||
}
|
||||
}
|
||||
|
||||
@ -154,6 +194,18 @@ void dl11_device::tra_complete()
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// rcv_callback -
|
||||
//-------------------------------------------------
|
||||
|
||||
void dl11_device::rx_w(int state)
|
||||
{
|
||||
device_serial_interface::rx_w(state);
|
||||
if (is_receive_register_synchronized())
|
||||
m_rcsr |= DLRCSR_ACT;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// rcv_complete -
|
||||
//-------------------------------------------------
|
||||
@ -161,13 +213,10 @@ void dl11_device::tra_complete()
|
||||
void dl11_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
m_rbuf = get_received_char();
|
||||
if (is_receive_framing_error())
|
||||
{
|
||||
m_rbuf = DLRBUF_ERR | DLRBUF_RBRK;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rbuf = get_received_char();
|
||||
m_rbuf |= DLRBUF_ERR | DLRBUF_RBRK;
|
||||
}
|
||||
if (is_receive_parity_error())
|
||||
{
|
||||
@ -181,6 +230,7 @@ void dl11_device::rcv_complete()
|
||||
{
|
||||
m_rcsr |= CSR_DONE;
|
||||
}
|
||||
m_rcsr &= ~DLRCSR_ACT;
|
||||
raise_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
}
|
||||
|
||||
@ -201,8 +251,11 @@ uint16_t dl11_device::read(offs_t offset)
|
||||
|
||||
case DLRBUF:
|
||||
data = m_rbuf;
|
||||
m_rcsr &= ~CSR_DONE;
|
||||
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
m_rcsr &= ~CSR_DONE;
|
||||
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
}
|
||||
break;
|
||||
|
||||
case DLTCSR:
|
||||
@ -236,9 +289,16 @@ void dl11_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
raise_virq(m_write_rxrdy, 1, 1, m_rxrdy);
|
||||
}
|
||||
m_rcsr = ((m_rcsr & ~DLRCSR_WR) | (data & DLRCSR_WR));
|
||||
if (data & DLRCSR_RDRENB)
|
||||
{
|
||||
m_rcsr &= ~CSR_DONE;
|
||||
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
}
|
||||
break;
|
||||
|
||||
case DLRBUF:
|
||||
m_rcsr &= ~CSR_DONE;
|
||||
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
break;
|
||||
|
||||
case DLTCSR:
|
||||
@ -250,14 +310,29 @@ void dl11_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
|
||||
{
|
||||
raise_virq(m_write_txrdy, 1, 1, m_txrdy);
|
||||
}
|
||||
if ((m_tcsr ^ data) & DLTCSR_XBRK)
|
||||
{
|
||||
if (data & DLTCSR_XBRK)
|
||||
{
|
||||
transmit_register_setup(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
transmit_register_reset();
|
||||
if (m_tcsr & DLTCSR_MAINT)
|
||||
rx_w(1);
|
||||
else
|
||||
m_write_txd(1);
|
||||
}
|
||||
}
|
||||
m_tcsr = ((m_tcsr & ~DLTCSR_WR) | (data & DLTCSR_WR));
|
||||
break;
|
||||
|
||||
case DLTBUF:
|
||||
m_tbuf = data;
|
||||
m_tbuf = data & 255;
|
||||
m_tcsr &= ~CSR_DONE;
|
||||
clear_virq(m_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
|
||||
transmit_register_setup(data & 0xff);
|
||||
transmit_register_setup((m_tcsr & DLTCSR_XBRK) ? 0 : m_tbuf);
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -281,3 +356,109 @@ int dl11_device::txrdy_r()
|
||||
{
|
||||
return ((m_tcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE;
|
||||
}
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// k1801vp065_device - constructor
|
||||
//-------------------------------------------------
|
||||
|
||||
k1801vp065_device::k1801vp065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
|
||||
: dl11_device(mconfig, K1801VP065, tag, owner, clock)
|
||||
, m_write_rts(*this)
|
||||
{
|
||||
}
|
||||
|
||||
void k1801vp065_device::device_reset()
|
||||
{
|
||||
if (!m_installed)
|
||||
{
|
||||
dl11_device::device_reset();
|
||||
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_2);
|
||||
m_write_rts(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rcsr &= ~(DLRCSR_RBRK | DLRCSR_OVR | DLRCSR_PERR | CSR_IE | CSR_DONE);
|
||||
m_tcsr &= ~(DLTCSR_XBRK | DLTCSR_MAINT | CSR_IE);
|
||||
clear_virq(m_write_rxrdy, 1, 1, m_rxrdy);
|
||||
clear_virq(m_write_txrdy, 1, 1, m_txrdy);
|
||||
}
|
||||
}
|
||||
|
||||
void k1801vp065_device::rcv_complete()
|
||||
{
|
||||
receive_register_extract();
|
||||
if (m_rcsr & CSR_DONE)
|
||||
{
|
||||
m_rcsr |= DLRCSR_OVR;
|
||||
}
|
||||
else
|
||||
{
|
||||
m_rbuf = get_received_char();
|
||||
m_rcsr |= CSR_DONE;
|
||||
if (is_receive_framing_error())
|
||||
{
|
||||
m_rcsr |= DLRCSR_RBRK;
|
||||
}
|
||||
if (is_receive_parity_error())
|
||||
{
|
||||
m_rcsr |= DLRCSR_PERR;
|
||||
}
|
||||
}
|
||||
raise_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
m_write_rts(1);
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// read - register read
|
||||
//-------------------------------------------------
|
||||
|
||||
uint16_t k1801vp065_device::read(offs_t offset)
|
||||
{
|
||||
uint16_t data = 0;
|
||||
|
||||
switch (offset & 3)
|
||||
{
|
||||
case DLRCSR:
|
||||
data = m_rcsr & DLRCSR_RD;
|
||||
break;
|
||||
|
||||
case DLRBUF:
|
||||
data = m_rbuf;
|
||||
if (!machine().side_effects_disabled())
|
||||
{
|
||||
m_rcsr &= ~(CSR_DONE | DLRCSR_PERR | DLRCSR_OVR | DLRCSR_RBRK);
|
||||
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
||||
m_write_rts(0);
|
||||
}
|
||||
break;
|
||||
|
||||
case DLTCSR:
|
||||
data = m_tcsr & DLTCSR_RD;
|
||||
break;
|
||||
|
||||
case DLTBUF:
|
||||
data = m_rxvec;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
//-------------------------------------------------
|
||||
// write - register write
|
||||
//-------------------------------------------------
|
||||
|
||||
void k1801vp065_device::write(offs_t offset, uint16_t data)
|
||||
{
|
||||
switch (offset & 3)
|
||||
{
|
||||
case DLRCSR:
|
||||
data &= ~DLRCSR_RDRENB;
|
||||
break;
|
||||
|
||||
case DLRBUF:
|
||||
return;
|
||||
}
|
||||
dl11_device::write(offset, data);
|
||||
}
|
||||
|
@ -46,9 +46,16 @@ public:
|
||||
int rxrdy_r();
|
||||
int txrdy_r();
|
||||
|
||||
void rx_w(int state) { device_serial_interface::rx_w(state); }
|
||||
void rx_w(int state);
|
||||
|
||||
// device_z80daisy_interface overrides
|
||||
virtual int z80daisy_irq_state() override;
|
||||
virtual int z80daisy_irq_ack() override;
|
||||
virtual void z80daisy_irq_reti() override;
|
||||
|
||||
protected:
|
||||
dl11_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
@ -58,25 +65,24 @@ protected:
|
||||
virtual void tra_complete() override;
|
||||
virtual void rcv_complete() override;
|
||||
|
||||
// device_z80daisy_interface overrides
|
||||
virtual int z80daisy_irq_state() override;
|
||||
virtual int z80daisy_irq_ack() override;
|
||||
virtual void z80daisy_irq_reti() override;
|
||||
|
||||
private:
|
||||
/* registers */
|
||||
|
||||
static constexpr uint16_t DLRCSR_RD = CSR_DONE | CSR_IE;
|
||||
static constexpr uint16_t DLRCSR_ACT = 0004000;
|
||||
static constexpr uint16_t DLRCSR_RDRENB = 0000001;
|
||||
static constexpr uint16_t DLRCSR_RD = CSR_DONE | CSR_IE | DLRCSR_ACT;
|
||||
static constexpr uint16_t DLRCSR_WR = CSR_IE;
|
||||
|
||||
static constexpr uint16_t DLRBUF_ERR = 0100000;
|
||||
static constexpr uint16_t DLRBUF_OVR = 0040000;
|
||||
static constexpr uint16_t DLRBUF_RBRK = 0020000;
|
||||
static constexpr uint16_t DLRBUF_PERR = 0020000;
|
||||
static constexpr uint16_t DLRBUF_PERR = 0010000;
|
||||
|
||||
static constexpr uint16_t DLTCSR_MAINT = 0000004;
|
||||
static constexpr uint16_t DLTCSR_XBRK = 0000001;
|
||||
static constexpr uint16_t DLTCSR_RD = CSR_DONE | CSR_IE | DLTCSR_XBRK;
|
||||
static constexpr uint16_t DLTCSR_WR = CSR_IE | DLTCSR_XBRK;
|
||||
static constexpr uint16_t DLTCSR_RD = CSR_DONE | CSR_IE | DLTCSR_MAINT | DLTCSR_XBRK;
|
||||
static constexpr uint16_t DLTCSR_WR = CSR_IE | DLTCSR_MAINT | DLTCSR_XBRK;
|
||||
|
||||
bool m_installed;
|
||||
|
||||
devcb_write_line m_write_txd;
|
||||
devcb_write_line m_write_rxrdy;
|
||||
@ -96,8 +102,37 @@ private:
|
||||
uint16_t m_tbuf;
|
||||
};
|
||||
|
||||
class k1801vp065_device : public dl11_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
k1801vp065_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
||||
|
||||
uint16_t read(offs_t offset);
|
||||
void write(offs_t offset, uint16_t data);
|
||||
|
||||
auto rts_wr_callback() { return m_write_rts.bind(); }
|
||||
|
||||
protected:
|
||||
// device-level overrides
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device_serial_interface overrides
|
||||
virtual void rcv_complete() override;
|
||||
|
||||
private:
|
||||
static constexpr uint16_t DLRCSR_PERR = 0100000;
|
||||
static constexpr uint16_t DLRCSR_OVR = 0010000;
|
||||
static constexpr uint16_t DLRCSR_RBRK = 0000001;
|
||||
static constexpr uint16_t DLRCSR_RD = CSR_DONE | CSR_IE | DLRCSR_PERR | DLRCSR_OVR | DLRCSR_RBRK;
|
||||
static constexpr uint16_t DLRCSR_WR = CSR_IE;
|
||||
|
||||
devcb_write_line m_write_rts;
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(DL11, dl11_device)
|
||||
DECLARE_DEVICE_TYPE(K1801VP065, k1801vp065_device)
|
||||
|
||||
#endif
|
||||
|
Loading…
Reference in New Issue
Block a user