// license:BSD-3-Clause
// copyright-holders:Sergey Svishchev
/***************************************************************************
DEC PC11 paper tape reader and punch controller (punch not implemented)
***************************************************************************/
#include "pc11.h"
//#define LOG_GENERAL (1U << 0)
#define LOG_DBG (1U << 2)
//#define VERBOSE (LOG_GENERAL | LOG_DBG)
//#define LOG_OUTPUT_FUNC printf
#include "logmacro.h"
#define LOGDBG(...) LOGMASKED(LOG_DBG, __VA_ARGS__)
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(DEC_PC11, pc11_device, "pc11", "DEC PC11 controller")
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
enum
{
REGISTER_RCSR = 0,
REGISTER_RBUF,
REGISTER_TCSR,
REGISTER_TBUF
};
const char* pc11_regnames[] = {
"RCSR", "RBUF", "TCSR", "TBUF"
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// pc11_device - constructor
//-------------------------------------------------
pc11_device::pc11_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, DEC_PC11, tag, owner, clock)
, device_image_interface(mconfig, *this)
, device_qbus_card_interface(mconfig, *this)
, m_rxvec(070)
, m_txvec(074)
{
(void)pc11_regnames;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void pc11_device::device_start()
{
m_bus->install_device(0177550, 0177557, read16sm_delegate(*this, FUNC(pc11_device::read)),
write16sm_delegate(*this, FUNC(pc11_device::write)));
// resolve callbacks
// save state
save_item(NAME(m_rcsr));
save_item(NAME(m_rbuf));
save_item(NAME(m_tcsr));
save_item(NAME(m_tbuf));
// about 300 cps
emu_timer *timer = timer_alloc();
timer->adjust(attotime::from_usec(333), 0, attotime::from_usec(333));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void pc11_device::device_reset()
{
LOG("Reset, rxvec %03o txvec %03o\n", m_rxvec, m_txvec);
m_rcsr = m_rbuf = m_tbuf = 0;
m_tcsr = CSR_DONE;
m_rxrdy = m_txrdy = CLEAR_LINE;
m_bus->birq4_w(CLEAR_LINE);
}
int pc11_device::z80daisy_irq_state()
{
if (m_rxrdy == ASSERT_LINE || m_txrdy == ASSERT_LINE)
return Z80_DAISY_INT;
else
return 0;
}
int pc11_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;
}
if (vec > 0)
LOGDBG("IRQ ACK vec %03o\n", vec);
return vec;
}
void pc11_device::z80daisy_irq_reti()
{
}
image_init_result pc11_device::call_load()
{
/* reader unit */
m_fd = this;
m_rcsr &= ~(CSR_ERR | CSR_BUSY);
LOG("call_load filename %s is_open %d\n", m_fd->filename(), m_fd->is_open());
return image_init_result::PASS;
}
void pc11_device::call_unload()
{
/* reader unit */
m_fd = nullptr;
m_rcsr |= CSR_ERR;
}
//-------------------------------------------------
// read - register read
//-------------------------------------------------
uint16_t pc11_device::read(offs_t offset)
{
uint16_t data = 0;
switch (offset & 0x03)
{
case REGISTER_RCSR:
data = m_rcsr & PTRCSR_IMP;
break;
case REGISTER_RBUF:
data = m_rbuf & 0377;
m_rcsr &= ~CSR_DONE;
clear_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy);
break;
}
LOGDBG("R %06o == %06o\n", 0177550 + (offset << 1), data);
return data;
}
//-------------------------------------------------
// write - register write
//-------------------------------------------------
void pc11_device::write(offs_t offset, uint16_t data)
{
LOGDBG("W %06o <- %06o\n", 0177550 + (offset << 1), data);
switch (offset & 0x03)
{
case REGISTER_RCSR:
if ((data & CSR_IE) == 0)
{
clear_virq(m_bus->birq4_w, 1, 1, m_rxrdy);
}
else if ((m_rcsr & (CSR_DONE + CSR_IE)) == CSR_DONE)
{
raise_virq(m_bus->birq4_w, 1, 1, m_rxrdy);
}
if (data & CSR_GO)
{
m_rcsr = (m_rcsr & ~CSR_DONE) | CSR_BUSY;
clear_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy);
}
m_rcsr = ((m_rcsr & ~PTRCSR_WR) | (data & PTRCSR_WR));
break;
case REGISTER_RBUF:
break;
}
}
void pc11_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
uint8_t reply;
if (!(m_rcsr & CSR_BUSY))
return;
LOGDBG("Timer rcsr %06o id %d param %d m_fd %p\n", m_rcsr, id, param, m_fd);
m_rcsr = (m_rcsr | CSR_ERR) & ~CSR_BUSY;
if (m_fd && m_fd->exists() && (m_fd->fread(&reply, 1) == 1))
{
m_rcsr = (m_rcsr | CSR_DONE) & ~CSR_ERR;
m_rbuf = reply;
}
raise_virq(m_bus->birq4_w, m_rcsr, CSR_IE, m_rxrdy);
}