// 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() { // 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 //------------------------------------------------- int dl11_device::rxrdy_r() { return ((m_rcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE; } //------------------------------------------------- // txrdy_r - transmitter empty //------------------------------------------------- int dl11_device::txrdy_r() { return ((m_tcsr & (CSR_DONE | CSR_IE)) == (CSR_DONE | CSR_IE)) ? ASSERT_LINE : CLEAR_LINE; }