summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2011-09-02 14:53:41 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2011-09-02 14:53:41 +0000
commitb764156f07218d6ae9701d0ac771b5f96304b482 (patch)
treed5a48461e71bb334af0b3e93406afff0b8d04f25
parentac2ff71b0cb85063fd0c9f0c4ede4178cc3691ee (diff)
- Created device_serial_interface that should be used by UART's (no whatsnew)
- It is used by MESS side i8251 and 6551 are using it now - Also created simple serial source devices (used by some cassette interface) This will be optimized and rechecked after new chips are converted to use it No whatsnew for now, but there will be info for the release.
-rw-r--r--.gitattributes2
-rw-r--r--src/emu/diserial.c387
-rw-r--r--src/emu/diserial.h174
-rw-r--r--src/emu/emu.h1
-rw-r--r--src/emu/emu.mak1
5 files changed, 565 insertions, 0 deletions
diff --git a/.gitattributes b/.gitattributes
index f451f79a5a1..1fcaad0707a 100644
--- a/.gitattributes
+++ b/.gitattributes
@@ -661,6 +661,8 @@ src/emu/dinvram.c svneol=native#text/plain
src/emu/dinvram.h svneol=native#text/plain
src/emu/dirtc.c svneol=native#text/plain
src/emu/dirtc.h svneol=native#text/plain
+src/emu/diserial.c svneol=native#text/plain
+src/emu/diserial.h svneol=native#text/plain
src/emu/dislot.c svneol=native#text/plain
src/emu/dislot.h svneol=native#text/plain
src/emu/disound.c svneol=native#text/plain
diff --git a/src/emu/diserial.c b/src/emu/diserial.c
new file mode 100644
index 00000000000..d24be920b43
--- /dev/null
+++ b/src/emu/diserial.c
@@ -0,0 +1,387 @@
+/***************************************************************************
+
+ Serial device interface
+
+***************************************************************************/
+
+#include "emu.h"
+
+
+/* receive is waiting for start bit. The transition from high-low indicates
+start of start bit. This is used to synchronise with the data being transfered */
+#define RECEIVE_REGISTER_WAITING_FOR_START_BIT 0x01
+/* receive is synchronised with data, data bits will be clocked in */
+#define RECEIVE_REGISTER_SYNCHRONISED 0x02
+/* set if receive register has been filled */
+#define RECEIVE_REGISTER_FULL 0x04
+
+/* register is empty and ready to be filled with data */
+#define TRANSMIT_REGISTER_EMPTY 0x0001
+
+device_serial_interface::device_serial_interface(const machine_config &mconfig, device_t &device)
+ : device_interface(device),
+ m_other_connection(NULL)
+{
+ /* if sum of all bits in the byte is even, then the data
+ has even parity, otherwise it has odd parity */
+ for (int i=0; i<256; i++)
+ {
+ int sum = 0;
+ int data = i;
+
+ for (int b=0; b<8; b++)
+ {
+ sum+=data & 0x01;
+ data = data>>1;
+ }
+
+ m_serial_parity_table[i] = sum & 0x01;
+ }
+}
+
+device_serial_interface::~device_serial_interface()
+{
+}
+
+
+void device_serial_interface::set_data_frame(int num_data_bits, int stop_bit_count, int parity_code)
+{
+ m_df_word_length = num_data_bits;
+ m_df_stop_bit_count = stop_bit_count;
+ m_df_parity = parity_code;
+
+ m_rcv_bit_count = m_df_word_length + m_df_stop_bit_count;
+
+ if (m_df_parity != SERIAL_PARITY_NONE)
+ {
+ m_rcv_bit_count++;
+ }
+}
+
+void device_serial_interface::receive_register_reset()
+{
+ m_rcv_bit_count_received = 0;
+ m_rcv_flags &=~RECEIVE_REGISTER_FULL;
+ m_rcv_flags &=~RECEIVE_REGISTER_SYNCHRONISED;
+ m_rcv_flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT;
+}
+
+/* this is generic code to be used in serial chip implementations */
+/* the majority of serial chips work in the same way and this code will work */
+/* for them */
+
+/* receive a bit */
+void device_serial_interface::receive_register_update_bit(int bit)
+{
+ int previous_bit;
+
+ //LOG(("receive register receive bit: %1x\n",bit));
+ previous_bit = m_rcv_register_data & 1;
+
+ /* shift previous bit 7 out */
+ m_rcv_register_data = m_rcv_register_data<<1;
+ /* shift new bit in */
+ m_rcv_register_data = (m_rcv_register_data & 0xfffe) | bit;
+ /* update bit count received */
+ m_rcv_bit_count_received++;
+
+ /* asyncrhonouse mode */
+ if (m_rcv_flags & RECEIVE_REGISTER_WAITING_FOR_START_BIT)
+ {
+ /* the previous bit is stored in uart.receive char bit 0 */
+ /* has the bit state changed? */
+ if (((previous_bit ^ bit) & 0x01)!=0)
+ {
+ /* yes */
+ if (bit==0)
+ {
+ //logerror("receive register saw start bit\n");
+
+ /* seen start bit! */
+ /* not waiting for start bit now! */
+ m_rcv_flags &=~RECEIVE_REGISTER_WAITING_FOR_START_BIT;
+ m_rcv_flags |=RECEIVE_REGISTER_SYNCHRONISED;
+ /* reset bit count received */
+ m_rcv_bit_count_received = 0;
+ }
+ }
+ }
+ else
+ if (m_rcv_flags & RECEIVE_REGISTER_SYNCHRONISED)
+ {
+ /* received all bits? */
+ if (m_rcv_bit_count_received==m_rcv_bit_count)
+ {
+ m_rcv_bit_count_received = 0;
+ m_rcv_flags &=~RECEIVE_REGISTER_SYNCHRONISED;
+ m_rcv_flags |= RECEIVE_REGISTER_WAITING_FOR_START_BIT;
+ //logerror("receive register full\n");
+ m_rcv_flags |= RECEIVE_REGISTER_FULL;
+ }
+ }
+}
+
+void device_serial_interface::receive_register_extract()
+{
+ unsigned long data_shift;
+ UINT8 data;
+
+ receive_register_reset();
+
+ data_shift = 0;
+
+ /* if parity is even or odd, there should be a parity bit in the stream! */
+ if (m_df_parity!=SERIAL_PARITY_NONE)
+ {
+ data_shift++;
+ }
+
+ data_shift+=m_df_stop_bit_count;
+
+ /* strip off stop bits and parity */
+ data = m_rcv_register_data>>data_shift;
+
+ /* mask off other bits so data byte has 0's in unused bits */
+ data = data & (0x0ff
+ >>
+ (8-(m_df_word_length)));
+
+ m_rcv_byte_received = data;
+
+ /* parity enable? */
+ switch (m_df_parity)
+ {
+ case SERIAL_PARITY_NONE:
+ break;
+
+ /* check parity */
+ case SERIAL_PARITY_ODD:
+ case SERIAL_PARITY_EVEN:
+ {
+ //unsigned char computed_parity;
+ //unsigned char parity_received;
+
+ /* get state of parity bit received */
+ //parity_received = (m_rcv_register_data>>m_df_stop_bit_count) & 0x01;
+
+ /* compute parity for received bits */
+ //computed_parity = serial_helper_get_parity(data);
+
+ if (m_df_parity == SERIAL_PARITY_ODD)
+ {
+ /* odd parity */
+
+
+ }
+ else
+ {
+ /* even parity */
+
+
+ }
+
+ }
+ break;
+ }
+}
+
+
+/***** TRANSMIT REGISTER *****/
+
+void device_serial_interface::transmit_register_reset()
+{
+ m_tra_flags |=TRANSMIT_REGISTER_EMPTY;
+}
+
+/* used to construct data in stream format */
+void device_serial_interface::transmit_register_add_bit(int bit)
+{
+ /* combine bit */
+ m_tra_register_data = m_tra_register_data<<1;
+ m_tra_register_data &=~1;
+ m_tra_register_data|=(bit & 0x01);
+ m_tra_bit_count++;
+}
+
+
+/* generate data in stream format ready for transfer */
+void device_serial_interface::transmit_register_setup(UINT8 data_byte)
+{
+ int i;
+ unsigned char transmit_data;
+
+
+ m_tra_bit_count_transmitted = 0;
+ m_tra_bit_count = 0;
+ m_tra_flags &=~TRANSMIT_REGISTER_EMPTY;
+
+ /* start bit */
+ transmit_register_add_bit(0);
+
+ /* data bits */
+ transmit_data = data_byte;
+ for (i=0; i<m_df_word_length; i++)
+ {
+ int databit;
+
+ /* get bit from data */
+ databit = (transmit_data>>(m_df_word_length-1)) & 0x01;
+ /* add bit to formatted byte */
+ transmit_register_add_bit(databit);
+ transmit_data = transmit_data<<1;
+ }
+
+ /* parity */
+ if (m_df_parity!=SERIAL_PARITY_NONE)
+ {
+ /* odd or even parity */
+ unsigned char parity;
+
+ /* get parity */
+ /* if parity = 0, data has even parity - i.e. there is an even number of one bits in the data */
+ /* if parity = 1, data has odd parity - i.e. there is an odd number of one bits in the data */
+ parity = serial_helper_get_parity(data_byte);
+
+ transmit_register_add_bit(parity);
+ }
+
+ /* stop bit(s) */
+ for (i=0; i<m_df_stop_bit_count; i++)
+ {
+ transmit_register_add_bit(1);
+ }
+}
+
+
+/* get a bit from the transmit register */
+UINT8 device_serial_interface::transmit_register_get_data_bit()
+{
+ int bit;
+
+ bit = (m_tra_register_data>>
+ (m_tra_bit_count - 1 -
+ m_tra_bit_count_transmitted)) & 0x01;
+
+ m_tra_bit_count_transmitted++;
+
+ /* have all bits of this stream formatted byte been sent? */
+ if (m_tra_bit_count_transmitted==m_tra_bit_count)
+ {
+ /* yes - generate a new byte to send */
+ m_tra_flags |= TRANSMIT_REGISTER_EMPTY;
+ }
+
+ return bit;
+}
+
+void device_serial_interface::transmit_register_send_bit()
+{
+ int data;
+
+ data = transmit_register_get_data_bit();
+
+ /* set tx data bit */
+ m_connection_state &=~SERIAL_STATE_TX_DATA;
+ m_connection_state|=(data<<5);
+
+ /* state out through connection */
+ serial_connection_out();
+}
+
+
+
+/* this converts state at this end to a state the other end can accept */
+/* e.g. CTS at this end becomes RTS at other end.
+ RTS at this end becomes CTS at other end.
+ TX at this end becomes RX at other end.
+ RX at this end becomes TX at other end.
+ etc
+
+ The same thing is done inside the serial null-terminal lead */
+
+static UINT8 serial_connection_spin_bits(UINT8 input_status)
+{
+ return
+ /* cts -> rts */
+ (((input_status & 0x01)<<1) |
+ /* rts -> cts */
+ ((input_status>>1) & 0x01) |
+ /* dsr -> dtr */
+ (((input_status>>2) & 0x01)<<3) |
+ /* dtr -> dsr */
+ (((input_status>>3) & 0x01)<<2) |
+ /* rx -> tx */
+ (((input_status>>4) & 0x01)<<5) |
+ /* tx -> rx */
+ (((input_status>>5) & 0x01)<<4));
+}
+
+void device_serial_interface::serial_connection_out()
+{
+
+ if (m_other_connection!=NULL)
+ {
+ UINT8 state_at_other_end = serial_connection_spin_bits(m_connection_state);
+
+ m_other_connection->input_callback(state_at_other_end);
+ }
+}
+
+bool device_serial_interface::is_receive_register_full()
+{
+ return m_rcv_flags & RECEIVE_REGISTER_FULL;
+}
+
+bool device_serial_interface::is_transmit_register_empty()
+{
+ return m_tra_flags & TRANSMIT_REGISTER_EMPTY;
+}
+
+void device_serial_interface::set_callback(device_serial_interface *other_connection)
+{
+ m_other_connection = other_connection;
+}
+
+/* join two serial connections together */
+void device_serial_interface::connect(device_serial_interface *other_connection)
+{
+ /* both connections should have their in connection setup! */
+ /* the in connection is the callback they use to update their state based
+ on the output from the other side */
+ set_callback(other_connection);
+ other_connection->set_callback(this);
+
+ /* let b know the state of a */
+ serial_connection_out();
+ /* let a know the state of b */
+ other_connection->serial_connection_out();
+}
+
+
+
+const device_type SERIAL_SOURCE = &device_creator<serial_source_device>;
+
+//-------------------------------------------------
+// serial_source_device - constructor
+//-------------------------------------------------
+
+serial_source_device::serial_source_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SERIAL_SOURCE, "Serial source", tag, owner, clock),
+ device_serial_interface(mconfig, *this)
+{
+}
+
+void serial_source_device::device_start()
+{
+}
+
+void serial_source_device::input_callback(UINT8 state)
+{
+ m_input_state = state;
+}
+
+void serial_source_device::send_bit(UINT8 data)
+{
+ set_out_data_bit(data);
+ serial_connection_out();
+}
diff --git a/src/emu/diserial.h b/src/emu/diserial.h
new file mode 100644
index 00000000000..fa8b6fc932d
--- /dev/null
+++ b/src/emu/diserial.h
@@ -0,0 +1,174 @@
+#pragma once
+
+#ifndef __EMU_H__
+#error Dont include this file directly; include emu.h instead.
+#endif
+
+#ifndef __DISERIAL_H__
+#define __DISERIAL_H__
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+/* parity selections */
+/* if all the bits are added in a byte, if the result is:
+ even -> parity is even
+ odd -> parity is odd
+*/
+enum
+{
+ SERIAL_PARITY_NONE, /* no parity. a parity bit will not be in the transmitted/received data */
+ SERIAL_PARITY_ODD, /* odd parity */
+ SERIAL_PARITY_EVEN /* even parity */
+};
+
+/*
+ CTS = Clear to Send. (INPUT)
+ Other end of connection is ready to accept data
+
+
+ NOTE:
+
+ This output is active low on serial chips (e.g. 0 is CTS is set),
+ but here it is active high!
+*/
+#define SERIAL_STATE_CTS 0x0001
+
+/*
+ RTS = Request to Send. (OUTPUT)
+ This end is ready to send data, and requests if the other
+ end is ready to accept it
+
+ NOTE:
+
+ This output is active low on serial chips (e.g. 0 is RTS is set),
+ but here it is active high!
+*/
+#define SERIAL_STATE_RTS 0x0002
+
+/*
+ DSR = Data Set ready. (INPUT)
+ Other end of connection has data
+
+
+ NOTE:
+
+ This output is active low on serial chips (e.g. 0 is DSR is set),
+ but here it is active high!
+*/
+#define SERIAL_STATE_DSR 0x0004
+
+/*
+ DTR = Data terminal Ready. (OUTPUT)
+ TX contains new data.
+
+ NOTE:
+
+ This output is active low on serial chips (e.g. 0 is DTR is set),
+ but here it is active high!
+*/
+#define SERIAL_STATE_DTR 0x0008
+/* RX = Recieve data. (INPUT) */
+#define SERIAL_STATE_RX_DATA 0x00010
+/* TX = Transmit data. (OUTPUT) */
+#define SERIAL_STATE_TX_DATA 0x00020
+
+
+// ======================> device_serial_interface
+class device_serial_interface : public device_interface
+{
+public:
+ // construction/destruction
+ device_serial_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_serial_interface();
+
+ virtual void input_callback(UINT8 state) = 0;
+
+ void set_data_frame(int num_data_bits, int stop_bit_count, int parity_code);
+
+ void receive_register_reset();
+ void receive_register_update_bit(int bit);
+ void receive_register_extract();
+
+
+ void transmit_register_reset();
+ void transmit_register_add_bit(int bit);
+ void transmit_register_setup(UINT8 data_byte);
+ UINT8 transmit_register_get_data_bit();
+ void transmit_register_send_bit();
+
+ UINT8 serial_helper_get_parity(UINT8 data) { return m_serial_parity_table[data]; }
+
+ UINT8 get_in_data_bit() { return ((m_input_state & SERIAL_STATE_RX_DATA)>>4) & 1; }
+ void set_out_data_bit(UINT8 data) { m_connection_state &=~SERIAL_STATE_TX_DATA; m_connection_state |=(data<<5); }
+
+ void serial_connection_out();
+
+ bool is_receive_register_full();
+ bool is_transmit_register_empty();
+
+ UINT8 get_received_char() { return m_rcv_byte_received; }
+
+ void set_callback(device_serial_interface *other_connection);
+
+ void connect(device_serial_interface *other_connection);
+protected:
+ UINT8 m_input_state;
+ UINT8 m_connection_state;
+private:
+ UINT8 m_serial_parity_table[256];
+
+ // Data frame
+ // length of word in bits
+ UINT8 m_df_word_length;
+ // parity state
+ UINT8 m_df_parity;
+ // number of stop bits
+ UINT8 m_df_stop_bit_count;
+
+ // Receive register
+ /* data */
+ UINT16 m_rcv_register_data;
+ /* flags */
+ UINT8 m_rcv_flags;
+ /* bit count received */
+ UINT8 m_rcv_bit_count_received;
+ /* length of data to receive - includes data bits, parity bit and stop bit */
+ UINT8 m_rcv_bit_count;
+ /* the byte of data received */
+ UINT8 m_rcv_byte_received;
+
+ // Transmit register
+ /* data */
+ UINT16 m_tra_register_data;
+ /* flags */
+ UINT8 m_tra_flags;
+ /* number of bits transmitted */
+ UINT8 m_tra_bit_count_transmitted;
+ /* length of data to send */
+ UINT8 m_tra_bit_count;
+
+ device_serial_interface *m_other_connection;
+};
+
+
+class serial_source_device : public device_t,
+ public device_serial_interface
+{
+public:
+ // construction/destruction
+ serial_source_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void input_callback(UINT8 state);
+ void send_bit(UINT8 data);
+protected:
+ // device-level overrides
+ virtual void device_start();
+};
+
+extern const device_type SERIAL_SOURCE;
+
+#define MCFG_SERIAL_SOURCE_ADD(_tag) \
+ MCFG_DEVICE_ADD((_tag), SERIAL_SOURCE, 0)
+
+#endif /* __DISERIAL_H__ */
diff --git a/src/emu/emu.h b/src/emu/emu.h
index 80c36b36026..6f3222c4910 100644
--- a/src/emu/emu.h
+++ b/src/emu/emu.h
@@ -92,6 +92,7 @@ typedef device_t * (*machine_config_constructor)(machine_config &config, device_
#include "diexec.h"
#include "opresolv.h"
#include "diimage.h"
+#include "diserial.h"
#include "dislot.h"
#include "disound.h"
#include "dinvram.h"
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index c61202b4e26..37ec4d7858f 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -66,6 +66,7 @@ EMUOBJS = \
$(EMUOBJ)/dimemory.o \
$(EMUOBJ)/dinvram.o \
$(EMUOBJ)/dirtc.o \
+ $(EMUOBJ)/diserial.o \
$(EMUOBJ)/dislot.o \
$(EMUOBJ)/disound.o \
$(EMUOBJ)/distate.o \