From c8be65d11517d1d0aa168e3808c1a5c377e6c369 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Thu, 26 Oct 2017 14:20:10 +0700 Subject: interpro: basic keyboard and graphics Many changes in this PR, including the following: * added support for InterPro 20x0, 24x0 and 27x0 systems * added support for SR bus/slot devices * added support for Ethernet, graphics, keyboard and mouse * added support for serial DMA * improved timer, interrupt and DMA handling * improved comments/documentation Note: ioga is still a major work in progress, and most of the other *ga's don't do anything useful yet, however this build can do some new and useful things, and it's closer to OS boot than before, as well as cleaned up in some of the better known areas. --- scripts/target/mame/mess.lua | 4 +- src/mame/drivers/interpro.cpp | 892 +++++++++++-------- src/mame/includes/interpro.h | 203 +++-- src/mame/layout/interpro.lay | 39 +- src/mame/machine/interpro_arbga.cpp | 88 ++ src/mame/machine/interpro_arbga.h | 90 ++ src/mame/machine/interpro_ioga.cpp | 1610 ++++++++++++++++++++--------------- src/mame/machine/interpro_ioga.h | 660 ++++++++------ src/mame/machine/interpro_mcga.cpp | 32 +- src/mame/machine/interpro_mcga.h | 18 +- src/mame/machine/interpro_sga.cpp | 74 +- src/mame/machine/interpro_sga.h | 72 +- src/mame/machine/interpro_srarb.cpp | 49 -- src/mame/machine/interpro_srarb.h | 72 -- src/mame/mame.lst | 6 +- 15 files changed, 2346 insertions(+), 1563 deletions(-) create mode 100644 src/mame/machine/interpro_arbga.cpp create mode 100644 src/mame/machine/interpro_arbga.h delete mode 100644 src/mame/machine/interpro_srarb.cpp delete mode 100644 src/mame/machine/interpro_srarb.h diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua index 040371bd0fb..6781ccbdaab 100644 --- a/scripts/target/mame/mess.lua +++ b/scripts/target/mame/mess.lua @@ -2204,8 +2204,8 @@ files { MAME_DIR .. "src/mame/machine/interpro_mcga.cpp", MAME_DIR .. "src/mame/machine/interpro_sga.h", MAME_DIR .. "src/mame/machine/interpro_sga.cpp", - MAME_DIR .. "src/mame/machine/interpro_srarb.h", - MAME_DIR .. "src/mame/machine/interpro_srarb.cpp", + MAME_DIR .. "src/mame/machine/interpro_arbga.h", + MAME_DIR .. "src/mame/machine/interpro_arbga.cpp", } createMESSProjects(_target, _subtarget, "interton") diff --git a/src/mame/drivers/interpro.cpp b/src/mame/drivers/interpro.cpp index 849d0a7d07e..f9f7eb307fe 100644 --- a/src/mame/drivers/interpro.cpp +++ b/src/mame/drivers/interpro.cpp @@ -1,6 +1,149 @@ // license:BSD-3-Clause // copyright-holders:Patrick Mackinlay +/* + * An emulation of the Intergraph InterPro/InterServe family of CLIPPER based + * UNIX workstations. + * + * The first systems were built using the original C100 CLIPPER CPU, and used + * an additional Intel 80186 as an I/O processor, later moving to a C300 with + * 80386 IOP. Around 1989, the CLIPPER became fast enough to obviate the need + * for the separate I/O processor, and systems from that point used the main + * CPU for both compute and I/O, along with some custom ASICs. + * + * Over the lifespan of the InterPro, there were five distinct families of + * systems, varying mainly in terms of the primary CPU, as follows: + * + * Year Family Models CPU + * 1986 amethyst 32C/100/200 C100 (80186 IOP) + * 1988 topaz 300/3000/4000/5000 C300/C300Plus (80386 IOP) + * 1989 turquoise 2000 C300 + * 1989 emerald 6000/6100/6200/6500/6600 C300/C300Plus (C4T in 6600?) + * 1991 sapphire 2400/6400 C4T + * 1992 sapphire 2500/2700/6700/6800/2800 C4I + * + * Individual models and some of their specific attributes include: + * + * Model Year CPU Clock Family + * 2000 1989 C300 turquoise + * 6000 1989 C300 emerald + * 2400 1991? C4T 40MHz? sapphire + * 6400 1991 C4T 40MHz sapphire + * 6600 C400 emerald (IOI, SRX bus?) + * 6700 1992 C400I 70MHz? sapphire + * 6800 1993 C400I 80MHz? sapphire + * 2500 1993? C400I 50MHz? sapphire + * 2700 1992 C400I 70MHz? sapphire + * 2800 1994 C400I 80MHz? sapphire + * + * 6100 emerald (IOI) + * 6200 1989 C300Plus 60MHz emerald + * 6500 C300Plus emerald (IOI, QWIC bus?) + * + * With many exceptions, the general model numbering system is ABCD, where: + * + * A: case type (2=desktop, 6=tower) + * B: CPU type (0=C300, 4=C4T, 6=C400?, 7/8/5 = C400I) + * C: graphics type (0=none, 3/5=GT, 4/8 = EDGE) + * D: always 0? + * + * Both the desktop and tower units supported an expansion bus with a variety + * of cards, although with different profiles and connectors between 2xxx and + * 6xxx systems. The bus is referred to as SR, SRX, SR Bus, CBUS and some + * combinations of these in various places, but all appears to be compatible or + * identical, possibly with SRX being an enhanced version. The bus supported a + * range of add-in cards, ranging from expanded SCSI and serial controllers, + * to specialised scanning and plotting controllers, a VME bridge, and most + * importantly various single and dual-headed graphics boards. + * + * The InterPro graphics options included the GT range, generally fitted to the + * desktop systems, and EDGE graphics for the towers. Systems with no graphics + * were operated through a serial console on serial port 2, and were branded as + * InterServe rather than InterPro systems. + * + * Model Year Performance + * GT 1990? 360k 2D vec/s (in a 2020) + * EDGE-1 + * EDGE-2 + * GT+ 760k 2D vec/s, 530k 3D vec/s (in a 2730) + * GTII 830k 2D vec/s, 640k 3D vec/s (in a 6750) + * 900k 2D vec/s, 700k 3D vec/s (in a 6850) + * EDGE II+ 50k Gouraud-shaded poly/s (in a 6780) + * + * This emulation currently supports the Turquoise and Sapphire desktop systems (i.e. models + * 2000/2400/2500/2700/2800). Base GT graphics can be used with any of these models, or the + * graphics and keyboard removed and the systems used with a serial terminal instead. + * + * Key parts lists for the supported models are as follows. + * + * 2000 Turquoise (C300 @ 40MHz?, main board PCB962) + * + * Ref Part Function + * U37 Intel 82072 Floppy drive controller + * U39 Intel 82586 Ethernet controller + * U40 Zilog 8530 SCC Keyboard and console serial controller + * U41 Zilog 8530 SCC Serial controller for serial port 0 and 1 + * U42 Xilinix XC3020-50 Plotter control FPGA? + * U43 (MPRGM610C) Bitstream for XC3020? + * U54 4.9152 MHz crystal Clock source for 8530s? + * U55 20.0 MHz crystal + * U57 24.0 MHz crystal Clock source for 53C90A? + * U61 NCR 53C90A SCSI controller + * U63 CIDC84607 TC110G75CY-0011 Intergraph I/O gate array? + * U116 Dallas DS1287 RTC and NVRAM + * U137? diagnostic 7-segment LED? + * U171 128 kB EPROM (MPRGM530E) Boot ROM MSB + * U172 128 kB EPROM (MPRGM540E) Boot ROM LSB + * + * 2400 Sapphire (C400T @ 40MHz?, main board SMT047) + * + * Ref Part Function + * U31 Zilog Z85C30 SCC Keyboard and console serial controller + * U32 Zilog Z85230 ESCC Serial controller for serial port 0 and 1 + * U34 Xilinix XC3020-50 Plotter control FPGA? + * U35 128 kB EPROM (MPRGW510B) Boot ROM + * U43? (MPRGM610P) Bitstream for XC3020? + * U44 Intel 82596SX Ethernet controller (20MHz) + * U68 CYID21603 TC150G89AF + * U71 LSI L1A6104 CICD 95801 Intergraph I/O gate array + * U81 NCR 53C94 SCSI controller + * U86 24.0 MHz crystal Clock source for 53C94? + * U87 4.9152 MHz crystal Clock source for 8530s? + * U88 20.0 MHz crystal Clock source for 82596? + * U91 Intel N82077AA Floppy drive controller + * U96 32.0 MHz crystal + * U97 40.0 MHz crystal + * U112? (MPRG4230A) node ID prom? + * U113? Dallas DS1287 RTC and NVRAM + * U117? diagnostic 7-segment LED? + * U118? (MPRG X510R) + * U155 CYID21704 TC140G54AF + * + * 2700 Sapphire (C400I @ 70MHz?, main board SMT128) + * + * Ref Part Function + * U31 Zilog Z85C30 SCC Keyboard and console serial controller + * U32 Zilog Z85230 ESCC Serial controller for serial port 0 and 1 + * U34 Xilinix XC3020-70 Plotter control FPGA? + * U35 128 kB EPROM (MPRGZ530A) Boot ROM + * U43? (MPRGM610P) Bitstream for XC3020? + * U44 Intel 82596SX? Ethernet controller + * U68 CYID21603 TC150G89AF + * U71 LSI L1A7374 CIDC094A3 Intergraph I/O gate array + * U81 NCR 53C94 SCSI controller + * U86 24.0 MHz crystal Clock source for 53C94? + * U87 4.9152 MHz crystal Clock source for 8530s? + * U88 20.0 MHz crystal Clock source for 82596? + * U91 Intel N82077AA? Floppy drive controller + * U96 32.0 MHz crystal? + * U97 40.0 MHz crystal + * U112? (MPRGZ260E) node ID prom? + * U113? Dallas DS12887 RTC and NVRAM + * U117? diagnostic 7-segment LED? + * U118? () + * U155 CYID212?4 TC140G54AF? + */ + #include "emu.h" #include "includes/interpro.h" @@ -10,26 +153,55 @@ #include "interpro.lh" #define VERBOSE 0 -#if VERBOSE -#define LOG_SYSTEM(...) logerror(__VA_ARGS__) -#define LOG_IDPROM(...) logerror(__VA_ARGS__) -#else -#define LOG_SYSTEM(...) {} -#define LOG_IDPROM(...) {} -#endif - -// machine start +#include "logmacro.h" + +// FIXME: eeprom/flash device embedded here until real device is known +DEFINE_DEVICE_TYPE(INTERPRO_EEPROM, interpro_eeprom_device, "interpro_eeprom", "InterPro Flash EEPROM"); + +interpro_eeprom_device::interpro_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : eeprom_base_device(mconfig, INTERPRO_EEPROM, tag, owner) +{ +} + void interpro_state::machine_start() { - m_sreg_ctrl2 = CTRL2_COLDSTART | CTRL2_PWRENA | CTRL2_PWRUP; + // FIXME: disabled for now to avoid cold start diagnostic errors + //m_sreg_ctrl2 = CTRL2_COLDSTART | CTRL2_PWRUP; + m_sreg_ctrl2 = 0; + + save_item(NAME(m_sreg_error)); + save_item(NAME(m_sreg_status)); + save_item(NAME(m_sreg_led)); + save_item(NAME(m_sreg_ctrl1)); + save_item(NAME(m_sreg_ctrl2)); + + save_item(NAME(m_sreg_ctrl3)); } void interpro_state::machine_reset() { // flash rom requires the following values - m_sreg_error = 0x00; + m_sreg_error = 0; m_sreg_status = 0x400; - m_sreg_ctrl1 = CTRL1_FLOPRDY; + m_sreg_ctrl1 = CTRL1_FLOPLOW; +} + +DRIVER_INIT_MEMBER(interpro_state, interpro) +{ + // FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and + // "optimum_memory" commands + + // 16 = reports 16M, banks empty? + // 32 = reports 16M, banks empty? + // 64 = reports 128M, 16x8 + // 128 = reports 128M, 16x8 + // 256 = reports 256M, 32x8 + + // grab the main memory space from the mmu + address_space &space = m_mmu->space(0); + + // map the configured ram + space.install_ram(0, m_ram->mask(), m_ram->pointer()); } WRITE16_MEMBER(interpro_state::sreg_led_w) @@ -38,167 +210,64 @@ WRITE16_MEMBER(interpro_state::sreg_led_w) static const u8 patterns[16] = { 0x3f, 0x06, 0x5b, 0x4f, 0x66, 0x6d, 0x7d, 0x07, 0x7f, 0x6f, 0x77, 0x7c, 0x39, 0x5e, 0x79, 0x71 }; output().set_digit_value(0, patterns[data & 0xf]); + + COMBINE_DATA(&m_sreg_led); } WRITE16_MEMBER(interpro_state::sreg_ctrl1_w) { - LOG_SYSTEM("system control register 1 write data 0x%x (%s)\n", data, machine().describe_context()); + LOG("control register 1 data 0x%04x mem_mask 0x%04x (%s)\n", data, mem_mask, machine().describe_context()); // check if led decimal point changes state if ((data ^ m_sreg_ctrl1) & CTRL1_LEDDP) output().set_digit_value(0, (output().get_digit_value(0) + 0x80) & 0xff); - m_sreg_ctrl1 = data; + COMBINE_DATA(&m_sreg_ctrl1); } WRITE16_MEMBER(interpro_state::sreg_ctrl2_w) { - LOG_SYSTEM("system control register 2 write data 0x%x (%s)\n", data, machine().describe_context()); + LOG("control register 2 data 0x%04x mem_mask 0x%04x (%s)\n", data, mem_mask, machine().describe_context()); if (data & CTRL2_RESET) { - m_sreg_ctrl1 &= ~CTRL2_COLDSTART; + m_sreg_ctrl2 &= ~CTRL2_COLDSTART; machine().schedule_soft_reset(); } else - m_sreg_ctrl1 = data & CTRL2_WMASK; + m_sreg_ctrl2 = (m_sreg_ctrl2 & ~CTRL2_MASK) | (data & CTRL2_MASK); } -READ16_MEMBER(interpro_state::sreg_error_r) +WRITE16_MEMBER(sapphire_state::sreg_ctrl2_w) { - u16 result = m_sreg_error; - - // clear error register on read - m_sreg_error = 0; + interpro_state::sreg_ctrl2_w(space, offset, data, mem_mask); - return result; + m_eeprom->write_enable(data & CTRL2_FLASHEN ? ASSERT_LINE : CLEAR_LINE); } -READ8_MEMBER(interpro_state::idprom_r) -{ - LOG_IDPROM("idprom read offset 0x%x mask 0x%08x at %s\n", offset, mem_mask, machine().describe_context()); - - // compute femtoseconds per cycle from main cpu clock - u32 speed = 1'000'000'000'000'000 / m_maincpu->clock(); - - static u8 idprom[] = { - // module type id - 'M', 'S', 'M', 'T', // board type MSMT/MPCB - detected by feature[3] - '1', '4', '5', // board number - '0', // board revision - - // ECO bytes - 0x00, 0x00, 0x00, 0x00, - 0x00, 0x00, 0x00, 0x00, - - // the following 8 bytes are "feature bytes" - - // for a 2700/2800/2500 system board, the first feature byte selects the variant - // model = (feature[0] & 0x2) ? (feature[0] & 0x8 ? 2700 : 2800) : 2500 - - // 0x0a, // 2700 series - 0x02, // 2800 series - // 0x00, // 2500 series - - 0x00, 0x00, - 0x00, // board type, 0x80 = MPCB, 0x00 = MSMT - - // for the system boards, these bytes contain cpu clock speed (as femtoseconds per cycle, big-endian) - (u8)(speed >> 24), (u8)(speed >> 16), (u8)(speed >> 8), (u8)(speed >> 0), - - // reserved bytes - 0xff, 0xff, - - // family - // boot rom tests for family == 0x41 or 0x42 - // if so, speed read from feature bytes 2 & 3 - // if not, read speed from feature bytes 4-7 - - //0x24, 0x00, // 2000 - - // 0x31, 0x00, // 2400 - 0x39, 0x00, // 2700/2800/2500 depending on first feature byte (0xa, 0x2, 0x0) - // 0x40, 0x00, // 6700 - // 0x41, 0x00, // idprom reports as 2800 series cpu? - //0x42, 0x00, // 6800 series - - // footprint and checksum - 0x55, 0xaa, 0x55, 0x00 - }; - - switch (offset) - { - case 0x1f: - { - u8 sum = 0; - - // compute the checksum (sum of all bytes must be == 0x00) - for (int i = 0; i < 0x20; i++) - sum += idprom[i]; - - return 0x100 - sum; - } - - default: - return idprom[offset]; - } -} - -READ8_MEMBER(interpro_state::slot0_r) +READ16_MEMBER(interpro_state::sreg_error_r) { -#if 0 - // a known graphics board idprom - static u8 slot0[] = { - 0x00, 0x00, 0x00, 0x00, '9', '6', '3', 'A', // board - 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // eco - 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // features - 0xff, 0xff, // reserved - 0x22, 0x00, // family - 0x55, 0xaa, 0x55, // footprint - 0x00 // checksum - }; -#else - static u8 slot0[] = { - 'M', 'S', 'M', 'T', // board type - '0', '7', '0', // board - 'B', // board revision - 0x02, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, // eco - 0xff, 0xff, 0xff, 0x7f, 0xff, 0xff, 0xff, 0xff, // features - 0xff, 0xff, // reserved - 0x05, 0x00, // family - 0x55, 0xaa, 0x55, // footprint - 0x00 // checksum - }; -#endif - switch (offset) - { - case 0x1f: - { - u8 sum = 0; - - // compute the checksum (sum of all bytes must be == 0x00) - for (int i = 0; i < 0x20; i++) - sum += slot0[i]; + const u16 result = m_sreg_error; - return 0x100 - sum; - } + // clear error register on read + if (!machine().side_effect_disabled()) + m_sreg_error = 0; - default: - return slot0[offset]; - } + return result; } READ32_MEMBER(interpro_state::unmapped_r) { // check if non-existent memory errors are enabled - if (m_srarb->tmctrl_r(space, offset, mem_mask) & interpro_srarb_device::TMCTRL_ENNEM) - { - // flag non-existent memory error in system error register - m_sreg_error |= (ERROR_SRXNEM | ERROR_SRXVALID); + if (!machine().side_effect_disabled()) + if (m_arbga->tctrl_r(space, offset, mem_mask) & interpro_arbga_device::TCTRL_ENNEM) + { + // flag non-existent memory error in system error register + m_sreg_error |= (ERROR_SRXNEM | ERROR_SRXVALID); - // tell ioga to raise a bus error - m_ioga->bus_error(space, interpro_ioga_device::BINFO_BERR | interpro_ioga_device::BINFO_SNAPOK, offset << 2); - } + // tell ioga to raise a bus error + m_ioga->bus_error(space, interpro_ioga_device::BINFO_BERR | interpro_ioga_device::BINFO_SNAPOK, offset << 2); + } return space.unmap(); } @@ -206,7 +275,7 @@ READ32_MEMBER(interpro_state::unmapped_r) WRITE32_MEMBER(interpro_state::unmapped_w) { // check if non-existent memory errors are enabled - if (m_srarb->tmctrl_r(space, offset, mem_mask) & interpro_srarb_device::TMCTRL_ENNEM) + if (m_arbga->tctrl_r(space, offset, mem_mask) & interpro_arbga_device::TCTRL_ENNEM) { // flag non-existent memory error in system error register m_sreg_error |= (ERROR_SRXNEM | ERROR_SRXVALID); @@ -216,122 +285,22 @@ WRITE32_MEMBER(interpro_state::unmapped_w) } } -WRITE8_MEMBER(interpro_state::rtc_w) +READ8_MEMBER(interpro_state::nodeid_r) { + // FIXME: hard coded node id for now switch (offset) { - case 0x00: - // write to RTC register - m_rtc->write(space, 1, data); - break; - - case 0x40: - // set RTC read/write address - m_rtc->write(space, 0, data); - break; - - default: - logerror("rtc: write to unknown offset 0x%02x data 0x%02x at %s\n", offset, data, machine().describe_context()); - break; + // read system node id prom (contains last 3 bytes of mac address) + case 0: return 0x12; + case 1: return 0x34; + case 2: return 0x56; + case 3: return 0x9c; // checksum - sum of other bytes } -} -READ8_MEMBER(interpro_state::rtc_r) -{ - switch (offset) - { - case 0x00: - // read from RTC register - return m_rtc->read(space, 1); - - // read from InterPro system ID PROM (contains MAC address) - case 0x40: return 0x12; - case 0x41: return 0x34; - case 0x42: return 0x56; - - default: - logerror("rtc: read from unknown offset 0x%02x at %s\n", offset, machine().describe_context()); - return 0xff; - } -} - -// these wrappers handle the two alternative scsi drivers, as well as the weird memory mapping on the InterPro -// that maps consecutive registers at offsets of 0x100 (and with lsb = 1, but we're ignoring that for now - -READ8_MEMBER(interpro_state::scsi_r) -{ - switch (offset >> 6) - { - case 0x0: return m_scsi->tcounter_lo_r(space, 0); - case 0x1: return m_scsi->tcounter_hi_r(space, 0); - case 0x2: return m_scsi->fifo_r(space, 0); - case 0x3: return m_scsi->command_r(space, 0); - case 0x4: return m_scsi->status_r(space, 0); - case 0x5: return m_scsi->istatus_r(space, 0); - case 0x6: return m_scsi->seq_step_r(space, 0); - 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()); return space.unmap(); } -WRITE8_MEMBER(interpro_state::scsi_w) -{ - switch (offset >> 6) - { - case 0: m_scsi->tcount_lo_w(space, 0, data); return; - case 1: m_scsi->tcount_hi_w(space, 0, data); return; - case 2: m_scsi->fifo_w(space, 0, data); return; - case 3: m_scsi->command_w(space, 0, data); return; - case 4: m_scsi->bus_id_w(space, 0, data); return; - case 5: m_scsi->timeout_w(space, 0, data); return; - case 6: m_scsi->sync_period_w(space, 0, data); return; - case 7: m_scsi->sync_offset_w(space, 0, data); return; - case 8: m_scsi->conf_w(space, 0, data); return; - 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()); -} - -DRIVER_INIT_MEMBER(interpro_state, ip2800) -{ - // FIXME: not all memory sizes are reported properly using fdm "5 inqhw" and "optimum_memory" commands - - // 16 = reports 16M, banks empty? - // 32 = reports 16M, banks empty? - // 64 = reports 128M, 16x8 - // 128 = reports 128M, 16x8 - // 256 = reports 256M, 32x8 - - // grab the main memory space from the mmu - address_space &space = m_mmu->space(0); - - // map the configured ram - space.install_ram(0, m_ram->mask(), m_ram->pointer()); -} - -static SLOT_INTERFACE_START(interpro_scsi_devices) - SLOT_INTERFACE("harddisk", NSCSI_HARDDISK) - SLOT_INTERFACE("cdrom", NSCSI_CDROM) - SLOT_INTERFACE_INTERNAL(INTERPRO_SCSI_ADAPTER_TAG, NCR53C94) -SLOT_INTERFACE_END - -static MACHINE_CONFIG_START(interpro_scsi_adapter) - MCFG_DEVICE_CLOCK(XTAL_24MHz) - MCFG_NCR5390_IRQ_HANDLER(DEVWRITELINE(":" INTERPRO_IOGA_TAG, interpro_ioga_device, ir0_w)) - MCFG_NCR5390_DRQ_HANDLER(DEVWRITELINE(":" INTERPRO_IOGA_TAG, interpro_ioga_device, drq_scsi)) -MACHINE_CONFIG_END - -// these maps point the cpu virtual addresses to the mmu +// these maps connect the cpu virtual addresses to the mmu static ADDRESS_MAP_START(clipper_insn_map, AS_PROGRAM, 32, interpro_state) AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD32(INTERPRO_MMU_TAG, cammu_device, insn_r, 0xffffffff) ADDRESS_MAP_END @@ -341,12 +310,13 @@ static ADDRESS_MAP_START(clipper_data_map, AS_DATA, 32, interpro_state) ADDRESS_MAP_END static ADDRESS_MAP_START(interpro_common_map, 0, 32, interpro_state) - AM_RANGE(0x40000000, 0x4000004f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_fmcc_device, map) - AM_RANGE(0x4f007e00, 0x4f007eff) AM_DEVICE(INTERPRO_SGA_TAG, interpro_sga_device, map) + // FIXME: don't know what this range is for + AM_RANGE(0x08000000, 0x08000fff) AM_NOP - AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, n82077aa_device, map, 0xff) - AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_SRARB_TAG, interpro_srarb_device, map) + AM_RANGE(0x4f007e00, 0x4f007eff) AM_DEVICE(INTERPRO_SGA_TAG, interpro_sga_device, map) + AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, upd765_family_device, map, 0xff) + AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_ARBGA_TAG, interpro_arbga_device, map) AM_RANGE(0x7f000300, 0x7f000303) AM_READ16(sreg_error_r, 0xffff) AM_RANGE(0x7f000304, 0x7f000307) AM_READWRITE16(sreg_status_r, sreg_led_w, 0xffff) AM_RANGE(0x7f000308, 0x7f00030b) AM_READWRITE16(sreg_ctrl1_r, sreg_ctrl1_w, 0xffff) @@ -354,44 +324,91 @@ 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, 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(0x7f000400, 0x7f00040f) AM_DEVREADWRITE8(INTERPRO_SCC1_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) + AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, z80scc_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) + + AM_RANGE(0x7f000500, 0x7f000503) AM_DEVREADWRITE8_MOD(INTERPRO_RTC_TAG, mc146818_device, read, write, xor<0x1>, 0xff) + AM_RANGE(0x7f000600, 0x7f000603) AM_DEVWRITE8(INTERPRO_RTC_TAG, mc146818_device, write, 0xff) + AM_RANGE(0x7f000600, 0x7f00060f) AM_READ8(nodeid_r, 0xff) + + // the system board id prom + AM_RANGE(0x7f000700, 0x7f00077f) AM_ROM AM_REGION(INTERPRO_IDPROM_TAG, 0) + + // scsi registers have unusual address mapping + AM_RANGE(0x7f001000, 0x7f001003) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_lo_r, tcount_lo_w, 0xff00) + AM_RANGE(0x7f001100, 0x7f001103) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, tcounter_hi_r, tcount_hi_w, 0xff00) + AM_RANGE(0x7f001200, 0x7f001203) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_r, fifo_w, 0xff00) + AM_RANGE(0x7f001300, 0x7f001303) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, command_r, command_w, 0xff00) + AM_RANGE(0x7f001400, 0x7f001403) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, status_r, bus_id_w, 0xff00) + AM_RANGE(0x7f001500, 0x7f001503) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, istatus_r, timeout_w, 0xff00) + AM_RANGE(0x7f001600, 0x7f001603) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, seq_step_r, sync_period_w, 0xff00) + AM_RANGE(0x7f001700, 0x7f001703) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, fifo_flags_r, sync_offset_w, 0xff00) + AM_RANGE(0x7f001800, 0x7f001803) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf_r, conf_w, 0xff00) + AM_RANGE(0x7f001900, 0x7f001903) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, clock_w, 0xff00) + AM_RANGE(0x7f001a00, 0x7f001a03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, test_w, 0xff00) + AM_RANGE(0x7f001b00, 0x7f001b03) AM_DEVREADWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, conf2_r, conf2_w, 0xff00) AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map) +ADDRESS_MAP_END - // 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) +static ADDRESS_MAP_START(turquoise_base_map, 0, 32, turquoise_state) + AM_RANGE(0x40000000, 0x4000003f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_mcga_device, map) + AM_RANGE(0x7f000300, 0x7f000303) AM_WRITE8(sreg_error_w, 0xff) - // 2800 (CBUS?) slots are mapped as follows - AM_RANGE(0x87000000, 0x8700007f) AM_MIRROR(0x78000000) AM_READWRITE(unmapped_r, unmapped_w) + AM_IMPORT_FROM(interpro_common_map) ADDRESS_MAP_END -// these maps represent the real main, i/o and boot spaces of the system -static ADDRESS_MAP_START(interpro_main_map, 0, 32, interpro_state) +static ADDRESS_MAP_START(turquoise_main_map, 0, 32, turquoise_state) AM_RANGE(0x00000000, 0x00ffffff) AM_RAM AM_SHARE(RAM_TAG) + AM_RANGE(0x7f100000, 0x7f13ffff) AM_ROM AM_REGION(INTERPRO_EPROM_TAG, 0) - AM_RANGE(0x7f100000, 0x7f11ffff) AM_ROM AM_REGION(INTERPRO_EPROM_TAG, 0) - AM_RANGE(0x7f180000, 0x7f1bffff) AM_ROM AM_REGION(INTERPRO_FLASH_TAG, 0) + AM_IMPORT_FROM(turquoise_base_map) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(sapphire_base_map, 0, 32, sapphire_state) + AM_RANGE(0x40000000, 0x4000004f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_fmcc_device, map) + AM_RANGE(0x7f001c00, 0x7f001c03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, conf3_w, 0xff00) + AM_RANGE(0x7f001f00, 0x7f001f03) AM_DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c94_device, fifo_align_w, 0xff00) AM_IMPORT_FROM(interpro_common_map) ADDRESS_MAP_END -static ADDRESS_MAP_START(interpro_io_map, 1, 32, interpro_state) +static ADDRESS_MAP_START(sapphire_main_map, 0, 32, sapphire_state) + AM_RANGE(0x00000000, 0x00ffffff) AM_RAM AM_SHARE(RAM_TAG) + AM_RANGE(0x7f100000, 0x7f11ffff) AM_ROM AM_REGION(INTERPRO_EPROM_TAG, 0) + AM_RANGE(0x7f180000, 0x7f1bffff) AM_DEVREADWRITE16(INTERPRO_EEPROM_TAG, interpro_eeprom_device, eeprom_r, eeprom_w, 0xffffffff) + + AM_IMPORT_FROM(sapphire_base_map) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(turquoise_io_map, 1, 32, interpro_state) AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map) - AM_IMPORT_FROM(interpro_common_map) + AM_IMPORT_FROM(turquoise_base_map) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(sapphire_io_map, 1, 32, interpro_state) + AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map) + + AM_IMPORT_FROM(sapphire_base_map) ADDRESS_MAP_END static ADDRESS_MAP_START(interpro_boot_map, 2, 32, interpro_state) + // FIXME: the real system may have some initial boot instructions in this boot + // memory space which jump to the start of the boot eprom code, or there may + // be some special address decoding logic for boot. For now, we fake it in the + // CPU by hard-coding the start address to point at the eprom. AM_RANGE(0x00000000, 0x00001fff) AM_RAM ADDRESS_MAP_END +static ADDRESS_MAP_START(interpro_82586_map, 0, 16, turquoise_state) + AM_RANGE(0x00000000, 0x00ffffff) AM_DEVREADWRITE(INTERPRO_IOGA_TAG, turquoise_ioga_device, eth_r, eth_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(interpro_82596_map, 0, 32, sapphire_state) + AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE(INTERPRO_IOGA_TAG, sapphire_ioga_device, eth_r, eth_w) +ADDRESS_MAP_END + FLOPPY_FORMATS_MEMBER(interpro_state::floppy_formats) FLOPPY_PC_FORMAT FLOPPY_FORMATS_END @@ -401,80 +418,105 @@ static SLOT_INTERFACE_START(interpro_floppies) SLOT_INTERFACE("35hd", FLOPPY_35_HD) SLOT_INTERFACE_END -// input ports -static INPUT_PORTS_START(ip2800) -INPUT_PORTS_END - -static MACHINE_CONFIG_START(ip2800) - MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C400, XTAL_12_5MHz) - MCFG_CPU_PROGRAM_MAP(clipper_insn_map) - MCFG_CPU_DATA_MAP(clipper_data_map) - MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, inta_cb) - - MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4T, 0) - MCFG_DEVICE_ADDRESS_MAP(0, interpro_main_map) - MCFG_DEVICE_ADDRESS_MAP(1, interpro_io_map) - MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) - MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) - - MCFG_RAM_ADD(RAM_TAG) - MCFG_RAM_DEFAULT_SIZE("16M") - 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)) +static MACHINE_CONFIG_START(interpro_serial1) + MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT1_TAG, rs232_port_device, write_txd)) + MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT2_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" + MCFG_RS232_PORT_ADD(INTERPRO_SERIAL_PORT1_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)) - // eprom uses this serial port for console (show_config calls it "port 2") - MCFG_RS232_PORT_ADD(INTERPRO_SERIAL2_TAG, default_rs232_devices, "terminal") + MCFG_RS232_PORT_ADD(INTERPRO_SERIAL_PORT2_TAG, default_rs232_devices, nullptr) 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)) +MACHINE_CONFIG_END - // second serial controller and devices - 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)) +static MACHINE_CONFIG_START(interpro_serial2) + MCFG_Z80SCC_OUT_TXDA_CB(DEVWRITELINE(INTERPRO_KEYBOARD_PORT_TAG, interpro_keyboard_port_device, write_txd)) + MCFG_Z80SCC_OUT_TXDB_CB(DEVWRITELINE(INTERPRO_SERIAL_PORT0_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_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_INTERPRO_KEYBOARD_PORT_ADD(INTERPRO_KEYBOARD_PORT_TAG, interpro_keyboard_devices, "hle_en_us") + MCFG_INTERPRO_KEYBOARD_RXD_HANDLER(DEVWRITELINE(INTERPRO_SCC2_TAG, z80scc_device, rxa_w)) - MCFG_RS232_PORT_ADD(INTERPRO_SERIAL4_TAG, default_rs232_devices, nullptr) + MCFG_RS232_PORT_ADD(INTERPRO_SERIAL_PORT0_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)) +MACHINE_CONFIG_END + +static SLOT_INTERFACE_START(interpro_scsi_devices) + SLOT_INTERFACE("harddisk", NSCSI_HARDDISK) + SLOT_INTERFACE("cdrom", NSCSI_CDROM) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(turquoise_scsi_devices) + SLOT_INTERFACE_INTERNAL(INTERPRO_SCSI_ADAPTER_TAG, NCR53C90A) +SLOT_INTERFACE_END + +static SLOT_INTERFACE_START(sapphire_scsi_devices) + SLOT_INTERFACE_INTERNAL(INTERPRO_SCSI_ADAPTER_TAG, NCR53C94) +SLOT_INTERFACE_END + +static MACHINE_CONFIG_START(interpro_scsi_adapter) + MCFG_DEVICE_CLOCK(XTAL_24MHz) + MCFG_NCR5390_IRQ_HANDLER(DEVWRITELINE(":" INTERPRO_IOGA_TAG, interpro_ioga_device, ir0_w)) + MCFG_NCR5390_DRQ_HANDLER(DEVWRITELINE(":" INTERPRO_IOGA_TAG, interpro_ioga_device, drq_scsi)) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_START(ioga) + MCFG_INTERPRO_IOGA_NMI_CB(INPUTLINE(INTERPRO_CPU_TAG, INPUT_LINE_NMI)) + MCFG_INTERPRO_IOGA_IRQ_CB(INPUTLINE(INTERPRO_CPU_TAG, INPUT_LINE_IRQ0)) + MCFG_INTERPRO_IOGA_IVEC_CB(DEVWRITE8(INTERPRO_CPU_TAG, clipper_device, set_ivec)) + + // ioga dma and serial dma channels + // TODO: check serial dma channels - scc2chanA (keyboard) has no dma + //MCFG_INTERPRO_IOGA_DMA_CB(0, unknown) // plotter + MCFG_INTERPRO_IOGA_DMA_CB(1, DEVREAD8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, mdma_r), DEVWRITE8(INTERPRO_SCSI_DEVICE_TAG, ncr53c90a_device, mdma_w)) + MCFG_INTERPRO_IOGA_DMA_CB(2, DEVREAD8(INTERPRO_FDC_TAG, upd765_family_device, mdma_r), DEVWRITE8(INTERPRO_FDC_TAG, upd765_family_device, mdma_w)) + MCFG_INTERPRO_IOGA_SERIAL_DMA_CB(0, DEVREAD8(INTERPRO_SCC2_TAG, z80scc_device, db_r), DEVWRITE8(INTERPRO_SCC2_TAG, z80scc_device, db_w)) + MCFG_INTERPRO_IOGA_SERIAL_DMA_CB(1, DEVREAD8(INTERPRO_SCC1_TAG, z80scc_device, da_r), DEVWRITE8(INTERPRO_SCC1_TAG, z80scc_device, da_w)) + MCFG_INTERPRO_IOGA_SERIAL_DMA_CB(2, DEVREAD8(INTERPRO_SCC1_TAG, z80scc_device, db_r), DEVWRITE8(INTERPRO_SCC1_TAG, z80scc_device, db_w)) + + // ioga floppy terminal count, ethernet channel attention + MCFG_INTERPRO_IOGA_FDCTC_CB(DEVWRITELINE(INTERPRO_FDC_TAG, upd765_family_device, tc_line_w)) + MCFG_INTERPRO_IOGA_ETH_CA_CB(DEVWRITELINE(INTERPRO_ETH_TAG, i82586_base_device, ca)) + + MCFG_INTERPRO_IOGA_DMA_BUS(INTERPRO_CAMMU_TAG, 0) +MACHINE_CONFIG_END + +static INPUT_PORTS_START(interpro) +INPUT_PORTS_END + +static MACHINE_CONFIG_START(interpro) + MCFG_RAM_ADD(RAM_TAG) + MCFG_RAM_DEFAULT_SIZE("16M") + MCFG_RAM_EXTRA_OPTIONS("32M,64M,128M,256M") + + // memory control gate array + + // srx gate array + MCFG_DEVICE_ADD(INTERPRO_SGA_TAG, INTERPRO_SGA, 0) + MCFG_INTERPRO_SGA_BERR_CB(DEVWRITE32(INTERPRO_IOGA_TAG, interpro_ioga_device, bus_error)) + + // floppy + + // srx arbiter gate array + MCFG_DEVICE_ADD(INTERPRO_ARBGA_TAG, INTERPRO_ARBGA, 0) + + // serial // real-time clock/non-volatile memory MCFG_MC146818_ADD(INTERPRO_RTC_TAG, XTAL_32_768kHz) MCFG_MC146818_UTC(true) MCFG_MC146818_IRQ_HANDLER(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir9_w)) - // floppy - MCFG_N82077AA_ADD(INTERPRO_FDC_TAG, n82077aa_device::MODE_PS2) - MCFG_UPD765_INTRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir1_w)) - MCFG_UPD765_DRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_floppy)) - MCFG_FLOPPY_DRIVE_ADD("fdc:0", interpro_floppies, "525dd", interpro_state::floppy_formats) - MCFG_FLOPPY_DRIVE_ADD("fdc:1", interpro_floppies, "35hd", interpro_state::floppy_formats) - MCFG_FLOPPY_DRIVE_SOUND(false) - // scsi MCFG_NSCSI_BUS_ADD(INTERPRO_SCSI_TAG) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":0", interpro_scsi_devices, "harddisk", false) @@ -484,45 +526,207 @@ static MACHINE_CONFIG_START(ip2800) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":4", interpro_scsi_devices, nullptr, false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":5", interpro_scsi_devices, nullptr, false) MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":6", interpro_scsi_devices, nullptr, false) - MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", interpro_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true) + + // ethernet + + // i/o gate array + + // sr bus and slots + MCFG_DEVICE_ADD(INTERPRO_SRBUS_TAG, SR, 0) + MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":0", sr_cards, nullptr, false) + MCFG_SR_SLOT_ADD(INTERPRO_SRBUS_TAG, INTERPRO_SRBUS_TAG ":1", sr_cards, nullptr, false) + + // system layout + MCFG_DEFAULT_LAYOUT(layout_interpro) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_DERIVED(turquoise, interpro) + MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C300, XTAL_12_5MHz) + MCFG_CPU_PROGRAM_MAP(clipper_insn_map) + MCFG_CPU_DATA_MAP(clipper_data_map) + MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt) + + MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C3, 0) + MCFG_DEVICE_ADDRESS_MAP(0, turquoise_main_map) + MCFG_DEVICE_ADDRESS_MAP(1, turquoise_io_map) + MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) + MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) + + // boot fails memory test without this + MCFG_DEVICE_MODIFY(RAM_TAG) + MCFG_RAM_DEFAULT_VALUE(0x00) + + // memory control gate array + MCFG_DEVICE_ADD(INTERPRO_MCGA_TAG, INTERPRO_MCGA, 0) + + // floppy controller + MCFG_I82072_ADD(INTERPRO_FDC_TAG, false) + MCFG_UPD765_INTRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir1_w)) + MCFG_UPD765_DRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_floppy)) + + // connect a 3.5" drive at id 3 + MCFG_DEVICE_ADD("fdc:0", FLOPPY_CONNECTOR, 0) + MCFG_DEVICE_ADD("fdc:1", FLOPPY_CONNECTOR, 0) + MCFG_DEVICE_ADD("fdc:2", FLOPPY_CONNECTOR, 0) + MCFG_FLOPPY_DRIVE_ADD("fdc:3", interpro_floppies, "35hd", interpro_state::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(false) + + // serial controllers and ports + MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_FRAGMENT_ADD(interpro_serial1) + MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_FRAGMENT_ADD(interpro_serial2) + + // scsi controller + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", turquoise_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true) MCFG_DEVICE_CARD_MACHINE_CONFIG(INTERPRO_SCSI_ADAPTER_TAG, interpro_scsi_adapter) + // ethernet controller + MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82586, 0) + MCFG_I82586_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir12_w)) + MCFG_DEVICE_ADDRESS_MAP(0, interpro_82586_map) + // i/o gate array - MCFG_INTERPRO_IOGA_ADD(INTERPRO_IOGA_TAG) - MCFG_INTERPRO_IOGA_NMI_CB(INPUTLINE(INTERPRO_CPU_TAG, INPUT_LINE_NMI)) - 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, 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_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) + MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, TURQUOISE_IOGA, 0) + MCFG_FRAGMENT_ADD(ioga) +MACHINE_CONFIG_END + +static MACHINE_CONFIG_DERIVED(sapphire, interpro) + MCFG_CPU_ADD(INTERPRO_CPU_TAG, CLIPPER_C400, XTAL_12_5MHz) + MCFG_CPU_PROGRAM_MAP(clipper_insn_map) + MCFG_CPU_DATA_MAP(clipper_data_map) + MCFG_CPU_IRQ_ACKNOWLEDGE_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, acknowledge_interrupt) + + MCFG_DEVICE_ADD(INTERPRO_MMU_TAG, CAMMU_C4T, 0) + MCFG_DEVICE_ADDRESS_MAP(0, sapphire_main_map) + MCFG_DEVICE_ADDRESS_MAP(1, sapphire_io_map) + MCFG_DEVICE_ADDRESS_MAP(2, interpro_boot_map) + MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, get_ssw)) // memory control gate array MCFG_DEVICE_ADD(INTERPRO_MCGA_TAG, INTERPRO_FMCC, 0) - // srx gate array - MCFG_DEVICE_ADD(INTERPRO_SGA_TAG, INTERPRO_SGA, 0) - MCFG_INTERPRO_SGA_BERR_CB(DEVWRITE32(INTERPRO_IOGA_TAG, interpro_ioga_device, bus_error)) + // floppy controller + MCFG_N82077AA_ADD(INTERPRO_FDC_TAG, n82077aa_device::MODE_PS2) + MCFG_UPD765_INTRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir1_w)) + MCFG_UPD765_DRQ_CALLBACK(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_floppy)) - // srx arbiter gate array - MCFG_DEVICE_ADD(INTERPRO_SRARB_TAG, INTERPRO_SRARB, 0) + // connect a 3.5" drive at id 1 + MCFG_DEVICE_ADD("fdc:0", FLOPPY_CONNECTOR, 0) + MCFG_FLOPPY_DRIVE_ADD("fdc:1", interpro_floppies, "35hd", interpro_state::floppy_formats) + MCFG_FLOPPY_DRIVE_SOUND(false) - MCFG_DEFAULT_LAYOUT(layout_interpro) + // serial controllers and ports + MCFG_SCC85230_ADD(INTERPRO_SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_FRAGMENT_ADD(interpro_serial1) + MCFG_SCC85C30_ADD(INTERPRO_SCC2_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) + MCFG_FRAGMENT_ADD(interpro_serial2) + + // scsi controller + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":7", sapphire_scsi_devices, INTERPRO_SCSI_ADAPTER_TAG, true) + MCFG_DEVICE_CARD_MACHINE_CONFIG(INTERPRO_SCSI_ADAPTER_TAG, interpro_scsi_adapter) + + // ethernet controller + MCFG_DEVICE_ADD(INTERPRO_ETH_TAG, I82596_LE32, XTAL_20MHz) + MCFG_I82586_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir12_w)) + MCFG_DEVICE_ADDRESS_MAP(0, interpro_82596_map) + + // i/o gate array + MCFG_DEVICE_ADD(INTERPRO_IOGA_TAG, SAPPHIRE_IOGA, 0) + MCFG_FRAGMENT_ADD(ioga) + + // eeprom + MCFG_DEVICE_ADD(INTERPRO_EEPROM_TAG, INTERPRO_EEPROM, 0) + MCFG_EEPROM_SIZE(0x20000, 16) + MCFG_EEPROM_WRITE_TIME(attotime::from_usec(1000)) +MACHINE_CONFIG_END +MACHINE_CONFIG_DERIVED(ip2000, turquoise) + //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) + //MCFG_DEVICE_CLOCK(XTAL_40MHz) MACHINE_CONFIG_END +MACHINE_CONFIG_DERIVED(ip2400, sapphire) + //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) + //MCFG_DEVICE_CLOCK(XTAL_40MHz) +MACHINE_CONFIG_END + +MACHINE_CONFIG_DERIVED(ip2500, sapphire) + //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) + //MCFG_DEVICE_CLOCK(XTAL_50MHz) +MACHINE_CONFIG_END + +MACHINE_CONFIG_DERIVED(ip2700, sapphire) + //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) + //MCFG_DEVICE_CLOCK(XTAL_70MHz) +MACHINE_CONFIG_END + +MACHINE_CONFIG_DERIVED(ip2800, sapphire) + //MCFG_DEVICE_MODIFY(INTERPRO_CPU_TAG) + //MCFG_DEVICE_CLOCK(XTAL_80MHz) +MACHINE_CONFIG_END + +ROM_START(ip2000) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) + ROM_LOAD32_BYTE("mpcb962a.bin", 0x0, 0x20, CRC(712f5ba9) SHA1(93ccdcb68be4038bb35b02cee612927ad4451190)) + + ROM_REGION(0x0040000, INTERPRO_EPROM_TAG, 0) + ROM_SYSTEM_BIOS(0, "ip2000", "InterPro 2000 EPROM") + ROMX_LOAD("mprgm530e__26_apr_91k.u171", 0x00001, 0x20000, CRC(e4c470cb) SHA1(ff1917bfa963988d739a9dbf0b8f034fe49f2f8c), ROM_SKIP(1) | ROM_BIOS(1)) + ROMX_LOAD("mprgm540e__06_may_91k.u172", 0x00000, 0x20000, CRC(03225843) SHA1(03cfcd5b8ae0057240ef808a40108cb5d082eb63), ROM_SKIP(1) | ROM_BIOS(1)) +ROM_END + +ROM_START(ip2400) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) + ROM_LOAD32_BYTE("msmt047a.bin", 0x0, 0x20, CRC(3078d84d) SHA1(2876b8b8054bb7528680d259fea428db6f1712b4)) + + ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) + ROM_SYSTEM_BIOS(0, "ip2400", "InterPro 2400 EPROM") + ROMX_LOAD("mprgw510b__05_16_92.u35", 0x00000, 0x20000, CRC(3b2c4545) SHA1(4e4c98d1cd1035a04be8527223f44d0b687ec3ef), ROM_BIOS(1)) + + ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) + ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) +ROM_END + +ROM_START(ip2500) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) + ROM_LOAD32_BYTE("msmt100a.bin", 0x0, 0x20, CRC(46647cdf) SHA1(581a3424a9b7028e619a7f03fa86ebdee3cf2494)) + + ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) + ROM_SYSTEM_BIOS(0, "ip2500", "InterPro 2500 EPROM") + ROMX_LOAD("ip2500_eprom.bin", 0x00000, 0x20000, NO_DUMP, ROM_BIOS(1)) + + ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) + ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) +ROM_END + +ROM_START(ip2700) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) + ROM_LOAD32_BYTE("msmt128a.bin", 0x0, 0x20, CRC(6d8e68e8) SHA1(a649097df730c79b03bbf777b788f0721e072f03)) + + ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) + ROM_SYSTEM_BIOS(0, "ip2700", "InterPro 2700 EPROM") + ROMX_LOAD("mprgz530a__9405181.u35", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) + + ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) + ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) +ROM_END + ROM_START(ip2800) + ROM_REGION(0x80, INTERPRO_IDPROM_TAG, 0) + ROM_LOAD32_BYTE("msmt145a.bin", 0x0, 0x20, CRC(e1c265e3) SHA1(105d646552d56c7af2f403aac1aa97b047b6a50e)) + ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) - ROM_SYSTEM_BIOS(0, "ip2830", "IP2830") - ROMX_LOAD("ip2830_eprom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) + ROM_SYSTEM_BIOS(0, "ip2800", "InterPro 2800 EPROM") + ROMX_LOAD("ip2800_eprom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) - ROM_REGION(0x0040000, INTERPRO_FLASH_TAG, 0) - ROM_LOAD_OPTIONAL("ip2830_flash.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION16_LE(0x0040000, INTERPRO_EEPROM_TAG, 0) + ROM_LOAD_OPTIONAL("c4saph.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) ROM_END -/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1993, ip2800, 0, 0, ip2800, ip2800, interpro_state, ip2800, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +/* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ +COMP( 1989, ip2000, 0, 0, ip2000, interpro, turquoise_state, interpro, "Intergraph", "InterPro 2000", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1991?, ip2400, 0, 0, ip2400, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2400", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1993?, ip2500, 0, 0, ip2500, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2500", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1992, ip2700, 0, 0, ip2700, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2700", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1994, ip2800, 0, 0, ip2800, interpro, sapphire_state, interpro, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/includes/interpro.h b/src/mame/includes/interpro.h index d2a08a9d47d..d64884fe77d 100644 --- a/src/mame/includes/interpro.h +++ b/src/mame/includes/interpro.h @@ -9,16 +9,17 @@ #include "cpu/clipper/clipper.h" #include "machine/cammu.h" -#include "machine/ram.h" - #include "machine/interpro_ioga.h" #include "machine/interpro_mcga.h" #include "machine/interpro_sga.h" -#include "machine/interpro_srarb.h" +#include "machine/interpro_arbga.h" -#include "machine/z80scc.h" +#include "machine/ram.h" +#include "machine/eeprom.h" #include "machine/mc146818.h" +#include "machine/z80scc.h" #include "machine/upd765.h" +#include "machine/i82586.h" #include "machine/ncr5390.h" #include "machine/nscsi_bus.h" @@ -27,69 +28,95 @@ #include "bus/rs232/rs232.h" +#include "bus/interpro/sr/sr.h" +#include "bus/interpro/sr/sr_cards.h" +#include "bus/interpro/keyboard/keyboard.h" + #include "formats/pc_dsk.h" -#define INTERPRO_CPU_TAG "cpu" -#define INTERPRO_MMU_TAG "mmu" - -#define INTERPRO_RTC_TAG "rtc" -#define INTERPRO_SCC1_TAG "scc1" -#define INTERPRO_SERIAL1_TAG "serial1" -#define INTERPRO_SERIAL2_TAG "serial2" -#define INTERPRO_SCC2_TAG "scc2" -#define INTERPRO_SERIAL3_TAG "serial3" -#define INTERPRO_SERIAL4_TAG "serial4" -#define INTERPRO_EPROM_TAG "eprom" -#define INTERPRO_FLASH_TAG "flash" -#define INTERPRO_TERMINAL_TAG "terminal" -#define INTERPRO_FDC_TAG "fdc" -#define INTERPRO_SCSI_TAG "scsi" -#define INTERPRO_SCSI_ADAPTER_TAG "adapter" -#define INTERPRO_SCSI_DEVICE_TAG INTERPRO_SCSI_TAG ":7:" INTERPRO_SCSI_ADAPTER_TAG - -#define INTERPRO_IOGA_TAG "ioga" -#define INTERPRO_MCGA_TAG "mcga" -#define INTERPRO_SGA_TAG "sga" -#define INTERPRO_SRARB_TAG "srarb" +#define INTERPRO_CPU_TAG "cpu" +#define INTERPRO_MMU_TAG "mmu" +#define INTERPRO_MCGA_TAG "mcga" +#define INTERPRO_SGA_TAG "sga" +#define INTERPRO_FDC_TAG "fdc" +#define INTERPRO_ARBGA_TAG "arbga" +#define INTERPRO_SCC1_TAG "scc1" +#define INTERPRO_SCC2_TAG "scc2" +#define INTERPRO_SERIAL_PORT0_TAG "serial0" +#define INTERPRO_SERIAL_PORT1_TAG "serial1" +#define INTERPRO_SERIAL_PORT2_TAG "serial2" +#define INTERPRO_KEYBOARD_PORT_TAG "kbd" +#define INTERPRO_RTC_TAG "rtc" +#define INTERPRO_SCSI_TAG "scsi" +#define INTERPRO_SCSI_ADAPTER_TAG "host" +#define INTERPRO_SCSI_DEVICE_TAG INTERPRO_SCSI_TAG ":7:" INTERPRO_SCSI_ADAPTER_TAG +#define INTERPRO_ETH_TAG "eth" +#define INTERPRO_IOGA_TAG "ioga" + +#define INTERPRO_IDPROM_TAG "idprom" +#define INTERPRO_EPROM_TAG "eprom" +#define INTERPRO_EEPROM_TAG "eeprom" + +#define INTERPRO_SRBUS_TAG "sr" + +class interpro_eeprom_device : public eeprom_base_device +{ +public: + interpro_eeprom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ16_MEMBER(eeprom_r) { return read(offset); } + DECLARE_WRITE16_MEMBER(eeprom_w) { if (m_write_enable) write(offset, data); } + + DECLARE_WRITE_LINE_MEMBER(write_enable) { m_write_enable = state; } + +protected: + virtual void device_start() override { eeprom_base_device::device_start(); } + virtual void device_reset() override { eeprom_base_device::device_reset(); } + +private: + int m_write_enable; +}; + +DECLARE_DEVICE_TYPE(INTERPRO_EEPROM, interpro_eeprom_device) class interpro_state : public driver_device { public: interpro_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag), - m_maincpu(*this, INTERPRO_CPU_TAG), - m_mmu(*this, INTERPRO_MMU_TAG), - m_ram(*this, RAM_TAG), - m_scc1(*this, INTERPRO_SCC1_TAG), - m_scc2(*this, INTERPRO_SCC2_TAG), - m_rtc(*this, INTERPRO_RTC_TAG), - m_fdc(*this, INTERPRO_FDC_TAG), - m_scsibus(*this, INTERPRO_SCSI_TAG), - m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG), - m_ioga(*this, INTERPRO_IOGA_TAG), - m_mcga(*this, INTERPRO_MCGA_TAG), - m_sga(*this, INTERPRO_SGA_TAG), - m_srarb(*this, INTERPRO_SRARB_TAG) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, INTERPRO_CPU_TAG) + , m_mmu(*this, INTERPRO_MMU_TAG) + , m_ram(*this, RAM_TAG) + , m_mcga(*this, INTERPRO_MCGA_TAG) + , m_sga(*this, INTERPRO_SGA_TAG) + , m_fdc(*this, INTERPRO_FDC_TAG) + , m_arbga(*this, INTERPRO_ARBGA_TAG) + , m_scc1(*this, INTERPRO_SCC1_TAG) + , m_scc2(*this, INTERPRO_SCC2_TAG) + , m_rtc(*this, INTERPRO_RTC_TAG) + , m_scsibus(*this, INTERPRO_SCSI_TAG) + , m_scsi(*this, INTERPRO_SCSI_DEVICE_TAG) + , m_eth(*this, INTERPRO_ETH_TAG) + , m_ioga(*this, INTERPRO_IOGA_TAG) { } required_device m_maincpu; required_device m_mmu; - required_device m_ram; - // FIXME: not sure which one is the escc + required_device m_mcga; + required_device m_sga; + required_device m_fdc; + required_device m_arbga; required_device m_scc1; required_device m_scc2; required_device m_rtc; - required_device m_fdc; required_device m_scsibus; - required_device m_scsi; + required_device m_scsi; + required_device m_eth; required_device m_ioga; - required_device m_mcga; - required_device m_sga; - required_device m_srarb; - DECLARE_DRIVER_INIT(ip2800); + DECLARE_DRIVER_INIT(interpro); enum sreg_error_mask { @@ -104,6 +131,7 @@ public: ERROR_BUSHOG = 0x0080 }; DECLARE_READ16_MEMBER(sreg_error_r); + DECLARE_WRITE16_MEMBER(sreg_led_w); enum sreg_status_mask @@ -118,63 +146,76 @@ public: enum sreg_ctrl1_mask { - CTRL1_FLOPLOW = 0x0001, - CTRL1_FLOPRDY = 0x0002, - CTRL1_LEDENA = 0x0004, - CTRL1_LEDDP = 0x0008, - CTRL1_ETHLOOP = 0x0010, // remote modem loopback - CTRL1_ETHDTR = 0x0020, - CTRL1_ETHRMOD = 0x0040, // remote modem configured active low - CTRL1_CLIPRESET = 0x0040, - CTRL1_FIFOACTIVE = 0x0080 + CTRL1_FLOPLOW = 0x0001, // 0 = 5.25" floppy selected + CTRL1_FLOPRDY = 0x0002, // 1 = plotter fifo empty? + CTRL1_LEDENA = 0x0004, // 0 = led display disabled + CTRL1_LEDDP = 0x0008, // 0 = led right decimal point disabled + CTRL1_ETHLOOP = 0x0010, // 1 = mmbe enabled + CTRL1_ETHDTR = 0x0020, // 0 = modem dtr pin activated + CTRL1_ETHRMOD = 0x0040, // 0 = sytem configured for remote modems + CTRL1_FIFOACTIVE = 0x0080 // 0 = plotter fifos reset }; - DECLARE_READ16_MEMBER(sreg_ctrl1_r) { return m_sreg_ctrl1; } + DECLARE_READ16_MEMBER(sreg_ctrl1_r) const { return m_sreg_ctrl1; } DECLARE_WRITE16_MEMBER(sreg_ctrl1_w); enum sreg_ctrl2_mask { - CTRL2_PWRUP = 0x0001, - CTRL2_PWRENA = 0x0002, - CTRL2_HOLDOFF = 0x0004, - CTRL2_EXTNMIENA = 0x0008, - CTRL2_COLDSTART = 0x0010, - CTRL2_RESET = 0x0020, - CTRL2_BUSENA = 0x0040, - CTRL2_FRCPARITY = 0x0080, - CTRL2_FLASHEN = 0x0080, - - CTRL2_WMASK = 0x000f + CTRL2_PWRUP = 0x0003, // 3 = power supply voltage adjusted up by 5% + CTRL2_HOLDOFF = 0x0004, // 0 = power supply will shut down 0.33 seconds after switch is turned off + CTRL2_EXTNMIENA = 0x0008, // 0 = power nmi disabled + CTRL2_COLDSTART = 0x0010, // 1 = cold start flag + CTRL2_RESET = 0x0020, // 0 = soft reset + CTRL2_BUSENA = 0x0040, // 0 = clear bus grant error + CTRL2_FLASHEN = 0x0080, // 0 = flash eprom writes disabled + + CTRL2_MASK = 0x004d }; - DECLARE_READ16_MEMBER(sreg_ctrl2_r) { return m_sreg_ctrl2; } - DECLARE_WRITE16_MEMBER(sreg_ctrl2_w); - DECLARE_READ16_MEMBER(sreg_ctrl3_r) { return m_sreg_ctrl3; } + DECLARE_READ16_MEMBER(sreg_ctrl2_r) const { return m_sreg_ctrl2; } + virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w); + DECLARE_READ16_MEMBER(sreg_ctrl3_r) const { return m_sreg_ctrl3; } DECLARE_WRITE16_MEMBER(sreg_ctrl3_w) { m_sreg_ctrl3 = data; } - DECLARE_WRITE8_MEMBER(rtc_w); - DECLARE_READ8_MEMBER(rtc_r); - - DECLARE_READ8_MEMBER(idprom_r); - DECLARE_READ8_MEMBER(slot0_r); + DECLARE_READ8_MEMBER(nodeid_r); DECLARE_READ32_MEMBER(unmapped_r); DECLARE_WRITE32_MEMBER(unmapped_w); - DECLARE_READ8_MEMBER(scsi_r); - DECLARE_WRITE8_MEMBER(scsi_w); - DECLARE_FLOPPY_FORMATS(floppy_formats); protected: virtual void machine_start() override; virtual void machine_reset() override; -private: u16 m_sreg_error; u16 m_sreg_status; + u16 m_sreg_led; u16 m_sreg_ctrl1; u16 m_sreg_ctrl2; u16 m_sreg_ctrl3; }; +class turquoise_state : public interpro_state +{ +public: + turquoise_state(const machine_config &mconfig, device_type type, const char *tag) + : interpro_state(mconfig, type, tag) + {} + + DECLARE_WRITE8_MEMBER(sreg_error_w) { m_sreg_error = data; } +}; + +class sapphire_state : public interpro_state +{ +public: + sapphire_state(const machine_config &mconfig, device_type type, const char *tag) + : interpro_state(mconfig, type, tag) + , m_eeprom(*this, INTERPRO_EEPROM_TAG) + {} + + required_device m_eeprom; + + virtual DECLARE_WRITE16_MEMBER(sreg_ctrl2_w) override; +}; + #endif // MAME_INCLUDES_INTERPRO_H diff --git a/src/mame/layout/interpro.lay b/src/mame/layout/interpro.lay index 3e110a2ca76..655264c4636 100644 --- a/src/mame/layout/interpro.lay +++ b/src/mame/layout/interpro.lay @@ -4,22 +4,37 @@ license:CC0 copyright-holders:Patrick Mackinlay Intergraph InterPro 2x00 layout. -For now, this is only used to display the (internal) diagnostic 7-segment LED. In the future, it -should be expanded to handle the monitor(s), system unit power/disk lights, and keyboard. +TODO + - system unit power light and reset button + - keyboard and leds + - monitor bezels --> - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/machine/interpro_arbga.cpp b/src/mame/machine/interpro_arbga.cpp new file mode 100644 index 00000000000..f900b80af73 --- /dev/null +++ b/src/mame/machine/interpro_arbga.cpp @@ -0,0 +1,88 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +/* + * An implementation of the ARBGA (SRX Arbiter Gate Array) device found in + * Intergraph InterPro family systems. There is no public documentation on this + * device, so the implementation is being built to follow the logic of the + * boot ROM and its diagnostic tests. + * + * Please be aware that code in here is not only broken, it's likely wrong in + * many cases. + * + * TODO + * - too long to list + */ + +#include "emu.h" +#include "interpro_arbga.h" + +#define VERBOSE 0 +#include "logmacro.h" + +#if 0 +// this might be for an earlier revision of the device +DEVICE_ADDRESS_MAP_START(map, 32, interpro_arbga_device) + AM_RANGE(0x00, 0x03) AM_READWRITE(sdepid_r, sdepid_w) + AM_RANGE(0x04, 0x07) AM_READWRITE(snapid_r, snapid_w) + AM_RANGE(0x08, 0x0b) AM_READWRITE(prilo_r, prilo_w) + AM_RANGE(0x0c, 0x0f) AM_READWRITE(prihi_r, prihi_w) + AM_RANGE(0x10, 0x13) AM_READWRITE(errdomlo_r, errdomlo_w) + AM_RANGE(0x14, 0x17) AM_READWRITE(errdomhi_r, errdomhi_w) + AM_RANGE(0x18, 0x1b) AM_READWRITE(tmctrl_r, tmctrl_w) + + AM_RANGE(0x24, 0x27) AM_READWRITE(tmsrnem_r, tmsrnem_w) + AM_RANGE(0x28, 0x2b) AM_READWRITE(tmsrhog_r, tmsrhog_w) + AM_RANGE(0x2c, 0x2f) AM_READWRITE(tmscale_r, tmscale_w) +ADDRESS_MAP_END +#endif + +// derived from the FDM "dump_arb" command +DEVICE_ADDRESS_MAP_START(map, 32, interpro_arbga_device) + AM_RANGE(0x00, 0x03) AM_READWRITE(sdepid_r, sdepid_w) + AM_RANGE(0x04, 0x07) AM_READWRITE(arbsnap_r, arbsnap_w) + AM_RANGE(0x08, 0x0b) AM_READWRITE(fixprils_r, fixprils_w) + AM_RANGE(0x0c, 0x0f) AM_READWRITE(fixprims_r, fixprims_w) + AM_RANGE(0x10, 0x13) AM_READWRITE(sysdomls_r, sysdomls_w) + AM_RANGE(0x14, 0x17) AM_READWRITE(sysdomms_r, sysdomms_w) + AM_RANGE(0x18, 0x1b) AM_READWRITE(tctrl_r, tctrl_w) + AM_RANGE(0x1c, 0x1f) AM_READWRITE8(inem_r, inem_w, 0x0000ff00) // boot code writes 0x10 + AM_RANGE(0x20, 0x23) AM_READWRITE8(enem_r, enem_w, 0x0000ff00) // boot code writes 0x07 + AM_RANGE(0x24, 0x27) AM_READWRITE(hog_r, hog_w) + AM_RANGE(0x28, 0x2b) AM_READWRITE(lock_r, lock_w) + AM_RANGE(0x2c, 0x2f) AM_READWRITE(lockprs_r, lockprs_w) + AM_RANGE(0x30, 0x33) AM_READWRITE(hiblockls_r, hiblockls_w) + AM_RANGE(0x34, 0x37) AM_READWRITE(hiblockms_r, hiblockms_w) + + AM_RANGE(0x3c, 0x3f) AM_READWRITE(arbrev_r, arbrev_w) +ADDRESS_MAP_END + +DEFINE_DEVICE_TYPE(INTERPRO_ARBGA, interpro_arbga_device, "arbga", "SRX Arbiter Gate Array") + +interpro_arbga_device::interpro_arbga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, INTERPRO_ARBGA, tag, owner, clock) +{ +} + +void interpro_arbga_device::device_start() +{ + save_item(NAME(m_sdepid)); + save_item(NAME(m_arbsnap)); + save_item(NAME(m_fixprils)); + save_item(NAME(m_fixprims)); + save_item(NAME(m_sysdomls)); + save_item(NAME(m_sysdomms)); + save_item(NAME(m_tctrl)); + save_item(NAME(m_inem)); + save_item(NAME(m_enem)); + save_item(NAME(m_hog)); + save_item(NAME(m_lock)); + save_item(NAME(m_lockprs)); + save_item(NAME(m_hiblockls)); + save_item(NAME(m_hiblockms)); + save_item(NAME(m_arbrev)); +} + +void interpro_arbga_device::device_reset() +{ +} diff --git a/src/mame/machine/interpro_arbga.h b/src/mame/machine/interpro_arbga.h new file mode 100644 index 00000000000..749601c83fc --- /dev/null +++ b/src/mame/machine/interpro_arbga.h @@ -0,0 +1,90 @@ +// license:BSD-3-Clause +// copyright-holders:Patrick Mackinlay + +#ifndef MAME_MACHINE_INTERPRO_ARBGA_H +#define MAME_MACHINE_INTERPRO_ARBGA_H + +#pragma once + +class interpro_arbga_device : public device_t +{ +public: + interpro_arbga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_ADDRESS_MAP(map, 32); + + DECLARE_READ32_MEMBER(sdepid_r) const { return m_sdepid; } + DECLARE_WRITE32_MEMBER(sdepid_w) { m_sdepid = data; } + + enum arbsnap_mask + { + ARBSNAP_GRANT = 0x0000000f, + ARBSNAP_HOGLOCK = 0x000000f0 + }; + DECLARE_READ32_MEMBER(arbsnap_r) const { return m_arbsnap; } + DECLARE_WRITE32_MEMBER(arbsnap_w) { m_arbsnap = data; } + DECLARE_READ32_MEMBER(fixprils_r) const { return m_fixprils; } + DECLARE_WRITE32_MEMBER(fixprils_w) { m_fixprils = data; } + DECLARE_READ32_MEMBER(fixprims_r) const { return m_fixprims; } + DECLARE_WRITE32_MEMBER(fixprims_w) { m_fixprims = data; } + + DECLARE_READ32_MEMBER(sysdomls_r) const { return m_sysdomls; } + DECLARE_WRITE32_MEMBER(sysdomls_w) { m_sysdomls = data; } + DECLARE_READ32_MEMBER(sysdomms_r) const { return m_sysdomms; } + DECLARE_WRITE32_MEMBER(sysdomms_w) { m_sysdomms = data; } + + enum tctrl_mask + { + TCTRL_UNUSED = 0x00000007, + TCTRL_ENNEM = 0x00000008, + TCTRL_ENHOG = 0x00000010 + }; + DECLARE_READ32_MEMBER(tctrl_r) const { return m_tctrl; } + DECLARE_WRITE32_MEMBER(tctrl_w) { m_tctrl = data; } + + DECLARE_READ8_MEMBER(inem_r) const { return m_inem; } + DECLARE_WRITE8_MEMBER(inem_w) { m_inem = data; } + DECLARE_READ8_MEMBER(enem_r) const { return m_enem; } + DECLARE_WRITE8_MEMBER(enem_w) { m_enem = data; } + + DECLARE_READ32_MEMBER(hog_r) const { return m_hog; } + DECLARE_WRITE32_MEMBER(hog_w) { m_hog = data; } + DECLARE_READ32_MEMBER(lock_r) const { return m_lock; } + DECLARE_WRITE32_MEMBER(lock_w) { m_lock = data; } + DECLARE_READ32_MEMBER(lockprs_r) const { return m_lockprs; } + DECLARE_WRITE32_MEMBER(lockprs_w) { m_lockprs = data; } + + DECLARE_READ32_MEMBER(hiblockls_r) const { return m_hiblockls; } + DECLARE_WRITE32_MEMBER(hiblockls_w) { m_hiblockls = data; } + DECLARE_READ32_MEMBER(hiblockms_r) const { return m_hiblockms; } + DECLARE_WRITE32_MEMBER(hiblockms_w) { m_hiblockms = data; } + + DECLARE_READ32_MEMBER(arbrev_r) const { return m_arbrev; } + DECLARE_WRITE32_MEMBER(arbrev_w) { m_arbrev = data; } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + +private: + u32 m_sdepid; + u32 m_arbsnap; + u32 m_fixprils; + u32 m_fixprims; + u32 m_sysdomls; + u32 m_sysdomms; + u32 m_tctrl; + u8 m_inem; + u8 m_enem; + u32 m_hog; + u32 m_lock; + u32 m_lockprs; + u32 m_hiblockls; + u32 m_hiblockms; + u32 m_arbrev; +}; + +// device type definition +extern const device_type INTERPRO_ARBGA; + +#endif // MAME_MACHINE_INTERPRO_ARBGA_H diff --git a/src/mame/machine/interpro_ioga.cpp b/src/mame/machine/interpro_ioga.cpp index 8c5d03131f2..9a58de26336 100644 --- a/src/mame/machine/interpro_ioga.cpp +++ b/src/mame/machine/interpro_ioga.cpp @@ -2,601 +2,518 @@ // copyright-holders:Patrick Mackinlay /* - * An implementation of the IOGA device found on Intergraph InterPro family workstations. There is no - * public documentation on this device, so the implementation is being built to follow the logic of the - * system boot ROM and its diagnostic tests. + * An implementation of the IOGA (I/O Gate Array) devices found in Intergraph + * InterPro family systems. There is no public documentation for these devices, + * so the implementation is being built to follow the logic of the system boot + * ROM and diagnostic tests. * - * The device handles most of the I/O for the system, including timers, interrupts, DMA and target device - * interfacing. There remains a significant amount of work to be completed before the boot diagnostics will - * pass without errors, let alone successfully booting CLIX. - * - * Please be aware that code in here is not only broken, it's likely wrong in many cases. + * The device handles most of the I/O for the system, including timers, DMA, + * interrupts, and target device interfacing. There is a significant amount of + * work to be completed before the boot diagnostics will pass without errors, + * let alone successfully booting CLIX. * * TODO - * - too long to list + * - edge/level triggered interrupts + * - make mouse a slot device + * - improve dma and timers */ + #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 +// enables hacks which allow iogadiag tests to complete but break scsi dma #define IOGA_DMA_DIAG_HACK 0 -#define LOG_GENERAL (1 << 31) -#define LOG_HWINT_ENABLE 0 -#define LOG_DMA_ENABLE 0 -#define LOG_TIMER_ENABLE 0 -#define LOG_DMA_SERIAL_ENABLE 0 - -#define VERBOSE 0 - -#if VERBOSE -#define LOG_INTERRUPT(...) logerror(__VA_ARGS__) -#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, ...) do {} while(0) -#define LOG_DMA_SERIAL(channel, ...) -#define LOG_ETH(...) -#endif +#define LOG_GENERAL (1U << 0) +#define LOG_NMI (1U << 1) +#define LOG_INT (1U << 2) +#define LOG_DMA (1U << 3) + +#define LOG_FLOPPY (1U << 4) +#define LOG_SCSI (1U << 5) +#define LOG_NETWORK (1U << 6) +#define LOG_MOUSE (1U << 7) +#define LOG_SERIALDMA (1U << 8) + +#define LOG_TIMER0 (1U << 0x10) +#define LOG_TIMER1 (1U << 0x11) +#define LOG_TIMER2 (1U << 0x12) +#define LOG_TIMER3 (1U << 0x13) +#define LOG_TIMERRD (1U << 0x14) +#define LOG_TIMERS (LOG_TIMER0 | LOG_TIMER1 | LOG_TIMER2 | LOG_TIMER3) + +//#define VERBOSE (LOG_GENERAL | LOG_INT | LOG_NMI | LOG_DMA | LOG_SERIALDMA | LOG_NETWORK) +//#define VERBOSE_IRQ ((1 << IRQ_SCSI) | (1 << IRQ_FLOPPY) | (1 << IRQ_MOUSE) | (1 << IRQ_SERDMA) | (1 << IRQ_SERIAL) | (1 << IRQ_ETHERNET)) +//#define VERBOSE_DMA ((1 << DMA_PLOTTER) | (1 << DMA_SCSI) | (1 << DMA_FLOPPY)) + +#define VERBOSE 0 +#define VERBOSE_IRQ 0 +#define VERBOSE_DMA 0 +#include "logmacro.h" + +#define LOGIRQ(irq, ...) do { if (VERBOSE_IRQ & (1U << irq)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false) +#define LOGDMA(dma, ...) do { if (VERBOSE_DMA & (1U << dma)) (LOG_OUTPUT_FUNC)(__VA_ARGS__); } while (false) + +const interpro_ioga_device::interrupt_data_t interpro_ioga_device::m_interrupt_data[] = +{ + { INT_HARD_IN, IRQ_TIMER2, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 3", "timer 2" }, // either external or internal? + { INT_HARD_IN, IRQ_TIMER3, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 4", "timer 3" }, // either external or internal? + { INT_HARD_EX, IRQ_SCSI, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 0", "scsi" }, // IRQ_ENABLE_INTERNAL + { INT_HARD_EX, IRQ_FLOPPY, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 1", "floppy" }, // IRQ_ENABLE_INTERNAL + { INT_HARD_EX, IRQ_PLOTTER, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 2", "plotter" }, // IRQ_ENABLE_INTERNAL + + { INT_HARD_EX, IRQ_SRXCBUS0, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 3", "srx/cbus 0" }, + { INT_HARD_EX, IRQ_SRXCBUS1, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 4", "srx/cbus 1" }, + { INT_HARD_EX, IRQ_SRXCBUS2, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 5", "srx/cbus 2" }, + + { INT_HARD_EX, IRQ_VB, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 6", "vb" }, + { INT_HARD_EX, IRQ_9, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 7", "?" }, + { INT_HARD_EX, IRQ_CBUS3, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 8", "cbus 3" }, + { INT_HARD_EX, IRQ_RTC, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 9", "clock/calendar" }, + { INT_HARD_EX, IRQ_12, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 10", "sga?" }, + + { INT_HARD_IN, IRQ_MOUSE, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 0", "mouse" }, + { INT_HARD_IN, IRQ_TIMER0, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 1", "timer 0" }, + { INT_HARD_IN, IRQ_TIMER1, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 2", "timer 1" }, + { INT_HARD_IN, IRQ_SERDMA, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "internal int 5", "serial dma" }, // IRQ_ENABLE_EXTERNAL << 0 | IRQ_ENABLE_EXTERNAL << 1 | IRQ_ENABLE_EXTERNAL << 2 + + { INT_HARD_EX, IRQ_SERIAL, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 11", "serial" }, + { INT_HARD_EX, IRQ_ETHERNET, IRQ_PENDING | IRQ_ENABLE_EXTERNAL, "external int 12", "ethernet" }, // IRQ_ENABLE_INTERNAL + + { INT_SOFT_LO, IRQ_SOFT0, 0x0100, "soft int 0", "soft" }, + { INT_SOFT_LO, IRQ_SOFT1, 0x0200, "soft int 1", "soft" }, + { INT_SOFT_LO, IRQ_SOFT2, 0x0400, "soft int 2", "soft" }, + { INT_SOFT_LO, IRQ_SOFT3, 0x0800, "soft int 3", "soft" }, + { INT_SOFT_LO, IRQ_SOFT4, 0x1000, "soft int 4", "soft" }, + { INT_SOFT_LO, IRQ_SOFT5, 0x2000, "soft int 5", "soft" }, + { INT_SOFT_LO, IRQ_SOFT6, 0x4000, "soft int 6", "soft" }, + { INT_SOFT_LO, IRQ_SOFT7, 0x8000, "soft int 7", "soft" }, + + { INT_SOFT_HI, IRQ_SOFT8, IRQ_PENDING, "soft int 8", "soft" }, + { INT_SOFT_HI, IRQ_SOFT9, IRQ_PENDING, "soft int 9", "soft" }, + { INT_SOFT_HI, IRQ_SOFT10, IRQ_PENDING, "soft int 10", "soft" }, + { INT_SOFT_HI, IRQ_SOFT11, IRQ_PENDING, "soft int 11", "soft" }, + { INT_SOFT_HI, IRQ_SOFT12, IRQ_PENDING, "soft int 12", "soft" }, + { INT_SOFT_HI, IRQ_SOFT13, IRQ_PENDING, "soft int 13", "soft" }, + { INT_SOFT_HI, IRQ_SOFT14, IRQ_PENDING, "soft int 14", "soft" }, + { INT_SOFT_HI, IRQ_SOFT15, IRQ_PENDING, "soft int 15", "soft" }, +}; 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) AM_RANGE(0x30, 0x3f) AM_READWRITE(dma_floppy_r, dma_floppy_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(0x40, 0x43) AM_READWRITE(serial_dma0_addr_r, serial_dma0_addr_w) + AM_RANGE(0x44, 0x47) AM_READWRITE(serial_dma0_ctrl_r, serial_dma0_ctrl_w) + AM_RANGE(0x48, 0x4b) AM_READWRITE(serial_dma1_addr_r, serial_dma1_addr_w) + AM_RANGE(0x4c, 0x4f) AM_READWRITE(serial_dma1_ctrl_r, serial_dma1_ctrl_w) + AM_RANGE(0x50, 0x53) AM_READWRITE(serial_dma2_addr_r, serial_dma2_addr_w) + AM_RANGE(0x54, 0x57) AM_READWRITE(serial_dma2_ctrl_r, serial_dma2_ctrl_w) + + // 5a - sib control? AM_RANGE(0x5c, 0x7f) AM_READWRITE16(icr_r, icr_w, 0xffffffff) AM_RANGE(0x80, 0x83) AM_READWRITE16(icr18_r, icr18_w, 0x0000ffff) AM_RANGE(0x80, 0x83) AM_READWRITE8(softint_r, softint_w, 0x00ff0000) AM_RANGE(0x80, 0x83) AM_READWRITE8(nmictrl_r, nmictrl_w, 0xff000000) - - AM_RANGE(0x88, 0x8b) AM_READWRITE(timer_prescaler_r, timer_prescaler_w) + AM_RANGE(0x84, 0x87) AM_READWRITE(mouse_status_r, mouse_status_w) + AM_RANGE(0x88, 0x8b) AM_READWRITE(prescaler_r, prescaler_w) AM_RANGE(0x8c, 0x8f) AM_READWRITE(timer0_r, timer0_w) AM_RANGE(0x90, 0x93) AM_READWRITE(timer1_r, timer1_w) AM_RANGE(0x94, 0x97) AM_READ(error_address_r) AM_RANGE(0x98, 0x9b) AM_READ(error_businfo_r) AM_RANGE(0x9c, 0x9f) AM_READWRITE16(arbctl_r, arbctl_w, 0x0000ffff) - + AM_RANGE(0xa0, 0xa3) AM_READWRITE(timer2_count_r, timer2_count_w) + AM_RANGE(0xa4, 0xa7) AM_READWRITE(timer2_value_r, timer2_value_w) AM_RANGE(0xa8, 0xab) AM_READWRITE(timer3_r, timer3_w) - AM_RANGE(0xac, 0xaf) AM_READWRITE(bus_timeout_r, bus_timeout_w) // boot code writes 0x64 - + AM_RANGE(0xac, 0xaf) AM_READWRITE(bus_timeout_r, bus_timeout_w) // boot writes 0x64 AM_RANGE(0xb0, 0xbf) AM_READWRITE16(softint_vector_r, softint_vector_w, 0xffffffff) + + //c0, c4, c8 -ethernet address a,b,c? ADDRESS_MAP_END -DEFINE_DEVICE_TYPE(INTERPRO_IOGA, interpro_ioga_device, "ioga", "InterPro IOGA") - -interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, INTERPRO_IOGA, tag, owner, clock), - m_out_nmi_func(*this), - m_out_irq_func(*this), - m_memory_space(nullptr), - m_dma_channel{ - { 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) +DEVICE_ADDRESS_MAP_START(map, 32, turquoise_ioga_device) + AM_INHERIT_FROM(interpro_ioga_device::map) + + AM_RANGE(0x00, 0x03) AM_READWRITE(eth_base_r, eth_base_w) + AM_RANGE(0x04, 0x07) AM_READWRITE16(eth_control_r, eth_control_w, 0xffff) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 32, sapphire_ioga_device) + AM_INHERIT_FROM(interpro_ioga_device::map) + + AM_RANGE(0x00, 0x03) AM_READWRITE(eth_remap_r, eth_remap_w) + AM_RANGE(0x04, 0x07) AM_READWRITE(eth_mappg_r, eth_mappg_w) + AM_RANGE(0x08, 0x0b) AM_READWRITE(eth_control_r, eth_control_w) +ADDRESS_MAP_END + +static INPUT_PORTS_START(interpro_mouse) + PORT_START("mouse_buttons") + PORT_BIT(0x01, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Mouse Left Button") PORT_CODE(MOUSECODE_BUTTON1) PORT_CHANGED_MEMBER(DEVICE_SELF, interpro_ioga_device, mouse_button, nullptr) + PORT_BIT(0x02, IP_ACTIVE_HIGH, IPT_BUTTON2) PORT_NAME("Mouse Middle Button") PORT_CODE(MOUSECODE_BUTTON3) PORT_CHANGED_MEMBER(DEVICE_SELF, interpro_ioga_device, mouse_button, nullptr) + PORT_BIT(0x04, IP_ACTIVE_HIGH, IPT_BUTTON3) PORT_NAME("Mouse Right Button") PORT_CODE(MOUSECODE_BUTTON2) PORT_CHANGED_MEMBER(DEVICE_SELF, interpro_ioga_device, mouse_button, nullptr) + + PORT_START("mouse_x") + PORT_BIT(0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(50) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CHANGED_MEMBER(DEVICE_SELF, interpro_ioga_device, mouse_x, nullptr) + PORT_START("mouse_y") + PORT_BIT(0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(50) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CHANGED_MEMBER(DEVICE_SELF, interpro_ioga_device, mouse_y, nullptr) +INPUT_PORTS_END + +DEFINE_DEVICE_TYPE(TURQUOISE_IOGA, turquoise_ioga_device, "ioga_t", "I/O Gate Array (Turquoise)") +DEFINE_DEVICE_TYPE(SAPPHIRE_IOGA, sapphire_ioga_device, "ioga_s", "I/O Gate Array (Sapphire)") + +interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : device_t(mconfig, type, tag, owner, clock) + , m_memory_space(nullptr) + , m_out_nmi_func(*this) + , m_out_irq_func(*this) + , m_out_ivec_func(*this) + , m_fdc_tc_func(*this) + , m_eth_ca_func(*this) + , m_dma_channel{ + { 0,0,0,0,CLEAR_LINE,IDLE, {*this}, {*this}, ARBCTL_BGR_PLOT, DMA_PLOTTER, "plotter" }, + { 0,0,0,0,CLEAR_LINE,IDLE, {*this}, {*this}, ARBCTL_BGR_SCSI, DMA_SCSI, "scsi" }, + { 0,0,0,0,CLEAR_LINE,IDLE, {*this}, {*this}, ARBCTL_BGR_FDC, DMA_FLOPPY, "floppy" } } + , m_serial_dma_channel{ + { 0,0,CLEAR_LINE, {*this}, {*this}, ARBCTL_BGR_SER0, 0, "serial0" }, + { 0,0,CLEAR_LINE, {*this}, {*this}, ARBCTL_BGR_SER1, 1, "serial1" }, + { 0,0,CLEAR_LINE, {*this}, {*this}, ARBCTL_BGR_SER2, 2, "serial2" } } { } -#if LOG_HWINT_ENABLE -static const char *interrupt_source[IOGA_INTERRUPT_COUNT] = { - // internal - "timer 2", - "timer 3", - // external - "SCSI", - "floppy", - "plotter", - "SRX / CBUS 0", - "SRX / CBUS 1", - "SRX / CBUS 2", - "VB", - "", - "CBUS 3", - "clock / calendar", - "clock / SGA", - // internal - "mouse", - "timer 0", - "timer 1", - "serial DMA", - // external - "serial", - "Ethernet", -}; -#endif +turquoise_ioga_device::turquoise_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : interpro_ioga_device(mconfig, TURQUOISE_IOGA, tag, owner, clock) +{ +} -void interpro_ioga_device::device_start() +sapphire_ioga_device::sapphire_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : interpro_ioga_device(mconfig, SAPPHIRE_IOGA, tag, owner, clock) { - // resolve callbacks - m_out_nmi_func.resolve(); - m_out_irq_func.resolve(); +} +void interpro_ioga_device::device_start() +{ // TODO: parameterise the cammu name and space number // grab the main memory space from the mmu so we can do DMA to/from it device_memory_interface *mmu; siblingdevice("mmu")->interface(mmu); m_memory_space = &mmu->space(0); - for (auto &dma_channel : m_dma_channel) + // resolve callbacks + m_out_nmi_func.resolve(); + m_out_irq_func.resolve(); + m_out_ivec_func.resolve(); + m_fdc_tc_func.resolve(); + m_eth_ca_func.resolve(); + + for (dma_channel_t &dma_channel : m_dma_channel) { - dma_channel.device_r.resolve_safe(0xff); + dma_channel.device_r.resolve(); dma_channel.device_w.resolve(); } - for (auto &dma_channel : m_dma_serial_channel) + for (serial_dma_channel_t &dma_channel : m_serial_dma_channel) { - dma_channel.device_r.resolve_safe(0xff); + dma_channel.device_r.resolve(); 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); - m_timer[1] = timer_alloc(IOGA_TIMER_1); - m_timer[2] = timer_alloc(IOGA_TIMER_2); - m_timer[3] = timer_alloc(IOGA_TIMER_3); + // allocate timers + m_interrupt_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::interrupt_check), this)); + m_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::dma), this)); + m_serial_dma_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::serial_dma), this)); - for (auto & timer : m_timer) - timer->enable(false); + m_timer0 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::timer0), this)); + m_timer1 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::timer1), this)); + m_timer2 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::timer2), this)); + m_timer3 = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::timer3), this)); - // allocate ioga interrupt and dma timer - m_ioga_clock = timer_alloc(IOGA_CLOCK); - m_ioga_clock->adjust(attotime::never); + m_mouse_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::mouse_timer), this)); + m_eth_reset_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(interpro_ioga_device::eth_reset), this)); } void interpro_ioga_device::device_reset() { // initialise interrupt state - m_active_interrupt_type = IOGA_INTERRUPT_NONE; - m_hwint_forced = 0; - m_nmi_pending = false; + m_active_interrupt = nullptr; m_nmi_state = CLEAR_LINE; m_irq_state = CLEAR_LINE; - m_int_line = 0; + m_ivec = 0; + m_hwint_forced = 0; - // configure timer 0 at 60Hz - m_timer_reg[0] = 0; - //m_timer[0]->adjust(attotime::zero, IOGA_TIMER_0, attotime::from_hz(60)); + // initialise dma state + for (dma_channel_t &dma_channel : m_dma_channel) + { + dma_channel.drq_state = CLEAR_LINE; + dma_channel.state = IDLE; + } - // configure ioga interrupt and dma timer - m_ioga_clock->adjust(attotime::zero, IOGA_CLOCK, attotime::from_hz(clock())); -} + for (serial_dma_channel_t &dma_channel : m_serial_dma_channel) + dma_channel.drq_state = CLEAR_LINE; -/****************************************************************************** - Timers -******************************************************************************/ -READ32_MEMBER(interpro_ioga_device::timer1_r) -{ - uint32_t result = m_timer1_count & IOGA_TIMER1_VMASK; + // disable timers + m_interrupt_timer->enable(false); + m_dma_timer->enable(false); + m_serial_dma_timer->enable(false); - // set the start bit if the timer is currently enabled - if (m_timer[1]->enabled()) - result |= IOGA_TIMER1_START; - else if (m_timer[1]->param()) - result |= IOGA_TIMER1_EXPIRED; + m_timer0->enable(false); + m_timer1->enable(false); + m_timer2->enable(false); + m_timer3->enable(false); - return result; -} + m_mouse_timer->enable(false); + m_eth_reset_timer->enable(false); -READ32_MEMBER(interpro_ioga_device::timer3_r) -{ - uint32_t result = m_timer3_count & IOGA_TIMER3_VMASK; + // configure timer 0 for 60Hz + m_timer0_count = 0; + m_timer0_limit = 0; + m_timer0->adjust(attotime::zero, 0, attotime::from_hz(60)); - if (m_timer[3]->enabled()) - result |= IOGA_TIMER3_START; - else if (m_timer[3]->param()) - result |= IOGA_TIMER3_EXPIRED; + m_timer1_count = 0; + m_timer2_count = 0; + m_timer2_value = 0; + m_timer3_count = 0; - return result; + m_prescaler = 0; } -void interpro_ioga_device::write_timer(int timer, u32 value, device_timer_id id) +ioport_constructor interpro_ioga_device::device_input_ports() const { - switch (id) - { - case IOGA_TIMER_1: - // disable the timer - m_timer[timer]->enable(false); + return INPUT_PORTS_NAME(interpro_mouse); +} - // store the timer count value - m_timer1_count = value; +void interpro_ioga_device::set_nmi_line(int state) +{ + LOGMASKED(LOG_NMI, "nmi: %s (%s)\n", state ? "asserted" : "cleared", machine().describe_context()); - // start the timer if necessary - if (value & IOGA_TIMER1_START) + if (state == ASSERT_LINE) + { + // check if nmi is enabled + if (((m_nmictrl & NMI_IE) == NMI_IE) || ((m_nmictrl & (NMI_ALL | NMI_ENABLE1)) == (NMI_ALL | NMI_ENABLE1))) { - LOG_TIMER(1, "timer 1: started prescaler %d value %d\n", m_prescaler & 0x7fff, value & IOGA_TIMER1_VMASK); - - // FIXME: this division by 50 is sufficient to pass iogadiag timer 1 tests - m_timer[timer]->adjust(attotime::zero, false, attotime::from_usec((m_prescaler & 0x7fff) / 50)); - } - break; - - case IOGA_TIMER_3: - // stop the timer so it won't trigger while we're fiddling with it - m_timer[timer]->enable(false); - - // write the new value to the timer register - m_timer3_count = value & IOGA_TIMER3_VMASK; + LOGMASKED(LOG_NMI, "nmi: asserting output nmi line\n"); - // start the timer if necessary - if (value & IOGA_TIMER3_START) - { - LOG_TIMER(3, "timer 3: started value %d\n", value & IOGA_TIMER3_VMASK); + // if level triggered, disable input from pin + if ((m_nmictrl & NMI_EDGE) == 0) + m_nmictrl &= ~NMI_ENABLE2; - m_timer[timer]->adjust(attotime::zero, false, attotime::from_hz(XTAL_25MHz)); + nmi(ASSERT_LINE); } - break; - - default: - // save the value - m_timer_reg[timer] = value; - - // timer_set(attotime::from_usec(500), id); - - LOG_TIMER(0xf, "timer %d: set to 0x%x (%d)\n", timer, m_timer_reg[timer], m_timer_reg[timer]); - break; } + else + nmi(CLEAR_LINE); } -void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +void interpro_ioga_device::set_int_line(interrupt_type type, int number, int state) { - switch (id) + LOGIRQ(number, "irq: set_int_line(%d, %d, %d)\n", type, number, state); +#if 0 + // preliminary edge/level triggered interrupt handling + if (type == INT_HARD_IN || type == INT_HARD_EX) { - case IOGA_TIMER_0: - m_timer_reg[0]++; - m_hwicr[IOGA_TIMER0_IRQ] |= IOGA_INTERRUPT_PENDING; - break; - - case IOGA_TIMER_1: - // decrement timer count value - m_timer1_count--; - - // check if timer has expired - if (m_timer1_count == 0) + /* + * existing new type result + * clear clear edge nothing + * clear assert edge pending if not masked + * assert clear edge nothing + * assert assert edge nothing + + * clear clear level nothing + * clear assert level pending + * assert clear level !pending + * assert assert level nothing + */ + + u16 icr = get_icr(type, number); + u32 mask = 1 << number; + + if (icr & IRQ_EDGE) { - LOG_TIMER(1, "timer 1: stopped\n"); - - // disable timer and set the zero flag - timer.enable(false); - timer.set_param(true); - - // throw an interrupt - m_hwicr[IOGA_TIMER1_IRQ] |= IOGA_INTERRUPT_PENDING; + if ((m_line_state & mask) == 0 && state) + set_pending(type, number, true); } - break; - - case IOGA_TIMER_3: - // decrement timer count value - m_timer3_count--; - - // check for expiry - if (m_timer3_count == 0) + else { - LOG_TIMER(3, "timer 3: stopped\n"); - - // disable timer and set the zero flag - timer.enable(false); - timer.set_param(true); - - // throw an interrupt - m_hwicr[IOGA_TIMER3_IRQ] |= IOGA_INTERRUPT_PENDING; + if (((m_line_state & mask) == 0) ^ (state != ASSERT_LINE)) + set_pending(type, number, state == ASSERT_LINE); } - break; - case IOGA_CLOCK: - interrupt_clock(); - dma_clock(); - dma_serial_clock(); - break; - } -} - -/****************************************************************************** - Interrupts -******************************************************************************/ -static const u16 irq_enable_mask[IOGA_INTERRUPT_COUNT] = -{ - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL, // external interrupt 0: SCSI - IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL, // external interrupt 1: floppy - IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL, // external interrupt 2: plotter - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - - // internal interrupt 5: serial DMA - one interrupt enable per DMA channel - IOGA_INTERRUPT_ENABLE_EXTERNAL << 0 | IOGA_INTERRUPT_ENABLE_EXTERNAL << 1 | IOGA_INTERRUPT_ENABLE_EXTERNAL << 2, - IOGA_INTERRUPT_ENABLE_EXTERNAL, - IOGA_INTERRUPT_ENABLE_EXTERNAL | IOGA_INTERRUPT_ENABLE_INTERNAL // external interrupt 12: Ethernet -}; - -bool interpro_ioga_device::nmi(int state) -{ - if (m_nmi_state != state) - { - m_nmi_state = state; - m_out_nmi_func(m_nmi_state); - - return true; + m_line_state = (state == ASSERT_LINE) ? (m_line_state | mask) : (m_line_state & ~mask); } else - return false; +#endif + set_pending(type, number, state == ASSERT_LINE); + + m_interrupt_timer->adjust(attotime::zero); } -bool interpro_ioga_device::irq(int state) +/* + * Interrupts + */ +IRQ_CALLBACK_MEMBER(interpro_ioga_device::acknowledge_interrupt) { - if (m_irq_state != state) + switch (irqline) { - m_irq_state = state; - m_out_irq_func(m_irq_state); + case INPUT_LINE_IRQ0: + // clear pending flag + set_pending(m_active_interrupt->type, m_active_interrupt->number, false); - return true; - } - else - return false; -} + // clear irq/ivec + irq(CLEAR_LINE, 0); -void interpro_ioga_device::set_nmi_line(int state) -{ - LOG_INTERRUPT("nmi: set_nmi_line(%d)\n", state); - switch (state) - { - case ASSERT_LINE: - m_nmi_pending = true; + m_active_interrupt = nullptr; break; - case CLEAR_LINE: - m_nmi_pending = false; + case INPUT_LINE_NMI: + nmi(CLEAR_LINE); break; } + + m_interrupt_timer->adjust(attotime::zero); + + return 0; } -void interpro_ioga_device::set_irq_line(int irq, int state) +TIMER_CALLBACK_MEMBER(interpro_ioga_device::interrupt_check) { - LOG_HWINT(irq, "irq: set_irq_line(%d, %d)\n", irq, state); - switch (state) + // find highest priority unmasked pending interrupt + u16 ivec = m_ivec; + for (const interrupt_data_t &interrupt : m_interrupt_data) { - case ASSERT_LINE: - // set pending bit - m_int_line |= (1 << irq); - m_hwicr[irq] |= IOGA_INTERRUPT_PENDING; - break; + u16 icr = get_icr(interrupt.type, interrupt.number); - case CLEAR_LINE: - // clear pending bit - m_int_line &= ~(1 << irq); - m_hwicr[irq] &= ~IOGA_INTERRUPT_PENDING; - break; + // test for pending and not masked + if ((icr & interrupt.mask) == interrupt.mask) + { + // check priority + if (m_active_interrupt == nullptr || (icr & IRQ_VECTOR) < ivec) + { + m_active_interrupt = &interrupt; + ivec = icr & IRQ_VECTOR; + } + } } + + // assert irq and ivec + if (m_active_interrupt != nullptr) + irq(ASSERT_LINE, ivec); } -void interpro_ioga_device::set_irq_soft(int irq, int state) +void interpro_ioga_device::set_pending(interrupt_type type, int number, bool pending) { - LOG_INTERRUPT("irq: set_irq_soft(%d, %d)\n", irq, state); - switch (state) + switch (type) { - case ASSERT_LINE: - // set pending bit - if (irq < 8) - m_softint |= 1 << irq; + case INT_HARD_IN: + case INT_HARD_EX: + if (pending) + m_hwicr[number] |= IRQ_PENDING; else - m_swicr[irq - 8] |= IOGA_INTERRUPT_PENDING; + m_hwicr[number] &= ~IRQ_PENDING; break; - case CLEAR_LINE: - // clear pending bit - if (irq < 8) - m_softint &= ~(1 << irq); + case INT_SOFT_LO: + if (pending) + m_softint |= (1 << number); else - m_swicr[irq - 8] &= ~IOGA_INTERRUPT_PENDING; + m_softint &= ~(1 << number); + break; + + case INT_SOFT_HI: + if (pending) + m_swicr[number] |= IRQ_PENDING; + else + m_swicr[number] &= ~IRQ_PENDING; break; } } -IRQ_CALLBACK_MEMBER(interpro_ioga_device::inta_cb) +bool interpro_ioga_device::nmi(int state) { - int vector = 0; - - switch (irqline) + if (m_nmi_state != state) { - case INPUT_LINE_IRQ0: - // FIXME: clear pending bit - can't rely on device callbacks - switch (m_active_interrupt_type) - { - case IOGA_INTERRUPT_INTERNAL: - case IOGA_INTERRUPT_EXTERNAL: - m_hwicr[m_active_interrupt_number] &= ~IOGA_INTERRUPT_PENDING; - break; - - case IOGA_INTERRUPT_SOFT_LO: - m_softint &= ~(1 << m_active_interrupt_number); - break; - - case IOGA_INTERRUPT_SOFT_HI: - m_swicr[m_active_interrupt_number] &= ~IOGA_INTERRUPT_PENDING; - break; - } - - // fall through to return interrupt vector - case -1: - // return vector for current interrupt without clearing pending flag - switch (m_active_interrupt_type) - { - case IOGA_INTERRUPT_INTERNAL: - case IOGA_INTERRUPT_EXTERNAL: - vector = m_hwicr[m_active_interrupt_number] & 0xff; - break; - - case IOGA_INTERRUPT_SOFT_LO: - vector = 0x8f + m_active_interrupt_number * 0x10; - break; - - case IOGA_INTERRUPT_SOFT_HI: - vector = m_swicr[m_active_interrupt_number] & 0xff; - break; - } - - // interrupt is acknowledged - if (irqline == INPUT_LINE_IRQ0) - m_active_interrupt_type = IOGA_INTERRUPT_NONE; - break; + m_nmi_state = state; + m_out_nmi_func(state); - case INPUT_LINE_NMI: - m_active_interrupt_type = IOGA_INTERRUPT_NONE; - m_nmi_pending = false; - break; + return true; } - - return vector; + else + return false; } -void interpro_ioga_device::interrupt_clock() +bool interpro_ioga_device::irq(int state, u8 ivec) { - // called on every ioga clock cycle - // if there are no active interrupts, raise the next pending one - - // don't do anything if any interrupts are currently being serviced - if (m_active_interrupt_type != IOGA_INTERRUPT_NONE) - return; - - // if nmi line is asserted, clear it - if (nmi(CLEAR_LINE)) - return; - - // if irq line is asserted, clear it - if (irq(CLEAR_LINE)) - return; - - // check for pending nmi - if (m_nmi_pending) + if (ivec != m_ivec) { - // check if nmi is enabled - if (((m_nmictrl & NMI_IE) == NMI_IE) - || ((m_nmictrl & (NMI_ALL | NMI_ENABLE1)) == (NMI_ALL | NMI_ENABLE1))) - { - LOG_INTERRUPT("nmi: accepting nmi\n"); + LOGIRQ(m_active_interrupt->number, "setting ivec 0x%02x\n", ivec); - // if level triggered, disable input from pin - if ((m_nmictrl & NMI_EDGE) == 0) - m_nmictrl &= ~NMI_ENABLE2; - - m_active_interrupt_type = IOGA_INTERRUPT_NMI; - nmi(ASSERT_LINE); - return; - } + m_ivec = ivec; + machine().scheduler().synchronize(timer_expired_delegate(FUNC(interpro_ioga_device::set_ivec), this)); } - // scan all hardware interrupts - for (int i = 0; i < IOGA_INTERRUPT_COUNT; i++) + if (m_irq_state != state) { - // check if there is a pending interrupt - if (m_hwicr[i] & IOGA_INTERRUPT_PENDING) - { - // check if from an external device or internal to ioga - bool external = m_int_line & (1 << i); - - // check if masked - if (m_hwicr[i] & irq_enable_mask[i]) //(external ? IRQ_ENABLE_EXTERNAL : IRQ_ENABLE_INTERNAL)) - { - LOG_HWINT(i, "irq: accepting interrupt %d - %s (%s)\n", i, interrupt_source[i], external ? "external" : "internal"); + LOGIRQ(m_active_interrupt->number, "%s %s number %d source %s (%s)\n", + state ? "asserting" : "clearing", m_active_interrupt->name, m_active_interrupt->number, m_active_interrupt->source, machine().describe_context()); - m_active_interrupt_type = external ? IOGA_INTERRUPT_EXTERNAL : IOGA_INTERRUPT_INTERNAL; - m_active_interrupt_number = i; + m_irq_state = state; + m_out_irq_func(state); - irq(ASSERT_LINE); - return; - } - } + return true; } + else + return false; +} - // check for any pending soft interrupts (low type) - for (int i = 0; i < 8; i++) - { - if (m_softint & (1 << i)) - { - m_active_interrupt_type = IOGA_INTERRUPT_SOFT_LO; - m_active_interrupt_number = i; - - irq(ASSERT_LINE); - return; - } - } +TIMER_CALLBACK_MEMBER(interpro_ioga_device::set_ivec) +{ + m_out_ivec_func(m_ivec); +} - // check for any pending soft interrupts (high type) - for (int i = 0; i < 8; i++) +u16 interpro_ioga_device::get_icr(interrupt_type type, int number) const +{ + switch (type) { - if (m_swicr[i] & IOGA_INTERRUPT_PENDING) - { - m_active_interrupt_type = IOGA_INTERRUPT_SOFT_HI; - m_active_interrupt_number = i; + case INT_HARD_IN: + case INT_HARD_EX: + return m_hwicr[number]; - irq(ASSERT_LINE); - return; - } + case INT_SOFT_LO: + return (m_softint << 8) | (0x8f + number * 0x10); + + case INT_SOFT_HI: + return m_swicr[number]; } + + return 0; } WRITE16_MEMBER(interpro_ioga_device::icr_w) { /* - * It appears that writing the pending flag high and then low again is intended to - * "force" an interrupt to be generated. We record the initial write in m_hwint_forced, - * and when a subsequent write occurrs, turn the pending bit on to trigger the interrupt. - * - * FIXME: should we only flag a forced interrupt if pending is written high from low? - */ - - LOG_HWINT(offset, "irq: interrupt vector %d = 0x%04x (%s)\n", offset, data, machine().describe_context()); - - if (data & IOGA_INTERRUPT_PENDING) + * It appears that writing the pending flag high and then low again is + * intended to force an interrupt to be generated. We record the initial + * write in m_hwint_forced, and when a subsequent write occurrs, turn the + * pending bit on to trigger the interrupt. + * + * FIXME: should we only flag a forced interrupt if pending is written high + * from low? Maybe all of this can be eliminated by the edge/level trigger + * logic in the future. + */ + + LOGIRQ(offset, "irq: interrupt vector %d = 0x%04x (%s)\n", offset, data, machine().describe_context()); + + if (data & IRQ_PENDING) { // record interrupt pending forced m_hwint_forced |= 1 << offset; // store all bits except pending - m_hwicr[offset] = (m_hwicr[offset] & IOGA_INTERRUPT_PENDING) | (data & ~IOGA_INTERRUPT_PENDING); + m_hwicr[offset] = (m_hwicr[offset] & IRQ_PENDING) | (data & ~IRQ_PENDING); + + // FIXME: is it possible trigger a pending interrupt by unmasking it here? } - else if (m_hwint_forced & 1 << offset) + else if (m_hwint_forced & (1 << offset)) { // interrupt is being forced m_hwicr[offset] = data; @@ -604,8 +521,9 @@ WRITE16_MEMBER(interpro_ioga_device::icr_w) // clear forced flag m_hwint_forced &= ~(1 << offset); - // force an interrupt - m_hwicr[offset] |= IOGA_INTERRUPT_PENDING; + // FIXME: in/ex + LOGIRQ(offset, "irq: forcing interrupt vector %d\n", offset); + set_int_line(INT_HARD_IN, offset, ASSERT_LINE); } else // otherwise just store the value @@ -614,121 +532,129 @@ WRITE16_MEMBER(interpro_ioga_device::icr_w) WRITE8_MEMBER(interpro_ioga_device::softint_w) { - // save the existing value - u8 previous = m_softint; + // check for forced interrupts + const u8 forced = m_softint & ~data; // store the written value m_softint = data; - // force soft interrupt for any bit written from 1 to 0 - for (int i = 0; i < 8; i++) + // force interrupts if needed + if (forced != 0) { - u8 mask = 1 << i; - - // check for transition from 1 to 0 and force a soft interrupt - if (previous & mask && !(data & mask)) - set_irq_soft(i, ASSERT_LINE); + for (int i = 0; i < 8; i++) + if (forced & (1 << i)) + set_int_line(INT_SOFT_LO, i, ASSERT_LINE); } } WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) { - LOG_INTERRUPT("nmi: nmictrl = 0x%02x, nmi_pending = %d (%s)\n", data, m_nmi_pending, machine().describe_context()); - // 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; - } + const bool forced = (m_nmictrl & NMI_NEGPOL) && ((data & (NMI_NEGPOL | NMI_IE)) == NMI_IE); + LOGMASKED(LOG_NMI, "nmi: nmictrl = 0x%02x (%s)\n", data, machine().describe_context()); m_nmictrl = data; + + if (forced) + { + LOGMASKED(LOG_NMI, "nmi: forcing nmi\n"); + + set_nmi_line(ASSERT_LINE); + } } WRITE16_MEMBER(interpro_ioga_device::softint_vector_w) { - // save the existing value - u16 previous = m_swicr[offset]; + // check for forced interrupt + const bool forced = (m_swicr[offset] & IRQ_PENDING) && !(data & IRQ_PENDING); // store the written value m_swicr[offset] = data; - // check for transition from 1 to 0 and force a soft interrupt - if (previous & IOGA_INTERRUPT_PENDING && !(data & IOGA_INTERRUPT_PENDING)) - set_irq_soft(offset + 8, ASSERT_LINE); + // force interrupt if needed + if (forced) + set_int_line(INT_SOFT_HI, offset, ASSERT_LINE); } -/****************************************************************************** - DMA -******************************************************************************/ -void interpro_ioga_device::dma_clock() +/* + * DMA + */ +TIMER_CALLBACK_MEMBER(interpro_ioga_device::dma) { - for (auto &dma_channel : m_dma_channel) + for (dma_channel_t &dma_channel : m_dma_channel) { - switch (dma_channel.state) + // check if there's something to transfer + if (dma_channel.transfer_count == 0 || (dma_channel.control & DMA_CTRL_BGR) == 0) + continue; + + // check if the device is requesting a transfer + if (dma_channel.drq_state == CLEAR_LINE) + continue; + + // check if the bus is available + if ((m_arbctl & dma_channel.arb_mask) == 0) { - case IDLE: - break; + // set bus wait flag and abort + dma_channel.control |= DMA_CTRL_WAIT; - case COMMAND: - // start a command - if (dma_channel.control & DMA_CTRL_BGR) - dma_channel.state = WAIT; - else - dma_channel.state = FINAL; - break; + continue; + } + else + // clear bus wait flag + dma_channel.control &= ~DMA_CTRL_WAIT; - 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; + //LOGMASKED(LOG_DMA, "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); - 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); + // transfer from the memory to device or device to memory + while (dma_channel.transfer_count && dma_channel.drq_state) + { + // transfer from the memory to device or device to memory + // TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set - dma_channel.state = TRANSFER; - } + if (dma_channel.control & DMA_CTRL_WRITE) + dma_channel.device_w(m_memory_space->read_byte(dma_channel.real_address)); else - // (7.0265) set the bus grant wait flag - dma_channel.control |= DMA_CTRL_WAIT; - break; + 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--; + } - case TRANSFER: - if (dma_channel.transfer_count) + // check if the transfer is complete + if (dma_channel.transfer_count == 0) + { + LOGMASKED(LOG_DMA, "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 == DMA_FLOPPY) { - if (dma_channel.drq_state) - { - // transfer from the memory to device or device to memory - // TODO: implement virtual addressing when DMA_CTRL_VIRTUAL is set - - 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--; - } + LOGMASKED(LOG_DMA | LOG_FLOPPY, "dma: asserting fdc terminal count line\n"); + + m_fdc_tc_func(ASSERT_LINE); + m_fdc_tc_func(CLEAR_LINE); } - else - dma_channel.state = COMPLETE; + + // clear bus grant required + dma_channel.control &= ~DMA_CTRL_BGR; + + // set transfer count zero flag + dma_channel.control |= DMA_CTRL_TCZERO; + } + #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); + LOGDMA(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; + m_hwicr[dma_channel.channel + 1] |= IRQ_PENDING; // (7.0268) set bus error bit dma_channel.control |= DMA_CTRL_BERR; @@ -784,121 +710,28 @@ void interpro_ioga_device::dma_clock() dma_channel.state = COMPLETE; } #endif - break; - - case COMPLETE: - 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; - } } } void interpro_ioga_device::drq(int state, int channel) { - struct dma &dma_channel = m_dma_channel[channel]; + dma_channel_t &dma_channel = m_dma_channel[channel]; dma_channel.drq_state = state; - // only log every 256 bytes + // 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); -} - -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; + { + LOGMASKED(LOG_DMA, "dma: drq for channel %d %s transfer_count 0x%08x\n", channel, state ? "asserted" : "deasserted", dma_channel.transfer_count); + } - LOG_DMA_SERIAL(channel, "dma: drq for serial channel %d %s, counter 0x%04x\n", channel, state ? "asserted" : "deasserted", dma_channel.count); + if (state) + m_dma_timer->adjust(attotime::zero); } -u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mask, int channel) +u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mask, dma_channel channel) const { - struct dma &dma_channel = m_dma_channel[channel]; + const dma_channel_t &dma_channel = m_dma_channel[channel]; switch (offset) { @@ -920,29 +753,29 @@ u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mas } } -void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) +void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, dma_channel channel) { - struct dma &dma_channel = m_dma_channel[channel]; + dma_channel_t &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()); + LOGMASKED(LOG_DMA, "dma: channel %d real address = 0x%08x (%s)\n", channel, data, machine().describe_context()); 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()); + LOGMASKED(LOG_DMA, "dma: channel %d virtual address = 0x%08x (%s)\n", channel, data, machine().describe_context()); 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()); + LOGMASKED(LOG_DMA, "dma: channel %d transfer count = 0x%08x (%s)\n", channel, data, machine().describe_context()); dma_channel.transfer_count = data; break; case 3: - LOG_DMA(channel, "dma: channel %d control = 0x%08x (%s)\n", channel, data, machine().describe_context()); + LOGMASKED(LOG_DMA, "dma: channel %d control = 0x%08x (%s)\n", channel, data, machine().describe_context()); // (7.0272) if bus error flag is set, clear existing bus error (otherwise retain existing state) if (data & DMA_CTRL_BERR) @@ -955,78 +788,521 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, } } -void interpro_ioga_device::dma_serial_addr_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) +TIMER_CALLBACK_MEMBER(interpro_ioga_device::serial_dma) +{ + LOGMASKED(LOG_SERIALDMA, "dma: serial_dma()\n"); + + for (serial_dma_channel_t &dma_channel : m_serial_dma_channel) + { + // check if there's something to transfer + if ((dma_channel.control & SDMA_COUNT) == 0) + continue; + + // check if the device is requesting a transfer + if (dma_channel.drq_state == CLEAR_LINE) + continue; + + // check if the bus is available + if ((m_arbctl & dma_channel.arb_mask) == 0) + continue; + + // transfer from the memory to device or device to memory + while ((dma_channel.control & SDMA_COUNT) && dma_channel.drq_state) + { + // TODO: work out which control register bits indicate read from device + if (dma_channel.control & SDMA_SEND) + { + u8 data = m_memory_space->read_byte(dma_channel.address); + + LOGMASKED(LOG_SERIALDMA, "dma: transmitting byte 0x%02x to serial channel %d\n", data, dma_channel.channel); + + dma_channel.device_w(data); + } + else + { + u8 data = dma_channel.device_r(); + + LOGMASKED(LOG_SERIALDMA, "dma: receiving byte 0x%02x from serial channel %d\n", data, dma_channel.channel); + + m_memory_space->write_byte(dma_channel.address, data); + } + + // increment address and decrement count + dma_channel.address++; + dma_channel.control = (dma_channel.control & SDMA_CONTROL) | ((dma_channel.control & SDMA_COUNT) - 1); + } + + if ((dma_channel.control & SDMA_COUNT) == 0) + { + // transfer count zero + dma_channel.control |= SDMA_TCZERO; + + // raise an interrupt + set_int_line(INT_HARD_IN, IRQ_SERDMA, ASSERT_LINE); + } + } +} + +void interpro_ioga_device::serial_drq(int state, int channel) +{ + serial_dma_channel_t &dma_channel = m_serial_dma_channel[channel]; + + dma_channel.drq_state = state; + + LOGMASKED(LOG_SERIALDMA, "dma: drq for serial channel %d %s count 0x%04x\n", channel, state ? "asserted" : "deasserted", dma_channel.control & SDMA_COUNT); + + if (state && (dma_channel.control & SDMA_COUNT)) + m_serial_dma_timer->adjust(attotime::zero); +} + +void interpro_ioga_device::serial_dma_addr_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) { - LOG_DMA_SERIAL(channel, "dma: serial channel %d address = 0x%08x (%s)\n", channel, data, machine().describe_context()); + LOGMASKED(LOG_SERIALDMA, "dma: serial channel %d address 0x%08x mask 0x%08x (%s)\n", channel, data, mem_mask, machine().describe_context()); - m_dma_serial_channel[channel].address = data; + COMBINE_DATA(&m_serial_dma_channel[channel].address); } -void interpro_ioga_device::dma_serial_count_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel) +void interpro_ioga_device::serial_dma_ctrl_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) { - LOG_DMA_SERIAL(channel, "dma: serial channel %d count = 0x%04x (%s)\n", channel, data, machine().describe_context()); + serial_dma_channel_t &dma_channel = m_serial_dma_channel[channel]; + + LOGMASKED(LOG_SERIALDMA, "dma: serial channel %d control 0x%08x mask 0x%08x (%s)\n", channel, data, mem_mask, machine().describe_context()); + + COMBINE_DATA(&dma_channel.control); - m_dma_serial_channel[channel].count = data; + if (dma_channel.control & SDMA_COUNT) + m_serial_dma_timer->adjust(attotime::zero); } -void interpro_ioga_device::dma_serial_ctrl_w(address_space &space, offs_t offset, u16 data, u16 mem_mask, int channel) +/* + * Bus arbitration and control + */ +WRITE16_MEMBER(interpro_ioga_device::arbctl_w) { - LOG_DMA_SERIAL(channel, "dma: serial channel %d control = 0x%04x (%s)\n", channel, data, machine().describe_context()); + LOGMASKED(LOG_DMA | LOG_SERIALDMA, "dma: arbctl = 0x%04x (%s)\n", data, machine().describe_context()); + + m_arbctl = data; - m_dma_serial_channel[channel].control = data; + // trigger serial dma waiting for bus access + if (m_arbctl & (ARBCTL_BGR_SER0 | ARBCTL_BGR_SER1 | ARBCTL_BGR_SER2)) + m_serial_dma_timer->adjust(attotime::zero); } READ32_MEMBER(interpro_ioga_device::error_businfo_r) { - u32 result = m_error_businfo; + const u32 result = m_error_businfo; // clear register after reading - m_error_businfo = 0; + if (!machine().side_effect_disabled()) + m_error_businfo = 0; return result; } -WRITE16_MEMBER(interpro_ioga_device::arbctl_w) +/* + * Timers + */ +READ32_MEMBER(interpro_ioga_device::timer0_r) const { - LOG_DMA(31, "dma: arbctl = 0x%04x (%s)\n", data, machine().describe_context()); + LOGMASKED(LOG_TIMERRD, "timer0_r data 0x%08x mask 0x%08x (%s)\n", m_timer0_count, mem_mask, machine().describe_context()); - m_arbctl = data; + return m_timer0_count; } -WRITE32_MEMBER(interpro_ioga_device::eth_remap_w) +WRITE32_MEMBER(interpro_ioga_device::timer0_w) { - LOG_ETH("eth: remap = 0x%08x (%s)\n", data, machine().describe_context()); + //m_timer0_limit = data; + m_timer0_count = data; - m_eth_remap = data & ~0xf; + m_timer0->adjust(attotime::zero, 0, attotime::from_hz(60)); + + LOGMASKED(LOG_TIMER0, "timer0_w data 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); } -WRITE32_MEMBER(interpro_ioga_device::eth_map_page_w) +TIMER_CALLBACK_MEMBER(interpro_ioga_device::timer0) { - LOG_ETH("eth: remap page = 0x%08x (%s)\n", data, machine().describe_context()); + if (m_timer0_count == 0) + set_int_line(INT_HARD_IN, IRQ_TIMER0, ASSERT_LINE); + else + m_timer0_count++; - m_eth_map_page = data & ~0xf; + //m_hwicr[IRQ_VB] |= IRQ_PENDING; // this makes mouse diag countdown work (at half correct speed) + set_int_line(INT_HARD_EX, IRQ_12, ASSERT_LINE); // FIXME: 60Hz timer on InterPro 2000 } -WRITE32_MEMBER(interpro_ioga_device::eth_control_w) +READ32_MEMBER(interpro_ioga_device::timer1_r) const { - LOG_ETH("eth: control = 0x%08x (%s)\n", data, machine().describe_context()); + u32 result = m_timer1_count & TIMER1_COUNT; - /* (7.0202) eth ctrl register input test patterns and expected outputs are: + // set the start bit if the timer is currently enabled + if (m_timer1->enabled()) + result |= TIMER1_START; + else if (m_timer1->param()) + result |= TIMER1_EXPIRED; + + LOGMASKED(LOG_TIMERRD, "timer1_r data 0x%08x mask 0x%08x (%s)\n", result, mem_mask, machine().describe_context()); + + return result; +} + +WRITE32_MEMBER(interpro_ioga_device::timer1_w) +{ + // disable the timer + m_timer1->enable(false); + + // store the timer count value + m_timer1_count = data & TIMER1_COUNT; + + // start the timer if necessary + if (data & TIMER1_START) + { + LOGMASKED(LOG_TIMER1, "timer1_w data 0x%08x mask 0x%08x prescaler 0x%04x (%s)\n", data, mem_mask, m_prescaler & 0x7fff, machine().describe_context()); + + // theory: timer 1 is 10MHz (typical prescaler value of 1000 and timer value of 100 giving a delay of 100ms) + // FIXME: division by 50 is sufficient to pass iogadiag timer 1 tests + m_timer1->adjust(attotime::zero, false, attotime::from_usec((m_prescaler & 0x7fff) / 50)); + } +} + +TIMER_CALLBACK_MEMBER(interpro_ioga_device::timer1) +{ + // decrement timer count value + m_timer1_count--; - 7809 -> 4000 + // check if timer has expired + if (m_timer1_count == 0) + { + LOGMASKED(LOG_TIMER1, "timer1 expired\n"); + + // disable timer and set the zero flag + m_timer1->enable(false); + m_timer1->set_param(true); + + // throw an interrupt + set_int_line(INT_HARD_IN, IRQ_TIMER1, ASSERT_LINE); + } +} + +READ32_MEMBER(interpro_ioga_device::timer2_count_r) const +{ + LOGMASKED(LOG_TIMERRD, "timer2_count_r data 0x%08x mask 0x%08x (%s)\n", m_timer2_count, mem_mask, machine().describe_context()); + + return m_timer2_count; +} + +WRITE32_MEMBER(interpro_ioga_device::timer2_count_w) +{ + m_timer2_count = data; + + LOGMASKED(LOG_TIMER2, "timer2_count_w data 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); +} + +READ32_MEMBER(interpro_ioga_device::timer2_value_r) const +{ + LOGMASKED(LOG_TIMERRD, "timer2_value_r data 0x%08x mask 0x%08x (%s)\n", m_timer2_value, mem_mask, machine().describe_context()); + + return m_timer2_value; +} + +WRITE32_MEMBER(interpro_ioga_device::timer2_value_w) +{ + m_timer2_value = data; + m_timer2_count = data; // ? + + LOGMASKED(LOG_TIMER2, "timer2_value_w data 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); +} + +READ32_MEMBER(interpro_ioga_device::timer3_r) const +{ + u32 result = m_timer3_count & TIMER3_COUNT; + + if (m_timer3->enabled()) + result |= TIMER3_START; + else if (m_timer3->param()) + result |= TIMER3_EXPIRED; + + LOGMASKED(LOG_TIMERRD, "timer3_r data 0x%08x mask 0x%08x (%s)\n", result, mem_mask, machine().describe_context()); + + return result; +} + +WRITE32_MEMBER(interpro_ioga_device::timer3_w) +{ + // stop the timer so it won't trigger while we're fiddling with it + m_timer3->enable(false); - 3809 -> 0800 - 3409 -> 0400 - 3209 -> 0200 - 3109 -> 0100 + // write the new value to the timer register + m_timer3_count = data & TIMER3_COUNT; - 3089 -> 80 - 3049 -> 40 - 3019 -> 10 - 300b -> 02 - */ - if (data & ETH_RESET) - m_eth_control = ETH_RESET; + // start the timer if necessary + if (data & TIMER3_START) + { + LOGMASKED(LOG_TIMER3, "timer3_w data 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); + + // theory: timer 3 is 12.5MHz (typical value of 12500 giving a delay of 1ms) + m_timer3->adjust(attotime::zero, false, attotime::from_hz(XTAL_12_5MHz)); + } +} + +TIMER_CALLBACK_MEMBER(interpro_ioga_device::timer3) +{ + // decrement timer count value + m_timer3_count--; + + // check for expiry + if (m_timer3_count == 0) + { + LOGMASKED(LOG_TIMER3, "timer3 expired\n"); + + // disable timer and set the zero flag + m_timer3->enable(false); + m_timer3->set_param(true); + + // throw an interrupt + set_int_line(INT_HARD_IN, IRQ_TIMER3, ASSERT_LINE); + } +} + +READ32_MEMBER(interpro_ioga_device::prescaler_r) const +{ + // FIXME: prescaler only used with timer 1? + LOGMASKED(LOG_TIMERRD, "prescaler_r data 0x%08x mask 0x%08x (%s)\n", m_prescaler, mem_mask, machine().describe_context()); + + return m_prescaler; +} + +WRITE32_MEMBER(interpro_ioga_device::prescaler_w) +{ + LOGMASKED(LOG_TIMER1, "prescaler_w data 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); + + // this logic satisfies prescaler tests, but fails timer prescaler tests + if ((data & 0x7fff) < 0x100 && (data & 0x7fff) != 0) + m_prescaler = (data ^ 0xffff0000); else - m_eth_control = data & 0x0ff2; + m_prescaler = (data ^ 0xffff0000) - 0x10000; +} + +/* + * Mouse + */ +READ32_MEMBER(interpro_ioga_device::mouse_status_r) +{ + const u32 result = m_mouse_status; + + LOGMASKED(LOG_MOUSE, "mouse_status_r status 0x%08x mask 0x%08x (%s)\n", result, mem_mask, machine().describe_context()); + + // clear xpos and ypos fields + if (!machine().side_effect_disabled()) + m_mouse_status &= ~(MOUSE_XPOS | MOUSE_YPOS); + + return result; +} + +WRITE32_MEMBER(interpro_ioga_device::mouse_status_w) +{ + LOGMASKED(LOG_MOUSE, "mouse_status_w status 0x%08x mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); + + m_mouse_status |= (data & MOUSE_COUNTER); + + // FIXME: diagnostic test fails with value >= 0x1000 + if (data & MOUSE_COUNTER) + m_mouse_timer->adjust(attotime::from_nsec(data & MOUSE_COUNTER)); +} + +INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_button) +{ + if (newval) + m_mouse_status |= (field.mask() << 16); + else + m_mouse_status &= ~(field.mask() << 16); + + set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE); +} + +INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_x) +{ + // compute x delta + int delta = newval - oldval; + if (delta > 0x80) + delta -= 0x100; + else if (delta < -0x80) + delta += 0x100; + + // set new x delta + m_mouse_status &= ~MOUSE_XPOS; + m_mouse_status |= ((delta << 8) & MOUSE_XPOS); + + set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE); +} + +INPUT_CHANGED_MEMBER(interpro_ioga_device::mouse_y) +{ + // compute y delta + int delta = newval - oldval; + if (delta > 0x80) + delta -= 0x100; + else if (delta < -0x80) + delta += 0x100; + + // set new x delta + m_mouse_status &= ~MOUSE_YPOS; + m_mouse_status |= ((delta << 0) & MOUSE_YPOS); + + set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE); +} + +TIMER_CALLBACK_MEMBER(interpro_ioga_device::mouse_timer) +{ + set_int_line(INT_HARD_IN, IRQ_MOUSE, ASSERT_LINE); +} + +/* + * Ethernet + */ +WRITE32_MEMBER(turquoise_ioga_device::eth_base_w) +{ + LOGMASKED(LOG_NETWORK, "eth: base_w 0x%08x mem_mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); + + m_eth_base = ((m_eth_base & ~mem_mask) | (data & mem_mask)) & ETH_BASE_MASK; +} + +WRITE16_MEMBER(turquoise_ioga_device::eth_control_w) +{ + LOGMASKED(LOG_NETWORK, "eth: control_w 0x%04x mem_mask 0x%04x (%s)\n", data, mem_mask, machine().describe_context()); + + m_eth_control = data; + + // ethernet device reset (active low) + if ((data & ETH_RESET) == 0) + { + // reset the ethernet device + siblingdevice("eth")->reset(); + + // clear the reset flag (the 250ns delay is long enough to pass diagnostic tests) + m_eth_reset_timer->adjust(attotime::from_nsec(250)); + } + + // ethernet channel attention + if (data & ETH_CA) + { + m_eth_ca_func(ASSERT_LINE); + m_eth_ca_func(CLEAR_LINE); + } +} + +WRITE16_MEMBER(turquoise_ioga_device::eth_w) +{ + const u32 address = m_eth_base | ((offset << 1) & ~ETH_BASE_MASK); + + LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x mask 0x%04x data 0x%04x\n", address, mem_mask, data); + m_memory_space->write_word(address, data, mem_mask); +} + +READ16_MEMBER(turquoise_ioga_device::eth_r) const +{ + const u32 address = m_eth_base | ((offset << 1) & ~ETH_BASE_MASK); + + const u16 data = m_memory_space->read_word(address, mem_mask); + LOGMASKED(LOG_NETWORK, "eth_r 0x%08x mask 0x%04x data 0x%04x\n", address, mem_mask, data); + + return data; +} + +TIMER_CALLBACK_MEMBER(turquoise_ioga_device::eth_reset) +{ + LOGMASKED(LOG_NETWORK, "eth: reset flag cleared\n"); + + // clear ethernet reset flag + m_eth_control &= ~ETH_RESET; +} + +WRITE32_MEMBER(sapphire_ioga_device::eth_remap_w) +{ + LOGMASKED(LOG_NETWORK, "eth: remap = 0x%08x (%s)\n", data, machine().describe_context()); + + m_eth_remap = data & ~0xf; +} + +WRITE32_MEMBER(sapphire_ioga_device::eth_mappg_w) +{ + LOGMASKED(LOG_NETWORK, "eth: map page = 0x%08x (%s)\n", data, machine().describe_context()); + + m_eth_mappg = data & ~0xf; +} + +READ32_MEMBER(sapphire_ioga_device::eth_control_r) const +{ + LOGMASKED(LOG_NETWORK, "eth: control_r 0x%08x (%s)\n", m_eth_control, machine().describe_context()); + + return m_eth_control; +} + +WRITE32_MEMBER(sapphire_ioga_device::eth_control_w) +{ + LOGMASKED(LOG_NETWORK, "eth: control_w 0x%08x mem_mask 0x%08x (%s)\n", data, mem_mask, machine().describe_context()); + + m_eth_control = data & ETH_MASK; + + // ethernet device reset + if ((data & ETH_RESET) == 0) + { + // reset the ethernet device + siblingdevice("eth")->reset(); + + // clear the reset flag (the 250ns delay is long enough to pass diagnostic tests) + m_eth_reset_timer->adjust(attotime::from_nsec(250)); + } + + // ethernet channel attention + if (data & ETH_CA) + { + m_eth_ca_func(ASSERT_LINE); + m_eth_ca_func(CLEAR_LINE); + } +} + +WRITE32_MEMBER(sapphire_ioga_device::eth_w) +{ + // top two bits give channel (0=A, 4=B, 8=C, f=?) + const int channel = offset >> 28; + u32 address = (offset << 2) & 0x3fffffff; + + if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG)) + { + address &= ~(m_eth_mappg & ETH_MAPPG); + address |= (m_eth_remap & ETH_REMAP_ADDR); + + LOGMASKED(LOG_NETWORK, "eth_w address 0x%08x remapped 0x%08x\n", offset << 2, address); + } + + LOGMASKED(LOG_NETWORK, "eth_w channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data); + m_memory_space->write_dword(address, data, mem_mask); +} + +READ32_MEMBER(sapphire_ioga_device::eth_r) const +{ + // top two bits give channel (0=A, 4=B, 8=C, f=?) + const int channel = offset >> 28; + u32 address = (offset << 2) & 0x3fffffff; + + if ((m_eth_control & ETH_MAPEN) && (address & ETH_MAPPG) == (m_eth_mappg & ETH_MAPPG)) + { + address &= ~(m_eth_mappg & ETH_MAPPG); + address |= (m_eth_remap & ETH_REMAP_ADDR); + address &= 0x3fffffff; + + LOGMASKED(LOG_NETWORK, "eth_r address 0x%08x remapped 0x%08x\n", offset << 2, address); + } + + u32 data = m_memory_space->read_dword(address, mem_mask); + LOGMASKED(LOG_NETWORK, "eth_r channel %c address 0x%08x mask 0x%08x data 0x%08x\n", channel + 'A', address, mem_mask, data); + return data; +} + +TIMER_CALLBACK_MEMBER(sapphire_ioga_device::eth_reset) +{ + LOGMASKED(LOG_NETWORK, "eth: reset flag cleared\n"); + + // clear ethernet reset flag + m_eth_control &= ~ETH_RESET; } diff --git a/src/mame/machine/interpro_ioga.h b/src/mame/machine/interpro_ioga.h index 530790cb3e0..55573a1d6ee 100644 --- a/src/mame/machine/interpro_ioga.h +++ b/src/mame/machine/interpro_ioga.h @@ -6,22 +6,22 @@ #pragma once -#define MCFG_INTERPRO_IOGA_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, INTERPRO_IOGA, XTAL_12_5MHz) - #define MCFG_INTERPRO_IOGA_NMI_CB(_out_nmi) \ devcb = &interpro_ioga_device::static_set_out_nmi_callback(*device, DEVCB_##_out_nmi); #define MCFG_INTERPRO_IOGA_IRQ_CB(_out_irq) \ devcb = &interpro_ioga_device::static_set_out_irq_callback(*device, DEVCB_##_out_irq); +#define MCFG_INTERPRO_IOGA_IVEC_CB(_out_ivec) \ + devcb = &interpro_ioga_device::static_set_out_ivec_callback(*device, DEVCB_##_out_ivec); + #define MCFG_INTERPRO_IOGA_DMA_CB(_channel, _dma_r, _dma_w) \ 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_SERIAL_DMA_CB(_channel, _dma_r, _dma_w) \ + devcb = &interpro_ioga_device::static_set_serial_dma_r_callback(*device, _channel, DEVCB_##_dma_r); \ + devcb = &interpro_ioga_device::static_set_serial_dma_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); @@ -31,181 +31,129 @@ #define MCFG_INTERPRO_IOGA_DMA_BUS(_mmu, _space) -// timer 0 seem to be a 60Hz cycle -#define IOGA_TIMER0_IRQ 14 - -// best guess for timer 1 is 10MHz based on typical prescaler value of 1000 and timer value of 100 for a delay of 100ms -#define IOGA_TIMER1_IRQ 15 -#define IOGA_TIMER1_VMASK 0xffff -#define IOGA_TIMER1_START 0x10000 -#define IOGA_TIMER1_EXPIRED 0x20000 - -// best guess for timer 3 is 12.5MHz based on typical value of 12500 for a delay of 1ms -#define IOGA_TIMER3_CLOCK XTAL_12_5MHz -#define IOGA_TIMER3_IRQ 1 -#define IOGA_TIMER3_VMASK 0x3fffffff -#define IOGA_TIMER3_START 0x40000000 -#define IOGA_TIMER3_EXPIRED 0x80000000 - -#define IOGA_INTERRUPT_COUNT 19 -#define IOGA_INTERRUPT_PENDING 0x0100 -#define IOGA_INTERRUPT_ENABLE_EXTERNAL 0x0200 -#define IOGA_INTERRUPT_EDGE 0x0400 -#define IOGA_INTERRUPT_NEGPOL 0x0800 -#define IOGA_INTERRUPT_ENABLE_INTERNAL 0x1000 - -#define IOGA_INTERRUPT_NONE 0 -#define IOGA_INTERRUPT_NMI 1 -#define IOGA_INTERRUPT_INTERNAL 2 -#define IOGA_INTERRUPT_EXTERNAL 3 -#define IOGA_INTERRUPT_SOFT_LO 4 -#define IOGA_INTERRUPT_SOFT_HI 5 - -#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 { -public: - interpro_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - template static devcb_base &static_set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_func.set_callback(object); } - template static devcb_base &static_set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_func.set_callback(object); } - - template static devcb_base &static_set_dma_r_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_channel[channel].device_r.set_callback(object); } - template static devcb_base &static_set_dma_w_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_channel[channel].device_w.set_callback(object); } - - template static devcb_base &static_set_dma_serial_r_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_serial_channel[channel].device_r.set_callback(object); } - template static devcb_base &static_set_dma_serial_w_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_serial_channel[channel].device_w.set_callback(object); } - - template static devcb_base &static_set_fdc_tc_callback(device_t &device, _Object object) { return downcast(device).m_fdc_tc_func.set_callback(object); } - template static devcb_base &static_set_eth_ca_callback(device_t &device, _Object object) { return downcast(device).m_eth_ca_func.set_callback(object); } - - virtual DECLARE_ADDRESS_MAP(map, 32); - - // external interrupt lines - DECLARE_WRITE_LINE_MEMBER(ir0_w) { set_irq_line(2, state); } - DECLARE_WRITE_LINE_MEMBER(ir1_w) { set_irq_line(3, state); } - DECLARE_WRITE_LINE_MEMBER(ir2_w) { set_irq_line(4, state); } - DECLARE_WRITE_LINE_MEMBER(ir3_w) { set_irq_line(5, state); } - DECLARE_WRITE_LINE_MEMBER(ir4_w) { set_irq_line(6, state); } - DECLARE_WRITE_LINE_MEMBER(ir5_w) { set_irq_line(7, state); } - DECLARE_WRITE_LINE_MEMBER(ir6_w) { set_irq_line(8, state); } - DECLARE_WRITE_LINE_MEMBER(ir7_w) { set_irq_line(9, state); } - DECLARE_WRITE_LINE_MEMBER(ir8_w) { set_irq_line(10, state); } - // FIXME: this is a workaround for the mc146818 code which inverts the normal irq state convention - DECLARE_WRITE_LINE_MEMBER(ir9_w) { set_irq_line(11, !state); } - DECLARE_WRITE_LINE_MEMBER(ir10_w) { set_irq_line(12, state); } - DECLARE_WRITE_LINE_MEMBER(ir11_w) { set_irq_line(17, state); } - DECLARE_WRITE_LINE_MEMBER(ir12_w) { set_irq_line(18, state); } - - IRQ_CALLBACK_MEMBER(inta_cb); - - DECLARE_WRITE_LINE_MEMBER(drq_plotter) { drq(state, IOGA_DMA_PLOTTER); } - 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); } +protected: + interpro_ioga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); - enum eth_remap_mask + enum interrupt_type { - ETH_REMAP_CHA_FLUSH = 0x00000008, - ETH_REMAP_CHA_BUF = 0x00000010, - ETH_REMAP_CHA_QUAD = 0x00000020, - ETH_REMAP_CHA_WTAG = 0x000001c0, - ETH_REMAP_CHA_RTAG = 0x00000e00, - ETH_REMAP_ADDR = 0xfffff000 + INT_HARD_IN, // hardware internal + INT_HARD_EX, // hardware external + INT_SOFT_LO, // soft low type + INT_SOFT_HI // soft high type }; - DECLARE_READ32_MEMBER(eth_remap_r) { return m_eth_remap; } - DECLARE_WRITE32_MEMBER(eth_remap_w); - enum eth_remap_page_mask + enum interrupt_number { - ETH_REMAP_CHB_FLUSH = 0x00000008, - ETH_REMAP_CHB_BUF = 0x00000010, - ETH_REMAP_CHB_QUAD = 0x00000020, - ETH_REMAP_CHB_WTAG = 0x000001c0, - ETH_REMAP_CHB_RTAG = 0x00000e00, - ETH_MAP_PAGE = 0xfffff000 + IRQ_TIMER2 = 0, // internal int 3 (5c) + IRQ_TIMER3 = 1, // internal int 4 (5e) + IRQ_SCSI = 2, // external int 0 (60) + IRQ_FLOPPY = 3, // external int 1 (62) + IRQ_PLOTTER = 4, // external int 2 (64) + IRQ_SRXCBUS0 = 5, // external int 3 (66) + IRQ_SRXCBUS1 = 6, // external int 4 (68) + IRQ_SRXCBUS2 = 7, // external int 5 (6a) + IRQ_VB = 8, // external int 6 (6c) + IRQ_9 = 9, // external int 7 (6e) + IRQ_CBUS3 = 10, // external int 8 (70) + IRQ_RTC = 11, // external int 9 (72) + IRQ_12 = 12, // external int 10 (74) SGA? + IRQ_MOUSE = 13, // internal int 0 (76) + IRQ_TIMER0 = 14, // internal int 1 (78) + IRQ_TIMER1 = 15, // internal int 2 (7a) + IRQ_SERDMA = 16, // internal int 5 (7c) + IRQ_SERIAL = 17, // external int 11 (7e) + IRQ_ETHERNET = 18, // external int 12 (80) + + // soft interrupts (low type) + IRQ_SOFT0 = 0, + IRQ_SOFT1 = 1, + IRQ_SOFT2 = 2, + IRQ_SOFT3 = 3, + IRQ_SOFT4 = 4, + IRQ_SOFT5 = 5, + IRQ_SOFT6 = 6, + IRQ_SOFT7 = 7, + + // soft interrupts (high type) + IRQ_SOFT8 = 0, + IRQ_SOFT9 = 1, + IRQ_SOFT10 = 2, + IRQ_SOFT11 = 3, + IRQ_SOFT12 = 4, + IRQ_SOFT13 = 5, + IRQ_SOFT14 = 6, + IRQ_SOFT15 = 7 }; - DECLARE_READ32_MEMBER(eth_map_page_r) { return m_eth_map_page; } - DECLARE_WRITE32_MEMBER(eth_map_page_w); - enum eth_control_mask + struct interrupt_data_t { - ETH_CA = 0x00000001, // channel attention - ETH_MAPEN = 0x00000002, - ETH_REMAP_CHC_BUF = 0x00000010, - ETH_REMAP_CHC_QUAD = 0x00000020, - ETH_REMAP_CHC_WTAG = 0x000001c0, - ETH_REMAP_CHC_RTAG = 0x00000e00, - ETH_BERR = 0x00001000, - ETH_MMBE = 0x00002000, - ETH_RESET = 0x00004000 - }; - DECLARE_READ32_MEMBER(eth_control_r) { return m_eth_control; } - DECLARE_WRITE32_MEMBER(eth_control_w); + const interrupt_type type; + const interrupt_number number; + const u16 mask; - DECLARE_READ32_MEMBER(timer_prescaler_r) { return m_prescaler; } - DECLARE_READ32_MEMBER(timer0_r) { return m_timer_reg[0]; } - DECLARE_READ32_MEMBER(timer1_r); + const char *const name; + const char *const source; + }; - enum arbctl_mask + enum dma_channel { - ARBCTL_BGR_ETHC = 0x0001, - ARBCTL_BGR_SCSI = 0x0002, - ARBCTL_BGR_PLOT = 0x0004, - ARBCTL_BGR_FDC = 0x0008, - ARBCTL_BGR_SER0 = 0x0010, - ARBCTL_BGR_SER1 = 0x0020, - ARBCTL_BGR_SER2 = 0x0040, - ARBCTL_BGR_ETHB = 0x0080, - ARBCTL_BGR_ETHA = 0x0100 + DMA_PLOTTER = 0, + DMA_SCSI = 1, + DMA_FLOPPY = 2 }; - DECLARE_READ16_MEMBER(arbctl_r) { return m_arbctl; } - DECLARE_WRITE16_MEMBER(arbctl_w); - DECLARE_READ32_MEMBER(timer2_r) { return m_timer_reg[2]; } - DECLARE_READ32_MEMBER(timer3_r); - - DECLARE_WRITE32_MEMBER(timer_prescaler_w) { - // this logic satisfies prescaler tests, but fails timer prescaler tests - if ((data & 0x7fff) < 0x100 && (data & 0x7fff) != 0) - m_prescaler = (data ^ 0xffff0000); - else - m_prescaler = (data ^ 0xffff0000) - 0x10000; - - //logerror("prescaler: input 0x%08x output 0x%08x\n", data, m_prescaler); - } - DECLARE_WRITE32_MEMBER(timer0_w) { write_timer(0, data, IOGA_TIMER_0); } - DECLARE_WRITE32_MEMBER(timer1_w) { write_timer(1, data, IOGA_TIMER_1); } - DECLARE_WRITE32_MEMBER(timer2_w) { write_timer(2, data, IOGA_TIMER_2); } - DECLARE_WRITE32_MEMBER(timer3_w) { write_timer(3, data, IOGA_TIMER_3); } - - enum hwicr_mask + +public: + template static devcb_base &static_set_out_nmi_callback(device_t &device, _Object object) { return downcast(device).m_out_nmi_func.set_callback(object); } + template static devcb_base &static_set_out_irq_callback(device_t &device, _Object object) { return downcast(device).m_out_irq_func.set_callback(object); } + template static devcb_base &static_set_out_ivec_callback(device_t &device, _Object object) { return downcast(device).m_out_ivec_func.set_callback(object); } + template static devcb_base &static_set_dma_r_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_channel[channel].device_r.set_callback(object); } + template static devcb_base &static_set_dma_w_callback(device_t &device, int channel, _Object object) { return downcast(device).m_dma_channel[channel].device_w.set_callback(object); } + template static devcb_base &static_set_serial_dma_r_callback(device_t &device, int channel, _Object object) { return downcast(device).m_serial_dma_channel[channel].device_r.set_callback(object); } + template static devcb_base &static_set_serial_dma_w_callback(device_t &device, int channel, _Object object) { return downcast(device).m_serial_dma_channel[channel].device_w.set_callback(object); } + template static devcb_base &static_set_fdc_tc_callback(device_t &device, _Object object) { return downcast(device).m_fdc_tc_func.set_callback(object); } + template static devcb_base &static_set_eth_ca_callback(device_t &device, _Object object) { return downcast(device).m_eth_ca_func.set_callback(object); } + + virtual DECLARE_ADDRESS_MAP(map, 32) = 0; + + // interrupt request lines + DECLARE_WRITE_LINE_MEMBER(ir0_w) { set_int_line(INT_HARD_EX, IRQ_SCSI, state); } + DECLARE_WRITE_LINE_MEMBER(ir1_w) { set_int_line(INT_HARD_EX, IRQ_FLOPPY, state); } + DECLARE_WRITE_LINE_MEMBER(ir2_w) { set_int_line(INT_HARD_EX, IRQ_PLOTTER, state); } + DECLARE_WRITE_LINE_MEMBER(ir3_w) { set_int_line(INT_HARD_EX, IRQ_SRXCBUS0, state); } + DECLARE_WRITE_LINE_MEMBER(ir4_w) { set_int_line(INT_HARD_EX, IRQ_SRXCBUS1, state); } + DECLARE_WRITE_LINE_MEMBER(ir5_w) { set_int_line(INT_HARD_EX, IRQ_SRXCBUS2, state); } + DECLARE_WRITE_LINE_MEMBER(ir6_w) { set_int_line(INT_HARD_EX, IRQ_VB, state); } + DECLARE_WRITE_LINE_MEMBER(ir7_w) { set_int_line(INT_HARD_EX, IRQ_9, state); } + DECLARE_WRITE_LINE_MEMBER(ir8_w) { set_int_line(INT_HARD_EX, IRQ_CBUS3, state); } + // FIXME: mc146818 inverts the normal irq state convention + DECLARE_WRITE_LINE_MEMBER(ir9_w) { set_int_line(INT_HARD_EX, IRQ_RTC, !state); } + DECLARE_WRITE_LINE_MEMBER(ir10_w) { set_int_line(INT_HARD_EX, IRQ_12, state); } + DECLARE_WRITE_LINE_MEMBER(ir11_w) { set_int_line(INT_HARD_EX, IRQ_SERIAL, state); } + DECLARE_WRITE_LINE_MEMBER(ir12_w) { set_int_line(INT_HARD_EX, IRQ_ETHERNET, state); } + + IRQ_CALLBACK_MEMBER(acknowledge_interrupt); + + // interrupt control + enum icr_mask { + IRQ_NUMBER = 0x000f, + IRQ_LEVEL = 0x00f0, + IRQ_VECTOR = 0x00ff, + IRQ_FLAGS = 0xff00, + IRQ_PENDING = 0x0100, IRQ_ENABLE_EXTERNAL = 0x0200, IRQ_EDGE = 0x0400, IRQ_NEGPOL = 0x0800, IRQ_ENABLE_INTERNAL = 0x1000 }; - DECLARE_READ16_MEMBER(icr_r) { return m_hwicr[offset]; } + DECLARE_READ16_MEMBER(icr_r) const { return m_hwicr[offset]; } DECLARE_WRITE16_MEMBER(icr_w); - DECLARE_READ16_MEMBER(icr18_r) { return icr_r(space, 18, mem_mask); } + DECLARE_READ16_MEMBER(icr18_r) const { return icr_r(space, 18, mem_mask); } DECLARE_WRITE16_MEMBER(icr18_w) { icr_w(space, 18, data, mem_mask); } - DECLARE_READ8_MEMBER(softint_r) { return m_softint; } - DECLARE_WRITE8_MEMBER(softint_w); - enum nmictrl_mask { NMI_ALL = 0x01, @@ -216,12 +164,23 @@ public: NMI_IE = NMI_ENABLE1 | NMI_ENABLE2 }; - DECLARE_READ8_MEMBER(nmictrl_r) { return m_nmictrl; } + DECLARE_READ8_MEMBER(nmictrl_r) const { return m_nmictrl; } DECLARE_WRITE8_MEMBER(nmictrl_w); - DECLARE_READ16_MEMBER(softint_vector_r) { return m_swicr[offset]; } + DECLARE_READ8_MEMBER(softint_r) const { return m_softint; } + DECLARE_WRITE8_MEMBER(softint_w); + DECLARE_READ16_MEMBER(softint_vector_r) const { return m_swicr[offset]; } DECLARE_WRITE16_MEMBER(softint_vector_w); + // dma request lines + DECLARE_WRITE_LINE_MEMBER(drq_plotter) { drq(state, DMA_PLOTTER); } + DECLARE_WRITE_LINE_MEMBER(drq_scsi) { drq(state, DMA_SCSI); } + DECLARE_WRITE_LINE_MEMBER(drq_floppy) { drq(state, DMA_FLOPPY); } + DECLARE_WRITE_LINE_MEMBER(drq_serial0) { serial_drq(state, 0); } + DECLARE_WRITE_LINE_MEMBER(drq_serial1) { serial_drq(state, 1); } + DECLARE_WRITE_LINE_MEMBER(drq_serial2) { serial_drq(state, 2); } + + // dma control enum dma_ctrl_mask { DMA_CTRL_TCZERO = 0x00000001, // transfer count zero @@ -231,45 +190,54 @@ public: 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? + DMA_CTRL_DOUBLE = 0x04000000, // double transfer size (double or quad quad) DMA_CTRL_VIRTUAL = 0x20000000, // use virtual addressing DMA_CTRL_WRITE = 0x40000000, // memory to device transfer + DMA_CTRL_QUAD = 0x80000000, // select quad transfer size (quad quad when combined with double) DMA_CTRL_WMASK = 0xfd000e00 // writable fields }; - DECLARE_READ32_MEMBER(dma_plotter_r) { return dma_r(space, offset, mem_mask, IOGA_DMA_PLOTTER); } - DECLARE_WRITE32_MEMBER(dma_plotter_w) { dma_w(space, offset, data, mem_mask, IOGA_DMA_PLOTTER); } - DECLARE_READ32_MEMBER(dma_scsi_r) { return dma_r(space, offset, mem_mask, IOGA_DMA_SCSI); } - DECLARE_WRITE32_MEMBER(dma_scsi_w) { dma_w(space, offset, data, mem_mask, IOGA_DMA_SCSI); } - 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_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; } - - DECLARE_READ32_MEMBER(error_address_r) { return m_error_address; } + DECLARE_READ32_MEMBER(dma_plotter_r) const { return dma_r(space, offset, mem_mask, DMA_PLOTTER); } + DECLARE_WRITE32_MEMBER(dma_plotter_w) { dma_w(space, offset, data, mem_mask, DMA_PLOTTER); } + DECLARE_READ32_MEMBER(dma_scsi_r) const { return dma_r(space, offset, mem_mask, DMA_SCSI); } + DECLARE_WRITE32_MEMBER(dma_scsi_w) { dma_w(space, offset, data, mem_mask, DMA_SCSI); } + DECLARE_READ32_MEMBER(dma_floppy_r) const { return dma_r(space, offset, mem_mask, DMA_FLOPPY); } + DECLARE_WRITE32_MEMBER(dma_floppy_w) { dma_w(space, offset, data, mem_mask, DMA_FLOPPY); } + + DECLARE_READ32_MEMBER(serial_dma0_addr_r) const { return serial_dma_addr_r(space, offset, mem_mask, 0); } + DECLARE_WRITE32_MEMBER(serial_dma0_addr_w) { serial_dma_addr_w(space, offset, data, mem_mask, 0); } + DECLARE_READ32_MEMBER(serial_dma0_ctrl_r) const { return serial_dma_ctrl_r(space, offset, mem_mask, 0); } + DECLARE_WRITE32_MEMBER(serial_dma0_ctrl_w) { serial_dma_ctrl_w(space, offset, data, mem_mask, 0); } + + DECLARE_READ32_MEMBER(serial_dma1_addr_r) const { return serial_dma_addr_r(space, offset, mem_mask, 1); } + DECLARE_WRITE32_MEMBER(serial_dma1_addr_w) { serial_dma_addr_w(space, offset, data, mem_mask, 1); } + DECLARE_READ32_MEMBER(serial_dma1_ctrl_r) const { return serial_dma_ctrl_r(space, offset, mem_mask, 1); } + DECLARE_WRITE32_MEMBER(serial_dma1_ctrl_w) { serial_dma_ctrl_w(space, offset, data, mem_mask, 1); } + + DECLARE_READ32_MEMBER(serial_dma2_addr_r) const { return serial_dma_addr_r(space, offset, mem_mask, 2); } + DECLARE_WRITE32_MEMBER(serial_dma2_addr_w) { serial_dma_addr_w(space, offset, data, mem_mask, 2); } + DECLARE_READ32_MEMBER(serial_dma2_ctrl_r) const { return serial_dma_ctrl_r(space, offset, mem_mask, 2); } + DECLARE_WRITE32_MEMBER(serial_dma2_ctrl_w) { serial_dma_ctrl_w(space, offset, data, mem_mask, 2); } + + DECLARE_READ32_MEMBER(dma_plotter_eosl_r) const { return m_dma_plotter_eosl; } + DECLARE_WRITE32_MEMBER(dma_plotter_eosl_w) { m_dma_plotter_eosl = data ^ 0xffff0000; } + + // bus arbitration and control + enum arbctl_mask + { + ARBCTL_BGR_ETHC = 0x0001, + ARBCTL_BGR_SCSI = 0x0002, + ARBCTL_BGR_PLOT = 0x0004, + ARBCTL_BGR_FDC = 0x0008, + ARBCTL_BGR_SER0 = 0x0010, + ARBCTL_BGR_SER1 = 0x0020, + ARBCTL_BGR_SER2 = 0x0040, + ARBCTL_BGR_ETHB = 0x0080, + ARBCTL_BGR_ETHA = 0x0100 + }; + DECLARE_READ16_MEMBER(arbctl_r) const { return m_arbctl; } + DECLARE_WRITE16_MEMBER(arbctl_w); enum error_businfo_mask { @@ -281,7 +249,7 @@ public: BINFO_SNAPOK = 0x4000, BINFO_MSBE = 0x8000 }; - enum error_businfo_bg + enum error_businfo_bg_mask { BINFO_BG_IOD = 0x0200, BINFO_BG_ICAMMU = 0x0400, @@ -289,41 +257,134 @@ public: BINFO_BG_SRMASTER = 0x0c00 }; DECLARE_READ32_MEMBER(error_businfo_r); - DECLARE_READ32_MEMBER(bus_timeout_r) { return m_bus_timeout; } + DECLARE_READ32_MEMBER(error_address_r) const { return m_error_address; } + DECLARE_READ32_MEMBER(bus_timeout_r) const { return m_bus_timeout; } DECLARE_WRITE32_MEMBER(bus_timeout_w) { m_bus_timeout = data; } DECLARE_WRITE32_MEMBER(bus_error) { m_error_address = data; m_error_businfo = offset; } + // timers + DECLARE_READ32_MEMBER(timer0_r) const; + DECLARE_WRITE32_MEMBER(timer0_w); + + enum timer1_mask + { + TIMER1_COUNT = 0x0000ffff, + TIMER1_START = 0x00010000, + TIMER1_EXPIRED = 0x00020000 + }; + DECLARE_READ32_MEMBER(timer1_r) const; + DECLARE_WRITE32_MEMBER(timer1_w); + + DECLARE_READ32_MEMBER(timer2_count_r) const; + DECLARE_WRITE32_MEMBER(timer2_count_w); + DECLARE_READ32_MEMBER(timer2_value_r) const; + DECLARE_WRITE32_MEMBER(timer2_value_w); + + enum timer3_mask + { + TIMER3_COUNT = 0x3fffffff, + TIMER3_START = 0x40000000, + TIMER3_EXPIRED = 0x80000000 + }; + DECLARE_READ32_MEMBER(timer3_r) const; + DECLARE_WRITE32_MEMBER(timer3_w); + + DECLARE_READ32_MEMBER(prescaler_r) const; + DECLARE_WRITE32_MEMBER(prescaler_w); + + // mouse + enum mouse_status_mask + { + MOUSE_YPOS = 0x000000ff, + MOUSE_XPOS = 0x0000ff00, + MOUSE_LBUTTON = 0x00010000, + MOUSE_MBUTTON = 0x00020000, + MOUSE_RBUTTON = 0x00040000, + + MOUSE_COUNTER = 0x0000ffff, + MOUSE_BUTTONS = 0x00070000 + }; + DECLARE_READ32_MEMBER(mouse_status_r); + DECLARE_WRITE32_MEMBER(mouse_status_w); + DECLARE_INPUT_CHANGED_MEMBER(mouse_button); + DECLARE_INPUT_CHANGED_MEMBER(mouse_x); + DECLARE_INPUT_CHANGED_MEMBER(mouse_y); + protected: // device-level overrides virtual void device_start() override; virtual void device_reset() override; - virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override; + virtual ioport_constructor device_input_ports() const override; -private: - static const device_timer_id IOGA_TIMER_0 = 0; - static const device_timer_id IOGA_TIMER_1 = 1; - static const device_timer_id IOGA_TIMER_2 = 2; - static const device_timer_id IOGA_TIMER_3 = 3; + address_space *m_memory_space; - static const device_timer_id IOGA_CLOCK = 4; + // callbacks + devcb_write_line m_out_nmi_func; + devcb_write_line m_out_irq_func; + devcb_write8 m_out_ivec_func; + devcb_write_line m_fdc_tc_func; + devcb_write_line m_eth_ca_func; void set_nmi_line(int state); - void set_irq_line(int irq, int state); - void set_irq_soft(int irq, int state); - void write_timer(int timer, u32 value, device_timer_id id); + void set_int_line(interrupt_type type, int number, int state); + + TIMER_CALLBACK_MEMBER(interrupt_check); + TIMER_CALLBACK_MEMBER(set_ivec); + TIMER_CALLBACK_MEMBER(dma); + TIMER_CALLBACK_MEMBER(serial_dma); + TIMER_CALLBACK_MEMBER(timer0); + TIMER_CALLBACK_MEMBER(timer1); + TIMER_CALLBACK_MEMBER(timer2) {} + TIMER_CALLBACK_MEMBER(timer3); + TIMER_CALLBACK_MEMBER(mouse_timer); - void interrupt_clock(); - void dma_clock(); - void dma_serial_clock(); + virtual TIMER_CALLBACK_MEMBER(eth_reset) = 0; + emu_timer *m_eth_reset_timer; + +private: + bool nmi(int state); + bool irq(int state, u8 ivec); + u16 get_icr(interrupt_type type, int number) const; + void set_pending(interrupt_type type, int number, bool pending); 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; + void serial_drq(int state, int channel); + + u32 dma_r(address_space &space, offs_t offset, u32 mem_mask, dma_channel channel) const; + void dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, dma_channel channel); + + enum serial_dma_ctrl_mask + { + SDMA_COUNT = 0x0000ffff, + SDMA_TCZERO = 0x00200000, + SDMA_SEND = 0x04000000, // transfer from memory to device + SDMA_CONTROL = 0xffff0000, + }; + u32 serial_dma_addr_r(address_space &space, offs_t offset, u32 mem_mask, int channel) const { return m_serial_dma_channel[channel].address; } + void serial_dma_addr_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel); + u32 serial_dma_ctrl_r(address_space &space, offs_t offset, u32 mem_mask, int channel) const { return m_serial_dma_channel[channel].control; } + void serial_dma_ctrl_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel); + + // interrupt state + static const interrupt_data_t m_interrupt_data[]; + interrupt_data_t const *m_active_interrupt; + int m_nmi_state; + int m_irq_state; + u8 m_ivec; + u32 m_hwint_forced; + u32 m_line_state; + + // interrupt control + static const int INTERRUPT_COUNT = 19; + u16 m_hwicr[INTERRUPT_COUNT]; + u8 m_softint; + u8 m_nmictrl; + u16 m_swicr[8]; - enum dma_states + // dma state + static const int DMA_CHANNEL_COUNT = 3; + enum dma_state { IDLE, WAIT, @@ -332,8 +393,7 @@ private: COMPLETE, FINAL }; - // dma channels - struct dma + struct dma_channel_t { u32 real_address; u32 virtual_address; @@ -341,84 +401,164 @@ private: u32 control; int drq_state; - dma_states state; + dma_state state; devcb_read8 device_r; devcb_write8 device_w; const u16 arb_mask; - const int channel; - const char *name; - } m_dma_channel[IOGA_DMA_CHANNELS]; + const dma_channel channel; + const char *const name; + } m_dma_channel[DMA_CHANNEL_COUNT]; u32 m_dma_plotter_eosl; - // dma serial channels - struct dma_serial + // serial dma state + static const int SERIAL_DMA_CHANNEL_COUNT = 3; + struct serial_dma_channel_t { u32 address; - u16 count; - u16 control; + u32 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; + const char *const name; + } m_serial_dma_channel[SERIAL_DMA_CHANNEL_COUNT]; - u32 m_hwint_forced; - bool m_nmi_pending; - - u16 m_hwicr[IOGA_INTERRUPT_COUNT]; - u8 m_softint; - u8 m_nmictrl; - u16 m_swicr[8]; - - u32 m_prescaler; - u32 m_timer_reg[3]; + // timers + u8 m_timer0_count; + u8 m_timer0_limit; u16 m_timer1_count; + u32 m_timer2_count; + u32 m_timer2_value; u32 m_timer3_count; - emu_timer *m_timer[4]; - - 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 m_prescaler; - 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); + emu_timer *m_interrupt_timer; + emu_timer *m_dma_timer; + emu_timer *m_serial_dma_timer; + emu_timer *m_timer0; + emu_timer *m_timer1; + emu_timer *m_timer2; + emu_timer *m_timer3; + // bus arbitration and control u16 m_arbctl; - u32 m_error_address; u32 m_error_businfo; u32 m_bus_timeout; - emu_timer *m_ioga_clock; - int m_nmi_state; - int m_irq_state; + // mouse + u32 m_mouse_status; + emu_timer *m_mouse_timer; +}; - u32 m_int_line; +class turquoise_ioga_device : public interpro_ioga_device +{ +public: + turquoise_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - bool nmi(int state); - bool irq(int state); + virtual DECLARE_ADDRESS_MAP(map, 32) override; + + DECLARE_WRITE16_MEMBER(eth_w); + DECLARE_READ16_MEMBER(eth_r) const; + +protected: + virtual TIMER_CALLBACK_MEMBER(eth_reset) override; + + enum eth_base_mask + { + ETH_BASE_MASK = 0xffe00000 + }; + DECLARE_READ32_MEMBER(eth_base_r) const { return m_eth_base; } + DECLARE_WRITE32_MEMBER(eth_base_w); + + enum eth_control_mask + { + ETH_CA = 0x0001, // channel attention + ETH_FLUSH = 0x0002, + ETH_BUF = 0x0004, + ETH_QUAD = 0x0008, + ETH_BERR = 0x0010, // bus error + ETH_PERR = 0x0020, // parity error + ETH_RESET = 0x0040, + ETH_WTAG = 0x0600, + ETH_RTAG = 0x3000, + + //ETH_MASK = 0x4ff2 // channel attention and error bits not persistent + }; + DECLARE_READ16_MEMBER(eth_control_r) const { return m_eth_control; } + DECLARE_WRITE16_MEMBER(eth_control_w); + +private: + u32 m_eth_base; + u16 m_eth_control; +}; + +class sapphire_ioga_device : public interpro_ioga_device +{ +public: + sapphire_ioga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_ADDRESS_MAP(map, 32) override; + + DECLARE_WRITE32_MEMBER(eth_w); + DECLARE_READ32_MEMBER(eth_r) const; + +protected: + virtual TIMER_CALLBACK_MEMBER(eth_reset) override; + + enum eth_remap_mask + { + ETH_CHA_FLUSH = 0x00000008, + ETH_CHA_BUF = 0x00000010, + ETH_CHA_QUAD = 0x00000020, + ETH_CHA_WTAG = 0x000001c0, + ETH_CHA_RTAG = 0x00000e00, + ETH_REMAP_ADDR = 0xfffff000 + }; + DECLARE_READ32_MEMBER(eth_remap_r) const { return m_eth_remap; } + DECLARE_WRITE32_MEMBER(eth_remap_w); + enum eth_mappg_mask + { + ETH_CHB_FLUSH = 0x00000008, + ETH_CHB_BUF = 0x00000010, + ETH_CHB_QUAD = 0x00000020, + ETH_CHB_WTAG = 0x000001c0, + ETH_CHB_RTAG = 0x00000e00, + ETH_MAPPG = 0xfffff000 + }; + DECLARE_READ32_MEMBER(eth_mappg_r) const { return m_eth_mappg; } + DECLARE_WRITE32_MEMBER(eth_mappg_w); + + enum eth_control_mask + { + ETH_CA = 0x00000001, // channel attention + ETH_MAPEN = 0x00000002, + ETH_CHC_BUF = 0x00000010, + ETH_CHC_QUAD = 0x00000020, + ETH_CHC_WTAG = 0x000001c0, + ETH_CHC_RTAG = 0x00000e00, + ETH_BERR = 0x00001000, + ETH_MMBE = 0x00002000, + ETH_RESET = 0x00004000, + + ETH_MASK = 0x00004ff2 // channel attention and error bits not persistent + }; + DECLARE_READ32_MEMBER(eth_control_r) const; + DECLARE_WRITE32_MEMBER(eth_control_w); + +private: u32 m_eth_remap; - u32 m_eth_map_page; + u32 m_eth_mappg; u32 m_eth_control; }; // device type definition -DECLARE_DEVICE_TYPE(INTERPRO_IOGA, interpro_ioga_device) +DECLARE_DEVICE_TYPE(TURQUOISE_IOGA, turquoise_ioga_device) +DECLARE_DEVICE_TYPE(SAPPHIRE_IOGA, sapphire_ioga_device) #endif // MAME_MACHINE_INTERPRO_IOGA_H diff --git a/src/mame/machine/interpro_mcga.cpp b/src/mame/machine/interpro_mcga.cpp index aca546233e4..5e61a9ed31d 100644 --- a/src/mame/machine/interpro_mcga.cpp +++ b/src/mame/machine/interpro_mcga.cpp @@ -2,24 +2,24 @@ // copyright-holders:Patrick Mackinlay /* -* An implementation of the MCGA device found on Intergraph InterPro family workstations. There is no -* public documentation on this device, so the implementation is being built to follow the logic of the -* system boot ROM and its diagnostic tests. -* -* Please be aware that code in here is not only broken, it's likely wrong in many cases. -* -* TODO -* - too long to list -*/ + * An implementation of the MCGA (Memory Controller Gate Array) and FMCC (Fast + * Memory Control Chip) devices found in Intergraph InterPro family systems. + * There is no public documentation on this device, so the implementation is + * being built to follow the logic of the system boot ROM and its diagnostic + * tests. + * + * Please be aware that code in here is not only broken, it's likely wrong in + * many cases. + * + * TODO + * - too long to list + */ + #include "emu.h" #include "interpro_mcga.h" #define VERBOSE 0 -#if VERBOSE -#define LOG_MCGA(...) logerror(__VA_ARGS__) -#else -#define LOG_MCGA(...) {} -#endif +#include "logmacro.h" DEVICE_ADDRESS_MAP_START(map, 32, interpro_mcga_device) AM_RANGE(0x00, 0x03) AM_READWRITE16(reg00_r, reg00_w, 0xffff) @@ -45,8 +45,8 @@ DEVICE_ADDRESS_MAP_START(map, 32, interpro_fmcc_device) AM_RANGE(0x48, 0x4b) AM_READWRITE16(error_control_r, error_control_w, 0xffff) ADDRESS_MAP_END -DEFINE_DEVICE_TYPE(INTERPRO_MCGA, interpro_mcga_device, "mcga", "InterPro MCGA") -DEFINE_DEVICE_TYPE(INTERPRO_FMCC, interpro_fmcc_device, "fmcc", "InterPro FMCC") +DEFINE_DEVICE_TYPE(INTERPRO_MCGA, interpro_mcga_device, "mcga", "Memory Controller Gate Array") +DEFINE_DEVICE_TYPE(INTERPRO_FMCC, interpro_fmcc_device, "fmcc", "Fast Memory Control Chip") interpro_mcga_device::interpro_mcga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, type, tag, owner, clock) diff --git a/src/mame/machine/interpro_mcga.h b/src/mame/machine/interpro_mcga.h index 20b82f8d7b3..e415df36f7d 100644 --- a/src/mame/machine/interpro_mcga.h +++ b/src/mame/machine/interpro_mcga.h @@ -13,7 +13,7 @@ public: virtual DECLARE_ADDRESS_MAP(map, 32); - DECLARE_READ16_MEMBER(reg00_r) { return m_reg[0]; } + DECLARE_READ16_MEMBER(reg00_r) const { return m_reg[0]; } DECLARE_WRITE16_MEMBER(reg00_w) { m_reg[0] = data; } enum control_mask @@ -29,7 +29,7 @@ public: CONTROL_MASK = 0x871f }; - DECLARE_READ16_MEMBER(control_r) { return m_control; } + DECLARE_READ16_MEMBER(control_r) const { return m_control; } virtual DECLARE_WRITE16_MEMBER(control_w); enum error_mask @@ -40,22 +40,22 @@ public: ERROR_ADDR = 0x1c00, ERROR_VALID = 0x8000 }; - DECLARE_READ16_MEMBER(error_r) { return m_error; } + DECLARE_READ16_MEMBER(error_r) const { return m_error; } DECLARE_WRITE16_MEMBER(error_w) { m_error = data; } - DECLARE_READ8_MEMBER(frcrd_r) { return m_frcrd; } + DECLARE_READ8_MEMBER(frcrd_r) const { return m_frcrd; } DECLARE_WRITE8_MEMBER(frcrd_w) { m_frcrd = data; } - DECLARE_READ8_MEMBER(cbsub_r) { return m_cbsub; } + DECLARE_READ8_MEMBER(cbsub_r) const { return m_cbsub; } DECLARE_WRITE8_MEMBER(cbsub_w) { m_cbsub = data; } - DECLARE_READ16_MEMBER(reg28_r) { return m_reg[1]; } + DECLARE_READ16_MEMBER(reg28_r) const { return m_reg[1]; } DECLARE_WRITE16_MEMBER(reg28_w) { m_reg[1] = data; } - DECLARE_READ16_MEMBER(reg30_r) { return m_reg[2]; } + DECLARE_READ16_MEMBER(reg30_r) const { return m_reg[2]; } DECLARE_WRITE16_MEMBER(reg30_w) { m_reg[2] = data; } enum memsize_mask { MEMSIZE_ADDR = 0x007f }; - DECLARE_READ16_MEMBER(memsize_r) { return m_memsize; } + DECLARE_READ16_MEMBER(memsize_r) const { return m_memsize; } DECLARE_WRITE16_MEMBER(memsize_w) { m_memsize = data; } protected: @@ -112,7 +112,7 @@ public: ERROR_CONTROL_CYCLE = 0x003f, ERROR_CONTROL_TAG = 0x01c0 }; - DECLARE_READ16_MEMBER(error_control_r) { return m_error_control; } + DECLARE_READ16_MEMBER(error_control_r) const { return m_error_control; } DECLARE_WRITE16_MEMBER(error_control_w) { m_error_control = data; } private: diff --git a/src/mame/machine/interpro_sga.cpp b/src/mame/machine/interpro_sga.cpp index 3d6b0731acc..cba3e1be13f 100644 --- a/src/mame/machine/interpro_sga.cpp +++ b/src/mame/machine/interpro_sga.cpp @@ -2,19 +2,23 @@ // copyright-holders:Patrick Mackinlay /* -* An implementation of the SGA device found on Intergraph InterPro family workstations. There is no -* public documentation on this device, so the implementation is being built to follow the logic of the -* system boot ROM and its diagnostic tests. -* -* Please be aware that code in here is not only broken, it's likely wrong in many cases. -* -* TODO -* - too long to list -*/ + * An implementation of the SGA (SRX Gate Array) device found in Intergraph + * InterPro family systems. There is no public documentation on this device, + * so the implementation is being built to follow the logic of the system boot + * ROM and its diagnostic tests. + * + * Please be aware that code in here is not only broken, it's likely wrong in + * many cases. + * + * TODO + * - too long to list + */ + #include "emu.h" #include "interpro_sga.h" #define VERBOSE 0 +#include "logmacro.h" DEVICE_ADDRESS_MAP_START(map, 32, interpro_sga_device) AM_RANGE(0x00, 0x03) AM_READWRITE(gcsr_r, gcsr_w) @@ -62,7 +66,7 @@ DEVICE_ADDRESS_MAP_START(map, 32, interpro_sga_device) AM_RANGE(0xec, 0xef) AM_READWRITE(dcksum1_r, dcksum1_w) // dma 1 device checksum register 1 (esga) ADDRESS_MAP_END -DEFINE_DEVICE_TYPE(INTERPRO_SGA, interpro_sga_device, "sga", "InterPro SGA") +DEFINE_DEVICE_TYPE(INTERPRO_SGA, interpro_sga_device, "sga", "SRX Gate Array") interpro_sga_device::interpro_sga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : device_t(mconfig, INTERPRO_SGA, tag, owner, clock), @@ -73,6 +77,48 @@ interpro_sga_device::interpro_sga_device(const machine_config &mconfig, const ch void interpro_sga_device::device_start() { out_berr_func.resolve(); + + save_item(NAME(m_gcsr)); + save_item(NAME(m_ipoll)); + save_item(NAME(m_imask)); + save_item(NAME(m_range_base)); + save_item(NAME(m_range_end)); + save_item(NAME(m_cttag)); + save_item(NAME(m_address)); + save_item(NAME(m_dmacsr)); + + save_item(NAME(m_edmacsr)); + save_item(NAME(m_reg6_range)); + + save_item(NAME(m_ddpta0)); + save_item(NAME(m_ddpad0)); + save_item(NAME(m_ddoff0)); + save_item(NAME(m_ddtc0)); + save_item(NAME(m_dspta0)); + save_item(NAME(m_dspad0)); + save_item(NAME(m_dsoff0)); + save_item(NAME(m_dstc0)); + + save_item(NAME(m_dspad1)); + save_item(NAME(m_dsoff1)); + save_item(NAME(m_dstc1)); + save_item(NAME(m_ddpad1)); + save_item(NAME(m_ddoff1)); + save_item(NAME(m_ddtc1)); + + save_item(NAME(m_ddpta2)); + save_item(NAME(m_ddpad2)); + save_item(NAME(m_ddoff2)); + save_item(NAME(m_ddtc2)); + save_item(NAME(m_dspta2)); + save_item(NAME(m_dspad2)); + save_item(NAME(m_dsoff2)); + save_item(NAME(m_dstc2)); + + save_item(NAME(m_ddrd2)); + save_item(NAME(m_dsrd2)); + save_item(NAME(m_dcksum0)); + save_item(NAME(m_dcksum1)); } void interpro_sga_device::device_reset() @@ -86,10 +132,10 @@ WRITE32_MEMBER(interpro_sga_device::ddtc1_w) // assume that when this register is written, we should start a // memory to memory dma transfer - logerror(" gcsr = 0x%08x dmacsr = 0x%08x\n", m_gcsr, m_dmacsr); - logerror(" ipoll = 0x%08x imask = 0x%08x\n", m_ipoll, m_imask); - logerror("dspad1 = 0x%08x dsoff1 = 0x%08x dstc1 = 0x%08x\n", m_dspad1, m_dsoff1, m_dstc1); - logerror("ddpad1 = 0x%08x ddoff1 = 0x%08x ddtc1 = 0x%08x\n", m_ddpad1, m_ddoff1, m_ddtc1); + LOG(" gcsr = 0x%08x dmacsr = 0x%08x\n", m_gcsr, m_dmacsr); + LOG(" ipoll = 0x%08x imask = 0x%08x\n", m_ipoll, m_imask); + LOG("dspad1 = 0x%08x dsoff1 = 0x%08x dstc1 = 0x%08x\n", m_dspad1, m_dsoff1, m_dstc1); + LOG("ddpad1 = 0x%08x ddoff1 = 0x%08x ddtc1 = 0x%08x\n", m_ddpad1, m_ddoff1, m_ddtc1); // when complete, we indicate by setting DMAEND(2) - 2 is probably the channel // we also turn off the INTBERR and INTMMBE flags diff --git a/src/mame/machine/interpro_sga.h b/src/mame/machine/interpro_sga.h index 9c49015a7b1..b0754f5e638 100644 --- a/src/mame/machine/interpro_sga.h +++ b/src/mame/machine/interpro_sga.h @@ -18,7 +18,7 @@ public: virtual DECLARE_ADDRESS_MAP(map, 32); - DECLARE_READ32_MEMBER(gcsr_r) { return m_gcsr; } + DECLARE_READ32_MEMBER(gcsr_r) const { return m_gcsr; } DECLARE_WRITE32_MEMBER(gcsr_w) { m_gcsr = data; } enum ipoll_mask { @@ -31,7 +31,7 @@ public: IPOLL_INTBERR = 0x00010000, IPOLL_INTMMBE = 0x00020000 }; - DECLARE_READ32_MEMBER(ipoll_r) { return m_ipoll; } + DECLARE_READ32_MEMBER(ipoll_r) const { return m_ipoll; } DECLARE_WRITE32_MEMBER(ipoll_w) { m_ipoll = data; } enum imask_mask @@ -44,11 +44,11 @@ public: IMASK_INTBERR = 0x00010000, IMASK_INTMMBE = 0x00020000 }; - DECLARE_READ32_MEMBER(imask_r) { return m_imask; } + DECLARE_READ32_MEMBER(imask_r) const { return m_imask; } DECLARE_WRITE32_MEMBER(imask_w) { m_imask = data; } - DECLARE_READ32_MEMBER(range_base_r) { return m_range_base; } + DECLARE_READ32_MEMBER(range_base_r) const { return m_range_base; } DECLARE_WRITE32_MEMBER(range_base_w) { m_range_base = data; } - DECLARE_READ32_MEMBER(range_end_r) { return m_range_end; } + DECLARE_READ32_MEMBER(range_end_r) const { return m_range_end; } DECLARE_WRITE32_MEMBER(range_end_w) { m_range_end = data; } enum cttag_mask @@ -58,84 +58,84 @@ public: CTTAG_MAXBCLK = 0x0003fe00, CTTAG_MAXRETRY = 0x3ffc0000 }; - DECLARE_READ32_MEMBER(cttag_r) { return m_cttag; } + DECLARE_READ32_MEMBER(cttag_r) const { return m_cttag; } DECLARE_WRITE32_MEMBER(cttag_w) { m_cttag = data; } - DECLARE_READ32_MEMBER(address_r) { return m_address; } + DECLARE_READ32_MEMBER(address_r) const { return m_address; } DECLARE_WRITE32_MEMBER(address_w) { m_address = data; } enum dmacsr_mask { DMACSR_CH1ENABLE = 0x00000080 }; - DECLARE_READ32_MEMBER(dmacsr_r) { return m_dmacsr; } + DECLARE_READ32_MEMBER(dmacsr_r) const { return m_dmacsr; } DECLARE_WRITE32_MEMBER(dmacsr_w) { m_dmacsr = data; } enum edmacsr_mask { EDMACSR_CH1RDONLY = 0x00000010 }; - DECLARE_READ32_MEMBER(edmacsr_r) { return m_edmacsr; } + DECLARE_READ32_MEMBER(edmacsr_r) const { return m_edmacsr; } DECLARE_WRITE32_MEMBER(edmacsr_w) { m_edmacsr = data; } - DECLARE_READ32_MEMBER(reg6_range_r) { return m_reg6_range; } + DECLARE_READ32_MEMBER(reg6_range_r) const { return m_reg6_range; } DECLARE_WRITE32_MEMBER(reg6_range_w) { m_reg6_range = data; } - DECLARE_READ32_MEMBER(ddpta0_r) { return m_ddpta0; } + DECLARE_READ32_MEMBER(ddpta0_r) const { return m_ddpta0; } DECLARE_WRITE32_MEMBER(ddpta0_w) { m_ddpta0 = data; } - DECLARE_READ32_MEMBER(ddpad0_r) { return m_ddpad0; } + DECLARE_READ32_MEMBER(ddpad0_r) const { return m_ddpad0; } DECLARE_WRITE32_MEMBER(ddpad0_w) { m_ddpad0 = data; } - DECLARE_READ32_MEMBER(ddoff0_r) { return m_ddoff0; } + DECLARE_READ32_MEMBER(ddoff0_r) const { return m_ddoff0; } DECLARE_WRITE32_MEMBER(ddoff0_w) { m_ddoff0 = data; } - DECLARE_READ32_MEMBER(ddtc0_r) { return m_ddtc0; } + DECLARE_READ32_MEMBER(ddtc0_r) const { return m_ddtc0; } DECLARE_WRITE32_MEMBER(ddtc0_w) { m_ddtc0 = data; } - DECLARE_READ32_MEMBER(dspta0_r) { return m_dspta0; } + DECLARE_READ32_MEMBER(dspta0_r) const { return m_dspta0; } DECLARE_WRITE32_MEMBER(dspta0_w) { m_dspta0 = data; } - DECLARE_READ32_MEMBER(dspad0_r) { return m_dspad0; } + DECLARE_READ32_MEMBER(dspad0_r) const { return m_dspad0; } DECLARE_WRITE32_MEMBER(dspad0_w) { m_dspad0 = data; } - DECLARE_READ32_MEMBER(dsoff0_r) { return m_dsoff0; } + DECLARE_READ32_MEMBER(dsoff0_r) const { return m_dsoff0; } DECLARE_WRITE32_MEMBER(dsoff0_w) { m_dsoff0 = data; } - DECLARE_READ32_MEMBER(dstc0_r) { return m_dstc0; } + DECLARE_READ32_MEMBER(dstc0_r) const { return m_dstc0; } DECLARE_WRITE32_MEMBER(dstc0_w) { m_dstc0 = data; } - DECLARE_READ32_MEMBER(dspad1_r) { return m_dspad1; } + DECLARE_READ32_MEMBER(dspad1_r) const { return m_dspad1; } DECLARE_WRITE32_MEMBER(dspad1_w) { m_dspad1 = data; } - DECLARE_READ32_MEMBER(dsoff1_r) { return m_dsoff1; } + DECLARE_READ32_MEMBER(dsoff1_r) const { return m_dsoff1; } DECLARE_WRITE32_MEMBER(dsoff1_w) { m_dsoff1 = data; } - DECLARE_READ32_MEMBER(dstc1_r) { return m_dstc1; } + DECLARE_READ32_MEMBER(dstc1_r) const { return m_dstc1; } DECLARE_WRITE32_MEMBER(dstc1_w) { m_dstc1 = data; } - DECLARE_READ32_MEMBER(ddpad1_r) { return m_ddpad1; } + DECLARE_READ32_MEMBER(ddpad1_r) const { return m_ddpad1; } DECLARE_WRITE32_MEMBER(ddpad1_w) { m_ddpad1 = data; } - DECLARE_READ32_MEMBER(ddoff1_r) { return m_ddoff1; } + DECLARE_READ32_MEMBER(ddoff1_r) const { return m_ddoff1; } DECLARE_WRITE32_MEMBER(ddoff1_w) { m_ddoff1 = data; } - DECLARE_READ32_MEMBER(ddtc1_r) { return m_ddtc1; } + DECLARE_READ32_MEMBER(ddtc1_r) const { return m_ddtc1; } DECLARE_WRITE32_MEMBER(ddtc1_w); - DECLARE_READ32_MEMBER(ddpta2_r) { return m_ddpta2; } + DECLARE_READ32_MEMBER(ddpta2_r) const { return m_ddpta2; } DECLARE_WRITE32_MEMBER(ddpta2_w) { m_ddpta2 = data; } - DECLARE_READ32_MEMBER(ddpad2_r) { return m_ddpad2; } + DECLARE_READ32_MEMBER(ddpad2_r) const { return m_ddpad2; } DECLARE_WRITE32_MEMBER(ddpad2_w) { m_ddpad2 = data; } - DECLARE_READ32_MEMBER(ddoff2_r) { return m_ddoff2; } + DECLARE_READ32_MEMBER(ddoff2_r) const { return m_ddoff2; } DECLARE_WRITE32_MEMBER(ddoff2_w) { m_ddoff2 = data; } - DECLARE_READ32_MEMBER(ddtc2_r) { return m_ddtc2; } + DECLARE_READ32_MEMBER(ddtc2_r) const { return m_ddtc2; } DECLARE_WRITE32_MEMBER(ddtc2_w) { m_ddtc2 = data; } - DECLARE_READ32_MEMBER(dspta2_r) { return m_dspta2; } + DECLARE_READ32_MEMBER(dspta2_r) const { return m_dspta2; } DECLARE_WRITE32_MEMBER(dspta2_w) { m_dspta2 = data; } - DECLARE_READ32_MEMBER(dspad2_r) { return m_dspad2; } + DECLARE_READ32_MEMBER(dspad2_r) const { return m_dspad2; } DECLARE_WRITE32_MEMBER(dspad2_w) { m_dspad2 = data; } - DECLARE_READ32_MEMBER(dsoff2_r) { return m_dsoff2; } + DECLARE_READ32_MEMBER(dsoff2_r) const { return m_dsoff2; } DECLARE_WRITE32_MEMBER(dsoff2_w) { m_dsoff2 = data; } - DECLARE_READ32_MEMBER(dstc2_r) { return m_dstc2; } + DECLARE_READ32_MEMBER(dstc2_r) const { return m_dstc2; } DECLARE_WRITE32_MEMBER(dstc2_w) { m_dstc2 = data; } - DECLARE_READ32_MEMBER(ddrd2_r) { return m_ddrd2; } + DECLARE_READ32_MEMBER(ddrd2_r) const { return m_ddrd2; } DECLARE_WRITE32_MEMBER(ddrd2_w) { m_ddrd2 = data; } - DECLARE_READ32_MEMBER(dsrd2_r) { return m_dsrd2; } + DECLARE_READ32_MEMBER(dsrd2_r) const { return m_dsrd2; } DECLARE_WRITE32_MEMBER(dsrd2_w) { m_dsrd2 = data; } - DECLARE_READ32_MEMBER(dcksum0_r) { return m_dcksum0; } + DECLARE_READ32_MEMBER(dcksum0_r) const { return m_dcksum0; } DECLARE_WRITE32_MEMBER(dcksum0_w) { m_dcksum0 = data; } - DECLARE_READ32_MEMBER(dcksum1_r) { return m_dcksum1; } + DECLARE_READ32_MEMBER(dcksum1_r) const { return m_dcksum1; } DECLARE_WRITE32_MEMBER(dcksum1_w) { m_dcksum1 = data; } protected: diff --git a/src/mame/machine/interpro_srarb.cpp b/src/mame/machine/interpro_srarb.cpp deleted file mode 100644 index d3074ea2847..00000000000 --- a/src/mame/machine/interpro_srarb.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Patrick Mackinlay - -/* -* An implementation of the SRX Abiter Gate Array device found on Intergraph InterPro family workstations. There is no -* public documentation on this device, so the implementation is being built to follow the logic of the -* system boot ROM and its diagnostic tests. -* -* Please be aware that code in here is not only broken, it's likely wrong in many cases. -* -* TODO -* - too long to list -*/ -#include "emu.h" -#include "interpro_srarb.h" - -#define VERBOSE 0 - -DEVICE_ADDRESS_MAP_START(map, 32, interpro_srarb_device) - AM_RANGE(0x00, 0x03) AM_READWRITE(sdepid_r, sdepid_w) - AM_RANGE(0x04, 0x07) AM_READWRITE(snapid_r, snapid_w) - AM_RANGE(0x08, 0x0b) AM_READWRITE(prilo_r, prilo_w) - AM_RANGE(0x0c, 0x0f) AM_READWRITE(prihi_r, prihi_w) - AM_RANGE(0x10, 0x13) AM_READWRITE(errdomlo_r, errdomlo_w) - AM_RANGE(0x14, 0x17) AM_READWRITE(errdomhi_r, errdomhi_w) - AM_RANGE(0x18, 0x1b) AM_READWRITE(tmctrl_r, tmctrl_w) - - AM_RANGE(0x1c, 0x1f) AM_READWRITE8(unknown0_r, unknown0_w, 0x0000ff00) // boot code writes 0x10 - AM_RANGE(0x20, 0x23) AM_READWRITE8(unknown1_r, unknown1_w, 0x0000ff00) // boot code writes 0x07 - - AM_RANGE(0x24, 0x27) AM_READWRITE(tmsrnem_r, tmsrnem_w) - AM_RANGE(0x28, 0x2b) AM_READWRITE(tmsrhog_r, tmsrhog_w) - AM_RANGE(0x2c, 0x2f) AM_READWRITE(tmscale_r, tmscale_w) -ADDRESS_MAP_END - -DEFINE_DEVICE_TYPE(INTERPRO_SRARB, interpro_srarb_device, "srarb", "InterPro SRARB") - -interpro_srarb_device::interpro_srarb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, INTERPRO_SRARB, tag, owner, clock) -{ -} - -void interpro_srarb_device::device_start() -{ -} - -void interpro_srarb_device::device_reset() -{ -} diff --git a/src/mame/machine/interpro_srarb.h b/src/mame/machine/interpro_srarb.h deleted file mode 100644 index d9adccddf20..00000000000 --- a/src/mame/machine/interpro_srarb.h +++ /dev/null @@ -1,72 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Patrick Mackinlay - -#ifndef MAME_MACHINE_INTERPRO_SRARB_H -#define MAME_MACHINE_INTERPRO_SRARB_H - -#pragma once - -class interpro_srarb_device : public device_t -{ -public: - interpro_srarb_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - virtual DECLARE_ADDRESS_MAP(map, 32); - - DECLARE_READ32_MEMBER(sdepid_r) { return sdepid; } - DECLARE_WRITE32_MEMBER(sdepid_w) { sdepid = data; } - - enum snapid_mask - { - SNAPID_GRANT = 0x0000000f, - SNAPID_HOGLOCK = 0x000000f0 - }; - DECLARE_READ32_MEMBER(snapid_r) { return snapid; } - DECLARE_WRITE32_MEMBER(snapid_w) { snapid = data; } - DECLARE_READ32_MEMBER(prilo_r) { return prilo; } - DECLARE_WRITE32_MEMBER(prilo_w) { prilo = data; } - DECLARE_READ32_MEMBER(prihi_r) { return prihi; } - DECLARE_WRITE32_MEMBER(prihi_w) { prihi = data; } - - DECLARE_READ32_MEMBER(errdomlo_r) { return errdomlo; } - DECLARE_WRITE32_MEMBER(errdomlo_w) { errdomlo = data; } - DECLARE_READ32_MEMBER(errdomhi_r) { return errdomhi; } - DECLARE_WRITE32_MEMBER(errdomhi_w) { errdomhi = data; } - - enum tmctrl_mask - { - TMCTRL_UNUSED = 0x00000007, - TMCTRL_ENNEM = 0x00000008, - TMCTRL_ENHOG = 0x00000010 - }; - DECLARE_READ32_MEMBER(tmctrl_r) { return tmctrl; } - DECLARE_WRITE32_MEMBER(tmctrl_w) { tmctrl = data; } - - DECLARE_READ8_MEMBER(unknown0_r) { return unknown0; } - DECLARE_WRITE8_MEMBER(unknown0_w) { unknown0 = data; } - DECLARE_READ8_MEMBER(unknown1_r) { return unknown1; } - DECLARE_WRITE8_MEMBER(unknown1_w) { unknown1 = data; } - - DECLARE_READ32_MEMBER(tmsrnem_r) { return tmsrnem; } - DECLARE_WRITE32_MEMBER(tmsrnem_w) { tmsrnem = data; } - DECLARE_READ32_MEMBER(tmsrhog_r) { return tmsrhog; } - DECLARE_WRITE32_MEMBER(tmsrhog_w) { tmsrhog = data; } - DECLARE_READ32_MEMBER(tmscale_r) { return tmscale; } - DECLARE_WRITE32_MEMBER(tmscale_w) { tmscale = data; } - -protected: - virtual void device_start() override; - virtual void device_reset() override; - -private: - u32 sdepid, snapid, prilo, prihi; - u32 errdomlo, errdomhi; - u32 tmctrl, tmsrnem, tmsrhog, tmscale; - - u8 unknown0, unknown1; -}; - -// device type definition -extern const device_type INTERPRO_SRARB; - -#endif // MAME_MACHINE_INTERPRO_SRARB_H diff --git a/src/mame/mame.lst b/src/mame/mame.lst index e9100ad0f4c..c09a67ad4ba 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -15204,7 +15204,11 @@ hector1 // interact // @source:interpro.cpp -ip2800 // Intergraph InterPro 28xx workstation +ip2000 // Intergraph InterPro/InterServe 20x0 +ip2400 // Intergraph InterPro/InterServe 24x0 +ip2500 // Intergraph InterPro/InterServe 25x0 +ip2700 // Intergraph InterPro/InterServe 27x0 +ip2800 // Intergraph InterPro/InterServe 28x0 @source:intrscti.cpp intrscti // ???? -- cgit v1.2.3