mirror of
https://github.com/holub/mame
synced 2025-04-23 00:39:36 +03:00
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:
parent
aa719358ad
commit
2b166ee1f6
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
46
src/mame/machine/interpro_srarb.cpp
Normal file
46
src/mame/machine/interpro_srarb.cpp
Normal 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()
|
||||
{
|
||||
}
|
52
src/mame/machine/interpro_srarb.h
Normal file
52
src/mame/machine/interpro_srarb.h
Normal 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
|
Loading…
Reference in New Issue
Block a user