mirror of
https://github.com/holub/mame
synced 2025-05-29 17:13:05 +03:00
Made the 8237 dma controller emulation more accurate by implementing it as a state machine.
Deprecated the dma8237_run_transfer function.
This commit is contained in:
parent
a736dab1eb
commit
145186f9f8
@ -23,44 +23,83 @@
|
||||
#include "8237dma.h"
|
||||
|
||||
|
||||
/* States that the dma8237 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 dma8237 dma8237_t;
|
||||
|
||||
struct dma8237
|
||||
{
|
||||
const struct dma8237_interface *intf;
|
||||
emu_timer *timer;
|
||||
emu_timer *msbflip_timer;
|
||||
|
||||
struct
|
||||
{
|
||||
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. */
|
||||
};
|
||||
|
||||
|
||||
#define DMA_MODE_CHANNEL(mode) ((mode) & 0x03)
|
||||
#define DMA_MODE_OPERATION(mode) (((mode) >> 2) & 0x03)
|
||||
#define DMA_MODE_DIRECTION(mode) (((mode) & 0x20) ? -1 : +1)
|
||||
#define DMA_MODE_TRANSFERMODE(mode) (((mode) >> 6) & 0x03)
|
||||
#define DMA_MODE_OPERATION(mode) ((mode) & 0x0c)
|
||||
#define DMA_MODE_AUTO_INIT(mode) ((mode) & 0x10)
|
||||
#define DMA_MODE_DIRECTION(mode) ((mode) & 0x20)
|
||||
#define DMA_MODE_TRANSFERMODE(mode) ((mode) & 0xc0)
|
||||
|
||||
#define DMA8237_VERIFY_TRANSFER 0x00
|
||||
#define DMA8237_WRITE_TRANSFER 0x04
|
||||
#define DMA8237_READ_TRANSFER 0x08
|
||||
#define DMA8237_ILLEGAL_TRANSFER 0x0c
|
||||
|
||||
#define DMA8237_DEMAND_MODE 0x00
|
||||
#define DMA8237_SINGLE_MODE 0x40
|
||||
#define DMA8237_BLOCK_MODE 0x80
|
||||
#define DMA8237_CASCADE_MODE 0xc0
|
||||
|
||||
static TIMER_CALLBACK( dma8237_timerproc );
|
||||
static TIMER_CALLBACK( dma8237_msbflip_timerproc );
|
||||
static void dma8237_update_status(const device_config *device);
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
@ -75,141 +114,277 @@ INLINE dma8237_t *get_safe_token(const device_config *device) {
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
static int dma8237_do_operation(const device_config *device, int channel)
|
||||
INLINE void dma8237_do_read( const device_config *device )
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
int done;
|
||||
UINT8 data;
|
||||
UINT8 mode;
|
||||
dma8237_t *dma8237 = get_safe_token( device );
|
||||
int channel = dma8237->service_channel;
|
||||
|
||||
mode = dma8237->chan[channel].mode;
|
||||
|
||||
switch(DMA_MODE_OPERATION(mode)) {
|
||||
case 1:
|
||||
data = dma8237->intf->channel_read_func[channel](device);
|
||||
dma8237->intf->memory_write_func(device, channel, dma8237->chan[channel].address, data);
|
||||
|
||||
dma8237->chan[channel].address += DMA_MODE_DIRECTION(mode);
|
||||
dma8237->chan[channel].count--;
|
||||
done = (dma8237->chan[channel].count == 0xFFFF);
|
||||
switch( DMA_MODE_OPERATION( dma8237->chan[ channel ].mode ) )
|
||||
{
|
||||
case DMA8237_WRITE_TRANSFER:
|
||||
dma8237->temporary_data = dma8237->intf->channel_read_func[ channel ]( device );
|
||||
break;
|
||||
|
||||
case 2:
|
||||
data = dma8237->intf->memory_read_func(device, channel, dma8237->chan[channel].address);
|
||||
dma8237->intf->channel_write_func[channel](device, data);
|
||||
|
||||
dma8237->chan[channel].address += DMA_MODE_DIRECTION(mode);
|
||||
dma8237->chan[channel].count--;
|
||||
done = (dma8237->chan[channel].count == 0xFFFF);
|
||||
case DMA8237_READ_TRANSFER:
|
||||
dma8237->temporary_data = dma8237->intf->memory_read_func( device, channel, dma8237->chan[ channel ].address );
|
||||
break;
|
||||
|
||||
default:
|
||||
done = TRUE;
|
||||
case DMA8237_VERIFY_TRANSFER:
|
||||
case DMA8237_ILLEGAL_TRANSFER:
|
||||
break;
|
||||
}
|
||||
return done;
|
||||
}
|
||||
|
||||
|
||||
INLINE void dma8237_do_write( const device_config *device )
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token( device );
|
||||
int channel = dma8237->service_channel;
|
||||
|
||||
switch( DMA_MODE_OPERATION( dma8237->chan[ channel ].mode ) )
|
||||
{
|
||||
case DMA8237_WRITE_TRANSFER:
|
||||
dma8237->intf->memory_write_func( device, channel, dma8237->chan[ channel ].address, dma8237->temporary_data );
|
||||
break;
|
||||
case DMA8237_READ_TRANSFER:
|
||||
dma8237->intf->channel_write_func[channel]( device, dma8237->temporary_data );
|
||||
break;
|
||||
case DMA8237_VERIFY_TRANSFER:
|
||||
case DMA8237_ILLEGAL_TRANSFER:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INLINE void dma8237_advance( const device_config *device )
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token( device );
|
||||
int channel = dma8237->service_channel;
|
||||
int mode = dma8237->chan[channel].mode;
|
||||
|
||||
switch ( DMA_MODE_OPERATION( mode ) )
|
||||
{
|
||||
case DMA8237_VERIFY_TRANSFER:
|
||||
case DMA8237_WRITE_TRANSFER:
|
||||
case DMA8237_READ_TRANSFER:
|
||||
dma8237->chan[channel].high_address_changed = 0;
|
||||
|
||||
if ( DMA_MODE_DIRECTION( mode ) )
|
||||
{
|
||||
dma8237->chan[channel].address -= 1;
|
||||
if ( ( dma8237->chan[channel].address & 0xFF ) == 0xFF )
|
||||
dma8237->chan[channel].high_address_changed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma8237->chan[channel].address += 1;
|
||||
if ( ( dma8237->chan[channel].address & 0xFF ) == 0x00 )
|
||||
dma8237->chan[channel].high_address_changed = 1;
|
||||
}
|
||||
|
||||
dma8237->chan[channel].count--;
|
||||
|
||||
if ( dma8237->chan[channel].count == 0xFFFF )
|
||||
{
|
||||
/* Set TC bit for this channel */
|
||||
dma8237->status |= ( 0x01 << channel );
|
||||
|
||||
if ( DMA_MODE_AUTO_INIT( mode ) )
|
||||
{
|
||||
dma8237->chan[channel].address = dma8237->chan[channel].base_address;
|
||||
dma8237->chan[channel].count = dma8237->chan[channel].base_count;
|
||||
dma8237->chan[channel].high_address_changed = 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma8237->mask |= ( 0x01 << channel );
|
||||
}
|
||||
}
|
||||
break;
|
||||
case DMA8237_ILLEGAL_TRANSFER:
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
static TIMER_CALLBACK( dma8237_timerproc )
|
||||
{
|
||||
const device_config *device = (const device_config *)ptr;
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
int channel = param % 4;
|
||||
int done;
|
||||
|
||||
done = dma8237_do_operation(device, channel);
|
||||
/* Check if operation is disabled */
|
||||
if ( dma8237->command & 0x04 )
|
||||
return;
|
||||
|
||||
if (done)
|
||||
{
|
||||
dma8237->status &= ~(0x10 << channel);
|
||||
dma8237->status |= (0x01 << channel);
|
||||
dma8237->drq &= ~(0x01 << channel);
|
||||
dma8237_update_status(device);
|
||||
}
|
||||
}
|
||||
switch ( dma8237->state ) {
|
||||
|
||||
|
||||
|
||||
static TIMER_CALLBACK( dma8237_msbflip_timerproc )
|
||||
{
|
||||
const device_config *device = (const device_config *)ptr;
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
dma8237->msb ^= 1;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static void dma8237_update_status(const device_config *device)
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
UINT16 pending_transfer;
|
||||
int channel;
|
||||
UINT32 new_eop;
|
||||
|
||||
if ((dma8237->status & 0xF0) == 0)
|
||||
{
|
||||
/* no transfer is active right now; is there a transfer pending right now? */
|
||||
pending_transfer = dma8237->drq & ~dma8237->mask;
|
||||
|
||||
if (pending_transfer)
|
||||
case DMA8237_SI:
|
||||
/* Make sure EOP is high */
|
||||
if ( ! dma8237->eop )
|
||||
{
|
||||
/* we do have a transfer in progress */
|
||||
for (channel = 3; (pending_transfer & (1 << channel)) == 0; channel--)
|
||||
;
|
||||
|
||||
dma8237->status |= 0x10 << channel;
|
||||
dma8237->status &= ~(0x01 << channel);
|
||||
|
||||
timer_adjust_periodic(dma8237->timer,
|
||||
attotime_zero,
|
||||
channel,
|
||||
double_to_attotime(dma8237->intf->bus_speed));
|
||||
dma8237->eop = 1;
|
||||
if ( dma8237->intf->out_eop_func )
|
||||
dma8237->intf->out_eop_func( device, 0, dma8237->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 = ( ( dma8237->command & 0x40 ) ? ~dma8237->drq : dma8237->drq ) & ~dma8237->mask;
|
||||
|
||||
if ( pending_request & 0x0f )
|
||||
{
|
||||
int i, channel, prio_channel = 0;
|
||||
|
||||
/* Determine the channel that should be serviced */
|
||||
channel = ( dma8237->command & 0x10 ) ? dma8237->last_service_channel : 3;
|
||||
for ( i = 0; i < 4; i++ )
|
||||
{
|
||||
if ( pending_request & ( 1 << channel ) )
|
||||
prio_channel = channel;
|
||||
channel = ( channel - 1 ) & 0x03;
|
||||
}
|
||||
|
||||
/* Store the channel we will be servicing and go to the next state */
|
||||
dma8237->service_channel = prio_channel;
|
||||
dma8237->last_service_channel = prio_channel;
|
||||
dma8237->hrq = 1;
|
||||
dma8237->intf->hrq_changed( device, dma8237->hrq );
|
||||
dma8237->state = DMA8237_S0;
|
||||
|
||||
timer_enable( dma8237->timer, 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
timer_enable( dma8237->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 ( dma8237->hlda )
|
||||
{
|
||||
if ( dma8237->command & 0x01 )
|
||||
{
|
||||
/* Memory-to-memory transfers */
|
||||
dma8237->state = DMA8237_S11;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Regular transfers */
|
||||
dma8237->state = DMA8237_S1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA8237_S1: /* Output A8-A15 */
|
||||
dma8237->state = DMA8237_S2;
|
||||
break;
|
||||
|
||||
case DMA8237_S2: /* Output A7-A0 */
|
||||
/* Check for compressed timing */
|
||||
if ( dma8237->command & 0x08 )
|
||||
dma8237->state = DMA8237_S4;
|
||||
else
|
||||
{
|
||||
/* no transfers active right now */
|
||||
timer_reset(dma8237->timer, attotime_never);
|
||||
}
|
||||
dma8237->state = DMA8237_S3;
|
||||
break;
|
||||
|
||||
/* set the halt line */
|
||||
if (dma8237->intf && dma8237->intf->cputag != NULL)
|
||||
{
|
||||
cputag_set_input_line(device->machine, dma8237->intf->cputag, INPUT_LINE_HALT,
|
||||
pending_transfer ? ASSERT_LINE : CLEAR_LINE);
|
||||
}
|
||||
case DMA8237_S3: /* Initiate read */
|
||||
dma8237_do_read( device );
|
||||
dma8237->state = DMA8237_S4;
|
||||
break;
|
||||
|
||||
case DMA8237_S4: /* Perform read/write */
|
||||
/* Perform read when in compressed timing mode */
|
||||
if ( dma8237->command & 0x08 )
|
||||
dma8237_do_read( device );
|
||||
|
||||
/* Perform write */
|
||||
dma8237_do_write( device );
|
||||
|
||||
/* Advance */
|
||||
dma8237_advance( device );
|
||||
|
||||
/* set the eop line, if it has changed */
|
||||
new_eop = (dma8237->status & 0x0F) == 0x0F ? 1 : 0;
|
||||
if (dma8237->eop != new_eop)
|
||||
{
|
||||
dma8237->eop = new_eop;
|
||||
if (dma8237->intf->out_eop_func)
|
||||
dma8237->intf->out_eop_func(device, new_eop ? ASSERT_LINE : CLEAR_LINE);
|
||||
int channel = dma8237->service_channel;
|
||||
|
||||
switch( DMA_MODE_TRANSFERMODE( dma8237->chan[channel].mode ) )
|
||||
{
|
||||
case DMA8237_DEMAND_MODE:
|
||||
/* Check for terminal count or EOP signal or DREQ begin de-asserted */
|
||||
if ( ( dma8237->status & ( 0x01 << channel ) ) || ! dma8237->eop || ! ( dma8237->drq & ( 0x01 << channel ) ) )
|
||||
{
|
||||
dma8237->hrq = 0;
|
||||
dma8237->hlda = 0;
|
||||
dma8237->intf->hrq_changed( device, dma8237->hrq );
|
||||
dma8237->state = DMA8237_SI;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma8237->state = dma8237->chan[channel].high_address_changed ? DMA8237_S1 : DMA8237_S2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA8237_SINGLE_MODE:
|
||||
dma8237->hrq = 0;
|
||||
dma8237->hlda = 0;
|
||||
dma8237->intf->hrq_changed( device, dma8237->hrq );
|
||||
dma8237->state = DMA8237_SI;
|
||||
break;
|
||||
|
||||
case DMA8237_BLOCK_MODE:
|
||||
/* Check for terminal count or EOP signal */
|
||||
if ( ( dma8237->status & ( 0x01 << channel ) ) || ! dma8237->eop )
|
||||
{
|
||||
dma8237->hrq = 0;
|
||||
dma8237->hlda = 0;
|
||||
dma8237->intf->hrq_changed( device, dma8237->hrq );
|
||||
dma8237->state = DMA8237_SI;
|
||||
}
|
||||
else
|
||||
{
|
||||
dma8237->state = dma8237->chan[channel].high_address_changed ? DMA8237_S1 : DMA8237_S2;
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA8237_CASCADE_MODE:
|
||||
if ( ! ( dma8237->drq & ( 0x01 << channel ) ) )
|
||||
{
|
||||
dma8237->hrq = 0;
|
||||
dma8237->hlda = 0;
|
||||
dma8237->intf->hrq_changed( device, dma8237->hrq );
|
||||
dma8237->state = DMA8237_SI;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
/* Check if EOP output needs to be asserted */
|
||||
if ( dma8237->status & ( 0x01 << channel ) )
|
||||
{
|
||||
dma8237->eop = 0;
|
||||
if ( dma8237->intf->out_eop_func )
|
||||
dma8237->intf->out_eop_func( device, channel, dma8237->eop ? ASSERT_LINE : CLEAR_LINE );
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case DMA8237_S11: /* Output A8-A15 */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/* ----------------------------------------------------------------------- */
|
||||
|
||||
|
||||
INLINE void prepare_msb_flip(const device_config *device)
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
|
||||
timer_adjust_oneshot(dma8237->msbflip_timer, attotime_zero, 0);
|
||||
}
|
||||
|
||||
|
||||
|
||||
READ8_DEVICE_HANDLER( dma8237_r )
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
UINT8 data = 0xFF;
|
||||
UINT8 mode;
|
||||
|
||||
offset &= 0x0F;
|
||||
|
||||
@ -220,17 +395,7 @@ READ8_DEVICE_HANDLER( dma8237_r )
|
||||
case 6:
|
||||
/* DMA address register */
|
||||
data = dma8237->chan[offset / 2].address >> (dma8237->msb ? 8 : 0);
|
||||
prepare_msb_flip(device);
|
||||
|
||||
/* hack simulating refresh activity for 'ibmxt' BIOS; I do not know
|
||||
* why this is needed; but in any case, the ibmxt driver does not load
|
||||
* if this code is not present */
|
||||
mode = dma8237->chan[0].mode;
|
||||
if ((DMA_MODE_OPERATION(mode) == 2) && (offset == 0))
|
||||
{
|
||||
dma8237->chan[0].address++;
|
||||
dma8237->chan[0].count--;
|
||||
}
|
||||
dma8237->msb ^= 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -239,12 +404,15 @@ READ8_DEVICE_HANDLER( dma8237_r )
|
||||
case 7:
|
||||
/* DMA count register */
|
||||
data = dma8237->chan[offset / 2].count >> (dma8237->msb ? 8 : 0);
|
||||
prepare_msb_flip(device);
|
||||
dma8237->msb ^= 1;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
/* DMA status register */
|
||||
data = (UINT8) dma8237->status;
|
||||
|
||||
/* TC bits are cleared on a status read */
|
||||
dma8237->status &= 0xF0;
|
||||
break;
|
||||
|
||||
case 10:
|
||||
@ -265,6 +433,7 @@ READ8_DEVICE_HANDLER( dma8237_r )
|
||||
data = 0xFF;
|
||||
break;
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
@ -277,17 +446,26 @@ WRITE8_DEVICE_HANDLER( dma8237_w )
|
||||
|
||||
offset &= 0x0F;
|
||||
|
||||
logerror("dma8237_w: offset = %02x, data = %02x\n", offset, data );
|
||||
|
||||
switch(offset) {
|
||||
case 0:
|
||||
case 2:
|
||||
case 4:
|
||||
case 6:
|
||||
/* DMA address register */
|
||||
channel = offset / 2;
|
||||
if (dma8237->msb)
|
||||
dma8237->chan[offset / 2].address |= ((UINT16) data) << 8;
|
||||
{
|
||||
dma8237->chan[channel].base_address = ( dma8237->chan[channel].base_address & 0x00FF ) | ( data << 8 );
|
||||
dma8237->chan[channel].address = ( dma8237->chan[channel].address & 0x00FF ) | ( data << 8 );
|
||||
}
|
||||
else
|
||||
dma8237->chan[offset / 2].address = data;
|
||||
prepare_msb_flip(device);
|
||||
{
|
||||
dma8237->chan[channel].base_address = ( dma8237->chan[channel].base_address & 0xFF00 ) | data;
|
||||
dma8237->chan[channel].address = ( dma8237->chan[channel].address & 0xFF00 ) | data;
|
||||
}
|
||||
dma8237->msb ^= 1;
|
||||
break;
|
||||
|
||||
case 1:
|
||||
@ -295,16 +473,39 @@ WRITE8_DEVICE_HANDLER( dma8237_w )
|
||||
case 5:
|
||||
case 7:
|
||||
/* DMA count register */
|
||||
channel = offset / 2;
|
||||
if (dma8237->msb)
|
||||
dma8237->chan[offset / 2].count |= ((UINT16) data) << 8;
|
||||
{
|
||||
dma8237->chan[channel].base_count = ( dma8237->chan[channel].base_count & 0x00FF ) | ( data << 8 );
|
||||
dma8237->chan[channel].count = ( dma8237->chan[channel].count & 0x00FF ) | ( data << 8 );
|
||||
}
|
||||
else
|
||||
dma8237->chan[offset / 2].count = data;
|
||||
prepare_msb_flip(device);
|
||||
{
|
||||
dma8237->chan[channel].base_count = ( dma8237->chan[channel].base_count & 0xFF00 ) | data;
|
||||
dma8237->chan[channel].count = ( dma8237->chan[channel].count & 0xFF00 ) | data;
|
||||
}
|
||||
dma8237->msb ^= 1;
|
||||
break;
|
||||
|
||||
case 8:
|
||||
/* DMA command register */
|
||||
dma8237->command = data;
|
||||
timer_enable( dma8237->timer, ( dma8237->command & 0x04 ) ? 0 : 1 );
|
||||
break;
|
||||
|
||||
case 9:
|
||||
/* DMA request register */
|
||||
channel = DMA_MODE_CHANNEL(data);
|
||||
if ( data & 0x04 )
|
||||
{
|
||||
dma8237->drq |= 0x01 << channel;
|
||||
timer_enable( dma8237->timer, ( dma8237->command & 0x04 ) ? 0 : 1 );
|
||||
}
|
||||
else
|
||||
{
|
||||
dma8237->status &= ~ ( 0x10 << channel );
|
||||
dma8237->drq &= ~ ( 0x01 << channel );
|
||||
}
|
||||
break;
|
||||
|
||||
case 10:
|
||||
@ -320,6 +521,8 @@ WRITE8_DEVICE_HANDLER( dma8237_w )
|
||||
/* DMA mode register */
|
||||
channel = DMA_MODE_CHANNEL(data);
|
||||
dma8237->chan[channel].mode = data;
|
||||
/* Apparently mode writes also clear the TC bit(?) */
|
||||
dma8237->status &= ~ ( 1 << channel );
|
||||
break;
|
||||
|
||||
case 12:
|
||||
@ -331,12 +534,15 @@ WRITE8_DEVICE_HANDLER( dma8237_w )
|
||||
case 13:
|
||||
/* DMA master clear */
|
||||
dma8237->msb = 0;
|
||||
dma8237->mask = 0x0f;
|
||||
dma8237->state = DMA8237_SI;
|
||||
dma8237->status &= 0xF0;
|
||||
break;
|
||||
|
||||
case 14:
|
||||
/* DMA clear mask register */
|
||||
dma8237->mask &= ~data;
|
||||
dma8237_update_status(device);
|
||||
dma8237->mask = 0;
|
||||
break;
|
||||
|
||||
case 15:
|
||||
@ -348,31 +554,26 @@ WRITE8_DEVICE_HANDLER( dma8237_w )
|
||||
|
||||
|
||||
|
||||
static void dma8237_drq_write_callback(const device_config *device, int param)
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token(device);
|
||||
int channel = (param >> 1) & 0x03;
|
||||
int state = param & 0x01;
|
||||
|
||||
/* normalize state */
|
||||
if (state)
|
||||
dma8237->drq |= 0x01 << channel;
|
||||
else
|
||||
dma8237->drq &= ~(0x01 << channel);
|
||||
|
||||
dma8237_update_status(device);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void dma8237_drq_write(const device_config *device, int channel, int state)
|
||||
{
|
||||
int param = (channel << 1) | (state ? 1 : 0);
|
||||
//timer_call_after_resynch(device->machine, NULL, param, dma8237_drq_write_callback);
|
||||
dma8237_drq_write_callback(device, param);
|
||||
dma8237_t *dma8237 = get_safe_token( device );
|
||||
|
||||
if (state)
|
||||
dma8237->drq |= ( 0x01 << channel );
|
||||
else
|
||||
dma8237->drq &= ~( 0x01 << channel );
|
||||
|
||||
timer_enable( dma8237->timer, ( dma8237->command & 0x04 ) ? 0 : 1 );
|
||||
}
|
||||
|
||||
|
||||
void dma8237_set_hlda(const device_config *device, int state)
|
||||
{
|
||||
dma8237_t *dma8237 = get_safe_token( device );
|
||||
|
||||
dma8237->hlda = state;
|
||||
}
|
||||
|
||||
|
||||
/******************* Unfortunate hacks *******************/
|
||||
|
||||
@ -382,8 +583,7 @@ void dma8237_run_transfer(const device_config *device, int channel)
|
||||
|
||||
dma8237->status |= 0x10 << channel; /* reset DMA running flag */
|
||||
|
||||
while(!dma8237_do_operation(device, channel))
|
||||
;
|
||||
popmessage("dma8237_run_transfer(): please do not use me anymore\n");
|
||||
|
||||
dma8237->status &= ~(0x10 << channel);
|
||||
dma8237->status |= (0x01 << channel);
|
||||
@ -403,17 +603,23 @@ static DEVICE_RESET( dma8237 ) {
|
||||
|
||||
dma8237->status = 0x0F;
|
||||
dma8237->timer = timer_alloc(device->machine, dma8237_timerproc, (void *)device);
|
||||
dma8237->msbflip_timer = timer_alloc(device->machine, dma8237_msbflip_timerproc, (void *)device);
|
||||
dma8237->eop = 1;
|
||||
dma8237->state = DMA8237_SI;
|
||||
dma8237->last_service_channel = 3;
|
||||
|
||||
dma8237->mask = 0x00;
|
||||
dma8237->status = 0x0F;
|
||||
dma8237->hrq = 0;
|
||||
dma8237->hlda = 0;
|
||||
dma8237->chan[0].mode = 0;
|
||||
dma8237->chan[1].mode = 0;
|
||||
dma8237->chan[2].mode = 0;
|
||||
dma8237->chan[3].mode = 0;
|
||||
|
||||
dma8237_update_status(device);
|
||||
timer_adjust_periodic(dma8237->timer,
|
||||
ATTOTIME_IN_HZ(dma8237->intf->bus_speed),
|
||||
0,
|
||||
ATTOTIME_IN_HZ(dma8237->intf->bus_speed));
|
||||
}
|
||||
|
||||
|
||||
@ -432,7 +638,7 @@ DEVICE_GET_INFO( dma8237 ) {
|
||||
/* --- the following bits of info are returned as NULL-terminated strings --- */
|
||||
case DEVINFO_STR_NAME: strcpy(info->s, "Intel DMA8237"); break;
|
||||
case DEVINFO_STR_FAMILY: strcpy(info->s, "DMA8237"); break;
|
||||
case DEVINFO_STR_VERSION: strcpy(info->s, "1.00"); 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;
|
||||
}
|
||||
|
@ -9,26 +9,28 @@
|
||||
|
||||
#define DMA8237 DEVICE_GET_INFO_NAME(dma8237)
|
||||
|
||||
typedef void (*dma8237_hrq_func)(const device_config *device, int state);
|
||||
typedef UINT8 (*dma8237_mem_read_func)(const device_config *device, int channel, offs_t offset);
|
||||
typedef void (*dma8237_mem_write_func)(const device_config *device, int channel, offs_t offset, UINT8 data);
|
||||
typedef int (*dma8237_channel_read_func)(const device_config *device);
|
||||
typedef void (*dma8237_channel_write_func)(const device_config *device, int data);
|
||||
typedef void (*dma8237_out_eop_func)(const device_config *device, int state);
|
||||
typedef void (*dma8237_out_eop_func)(const device_config *device, int channel, int state);
|
||||
|
||||
#define DMA8237_HRQ_CHANGED(name) void name(const device_config *device, int state)
|
||||
#define DMA8237_MEM_READ(name) UINT8 name(const device_config *device, int channel, offs_t offset)
|
||||
#define DMA8237_MEM_WRITE(name) void name(const device_config *device, int channel, offs_t offset, UINT8 data)
|
||||
#define DMA8237_CHANNEL_READ(name) int name(const device_config *device)
|
||||
#define DMA8237_CHANNEL_WRITE(name) void name(const device_config *device, int data)
|
||||
#define DMA8237_OUT_EOP(name) void name(const device_config *device, int state)
|
||||
#define DMA8237_OUT_EOP(name) void name(const device_config *device, int channel, int state)
|
||||
|
||||
struct dma8237_interface
|
||||
{
|
||||
/* CPU to halt when DMA is active */
|
||||
const char *cputag;
|
||||
|
||||
/* speed of DMA accesses (per byte) */
|
||||
double bus_speed;
|
||||
|
||||
/* function that will be called when HRQ may have changed */
|
||||
dma8237_hrq_func hrq_changed;
|
||||
|
||||
/* accessors to main memory */
|
||||
dma8237_mem_read_func memory_read_func;
|
||||
dma8237_mem_write_func memory_write_func;
|
||||
@ -56,6 +58,7 @@ DEVICE_GET_INFO( dma8237 );
|
||||
READ8_DEVICE_HANDLER( dma8237_r );
|
||||
WRITE8_DEVICE_HANDLER( dma8237_w );
|
||||
void dma8237_drq_write(const device_config *device, int channel, int state);
|
||||
void dma8237_set_hlda(const device_config *device, int state);
|
||||
|
||||
/* unfortunate hack for the interim for PC HDC */
|
||||
void dma8237_run_transfer(const device_config *device, int channel);
|
||||
|
@ -213,6 +213,15 @@ static WRITE8_HANDLER(at_page8_w)
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -235,23 +244,23 @@ static DMA8237_MEM_WRITE( pc_dma_write_byte )
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static const struct dma8237_interface dma8237_2_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
|
@ -420,6 +420,15 @@ static WRITE8_HANDLER(at_page8_w)
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -442,23 +451,23 @@ static DMA8237_MEM_WRITE( pc_dma_write_byte )
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static const struct dma8237_interface dma8237_2_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
|
@ -773,6 +773,15 @@ static WRITE8_HANDLER(at_page8_w)
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -795,23 +804,23 @@ static DMA8237_MEM_WRITE( pc_dma_write_byte )
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static const struct dma8237_interface dma8237_2_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
|
@ -188,6 +188,15 @@ DMA8237 Controller
|
||||
static UINT8 dma_offset[2][4];
|
||||
static UINT8 at_pages[0x10];
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -254,27 +263,27 @@ static WRITE8_HANDLER(dma_page_select_w)
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct dma8237_interface dma8237_2_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -551,6 +551,15 @@ DMA8237 Controller
|
||||
static UINT8 dma_offset[2][4];
|
||||
static UINT8 at_pages[0x10];
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -615,14 +624,14 @@ static WRITE8_HANDLER(dma_page_select_w)
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
@ -365,6 +365,15 @@ static WRITE8_HANDLER(at_page8_w)
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_HRQ_CHANGED( pc_dma_hrq_changed )
|
||||
{
|
||||
cputag_set_input_line(device->machine, "maincpu", INPUT_LINE_HALT, state ? ASSERT_LINE : CLEAR_LINE);
|
||||
|
||||
/* Assert HLDA */
|
||||
dma8237_set_hlda( device, state );
|
||||
}
|
||||
|
||||
|
||||
static DMA8237_MEM_READ( pc_dma_read_byte )
|
||||
{
|
||||
const address_space *space = cputag_get_address_space(device->machine, "maincpu", ADDRESS_SPACE_PROGRAM);
|
||||
@ -387,23 +396,23 @@ static DMA8237_MEM_WRITE( pc_dma_write_byte )
|
||||
|
||||
static const struct dma8237_interface dma8237_1_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
pc_dma_hrq_changed,
|
||||
pc_dma_read_byte,
|
||||
pc_dma_write_byte,
|
||||
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ 0, 0, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
{ NULL, NULL, NULL, NULL },
|
||||
NULL
|
||||
};
|
||||
|
||||
|
||||
static const struct dma8237_interface dma8237_2_config =
|
||||
{
|
||||
"maincpu",
|
||||
1.0e-6, // 1us
|
||||
XTAL_14_31818MHz/3,
|
||||
|
||||
NULL,
|
||||
NULL,
|
||||
NULL,
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user