summaryrefslogtreecommitdiffstatshomepage
path: root/src
diff options
context:
space:
mode:
author Curt Coder <curtcoder@mail.com>2010-03-08 16:47:53 +0000
committer Curt Coder <curtcoder@mail.com>2010-03-08 16:47:53 +0000
commit5826c45ea48778bd9bf513fef1311a77c447ff8e (patch)
tree728393efdbfd25e840082da59925a8d3b233f20e /src
parentaac8859b8019343c5d43739c9be000d483a1cc5f (diff)
Imported Z80 DART and Z80 STI from MESS. (no whatsnew)
Diffstat (limited to 'src')
-rw-r--r--src/emu/emu.mak2
-rw-r--r--src/emu/machine/z80dart.c1504
-rw-r--r--src/emu/machine/z80dart.h132
-rw-r--r--src/emu/machine/z80sti.c849
-rw-r--r--src/emu/machine/z80sti.h116
5 files changed, 2603 insertions, 0 deletions
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index a330e3cf634..5c0f89efe36 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -179,9 +179,11 @@ EMUMACHINEOBJS = \
$(EMUMACHINE)/x76f041.o \
$(EMUMACHINE)/x76f100.o \
$(EMUMACHINE)/z80ctc.o \
+ $(EMUMACHINE)/z80dart.o \
$(EMUMACHINE)/z80dma.o \
$(EMUMACHINE)/z80pio.o \
$(EMUMACHINE)/z80sio.o \
+ $(EMUMACHINE)/z80sti.o \
EMUVIDEOOBJS = \
$(EMUVIDEO)/generic.o \
diff --git a/src/emu/machine/z80dart.c b/src/emu/machine/z80dart.c
new file mode 100644
index 00000000000..9e9e3c791a5
--- /dev/null
+++ b/src/emu/machine/z80dart.c
@@ -0,0 +1,1504 @@
+/***************************************************************************
+
+ Z80 DART Dual Asynchronous Receiver/Transmitter emulation
+
+ Copyright (c) 2008, The MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/*
+
+ TODO:
+
+ - break detection
+ - wr0 reset tx interrupt pending
+ - wait/ready
+ - 1.5 stop bits
+
+*/
+
+#include "emu.h"
+#include "z80dart.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+enum
+{
+ STATE_START = 0,
+ STATE_DATA,
+ STATE_PARITY,
+ STATE_STOP,
+ STATE_STOP2
+};
+
+enum
+{
+ INT_TRANSMIT = 0,
+ INT_EXTERNAL,
+ INT_RECEIVE,
+ INT_SPECIAL
+};
+
+#define Z80DART_RR0_RX_CHAR_AVAILABLE 0x01
+#define Z80DART_RR0_INTERRUPT_PENDING 0x02
+#define Z80DART_RR0_TX_BUFFER_EMPTY 0x04
+#define Z80DART_RR0_DCD 0x08
+#define Z80DART_RR0_RI 0x10
+#define Z80DART_RR0_CTS 0x20
+#define Z80DART_RR0_BREAK 0x80 /* not supported */
+
+#define Z80DART_RR1_ALL_SENT 0x01
+#define Z80DART_RR1_PARITY_ERROR 0x10
+#define Z80DART_RR1_RX_OVERRUN_ERROR 0x20
+#define Z80DART_RR1_FRAMING_ERROR 0x40
+
+#define Z80DART_WR0_REGISTER_MASK 0x07
+#define Z80DART_WR0_COMMAND_MASK 0x38
+#define Z80DART_WR0_NULL_CODE 0x00
+#define Z80DART_WR0_RESET_EXT_STATUS 0x10
+#define Z80DART_WR0_CHANNEL_RESET 0x18
+#define Z80DART_WR0_ENABLE_INT_NEXT_RX 0x20
+#define Z80DART_WR0_RESET_TX_INT 0x28 /* not supported */
+#define Z80DART_WR0_ERROR_RESET 0x30
+#define Z80DART_WR0_RETURN_FROM_INT 0x38 /* not supported */
+
+#define Z80DART_WR1_EXT_INT_ENABLE 0x01
+#define Z80DART_WR1_TX_INT_ENABLE 0x02
+#define Z80DART_WR1_STATUS_VECTOR 0x04
+#define Z80DART_WR1_RX_INT_ENABLE_MASK 0x18
+#define Z80DART_WR1_RX_INT_DISABLE 0x00
+#define Z80DART_WR1_RX_INT_FIRST 0x08
+#define Z80DART_WR1_RX_INT_ALL_PARITY 0x10 /* not supported */
+#define Z80DART_WR1_RX_INT_ALL 0x18
+#define Z80DART_WR1_WRDY_ON_RX_TX 0x20 /* not supported */
+#define Z80DART_WR1_WRDY_FUNCTION 0x40 /* not supported */
+#define Z80DART_WR1_WRDY_ENABLE 0x80 /* not supported */
+
+#define Z80DART_WR3_RX_ENABLE 0x01
+#define Z80DART_WR3_AUTO_ENABLES 0x20
+#define Z80DART_WR3_RX_WORD_LENGTH_MASK 0xc0
+#define Z80DART_WR3_RX_WORD_LENGTH_5 0x00
+#define Z80DART_WR3_RX_WORD_LENGTH_7 0x40
+#define Z80DART_WR3_RX_WORD_LENGTH_6 0x80
+#define Z80DART_WR3_RX_WORD_LENGTH_8 0xc0
+
+#define Z80DART_WR4_PARITY_ENABLE 0x01 /* not supported */
+#define Z80DART_WR4_PARITY_EVEN 0x02 /* not supported */
+#define Z80DART_WR4_STOP_BITS_MASK 0x0c
+#define Z80DART_WR4_STOP_BITS_1 0x04
+#define Z80DART_WR4_STOP_BITS_1_5 0x08 /* not supported */
+#define Z80DART_WR4_STOP_BITS_2 0x0c
+#define Z80DART_WR4_CLOCK_MODE_MASK 0xc0
+#define Z80DART_WR4_CLOCK_MODE_X1 0x00
+#define Z80DART_WR4_CLOCK_MODE_X16 0x40
+#define Z80DART_WR4_CLOCK_MODE_X32 0x80
+#define Z80DART_WR4_CLOCK_MODE_X64 0xc0
+
+#define Z80DART_WR5_RTS 0x02
+#define Z80DART_WR5_TX_ENABLE 0x08
+#define Z80DART_WR5_SEND_BREAK 0x10
+#define Z80DART_WR5_TX_WORD_LENGTH_MASK 0xc0
+#define Z80DART_WR5_TX_WORD_LENGTH_5 0x00
+#define Z80DART_WR5_TX_WORD_LENGTH_7 0x40
+#define Z80DART_WR5_TX_WORD_LENGTH_6 0x80
+#define Z80DART_WR5_TX_WORD_LENGTH_8 0xc0
+#define Z80DART_WR5_DTR 0x80
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _dart_channel dart_channel;
+struct _dart_channel
+{
+ devcb_resolved_read_line in_rxd_func;
+ devcb_resolved_write_line out_txd_func;
+ devcb_resolved_write_line out_dtr_func;
+ devcb_resolved_write_line out_rts_func;
+ devcb_resolved_write_line out_wrdy_func;
+
+ /* register state */
+ UINT8 rr[3]; /* read register */
+ UINT8 wr[6]; /* write register */
+
+ /* receiver state */
+ UINT8 rx_data_fifo[3]; /* receive data FIFO */
+ UINT8 rx_error_fifo[3]; /* receive error FIFO */
+ UINT8 rx_shift; /* 8-bit receive shift register */
+ UINT8 rx_error; /* current receive error */
+ int rx_fifo; /* receive FIFO pointer */
+
+ int rx_clock; /* receive clock pulse count */
+ int rx_state; /* receive state */
+ int rx_bits; /* bits received */
+ int rx_first; /* first character received */
+ int rx_parity; /* received data parity */
+ int rx_break; /* receive break condition */
+ UINT8 rx_rr0_latch; /* read register 0 latched */
+
+ int ri; /* ring indicator latch */
+ int cts; /* clear to send latch */
+ int dcd; /* data carrier detect latch */
+
+ /* transmitter state */
+ UINT8 tx_data; /* transmit data register */
+ UINT8 tx_shift; /* transmit shift register */
+
+ int tx_clock; /* transmit clock pulse count */
+ int tx_state; /* transmit state */
+ int tx_bits; /* bits transmitted */
+ int tx_parity; /* transmitted data parity */
+
+ int dtr; /* data terminal ready */
+ int rts; /* request to send */
+};
+
+typedef struct _z80dart_t z80dart_t;
+struct _z80dart_t
+{
+ devcb_resolved_write_line out_int_func;
+
+ dart_channel channel[2]; /* channels */
+
+ int int_state[8]; /* interrupt state */
+
+ /* timers */
+ emu_timer *rxca_timer;
+ emu_timer *txca_timer;
+ emu_timer *rxtxcb_timer;
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int z80dart_irq_state(running_device *device);
+static void z80dart_irq_reti(running_device *device);
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE z80dart_t *get_safe_token(running_device *device)
+{
+ assert(device != NULL);
+ assert(device->token != NULL);
+ assert(device->type == Z80DART);
+ return (z80dart_t *)device->token;
+}
+
+INLINE const z80dart_interface *get_interface(running_device *device)
+{
+ assert(device != NULL);
+ assert((device->type == Z80DART));
+ return (const z80dart_interface *) device->baseconfig().static_config;
+}
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+#define RXD \
+ devcb_call_read_line(&ch->in_rxd_func)
+
+#define TXD(_state) \
+ devcb_call_write_line(&ch->out_txd_func, _state)
+
+#define RTS(_state) \
+ devcb_call_write_line(&ch->out_rts_func, _state)
+
+#define DTR(_state) \
+ devcb_call_write_line(&ch->out_dtr_func, _state)
+
+/*-------------------------------------------------
+ check_interrupts - control interrupt line
+-------------------------------------------------*/
+
+static void check_interrupts(running_device *device)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ int state = (z80dart_irq_state(device) & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE;
+
+ devcb_call_write_line(&z80dart->out_int_func, state);
+}
+
+/*-------------------------------------------------
+ take_interrupt - trigger interrupt
+-------------------------------------------------*/
+
+static void take_interrupt(running_device *device, int channel, int level)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+ UINT8 vector = ch->wr[2];
+ int priority = (channel << 2) | level;
+
+ LOG(("Z80DART \"%s\" Channel %c : Interrupt Request %u\n", device->tag.cstr(), 'A' + channel, level));
+
+ if ((channel == Z80DART_CH_B) && (ch->wr[1] & Z80DART_WR1_STATUS_VECTOR))
+ {
+ /* status affects vector */
+ vector = (ch->wr[2] & 0xf1) | (!channel << 3) | (level << 1);
+ }
+
+ /* update vector register */
+ ch->rr[2] = vector;
+
+ /* trigger interrupt */
+ z80dart->int_state[priority] |= Z80_DAISY_INT;
+ z80dart->channel[Z80DART_CH_A].rr[0] |= Z80DART_RR0_INTERRUPT_PENDING;
+
+ /* check for interrupt */
+ check_interrupts(device);
+}
+
+/*-------------------------------------------------
+ get_clock_mode - get clock divisor
+-------------------------------------------------*/
+
+static int get_clock_mode(dart_channel *ch)
+{
+ int clocks = 1;
+
+ switch (ch->wr[4] & Z80DART_WR4_CLOCK_MODE_MASK)
+ {
+ case Z80DART_WR4_CLOCK_MODE_X1: clocks = 1; break;
+ case Z80DART_WR4_CLOCK_MODE_X16: clocks = 16; break;
+ case Z80DART_WR4_CLOCK_MODE_X32: clocks = 32; break;
+ case Z80DART_WR4_CLOCK_MODE_X64: clocks = 64; break;
+ }
+
+ return clocks;
+}
+
+/*-------------------------------------------------
+ get_stop_bits - get number of stop bits
+-------------------------------------------------*/
+
+static float get_stop_bits(dart_channel *ch)
+{
+ float bits = 1;
+
+ switch (ch->wr[4] & Z80DART_WR4_STOP_BITS_MASK)
+ {
+ case Z80DART_WR4_STOP_BITS_1: bits = 1; break;
+ case Z80DART_WR4_STOP_BITS_1_5: bits = 1.5; break;
+ case Z80DART_WR4_STOP_BITS_2: bits = 2; break;
+ }
+
+ return bits;
+}
+
+/*-------------------------------------------------
+ get_rx_word_length - get receive word length
+-------------------------------------------------*/
+
+static int get_rx_word_length(dart_channel *ch)
+{
+ int bits = 5;
+
+ switch (ch->wr[3] & Z80DART_WR3_RX_WORD_LENGTH_MASK)
+ {
+ case Z80DART_WR3_RX_WORD_LENGTH_5: bits = 5; break;
+ case Z80DART_WR3_RX_WORD_LENGTH_6: bits = 6; break;
+ case Z80DART_WR3_RX_WORD_LENGTH_7: bits = 7; break;
+ case Z80DART_WR3_RX_WORD_LENGTH_8: bits = 8; break;
+ }
+
+ return bits;
+}
+
+/*-------------------------------------------------
+ get_rx_word_length - get transmit word length
+-------------------------------------------------*/
+
+static int get_tx_word_length(dart_channel *ch)
+{
+ int bits = 5;
+
+ switch (ch->wr[5] & Z80DART_WR5_TX_WORD_LENGTH_MASK)
+ {
+ case Z80DART_WR5_TX_WORD_LENGTH_5: bits = 5; break;
+ case Z80DART_WR5_TX_WORD_LENGTH_6: bits = 6; break;
+ case Z80DART_WR5_TX_WORD_LENGTH_7: bits = 7; break;
+ case Z80DART_WR5_TX_WORD_LENGTH_8: bits = 8; break;
+ }
+
+ return bits;
+}
+
+/*-------------------------------------------------
+ reset_channel - reset channel status
+-------------------------------------------------*/
+
+static void reset_channel(running_device *device, int channel)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ /* disable receiver */
+ ch->wr[3] &= ~Z80DART_WR3_RX_ENABLE;
+ ch->rx_state = STATE_START;
+
+ /* disable transmitter */
+ ch->wr[5] &= ~Z80DART_WR5_TX_ENABLE;
+ ch->tx_state = STATE_START;
+
+ /* reset external lines */
+ RTS(1);
+ DTR(1);
+
+ if (channel == Z80DART_CH_A)
+ {
+ /* reset interrupt logic */
+ int i;
+
+ for (i = 0; i < 8; i++)
+ {
+ z80dart->int_state[i] = 0;
+ }
+
+ check_interrupts(device);
+ }
+}
+
+/*-------------------------------------------------
+ detect_start_bit - detect start bit
+-------------------------------------------------*/
+
+static int detect_start_bit(dart_channel *ch)
+{
+ if (!(ch->wr[3] & Z80DART_WR3_RX_ENABLE)) return 0;
+
+ return !RXD;
+}
+
+/*-------------------------------------------------
+ shift_data_in - shift in serial data
+-------------------------------------------------*/
+
+static void shift_data_in(dart_channel *ch)
+{
+ if (ch->rx_bits < 8)
+ {
+ int rxd = RXD;
+
+ ch->rx_shift >>= 1;
+ ch->rx_shift = (rxd << 7) | (ch->rx_shift & 0x7f);
+ ch->rx_parity ^= rxd;
+ ch->rx_bits++;
+ }
+}
+
+/*-------------------------------------------------
+ character_completed - check if complete
+ data word has been transferred
+-------------------------------------------------*/
+
+static int character_completed(dart_channel *ch)
+{
+ return ch->rx_bits == get_rx_word_length(ch);
+}
+
+/*-------------------------------------------------
+ detect_parity_error - detect parity error
+-------------------------------------------------*/
+
+static void detect_parity_error(running_device *device, int channel)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ int parity = (ch->wr[1] & Z80DART_WR4_PARITY_EVEN) ? 1 : 0;
+
+ if (RXD != (ch->rx_parity ^ parity))
+ {
+ /* parity error detected */
+ ch->rx_error |= Z80DART_RR1_PARITY_ERROR;
+
+ switch (ch->wr[1] & Z80DART_WR1_RX_INT_ENABLE_MASK)
+ {
+ case Z80DART_WR1_RX_INT_FIRST:
+ if (!ch->rx_first)
+ {
+ take_interrupt(device, channel, INT_SPECIAL);
+ }
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL_PARITY:
+ take_interrupt(device, channel, INT_SPECIAL);
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL:
+ take_interrupt(device, channel, INT_RECEIVE);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+ detect_framing_error - detect framing error
+-------------------------------------------------*/
+
+static void detect_framing_error(running_device *device, int channel)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ if (!RXD)
+ {
+ /* framing error detected */
+ ch->rx_error |= Z80DART_RR1_FRAMING_ERROR;
+
+ switch (ch->wr[1] & Z80DART_WR1_RX_INT_ENABLE_MASK)
+ {
+ case Z80DART_WR1_RX_INT_FIRST:
+ if (!ch->rx_first)
+ {
+ take_interrupt(device, channel, INT_SPECIAL);
+ }
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL_PARITY:
+ case Z80DART_WR1_RX_INT_ALL:
+ take_interrupt(device, channel, INT_SPECIAL);
+ break;
+ }
+ }
+}
+
+/*-------------------------------------------------
+ receive - receive serial data
+-------------------------------------------------*/
+
+static void receive(running_device *device, int channel)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ float stop_bits = get_stop_bits(ch);
+
+ switch (ch->rx_state)
+ {
+ case STATE_START:
+ /* check for start bit */
+ if (detect_start_bit(ch))
+ {
+ /* start bit detected */
+ ch->rx_shift = 0;
+ ch->rx_error = 0;
+ ch->rx_bits = 0;
+ ch->rx_parity = 0;
+
+ /* next bit is a data bit */
+ ch->rx_state = STATE_DATA;
+ }
+ break;
+
+ case STATE_DATA:
+ /* shift bit into shift register */
+ shift_data_in(ch);
+
+ if (character_completed(ch))
+ {
+ /* all data bits received */
+ if (ch->wr[4] & Z80DART_WR4_PARITY_ENABLE)
+ {
+ /* next bit is the parity bit */
+ ch->rx_state = STATE_PARITY;
+ }
+ else
+ {
+ /* next bit is a STOP bit */
+ if (stop_bits == 1)
+ ch->rx_state = STATE_STOP2;
+ else
+ ch->rx_state = STATE_STOP;
+ }
+ }
+ break;
+
+ case STATE_PARITY:
+ /* shift bit into shift register */
+ shift_data_in(ch);
+
+ /* check for parity error */
+ detect_parity_error(device, channel);
+
+ /* next bit is a STOP bit */
+ if (stop_bits == 1)
+ ch->rx_state = STATE_STOP2;
+ else
+ ch->rx_state = STATE_STOP;
+ break;
+
+ case STATE_STOP:
+ /* shift bit into shift register */
+ shift_data_in(ch);
+
+ /* check for framing error */
+ detect_framing_error(device, channel);
+
+ /* next bit is the second STOP bit */
+ ch->rx_state = STATE_STOP2;
+ break;
+
+ case STATE_STOP2:
+ /* shift bit into shift register */
+ shift_data_in(ch);
+
+ /* check for framing error */
+ detect_framing_error(device, channel);
+
+ /* store data into FIFO */
+ z80dart_receive_data(device, channel, ch->rx_shift);
+
+ /* next bit is the START bit */
+ ch->rx_state = STATE_START;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ transmit - transmit serial data
+-------------------------------------------------*/
+
+static void transmit(running_device *device, int channel)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ int word_length = get_tx_word_length(ch);
+ float stop_bits = get_stop_bits(ch);
+
+ switch (ch->tx_state)
+ {
+ case STATE_START:
+ if ((ch->wr[5] & Z80DART_WR5_TX_ENABLE) && !(ch->rr[0] & Z80DART_RR0_TX_BUFFER_EMPTY))
+ {
+ /* transmit start bit */
+ TXD(0);
+
+ ch->tx_bits = 0;
+ ch->tx_shift = ch->tx_data;
+
+ /* empty transmit buffer */
+ ch->rr[0] |= Z80DART_RR0_TX_BUFFER_EMPTY;
+
+ if (ch->wr[1] & Z80DART_WR1_TX_INT_ENABLE)
+ take_interrupt(device, channel, INT_TRANSMIT);
+
+ ch->tx_state = STATE_DATA;
+ }
+ else if (ch->wr[5] & Z80DART_WR5_SEND_BREAK)
+ {
+ /* transmit break */
+ TXD(0);
+ }
+ else
+ {
+ /* transmit marking line */
+ TXD(1);
+ }
+
+ break;
+
+ case STATE_DATA:
+ /* transmit data bit */
+ TXD(BIT(ch->tx_shift, 0));
+
+ /* shift data */
+ ch->tx_shift >>= 1;
+ ch->tx_bits++;
+
+ if (ch->rx_bits == word_length)
+ {
+ if (ch->wr[4] & Z80DART_WR4_PARITY_ENABLE)
+ ch->tx_state = STATE_PARITY;
+ else
+ {
+ if (stop_bits == 1)
+ ch->tx_state = STATE_STOP2;
+ else
+ ch->tx_state = STATE_STOP;
+ }
+ }
+ break;
+
+ case STATE_PARITY:
+ // TODO: calculate parity
+ if (stop_bits == 1)
+ ch->tx_state = STATE_STOP2;
+ else
+ ch->tx_state = STATE_STOP;
+ break;
+
+ case STATE_STOP:
+ /* transmit stop bit */
+ TXD(1);
+
+ ch->tx_state = STATE_STOP2;
+ break;
+
+ case STATE_STOP2:
+ /* transmit stop bit */
+ TXD(1);
+
+ /* if transmit buffer is empty */
+ if (ch->rr[0] & Z80DART_RR0_TX_BUFFER_EMPTY)
+ {
+ /* then all characters have been sent */
+ ch->rr[1] |= Z80DART_RR1_ALL_SENT;
+
+ /* when the RTS bit is reset, the _RTS output goes high after the transmitter empties */
+ if (!ch->rts)
+ RTS(1);
+ }
+
+ ch->tx_state = STATE_START;
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_c_r - read control register
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( z80dart_c_r )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ int channel = offset & 0x01;
+ dart_channel *ch = &z80dart->channel[channel];
+ UINT8 data = 0;
+
+ int reg = ch->wr[0] & Z80DART_WR0_REGISTER_MASK;
+
+ switch (reg)
+ {
+ case 0:
+ case 1:
+ data = ch->rr[reg];
+ break;
+
+ case 2:
+ /* channel B only */
+ if (channel == Z80DART_CH_B)
+ data = ch->rr[reg];
+ break;
+ }
+
+ LOG(("Z80DART \"%s\" Channel %c : Control Register Read '%02x'\n", device->tag.cstr(), 'A' + channel, data));
+
+ return data;
+}
+
+/*-------------------------------------------------
+ z80dart_c_w - write control register
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( z80dart_c_w )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ int channel = offset & 0x01;
+ dart_channel *ch = &z80dart->channel[channel];
+
+ int reg = ch->wr[0] & Z80DART_WR0_REGISTER_MASK;
+
+ LOG(("Z80DART \"%s\" Channel %c : Control Register Write '%02x'\n", device->tag.cstr(), 'A' + channel, data));
+
+ /* write data to selected register */
+ ch->wr[reg] = data;
+
+ if (reg != 0)
+ {
+ /* mask out register index */
+ ch->wr[0] &= ~Z80DART_WR0_REGISTER_MASK;
+ }
+
+ switch (reg)
+ {
+ case 0:
+ switch (data & Z80DART_WR0_COMMAND_MASK)
+ {
+ case Z80DART_WR0_RESET_EXT_STATUS:
+ /* reset external/status interrupt */
+ ch->rr[0] &= ~(Z80DART_RR0_DCD | Z80DART_RR0_RI | Z80DART_RR0_CTS | Z80DART_RR0_BREAK);
+
+ if (!ch->dcd) ch->rr[0] |= Z80DART_RR0_DCD;
+ if (ch->ri) ch->rr[0] |= Z80DART_RR0_RI;
+ if (ch->cts) ch->rr[0] |= Z80DART_RR0_CTS;
+
+ ch->rx_rr0_latch = 0;
+
+ LOG(("Z80DART \"%s\" Channel %c : Reset External/Status Interrupt\n", device->tag.cstr(), 'A' + channel));
+ break;
+
+ case Z80DART_WR0_CHANNEL_RESET:
+ /* channel reset */
+ LOG(("Z80DART \"%s\" Channel %c : Channel Reset\n", device->tag.cstr(), 'A' + channel));
+ reset_channel(device, channel);
+ break;
+
+ case Z80DART_WR0_ENABLE_INT_NEXT_RX:
+ /* enable interrupt on next receive character */
+ LOG(("Z80DART \"%s\" Channel %c : Enable Interrupt on Next Received Character\n", device->tag.cstr(), 'A' + channel));
+ ch->rx_first = 1;
+ break;
+
+ case Z80DART_WR0_RESET_TX_INT:
+ /* reset transmitter interrupt pending */
+ LOG(("Z80DART \"%s\" Channel %c : Reset Transmitter Interrupt Pending\n", device->tag.cstr(), 'A' + channel));
+ break;
+
+ case Z80DART_WR0_ERROR_RESET:
+ /* error reset */
+ LOG(("Z80DART \"%s\" Channel %c : Error Reset\n", device->tag.cstr(), 'A' + channel));
+ ch->rr[1] &= ~(Z80DART_RR1_FRAMING_ERROR | Z80DART_RR1_RX_OVERRUN_ERROR | Z80DART_RR1_PARITY_ERROR);
+ break;
+
+ case Z80DART_WR0_RETURN_FROM_INT:
+ /* return from interrupt */
+ LOG(("Z80DART \"%s\" Channel %c : Return from Interrupt\n", device->tag.cstr(), 'A' + channel));
+ z80dart_irq_reti(device);
+ break;
+ }
+ break;
+
+ case 1:
+ LOG(("Z80DART \"%s\" Channel %c : External Interrupt Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR1_EXT_INT_ENABLE) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Transmit Interrupt Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR1_TX_INT_ENABLE) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Status Affects Vector %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR1_STATUS_VECTOR) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Wait/Ready Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR1_WRDY_ENABLE) ? 1 : 0));
+
+ switch (data & Z80DART_WR1_RX_INT_ENABLE_MASK)
+ {
+ case Z80DART_WR1_RX_INT_DISABLE:
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt Disabled\n", device->tag.cstr(), 'A' + channel));
+ break;
+
+ case Z80DART_WR1_RX_INT_FIRST:
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on First Character\n", device->tag.cstr(), 'A' + channel));
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL_PARITY:
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on All Characters, Parity Affects Vector\n", device->tag.cstr(), 'A' + channel));
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL:
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Interrupt on All Characters\n", device->tag.cstr(), 'A' + channel));
+ break;
+ }
+
+ check_interrupts(device);
+ break;
+
+ case 2:
+ /* interrupt vector */
+ check_interrupts(device);
+ LOG(("Z80DART \"%s\" Channel %c : Interrupt Vector %02x\n", device->tag.cstr(), 'A' + channel, data));
+ break;
+
+ case 3:
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR3_RX_ENABLE) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Auto Enables %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR3_AUTO_ENABLES) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Receiver Bits/Character %u\n", device->tag.cstr(), 'A' + channel, get_rx_word_length(ch)));
+ break;
+
+ case 4:
+ LOG(("Z80DART \"%s\" Channel %c : Parity Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR4_PARITY_ENABLE) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Parity %s\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR4_PARITY_EVEN) ? "Even" : "Odd"));
+ LOG(("Z80DART \"%s\" Channel %c : Stop Bits %f\n", device->tag.cstr(), 'A' + channel, get_stop_bits(ch)));
+ LOG(("Z80DART \"%s\" Channel %c : Clock Mode %uX\n", device->tag.cstr(), 'A' + channel, get_clock_mode(ch)));
+ break;
+
+ case 5:
+ LOG(("Z80DART \"%s\" Channel %c : Transmitter Enable %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR5_TX_ENABLE) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Transmitter Bits/Character %u\n", device->tag.cstr(), 'A' + channel, get_tx_word_length(ch)));
+ LOG(("Z80DART \"%s\" Channel %c : Send Break %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR5_SEND_BREAK) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Request to Send %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR5_RTS) ? 1 : 0));
+ LOG(("Z80DART \"%s\" Channel %c : Data Terminal Ready %u\n", device->tag.cstr(), 'A' + channel, (data & Z80DART_WR5_DTR) ? 1 : 0));
+
+ if (data & Z80DART_WR5_RTS)
+ {
+ /* when the RTS bit is set, the _RTS output goes low */
+ RTS(0);
+
+ ch->rts = 1;
+ }
+ else
+ {
+ /* when the RTS bit is reset, the _RTS output goes high after the transmitter empties */
+ ch->rts = 0;
+ }
+
+ /* data terminal ready output follows the state programmed into the DTR bit*/
+ ch->dtr = (data & Z80DART_WR5_DTR) ? 0 : 1;
+ DTR(ch->dtr);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_d_r - read data register
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( z80dart_d_r )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ int channel = offset & 0x01;
+ dart_channel *ch = &z80dart->channel[channel];
+ UINT8 data = 0;
+
+ if (ch->rx_fifo >= 0)
+ {
+ /* load data from the FIFO */
+ data = ch->rx_data_fifo[ch->rx_fifo];
+
+ /* load error status from the FIFO, retain overrun and parity errors */
+ ch->rr[1] = (ch->rr[1] & (Z80DART_RR1_RX_OVERRUN_ERROR | Z80DART_RR1_PARITY_ERROR)) | ch->rx_error_fifo[ch->rx_fifo];
+
+ /* decrease FIFO pointer */
+ ch->rx_fifo--;
+
+ if (ch->rx_fifo < 0)
+ {
+ /* no more characters available in the FIFO */
+ ch->rr[0] &= ~ Z80DART_RR0_RX_CHAR_AVAILABLE;
+ }
+ }
+
+ LOG(("Z80DART \"%s\" Channel %c : Data Register Read '%02x'\n", device->tag.cstr(), 'A' + channel, data));
+
+ return data;
+}
+
+/*-------------------------------------------------
+ z80dart_d_w - write data register
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( z80dart_d_w )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ int channel = offset & 0x01;
+ dart_channel *ch = &z80dart->channel[channel];
+
+ ch->tx_data = data;
+
+ ch->rr[0] &= ~Z80DART_RR0_TX_BUFFER_EMPTY;
+ ch->rr[1] &= ~Z80DART_RR1_ALL_SENT;
+
+ LOG(("Z80DART \"%s\" Channel %c : Data Register Write '%02x'\n", device->tag.cstr(), 'A' + channel, data));
+}
+
+/*-------------------------------------------------
+ z80dart_receive_data - receive data word
+-------------------------------------------------*/
+
+void z80dart_receive_data(running_device *device, int channel, UINT8 data)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ LOG(("Z80DART \"%s\" Channel %c : Receive Data Byte '%02x'\n", device->tag.cstr(), 'A' + channel, data));
+
+ if (ch->rx_fifo == 2)
+ {
+ /* receive overrun error detected */
+ ch->rx_error |= Z80DART_RR1_RX_OVERRUN_ERROR;
+
+ switch (ch->wr[1] & Z80DART_WR1_RX_INT_ENABLE_MASK)
+ {
+ case Z80DART_WR1_RX_INT_FIRST:
+ if (!ch->rx_first)
+ {
+ take_interrupt(device, channel, INT_SPECIAL);
+ }
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL_PARITY:
+ case Z80DART_WR1_RX_INT_ALL:
+ take_interrupt(device, channel, INT_SPECIAL);
+ break;
+ }
+ }
+ else
+ {
+ ch->rx_fifo++;
+ }
+
+ /* store received character and error status into FIFO */
+ ch->rx_data_fifo[ch->rx_fifo] = data;
+ ch->rx_error_fifo[ch->rx_fifo] = ch->rx_error;
+
+ ch->rr[0] |= Z80DART_RR0_RX_CHAR_AVAILABLE;
+
+ /* receive interrupt */
+ switch (ch->wr[1] & Z80DART_WR1_RX_INT_ENABLE_MASK)
+ {
+ case Z80DART_WR1_RX_INT_FIRST:
+ if (ch->rx_first)
+ {
+ take_interrupt(device, channel, INT_RECEIVE);
+
+ ch->rx_first = 0;
+ }
+ break;
+
+ case Z80DART_WR1_RX_INT_ALL_PARITY:
+ case Z80DART_WR1_RX_INT_ALL:
+ take_interrupt(device, channel, INT_RECEIVE);
+ break;
+ }
+}
+
+/*-------------------------------------------------
+ cts_w - clear to send handler
+-------------------------------------------------*/
+
+static void cts_w(running_device *device, int channel, int state)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ LOG(("Z80DART \"%s\" Channel %c : CTS %u\n", device->tag.cstr(), 'A' + channel, state));
+
+ if (ch->cts != state)
+ {
+ /* enable transmitter if in auto enables mode */
+ if (!state)
+ if (ch->wr[3] & Z80DART_WR3_AUTO_ENABLES)
+ ch->wr[5] |= Z80DART_WR5_TX_ENABLE;
+
+ /* set clear to send */
+ ch->cts = state;
+
+ if (!ch->rx_rr0_latch)
+ {
+ if (!ch->cts)
+ ch->rr[0] |= Z80DART_RR0_CTS;
+ else
+ ch->rr[0] &= ~Z80DART_RR0_CTS;
+
+ /* trigger interrupt */
+ if (ch->wr[1] & Z80DART_WR1_EXT_INT_ENABLE)
+ {
+ /* trigger interrupt */
+ take_interrupt(device, channel, INT_EXTERNAL);
+
+ /* latch read register 0 */
+ ch->rx_rr0_latch = 1;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_ctsa_w - clear to send (channel A)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_ctsa_w )
+{
+ cts_w(device, Z80DART_CH_A, state);
+}
+
+/*-------------------------------------------------
+ z80dart_ctsb_w - clear to send (channel B)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_ctsb_w )
+{
+ cts_w(device, Z80DART_CH_B, state);
+}
+
+/*-------------------------------------------------
+ dcd_w - data carrier detected handler
+-------------------------------------------------*/
+
+static void dcd_w(running_device *device, int channel, int state)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ LOG(("Z80DART \"%s\" Channel %c : DCD %u\n", device->tag.cstr(), 'A' + channel, state));
+
+ if (ch->dcd != state)
+ {
+ /* enable receiver if in auto enables mode */
+ if (!state)
+ if (ch->wr[3] & Z80DART_WR3_AUTO_ENABLES)
+ ch->wr[3] |= Z80DART_WR3_RX_ENABLE;
+
+ /* set data carrier detect */
+ ch->dcd = state;
+
+ if (!ch->rx_rr0_latch)
+ {
+ if (ch->dcd)
+ ch->rr[0] |= Z80DART_RR0_DCD;
+ else
+ ch->rr[0] &= ~Z80DART_RR0_DCD;
+
+ if (ch->wr[1] & Z80DART_WR1_EXT_INT_ENABLE)
+ {
+ /* trigger interrupt */
+ take_interrupt(device, channel, INT_EXTERNAL);
+
+ /* latch read register 0 */
+ ch->rx_rr0_latch = 1;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_dcda_w - data carrier detected
+ (channel A)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_dcda_w )
+{
+ dcd_w(device, Z80DART_CH_A, state);
+}
+
+/*-------------------------------------------------
+ z80dart_dcdb_w - data carrier detected
+ (channel B)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_dcdb_w )
+{
+ dcd_w(device, Z80DART_CH_B, state);
+}
+
+/*-------------------------------------------------
+ ri_w - ring indicator handler
+-------------------------------------------------*/
+
+static void ri_w(running_device *device, int channel, int state)
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[channel];
+
+ LOG(("Z80DART \"%s\" Channel %c : RI %u\n", device->tag.cstr(), 'A' + channel, state));
+
+ if (ch->ri != state)
+ {
+ /* set ring indicator state */
+ ch->ri = state;
+
+ if (!ch->rx_rr0_latch)
+ {
+ if (ch->ri)
+ ch->rr[0] |= Z80DART_RR0_RI;
+ else
+ ch->rr[0] &= ~Z80DART_RR0_RI;
+
+ if (ch->wr[1] & Z80DART_WR1_EXT_INT_ENABLE)
+ {
+ /* trigger interrupt */
+ take_interrupt(device, channel, INT_EXTERNAL);
+
+ /* latch read register 0 */
+ ch->rx_rr0_latch = 1;
+ }
+ }
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_ria_w - ring indicator (channel A)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_ria_w )
+{
+ ri_w(device, Z80DART_CH_A, state);
+}
+
+/*-------------------------------------------------
+ z80dart_rib_w - ring indicator (channel B)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_rib_w )
+{
+ ri_w(device, Z80DART_CH_B, state);
+}
+
+/*-------------------------------------------------
+ z80dart_rxca_w - receive clock (channel A)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_rxca_w )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[Z80DART_CH_A];
+
+ int clocks = get_clock_mode(ch);
+
+ if (!state) return;
+
+ LOG(("Z80DART \"%s\" Channel A : Receiver Clock Pulse\n", device->tag.cstr()));
+
+ ch->rx_clock++;
+
+ if (ch->rx_clock == clocks)
+ {
+ ch->rx_clock = 0;
+
+ /* receive data */
+ receive(device, Z80DART_CH_A);
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_txca_w - transmit clock (channel A)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_txca_w )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[Z80DART_CH_A];
+
+ int clocks = get_clock_mode(ch);
+
+ if (!state) return;
+
+ LOG(("Z80DART \"%s\" Channel A : Transmitter Clock Pulse\n", device->tag.cstr()));
+
+ ch->tx_clock++;
+
+ if (ch->tx_clock == clocks)
+ {
+ ch->tx_clock = 0;
+
+ /* transmit data */
+ transmit(device, Z80DART_CH_A);
+ }
+}
+
+/*-------------------------------------------------
+ z80dart_rxtxcb_w - receive/transmit clock
+ (channel B)
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80dart_rxtxcb_w )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ dart_channel *ch = &z80dart->channel[Z80DART_CH_B];
+
+ int clocks = get_clock_mode(ch);
+
+ if (!state) return;
+
+ LOG(("Z80DART \"%s\" Channel A : Receiver/Transmitter Clock Pulse\n", device->tag.cstr()));
+
+ ch->rx_clock++;
+ ch->tx_clock++;
+
+ if (ch->rx_clock == clocks)
+ {
+ ch->rx_clock = 0;
+ ch->tx_clock = 0;
+
+ /* receive and transmit data */
+ receive(device, Z80DART_CH_B);
+ transmit(device, Z80DART_CH_B);
+ }
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( rxca_tick )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( rxca_tick )
+{
+ z80dart_rxca_w((running_device *)ptr, 1);
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( txca_tick )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( txca_tick )
+{
+ z80dart_txca_w((running_device *)ptr, 1);
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( rxtxcb_tick )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( rxtxcb_tick )
+{
+ z80dart_rxtxcb_w((running_device *)ptr, 1);
+}
+
+/*-------------------------------------------------
+ z80dart_irq_state - get interrupt status
+-------------------------------------------------*/
+
+static int z80dart_irq_state(running_device *device)
+{
+ z80dart_t *z80dart = get_safe_token( device );
+ int state = 0;
+ int i;
+
+ LOG(("Z80DART \"%s\" : Interrupt State B:%d%d%d%d A:%d%d%d%d\n", device->tag.cstr(),
+ z80dart->int_state[0], z80dart->int_state[1], z80dart->int_state[2], z80dart->int_state[3],
+ z80dart->int_state[4], z80dart->int_state[5], z80dart->int_state[6], z80dart->int_state[7]));
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ /* if we're servicing a request, don't indicate more interrupts */
+ if (z80dart->int_state[i] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+ state |= z80dart->int_state[i];
+ }
+
+ LOG(("Z80DART \"%s\" : Interrupt State %u\n", device->tag.cstr(), state));
+
+ return state;
+}
+
+/*-------------------------------------------------
+ z80dart_irq_ack - interrupt acknowledge
+-------------------------------------------------*/
+
+static int z80dart_irq_ack(running_device *device)
+{
+ z80dart_t *z80dart = get_safe_token( device );
+ int i;
+
+ LOG(("Z80DART \"%s\" Interrupt Acknowledge\n", device->tag.cstr()));
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ /* find the first channel with an interrupt requested */
+ if (z80dart->int_state[i] & Z80_DAISY_INT)
+ {
+ /* clear interrupt, switch to the IEO state, and update the IRQs */
+ z80dart->int_state[i] = Z80_DAISY_IEO;
+ z80dart->channel[Z80DART_CH_A].rr[0] &= ~Z80DART_RR0_INTERRUPT_PENDING;
+ check_interrupts(device);
+
+ LOG(("Z80DART \"%s\" : Interrupt Acknowledge Vector %02x\n", device->tag.cstr(), z80dart->channel[Z80DART_CH_B].rr[2]));
+
+ return z80dart->channel[Z80DART_CH_B].rr[2];
+ }
+ }
+
+ logerror("z80dart_irq_ack: failed to find an interrupt to ack!\n");
+
+ return z80dart->channel[Z80DART_CH_B].rr[2];
+}
+
+/*-------------------------------------------------
+ z80dart_irq_reti - return from interrupt
+-------------------------------------------------*/
+
+static void z80dart_irq_reti(running_device *device)
+{
+ z80dart_t *z80dart = get_safe_token( device );
+ int i;
+
+ LOG(("Z80DART \"%s\" Return from Interrupt\n", device->tag.cstr()));
+
+ /* loop over all interrupt sources */
+ for (i = 0; i < 8; i++)
+ {
+ /* find the first channel with an IEO pending */
+ if (z80dart->int_state[i] & Z80_DAISY_IEO)
+ {
+ /* clear the IEO state and update the IRQs */
+ z80dart->int_state[i] &= ~Z80_DAISY_IEO;
+ check_interrupts(device);
+ return;
+ }
+ }
+
+ logerror("z80dart_irq_reti: failed to find an interrupt to clear IEO on!\n");
+}
+
+/*-------------------------------------------------
+ z80dart_cd_ba_r - register read
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( z80dart_cd_ba_r )
+{
+ return (offset & 2) ? z80dart_c_r(device, offset & 1) : z80dart_d_r(device, offset & 1);
+}
+
+/*-------------------------------------------------
+ z80dart_cd_ba_w - register write
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( z80dart_cd_ba_w )
+{
+ if (offset & 2)
+ z80dart_c_w(device, offset & 1, data);
+ else
+ z80dart_d_w(device, offset & 1, data);
+}
+
+/*-------------------------------------------------
+ z80dart_ba_cd_r - register read
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( z80dart_ba_cd_r )
+{
+ int channel = BIT(offset, 1);
+
+ return (offset & 1) ? z80dart_c_r(device, channel) : z80dart_d_r(device, channel);
+}
+
+/*-------------------------------------------------
+ z80dart_ba_cd_w - register write
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( z80dart_ba_cd_w )
+{
+ int channel = BIT(offset, 1);
+
+ if (offset & 1)
+ z80dart_c_w(device, channel, data);
+ else
+ z80dart_d_w(device, channel, data);
+}
+
+/*-------------------------------------------------
+ DEVICE_START( z80dart )
+-------------------------------------------------*/
+
+static DEVICE_START( z80dart )
+{
+ z80dart_t *z80dart = get_safe_token(device);
+ const z80dart_interface *intf = (const z80dart_interface *)device->baseconfig().static_config;
+ int channel;
+
+ /* resolve callbacks */
+ devcb_resolve_read_line(&z80dart->channel[Z80DART_CH_A].in_rxd_func, &intf->in_rxda_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_A].out_txd_func, &intf->out_txda_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_A].out_dtr_func, &intf->out_dtra_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_A].out_rts_func, &intf->out_rtsa_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_A].out_wrdy_func, &intf->out_wrdya_func, device);
+ devcb_resolve_read_line(&z80dart->channel[Z80DART_CH_B].in_rxd_func, &intf->in_rxdb_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_B].out_txd_func, &intf->out_txdb_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_B].out_dtr_func, &intf->out_dtrb_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_B].out_rts_func, &intf->out_rtsb_func, device);
+ devcb_resolve_write_line(&z80dart->channel[Z80DART_CH_B].out_wrdy_func, &intf->out_wrdyb_func, device);
+ devcb_resolve_write_line(&z80dart->out_int_func, &intf->out_int_func, device);
+
+ if (intf->rx_clock_a)
+ {
+ /* allocate channel A receive timer */
+ z80dart->rxca_timer = timer_alloc(device->machine, rxca_tick, (void *)device);
+ timer_adjust_periodic(z80dart->rxca_timer, attotime_zero, 0, ATTOTIME_IN_HZ(intf->rx_clock_a));
+ }
+
+ if (intf->tx_clock_a)
+ {
+ /* allocate channel A transmit timer */
+ z80dart->txca_timer = timer_alloc(device->machine, txca_tick, (void *)device);
+ timer_adjust_periodic(z80dart->txca_timer, attotime_zero, 0, ATTOTIME_IN_HZ(intf->tx_clock_a));
+ }
+
+ if (intf->rx_tx_clock_b)
+ {
+ /* allocate channel B receive/transmit timer */
+ z80dart->rxtxcb_timer = timer_alloc(device->machine, rxtxcb_tick, (void *)device);
+ timer_adjust_periodic(z80dart->rxtxcb_timer, attotime_zero, 0, ATTOTIME_IN_HZ(intf->rx_tx_clock_b));
+ }
+
+ /* register for state saving */
+ for (channel = Z80DART_CH_A; channel <= Z80DART_CH_B; channel++)
+ {
+ state_save_register_device_item_array(device, channel, z80dart->channel[channel].rr);
+ state_save_register_device_item_array(device, channel, z80dart->channel[channel].wr);
+ state_save_register_device_item_array(device, channel, z80dart->channel[channel].rx_data_fifo);
+ state_save_register_device_item_array(device, channel, z80dart->channel[channel].rx_error_fifo);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_shift);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_error);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_fifo);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_clock);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_state);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_bits);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_first);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_parity);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_break);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rx_rr0_latch);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].ri);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].cts);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].dcd);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_data);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_shift);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_clock);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_state);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_bits);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].tx_parity);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].dtr);
+ state_save_register_device_item(device, channel, z80dart->channel[channel].rts);
+ }
+
+ state_save_register_device_item_array(device, 0, z80dart->int_state);
+}
+
+/*-------------------------------------------------
+ DEVICE_RESET( z80dart )
+-------------------------------------------------*/
+
+static DEVICE_RESET( z80dart )
+{
+ int channel;
+
+ LOG(("Z80DART \"%s\" Reset\n", device->tag.cstr()));
+
+ for (channel = Z80DART_CH_A; channel <= Z80DART_CH_B; channel++)
+ {
+ reset_channel(device, channel);
+ }
+
+ check_interrupts(device);
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( z80dart )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( z80dart )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(z80dart_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(z80dart); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(z80dart); break;
+ case DEVINFO_FCT_IRQ_STATE: info->f = (genf *)z80dart_irq_state; break;
+ case DEVINFO_FCT_IRQ_ACK: info->f = (genf *)z80dart_irq_ack; break;
+ case DEVINFO_FCT_IRQ_RETI: info->f = (genf *)z80dart_irq_reti; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Zilog Z80 DART"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Z80"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
diff --git a/src/emu/machine/z80dart.h b/src/emu/machine/z80dart.h
new file mode 100644
index 00000000000..c6da23f6d6f
--- /dev/null
+++ b/src/emu/machine/z80dart.h
@@ -0,0 +1,132 @@
+/***************************************************************************
+
+ Z80 DART Dual Asynchronous Receiver/Transmitter implementation
+
+ Copyright (c) 2008, The MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+****************************************************************************
+ _____ _____
+ D1 1 |* \_/ | 40 D0
+ D3 2 | | 39 D2
+ D5 3 | | 38 D4
+ D7 4 | | 37 D6
+ _INT 5 | | 36 _IORQ
+ IEI 6 | | 35 _CE
+ IEO 7 | | 34 B/_A
+ _M1 8 | | 33 C/_D
+ Vdd 9 | | 32 _RD
+ _W/RDYA 10 | Z80-DART | 31 GND
+ _RIA 11 | | 30 _W/RDYB
+ RxDA 12 | | 29 _RIB
+ _RxCA 13 | | 28 RxDB
+ _TxCA 14 | | 27 _RxTxCB
+ TxDA 15 | | 26 TxDB
+ _DTRA 16 | | 25 _DTRB
+ _RTSA 17 | | 24 _RTSB
+ _CTSA 18 | | 23 _CTSB
+ _DCDA 19 | | 22 _DCDB
+ CLK 20 |_____________| 21 _RESET
+
+***************************************************************************/
+
+#ifndef __Z80DART_H_
+#define __Z80DART_H_
+
+#include "devcb.h"
+
+/***************************************************************************
+ MACROS / CONSTANTS
+***************************************************************************/
+
+#define Z80DART DEVICE_GET_INFO_NAME(z80dart)
+/*
+#define Z8470 DEVICE_GET_INFO_NAME(z8470)
+#define LH0081 DEVICE_GET_INFO_NAME(lh0088)
+#define MK3881 DEVICE_GET_INFO_NAME(mk3888)
+*/
+
+#define MDRV_Z80DART_ADD(_tag, _clock, _config) \
+ MDRV_DEVICE_ADD(_tag, Z80DART, _clock) \
+ MDRV_DEVICE_CONFIG(_config)
+
+#define MDRV_Z80DART_REMOVE(_tag) \
+ MDRV_DEVICE_REMOVE(_tag)
+
+#define Z80DART_INTERFACE(_name) \
+ const z80dart_interface (_name) =
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+enum
+{
+ Z80DART_CH_A = 0,
+ Z80DART_CH_B
+};
+
+typedef struct _z80dart_interface z80dart_interface;
+struct _z80dart_interface
+{
+ int rx_clock_a; /* channel A receive clock */
+ int tx_clock_a; /* channel A transmit clock */
+ int rx_tx_clock_b; /* channel B receive/transmit clock */
+
+ devcb_read_line in_rxda_func;
+ devcb_write_line out_txda_func;
+ devcb_write_line out_dtra_func;
+ devcb_write_line out_rtsa_func;
+ devcb_write_line out_wrdya_func;
+
+ devcb_read_line in_rxdb_func;
+ devcb_write_line out_txdb_func;
+ devcb_write_line out_dtrb_func;
+ devcb_write_line out_rtsb_func;
+ devcb_write_line out_wrdyb_func;
+
+ devcb_write_line out_int_func;
+};
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* register access */
+READ8_DEVICE_HANDLER( z80dart_cd_ba_r );
+WRITE8_DEVICE_HANDLER( z80dart_cd_ba_w );
+
+READ8_DEVICE_HANDLER( z80dart_ba_cd_r );
+WRITE8_DEVICE_HANDLER( z80dart_ba_cd_w );
+
+/* control register access */
+WRITE8_DEVICE_HANDLER( z80dart_c_w );
+READ8_DEVICE_HANDLER( z80dart_c_r );
+
+/* data register access */
+WRITE8_DEVICE_HANDLER( z80dart_d_w );
+READ8_DEVICE_HANDLER( z80dart_d_r );
+
+/* serial clocks */
+WRITE_LINE_DEVICE_HANDLER( z80dart_rxca_w );
+WRITE_LINE_DEVICE_HANDLER( z80dart_txca_w );
+WRITE_LINE_DEVICE_HANDLER( z80dart_rxtxcb_w );
+
+/* ring indicator */
+WRITE_LINE_DEVICE_HANDLER( z80dart_ria_w );
+WRITE_LINE_DEVICE_HANDLER( z80dart_rib_w );
+
+/* data carrier detected */
+WRITE_LINE_DEVICE_HANDLER( z80dart_dcda_w );
+WRITE_LINE_DEVICE_HANDLER( z80dart_dcdb_w );
+
+/* clear to send */
+WRITE_LINE_DEVICE_HANDLER( z80dart_ctsa_w );
+WRITE_LINE_DEVICE_HANDLER( z80dart_ctsb_w );
+
+/* receive data byte HACK */
+void z80dart_receive_data(running_device *device, int channel, UINT8 data);
+
+DEVICE_GET_INFO( z80dart );
+
+#endif
diff --git a/src/emu/machine/z80sti.c b/src/emu/machine/z80sti.c
new file mode 100644
index 00000000000..2738ec8a1e9
--- /dev/null
+++ b/src/emu/machine/z80sti.c
@@ -0,0 +1,849 @@
+/***************************************************************************
+
+ Mostek MK3801 Serial Timer Interrupt Controller (Z80-STI) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+***************************************************************************/
+
+/*
+
+ TODO:
+
+ - timers (other than delay mode)
+ - serial I/O
+ - reset behavior
+
+*/
+
+#include "emu.h"
+#include "z80sti.h"
+#include "cpu/z80/z80.h"
+#include "cpu/z80/z80daisy.h"
+
+/***************************************************************************
+ PARAMETERS
+***************************************************************************/
+
+#define VERBOSE 0
+
+#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
+
+/* registers */
+enum
+{
+ Z80STI_REGISTER_IR = 0,
+ Z80STI_REGISTER_GPIP,
+ Z80STI_REGISTER_IPRB,
+ Z80STI_REGISTER_IPRA,
+ Z80STI_REGISTER_ISRB,
+ Z80STI_REGISTER_ISRA,
+ Z80STI_REGISTER_IMRB,
+ Z80STI_REGISTER_IMRA,
+ Z80STI_REGISTER_PVR,
+ Z80STI_REGISTER_TABC,
+ Z80STI_REGISTER_TBDR,
+ Z80STI_REGISTER_TADR,
+ Z80STI_REGISTER_UCR,
+ Z80STI_REGISTER_RSR,
+ Z80STI_REGISTER_TSR,
+ Z80STI_REGISTER_UDR
+};
+
+/* variable registers */
+enum
+{
+ Z80STI_REGISTER_IR_SCR = 0,
+ Z80STI_REGISTER_IR_TDDR,
+ Z80STI_REGISTER_IR_TCDR,
+ Z80STI_REGISTER_IR_AER,
+ Z80STI_REGISTER_IR_IERB,
+ Z80STI_REGISTER_IR_IERA,
+ Z80STI_REGISTER_IR_DDR,
+ Z80STI_REGISTER_IR_TCDC
+};
+
+/* timers */
+enum
+{
+ TIMER_A = 0,
+ TIMER_B,
+ TIMER_C,
+ TIMER_D,
+ TIMER_COUNT
+};
+
+/* interrupt levels */
+enum
+{
+ Z80STI_IR_P0 = 0,
+ Z80STI_IR_P1,
+ Z80STI_IR_P2,
+ Z80STI_IR_P3,
+ Z80STI_IR_TD,
+ Z80STI_IR_TC,
+ Z80STI_IR_P4,
+ Z80STI_IR_P5,
+ Z80STI_IR_TB,
+ Z80STI_IR_XE,
+ Z80STI_IR_XB,
+ Z80STI_IR_RE,
+ Z80STI_IR_RB,
+ Z80STI_IR_TA,
+ Z80STI_IR_P6,
+ Z80STI_IR_P7
+};
+
+/* timer C/D control register */
+#define Z80STI_TCDC_TARS 0x80
+#define Z80STI_TCDC_TBRS 0x08
+
+/* interrupt vector register */
+#define Z80STI_PVR_ISE 0x08
+#define Z80STI_PVR_VR4 0x10
+
+/* general purpose I/O interrupt levels */
+static const int INT_LEVEL_GPIP[] =
+{
+ Z80STI_IR_P0, Z80STI_IR_P1, Z80STI_IR_P2, Z80STI_IR_P3, Z80STI_IR_P4, Z80STI_IR_P5, Z80STI_IR_P6, Z80STI_IR_P7
+};
+
+/* timer interrupt levels */
+static const int INT_LEVEL_TIMER[] =
+{
+ Z80STI_IR_TA, Z80STI_IR_TB, Z80STI_IR_TC, Z80STI_IR_TD
+};
+
+/* interrupt vectors */
+static const UINT8 INT_VECTOR[] =
+{
+ 0x00, 0x02, 0x04, 0x06, 0x08, 0x0a, 0x0c, 0x0e,
+ 0x10, 0x12, 0x14, 0x16, 0x18, 0x1a, 0x1c, 0x1e
+};
+
+/* timer prescaler divisors */
+static const int PRESCALER[] = { 0, 4, 10, 16, 50, 64, 100, 200 };
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _z80sti_t z80sti_t;
+struct _z80sti_t
+{
+ /* device callbacks */
+ devcb_resolved_read8 in_gpio_func;
+ devcb_resolved_write8 out_gpio_func;
+ devcb_resolved_read_line in_si_func;
+ devcb_resolved_write_line out_so_func;
+ devcb_resolved_write_line out_tao_func;
+ devcb_resolved_write_line out_tbo_func;
+ devcb_resolved_write_line out_tco_func;
+ devcb_resolved_write_line out_tdo_func;
+ devcb_resolved_write_line out_int_func;
+
+ /* I/O state */
+ UINT8 gpip; /* general purpose I/O register */
+ UINT8 aer; /* active edge register */
+ UINT8 ddr; /* data direction register */
+
+ /* interrupt state */
+ UINT16 ier; /* interrupt enable register */
+ UINT16 ipr; /* interrupt pending register */
+ UINT16 isr; /* interrupt in-service register */
+ UINT16 imr; /* interrupt mask register */
+ UINT8 pvr; /* interrupt vector register */
+ int int_state[16]; /* interrupt state */
+
+ /* timer state */
+ UINT8 tabc; /* timer A/B control register */
+ UINT8 tcdc; /* timer C/D control register */
+ UINT8 tdr[TIMER_COUNT]; /* timer data registers */
+ UINT8 tmc[TIMER_COUNT]; /* timer main counters */
+ int to[TIMER_COUNT]; /* timer out latch */
+
+ /* serial state */
+ UINT8 scr; /* synchronous character register */
+ UINT8 ucr; /* USART control register */
+ UINT8 tsr; /* transmitter status register */
+ UINT8 rsr; /* receiver status register */
+ UINT8 udr; /* USART data register */
+
+ /* timers */
+ emu_timer *timer[TIMER_COUNT]; /* counter timers */
+ emu_timer *rx_timer; /* serial receive timer */
+ emu_timer *tx_timer; /* serial transmit timer */
+};
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+***************************************************************************/
+
+static int z80sti_irq_state(running_device *device);
+static void z80sti_irq_reti(running_device *device);
+
+/***************************************************************************
+ INLINE FUNCTIONS
+***************************************************************************/
+
+INLINE z80sti_t *get_safe_token(running_device *device)
+{
+ assert(device != NULL);
+ assert(device->token != NULL);
+ assert(device->type == Z80STI);
+ return (z80sti_t *)device->token;
+}
+
+INLINE const z80sti_interface *get_interface(running_device *device)
+{
+ assert(device != NULL);
+ assert((device->type == Z80STI));
+ return (const z80sti_interface *) device->baseconfig().static_config;
+}
+
+/***************************************************************************
+ IMPLEMENTATION
+***************************************************************************/
+
+/*-------------------------------------------------
+ check_interrupts - set the interrupt request
+ line state
+-------------------------------------------------*/
+
+static void check_interrupts(z80sti_t *z80sti)
+{
+ if (z80sti->ipr & z80sti->imr)
+ {
+ devcb_call_write_line(&z80sti->out_int_func, ASSERT_LINE);
+ }
+ else
+ {
+ devcb_call_write_line(&z80sti->out_int_func, CLEAR_LINE);
+ }
+}
+
+/*-------------------------------------------------
+ take_interrupt - mark an interrupt pending
+-------------------------------------------------*/
+
+static void take_interrupt(z80sti_t *z80sti, int level)
+{
+ /* set interrupt pending register bit */
+ z80sti->ipr |= 1 << level;
+
+ /* trigger interrupt */
+ z80sti->int_state[level] |= Z80_DAISY_INT;
+
+ check_interrupts(z80sti);
+}
+
+/*-------------------------------------------------
+ serial_receive - receive serial bit
+-------------------------------------------------*/
+
+static void serial_receive(z80sti_t *z80sti)
+{
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( rx_tick )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( rx_tick )
+{
+ running_device *device = (running_device *)ptr;
+ z80sti_t *z80sti = get_safe_token(device);
+
+ serial_receive(z80sti);
+}
+
+/*-------------------------------------------------
+ serial_transmit - transmit serial bit
+-------------------------------------------------*/
+
+static void serial_transmit(z80sti_t *z80sti)
+{
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( tx_tick )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( tx_tick )
+{
+ running_device *device = (running_device *)ptr;
+ z80sti_t *z80sti = get_safe_token(device);
+
+ serial_transmit(z80sti);
+}
+
+/*-------------------------------------------------
+ z80sti_r - register read
+-------------------------------------------------*/
+
+READ8_DEVICE_HANDLER( z80sti_r )
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ switch (offset & 0x0f)
+ {
+ case Z80STI_REGISTER_IR:
+ switch (z80sti->pvr & 0x07)
+ {
+ case Z80STI_REGISTER_IR_SCR: return z80sti->scr;
+ case Z80STI_REGISTER_IR_TDDR: return z80sti->tmc[TIMER_D];
+ case Z80STI_REGISTER_IR_TCDR: return z80sti->tmc[TIMER_C];
+ case Z80STI_REGISTER_IR_AER: return z80sti->aer;
+ case Z80STI_REGISTER_IR_IERB: return z80sti->ier & 0xff;
+ case Z80STI_REGISTER_IR_IERA: return z80sti->ier >> 8;
+ case Z80STI_REGISTER_IR_DDR: return z80sti->ddr;
+ case Z80STI_REGISTER_IR_TCDC: return z80sti->tcdc;
+ }
+ break;
+
+ case Z80STI_REGISTER_GPIP: z80sti->gpip = (devcb_call_read8(&z80sti->in_gpio_func, 0) & ~z80sti->ddr) | (z80sti->gpip & z80sti->ddr); return z80sti->gpip;
+ case Z80STI_REGISTER_IPRB: return z80sti->ipr & 0xff;
+ case Z80STI_REGISTER_IPRA: return z80sti->ipr >> 8;
+ case Z80STI_REGISTER_ISRB: return z80sti->isr & 0xff;
+ case Z80STI_REGISTER_ISRA: return z80sti->isr >> 8;
+ case Z80STI_REGISTER_IMRB: return z80sti->imr & 0xff;
+ case Z80STI_REGISTER_IMRA: return z80sti->imr >> 8;
+ case Z80STI_REGISTER_PVR: return z80sti->pvr;
+ case Z80STI_REGISTER_TABC: return z80sti->tabc;
+ case Z80STI_REGISTER_TBDR: return z80sti->tmc[TIMER_B];
+ case Z80STI_REGISTER_TADR: return z80sti->tmc[TIMER_A];
+ case Z80STI_REGISTER_UCR: return z80sti->ucr;
+ case Z80STI_REGISTER_RSR: return z80sti->rsr;
+ case Z80STI_REGISTER_TSR: return z80sti->tsr;
+ case Z80STI_REGISTER_UDR: return z80sti->udr;
+ }
+
+ return 0;
+}
+
+/*-------------------------------------------------
+ z80sti_w - register write
+-------------------------------------------------*/
+
+WRITE8_DEVICE_HANDLER( z80sti_w )
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ switch (offset & 0x0f)
+ {
+ case Z80STI_REGISTER_IR:
+ switch (z80sti->pvr & 0x07)
+ {
+ case Z80STI_REGISTER_IR_SCR:
+ LOG(("Z80STI '%s' Sync Character Register: %x\n", device->tag.cstr(), data));
+ z80sti->scr = data;
+ break;
+
+ case Z80STI_REGISTER_IR_TDDR:
+ LOG(("Z80STI '%s' Timer D Data Register: %x\n", device->tag.cstr(), data));
+ z80sti->tdr[TIMER_D] = data;
+ break;
+
+ case Z80STI_REGISTER_IR_TCDR:
+ LOG(("Z80STI '%s' Timer C Data Register: %x\n", device->tag.cstr(), data));
+ z80sti->tdr[TIMER_C] = data;
+ break;
+
+ case Z80STI_REGISTER_IR_AER:
+ LOG(("Z80STI '%s' Active Edge Register: %x\n", device->tag.cstr(), data));
+ z80sti->aer = data;
+ break;
+
+ case Z80STI_REGISTER_IR_IERB:
+ LOG(("Z80STI '%s' Interrupt Enable Register B: %x\n", device->tag.cstr(), data));
+ z80sti->ier = (z80sti->ier & 0xff00) | data;
+ check_interrupts(z80sti);
+ break;
+
+ case Z80STI_REGISTER_IR_IERA:
+ LOG(("Z80STI '%s' Interrupt Enable Register A: %x\n", device->tag.cstr(), data));
+ z80sti->ier = (data << 8) | (z80sti->ier & 0xff);
+ check_interrupts(z80sti);
+ break;
+
+ case Z80STI_REGISTER_IR_DDR:
+ LOG(("Z80STI '%s' Data Direction Register: %x\n", device->tag.cstr(), data));
+ z80sti->ddr = data;
+ break;
+
+ case Z80STI_REGISTER_IR_TCDC:
+ {
+ int tcc = PRESCALER[(data >> 4) & 0x07];
+ int tdc = PRESCALER[data & 0x07];
+
+ z80sti->tcdc = data;
+
+ LOG(("Z80STI '%s' Timer C Prescaler: %u\n", device->tag.cstr(), tcc));
+ LOG(("Z80STI '%s' Timer D Prescaler: %u\n", device->tag.cstr(), tdc));
+
+ if (tcc)
+ timer_adjust_periodic(z80sti->timer[TIMER_C], ATTOTIME_IN_HZ(device->clock / tcc), 0, ATTOTIME_IN_HZ(device->clock / tcc));
+ else
+ timer_enable(z80sti->timer[TIMER_C], 0);
+
+ if (tdc)
+ timer_adjust_periodic(z80sti->timer[TIMER_D], ATTOTIME_IN_HZ(device->clock / tdc), 0, ATTOTIME_IN_HZ(device->clock / tdc));
+ else
+ timer_enable(z80sti->timer[TIMER_D], 0);
+
+ if (BIT(data, 7))
+ {
+ LOG(("Z80STI '%s' Timer A Reset\n", device->tag.cstr()));
+ z80sti->to[TIMER_A] = 0;
+
+ devcb_call_write_line(&z80sti->out_tao_func, z80sti->to[TIMER_A]);
+ }
+
+ if (BIT(data, 3))
+ {
+ LOG(("Z80STI '%s' Timer B Reset\n", device->tag.cstr()));
+ z80sti->to[TIMER_B] = 0;
+
+ devcb_call_write_line(&z80sti->out_tbo_func, z80sti->to[TIMER_B]);
+ }
+ }
+ break;
+ }
+ break;
+
+ case Z80STI_REGISTER_GPIP:
+ LOG(("Z80STI '%s' General Purpose I/O Register: %x\n", device->tag.cstr(), data));
+ z80sti->gpip = data & z80sti->ddr;
+ devcb_call_write8(&z80sti->out_gpio_func, 0, z80sti->gpip);
+ break;
+
+ case Z80STI_REGISTER_IPRB:
+ {
+ int i;
+ LOG(("Z80STI '%s' Interrupt Pending Register B: %x\n", device->tag.cstr(), data));
+ z80sti->ipr &= (z80sti->ipr & 0xff00) | data;
+
+ for (i = 0; i < 16; i++)
+ {
+ if (!BIT(z80sti->ipr, i) && (z80sti->int_state[i] == Z80_DAISY_INT)) z80sti->int_state[i] = 0;
+ }
+
+ check_interrupts(z80sti);
+ }
+ break;
+
+ case Z80STI_REGISTER_IPRA:
+ {
+ int i;
+ LOG(("Z80STI '%s' Interrupt Pending Register A: %x\n", device->tag.cstr(), data));
+ z80sti->ipr &= (data << 8) | (z80sti->ipr & 0xff);
+
+ for (i = 0; i < 16; i++)
+ {
+ if (!BIT(z80sti->ipr, i) && (z80sti->int_state[i] == Z80_DAISY_INT)) z80sti->int_state[i] = 0;
+ }
+
+ check_interrupts(z80sti);
+ }
+ break;
+
+ case Z80STI_REGISTER_ISRB:
+ LOG(("Z80STI '%s' Interrupt In-Service Register B: %x\n", device->tag.cstr(), data));
+ z80sti->isr &= (z80sti->isr & 0xff00) | data;
+ break;
+
+ case Z80STI_REGISTER_ISRA:
+ LOG(("Z80STI '%s' Interrupt In-Service Register A: %x\n", device->tag.cstr(), data));
+ z80sti->isr &= (data << 8) | (z80sti->isr & 0xff);
+ break;
+
+ case Z80STI_REGISTER_IMRB:
+ LOG(("Z80STI '%s' Interrupt Mask Register B: %x\n", device->tag.cstr(), data));
+ z80sti->imr = (z80sti->imr & 0xff00) | data;
+ z80sti->isr &= z80sti->imr;
+ check_interrupts(z80sti);
+ break;
+
+ case Z80STI_REGISTER_IMRA:
+ LOG(("Z80STI '%s' Interrupt Mask Register A: %x\n", device->tag.cstr(), data));
+ z80sti->imr = (data << 8) | (z80sti->imr & 0xff);
+ z80sti->isr &= z80sti->imr;
+ check_interrupts(z80sti);
+ break;
+
+ case Z80STI_REGISTER_PVR:
+ LOG(("Z80STI '%s' Interrupt Vector: %02x\n", device->tag.cstr(), data & 0xe0));
+ LOG(("Z80STI '%s' IR Address: %01x\n", device->tag.cstr(), data & 0x07));
+ z80sti->pvr = data;
+ break;
+
+ case Z80STI_REGISTER_TABC:
+ {
+ int tac = PRESCALER[(data >> 4) & 0x07];
+ int tbc = PRESCALER[data & 0x07];
+
+ z80sti->tabc = data;
+
+ LOG(("Z80STI '%s' Timer A Prescaler: %u\n", device->tag.cstr(), tac));
+ LOG(("Z80STI '%s' Timer B Prescaler: %u\n", device->tag.cstr(), tbc));
+
+ if (tac)
+ timer_adjust_periodic(z80sti->timer[TIMER_A], ATTOTIME_IN_HZ(device->clock / tac), 0, ATTOTIME_IN_HZ(device->clock / tac));
+ else
+ timer_enable(z80sti->timer[TIMER_A], 0);
+
+ if (tbc)
+ timer_adjust_periodic(z80sti->timer[TIMER_B], ATTOTIME_IN_HZ(device->clock / tbc), 0, ATTOTIME_IN_HZ(device->clock / tbc));
+ else
+ timer_enable(z80sti->timer[TIMER_B], 0);
+ }
+ break;
+
+ case Z80STI_REGISTER_TBDR:
+ LOG(("Z80STI '%s' Timer B Data Register: %x\n", device->tag.cstr(), data));
+ z80sti->tdr[TIMER_B] = data;
+ break;
+
+ case Z80STI_REGISTER_TADR:
+ LOG(("Z80STI '%s' Timer A Data Register: %x\n", device->tag.cstr(), data));
+ z80sti->tdr[TIMER_A] = data;
+ break;
+#if 0
+ case Z80STI_REGISTER_UCR:
+ z80sti->ucr = data;
+ break;
+
+ case Z80STI_REGISTER_RSR:
+ z80sti->rsr = data;
+ break;
+
+ case Z80STI_REGISTER_TSR:
+ z80sti->tsr = data;
+ break;
+
+ case Z80STI_REGISTER_UDR:
+ z80sti->udr = data;
+ break;
+#endif
+ default:
+ LOG(("Z80STI '%s' Unsupported Register %x\n", device->tag.cstr(), offset & 0x0f));
+ }
+}
+
+/*-------------------------------------------------
+ z80sti_rc_w - receiver clock write
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80sti_rc_w )
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ if (state)
+ {
+ serial_receive(z80sti);
+ }
+}
+
+/*-------------------------------------------------
+ z80sti_tc_w - transmitter clock write
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80sti_tc_w )
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ if (state)
+ {
+ serial_transmit(z80sti);
+ }
+}
+
+/*-------------------------------------------------
+ timer_count - timer count down
+-------------------------------------------------*/
+
+static void timer_count(running_device *device, int index)
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ if (z80sti->tmc[index] == 0x01)
+ {
+ //LOG(("Z80STI '%s' Timer %c Expired\n", device->tag, 'A' + index));
+
+ /* toggle timer output signal */
+ z80sti->to[index] = !z80sti->to[index];
+
+ switch (index)
+ {
+ case TIMER_A: devcb_call_write_line(&z80sti->out_tao_func, z80sti->to[index]); break;
+ case TIMER_B: devcb_call_write_line(&z80sti->out_tbo_func, z80sti->to[index]); break;
+ case TIMER_C: devcb_call_write_line(&z80sti->out_tco_func, z80sti->to[index]); break;
+ case TIMER_D: devcb_call_write_line(&z80sti->out_tdo_func, z80sti->to[index]); break;
+ }
+
+ if (z80sti->ier & (1 << INT_LEVEL_TIMER[index]))
+ {
+ LOG(("Z80STI '%s' Interrupt Pending for Timer %c\n", device->tag.cstr(), 'A' + index));
+
+ /* signal timer elapsed interrupt */
+ take_interrupt(z80sti, INT_LEVEL_TIMER[index]);
+ }
+
+ /* load timer main counter */
+ z80sti->tmc[index] = z80sti->tdr[index];
+ }
+ else
+ {
+ /* count down */
+ z80sti->tmc[index]--;
+ }
+}
+
+/*-------------------------------------------------
+ TIMER_CALLBACK( timer_# )
+-------------------------------------------------*/
+
+static TIMER_CALLBACK( timer_a ) { timer_count((running_device *)ptr, TIMER_A); }
+static TIMER_CALLBACK( timer_b ) { timer_count((running_device *)ptr, TIMER_B); }
+static TIMER_CALLBACK( timer_c ) { timer_count((running_device *)ptr, TIMER_C); }
+static TIMER_CALLBACK( timer_d ) { timer_count((running_device *)ptr, TIMER_D); }
+
+/*-------------------------------------------------
+ gpip_input - GPIP input line write
+-------------------------------------------------*/
+
+static void gpip_input(running_device *device, int bit, int state)
+{
+ z80sti_t *z80sti = get_safe_token(device);
+
+ int aer = BIT(z80sti->aer, bit);
+ int old_state = BIT(z80sti->gpip, bit);
+
+ if ((old_state ^ aer) && !(state ^ aer))
+ {
+ LOG(("Z80STI '%s' Edge Transition Detected on Bit: %u\n", device->tag.cstr(), bit));
+
+ if (z80sti->ier & (1 << INT_LEVEL_GPIP[bit]))
+ {
+ LOG(("Z80STI '%s' Interrupt Pending for P%u\n", device->tag.cstr(), bit));
+
+ take_interrupt(z80sti, INT_LEVEL_GPIP[bit]);
+ }
+ }
+
+ z80sti->gpip = (z80sti->gpip & ~(1 << bit)) | (state << bit);
+}
+
+/*-------------------------------------------------
+ z80sti_i#_w - GPIP input line # write
+-------------------------------------------------*/
+
+WRITE_LINE_DEVICE_HANDLER( z80sti_i0_w ) { gpip_input(device, 0, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i1_w ) { gpip_input(device, 1, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i2_w ) { gpip_input(device, 2, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i3_w ) { gpip_input(device, 3, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i4_w ) { gpip_input(device, 4, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i5_w ) { gpip_input(device, 5, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i6_w ) { gpip_input(device, 6, state); }
+WRITE_LINE_DEVICE_HANDLER( z80sti_i7_w ) { gpip_input(device, 7, state); }
+
+/*-------------------------------------------------
+ z80sti_irq_state - get interrupt status
+-------------------------------------------------*/
+
+static int z80sti_irq_state(running_device *device)
+{
+ z80sti_t *z80sti = get_safe_token(device);
+ int state = 0, i;
+
+ /* loop over all interrupt sources */
+ for (i = 15; i >= 0; i--)
+ {
+ /* if we're servicing a request, don't indicate more interrupts */
+ if (z80sti->int_state[i] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+
+ if (BIT(z80sti->imr, i))
+ {
+ state |= z80sti->int_state[i];
+ }
+ }
+
+ LOG(("Z80STI '%s' Interrupt State: %u\n", device->tag.cstr(), state));
+
+ return state;
+}
+
+/*-------------------------------------------------
+ z80sti_irq_ack - interrupt acknowledge
+-------------------------------------------------*/
+
+static int z80sti_irq_ack(running_device *device)
+{
+ z80sti_t *z80sti = get_safe_token(device);
+ int i;
+
+ /* loop over all interrupt sources */
+ for (i = 15; i >= 0; i--)
+ {
+ /* find the first channel with an interrupt requested */
+ if (z80sti->int_state[i] & Z80_DAISY_INT)
+ {
+ UINT8 vector = (z80sti->pvr & 0xe0) | INT_VECTOR[i];
+
+ /* clear interrupt, switch to the IEO state, and update the IRQs */
+ z80sti->int_state[i] = Z80_DAISY_IEO;
+
+ /* clear interrupt pending register bit */
+ z80sti->ipr &= ~(1 << i);
+
+ /* set interrupt in-service register bit */
+ z80sti->isr |= (1 << i);
+
+ check_interrupts(z80sti);
+
+ LOG(("Z80STI '%s' Interrupt Acknowledge Vector: %02x\n", device->tag.cstr(), vector));
+
+ return vector;
+ }
+ }
+
+ logerror("z80sti_irq_ack: failed to find an interrupt to ack!\n");
+
+ return 0;
+}
+
+/*-------------------------------------------------
+ z80sti_irq_reti - return from interrupt
+-------------------------------------------------*/
+
+static void z80sti_irq_reti(running_device *device)
+{
+ z80sti_t *z80sti = get_safe_token(device);
+ int i;
+
+ LOG(("Z80STI '%s' Return from Interrupt\n", device->tag.cstr()));
+
+ /* loop over all interrupt sources */
+ for (i = 15; i >= 0; i--)
+ {
+ /* find the first channel with an IEO pending */
+ if (z80sti->int_state[i] & Z80_DAISY_IEO)
+ {
+ /* clear the IEO state and update the IRQs */
+ z80sti->int_state[i] &= ~Z80_DAISY_IEO;
+
+ /* clear interrupt in-service register bit */
+ z80sti->isr &= ~(1 << i);
+
+ check_interrupts(z80sti);
+ return;
+ }
+ }
+
+ logerror("z80sti_irq_reti: failed to find an interrupt to clear IEO on!\n");
+}
+
+/*-------------------------------------------------
+ DEVICE_START( z80sti )
+-------------------------------------------------*/
+
+static DEVICE_START( z80sti )
+{
+ z80sti_t *z80sti = get_safe_token(device);
+ const z80sti_interface *intf = (const z80sti_interface *)device->baseconfig().static_config;
+
+ /* resolve callbacks */
+ devcb_resolve_read8(&z80sti->in_gpio_func, &intf->in_gpio_func, device);
+ devcb_resolve_write8(&z80sti->out_gpio_func, &intf->out_gpio_func, device);
+ devcb_resolve_read_line(&z80sti->in_si_func, &intf->in_si_func, device);
+ devcb_resolve_write_line(&z80sti->out_so_func, &intf->out_so_func, device);
+ devcb_resolve_write_line(&z80sti->out_tao_func, &intf->out_tao_func, device);
+ devcb_resolve_write_line(&z80sti->out_tbo_func, &intf->out_tbo_func, device);
+ devcb_resolve_write_line(&z80sti->out_tco_func, &intf->out_tco_func, device);
+ devcb_resolve_write_line(&z80sti->out_tdo_func, &intf->out_tdo_func, device);
+ devcb_resolve_write_line(&z80sti->out_int_func, &intf->out_int_func, device);
+
+ /* create the counter timers */
+ z80sti->timer[TIMER_A] = timer_alloc(device->machine, timer_a, (void *)device);
+ z80sti->timer[TIMER_B] = timer_alloc(device->machine, timer_b, (void *)device);
+ z80sti->timer[TIMER_C] = timer_alloc(device->machine, timer_c, (void *)device);
+ z80sti->timer[TIMER_D] = timer_alloc(device->machine, timer_d, (void *)device);
+
+ /* create serial receive clock timer */
+ if (intf->rx_clock > 0)
+ {
+ z80sti->rx_timer = timer_alloc(device->machine, rx_tick, (void *)device);
+ timer_adjust_periodic(z80sti->rx_timer, attotime_zero, 0, ATTOTIME_IN_HZ(intf->rx_clock));
+ }
+
+ /* create serial transmit clock timer */
+ if (intf->tx_clock > 0)
+ {
+ z80sti->tx_timer = timer_alloc(device->machine, tx_tick, (void *)device);
+ timer_adjust_periodic(z80sti->tx_timer, attotime_zero, 0, ATTOTIME_IN_HZ(intf->tx_clock));
+ }
+
+ /* register for state saving */
+ state_save_register_device_item(device, 0, z80sti->gpip);
+ state_save_register_device_item(device, 0, z80sti->aer);
+ state_save_register_device_item(device, 0, z80sti->ddr);
+ state_save_register_device_item(device, 0, z80sti->ier);
+ state_save_register_device_item(device, 0, z80sti->ipr);
+ state_save_register_device_item(device, 0, z80sti->isr);
+ state_save_register_device_item(device, 0, z80sti->imr);
+ state_save_register_device_item(device, 0, z80sti->pvr);
+ state_save_register_device_item_array(device, 0, z80sti->int_state);
+ state_save_register_device_item(device, 0, z80sti->tabc);
+ state_save_register_device_item(device, 0, z80sti->tcdc);
+ state_save_register_device_item_array(device, 0, z80sti->tdr);
+ state_save_register_device_item_array(device, 0, z80sti->tmc);
+ state_save_register_device_item_array(device, 0, z80sti->to);
+ state_save_register_device_item(device, 0, z80sti->scr);
+ state_save_register_device_item(device, 0, z80sti->ucr);
+ state_save_register_device_item(device, 0, z80sti->rsr);
+ state_save_register_device_item(device, 0, z80sti->tsr);
+ state_save_register_device_item(device, 0, z80sti->udr);
+}
+
+/*-------------------------------------------------
+ DEVICE_RESET( z80sti )
+-------------------------------------------------*/
+
+static DEVICE_RESET( z80sti )
+{
+}
+
+/*-------------------------------------------------
+ DEVICE_GET_INFO( z80sti )
+-------------------------------------------------*/
+
+DEVICE_GET_INFO( z80sti )
+{
+ switch (state)
+ {
+ /* --- the following bits of info are returned as 64-bit signed integers --- */
+ case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(z80sti_t); break;
+ case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break;
+ case DEVINFO_INT_CLASS: info->i = DEVICE_CLASS_PERIPHERAL; break;
+
+ /* --- the following bits of info are returned as pointers to data or functions --- */
+ case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(z80sti); break;
+ case DEVINFO_FCT_STOP: /* Nothing */ break;
+ case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(z80sti); break;
+ case DEVINFO_FCT_IRQ_STATE: info->f = (genf *)z80sti_irq_state; break;
+ case DEVINFO_FCT_IRQ_ACK: info->f = (genf *)z80sti_irq_ack; break;
+ case DEVINFO_FCT_IRQ_RETI: info->f = (genf *)z80sti_irq_reti; break;
+
+ /* --- the following bits of info are returned as NULL-terminated strings --- */
+ case DEVINFO_STR_NAME: strcpy(info->s, "Mostek MK3801"); break;
+ case DEVINFO_STR_FAMILY: strcpy(info->s, "Z80-STI"); break;
+ case DEVINFO_STR_VERSION: strcpy(info->s, "1.0"); break;
+ case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break;
+ case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MESS Team"); break;
+ }
+}
diff --git a/src/emu/machine/z80sti.h b/src/emu/machine/z80sti.h
new file mode 100644
index 00000000000..4b9df8bd818
--- /dev/null
+++ b/src/emu/machine/z80sti.h
@@ -0,0 +1,116 @@
+/**********************************************************************
+
+ Mostek MK3801 Serial Timer Interrupt Controller (Z80-STI) emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+ _____ _____
+ TAO 1 |* \_/ | 40 Vcc
+ TBO 2 | | 39 RC
+ TCO 3 | | 38 SI
+ TDO 4 | | 37 SO
+ TCK 5 | | 36 TC
+ _M1 6 | | 35 A0
+ _RES 7 | | 34 A1
+ I0 8 | | 33 A2
+ I1 9 | | 32 A3
+ I2 10 | MK3801 | 31 _WR
+ I3 11 | Z80-STI | 30 _CE
+ I4 12 | | 29 _RD
+ I5 13 | | 28 D7
+ I6 14 | | 27 D6
+ I7 15 | | 26 D5
+ IEI 16 | | 25 D4
+ _INT 17 | | 24 D3
+ IEO 18 | | 23 D2
+ _IORQ 19 | | 22 D1
+ Vss 20 |_____________| 21 D0
+
+**********************************************************************/
+
+#ifndef __Z80STI__
+#define __Z80STI__
+
+#include "emu.h"
+#include "devcb.h"
+
+/***************************************************************************
+ MACROS / CONSTANTS
+***************************************************************************/
+
+#define Z80STI DEVICE_GET_INFO_NAME( z80sti )
+
+#define MDRV_Z80STI_ADD(_tag, _clock, _config) \
+ MDRV_DEVICE_ADD((_tag), Z80STI, _clock) \
+ MDRV_DEVICE_CONFIG(_config)
+
+#define Z80STI_INTERFACE(name) const z80sti_interface (name) =
+
+/***************************************************************************
+ TYPE DEFINITIONS
+***************************************************************************/
+
+typedef struct _z80sti_interface z80sti_interface;
+struct _z80sti_interface
+{
+ int rx_clock; /* serial receive clock */
+ int tx_clock; /* serial transmit clock */
+
+ /* this gets called on each change of the _INT pin (pin 17) */
+ devcb_write_line out_int_func;
+
+ /* this is called on each read of the GPIO pins */
+ devcb_read8 in_gpio_func;
+
+ /* this is called on each write of the GPIO pins */
+ devcb_write8 out_gpio_func;
+
+ /* this gets called for each read of the SI pin (pin 38) */
+ devcb_read_line in_si_func;
+
+ /* this gets called for each change of the SO pin (pin 37) */
+ devcb_write_line out_so_func;
+
+ /* this gets called for each change of the TAO pin (pin 1) */
+ devcb_write_line out_tao_func;
+
+ /* this gets called for each change of the TBO pin (pin 2) */
+ devcb_write_line out_tbo_func;
+
+ /* this gets called for each change of the TCO pin (pin 3) */
+ devcb_write_line out_tco_func;
+
+ /* this gets called for each change of the TDO pin (pin 4) */
+ devcb_write_line out_tdo_func;
+};
+
+/***************************************************************************
+ PROTOTYPES
+***************************************************************************/
+
+/* device interface */
+DEVICE_GET_INFO( z80sti );
+
+/* register access */
+READ8_DEVICE_HANDLER( z80sti_r );
+WRITE8_DEVICE_HANDLER( z80sti_w );
+
+/* receive clock */
+WRITE_LINE_DEVICE_HANDLER( z80sti_rc_w );
+
+/* transmit clock */
+WRITE_LINE_DEVICE_HANDLER( z80sti_tc_w );
+
+/* GPIP input lines */
+WRITE_LINE_DEVICE_HANDLER( z80sti_i0_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i1_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i2_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i3_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i4_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i5_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i6_w );
+WRITE_LINE_DEVICE_HANDLER( z80sti_i7_w );
+
+#endif