// license:BSD-3-Clause
// copyright-holders:Dirk Best
/***************************************************************************
IBM-PC printer interface
***************************************************************************/
#include "emu.h"
#include "pc_lpt.h"
DEFINE_DEVICE_TYPE(PC_LPT, pc_lpt_device, "pc_lpt", "PC LPT")
pc_lpt_device::pc_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, PC_LPT, tag, owner, clock),
m_irq(1),
m_data(0xff), m_control(0),
m_irq_enabled(1),
m_centronics_ack(1),
m_irq_handler(*this),
m_cent_data_in(*this, "cent_data_in"),
m_cent_data_out(*this, "cent_data_out"),
m_cent_status_in(*this, "cent_status_in"),
m_cent_ctrl_in(*this, "cent_ctrl_in"),
m_cent_ctrl_out(*this, "cent_ctrl_out")
{
}
void pc_lpt_device::device_start()
{
m_irq_handler.resolve_safe();
save_item(NAME(m_irq));
save_item(NAME(m_data));
save_item(NAME(m_control));
save_item(NAME(m_centronics_ack));
save_item(NAME(m_irq_enabled));
m_cent_data_out->write(m_data);
}
void pc_lpt_device::device_reset()
{
m_control = ~(0 ^ CONTROL_INIT);
m_cent_ctrl_out->write(m_control);
}
MACHINE_CONFIG_START(pc_lpt_device::device_add_mconfig)
MCFG_DEVICE_ADD("centronics", CENTRONICS, centronics_devices, "printer")
MCFG_CENTRONICS_DATA_INPUT_BUFFER("cent_data_in")
MCFG_CENTRONICS_FAULT_HANDLER(WRITELINE("cent_status_in", input_buffer_device, write_bit3))
MCFG_CENTRONICS_SELECT_HANDLER(WRITELINE("cent_status_in", input_buffer_device, write_bit4))
MCFG_CENTRONICS_PERROR_HANDLER(WRITELINE("cent_status_in", input_buffer_device, write_bit5))
MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(*this, pc_lpt_device, write_centronics_ack))
MCFG_CENTRONICS_BUSY_HANDLER(WRITELINE("cent_status_in", input_buffer_device, write_bit7))
MCFG_CENTRONICS_STROBE_HANDLER(WRITELINE("cent_ctrl_in", input_buffer_device, write_bit0))
MCFG_CENTRONICS_AUTOFD_HANDLER(WRITELINE("cent_ctrl_in", input_buffer_device, write_bit1))
MCFG_CENTRONICS_INIT_HANDLER(WRITELINE("cent_ctrl_in", input_buffer_device, write_bit2))
MCFG_CENTRONICS_SELECT_IN_HANDLER(WRITELINE("cent_ctrl_in", input_buffer_device, write_bit3))
MCFG_DEVICE_ADD("cent_data_in", INPUT_BUFFER, 0)
MCFG_DEVICE_ADD("cent_ctrl_in", INPUT_BUFFER, 0)
MCFG_DEVICE_ADD("cent_status_in", INPUT_BUFFER, 0)
MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
MCFG_DEVICE_ADD("cent_ctrl_out", OUTPUT_LATCH, 0)
MCFG_OUTPUT_LATCH_BIT0_HANDLER(WRITELINE("centronics", centronics_device, write_strobe))
MCFG_OUTPUT_LATCH_BIT1_HANDLER(WRITELINE("centronics", centronics_device, write_autofd))
MCFG_OUTPUT_LATCH_BIT2_HANDLER(WRITELINE("centronics", centronics_device, write_init))
MCFG_OUTPUT_LATCH_BIT3_HANDLER(WRITELINE("centronics", centronics_device, write_select_in))
MCFG_OUTPUT_LATCH_BIT4_HANDLER(WRITELINE(*this, pc_lpt_device, write_irq_enabled))
MACHINE_CONFIG_END
READ8_MEMBER( pc_lpt_device::data_r )
{
// pull up mechanism for input lines, zeros are provided by peripheral
return m_data & m_cent_data_in->read();
}
WRITE8_MEMBER( pc_lpt_device::data_w )
{
m_data = data;
m_cent_data_out->write(m_data);
}
READ8_MEMBER( pc_lpt_device::status_r )
{
return m_cent_status_in->read() ^ STATUS_BUSY;
}
READ8_MEMBER( pc_lpt_device::control_r )
{
return ~((m_control & m_cent_ctrl_in->read() & 0x3f) ^ CONTROL_INIT);
}
WRITE8_MEMBER( pc_lpt_device::control_w )
{
// logerror("pc_lpt_control_w: 0x%02x\n", data);
m_control = ~(data ^ CONTROL_INIT);
m_cent_ctrl_out->write(m_control);
}
READ8_MEMBER( pc_lpt_device::read )
{
switch (offset)
{
case 0: return data_r(space, 0);
case 1: return status_r(space, 0);
case 2: return control_r(space, 0);
}
/* if we reach this its an error */
logerror("PC-LPT %s: Read from invalid offset %x\n", tag(), offset);
return 0xff;
}
WRITE8_MEMBER( pc_lpt_device::write )
{
switch (offset)
{
case 0: data_w(space, 0, data); break;
case 1: break;
case 2: control_w(space, 0, data); break;
}
}
void pc_lpt_device::update_irq()
{
int irq = 1; // high impedance
if (!m_irq_enabled)
{
irq = m_centronics_ack;
}
if (m_irq != irq)
{
m_irq = irq;
m_irq_handler(!irq);
}
}
WRITE_LINE_MEMBER( pc_lpt_device::write_irq_enabled )
{
m_irq_enabled = state;
update_irq();
}
WRITE_LINE_MEMBER( pc_lpt_device::write_centronics_ack )
{
m_centronics_ack = state;
m_cent_status_in->write_bit6(state);
update_irq();
}