From 2f94dc89663db74b15b2860e4a055d7dc5ff0225 Mon Sep 17 00:00:00 2001 From: Ryan Holtz Date: Thu, 26 Aug 2010 17:48:39 +0000 Subject: Updated the i8237 DMA device to no longer be legacy. [Harmony] Non-whatsnew note: I tested filetto, seems to still work properly. --- src/emu/machine/8237dma.c | 640 ++++++++++++++++++++++------------------------ src/emu/machine/8237dma.h | 165 +++++++++++- 2 files changed, 461 insertions(+), 344 deletions(-) diff --git a/src/emu/machine/8237dma.c b/src/emu/machine/8237dma.c index 880400c9396..0dbeca7b2d8 100644 --- a/src/emu/machine/8237dma.c +++ b/src/emu/machine/8237dma.c @@ -21,74 +21,11 @@ #include "emu.h" #include "memconv.h" #include "8237dma.h" +#include "devhelpr.h" - -/* States that the i8237 device can be in */ -typedef enum { - DMA8237_SI, /* Idle state */ - DMA8237_S0, /* HRQ has been triggered, waiting to receive HLDA */ -// DMA8237_SW, /* Wait state */ - - /* Normal transfer states */ - DMA8237_S1, /* Output A8-A15; only used when A8-A15 really needs to be output */ - DMA8237_S2, /* Output A0-A7 */ - DMA8237_S3, /* Initiate read; skipped in compressed timing. On the S2->S3 transition DACK is set. */ - DMA8237_S4, /* Perform read/write */ - - /* Memory to memory transfer states */ - DMA8237_S11, /* Output A8-A15 */ -// DMA8237_S12, /* Output A0-A7 */ -// DMA8237_S13, /* Initiate read */ -// DMA8237_S14, /* Perform read/write */ -// DMA8237_S21, /* Output A8-A15 */ -// DMA8237_S22, /* Output A0-A7 */ -// DMA8237_S23, /* Initiate read */ -// DMA8237_S24, /* Perform read/write */ -} dma8237_state; - - -typedef struct _i8237_t i8237_t; -struct _i8237_t -{ - devcb_resolved_write_line out_hrq_func; - devcb_resolved_write_line out_eop_func; - devcb_resolved_read8 in_memr_func; - devcb_resolved_write8 out_memw_func; - - emu_timer *timer; - - struct - { - devcb_resolved_read8 in_ior_func; - devcb_resolved_write8 out_iow_func; - devcb_resolved_write_line out_dack_func; - UINT16 base_address; - UINT16 base_count; - UINT16 address; - UINT16 count; - UINT8 mode; - int high_address_changed; - } chan[4]; - - UINT32 msb : 1; - UINT32 eop : 1; - UINT8 temp; - UINT8 temporary_data; - UINT8 command; - UINT8 drq; - UINT8 mask; - UINT8 hrq; - UINT8 hlda; - - /* bits 0- 3 : Terminal count for channels 0-3 - * bits 4- 7 : Transfer in progress for channels 0-3 */ - UINT8 status; - - dma8237_state state; /* State the device is currently in */ - int service_channel; /* Channel we will be servicing */ - int last_service_channel; /* Previous channel we serviced; used to determine channel priority. */ -}; - +/*************************************************************************** + MACROS +***************************************************************************/ #define DMA_MODE_CHANNEL(mode) ((mode) & 0x03) #define DMA_MODE_OPERATION(mode) ((mode) & 0x0c) @@ -107,30 +44,126 @@ struct _i8237_t #define DMA8237_CASCADE_MODE 0xc0 -/* ----------------------------------------------------------------------- */ +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +GENERIC_DEVICE_CONFIG_SETUP(i8237, "I8237") + +//------------------------------------------------- +// device_config_complete - perform any +// operations now that the configuration is +// complete +//------------------------------------------------- -INLINE i8237_t *get_safe_token(running_device *device) { - assert( device != NULL ); - assert( device->type() == I8237 ); - return ( i8237_t *) downcast(device)->token(); +void i8237_device_config::device_config_complete() +{ + // inherit a copy of the static data + const i8237_interface *intf = reinterpret_cast(static_config()); + if (intf != NULL) + { + *static_cast(this) = *intf; + } + + // or initialize to defaults if none provided + else + { + memset(&m_out_hrq_func, 0, sizeof(m_out_hrq_func)); + memset(&m_out_eop_func, 0, sizeof(m_out_eop_func)); + memset(&m_in_memr_func, 0, sizeof(m_in_memr_func)); + memset(&m_out_memw_func, 0, sizeof(m_out_memw_func)); + memset(&m_in_ior_func[0], 0, sizeof(m_in_ior_func[0])); + memset(&m_in_ior_func[1], 0, sizeof(m_in_ior_func[1])); + memset(&m_in_ior_func[2], 0, sizeof(m_in_ior_func[2])); + memset(&m_in_ior_func[3], 0, sizeof(m_in_ior_func[3])); + memset(&m_out_iow_func[0], 0, sizeof(m_out_iow_func[0])); + memset(&m_out_iow_func[1], 0, sizeof(m_out_iow_func[1])); + memset(&m_out_iow_func[2], 0, sizeof(m_out_iow_func[2])); + memset(&m_out_iow_func[3], 0, sizeof(m_out_iow_func[3])); + memset(&m_out_dack_func[0], 0, sizeof(m_out_dack_func[0])); + memset(&m_out_dack_func[1], 0, sizeof(m_out_dack_func[1])); + memset(&m_out_dack_func[2], 0, sizeof(m_out_dack_func[2])); + memset(&m_out_dack_func[3], 0, sizeof(m_out_dack_func[3])); + } } -/* ----------------------------------------------------------------------- */ +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +const device_type I8237 = i8237_device_config::static_alloc_device_config; -INLINE void dma8237_do_read( running_device *device ) +//------------------------------------------------- +// i8237_device - constructor +//------------------------------------------------- + +i8237_device::i8237_device(running_machine &_machine, const i8237_device_config &config) + : device_t(_machine, config), + m_config(config) +{ + +} + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void i8237_device::device_start() { - i8237_t *i8237 = get_safe_token( device ); - int channel = i8237->service_channel; + /* resolve callbacks */ + devcb_resolve_write_line(&m_out_hrq_func, &m_config.m_out_hrq_func, this); + devcb_resolve_write_line(&m_out_eop_func, &m_config.m_out_eop_func, this); + devcb_resolve_read8(&m_in_memr_func, &m_config.m_in_memr_func, this); + devcb_resolve_write8(&m_out_memw_func, &m_config.m_out_memw_func, this); - switch( DMA_MODE_OPERATION( i8237->chan[ channel ].mode ) ) + for (int i = 0; i < 4; i++) + { + devcb_resolve_read8(&m_chan[i].m_in_ior_func, &m_config.m_in_ior_func[i], this); + devcb_resolve_write8(&m_chan[i].m_out_iow_func, &m_config.m_out_iow_func[i], this); + devcb_resolve_write_line(&m_chan[i].m_out_dack_func, &m_config.m_out_dack_func[i], this); + } + + m_timer = timer_alloc(&m_machine, i8237_timerproc_callback, (void *)this); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void i8237_device::device_reset() +{ + m_status = 0x0F; + m_eop = 1; + m_state = DMA8237_SI; + m_last_service_channel = 3; + + m_mask = 0x00; + m_status = 0x0F; + m_hrq = 0; + m_hlda = 0; + m_chan[0].m_mode = 0; + m_chan[1].m_mode = 0; + m_chan[2].m_mode = 0; + m_chan[3].m_mode = 0; + + timer_adjust_periodic(m_timer, ATTOTIME_IN_HZ(clock()), 0, ATTOTIME_IN_HZ(clock())); +} + + +void i8237_device::i8237_do_read() +{ + int channel = m_service_channel; + + switch( DMA_MODE_OPERATION( m_chan[ channel ].m_mode ) ) { case DMA8237_WRITE_TRANSFER: - i8237->temporary_data = devcb_call_read8(&i8237->chan[channel].in_ior_func, 0); + m_temporary_data = devcb_call_read8(&m_chan[channel].m_in_ior_func, 0); break; case DMA8237_READ_TRANSFER: - i8237->temporary_data = devcb_call_read8(&i8237->in_memr_func, i8237->chan[ channel ].address); + m_temporary_data = devcb_call_read8(&m_in_memr_func, m_chan[ channel ].m_address); break; case DMA8237_VERIFY_TRANSFER: case DMA8237_ILLEGAL_TRANSFER: @@ -139,18 +172,17 @@ INLINE void dma8237_do_read( running_device *device ) } -INLINE void dma8237_do_write( running_device *device ) +void i8237_device::i8237_do_write() { - i8237_t *i8237 = get_safe_token( device ); - int channel = i8237->service_channel; + int channel = m_service_channel; - switch( DMA_MODE_OPERATION( i8237->chan[ channel ].mode ) ) + switch( DMA_MODE_OPERATION( m_chan[ channel ].m_mode ) ) { case DMA8237_WRITE_TRANSFER: - devcb_call_write8(&i8237->out_memw_func, i8237->chan[ channel ].address, i8237->temporary_data); + devcb_call_write8(&m_out_memw_func, m_chan[ channel ].m_address, m_temporary_data); break; case DMA8237_READ_TRANSFER: - devcb_call_write8(&i8237->chan[channel].out_iow_func, 0, i8237->temporary_data); + devcb_call_write8(&m_chan[channel].m_out_iow_func, 0, m_temporary_data); break; case DMA8237_VERIFY_TRANSFER: case DMA8237_ILLEGAL_TRANSFER: @@ -159,235 +191,252 @@ INLINE void dma8237_do_write( running_device *device ) } -INLINE void dma8237_advance( running_device *device ) +void i8237_device::i8237_advance() { - i8237_t *i8237 = get_safe_token( device ); - int channel = i8237->service_channel; - int mode = i8237->chan[channel].mode; + int channel = m_service_channel; + int mode = m_chan[channel].m_mode; switch ( DMA_MODE_OPERATION( mode ) ) { case DMA8237_VERIFY_TRANSFER: case DMA8237_WRITE_TRANSFER: case DMA8237_READ_TRANSFER: - i8237->chan[channel].high_address_changed = 0; + m_chan[channel].m_high_address_changed = 0; if ( DMA_MODE_DIRECTION( mode ) ) { - i8237->chan[channel].address -= 1; - if ( ( i8237->chan[channel].address & 0xFF ) == 0xFF ) - i8237->chan[channel].high_address_changed = 1; + m_chan[channel].m_address -= 1; + if ( ( m_chan[channel].m_address & 0xFF ) == 0xFF ) + { + m_chan[channel].m_high_address_changed = 1; + } } else { - i8237->chan[channel].address += 1; - if ( ( i8237->chan[channel].address & 0xFF ) == 0x00 ) - i8237->chan[channel].high_address_changed = 1; + m_chan[channel].m_address += 1; + if ( ( m_chan[channel].m_address & 0xFF ) == 0x00 ) + { + m_chan[channel].m_high_address_changed = 1; + } } - i8237->chan[channel].count--; + m_chan[channel].m_count--; - if ( i8237->chan[channel].count == 0xFFFF ) + if ( m_chan[channel].m_count == 0xFFFF ) { /* Set TC bit for this channel */ - i8237->status |= ( 0x01 << channel ); + m_status |= ( 0x01 << channel ); if ( DMA_MODE_AUTO_INIT( mode ) ) { - i8237->chan[channel].address = i8237->chan[channel].base_address; - i8237->chan[channel].count = i8237->chan[channel].base_count; - i8237->chan[channel].high_address_changed = 1; + m_chan[channel].m_address = m_chan[channel].m_base_address; + m_chan[channel].m_count = m_chan[channel].m_base_count; + m_chan[channel].m_high_address_changed = 1; } else { - i8237->mask |= ( 0x01 << channel ); + m_mask |= ( 0x01 << channel ); } } break; case DMA8237_ILLEGAL_TRANSFER: break; } - } -static void set_dack(i8237_t *i8237, int channel) -{ - int i; - for (i = 0; i < 4; i++) +void i8237_device::set_dack(int channel) +{ + for (int i = 0; i < 4; i++) { - int state = (i == channel) ^ !BIT(i8237->command, 7); + int state = (i == channel) ^ !BIT(m_command, 7); - devcb_call_write_line(&i8237->chan[i].out_dack_func, state); + devcb_call_write_line(&m_chan[i].m_out_dack_func, state); } } -static TIMER_CALLBACK( dma8237_timerproc ) + +TIMER_CALLBACK( i8237_device::i8237_timerproc_callback ) { - running_device *device = (running_device *)ptr; - i8237_t *i8237 = get_safe_token(device); + reinterpret_cast(ptr)->i8237_timerproc(); +} + +void i8237_device::i8237_timerproc() +{ /* Check if operation is disabled */ - if ( i8237->command & 0x04 ) + if ( m_command & 0x04 ) + { return; + } - switch ( i8237->state ) { + switch ( m_state ) + { case DMA8237_SI: + { /* Make sure EOP is high */ - if ( ! i8237->eop ) + if ( !m_eop ) { - i8237->eop = 1; - devcb_call_write_line(&i8237->out_eop_func, i8237->eop ? ASSERT_LINE : CLEAR_LINE); + m_eop = 1; + devcb_call_write_line(&m_out_eop_func, m_eop ? ASSERT_LINE : CLEAR_LINE); } /* Check if a new DMA request has been received. */ + /* Bit 6 of the command register determines whether the DREQ signals are active + high or active low. */ + UINT16 pending_request = ( ( m_command & 0x40 ) ? ~m_drq : m_drq ) & ~m_mask; + + if ( pending_request & 0x0f ) { - /* Bit 6 of the command register determines whether the DREQ signals are active - high or active low. */ - UINT16 pending_request = ( ( i8237->command & 0x40 ) ? ~i8237->drq : i8237->drq ) & ~i8237->mask; + int prio_channel = 0; - if ( pending_request & 0x0f ) + /* Determine the channel that should be serviced */ + int channel = ( m_command & 0x10 ) ? m_last_service_channel : 3; + for ( int i = 0; i < 4; i++ ) { - int i, channel, prio_channel = 0; - - /* Determine the channel that should be serviced */ - channel = ( i8237->command & 0x10 ) ? i8237->last_service_channel : 3; - for ( i = 0; i < 4; i++ ) + if ( pending_request & ( 1 << channel ) ) { - if ( pending_request & ( 1 << channel ) ) - prio_channel = channel; - channel = ( channel - 1 ) & 0x03; + prio_channel = channel; } + channel = ( channel - 1 ) & 0x03; + } - /* Store the channel we will be servicing and go to the next state */ - i8237->service_channel = prio_channel; - i8237->last_service_channel = prio_channel; - i8237->hrq = 1; - devcb_call_write_line(&i8237->out_hrq_func, i8237->hrq); - i8237->state = DMA8237_S0; + /* Store the channel we will be servicing and go to the next state */ + m_service_channel = prio_channel; + m_last_service_channel = prio_channel; + m_hrq = 1; + devcb_call_write_line(&m_out_hrq_func, m_hrq); + m_state = DMA8237_S0; - timer_enable( i8237->timer, 1 ); - } - else - { - timer_enable( i8237->timer, 0 ); - } + timer_enable( m_timer, 1 ); + } + else + { + timer_enable( m_timer, 0 ); } break; + } case DMA8237_S0: /* S0 is the first of the DMA service. We have requested a hold but are waiting for confirmation. */ - if ( i8237->hlda ) + if ( m_hlda ) { - if ( i8237->command & 0x01 ) + if ( m_command & 0x01 ) { /* Memory-to-memory transfers */ - i8237->state = DMA8237_S11; + m_state = DMA8237_S11; } else { /* Regular transfers */ - i8237->state = DMA8237_S1; + m_state = DMA8237_S1; } } break; case DMA8237_S1: /* Output A8-A15 */ - i8237->state = DMA8237_S2; + m_state = DMA8237_S2; break; case DMA8237_S2: /* Output A7-A0 */ /* set DACK */ - set_dack(i8237, i8237->service_channel); + set_dack(m_service_channel); /* Check for compressed timing */ - if ( i8237->command & 0x08 ) - i8237->state = DMA8237_S4; + if ( m_command & 0x08 ) + { + m_state = DMA8237_S4; + } else - i8237->state = DMA8237_S3; + { + m_state = DMA8237_S3; + } break; case DMA8237_S3: /* Initiate read */ - dma8237_do_read( device ); - i8237->state = DMA8237_S4; + i8237_do_read(); + m_state = DMA8237_S4; break; case DMA8237_S4: /* Perform read/write */ /* Perform read when in compressed timing mode */ - if ( i8237->command & 0x08 ) - dma8237_do_read( device ); + if ( m_command & 0x08 ) + { + i8237_do_read(); + } /* Perform write */ - dma8237_do_write( device ); + i8237_do_write(); + /* Advance */ - dma8237_advance( device ); + i8237_advance(); { - int channel = i8237->service_channel; + int channel = m_service_channel; - switch( DMA_MODE_TRANSFERMODE( i8237->chan[channel].mode ) ) + switch( DMA_MODE_TRANSFERMODE( m_chan[channel].m_mode ) ) { case DMA8237_DEMAND_MODE: /* Check for terminal count or EOP signal or DREQ begin de-asserted */ - if ( ( i8237->status & ( 0x01 << channel ) ) || ! i8237->eop || ! ( i8237->drq & ( 0x01 << channel ) ) ) + if ( ( m_status & ( 0x01 << channel ) ) || !m_eop || !( m_drq & ( 0x01 << channel ) ) ) { - i8237->hrq = 0; - i8237->hlda = 0; - devcb_call_write_line(&i8237->out_hrq_func, i8237->hrq); - i8237->state = DMA8237_SI; + m_hrq = 0; + m_hlda = 0; + devcb_call_write_line(&m_out_hrq_func, m_hrq); + m_state = DMA8237_SI; } else { - i8237->state = i8237->chan[channel].high_address_changed ? DMA8237_S1 : DMA8237_S2; + m_state = m_chan[channel].m_high_address_changed ? DMA8237_S1 : DMA8237_S2; } break; case DMA8237_SINGLE_MODE: - i8237->hrq = 0; - i8237->hlda = 0; - devcb_call_write_line(&i8237->out_hrq_func, i8237->hrq); - i8237->state = DMA8237_SI; + m_hrq = 0; + m_hlda = 0; + devcb_call_write_line(&m_out_hrq_func, m_hrq); + m_state = DMA8237_SI; break; case DMA8237_BLOCK_MODE: /* Check for terminal count or EOP signal */ - if ( ( i8237->status & ( 0x01 << channel ) ) || ! i8237->eop ) + if ( ( m_status & ( 0x01 << channel ) ) || !m_eop ) { - i8237->hrq = 0; - i8237->hlda = 0; - devcb_call_write_line(&i8237->out_hrq_func, i8237->hrq); - i8237->state = DMA8237_SI; + m_hrq = 0; + m_hlda = 0; + devcb_call_write_line(&m_out_hrq_func, m_hrq); + m_state = DMA8237_SI; } else { - i8237->state = i8237->chan[channel].high_address_changed ? DMA8237_S1 : DMA8237_S2; + m_state = m_chan[channel].m_high_address_changed ? DMA8237_S1 : DMA8237_S2; } break; case DMA8237_CASCADE_MODE: - if ( ! ( i8237->drq & ( 0x01 << channel ) ) ) + if ( ! ( m_drq & ( 0x01 << channel ) ) ) { - i8237->hrq = 0; - i8237->hlda = 0; - devcb_call_write_line(&i8237->out_hrq_func, i8237->hrq); - i8237->state = DMA8237_SI; + m_hrq = 0; + m_hlda = 0; + devcb_call_write_line(&m_out_hrq_func, m_hrq); + m_state = DMA8237_SI; } break; } /* Check if EOP output needs to be asserted */ - if ( i8237->status & ( 0x01 << channel ) ) + if ( m_status & ( 0x01 << channel ) ) { - i8237->eop = 0; - devcb_call_write_line(&i8237->out_eop_func, i8237->eop ? ASSERT_LINE : CLEAR_LINE); + m_eop = 0; + devcb_call_write_line(&m_out_eop_func, m_eop ? ASSERT_LINE : CLEAR_LINE); } } /* clear DACK */ - set_dack(i8237, -1); + set_dack(-1); break; case DMA8237_S11: /* Output A8-A15 */ @@ -396,14 +445,8 @@ static TIMER_CALLBACK( dma8237_timerproc ) } - - -/* ----------------------------------------------------------------------- */ - - -READ8_DEVICE_HANDLER( i8237_r ) +READ8_DEVICE_HANDLER_TRAMPOLINE(i8237, i8237_r) { - i8237_t *i8237 = get_safe_token(device); UINT8 data = 0xFF; offset &= 0x0F; @@ -414,8 +457,8 @@ READ8_DEVICE_HANDLER( i8237_r ) case 4: case 6: /* DMA address register */ - data = i8237->chan[offset / 2].address >> (i8237->msb ? 8 : 0); - i8237->msb ^= 1; + data = m_chan[offset / 2].m_address >> (m_msb ? 8 : 0); + m_msb ^= 1; break; case 1: @@ -423,26 +466,26 @@ READ8_DEVICE_HANDLER( i8237_r ) case 5: case 7: /* DMA count register */ - data = i8237->chan[offset / 2].count >> (i8237->msb ? 8 : 0); - i8237->msb ^= 1; + data = m_chan[offset / 2].m_count >> (m_msb ? 8 : 0); + m_msb ^= 1; break; case 8: /* DMA status register */ - data = (UINT8) i8237->status; + data = (UINT8) m_status; /* TC bits are cleared on a status read */ - i8237->status &= 0xF0; + m_status &= 0xF0; break; case 10: /* DMA mask register */ - data = i8237->mask; + data = m_mask; break; case 13: /* DMA master clear */ - data = i8237->temp; + data = m_temp; break; case 9: /* DMA write request register */ @@ -458,12 +501,8 @@ READ8_DEVICE_HANDLER( i8237_r ) } - -WRITE8_DEVICE_HANDLER( i8237_w ) +WRITE8_DEVICE_HANDLER_TRAMPOLINE(i8237, i8237_w) { - i8237_t *i8237 = get_safe_token(device); - int channel; - offset &= 0x0F; logerror("i8237_w: offset = %02x, data = %02x\n", offset, data ); @@ -473,205 +512,144 @@ WRITE8_DEVICE_HANDLER( i8237_w ) case 2: case 4: case 6: + { /* DMA address register */ - channel = offset / 2; - if (i8237->msb) + int channel = offset / 2; + if (m_msb) { - i8237->chan[channel].base_address = ( i8237->chan[channel].base_address & 0x00FF ) | ( data << 8 ); - i8237->chan[channel].address = ( i8237->chan[channel].address & 0x00FF ) | ( data << 8 ); + m_chan[channel].m_base_address = ( m_chan[channel].m_base_address & 0x00FF ) | ( data << 8 ); + m_chan[channel].m_address = ( m_chan[channel].m_address & 0x00FF ) | ( data << 8 ); } else { - i8237->chan[channel].base_address = ( i8237->chan[channel].base_address & 0xFF00 ) | data; - i8237->chan[channel].address = ( i8237->chan[channel].address & 0xFF00 ) | data; + m_chan[channel].m_base_address = ( m_chan[channel].m_base_address & 0xFF00 ) | data; + m_chan[channel].m_address = ( m_chan[channel].m_address & 0xFF00 ) | data; } - i8237->msb ^= 1; + m_msb ^= 1; break; + } case 1: case 3: case 5: case 7: + { /* DMA count register */ - channel = offset / 2; - if (i8237->msb) + int channel = offset / 2; + if (m_msb) { - i8237->chan[channel].base_count = ( i8237->chan[channel].base_count & 0x00FF ) | ( data << 8 ); - i8237->chan[channel].count = ( i8237->chan[channel].count & 0x00FF ) | ( data << 8 ); + m_chan[channel].m_base_count = ( m_chan[channel].m_base_count & 0x00FF ) | ( data << 8 ); + m_chan[channel].m_count = ( m_chan[channel].m_count & 0x00FF ) | ( data << 8 ); } else { - i8237->chan[channel].base_count = ( i8237->chan[channel].base_count & 0xFF00 ) | data; - i8237->chan[channel].count = ( i8237->chan[channel].count & 0xFF00 ) | data; + m_chan[channel].m_base_count = ( m_chan[channel].m_base_count & 0xFF00 ) | data; + m_chan[channel].m_count = ( m_chan[channel].m_count & 0xFF00 ) | data; } - i8237->msb ^= 1; + m_msb ^= 1; break; + } case 8: /* DMA command register */ - i8237->command = data; - timer_enable( i8237->timer, ( i8237->command & 0x04 ) ? 0 : 1 ); + m_command = data; + timer_enable( m_timer, ( m_command & 0x04 ) ? 0 : 1 ); break; case 9: + { /* DMA request register */ - channel = DMA_MODE_CHANNEL(data); + int channel = DMA_MODE_CHANNEL(data); if ( data & 0x04 ) { - i8237->drq |= 0x01 << channel; - timer_enable( i8237->timer, ( i8237->command & 0x04 ) ? 0 : 1 ); + m_drq |= 0x01 << channel; + timer_enable( m_timer, ( m_command & 0x04 ) ? 0 : 1 ); } else { - i8237->status &= ~ ( 0x10 << channel ); - i8237->drq &= ~ ( 0x01 << channel ); + m_status &= ~ ( 0x10 << channel ); + m_drq &= ~ ( 0x01 << channel ); } break; + } case 10: + { /* DMA mask register */ - channel = DMA_MODE_CHANNEL(data); + int channel = DMA_MODE_CHANNEL(data); if (data & 0x04) - i8237->mask |= 0x11 << channel; + { + m_mask |= 0x11 << channel; + } else - i8237->mask &= ~(0x11 << channel); + { + m_mask &= ~(0x11 << channel); + } break; + } case 11: + { /* DMA mode register */ - channel = DMA_MODE_CHANNEL(data); - i8237->chan[channel].mode = data; + int channel = DMA_MODE_CHANNEL(data); + m_chan[channel].m_mode = data; /* Apparently mode writes also clear the TC bit(?) */ - i8237->status &= ~ ( 1 << channel ); + m_status &= ~ ( 1 << channel ); break; + } case 12: /* DMA clear byte pointer flip-flop */ - i8237->temp = data; - i8237->msb = 0; + m_temp = data; + m_msb = 0; break; case 13: /* DMA master clear */ - i8237->msb = 0; - i8237->mask = 0x0f; - i8237->state = DMA8237_SI; - i8237->status &= 0xF0; + m_msb = 0; + m_mask = 0x0f; + m_state = DMA8237_SI; + m_status &= 0xF0; break; case 14: /* DMA clear mask register */ - i8237->mask &= ~data; - i8237->mask = 0; + m_mask &= ~data; + m_mask = 0; break; case 15: /* DMA write mask register */ - i8237->mask = data & 0x0f; + m_mask = data & 0x0f; break; } } - -static void dma8237_drq_write(running_device *device, int channel, int state) +void i8237_device::i8237_drq_write(int channel, int state) { - i8237_t *i8237 = get_safe_token( device ); - if (state) - i8237->drq |= ( 0x01 << channel ); + { + m_drq |= ( 0x01 << channel ); + } else - i8237->drq &= ~( 0x01 << channel ); - - timer_enable( i8237->timer, ( i8237->command & 0x04 ) ? 0 : 1 ); -} - -WRITE_LINE_DEVICE_HANDLER( i8237_hlda_w ) -{ - i8237_t *i8237 = get_safe_token( device ); - - i8237->hlda = state; -} - -WRITE_LINE_DEVICE_HANDLER( i8237_ready_w ) -{ -} - -WRITE_LINE_DEVICE_HANDLER( i8237_dreq0_w ) { dma8237_drq_write(device, 0, state); } -WRITE_LINE_DEVICE_HANDLER( i8237_dreq1_w ) { dma8237_drq_write(device, 1, state); } -WRITE_LINE_DEVICE_HANDLER( i8237_dreq2_w ) { dma8237_drq_write(device, 2, state); } -WRITE_LINE_DEVICE_HANDLER( i8237_dreq3_w ) { dma8237_drq_write(device, 3, state); } - -WRITE_LINE_DEVICE_HANDLER( i8237_eop_w ) -{ -} - - -static DEVICE_START( i8237 ) { - i8237_t *i8237 = get_safe_token(device); - i8237_interface *intf = (i8237_interface *)device->baseconfig().static_config(); - int i; - - /* resolve callbacks */ - devcb_resolve_write_line(&i8237->out_hrq_func, &intf->out_hrq_func, device); - devcb_resolve_write_line(&i8237->out_eop_func, &intf->out_eop_func, device); - devcb_resolve_read8(&i8237->in_memr_func, &intf->in_memr_func, device); - devcb_resolve_write8(&i8237->out_memw_func, &intf->out_memw_func, device); - - for (i = 0; i < 4; i++) { - devcb_resolve_read8(&i8237->chan[i].in_ior_func, &intf->in_ior_func[i], device); - devcb_resolve_write8(&i8237->chan[i].out_iow_func, &intf->out_iow_func[i], device); - devcb_resolve_write_line(&i8237->chan[i].out_dack_func, &intf->out_dack_func[i], device); + m_drq &= ~( 0x01 << channel ); } - i8237->timer = timer_alloc(device->machine, dma8237_timerproc, (void *)device); + timer_enable( m_timer, ( m_command & 0x04 ) ? 0 : 1 ); } -static DEVICE_RESET( i8237 ) { - i8237_t *i8237 = get_safe_token(device); - - i8237->status = 0x0F; - i8237->eop = 1; - i8237->state = DMA8237_SI; - i8237->last_service_channel = 3; - - i8237->mask = 0x00; - i8237->status = 0x0F; - i8237->hrq = 0; - i8237->hlda = 0; - i8237->chan[0].mode = 0; - i8237->chan[1].mode = 0; - i8237->chan[2].mode = 0; - i8237->chan[3].mode = 0; - - timer_adjust_periodic(i8237->timer, - ATTOTIME_IN_HZ(device->clock()), - 0, - ATTOTIME_IN_HZ(device->clock())); -} - - -DEVICE_GET_INFO( i8237 ) { - switch ( state ) { - /* --- the following bits of info are returned as 64-bit signed integers --- */ - case DEVINFO_INT_TOKEN_BYTES: info->i = sizeof(i8237_t); break; - case DEVINFO_INT_INLINE_CONFIG_BYTES: info->i = 0; break; - - /* --- the following bits of info are returned as pointers to data or functions --- */ - case DEVINFO_FCT_START: info->start = DEVICE_START_NAME(i8237); break; - case DEVINFO_FCT_STOP: /* nothing */ break; - case DEVINFO_FCT_RESET: info->reset = DEVICE_RESET_NAME(i8237); break; - - /* --- the following bits of info are returned as NULL-terminated strings --- */ - case DEVINFO_STR_NAME: strcpy(info->s, "Intel 8237"); break; - case DEVINFO_STR_FAMILY: strcpy(info->s, "Intel 8080"); break; - case DEVINFO_STR_VERSION: strcpy(info->s, "1.01"); break; - case DEVINFO_STR_SOURCE_FILE: strcpy(info->s, __FILE__); break; - case DEVINFO_STR_CREDITS: strcpy(info->s, "Copyright the MAME and MESS Teams"); break; - } -} +/*************************************************************************** + TRAMPOLINES +***************************************************************************/ -DEFINE_LEGACY_DEVICE(I8237, i8237); +WRITE_LINE_DEVICE_HANDLER( i8237_hlda_w ) { downcast(device)->i8237_hlda_w(state); } +WRITE_LINE_DEVICE_HANDLER( i8237_ready_w ) { } +WRITE_LINE_DEVICE_HANDLER( i8237_dreq0_w ) { downcast(device)->i8237_drq_write(0, state); } +WRITE_LINE_DEVICE_HANDLER( i8237_dreq1_w ) { downcast(device)->i8237_drq_write(1, state); } +WRITE_LINE_DEVICE_HANDLER( i8237_dreq2_w ) { downcast(device)->i8237_drq_write(2, state); } +WRITE_LINE_DEVICE_HANDLER( i8237_dreq3_w ) { downcast(device)->i8237_drq_write(3, state); } +WRITE_LINE_DEVICE_HANDLER( i8237_eop_w ) { } diff --git a/src/emu/machine/8237dma.h b/src/emu/machine/8237dma.h index fcdd82c8444..3d10feff977 100644 --- a/src/emu/machine/8237dma.h +++ b/src/emu/machine/8237dma.h @@ -30,18 +30,19 @@ ***************************************************************************/ +#pragma once + #ifndef __I8237__ #define __I8237__ -#include "devlegcy.h" +#include "emu.h" + /*************************************************************************** - MACROS / CONSTANTS + DEVICE CONFIGURATION MACROS ***************************************************************************/ -DECLARE_LEGACY_DEVICE(I8237, i8237); - #define MDRV_I8237_ADD(_tag, _clock, _config) \ MDRV_DEVICE_ADD(_tag, I8237, _clock) \ MDRV_DEVICE_CONFIG(_config) @@ -49,26 +50,164 @@ DECLARE_LEGACY_DEVICE(I8237, i8237); #define I8237_INTERFACE(_name) \ const i8237_interface (_name) = + /*************************************************************************** TYPE DEFINITIONS ***************************************************************************/ -typedef struct _i8237_interface i8237_interface; -struct _i8237_interface + +// ======================> i8237_interface + +struct i8237_interface { - devcb_write_line out_hrq_func; - devcb_write_line out_eop_func; + devcb_write_line m_out_hrq_func; + devcb_write_line m_out_eop_func; /* accessors to main memory */ - devcb_read8 in_memr_func; - devcb_write8 out_memw_func; + devcb_read8 m_in_memr_func; + devcb_write8 m_out_memw_func; /* channel accessors */ - devcb_read8 in_ior_func[4]; - devcb_write8 out_iow_func[4]; - devcb_write_line out_dack_func[4]; + devcb_read8 m_in_ior_func[4]; + devcb_write8 m_out_iow_func[4]; + devcb_write_line m_out_dack_func[4]; }; + + +// ======================> i8237_device_config + +class i8237_device_config : public device_config, + public i8237_interface +{ + friend class i8237_device; + + // construction/destruction + i8237_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + +public: + // allocators + static device_config *static_alloc_device_config(const machine_config &mconfig, const char *tag, const device_config *owner, UINT32 clock); + virtual device_t *alloc_device(running_machine &machine) const; + +protected: + // device_config overrides + virtual void device_config_complete(); +}; + + + +// ======================> i8237_device + +class i8237_device : public device_t +{ + friend class i8237_device_config; + + // construction/destruction + i8237_device(running_machine &_machine, const i8237_device_config &_config); + +public: + + /* register access */ + UINT8 i8237_r(UINT32 offset); + void i8237_w(UINT32 offset, UINT8 data); + + /* hold acknowledge */ + void i8237_hlda_w(UINT8 state) { m_hlda = state; } + + /* data request */ + void i8237_drq_write(int channel, int state); + + void i8237_timerproc(); + +protected: + // device-level overrides + virtual void device_start(); + virtual void device_reset(); + virtual void device_post_load() { } + virtual void device_clock_changed() { } + + static TIMER_CALLBACK( i8237_timerproc_callback ); + static TIMER_CALLBACK( receive_event_callback ); + +private: + + void i8237_do_read(); + void i8237_do_write(); + void i8237_advance(); + void set_dack(int channel); + + /* States that the i8237 device can be in */ + enum dma8237_state + { + DMA8237_SI, /* Idle state */ + DMA8237_S0, /* HRQ has been triggered, waiting to receive HLDA */ + // DMA8237_SW, /* Wait state */ + + /* Normal transfer states */ + DMA8237_S1, /* Output A8-A15; only used when A8-A15 really needs to be output */ + DMA8237_S2, /* Output A0-A7 */ + DMA8237_S3, /* Initiate read; skipped in compressed timing. On the S2->S3 transition DACK is set. */ + DMA8237_S4, /* Perform read/write */ + + /* Memory to memory transfer states */ + DMA8237_S11, /* Output A8-A15 */ + // DMA8237_S12, /* Output A0-A7 */ + // DMA8237_S13, /* Initiate read */ + // DMA8237_S14, /* Perform read/write */ + // DMA8237_S21, /* Output A8-A15 */ + // DMA8237_S22, /* Output A0-A7 */ + // DMA8237_S23, /* Initiate read */ + // DMA8237_S24, /* Perform read/write */ + }; + + devcb_resolved_write_line m_out_hrq_func; + devcb_resolved_write_line m_out_eop_func; + devcb_resolved_read8 m_in_memr_func; + devcb_resolved_write8 m_out_memw_func; + + emu_timer *m_timer; + + struct + { + devcb_resolved_read8 m_in_ior_func; + devcb_resolved_write8 m_out_iow_func; + devcb_resolved_write_line m_out_dack_func; + UINT16 m_base_address; + UINT16 m_base_count; + UINT16 m_address; + UINT16 m_count; + UINT8 m_mode; + int m_high_address_changed; + } m_chan[4]; + + UINT32 m_msb : 1; + UINT32 m_eop : 1; + UINT8 m_temp; + UINT8 m_temporary_data; + UINT8 m_command; + UINT8 m_drq; + UINT8 m_mask; + UINT8 m_hrq; + UINT8 m_hlda; + + /* bits 0- 3 : Terminal count for channels 0-3 + * bits 4- 7 : Transfer in progress for channels 0-3 */ + UINT8 m_status; + + dma8237_state m_state; /* State the device is currently in */ + int m_service_channel; /* Channel we will be servicing */ + int m_last_service_channel; /* Previous channel we serviced; used to determine channel priority. */ + + const i8237_device_config &m_config; +}; + + +// device type definition +extern const device_type I8237; + + + /*************************************************************************** PROTOTYPES ***************************************************************************/ -- cgit v1.2.3