diff options
Diffstat (limited to 'src/mess/machine/pce220_ser.c')
-rw-r--r-- | src/mess/machine/pce220_ser.c | 306 |
1 files changed, 306 insertions, 0 deletions
diff --git a/src/mess/machine/pce220_ser.c b/src/mess/machine/pce220_ser.c new file mode 100644 index 00000000000..67d7f1fef3d --- /dev/null +++ b/src/mess/machine/pce220_ser.c @@ -0,0 +1,306 @@ +/**************************************************************************** + + pce220_ser.c + + Sharp PC-E220/PC-G850V Serial I/O + +****************************************************************************/ + +#include "emu.h" +#include "pce220_ser.h" + +// SIO configuration +#define SIO_BAUD_RATE 1200 +#define SIO_EOT_BYTE 0x1a +#define SIO_DATA_BIT 8 // number of data bit +#define SIO_PARITY 0 // 0=none 1=odd 2=even +#define SIO_STOP_BIT 1 // number of stop bit + +//SIO states +enum +{ + SIO_WAIT = 0, + SIO_SEND_START, + SIO_SEND_BIT0, + SIO_SEND_BIT1, + SIO_SEND_BIT2, + SIO_SEND_BIT3, + SIO_SEND_BIT4, + SIO_SEND_BIT5, + SIO_SEND_BIT6, + SIO_SEND_BIT7, + SIO_SEND_PARITY, + SIO_SEND_STOP1, + SIO_SEND_STOP2 +}; + +// device type definition +const device_type PCE220SERIAL = &device_creator<pce220_serial_device>; + +//------------------------------------------------- +// pce220_serial_device - constructor +//------------------------------------------------- + +pce220_serial_device::pce220_serial_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, PCE220SERIAL, "Sharp PC-E220 serial", tag, owner, clock), + device_image_interface(mconfig, *this) +{ +} + +//------------------------------------------------- +// pce220_serial_device - destructor +//------------------------------------------------- + +pce220_serial_device::~pce220_serial_device() +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void pce220_serial_device::device_start() +{ + m_send_timer = timer_alloc(TIMER_SEND); + m_receive_timer = timer_alloc(TIMER_RECEIVE); + m_send_timer->reset(); + m_receive_timer->reset(); +} + + +//------------------------------------------------- +// device_reset - reset up the device +//------------------------------------------------- + +void pce220_serial_device::device_reset() +{ + m_state = SIO_WAIT; + m_bytes_count = 0; + m_dout = m_busy = m_xout = 0; + m_din = m_xin = m_ack = 0; +} + + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- + +void pce220_serial_device::device_config_complete() +{ + // set brief and instance name + update_names(); +} + + +//------------------------------------------------- +// device_timer - handler timer events +//------------------------------------------------- + +void pce220_serial_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + if (id == TIMER_SEND && m_enabled) + { + //send data + if (m_bytes_count <= length()) + { + switch(m_state) + { + case SIO_WAIT: + m_ack = 1; //data send request + //waits until is ready to receive + if(!m_busy) + return; + break; + case SIO_SEND_START: + //send start bit + m_xin = 1; + break; + case SIO_SEND_BIT0: + case SIO_SEND_BIT1: + case SIO_SEND_BIT2: + case SIO_SEND_BIT3: + case SIO_SEND_BIT4: + case SIO_SEND_BIT5: + case SIO_SEND_BIT6: + case SIO_SEND_BIT7: + m_xin = BIT(~m_current_byte, m_state - SIO_SEND_BIT0); + break; + case SIO_SEND_PARITY: + m_xin = calc_parity(m_current_byte); + break; + case SIO_SEND_STOP1: + case SIO_SEND_STOP2: + //stop bit + m_xin = m_ack = 0; + break; + } + + if (m_state == (SIO_SEND_PARITY + SIO_STOP_BIT)) + { + //next byte + m_bytes_count++; + popmessage("Send %d/%d bytes\n", m_bytes_count , (UINT32)length()); + m_state = SIO_WAIT; + if (m_bytes_count < length()) + fread(&m_current_byte, 1); + else + m_current_byte = SIO_EOT_BYTE; + } + else + { + m_state = get_next_state(); + } + + } + else + { + m_din = m_xin = m_ack = 0; + } + } + else if (id == TIMER_RECEIVE && m_enabled) + { + //receive data + switch(m_state) + { + case SIO_WAIT: + //wait send request + if(m_busy) + return; + m_ack = 1; //acknowledge + break; + case SIO_SEND_START: + //wait for the start bit + if (!m_xout) + return; + break; + case SIO_SEND_BIT0: + case SIO_SEND_BIT1: + case SIO_SEND_BIT2: + case SIO_SEND_BIT3: + case SIO_SEND_BIT4: + case SIO_SEND_BIT5: + case SIO_SEND_BIT6: + case SIO_SEND_BIT7: + m_current_byte |= ((~m_xout)&1) << (m_state - SIO_SEND_BIT0); + break; + case SIO_SEND_PARITY: + if (m_xout != calc_parity(m_current_byte)) + logerror("SIO %s: byte %d has wrong parity!\n", tag(), m_bytes_count); + break; + case SIO_SEND_STOP1: + case SIO_SEND_STOP2: + //receive stop bit + m_ack = 0; + break; + } + + if (m_state == (SIO_SEND_PARITY + SIO_STOP_BIT)) + { + //next byte + m_bytes_count++; + popmessage("Received %d bytes\n", m_bytes_count); + m_state = SIO_WAIT; + if (m_current_byte != SIO_EOT_BYTE) + fwrite(&m_current_byte, 1); + m_current_byte = 0; + } + else + { + m_state = get_next_state(); + } + } + else + { + m_din = m_xin = m_ack = 0; + } +} + +/*------------------------------------------------- + DEVICE_IMAGE_LOAD( pce220_serial ) +-------------------------------------------------*/ + +bool pce220_serial_device::call_load() +{ + m_state = SIO_WAIT; + m_bytes_count = 0; + m_send_timer->adjust(attotime::from_hz(SIO_BAUD_RATE), 0, attotime::from_hz(SIO_BAUD_RATE)); + + //read the first byte + fread(&m_current_byte, 1); + + return IMAGE_INIT_PASS; +} + +/*------------------------------------------------- + DEVICE_IMAGE_CREATE( pce220_serial ) +-------------------------------------------------*/ + +bool pce220_serial_device::call_create(int format_type, option_resolution *format_options) +{ + m_state = SIO_WAIT; + m_bytes_count = 0; + m_current_byte = 0; + m_receive_timer->adjust(attotime::from_hz(SIO_BAUD_RATE), 0, attotime::from_hz(SIO_BAUD_RATE)); + + return IMAGE_INIT_PASS; +} + + +/*------------------------------------------------- + DEVICE_IMAGE_UNLOAD( pce220_serial ) +-------------------------------------------------*/ + +void pce220_serial_device::call_unload() +{ + m_send_timer->reset(); + m_receive_timer->reset(); + m_state = SIO_WAIT; + m_bytes_count = 0; + m_current_byte = 0; +} + + +/*------------------------------------------------- + calculate the byte parity +-------------------------------------------------*/ + +int pce220_serial_device::calc_parity(UINT8 data) +{ + UINT8 count = 0; + + while(data != 0) + { + count++; + data &= (data-1); + } + + return (count ^ BIT(SIO_PARITY, 1)) & 1; +} + + +/*------------------------------------------------- + returns the next SIO state basing on the + configuration +-------------------------------------------------*/ + +int pce220_serial_device::get_next_state() +{ + switch(m_state) + { + case SIO_SEND_BIT6: + if (SIO_DATA_BIT == 8) + return SIO_SEND_BIT7; + //fall through + case SIO_SEND_BIT7: + return (SIO_PARITY ? SIO_SEND_PARITY : SIO_SEND_STOP1); + case SIO_SEND_STOP1: + case SIO_SEND_STOP2: + return (SIO_STOP_BIT == 2 ? SIO_SEND_STOP2 : SIO_SEND_STOP1); + default: + return m_state + 1; + } +} + |