(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) READ8_MEMBER(towns_state::towns_dma1_r)
{ {
// logerror("DMA#1: read register %i\n",offset); // 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) WRITE8_MEMBER(towns_state::towns_dma1_w)
{ {
// logerror("DMA#1: wrote 0x%02x to register %i\n",data,offset); // 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) READ8_MEMBER(towns_state::towns_dma2_r)
{ {
logerror("DMA#2: read register %i\n",offset); 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) WRITE8_MEMBER(towns_state::towns_dma2_w)
{ {
logerror("DMA#2: wrote 0x%02x to register %i\n",data,offset); 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 ) 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) 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) TIMER_CALLBACK_MEMBER(towns_state::towns_cdrom_read_byte)
{ {
device_t* device = (device_t* )ptr; upd71071_device* device = (upd71071_device* )ptr;
int masked; int masked;
// TODO: support software transfers, for now DMA is assumed. // TODO: support software transfers, for now DMA is assumed.
if(m_towns_cd.buffer_ptr < 0) // transfer has ended if(m_towns_cd.buffer_ptr < 0) // transfer has ended
return; 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); // logerror("DMARQ: param=%i ret=%i bufferptr=%i\n",param,masked,m_towns_cd.buffer_ptr);
if(param != 0) if(param != 0)
{ {
@ -1993,7 +1993,7 @@ WRITE_LINE_MEMBER(towns_state::towns_scsi_irq)
WRITE_LINE_MEMBER(towns_state::towns_scsi_drq) 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() void towns_state::machine_reset()
{ {
address_space &program = m_maincpu->space(AS_PROGRAM); 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_fdc = machine().device("fdc");
m_messram = m_ram; m_messram = m_ram;
m_cdrom = machine().device<cdrom_image_device>("cdrom"); 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); timer_set(attotime::from_msec(100), TIMER_PC88VA_FDC_TIMER);
if((m_fdc_ctrl_2 & 0x10) != (data & 0x10)) if((m_fdc_ctrl_2 & 0x10) != (data & 0x10))
upd71071_dmarq(m_dmac,1,2); m_dmac->dmarq(1, 2);
if(data & 0x80) // correct? if(data & 0x80) // correct?
machine().device<upd765a_device>("upd765")->reset(); 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(0x0156, 0x0157) AM_READ8(rom_bank_r,0x00ff) // ROM bank status
// AM_RANGE(0x0158, 0x0159) Interruption Mode Modification // AM_RANGE(0x0158, 0x0159) Interruption Mode Modification
// AM_RANGE(0x015c, 0x015f) NMI mask port (strobe port) // 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(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(0x0188, 0x018b) AM_DEVREADWRITE8("pic8259_master", pic8259_device, read, write, 0x00ff) // ICU, also controls 8214 emulation
// AM_RANGE(0x0190, 0x0191) System Port 5 // 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) void pc88va_state::fdc_drq(bool state)
{ {
printf("%02x DRQ\n",state); printf("%02x DRQ\n",state);
upd71071_dmarq(m_dmac,state,2); m_dmac->dmarq(state, 2);
} }
void pc88va_state::fdc_irq(bool state) 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_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_UPD765A_ADD("upd765", false, true)
MCFG_FLOPPY_DRIVE_ADD("upd765:0", pc88va_floppies, "525hd", pc88va_state::floppy_formats) 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_master(*this, "pic8259_master"),
m_pic_slave(*this, "pic8259_slave"), m_pic_slave(*this, "pic8259_slave"),
m_pit(*this, "pit"), m_pit(*this, "pit"),
m_dma_1(*this, "dma_1"),
m_dma_2(*this, "dma_2"),
m_ram(*this, RAM_TAG), m_ram(*this, RAM_TAG),
m_nvram(*this, "nvram"), m_nvram(*this, "nvram"),
m_nvram16(*this, "nvram16") 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_master;
required_device<pic8259_device> m_pic_slave; required_device<pic8259_device> m_pic_slave;
required_device<pit8253_device> m_pit; 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; required_device<ram_device> m_ram;
device_t* m_dma_1;
device_t* m_dma_2;
device_t* m_fdc; device_t* m_fdc;
ram_device* m_messram; ram_device* m_messram;
cdrom_image_device* m_cdrom; cdrom_image_device* m_cdrom;

View File

@ -80,154 +80,151 @@
#include "emu.h" #include "emu.h"
#include "machine/upd71071.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 const device_type UPD71071 = &device_creator<upd71071_device>;
{
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;
};
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 // single byte or word transfer
device_t* device = (device_t*)ptr; address_space& space = m_cpu->space(AS_PROGRAM);
upd71071_t* dmac = get_safe_token(device);
address_space& space = device->machine().device(dmac->intf->cputag)->memory().space(AS_PROGRAM);
int channel = param; int channel = param;
UINT16 data = 0; // data to transfer UINT16 data = 0; // data to transfer
switch(dmac->reg.mode_control[channel] & 0x0c) switch (m_reg.mode_control[channel] & 0x0c)
{ {
case 0x00: // Verify case 0x00: // Verify
break; break;
case 0x04: // I/O -> memory case 0x04: // I/O -> memory
if(!dmac->m_dma_read[channel].isnull()) if (!m_dma_read[channel].isnull())
data = dmac->m_dma_read[channel](0); data = m_dma_read[channel](0);
space.write_byte(dmac->reg.address_current[channel],data & 0xff); space.write_byte(m_reg.address_current[channel], data & 0xff);
if(dmac->reg.mode_control[channel] & 0x20) // Address direction if (m_reg.mode_control[channel] & 0x20) // Address direction
dmac->reg.address_current[channel]--; m_reg.address_current[channel]--;
else else
dmac->reg.address_current[channel]++; m_reg.address_current[channel]++;
if(dmac->reg.count_current[channel] == 0) 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]; m_reg.address_current[channel] = m_reg.address_base[channel];
dmac->reg.count_current[channel] = dmac->reg.count_base[channel]; m_reg.count_current[channel] = m_reg.count_base[channel];
} }
// TODO: send terminal count // TODO: send terminal count
set_eop(device,ASSERT_LINE); set_eop(ASSERT_LINE);
} }
else else
dmac->reg.count_current[channel]--; m_reg.count_current[channel]--;
break; break;
case 0x08: // memory -> I/O case 0x08: // memory -> I/O
data = space.read_byte(dmac->reg.address_current[channel]); data = space.read_byte(m_reg.address_current[channel]);
if(!dmac->m_dma_write[channel].isnull()) if (!m_dma_write[channel].isnull())
dmac->m_dma_write[channel](0,data); m_dma_write[channel](0, data);
if(dmac->reg.mode_control[channel] & 0x20) // Address direction if (m_reg.mode_control[channel] & 0x20) // Address direction
dmac->reg.address_current[channel]--; m_reg.address_current[channel]--;
else else
dmac->reg.address_current[channel]++; m_reg.address_current[channel]++;
if(dmac->reg.count_current[channel] == 0) 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]; m_reg.address_current[channel] = m_reg.address_base[channel];
dmac->reg.count_current[channel] = dmac->reg.count_base[channel]; m_reg.count_current[channel] = m_reg.count_base[channel];
} }
// TODO: send terminal count // TODO: send terminal count
set_eop(device,ASSERT_LINE); set_eop(ASSERT_LINE);
} }
else else
dmac->reg.count_current[channel]--; m_reg.count_current[channel]--;
break; break;
case 0x0c: // Invalid case 0x0c: // Invalid
break; 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 // Does not change base/current address, count, or buswidth
dmac->selected_channel = 0; m_selected_channel = 0;
dmac->base = 0; m_base = 0;
for(x=0;x<4;x++) for (int x = 0; x < 4; x++)
dmac->reg.mode_control[x] = 0; m_reg.mode_control[x] = 0;
dmac->reg.device_control = 0; m_reg.device_control = 0;
dmac->reg.temp_h = 0; m_reg.temp_h = 0;
dmac->reg.temp_l = 0; m_reg.temp_l = 0;
dmac->reg.mask = 0x0f; // mask all channels m_reg.mask = 0x0f; // mask all channels
dmac->reg.status &= ~0x0f; // clears bits 0-3 only m_reg.status &= ~0x0f; // clears bits 0-3 only
dmac->reg.request = 0; 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; return 2;
if(dmac->reg.mask & (1 << channel)) // is channel masked? if (m_reg.mask & (1 << channel)) // is channel masked?
return 1; return 1;
dmac->dmarq[channel] = 1; // DMARQ line is set m_dmarq[channel] = 1; // DMARQ line is set
dmac->reg.status |= (0x10 << channel); m_reg.status |= (0x10 << channel);
// start transfer // start transfer
switch(dmac->reg.mode_control[channel] & 0xc0) switch (m_reg.mode_control[channel] & 0xc0)
{ {
case 0x00: // Demand case 0x00: // Demand
// TODO // TODO
set_eop(device,CLEAR_LINE); set_eop(CLEAR_LINE);
dmac->timer[channel]->adjust(attotime::from_hz(dmac->intf->clock),channel); m_timer[channel]->adjust(attotime::from_hz(m_upd_clock), channel);
break; break;
case 0x40: // Single 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; break;
case 0x80: // Block case 0x80: // Block
// TODO // TODO
@ -240,249 +237,191 @@ int upd71071_dmarq(device_t* device, int state,int channel)
} }
else else
{ {
dmac->dmarq[channel] = 0; // clear DMARQ line m_dmarq[channel] = 0; // clear DMARQ line
dmac->reg.status &= ~(0x10 << channel); m_reg.status &= ~(0x10 << channel);
dmac->reg.status |= (0x01 << channel); // END or TC m_reg.status |= (0x01 << channel); // END or TC
} }
return 0; 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; UINT8 ret = 0;
logerror("DMA: read from register %02x\n",offset); logerror("DMA: read from register %02x\n",offset);
switch(offset) switch(offset)
{ {
case 0x01: // Channel case 0x01: // Channel
ret = (1 << dmac->selected_channel); ret = (1 << m_selected_channel);
if(dmac->base != 0) if (m_base != 0)
ret |= 0x10; ret |= 0x10;
break; break;
case 0x02: // Count (low) case 0x02: // Count (low)
if(dmac->base != 0) if (m_base != 0)
ret = dmac->reg.count_base[dmac->selected_channel] & 0xff; ret = m_reg.count_base[m_selected_channel] & 0xff;
else else
ret = dmac->reg.count_current[dmac->selected_channel] & 0xff; ret = m_reg.count_current[m_selected_channel] & 0xff;
break; break;
case 0x03: // Count (high) case 0x03: // Count (high)
if(dmac->base != 0) if (m_base != 0)
ret = (dmac->reg.count_base[dmac->selected_channel] >> 8) & 0xff; ret = (m_reg.count_base[m_selected_channel] >> 8) & 0xff;
else else
ret = (dmac->reg.count_current[dmac->selected_channel] >> 8) & 0xff; ret = (m_reg.count_current[m_selected_channel] >> 8) & 0xff;
break; break;
case 0x04: // Address (low) case 0x04: // Address (low)
if(dmac->base != 0) if (m_base != 0)
ret = dmac->reg.address_base[dmac->selected_channel] & 0xff; ret = m_reg.address_base[m_selected_channel] & 0xff;
else else
ret = dmac->reg.address_current[dmac->selected_channel] & 0xff; ret = m_reg.address_current[m_selected_channel] & 0xff;
break; break;
case 0x05: // Address (mid) case 0x05: // Address (mid)
if(dmac->base != 0) if (m_base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 8) & 0xff; ret = (m_reg.address_base[m_selected_channel] >> 8) & 0xff;
else else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 8) & 0xff; ret = (m_reg.address_current[m_selected_channel] >> 8) & 0xff;
break; break;
case 0x06: // Address (high) case 0x06: // Address (high)
if(dmac->base != 0) if (m_base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 16) & 0xff; ret = (m_reg.address_base[m_selected_channel] >> 16) & 0xff;
else else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 16) & 0xff; ret = (m_reg.address_current[m_selected_channel] >> 16) & 0xff;
break; break;
case 0x07: // Address (highest) case 0x07: // Address (highest)
if(dmac->base != 0) if (m_base != 0)
ret = (dmac->reg.address_base[dmac->selected_channel] >> 24) & 0xff; ret = (m_reg.address_base[m_selected_channel] >> 24) & 0xff;
else else
ret = (dmac->reg.address_current[dmac->selected_channel] >> 24) & 0xff; ret = (m_reg.address_current[m_selected_channel] >> 24) & 0xff;
break; break;
case 0x08: // Device control (low) case 0x08: // Device control (low)
ret = dmac->reg.device_control & 0xff; ret = m_reg.device_control & 0xff;
break; break;
case 0x09: // Device control (high) case 0x09: // Device control (high)
ret = (dmac->reg.device_control >> 8) & 0xff; ret = (m_reg.device_control >> 8) & 0xff;
break; break;
case 0x0a: // Mode control case 0x0a: // Mode control
ret = dmac->reg.mode_control[dmac->selected_channel]; ret = m_reg.mode_control[m_selected_channel];
break; break;
case 0x0b: // Status case 0x0b: // Status
ret = dmac->reg.status; ret = m_reg.status;
dmac->reg.status &= ~0x0f; // resets END/TC? m_reg.status &= ~0x0f; // resets END/TC?
break; break;
case 0x0c: // Temporary (low) case 0x0c: // Temporary (low)
ret = dmac->reg.temp_h; ret = m_reg.temp_h;
break; break;
case 0x0d: // Temporary (high) case 0x0d: // Temporary (high)
ret = dmac->reg.temp_l; ret = m_reg.temp_l;
break; break;
case 0x0e: // Request case 0x0e: // Request
ret = dmac->reg.request; ret = m_reg.request;
break; break;
case 0x0f: // Mask case 0x0f: // Mask
ret = dmac->reg.mask; ret = m_reg.mask;
break; break;
} }
return ret; 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 case 0x00: // Initialise
// TODO: reset (bit 0) // TODO: reset (bit 0)
dmac->buswidth = data & 0x02; m_buswidth = data & 0x02;
if(data & 0x01) if (data & 0x01)
upd71071_soft_reset(device); soft_reset();
logerror("DMA: Initialise [%02x]\n",data); logerror("DMA: Initialise [%02x]\n",data);
break; break;
case 0x01: // Channel case 0x01: // Channel
dmac->selected_channel = data & 0x03; m_selected_channel = data & 0x03;
dmac->base = data & 0x04; m_base = data & 0x04;
logerror("DMA: Channel selected [%02x]\n",data); logerror("DMA: Channel selected [%02x]\n",data);
break; break;
case 0x02: // Count (low) case 0x02: // Count (low)
dmac->reg.count_base[dmac->selected_channel] = m_reg.count_base[m_selected_channel] =
(dmac->reg.count_base[dmac->selected_channel] & 0xff00) | data; (m_reg.count_base[m_selected_channel] & 0xff00) | data;
if(dmac->base == 0) if (m_base == 0)
dmac->reg.count_current[dmac->selected_channel] = m_reg.count_current[m_selected_channel] =
(dmac->reg.count_current[dmac->selected_channel] & 0xff00) | data; (m_reg.count_current[m_selected_channel] & 0xff00) | data;
logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]); logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]);
break; break;
case 0x03: // Count (high) case 0x03: // Count (high)
dmac->reg.count_base[dmac->selected_channel] = m_reg.count_base[m_selected_channel] =
(dmac->reg.count_base[dmac->selected_channel] & 0x00ff) | (data << 8); (m_reg.count_base[m_selected_channel] & 0x00ff) | (data << 8);
if(dmac->base == 0) if (m_base == 0)
dmac->reg.count_current[dmac->selected_channel] = m_reg.count_current[m_selected_channel] =
(dmac->reg.count_current[dmac->selected_channel] & 0x00ff) | (data << 8); (m_reg.count_current[m_selected_channel] & 0x00ff) | (data << 8);
logerror("DMA: Channel %i Counter set [%04x]\n",dmac->selected_channel,dmac->reg.count_base[dmac->selected_channel]); logerror("DMA: Channel %i Counter set [%04x]\n",m_selected_channel,m_reg.count_base[m_selected_channel]);
break; break;
case 0x04: // Address (low) case 0x04: // Address (low)
dmac->reg.address_base[dmac->selected_channel] = m_reg.address_base[m_selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xffffff00) | data; (m_reg.address_base[m_selected_channel] & 0xffffff00) | data;
if(dmac->base == 0) if (m_base == 0)
dmac->reg.address_current[dmac->selected_channel] = m_reg.address_current[m_selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xffffff00) | data; (m_reg.address_current[m_selected_channel] & 0xffffff00) | data;
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]); logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break; break;
case 0x05: // Address (mid) case 0x05: // Address (mid)
dmac->reg.address_base[dmac->selected_channel] = m_reg.address_base[m_selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xffff00ff) | (data << 8); (m_reg.address_base[m_selected_channel] & 0xffff00ff) | (data << 8);
if(dmac->base == 0) if (m_base == 0)
dmac->reg.address_current[dmac->selected_channel] = m_reg.address_current[m_selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xffff00ff) | (data << 8); (m_reg.address_current[m_selected_channel] & 0xffff00ff) | (data << 8);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]); logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break; break;
case 0x06: // Address (high) case 0x06: // Address (high)
dmac->reg.address_base[dmac->selected_channel] = m_reg.address_base[m_selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0xff00ffff) | (data << 16); (m_reg.address_base[m_selected_channel] & 0xff00ffff) | (data << 16);
if(dmac->base == 0) if (m_base == 0)
dmac->reg.address_current[dmac->selected_channel] = m_reg.address_current[m_selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0xff00ffff) | (data << 16); (m_reg.address_current[m_selected_channel] & 0xff00ffff) | (data << 16);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]); logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break; break;
case 0x07: // Address (highest) case 0x07: // Address (highest)
dmac->reg.address_base[dmac->selected_channel] = m_reg.address_base[m_selected_channel] =
(dmac->reg.address_base[dmac->selected_channel] & 0x00ffffff) | (data << 24); (m_reg.address_base[m_selected_channel] & 0x00ffffff) | (data << 24);
if(dmac->base == 0) if (m_base == 0)
dmac->reg.address_current[dmac->selected_channel] = m_reg.address_current[m_selected_channel] =
(dmac->reg.address_current[dmac->selected_channel] & 0x00ffffff) | (data << 24); (m_reg.address_current[m_selected_channel] & 0x00ffffff) | (data << 24);
logerror("DMA: Channel %i Address set [%08x]\n",dmac->selected_channel,dmac->reg.address_base[dmac->selected_channel]); logerror("DMA: Channel %i Address set [%08x]\n",m_selected_channel,m_reg.address_base[m_selected_channel]);
break; break;
case 0x08: // Device control (low) case 0x08: // Device control (low)
dmac->reg.device_control = (dmac->reg.device_control & 0xff00) | data; m_reg.device_control = (m_reg.device_control & 0xff00) | data;
logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control); logerror("DMA: Device control set [%04x]\n",m_reg.device_control);
break; break;
case 0x09: // Device control (high) case 0x09: // Device control (high)
dmac->reg.device_control = (dmac->reg.device_control & 0x00ff) | (data << 8); m_reg.device_control = (m_reg.device_control & 0x00ff) | (data << 8);
logerror("DMA: Device control set [%04x]\n",dmac->reg.device_control); logerror("DMA: Device control set [%04x]\n",m_reg.device_control);
break; break;
case 0x0a: // Mode control case 0x0a: // Mode control
dmac->reg.mode_control[dmac->selected_channel] = data; m_reg.mode_control[m_selected_channel] = data;
logerror("DMA: Channel %i Mode control set [%02x]\n",dmac->selected_channel,dmac->reg.mode_control[dmac->selected_channel]); logerror("DMA: Channel %i Mode control set [%02x]\n",m_selected_channel,m_reg.mode_control[m_selected_channel]);
break; break;
case 0x0e: // Request case 0x0e: // Request
dmac->reg.request = data; m_reg.request = data;
logerror("DMA: Request set [%02x]\n",data); logerror("DMA: Request set [%02x]\n",data);
break; break;
case 0x0f: // Mask case 0x0f: // Mask
dmac->reg.mask = data; m_reg.mask = data;
logerror("DMA: Mask set [%02x]\n",data); logerror("DMA: Mask set [%02x]\n",data);
break; break;
} }
} }
READ8_DEVICE_HANDLER(upd71071_r) { return upd71071_read(device,space,offset,mem_mask); } WRITE_LINE_MEMBER(upd71071_device::set_hreq)
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)
{ {
m_token = global_alloc_clear(upd71071_t); if (m_hreq != state)
}
//-------------------------------------------------
// 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)
{ {
dmac->m_out_hreq_func(state); m_out_hreq_func(state);
m_hreq = state;
dmac->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 (m_eop != state)
if (dmac->m_eop != state)
{ {
dmac->m_out_eop_func(state); m_out_eop_func(state);
m_eop = state;
dmac->m_eop = state;
} }
} }

View File

@ -1,36 +1,76 @@
#ifndef UPD71071_H_ #ifndef __UPD71071_H__
#define UPD71071_H_ #define __UPD71071_H__
#include "emu.h" #include "emu.h"
struct upd71071_intf struct upd71071_intf
{ {
const char* cputag; const char* cputag;
int clock; int m_upd_clock;
devcb_write_line m_out_hreq_cb; devcb_write_line m_out_hreq_cb;
devcb_write_line m_out_eop_cb; devcb_write_line m_out_eop_cb;
devcb_read16 m_dma_read[4]; devcb_read16 m_dma_read_cb[4];
devcb_write16 m_dma_write[4]; devcb_write16 m_dma_write_cb[4];
devcb_write_line m_out_dack_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: public:
upd71071_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); 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: protected:
// device-level overrides // device-level overrides
virtual void device_config_complete(); virtual void device_config_complete();
virtual void device_start(); virtual void device_start();
private: private:
// internal state // 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; extern const device_type UPD71071;
@ -40,11 +80,5 @@ extern const device_type UPD71071;
MCFG_DEVICE_ADD(_tag, UPD71071, 0) \ MCFG_DEVICE_ADD(_tag, UPD71071, 0) \
MCFG_DEVICE_CONFIG(_config) 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_*/ #endif /*UPD71071_H_*/