summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu/machine/z80sio.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/emu/machine/z80sio.c')
-rw-r--r--src/emu/machine/z80sio.c1227
1 files changed, 618 insertions, 609 deletions
diff --git a/src/emu/machine/z80sio.c b/src/emu/machine/z80sio.c
index 0cf01579e41..c791507c42c 100644
--- a/src/emu/machine/z80sio.c
+++ b/src/emu/machine/z80sio.c
@@ -14,9 +14,9 @@
-/***************************************************************************
- DEBUGGING
-***************************************************************************/
+//**************************************************************************
+// DEBUGGING
+//**************************************************************************
#define VERBOSE 0
@@ -24,167 +24,149 @@
-/***************************************************************************
- CONSTANTS
-***************************************************************************/
-
-/* interrupt states */
-#define INT_CHB_TRANSMIT 0x00 /* not confirmed */
-#define INT_CHB_STATUS 0x01
-#define INT_CHB_RECEIVE 0x02
-#define INT_CHB_ERROR 0x03
-
-#define INT_CHA_TRANSMIT 0x04 /* not confirmed */
-#define INT_CHA_STATUS 0x05
-#define INT_CHA_RECEIVE 0x06
-#define INT_CHA_ERROR 0x07
-
-/* SIO write register 0 */
-#define SIO_WR0_RESET_MASK 0xc0 /* D7-D6: Reset control */
-#define SIO_WR0_RESET_NULL 0x00 /* 00 = NULL code */
-#define SIO_WR0_RESET_RX_CRC 0x40 /* 01 = Reset Rx CRC checker */
-#define SIO_WR0_RESET_TX_CRC 0x80 /* 10 = Reset Tx CRC generator */
-#define SIO_WR0_RESET_TX_LATCH 0xc0 /* 11 = Reset Tx Underrun/EOM latch */
-#define SIO_WR0_COMMAND_MASK 0x38 /* D5-D3: Command */
-#define SIO_WR0_COMMAND_NULL 0x00 /* 000 = NULL code */
-#define SIO_WR0_COMMAND_SET_ABORT 0x08 /* 001 = Set abort (SDLC) */
-#define SIO_WR0_COMMAND_RES_STATUS_INT 0x10 /* 010 = reset ext/status interrupts */
-#define SIO_WR0_COMMAND_CH_RESET 0x18 /* 011 = Channel reset */
-#define SIO_WR0_COMMAND_ENA_RX_INT 0x20 /* 100 = Enable int on next Rx character */
-#define SIO_WR0_COMMAND_RES_TX_INT 0x28 /* 101 = Reset Tx int pending */
-#define SIO_WR0_COMMAND_RES_ERROR 0x30 /* 110 = Error reset */
-#define SIO_WR0_COMMAND_RETI 0x38 /* 111 = Return from int (CH-A only) */
-#define SIO_WR0_REGISTER_MASK 0x07 /* D2-D0: Register select (0-7) */
-
-/* SIO write register 1 */
-#define SIO_WR1_READY_WAIT_ENA 0x80 /* D7 = READY/WAIT enable */
-#define SIO_WR1_READY_WAIT_FUNCTION 0x40 /* D6 = READY/WAIT function */
-#define SIO_WR1_READY_WAIT_ON_RT 0x20 /* D5 = READY/WAIT on R/T */
-#define SIO_WR1_RXINT_MASK 0x18 /* D4-D3 = Rx int control */
-#define SIO_WR1_RXINT_DISABLE 0x00 /* 00 = Rx int disable */
-#define SIO_WR1_RXINT_FIRST 0x08 /* 01 = Rx int on first character */
-#define SIO_WR1_RXINT_ALL_PARITY 0x10 /* 10 = int on all Rx characters (parity affects vector) */
-#define SIO_WR1_RXINT_ALL_NOPARITY 0x18 /* 11 = int on all Rx characters (parity ignored) */
-#define SIO_WR1_STATUS_AFFECTS_VECTOR 0x04 /* D2 = Status affects vector (CH-B only) */
-#define SIO_WR1_TXINT_ENABLE 0x02 /* D1 = Tx int enable */
-#define SIO_WR1_STATUSINT_ENABLE 0x01 /* D0 = Ext int enable */
-
-/* SIO write register 2 (CH-B only) */
-#define SIO_WR2_INT_VECTOR_MASK 0xff /* D7-D0 = interrupt vector */
-
-/* SIO write register 3 */
-#define SIO_WR3_RX_DATABITS_MASK 0xc0 /* D7-D6 = Rx Data bits */
-#define SIO_WR3_RX_DATABITS_5 0x00 /* 00 = Rx 5 bits/character */
-#define SIO_WR3_RX_DATABITS_7 0x40 /* 01 = Rx 7 bits/character */
-#define SIO_WR3_RX_DATABITS_6 0x80 /* 10 = Rx 6 bits/character */
-#define SIO_WR3_RX_DATABITS_8 0xc0 /* 11 = Rx 8 bits/character */
-#define SIO_WR3_AUTO_ENABLES 0x20 /* D5 = Auto enables */
-#define SIO_WR3_ENTER_HUNT_PHASE 0x10 /* D4 = Enter hunt phase */
-#define SIO_WR3_RX_CRC_ENABLE 0x08 /* D3 = Rx CRC enable */
-#define SIO_WR3_ADDR_SEARCH_MODE 0x04 /* D2 = Address search mode (SDLC) */
-#define SIO_WR3_SYNC_LOAD_INHIBIT 0x02 /* D1 = Sync character load inhibit */
-#define SIO_WR3_RX_ENABLE 0x01 /* D0 = Rx enable */
-
-/* SIO write register 4 */
-#define SIO_WR4_CLOCK_MODE_MASK 0xc0 /* D7-D6 = Clock mode */
-#define SIO_WR4_CLOCK_MODE_x1 0x00 /* 00 = x1 clock mode */
-#define SIO_WR4_CLOCK_MODE_x16 0x40 /* 01 = x16 clock mode */
-#define SIO_WR4_CLOCK_MODE_x32 0x80 /* 10 = x32 clock mode */
-#define SIO_WR4_CLOCK_MODE_x64 0xc0 /* 11 = x64 clock mode */
-#define SIO_WR4_SYNC_MODE_MASK 0x30 /* D5-D4 = Sync mode */
-#define SIO_WR4_SYNC_MODE_8BIT 0x00 /* 00 = 8 bit sync character */
-#define SIO_WR4_SYNC_MODE_16BIT 0x10 /* 01 = 16 bit sync character */
-#define SIO_WR4_SYNC_MODE_SDLC 0x20 /* 10 = SDLC mode (01111110 flag) */
-#define SIO_WR4_SYNC_MODE_EXTERNAL 0x30 /* 11 = External sync mode */
-#define SIO_WR4_STOPBITS_MASK 0x0c /* D3-D2 = Stop bits */
-#define SIO_WR4_STOPBITS_SYNC 0x00 /* 00 = Sync modes enable */
-#define SIO_WR4_STOPBITS_1 0x04 /* 01 = 1 stop bit/character */
-#define SIO_WR4_STOPBITS_15 0x08 /* 10 = 1.5 stop bits/character */
-#define SIO_WR4_STOPBITS_2 0x0c /* 11 = 2 stop bits/character */
-#define SIO_WR4_PARITY_EVEN 0x02 /* D1 = Parity even/odd */
-#define SIO_WR4_PARITY_ENABLE 0x01 /* D0 = Parity enable */
-
-/* SIO write register 5 */
-#define SIO_WR5_DTR 0x80 /* D7 = DTR */
-#define SIO_WR5_TX_DATABITS_MASK 0x60 /* D6-D5 = Tx Data bits */
-#define SIO_WR5_TX_DATABITS_5 0x00 /* 00 = Tx 5 bits/character */
-#define SIO_WR5_TX_DATABITS_7 0x20 /* 01 = Tx 7 bits/character */
-#define SIO_WR5_TX_DATABITS_6 0x40 /* 10 = Tx 6 bits/character */
-#define SIO_WR5_TX_DATABITS_8 0x60 /* 11 = Tx 8 bits/character */
-#define SIO_WR5_SEND_BREAK 0x10 /* D4 = Send break */
-#define SIO_WR5_TX_ENABLE 0x08 /* D3 = Tx Enable */
-#define SIO_WR5_CRC16_SDLC 0x04 /* D2 = CRC-16/SDLC */
-#define SIO_WR5_RTS 0x02 /* D1 = RTS */
-#define SIO_WR5_TX_CRC_ENABLE 0x01 /* D0 = Tx CRC enable */
-
-/* SIO write register 6 */
-#define SIO_WR6_SYNC_7_0_MASK 0xff /* D7-D0 = Sync bits 7-0 */
-
-/* SIO write register 7 */
-#define SIO_WR7_SYNC_15_8_MASK 0xff /* D7-D0 = Sync bits 15-8 */
-
-/* SIO read register 0 */
-#define SIO_RR0_BREAK_ABORT 0x80 /* D7 = Break/abort */
-#define SIO_RR0_TX_UNDERRUN 0x40 /* D6 = Tx underrun/EOM */
-#define SIO_RR0_CTS 0x20 /* D5 = CTS */
-#define SIO_RR0_SYNC_HUNT 0x10 /* D4 = Sync/hunt */
-#define SIO_RR0_DCD 0x08 /* D3 = DCD */
-#define SIO_RR0_TX_BUFFER_EMPTY 0x04 /* D2 = Tx buffer empty */
-#define SIO_RR0_INT_PENDING 0x02 /* D1 = int pending (CH-A only) */
-#define SIO_RR0_RX_CHAR_AVAILABLE 0x01 /* D0 = Rx character available */
-
-/* SIO read register 1 */
-#define SIO_RR1_END_OF_FRAME 0x80 /* D7 = End of frame (SDLC) */
-#define SIO_RR1_CRC_FRAMING_ERROR 0x40 /* D6 = CRC/Framing error */
-#define SIO_RR1_RX_OVERRUN_ERROR 0x20 /* D5 = Rx overrun error */
-#define SIO_RR1_PARITY_ERROR 0x10 /* D4 = Parity error */
-#define SIO_RR1_IFIELD_BITS_MASK 0x0e /* D3-D1 = I field bits */
- /* 100 = 0 in prev, 3 in 2nd prev */
- /* 010 = 0 in prev, 4 in 2nd prev */
- /* 110 = 0 in prev, 5 in 2nd prev */
- /* 001 = 0 in prev, 6 in 2nd prev */
- /* 101 = 0 in prev, 7 in 2nd prev */
- /* 011 = 0 in prev, 8 in 2nd prev */
- /* 111 = 1 in prev, 8 in 2nd prev */
- /* 000 = 2 in prev, 8 in 2nd prev */
-#define SIO_RR1_ALL_SENT 0x01 /* D0 = All sent */
-
-/* SIO read register 2 (CH-B only) */
-#define SIO_RR2_VECTOR_MASK 0xff /* D7-D0 = Interrupt vector */
-
-
-
-/***************************************************************************
- TYPE DEFINITIONS
-***************************************************************************/
-
-typedef struct _sio_channel sio_channel;
-struct _sio_channel
-{
- UINT8 regs[8]; /* 8 writeable registers */
- UINT8 status[4]; /* 3 readable registers */
- int inbuf; /* input buffer */
- int outbuf; /* output buffer */
- UINT8 int_on_next_rx; /* interrupt on next rx? */
- emu_timer * receive_timer; /* timer to clock data in */
- UINT8 receive_buffer[16]; /* buffer for incoming data */
- UINT8 receive_inptr; /* index of data coming in */
- UINT8 receive_outptr; /* index of data going out */
-};
-
-
-typedef struct _z80sio z80sio;
-struct _z80sio
+//**************************************************************************
+// CONSTANTS
+//**************************************************************************
+
+// interrupt states
+const int INT_TRANSMIT = 0x00; // not confirmed
+const int INT_STATUS = 0x01;
+const int INT_RECEIVE = 0x02;
+const int INT_ERROR = 0x03;
+
+const int INT_CHB_TRANSMIT = 0 + INT_TRANSMIT;
+const int INT_CHB_STATUS = 0 + INT_STATUS;
+const int INT_CHB_RECEIVE = 0 + INT_RECEIVE;
+const int INT_CHB_ERROR = 0 + INT_ERROR;
+const int INT_CHA_TRANSMIT = 4 + INT_TRANSMIT;
+const int INT_CHA_STATUS = 4 + INT_STATUS;
+const int INT_CHA_RECEIVE = 4 + INT_RECEIVE;
+const int INT_CHA_ERROR = 4 + INT_ERROR;
+
+// SIO write register 0
+const int SIO_WR0_RESET_MASK = 0xc0; // D7-D6: Reset control
+const int SIO_WR0_RESET_NULL = 0x00; // 00 = NULL code
+const int SIO_WR0_RESET_RX_CRC = 0x40; // 01 = Reset Rx CRC checker
+const int SIO_WR0_RESET_TX_CRC = 0x80; // 10 = Reset Tx CRC generator
+const int SIO_WR0_RESET_TX_LATCH = 0xc0; // 11 = Reset Tx Underrun/EOM latch
+const int SIO_WR0_COMMAND_MASK = 0x38; // D5-D3: Command
+const int SIO_WR0_COMMAND_NULL = 0x00; // 000 = NULL code
+const int SIO_WR0_COMMAND_SET_ABORT = 0x08; // 001 = Set abort (SDLC)
+const int SIO_WR0_COMMAND_RES_STATUS_INT = 0x10; // 010 = reset ext/status interrupts
+const int SIO_WR0_COMMAND_CH_RESET = 0x18; // 011 = Channel reset
+const int SIO_WR0_COMMAND_ENA_RX_INT = 0x20; // 100 = Enable int on next Rx character
+const int SIO_WR0_COMMAND_RES_TX_INT = 0x28; // 101 = Reset Tx int pending
+const int SIO_WR0_COMMAND_RES_ERROR = 0x30; // 110 = Error reset
+const int SIO_WR0_COMMAND_RETI = 0x38; // 111 = Return from int (CH-A only)
+const int SIO_WR0_REGISTER_MASK = 0x07; // D2-D0: Register select (0-7)
+
+// SIO write register 1
+const int SIO_WR1_READY_WAIT_ENA = 0x80; // D7 = READY/WAIT enable
+const int SIO_WR1_READY_WAIT_FUNCTION = 0x40; // D6 = READY/WAIT function
+const int SIO_WR1_READY_WAIT_ON_RT = 0x20; // D5 = READY/WAIT on R/T
+const int SIO_WR1_RXINT_MASK = 0x18; // D4-D3 = Rx int control
+const int SIO_WR1_RXINT_DISABLE = 0x00; // 00 = Rx int disable
+const int SIO_WR1_RXINT_FIRST = 0x08; // 01 = Rx int on first character
+const int SIO_WR1_RXINT_ALL_PARITY = 0x10; // 10 = int on all Rx characters (parity affects vector)
+const int SIO_WR1_RXINT_ALL_NOPARITY = 0x18; // 11 = int on all Rx characters (parity ignored)
+const int SIO_WR1_STATUS_AFFECTS_VECTOR = 0x04; // D2 = Status affects vector (CH-B only)
+const int SIO_WR1_TXINT_ENABLE = 0x02; // D1 = Tx int enable
+const int SIO_WR1_STATUSINT_ENABLE = 0x01; // D0 = Ext int enable
+
+// SIO write register 2 (CH-B only)
+const int SIO_WR2_INT_VECTOR_MASK = 0xff; // D7-D0 = interrupt vector
+
+// SIO write register 3
+const int SIO_WR3_RX_DATABITS_MASK = 0xc0; // D7-D6 = Rx Data bits
+const int SIO_WR3_RX_DATABITS_5 = 0x00; // 00 = Rx 5 bits/character
+const int SIO_WR3_RX_DATABITS_7 = 0x40; // 01 = Rx 7 bits/character
+const int SIO_WR3_RX_DATABITS_6 = 0x80; // 10 = Rx 6 bits/character
+const int SIO_WR3_RX_DATABITS_8 = 0xc0; // 11 = Rx 8 bits/character
+const int SIO_WR3_AUTO_ENABLES = 0x20; // D5 = Auto enables
+const int SIO_WR3_ENTER_HUNT_PHASE = 0x10; // D4 = Enter hunt phase
+const int SIO_WR3_RX_CRC_ENABLE = 0x08; // D3 = Rx CRC enable
+const int SIO_WR3_ADDR_SEARCH_MODE = 0x04; // D2 = Address search mode (SDLC)
+const int SIO_WR3_SYNC_LOAD_INHIBIT = 0x02; // D1 = Sync character load inhibit
+const int SIO_WR3_RX_ENABLE = 0x01; // D0 = Rx enable
+
+// SIO write register 4
+const int SIO_WR4_CLOCK_MODE_MASK = 0xc0; // D7-D6 = Clock mode
+const int SIO_WR4_CLOCK_MODE_x1 = 0x00; // 00 = x1 clock mode
+const int SIO_WR4_CLOCK_MODE_x16 = 0x40; // 01 = x16 clock mode
+const int SIO_WR4_CLOCK_MODE_x32 = 0x80; // 10 = x32 clock mode
+const int SIO_WR4_CLOCK_MODE_x64 = 0xc0; // 11 = x64 clock mode
+const int SIO_WR4_SYNC_MODE_MASK = 0x30; // D5-D4 = Sync mode
+const int SIO_WR4_SYNC_MODE_8BIT = 0x00; // 00 = 8 bit sync character
+const int SIO_WR4_SYNC_MODE_16BIT = 0x10; // 01 = 16 bit sync character
+const int SIO_WR4_SYNC_MODE_SDLC = 0x20; // 10 = SDLC mode (01111110 flag)
+const int SIO_WR4_SYNC_MODE_EXTERNAL = 0x30; // 11 = External sync mode
+const int SIO_WR4_STOPBITS_MASK = 0x0c; // D3-D2 = Stop bits
+const int SIO_WR4_STOPBITS_SYNC = 0x00; // 00 = Sync modes enable
+const int SIO_WR4_STOPBITS_1 = 0x04; // 01 = 1 stop bit/character
+const int SIO_WR4_STOPBITS_15 = 0x08; // 10 = 1.5 stop bits/character
+const int SIO_WR4_STOPBITS_2 = 0x0c; // 11 = 2 stop bits/character
+const int SIO_WR4_PARITY_EVEN = 0x02; // D1 = Parity even/odd
+const int SIO_WR4_PARITY_ENABLE = 0x01; // D0 = Parity enable
+
+// SIO write register 5
+const int SIO_WR5_DTR = 0x80; // D7 = DTR
+const int SIO_WR5_TX_DATABITS_MASK = 0x60; // D6-D5 = Tx Data bits
+const int SIO_WR5_TX_DATABITS_5 = 0x00; // 00 = Tx 5 bits/character
+const int SIO_WR5_TX_DATABITS_7 = 0x20; // 01 = Tx 7 bits/character
+const int SIO_WR5_TX_DATABITS_6 = 0x40; // 10 = Tx 6 bits/character
+const int SIO_WR5_TX_DATABITS_8 = 0x60; // 11 = Tx 8 bits/character
+const int SIO_WR5_SEND_BREAK = 0x10; // D4 = Send break
+const int SIO_WR5_TX_ENABLE = 0x08; // D3 = Tx Enable
+const int SIO_WR5_CRC16_SDLC = 0x04; // D2 = CRC-16/SDLC
+const int SIO_WR5_RTS = 0x02; // D1 = RTS
+const int SIO_WR5_TX_CRC_ENABLE = 0x01; // D0 = Tx CRC enable
+
+// SIO write register 6
+const int SIO_WR6_SYNC_7_0_MASK = 0xff; // D7-D0 = Sync bits 7-0
+
+// SIO write register 7
+const int SIO_WR7_SYNC_15_8_MASK = 0xff; // D7-D0 = Sync bits 15-8
+
+// SIO read register 0
+const int SIO_RR0_BREAK_ABORT = 0x80; // D7 = Break/abort
+const int SIO_RR0_TX_UNDERRUN = 0x40; // D6 = Tx underrun/EOM
+const int SIO_RR0_CTS = 0x20; // D5 = CTS
+const int SIO_RR0_SYNC_HUNT = 0x10; // D4 = Sync/hunt
+const int SIO_RR0_DCD = 0x08; // D3 = DCD
+const int SIO_RR0_TX_BUFFER_EMPTY = 0x04; // D2 = Tx buffer empty
+const int SIO_RR0_INT_PENDING = 0x02; // D1 = int pending (CH-A only)
+const int SIO_RR0_RX_CHAR_AVAILABLE = 0x01; // D0 = Rx character available
+
+// SIO read register 1
+const int SIO_RR1_END_OF_FRAME = 0x80; // D7 = End of frame (SDLC)
+const int SIO_RR1_CRC_FRAMING_ERROR = 0x40; // D6 = CRC/Framing error
+const int SIO_RR1_RX_OVERRUN_ERROR = 0x20; // D5 = Rx overrun error
+const int SIO_RR1_PARITY_ERROR = 0x10; // D4 = Parity error
+const int SIO_RR1_IFIELD_BITS_MASK = 0x0e; // D3-D1 = I field bits
+ // 100 = 0 in prev, 3 in 2nd prev
+ // 010 = 0 in prev, 4 in 2nd prev
+ // 110 = 0 in prev, 5 in 2nd prev
+ // 001 = 0 in prev, 6 in 2nd prev
+ // 101 = 0 in prev, 7 in 2nd prev
+ // 011 = 0 in prev, 8 in 2nd prev
+ // 111 = 1 in prev, 8 in 2nd prev
+ // 000 = 2 in prev, 8 in 2nd prev
+const int SIO_RR1_ALL_SENT = 0x01; // D0 = All sent
+
+// SIO read register 2 (CH-B only)
+const int SIO_RR2_VECTOR_MASK = 0xff; // D7-D0 = Interrupt vector
+
+
+const UINT8 z80sio_device::k_int_priority[] =
{
- sio_channel chan[2]; /* 2 channels */
- UINT8 int_state[8]; /* interrupt states */
-
- void (*irq_cb)(running_device *device, int state);
- write8_device_func dtr_changed_cb;
- write8_device_func rts_changed_cb;
- write8_device_func break_changed_cb;
- write8_device_func transmit_cb;
- int (*receive_poll_cb)(running_device *device, int channel);
+ INT_CHA_RECEIVE,
+ INT_CHA_TRANSMIT,
+ INT_CHA_STATUS,
+ INT_CHA_ERROR,
+ INT_CHB_RECEIVE,
+ INT_CHB_TRANSMIT,
+ INT_CHB_STATUS,
+ INT_CHB_ERROR
};
@@ -193,9 +175,6 @@ struct _z80sio
FUNCTION PROTOTYPES
***************************************************************************/
-static TIMER_CALLBACK( serial_callback );
-
-
/*
@@ -249,641 +228,671 @@ static TIMER_CALLBACK( serial_callback );
*/
-/***************************************************************************
- FUNCTION PROTOTYPES
-***************************************************************************/
+//**************************************************************************
+// INLINE FUNCTIONS
+//**************************************************************************
-static int z80sio_irq_state(running_device *device);
-static int z80sio_irq_ack(running_device *device);
-static void z80sio_irq_reti(running_device *device);
+//-------------------------------------------------
+// update_interrupt_state - update the interrupt
+// state to the external world
+//-------------------------------------------------
+inline void z80sio_device::update_interrupt_state()
+{
+ // if we have a callback, update it with the current state
+ if (m_config.m_irq_cb != NULL)
+ (*m_config.m_irq_cb)(this, (z80daisy_irq_state() & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE);
+}
-/***************************************************************************
- INLINE FUNCTIONS
-***************************************************************************/
+//-------------------------------------------------
+// set_interrupt - set the given interrupt state
+// on this channel and update the overall device
+// state
+//-------------------------------------------------
-INLINE z80sio *get_safe_token(running_device *device)
+inline void z80sio_device::sio_channel::set_interrupt(int type)
{
- assert(device != NULL);
- assert(device->token != NULL);
- assert(device->type == Z80SIO);
- return (z80sio *)device->token;
+ int inum = (this == &m_device->m_channel[0] ? 4 : 0) + type;
+ m_device->m_int_state[inum] = Z80_DAISY_INT;
+ m_device->update_interrupt_state();
}
-INLINE void interrupt_check(running_device *device)
+//-------------------------------------------------
+// clear_interrupt - clear the given interrupt
+// state on this channel and update the overall
+// device state
+//-------------------------------------------------
+
+inline void z80sio_device::sio_channel::clear_interrupt(int type)
{
- /* if we have a callback, update it with the current state */
- z80sio *sio = get_safe_token(device);
- if (sio->irq_cb != NULL)
- (*sio->irq_cb)(device, (z80sio_irq_state(device) & Z80_DAISY_INT) ? ASSERT_LINE : CLEAR_LINE);
+ int inum = (this == &m_device->m_channel[0] ? 4 : 0) + type;
+ m_device->m_int_state[inum] &= ~Z80_DAISY_INT;
+ m_device->update_interrupt_state();
}
-INLINE attotime compute_time_per_character(z80sio *sio, int which)
+//-------------------------------------------------
+// compute_time_per_character - compute the
+// serial clocking period
+//-------------------------------------------------
+
+inline attotime z80sio_device::sio_channel::compute_time_per_character()
{
- /* fix me -- should compute properly and include data, stop, parity bits */
+ // fix me -- should compute properly and include data, stop, parity bit
return attotime_mul(ATTOTIME_IN_HZ(9600), 10);
}
-/***************************************************************************
- INITIALIZATION/CONFIGURATION
-***************************************************************************/
+//**************************************************************************
+// DEVICE CONFIGURATION
+//**************************************************************************
-/*-------------------------------------------------
- reset_channel - reset a single SIO channel
--------------------------------------------------*/
+//-------------------------------------------------
+// z80sio_device_config - constructor
+//-------------------------------------------------
-static void reset_channel(running_device *device, int ch)
+z80sio_device_config::z80sio_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+ : device_config(mconfig, static_alloc_device_config, tag, owner, clock),
+ device_config_z80daisy_interface(mconfig, *this)
{
- z80sio *sio = get_safe_token(device);
- attotime tpc = compute_time_per_character(sio, ch);
- sio_channel *chan = &sio->chan[ch];
+}
+
- chan->status[0] = SIO_RR0_TX_BUFFER_EMPTY;
- chan->status[1] = 0x00;
- chan->status[2] = 0x00;
- chan->int_on_next_rx = 0;
- chan->outbuf = -1;
+//-------------------------------------------------
+// static_alloc_device_config - allocate a new
+// configuration object
+//-------------------------------------------------
+
+device_config *z80sio_device_config::static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock)
+{
+ return global_alloc(z80sio_device_config(mconfig, tag, owner, clock));
+}
- sio->int_state[0 + 4*ch] = 0;
- sio->int_state[1 + 4*ch] = 0;
- sio->int_state[2 + 4*ch] = 0;
- sio->int_state[3 + 4*ch] = 0;
- interrupt_check(device);
+//-------------------------------------------------
+// alloc_device - allocate a new device object
+//-------------------------------------------------
- /* start the receive timer running */
- timer_adjust_periodic(chan->receive_timer, tpc, ch, tpc);
+device_t *z80sio_device_config::alloc_device(running_machine &machine) const
+{
+ return auto_alloc(&machine, z80sio_device(machine, *this));
}
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
-/***************************************************************************
- CONTROL REGISTER READ/WRITE
-***************************************************************************/
+void z80sio_device_config::device_config_complete()
+{
+ // inherit a copy of the static data
+ const z80sio_interface *intf = reinterpret_cast<const z80sio_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<z80sio_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ m_irq_cb = NULL;
+ m_dtr_changed_cb = NULL;
+ m_rts_changed_cb = NULL;
+ m_break_changed_cb = NULL;
+ m_transmit_cb = NULL;
+ m_receive_poll_cb = NULL;
+ }
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80sio_device - constructor
+//-------------------------------------------------
+
+z80sio_device::z80sio_device(running_machine &_machine, const z80sio_device_config &config)
+ : device_t(_machine, config),
+ device_z80daisy_interface(_machine, config, *this),
+ m_config(config)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void z80sio_device::device_start()
+{
+ m_channel[0].start(this, 0);
+ m_channel[1].start(this, 1);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void z80sio_device::device_reset()
+{
+ // loop over channels
+ for (int ch = 0; ch < 2; ch++)
+ m_channel[ch].reset();
+}
+
+
+
+//**************************************************************************
+// DAISY CHAIN INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// z80daisy_irq_state - return the overall IRQ
+// state for this device
+//-------------------------------------------------
+
+int z80sio_device::z80daisy_irq_state()
+{
+ int state = 0;
+
+ VPRINTF(("sio IRQ state = B:%d%d%d%d A:%d%d%d%d\n",
+ m_int_state[0], m_int_state[1], m_int_state[2], m_int_state[3],
+ m_int_state[4], m_int_state[5], m_int_state[6], m_int_state[7]));
+
+ // loop over all interrupt sources
+ for (int irqsource = 0; irqsource < 8; irqsource++)
+ {
+ int inum = k_int_priority[irqsource];
+
+ // if we're servicing a request, don't indicate more interrupts
+ if (m_int_state[inum] & Z80_DAISY_IEO)
+ {
+ state |= Z80_DAISY_IEO;
+ break;
+ }
+ state |= m_int_state[inum];
+ }
+
+ return state;
+}
-/*-------------------------------------------------
- z80sio_c_w - write to a control register
--------------------------------------------------*/
-WRITE8_DEVICE_HANDLER( z80sio_c_w )
+//-------------------------------------------------
+// z80daisy_irq_ack - acknowledge an IRQ and
+// return the appropriate vector
+//-------------------------------------------------
+
+int z80sio_device::z80daisy_irq_ack()
{
- z80sio *sio = get_safe_token(device);
- int ch = offset & 1;
- sio_channel *chan = &sio->chan[ch];
- int reg = chan->regs[0] & 7;
- UINT8 old = chan->regs[reg];
+ // loop over all interrupt sources
+ for (int irqsource = 0; irqsource < 8; irqsource++)
+ {
+ int inum = k_int_priority[irqsource];
- if (reg != 0 || (reg & 0xf8))
- VPRINTF(("%s:sio_reg_w(%c,%d) = %02X\n", cpuexec_describe_context(device->machine), 'A' + ch, reg, data));
+ // find the first channel with an interrupt requested
+ if (m_int_state[inum] & Z80_DAISY_INT)
+ {
+ VPRINTF(("sio IRQAck %d\n", inum));
+
+ // clear interrupt, switch to the IEO state, and update the IRQs
+ m_int_state[inum] = Z80_DAISY_IEO;
+ update_interrupt_state();
+ return m_channel[1].m_regs[2] + inum * 2;
+ }
+ }
+
+ logerror("z80sio_irq_ack: failed to find an interrupt to ack!\n");
+ return m_channel[1].m_regs[2];
+}
- /* write a new value to the selected register */
- chan->regs[reg] = data;
- /* clear the register number for the next write */
- if (reg != 0)
- chan->regs[0] &= ~7;
+//-------------------------------------------------
+// z80daisy_irq_reti - clear the interrupt
+// pending state to allow other interrupts through
+//-------------------------------------------------
- /* switch off the register for live state changes */
- switch (reg)
+void z80sio_device::z80daisy_irq_reti()
+{
+ // loop over all interrupt sources
+ for (int irqsource = 0; irqsource < 8; irqsource++)
{
- /* SIO write register 0 */
+ int inum = k_int_priority[irqsource];
+
+ // find the first channel with an IEO pending
+ if (m_int_state[inum] & Z80_DAISY_IEO)
+ {
+ VPRINTF(("sio IRQReti %d\n", inum));
+
+ // clear the IEO state and update the IRQs
+ m_int_state[inum] &= ~Z80_DAISY_IEO;
+ update_interrupt_state();
+ return;
+ }
+ }
+
+ logerror("z80sio_irq_reti: failed to find an interrupt to clear IEO on!\n");
+}
+
+
+
+//**************************************************************************
+// SIO CHANNEL
+//**************************************************************************
+
+//-------------------------------------------------
+// sio_channel - constructor
+//-------------------------------------------------
+
+z80sio_device::sio_channel::sio_channel()
+ : m_device(NULL),
+ m_index(0),
+ m_inbuf(-1),
+ m_outbuf(-1),
+ m_int_on_next_rx(false),
+ m_receive_timer(NULL),
+ m_receive_inptr(0),
+ m_receive_outptr(0)
+{
+ memset(m_regs, 0, sizeof(m_regs));
+ memset(m_status, 0, sizeof(m_status));
+ memset(m_receive_buffer, 0, sizeof(m_receive_buffer));
+}
+
+
+//-------------------------------------------------
+// start - channel-specific startup
+//-------------------------------------------------
+
+void z80sio_device::sio_channel::start(z80sio_device *device, int index)
+{
+ m_device = device;
+ m_index = index;
+ m_receive_timer = timer_alloc(&m_device->m_machine, static_serial_callback, this);
+}
+
+
+//-------------------------------------------------
+// reset - reset a single SIO channel
+//-------------------------------------------------
+
+void z80sio_device::sio_channel::reset()
+{
+ m_status[0] = SIO_RR0_TX_BUFFER_EMPTY;
+ m_status[1] = 0x00;
+ m_status[2] = 0x00;
+ m_int_on_next_rx = false;
+ m_outbuf = -1;
+
+ // reset interrupts
+ clear_interrupt(INT_TRANSMIT);
+ clear_interrupt(INT_STATUS);
+ clear_interrupt(INT_RECEIVE);
+ clear_interrupt(INT_ERROR);
+
+ // start the receive timer running
+ attotime tpc = compute_time_per_character();
+ timer_adjust_periodic(m_receive_timer, tpc, 0, tpc);
+}
+
+
+//-------------------------------------------------
+// control_write - write to a control register
+//-------------------------------------------------
+
+void z80sio_device::sio_channel::control_write(UINT8 data)
+{
+ int regnum = m_regs[0] & 7;
+
+ if (regnum != 0 || (regnum & 0xf8) != 0)
+ VPRINTF(("%s:sio_reg_w(%c,%d) = %02X\n", cpuexec_describe_context(&m_device->m_machine), 'A' + m_index, regnum, data));
+
+ // write a new value to the selected register
+ UINT8 old = m_regs[regnum];
+ m_regs[regnum] = data;
+
+ // clear the register number for the next write
+ if (regnum != 0)
+ m_regs[0] &= ~7;
+
+ // switch off the register for live state changes
+ switch (regnum)
+ {
+ // SIO write register 0
case 0:
switch (data & SIO_WR0_COMMAND_MASK)
{
case SIO_WR0_COMMAND_CH_RESET:
- VPRINTF(("%s:SIO reset channel %c\n", cpuexec_describe_context(device->machine), 'A' + ch));
- reset_channel(device, ch);
+ VPRINTF(("%s:SIO reset channel %c\n", cpuexec_describe_context(&m_device->m_machine), 'A' + m_index));
+ reset();
break;
case SIO_WR0_COMMAND_RES_STATUS_INT:
- sio->int_state[INT_CHA_STATUS - 4*ch] &= ~Z80_DAISY_INT;
- interrupt_check(device);
+ clear_interrupt(INT_STATUS);
break;
case SIO_WR0_COMMAND_ENA_RX_INT:
- chan->int_on_next_rx = TRUE;
- interrupt_check(device);
+ m_int_on_next_rx = true;
+ m_device->update_interrupt_state();
break;
case SIO_WR0_COMMAND_RES_TX_INT:
- sio->int_state[INT_CHA_TRANSMIT - 4*ch] &= ~Z80_DAISY_INT;
- interrupt_check(device);
+ clear_interrupt(INT_TRANSMIT);
break;
case SIO_WR0_COMMAND_RES_ERROR:
- sio->int_state[INT_CHA_ERROR - 4*ch] &= ~Z80_DAISY_INT;
- interrupt_check(device);
+ clear_interrupt(INT_ERROR);
break;
}
break;
- /* SIO write register 1 */
+ // SIO write register 1
case 1:
- interrupt_check(device);
+ m_device->update_interrupt_state();
break;
- /* SIO write register 5 */
+ // SIO write register 5
case 5:
- if (((old ^ data) & SIO_WR5_DTR) && sio->dtr_changed_cb)
- (*sio->dtr_changed_cb)(device, ch, (data & SIO_WR5_DTR) != 0);
- if (((old ^ data) & SIO_WR5_SEND_BREAK) && sio->break_changed_cb)
- (*sio->break_changed_cb)(device, ch, (data & SIO_WR5_SEND_BREAK) != 0);
- if (((old ^ data) & SIO_WR5_RTS) && sio->rts_changed_cb)
- (*sio->rts_changed_cb)(device, ch, (data & SIO_WR5_RTS) != 0);
+ if (((old ^ data) & SIO_WR5_DTR) && m_device->m_config.m_dtr_changed_cb)
+ (*m_device->m_config.m_dtr_changed_cb)(m_device, m_index, (data & SIO_WR5_DTR) != 0);
+ if (((old ^ data) & SIO_WR5_SEND_BREAK) && m_device->m_config.m_break_changed_cb)
+ (*m_device->m_config.m_break_changed_cb)(m_device, m_index, (data & SIO_WR5_SEND_BREAK) != 0);
+ if (((old ^ data) & SIO_WR5_RTS) && m_device->m_config.m_rts_changed_cb)
+ (*m_device->m_config.m_rts_changed_cb)(m_device, m_index, (data & SIO_WR5_RTS) != 0);
break;
}
}
-/*-------------------------------------------------
- z80sio_c_r - read from a control register
--------------------------------------------------*/
+//-------------------------------------------------
+// control_read - read from a control register
+//-------------------------------------------------
-READ8_DEVICE_HANDLER( z80sio_c_r )
+UINT8 z80sio_device::sio_channel::control_read()
{
- z80sio *sio = get_safe_token(device);
- int ch = offset & 1;
- sio_channel *chan = &sio->chan[ch];
- int reg = chan->regs[0] & 7;
- UINT8 result = chan->status[reg];
+ int regnum = m_regs[0] & 7;
+ UINT8 result = m_status[regnum];
- /* switch off the register for live state changes */
- switch (reg)
+ // switch off the register for live state changes
+ switch (regnum)
{
- /* SIO read register 0 */
+ // SIO read register 0
case 0:
result &= ~SIO_RR0_INT_PENDING;
- if (z80sio_irq_state(device) & Z80_DAISY_INT)
+ if (m_device->z80daisy_irq_state() & Z80_DAISY_INT)
result |= SIO_RR0_INT_PENDING;
break;
}
- VPRINTF(("%s:sio_reg_r(%c,%d) = %02x\n", cpuexec_describe_context(device->machine), 'A' + ch, reg, chan->status[reg]));
+ VPRINTF(("%s:sio_reg_r(%c,%d) = %02x\n", cpuexec_describe_context(&m_device->m_machine), 'A' + m_index, regnum, m_status[regnum]));
- return chan->status[reg];
+ return m_status[regnum];
}
+//-------------------------------------------------
+// data_write - write to a data register
+//-------------------------------------------------
-
-/***************************************************************************
- DATA REGISTER READ/WRITE
-***************************************************************************/
-
-/*-------------------------------------------------
- z80sio_d_w - write to a data register
--------------------------------------------------*/
-
-WRITE8_DEVICE_HANDLER( z80sio_d_w )
+void z80sio_device::sio_channel::data_write(UINT8 data)
{
- z80sio *sio = get_safe_token(device);
- int ch = offset & 1;
- sio_channel *chan = &sio->chan[ch];
+ VPRINTF(("%s:sio_data_w(%c) = %02X\n", cpuexec_describe_context(&m_device->m_machine), 'A' + m_index, data));
- VPRINTF(("%s:sio_data_w(%c) = %02X\n", cpuexec_describe_context(device->machine), 'A' + ch, data));
-
- /* if tx not enabled, just ignore it */
- if (!(chan->regs[5] & SIO_WR5_TX_ENABLE))
+ // if tx not enabled, just ignore it
+ if (!(m_regs[5] & SIO_WR5_TX_ENABLE))
return;
- /* update the status register */
- chan->status[0] &= ~SIO_RR0_TX_BUFFER_EMPTY;
+ // update the status register
+ m_status[0] &= ~SIO_RR0_TX_BUFFER_EMPTY;
- /* reset the transmit interrupt */
- sio->int_state[INT_CHA_TRANSMIT - 4*ch] &= ~Z80_DAISY_INT;
- interrupt_check(device);
+ // reset the transmit interrupt
+ clear_interrupt(INT_TRANSMIT);
- /* stash the character */
- chan->outbuf = data;
+ // stash the character
+ m_outbuf = data;
}
-/*-------------------------------------------------
- z80sio_d_r - read from a data register
--------------------------------------------------*/
+//-------------------------------------------------
+// data_read - read from a data register
+//-------------------------------------------------
-READ8_DEVICE_HANDLER( z80sio_d_r )
+UINT8 z80sio_device::sio_channel::data_read()
{
- z80sio *sio = get_safe_token(device);
- int ch = offset & 1;
- sio_channel *chan = &sio->chan[ch];
-
- /* update the status register */
- chan->status[0] &= ~SIO_RR0_RX_CHAR_AVAILABLE;
+ // update the status register
+ m_status[0] &= ~SIO_RR0_RX_CHAR_AVAILABLE;
- /* reset the receive interrupt */
- sio->int_state[INT_CHA_RECEIVE - 4*ch] &= ~Z80_DAISY_INT;
- interrupt_check(device);
+ // reset the receive interrupt
+ clear_interrupt(INT_RECEIVE);
- VPRINTF(("%s:sio_data_r(%c) = %02X\n", cpuexec_describe_context(device->machine), 'A' + ch, chan->inbuf));
+ VPRINTF(("%s:sio_data_r(%c) = %02X\n", cpuexec_describe_context(&m_device->m_machine), 'A' + m_index, m_inbuf));
- return chan->inbuf;
+ return m_inbuf;
}
-/***************************************************************************
- CONTROL/DATA REGISTER
-***************************************************************************/
-
-READ8_DEVICE_HANDLER( z80sio_cd_ba_r )
-{
- switch (offset & 3)
- {
- case 0: return z80sio_d_r(device, 0);
- case 1: return z80sio_d_r(device, 1);
- case 2: return z80sio_c_r(device, 0);
- case 3: return z80sio_c_r(device, 1);
- }
-
- return 0xff;
-}
+//-------------------------------------------------
+// dtr - return the state of the DTR line
+//-------------------------------------------------
-WRITE8_DEVICE_HANDLER( z80sio_cd_ba_w )
+int z80sio_device::sio_channel::dtr()
{
- switch (offset & 3)
- {
- case 0: z80sio_d_w(device, 0, data); break;
- case 1: z80sio_d_w(device, 1, data); break;
- case 2: z80sio_c_w(device, 0, data); break;
- case 3: z80sio_c_w(device, 1, data); break;
- }
+ return ((m_regs[5] & SIO_WR5_DTR) != 0);
}
-READ8_DEVICE_HANDLER( z80sio_ba_cd_r )
-{
- switch (offset & 3)
- {
- case 0: return z80sio_d_r(device, 0);
- case 1: return z80sio_c_r(device, 0);
- case 2: return z80sio_d_r(device, 1);
- case 3: return z80sio_c_r(device, 1);
- }
- return 0xff;
-}
+//-------------------------------------------------
+// rts - return the state of the RTS line
+//-------------------------------------------------
-WRITE8_DEVICE_HANDLER( z80sio_ba_cd_w )
+int z80sio_device::sio_channel::rts()
{
- switch (offset & 3)
- {
- case 0: z80sio_d_w(device, 0, data); break;
- case 1: z80sio_c_w(device, 0, data); break;
- case 2: z80sio_d_w(device, 1, data); break;
- case 3: z80sio_c_w(device, 1, data); break;
- }
+ return ((m_regs[5] & SIO_WR5_RTS) != 0);
}
-/***************************************************************************
- CONTROL LINE READ/WRITE
-***************************************************************************/
-
-/*-------------------------------------------------
- z80sio_get_dtr - return the state of the DTR
- line
--------------------------------------------------*/
+//-------------------------------------------------
+// set_cts - set the state of the CTS line
+//-------------------------------------------------
-READ8_DEVICE_HANDLER( z80sio_get_dtr )
+void z80sio_device::sio_channel::set_cts(int state)
{
- z80sio *sio = get_safe_token(device);
- sio_channel *chan = &sio->chan[offset & 1];
- return ((chan->regs[5] & SIO_WR5_DTR) != 0);
+ timer_call_after_resynch(&m_device->m_machine, this, (SIO_RR0_CTS << 1) + (state != 0), static_change_input_line);
}
-/*-------------------------------------------------
- z80sio_get_rts - return the state of the RTS
- line
--------------------------------------------------*/
+//-------------------------------------------------
+// set_dcd - set the state of the DCD line
+//-------------------------------------------------
-READ8_DEVICE_HANDLER( z80sio_get_rts )
+void z80sio_device::sio_channel::set_dcd(int state)
{
- z80sio *sio = get_safe_token(device);
- sio_channel *chan = &sio->chan[offset & 1];
- return ((chan->regs[5] & SIO_WR5_RTS) != 0);
+ timer_call_after_resynch(&m_device->m_machine, this, (SIO_RR0_DCD << 1) + (state != 0), static_change_input_line);
}
-/*-------------------------------------------------
- z80sio_set_cts - set the state of the CTS
- line
--------------------------------------------------*/
+//-------------------------------------------------
+// receive_data - receive data on the input lines
+//-------------------------------------------------
-static TIMER_CALLBACK( change_input_line )
+void z80sio_device::sio_channel::receive_data(int data)
{
- running_device *device = (running_device *)ptr;
- z80sio *sio = get_safe_token(device);
- sio_channel *chan = &sio->chan[param & 1];
- UINT8 line = (param >> 8) & 0xff;
- int state = (param >> 7) & 1;
- int ch = param & 1;
- UINT8 old;
-
- VPRINTF(("sio_change_input_line(%c, %s) = %d\n", 'A' + ch, (line == SIO_RR0_CTS) ? "CTS" : "DCD", state));
-
- /* remember the old value */
- old = chan->status[0];
-
- /* set the bit in the status register */
- chan->status[0] &= ~line;
- if (state)
- chan->status[0] |= line;
-
- /* if state change interrupts are enabled, signal */
- if (((old ^ chan->status[0]) & line) && (chan->regs[1] & SIO_WR1_STATUSINT_ENABLE))
+ // put it on the queue
+ int newinptr = (m_receive_inptr + 1) % ARRAY_LENGTH(m_receive_buffer);
+ if (newinptr != m_receive_outptr)
{
- sio->int_state[INT_CHA_STATUS - 4*ch] |= Z80_DAISY_INT;
- interrupt_check(device);
+ m_receive_buffer[m_receive_inptr] = data;
+ m_receive_inptr = newinptr;
}
+ else
+ logerror("z80sio_receive_data: buffer overrun\n");
}
-/*-------------------------------------------------
- z80sio_set_cts - set the state of the CTS
- line
--------------------------------------------------*/
-
-WRITE8_DEVICE_HANDLER( z80sio_set_cts )
-{
- /* operate deferred */
- void *ptr = (void *)device;
- timer_call_after_resynch(device->machine, ptr, (SIO_RR0_CTS << 8) + (data != 0) * 0x80 + (offset & 1), change_input_line);
-}
-
-
-/*-------------------------------------------------
- z80sio_set_dcd - set the state of the DCD
- line
--------------------------------------------------*/
+//-------------------------------------------------
+// change_input_line - generically change the
+// state of an input line; designed to be called
+// from a timer callback
+//-------------------------------------------------
-WRITE8_DEVICE_HANDLER( z80sio_set_dcd )
+void z80sio_device::sio_channel::change_input_line(int line, int state)
{
- /* operate deferred */
- void *ptr = (void *)device;
- timer_call_after_resynch(device->machine, ptr, (SIO_RR0_DCD << 8) + (data != 0) * 0x80 + (offset & 1), change_input_line);
-}
+ VPRINTF(("sio_change_input_line(%c, %s) = %d\n", 'A' + m_index, (line == SIO_RR0_CTS) ? "CTS" : "DCD", state));
+ // remember the old value
+ UINT8 old = m_status[0];
-/*-------------------------------------------------
- z80sio_receive_data - receive data on the
- input lines
--------------------------------------------------*/
-
-WRITE8_DEVICE_HANDLER( z80sio_receive_data )
-{
- z80sio *sio = get_safe_token(device);
- sio_channel *chan = &sio->chan[offset & 1];
- int newinptr;
+ // set the bit in the status register
+ m_status[0] &= ~line;
+ if (state)
+ m_status[0] |= line;
- /* put it on the queue */
- newinptr = (chan->receive_inptr + 1) % ARRAY_LENGTH(chan->receive_buffer);
- if (newinptr != chan->receive_outptr)
- {
- chan->receive_buffer[chan->receive_inptr] = data;
- chan->receive_inptr = newinptr;
- }
- else
- logerror("z80sio_receive_data: buffer overrun\n");
+ // if state change interrupts are enabled, signal
+ if (((old ^ m_status[0]) & line) && (m_regs[1] & SIO_WR1_STATUSINT_ENABLE))
+ set_interrupt(INT_STATUS);
}
-/*-------------------------------------------------
- serial_callback - callback to pump
- data through
--------------------------------------------------*/
+//-------------------------------------------------
+// serial_callback - callback to pump
+// data through
+//-------------------------------------------------
-static TIMER_CALLBACK( serial_callback )
+void z80sio_device::sio_channel::serial_callback()
{
- running_device *device = (running_device *)ptr;
- z80sio *sio = get_safe_token(device);
- sio_channel *chan = &sio->chan[param];
- int ch = param;
int data = -1;
- /* first perform any outstanding transmits */
- if (chan->outbuf != -1)
+ // first perform any outstanding transmits
+ if (m_outbuf != -1)
{
- VPRINTF(("serial_callback(%c): Transmitting %02x\n", 'A' + ch, chan->outbuf));
+ VPRINTF(("serial_callback(%c): Transmitting %02x\n", 'A' + m_index, m_outbuf));
- /* actually transmit the character */
- if (sio->transmit_cb != NULL)
- (*sio->transmit_cb)(device, ch, chan->outbuf);
+ // actually transmit the character
+ if (m_device->m_config.m_transmit_cb != NULL)
+ (*m_device->m_config.m_transmit_cb)(m_device, m_index, m_outbuf);
- /* update the status register */
- chan->status[0] |= SIO_RR0_TX_BUFFER_EMPTY;
+ // update the status register
+ m_status[0] |= SIO_RR0_TX_BUFFER_EMPTY;
- /* set the transmit buffer empty interrupt if enabled */
- if (chan->regs[1] & SIO_WR1_TXINT_ENABLE)
- {
- sio->int_state[INT_CHA_TRANSMIT - 4*ch] |= Z80_DAISY_INT;
- interrupt_check(device);
- }
+ // set the transmit buffer empty interrupt if enabled
+ if (m_regs[1] & SIO_WR1_TXINT_ENABLE)
+ set_interrupt(INT_TRANSMIT);
- /* reset the output buffer */
- chan->outbuf = -1;
+ // reset the output buffer
+ m_outbuf = -1;
}
- /* ask the polling callback if there is data to receive */
- if (sio->receive_poll_cb != NULL)
- data = (*sio->receive_poll_cb)(device, ch);
+ // ask the polling callback if there is data to receive
+ if (m_device->m_config.m_receive_poll_cb != NULL)
+ data = (*m_device->m_config.m_receive_poll_cb)(m_device, m_index);
- /* if we have buffered data, pull it */
- if (chan->receive_inptr != chan->receive_outptr)
+ // if we have buffered data, pull it
+ if (m_receive_inptr != m_receive_outptr)
{
- data = chan->receive_buffer[chan->receive_outptr];
- chan->receive_outptr = (chan->receive_outptr + 1) % ARRAY_LENGTH(chan->receive_buffer);
+ data = m_receive_buffer[m_receive_outptr];
+ m_receive_outptr = (m_receive_outptr + 1) % ARRAY_LENGTH(m_receive_buffer);
}
- /* if we have data, receive it */
+ // if we have data, receive it
if (data != -1)
{
- VPRINTF(("serial_callback(%c): Receiving %02x\n", 'A' + ch, data));
+ VPRINTF(("serial_callback(%c): Receiving %02x\n", 'A' + m_index, data));
- /* if rx not enabled, just ignore it */
- if (!(chan->regs[3] & SIO_WR3_RX_ENABLE))
+ // if rx not enabled, just ignore it
+ if (!(m_regs[3] & SIO_WR3_RX_ENABLE))
{
VPRINTF((" (ignored because receive is disabled)\n"));
return;
}
- /* stash the data and update the status */
- chan->inbuf = data;
- chan->status[0] |= SIO_RR0_RX_CHAR_AVAILABLE;
+ // stash the data and update the status
+ m_inbuf = data;
+ m_status[0] |= SIO_RR0_RX_CHAR_AVAILABLE;
- /* update our interrupt state */
- switch (chan->regs[1] & SIO_WR1_RXINT_MASK)
+ // update our interrupt state
+ switch (m_regs[1] & SIO_WR1_RXINT_MASK)
{
case SIO_WR1_RXINT_FIRST:
- if (!chan->int_on_next_rx)
+ if (!m_int_on_next_rx)
break;
case SIO_WR1_RXINT_ALL_NOPARITY:
case SIO_WR1_RXINT_ALL_PARITY:
- sio->int_state[INT_CHA_RECEIVE - 4*ch] |= Z80_DAISY_INT;
- interrupt_check(device);
+ set_interrupt(INT_RECEIVE);
break;
}
- chan->int_on_next_rx = FALSE;
+ m_int_on_next_rx = false;
}
}
-/***************************************************************************
- DAISY CHAIN INTERFACE
-***************************************************************************/
-
-static const UINT8 int_priority[] =
-{
- INT_CHA_RECEIVE,
- INT_CHA_TRANSMIT,
- INT_CHA_STATUS,
- INT_CHA_ERROR,
- INT_CHB_RECEIVE,
- INT_CHB_TRANSMIT,
- INT_CHB_STATUS,
- INT_CHB_ERROR
-};
+//**************************************************************************
+// GLOBAL STUBS
+//**************************************************************************
+WRITE8_DEVICE_HANDLER( z80sio_c_w ) { downcast<z80sio_device *>(device)->control_write(offset & 1, data); }
+WRITE8_DEVICE_HANDLER( z80sio_d_w ) { downcast<z80sio_device *>(device)->data_write(offset & 1, data); }
+READ8_DEVICE_HANDLER( z80sio_c_r ) { return downcast<z80sio_device *>(device)->control_read(offset & 1); }
+READ8_DEVICE_HANDLER( z80sio_d_r ) { return downcast<z80sio_device *>(device)->data_read(offset & 1); }
-static int z80sio_irq_state(running_device *device)
-{
- z80sio *sio = get_safe_token(device);
- int state = 0;
- int i;
+READ8_DEVICE_HANDLER( z80sio_get_dtr ) { return downcast<z80sio_device *>(device)->dtr(offset & 1); }
+READ8_DEVICE_HANDLER( z80sio_get_rts ) { return downcast<z80sio_device *>(device)->rts(offset & 1); }
- VPRINTF(("sio IRQ state = B:%d%d%d%d A:%d%d%d%d\n",
- sio->int_state[0], sio->int_state[1], sio->int_state[2], sio->int_state[3],
- sio->int_state[4], sio->int_state[5], sio->int_state[6], sio->int_state[7]));
+WRITE8_DEVICE_HANDLER( z80sio_set_cts ) { downcast<z80sio_device *>(device)->set_cts(offset & 1, data); }
+WRITE8_DEVICE_HANDLER( z80sio_set_dcd ) { downcast<z80sio_device *>(device)->set_dcd(offset & 1, data); }
+WRITE8_DEVICE_HANDLER( z80sio_receive_data ) { downcast<z80sio_device *>(device)->receive_data(offset & 1, data); }
- /* loop over all interrupt sources */
- for (i = 0; i < 8; i++)
+READ8_DEVICE_HANDLER( z80sio_cd_ba_r )
+{
+ switch (offset & 3)
{
- int inum = int_priority[i];
-
- /* if we're servicing a request, don't indicate more interrupts */
- if (sio->int_state[inum] & Z80_DAISY_IEO)
- {
- state |= Z80_DAISY_IEO;
- break;
- }
- state |= sio->int_state[inum];
+ case 0: return z80sio_d_r(device, 0);
+ case 1: return z80sio_d_r(device, 1);
+ case 2: return z80sio_c_r(device, 0);
+ case 3: return z80sio_c_r(device, 1);
}
- return state;
+ return 0xff;
}
-
-static int z80sio_irq_ack(running_device *device)
+WRITE8_DEVICE_HANDLER( z80sio_cd_ba_w )
{
- z80sio *sio = get_safe_token(device);
- int i;
-
- /* loop over all interrupt sources */
- for (i = 0; i < 8; i++)
+ switch (offset & 3)
{
- int inum = int_priority[i];
-
- /* find the first channel with an interrupt requested */
- if (sio->int_state[inum] & Z80_DAISY_INT)
- {
- VPRINTF(("sio IRQAck %d\n", inum));
-
- /* clear interrupt, switch to the IEO state, and update the IRQs */
- sio->int_state[inum] = Z80_DAISY_IEO;
- interrupt_check(device);
- return sio->chan[1].regs[2] + inum * 2;
- }
+ case 0: z80sio_d_w(device, 0, data); break;
+ case 1: z80sio_d_w(device, 1, data); break;
+ case 2: z80sio_c_w(device, 0, data); break;
+ case 3: z80sio_c_w(device, 1, data); break;
}
-
- logerror("z80sio_irq_ack: failed to find an interrupt to ack!\n");
- return sio->chan[1].regs[2];
}
-
-static void z80sio_irq_reti(running_device *device)
+READ8_DEVICE_HANDLER( z80sio_ba_cd_r )
{
- z80sio *sio = get_safe_token(device);
- int i;
-
- /* loop over all interrupt sources */
- for (i = 0; i < 8; i++)
+ switch (offset & 3)
{
- int inum = int_priority[i];
-
- /* find the first channel with an IEO pending */
- if (sio->int_state[inum] & Z80_DAISY_IEO)
- {
- VPRINTF(("sio IRQReti %d\n", inum));
-
- /* clear the IEO state and update the IRQs */
- sio->int_state[inum] &= ~Z80_DAISY_IEO;
- interrupt_check(device);
- return;
- }
+ case 0: return z80sio_d_r(device, 0);
+ case 1: return z80sio_c_r(device, 0);
+ case 2: return z80sio_d_r(device, 1);
+ case 3: return z80sio_c_r(device, 1);
}
- logerror("z80sio_irq_reti: failed to find an interrupt to clear IEO on!\n");
-}
-
-
-static DEVICE_START( z80sio )
-{
- const z80sio_interface *intf = (const z80sio_interface *)device->baseconfig().static_config;
- z80sio *sio = get_safe_token(device);
- void *ptr = (void *)device;
- astring tempstring;
-
- sio->chan[0].receive_timer = timer_alloc(device->machine, serial_callback, ptr);
- sio->chan[1].receive_timer = timer_alloc(device->machine, serial_callback, ptr);
-
- sio->irq_cb = intf->irq_cb;
- sio->dtr_changed_cb = intf->dtr_changed_cb;
- sio->rts_changed_cb = intf->rts_changed_cb;
- sio->break_changed_cb = intf->break_changed_cb;
- sio->transmit_cb = intf->transmit_cb;
- sio->receive_poll_cb = intf->receive_poll_cb;
-}
-
-
-static DEVICE_RESET( z80sio )
-{
- int ch;
-
- /* loop over channels */
- for (ch = 0; ch < 2; ch++)
- reset_channel(device, ch);
+ return 0xff;
}
-
-DEVICE_GET_INFO( z80sio )
+WRITE8_DEVICE_HANDLER( z80sio_ba_cd_w )
{
- switch (state)
+ switch (offset & 3)
{
- /* --- the following bits of info are returned as 64-bit signed integers --- */
- case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(z80sio); 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(z80sio);break;
- case DEVINFO_FCT_STOP: /* Nothing */ break;
- case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(z80sio);break;
- case DEVINFO_FCT_IRQ_STATE: info->f = (genf *)z80sio_irq_state; break;
- case DEVINFO_FCT_IRQ_ACK: info->f = (genf *)z80sio_irq_ack; break;
- case DEVINFO_FCT_IRQ_RETI: info->f = (genf *)z80sio_irq_reti; break;
-
- /* --- the following bits of info are returned as NULL-terminated strings --- */
- case DEVINFO_STR_NAME: strcpy(info->s, "Zilog Z80 SIO"); 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 Nicola Salmoria and the MAME Team"); break;
+ case 0: z80sio_d_w(device, 0, data); break;
+ case 1: z80sio_c_w(device, 0, data); break;
+ case 2: z80sio_d_w(device, 1, data); break;
+ case 3: z80sio_c_w(device, 1, data); break;
}
}
-