289 lines
5.9 KiB
C++
289 lines
5.9 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Sergey Svishchev
|
|
/***************************************************************************
|
|
|
|
DEC DL11-type SLU (serial line unit).
|
|
|
|
Frame format is not software-configurable; hardcoded to 8N1 for now.
|
|
|
|
http://www.ibiblio.org/pub/academic/computer-science/history/pdp-11/hardware/micronotes/numerical/micronote33.txt
|
|
|
|
***************************************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "dl11.h"
|
|
|
|
|
|
//**************************************************************************
|
|
// GLOBAL VARIABLES
|
|
//**************************************************************************
|
|
|
|
// device type definition
|
|
DEFINE_DEVICE_TYPE(DL11, dl11_device, "dl11", "DEC DL11-type SLU")
|
|
|
|
|
|
//**************************************************************************
|
|
// MACROS / CONSTANTS
|
|
//**************************************************************************
|
|
|
|
enum
|
|
{
|
|
DLRCSR = 0,
|
|
DLRBUF,
|
|
DLTCSR,
|
|
DLTBUF
|
|
};
|
|
|
|
//**************************************************************************
|
|
// LIVE DEVICE
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// 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)
|
|
, device_serial_interface(mconfig, *this)
|
|
, device_z80daisy_interface(mconfig, *this)
|
|
, m_write_txd(*this)
|
|
, m_write_rxrdy(*this)
|
|
, m_write_txrdy(*this)
|
|
, m_rxc(0)
|
|
, m_txc(0)
|
|
, m_rxvec(0)
|
|
, m_txvec(0)
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_start - device-specific startup
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::device_start()
|
|
{
|
|
// resolve callbacks
|
|
m_write_txd.resolve_safe();
|
|
m_write_rxrdy.resolve_safe();
|
|
m_write_txrdy.resolve_safe();
|
|
|
|
// save state
|
|
save_item(NAME(m_rcsr));
|
|
save_item(NAME(m_rbuf));
|
|
save_item(NAME(m_tcsr));
|
|
save_item(NAME(m_tbuf));
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_reset - device-specific reset
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::device_reset()
|
|
{
|
|
set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
|
|
|
|
// create the timers
|
|
if (m_rxc > 0)
|
|
set_rcv_rate(m_rxc);
|
|
|
|
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_write_txd(1);
|
|
m_write_rxrdy(m_rxrdy);
|
|
m_write_txrdy(m_txrdy);
|
|
}
|
|
|
|
int dl11_device::z80daisy_irq_state()
|
|
{
|
|
if (m_rxrdy == ASSERT_LINE || m_txrdy == ASSERT_LINE)
|
|
return Z80_DAISY_INT;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int dl11_device::z80daisy_irq_ack()
|
|
{
|
|
int vec = -1;
|
|
|
|
if (m_rxrdy == ASSERT_LINE)
|
|
{
|
|
m_rxrdy = CLEAR_LINE;
|
|
vec = m_rxvec;
|
|
}
|
|
else if (m_txrdy == ASSERT_LINE)
|
|
{
|
|
m_txrdy = CLEAR_LINE;
|
|
vec = m_txvec;
|
|
}
|
|
|
|
return vec;
|
|
}
|
|
|
|
void dl11_device::z80daisy_irq_reti()
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// tra_callback -
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::tra_callback()
|
|
{
|
|
if (m_tcsr & DLTCSR_XBRK)
|
|
{
|
|
m_write_txd(0);
|
|
}
|
|
else if (!is_transmit_register_empty())
|
|
{
|
|
m_write_txd(transmit_register_get_data_bit());
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// tra_complete -
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::tra_complete()
|
|
{
|
|
m_tcsr |= CSR_DONE;
|
|
raise_virq(m_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rcv_complete -
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::rcv_complete()
|
|
{
|
|
receive_register_extract();
|
|
if (is_receive_framing_error())
|
|
{
|
|
m_rbuf = DLRBUF_ERR | DLRBUF_RBRK;
|
|
}
|
|
else
|
|
{
|
|
m_rbuf = get_received_char();
|
|
}
|
|
if (is_receive_parity_error())
|
|
{
|
|
m_rbuf |= DLRBUF_ERR | DLRBUF_PERR;
|
|
}
|
|
if (m_rcsr & CSR_DONE)
|
|
{
|
|
m_rbuf |= DLRBUF_ERR | DLRBUF_OVR;
|
|
}
|
|
else
|
|
{
|
|
m_rcsr |= CSR_DONE;
|
|
}
|
|
raise_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// read - register read
|
|
//-------------------------------------------------
|
|
|
|
uint16_t dl11_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;
|
|
m_rcsr &= ~CSR_DONE;
|
|
clear_virq(m_write_rxrdy, m_rcsr, CSR_IE, m_rxrdy);
|
|
break;
|
|
|
|
case DLTCSR:
|
|
data = m_tcsr & DLTCSR_RD;
|
|
break;
|
|
|
|
case DLTBUF:
|
|
data = m_tbuf;
|
|
break;
|
|
}
|
|
|
|
return data;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// write - register write
|
|
//-------------------------------------------------
|
|
|
|
void dl11_device::write(offs_t offset, uint16_t data, uint16_t mem_mask)
|
|
{
|
|
switch (offset & 3)
|
|
{
|
|
case DLRCSR:
|
|
if ((data & CSR_IE) == 0)
|
|
{
|
|
clear_virq(m_write_rxrdy, 1, 1, m_rxrdy);
|
|
}
|
|
else if ((m_rcsr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
|
{
|
|
raise_virq(m_write_rxrdy, 1, 1, m_rxrdy);
|
|
}
|
|
m_rcsr = ((m_rcsr & ~DLRCSR_WR) | (data & DLRCSR_WR));
|
|
break;
|
|
|
|
case DLRBUF:
|
|
break;
|
|
|
|
case DLTCSR:
|
|
if ((data & CSR_IE) == 0)
|
|
{
|
|
clear_virq(m_write_txrdy, 1, 1, m_txrdy);
|
|
}
|
|
else if ((m_tcsr & (CSR_DONE + CSR_IE)) == CSR_DONE)
|
|
{
|
|
raise_virq(m_write_txrdy, 1, 1, m_txrdy);
|
|
}
|
|
m_tcsr = ((m_tcsr & ~DLTCSR_WR) | (data & DLTCSR_WR));
|
|
break;
|
|
|
|
case DLTBUF:
|
|
m_tbuf = data;
|
|
m_tcsr &= ~CSR_DONE;
|
|
clear_virq(m_write_txrdy, m_tcsr, CSR_IE, m_txrdy);
|
|
transmit_register_setup(data & 0xff);
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rxrdy_r - receiver ready
|
|
//-------------------------------------------------
|
|
|
|
READ_LINE_MEMBER(dl11_device::rxrdy_r)
|
|
{
|
|
return ((m_rcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// txrdy_r - transmitter empty
|
|
//-------------------------------------------------
|
|
|
|
READ_LINE_MEMBER(dl11_device::txrdy_r)
|
|
{
|
|
return ((m_tcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE;
|
|
}
|