summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Patrick Mackinlay <pmackinlay@hotmail.com>2019-07-03 20:50:27 +0700
committer Patrick Mackinlay <pmackinlay@hotmail.com>2019-07-03 20:50:27 +0700
commitbad674aca2c06981c8984015ed6583b02188515d (patch)
treef0800040071206a022aed8df765c29b3f11d965e
parentf8c1f01694571cb8ab369d60b15977d1ac6912ea (diff)
4dpi: wip (nw)
* lance and scsi working * monitor, fx and sash run (latter two from cdrom or network) * irix boots from miniroot but hangs
-rw-r--r--src/mame/drivers/4dpi.cpp318
1 files changed, 261 insertions, 57 deletions
diff --git a/src/mame/drivers/4dpi.cpp b/src/mame/drivers/4dpi.cpp
index 5416bdf9d50..801eea75c7f 100644
--- a/src/mame/drivers/4dpi.cpp
+++ b/src/mame/drivers/4dpi.cpp
@@ -22,18 +22,22 @@
****************************************************************************/
/*
* Sources:
+ * - http://www.bitsavers.org/pdf/sgi/personal_iris/SGI_IP-6_Schematic.pdf
* - http://www.futuretech.blinkenlights.nl/pitechrep.html
* - https://hardware.majix.org/computers/sgi.pi/index.shtml
* - http://archive.irix.cc/sgistuff/hardware/systems/personal.html
+ * - http://archive.irix.cc/developerforum95/Silicon_Graphics_Developer_Forum_95_The_CD_Volume_2/documents/hw_handbook_html/handbook.html
* - https://github.com/NetBSD/src/tree/trunk/sys/arch/sgimips/
*
* TODO:
* - IOC1 and CTL1
- * - graphics, keyboard, mouse, audio
+ * - graphics, audio
*
* Status:
- * - hangs waiting for wd33c93 reset interrupt
- * - if bypassed, hangs waiting on a timer(?) at bfa40004
+ * - eeprom is glitchy/unreliable
+ * - parity and cache diagnostics fail
+ * - boots monitor and fx/sash from cdrom or network
+ * - hangs after booting irix from miniroot
*/
#include "emu.h"
@@ -55,6 +59,8 @@
#include "machine/nscsi_hd.h"
#include "machine/nscsi_cd.h"
#include "bus/rs232/rs232.h"
+#include "bus/sgikbd/sgikbd.h"
+#include "bus/rs232/hlemouse.h"
// video and audio
#include "screen.h"
@@ -75,9 +81,10 @@ public:
, m_rtc(*this, "rtc")
, m_pit(*this, "pit")
, m_scsi(*this, "scsi:0:wd33c93")
- , m_net(*this, "net")
+ , m_enet(*this, "enet")
, m_duart(*this, "duart%u", 0U)
- , m_serial(*this, "serial%u", 0U)
+ , m_serial(*this, "serial%u", 1U)
+ , m_leds(*this, "led%u", 0U)
{
}
@@ -92,30 +99,92 @@ private:
required_device<dp8573_device> m_rtc;
required_device<pit8254_device> m_pit;
required_device<wd33c93_device> m_scsi;
- required_device<am7990_device> m_net;
+ required_device<am7990_device> m_enet;
required_device_array<scn2681_device, 2> m_duart;
required_device_array<rs232_port_device, 2> m_serial;
+ enum leds : unsigned
+ {
+ LED_HBT = 0, // heartbeat (1Hz)
+ LED_CPU = 1, // cpu activity
+ LED_GFX = 2, // graphics
+ LED_FPU = 3, // fpu present
+ };
+ output_finder<4> m_leds;
+
void map(address_map &map);
+ template <unsigned N> void lio_interrupt(int state) { lio_interrupt(N, state); }
+ void lio_interrupt(unsigned number, int state);
+ void scsi_drq(int state);
+
+ enum sysid_mask : u8
+ {
+ SID_SERDATA = 0x01, // serial memory data output state
+ SID_FPPRES = 0x02, // floating point processor present
+ SID_SERCLK = 0x04, // serial memory clock
+ SID_GDMAERR = 0x08, // error in graphics dma
+ SID_GDMAEN = 0x10, // graphics dma busy
+ SID_GDMARDY = 0x20, // asserted at end of graphics dma
+ SID_GDMARST = 0x40, // asserted in reset of graphics dma
+ SID_VMERMW = 0x80, // asserted in vme read-modify-write
+ };
+
+ enum lio_int_number : unsigned
+ {
+ LIO_D0 = 0, // duart 0 interrupt
+ LIO_D1 = 1, // duart 1 interrupt
+ LIO_VR = 2, // vertical retrace interrupt
+ LIO_CENTR = 3, // parallel port interrupt
+ LIO_SCSI = 4, // scsi interrupt
+ LIO_ENET = 5, // ethernet interrupt
+ LIO_GE = 6, // ge interrupt
+ LIO_FIFO = 7, // fifo full interrupt
+ LIO_AC = 8, // vme ac fail interrupt
+ LIO_VRSTAT = 9, // vert retrace status: no interrupt
+ };
+
+ enum mem_cfg_mask : u8
+ {
+ MCF_4MRAM = 0x10,
+ MCF_MEMSIZE = 0x1f,
+ MCF_TIMERDIS = 0x20, // reduce peripheral r/w strobe
+ MCF_FMEM = 0x40, // reduce cas pulse on reads
+ MCF_REFDIS = 0x80, // disable memory refresh
+ };
+
+ u8 m_mem_cfg;
u8 m_ctl_sysid;
+ u8 m_vme_isr;
+ u8 m_vme_imr;
u8 m_aux_cpuctrl;
u16 m_ctl_cpuctrl;
+ attotime m_refresh_timer;
- u8 m_int_mask;
+ u16 m_lio_isr;
+ u8 m_lio_imr;
+ bool m_lio_int;
+
+ u16 m_scsi_dmalo;
+ unsigned m_scsi_dmapage;
+ std::unique_ptr<u16 []> m_dma_map;
};
void ip6_state::map(address_map &map)
{
- //map(0x10000000, 0x1bffffff); // a32 kernel vme bus, vme modifier 0x09
- //map(0x1c000000, 0x1cffffff); // a24 kernel vme bus, vme modifier 0x3d
- //map(0x1e000000, 0x1effffff); // a24 kernel vme bus, vme modifier 0x39
+ //map(0x10000000, 0x1bffffff); // vme a32 modifier 0x09 non-privileged
+ //map(0x1c000000, 0x1cffffff); // vme a24 modifier 0x3d privileged
+ //map(0x1e000000, 0x1effffff); // vme a24 modifier 0x39 non-privileged
+ //map(0x1d000000, 0x1d00ffff); // vme a16 modifier 0x2d privileged
+ //map(0x1d100000, 0x1d10ffff); // vme a16 modifier 0x29 non-privileged
- //map(0x1f900000, 0x1f900000); // i/o controller (also lance and scsi)
+ //map(0x1df00000, 0x1df00003).umask32(0x0000ff00); // VME_IACK: vme interrupt acknowledge
+ map(0x1f800000, 0x1f800003).lw8("mem_cfg", [this](u8 data) { m_mem_cfg = data; }).umask32(0xff000000);
map(0x1f800000, 0x1f800003).lr8("ctl_sysid", [this]() { return m_ctl_sysid; }).umask32(0x00ff0000);
- map(0x1f840008, 0x1f84000b).ram().umask32(0x000000ff); // vme mask?
+ map(0x1f840000, 0x1f840003).lrw8("vme_isr", [this]() { return m_vme_isr; }, [this](u8 data) { m_vme_isr = data; }).umask32(0x000000ff);
+ map(0x1f840008, 0x1f84000b).lrw8("vme_imr", [this]() { return m_vme_imr; }, [this](u8 data) { m_vme_imr = data; }).umask32(0x000000ff);
map(0x1f880000, 0x1f880003).lrw16("ctl_cpuctrl",
[this]()
@@ -129,10 +198,14 @@ void ip6_state::map(address_map &map)
//BIT(data, 9); // reset system
//BIT(data, 10); // enable parity checking
//BIT(data, 11); // enable slave accesses
+ //BIT(data, 12); // enable vme arbiter
+ //BIT(data, 13); // write bad parity
//BIT(data, 14); // watchdog enable
+ //BIT(data, 15); // unused/fast peripheral cycle?
m_ctl_cpuctrl = data;
}).umask32(0x0000ffff);
+ //map(0x1f8c0000, 0x1f8c0003); // lca readback trigger (b)
map(0x1f8e0000, 0x1f8e0003).lrw8("aux_cpuctrl",
[this]()
{
@@ -140,50 +213,103 @@ void ip6_state::map(address_map &map)
},
[this](u8 data)
{
- //BIT(data, 1); // heartbeat
- //BIT(data, 4); // enable console led(?)/eeprom program enable?
+ // cpu leds
+ m_leds[LED_HBT] = BIT(data, 0);
+ m_leds[LED_CPU] = BIT(data, 1);
+ m_leds[LED_GFX] = BIT(data, 2);
+ m_leds[LED_FPU] = BIT(data, 3);
+
+ //BIT(data, 4); // console led(?) & eeprom program enable
m_eeprom->cs_write(BIT(data, 5));
m_eeprom->clk_write(BIT(data, 6));
+ //BIT(data, 7); // gfx_reset: reset graphics subsystem
m_aux_cpuctrl = data;
}).umask32(0xff000000);
- map(0x1f950000, 0x1f9501ff).rw(m_net, FUNC(am7990_device::regs_r), FUNC(am7990_device::regs_w)).umask32(0xffff0000);
+ map(0x1f900000, 0x1f900003).lrw16("scsi_dmalo_addr", [this]() { return m_scsi_dmalo; }, [this](u16 data) { m_scsi_dmalo = data; m_scsi_dmapage = 0; }).umask32(0x0000ffff);
+
+ /*
+ * DMA address mapping table is a pair of CY7C128-35PC 2048x8 SRAMs which
+ * read/write to data bus D27-12. A10 is tied high, giving 1024 entries.
+ */
+ map(0x1f920000, 0x1f920fff).lrw16("dma_map",
+ [this](offs_t offset)
+ {
+ return m_dma_map[offset];
+ },
+ [this](offs_t offset, u16 data, u16 mem_mask)
+ {
+ mem_mask &= 0x0fff;
+ COMBINE_DATA(&m_dma_map[offset]);
+ }).umask32(0x0000ffff);
+
+ //map(0x1f940000, 0x1f940003).umask32(?); // scsi_flush_addr
+
+ map(0x1f950000, 0x1f9501ff).rw(m_enet, FUNC(am7990_device::regs_r), FUNC(am7990_device::regs_w)).umask32(0xffff0000);
+ map(0x1f960000, 0x1f960007).lr8("enet_reset", [this](offs_t offset) { m_enet->reset_w(!offset); return 0; }).umask32(0xff000000);
- // local interrupt goes to cpu interrupt 1
- //map(0x1f980000, 0x1f980003).r().umask32(0x0000ffff); // int1_local_status
- map(0x1f980008, 0x1f98000b).lrw8("int_mask", [this]() { return m_int_mask; }, [this](u8 data) { m_int_mask = data; }).umask32(0x000000ff); // int1_local_mask
+ map(0x1f980000, 0x1f980003).lr16("lio_isr", [this]() { return m_lio_isr; }).umask32(0x0000ffff);
+ map(0x1f980008, 0x1f98000b).lrw8("lio_imr", [this]() { return m_lio_imr; }, [this](u8 data) { m_lio_imr = data; }).umask32(0x000000ff);
map(0x1fa00000, 0x1fa00003).lr8("timer1_ack", [this]() { m_cpu->set_input_line(INPUT_LINE_IRQ4, 0); return 0; }).umask32(0xff000000);
map(0x1fa20000, 0x1fa20003).lr8("timer0_ack", [this]() { m_cpu->set_input_line(INPUT_LINE_IRQ2, 0); return 0; }).umask32(0xff000000);
- //map(0x1fa40000, 0x1fa4000f).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask32(0xff000000); // NetBSD says 0x1fb40000?
+
+ //map(0x1fa40000, 0x1fa40000); // system bus error address
+ map(0x1fa40004, 0x1fa40007).lrw32("refresh_timer",
+ [this]()
+ {
+ return u32((machine().time() - m_refresh_timer).as_attoseconds() / ATTOSECONDS_PER_NANOSECOND);
+ },
+ [this](u32 data)
+ {
+ m_refresh_timer = machine().time() - attotime::from_nsec(data);
+ });
+
+ //map(0x1fa40008, 0x1fa4000b); // GDMA_DABR_PHYS descriptor array base register
+ //map(0x1fa4000c, 0x1fa4000f); // GDMA_BUFADR_PHYS buffer address register
+ //map(0x1fa40010, 0x1fa400013).umask32(0xffff0000); // GDMA_BURST_PHYS burst/delay register
+ //map(0x1fa40010, 0x1fa400013).umask32(0x0000ffff); // GDMA_BUFLEN_PHYS buffer length register
+
+ //map(0x1fa60000, 0x1fa600003); // VMA_RMW_ADDR
map(0x1fa80000, 0x1fa80007).lr32("scsi_reset", [this](offs_t offset) { m_scsi->reset_w(!!offset); return 0; });
- // TODO: firmware resets wd33c93 and expects it to produce an interrupt - device emulation is currently wrong
+ //map(0x1fa80008, 0x1fa8000b); // IOC2 configuration register, bus error on IOC1
+
+ //map(0x1faa0000, 0x1faa0003).umask32(0xff000000); // clear lan access bit
+ //map(0x1faa0000, 0x1faa0003).umask32(0x00ff0000); // clear dma access bit
+ //map(0x1faa0000, 0x1faa0003).umask32(0x0000ff00); // clear cpu access bit
+ //map(0x1faa0000, 0x1faa0003).umask32(0x000000ff); // clear vme access bit
+ //map(0x1faa0004, 0x1faa0007).umask32(0x00ff0000); // parity error register
+
map(0x1fb00000, 0x1fb00003).rw(m_scsi, FUNC(wd33c93_device::indir_addr_r), FUNC(wd33c93_device::indir_addr_w)).umask32(0x00ff0000);
map(0x1fb00100, 0x1fb00103).rw(m_scsi, FUNC(wd33c93_device::indir_reg_r), FUNC(wd33c93_device::indir_reg_w)).umask32(0x00ff0000);
map(0x1fb40000, 0x1fb4000f).rw(m_pit, FUNC(pit8254_device::read), FUNC(pit8254_device::write)).umask32(0xff000000);
- map(0x1fb80000, 0x1fb800ff).lrw8("duart0",
+ map(0x1fb80000, 0x1fb800ff).lrw8("duarts",
[this](offs_t offset)
{
- return m_duart[0]->read(offset >> 2);
+ return m_duart[BIT(offset, 0)]->read(offset >> 2);
},
[this](offs_t offset, u8 data)
{
- m_duart[0]->write(offset >> 2, data);
+ m_duart[BIT(offset, 0)]->write(offset >> 2, data);
}).umask32(0xff000000);
- map(0x1fbc0000, 0x1fbc00ff).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0xff000000);
+ map(0x1fbc0000, 0x1fbc007f).rw(m_rtc, FUNC(dp8573_device::read), FUNC(dp8573_device::write)).umask32(0xff000000);
map(0x1fc00000, 0x1fc3ffff).rom().region("prom", 0);
}
static void scsi_devices(device_slot_interface &device)
{
- device.option_add("cdrom", NSCSI_CDROM);
+ device.option_add("cdrom", NSCSI_CDROM_SGI).machine_config(
+ [](device_t *device)
+ {
+ downcast<nscsi_cdrom_device &>(*device).set_block_size(512);
+ });
device.option_add("harddisk", NSCSI_HARDDISK);
}
@@ -206,12 +332,12 @@ void ip6_state::configure(machine_config &config)
[this](int state)
{
if (state)
- m_ctl_sysid |= 0x01;
+ m_ctl_sysid |= SID_SERDATA;
else
- m_ctl_sysid &= ~0x01;
+ m_ctl_sysid &= ~SID_SERDATA;
});
- DP8573(config, m_rtc);
+ DP8573(config, m_rtc); // DP8572AN
PIT8254(config, m_pit);
m_pit->set_clk<2>(3.6864_MHz_XTAL);
@@ -222,11 +348,13 @@ void ip6_state::configure(machine_config &config)
NSCSI_BUS(config, "scsi");
NSCSI_CONNECTOR(config, "scsi:0").option_set("wd33c93", WD33C93).machine_config(
- [](device_t *device)
+ [this](device_t *device)
{
- device->set_clock(10000000);
+ wd33c93_device &wd33c93(downcast<wd33c93_device &>(*device));
- // TODO: connect irq and drq
+ wd33c93.set_clock(10000000);
+ wd33c93.irq_cb().set(*this, FUNC(ip6_state::lio_interrupt<LIO_SCSI>)).invert();
+ wd33c93.drq_cb().set(*this, FUNC(ip6_state::scsi_drq));
});
NSCSI_CONNECTOR(config, "scsi:1", scsi_devices, "harddisk", false);
NSCSI_CONNECTOR(config, "scsi:2", scsi_devices, nullptr, false);
@@ -236,42 +364,72 @@ void ip6_state::configure(machine_config &config)
NSCSI_CONNECTOR(config, "scsi:6", scsi_devices, "cdrom", false);
NSCSI_CONNECTOR(config, "scsi:7", scsi_devices, nullptr, false);
- AM7990(config, m_net);
- // TODO: irq, drq, memory accessors (via ioc)
+ AM7990(config, m_enet);
+ m_enet->intr_out().set(FUNC(ip6_state::lio_interrupt<LIO_ENET>));
+ m_enet->dma_in().set(
+ [this](offs_t offset)
+ {
+ unsigned const page = 0x200 + (offset >> 12);
+ u32 const address = (u32(m_dma_map[page]) << 12) | (offset & 0xfff);
- // duarts
- // NOTE: one of these is has 40 pins, while the other has only 24 pins; most
- // likely the keyboard/mouse one is without and doesn't have any flow control
- SCN2681(config, m_duart[0], 3.6864_MHz_XTAL);
- SCN2681(config, m_duart[1], 3.6864_MHz_XTAL); // TODO: probably for the keyboard and mouse
+ return m_cpu->space(0).read_word(address);
+ });
+ m_enet->dma_out().set(
+ [this](offs_t offset, u16 data, u16 mem_mask)
+ {
+ unsigned const page = 0x200 + (offset >> 12);
+ u32 const address = (u32(m_dma_map[page]) << 12) | (offset & 0xfff);
+
+ m_cpu->space(0).write_word(address, data, mem_mask);
+ });
+
+ // duart 0 (keyboard/mouse)
+ SCN2681(config, m_duart[0], 3.6864_MHz_XTAL); // SCN2681AC1N24
+ sgi_keyboard_port_device &keyboard_port(SGIKBD_PORT(config, "keyboard_port", default_sgi_keyboard_devices, "hlekbd"));
+ rs232_port_device &mouse_port(RS232_PORT(config, "mouse_port",
+ [](device_slot_interface &device)
+ {
+ device.option_add("mouse", SGI_HLE_SERIAL_MOUSE);
+ },
+ "mouse"));
+
+ // duart 0 outputs
+ m_duart[0]->irq_cb().set(FUNC(ip6_state::lio_interrupt<LIO_D0>));
+ m_duart[0]->a_tx_cb().set(keyboard_port, FUNC(sgi_keyboard_port_device::write_txd));
+ m_duart[0]->b_tx_cb().set(mouse_port, FUNC(rs232_port_device::write_txd));
+
+ // duart 0 inputs
+ keyboard_port.rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_a_w));
+ mouse_port.rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_b_w));
+
+ // duart 1 (serial ports)
+ SCN2681(config, m_duart[1], 3.6864_MHz_XTAL); // SCN2681AC1N40
RS232_PORT(config, m_serial[0], default_rs232_devices, "terminal");
RS232_PORT(config, m_serial[1], default_rs232_devices, nullptr);
- // duart 0 outputs
- // TODO: irq
- m_duart[0]->a_tx_cb().set(m_serial[0], FUNC(rs232_port_device::write_txd));
- m_duart[0]->b_tx_cb().set(m_serial[1], FUNC(rs232_port_device::write_txd));
- m_duart[0]->outport_cb().set(
+ // duart 1 outputs
+ m_duart[1]->irq_cb().set(FUNC(ip6_state::lio_interrupt<LIO_D1>));
+ m_duart[1]->a_tx_cb().set(m_serial[0], FUNC(rs232_port_device::write_txd));
+ m_duart[1]->b_tx_cb().set(m_serial[1], FUNC(rs232_port_device::write_txd));
+ m_duart[1]->outport_cb().set(
[this](u8 data)
{
m_serial[0]->write_rts(BIT(data, 0));
m_serial[1]->write_rts(BIT(data, 1));
- m_serial[0]->write_dtr(BIT(data, 2));
- m_serial[1]->write_dtr(BIT(data, 3));
-
- // TODO: bit 4-7
+ m_duart[1]->ip5_w(BIT(data, 3));
+ m_duart[1]->ip6_w(BIT(data, 3));
+ m_serial[0]->write_dtr(BIT(data, 4));
+ m_serial[1]->write_dtr(BIT(data, 5));
});
- // duart inputs (guessed for now)
- m_serial[0]->rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_a_w));
- m_serial[0]->cts_handler().set(m_duart[0], FUNC(scn2681_device::ip0_w));
- m_serial[0]->dsr_handler().set(m_duart[0], FUNC(scn2681_device::ip3_w));
- m_serial[0]->dcd_handler().set(m_duart[0], FUNC(scn2681_device::ip4_w));
+ // duart 1 inputs
+ m_serial[0]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_a_w));
+ m_serial[0]->cts_handler().set(m_duart[1], FUNC(scn2681_device::ip0_w));
+ m_serial[0]->dcd_handler().set(m_duart[1], FUNC(scn2681_device::ip3_w));
- m_serial[1]->rxd_handler().set(m_duart[0], FUNC(scn2681_device::rx_b_w));
- m_serial[1]->cts_handler().set(m_duart[0], FUNC(scn2681_device::ip1_w));
- m_serial[1]->dsr_handler().set(m_duart[0], FUNC(scn2681_device::ip5_w));
- m_serial[1]->dcd_handler().set(m_duart[0], FUNC(scn2681_device::ip6_w));
+ m_serial[1]->rxd_handler().set(m_duart[1], FUNC(scn2681_device::rx_b_w));
+ m_serial[1]->cts_handler().set(m_duart[1], FUNC(scn2681_device::ip1_w));
+ m_serial[1]->dcd_handler().set(m_duart[1], FUNC(scn2681_device::ip2_w));
}
void ip6_state::initialize()
@@ -279,7 +437,53 @@ void ip6_state::initialize()
// map the configured ram
m_cpu->space(0).install_ram(0x00000000, m_ram->mask(), m_ram->pointer());
- m_ctl_sysid = 0x02; // fpu present
+ m_ctl_sysid = SID_FPPRES;
+
+ m_lio_isr = 0x3ff;
+ m_lio_imr = 0;
+ m_lio_int = false;
+
+ m_refresh_timer = machine().time();
+
+ m_dma_map = make_unique_clear<u16 []>(2048);
+
+ m_leds.resolve();
+}
+
+void ip6_state::lio_interrupt(unsigned number, int state)
+{
+ u16 const mask = 1 << number;
+
+ // record interrupt state
+ if (!state)
+ m_lio_isr &= ~mask;
+ else
+ m_lio_isr |= mask;
+
+ // update interrupt line
+ bool const lio_int = ~m_lio_isr & m_lio_imr;
+ if (m_lio_imr ^ lio_int)
+ {
+ m_lio_int = lio_int;
+ m_cpu->set_input_line(INPUT_LINE_IRQ1, m_lio_int);
+ }
+}
+
+void ip6_state::scsi_drq(int state)
+{
+ if (state)
+ {
+ u32 const address = (u32(m_dma_map[m_scsi_dmapage]) << 12) | (m_scsi_dmalo & 0x0fff);
+
+ if (m_scsi_dmalo & 0x8000)
+ m_cpu->space(0).write_byte(address, m_scsi->dma_r());
+ else
+ m_scsi->dma_w(m_cpu->space(0).read_byte(address));
+
+ m_scsi_dmalo = (m_scsi_dmalo & 0xf000) | ((m_scsi_dmalo + 1) & 0x0fff);
+ if (!(m_scsi_dmalo & 0x0fff))
+ m_scsi_dmapage++;
+ }
}
ROM_START(4d20)