interpro improvements, plus some naive scsi hacks (#2330)

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.
This commit is contained in:
Patrick Mackinlay 2017-05-23 19:57:22 +07:00 committed by Vas Crabb
parent aa719358ad
commit 2b166ee1f6
17 changed files with 1484 additions and 453 deletions

View File

@ -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;

View File

@ -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 <limits.h>
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);

View File

@ -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());
}

View File

@ -22,7 +22,7 @@ public:
template <class Object> static devcb_base &set_irq_handler(device_t &device, Object &&cb) { return downcast<ncr5390_device &>(device).m_irq_handler.set_callback(std::forward<Object>(cb)); }
template <class Object> static devcb_base &set_drq_handler(device_t &device, Object &&cb) { return downcast<ncr5390_device &>(device).m_drq_handler.set_callback(std::forward<Object>(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

View File

@ -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;

View File

@ -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)

View File

@ -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<clipper_device> m_maincpu;
@ -97,11 +113,17 @@ public:
required_device<z80scc_device> m_scc2;
required_device<mc146818_device> m_rtc;
required_device<n82077aa_device> m_fdc;
#if NEW_SCSI
required_device<nscsi_bus_device> m_scsibus;
required_device<ncr53c94_device> m_scsi;
#else
required_device<ncr539x_device> m_scsi;
#endif
required_device<interpro_ioga_device> m_ioga;
required_device<interpro_mcga_device> m_mcga;
required_device<interpro_fmcc_device> m_mcga;
required_device<interpro_sga_device> m_sga;
required_device<interpro_srarb_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

View File

@ -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;
}

View File

@ -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

View File

@ -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;
}

View File

@ -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<class _Object> static devcb_base &static_set_out_nmi_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_out_nmi_func.set_callback(object); }
template<class _Object> static devcb_base &static_set_out_int_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_out_int_func.set_callback(object); }
template<class _Object> static devcb_base &static_set_out_irq_callback(device_t &device, _Object object) { return downcast<interpro_ioga_device &>(device).m_out_irq_func.set_callback(object); }
template<class _Object> static devcb_base &static_set_dma_r_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_channel[channel].device_r.set_callback(object); }
template<class _Object> static devcb_base &static_set_dma_w_callback(device_t &device, int channel, _Object object) { return downcast<interpro_ioga_device &>(device).m_dma_channel[channel].device_w.set_callback(object); }
@ -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

View File

@ -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;
}

View File

@ -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

View File

@ -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)

View File

@ -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<class _Object> static devcb_base &static_set_out_berr_callback(device_t &device, _Object object) { return downcast<interpro_sga_device &>(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

View File

@ -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()
{
}

View File

@ -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