From 2b166ee1f68e3219c5842060aed97e630f86ca53 Mon Sep 17 00:00:00 2001 From: Patrick Mackinlay Date: Tue, 23 May 2017 19:57:22 +0700 Subject: [PATCH] interpro improvements, plus some naive scsi hacks (#2330) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Various InterPro changes: * fixed cpu/mmu ssw bug * added preliminary nscsi support * added preliminary mmu address translation * expanded memory maps for several devices * improved irq and dma handling (still not working properly) * stubbed out more sga registers, added srarb For the following, I don't really know what I'm doing, so please check carefully: * WARNING: includes a naïve addition of ncr53c94 support to ncr5390.cpp * WARNING: adds a start/stop unit command to t10spc.cpp After these changes, ip2800 boots to FDM prompt with a ton of memdiag test failures, but not much else is visibly improved. --- src/devices/cpu/clipper/clipper.cpp | 4 +- src/devices/cpu/clipper/clipper.h | 4 +- src/devices/machine/ncr5390.cpp | 72 +++- src/devices/machine/ncr5390.h | 35 +- src/devices/machine/t10spc.cpp | 6 + src/mame/drivers/interpro.cpp | 191 ++++++++--- src/mame/includes/interpro.h | 46 ++- src/mame/machine/cammu.cpp | 328 ++++++++++++++++--- src/mame/machine/cammu.h | 199 ++++++++++-- src/mame/machine/interpro_ioga.cpp | 488 +++++++++++++++++----------- src/mame/machine/interpro_ioga.h | 97 +++--- src/mame/machine/interpro_mcga.cpp | 95 +++--- src/mame/machine/interpro_mcga.h | 67 +++- src/mame/machine/interpro_sga.cpp | 74 +++-- src/mame/machine/interpro_sga.h | 133 ++++++-- src/mame/machine/interpro_srarb.cpp | 46 +++ src/mame/machine/interpro_srarb.h | 52 +++ 17 files changed, 1484 insertions(+), 453 deletions(-) create mode 100644 src/mame/machine/interpro_srarb.cpp create mode 100644 src/mame/machine/interpro_srarb.h diff --git a/src/devices/cpu/clipper/clipper.cpp b/src/devices/cpu/clipper/clipper.cpp index ffdc3177bfd..69f00ba1f15 100644 --- a/src/devices/cpu/clipper/clipper.cpp +++ b/src/devices/cpu/clipper/clipper.cpp @@ -1269,7 +1269,7 @@ int clipper_device::execute_instruction () case 0x04: // reti: restore psw, ssw and pc from supervisor stack LOG_INTERRUPT("reti r%d, ssp = %08x, pc = %08x, next_pc = %08x\n", - (m_info.macro >> 4) & 0xf, m_rs[(m_info.macro >> 4) & 0xf], m_pc, m_insn->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 8)); + (m_info.macro >> 4) & 0xf, m_rs[(m_info.macro >> 4) & 0xf], m_pc, m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 8)); m_psw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 0); m_ssw = m_data->read_dword(m_rs[(m_info.macro >> 4) & 0xf] + 4); @@ -1327,7 +1327,7 @@ int clipper_device::execute_instruction () */ u32 clipper_device::intrap(u32 vector, u32 pc, u32 cts, u32 mts) { - LOG_INTERRUPT("intrap - vector %x, pc = 0x%08x, next_pc = 0x%08x, ssp = 0x%08x\n", vector, pc, m_insn->read_dword(vector + 4), m_rs[15]); + LOG_INTERRUPT("intrap - vector %x, pc = 0x%08x, next_pc = 0x%08x, ssp = 0x%08x\n", vector, pc, m_data->read_dword(vector + 4), m_rs[15]); // set cts and mts to indicate source of exception m_psw = (m_psw & ~(PSW_CTS | PSW_MTS)) | mts | cts; diff --git a/src/devices/cpu/clipper/clipper.h b/src/devices/cpu/clipper/clipper.h index 49857a0a689..a00b8d5ce1c 100644 --- a/src/devices/cpu/clipper/clipper.h +++ b/src/devices/cpu/clipper/clipper.h @@ -1,5 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Patrick Mackinlay + #ifndef MAME_CPU_CLIPPER_CLIPPER_H #define MAME_CPU_CLIPPER_CLIPPER_H @@ -7,7 +8,6 @@ #include - class clipper_device : public cpu_device { enum registers @@ -164,7 +164,7 @@ class clipper_device : public cpu_device }; public: - DECLARE_READ_LINE_MEMBER(ssw) { return m_ssw; } + DECLARE_READ32_MEMBER(ssw) { return m_ssw; } protected: clipper_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock); diff --git a/src/devices/machine/ncr5390.cpp b/src/devices/machine/ncr5390.cpp index 729e486856d..c140c2bd8b9 100644 --- a/src/devices/machine/ncr5390.cpp +++ b/src/devices/machine/ncr5390.cpp @@ -7,6 +7,7 @@ #define DELAY_HACK DEFINE_DEVICE_TYPE(NCR5390, ncr5390_device, "ncr5390", "NCR 5390 SCSI") +DEFINE_DEVICE_TYPE(NCR53C94, ncr53c94_device, "ncr53c94", "NCR 53C94 SCSI") DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) AM_RANGE(0x0, 0x0) AM_READWRITE(tcount_lo_r, tcount_lo_w) @@ -21,8 +22,25 @@ DEVICE_ADDRESS_MAP_START(map, 8, ncr5390_device) AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) ADDRESS_MAP_END -ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : nscsi_device(mconfig, NCR5390, tag, owner, clock) +DEVICE_ADDRESS_MAP_START(map, 8, ncr53c94_device) + AM_RANGE(0x0, 0x0) AM_READWRITE(tcount_lo_r, tcount_lo_w) + AM_RANGE(0x1, 0x1) AM_READWRITE(tcount_hi_r, tcount_hi_w) + AM_RANGE(0x2, 0x2) AM_READWRITE(fifo_r, fifo_w) + AM_RANGE(0x3, 0x3) AM_READWRITE(command_r, command_w) + AM_RANGE(0x4, 0x4) AM_READWRITE(status_r, bus_id_w) + AM_RANGE(0x5, 0x5) AM_READWRITE(istatus_r, timeout_w) + AM_RANGE(0x6, 0x6) AM_READWRITE(seq_step_r, sync_period_w) + AM_RANGE(0x7, 0x7) AM_READWRITE(fifo_flags_r, sync_offset_w) + AM_RANGE(0x8, 0x8) AM_READWRITE(conf_r, conf_w) + AM_RANGE(0x9, 0x9) AM_WRITE(clock_w) + AM_RANGE(0xa, 0xa) AM_WRITE(test_w) + AM_RANGE(0xb, 0xb) AM_READWRITE(conf2_r, conf2_w) + AM_RANGE(0xc, 0xc) AM_READWRITE(conf3_r, conf3_w) + AM_RANGE(0xf, 0xf) AM_WRITE(fifo_align_w) +ADDRESS_MAP_END + +ncr5390_device::ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : nscsi_device(mconfig, type, tag, owner, clock) , tm(nullptr), config(0), status(0), istatus(0), clock_conv(0), sync_offset(0), sync_period(0), bus_id(0) , select_timeout(0), seq(0), tcount(0), mode(0), fifo_pos(0), command_pos(0), state(0), xfr_phase(0), command_length(0), dma_dir(0), irq(false), drq(false) , m_irq_handler(*this) @@ -30,6 +48,19 @@ ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, d { } +ncr5390_device::ncr5390_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ncr5390_device(mconfig, NCR5390, tag, owner, clock) +{ +} + +ncr53c94_device::ncr53c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : ncr5390_device(mconfig, NCR53C94, tag, owner, clock) + , test_mode(false) + , config2(0) + , config3(0) +{ +} + void ncr5390_device::device_start() { nscsi_device::device_start(); @@ -866,3 +897,40 @@ void ncr5390_device::drq_clear() m_drq_handler(drq); } } + +void ncr53c94_device::device_start() +{ + save_item(NAME(test_mode)); + save_item(NAME(config2)); + save_item(NAME(config3)); + + test_mode = false; + config2 = 0; + config3 = 0; + + ncr5390_device::device_start(); +} + +void ncr53c94_device::reset_soft() +{ + test_mode = false; + config2 = 0; + config3 = 0; + + ncr5390_device::reset_soft(); +} + +WRITE8_MEMBER(ncr53c94_device::conf_w) +{ + ncr5390_device::conf_w(space, offset, data, mem_mask); + + // test mode can only be cleared by hard/soft reset + if (data & 0x8) + test_mode = true; +} + +WRITE8_MEMBER(ncr53c94_device::test_w) +{ + if (test_mode) + logerror("%s: test_w %d (%08x) - test mode not implemented\n", tag(), data, space.device().safe_pc()); +} diff --git a/src/devices/machine/ncr5390.h b/src/devices/machine/ncr5390.h index 018f9fb5098..0f62fe69c5e 100644 --- a/src/devices/machine/ncr5390.h +++ b/src/devices/machine/ncr5390.h @@ -22,7 +22,7 @@ public: template static devcb_base &set_irq_handler(device_t &device, Object &&cb) { return downcast(device).m_irq_handler.set_callback(std::forward(cb)); } template static devcb_base &set_drq_handler(device_t &device, Object &&cb) { return downcast(device).m_drq_handler.set_callback(std::forward(cb)); } - DECLARE_ADDRESS_MAP(map, 8); + virtual DECLARE_ADDRESS_MAP(map, 8); DECLARE_READ8_MEMBER(tcount_lo_r); DECLARE_WRITE8_MEMBER(tcount_lo_w); @@ -50,6 +50,8 @@ public: void dma_w(uint8_t val); protected: + ncr5390_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + 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; @@ -214,7 +216,10 @@ private: void command_pop_and_chain(); void check_irq(); +protected: void reset_soft(); + +private: void reset_disconnect(); uint8_t fifo_pop(); @@ -229,6 +234,34 @@ private: devcb_write_line m_drq_handler; }; +class ncr53c94_device : public ncr5390_device +{ +public: + ncr53c94_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_ADDRESS_MAP(map, 8) override; + + DECLARE_WRITE8_MEMBER(conf_w); + + DECLARE_WRITE8_MEMBER(test_w); + DECLARE_READ8_MEMBER(conf2_r) { return config2; }; + DECLARE_WRITE8_MEMBER(conf2_w) { config2 = data; }; + DECLARE_READ8_MEMBER(conf3_r) { return config3; }; + DECLARE_WRITE8_MEMBER(conf3_w) { config3 = data; }; + DECLARE_WRITE8_MEMBER(fifo_align_w) { fifo_align = data; }; + +protected: + virtual void device_start() override; + void reset_soft(); + +private: + bool test_mode; + u8 config2; + u8 config3; + u8 fifo_align; +}; + DECLARE_DEVICE_TYPE(NCR5390, ncr5390_device) +DECLARE_DEVICE_TYPE(NCR53C94, ncr53c94_device) #endif // MAME_MACHINE_NCR5390_H diff --git a/src/devices/machine/t10spc.cpp b/src/devices/machine/t10spc.cpp index d77560c6965..ecea2802511 100644 --- a/src/devices/machine/t10spc.cpp +++ b/src/devices/machine/t10spc.cpp @@ -67,6 +67,12 @@ void t10spc::ExecCommand() } break; + case T10SPC_CMD_START_STOP_UNIT: + m_phase = SCSI_PHASE_STATUS; + m_status_code = SCSI_STATUS_CODE_GOOD; + m_transfer_length = 0; + break; + case T10SPC_CMD_SEND_DIAGNOSTIC: m_phase = SCSI_PHASE_DATAOUT; m_status_code = SCSI_STATUS_CODE_GOOD; diff --git a/src/mame/drivers/interpro.cpp b/src/mame/drivers/interpro.cpp index 47e8f41c1fd..295e49af7ff 100644 --- a/src/mame/drivers/interpro.cpp +++ b/src/mame/drivers/interpro.cpp @@ -2,6 +2,9 @@ // copyright-holders:Patrick Mackinlay #include "emu.h" + +#define NEW_SCSI 0 + #include "includes/interpro.h" #include "debugger.h" @@ -33,14 +36,14 @@ WRITE16_MEMBER(interpro_state::system_w) switch (offset) { case SREG_LED: - LOG_SYSTEM("LED value %d at pc 0x%08x\n", data, space.device().safe_pc()); + LOG_SYSTEM("LED value %d at %s\n", data, machine().describe_context()); break; case SREG_STATUS: // not sure if writable? break; case SREG_CTRL1: - LOG_SYSTEM("system control register 1 write data 0x%x pc 0x%08x\n", data, space.device().safe_pc()); + LOG_SYSTEM("system control register 1 write data 0x%x pc %s\n", data, machine().describe_context()); if ((data ^ m_system_reg[offset]) & CTRL1_LEDDP) LOG_SYSTEM("LED decimal point %s\n", data & CTRL1_LEDDP ? "on" : "off"); @@ -49,7 +52,7 @@ WRITE16_MEMBER(interpro_state::system_w) break; case SREG_CTRL2: - LOG_SYSTEM("system control register 2 write data 0x%x pc 0x%08x\n", data, space.device().safe_pc()); + LOG_SYSTEM("system control register 2 write data 0x%x at %s\n", data, machine().describe_context()); if (data & CTRL2_RESET) { m_system_reg[SREG_CTRL2] &= ~CTRL2_COLDSTART; @@ -64,7 +67,7 @@ WRITE16_MEMBER(interpro_state::system_w) READ16_MEMBER(interpro_state::system_r) { - LOG_SYSTEM("system register read offset %d pc 0x%08x\n", offset, space.device().safe_pc()); + LOG_SYSTEM("system register read offset %d at %s\n", offset, machine().describe_context()); switch (offset) { case SREG_ERROR: @@ -79,10 +82,10 @@ READ16_MEMBER(interpro_state::system_r) READ32_MEMBER(interpro_state::idprom_r) { - LOG_IDPROM("idprom read offset 0x%x mask 0x%08x at 0x%08x\n", offset, mem_mask, space.device().safe_pc()); + LOG_IDPROM("idprom read offset 0x%x mask 0x%08x at %s\n", offset, mem_mask, machine().describe_context()); // abitrary fake number for now, not working properly - u32 speed = 70000000; + u32 speed = 20000000; u32 speed1 = speed >> 24; u32 speed2 = speed >> 16; u32 speed3 = speed >> 8; @@ -90,7 +93,7 @@ READ32_MEMBER(interpro_state::idprom_r) static uint8_t idprom[] = { // module type id 'M', 'P', 'C', 'B', - '*', '*', '*', '*', + '0', '1', '4', '5', // ECO bytes 0x87, 0x65, 0x43, 0x21, @@ -101,7 +104,7 @@ READ32_MEMBER(interpro_state::idprom_r) // if they're empty, a default value of 50 000 000 is used // perhaps this is a system speed (50MHz)? 0x2, 0x34, 0x56, 0x78, - (u8)speed1, (u8)speed2, (u8)speed3, (u8)speed, + (u8)speed, (u8)speed3, (u8)speed2, (u8)speed1, // reserved bytes 0xff, 0xff, @@ -110,8 +113,8 @@ READ32_MEMBER(interpro_state::idprom_r) // 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 - //0x41, 0x00, // 2800-series CPU - 0x24, 0x00, // 2000-series system board + 0x41, 0x00, // 2800-series CPU + //0x24, 0x00, // 2000-series system board // footprint and checksum 0x55, 0xaa, 0x55, 0x00 @@ -165,7 +168,7 @@ WRITE8_MEMBER(interpro_state::rtc_w) break; default: - logerror("rtc: write to unknown offset 0x%02x data 0x%02x at pc 0x%08x\n", offset, data, space.device().safe_pc()); + logerror("rtc: write to unknown offset 0x%02x data 0x%02x at %s\n", offset, data, machine().describe_context()); break; } } @@ -184,54 +187,148 @@ READ8_MEMBER(interpro_state::rtc_r) case 0x42: return 0x56; default: - logerror("rtc: read from unknown offset 0x%02x at pc 0x%08x\n", offset, space.device().safe_pc()); + 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) { +#if NEW_SCSI + switch (offset >> 6) + { + case 0x0: return m_scsi->tcount_lo_r(space, 0); + case 0x1: return m_scsi->tcount_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("read unmapped scsi adapter register 0x%x\n", offset >> 6); + return 0x00; +#else return m_scsi->read(space, offset >> 6, mem_mask); +#endif } WRITE8_MEMBER(interpro_state::scsi_w) { +#if NEW_SCSI + 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("unmapped scsi register write 0x%02x data 0x%02x\n", offset >> 6, data); +#else m_scsi->write(space, offset >> 6, data, mem_mask); +#endif +} + +READ8_MEMBER(interpro_state::scsi_dma_r) +{ +#if NEW_SCSI + return m_scsi->dma_r(); +#else + u8 data = 0; + + m_scsi->dma_read_data(1, &data); + + return data; +#endif +} + +WRITE8_MEMBER(interpro_state::scsi_dma_w) +{ +#if NEW_SCSI + m_scsi->dma_w(data); +#else + m_scsi->dma_write_data(1, &data); +#endif } -// driver init DRIVER_INIT_MEMBER(interpro_state, ip2800) { - //address_space &as = m_mmu->space(AS_1); } +#if NEW_SCSI +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_FRAGMENT(interpro_scsi_adapter) + MCFG_DEVICE_CLOCK(XTAL_12_5MHz) + 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 +#endif + // these maps point 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, mmu_r, 0xffffffff) + AM_RANGE(0x00000000, 0xffffffff) AM_DEVREAD32(INTERPRO_MMU_TAG, cammu_device, insn_r, 0xffffffff) ADDRESS_MAP_END static ADDRESS_MAP_START(clipper_data_map, AS_DATA, 32, interpro_state) -AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE32(INTERPRO_MMU_TAG, cammu_device, mmu_r, mmu_w, 0xffffffff) + AM_RANGE(0x00000000, 0xffffffff) AM_DEVREADWRITE32(INTERPRO_MMU_TAG, cammu_device, data_r, data_w, 0xffffffff) ADDRESS_MAP_END // these maps represent the real main, i/o and boot spaces of the system static ADDRESS_MAP_START(interpro_main_map, AS_0, 32, interpro_state) AM_RANGE(0x00000000, 0x00ffffff) AM_RAM // 16M RAM - - AM_RANGE(0x7f100000, 0x7f11ffff) AM_ROM AM_REGION(INTERPRO_ROM_TAG, 0) - AM_RANGE(0x7f180000, 0x7f1bffff) AM_ROM AM_REGION(INTERPRO_EEPROM_TAG, 0) -ADDRESS_MAP_END - -static ADDRESS_MAP_START(interpro_io_map, AS_1, 32, interpro_state) - AM_RANGE(0x00000000, 0x00000fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map) - AM_RANGE(0x00001000, 0x00001fff) AM_RAM - - AM_RANGE(0x40000000, 0x4000003f) AM_DEVICE16(INTERPRO_MCGA_TAG, interpro_mcga_device, map, 0xffff) + + AM_RANGE(0x40000000, 0x4000003f) AM_DEVICE(INTERPRO_MCGA_TAG, interpro_fmcc_device, map) AM_RANGE(0x4f007e00, 0x4f007eff) AM_DEVICE(INTERPRO_SGA_TAG, interpro_sga_device, map) AM_RANGE(0x7f000100, 0x7f00011f) AM_DEVICE8(INTERPRO_FDC_TAG, n82077aa_device, map, 0xff) - // this is probably the srx arbiter ga - AM_RANGE(0x7f000200, 0x7f0002ff) AM_RAM + AM_RANGE(0x7f000200, 0x7f0002ff) AM_DEVICE(INTERPRO_SRARB_TAG, interpro_srarb_device, map) + AM_RANGE(0x7f000300, 0x7f00030f) AM_READWRITE16(system_r, system_w, 0xffff) + AM_RANGE(0x7f000400, 0x7f00040f) AM_DEVREADWRITE8(INTERPRO_SCC1_TAG, scc85c30_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) + AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, scc85230_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) + AM_RANGE(0x7f000500, 0x7f0006ff) AM_READWRITE8(rtc_r, rtc_w, 0xff) + AM_RANGE(0x7f000700, 0x7f00077f) AM_READ(idprom_r) + AM_RANGE(0x7f001000, 0x7f001fff) AM_READWRITE8(scsi_r, scsi_w, 0x0000ff00) + + AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map) + + AM_RANGE(0x7f100000, 0x7f11ffff) AM_ROM AM_REGION(INTERPRO_EPROM_TAG, 0) + AM_RANGE(0x7f180000, 0x7f1bffff) AM_ROM AM_REGION(INTERPRO_FLASH_TAG, 0) + + AM_RANGE(0x08000000, 0x08000fff) AM_NOP // bogus + AM_RANGE(0x8f000000, 0x8f0fffff) AM_NOP // AM_READ(slot0_r) +ADDRESS_MAP_END + +static ADDRESS_MAP_START(interpro_io_map, AS_1, 32, interpro_state) + AM_RANGE(0x00000000, 0x00001fff) AM_DEVICE(INTERPRO_MMU_TAG, cammu_device, map) + + 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) + + 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(0x7f000300, 0x7f00030f) AM_READWRITE16(system_r, system_w, 0xffff) AM_RANGE(0x7f000400, 0x7f00040f) AM_DEVREADWRITE8(INTERPRO_SCC1_TAG, scc85c30_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) AM_RANGE(0x7f000410, 0x7f00041f) AM_DEVREADWRITE8(INTERPRO_SCC2_TAG, scc85230_device, ba_cd_inv_r, ba_cd_inv_w, 0xff) @@ -242,7 +339,7 @@ static ADDRESS_MAP_START(interpro_io_map, AS_1, 32, interpro_state) AM_RANGE(0x7f0fff00, 0x7f0fffff) AM_DEVICE(INTERPRO_IOGA_TAG, interpro_ioga_device, map) AM_RANGE(0x08000000, 0x08000fff) AM_NOP // bogus - AM_RANGE(0x8f000000, 0x8f0fffff) AM_READ(slot0_r) + AM_RANGE(0x8f000000, 0x8f0fffff) AM_NOP // AM_READ(slot0_r) ADDRESS_MAP_END static ADDRESS_MAP_START(interpro_boot_map, AS_2, 32, interpro_state) @@ -272,7 +369,7 @@ static MACHINE_CONFIG_START(ip2800) MCFG_DEVICE_ADDRESS_MAP(AS_0, interpro_main_map) MCFG_DEVICE_ADDRESS_MAP(AS_1, interpro_io_map) MCFG_DEVICE_ADDRESS_MAP(AS_2, interpro_boot_map) - MCFG_CAMMU_SSW_CB(DEVREADLINE(INTERPRO_CPU_TAG, clipper_device, ssw)) + MCFG_CAMMU_SSW_CB(DEVREAD32(INTERPRO_CPU_TAG, clipper_device, ssw)) // serial controllers and rs232 bus MCFG_SCC85C30_ADD(INTERPRO_SCC1_TAG, XTAL_4_9152MHz, 0, 0, 0, 0) @@ -308,6 +405,18 @@ static MACHINE_CONFIG_START(ip2800) MCFG_FLOPPY_DRIVE_SOUND(false) // scsi +#if NEW_SCSI + MCFG_NSCSI_BUS_ADD(INTERPRO_SCSI_TAG) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":0", interpro_scsi_devices, "harddisk", false) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":1", interpro_scsi_devices, "cdrom", false) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":2", interpro_scsi_devices, nullptr, false) + MCFG_NSCSI_ADD(INTERPRO_SCSI_TAG ":3", interpro_scsi_devices, nullptr, false) + 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) + MCFG_DEVICE_CARD_MACHINE_CONFIG(INTERPRO_SCSI_ADAPTER_TAG, interpro_scsi_adapter) +#else MCFG_DEVICE_ADD(INTERPRO_SCSI_TAG, SCSI_PORT, 0) MCFG_SCSIDEV_ADD(INTERPRO_SCSI_TAG ":" SCSI_PORT_DEVICE1, "harddisk", SCSIHD, SCSI_ID_0) MCFG_SCSIDEV_ADD(INTERPRO_SCSI_TAG ":" SCSI_PORT_DEVICE2, "cdrom", SCSICD, SCSI_ID_3) @@ -316,34 +425,42 @@ static MACHINE_CONFIG_START(ip2800) MCFG_LEGACY_SCSI_PORT(INTERPRO_SCSI_TAG) MCFG_NCR539X_OUT_IRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, ir0_w)) MCFG_NCR539X_OUT_DRQ_CB(DEVWRITELINE(INTERPRO_IOGA_TAG, interpro_ioga_device, drq_scsi)) +#endif // 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_TAG, ncr539x_device, dma_read_data), DEVWRITE8(INTERPRO_SCSI_TAG, ncr539x_device, dma_write_data)) + + // use driver helper functions to wrap scsi adapter dma read/write + MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_SCSI, DEVREAD8("", interpro_state, scsi_dma_r), DEVWRITE8("", interpro_state, scsi_dma_w)) + MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_FLOPPY, DEVREAD8(INTERPRO_FDC_TAG, n82077aa_device, mdma_r), DEVWRITE8(INTERPRO_FDC_TAG, n82077aa_device, mdma_w)) MCFG_INTERPRO_IOGA_DMA_CB(IOGA_DMA_SERIAL, DEVREAD8(INTERPRO_SCC1_TAG, z80scc_device, da_r), DEVWRITE8(INTERPRO_SCC1_TAG, z80scc_device, da_w)) MCFG_INTERPRO_IOGA_FDCTC_CB(DEVWRITELINE(INTERPRO_FDC_TAG, n82077aa_device, tc_line_w)) MCFG_INTERPRO_IOGA_DMA_BUS(INTERPRO_CAMMU_TAG, AS_0) // memory control gate array - MCFG_DEVICE_ADD(INTERPRO_MCGA_TAG, INTERPRO_MCGA, 0) + 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)) + + // srx arbiter gate array + MCFG_DEVICE_ADD(INTERPRO_SRARB_TAG, INTERPRO_SRARB, 0) MACHINE_CONFIG_END ROM_START(ip2800) - ROM_REGION(0x0020000, INTERPRO_ROM_TAG, 0) + ROM_REGION(0x0020000, INTERPRO_EPROM_TAG, 0) ROM_SYSTEM_BIOS(0, "IP2830", "IP2830") - ROMX_LOAD("ip2830_rom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) + ROMX_LOAD("ip2830_eprom.bin", 0x00000, 0x20000, CRC(467ce7bd) SHA1(53faee40d5df311f53b24c930e434cbf94a5c4aa), ROM_BIOS(1)) - ROM_REGION(0x0040000, INTERPRO_EEPROM_TAG, 0) - ROM_LOAD_OPTIONAL("ip2830_eeprom.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) + ROM_REGION(0x0040000, INTERPRO_FLASH_TAG, 0) + ROM_LOAD_OPTIONAL("ip2830_flash.bin", 0x00000, 0x40000, CRC(a0c0899f) SHA1(dda6fbca81f9885a1a76ca3c25e80463a83a0ef7)) ROM_END /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */ -COMP( 1990, ip2800, 0, 0, ip2800, ip2800, interpro_state, ip2800, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) +COMP( 1993, ip2800, 0, 0, ip2800, ip2800, interpro_state, ip2800, "Intergraph", "InterPro 2800", MACHINE_NOT_WORKING | MACHINE_NO_SOUND) diff --git a/src/mame/includes/interpro.h b/src/mame/includes/interpro.h index 927d626f5a0..d2a45e24225 100644 --- a/src/mame/includes/interpro.h +++ b/src/mame/includes/interpro.h @@ -1,27 +1,35 @@ // license:BSD-3-Clause // copyright-holders:Patrick Mackinlay +#ifndef MAME_INCLUDES_INTERPRO_H +#define MAME_INCLUDES_INTERPRO_H + #pragma once -#ifndef INTERPRO_H_ -#define INTERPRO_H_ - - #include "cpu/clipper/clipper.h" #include "machine/cammu.h" #include "machine/interpro_ioga.h" #include "machine/interpro_mcga.h" #include "machine/interpro_sga.h" +#include "machine/interpro_srarb.h" #include "machine/z80scc.h" #include "machine/mc146818.h" #include "machine/upd765.h" +#if NEW_SCSI +#include "machine/ncr5390.h" + +#include "machine/nscsi_bus.h" +#include "machine/nscsi_cd.h" +#include "machine/nscsi_hd.h" +#else #include "machine/ncr539x.h" #include "bus/scsi/scsi.h" #include "bus/scsi/scsicd.h" #include "bus/scsi/scsihd.h" +#endif #include "bus/rs232/rs232.h" #include "formats/pc_dsk.h" @@ -32,15 +40,17 @@ #define INTERPRO_RTC_TAG "rtc" #define INTERPRO_SCC1_TAG "scc1" #define INTERPRO_SCC2_TAG "scc2" -#define INTERPRO_ROM_TAG "rom" -#define INTERPRO_EEPROM_TAG "eeprom" +#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_IOGA_TAG "ioga" #define INTERPRO_MCGA_TAG "mcga" #define INTERPRO_SGA_TAG "sga" -#define INTERPRO_SCSI_ADAPTER_TAG "adapter" +#define INTERPRO_SRARB_TAG "srarb" // system board register offsets #define SREG_LED 0 @@ -83,10 +93,16 @@ public: m_scc2(*this, INTERPRO_SCC2_TAG), m_rtc(*this, INTERPRO_RTC_TAG), m_fdc(*this, INTERPRO_FDC_TAG), +#if NEW_SCSI + m_scsibus(*this, INTERPRO_SCSI_TAG), + m_scsi(*this, INTERPRO_SCSI_TAG ":7:" INTERPRO_SCSI_ADAPTER_TAG), +#else m_scsi(*this, INTERPRO_SCSI_ADAPTER_TAG), +#endif m_ioga(*this, INTERPRO_IOGA_TAG), m_mcga(*this, INTERPRO_MCGA_TAG), - m_sga(*this, INTERPRO_SGA_TAG) + m_sga(*this, INTERPRO_SGA_TAG), + m_srarb(*this, INTERPRO_SRARB_TAG) { } required_device m_maincpu; @@ -97,11 +113,17 @@ public: required_device m_scc2; required_device m_rtc; required_device m_fdc; +#if NEW_SCSI + required_device m_scsibus; + required_device m_scsi; +#else required_device m_scsi; +#endif required_device m_ioga; - required_device m_mcga; + required_device m_mcga; required_device m_sga; + required_device m_srarb; DECLARE_DRIVER_INIT(ip2800); @@ -116,6 +138,8 @@ public: DECLARE_READ8_MEMBER(scsi_r); DECLARE_WRITE8_MEMBER(scsi_w); + DECLARE_READ8_MEMBER(scsi_dma_r); + DECLARE_WRITE8_MEMBER(scsi_dma_w); DECLARE_FLOPPY_FORMATS(floppy_formats); @@ -124,7 +148,7 @@ protected: virtual void machine_reset() override; private: - uint16_t m_system_reg[4]; + u16 m_system_reg[4]; }; -#endif +#endif // MAME_INCLUDES_INTERPRO_H diff --git a/src/mame/machine/cammu.cpp b/src/mame/machine/cammu.cpp index 262b6b5ad45..f62bfa167be 100644 --- a/src/mame/machine/cammu.cpp +++ b/src/mame/machine/cammu.cpp @@ -11,9 +11,7 @@ * * TODO * - almost everything - * - map registers * - refactor hardware tlb - * - address translation * - faults * - tlb * - cache @@ -21,22 +19,84 @@ */ #include "emu.h" -#include "cammu.h" #define VERBOSE 0 +#define DTU 1 // enable preliminary/incomplete address translation + +#include "cammu.h" // each variant of the cammu has different registers and a different addressing map -// TODO: decode the cammu registers properly DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4t_device) - AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w) + AM_RANGE(0x008, 0x00b) AM_READWRITE(ram_line_r, ram_line_w) + AM_RANGE(0x010, 0x013) AM_READWRITE(s_pdo_r, s_pdo_w) + AM_RANGE(0x018, 0x01b) AM_READWRITE(u_pdo_r, u_pdo_w) + AM_RANGE(0x020, 0x023) AM_READWRITE(htlb_offset_r, htlb_offset_w) + AM_RANGE(0x028, 0x02b) AM_READWRITE(i_fault_r, i_fault_w) + AM_RANGE(0x030, 0x033) AM_READWRITE(fault_address_1_r, fault_address_1_w) + AM_RANGE(0x038, 0x03b) AM_READWRITE(fault_address_2_r, fault_address_2_w) + AM_RANGE(0x040, 0x043) AM_READWRITE(fault_data_1_lo_r, fault_data_1_lo_w) + AM_RANGE(0x048, 0x04b) AM_READWRITE(fault_data_1_hi_r, fault_data_1_hi_w) + AM_RANGE(0x050, 0x053) AM_READWRITE(fault_data_2_lo_r, fault_data_2_lo_w) + AM_RANGE(0x058, 0x05b) AM_READWRITE(fault_data_2_hi_r, fault_data_2_hi_w) + AM_RANGE(0x060, 0x063) AM_READWRITE(c4_bus_poll_r, c4_bus_poll_w) + AM_RANGE(0x068, 0x06b) AM_READWRITE(control_r, control_w) + AM_RANGE(0x070, 0x073) AM_READWRITE(bio_control_r, bio_control_w) + AM_RANGE(0x078, 0x07b) AM_READWRITE(bio_address_tag_r, bio_address_tag_w) + + AM_RANGE(0x100, 0x103) AM_READWRITE(cache_data_lo_r, cache_data_lo_w) + AM_RANGE(0x104, 0x107) AM_READWRITE(cache_data_hi_r, cache_data_hi_w) + AM_RANGE(0x108, 0x10b) AM_READWRITE(cache_cpu_tag_r, cache_cpu_tag_w) + AM_RANGE(0x10c, 0x10f) AM_READWRITE(cache_system_tag_valid_r, cache_system_tag_valid_w) + AM_RANGE(0x110, 0x113) AM_READWRITE(cache_system_tag_r, cache_system_tag_w) + AM_RANGE(0x118, 0x11b) AM_READWRITE(tlb_va_line_r, tlb_va_line_w) + AM_RANGE(0x11c, 0x11f) AM_READWRITE(tlb_ra_line_r, tlb_ra_line_w) ADDRESS_MAP_END DEVICE_ADDRESS_MAP_START(map, 32, cammu_c4i_device) - AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w) + AM_RANGE(0x000, 0x003) AM_READWRITE(reset_r, reset_w) + AM_RANGE(0x010, 0x013) AM_READWRITE(s_pdo_r, s_pdo_w) + AM_RANGE(0x018, 0x01b) AM_READWRITE(u_pdo_r, u_pdo_w) + AM_RANGE(0x020, 0x023) AM_READWRITE(clr_s_data_tlb_r, clr_s_data_tlb_w) + AM_RANGE(0x028, 0x02b) AM_READWRITE(clr_u_data_tlb_r, clr_u_data_tlb_w) + AM_RANGE(0x030, 0x033) AM_READWRITE(clr_s_insn_tlb_r, clr_s_insn_tlb_w) + AM_RANGE(0x038, 0x03b) AM_READWRITE(clr_u_insn_tlb_r, clr_u_insn_tlb_w) + + AM_RANGE(0x068, 0x06b) AM_READWRITE(control_r, control_w) + + AM_RANGE(0x080, 0x083) AM_READWRITE(test_data_r, test_data_w) + AM_RANGE(0x088, 0x08b) AM_READWRITE(i_fault_r, i_fault_w) + AM_RANGE(0x090, 0x093) AM_READWRITE(fault_address_1_r, fault_address_1_w) + AM_RANGE(0x098, 0x09b) AM_READWRITE(fault_address_2_r, fault_address_2_w) + AM_RANGE(0x0a0, 0x0a3) AM_READWRITE(fault_data_1_lo_r, fault_data_1_lo_w) + AM_RANGE(0x0a8, 0x0ab) AM_READWRITE(fault_data_1_hi_r, fault_data_1_hi_w) + AM_RANGE(0x0b0, 0x0b3) AM_READWRITE(fault_data_2_lo_r, fault_data_2_lo_w) + AM_RANGE(0x0b8, 0x0bb) AM_READWRITE(fault_data_2_hi_r, fault_data_2_hi_w) + AM_RANGE(0x0c0, 0x0c3) AM_READWRITE(test_address_r, test_address_w) ADDRESS_MAP_END DEVICE_ADDRESS_MAP_START(map, 32, cammu_c3_device) - AM_RANGE(0x000, 0xfff) AM_READWRITE(cammu_r, cammu_w) + // the first AM_NOP in each range is in fact the TLB in the C3 CAMMU + + AM_RANGE(0x800, 0x8ff) AM_NOP + AM_RANGE(0x904, 0x907) AM_READWRITE(d_s_pdo_r, d_s_pdo_w) + AM_RANGE(0x908, 0x90b) AM_READWRITE(d_u_pdo_r, d_u_pdo_w) + AM_RANGE(0x910, 0x913) AM_READWRITE(d_fault_r, d_fault_w) + AM_RANGE(0x940, 0x943) AM_READWRITE(d_control_r, d_control_w) + AM_RANGE(0x980, 0x983) AM_READWRITE(d_reset_r, d_reset_w) + + AM_RANGE(0xa00, 0xaff) AM_NOP + AM_RANGE(0xb04, 0xb07) AM_READWRITE(i_s_pdo_r, i_s_pdo_w) + AM_RANGE(0xb08, 0xb0b) AM_READWRITE(i_u_pdo_r, i_u_pdo_w) + AM_RANGE(0xb10, 0xb13) AM_READWRITE(i_fault_r, i_fault_w) + AM_RANGE(0xb40, 0xb43) AM_READWRITE(i_control_r, i_control_w) + AM_RANGE(0xb80, 0xb83) AM_READWRITE(i_reset_r, i_reset_w) + + AM_RANGE(0xc00, 0xcff) AM_NOP + AM_RANGE(0xd04, 0xd07) AM_WRITE(g_s_pdo_w) + AM_RANGE(0xd08, 0xd0b) AM_WRITE(g_u_pdo_w) + AM_RANGE(0xd10, 0xd13) AM_WRITE(g_fault_w) + AM_RANGE(0xd40, 0xd43) AM_WRITE(g_control_w) + AM_RANGE(0xd80, 0xd83) AM_WRITE(g_reset_w) ADDRESS_MAP_END DEFINE_DEVICE_TYPE(CAMMU_C4T, cammu_c4t_device, "c4t", "C4E/C4T CAMMU") @@ -44,12 +104,17 @@ DEFINE_DEVICE_TYPE(CAMMU_C4I, cammu_c4i_device, "c4i", "C4I CAMMU") DEFINE_DEVICE_TYPE(CAMMU_C3, cammu_c3_device, "c3", "C1/C3 CAMMU") cammu_c4t_device::cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cammu_device(mconfig, CAMMU_C4T, tag, owner, clock) + : cammu_c4_device(mconfig, CAMMU_C4T, tag, owner, clock) { } cammu_c4i_device::cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : cammu_device(mconfig, CAMMU_C4I, tag, owner, clock) + : cammu_c4_device(mconfig, CAMMU_C4I, tag, owner, clock) +{ +} + +cammu_c4_device::cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) + : cammu_device(mconfig, type, tag, owner, clock) { } @@ -68,11 +133,12 @@ cammu_device::cammu_device(const machine_config &mconfig, device_type type, cons m_io_space(nullptr), m_boot_space(nullptr), m_ssw_func(*this) -{ } +{ +} void cammu_device::device_start() { - m_ssw_func.resolve_safe(0); + m_ssw_func.resolve(); m_main_space = &space(AS_0); m_io_space = &space(AS_1); @@ -96,93 +162,259 @@ const address_space_config *cammu_device::memory_space_config (address_spacenum return nullptr; } -READ32_MEMBER(cammu_device::mmu_r) +READ32_MEMBER(cammu_device::insn_r) { u32 ssw = m_ssw_func(); - u32 address = offset << 2; + u32 va = offset << 2; // in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb - if ((ssw & 0x40000000) == 0 && (address & ~0x7fff) == 0) + if ((ssw & 0x40000000) == 0 && (va & ~0x7fff) == 0) { - switch (address & 0xf000) + switch (va & 0xf000) { case 0x0000: case 0x1000: case 0x2000: case 0x3000: // pages 0-3: main space pages 0-3 - return m_main_space->read_dword(address, mem_mask); + return m_main_space->read_dword(va, mem_mask); case 0x4000: case 0x5000: // pages 4-5: i/o space pages 0-1 - return m_io_space->read_dword(address & 0x1fff, mem_mask); + return m_io_space->read_dword(va & 0x1fff, mem_mask); case 0x6000: case 0x7000: // pages 6-7: boot space pages 0-1 - return m_boot_space->read_dword(address & 0x1fff, mem_mask); + return m_boot_space->read_dword(va & 0x1fff, mem_mask); } } - // FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O - if ((address & 0xff000000) == 0x00000000 || (address & 0xfff00000) == 0x7f100000) - { -#ifdef ICACHE_ENTRIES - // if this is an instruction fetch, check the cache first - if (space.spacenum() == AS_PROGRAM) - { - if (m_icache[offset & (ICACHE_ENTRIES-1)].offset != offset) - { - m_icache[offset & (ICACHE_ENTRIES - 1)].offset = offset; - m_icache[offset & (ICACHE_ENTRIES - 1)].data = m_main_space->read_dword(address, mem_mask); - } + // if not in mapped mode, default to main memory space + if ((ssw & 0x04000000) == 0) + return m_main_space->read_dword(va); - return m_icache[offset & (ICACHE_ENTRIES - 1)].data; - } - else +#if DTU + // get the page table entry + u32 pte = get_pte(va, ssw & 0x40000000, false); + + // translate the address + u32 ra = (pte & 0xfffff000) | (va & 0xfff); + + // execute the read based on the system tag + switch ((pte & 0xe00) >> 9) + { + case 0: + case 1: + case 2: + case 3: + return m_main_space->read_dword(ra, mem_mask); + + case 4: + return m_io_space->read_dword(ra, mem_mask); + + case 5: + return m_boot_space->read_dword(ra, mem_mask); + + case 6: // cache purge + case 7: // main memory, slave mode + fatalerror("system tag %d not supported %s\n", (pte & 0xe00) >> 9, machine().describe_context()); + } + + return 0; +#else + // FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O + if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000) + return m_main_space->read_dword(va, mem_mask); + else + return m_io_space->read_dword(va, mem_mask); #endif - return m_main_space->read_dword(address, mem_mask); - } - else - return m_io_space->read_dword(address, mem_mask); } -WRITE32_MEMBER(cammu_device::mmu_w) +READ32_MEMBER(cammu_device::data_r) { u32 ssw = m_ssw_func(); - u32 address = offset << 2; + u32 va = offset << 2; - // in supervisor mode, the first 8 pages are always mapped via the hard-wired tlb - if ((ssw & 0x40000000) == 0 && (address & ~0x7fff) == 0) + // in supervisor mode (and not user data mode), the first 8 pages are always mapped via the hard-wired tlb + if (((ssw & 0x50000000) == 0) && ((va & ~0x7fff) == 0)) { - switch (address & 0xf000) + switch (va & 0xf000) { case 0x0000: case 0x1000: case 0x2000: case 0x3000: // pages 0-3: main space pages 0-3 - m_main_space->write_dword(address, data, mem_mask); + return m_main_space->read_dword(va, mem_mask); + + case 0x4000: + case 0x5000: + // pages 4-5: i/o space pages 0-1 + return m_io_space->read_dword(va & 0x1fff, mem_mask); + + case 0x6000: + case 0x7000: + // pages 6-7: boot space pages 0-1 + return m_boot_space->read_dword(va & 0x1fff, mem_mask); + } + } + + // if not in mapped mode, default to main memory space + if ((ssw & 0x04000000) == 0) + return m_main_space->read_dword(va); + +#if DTU + // get the page table entry + u32 pte = get_pte(va, ssw & 0x50000000, space.spacenum() == AS_DATA); + + // translate the address + u32 ra = (pte & 0xfffff000) | (va & 0xfff); + + // execute the read based on the system tag + switch ((pte & 0xe00) >> 9) + { + case 0: + case 1: + case 2: + case 3: + return m_main_space->read_dword(ra, mem_mask); + + case 4: + return m_io_space->read_dword(ra, mem_mask); + + case 5: + return m_boot_space->read_dword(ra, mem_mask); + + case 6: // cache purge + case 7: // main memory, slave mode + fatalerror("data_r: system tag %d not supported at %s\n", (pte & 0xe00) >> 9, machine().describe_context()); + } + + return 0; +#else + // FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O + if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000) + return m_main_space->read_dword(va, mem_mask); + else + return m_io_space->read_dword(va, mem_mask); +#endif +} + +WRITE32_MEMBER(cammu_device::data_w) +{ + u32 ssw = m_ssw_func(); + u32 va = offset << 2; + + // in supervisor mode (and not user data mode), the first 8 pages are always mapped via the hard-wired tlb + if (((ssw & 0x50000000) == 0) && ((va & ~0x7fff) == 0)) + { + switch (va & 0xf000) + { + case 0x0000: + case 0x1000: + case 0x2000: + case 0x3000: + // pages 0-3: main space pages 0-3 + m_main_space->write_dword(va, data, mem_mask); return; case 0x4000: case 0x5000: // pages 4-5: i/o space pages 0-1 - m_io_space->write_dword(address & 0x1fff, data, mem_mask); + m_io_space->write_dword(va & 0x1fff, data, mem_mask); return; case 0x6000: case 0x7000: // pages 6-7: boot space pages 0-1 - m_boot_space->write_dword(address & 0x1fff, data, mem_mask); + m_boot_space->write_dword(va & 0x1fff, data, mem_mask); return; } } + // if not in mapped mode, default to main memory space + if ((ssw & 0x04000000) == 0) + { + m_main_space->write_dword(va, data, mem_mask); + return; + } + +#if DTU + // get the page table entry + u32 pte = get_pte(va, ssw & 0x50000000, space.spacenum() == AS_DATA); + + // translate the address + u32 ra = (pte & 0xfffff000) | (va & 0xfff); + + // execute the read based on the system tag + switch ((pte & 0xe00) >> 9) + { + case 0: + case 1: + case 2: + case 3: + m_main_space->write_dword(ra, data, mem_mask); + break; + + case 4: + m_io_space->write_dword(ra, data, mem_mask); + break; + + case 5: + m_boot_space->write_dword(ra, data, mem_mask); + break; + + case 6: // cache purge + case 7: // main memory, slave mode + fatalerror("data_w: system tag %d not supported at %s\n", (pte & 0xe00) >> 9, machine().describe_context()); + break; + } +#else // FIXME: currently maps addresses with upper bits 0x00 or 0x7f1 to main memory and everything else to I/O - if ((address & 0xff000000) == 0x00000000 || (address & 0xfff00000) == 0x7f100000) - m_main_space->write_dword(address, data, mem_mask); + if ((va & 0xff000000) == 0x00000000 || (va & 0xfff00000) == 0x7f100000) + m_main_space->write_dword(va, data, mem_mask); else - m_io_space->write_dword(address, data, mem_mask); + m_io_space->write_dword(va, data, mem_mask); +#endif +} + +u32 cammu_c4_device::get_pte(u32 va, int user, bool data) +{ + u32 tlb_index = (user ? 2 : 0) + (data ? 1 : 0); + if ((va & 0xfffff000) != m_tlb[tlb_index].va) + { + // return the page table entry for a given virtual address + u32 pdo = user ? m_u_pdo : m_s_pdo; + + u32 pto = m_main_space->read_dword(pdo | (va & 0xffc00000) >> 20); + if (pto & 0x1) + fatalerror("can't deal with pto faults va 0x%08x %s\n", va, machine().describe_context()); + + u32 pte = m_main_space->read_dword((pto & 0xfffff000) | (va & 0x003ff000) >> 10); + if (pte & 0x1) + fatalerror("can't deal with pte faults va 0x%08x %s\n", va, machine().describe_context()); + + m_tlb[tlb_index].va = va & 0xfffff000; + m_tlb[tlb_index].pte = pte; + } + + return m_tlb[tlb_index].pte; +} + +u32 cammu_c3_device::get_pte(u32 va, int user, bool data) +{ + // return the page table entry for a given virtual address + u32 pdo = user ? (data ? m_d_u_pdo : m_i_u_pdo) : (data ? m_d_s_pdo : m_i_s_pdo); + + u32 pto = m_main_space->read_dword(pdo | (va & 0xffc00000) >> 20); + if (pto & 0x1) + fatalerror("can't deal with pto faults va 0x%08x %s\n", va, machine().describe_context()); + + u32 pte = m_main_space->read_dword((pto & 0xfffff000) | (va & 0x003ff000) >> 10); + if (pte & 0x1) + fatalerror("can't deal with pte faults va 0x%08x %s\n", va, machine().describe_context()); + + return pte; } diff --git a/src/mame/machine/cammu.h b/src/mame/machine/cammu.h index 23265109486..cdeb036f49c 100644 --- a/src/mame/machine/cammu.h +++ b/src/mame/machine/cammu.h @@ -6,12 +6,6 @@ #pragma once - -// the following enables a very crude instruction cache - it has known (future) -// problems, but speeds up cpu execution quite noticeably in the short term by -// avoiding some of the delays in the mame memory subsystem -#define ICACHE_ENTRIES 32768 - #define MCFG_CAMMU_SSW_CB(_sswcb) \ devcb = &cammu_device::static_set_ssw_callback(*device, DEVCB_##_sswcb); @@ -22,11 +16,10 @@ public: virtual DECLARE_ADDRESS_MAP(map, 32) = 0; - DECLARE_READ32_MEMBER(mmu_r); - DECLARE_WRITE32_MEMBER(mmu_w); + DECLARE_READ32_MEMBER(insn_r); - DECLARE_READ32_MEMBER(cammu_r) { return m_cammu[offset]; } - DECLARE_WRITE32_MEMBER(cammu_w) { m_cammu[offset] = data; } + DECLARE_READ32_MEMBER(data_r); + DECLARE_WRITE32_MEMBER(data_w); protected: cammu_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); @@ -38,40 +31,161 @@ protected: // device_memory_interface overrides virtual const address_space_config *memory_space_config (address_spacenum spacenum) const override; + virtual u32 get_pte(u32 va, int user, bool data) = 0; + private: address_space_config m_main_space_config; address_space_config m_io_space_config; address_space_config m_boot_space_config; + +protected: address_space *m_main_space; address_space *m_io_space; address_space *m_boot_space; - devcb_read32 m_ssw_func; - u32 m_cammu[1024]; - -#ifdef ICACHE_ENTRIES - struct icache + struct { - u32 offset; - u32 data; - } m_icache[ICACHE_ENTRIES]; -#endif + u32 va; + u32 pte; + } m_tlb[4]; + +private: + devcb_read32 m_ssw_func; }; -class cammu_c4t_device : public cammu_device +class cammu_c4_device : public cammu_device +{ +public: + cammu_c4_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + + DECLARE_READ32_MEMBER(s_pdo_r) { return m_s_pdo; } + DECLARE_WRITE32_MEMBER(s_pdo_w) { m_s_pdo = data; } + DECLARE_READ32_MEMBER(u_pdo_r) { return m_u_pdo; } + DECLARE_WRITE32_MEMBER(u_pdo_w) { m_u_pdo = data; } + + virtual DECLARE_READ32_MEMBER(control_r) = 0; + virtual DECLARE_WRITE32_MEMBER(control_w) = 0; + + DECLARE_READ32_MEMBER(i_fault_r) { return m_i_fault; } + DECLARE_WRITE32_MEMBER(i_fault_w) { m_i_fault = data; } + DECLARE_READ32_MEMBER(fault_address_1_r) { return m_fault_address_1; } + DECLARE_WRITE32_MEMBER(fault_address_1_w) { m_fault_address_1 = data; } + DECLARE_READ32_MEMBER(fault_address_2_r) { return m_fault_address_2; } + DECLARE_WRITE32_MEMBER(fault_address_2_w) { m_fault_address_2 = data; } + DECLARE_READ32_MEMBER(fault_data_1_lo_r) { return m_fault_data_1_lo; } + DECLARE_WRITE32_MEMBER(fault_data_1_lo_w) { m_fault_data_1_lo = data; } + DECLARE_READ32_MEMBER(fault_data_1_hi_r) { return m_fault_data_1_hi; } + DECLARE_WRITE32_MEMBER(fault_data_1_hi_w) { m_fault_data_1_hi = data; } + DECLARE_READ32_MEMBER(fault_data_2_lo_r) { return m_fault_data_2_lo; } + DECLARE_WRITE32_MEMBER(fault_data_2_lo_w) { m_fault_data_2_lo = data; } + DECLARE_READ32_MEMBER(fault_data_2_hi_r) { return m_fault_data_2_hi; } + DECLARE_WRITE32_MEMBER(fault_data_2_hi_w) { m_fault_data_2_hi = data; } + +protected: + u32 get_pte(u32 va, int user, bool data) override; + + u32 m_s_pdo; + u32 m_u_pdo; + u32 m_control; + + u32 m_i_fault; + u32 m_fault_address_1; + u32 m_fault_address_2; + u32 m_fault_data_1_lo; + u32 m_fault_data_1_hi; + u32 m_fault_data_2_lo; + u32 m_fault_data_2_hi; +}; + +class cammu_c4t_device : public cammu_c4_device { public: cammu_c4t_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_ADDRESS_MAP(map, 32) override; + + DECLARE_READ32_MEMBER(ram_line_r) { return m_ram_line; } + DECLARE_WRITE32_MEMBER(ram_line_w) { m_ram_line = data; } + + DECLARE_READ32_MEMBER(htlb_offset_r) { return m_htlb_offset; } + DECLARE_WRITE32_MEMBER(htlb_offset_w) { m_htlb_offset = data; } + + DECLARE_READ32_MEMBER(c4_bus_poll_r) { return m_c4_bus_poll; } + DECLARE_WRITE32_MEMBER(c4_bus_poll_w) { m_c4_bus_poll = data; } + virtual DECLARE_READ32_MEMBER(control_r) override { return m_control | 0x00000000; } + virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = data & 0x00ffffff; } + DECLARE_READ32_MEMBER(bio_control_r) { return m_bio_control; } + DECLARE_WRITE32_MEMBER(bio_control_w) { m_bio_control = data; } + DECLARE_READ32_MEMBER(bio_address_tag_r) { return m_bio_address_tag; } + DECLARE_WRITE32_MEMBER(bio_address_tag_w) { m_bio_address_tag = data; } + + DECLARE_READ32_MEMBER(cache_data_lo_r) { return m_cache_data_lo; } + DECLARE_WRITE32_MEMBER(cache_data_lo_w) { m_cache_data_lo = data; } + DECLARE_READ32_MEMBER(cache_data_hi_r) { return m_cache_data_hi; } + DECLARE_WRITE32_MEMBER(cache_data_hi_w) { m_cache_data_hi = data; } + DECLARE_READ32_MEMBER(cache_cpu_tag_r) { return m_cache_cpu_tag; } + DECLARE_WRITE32_MEMBER(cache_cpu_tag_w) { m_cache_cpu_tag = data; } + DECLARE_READ32_MEMBER(cache_system_tag_valid_r) { return m_cache_system_tag_valid; } + DECLARE_WRITE32_MEMBER(cache_system_tag_valid_w) { m_cache_system_tag_valid = data; } + DECLARE_READ32_MEMBER(cache_system_tag_r) { return m_cache_system_tag; } + DECLARE_WRITE32_MEMBER(cache_system_tag_w) { m_cache_system_tag = data; } + DECLARE_READ32_MEMBER(tlb_va_line_r) { return m_tlb_va_line; } + DECLARE_WRITE32_MEMBER(tlb_va_line_w) { m_tlb_va_line = data; } + DECLARE_READ32_MEMBER(tlb_ra_line_r) { return m_tlb_ra_line; } + DECLARE_WRITE32_MEMBER(tlb_ra_line_w) { m_tlb_ra_line = data; } + +private: + u32 m_ram_line; + u32 m_htlb_offset; + u32 m_c4_bus_poll; + u32 m_bio_control; + u32 m_bio_address_tag; + + u32 m_cache_data_lo; + u32 m_cache_data_hi; + u32 m_cache_cpu_tag; + u32 m_cache_system_tag_valid; + u32 m_cache_system_tag; + u32 m_tlb_va_line; + u32 m_tlb_ra_line; }; -class cammu_c4i_device : public cammu_device +class cammu_c4i_device : public cammu_c4_device { public: cammu_c4i_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_ADDRESS_MAP(map, 32) override; + + virtual DECLARE_READ32_MEMBER(control_r) override { return m_control | 0x02000000; } + virtual DECLARE_WRITE32_MEMBER(control_w) override { m_control = data & 0x00ffffff; } + + DECLARE_READ32_MEMBER(reset_r) { return m_reset; } + DECLARE_WRITE32_MEMBER(reset_w) { m_reset = data; } + + DECLARE_READ32_MEMBER(clr_s_data_tlb_r) { return m_clr_s_data_tlb; } + DECLARE_WRITE32_MEMBER(clr_s_data_tlb_w) { m_clr_s_data_tlb = data; } + DECLARE_READ32_MEMBER(clr_u_data_tlb_r) { return m_clr_u_data_tlb; } + DECLARE_WRITE32_MEMBER(clr_u_data_tlb_w) { m_clr_u_data_tlb = data; } + DECLARE_READ32_MEMBER(clr_s_insn_tlb_r) { return m_clr_s_insn_tlb; } + DECLARE_WRITE32_MEMBER(clr_s_insn_tlb_w) { m_clr_s_insn_tlb = data; } + DECLARE_READ32_MEMBER(clr_u_insn_tlb_r) { return m_clr_u_insn_tlb; } + DECLARE_WRITE32_MEMBER(clr_u_insn_tlb_w) { m_clr_u_insn_tlb = data; } + + DECLARE_READ32_MEMBER(test_data_r) { return m_test_data; } + DECLARE_WRITE32_MEMBER(test_data_w) { m_test_data = data; } + + DECLARE_READ32_MEMBER(test_address_r) { return m_test_address; } + DECLARE_WRITE32_MEMBER(test_address_w) { m_test_address = data; } + +private: + u32 m_reset; + u32 m_clr_s_data_tlb; + u32 m_clr_u_data_tlb; + u32 m_clr_s_insn_tlb; + u32 m_clr_u_insn_tlb; + u32 m_test_data; + u32 m_test_address; }; class cammu_c3_device : public cammu_device @@ -80,6 +194,49 @@ public: cammu_c3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); virtual DECLARE_ADDRESS_MAP(map, 32) override; + + DECLARE_READ32_MEMBER(d_s_pdo_r) { return m_d_s_pdo; } + DECLARE_WRITE32_MEMBER(d_s_pdo_w) { m_d_s_pdo = data; } + DECLARE_READ32_MEMBER(d_u_pdo_r) { return m_d_u_pdo; } + DECLARE_WRITE32_MEMBER(d_u_pdo_w) { m_d_u_pdo = data; } + DECLARE_READ32_MEMBER(d_fault_r) { return m_d_fault; } + DECLARE_WRITE32_MEMBER(d_fault_w) { m_d_fault = data; } + DECLARE_READ32_MEMBER(d_control_r) { return m_d_control; } + DECLARE_WRITE32_MEMBER(d_control_w) { m_d_control = data; } + DECLARE_READ32_MEMBER(d_reset_r) { return m_d_reset; } + DECLARE_WRITE32_MEMBER(d_reset_w) { m_d_reset = data; } + + DECLARE_READ32_MEMBER(i_s_pdo_r) { return m_i_s_pdo; } + DECLARE_WRITE32_MEMBER(i_s_pdo_w) { m_i_s_pdo = data; } + DECLARE_READ32_MEMBER(i_u_pdo_r) { return m_i_u_pdo; } + DECLARE_WRITE32_MEMBER(i_u_pdo_w) { m_i_u_pdo = data; } + DECLARE_READ32_MEMBER(i_fault_r) { return m_i_fault; } + DECLARE_WRITE32_MEMBER(i_fault_w) { m_i_fault = data; } + DECLARE_READ32_MEMBER(i_control_r) { return m_i_control; } + DECLARE_WRITE32_MEMBER(i_control_w) { m_i_control = data; } + DECLARE_READ32_MEMBER(i_reset_r) { return m_i_reset; } + DECLARE_WRITE32_MEMBER(i_reset_w) { m_i_reset = data; } + + DECLARE_WRITE32_MEMBER(g_s_pdo_w) { d_s_pdo_w(space, offset, data, mem_mask); i_s_pdo_w(space, offset, data, mem_mask); } + DECLARE_WRITE32_MEMBER(g_u_pdo_w) { d_u_pdo_w(space, offset, data, mem_mask); i_u_pdo_w(space, offset, data, mem_mask); } + DECLARE_WRITE32_MEMBER(g_fault_w) { d_fault_w(space, offset, data, mem_mask); i_fault_w(space, offset, data, mem_mask); } + DECLARE_WRITE32_MEMBER(g_control_w) { d_control_w(space, offset, data, mem_mask); i_control_w(space, offset, data, mem_mask); } + DECLARE_WRITE32_MEMBER(g_reset_w) { d_reset_w(space, offset, data, mem_mask); i_reset_w(space, offset, data, mem_mask); } + +protected: + u32 get_pte(u32 va, int user, bool data) override; + +private: + u32 m_d_s_pdo; + u32 m_d_u_pdo; + u32 m_d_fault; + u32 m_d_control; + u32 m_d_reset; + u32 m_i_s_pdo; + u32 m_i_u_pdo; + u32 m_i_fault; + u32 m_i_control; + u32 m_i_reset; }; // device type definitions diff --git a/src/mame/machine/interpro_ioga.cpp b/src/mame/machine/interpro_ioga.cpp index f08c03adef6..6904c3bb09b 100644 --- a/src/mame/machine/interpro_ioga.cpp +++ b/src/mame/machine/interpro_ioga.cpp @@ -18,19 +18,26 @@ #include "emu.h" #include "interpro_ioga.h" +#define LOG_HWINT_ENABLE ((1<<2) | LOG_GENERAL) +#define LOG_DMA_ENABLE ((1<<2) | LOG_GENERAL) + +#define LOG_GENERAL (1 << 31) + +#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 VERBOSE 0 + #if VERBOSE #define LOG_TIMER_MASK 0xff #define LOG_TIMER(timer, ...) if (LOG_TIMER_MASK & (1 << timer)) logerror(__VA_ARGS__) #define LOG_INTERRUPT(...) logerror(__VA_ARGS__) #define LOG_IOGA(...) logerror(__VA_ARGS__) -#define LOG_DMA(...) logerror(__VA_ARGS__) #else #define LOG_TIMER_MASK 0x00 #define LOG_TIMER(timer, ...) #define LOG_INTERRUPT(...) #define LOG_IOGA(...) -#define LOG_DMA(...) #endif DEVICE_ADDRESS_MAP_START(map, 32, interpro_ioga_device) @@ -61,7 +68,7 @@ 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_int_func(*this), + m_out_irq_func(*this), m_memory_space(nullptr), m_dma_channel{ { 0,0,0,0,false, 0, {*this}, {*this} }, @@ -72,11 +79,39 @@ interpro_ioga_device::interpro_ioga_device(const machine_config &mconfig, const { } +#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 + void interpro_ioga_device::device_start() { // resolve callbacks m_out_nmi_func.resolve(); - m_out_int_func.resolve(); + m_out_irq_func.resolve(); // TODO: parameterise the cammu name and space number // grab the main memory space from the mmu so we can do DMA to/from it @@ -104,18 +139,26 @@ void interpro_ioga_device::device_start() // allocate timer for DMA controller m_dma_timer = timer_alloc(IOGA_TIMER_DMA); m_dma_timer->adjust(attotime::never); + + m_ioga_clock = timer_alloc(IOGA_CLOCK); + m_ioga_clock->adjust(attotime::never); } void interpro_ioga_device::device_reset() { - m_nmi_pending = false; - - m_interrupt_active = 0; - m_irq_forced = 0; + // initialise interrupt state + m_active_interrupt_type = IOGA_INTERRUPT_NONE; + m_hwint_forced = 0; + m_nmi_state = CLEAR_LINE; + m_irq_state = CLEAR_LINE; + m_int_line = 0; // configure timer 0 at 60Hz m_timer_reg[0] = 0; - m_timer[0]->adjust(attotime::zero, IOGA_TIMER_0, attotime::from_hz(60)); + //m_timer[0]->adjust(attotime::zero, IOGA_TIMER_0, attotime::from_hz(60)); + + // configure ioga clock timer + m_ioga_clock->adjust(attotime::zero, IOGA_CLOCK, attotime::from_hz(clock())); } /****************************************************************************** @@ -146,7 +189,7 @@ READ32_MEMBER(interpro_ioga_device::timer3_r) return result; } -void interpro_ioga_device::write_timer(int timer, uint32_t value, device_timer_id id) +void interpro_ioga_device::write_timer(int timer, u32 value, device_timer_id id) { switch (id) { @@ -240,59 +283,19 @@ void interpro_ioga_device::device_timer(emu_timer &timer, device_timer_id id, in break; case IOGA_TIMER_DMA: - // transfer data between device and main memory + dma_clock(param); + break; - // TODO: figure out what indicates dma write (memory -> device) - // TODO: implement multiple dma channels - // TODO: virtual memory? - - if (!m_dma_channel[param].dma_active) - { - LOG_DMA("dma: transfer started, channel = %d, control 0x%08x, real address 0x%08x count 0x%08x\n", - param, m_dma_channel[param].control, m_dma_channel[param].real_address, m_dma_channel[param].transfer_count); - m_dma_channel[param].dma_active = true; - } - - // while the device is requesting a data transfer and the transfer count is not zero - while (m_dma_channel[param].drq_state && m_dma_channel[param].transfer_count) - { - // transfer a byte between device and memory - if (true) - m_memory_space->write_byte(m_dma_channel[param].real_address, m_dma_channel[param].device_r()); - else - m_dma_channel[param].device_w(m_memory_space->read_byte(m_dma_channel[param].real_address)); - - // increment addresses and decrement count - m_dma_channel[param].real_address++; - m_dma_channel[param].virtual_address++; - m_dma_channel[param].transfer_count--; - } - - // if there are no more bytes remaining, terminate the transfer - if (m_dma_channel[param].transfer_count == 0) - { - LOG_DMA("dma: transfer stopped, control 0x%08x, real address 0x%08x count 0x%08x\n", - m_dma_channel[param].control, m_dma_channel[param].fdc_real_address, m_dma_channel[param].transfer_count); - - if (param == IOGA_DMA_FLOPPY) - { - LOG_DMA("dma: asserting fdc terminal count line\n"); - - m_fdc_tc_func(ASSERT_LINE); - m_fdc_tc_func(CLEAR_LINE); - } - - m_dma_channel[param].dma_active = false; - } - break; + case IOGA_CLOCK: + interrupt_clock(); + break; } } /****************************************************************************** Interrupts ******************************************************************************/ - -static const uint16_t irq_enable_mask[IOGA_INTERRUPT_COUNT] = +static const u16 irq_enable_mask[IOGA_INTERRUPT_COUNT] = { IOGA_INTERRUPT_ENABLE_EXTERNAL, IOGA_INTERRUPT_ENABLE_EXTERNAL, @@ -318,56 +321,70 @@ static const uint16_t irq_enable_mask[IOGA_INTERRUPT_COUNT] = 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; + } + else + return false; +} + +bool interpro_ioga_device::irq(int state) +{ + if (m_irq_state != state) + { + m_irq_state = state; + m_out_irq_func(m_irq_state); + + return true; + } + else + return false; +} + void interpro_ioga_device::set_nmi_line(int state) { + LOG_INTERRUPT("set_nmi_line(%d)\n", state); switch (state) { case ASSERT_LINE: - - LOG_INTERRUPT("nmi: ctrl = 0x%02x\n", m_nmictrl); - +#if 0 if ((m_nmictrl & IOGA_NMI_ENABLE) == IOGA_NMI_ENABLE) { // if edge triggered mode, clear enable in if (m_nmictrl & IOGA_NMI_EDGE) m_nmictrl &= ~IOGA_NMI_ENABLE_IN; - - m_nmi_pending = true; - update_interrupt(ASSERT_LINE); } +#endif + m_nmictrl |= IOGA_NMI_PENDING; break; case CLEAR_LINE: - m_nmi_pending = false; - update_interrupt(ASSERT_LINE); + m_nmictrl &= ~IOGA_NMI_PENDING; break; } } void interpro_ioga_device::set_irq_line(int irq, int state) { - LOG_INTERRUPT("set_irq_line(%d, %d)\n", irq, state); + LOG_HWINT(irq, "set_irq_line(%d, %d)\n", irq, state); switch (state) { case ASSERT_LINE: - if (m_int_vector[irq] & irq_enable_mask[irq]) - { - // set pending bit - m_int_vector[irq] |= IOGA_INTERRUPT_PENDING; - - // update irq line state - update_interrupt(state); - } - else - LOG_INTERRUPT("received disabled interrupt irq %d vector 0x%04x\n", irq, m_int_vector[irq]); + // set pending bit + m_int_line |= (1 << irq); + m_hwicr[irq] |= IOGA_INTERRUPT_PENDING; break; case CLEAR_LINE: // clear pending bit - m_int_vector[irq] &= ~IOGA_INTERRUPT_PENDING; - - // update irq line state - update_interrupt(state); + m_int_line &= (1 << irq); + m_hwicr[irq] &= ~IOGA_INTERRUPT_PENDING; break; } } @@ -382,9 +399,7 @@ void interpro_ioga_device::set_irq_soft(int irq, int state) if (irq < 8) m_softint |= 1 << irq; else - m_softint_vector[irq - 8] |= IOGA_INTERRUPT_PENDING; - - update_interrupt(state); + m_swicr[irq - 8] |= IOGA_INTERRUPT_PENDING; break; case CLEAR_LINE: @@ -392,170 +407,180 @@ void interpro_ioga_device::set_irq_soft(int irq, int state) if (irq < 8) m_softint &= ~(1 << irq); else - m_softint_vector[irq - 8] &= ~IOGA_INTERRUPT_PENDING; - - // update irq line state - update_interrupt(state); + m_swicr[irq - 8] &= ~IOGA_INTERRUPT_PENDING; break; } } IRQ_CALLBACK_MEMBER(interpro_ioga_device::inta_cb) { + int vector = 0; + switch (irqline) { case INPUT_LINE_IRQ0: // FIXME: clear pending bit - can't rely on device callbacks - switch (m_interrupt_active) + switch (m_active_interrupt_type) { case IOGA_INTERRUPT_INTERNAL: case IOGA_INTERRUPT_EXTERNAL: - m_int_vector[m_irq_current] &= ~IOGA_INTERRUPT_PENDING; + m_hwicr[m_active_interrupt_number] &= ~IOGA_INTERRUPT_PENDING; break; case IOGA_INTERRUPT_SOFT_LO: - m_softint &= ~(1 << m_irq_current); + m_softint &= ~(1 << m_active_interrupt_number); break; case IOGA_INTERRUPT_SOFT_HI: - m_softint_vector[m_irq_current] &= ~IOGA_INTERRUPT_PENDING; + m_swicr[m_active_interrupt_number] &= ~IOGA_INTERRUPT_PENDING; break; } - // clear irq line - update_interrupt(CLEAR_LINE); - // fall through to return interrupt vector case -1: // return vector for current interrupt without clearing irq line - switch (m_interrupt_active) + switch (m_active_interrupt_type) { - case IOGA_INTERRUPT_EXTERNAL: case IOGA_INTERRUPT_INTERNAL: - return m_int_vector[m_irq_current] & 0xff; + case IOGA_INTERRUPT_EXTERNAL: + vector = m_hwicr[m_active_interrupt_number] & 0xff; + break; - case IOGA_INTERRUPT_SOFT_LO: - return 0x8f + m_irq_current * 0x10; + case IOGA_INTERRUPT_SOFT_LO: + vector = 0x8f + m_active_interrupt_number * 0x10; + break; - case IOGA_INTERRUPT_SOFT_HI: - return m_softint_vector[m_irq_current] & 0xff; + 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; case INPUT_LINE_NMI: // clear pending flag - m_nmi_pending = false; - - // clear line - update_interrupt(CLEAR_LINE); - - // return vector - return 0; + m_nmictrl &= ~IOGA_NMI_PENDING; + m_active_interrupt_type = IOGA_INTERRUPT_NONE; + break; } - return 0; + return vector; } -void interpro_ioga_device::update_interrupt(int state) +void interpro_ioga_device::interrupt_clock() { - switch (state) + // 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_nmictrl & IOGA_NMI_PENDING) { - case CLEAR_LINE: - if (m_interrupt_active) + m_active_interrupt_type = IOGA_INTERRUPT_NMI; + nmi(ASSERT_LINE); + return; + } + + // check for any pending and enabled hardware interrupts + for (int i = 0; i < IOGA_INTERRUPT_COUNT; i++) + { + if ((m_hwicr[i] & irq_enable_mask[i]) && (m_hwicr[i] & IOGA_INTERRUPT_PENDING)) { - // the cpu has acknowledged the active interrupt, deassert the nmi/irq line - m_interrupt_active == IOGA_INTERRUPT_NMI ? m_out_nmi_func(CLEAR_LINE) : m_out_int_func(CLEAR_LINE); + LOG_HWINT(i, "accepting interrupt %d - %s (%s)\n", i, interrupt_source[i], m_int_line & (1 << i) ? "real" : "forced"); - // clear the active status - m_interrupt_active = 0; + m_active_interrupt_type = IOGA_INTERRUPT_EXTERNAL; // TODO: flag internal/external + m_active_interrupt_number = i; + + irq(ASSERT_LINE); + return; } - // fall through to handle any pending interrupts + } - case ASSERT_LINE: - // if an interrupt is currently active, don't do anything - if (m_interrupt_active == 0) + // check for any pending soft interrupts (low type) + for (int i = 0; i < 8; i++) + { + if (m_softint & (1 << i)) { - // check for pending nmi - if (m_nmi_pending) - { - m_interrupt_active = IOGA_INTERRUPT_NMI; + m_active_interrupt_type = IOGA_INTERRUPT_SOFT_LO; + m_active_interrupt_number = i; - m_out_nmi_func(ASSERT_LINE); - return; - } - - // check for any pending irq - for (int i = 0; i < IOGA_INTERRUPT_COUNT; i++) - { - if (m_int_vector[i] & IOGA_INTERRUPT_PENDING) - { - m_interrupt_active = IOGA_INTERRUPT_INTERNAL; // TODO: flag internal/external - m_irq_current = i; - - m_out_int_func(ASSERT_LINE); - return; - } - } - - // check for any pending soft interrupts (low type) - for (int i = 0; i < 8; i++) - { - if (m_softint & (1 << i)) - { - m_interrupt_active = IOGA_INTERRUPT_SOFT_LO; - m_irq_current = i; - - m_out_int_func(ASSERT_LINE); - return; - } - } - - // check for any pending soft interrupts (high type) - for (int i = 0; i < 8; i++) - { - if (m_softint_vector[i] & IOGA_INTERRUPT_PENDING) - { - m_interrupt_active = IOGA_INTERRUPT_SOFT_HI; - m_irq_current = i; - - m_out_int_func(ASSERT_LINE); - return; - } - } + irq(ASSERT_LINE); + return; + } + } + + // check for any pending soft interrupts (high type) + for (int i = 0; i < 8; i++) + { + if (m_swicr[i] & IOGA_INTERRUPT_PENDING) + { + m_active_interrupt_type = IOGA_INTERRUPT_SOFT_HI; + m_active_interrupt_number = i; + + irq(ASSERT_LINE); + return; } - break; } } WRITE16_MEMBER(interpro_ioga_device::icr_w) { - LOG_INTERRUPT("interrupt vector %d set to 0x%04x at pc 0x%08x\n", offset, data, space.device().safe_pc()); + /* + * 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? + */ - // FIXME: now that the interrupt handling only depends on IOGA_INTERRUPT_PENDING, we might be able - // to avoid this hack + LOG_HWINT(offset, "interrupt vector %d set to 0x%04x at %s\n", offset, data, machine().describe_context()); +#if 1 if (data & IOGA_INTERRUPT_PENDING) { - m_irq_forced |= 1 << offset; - m_int_vector[offset] = data & ~IOGA_INTERRUPT_PENDING; + m_hwint_forced |= 1 << offset; + m_hwicr[offset] = (m_hwicr[offset] & IOGA_INTERRUPT_PENDING) | (data & ~IOGA_INTERRUPT_PENDING); } - else if (m_irq_forced & 1 << offset) + else if (m_hwint_forced & 1 << offset) { - m_int_vector[offset] = data; + m_hwicr[offset] = data; // clear forced flag - m_irq_forced &= ~(1 << offset); + m_hwint_forced &= ~(1 << offset); // force an interrupt - set_irq_line(offset, ASSERT_LINE); + m_hwicr[offset] |= IOGA_INTERRUPT_PENDING; } else - m_int_vector[offset] = data; + m_hwicr[offset] = data; +#else + if (data & IOGA_INTERRUPT_PENDING) + m_hwint_forced |= 1 << offset; + + if (data & IOGA_INTERRUPT_ENABLE_EXTERNAL) + m_hwicr[offset] = data; + else + m_hwicr[offset] = data & ~IOGA_INTERRUPT_PENDING; +#endif } WRITE8_MEMBER(interpro_ioga_device::softint_w) { // save the existing value - uint8_t previous = m_softint; + u8 previous = m_softint; // store the written value m_softint = data; @@ -563,7 +588,7 @@ WRITE8_MEMBER(interpro_ioga_device::softint_w) // force soft interrupt for any bit written from 1 to 0 for (int i = 0; i < 8; i++) { - uint8_t mask = 1 << i; + u8 mask = 1 << i; // check for transition from 1 to 0 and force a soft interrupt if (previous & mask && !(data & mask)) @@ -572,7 +597,8 @@ WRITE8_MEMBER(interpro_ioga_device::softint_w) } WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) -{ +{ +#if 0 // save the existing value uint8_t previous = m_nmictrl; @@ -582,15 +608,32 @@ WRITE8_MEMBER(interpro_ioga_device::nmictrl_w) // force an nmi when pending bit is written low if (previous & IOGA_NMI_PENDING && !(data & IOGA_NMI_PENDING)) set_nmi_line(ASSERT_LINE); +#else + if (data & IOGA_NMI_PENDING) + { + m_nmi_forced = true; + m_nmictrl = (m_nmictrl & IOGA_NMI_PENDING) | (data & ~IOGA_NMI_PENDING); + } + else if (m_nmi_forced) + { + m_nmi_forced = false; + + m_nmictrl = data | IOGA_NMI_PENDING; + } + else + m_nmictrl = data; + + //m_nmictrl = data & ~IOGA_NMI_PENDING; +#endif } WRITE16_MEMBER(interpro_ioga_device::softint_vector_w) { // save the existing value - uint16_t previous = m_softint_vector[offset]; + u16 previous = m_swicr[offset]; // store the written value - m_softint_vector[offset] = data; + 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)) @@ -600,6 +643,54 @@ WRITE16_MEMBER(interpro_ioga_device::softint_vector_w) /****************************************************************************** DMA ******************************************************************************/ +void interpro_ioga_device::dma_clock(int channel) +{ + // transfer data between device and main memory + + // TODO: figure out what indicates dma write (memory -> device) + // TODO: implement multiple dma channels + // TODO: virtual memory? + + if (!m_dma_channel[channel].dma_active) + { + LOG_DMA(channel, "dma: transfer started, channel = %d, control 0x%08x, real address 0x%08x count 0x%08x\n", + channel, m_dma_channel[channel].control, m_dma_channel[channel].real_address, m_dma_channel[channel].transfer_count); + m_dma_channel[channel].dma_active = true; + } + + // while the device is requesting a data transfer and the transfer count is not zero + while (m_dma_channel[channel].drq_state && m_dma_channel[channel].transfer_count) + { + // transfer a byte between device and memory + if (true) + m_memory_space->write_byte(m_dma_channel[channel].real_address, m_dma_channel[channel].device_r()); + else + m_dma_channel[channel].device_w(m_memory_space->read_byte(m_dma_channel[channel].real_address)); + + // increment addresses and decrement count + m_dma_channel[channel].real_address++; + m_dma_channel[channel].virtual_address++; + m_dma_channel[channel].transfer_count--; + } + + // if there are no more bytes remaining, terminate the transfer + if (m_dma_channel[channel].transfer_count == 0) + { + LOG_DMA(channel, "dma: transfer completed, control 0x%08x, real address 0x%08x count 0x%08x\n", + m_dma_channel[channel].control, m_dma_channel[channel].real_address, m_dma_channel[channel].transfer_count); + + if (channel == IOGA_DMA_FLOPPY) + { + LOG_DMA(channel, "dma: asserting fdc terminal count line\n"); + + m_fdc_tc_func(ASSERT_LINE); + m_fdc_tc_func(CLEAR_LINE); + } + + m_dma_channel[channel].dma_active = false; + } +} + void interpro_ioga_device::drq(int state, int channel) { // this member is called when the device has data ready for reading via dma @@ -607,6 +698,8 @@ void interpro_ioga_device::drq(int state, int channel) if (state) { + LOG_DMA(channel, "dma: recieved drq for channel %d\n", channel); + // TODO: check if dma is enabled m_dma_timer->adjust(attotime::zero, channel); } @@ -620,7 +713,7 @@ void interpro_ioga_device::drq(int state, int channel) */ // TODO: 7.0266 - forced BERR not working -uint32_t interpro_ioga_device::dma_r(address_space &space, offs_t offset, uint32_t mem_mask, int channel) +u32 interpro_ioga_device::dma_r(address_space &space, offs_t offset, u32 mem_mask, int channel) { switch (offset) { @@ -641,7 +734,7 @@ uint32_t interpro_ioga_device::dma_r(address_space &space, offs_t offset, uint32 return 0; } -void interpro_ioga_device::dma_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask, int channel) +void interpro_ioga_device::dma_w(address_space &space, offs_t offset, u32 data, u32 mem_mask, int channel) { switch (offset) { @@ -660,11 +753,24 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, uint32_t d case 3: m_dma_channel[channel].control = data & IOGA_DMA_CTRL_WMASK; - logerror("dma: channel = %d, control = 0x%08x, ra = 0x%08x, va = 0x%08x, tc = 0x%08x\n", - channel, data, m_dma_channel[channel].real_address, m_dma_channel[channel].virtual_address, m_dma_channel[channel].transfer_count); + logerror("dma: channel = %d, control = 0x%08x, ra = 0x%08x, va = 0x%08x, tc = 0x%08x at %s\n", + channel, data, m_dma_channel[channel].real_address, m_dma_channel[channel].virtual_address, m_dma_channel[channel].transfer_count, machine().describe_context()); + + // scsidiag + // dma ctrl = 0xbf000600 + // = 0xff000600 + // = 0x63xxxxxx + // 600 = scsi channel? + // b = 1011 + // f = 1111 + // 6 = 0101 + // -> bit 0x4 = read/write? + + + // mask // iogadiag test 7.0265 - if (data == IOGA_DMA_CTRL_START) + if (data & IOGA_DMA_CTRL_START) { uint32_t mask = 0; @@ -686,6 +792,14 @@ void interpro_ioga_device::dma_w(address_space &space, offs_t offset, uint32_t d // if bus grant is not enabled, set the busy flag if (!(m_arbctl & mask)) m_dma_channel[channel].control |= IOGA_DMA_CTRL_BUSY; +#if 0 + // flip transfer count zero on immediately if needed + if (m_dma_channel[channel].transfer_count == 0) + { + m_dma_channel[channel].control |= IOGA_DMA_CTRL_TCZERO; + set_irq_line(2, ASSERT_LINE); + } +#endif } break; } diff --git a/src/mame/machine/interpro_ioga.h b/src/mame/machine/interpro_ioga.h index 34d8ed8f7dd..766a11e9ab9 100644 --- a/src/mame/machine/interpro_ioga.h +++ b/src/mame/machine/interpro_ioga.h @@ -6,15 +6,14 @@ #pragma once - #define MCFG_INTERPRO_IOGA_ADD(_tag) \ - MCFG_DEVICE_ADD(_tag, INTERPRO_IOGA, 0) + 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_int) \ - devcb = &interpro_ioga_device::static_set_out_int_callback(*device, DEVCB_##_out_int); +#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_DMA_CB(_channel, _dma_r, _dma_w) \ devcb = &interpro_ioga_device::static_set_dma_r_callback(*device, _channel, DEVCB_##_dma_r); \ @@ -53,6 +52,7 @@ #define IOGA_NMI_ENABLE_IN 0x10 #define IOGA_NMI_ENABLE (IOGA_NMI_EDGE | IOGA_NMI_ENABLE_IN) +#define IOGA_INTERRUPT_NONE 0 #define IOGA_INTERRUPT_NMI 1 #define IOGA_INTERRUPT_INTERNAL 2 #define IOGA_INTERRUPT_EXTERNAL 3 @@ -70,13 +70,23 @@ #define IOGA_DMA_CTRL_RESET_L 0x61000000 // do not clear bus error bit #define IOGA_DMA_CTRL_RESET 0x60400000 // clear bus error bit -#define IOGA_DMA_CTRL_START 0x63000800 // perhaps start a transfer? - maybe the 8 is the channel? +#define IOGA_DMA_CTRL_START 0x10000000 +#define IOGA_DMA_CTRL_WRITE 0x40000000 // indicates memory to device transfer +#define IOGA_DMA_CTRL_BUSY 0x02000000 +#define IOGA_DMA_CTRL_BERR 0x00400000 // iogadiag code expects 0x60400000 on bus error +#define IOGA_DMA_CTRL_X 0x00800000 // another error bit? +#define IOGA_DMA_CTRL_Y 0x01000000 // turned off if either of two above are found +#define IOGA_DMA_CTRL_TCZERO 0x00000001 + +// DMA_ENABLE, INT_ENABLE, + +//#define IOGA_DMA_CTRL_START 0x63000800 // perhaps start a transfer? - maybe the 8 is the channel? #define IOGA_DMA_CTRL_UNK1 0x60000000 // don't know yet #define IOGA_DMA_CTRL_UNK2 0x67000600 // forced berr with nmi and interrupts disabled +#define IOGA_DMA_CTRL_UNK3 0xbf000600 // set by scsidiag before executing scsi "transfer information" command + // read values -#define IOGA_DMA_CTRL_BUSY 0x02000000 -#define IOGA_DMA_CTRL_BERR 0x00400000 // iogadiag code expects 0x60400000 on bus error // iogadiag expects 0x64400800 after forced berr with nmi/interrupts disabled @@ -97,7 +107,7 @@ 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_int_callback(device_t &device, _Object object) { return downcast(device).m_out_int_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); } @@ -150,7 +160,7 @@ public: DECLARE_WRITE32_MEMBER(timer2_w) { write_timer(2, data, IOGA_TIMER_2); } DECLARE_WRITE32_MEMBER(timer3_w) { write_timer(3, data, IOGA_TIMER_3); } - DECLARE_READ16_MEMBER(icr_r) { return m_int_vector[offset]; } + DECLARE_READ16_MEMBER(icr_r) { return m_hwicr[offset]; } DECLARE_WRITE16_MEMBER(icr_w); DECLARE_READ16_MEMBER(icr18_r) { return icr_r(space, 18, mem_mask); } DECLARE_WRITE16_MEMBER(icr18_w) { icr_w(space, 18, data, mem_mask); } @@ -160,7 +170,7 @@ public: DECLARE_READ8_MEMBER(nmictrl_r) { return m_nmictrl; } DECLARE_WRITE8_MEMBER(nmictrl_w); - DECLARE_READ16_MEMBER(softint_vector_r) { return m_softint_vector[offset]; } + DECLARE_READ16_MEMBER(softint_vector_r) { return m_swicr[offset]; } DECLARE_WRITE16_MEMBER(softint_vector_w); DECLARE_READ32_MEMBER(dma_plotter_r) { return dma_r(space, offset, mem_mask, IOGA_DMA_PLOTTER); } @@ -175,7 +185,9 @@ public: DECLARE_READ32_MEMBER(error_address_r) { return m_error_address; } DECLARE_READ32_MEMBER(error_businfo_r) { return m_error_businfo; } - void bus_error(uint32_t address, uint32_t cycle_type) { m_error_address = address; m_error_businfo = cycle_type; } + + DECLARE_WRITE32_MEMBER(bus_error) { m_error_address = data; m_error_businfo = offset; } + //void bus_error(uint32_t address, uint32_t cycle_type) { m_error_address = address; m_error_businfo = cycle_type; } protected: // device-level overrides @@ -188,64 +200,75 @@ private: 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; - static const device_timer_id IOGA_TIMER_DMA = 4; + static const device_timer_id IOGA_CLOCK = 5; 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, uint32_t value, device_timer_id id); + void write_timer(int timer, u32 value, device_timer_id id); - void update_interrupt(int state); + void interrupt_clock(); + void dma_clock(int channel); void drq(int state, int channel); devcb_write_line m_out_nmi_func; - devcb_write_line m_out_int_func; + devcb_write_line m_out_irq_func; address_space *m_memory_space; // dma channels struct dma { - uint32_t real_address; - uint32_t virtual_address; - uint32_t transfer_count; - uint32_t control; + u32 real_address; + u32 virtual_address; + u32 transfer_count; + u32 control; bool dma_active; int drq_state; devcb_read8 device_r; devcb_write8 device_w; } m_dma_channel[IOGA_DMA_CHANNELS]; - uint32_t m_dma_plotter_eosl; + u32 m_dma_plotter_eosl; devcb_write_line m_fdc_tc_func; - bool m_nmi_pending; - uint32_t m_interrupt_active; - uint32_t m_irq_current; - uint32_t m_irq_forced; + u32 m_active_interrupt_type; + u32 m_active_interrupt_number; - uint16_t m_int_vector[IOGA_INTERRUPT_COUNT]; - uint8_t m_softint; - uint8_t m_nmictrl; - uint16_t m_softint_vector[8]; + u32 m_hwint_forced; + bool m_nmi_forced; - uint32_t m_prescaler; - uint32_t m_timer_reg[3]; - uint16_t m_timer1_count; - uint32_t m_timer3_count; + u16 m_hwicr[IOGA_INTERRUPT_COUNT]; + u8 m_softint; + u8 m_nmictrl; + u16 m_swicr[8]; + + u32 m_prescaler; + u32 m_timer_reg[3]; + u16 m_timer1_count; + u32 m_timer3_count; emu_timer *m_timer[4]; // dma state emu_timer *m_dma_timer; - uint32_t dma_r(address_space &space, offs_t offset, uint32_t mem_mask, int channel); - void dma_w(address_space &space, offs_t offset, uint32_t data, uint32_t mem_mask, int channel); + 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); - uint16_t m_arbctl; + u16 m_arbctl; - uint32_t m_error_address; - uint32_t m_error_businfo; + u32 m_error_address; + u32 m_error_businfo; + + emu_timer *m_ioga_clock; + int m_nmi_state; + int m_irq_state; + + u32 m_int_line; + + bool nmi(int state); + bool irq(int state); }; // device type definition diff --git a/src/mame/machine/interpro_mcga.cpp b/src/mame/machine/interpro_mcga.cpp index ac6b0546a2b..5ccc934f54a 100644 --- a/src/mame/machine/interpro_mcga.cpp +++ b/src/mame/machine/interpro_mcga.cpp @@ -21,14 +21,44 @@ #define LOG_MCGA(...) {} #endif -DEVICE_ADDRESS_MAP_START(map, 16, interpro_mcga_device) - AM_RANGE(0x00, 0x3f) AM_READWRITE16(read, write, 0xffff) +DEVICE_ADDRESS_MAP_START(map, 32, interpro_mcga_device) + AM_RANGE(0x00, 0x03) AM_READWRITE16(reg00_r, reg00_w, 0xffff) + AM_RANGE(0x08, 0x0b) AM_READWRITE16(control_r, control_w, 0xffff) + AM_RANGE(0x10, 0x13) AM_READWRITE16(error_r, error_w, 0xffff) + AM_RANGE(0x18, 0x1b) AM_READWRITE8(frcrd_r, frcrd_w, 0xff) + AM_RANGE(0x20, 0x23) AM_READWRITE8(cbsub_r, cbsub_w, 0xff) + AM_RANGE(0x28, 0x2b) AM_READWRITE16(reg28_r, reg28_w, 0xffff) + AM_RANGE(0x30, 0x33) AM_READWRITE16(reg30_r, reg30_w, 0xffff) + AM_RANGE(0x38, 0x3b) AM_READWRITE16(memsize_r, memsize_w, 0xffff) +ADDRESS_MAP_END + +DEVICE_ADDRESS_MAP_START(map, 32, interpro_fmcc_device) + AM_RANGE(0x00, 0x03) AM_READWRITE16(reg00_r, reg00_w, 0xffff) + AM_RANGE(0x08, 0x0b) AM_READWRITE16(control_r, control_w, 0xffff) + AM_RANGE(0x10, 0x13) AM_READWRITE16(error_r, error_w, 0xffff) + AM_RANGE(0x18, 0x1b) AM_READWRITE8(frcrd_r, frcrd_w, 0xff) + AM_RANGE(0x20, 0x23) AM_READWRITE8(cbsub_r, cbsub_w, 0xff) + AM_RANGE(0x28, 0x2b) AM_READWRITE16(reg28_r, reg28_w, 0xffff) + AM_RANGE(0x30, 0x33) AM_READWRITE16(reg30_r, reg30_w, 0xffff) + AM_RANGE(0x38, 0x3b) AM_READWRITE16(memsize_r, memsize_w, 0xffff) + 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") + +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) +{ +} interpro_mcga_device::interpro_mcga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) - : device_t(mconfig, INTERPRO_MCGA, tag, owner, clock) + : interpro_mcga_device(mconfig, INTERPRO_MCGA, tag, owner, clock) +{ +} + +interpro_fmcc_device::interpro_fmcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : interpro_mcga_device(mconfig, INTERPRO_FMCC, tag, owner, clock) { } @@ -38,53 +68,30 @@ void interpro_mcga_device::device_start() void interpro_mcga_device::device_reset() { - m_reg[0] = 0x00ff; // 0x00 - m_reg[2] = MCGA_CTRL_ENREFRESH | MCGA_CTRL_CBITFRCSUB | MCGA_CTRL_CBITFRCRD; // 0x08 ctrl - //m_mcga[4] = 0x8000; // 0x10 error - m_reg[10] = 0x00ff; // 0x28 - m_reg[14] = 0x0340; // 0x38 memsize + m_reg[0] = 0x00ff; + m_control = MCGA_CTRL_ENREFRESH | MCGA_CTRL_CBITFRCSUB | MCGA_CTRL_CBITFRCRD; + m_reg[1] = 0x00ff; + m_memsize = 0x0340; } -WRITE16_MEMBER(interpro_mcga_device::write) +WRITE16_MEMBER(interpro_mcga_device::control_w) { - /* - read MEMSIZE 0x38 mask 0xffff - read 0x00 mask 0x0000 - write CBSUB 0x20 mask 0x00ff data 0 - write FRCRD 0x18 mask 0x00ff data 0 - read ERROR 0x10 mask 0xffff - read 0x00 mask 0xffff + m_control = data & MCGA_CTRL_MASK; - (0x38 >> 8) & 0xF == 3? - - if (0x00 != 0xFF) -> register reset error - - 0x00 = 0x0055 (test value & 0xff) - r7 = 0x00 & 0xff - */ - LOG_MCGA("mcga write offset = 0x%08x, mask = 0x%08x, data = 0x%08x, pc = 0x%08x\n", offset, mem_mask, data, space.device().safe_pc()); - switch (offset) - { - case 0x02: // MCGA_CTRL - // HACK: set or clear error status depending on ENMMBE bit - if (data & MCGA_CTRL_ENMMBE) - m_reg[4] |= MCGA_ERROR_VALID; - // else - // m_reg[4] &= ~MCGA_ERROR_VALID; - - default: - m_reg[offset] = data; - break; - } + // HACK: set or clear error status depending on ENMMBE bit + if (data & MCGA_CTRL_ENMMBE) + m_error |= MCGA_ERROR_VALID; + // else + // error &= ~MCGA_ERROR_VALID; } -READ16_MEMBER(interpro_mcga_device::read) +WRITE16_MEMBER(interpro_fmcc_device::control_w) { - LOG_MCGA("mcga read offset = 0x%08x, mask = 0x%08x, pc = 0x%08x\n", offset, mem_mask, space.device().safe_pc()); + m_control = data & FMCC_CTRL_MASK; - switch (offset) - { - default: - return m_reg[offset]; - } + // HACK: set or clear error status depending on ENMMBE bit + if (data & MCGA_CTRL_ENMMBE) + m_error |= MCGA_ERROR_VALID; + // else + // error &= ~MCGA_ERROR_VALID; } diff --git a/src/mame/machine/interpro_mcga.h b/src/mame/machine/interpro_mcga.h index bb48f9b1689..22535746ddc 100644 --- a/src/mame/machine/interpro_mcga.h +++ b/src/mame/machine/interpro_mcga.h @@ -6,19 +6,22 @@ #pragma once - // mcga control register -#define MCGA_CTRL_OPTMASK 0x00000003 -#define MCGA_CTRL_CBITFRCRD 0x00000004 -#define MCGA_CTRL_CBITFRCSUB 0x00000008 -#define MCGA_CTRL_ENREFRESH 0x00000010 -#define MCGA_CTRL_ENMSBE 0x00000100 -#define MCGA_CTRL_ENMMBE 0x00000200 -#define MCGA_CTRL_ENECC 0x00000400 -#define MCGA_CTRL_WRPROT 0x00008000 +#define MCGA_CTRL_OPTMASK 0x0003 +#define MCGA_CTRL_CBITFRCRD 0x0004 +#define MCGA_CTRL_CBITFRCSUB 0x0008 +#define MCGA_CTRL_ENREFRESH 0x0010 +#define MCGA_CTRL_ENMSBE 0x0100 +#define MCGA_CTRL_ENMMBE 0x0200 +#define MCGA_CTRL_ENECC 0x0400 +#define MCGA_CTRL_WRPROT 0x8000 + +// rom writes bit 0x80 to test if fmcc or mcga +#define MCGA_CTRL_MASK 0x871f +#define FMCC_CTRL_MASK 0x8fff // mcga error register -#define MCGA_ERROR_VALID 0x00008000 +#define MCGA_ERROR_VALID 0x00008000 class interpro_mcga_device : public device_t { @@ -27,18 +30,56 @@ public: virtual DECLARE_ADDRESS_MAP(map, 32); - DECLARE_WRITE16_MEMBER(write); - DECLARE_READ16_MEMBER(read); + DECLARE_READ16_MEMBER(reg00_r) { return m_reg[0]; } + DECLARE_WRITE16_MEMBER(reg00_w) { m_reg[0] = data; } + DECLARE_READ16_MEMBER(control_r) { return m_control; } + virtual DECLARE_WRITE16_MEMBER(control_w); + DECLARE_READ16_MEMBER(error_r) { return m_error; } + DECLARE_WRITE16_MEMBER(error_w) { m_error = data; } + DECLARE_READ8_MEMBER(frcrd_r) { return m_frcrd; } + DECLARE_WRITE8_MEMBER(frcrd_w) { m_frcrd = data; } + DECLARE_READ8_MEMBER(cbsub_r) { return m_cbsub; } + DECLARE_WRITE8_MEMBER(cbsub_w) { m_cbsub = data; } + DECLARE_READ16_MEMBER(reg28_r) { return m_reg[1]; } + DECLARE_WRITE16_MEMBER(reg28_w) { m_reg[1] = data; } + DECLARE_READ16_MEMBER(reg30_r) { return m_reg[2]; } + DECLARE_WRITE16_MEMBER(reg30_w) { m_reg[2] = data; } + DECLARE_READ16_MEMBER(memsize_r) { return m_memsize; } + DECLARE_WRITE16_MEMBER(memsize_w) { m_memsize = data; } protected: + interpro_mcga_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual void device_start() override; virtual void device_reset() override; + u16 m_control, m_error, m_memsize; + u8 m_frcrd, m_cbsub; + + u16 m_reg[3]; + private: - uint16_t m_reg[32]; + +}; + +class interpro_fmcc_device : public interpro_mcga_device +{ +public: + interpro_fmcc_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + virtual DECLARE_ADDRESS_MAP(map, 32) override; + + DECLARE_WRITE16_MEMBER(control_w) override; + + DECLARE_READ16_MEMBER(error_control_r) { return m_error_control; } + DECLARE_WRITE16_MEMBER(error_control_w) { m_error_control = data; } + +private: + u16 m_error_control; }; // device type definition DECLARE_DEVICE_TYPE(INTERPRO_MCGA, interpro_mcga_device) +DECLARE_DEVICE_TYPE(INTERPRO_FMCC, interpro_fmcc_device) #endif // MAME_MACHINE_INTERPRO_MCGA_H diff --git a/src/mame/machine/interpro_sga.cpp b/src/mame/machine/interpro_sga.cpp index 332225ffd74..8cc35fd82b3 100644 --- a/src/mame/machine/interpro_sga.cpp +++ b/src/mame/machine/interpro_sga.cpp @@ -17,33 +17,62 @@ #define VERBOSE 0 DEVICE_ADDRESS_MAP_START(map, 32, interpro_sga_device) - AM_RANGE(0x00, 0x03) AM_READWRITE(gcs_r, gcs_w) + AM_RANGE(0x00, 0x03) AM_READWRITE(gcsr_r, gcsr_w) AM_RANGE(0x04, 0x07) AM_READWRITE(ipoll_r, ipoll_w) AM_RANGE(0x08, 0x0b) AM_READWRITE(imask_r, imask_w) AM_RANGE(0x0c, 0x0f) AM_READWRITE(range_base_r, range_base_w) AM_RANGE(0x10, 0x13) AM_READWRITE(range_end_r, range_end_w) - AM_RANGE(0x14, 0x17) AM_READWRITE(cttag_r, cttag_w) - AM_RANGE(0x18, 0x1b) AM_READWRITE(address_r, address_w) - AM_RANGE(0x1c, 0x1f) AM_READWRITE(dmacs_r, dmacs_w) - AM_RANGE(0x20, 0x23) AM_READWRITE(edmacs_r, edmacs_w) + AM_RANGE(0x14, 0x17) AM_READWRITE(cttag_r, cttag_w) // aka diag1 + AM_RANGE(0x18, 0x1b) AM_READWRITE(address_r, address_w) // aka diag0 + AM_RANGE(0x1c, 0x1f) AM_READWRITE(dmacsr_r, dmacsr_w) + AM_RANGE(0x20, 0x23) AM_READWRITE(edmacsr_r, edmacsr_w) // esga + AM_RANGE(0x24, 0x27) AM_READWRITE(reg6_range_r, reg6_range_w) // esga - AM_RANGE(0xa4, 0xa7) AM_READWRITE(dspad1_r, dspad1_w) - AM_RANGE(0xa8, 0xab) AM_READWRITE(dsoff1_r, dsoff1_w) + AM_RANGE(0x80, 0x83) AM_READWRITE(ddpta0_r, ddpta0_w) // dma 0 device page table address (esga) + AM_RANGE(0x84, 0x87) AM_READWRITE(ddpad0_r, ddpad0_w) // dma 0 device page address + AM_RANGE(0x88, 0x8b) AM_READWRITE(ddoff0_r, ddoff0_w) // dma 0 device page offset + AM_RANGE(0x8c, 0x8f) AM_READWRITE(ddtc0_r, ddtc0_w) // dma 0 device transfer context - AM_RANGE(0xb4, 0xb7) AM_READWRITE(unknown1_r, unknown1_w) - AM_RANGE(0xb8, 0xbb) AM_READWRITE(unknown2_r, unknown2_w) - AM_RANGE(0xbc, 0xbf) AM_READWRITE(ddtc1_r, ddtc1_w) + AM_RANGE(0x90, 0x93) AM_READWRITE(dspta0_r, dspta0_w) // dma 0 SRX page table address (esga) + AM_RANGE(0x94, 0x97) AM_READWRITE(dspad0_r, dspad0_w) // dma 0 SRX page address + AM_RANGE(0x98, 0x9b) AM_READWRITE(dsoff0_r, dsoff0_w) // dma 0 SRX page offset + AM_RANGE(0x9c, 0x9f) AM_READWRITE(dstc0_r, dstc0_w) // dma 0 SRX transfer context + + AM_RANGE(0xa4, 0xa7) AM_READWRITE(dspad1_r, dspad1_w) // dma 1 source page address + AM_RANGE(0xa8, 0xab) AM_READWRITE(dsoff1_r, dsoff1_w) // dma 1 source page offset + AM_RANGE(0xac, 0xaf) AM_READWRITE(dstc1_r, dstc1_w) // dma 1 source transfer count + + AM_RANGE(0xb4, 0xb7) AM_READWRITE(ddpad1_r, ddpad1_w) // dma 1 destination page address + AM_RANGE(0xb8, 0xbb) AM_READWRITE(ddoff1_r, ddoff1_w) // dma 1 destination page offset + AM_RANGE(0xbc, 0xbf) AM_READWRITE(ddtc1_r, ddtc1_w) // dma 1 destination transfer count + + AM_RANGE(0xc0, 0xc3) AM_READWRITE(ddpta2_r, ddpta2_w) // dma 2 device page table address (esga) + AM_RANGE(0xc4, 0xc7) AM_READWRITE(ddpad2_r, ddpad2_w) // dma 2 device page address + AM_RANGE(0xc8, 0xcb) AM_READWRITE(ddoff2_r, ddoff2_w) // dma 2 device page offset + AM_RANGE(0xcc, 0xcf) AM_READWRITE(ddtc2_r, ddtc2_w) // dma 2 device transfer context + + AM_RANGE(0xd0, 0xd3) AM_READWRITE(dspta2_r, dspta2_w) // dma 2 SRX page table address (esga) + AM_RANGE(0xd4, 0xd7) AM_READWRITE(dspad2_r, dspad2_w) // dma 2 SRX page address + AM_RANGE(0xd8, 0xdb) AM_READWRITE(dsoff2_r, dsoff2_w) // dma 2 SRX page offset + AM_RANGE(0xdc, 0xdf) AM_READWRITE(dstc2_r, dstc2_w) // dma 2 SRX transfer context + + AM_RANGE(0xe0, 0xe3) AM_READWRITE(ddrd2_r, ddrd2_w) // dma 2 device record descriptor (esga) + AM_RANGE(0xe4, 0xe7) AM_READWRITE(dsrd2_r, dsrd2_w) // dma 2 SRX record descriptor (esga) + AM_RANGE(0xe8, 0xeb) AM_READWRITE(dcksum0_r, dcksum0_w) // dma 1 device checksum register 0 (esga) + 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") 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) + : device_t(mconfig, INTERPRO_SGA, tag, owner, clock), + out_berr_func(*this) { } void interpro_sga_device::device_start() { + out_berr_func.resolve(); } void interpro_sga_device::device_reset() @@ -52,16 +81,15 @@ void interpro_sga_device::device_reset() WRITE32_MEMBER(interpro_sga_device::ddtc1_w) { - // we assume that when this register is written, we should start a + m_ddtc1 = data; + + // assume that when this register is written, we should start a // memory to memory dma transfer - logerror(" gcs = 0x%08x dmacs = 0x%08x\n", m_gcs, m_dmacs); + 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\n", m_dspad1, m_dsoff1); - logerror(" unk1 = 0x%08x unk2 = 0x%08x\n", m_unknown1, m_unknown2); - logerror(" ddtc1 = 0x%08x\n", data); - - m_ddtc1 = data; + 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); // when complete, we indicate by setting DMAEND(2) - 2 is probably the channel // we also turn off the INTBERR and INTMMBE flags @@ -69,19 +97,17 @@ WRITE32_MEMBER(interpro_sga_device::ddtc1_w) m_ipoll |= 0x200; // if the address is invalid, fake a bus error - if (m_dspad1 == 0x40000000 || m_unknown1 == 0x40000000 - || m_dspad1 == 0x40000200 || m_unknown1 == 0x40000200) + if ((m_dspad1 & 0xfffff000) == 0x40000000 || (m_ddpad1 & 0xfffff) == 0x40000000) { m_ipoll |= 0x10000; // error cycle - bit 0x10 indicates source address error (dspad1) // now expecting 0x5463? -#if 0 if ((m_dspad1 & 0xfffff000) == 0x40000000) - m_ioga->bus_error(m_dspad1, 0x5433); + out_berr_func(space, 0x5433, m_dspad1); else - m_ioga->bus_error(m_unknown1, 0x5423); -#endif + out_berr_func(space, 0x5423, m_ddpad1); + // 0x5423 = BERR|SNAPOK | BG(ICAMMU)? | CT(23) // 0x5433 = BERR|SNAPOK | BG(ICAMMU)? | CT(33) // 0x5463 = BERR|SNAPOK | BG(ICAMMU)? | TAG(1) | CT(23) diff --git a/src/mame/machine/interpro_sga.h b/src/mame/machine/interpro_sga.h index ab850ea01a2..4232a436fa1 100644 --- a/src/mame/machine/interpro_sga.h +++ b/src/mame/machine/interpro_sga.h @@ -6,16 +6,20 @@ #pragma once +#define MCFG_INTERPRO_SGA_BERR_CB(_out_berr) \ + devcb = &interpro_sga_device::static_set_out_berr_callback(*device, DEVCB_##_out_berr); class interpro_sga_device : public device_t { public: interpro_sga_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + template static devcb_base &static_set_out_berr_callback(device_t &device, _Object object) { return downcast(device).out_berr_func.set_callback(object); } + virtual DECLARE_ADDRESS_MAP(map, 32); - DECLARE_READ32_MEMBER(gcs_r) { return m_gcs; } - DECLARE_WRITE32_MEMBER(gcs_w) { m_gcs = data; } + DECLARE_READ32_MEMBER(gcsr_r) { return m_gcsr; } + DECLARE_WRITE32_MEMBER(gcsr_w) { m_gcsr = data; } DECLARE_READ32_MEMBER(ipoll_r) { return m_ipoll; } DECLARE_WRITE32_MEMBER(ipoll_w) { m_ipoll = data; } DECLARE_READ32_MEMBER(imask_r) { return m_imask; } @@ -28,40 +32,121 @@ public: DECLARE_WRITE32_MEMBER(cttag_w) { m_cttag = data; } DECLARE_READ32_MEMBER(address_r) { return m_address; } DECLARE_WRITE32_MEMBER(address_w) { m_address = data; } - DECLARE_READ32_MEMBER(dmacs_r) { return m_dmacs; } - DECLARE_WRITE32_MEMBER(dmacs_w) { m_dmacs = data; } - DECLARE_READ32_MEMBER(edmacs_r) { return m_edmacs; } - DECLARE_WRITE32_MEMBER(edmacs_w) { m_edmacs = data; } + DECLARE_READ32_MEMBER(dmacsr_r) { return m_dmacsr; } + DECLARE_WRITE32_MEMBER(dmacsr_w) { m_dmacsr = data; } + + DECLARE_READ32_MEMBER(edmacsr_r) { return m_edmacsr; } + DECLARE_WRITE32_MEMBER(edmacsr_w) { m_edmacsr = data; } + DECLARE_READ32_MEMBER(reg6_range_r) { return m_reg6_range; } + DECLARE_WRITE32_MEMBER(reg6_range_w) { m_reg6_range = data; } + + DECLARE_READ32_MEMBER(ddpta0_r) { return m_ddpta0; } + DECLARE_WRITE32_MEMBER(ddpta0_w) { m_ddpta0 = data; } + DECLARE_READ32_MEMBER(ddpad0_r) { return m_ddpad0; } + DECLARE_WRITE32_MEMBER(ddpad0_w) { m_ddpad0 = data; } + DECLARE_READ32_MEMBER(ddoff0_r) { return m_ddoff0; } + DECLARE_WRITE32_MEMBER(ddoff0_w) { m_ddoff0 = data; } + DECLARE_READ32_MEMBER(ddtc0_r) { return m_ddtc0; } + DECLARE_WRITE32_MEMBER(ddtc0_w) { m_ddtc0 = data; } + + DECLARE_READ32_MEMBER(dspta0_r) { return m_dspta0; } + DECLARE_WRITE32_MEMBER(dspta0_w) { m_dspta0 = data; } + DECLARE_READ32_MEMBER(dspad0_r) { return m_dspad0; } + DECLARE_WRITE32_MEMBER(dspad0_w) { m_dspad0 = data; } + DECLARE_READ32_MEMBER(dsoff0_r) { return m_dsoff0; } + DECLARE_WRITE32_MEMBER(dsoff0_w) { m_dsoff0 = data; } + DECLARE_READ32_MEMBER(dstc0_r) { return m_dstc0; } + DECLARE_WRITE32_MEMBER(dstc0_w) { m_dstc0 = data; } + DECLARE_READ32_MEMBER(dspad1_r) { return m_dspad1; } DECLARE_WRITE32_MEMBER(dspad1_w) { m_dspad1 = data; } DECLARE_READ32_MEMBER(dsoff1_r) { return m_dsoff1; } DECLARE_WRITE32_MEMBER(dsoff1_w) { m_dsoff1 = data; } - DECLARE_READ32_MEMBER(unknown1_r) { return m_unknown1; } - DECLARE_WRITE32_MEMBER(unknown1_w) { m_unknown1 = data; } - DECLARE_READ32_MEMBER(unknown2_r) { return m_unknown2; } - DECLARE_WRITE32_MEMBER(unknown2_w) { m_unknown2 = data; } + DECLARE_READ32_MEMBER(dstc1_r) { return m_dstc1; } + DECLARE_WRITE32_MEMBER(dstc1_w) { m_dstc1 = data; } + + DECLARE_READ32_MEMBER(ddpad1_r) { return m_ddpad1; } + DECLARE_WRITE32_MEMBER(ddpad1_w) { m_ddpad1 = data; } + DECLARE_READ32_MEMBER(ddoff1_r) { return m_ddoff1; } + DECLARE_WRITE32_MEMBER(ddoff1_w) { m_ddoff1 = data; } DECLARE_READ32_MEMBER(ddtc1_r) { return m_ddtc1; } DECLARE_WRITE32_MEMBER(ddtc1_w); + DECLARE_READ32_MEMBER(ddpta2_r) { return m_ddpta2; } + DECLARE_WRITE32_MEMBER(ddpta2_w) { m_ddpta2 = data; } + DECLARE_READ32_MEMBER(ddpad2_r) { return m_ddpad2; } + DECLARE_WRITE32_MEMBER(ddpad2_w) { m_ddpad2 = data; } + DECLARE_READ32_MEMBER(ddoff2_r) { return m_ddoff2; } + DECLARE_WRITE32_MEMBER(ddoff2_w) { m_ddoff2 = data; } + DECLARE_READ32_MEMBER(ddtc2_r) { return m_ddtc2; } + DECLARE_WRITE32_MEMBER(ddtc2_w) { m_ddtc2 = data; } + + DECLARE_READ32_MEMBER(dspta2_r) { return m_dspta2; } + DECLARE_WRITE32_MEMBER(dspta2_w) { m_dspta2 = data; } + DECLARE_READ32_MEMBER(dspad2_r) { return m_dspad2; } + DECLARE_WRITE32_MEMBER(dspad2_w) { m_dspad2 = data; } + DECLARE_READ32_MEMBER(dsoff2_r) { return m_dsoff2; } + DECLARE_WRITE32_MEMBER(dsoff2_w) { m_dsoff2 = data; } + DECLARE_READ32_MEMBER(dstc2_r) { return m_dstc2; } + DECLARE_WRITE32_MEMBER(dstc2_w) { m_dstc2 = data; } + + DECLARE_READ32_MEMBER(ddrd2_r) { return m_ddrd2; } + DECLARE_WRITE32_MEMBER(ddrd2_w) { m_ddrd2 = data; } + DECLARE_READ32_MEMBER(dsrd2_r) { return m_dsrd2; } + DECLARE_WRITE32_MEMBER(dsrd2_w) { m_dsrd2 = data; } + DECLARE_READ32_MEMBER(dcksum0_r) { return m_dcksum0; } + DECLARE_WRITE32_MEMBER(dcksum0_w) { m_dcksum0 = data; } + DECLARE_READ32_MEMBER(dcksum1_r) { return m_dcksum1; } + DECLARE_WRITE32_MEMBER(dcksum1_w) { m_dcksum1 = data; } + protected: virtual void device_start() override; virtual void device_reset() override; private: - uint32_t m_gcs; // general control/status - uint32_t m_ipoll; // interrupt poll - uint32_t m_imask; // interrupt mask - uint32_t m_range_base; - uint32_t m_range_end; - uint32_t m_cttag; // error cycletype/tag - uint32_t m_address; - uint32_t m_dmacs; // dma control/status - uint32_t m_edmacs; // extended dma control/status - uint32_t m_dspad1; - uint32_t m_dsoff1; - uint32_t m_unknown1; - uint32_t m_unknown2; - uint32_t m_ddtc1; + u32 m_gcsr; // general control/status + u32 m_ipoll; // interrupt poll + u32 m_imask; // interrupt mask + u32 m_range_base; + u32 m_range_end; + u32 m_cttag; // error cycletype/tag, aka diag1 + u32 m_address; // aka diag0 + u32 m_dmacsr; // dma control/status + + u32 m_edmacsr; // extended dma control/status + u32 m_reg6_range; // region 6 range + + u32 m_ddpta0; // dma 0 device page table address + u32 m_ddpad0; // dma 0 device page address + u32 m_ddoff0; // dma 0 device page offset + u32 m_ddtc0; // dma 0 device transfer context + u32 m_dspta0; // dma 0 SRX page table address + u32 m_dspad0; // dma 0 SRX page address + u32 m_dsoff0; // dma 0 SRX page offset + u32 m_dstc0; // dma 0 SRX transfer context + + u32 m_dspad1; // dma 1 source page address + u32 m_dsoff1; // dma 1 source page offset + u32 m_dstc1; // dma 1 source transfer count + u32 m_ddpad1; // dma 1 destination page address + u32 m_ddoff1; // dma 1 destination page offset + u32 m_ddtc1; // dma 1 destination transfer count + + u32 m_ddpta2; // dma 2 device page table address + u32 m_ddpad2; // dma 2 device page address + u32 m_ddoff2; // dma 2 device page offset + u32 m_ddtc2; // dma 2 device transfer context + u32 m_dspta2; // dma 2 SRX page table address + u32 m_dspad2; // dma 2 SRX page address + u32 m_dsoff2; // dma 2 SRX page offset + u32 m_dstc2; // dma 2 SRX transfer context + + u32 m_ddrd2; // dma 2 device record descriptor + u32 m_dsrd2; // dma 2 SRX record descriptor + u32 m_dcksum0; // dma 1 device checksum register 0 + u32 m_dcksum1; // dma 1 device checksum register 1 + + devcb_write32 out_berr_func; }; // device type definition diff --git a/src/mame/machine/interpro_srarb.cpp b/src/mame/machine/interpro_srarb.cpp new file mode 100644 index 00000000000..a389a272317 --- /dev/null +++ b/src/mame/machine/interpro_srarb.cpp @@ -0,0 +1,46 @@ +// 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(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 new file mode 100644 index 00000000000..f1b5c9a34d5 --- /dev/null +++ b/src/mame/machine/interpro_srarb.h @@ -0,0 +1,52 @@ +// 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; } + 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; } + + DECLARE_READ32_MEMBER(tmctrl_r) { return tmctrl; } + DECLARE_WRITE32_MEMBER(tmctrl_w) { tmctrl = 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; +}; + +// device type definition +extern const device_type INTERPRO_SRARB; + +#endif // MAME_MACHINE_INTERPRO_SRARB_H