(MESS) modernized uPD71071 DMA device. [Fabio Priuli]

This commit is contained in:
Fabio Priuli 2013-06-04 10:17:53 +00:00
parent f8269256cd
commit f9d591b7bc
5 changed files with 251 additions and 278 deletions

View File

@ -458,25 +458,25 @@ WRITE8_MEMBER(towns_state::towns_sys6c_w)
READ8_MEMBER(towns_state::towns_dma1_r)
{
// logerror("DMA#1: read register %i\n",offset);
return upd71071_r(m_dma_1,space, offset);
return m_dma_1->read(space, offset);
}
WRITE8_MEMBER(towns_state::towns_dma1_w)
{
// logerror("DMA#1: wrote 0x%02x to register %i\n",data,offset);
upd71071_w(m_dma_1,space, offset,data);
m_dma_1->write(space, offset, data);
}
READ8_MEMBER(towns_state::towns_dma2_r)
{
logerror("DMA#2: read register %i\n",offset);
return upd71071_r(m_dma_2,space, offset);
return m_dma_2->read(space, offset);
}
WRITE8_MEMBER(towns_state::towns_dma2_w)
{
logerror("DMA#2: wrote 0x%02x to register %i\n",data,offset);
upd71071_w(m_dma_2,space, offset,data);
m_dma_2->write(space, offset, data);
}
/*
@ -493,7 +493,7 @@ WRITE_LINE_MEMBER( towns_state::mb8877a_irq_w )
WRITE_LINE_MEMBER( towns_state::mb8877a_drq_w )
{
upd71071_dmarq(m_dma_1, state, 0);
m_dma_1->dmarq(state, 0);
}
READ8_MEMBER(towns_state::towns_floppy_r)
@ -1394,14 +1394,14 @@ UINT8 towns_state::towns_cd_get_track()
TIMER_CALLBACK_MEMBER(towns_state::towns_cdrom_read_byte)
{
device_t* device = (device_t* )ptr;
upd71071_device* device = (upd71071_device* )ptr;
int masked;
// TODO: support software transfers, for now DMA is assumed.
if(m_towns_cd.buffer_ptr < 0) // transfer has ended
return;
masked = upd71071_dmarq(device,param,3); // CD-ROM controller uses DMA1 channel 3
masked = device->dmarq(param, 3); // CD-ROM controller uses DMA1 channel 3
// logerror("DMARQ: param=%i ret=%i bufferptr=%i\n",param,masked,m_towns_cd.buffer_ptr);
if(param != 0)
{
@ -1993,7 +1993,7 @@ WRITE_LINE_MEMBER(towns_state::towns_scsi_irq)
WRITE_LINE_MEMBER(towns_state::towns_scsi_drq)
{
upd71071_dmarq(m_dma_1,state,1); // SCSI HDs use channel 1
m_dma_1->dmarq(state, 1); // SCSI HDs use channel 1
}
@ -2605,8 +2605,6 @@ void marty_state::driver_start()
void towns_state::machine_reset()
{
address_space &program = m_maincpu->space(AS_PROGRAM);
m_dma_1 = machine().device("dma_1");
m_dma_2 = machine().device("dma_2");
m_fdc = machine().device("fdc");
m_messram = m_ram;
m_cdrom = machine().device<cdrom_image_device>("cdrom");

View File

@ -1141,7 +1141,7 @@ WRITE8_MEMBER(pc88va_state::pc88va_fdc_w)
timer_set(attotime::from_msec(100), TIMER_PC88VA_FDC_TIMER);
if((m_fdc_ctrl_2 & 0x10) != (data & 0x10))
upd71071_dmarq(m_dmac,1,2);
m_dmac->dmarq(1, 2);
if(data & 0x80) // correct?
machine().device<upd765a_device>("upd765")->reset();
@ -1278,7 +1278,7 @@ static ADDRESS_MAP_START( pc88va_io_map, AS_IO, 16, pc88va_state )
AM_RANGE(0x0156, 0x0157) AM_READ8(rom_bank_r,0x00ff) // ROM bank status
// AM_RANGE(0x0158, 0x0159) Interruption Mode Modification
// AM_RANGE(0x015c, 0x015f) NMI mask port (strobe port)
AM_RANGE(0x0160, 0x016f) AM_DEVREADWRITE8_LEGACY("dmac", upd71071_r, upd71071_w,0xffff) // DMA Controller
AM_RANGE(0x0160, 0x016f) AM_DEVREADWRITE8("dmac", upd71071_device, read, write, 0xffff) // DMA Controller
AM_RANGE(0x0184, 0x0187) AM_DEVREADWRITE8("pic8259_slave", pic8259_device, read, write, 0x00ff)
AM_RANGE(0x0188, 0x018b) AM_DEVREADWRITE8("pic8259_master", pic8259_device, read, write, 0x00ff) // ICU, also controls 8214 emulation
// AM_RANGE(0x0190, 0x0191) System Port 5
@ -1769,7 +1769,7 @@ static const struct pit8253_interface pc88va_pit8253_config =
void pc88va_state::fdc_drq(bool state)
{
printf("%02x DRQ\n",state);
upd71071_dmarq(m_dmac,state,2);
m_dmac->dmarq(state, 2);
}
void pc88va_state::fdc_irq(bool state)
@ -1882,7 +1882,7 @@ static MACHINE_CONFIG_START( pc88va, pc88va_state )
MCFG_PIC8259_ADD( "pic8259_slave", DEVWRITELINE("pic8259_master", pic8259_device, ir7_w), GND, NULL )
MCFG_UPD71071_ADD("dmac",pc88va_dma_config)
MCFG_UPD71071_ADD("dmac", pc88va_dma_config)
MCFG_UPD765A_ADD("upd765", false, true)
MCFG_FLOPPY_DRIVE_ADD("upd765:0", pc88va_floppies, "525hd", pc88va_state::floppy_formats)

View File

@ -83,6 +83,8 @@ class towns_state : public driver_device
m_pic_master(*this, "pic8259_master"),
m_pic_slave(*this, "pic8259_slave"),
m_pit(*this, "pit"),
m_dma_1(*this, "dma_1"),
m_dma_2(*this, "dma_2"),
m_ram(*this, RAM_TAG),
m_nvram(*this, "nvram"),
m_nvram16(*this, "nvram16")
@ -94,9 +96,9 @@ class towns_state : public driver_device
required_device<pic8259_device> m_pic_master;
required_device<pic8259_device> m_pic_slave;
required_device<pit8253_device> m_pit;
required_device<upd71071_device> m_dma_1;
required_device<upd71071_device> m_dma_2;
required_device<ram_device> m_ram;
device_t* m_dma_1;
device_t* m_dma_2;
device_t* m_fdc;
ram_device* m_messram;
cdrom_image_device* m_cdrom;

View File

@ -80,154 +80,151 @@
#include "emu.h"
#include "machine/upd71071.h"
struct upd71071_reg
{
UINT8 initialise;
UINT8 channel;
UINT16 count_current[4];
UINT16 count_base[4];
UINT32 address_current[4];
UINT32 address_base[4];
UINT16 device_control;
UINT8 mode_control[4];
UINT8 status;
UINT8 temp_l;
UINT8 temp_h;
UINT8 request;
UINT8 mask;
};
struct upd71071_t
{
struct upd71071_reg reg;
int selected_channel;
int buswidth;
int dmarq[4];
emu_timer* timer[4];
int in_progress[4];
int transfer_size[4];
int base;
const upd71071_intf* intf;
devcb_resolved_write_line m_out_hreq_func;
devcb_resolved_write_line m_out_eop_func;
devcb_resolved_read16 m_dma_read[4];
devcb_resolved_write16 m_dma_write[4];
devcb_resolved_write_line m_out_dack_func[4];
int m_hreq;
int m_eop;
};
const device_type UPD71071 = &device_creator<upd71071_device>;
INLINE upd71071_t *get_safe_token(device_t *device)
upd71071_device::upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, UPD71071, "NEC uPD71071", tag, owner, clock)
{
assert(device != NULL);
assert(device->type() == UPD71071);
return (upd71071_t*)downcast<upd71071_device *>(device)->token();
}
static TIMER_CALLBACK(dma_transfer_timer)
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void upd71071_device::device_config_complete()
{
// inherit a copy of the static data
const upd71071_intf *intf = reinterpret_cast<const upd71071_intf *>(static_config());
if (intf != NULL)
*static_cast<upd71071_intf *>(this) = *intf;
// or initialize to defaults if none provided
else
{
}
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void upd71071_device::device_start()
{
m_cpu = machine().device<cpu_device>(cputag);
m_out_hreq_func.resolve(m_out_hreq_cb, *this);
m_out_eop_func.resolve(m_out_eop_cb, *this);
for (int x = 0; x < 4; x++)
{
m_timer[x] = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(upd71071_device::dma_transfer_timer),this));
m_dma_read[x].resolve(m_dma_read_cb[x], *this);
m_dma_write[x].resolve(m_dma_write_cb[x], *this);
m_out_dack_func[x].resolve(m_out_dack_cb[x], *this);
}
m_selected_channel = 0;
}
TIMER_CALLBACK_MEMBER(upd71071_device::dma_transfer_timer)
{
// single byte or word transfer
device_t* device = (device_t*)ptr;
upd71071_t* dmac = get_safe_token(device);
address_space& space = device->machine().device(dmac->intf->cputag)->memory().space(AS_PROGRAM);
address_space& space = m_cpu->space(AS_PROGRAM);
int channel = param;
UINT16 data = 0; // data to transfer
switch(dmac->reg.mode_control[channel] & 0x0c)
switch (m_reg.mode_control[channel] & 0x0c)
{
case 0x00: // Verify
break;
case 0x04: // I/O -> memory
if(!dmac->m_dma_read[channel].isnull())
data = dmac->m_dma_read[channel](0);
space.write_byte(dmac->reg.address_current[channel],data & 0xff);
if(dmac->reg.mode_control[channel] & 0x20) // Address direction
dmac->reg.address_current[channel]--;
if (!m_dma_read[channel].isnull())
data = m_dma_read[channel](0);
space.write_byte(m_reg.address_current[channel], data & 0xff);
if (m_reg.mode_control[channel] & 0x20) // Address direction
m_reg.address_current[channel]--;
else
dmac->reg.address_current[channel]++;
if(dmac->reg.count_current[channel] == 0)
m_reg.address_current[channel]++;
if (m_reg.count_current[channel] == 0)
{
if(dmac->reg.mode_control[channel] & 0x10) // auto-initialise
if (m_reg.mode_control[channel] & 0x10) // auto-initialise
{
dmac->reg.address_current[channel] = dmac->reg.address_base[channel];
dmac->reg.count_current[channel] = dmac->reg.count_base[channel];
m_reg.address_current[channel] = m_reg.address_base[channel];
m_reg.count_current[channel] = m_reg.count_base[channel];
}
// TODO: send terminal count
set_eop(device,ASSERT_LINE);
set_eop(ASSERT_LINE);
}
else
dmac->reg.count_current[channel]--;
m_reg.count_current[channel]--;
break;
case 0x08: // memory -> I/O
data = space.read_byte(dmac->reg.address_current[channel]);
if(!dmac->m_dma_write[channel].isnull())
dmac->m_dma_write[channel](0,data);
if(dmac->reg.mode_control[channel] & 0x20) // Address direction
dmac->reg.address_current[channel]--;
data = space.read_byte(m_reg.address_current[channel]);
if (!m_dma_write[channel].isnull())
m_dma_write[channel](0, data);
if (m_reg.mode_control[channel] & 0x20) // Address direction
m_reg.address_current[channel]--;
else
dmac->reg.address_current[channel]++;
if(dmac->reg.count_current[channel] == 0)
m_reg.address_current[channel]++;
if (m_reg.count_current[channel] == 0)
{
if(dmac->reg.mode_control[channel] & 0x10) // auto-initialise
if (m_reg.mode_control[channel] & 0x10) // auto-initialise
{
dmac->reg.address_current[channel] = dmac->reg.address_base[channel];
dmac->reg.count_current[channel] = dmac->reg.count_base[channel];
m_reg.address_current[channel] = m_reg.address_base[channel];
m_reg.count_current[channel] = m_reg.count_base[channel];
}
// TODO: send terminal count
set_eop(device,ASSERT_LINE);
set_eop(ASSERT_LINE);
}
else
dmac->reg.count_current[channel]--;
m_reg.count_current[channel]--;
break;
case 0x0c: // Invalid
break;
}
}
static void upd71071_soft_reset(device_t* device)
void upd71071_device::soft_reset()
{
upd71071_t* dmac = get_safe_token(device);
int x;
// Does not change base/current address, count, or buswidth
dmac->selected_channel = 0;
dmac->base = 0;
for(x=0;x<4;x++)
dmac->reg.mode_control[x] = 0;
dmac->reg.device_control = 0;
dmac->reg.temp_h = 0;
dmac->reg.temp_l = 0;
dmac->reg.mask = 0x0f; // mask all channels
dmac->reg.status &= ~0x0f; // clears bits 0-3 only
dmac->reg.request = 0;
m_selected_channel = 0;
m_base = 0;
for (int x = 0; x < 4; x++)
m_reg.mode_control[x] = 0;
m_reg.device_control = 0;
m_reg.temp_h = 0;
m_reg.temp_l = 0;
m_reg.mask = 0x0f; // mask all channels
m_reg.status &= ~0x0f; // clears bits 0-3 only
m_reg.request = 0;
}
int upd71071_dmarq(device_t* device, int state,int channel)
int upd71071_device::dmarq(int state, int channel)
{
upd71071_t* dmac = get_safe_token(device);
if(state != 0)
if (state != 0)
{
if(dmac->reg.device_control & 0x0004)
if (m_reg.device_control & 0x0004)
return 2;
if(dmac->reg.mask & (1 << channel)) // is channel masked?
if (m_reg.mask & (1 << channel)) // is channel masked?
return 1;
dmac->dmarq[channel] = 1; // DMARQ line is set
dmac->reg.status |= (0x10 << channel);
m_dmarq[channel] = 1; // DMARQ line is set
m_reg.status |= (0x10 << channel);
// start transfer
switch(dmac->reg.mode_control[channel] & 0xc0)
switch (m_reg.mode_control[channel] & 0xc0)
{
case 0x00: // Demand
// TODO
set_eop(device,CLEAR_LINE);
dmac->timer[channel]->adjust(attotime::from_hz(dmac->intf->clock),channel);
set_eop(CLEAR_LINE);
m_timer[channel]->adjust(attotime::from_hz(m_upd_clock), channel);
break;
case 0x40: // Single
dmac->timer[channel]->adjust(attotime::from_hz(dmac->intf->clock),channel);
m_timer[channel]->adjust(attotime::from_hz(m_upd_clock), channel);
break;
case 0x80: // Block
// TODO
@ -240,249 +237,191 @@ int upd71071_dmarq(device_t* device, int state,int channel)
}
else
{
dmac->dmarq[channel] = 0; // clear DMARQ line
dmac->reg.status &= ~(0x10 << channel);
dmac->reg.status |= (0x01 << channel); // END or TC
m_dmarq[channel] = 0; // clear DMARQ line
m_reg.status &= ~(0x10 << channel);
m_reg.status |= (0x01 << channel); // END or TC
}
return 0;
}
static DEVICE_START(upd71071)
READ8_MEMBER(upd71071_device::read)
{
upd71071_t* dmac = get_safe_token(device);
int x;
dmac->intf = (const upd71071_intf*)device->static_config();
dmac->m_out_hreq_func.resolve(dmac->intf->m_out_hreq_cb, *device);
dmac->m_out_eop_func.resolve(dmac->intf->m_out_eop_cb, *device);
for(x=0;x<4;x++)
{
dmac->timer[x] = device->machine().scheduler().timer_alloc(FUNC(dma_transfer_timer), (void*)device);
dmac->m_dma_read[x].resolve(dmac->intf->m_dma_read[x], *device);
dmac->m_dma_write[x].resolve(dmac->intf->m_dma_write[x], *device);
dmac->m_out_dack_func[x].resolve(dmac->intf->m_out_dack_cb[x], *device);
}
dmac->selected_channel = 0;
}
static READ8_DEVICE_HANDLER(upd71071_read)
{
upd71071_t* dmac = get_safe_token(device);
UINT8 ret = 0;
logerror("DMA: read from register %02x\n",offset);
switch(offset)
{
case 0x01: // Channel
ret = (1 << dmac->selected_channel);
if(dmac->base != 0)
ret = (1 << m_selected_channel);
if (m_base != 0)
ret |= 0x10;
break;
case 0x02: // Count (low)
if(dmac->base != 0)
ret = dmac->reg.count_base[dmac->selected_channel] & 0xff;
if (m_base != 0)
ret = m_reg.count_base[m_selected_channel] & 0xff;
else
ret = dmac->reg.count_current[dmac->selected_channel] & 0xff;
ret = m_reg.count_current[m_selected_channel] & 0xff;
break;
case 0x03: // Count (high)
if(dmac->base != 0)
ret = (dmac->reg.count_base[dmac->selected_channel] >> 8) & 0xff;
if (m_base != 0)
ret = (m_reg.count_base[m_selected_channel] >> 8) & 0xff;
else
ret = (dmac->reg.count_current[dmac->selected_channel] >> 8) & 0xff;
ret = (m_reg.count_current[m_selected_channel] >> 8) & 0xff;
break;
case 0x04: // Address (low)
if(dmac->base != 0)
ret = dmac->reg.address_base[dmac->selected_channel] & 0xff;
if (m_base != 0)
ret = m_reg.address_base[m_selected_channel] & 0xff;
else
ret = dmac->reg.address_current[dmac->selected_channel] & 0xff;
ret = m_reg.address_current[m_selected_channel] & 0xff;
break;
case 0x05: // Address (mid)
if(dmac->base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 8) & 0xff;
if (m_base != 0)
ret = (m_reg.address_base[m_selected_channel] >> 8) & 0xff;
else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 8) & 0xff;
ret = (m_reg.address_current[m_selected_channel] >> 8) & 0xff;
break;
case 0x06: // Address (high)
if(dmac->base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 16) & 0xff;
if (m_base != 0)
ret = (m_reg.address_base[m_selected_channel] >> 16) & 0xff;
else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 16) & 0xff;
ret = (m_reg.address_current[m_selected_channel] >> 16) & 0xff;
break;
case 0x07: // Address (highest)
if(dmac->base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 24) & 0xff;
if (m_base != 0)
ret = (m_reg.address_base[m_selected_channel] >> 24) & 0xff;
else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 24) & 0xff;
ret = (m_reg.address_current[m_selected_channel] >> 24) & 0xff;
break;
case 0x08: // Device control (low)
ret = dmac->reg.device_control & 0xff;
ret = m_reg.device_control & 0xff;
break;
case 0x09: // Device control (high)
ret = (dmac->reg.device_control >> 8) & 0xff;
ret = (m_reg.device_control >> 8) & 0xff;
break;
case 0x0a: // Mode control
ret = dmac->reg.mode_control[dmac->selected_channel];
ret = m_reg.mode_control[m_selected_channel];
break;
case 0x0b: // Status
ret = dmac->reg.status;
dmac->reg.status &= ~0x0f; // resets END/TC?
ret = m_reg.status;
m_reg.status &= ~0x0f; // resets END/TC?
break;
case 0x0c: // Temporary (low)
ret = dmac->reg.temp_h;
ret = m_reg.temp_h;
break;
case 0x0d: // Temporary (high)
ret = dmac->reg.temp_l;
ret = m_reg.temp_l;
break;
case 0x0e: // Request
ret = dmac->reg.request;
ret = m_reg.request;
break;
case 0x0f: // Mask
ret = dmac->reg.mask;
ret = m_reg.mask;
break;
}
return ret;
}
static WRITE8_DEVICE_HANDLER(upd71071_write)
WRITE8_MEMBER(upd71071_device::write)
{
upd71071_t* dmac = get_safe_token(device);
switch(offset)
switch (offset)
{
case 0x00: // Initialise
// TODO: reset (bit 0)
dmac->buswidth = data & 0x02;
if(data & 0x01)
upd71071_soft_reset(device);
m_buswidth = data & 0x02;
if (data & 0x01)
soft_reset();
logerror("DMA: Initialise [%02x]\n",data);
break;
case 0x01: // Channel
dmac->selected_channel = data & 0x03;
dmac->base = data & 0x04;
m_selected_channel = data & 0x03;
m_base = data & 0x04;
logerror("DMA: Channel selected [%02x]\n",data);
break;
case 0x02: // Count (low)
dmac->reg.count_base[dmac->selected_channel] =
(dmac->reg.count_base[dmac->selected_channel] & 0xff00) | data;
if(dmac->base == 0)
dmac->reg.count_current[dmac->selected_channel] =
(dmac->reg.count_current[dmac->selected_channel] & 0xff00) | data;
logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]);
m_reg.count_base[m_selected_channel] =
(m_reg.count_base[m_selected_channel] & 0xff00) | data;
if (m_base == 0)
m_reg.count_current[m_selected_channel] =
(m_reg.count_current[m_selected_channel] & 0xff00) | data;
logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]);
break;
case 0x03: // Count (high)
dmac->reg.count_base[dmac->selected_channel] =
(dmac->reg.count_base[dmac->selected_channel] & 0x00ff) | (data << 8);
if(dmac->base == 0)
dmac->reg.count_current[dmac->selected_channel] =
(dmac->reg.count_current[dmac->selected_channel] & 0x00ff) | (data << 8);
logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]);
m_reg.count_base[m_selected_channel] =
(m_reg.count_base[m_selected_channel] & 0x00ff) | (data << 8);
if (m_base == 0)
m_reg.count_current[m_selected_channel] =
(m_reg.count_current[m_selected_channel] & 0x00ff) | (data << 8);
logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]);
break;
case 0x04: // Address (low)
dmac->reg.address_base[dmac->selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xffffff00) | data;
if(dmac->base == 0)
dmac->reg.address_current[dmac->selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xffffff00) | data;
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
m_reg.address_base[m_selected_channel] =
(m_reg.address_base[m_selected_channel] & 0xffffff00) | data;
if (m_base == 0)
m_reg.address_current[m_selected_channel] =
(m_reg.address_current[m_selected_channel] & 0xffffff00) | data;
logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break;
case 0x05: // Address (mid)
dmac->reg.address_base[dmac->selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xffff00ff) | (data << 8);
if(dmac->base == 0)
dmac->reg.address_current[dmac->selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xffff00ff) | (data << 8);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
m_reg.address_base[m_selected_channel] =
(m_reg.address_base[m_selected_channel] & 0xffff00ff) | (data << 8);
if (m_base == 0)
m_reg.address_current[m_selected_channel] =
(m_reg.address_current[m_selected_channel] & 0xffff00ff) | (data << 8);
logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break;
case 0x06: // Address (high)
dmac->reg.address_base[dmac->selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xff00ffff) | (data << 16);
if(dmac->base == 0)
dmac->reg.address_current[dmac->selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xff00ffff) | (data << 16);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
m_reg.address_base[m_selected_channel] =
(m_reg.address_base[m_selected_channel] & 0xff00ffff) | (data << 16);
if (m_base == 0)
m_reg.address_current[m_selected_channel] =
(m_reg.address_current[m_selected_channel] & 0xff00ffff) | (data << 16);
logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break;
case 0x07: // Address (highest)
dmac->reg.address_base[dmac->selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0x00ffffff) | (data << 24);
if(dmac->base == 0)
dmac->reg.address_current[dmac->selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0x00ffffff) | (data << 24);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]);
m_reg.address_base[m_selected_channel] =
(m_reg.address_base[m_selected_channel] & 0x00ffffff) | (data << 24);
if (m_base == 0)
m_reg.address_current[m_selected_channel] =
(m_reg.address_current[m_selected_channel] & 0x00ffffff) | (data << 24);
logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break;
case 0x08: // Device control (low)
dmac->reg.device_control = (dmac->reg.device_control & 0xff00) | data;
logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control);
m_reg.device_control = (m_reg.device_control & 0xff00) | data;
logerror("DMA: Device control set [%04x]\n",m_reg.device_control);
break;
case 0x09: // Device control (high)
dmac->reg.device_control = (dmac->reg.device_control & 0x00ff) | (data << 8);
logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control);
m_reg.device_control = (m_reg.device_control & 0x00ff) | (data << 8);
logerror("DMA: Device control set [%04x]\n",m_reg.device_control);
break;
case 0x0a: // Mode control
dmac->reg.mode_control[dmac->selected_channel] = data;
logerror("DMA: Channel %i Mode control set [%02x]\n",dmac->selected_channel,dmac->reg.mode_control[dmac->selected_channel]);
m_reg.mode_control[m_selected_channel] = data;
logerror("DMA: Channel %i Mode control set [%02x]\n",m_selected_channel,m_reg.mode_control[m_selected_channel]);
break;
case 0x0e: // Request
dmac->reg.request = data;
m_reg.request = data;
logerror("DMA: Request set [%02x]\n",data);
break;
case 0x0f: // Mask
dmac->reg.mask = data;
m_reg.mask = data;
logerror("DMA: Mask set [%02x]\n",data);
break;
}
}
READ8_DEVICE_HANDLER(upd71071_r) { return upd71071_read(device,space,offset,mem_mask); }
WRITE8_DEVICE_HANDLER(upd71071_w) { upd71071_write(device,space,offset,data,mem_mask); }
const device_type UPD71071 = &device_creator<upd71071_device>;
upd71071_device::upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, UPD71071, "NEC uPD71071", tag, owner, clock)
WRITE_LINE_MEMBER(upd71071_device::set_hreq)
{
m_token = global_alloc_clear(upd71071_t);
}
//-------------------------------------------------
// device_config_complete - perform any
// operations now that the configuration is
// complete
//-------------------------------------------------
void upd71071_device::device_config_complete()
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void upd71071_device::device_start()
{
DEVICE_START_NAME( upd71071 )(this);
}
void set_hreq( device_t *device, int state)
{
upd71071_t* dmac = get_safe_token(device);
if (dmac->m_hreq != state)
if (m_hreq != state)
{
dmac->m_out_hreq_func(state);
dmac->m_hreq = state;
m_out_hreq_func(state);
m_hreq = state;
}
}
void set_eop( device_t *device, int state)
WRITE_LINE_MEMBER(upd71071_device::set_eop)
{
upd71071_t* dmac = get_safe_token(device);
if (dmac->m_eop != state)
if (m_eop != state)
{
dmac->m_out_eop_func(state);
dmac->m_eop = state;
m_out_eop_func(state);
m_eop = state;
}
}

View File

@ -1,36 +1,76 @@
#ifndef UPD71071_H_
#define UPD71071_H_
#ifndef __UPD71071_H__
#define __UPD71071_H__
#include "emu.h"
struct upd71071_intf
{
const char* cputag;
int clock;
int m_upd_clock;
devcb_write_line m_out_hreq_cb;
devcb_write_line m_out_eop_cb;
devcb_read16 m_dma_read[4];
devcb_write16 m_dma_write[4];
devcb_read16 m_dma_read_cb[4];
devcb_write16 m_dma_write_cb[4];
devcb_write_line m_out_dack_cb[4];
};
int upd71071_dmarq(device_t* device,int state,int channel);
struct upd71071_reg
{
UINT8 initialise;
UINT8 channel;
UINT16 count_current[4];
UINT16 count_base[4];
UINT32 address_current[4];
UINT32 address_base[4];
UINT16 device_control;
UINT8 mode_control[4];
UINT8 status;
UINT8 temp_l;
UINT8 temp_h;
UINT8 request;
UINT8 mask;
};
class upd71071_device : public device_t
class upd71071_device : public device_t,
public upd71071_intf
{
public:
upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
~upd71071_device() { global_free(m_token); }
~upd71071_device() {}
DECLARE_READ8_MEMBER(read);
DECLARE_WRITE8_MEMBER(write);
DECLARE_WRITE_LINE_MEMBER(set_hreq);
DECLARE_WRITE_LINE_MEMBER(set_eop);
int dmarq(int state, int channel);
// access to legacy token
void *token() const { assert(m_token != NULL); return m_token; }
protected:
// device-level overrides
virtual void device_config_complete();
virtual void device_start();
private:
// internal state
void *m_token;
void soft_reset();
TIMER_CALLBACK_MEMBER(dma_transfer_timer);
struct upd71071_reg m_reg;
int m_selected_channel;
int m_buswidth;
int m_dmarq[4];
emu_timer* m_timer[4];
int m_in_progress[4];
int m_transfer_size[4];
int m_base;
devcb_resolved_write_line m_out_hreq_func;
devcb_resolved_write_line m_out_eop_func;
devcb_resolved_read16 m_dma_read[4];
devcb_resolved_write16 m_dma_write[4];
devcb_resolved_write_line m_out_dack_func[4];
int m_hreq;
int m_eop;
cpu_device *m_cpu;
};
extern const device_type UPD71071;
@ -40,11 +80,5 @@ extern const device_type UPD71071;
MCFG_DEVICE_ADD(_tag, UPD71071, 0) \
MCFG_DEVICE_CONFIG(_config)
DECLARE_READ8_DEVICE_HANDLER(upd71071_r);
DECLARE_WRITE8_DEVICE_HANDLER(upd71071_w);
void set_hreq( device_t *device, int state);
void set_eop( device_t *device, int state);
#endif /*UPD71071_H_*/