mirror of
https://github.com/holub/mame
synced 2025-06-05 04:16:28 +03:00
754 lines
20 KiB
C
754 lines
20 KiB
C
// license:BSD-3-Clause
|
|
// copyright-holders:Robbbert
|
|
/****************************************************************************
|
|
|
|
ay31015.c by Robbbert, May 2008. Bugs fixed by Judge.
|
|
|
|
Code for the AY-3-1014A, AY-3-1015(D), AY-5-1013(A), and AY-6-1013 UARTs
|
|
The HD6402 UART is compatible with the AY-3-1015 UART.
|
|
|
|
This is cycle-accurate according to the specifications.
|
|
|
|
It supports independent receive and transmit clocks,
|
|
and transmission and reception can occur simultaneously if desired.
|
|
|
|
*****************************************************************************
|
|
|
|
Differences between the chip types:
|
|
- All units have pull-up resistors on the inputs, except for the AY-3-1014A which is CMOS-compatible.
|
|
- AY-3-1014A and AY-3-1015 - 1.5 stop bits mode available.
|
|
- Max baud rate of 30k, except AY-5-1013 which has 20k.
|
|
- AY-5-1013 has extended temperature ratings.
|
|
- AY-5-1013 and AY-6-1013 require a -12 volt supply on pin 2. Pin is not used otherwise.
|
|
- AY-5-1013 and AY-6-1013 do not reset the received data register when XR pin is used.
|
|
|
|
******************************************************************************
|
|
|
|
It is not clear in the documentation as to which settings will reset the device.
|
|
To be safe, we will always reset whenever the control register changes.
|
|
|
|
Also, it not clear exactly what happens under various error conditions.
|
|
|
|
********************************************************************************
|
|
|
|
Device Data:
|
|
|
|
* Common Controls:
|
|
-- Pin 1 - Vcc - 5 volts
|
|
-- Pin 2 - not used (on AY-5-1013 and AY-6-1013 this is Voo = -12 volts)
|
|
-- Pin 3 - Gnd - 0 volts
|
|
-- Pin 21 - XR - External Reset - resets all registers to initial state except for the control register
|
|
-- Pin 35 - NP - No Parity - "1" will kill any parity processing
|
|
-- Pin 36 - TSB - Number of Stop Bits - "0" = 1 stop bit; "1" = 2 stop bits. If "1", and 5 bits per character, then we have 1.5 stop bits
|
|
-- pin 37 - NB1
|
|
-- pin 38 - NB2 - Number of bits per character = NB1 + (NB2 * 2) + 5
|
|
-- pin 39 - EPS - Odd or Even Parity Select - "0" = Odd parity; "1" = Even parity. Has no effect if NP is high.
|
|
-- Pin 34 - CS - Control Strobe - Read NP, TSB, EPS, NB1, NB2 into the control register.
|
|
|
|
Format of data stream:
|
|
Start bit (low), Bit 0, Bit 1... highest bit, Parity bit (if enabled), 1-2 stop bits (high)
|
|
|
|
|
|
* Receiver Controls:
|
|
-- Pin 17 - RCP - Clock which is 16x the desired baud rate
|
|
-- Pin 20 - SI - Serial input stream - "1" = Mark (waiting for input), "0" = Space (Start bit) initiates the transfer of a byte
|
|
-- Pin 4 - RDE - "0" causes the received data to appear on RD1 to RD8.
|
|
-- Pins 5 to 12 - RD8 to RD1 - These are the data lines (bits 7 to 0). Data is right-justified.
|
|
-- Pin 16 - SWE - Status word enable - causes the status bits (PE, FE, OR, DAV, TBMT) to appear at the pins.
|
|
-- Pin 19 - DAV - "1" indicates that a byte has been received by the UART, and should now be accepted by the computer
|
|
-- Pin 18 - RDAV - "0" will force DAV low.
|
|
-- Pin 13 - PE - Parity error - "1" indicates that a parity error occurred
|
|
-- Pin 14 - FE - Framing error - "1" Indicates that the stop bit was missing
|
|
-- Pin 15 - OR - overrun - "1" indicates that a new character has become available before the computer had accepted the previous character
|
|
|
|
* Transmitter controls:
|
|
-- Pin 40 - TCP - Clock which is 16x the desired baud rate
|
|
-- Pin 25 - SO - Serial output stream - it will stay at "1" while no data is being transmitted
|
|
-- Pins 26 to 33 - DB1 to DB8 - These are the data lines containing the byte to be sent
|
|
-- Pin 23 - DS - Data Strobe - "0" will copy DB1 to DB8 into the transmit buffer
|
|
-- Pin 22 - TBMT - Transmit buffer Empty - "1" indicates to the computer that another byte may be sent to the UART
|
|
-- Pin 24 - EOC - End of Character - "0" means that a character is being sent.
|
|
|
|
******************************************* COMMON CONTROLS ********************************************************/
|
|
|
|
#include "emu.h"
|
|
#include "ay31015.h"
|
|
|
|
|
|
|
|
/* control reg */
|
|
#define CONTROL_NB1 0x01
|
|
#define CONTROL_NB2 0x02
|
|
#define CONTROL_TSB 0x04
|
|
#define CONTROL_EPS 0x08
|
|
#define CONTROL_NP 0x10
|
|
|
|
|
|
/* status reg */
|
|
#define STATUS_TBMT 0x01
|
|
#define STATUS_DAV 0x02
|
|
#define STATUS_OR 0x04
|
|
#define STATUS_FE 0x08
|
|
#define STATUS_PE 0x10
|
|
#define STATUS_EOC 0x20
|
|
|
|
|
|
|
|
const device_type AY31015 = &device_creator<ay31015_device>;
|
|
const device_type AY51013 = &device_creator<ay51013_device>;
|
|
|
|
ay31015_device::ay31015_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source)
|
|
: device_t(mconfig, type, name, tag, owner, clock, shortname, source),
|
|
m_control_reg(0),
|
|
m_status_reg(0),
|
|
m_second_stop_bit(0),
|
|
m_total_pulses(0),
|
|
m_internal_sample(0),
|
|
m_rx_data(0),
|
|
m_rx_buffer(0),
|
|
m_rx_bit_count(0),
|
|
m_rx_parity(0),
|
|
m_rx_pulses(0),
|
|
m_rx_clock(0),
|
|
m_rx_timer(NULL),
|
|
m_tx_data(0),
|
|
m_tx_buffer(0),
|
|
m_tx_parity(0),
|
|
m_tx_pulses(0),
|
|
m_tx_clock(0),
|
|
m_tx_timer(NULL),
|
|
m_read_si_cb(*this),
|
|
m_write_so_cb(*this),
|
|
m_status_changed_cb(*this)
|
|
{
|
|
for (int i = 0; i < 41; i++)
|
|
m_pins[i] = 0;
|
|
}
|
|
|
|
ay31015_device::ay31015_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
: device_t(mconfig, AY31015, "AY-3-1015", tag, owner, clock, "ay31015", __FILE__),
|
|
m_control_reg(0),
|
|
m_status_reg(0),
|
|
m_second_stop_bit(0),
|
|
m_total_pulses(0),
|
|
m_internal_sample(0),
|
|
m_rx_data(0),
|
|
m_rx_buffer(0),
|
|
m_rx_bit_count(0),
|
|
m_rx_parity(0),
|
|
m_rx_pulses(0),
|
|
m_rx_clock(0),
|
|
m_rx_timer(NULL),
|
|
m_tx_data(0),
|
|
m_tx_buffer(0),
|
|
m_tx_parity(0),
|
|
m_tx_pulses(0),
|
|
m_tx_clock(0),
|
|
m_tx_timer(NULL),
|
|
m_read_si_cb(*this),
|
|
m_write_so_cb(*this),
|
|
m_status_changed_cb(*this)
|
|
{
|
|
for (int i = 0; i < 41; i++)
|
|
m_pins[i] = 0;
|
|
}
|
|
|
|
ay51013_device::ay51013_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
|
|
: ay31015_device(mconfig, AY31015, "AY-5-1013", tag, owner, clock, "ay51013", __FILE__)
|
|
{
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// device_start - device-specific startup
|
|
//-------------------------------------------------
|
|
|
|
void ay31015_device::device_start()
|
|
{
|
|
m_read_si_cb.resolve();
|
|
m_write_so_cb.resolve();
|
|
m_status_changed_cb.resolve();
|
|
|
|
m_rx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ay31015_device::rx_process),this));
|
|
m_tx_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(ay31015_device::tx_process),this));
|
|
|
|
update_rx_timer();
|
|
update_tx_timer();
|
|
|
|
save_item(NAME(m_pins));
|
|
save_item(NAME(m_control_reg));
|
|
save_item(NAME(m_status_reg));
|
|
save_item(NAME(m_second_stop_bit));
|
|
save_item(NAME(m_total_pulses));
|
|
save_item(NAME(m_internal_sample));
|
|
|
|
save_item(NAME(m_rx_state));
|
|
save_item(NAME(m_rx_data));
|
|
save_item(NAME(m_rx_buffer));
|
|
save_item(NAME(m_rx_bit_count));
|
|
save_item(NAME(m_rx_parity));
|
|
save_item(NAME(m_rx_pulses));
|
|
save_item(NAME(m_rx_clock));
|
|
|
|
save_item(NAME(m_tx_state));
|
|
save_item(NAME(m_tx_data));
|
|
save_item(NAME(m_tx_buffer));
|
|
save_item(NAME(m_tx_parity));
|
|
save_item(NAME(m_tx_pulses));
|
|
save_item(NAME(m_tx_clock));
|
|
}
|
|
|
|
//-------------------------------------------------
|
|
// device_reset - device-specific reset
|
|
//-------------------------------------------------
|
|
|
|
void ay31015_device::device_reset()
|
|
{
|
|
m_control_reg = 0;
|
|
m_rx_data = 0;
|
|
|
|
internal_reset();
|
|
}
|
|
|
|
|
|
inline UINT8 ay31015_device::get_si()
|
|
{
|
|
if (!m_read_si_cb.isnull())
|
|
m_pins[AY31015_SI] = m_read_si_cb(0) ? 1 : 0;
|
|
|
|
return m_pins[AY31015_SI];
|
|
}
|
|
|
|
|
|
inline void ay31015_device::set_so( int data )
|
|
{
|
|
m_pins[AY31015_SO] = data ? 1 : 0;
|
|
|
|
if (!m_write_so_cb.isnull())
|
|
m_write_so_cb((offs_t)0, m_pins[AY31015_SO]);
|
|
}
|
|
|
|
|
|
inline int ay31015_device::update_status_pin( UINT8 reg_bit, ay31015_output_pin_t pin )
|
|
{
|
|
int new_value = (m_status_reg & reg_bit) ? 1 : 0;
|
|
|
|
if (new_value == m_pins[pin])
|
|
return 0;
|
|
|
|
m_pins[pin] = new_value;
|
|
return 1;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_update_status_pins - Update the status pins
|
|
-------------------------------------------------*/
|
|
|
|
void ay31015_device::update_status_pins()
|
|
{
|
|
int status_pins_changed = 0;
|
|
|
|
/* Should status pins be updated? */
|
|
if (!m_pins[AY31015_SWE])
|
|
{
|
|
status_pins_changed += update_status_pin(STATUS_PE, AY31015_PE);
|
|
status_pins_changed += update_status_pin(STATUS_FE, AY31015_FE);
|
|
status_pins_changed += update_status_pin(STATUS_OR, AY31015_OR);
|
|
status_pins_changed += update_status_pin(STATUS_DAV, AY31015_DAV);
|
|
status_pins_changed += update_status_pin(STATUS_TBMT, AY31015_TBMT);
|
|
}
|
|
status_pins_changed += update_status_pin(STATUS_EOC, AY31015_EOC);
|
|
|
|
if (status_pins_changed && !m_status_changed_cb.isnull())
|
|
{
|
|
m_status_changed_cb((offs_t)0, status_pins_changed);
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************** RECEIVE CONTROLS *************************************************/
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_rx_process - convert serial to parallel
|
|
-------------------------------------------------*/
|
|
|
|
TIMER_CALLBACK_MEMBER( ay31015_device::rx_process )
|
|
{
|
|
switch (m_rx_state)
|
|
{
|
|
case PREP_TIME: // assist sync by ensuring high bit occurs
|
|
m_rx_pulses--;
|
|
if (get_si())
|
|
m_rx_state = IDLE;
|
|
return;
|
|
|
|
case IDLE:
|
|
m_rx_pulses--;
|
|
if (!get_si())
|
|
{
|
|
m_rx_state = START_BIT;
|
|
m_rx_pulses = 16;
|
|
}
|
|
return;
|
|
|
|
case START_BIT:
|
|
m_rx_pulses--;
|
|
if (m_rx_pulses == 8) // start bit must be low at sample time
|
|
{
|
|
if (get_si())
|
|
m_rx_state = IDLE;
|
|
}
|
|
else
|
|
if (!m_rx_pulses) // end of start bit
|
|
{
|
|
m_rx_state = PROCESSING;
|
|
m_rx_pulses = m_total_pulses;
|
|
m_rx_bit_count = 0;
|
|
m_rx_parity = 0;
|
|
m_rx_data = 0;
|
|
}
|
|
return;
|
|
|
|
case PROCESSING:
|
|
m_rx_pulses--;
|
|
if (!m_rx_pulses) // end of a byte
|
|
{
|
|
m_rx_pulses = 16;
|
|
if (m_control_reg & CONTROL_NP) // see if we need to get a parity bit
|
|
m_rx_state = FIRST_STOP_BIT;
|
|
else
|
|
m_rx_state = PARITY_BIT;
|
|
}
|
|
else
|
|
if (!(m_rx_pulses & 15)) // end of a bit
|
|
m_rx_bit_count++;
|
|
else
|
|
if ((m_rx_pulses & 15) == 8) // sample input stream
|
|
{
|
|
m_internal_sample = get_si();
|
|
m_rx_parity ^= m_internal_sample; // calculate cumulative parity
|
|
m_rx_data |= m_internal_sample << m_rx_bit_count;
|
|
}
|
|
return;
|
|
|
|
case PARITY_BIT:
|
|
m_rx_pulses--;
|
|
|
|
if (m_rx_pulses == 8) // sample input stream
|
|
{
|
|
m_rx_parity ^= get_si(); // calculate cumulative parity
|
|
}
|
|
else
|
|
if (!m_rx_pulses) // end of a byte
|
|
{
|
|
m_rx_pulses = 16;
|
|
m_rx_state = FIRST_STOP_BIT;
|
|
|
|
if ((!(m_control_reg & CONTROL_EPS)) && (m_rx_parity))
|
|
m_rx_parity = 0; // odd parity, ok
|
|
else
|
|
if ((m_control_reg & CONTROL_EPS) && (!m_rx_parity))
|
|
m_rx_parity = 0; // even parity, ok
|
|
else
|
|
m_rx_parity = 1; // parity error
|
|
}
|
|
return;
|
|
|
|
case FIRST_STOP_BIT:
|
|
m_rx_pulses--;
|
|
if (m_rx_pulses == 8) // sample input stream
|
|
m_internal_sample = get_si();
|
|
else
|
|
if (m_rx_pulses == 7) // set error flags
|
|
{
|
|
if (!m_internal_sample)
|
|
{
|
|
m_status_reg |= STATUS_FE; // framing error - the stop bit not high
|
|
m_rx_state = PREP_TIME; // lost sync - start over
|
|
// return;
|
|
}
|
|
else
|
|
m_status_reg &= ~STATUS_FE;
|
|
|
|
if ((m_rx_parity) && (!(m_control_reg & CONTROL_NP)))
|
|
m_status_reg |= STATUS_PE; // parity error
|
|
else
|
|
m_status_reg &= ~STATUS_PE;
|
|
|
|
if (m_status_reg & STATUS_DAV)
|
|
m_status_reg |= STATUS_OR; // overrun error - previous byte still in buffer
|
|
else
|
|
m_status_reg &= ~STATUS_OR;
|
|
|
|
m_rx_buffer = m_rx_data; // bring received byte out for computer to read
|
|
|
|
update_status_pins();
|
|
}
|
|
else
|
|
if (m_rx_pulses == 6)
|
|
{
|
|
m_status_reg |= STATUS_DAV; // tell computer that new byte is ready
|
|
update_status_pins();
|
|
}
|
|
else
|
|
if (m_rx_pulses == 4)
|
|
{
|
|
if (m_second_stop_bit)
|
|
{
|
|
/* We should wait for the full first stop bit and
|
|
the beginning of the second stop bit */
|
|
m_rx_state = SECOND_STOP_BIT;
|
|
m_rx_pulses += m_second_stop_bit - 7;
|
|
}
|
|
else
|
|
{
|
|
/* We have seen a STOP bit, go back to PREP_TIME */
|
|
m_rx_state = PREP_TIME;
|
|
}
|
|
}
|
|
return;
|
|
|
|
case SECOND_STOP_BIT:
|
|
m_rx_pulses--;
|
|
if (!m_rx_pulses)
|
|
m_rx_state = PREP_TIME;
|
|
return;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*************************************************** TRANSMIT CONTROLS *************************************************/
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_tx_process - convert parallel to serial
|
|
-------------------------------------------------*/
|
|
|
|
TIMER_CALLBACK_MEMBER( ay31015_device::tx_process )
|
|
{
|
|
UINT8 t1;
|
|
switch (m_tx_state)
|
|
{
|
|
case IDLE:
|
|
if (!(m_status_reg & STATUS_TBMT))
|
|
{
|
|
m_tx_state = PREP_TIME; // When idle, see if a byte has been sent to us
|
|
m_tx_pulses = 1;
|
|
}
|
|
return;
|
|
|
|
case PREP_TIME: // This phase lets the transmitter regain sync after an idle period
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses)
|
|
{
|
|
m_tx_state = START_BIT;
|
|
m_tx_pulses = 16;
|
|
}
|
|
return;
|
|
|
|
case START_BIT:
|
|
if (m_tx_pulses == 16) // beginning of start bit
|
|
{
|
|
m_tx_data = m_tx_buffer; // load the shift register
|
|
m_status_reg |= STATUS_TBMT; // tell computer that another byte can be sent to uart
|
|
set_so(0); /* start bit begins now (we are "spacing") */
|
|
m_status_reg &= ~STATUS_EOC; // we are no longer idle
|
|
m_tx_parity = 0;
|
|
update_status_pins();
|
|
}
|
|
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses) // end of start bit
|
|
{
|
|
m_tx_state = PROCESSING;
|
|
m_tx_pulses = m_total_pulses;
|
|
}
|
|
return;
|
|
|
|
case PROCESSING:
|
|
if (!(m_tx_pulses & 15)) // beginning of a data bit
|
|
{
|
|
if (m_tx_data & 1)
|
|
{
|
|
set_so(1);
|
|
m_tx_parity++; // calculate cumulative parity
|
|
}
|
|
else
|
|
set_so(0);
|
|
|
|
m_tx_data >>= 1; // adjust the shift register
|
|
}
|
|
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses) // all data bits sent
|
|
{
|
|
m_tx_pulses = 16;
|
|
if (m_control_reg & CONTROL_NP) // see if we need to make a parity bit
|
|
m_tx_state = FIRST_STOP_BIT;
|
|
else
|
|
m_tx_state = PARITY_BIT;
|
|
}
|
|
|
|
return;
|
|
|
|
case PARITY_BIT:
|
|
if (m_tx_pulses == 16)
|
|
{
|
|
t1 = (m_control_reg & CONTROL_EPS) ? 0 : 1;
|
|
t1 ^= (m_tx_parity & 1);
|
|
if (t1)
|
|
set_so(1); /* extra bit to set the correct parity */
|
|
else
|
|
set_so(0); /* it was already correct */
|
|
}
|
|
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses)
|
|
{
|
|
m_tx_state = FIRST_STOP_BIT;
|
|
m_tx_pulses = 16;
|
|
}
|
|
return;
|
|
|
|
case FIRST_STOP_BIT:
|
|
if (m_tx_pulses == 16)
|
|
set_so(1); /* create a stop bit (marking and soon idle) */
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses)
|
|
{
|
|
m_status_reg |= STATUS_EOC; // character is completely sent
|
|
if (m_second_stop_bit)
|
|
{
|
|
m_tx_state = SECOND_STOP_BIT;
|
|
m_tx_pulses = m_second_stop_bit;
|
|
}
|
|
else
|
|
if (m_status_reg & STATUS_TBMT)
|
|
m_tx_state = IDLE; // if nothing to send, go idle
|
|
else
|
|
{
|
|
m_tx_pulses = 16;
|
|
m_tx_state = START_BIT; // otherwise immediately start next byte
|
|
}
|
|
update_status_pins();
|
|
}
|
|
return;
|
|
|
|
case SECOND_STOP_BIT:
|
|
m_tx_pulses--;
|
|
if (!m_tx_pulses)
|
|
{
|
|
if (m_status_reg & STATUS_TBMT)
|
|
m_tx_state = IDLE; // if nothing to send, go idle
|
|
else
|
|
{
|
|
m_tx_pulses = 16;
|
|
m_tx_state = START_BIT; // otherwise immediately start next byte
|
|
}
|
|
}
|
|
return;
|
|
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_reset - reset internal state
|
|
-------------------------------------------------*/
|
|
|
|
void ay31015_device::internal_reset()
|
|
{
|
|
/* total pulses = 16 * data-bits */
|
|
UINT8 t1;
|
|
|
|
if (m_control_reg & CONTROL_NB2)
|
|
t1 = (m_control_reg & CONTROL_NB1) ? 8 : 7;
|
|
else
|
|
t1 = (m_control_reg & CONTROL_NB1) ? 6 : 5;
|
|
|
|
m_total_pulses = t1 << 4; /* total clock pulses to load a byte */
|
|
m_second_stop_bit = ((m_control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */
|
|
if ((t1 == 5) && (m_second_stop_bit == 16))
|
|
m_second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */
|
|
m_status_reg = STATUS_EOC | STATUS_TBMT;
|
|
m_tx_data = 0;
|
|
m_rx_state = PREP_TIME;
|
|
m_tx_state = IDLE;
|
|
m_pins[AY31015_SI] = 1;
|
|
set_so(1);
|
|
|
|
m_rx_data = 0;
|
|
}
|
|
|
|
|
|
void ay51013_device::internal_reset()
|
|
{
|
|
/* total pulses = 16 * data-bits */
|
|
UINT8 t1;
|
|
|
|
if (m_control_reg & CONTROL_NB2)
|
|
t1 = (m_control_reg & CONTROL_NB1) ? 8 : 7;
|
|
else
|
|
t1 = (m_control_reg & CONTROL_NB1) ? 6 : 5;
|
|
|
|
m_total_pulses = t1 << 4; /* total clock pulses to load a byte */
|
|
m_second_stop_bit = ((m_control_reg & CONTROL_TSB) ? 16 : 0); /* 2nd stop bit */
|
|
if ((t1 == 5) && (m_second_stop_bit == 16))
|
|
m_second_stop_bit = 8; /* 5 data bits and 2 stop bits = 1.5 stop bits */
|
|
m_status_reg = STATUS_EOC | STATUS_TBMT;
|
|
m_tx_data = 0;
|
|
m_rx_state = PREP_TIME;
|
|
m_tx_state = IDLE;
|
|
m_pins[AY31015_SI] = 1;
|
|
set_so(1);
|
|
// no m_rx_data = 0 in this case
|
|
}
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_transfer_control_pins - transfers contents of controls pins to the control register
|
|
-------------------------------------------------*/
|
|
|
|
void ay31015_device::transfer_control_pins()
|
|
{
|
|
UINT8 control = 0;
|
|
|
|
control |= m_pins[AY31015_NP ] ? CONTROL_NP : 0;
|
|
control |= m_pins[AY31015_TSB] ? CONTROL_TSB : 0;
|
|
control |= m_pins[AY31015_NB1] ? CONTROL_NB1 : 0;
|
|
control |= m_pins[AY31015_NB2] ? CONTROL_NB2 : 0;
|
|
control |= m_pins[AY31015_EPS] ? CONTROL_EPS : 0;
|
|
|
|
if (m_control_reg != control)
|
|
{
|
|
m_control_reg = control;
|
|
internal_reset();
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_set_input_pin - set an input pin
|
|
-------------------------------------------------*/
|
|
void ay31015_device::set_input_pin( ay31015_input_pin_t pin, int data )
|
|
{
|
|
data = data ? 1 : 0;
|
|
|
|
switch (pin)
|
|
{
|
|
case AY31015_SWE:
|
|
m_pins[pin] = data;
|
|
update_status_pins();
|
|
break;
|
|
case AY31015_RDAV:
|
|
m_pins[pin] = data;
|
|
if (!data)
|
|
{
|
|
m_status_reg &= ~STATUS_DAV;
|
|
m_pins[AY31015_DAV] = 0;
|
|
}
|
|
break;
|
|
case AY31015_SI:
|
|
m_pins[pin] = data;
|
|
break;
|
|
case AY31015_XR:
|
|
m_pins[pin] = data;
|
|
if (data)
|
|
internal_reset();
|
|
break;
|
|
case AY31015_CS:
|
|
case AY31015_NP:
|
|
case AY31015_TSB:
|
|
case AY31015_NB1:
|
|
case AY31015_NB2:
|
|
case AY31015_EPS:
|
|
m_pins[pin] = data;
|
|
if (m_pins[AY31015_CS])
|
|
transfer_control_pins();
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_get_output_pin - get the status of an output pin
|
|
-------------------------------------------------*/
|
|
|
|
int ay31015_device::get_output_pin( ay31015_output_pin_t pin )
|
|
{
|
|
return m_pins[pin];
|
|
}
|
|
|
|
|
|
inline void ay31015_device::update_rx_timer()
|
|
{
|
|
if (m_rx_clock > 0.0)
|
|
{
|
|
m_rx_timer->adjust(attotime::from_hz(m_rx_clock), 0, attotime::from_hz(m_rx_clock));
|
|
}
|
|
else
|
|
{
|
|
m_rx_timer->enable(0);
|
|
}
|
|
}
|
|
|
|
|
|
inline void ay31015_device::update_tx_timer()
|
|
{
|
|
if (m_tx_clock > 0.0)
|
|
{
|
|
m_tx_timer->adjust(attotime::from_hz(m_tx_clock), 0, attotime::from_hz(m_tx_clock));
|
|
}
|
|
else
|
|
{
|
|
m_tx_timer->enable(0);
|
|
}
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_set_receiver_clock - set receive clock
|
|
-------------------------------------------------*/
|
|
|
|
void ay31015_device::set_receiver_clock( double new_clock )
|
|
{
|
|
m_rx_clock = new_clock;
|
|
update_rx_timer();
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_set_transmitter_clock - set transmit clock
|
|
-------------------------------------------------*/
|
|
|
|
void ay31015_device::set_transmitter_clock( double new_clock )
|
|
{
|
|
m_tx_clock = new_clock;
|
|
update_tx_timer();
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_get_received_data - return a byte to the computer
|
|
-------------------------------------------------*/
|
|
|
|
UINT8 ay31015_device::get_received_data()
|
|
{
|
|
return m_rx_buffer;
|
|
}
|
|
|
|
|
|
/*-------------------------------------------------
|
|
ay31015_set_transmit_data - accept a byte to transmit, if able
|
|
-------------------------------------------------*/
|
|
void ay31015_device::set_transmit_data( UINT8 data )
|
|
{
|
|
if (m_status_reg & STATUS_TBMT)
|
|
{
|
|
m_tx_buffer = data;
|
|
m_status_reg &= ~STATUS_TBMT;
|
|
update_status_pins();
|
|
}
|
|
}
|