diff options
Diffstat (limited to 'src/mame/machine/interpro_ioga.cpp')
-rw-r--r-- | src/mame/machine/interpro_ioga.cpp | 310 |
1 files changed, 221 insertions, 89 deletions
diff --git a/src/mame/machine/interpro_ioga.cpp b/src/mame/machine/interpro_ioga.cpp index 236b64b0d7b..010791f5165 100644 --- a/src/mame/machine/interpro_ioga.cpp +++ b/src/mame/machine/interpro_ioga.cpp @@ -18,10 +18,13 @@ #include "emu.h" #include "interpro_ioga.h" +// the following enables some hacks which will allow all iogadiag tests to complete successfully, but also breaks scsi dma +#define IOGA_DMA_DIAG_HACK 0 + #define LOG_GENERAL (1 << 31) -#define LOG_HWINT_ENABLE 0 //((1<<3) | LOG_GENERAL) -#define LOG_DMA_ENABLE ((1<<IOGA_DMA_FLOPPY) | LOG_GENERAL) -#define LOG_TIMER_ENABLE 0 +#define LOG_HWINT_ENABLE 0 +#define LOG_DMA_ENABLE 0 +#define LOG_TIMER_ENABLE 0 #define VERBOSE 0 @@ -30,14 +33,20 @@ #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_ETH(...) logerror(__VA_ARGS__) #else #define LOG_INTERRUPT(...) #define LOG_TIMER(timer, ...) #define LOG_HWINT(interrupt, ...) #define LOG_DMA(channel, ...) +#define LOG_ETH(...) #endif DEVICE_ADDRESS_MAP_START(map, 32, interpro_ioga_device) + AM_RANGE(0x00, 0x03) AM_READWRITE(eth_remap_r, eth_remap_w) + AM_RANGE(0x04, 0x07) AM_READWRITE(eth_map_page_r, eth_map_page_w) + AM_RANGE(0x08, 0x0b) AM_READWRITE(eth_control_r, eth_control_w) + AM_RANGE(0x0c, 0x1b) AM_READWRITE(dma_plotter_r, dma_plotter_w) 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) @@ -70,10 +79,10 @@ 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,false, 0, {*this}, {*this}, ARBCTL_BGR_PLOT }, - { 0,0,0,0,false, 0, {*this}, {*this}, ARBCTL_BGR_SCSI }, - { 0,0,0,0,false, 0, {*this}, {*this}, ARBCTL_BGR_FDC }, - { 0,0,0,0,false, 0, {*this}, {*this}, ARBCTL_BGR_SER0 | ARBCTL_BGR_SER1 | ARBCTL_BGR_SER2 } }, + { 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) { } @@ -135,10 +144,7 @@ void interpro_ioga_device::device_start() for (auto & timer : m_timer) timer->enable(false); - // allocate timer for DMA controller - m_dma_timer = timer_alloc(IOGA_TIMER_DMA); - m_dma_timer->adjust(attotime::never); - + // allocate ioga interrupt and dma timer m_ioga_clock = timer_alloc(IOGA_CLOCK); m_ioga_clock->adjust(attotime::never); } @@ -157,7 +163,7 @@ void interpro_ioga_device::device_reset() m_timer_reg[0] = 0; //m_timer[0]->adjust(attotime::zero, IOGA_TIMER_0, attotime::from_hz(60)); - // configure ioga clock timer + // configure ioga interrupt and dma timer m_ioga_clock->adjust(attotime::zero, IOGA_CLOCK, attotime::from_hz(clock())); } @@ -282,12 +288,9 @@ void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, in } break; - case IOGA_TIMER_DMA: - dma_clock(param); - break; - case IOGA_CLOCK: interrupt_clock(); + dma_clock(); break; } } @@ -482,7 +485,8 @@ void interpro_ioga_device::interrupt_clock() if (m_nmi_pending) { // check if nmi is enabled - if ((m_nmictrl & NMI_IE) == NMI_IE) + if (((m_nmictrl & NMI_IE) == NMI_IE) + || ((m_nmictrl & (NMI_ALL | NMI_ENABLE1)) == (NMI_ALL | NMI_ENABLE1))) { LOG_INTERRUPT("nmi: accepting nmi\n"); @@ -607,7 +611,10 @@ WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) // check for a forced nmi (NMI_NEGPOL written from 1 to 0 with NMI_IE set) if ((m_nmictrl & NMI_NEGPOL) && (data & (NMI_NEGPOL | NMI_IE)) == NMI_IE) + { + LOG_INTERRUPT("nmi: forced nmi\n"); m_nmi_pending = true; + } m_nmictrl = data; } @@ -628,136 +635,223 @@ WRITE16_MEMBER(interpro_ioga_device::softint_vector_w) /****************************************************************************** DMA ******************************************************************************/ -void interpro_ioga_device::dma_clock(int channel) +void interpro_ioga_device::dma_clock() { - struct dma &dma_channel = m_dma_channel[channel]; - - // if bus grant is not enabled, set the busy flag (iogadiag test 7.0265) - if (!(m_arbctl & dma_channel.arb_mask)) + for (auto &dma_channel : m_dma_channel) { - dma_channel.control |= DMA_CTRL_BUSY; - m_dma_channel[channel].control |= DMA_CTRL_BUSY; - m_dma_timer->adjust(attotime::from_hz(clock()), channel); + switch (dma_channel.state) + { + case IDLE: + break; - return; - } - else - dma_channel.control &= ~DMA_CTRL_BUSY; + case COMMAND: + // start a command + // HACK: busy flag indicates bus access required? + if (dma_channel.control & DMA_CTRL_BUSY) + dma_channel.state = WAIT; + else + dma_channel.state = COMPLETE; + break; - // if the channel isn't active yet, make it active and log something - if (!dma_channel.dma_active) - { - LOG_DMA(channel, "dma: transfer %s device begun, 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", - channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count); - dma_channel.dma_active = true; - } + case WAIT: + // if bus grant is enabled, clear wait flag and execute transfer + if (m_arbctl & dma_channel.arb_mask) + { + // clear bus wait flag + dma_channel.control &= ~DMA_CTRL_WAIT; - // transfer data while the device is requesting a data transfer and the transfer count is not zero - while (dma_channel.drq_state && 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()); + LOG_DMA(dma_channel.channel, "dma: transfer %s device begun, 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); - // increment addresses and decrement count - dma_channel.real_address++; - dma_channel.virtual_address++; - dma_channel.transfer_count--; - } + dma_channel.state = TRANSFER; + } + else + // (7.0265) set the bus grant wait flag + dma_channel.control |= DMA_CTRL_WAIT; + break; - // if there are no more bytes remaining, terminate the transfer - if (dma_channel.transfer_count == 0) - { - LOG_DMA(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", - channel, dma_channel.control, dma_channel.real_address, dma_channel.virtual_address, dma_channel.transfer_count); + case TRANSFER: + // if there are no more bytes remaining, terminate the transfer + if (dma_channel.transfer_count == 0) + { + 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 (channel == IOGA_DMA_FLOPPY) - { - LOG_DMA(channel, "dma: asserting fdc terminal count line\n"); + 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); - } + m_fdc_tc_func(ASSERT_LINE); + m_fdc_tc_func(CLEAR_LINE); + } + + // set transfer count zero flag + dma_channel.control |= DMA_CTRL_TCZERO; + dma_channel.state = COMPLETE; + } +#if IOGA_DMA_DIAG_HACK + else +#define TAG ((dma_channel.control & DMA_CTRL_TAG) >> 3) + + // hacks for forced dma bus error diagnostic tests + if ((dma_channel.control & 0xfe000000 && dma_channel.control & 0xe00) || ((dma_channel.control & DMA_CTRL_WMASK) == 0x41000000)) + if (dma_channel.real_address & 0xff000000 || dma_channel.real_address == 0) + { + LOG_DMA(dma_channel.channel, "dma: forced bus error hack, control 0x%08x\n", dma_channel.control); + + // (7.0267) trigger an interrupt + m_hwicr[dma_channel.channel + 1] |= IOGA_INTERRUPT_PENDING; + + // (7.0268) set bus error bit + dma_channel.control |= DMA_CTRL_BERR; + + // 7.0269, 7.0276, 7.0281, 7.0289: set error address from virtual or real dma address + // HACK: don't set error address for 7.0276 special case + if (!(dma_channel.control == 0x65400600 && dma_channel.real_address != 0)) + m_error_address = dma_channel.control & DMA_CTRL_VIRTUAL ? dma_channel.virtual_address : dma_channel.real_address; + + // compute bus error cycle type from control register + u8 cycle_type = 0x30; + switch ((dma_channel.control >> 24) & 0x8c) + { + case 0x00: cycle_type |= 2; break; + case 0x04: cycle_type |= 1; break; + case 0x08: cycle_type |= 3; break; + case 0x80: cycle_type |= 4; break; + case 0x84: cycle_type |= 8; break; + } + + switch (dma_channel.control & ~DMA_CTRL_BERR) + { + case 0x61000800: // VIRTUAL | WRITE | TAG(3) + // (7.0266) trigger an nmi + m_nmi_pending = true; + + // (7.0270) set error cycle type 0x52f0: SNAPOK | BERR | BG(IOD) | TAG(0c0) | CT(30) + m_error_businfo = BINFO_SNAPOK | BINFO_BERR | BINFO_BG_IOD | 0xf0; + break; + + case 0x65000600: // VIRTUAL | WRITE | X | TAG(4) + if (dma_channel.real_address != 0) + { + // (7.0275) control register expect 0x64400800 + dma_channel.control &= ~0x600; + dma_channel.control |= 0x800; + + // (7.0277) set error cycle type 0x5331: SNAPOK | BERR | BG(IOD) | TAG(100) | CT(31) + m_error_businfo = BINFO_SNAPOK | BINFO_BERR | BINFO_BG_IOD | TAG | cycle_type; + } + else + { + // (7.0287) set error cycle type 0x62f0: SNAPOK | MMBE | BG(IOD) | TAG(0c0) | CT(30) + m_error_businfo = BINFO_SNAPOK | BINFO_MMBE | BINFO_BG_IOD | TAG | 0x30; + } + break; + + default: + m_error_businfo = BINFO_SNAPOK | BINFO_BERR | BINFO_BG_IOD | TAG | cycle_type; + break; + } + + dma_channel.state = COMPLETE; + } +#endif + break; - dma_channel.control |= DMA_CTRL_TCZERO; - dma_channel.dma_active = false; + case COMPLETE: + // clear busy flag + dma_channel.control &= ~DMA_CTRL_BUSY; + dma_channel.state = IDLE; + break; + } } } void interpro_ioga_device::drq(int state, int channel) { - // a device is requesting a dma data transfer (read or write) - m_dma_channel[channel].drq_state = state; + // 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); - m_dma_timer->adjust(attotime::zero, channel); + 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()); + + // 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); } -/* -0x94: error address reg: expect 0x7f200000 after bus error (from dma virtual address) -0x98: error cycle type: expect 0x52f0 (after failed dma?) - 0x5331 - forced berr with nmi/interrupts disabled? - 0xc2f0 - 0x62f0 -*/ -// TODO: 7.0266 - forced BERR not working u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mask, int channel) { + struct dma &dma_channel = m_dma_channel[channel]; + switch (offset) { case 0: - return m_dma_channel[channel].real_address; + return dma_channel.real_address; case 1: - return m_dma_channel[channel].virtual_address; + return dma_channel.virtual_address; case 2: - return m_dma_channel[channel].transfer_count; + return dma_channel.transfer_count; case 3: - return m_dma_channel[channel].control; - } + return dma_channel.control; - logerror("dma_r: unknown channel %d\n", channel); - return 0; + default: + logerror("dma_r: unknown dma register %d\n", offset); + return 0; + } } void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) { + struct dma &dma_channel = m_dma_channel[channel]; + switch (offset) { case 0: LOG_DMA(channel, "dma: channel %d real address = 0x%08x (%s)\n", channel, data, machine().describe_context()); - m_dma_channel[channel].real_address = data; + dma_channel.real_address = data; break; case 1: LOG_DMA(channel, "dma: channel %d virtual address = 0x%08x (%s)\n", channel, data, machine().describe_context()); - m_dma_channel[channel].virtual_address = data & ~0x3; + dma_channel.virtual_address = data & ~0x3; break; case 2: LOG_DMA(channel, "dma: channel %d transfer count = 0x%08x (%s)\n", channel, data, machine().describe_context()); - m_dma_channel[channel].transfer_count = data; + dma_channel.transfer_count = data; break; case 3: LOG_DMA(channel, "dma: channel %d control = 0x%08x (%s)\n", channel, data, machine().describe_context()); - m_dma_channel[channel].control = data & DMA_CTRL_WMASK; - // start a forced dma transfer if necessary - if ((data & DMA_CTRL_FORCED) == DMA_CTRL_FORCED) - m_dma_timer->adjust(attotime::from_hz(clock()), channel); + // (7.0272) if bus error flag is set, clear existing bus error (otherwise retain existing state) + if (data & DMA_CTRL_BERR) + dma_channel.control = data & DMA_CTRL_WMASK; + else + dma_channel.control = (data & DMA_CTRL_WMASK) | (dma_channel.control & DMA_CTRL_BERR); + + dma_channel.state = COMMAND; break; } } @@ -806,3 +900,41 @@ WRITE16_MEMBER(interpro_ioga_device::arbctl_w) m_arbctl = data; } + +WRITE32_MEMBER(interpro_ioga_device::eth_remap_w) +{ + LOG_ETH("eth: remap = 0x%08x (%s)\n", data, machine().describe_context()); + + m_eth_remap = data & ~0xf; +} + +WRITE32_MEMBER(interpro_ioga_device::eth_map_page_w) +{ + LOG_ETH("eth: remap page = 0x%08x (%s)\n", data, machine().describe_context()); + + m_eth_map_page = data & ~0xf; +} + +WRITE32_MEMBER(interpro_ioga_device::eth_control_w) +{ + LOG_ETH("eth: control = 0x%08x (%s)\n", data, machine().describe_context()); + + /* (7.0202) eth ctrl register input test patterns and expected outputs are: + + 7809 -> 4000 + + 3809 -> 0800 + 3409 -> 0400 + 3209 -> 0200 + 3109 -> 0100 + + 3089 -> 80 + 3049 -> 40 + 3019 -> 10 + 300b -> 02 + */ + if (data & ETH_RESET) + m_eth_control = ETH_RESET; + else + m_eth_control = data & 0x0ff2; +} |