interpro: serial dma [P. Mackinlay]

* interpro: serial dma

* implemented basic serial dma
* switch to ncr53c94
* initial ethernet preparation
* timer-based dma

* oops (nw)
This commit is contained in:
Patrick Mackinlay 2017-07-10 13:40:50 +07:00 committed by Olivier Galibert
parent 5ddd006919
commit 65a381c706
6 changed files with 268 additions and 110 deletions

View File

@ -2154,8 +2154,6 @@ files {
MAME_DIR .. "src/mame/machine/cammu.cpp",
MAME_DIR .. "src/mame/machine/interpro_ioga.h",
MAME_DIR .. "src/mame/machine/interpro_ioga.cpp",
MAME_DIR .. "src/mame/machine/interpro_ioga.h",
MAME_DIR .. "src/mame/machine/interpro_ioga.cpp",
MAME_DIR .. "src/mame/machine/interpro_mcga.h",
MAME_DIR .. "src/mame/machine/interpro_mcga.cpp",
MAME_DIR .. "src/mame/machine/interpro_sga.h",

View File

@ -72,24 +72,20 @@ static const char *const cc[] =
/*
* Decode an addressing mode into a string.
*/
char *address (offs_t pc, u16 *insn)
std::string address (offs_t pc, u16 *insn)
{
static char buffer[32];
switch (ADDR_MODE)
{
case ADDR_MODE_PC32: sprintf(buffer, "0x%x", pc + I32); break;
case ADDR_MODE_ABS32: sprintf(buffer, "0x%x", I32); break;
case ADDR_MODE_REL32: sprintf(buffer, "%d(r%d)", *(int32_t *)&insn[2], R2); break;
case ADDR_MODE_PC16: sprintf(buffer, "0x%x", pc + I16); break;
case ADDR_MODE_REL12: sprintf(buffer, "%d(r%d)", ADDR_I12, R2); break;
case ADDR_MODE_ABS16: sprintf(buffer, "0x%x", I16); break;
case ADDR_MODE_PCX: sprintf(buffer, "[r%d](pc)", ADDR_RX); break;
case ADDR_MODE_RELX: sprintf(buffer, "[r%d](r%d)", ADDR_RX, R2); break;
default: sprintf(buffer, "ERROR"); break;
case ADDR_MODE_PC32: return util::string_format("0x%x", pc + I32);
case ADDR_MODE_ABS32: return util::string_format("0x%x", I32);
case ADDR_MODE_REL32: return util::string_format("%d(r%d)", *(int32_t *)&insn[2], R2);
case ADDR_MODE_PC16: return util::string_format("0x%x", pc + I16);
case ADDR_MODE_REL12: return util::string_format("%d(r%d)", ADDR_I12, R2);
case ADDR_MODE_ABS16: return util::string_format("0x%x", I16);
case ADDR_MODE_PCX: return util::string_format("[r%d](pc)", ADDR_RX);
case ADDR_MODE_RELX: return util::string_format("[r%d](r%d)", ADDR_RX, R2);
default: return std::string("ERROR");
}
return buffer;
}
/*

View File

@ -272,6 +272,7 @@ READ8_MEMBER(interpro_state::scsi_r)
case 0x7: return m_scsi->fifo_flags_r(space, 0);
case 0x8: return m_scsi->conf_r(space, 0);
case 0xb: return m_scsi->conf2_r(space, 0);
case 0xc: return m_scsi->conf3_r(space, 0);
}
logerror("scsi: read unmapped register 0x%x (%s)\n", offset >> 6, machine().describe_context());
@ -294,6 +295,8 @@ WRITE8_MEMBER(interpro_state::scsi_w)
case 9: m_scsi->clock_w(space, 0, data); return;
case 0xa: m_scsi->test_w(space, 0, data); return;
case 0xb: m_scsi->conf2_w(space, 0, data); return;
case 0xc: m_scsi->conf3_w(space, 0, data); return;
case 0xf: m_scsi->fifo_align_w(space, 0, data); return;
}
logerror("scsi: unmapped register write 0x%02x data 0x%02x (%s)\n", offset >> 6, data, machine().describe_context());
@ -319,7 +322,7 @@ DRIVER_INIT_MEMBER(interpro_state, ip2800)
static SLOT_INTERFACE_START(interpro_scsi_devices)
SLOT_INTERFACE("harddisk", NSCSI_HARDDISK)
SLOT_INTERFACE("cdrom", NSCSI_CDROM)
SLOT_INTERFACE_INTERNAL(INTERPRO_SCSI_ADAPTER_TAG, NCR53C90A)
SLOT_INTERFACE_INTERNAL(INTERPRO_SCSI_ADAPTER_TAG, NCR53C94)
SLOT_INTERFACE_END
static MACHINE_CONFIG_START(interpro_scsi_adapter)
@ -352,15 +355,18 @@ static ADDRESS_MAP_START(interpro_common_map, 0, 32, interpro_state)
AM_RANGE(0x7f00031c, 0x7f00031f) AM_READWRITE16(sreg_ctrl3_r, sreg_ctrl3_w, 0xffff)
AM_RANGE(0x7f000400, 0x7f00040f) AM_DEVREADWRITE8(INTERPRO_SCC1_TAG, scc85c30_device, ba_cd_inv_r, ba_cd_inv_w, 0xff)
AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, scc85230_device, ba_cd_inv_r, ba_cd_inv_w, 0xff)
AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, scc85c30_device, ba_cd_inv_r, ba_cd_inv_w, 0xff)
AM_RANGE(0x7f000500, 0x7f0006ff) AM_READWRITE8(rtc_r, rtc_w, 0xff)
AM_RANGE(0x7f000700, 0x7f00077f) AM_READ8(idprom_r, 0xff)
AM_RANGE(0x7f001000, 0x7f001fff) AM_READWRITE8(scsi_r, scsi_w, 0x0000ff00)
AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map)
AM_RANGE(0x08000000, 0x08000fff) AM_NOP // bogus
AM_RANGE(0x87000000, 0x8700007f) AM_READ8(slot0_r, 0xff)
// this is probably a shared memory region for the i82596
AM_RANGE(0x08000000, 0x0800ffff) AM_RAM
// disable the graphics slot to focus on headless operating system boot
//AM_RANGE(0x87000000, 0x8700007f) AM_READ8(slot0_r, 0xff)
// 2800 (CBUS?) slots are mapped as follows
AM_RANGE(0x87000000, 0x8700007f) AM_MIRROR(0x78000000) AM_READWRITE(unmapped_r, unmapped_w)
@ -416,12 +422,15 @@ static MACHINE_CONFIG_START(ip2800)
MCFG_RAM_EXTRA_OPTIONS("32M,64M,128M,256M")
// TODO: work out serial port assignments for mouse, console, keyboard and ?
// TODO: also work out the correct serial dma channels - scc2chanA has no dma
// first serial controller and devices
MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_SERIAL1_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL2_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w))
MCFG_Z80SCC_OUT_WREQA_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_serial1))
MCFG_Z80SCC_OUT_WREQB_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_serial2))
// is this the keyboard port?
MCFG_RS232_PORT_ADD(INTERPRO_SERIAL1_TAG, default_rs232_devices, nullptr) // "keyboard"
@ -436,21 +445,22 @@ static MACHINE_CONFIG_START(ip2800)
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsb_w))
// second serial controller and devices
MCFG_SCC85230_ADD(INTERPRO_SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0)
MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_SERIAL3_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL4_TAG, rs232_port_device, write_txd))
MCFG_Z80SCC_OUT_INT_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir11_w))
MCFG_Z80SCC_OUT_WREQB_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_serial0))
MCFG_RS232_PORT_ADD(INTERPRO_SERIAL3_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, rxa_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, dcda_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsa_w))
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, rxa_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, dcda_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, ctsa_w))
MCFG_RS232_PORT_ADD(INTERPRO_SERIAL4_TAG, default_rs232_devices, nullptr) //"terminal")
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, rxb_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, dcdb_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC1_TAG, z80scc_device, ctsb_w))
MCFG_RS232_PORT_ADD(INTERPRO_SERIAL4_TAG, default_rs232_devices, nullptr)
MCFG_RS232_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, rxb_w))
MCFG_RS232_DCD_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, dcdb_w))
MCFG_RS232_CTS_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, ctsb_w))
// real-time clock/non-volatile memory
MCFG_MC146818_ADD(INTERPRO_RTC_TAG, XTAL_32_768kHz)
@ -483,9 +493,11 @@ static MACHINE_CONFIG_START(ip2800)
MCFG_INTERPRO_IOGA_IRQ_CB(INPUTLINE(INTERPRO_CPU_TAG, INPUT_LINE_IRQ0))
//MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_CHANNEL_PLOTTER, unknown)
MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_SCSI, DEVREAD8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, mdma_r), DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, mdma_w))
MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_SCSI, DEVREAD8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, mdma_r), DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, mdma_w))
MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_FLOPPY, DEVREAD8(INTERPRO_FDC_TAG, n82077aa_device, mdma_r), DEVWRITE8(INTERPRO_FDC_TAG, n82077aa_device, mdma_w))
MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_SERIAL, DEVREAD8(INTERPRO_SCC1_TAG, z80scc_device, da_r), DEVWRITE8(INTERPRO_SCC1_TAG, z80scc_device, da_w))
MCFG_INTERPRO_IOGA_DMA_SERIAL_CB(IOGA_DMA_SERIAL0, DEVREAD8(INTERPRO_SCC2_TAG, z80scc_device, db_r), DEVWRITE8(INTERPRO_SCC2_TAG, z80scc_device, db_w))
MCFG_INTERPRO_IOGA_DMA_SERIAL_CB(IOGA_DMA_SERIAL1, DEVREAD8(INTERPRO_SCC2_TAG, z80scc_device, da_r), DEVWRITE8(INTERPRO_SCC2_TAG, z80scc_device, da_w))
MCFG_INTERPRO_IOGA_DMA_SERIAL_CB(IOGA_DMA_SERIAL2, DEVREAD8(INTERPRO_SCC1_TAG, z80scc_device, db_r), DEVWRITE8(INTERPRO_SCC1_TAG, z80scc_device, db_w))
MCFG_INTERPRO_IOGA_FDCTC_CB(DEVWRITELINE(INTERPRO_FDC_TAG, n82077aa_device, tc_line_w))
MCFG_INTERPRO_IOGA_DMA_BUS(INTERPRO_CAMMU_TAG, 0)

View File

@ -83,7 +83,7 @@ public:
required_device<mc146818_device> m_rtc;
required_device<n82077aa_device> m_fdc;
required_device<nscsi_bus_device> m_scsibus;
required_device<ncr53c90a_device> m_scsi;
required_device<ncr53c94_device> m_scsi;
required_device<interpro_ioga_device> m_ioga;
required_device<interpro_fmcc_device> m_mcga;
required_device<interpro_sga_device> m_sga;

View File

@ -25,6 +25,7 @@
#define LOG_HWINT_ENABLE 0
#define LOG_DMA_ENABLE 0
#define LOG_TIMER_ENABLE 0
#define LOG_DMA_SERIAL_ENABLE 0
#define VERBOSE 0
@ -33,12 +34,14 @@
#define LOG_TIMER(timer, ...) if (LOG_TIMER_ENABLE & (1 << timer)) logerror(__VA_ARGS__)
#define LOG_HWINT(interrupt, ...) if (LOG_HWINT_ENABLE & (1 << interrupt)) logerror(__VA_ARGS__)
#define LOG_DMA(channel, ...) if (LOG_DMA_ENABLE & (1 << channel)) logerror(__VA_ARGS__)
#define LOG_DMA_SERIAL(channel, ...) if (LOG_DMA_SERIAL_ENABLE & (1 << channel)) logerror(__VA_ARGS__)
#define LOG_ETH(...) logerror(__VA_ARGS__)
#else
#define LOG_INTERRUPT(...)
#define LOG_TIMER(timer, ...)
#define LOG_HWINT(interrupt, ...)
#define LOG_DMA(channel, ...)
#define LOG_DMA_SERIAL(channel, ...)
#define LOG_ETH(...)
#endif
@ -51,7 +54,18 @@ DEVICE_ADDRESS_MAP_START(map, 32, interpro_ioga_device)
AM_RANGE(0x1c, 0x1f) AM_READWRITE(dma_plotter_eosl_r, dma_plotter_eosl_w)
AM_RANGE(0x20, 0x2f) AM_READWRITE(dma_scsi_r, dma_scsi_w)
AM_RANGE(0x30, 0x3f) AM_READWRITE(dma_floppy_r, dma_floppy_w)
AM_RANGE(0x40, 0x57) AM_READWRITE(dma_serial_r, dma_serial_w)
AM_RANGE(0x40, 0x43) AM_READWRITE(dma_serial0_addr_r, dma_serial0_addr_w)
AM_RANGE(0x44, 0x47) AM_READWRITE16(dma_serial0_count_r, dma_serial0_count_w, 0x0000ffff)
AM_RANGE(0x44, 0x47) AM_READWRITE16(dma_serial0_ctrl_r, dma_serial0_ctrl_w, 0xffff0000)
AM_RANGE(0x48, 0x4b) AM_READWRITE(dma_serial1_addr_r, dma_serial1_addr_w)
AM_RANGE(0x4c, 0x4f) AM_READWRITE16(dma_serial1_count_r, dma_serial1_count_w, 0x0000ffff)
AM_RANGE(0x4c, 0x4f) AM_READWRITE16(dma_serial1_ctrl_r, dma_serial1_ctrl_w, 0xffff0000)
AM_RANGE(0x50, 0x53) AM_READWRITE(dma_serial2_addr_r, dma_serial2_addr_w)
AM_RANGE(0x54, 0x57) AM_READWRITE16(dma_serial2_count_r, dma_serial2_count_w, 0x0000ffff)
AM_RANGE(0x54, 0x57) AM_READWRITE16(dma_serial2_ctrl_r, dma_serial2_ctrl_w, 0xffff0000)
AM_RANGE(0x5c, 0x7f) AM_READWRITE16(icr_r, icr_w, 0xffffffff)
AM_RANGE(0x80, 0x83) AM_READWRITE16(icr18_r, icr18_w, 0x0000ffff)
@ -79,11 +93,15 @@ interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, const
m_out_irq_func(*this),
m_memory_space(nullptr),
m_dma_channel{
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_PLOT, IOGA_DMA_PLOTTER, "plotter" },
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SCSI, IOGA_DMA_SCSI, "scsi" },
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_FDC, IOGA_DMA_FLOPPY, "floppy" },
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SER0 | ARBCTL_BGR_SER1 | ARBCTL_BGR_SER2, IOGA_DMA_SERIAL, "serial" } },
m_fdc_tc_func(*this)
{ 0,0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_PLOT, IOGA_DMA_PLOTTER, "plotter" },
{ 0,0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SCSI, IOGA_DMA_SCSI, "scsi" },
{ 0,0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_FDC, IOGA_DMA_FLOPPY, "floppy" } },
m_dma_serial_channel {
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SER0, IOGA_DMA_SERIAL0, "serial0" },
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SER1, IOGA_DMA_SERIAL1, "serial1" },
{ 0,0,0,0,IDLE, {*this}, {*this}, ARBCTL_BGR_SER2, IOGA_DMA_SERIAL2, "serial2" } },
m_fdc_tc_func(*this),
m_eth_ca_func(*this)
{
}
@ -127,13 +145,20 @@ void interpro_ioga_device::device_start()
siblingdevice("mmu")->interface(mmu);
m_memory_space = &mmu->space(0);
for (int i = 0; i < IOGA_DMA_CHANNELS; i++)
for (auto &dma_channel : m_dma_channel)
{
m_dma_channel[i].device_r.resolve_safe(0xff);
m_dma_channel[i].device_w.resolve();
dma_channel.device_r.resolve_safe(0xff);
dma_channel.device_w.resolve();
}
for (auto &dma_channel : m_dma_serial_channel)
{
dma_channel.device_r.resolve_safe(0xff);
dma_channel.device_w.resolve();
}
m_fdc_tc_func.resolve();
m_eth_ca_func.resolve();
// allocate ioga timers
m_timer[0] = timer_alloc(IOGA_TIMER_0);
@ -291,6 +316,7 @@ void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, in
case IOGA_CLOCK:
interrupt_clock();
dma_clock();
dma_serial_clock();
break;
}
}
@ -646,11 +672,10 @@ void interpro_ioga_device::dma_clock()
case COMMAND:
// start a command
// HACK: busy flag indicates bus access required?
if (dma_channel.control & DMA_CTRL_BUSY)
if (dma_channel.control & DMA_CTRL_BGR)
dma_channel.state = WAIT;
else
dma_channel.state = COMPLETE;
dma_channel.state = FINAL;
break;
case WAIT:
@ -672,25 +697,26 @@ void interpro_ioga_device::dma_clock()
break;
case TRANSFER:
// if there are no more bytes remaining, terminate the transfer
if (dma_channel.transfer_count == 0)
if (dma_channel.transfer_count)
{
LOG_DMA(dma_channel.channel, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
(dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from",
dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count);
if (dma_channel.channel == IOGA_DMA_FLOPPY)
if (dma_channel.drq_state)
{
LOG_DMA(dma_channel.channel, "dma: asserting fdc terminal count line\n");
// transfer from the memory to device or device to memory
// TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set
m_fdc_tc_func(ASSERT_LINE);
m_fdc_tc_func(CLEAR_LINE);
if (dma_channel.control & DMA_CTRL_WRITE)
dma_channel.device_w(m_memory_space->read_byte(dma_channel.real_address));
else
m_memory_space->write_byte(dma_channel.real_address, dma_channel.device_r());
// increment addresses and decrement count
dma_channel.real_address++;
dma_channel.virtual_address++;
dma_channel.transfer_count--;
}
// set transfer count zero flag
dma_channel.control |= DMA_CTRL_TCZERO;
dma_channel.state = COMPLETE;
}
else
dma_channel.state = COMPLETE;
#if IOGA_DMA_DIAG_HACK
else
#define TAG ((dma_channel.control & DMA_CTRL_TAG) >> 3)
@ -761,8 +787,89 @@ void interpro_ioga_device::dma_clock()
break;
case COMPLETE:
// clear busy flag
dma_channel.control &= ~DMA_CTRL_BUSY;
LOG_DMA(dma_channel.channel, "dma: transfer %s device ended, channel = %d, control 0x%08x, real address 0x%08x, virtual address 0x%08x, count 0x%08x\n",
(dma_channel.control & DMA_CTRL_WRITE) ? "to" : "from",
dma_channel.channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count);
if (dma_channel.channel == IOGA_DMA_FLOPPY)
{
LOG_DMA(dma_channel.channel, "dma: asserting fdc terminal count line\n");
m_fdc_tc_func(ASSERT_LINE);
m_fdc_tc_func(CLEAR_LINE);
}
// clear bus grant required
dma_channel.control &= ~DMA_CTRL_BGR;
// set transfer count zero flag
dma_channel.control |= DMA_CTRL_TCZERO;
dma_channel.state = FINAL;
break;
case FINAL:
dma_channel.state = IDLE;
break;
}
}
}
void interpro_ioga_device::dma_serial_clock()
{
for (auto &dma_channel : m_dma_serial_channel)
{
switch (dma_channel.state)
{
case IDLE:
if (dma_channel.drq_state && dma_channel.count)
dma_channel.state = WAIT;
break;
case COMMAND:
case WAIT:
if (m_arbctl & dma_channel.arb_mask)
dma_channel.state = TRANSFER;
break;
case TRANSFER:
if (dma_channel.count)
{
if (dma_channel.drq_state)
{
// transfer from the memory to device or device to memory
// TODO: work out which control register bits indicate read from device
if (true)
{
u8 data = m_memory_space->read_byte(dma_channel.address);
LOG_DMA_SERIAL(dma_channel.channel, "dma: transferring byte 0x%02x to serial channel %d\n", data, dma_channel.channel);
dma_channel.device_w(data);
}
else
m_memory_space->write_byte(dma_channel.address, dma_channel.device_r());
// increment address and decrement count
dma_channel.address++;
dma_channel.count--;
}
}
else
dma_channel.state = COMPLETE;
break;
case COMPLETE:
// transfer count zero
dma_channel.control |= 0x20;
dma_channel.state = FINAL;
break;
case FINAL:
// raise an interrupt
m_hwicr[16] |= IOGA_INTERRUPT_PENDING;
dma_channel.state = IDLE;
break;
}
@ -771,30 +878,22 @@ void interpro_ioga_device::dma_clock()
void interpro_ioga_device::drq(int state, int channel)
{
// TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set
struct dma &dma_channel = m_dma_channel[channel];
if (state)
{
LOG_DMA(channel, "dma: drq for channel %d asserted\n", channel);
dma_channel.drq_state = state;
if (dma_channel.state == TRANSFER && dma_channel.transfer_count)
{
// transfer from the memory to device or device to memory
if (dma_channel.control & DMA_CTRL_WRITE)
dma_channel.device_w(m_memory_space->read_byte(dma_channel.real_address));
else
m_memory_space->write_byte(dma_channel.real_address, dma_channel.device_r());
// only log every 256 bytes
if ((dma_channel.transfer_count & 0xff) == 0)
LOG_DMA(channel, "dma: drq for channel %d %s, transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count);
}
// increment addresses and decrement count
dma_channel.real_address++;
dma_channel.virtual_address++;
dma_channel.transfer_count--;
}
}
else
LOG_DMA(channel, "dma: drq for channel %d deasserted\n", channel);
void interpro_ioga_device::drq_serial(int state, int channel)
{
struct dma_serial &dma_channel = m_dma_serial_channel[channel];
dma_channel.drq_state = state;
LOG_DMA_SERIAL(channel, "dma: drq for serial channel %d %s, counter 0x%04x\n", channel, state ? "asserted" : "deasserted", dma_channel.count);
}
u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mask, int channel)
@ -856,32 +955,25 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data,
}
}
u32 interpro_ioga_device::dma_serial_r(address_space &space, offs_t offset, u32 mem_mask)
void interpro_ioga_device::dma_serial_addr_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel)
{
int channel = offset >> 1;
LOG_DMA_SERIAL(channel, "dma: serial channel %d address = 0x%08x (%s)\n", channel, data, machine().describe_context());
if (offset & 1)
return m_dma_serial[channel].control;
else
return m_dma_serial[channel].address;
m_dma_serial_channel[channel].address = data;
}
void interpro_ioga_device::dma_serial_w(address_space &space, offs_t offset, u32 data, u32 mem_mask)
void interpro_ioga_device::dma_serial_count_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel)
{
int channel = offset >> 1;
LOG_DMA_SERIAL(channel, "dma: serial channel %d count = 0x%04x (%s)\n", channel, data, machine().describe_context());
if (offset & 1)
{
LOG_DMA(IOGA_DMA_SERIAL, "dma: channel %d(%d) control = 0x%08x, mask = 0x%08x (%s)\n", IOGA_DMA_SERIAL, channel, data, mem_mask, machine().describe_context());
m_dma_serial_channel[channel].count = data;
}
m_dma_serial[channel].control = (m_dma_serial[channel].control & ~mem_mask) | data;
}
else
{
LOG_DMA(IOGA_DMA_SERIAL, "dma: channel %d(%d) address = 0x%08x, mask = 0x%08x (%s)\n", IOGA_DMA_SERIAL, channel, data, mem_mask, machine().describe_context());
void interpro_ioga_device::dma_serial_ctrl_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel)
{
LOG_DMA_SERIAL(channel, "dma: serial channel %d control = 0x%04x (%s)\n", channel, data, machine().describe_context());
m_dma_serial[channel].address = (m_dma_serial[channel].address & ~mem_mask) | data;
}
m_dma_serial_channel[channel].control = data;
}
READ32_MEMBER(interpro_ioga_device::error_businfo_r)

View File

@ -19,9 +19,16 @@
devcb = &interpro_ioga_device::static_set_dma_r_callback(*device, _channel, DEVCB_##_dma_r); \
devcb = &interpro_ioga_device::static_set_dma_w_callback(*device, _channel, DEVCB_##_dma_w);
#define MCFG_INTERPRO_IOGA_DMA_SERIAL_CB(_channel, _dma_r, _dma_w) \
devcb = &interpro_ioga_device::static_set_dma_serial_r_callback(*device, _channel, DEVCB_##_dma_r); \
devcb = &interpro_ioga_device::static_set_dma_serial_w_callback(*device, _channel, DEVCB_##_dma_w);
#define MCFG_INTERPRO_IOGA_FDCTC_CB(_tc) \
devcb = &interpro_ioga_device::static_set_fdc_tc_callback(*device, DEVCB_##_tc);
#define MCFG_INTERPRO_IOGA_ETH_CA_CB(_ca) \
devcb = &interpro_ioga_device::static_set_eth_ca_callback(*device, DEVCB_##_ca);
#define MCFG_INTERPRO_IOGA_DMA_BUS(_mmu, _space)
// timer 0 seem to be a 60Hz cycle
@ -54,11 +61,15 @@
#define IOGA_INTERRUPT_SOFT_LO 4
#define IOGA_INTERRUPT_SOFT_HI 5
#define IOGA_DMA_CHANNELS 4
#define IOGA_DMA_PLOTTER 0
#define IOGA_DMA_SCSI 1
#define IOGA_DMA_FLOPPY 2
#define IOGA_DMA_SERIAL 3
#define IOGA_DMA_CHANNELS 3
#define IOGA_DMA_PLOTTER 0
#define IOGA_DMA_SCSI 1
#define IOGA_DMA_FLOPPY 2
#define IOGA_DMA_SERIAL_CHANNELS 3
#define IOGA_DMA_SERIAL0 0
#define IOGA_DMA_SERIAL1 1
#define IOGA_DMA_SERIAL2 2
class interpro_ioga_device : public device_t
{
@ -71,7 +82,11 @@ public:
template<class _Object> static devcb_base &static_set_dma_r_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_channel[channel].device_r.set_callback(object); }
template<class _Object> static devcb_base &static_set_dma_w_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_channel[channel].device_w.set_callback(object); }
template<class _Object> static devcb_base &static_set_dma_serial_r_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_serial_channel[channel].device_r.set_callback(object); }
template<class _Object> static devcb_base &static_set_dma_serial_w_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_serial_channel[channel].device_w.set_callback(object); }
template<class _Object> static devcb_base &static_set_fdc_tc_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_fdc_tc_func.set_callback(object); }
template<class _Object> static devcb_base &static_set_eth_ca_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_eth_ca_func.set_callback(object); }
virtual DECLARE_ADDRESS_MAP(map, 32);
@ -97,6 +112,10 @@ public:
DECLARE_WRITE_LINE_MEMBER(drq_scsi) { drq(state, IOGA_DMA_SCSI); }
DECLARE_WRITE_LINE_MEMBER(drq_floppy) { drq(state, IOGA_DMA_FLOPPY); }
DECLARE_WRITE_LINE_MEMBER(drq_serial0) { drq_serial(state, IOGA_DMA_SERIAL0); }
DECLARE_WRITE_LINE_MEMBER(drq_serial1) { drq_serial(state, IOGA_DMA_SERIAL1); }
DECLARE_WRITE_LINE_MEMBER(drq_serial2) { drq_serial(state, IOGA_DMA_SERIAL2); }
enum eth_remap_mask
{
ETH_REMAP_CHA_FLUSH = 0x00000008,
@ -123,7 +142,7 @@ public:
enum eth_control_mask
{
ETH_CA = 0x00000001,
ETH_CA = 0x00000001, // channel attention
ETH_MAPEN = 0x00000002,
ETH_REMAP_CHC_BUF = 0x00000010,
ETH_REMAP_CHC_QUAD = 0x00000020,
@ -210,7 +229,7 @@ public:
DMA_CTRL_BERR = 0x00400000, // bus error
DMA_CTRL_ERR = 0x00800000, // checked for in scsi isr
DMA_CTRL_BUSY = 0x01000000, // cleared when command complete (maybe bus grant required?)
DMA_CTRL_BGR = 0x01000000, // cleared when command complete (maybe bus grant required?)
DMA_CTRL_WAIT = 0x02000000, // waiting for bus grant
DMA_CTRL_X = 0x04000000, // set during fdc dma?
@ -226,8 +245,26 @@ public:
DECLARE_READ32_MEMBER(dma_floppy_r) { return dma_r(space, offset, mem_mask, IOGA_DMA_FLOPPY); }
DECLARE_WRITE32_MEMBER(dma_floppy_w) { dma_w(space, offset, data, mem_mask, IOGA_DMA_FLOPPY); }
DECLARE_READ32_MEMBER(dma_serial_r);
DECLARE_WRITE32_MEMBER(dma_serial_w);
DECLARE_READ32_MEMBER(dma_serial0_addr_r) { return dma_serial_addr_r(space, offset, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_WRITE32_MEMBER(dma_serial0_addr_w) { dma_serial_addr_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_READ16_MEMBER(dma_serial0_count_r) { return dma_serial_count_r(space, offset, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_WRITE16_MEMBER(dma_serial0_count_w) { dma_serial_count_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_READ16_MEMBER(dma_serial0_ctrl_r) { return dma_serial_ctrl_r(space, offset, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_WRITE16_MEMBER(dma_serial0_ctrl_w) { dma_serial_ctrl_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL0); }
DECLARE_READ32_MEMBER(dma_serial1_addr_r) { return dma_serial_addr_r(space, offset, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_WRITE32_MEMBER(dma_serial1_addr_w) { dma_serial_addr_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_READ16_MEMBER(dma_serial1_count_r) { return dma_serial_count_r(space, offset, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_WRITE16_MEMBER(dma_serial1_count_w) { dma_serial_count_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_READ16_MEMBER(dma_serial1_ctrl_r) { return dma_serial_ctrl_r(space, offset, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_WRITE16_MEMBER(dma_serial1_ctrl_w) { dma_serial_ctrl_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL1); }
DECLARE_READ32_MEMBER(dma_serial2_addr_r) { return dma_serial_addr_r(space, offset, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_WRITE32_MEMBER(dma_serial2_addr_w) { dma_serial_addr_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_READ16_MEMBER(dma_serial2_count_r) { return dma_serial_count_r(space, offset, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_WRITE16_MEMBER(dma_serial2_count_w) { dma_serial_count_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_READ16_MEMBER(dma_serial2_ctrl_r) { return dma_serial_ctrl_r(space, offset, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_WRITE16_MEMBER(dma_serial2_ctrl_w) { dma_serial_ctrl_w(space, offset, data, mem_mask, IOGA_DMA_SERIAL2); }
DECLARE_READ32_MEMBER(dma_plotter_eosl_r) { return m_dma_plotter_eosl; }
DECLARE_WRITE32_MEMBER(dma_plotter_eosl_w) { m_dma_plotter_eosl = data; }
@ -278,8 +315,10 @@ private:
void interrupt_clock();
void dma_clock();
void dma_serial_clock();
void drq(int state, int channel);
void drq_serial(int state, int channel);
devcb_write_line m_out_nmi_func;
devcb_write_line m_out_irq_func;
address_space *m_memory_space;
@ -290,7 +329,8 @@ private:
WAIT,
COMMAND,
TRANSFER,
COMPLETE
COMPLETE,
FINAL
};
// dma channels
struct dma
@ -300,6 +340,7 @@ private:
u32 transfer_count;
u32 control;
int drq_state;
dma_states state;
devcb_read8 device_r;
devcb_write8 device_w;
@ -310,13 +351,25 @@ private:
} m_dma_channel[IOGA_DMA_CHANNELS];
u32 m_dma_plotter_eosl;
struct serial_dma
// dma serial channels
struct dma_serial
{
u32 address;
u32 control;
} m_dma_serial[3];
u16 count;
u16 control;
int drq_state;
dma_states state;
devcb_read8 device_r;
devcb_write8 device_w;
const u16 arb_mask;
const int channel;
const char *name;
} m_dma_serial_channel[IOGA_DMA_SERIAL_CHANNELS];
devcb_write_line m_fdc_tc_func;
devcb_write_line m_eth_ca_func;
u32 m_active_interrupt_type;
u32 m_active_interrupt_number;
@ -338,6 +391,13 @@ private:
u32 dma_r(address_space &space, offs_t offset, u32 mem_mask, int channel);
void dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel);
u32 dma_serial_addr_r(address_space &space, offs_t offset, u32 mem_mask, int channel) { return m_dma_serial_channel[channel].address; }
void dma_serial_addr_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel);
u16 dma_serial_count_r(address_space &space, offs_t offset, u16 mem_mask, int channel) { return m_dma_serial_channel[channel].count; }
void dma_serial_count_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel);
u16 dma_serial_ctrl_r(address_space &space, offs_t offset, u16 mem_mask, int channel) { return m_dma_serial_channel[channel].control; }
void dma_serial_ctrl_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel);
u16 m_arbctl;
u32 m_error_address;