summaryrefslogblamecommitdiffstatshomepage
path: root/src/devices/machine/i8251.cpp
blob: 2ef674ec1c04c93caefa8eea5c5492d7b574177d (plain) (tree)
1
2
3
4
5
6
7
8
9
                       
                                  

                                                                      
             
 
                                                                           
                           
 

                                                                         
 





                                                                          
 





                                                                      







                                        
                     
 



                                                       
 



                                                                            
                                                                          
                                                                     

 



                                                   


                                              

                                

                                                     









                                                
                 




                 
                                                                                                           
                                                         


 

                                                                                                               



 
                                                   





                                                   
                                     

                                     


                                         
                                        
                                 
                                           


                                     




                                         







                                     

                                   




                                           










                                                   
                                                     
 

                               
                          
 
                                    










                                                   
                              
         







                                                                     

                                                                                  
                                                          
                                                   

                                                                                 



                                                   



                                                                       




                                                               















































































                                                                                     


















































                                                                                     

 


                                                   
                                        
 
                                           




                                                   
                                       
 
                                                                                                                     
         
                           
         
 
 


                                                   
                             
 
                                          


                                           
 






                                                   
                      
                                       

                       



                                         
                                                                                                    
                                   
                    
                                                          
 


                                  
 
                                                        

                                          
                                                                
                                                         

                                    













                                                   



                                
 
                                                                              
 
                                  











                                                   

                                                                                    

         
                                                                   



 

























                                                                 




                                                   
 
                              




                                                                       
                         
 


                         



                                  
                                  



                                                                 
                                                       

                        

                      
                                      
                        














                                                   
                                          
 
                     

                         








                                                                                                                
 

                                     
 
                         

                                                     
                                                                                                                   
         
 
                         
         


                                                                       
                                          
         
 










                                         
                             

                          
                          
 
 
                                       
 
                                               
 
                           
 

                                




















                                                                            
 
                               


















                                                    
 

                                                         
 





                                                             

                              


                                                              

                              


                                                       
 




                                            
 



                                                       
 
                                    
                 

















                                                            
                 
 
                                                                        
 
                                    
                 


                                                 
 



                                                 


            
                                                      
 
                                            







                                                                             
         


                                 















                                        
 
 
                                          
 







                                        
            
                                







                                                   
                                
 
                                                 
 
                                      


                                                   
 
                      







                                                   
                                       
 
                         
 
                                   


                                          
                                                             
                          
 


                                                             



                                                                       
                          








                                                   
                                                
 

                                            
                       
 
                                                         

                                                             
         
                                                       

                                                
 
                                                            
                                          
                                                             









                                                   
                              
 
                                                                 
                            


                                                   
                                                     

                                  
                         
 
 
 

                                         
                   






                                                     
                   





                                
                                          
 
                      

                                                 

 

                                          
                      
 


                             

 

                                          
                       
 


                                          
                            
         





                                           

                                        

                      







                                          

                                         

         
 










                                                             



                                                                          








































                                                            
// license:BSD-3-Clause
// copyright-holders:smf, Robbbert
/*********************************************************************

    i8251.cpp

    Intel 8251 Universal Synchronous/Asynchronous Receiver Transmitter code
    NEC uPD71051 is a clone

    The V53/V53A use a customized version with only the Asynchronous mode
    and a split command / mode register

To Do:
- BRKDET: if, in Async mode, 16 low RxD bits in succession are clocked in,
          the SYNDET pin & status must go high. It will go low upon a
          status read, same as what happens with sync.

- SYNC/BISYNC with PARITY is not tested, and therefore possibly buggy.


*********************************************************************/

#include "emu.h"
#include "i8251.h"

#define LOG_STAT    (1U << 1)
#define LOG_COM     (1U << 2)
#define LOG_MODE    (1U << 3)
#define LOG_BITS    (1U << 4)

//#define VERBOSE (LOG_BITS|LOG_GENERAL)
//#define LOG_OUTPUT_STREAM std::cout

#include "logmacro.h"

#define LOGSTAT(...)  LOGMASKED(LOG_STAT,  __VA_ARGS__)
#define LOGCOM(...)   LOGMASKED(LOG_COM,   __VA_ARGS__)
#define LOGMODE(...)  LOGMASKED(LOG_MODE,  __VA_ARGS__)
#define LOGBITS(...)  LOGMASKED(LOG_BITS,  __VA_ARGS__)

//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE(I8251,   i8251_device,  "i8251",    "Intel 8251 USART")
DEFINE_DEVICE_TYPE(V5X_SCU, v5x_scu_device, "v5x_scu", "NEC V5X SCU")


//-------------------------------------------------
//  i8251_device - constructor
//-------------------------------------------------

i8251_device::i8251_device(
		const machine_config &mconfig,
		device_type type,
		const char *tag,
		device_t *owner,
		uint32_t clock)
	: device_t(mconfig, type, tag, owner, clock),
	device_serial_interface(mconfig, *this),
	m_txd_handler(*this),
	m_dtr_handler(*this),
	m_rts_handler(*this),
	m_rxrdy_handler(*this),
	m_txrdy_handler(*this),
	m_txempty_handler(*this),
	m_syndet_handler(*this),
	m_cts(1),
	m_dsr(1),
	m_rxd(1),
	m_rxc(0),
	m_txc(0)
{
}

i8251_device::i8251_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: i8251_device(mconfig, I8251, tag, owner, clock)
{
}

v5x_scu_device::v5x_scu_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
	: i8251_device(mconfig, V5X_SCU, tag, owner, clock)
{
}


//-------------------------------------------------
//  device_start - device-specific startup
//-------------------------------------------------

void i8251_device::device_start()
{
	// resolve callbacks
	m_txd_handler.resolve_safe();
	m_rts_handler.resolve_safe();
	m_dtr_handler.resolve_safe();
	m_rxrdy_handler.resolve_safe();
	m_txrdy_handler.resolve_safe();
	m_txempty_handler.resolve_safe();
	m_syndet_handler.resolve_safe();
	save_item(NAME(m_flags));
	save_item(NAME(m_sync_byte_count));
	save_item(NAME(m_status));
	save_item(NAME(m_command));
	save_item(NAME(m_mode_byte));
	save_item(NAME(m_delayed_tx_en));
	save_item(NAME(m_sync1));
	save_item(NAME(m_sync2));
	save_item(NAME(m_sync8));
	save_item(NAME(m_sync16));
	save_item(NAME(m_cts));
	save_item(NAME(m_dsr));
	save_item(NAME(m_rxd));
	save_item(NAME(m_rxc));
	save_item(NAME(m_txc));
	save_item(NAME(m_rxc_count));
	save_item(NAME(m_txc_count));
	save_item(NAME(m_br_factor));
	save_item(NAME(m_rx_data));
	save_item(NAME(m_tx_data));
	save_item(NAME(m_syndet_pin));
	save_item(NAME(m_hunt_on));
	save_item(NAME(m_ext_syn_set));
	save_item(NAME(m_rxd_bits));
	save_item(NAME(m_data_bits_count));
}




/*-------------------------------------------------
    update_rx_ready
-------------------------------------------------*/

void i8251_device::update_rx_ready()
{
	int state = m_status & I8251_STATUS_RX_READY;

	// masked?
	if (!BIT(m_command, 2))
		state = 0;

	m_rxrdy_handler(state != 0);
}



/*-------------------------------------------------
    receive_clock
-------------------------------------------------*/

void i8251_device::receive_clock()
{
	/* receive enable? */
	if (BIT(m_command, 2))
	{
		const bool sync = is_receive_register_synchronized();
		if (sync)
		{
			--m_rxc_count;
			if (m_rxc_count)
				return;
		}

		//logerror("I8251\n");
		/* get bit received from other side and update receive register */
		//LOGBITS("8251: Rx Sampled %d\n", m_rxd);
		receive_register_update_bit(m_rxd);
		if (is_receive_register_synchronized())
			m_rxc_count = sync ? m_br_factor : (3 * m_br_factor / 2);

		if (is_receive_register_full())
		{
			receive_register_extract();
			if (is_receive_parity_error())
				m_status |= I8251_STATUS_PARITY_ERROR;
			if (is_receive_framing_error())
				m_status |= I8251_STATUS_FRAMING_ERROR;
			receive_character(get_received_char());
		}
	}
}

bool i8251_device::calc_parity(u8 ch)
{
	bool data = 0;
	for (u8 b = 0; b < 8; b++)
		data ^= BIT(ch, b);
	return data;
}

void i8251_device::sync1_rxc()
{
	// is rx enabled?
	if (!BIT(m_command, 2))
		return;

	// if ext sync, and syndet low, quit
	// Todo: what should happen here?
	if (m_syndet_pin && !m_ext_syn_set)
		return;

	u8 need_parity = BIT(m_mode_byte, 4);

	// see about parity
	if (need_parity && (m_rxd_bits == m_data_bits_count))
	{
		if (calc_parity(m_sync1) != m_rxd)
			m_status |= I8251_STATUS_PARITY_ERROR;
		// and then continue on as if everything was ok
	}
	else
	{
		// add bit to byte
		m_sync1 = (m_sync1 >> 1) | (m_rxd << (m_data_bits_count-1));
	}

	// if we are in hunt mode, the byte loaded has to
	// be the sync byte. If not, go around again.
	// if we leave hunt mode now, the sync byte must not go to the receive buffer
	bool was_in_hunt_mode = false;
	if (m_hunt_on)
	{
		if (m_sync1 == m_sync8)
		{
			m_rxd_bits = m_data_bits_count;
			m_hunt_on = false;
			was_in_hunt_mode = true;
		}
		else
			return;
	}

	// is byte complete? if not, quit
	m_rxd_bits++;
	if (m_rxd_bits < (m_data_bits_count + need_parity))
		return;

	// now we have a synchronised byte, and parity has been dealt with

	// copy byte to rx buffer
	if (!was_in_hunt_mode)
		receive_character(m_sync1);

	// Is it a sync byte? syndet gets indicated whenever
	// a sync byte passes by, regardless of hunt_mode status.
	if (m_sync1 == m_sync8)
		update_syndet(true);

	m_rxd_bits = 0;
	m_sync1 = 0;
}

void i8251_device::sync2_rxc()
{
	// is rx enabled?
	if (!BIT(m_command, 2))
		return;

	// if ext sync, and syndet low, quit
	if (m_syndet_pin && !m_ext_syn_set)
		return;

	u8 need_parity = BIT(m_mode_byte, 4);

	// see about parity
	if (need_parity && (m_rxd_bits == m_data_bits_count))
	{
		if (calc_parity(m_sync1) != m_rxd)
			m_status |= I8251_STATUS_PARITY_ERROR;
		// and then continue on as if everything was ok
	}
	else
	{
		// add bit to byte
		m_sync1 = (m_sync1 >> 1) | (m_rxd << (m_data_bits_count-1));
		m_sync2 = (m_sync2 >> 1) | (m_rxd << (m_data_bits_count*2-1));
	}

	// if we are in hunt mode, the byte loaded has to
	// be the sync byte. If not, go around again.
	// if we leave hunt mode now, the sync byte must not go to the receive buffer
	bool was_in_hunt_mode = false;
	if (m_hunt_on)
	{
		if (m_sync2 == m_sync16)
		{
			m_rxd_bits = m_data_bits_count;
			m_hunt_on = false;
			was_in_hunt_mode = true;
		}
		else
			return;
	}

	// is byte complete? if not, quit
	m_rxd_bits++;
	if (m_rxd_bits < (m_data_bits_count + need_parity))
		return;

	// now we have a synchronised byte, and parity has been dealt with

	// copy byte to rx buffer
	if (!was_in_hunt_mode)
		receive_character(m_sync1);

	// Is it a sync byte? syndet gets indicated whenever
	// a sync byte passes by, regardless of hunt_mode status.
	if (m_sync2 == m_sync16)
		update_syndet(true);

	m_rxd_bits = 0;
	m_sync1 = 0;
	m_sync2 = 0;
}

/*-------------------------------------------------
    is_tx_enabled
-------------------------------------------------*/
bool i8251_device::is_tx_enabled() const
{
	return BIT(m_command, 0) && !m_cts;
}

/*-------------------------------------------------
    check_for_tx_start
-------------------------------------------------*/
void i8251_device::check_for_tx_start()
{
	if (is_tx_enabled() && (m_status & (I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY)) == I8251_STATUS_TX_EMPTY)
	{
		start_tx();
	}
}

/*-------------------------------------------------
    start_tx
-------------------------------------------------*/
void i8251_device::start_tx()
{
	LOG("start_tx %02x\n", m_tx_data);
	transmit_register_setup(m_tx_data);
	m_status &= ~I8251_STATUS_TX_EMPTY;
	m_status |= I8251_STATUS_TX_READY;
}

/*-------------------------------------------------
    transmit_clock
-------------------------------------------------*/

void i8251_device::transmit_clock()
{
	m_txc_count++;
	if (m_txc_count != m_br_factor)
		return;

	m_txc_count = 0;

	if (is_transmit_register_empty())
	{
		if ((m_status & I8251_STATUS_TX_READY) == 0 && (is_tx_enabled() || m_delayed_tx_en))
			start_tx();
		else
			m_status |= I8251_STATUS_TX_EMPTY;

		update_tx_ready();
		update_tx_empty();
	}

	/* if diserial has bits to send, make them so */
	if (!is_transmit_register_empty())
	{
		uint8_t data = transmit_register_get_data_bit();
		LOGBITS("8251: Tx Present a %d\n", data);
		m_txd_handler(data);
	}
}



/*-------------------------------------------------
    update_tx_ready
-------------------------------------------------*/

void i8251_device::update_tx_ready()
{
	/* clear tx ready state */
	int tx_ready;

	/* tx ready output is set if:
	    DB Buffer Empty &
	    CTS is set &
	    Transmit enable is 1
	*/

	tx_ready = is_tx_enabled() && (m_status & I8251_STATUS_TX_READY) != 0;

	m_txrdy_handler(tx_ready);
}



/*-------------------------------------------------
    update_tx_empty
-------------------------------------------------*/

void i8251_device::update_tx_empty()
{
	if (m_status & I8251_STATUS_TX_EMPTY)
	{
		// return TxD to marking state (high) if not sending break character
		m_txd_handler(!BIT(m_command, 3));
	}

	m_txempty_handler((m_status & I8251_STATUS_TX_EMPTY) != 0);
}



/*---------------------------------------------------
    update_syndet - indicates that a sync
    character string has been received
    1 = valid sync; 0 = hunt mode on, or status read
-----------------------------------------------------*/

void i8251_device::update_syndet(bool voltage)
{
	LOG("I8251: Syndet %d\n",voltage);
	// Sanity check
	if (voltage && m_hunt_on)
		printf("I8251: Syndet - invalid parameters\n");

	// Adjust status register
	if (voltage)
		m_status |= 0x40;
	else
		m_status &= ~0x40;

	// If syndet is set as an output pin, indicate new status
	if (!m_syndet_pin)
		m_syndet_handler(voltage);
}



//-------------------------------------------------
//  device_reset - device-specific reset
//-------------------------------------------------

void i8251_device::device_reset()
{
	LOG("I8251: Reset\n");

	/* what is the default setup when the 8251 has been reset??? */

	/* i8251 datasheet explains the state of tx pin at reset */
	/* tx is set to 1 */
	m_txd_handler(1);

	/* assumption */
	m_rts_handler(1);
	m_dtr_handler(1);

	transmit_register_reset();
	receive_register_reset();
	/* expecting mode byte */
	m_flags = I8251_NEXT_MODE;

	/* no character to read by cpu */
	/* transmitter is ready and is empty */
	m_status = I8251_STATUS_TX_EMPTY | I8251_STATUS_TX_READY;
	LOGSTAT("status is reset to %02x\n", m_status);
	m_mode_byte = 0;
	m_command = 0;
	m_rx_data = 0;
	m_tx_data = 0;
	m_rxc_count = m_txc_count = 0;
	m_br_factor = 1;

	/* update tx empty pin output */
	update_tx_empty();
	/* update rx ready pin output */
	update_rx_ready();
	/* update tx ready pin output */
	update_tx_ready();
}



/*-------------------------------------------------
    control_w
-------------------------------------------------*/

void i8251_device::command_w(uint8_t data)
{
	/* command */
	m_command = data;

	LOG("I8251: Command byte: %02x\n", data);
	LOGCOM(" Tx enable: %d\n", data & 0x01 ? 1 : 0); // bit 0: 0 = transmit disable 1 = transmit enable
	LOGCOM(" DTR      : %d\n", data & 0x02 ? 1 : 0); // bit 1: 0 = /DTR set to 1    1 = /DTR set to 0
	LOGCOM(" Rx enable: %d\n", data & 0x04 ? 1 : 0); // bit 2: 0 = receive disable  1 = receive enable
	LOGCOM(" Send BRK : %d\n", data & 0x08 ? 1 : 0); // bit 3: 0 = normal operation 1 = send break character
	LOGCOM(" Err reset: %d\n", data & 0x10 ? 1 : 0); // bit 4: 0 = normal operation 1 = reset error flag
	LOGCOM(" RTS      : %d\n", data & 0x20 ? 1 : 0); // bit 5: 0 = /RTS set to 1    1 = /RTS set to 0
	LOGCOM(" Reset    : %d\n", data & 0x40 ? 1 : 0); // bit 6: 0 = normal operation 1 = internal reset
	LOGCOM(" Hunt mode: %d\n", data & 0x80 ? 1 : 0); // bit 7: 0 = normal operation 1 = hunt mode

	m_rts_handler(!BIT(data, 5));
	m_dtr_handler(!BIT(data, 1));

	if (BIT(data, 4))
	{
		LOGSTAT("status errors are reset\n");
		m_status &= ~(I8251_STATUS_PARITY_ERROR | I8251_STATUS_OVERRUN_ERROR | I8251_STATUS_FRAMING_ERROR);
	}

	if (BIT(data, 6))
	{
		// datasheet says "returns to mode format", not
		// completely resets the chip.  behavior of DEC Rainbow
		// backs this up.
		m_flags = I8251_NEXT_MODE;
	}

	// Hunt mode
	m_hunt_on = false;
	update_syndet(false);
	if (m_sync_byte_count)
		m_hunt_on = BIT(data, 7);
	if (m_hunt_on)
		m_ext_syn_set = false;

	if (BIT(data, 3))
		m_txd_handler(0);

	check_for_tx_start();
	update_rx_ready();
	update_tx_ready();
	update_tx_empty();
}

void i8251_device::mode_w(uint8_t data)
{
	LOG("I8251: Mode byte = %02X\n", data);

	m_mode_byte = data;

		/*  Asynchronous

		    bit 7,6: stop bit length
		    0 = inhibit
		    1 = 1 bit
		    2 = 1.5 bits
		    3 = 2 bits
		    bit 5: parity type
		    0 = parity odd
		    1 = parity even
		    bit 4: parity test enable
		    0 = disable
		    1 = enable
		    bit 3,2: character length
		    0 = 5 bits
		    1 = 6 bits
		    2 = 7 bits
		    3 = 8 bits
		    bit 1,0: baud rate factor
		    0 = defines command byte for synchronous or asynchronous
		    1 = x1
		    2 = x16
		    3 = x64

		    Synchronous
		    bit 7: Number of sync characters
		    0 = 1 character
		    1 = 2 character
		    bit 6: Synchronous mode
		    0 = Internal synchronisation
		    1 = External synchronisation
		    bit 5: parity type
		    0 = parity odd
		    1 = parity even
		    bit 4: parity test enable
		    0 = disable
		    1 = enable
		    bit 3,2: character length
		    0 = 5 bits
		    1 = 6 bits
		    2 = 7 bits
		    3 = 8 bits
		    bit 1,0 = 0
		        */

	m_data_bits_count = ((data >> 2) & 0x03) + 5;
	LOG("Character length: %d\n", m_data_bits_count);

	parity_t parity = PARITY_NONE;
	switch (data & 0x30)
	{
		case 0x10:
			LOG("Enable ODD parity checking.\n");
			parity = PARITY_ODD;
			break;

		case 0x30:
			LOG("Enable EVEN parity checking.\n");
			parity = PARITY_EVEN;
			break;

		default:
			LOG("Disable parity check.\n");
	}

	stop_bits_t stop_bits = STOP_BITS_0;
	m_br_factor = 1;
	m_flags = I8251_NEXT_COMMAND;
	m_sync_byte_count = 0;
	m_syndet_pin = false;

	/* Synchronous or Asynchronous? */
	if (data & 0x03)
	{
		LOG("I8251: Asynchronous operation\n");

		switch (data & 0xc0)
		{
			case 0x40:
				stop_bits = STOP_BITS_1;
				LOG("stop bit: 1 bit\n");
				break;

			case 0x80:
				stop_bits = STOP_BITS_1_5;
				LOG("stop bit: 1.5 bits\n");
				break;

			case 0xc0:
				stop_bits = STOP_BITS_2;
				LOG("stop bit: 2 bits\n");
				break;

			default:
				LOG("stop bit: inhibit\n");
				break;
		}

		set_data_frame(1, m_data_bits_count, parity, stop_bits);

		switch (data & 0x03)
		{
			case 2:
				m_br_factor = 16;
				break;

			case 3:
				m_br_factor = 64;
				break;
		}
	}
	else
	{
		LOG("I8251: Synchronous operation\n");

		/* setup for sync byte(s) */
		m_flags = BIT(data, 7) ? I8251_NEXT_SYNC2 : I8251_NEXT_SYNC1;
		m_sync_byte_count = BIT(data, 7) ? 1 : 2;
		set_data_frame(0, m_data_bits_count, parity, stop_bits);
		m_syndet_pin = BIT(data, 6);
		m_sync8 = 0;
		m_sync16 = 0;
		m_rxd_bits = 0;
		m_sync1 = 0;
	}

	receive_register_reset();
	m_txc_count = 0;
}

void i8251_device::sync1_w(uint8_t data)
{
	m_sync16 = (data << 8);
	m_flags = I8251_NEXT_SYNC2;
}

void i8251_device::sync2_w(uint8_t data)
{
	if (m_sync_byte_count == 2)
		m_sync16 |= data;
	else
		m_sync8 = data;

	m_flags = I8251_NEXT_COMMAND;
}

void i8251_device::control_w(uint8_t data)
{
	if (m_flags == I8251_NEXT_SYNC1)
		sync1_w(data);
	else
	if (m_flags == I8251_NEXT_SYNC2)
		sync2_w(data);
	else
	if (m_flags == I8251_NEXT_MODE)
		mode_w(data);
	else
		command_w(data);
}



/*-------------------------------------------------
    status_r
-------------------------------------------------*/

uint8_t i8251_device::status_r()
{
	uint8_t status = (m_dsr << 7) | m_status;

	LOG("status: %02x\n", status);

	// Syndet always goes off after status read
	update_syndet(false);

	return status;
}



/*-------------------------------------------------
    data_w
-------------------------------------------------*/

void i8251_device::data_w(uint8_t data)
{
	m_tx_data = data;

	LOG("data_w %02x\n", data);

	/* writing clears */
	m_status &=~I8251_STATUS_TX_READY;
	LOGSTAT("8251: status cleared TX_READY by data_w\n");
	update_tx_ready();

	// Store state of tx enable when writing to DB buffer
	m_delayed_tx_en = is_tx_enabled();
	check_for_tx_start();

	/* if transmitter is active, then tx empty will be signalled */

	update_tx_ready();
	update_tx_empty();
}



/*-------------------------------------------------
    receive_character - called when last
    bit of data has been received
-------------------------------------------------*/

void i8251_device::receive_character(uint8_t ch)
{
	LOG("receive_character %02x\n", ch);

	m_rx_data = ch;

	LOGSTAT("status RX READY test %02x\n", m_status);
	/* char has not been read and another has arrived! */
	if (m_status & I8251_STATUS_RX_READY)
	{
		m_status |= I8251_STATUS_OVERRUN_ERROR;
		LOGSTAT("status overrun set\n");
	}

	LOGSTAT("status pre RX READY set %02x\n", m_status);
	m_status |= I8251_STATUS_RX_READY;
	LOGSTAT("status post RX READY set %02x\n", m_status);

	update_rx_ready();
}



/*-------------------------------------------------
    data_r - read data
-------------------------------------------------*/

uint8_t i8251_device::data_r()
{
	LOG("read data: %02x, STATUS=%02x\n",m_rx_data,m_status);
	/* reading clears */
	if (!machine().side_effects_disabled())
	{
		m_status &= ~I8251_STATUS_RX_READY;
		LOGSTAT("status RX_READY cleared\n");
		update_rx_ready();
	}
	return m_rx_data;
}


uint8_t i8251_device::read(offs_t offset)
{
	if (offset)
		return status_r();
	else
		return data_r();
}

void i8251_device::write(offs_t offset, uint8_t data)
{
	if (offset)
		control_w(data);
	else
		data_w(data);
}


WRITE_LINE_MEMBER(i8251_device::write_rxd)
{
	m_rxd = state;
	LOGBITS("8251: Presented a %d\n", m_rxd);
	//  device_serial_interface::rx_w(state);
}

WRITE_LINE_MEMBER(i8251_device::write_cts)
{
	m_cts = state;

	check_for_tx_start();
	update_tx_ready();
	update_tx_empty();
}

WRITE_LINE_MEMBER(i8251_device::write_dsr)
{
	m_dsr = !state;
}

WRITE_LINE_MEMBER(i8251_device::write_rxc)
{
	if (!m_rxc && state)
	{
		if (m_sync_byte_count == 1)
			sync1_rxc();
		else
		if (m_sync_byte_count == 2)
			sync2_rxc();
		else
			receive_clock();
	}

	m_rxc = state;
}

WRITE_LINE_MEMBER(i8251_device::write_txc)
{
	if (m_txc != state)
	{
		m_txc = state;

		if (!m_txc)
			transmit_clock();
	}
}

// forcibly kill hunt mode
WRITE_LINE_MEMBER(i8251_device::write_syn)
{
	if (m_syndet_pin && state)    // must be set as input
	{
		m_ext_syn_set = true;
		m_hunt_on = false;
		update_syndet(true);
	}
}

READ_LINE_MEMBER(i8251_device::txrdy_r)
{
	return is_tx_enabled() && (m_status & I8251_STATUS_TX_READY) != 0;
}

void v5x_scu_device::device_start()
{
	i8251_device::device_start();

	save_item(NAME(m_simk));
}

void v5x_scu_device::device_reset()
{
	// FIXME: blindly copied from v53.cpp - not verified
	m_simk = 0x03;

	i8251_device::device_reset();
}

u8 v5x_scu_device::read(offs_t offset)
{
	u8 data = 0;

	switch (offset)
	{
	case 0: data = data_r(); break;
	case 1: data = status_r(); break;
	case 2: break;
	case 3: data = simk_r(); break;
	}

	return data;
}

void v5x_scu_device::write(offs_t offset, uint8_t data)
{
	switch (offset)
	{
	case 0: data_w(data); break;
	case 1: control_w(data); break;
	case 2: mode_w(data); break;
	case 3: simk_w(data); break;
	}
}