mirror of
https://github.com/holub/mame
synced 2025-04-16 13:34:55 +03:00
416 lines
8.8 KiB
C++
416 lines
8.8 KiB
C++
// license:BSD-3-Clause
|
|
// copyright-holders:Curt Coder
|
|
/***************************************************************************
|
|
|
|
Intersil IM6402 Universal Asynchronous Receiver/Transmitter emulation
|
|
|
|
***************************************************************************/
|
|
|
|
#include "im6402.h"
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// DEVICE DEFINITIONS
|
|
//**************************************************************************
|
|
|
|
const device_type IM6402 = &device_creator<im6402_device>;
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// MACROS / CONSTANTS
|
|
//**************************************************************************
|
|
|
|
#define LOG 0
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// INLINE HELPERS
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// set_dr -
|
|
//-------------------------------------------------
|
|
|
|
inline void im6402_device::set_dr(int state)
|
|
{
|
|
m_dr = state;
|
|
|
|
m_write_dr(state);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// set_tbre -
|
|
//-------------------------------------------------
|
|
|
|
inline void im6402_device::set_tbre(int state)
|
|
{
|
|
m_tbre = state;
|
|
|
|
m_write_tbre(state);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// set_tre -
|
|
//-------------------------------------------------
|
|
|
|
inline void im6402_device::set_tre(int state)
|
|
{
|
|
m_tre = state;
|
|
|
|
m_write_tre(state);
|
|
}
|
|
|
|
|
|
|
|
//**************************************************************************
|
|
// LIVE DEVICE
|
|
//**************************************************************************
|
|
|
|
//-------------------------------------------------
|
|
// im6402_device - constructor
|
|
//-------------------------------------------------
|
|
|
|
im6402_device::im6402_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
|
|
device_t(mconfig, IM6402, "Intersil IM6402", tag, owner, clock, "im6402", __FILE__),
|
|
device_serial_interface(mconfig, *this),
|
|
m_write_tro(*this),
|
|
m_write_dr(*this),
|
|
m_write_tbre(*this),
|
|
m_write_tre(*this),
|
|
m_rrc_count(0),
|
|
m_trc_count(0)
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_start - device-specific startup
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::device_start()
|
|
{
|
|
// resolve callbacks
|
|
m_write_tro.resolve_safe();
|
|
m_write_dr.resolve_safe();
|
|
m_write_tbre.resolve_safe();
|
|
m_write_tre.resolve_safe();
|
|
|
|
// create the timers
|
|
if (m_rrc > 0)
|
|
{
|
|
set_rcv_rate(m_rrc/16);
|
|
}
|
|
|
|
if (m_trc > 0)
|
|
{
|
|
set_tra_rate(m_trc/16);
|
|
}
|
|
|
|
// state saving
|
|
save_item(NAME(m_dr));
|
|
save_item(NAME(m_tbre));
|
|
save_item(NAME(m_tre));
|
|
save_item(NAME(m_pe));
|
|
save_item(NAME(m_fe));
|
|
save_item(NAME(m_oe));
|
|
save_item(NAME(m_cls1));
|
|
save_item(NAME(m_cls2));
|
|
save_item(NAME(m_sbs));
|
|
save_item(NAME(m_sfd));
|
|
save_item(NAME(m_epe));
|
|
save_item(NAME(m_pi));
|
|
save_item(NAME(m_rbr));
|
|
save_item(NAME(m_rrc_count));
|
|
save_item(NAME(m_tbr));
|
|
save_item(NAME(m_trc_count));
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_reset - device-specific reset
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::device_reset()
|
|
{
|
|
receive_register_reset();
|
|
transmit_register_reset();
|
|
|
|
m_write_tro(1);
|
|
|
|
m_rrc_count = 0;
|
|
m_trc_count = 0;
|
|
|
|
m_rbr = 0;
|
|
m_pe = 0;
|
|
m_fe = 0;
|
|
m_oe = 0;
|
|
|
|
set_dr(CLEAR_LINE);
|
|
set_tbre(ASSERT_LINE);
|
|
set_tre(ASSERT_LINE);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// device_timer - handler timer events
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
|
|
{
|
|
device_serial_interface::device_timer(timer, id, param, ptr);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// tra_callback -
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::tra_callback()
|
|
{
|
|
m_write_tro(transmit_register_get_data_bit());
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// tra_complete -
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::tra_complete()
|
|
{
|
|
if (!m_tbre)
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Transmit Data %02x\n", tag(), m_tbr);
|
|
|
|
transmit_register_setup(m_tbr);
|
|
|
|
set_tbre(ASSERT_LINE);
|
|
set_tre(CLEAR_LINE);
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rcv_callback -
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::rcv_callback()
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rcv_complete -
|
|
//-------------------------------------------------
|
|
|
|
void im6402_device::rcv_complete()
|
|
{
|
|
receive_register_extract();
|
|
m_rbr = get_received_char();
|
|
|
|
if (LOG) logerror("IM6402 '%s' Receive Data %02x\n", tag(), m_rbr);
|
|
|
|
if (m_dr)
|
|
{
|
|
m_oe = 1;
|
|
}
|
|
|
|
set_dr(ASSERT_LINE);
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// write - transmitter buffer register write
|
|
//-------------------------------------------------
|
|
|
|
WRITE8_MEMBER( im6402_device::write )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Transmit Buffer Register %02x\n", tag(), data);
|
|
|
|
m_tbr = data;
|
|
|
|
if (is_transmit_register_empty())
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Transmit Data %02x\n", tag(), m_tbr);
|
|
|
|
transmit_register_setup(m_tbr);
|
|
|
|
set_tbre(ASSERT_LINE);
|
|
set_tre(CLEAR_LINE);
|
|
}
|
|
else
|
|
{
|
|
set_tbre(CLEAR_LINE);
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rrc_w - receiver register clock
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::rrc_w )
|
|
{
|
|
if (state)
|
|
{
|
|
rx_clock_w(m_rrc_count < 8);
|
|
m_rrc_count = (m_rrc_count + 1) & 15;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// trc_w - transmitter register clock
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::trc_w )
|
|
{
|
|
if (state)
|
|
{
|
|
tx_clock_w(m_trc_count < 8);
|
|
m_trc_count = (m_trc_count + 1) & 15;
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// rrd_w - receiver register disable
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::rrd_w )
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// sfd_w - status flags disable
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::sfd_w )
|
|
{
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// drr_w - data received reset
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::drr_w )
|
|
{
|
|
if (state)
|
|
{
|
|
set_dr(CLEAR_LINE);
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// mr_w - master reset
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::mr_w )
|
|
{
|
|
if (state)
|
|
{
|
|
device_reset();
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// crl_w - control register load
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::crl_w )
|
|
{
|
|
if (state)
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Control Register Load\n", tag());
|
|
|
|
int data_bit_count = 5 + ((m_cls2 << 1) | m_cls1);
|
|
stop_bits_t stop_bits = (m_sbs ? ((data_bit_count == 5) ? STOP_BITS_1_5 : STOP_BITS_2) : STOP_BITS_1);
|
|
parity_t parity;
|
|
|
|
if (m_pi) parity = PARITY_NONE;
|
|
else if (m_epe) parity = PARITY_EVEN;
|
|
else parity = PARITY_ODD;
|
|
|
|
set_data_frame(1, data_bit_count, parity, stop_bits);
|
|
|
|
receive_register_reset();
|
|
transmit_register_reset();
|
|
}
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// pi_w - parity inhibit
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::pi_w )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Parity Inhibit %u\n", tag(), state);
|
|
|
|
m_pi = state;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// sbs_w - stop bit select
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::sbs_w )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Stop Bit Select %u\n", tag(), state);
|
|
|
|
m_sbs = state;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// cls1_w - character length select 1
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::cls1_w )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Character Length Select 1 %u\n", tag(), state);
|
|
|
|
m_cls1 = state;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// cls2_w - character length select 2
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::cls2_w )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Character Length Select 2 %u\n", tag(), state);
|
|
|
|
m_cls2 = state;
|
|
}
|
|
|
|
|
|
//-------------------------------------------------
|
|
// epe_w - even parity enable
|
|
//-------------------------------------------------
|
|
|
|
WRITE_LINE_MEMBER( im6402_device::epe_w )
|
|
{
|
|
if (LOG) logerror("IM6402 '%s' Even Parity Enable %u\n", tag(), state);
|
|
|
|
m_epe = state;
|
|
}
|
|
|
|
WRITE_LINE_MEMBER(im6402_device::write_rri)
|
|
{
|
|
// HACK derive clock from data line as wangpckb sends bytes instantly to make up for mcs51 serial implementation
|
|
receive_register_update_bit(state);
|
|
rx_clock_w(1);
|
|
rx_clock_w(0);
|
|
}
|