// license:BSD-3-Clause
// copyright-holders:Curt Coder
/**********************************************************************
RCA CDP1852 Byte-Wide Input/Output Port emulation
**********************************************************************/
#include "emu.h"
#include "cdp1852.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(CDP1852, cdp1852_device, "cdp1852", "RCA CDP1852 I/O")
//**************************************************************************
// MACROS / CONSTANTS
//**************************************************************************
enum
{
MODE_INPUT = 0,
MODE_OUTPUT
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// cdp1852_device - constructor
//-------------------------------------------------
cdp1852_device::cdp1852_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
device_t(mconfig, CDP1852, tag, owner, clock),
m_read_mode(*this),
m_write_sr(*this),
m_read_data(*this),
m_write_data(*this),
m_new_data(false), m_data(0),
m_clock_active(true), m_sr(false), m_next_sr(false),
m_update_do_timer(nullptr),
m_update_sr_timer(nullptr)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void cdp1852_device::device_start()
{
// resolve callbacks
m_read_mode.resolve_safe(0);
m_write_sr.resolve_safe();
m_read_data.resolve_safe(0);
m_write_data.resolve_safe();
// allocate timers
m_update_do_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdp1852_device::update_do), this));
m_update_sr_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(cdp1852_device::update_sr), this));
// register for state saving
save_item(NAME(m_new_data));
save_item(NAME(m_data));
save_item(NAME(m_clock_active));
save_item(NAME(m_sr));
save_item(NAME(m_next_sr));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void cdp1852_device::device_reset()
{
// reset data register
m_data = 0;
if (!m_read_mode())
{
// reset service request flip-flop
set_sr_line(true);
}
else
{
// output data
m_write_data((offs_t)0, m_data);
// reset service request flip-flop
set_sr_line(false);
}
}
//-------------------------------------------------
// clock_w - clock write
//-------------------------------------------------
WRITE_LINE_MEMBER(cdp1852_device::clock_w)
{
if (m_clock_active != bool(state))
return;
m_clock_active = bool(state);
if (!state)
{
if (!m_read_mode())
{
// input data into register
m_data = m_read_data(0);
// signal processor
set_sr_line(0);
}
else
{
if (m_new_data)
{
m_new_data = false;
// signal peripheral device
set_sr_line(true);
m_next_sr = false;
}
else
{
set_sr_line(m_next_sr);
}
}
}
}
//-------------------------------------------------
// set_sr_line -
//-------------------------------------------------
void cdp1852_device::set_sr_line(bool state)
{
if (m_sr != state)
{
m_sr = state;
m_update_sr_timer->adjust(attotime::zero);
}
}
//-------------------------------------------------
// update_do - update data output
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(cdp1852_device::update_do)
{
m_write_data(param);
}
//-------------------------------------------------
// update_sr - update status request output
//-------------------------------------------------
TIMER_CALLBACK_MEMBER(cdp1852_device::update_sr)
{
m_write_sr(m_sr ? 1 : 0);
}
//-------------------------------------------------
// read - data read
//-------------------------------------------------
READ8_MEMBER(cdp1852_device::read)
{
if (!m_read_mode() && m_clock_active)
{
// input data into register
m_data = m_read_data(0);
}
set_sr_line(true);
return m_data;
}
//-------------------------------------------------
// write - data write
//-------------------------------------------------
WRITE8_MEMBER(cdp1852_device::write)
{
if (m_read_mode() && m_clock_active)
{
// output data
m_update_do_timer->adjust(attotime::zero, data);
m_new_data = true;
}
}