summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author Miodrag Milanovic <mmicko@gmail.com>2014-03-07 13:35:21 +0000
committer Miodrag Milanovic <mmicko@gmail.com>2014-03-07 13:35:21 +0000
commit250dac1722b9f9f2ff602b4e40c2cd63cd97e504 (patch)
treef49e429b7d123f381c09b5b8e457860af49e48c8 /src/emu
parenta190ceefc53d10fcbb8b2a3b8fc7749975b7a987 (diff)
Shuffle ISA and some more PC related devices around (nw)
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/bus/bus.mak63
-rw-r--r--src/emu/bus/cbmiec/c1571.h4
-rw-r--r--src/emu/bus/isa/3c503.c306
-rw-r--r--src/emu/bus/isa/3c503.h62
-rw-r--r--src/emu/bus/isa/adlib.c89
-rw-r--r--src/emu/bus/isa/adlib.h37
-rw-r--r--src/emu/bus/isa/aha1542.c206
-rw-r--r--src/emu/bus/isa/aha1542.h58
-rw-r--r--src/emu/bus/isa/cga.c2209
-rw-r--r--src/emu/bus/isa/cga.h206
-rw-r--r--src/emu/bus/isa/com.c196
-rw-r--r--src/emu/bus/isa/com.h56
-rw-r--r--src/emu/bus/isa/dectalk.c215
-rw-r--r--src/emu/bus/isa/dectalk.h54
-rw-r--r--src/emu/bus/isa/ega.c1409
-rw-r--r--src/emu/bus/isa/ega.h106
-rw-r--r--src/emu/bus/isa/fdc.c158
-rw-r--r--src/emu/bus/isa/fdc.h85
-rw-r--r--src/emu/bus/isa/finalchs.c125
-rw-r--r--src/emu/bus/isa/finalchs.h48
-rw-r--r--src/emu/bus/isa/gblaster.c89
-rw-r--r--src/emu/bus/isa/gblaster.h37
-rw-r--r--src/emu/bus/isa/gus.c1740
-rw-r--r--src/emu/bus/isa/gus.h301
-rw-r--r--src/emu/bus/isa/hdc.c827
-rw-r--r--src/emu/bus/isa/hdc.h102
-rw-r--r--src/emu/bus/isa/ibm_mfc.c496
-rw-r--r--src/emu/bus/isa/ibm_mfc.h88
-rw-r--r--src/emu/bus/isa/ide.c118
-rw-r--r--src/emu/bus/isa/ide.h48
-rw-r--r--src/emu/bus/isa/isa.c790
-rw-r--r--src/emu/bus/isa/isa.h415
-rw-r--r--src/emu/bus/isa/isa_cards.c88
-rw-r--r--src/emu/bus/isa/isa_cards.h66
-rw-r--r--src/emu/bus/isa/lpt.c67
-rw-r--r--src/emu/bus/isa/lpt.h48
-rw-r--r--src/emu/bus/isa/mc1502_fdc.c240
-rw-r--r--src/emu/bus/isa/mc1502_fdc.h66
-rw-r--r--src/emu/bus/isa/mc1502_rom.c74
-rw-r--r--src/emu/bus/isa/mc1502_rom.h45
-rw-r--r--src/emu/bus/isa/mda.c745
-rw-r--r--src/emu/bus/isa/mda.h93
-rw-r--r--src/emu/bus/isa/mpu401.c91
-rw-r--r--src/emu/bus/isa/mpu401.h44
-rw-r--r--src/emu/bus/isa/mufdc.c205
-rw-r--r--src/emu/bus/isa/mufdc.h95
-rw-r--r--src/emu/bus/isa/ne1000.c135
-rw-r--r--src/emu/bus/isa/ne1000.h35
-rw-r--r--src/emu/bus/isa/ne2000.c145
-rw-r--r--src/emu/bus/isa/ne2000.h33
-rw-r--r--src/emu/bus/isa/omti8621.c1393
-rw-r--r--src/emu/bus/isa/omti8621.h154
-rw-r--r--src/emu/bus/isa/p1_fdc.c214
-rw-r--r--src/emu/bus/isa/p1_fdc.h61
-rw-r--r--src/emu/bus/isa/p1_hdc.c159
-rw-r--r--src/emu/bus/isa/p1_hdc.h58
-rw-r--r--src/emu/bus/isa/p1_rom.c79
-rw-r--r--src/emu/bus/isa/p1_rom.h45
-rw-r--r--src/emu/bus/isa/pc1640_iga.c120
-rw-r--r--src/emu/bus/isa/pc1640_iga.h49
-rw-r--r--src/emu/bus/isa/pds.c76
-rw-r--r--src/emu/bus/isa/pds.h38
-rw-r--r--src/emu/bus/isa/s3virge.c651
-rw-r--r--src/emu/bus/isa/s3virge.h46
-rw-r--r--src/emu/bus/isa/sblaster.c1673
-rw-r--r--src/emu/bus/isa/sblaster.h242
-rw-r--r--src/emu/bus/isa/side116.c191
-rw-r--r--src/emu/bus/isa/side116.h60
-rw-r--r--src/emu/bus/isa/ssi2001.c37
-rw-r--r--src/emu/bus/isa/ssi2001.h38
-rw-r--r--src/emu/bus/isa/stereo_fx.c231
-rw-r--r--src/emu/bus/isa/stereo_fx.h79
-rw-r--r--src/emu/bus/isa/svga_cirrus.c93
-rw-r--r--src/emu/bus/isa/svga_cirrus.h41
-rw-r--r--src/emu/bus/isa/svga_s3.c275
-rw-r--r--src/emu/bus/isa/svga_s3.h87
-rw-r--r--src/emu/bus/isa/svga_tseng.c92
-rw-r--r--src/emu/bus/isa/svga_tseng.h41
-rw-r--r--src/emu/bus/isa/vga.c82
-rw-r--r--src/emu/bus/isa/vga.h41
-rw-r--r--src/emu/bus/isa/vga_ati.c133
-rw-r--r--src/emu/bus/isa/vga_ati.h50
-rw-r--r--src/emu/bus/isa/wd1002a_wx1.c73
-rw-r--r--src/emu/bus/isa/wd1002a_wx1.h49
-rw-r--r--src/emu/bus/isa/wdxt_gen.c400
-rw-r--r--src/emu/bus/isa/wdxt_gen.h88
-rw-r--r--src/emu/bus/isa/xsu_cards.c36
-rw-r--r--src/emu/bus/isa/xsu_cards.h35
-rw-r--r--src/emu/bus/isa/xtide.c331
-rw-r--r--src/emu/bus/isa/xtide.h49
-rw-r--r--src/emu/bus/pc_joy/pc_joy.c91
-rw-r--r--src/emu/bus/pc_joy/pc_joy.h76
-rw-r--r--src/emu/bus/pc_joy/pc_joy_sw.c175
-rw-r--r--src/emu/bus/pc_joy/pc_joy_sw.h36
-rw-r--r--src/emu/emu.mak2
-rw-r--r--src/emu/machine/dp8390.c485
-rw-r--r--src/emu/machine/dp8390.h130
-rw-r--r--src/emu/machine/machine.mak37
-rw-r--r--src/emu/machine/mpu401.c287
-rw-r--r--src/emu/machine/mpu401.h70
-rw-r--r--src/emu/machine/pc_fdc.c195
-rw-r--r--src/emu/machine/pc_fdc.h75
-rw-r--r--src/emu/machine/pc_lpt.c170
-rw-r--r--src/emu/machine/pc_lpt.h85
-rw-r--r--src/emu/video/crtc_ega.c740
-rw-r--r--src/emu/video/crtc_ega.h223
-rw-r--r--src/emu/video/video.mak10
107 files changed, 23633 insertions, 2 deletions
diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak
index de21d12b3f5..b63079e04f1 100644
--- a/src/emu/bus/bus.mak
+++ b/src/emu/bus/bus.mak
@@ -292,6 +292,58 @@ endif
#-------------------------------------------------
#
+#@src/emu/bus/isa/isa.h,BUSES += ISA
+#-------------------------------------------------
+
+ifneq ($(filter ISA,$(BUSES)),)
+BUSOBJS += $(BUSOBJ)/isa/isa.o
+BUSOBJS += $(BUSOBJ)/isa/isa_cards.o
+BUSOBJS += $(BUSOBJ)/isa/mda.o
+BUSOBJS += $(BUSOBJ)/isa/wdxt_gen.o
+BUSOBJS += $(BUSOBJ)/isa/adlib.o
+BUSOBJS += $(BUSOBJ)/isa/com.o
+BUSOBJS += $(BUSOBJ)/isa/fdc.o
+BUSOBJS += $(BUSOBJ)/isa/mufdc.o
+BUSOBJS += $(BUSOBJ)/isa/finalchs.o
+BUSOBJS += $(BUSOBJ)/isa/gblaster.o
+BUSOBJS += $(BUSOBJ)/isa/gus.o
+BUSOBJS += $(BUSOBJ)/isa/hdc.o
+BUSOBJS += $(BUSOBJ)/isa/ibm_mfc.o
+BUSOBJS += $(BUSOBJ)/isa/mpu401.o
+BUSOBJS += $(BUSOBJ)/isa/sblaster.o
+BUSOBJS += $(BUSOBJ)/isa/stereo_fx.o
+BUSOBJS += $(BUSOBJ)/isa/ssi2001.o
+BUSOBJS += $(BUSOBJ)/isa/ide.o
+BUSOBJS += $(BUSOBJ)/isa/xtide.o
+BUSOBJS += $(BUSOBJ)/isa/side116.o
+BUSOBJS += $(BUSOBJ)/isa/aha1542.o
+BUSOBJS += $(BUSOBJ)/isa/wd1002a_wx1.o
+BUSOBJS += $(BUSOBJ)/isa/dectalk.o
+BUSOBJS += $(BUSOBJ)/isa/pds.o
+BUSOBJS += $(BUSOBJ)/isa/omti8621.o
+BUSOBJS += $(BUSOBJ)/isa/cga.o
+BUSOBJS += $(BUSOBJ)/isa/svga_cirrus.o
+BUSOBJS += $(BUSOBJ)/isa/ega.o
+BUSOBJS += $(BUSOBJ)/isa/vga.o
+BUSOBJS += $(BUSOBJ)/isa/vga_ati.o
+BUSOBJS += $(BUSOBJ)/isa/svga_tseng.o
+BUSOBJS += $(BUSOBJ)/isa/svga_s3.o
+BUSOBJS += $(BUSOBJ)/isa/s3virge.o
+BUSOBJS += $(BUSOBJ)/isa/pc1640_iga.o
+BUSOBJS += $(BUSOBJ)/isa/3c503.o
+BUSOBJS += $(BUSOBJ)/isa/ne1000.o
+BUSOBJS += $(BUSOBJ)/isa/ne2000.o
+BUSOBJS += $(BUSOBJ)/isa/lpt.o
+BUSOBJS += $(BUSOBJ)/isa/p1_fdc.o
+BUSOBJS += $(BUSOBJ)/isa/p1_hdc.o
+BUSOBJS += $(BUSOBJ)/isa/p1_rom.o
+BUSOBJS += $(BUSOBJ)/isa/mc1502_fdc.o
+BUSOBJS += $(BUSOBJ)/isa/mc1502_rom.o
+BUSOBJS += $(BUSOBJ)/isa/xsu_cards.o
+endif
+
+#-------------------------------------------------
+#
#@src/emu/bus/isbx/isbx.h,BUSES += ISBX
#-------------------------------------------------
@@ -317,6 +369,17 @@ endif
#-------------------------------------------------
#
+#@src/emu/bus/pc_joy/pc_joy.h,BUSES += PC_JOY
+#-------------------------------------------------
+
+ifneq ($(filter PC_JOY,$(BUSES)),)
+BUSOBJS += $(BUSOBJ)/pc_joy/pc_joy.o
+BUSOBJS += $(BUSOBJ)/pc_joy/pc_joy_sw.o
+endif
+
+
+#-------------------------------------------------
+#
#@src/emu/bus/pc_kbd/pc_kbdc.h,BUSES += PC_KBD
#-------------------------------------------------
diff --git a/src/emu/bus/cbmiec/c1571.h b/src/emu/bus/cbmiec/c1571.h
index 73406ecadfe..519ed496fe2 100644
--- a/src/emu/bus/cbmiec/c1571.h
+++ b/src/emu/bus/cbmiec/c1571.h
@@ -20,8 +20,8 @@
#include "cpu/m6502/m6502.h"
#include "machine/64h156.h"
#include "machine/6522via.h"
-#include "machine/isa.h"
-#include "machine/isa_wd1002a_wx1.h"
+#include "bus/isa/isa.h"
+#include "bus/isa/wd1002a_wx1.h"
#include "machine/mos6526.h"
#include "machine/wd_fdc.h"
diff --git a/src/emu/bus/isa/3c503.c b/src/emu/bus/isa/3c503.c
new file mode 100644
index 00000000000..285de414271
--- /dev/null
+++ b/src/emu/bus/isa/3c503.c
@@ -0,0 +1,306 @@
+#include "emu.h"
+#include "3c503.h"
+
+#define SADDR 0xcc000
+
+static const dp8390_interface el2_3c503_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, el2_3c503_device, el2_3c503_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(el2_3c503_config)
+ MCFG_DP8390D_ADD("dp8390d", el2_3c503_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type EL2_3C503 = &device_creator<el2_3c503_device>;
+
+machine_config_constructor el2_3c503_device::device_mconfig_additions() const {
+ return MACHINE_CONFIG_NAME(el2_3c503_config);
+}
+
+el2_3c503_device::el2_3c503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, EL2_3C503, "3C503 Network Adapter", tag, owner, clock, "el2_3c503", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_dp8390(*this, "dp8390d") {
+}
+
+void el2_3c503_device::device_start() {
+ char mac[7];
+ UINT32 num = rand();
+ memset(m_prom, 0x57, 16);
+ sprintf(mac, "\x02\x60\x8c%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff);
+ memcpy(m_prom, mac, 6);
+ memset(m_rom, 0, 8*1024); // empty
+ m_dp8390->set_mac(mac);
+ set_isa_device();
+ m_isa->install_device(0x0300, 0x030f, 0, 0, read8_delegate(FUNC(el2_3c503_device::el2_3c503_loport_r), this), write8_delegate(FUNC(el2_3c503_device::el2_3c503_loport_w), this));
+ m_isa->install_device(0x0700, 0x070f, 0, 0, read8_delegate(FUNC(el2_3c503_device::el2_3c503_hiport_r), this), write8_delegate(FUNC(el2_3c503_device::el2_3c503_hiport_w), this));
+
+ // TODO: This is wrong, fix if anything actually uses it
+ // DMA can change in runtime
+ int chan = 0, idcfr = m_regs.idcfr & 0x0f;
+ if((m_regs.streg & 0x08)) {
+ while(idcfr) {
+ chan++;
+ idcfr >>= 1;
+ }
+ m_isa->set_dma_channel(chan, this, FALSE);
+ }
+}
+
+void el2_3c503_device::device_reset() {
+ memcpy(m_prom, m_dp8390->get_mac(), 6);
+ memset(&m_regs, 0, sizeof(m_regs));
+ m_regs.bcfr = 0x80; // port 0x300
+ m_regs.pcfr = 0x20; // address 0xcc000
+ m_regs.ctrl = 0x0a;
+ m_irq_state = CLEAR_LINE;
+ m_isa->unmap_bank(SADDR, SADDR + 0x1fff, 0, 0);
+ m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 rom", m_rom);
+}
+
+void el2_3c503_device::set_irq(int state) {
+ switch(m_regs.idcfr & 0xf0) {
+ case 0x10:
+ m_isa->irq2_w(state);
+ break;
+ case 0x20:
+ m_isa->irq3_w(state);
+ break;
+ case 0x40:
+ m_isa->irq4_w(state);
+ break;
+ case 0x80:
+ m_isa->irq5_w(state);
+ break;
+ }
+}
+
+void el2_3c503_device::set_drq(int state) {
+ switch(m_regs.idcfr & 0x0f) {
+ case 0x01:
+ m_isa->drq1_w(state);
+ break;
+ case 0x02:
+ m_isa->drq2_w(state);
+ break;
+ case 0x04:
+ m_isa->drq3_w(state);
+ break;
+ }
+}
+
+void el2_3c503_device::eop_w(int state) {
+ if((m_regs.streg & 0x08) && (state == ASSERT_LINE)) {
+ m_regs.streg |= 0x10;
+ m_regs.streg &= ~0x08;
+ if(!(m_regs.gacfr & 0x40)) set_irq(ASSERT_LINE);
+ }
+}
+
+UINT8 el2_3c503_device::dack_r(int line) {
+ set_drq(CLEAR_LINE);
+ return el2_3c503_mem_read(m_regs.da++);
+}
+
+void el2_3c503_device::dack_w(int line, UINT8 data) {
+ set_drq(CLEAR_LINE);
+ el2_3c503_mem_write(m_regs.da++, data);
+}
+
+READ8_MEMBER(el2_3c503_device::el2_3c503_loport_r) {
+ switch((m_regs.ctrl >> 2) & 3) {
+ case 0:
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ return m_dp8390->dp8390_r(space, offset, mem_mask);
+ case 1:
+ return m_prom[offset];
+ case 2:
+ return m_prom[offset + 16];
+ case 3:
+ logerror("3c503: invalid low register read, page 3\n");
+ }
+ return 0;
+}
+
+WRITE8_MEMBER(el2_3c503_device::el2_3c503_loport_w) {
+ switch((m_regs.ctrl >> 2) & 3) {
+ case 0:
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ return m_dp8390->dp8390_w(space, offset, data, mem_mask);
+ case 1:
+ case 2:
+ logerror("3c503: invalid attempt to write to prom\n");
+ return;
+ case 3:
+ logerror("3c503: invalid low register write, page 3\n");
+ return;
+ }
+}
+
+READ8_MEMBER(el2_3c503_device::el2_3c503_hiport_r) {
+ switch(offset) {
+ case 0:
+ return m_regs.pstr;
+ case 1:
+ return m_regs.pspr;
+ case 2:
+ return m_regs.dqtr;
+ case 3:
+ return m_regs.bcfr;
+ case 4:
+ return m_regs.pcfr;
+ case 5:
+ return m_regs.gacfr;
+ case 6:
+ return m_regs.ctrl;
+ case 7:
+ return m_regs.streg;
+ case 8:
+ return m_regs.idcfr;
+ case 9:
+ return m_regs.da >> 8;
+ case 10:
+ return m_regs.da & 0xff;
+ case 11:
+ return (m_regs.vptr >> 12) & 0xff;
+ case 12:
+ return (m_regs.vptr >> 4) & 0xff;
+ case 13:
+ return (m_regs.vptr & 0x0f) << 4;
+ case 14:
+ if(!(m_regs.ctrl & 0x80)) return 0xff;
+ return el2_3c503_mem_read(space, m_regs.da++, mem_mask);
+ case 15:
+ if(!(m_regs.ctrl & 0x80)) return 0xff;
+ return el2_3c503_mem_read(space, m_regs.da++, mem_mask);
+ }
+ return 0;
+}
+
+WRITE8_MEMBER(el2_3c503_device::el2_3c503_hiport_w) {
+ switch(offset) {
+ case 0:
+ m_regs.pstr = data; // pstr and pspr are supposed to be set same as 8390 pstart and pstop
+ return; // what happens if they aren't?
+ case 1:
+ m_regs.pspr = data;
+ return;
+ case 2:
+ m_regs.dqtr = data;
+ return;
+ case 5:
+ if((m_regs.gacfr & 0xf) != (data & 0xf)) {
+ m_isa->unmap_bank(SADDR, SADDR + 0x1fff, 0, 0);
+ switch(data & 0xf) {
+ case 0:
+ m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 rom", m_rom);
+ break;
+ case 9:
+ m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 ram", m_board_ram);
+ break;
+ default:
+ m_isa->install_bank(SADDR, SADDR + 0x1fff, 0, 0, "3c503 no map", m_rom);
+ break;
+ }
+ }
+
+ if(!(data & 0x80)) set_irq(m_irq_state);
+ else set_irq(CLEAR_LINE);
+
+ m_regs.gacfr = data;
+ return;
+ case 6:
+ if(data & 1) {
+ device_reset();
+ m_regs.ctrl = 0x0b;
+ return;
+ }
+ if((data & 0x80) != (m_regs.ctrl & 0x80)) {
+ if(data & 0x80) m_regs.streg |= 0x88;
+ else m_regs.streg &= ~0x88;
+ m_regs.streg &= ~0x10;
+ }
+ m_regs.ctrl = data;
+ return;
+ case 8:
+ // allow only one irq and drq to be set, hw may not enforce this
+ switch(data & 0xf0) {
+ case 0x00:
+ case 0x10:
+ case 0x20:
+ case 0x40:
+ case 0x80:
+ m_regs.idcfr = (m_regs.idcfr & 0xf) | (data & 0xf0);
+ break;
+ default:
+ logerror("3c503: trying to set multiple irqs %X\n", data);
+ }
+ switch(data & 0x0f) {
+ case 0x00:
+ case 0x01:
+ case 0x02:
+ case 0x04:
+ m_regs.idcfr = (m_regs.idcfr & 0xf0) | (data & 0xf);
+ break;
+ case 0x08:
+ break;
+ default:
+ logerror("3c503: trying to set multiple drqs %X\n", data);
+ }
+ case 9:
+ if(m_regs.ctrl & 0x80) logerror("3c503: changing dma address during dma is undefined\n");
+ m_regs.da = (data << 8) | (m_regs.da & 0xff);
+ return;
+ case 10:
+ if(m_regs.ctrl & 0x80) logerror("3c503: changing dma address during dma is undefined\n");
+ m_regs.da = (m_regs.da & 0xff00) | data;
+ return;
+ case 11:
+ // vptr requires access to system memory address bus and so isn't currently emulatable
+ // it enables mmio to be set to rom on soft reset in case the machine is remote booted
+ m_regs.vptr = (data << 12) | (m_regs.vptr & 0xfff);
+ return;
+ case 12:
+ m_regs.vptr = (data << 4) | (m_regs.vptr & 0xff00f);
+ return;
+ case 13:
+ m_regs.vptr = (data >> 4) | (m_regs.vptr & 0xffff0);
+ return;
+ case 14:
+ if(!(m_regs.ctrl & 0x80)) return;
+ el2_3c503_mem_write(space, m_regs.da++, data, mem_mask);
+ return;
+ case 15:
+ if(!(m_regs.ctrl & 0x80)) return;
+ el2_3c503_mem_write(space, m_regs.da++, data, mem_mask);
+ return;
+ default:
+ logerror("3c503: invalid high register write %02x\n", offset);
+ }
+}
+
+WRITE_LINE_MEMBER(el2_3c503_device::el2_3c503_irq_w) {
+ m_irq_state = state;
+ if(!(m_regs.gacfr & 0x80)) set_irq(state);
+}
+
+READ8_MEMBER(el2_3c503_device::el2_3c503_mem_read) {
+ return el2_3c503_mem_read(offset);
+}
+
+WRITE8_MEMBER(el2_3c503_device::el2_3c503_mem_write) {
+ el2_3c503_mem_write(offset, data);
+}
+
+UINT8 el2_3c503_device::el2_3c503_mem_read(offs_t offset) {
+ if((offset < 8*1024) || (offset >= 16*1024)) return 0xff;
+ return m_board_ram[offset - (8*1024)];
+}
+
+void el2_3c503_device::el2_3c503_mem_write(offs_t offset, UINT8 data) {
+ if((offset < 8*1024) || (offset >= 16*1024)) return;
+ m_board_ram[offset - (8*1024)] = data;
+}
diff --git a/src/emu/bus/isa/3c503.h b/src/emu/bus/isa/3c503.h
new file mode 100644
index 00000000000..a8e4bc8722d
--- /dev/null
+++ b/src/emu/bus/isa/3c503.h
@@ -0,0 +1,62 @@
+/* 3com Etherlink II 3c503 */
+
+#ifndef __3C503_H__
+#define __3C503_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/dp8390.h"
+
+class el2_3c503_device: public device_t,
+ public device_isa8_card_interface
+{
+public:
+ el2_3c503_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ void el2_3c503_irq_w(int state);
+ DECLARE_READ8_MEMBER(el2_3c503_mem_read);
+ DECLARE_WRITE8_MEMBER(el2_3c503_mem_write);
+ DECLARE_READ8_MEMBER(el2_3c503_loport_r);
+ DECLARE_WRITE8_MEMBER(el2_3c503_loport_w);
+ DECLARE_READ8_MEMBER(el2_3c503_hiport_r);
+ DECLARE_WRITE8_MEMBER(el2_3c503_hiport_w);
+ void eop_w(int state);
+ UINT8 dack_r(int line);
+ void dack_w(int line, UINT8 data);
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ required_device<dp8390d_device> m_dp8390;
+ UINT8 m_board_ram[8*1024];
+ UINT8 m_rom[8*1024];
+ UINT8 m_prom[32];
+ UINT8 m_irq_state;
+
+ UINT8 el2_3c503_mem_read(offs_t offset);
+ void el2_3c503_mem_write(offs_t offset, UINT8 data);
+
+ void set_irq(int state);
+ void set_drq(int state);
+
+ struct {
+ UINT8 pstr;
+ UINT8 pspr;
+ UINT8 dqtr;
+ UINT8 bcfr;
+ UINT8 pcfr;
+ UINT8 gacfr;
+ UINT8 ctrl;
+ UINT8 streg;
+ UINT8 idcfr;
+ UINT16 da;
+ UINT32 vptr;
+ UINT8 rfmsb;
+ UINT8 rflsb;
+ } m_regs;
+};
+
+extern const device_type EL2_3C503;
+
+#endif
diff --git a/src/emu/bus/isa/adlib.c b/src/emu/bus/isa/adlib.c
new file mode 100644
index 00000000000..de59cb48fe8
--- /dev/null
+++ b/src/emu/bus/isa/adlib.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ ISA 8 bit Adlib Sound Card
+
+***************************************************************************/
+
+#include "emu.h"
+#include "adlib.h"
+#include "sound/speaker.h"
+#include "sound/3812intf.h"
+
+#define ym3812_StdClock 3579545
+
+static MACHINE_CONFIG_FRAGMENT( adlib_config )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 3.00)
+MACHINE_CONFIG_END
+
+static READ8_DEVICE_HANDLER( ym3812_16_r )
+{
+ ym3812_device *ym3812 = (ym3812_device *) device;
+
+ UINT8 retVal = 0xff;
+ switch(offset)
+ {
+ case 0 : retVal = ym3812->status_port_r( space, offset ); break;
+ }
+ return retVal;
+}
+
+static WRITE8_DEVICE_HANDLER( ym3812_16_w )
+{
+ ym3812_device *ym3812 = (ym3812_device *) device;
+
+ switch(offset)
+ {
+ case 0 : ym3812->control_port_w( space, offset, data ); break;
+ case 1 : ym3812->write_port_w( space, offset, data ); break;
+ }
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_ADLIB = &device_creator<isa8_adlib_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_adlib_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( adlib_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_adlib_device - constructor
+//-------------------------------------------------
+
+isa8_adlib_device::isa8_adlib_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_ADLIB, "Ad Lib Sound Card", tag, owner, clock, "isa_adlib", __FILE__),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_adlib_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(subdevice("ym3812"), 0x0388, 0x0389, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_adlib_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/adlib.h b/src/emu/bus/isa/adlib.h
new file mode 100644
index 00000000000..7f773112b78
--- /dev/null
+++ b/src/emu/bus/isa/adlib.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#ifndef __ISA_ADLIB_H__
+#define __ISA_ADLIB_H__
+
+#include "emu.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_adlib_device
+
+class isa8_adlib_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_adlib_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_ADLIB;
+
+#endif /* __ISA_ADLIB_H__ */
diff --git a/src/emu/bus/isa/aha1542.c b/src/emu/bus/isa/aha1542.c
new file mode 100644
index 00000000000..6a335d26fc6
--- /dev/null
+++ b/src/emu/bus/isa/aha1542.c
@@ -0,0 +1,206 @@
+// license:BSD-3-Clause or GPL
+// copyright-holders:Darkstar
+/**********************************************************************
+ *
+ * Adaptec AHA-1542{,C,CF} SCSI Controller
+ *
+ * Copyright MESS Team.
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ **********************************************************************/
+
+/*
+ PCB layout
+ ----------
+ Floppy SCSI
+ +-----------+ +------------------+ +-
+ +-----+-----------+-+------------------+--+
+ | |
+ | DIPSW DS1 |\
+ | +-----+ | |
+ | | | Y1 +---+ TRM TRM | |
+ | | U3 | |U5 | |S|
+ | U8 +-----+ +---+ |C|
+ | +---+ +------+ +-------+ |S|
+ | |U13| |U15 | Y2 | | |I|
+ | +---+ +------+ | | | |
+ | |U16 | |U17 | | |
+ | +------+ +-------+ |/
+ +-----------------------------------------+
+ ||||||||| ||||||||||||||||||||||||| |
+
+
+ DIPSW sw1 - sw8
+ U3 Intel chip labelled "AHA-1542CF/552800-01 D/9346", probably FDC (82077)
+ U5 Z84C0010VEC
+ U8 EEPROM(?) labelled 545120A
+ U13 CXK5864CM-10LL (64kbit SRAM)
+ U15 M27C256B labelled "ADAPTEC INC/553801-00 C/MCODE 563D/(C) 1993"
+ U16 M27C256B labelled "ADAPTEC INC/553601-00 C/BIOS C38D/(C) 1993"
+ U17 AIC-7970Q
+ Y1 XTAL SRX4054 93-38
+ Y2 XTAL SRX4053 93-40
+ TRM Dallas DS2107AS (SCSI termination)
+ DS1 LED
+
+*/
+
+/*
+ * The PCB has a couple of DIP switches:
+ *
+ * sw1 on enable termination
+ * off software-controlled termination
+ *
+ * sw2 sw3 sw4 I/O Port
+ * off off off 0x330 - 0x333 (default)
+ * on off off 0x334 - 0x337
+ * off on off 0x230 - 0x233
+ * on on off 0x234 - 0x237
+ * off off on 0x130 - 0x133
+ * on off on 0x134 - 0x137
+ * off on on reserved
+ * on on on reserved
+ *
+ * sw5 on disable floppy interface
+ * off enable floppy interface
+ *
+ * sw6 sw7 sw8 BIOS base address
+ * off off off 0xdc000 (default)
+ * on off off 0xd8000
+ * off on off 0xd4000
+ * on on off 0xd0000
+ * off off on 0xcc000
+ * on off on 0xc8000
+ * off on on reserved
+ * on on on BIOS disabled
+ *
+ * source: http://download.adaptec.com/pdfs/installation_guides/1540cfig.pdf
+ */
+
+#include "aha1542.h"
+#include "cpu/z80/z80.h"
+
+// I/O Port interface
+// READ Port x+0: STATUS
+// WRITE Port x+0: CONTROL
+//
+// READ Port x+1: DATA
+// WRITE Port x+1: COMMAND
+//
+// READ Port x+2: INTERRUPT STATUS
+// WRITE Port x+2: (undefined?)
+//
+// R/W Port x+3: (undefined)
+
+// READ STATUS flags
+#define STAT_STST 0x80 // self-test in progress
+#define STAT_DIAGF 0x40 // internal diagnostic failure
+#define STAT_INIT 0x20 // mailbox initialization required
+#define STAT_IDLE 0x10 // HBA is idle
+#define STAT_CDFULL 0x08 // Command/Data output port is full
+#define STAT_DFULL 0x04 // Data input port is full
+#define STAT_INVCMD 0x01 // Invalid command
+
+// READ INTERRUPT STATUS flags
+#define INTR_ANY 0x80 // any interrupt
+#define INTR_SRCD 0x08 // SCSI reset detected
+#define INTR_HACC 0x04 // HA command complete
+#define INTR_MBOA 0x02 // MBO empty
+#define INTR_MBIF 0x01 // MBI full
+
+// WRITE CONTROL commands
+#define CTRL_HRST 0x80 // Hard reset
+#define CTRL_SRST 0x40 // Soft reset
+#define CTRL_IRST 0x20 // interrupt reset
+#define CTRL_SCRST 0x10 // SCSI bus reset
+
+// READ/WRITE DATA commands
+#define CMD_NOP 0x00 // No operation
+#define CMD_MBINIT 0x01 // mailbox initialization
+#define CMD_START_SCSI 0x02 // Start SCSI command
+#define CMD_BIOSCMD 0x03 // undocumented BIOS conmmand (shadow RAM etc.)
+#define CMD_INQUIRY 0x04 // Adapter inquiry
+#define CMD_EMBOI 0x05 // enable Mailbox Out Interrupt
+#define CMD_SELTIMEOUT 0x06 // Set SEL timeout
+#define CMD_BUSON_TIME 0x07 // set bus-On time
+#define CMD_BUSOFF_TIME 0x08 // set bus-off time
+#define CMD_DMASPEED 0x09 // set ISA DMA speed
+#define CMD_RETDEVS 0x0a // return installed devices
+#define CMD_RETCONF 0x0b // return configuration data
+#define CMD_TARGET 0x0c // set HBA to target mode
+#define CMD_RETSETUP 0x0d // return setup data
+#define CMD_ECHO 0x1f // ECHO command data (NetBSD says it is 0x1e)
+
+// these are for 1541C only:
+#define CMD_RETDEVSHI 0x23 // return devices 8-15 (from NetBSD)
+#define CMD_EXTBIOS 0x28 // return extended BIOS information
+#define CMD_MBENABLE 0x29 // set mailbox interface enable
+
+const device_type AHA1542 = &device_creator<aha1542_device>;
+
+#define Z84C0010_TAG "u5"
+
+READ8_MEMBER( aha1542_device::aha1542_r )
+{
+ printf("%s aha1542_r(): offset=%d\n", machine().describe_context(), offset);
+ return 0xff;
+}
+
+WRITE8_MEMBER( aha1542_device::aha1542_w )
+{
+ printf("%s aha1542_w(): offset=%d data=0x%02x\n", machine().describe_context(), offset, data);
+}
+
+//-------------------------------------------------
+// ROM( aha1542 )
+//-------------------------------------------------
+
+ROM_START( aha1542 )
+ ROM_REGION( 0x8000, "aha1542", 0 )
+ ROM_LOAD( "553601-00.u16", 0x0000, 0x8000, CRC(AB22FC02) SHA1(f9f783e0272fc14ba3de32316997f1f6cadc67d0) ) /* Adaptec 1540CF/1542CF BIOS v2.01 */
+
+ ROM_REGION( 0x8000, Z84C0010_TAG, 0 )
+ ROM_LOAD( "553801-00.u15", 0x0000, 0x8000, CRC(7824397E) SHA1(35bc2c8fab31aad3190a478f2dc8f3a72958cf04) ) /* ADAPTEC, INC MCODE */
+ROM_END
+
+static ADDRESS_MAP_START( z84c0010_mem, AS_PROGRAM, 8, aha1542_device )
+ AM_RANGE(0x0000, 0x7fff) AM_ROM AM_REGION(Z84C0010_TAG, 0)
+ AM_RANGE(0x8000, 0x800f) AM_NOP // something is mapped there
+ AM_RANGE(0x9000, 0xafff) AM_RAM // 2kb RAM chip
+ AM_RANGE(0xe000, 0xe0ff) AM_RAM // probably PC<->Z80 communication area
+ AM_RANGE(0xb000, 0xb000) AM_NOP // something?
+ADDRESS_MAP_END
+
+static MACHINE_CONFIG_FRAGMENT( aha1542 )
+ MCFG_CPU_ADD(Z84C0010_TAG, Z80, XTAL_12MHz)
+ MCFG_CPU_PROGRAM_MAP( z84c0010_mem )
+MACHINE_CONFIG_END
+
+const rom_entry *aha1542_device::device_rom_region() const
+{
+ return ROM_NAME( aha1542 );
+}
+
+machine_config_constructor aha1542_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( aha1542 );
+}
+
+aha1542_device::aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, AHA1542, "AHA1542 SCSI Controller", tag, owner, clock, "aha1542", __FILE__ ),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+void aha1542_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xdc000, 0xdffff, 0, 0, "aha1542", "aha1542");
+ m_isa->install_device(0x330, 0x333, 0, 0, read8_delegate(FUNC( aha1542_device::aha1542_r ), this),
+ write8_delegate(FUNC( aha1542_device::aha1542_w ), this) );
+}
+
+
+void aha1542_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/aha1542.h b/src/emu/bus/isa/aha1542.h
new file mode 100644
index 00000000000..1a6122c8d74
--- /dev/null
+++ b/src/emu/bus/isa/aha1542.h
@@ -0,0 +1,58 @@
+/**********************************************************************
+ *
+ * Adaptec AHA-1542{,C,CF} SCSI Controller
+ *
+ * Copyright MESS Team.
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ **********************************************************************
+
+
+
+ **********************************************************************/
+
+#pragma once
+
+#ifndef __AHA1542__
+#define __AHA1542__
+
+
+#include "emu.h"
+#include "isa.h"
+
+//*********************************************************************
+// TYPE DEFINITIONS
+//*********************************************************************
+
+// ====================> aha1542_device
+
+class aha1542_device : public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ aha1542_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ DECLARE_READ8_MEMBER( aha1542_r );
+ DECLARE_WRITE8_MEMBER( aha1542_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_isa16_card_interface
+
+private:
+ // internal state
+};
+
+// device type definition
+
+extern const device_type AHA1542;
+
+#endif
diff --git a/src/emu/bus/isa/cga.c b/src/emu/bus/isa/cga.c
new file mode 100644
index 00000000000..d24d91a6567
--- /dev/null
+++ b/src/emu/bus/isa/cga.c
@@ -0,0 +1,2209 @@
+/***************************************************************************
+
+ Color Graphics Adapter (CGA) section
+
+
+ Notes on Port 3D8
+ (http://www.clipx.net/ng/interrupts_and_ports/ng2d045.php)
+
+ Port 3D8 - Color/VGA Mode control register
+
+ xx1x xxxx Attribute bit 7. 0=blink, 1=Intesity
+ xxx1 xxxx 640x200 mode
+ xxxx 1xxx Enable video signal
+ xxxx x1xx Select B/W mode
+ xxxx xx1x Select graphics
+ xxxx xxx1 80x25 text
+
+
+ The usage of the above control register for various modes is:
+ xx10 1100 40x25 alpha B/W
+ xx10 1000 40x25 alpha color
+ xx10 1101 80x25 alpha B/W
+ xx10 1001 80x25 alpha color
+ xxx0 1110 320x200 graph B/W
+ xxx0 1010 320x200 graph color
+ xxx1 1110 640x200 graph B/W
+
+
+ PC1512 display notes
+
+ The PC1512 built-in display adaptor is an emulation of IBM's CGA. Unlike a
+ real CGA, it is not built around a real MC6845 controller, and so attempts
+ to get custom video modes out of it may not work as expected. Its 640x200
+ CGA mode can be set up to be a 16-color mode rather than mono.
+
+ If you program it with BIOS calls, the PC1512 behaves just like a real CGA,
+ except:
+
+ - The 'greyscale' text modes (0 and 2) behave just like the 'color'
+ ones (1 and 3). On a color monitor both are in color; on a mono
+ monitor both are in greyscale.
+ - Mode 5 (the 'greyscale' graphics mode) displays in color, using
+ an alternative color palette: Cyan, Red and White.
+ - The undocumented 160x100x16 "graphics" mode works correctly.
+
+ (source John Elliott http://www.seasip.info/AmstradXT/pc1512disp.html)
+
+
+ Cursor signal handling:
+
+ The alpha dots signal is set when a character pixel should be set. This signal is
+ also set when the cursor should be displayed. The following formula for alpha
+ dots is derived from the schematics:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK OR NOT ENABLE BLINK ) AND ( CHG DOTS ) )
+
+ -CURSOR BLINK = VSYNC DLY (LS393) (changes every 8 vsyncs)
+ -BLINK = -CURSOR BLINK (LS393) (changes every 16 vsyncs)
+ -CURSOR DLY = -CURSOR signal from mc6845 and LS174
+ CHG DOTS = character pixel (from character rom)
+
+ For non-blinking modes this formula reduces to:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( CHG DOTS )
+
+ This means the cursor switches on/off state every 8 vsyncs.
+
+
+ For blinking modes this formula reduces to:
+ ALPHA DOTS = ( ( CURSOR DLY ) AND ( CURSOR BLINK ) ) OR ( ( ( NOT AT7 ) OR CURSOR DLY OR -BLINK ) AND ( CHG DOTS ) )
+
+ So, at the cursor location the attribute blinking is ignored and only regular
+ cursor blinking takes place (state switches every 8 vsyncs). On non-cursor
+ locations with the highest attribute bits set the character will switch
+ on/off every 16 vsyncs. In all other cases the character is displayed as
+ usual.
+
+
+TODO:
+- Update more drivers in MESS and MAME and unify with src/emu/video/pc_cga.c
+- Separate out more cards/implementations
+
+***************************************************************************/
+
+#include "emu.h"
+#include "video/mc6845.h"
+#include "cga.h"
+
+#define VERBOSE_CGA 0 /* CGA (Color Graphics Adapter) */
+
+#define CGA_PALETTE_SETS 83 /* one for colour, one for mono,
+ * 81 for colour composite */
+
+#define CGA_SCREEN_NAME "screen"
+#define CGA_MC6845_NAME "mc6845_cga"
+
+#define CGA_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_CGA>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine.time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+/***************************************************************************
+
+ Static declarations
+
+***************************************************************************/
+
+static INPUT_PORTS_START( cga )
+ PORT_START( "cga_config" )
+ PORT_CONFNAME( 0x03, 0x00, "CGA character set")
+ PORT_CONFSETTING(0x00, DEF_STR( Normal ))
+ PORT_CONFSETTING(0x01, "Alternative")
+ PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type")
+ PORT_CONFSETTING(0x00, "Colour RGB")
+ PORT_CONFSETTING(0x04, "Mono RGB")
+ PORT_CONFSETTING(0x08, "Colour composite")
+ PORT_CONFSETTING(0x0C, "Television")
+ PORT_CONFSETTING(0x10, "LCD")
+ PORT_CONFNAME( 0xE0, 0x00, "CGA chipset")
+ PORT_CONFSETTING(0x00, "IBM")
+ PORT_CONFSETTING(0x20, "Amstrad PC1512")
+ PORT_CONFSETTING(0x40, "Amstrad PPC512")
+ PORT_CONFSETTING(0x60, "ATI")
+ PORT_CONFSETTING(0x80, "Paradise")
+INPUT_PORTS_END
+
+
+static INPUT_PORTS_START( pc1512 )
+ PORT_START( "cga_config" )
+ PORT_CONFNAME( 0x03, 0x03, "CGA character set")
+ PORT_CONFSETTING(0x00, "Greek")
+ PORT_CONFSETTING(0x01, "Danish 2")
+ PORT_CONFSETTING(0x02, "Danish 1")
+ PORT_CONFSETTING(0x03, "Default")
+ PORT_CONFNAME( 0x1C, 0x00, "CGA monitor type")
+ PORT_CONFSETTING(0x00, "Colour RGB")
+ PORT_CONFSETTING(0x04, "Mono RGB")
+ PORT_BIT ( 0xE0, 0x20, IPT_UNUSED ) /* Chipset is always PC1512 */
+INPUT_PORTS_END
+
+
+/* Dipswitch for font selection */
+#define CGA_FONT (m_cga_config->read() & m_font_selection_mask)
+
+/* Dipswitch for monitor selection */
+#define CGA_MONITOR (m_cga_config->read()&0x1C)
+#define CGA_MONITOR_RGB 0x00 /* Colour RGB */
+#define CGA_MONITOR_MONO 0x04 /* Greyscale RGB */
+#define CGA_MONITOR_COMPOSITE 0x08 /* Colour composite */
+#define CGA_MONITOR_TELEVISION 0x0C /* Television */
+#define CGA_MONITOR_LCD 0x10 /* LCD, eg PPC512 */
+
+
+/* Dipswitch for chipset selection */
+/* TODO: Get rid of this; these should be handled by separate classes */
+#define CGA_CHIPSET (m_cga_config->read() & 0xE0)
+#define CGA_CHIPSET_IBM 0x00 /* Original IBM CGA */
+#define CGA_CHIPSET_PC1512 0x20 /* PC1512 CGA subset */
+#define CGA_CHIPSET_PC200 0x40 /* PC200 in CGA mode */
+#define CGA_CHIPSET_ATI 0x60 /* ATI (supports Plantronics) */
+#define CGA_CHIPSET_PARADISE 0x80 /* Paradise (used in PC1640) */
+
+
+/* CGA palettes
+ *
+ * The first 16 are for RGB monitors
+ * The next 16 are for greyscale modes
+ * The next 16 are for text modes on colour composite
+ * The next 16*16 are Mode 6 (colour composite) }
+ * The next 64*16 are Mode 4 (colour composite) } both indexed by the CGA colour select register 0x3D9
+ *
+ */
+
+const unsigned char cga_palette[16 * CGA_PALETTE_SETS][3] =
+{
+/* RGB colours */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0xaa }, { 0x00, 0xaa, 0x00 }, { 0x00, 0xaa, 0xaa },
+ { 0xaa, 0x00, 0x00 }, { 0xaa, 0x00, 0xaa }, { 0xaa, 0x55, 0x00 }, { 0xaa, 0xaa, 0xaa },
+ { 0x55, 0x55, 0x55 }, { 0x55, 0x55, 0xff }, { 0x55, 0xff, 0x55 }, { 0x55, 0xff, 0xff },
+ { 0xff, 0x55, 0x55 }, { 0xff, 0x55, 0xff }, { 0xff, 0xff, 0x55 }, { 0xff, 0xff, 0xff },
+/* Greyscale */
+ { 0x00, 0x00, 0x00 }, { 0x11, 0x11, 0x11 }, { 0x44, 0x44, 0x44 }, { 0x55, 0x55, 0x55 },
+ { 0x22, 0x22, 0x22 }, { 0x33, 0x33, 0x33 }, { 0x66, 0x66, 0x66 }, { 0x77, 0x77, 0x77 },
+ { 0x88, 0x88, 0x88 }, { 0x99, 0x99, 0x99 }, { 0xCC, 0xCC, 0xCC }, { 0xDD, 0xDD, 0xDD },
+ { 0xAA, 0xAA, 0xAA }, { 0xBB, 0xBB, 0xBB }, { 0xEE, 0xEE, 0xEE }, { 0xFF, 0xFF, 0xFF },
+/* Text mode, composite monitor */
+ { 0x00, 0x00, 0x00 }, { 0x0E, 0x00, 0x7A }, { 0x07, 0x55, 0x00 }, { 0x02, 0x65, 0x39 },
+ { 0x51, 0x00, 0x1A }, { 0x54, 0x00, 0x76 }, { 0x48, 0x63, 0x00 }, { 0x8c, 0x8c, 0x8c },
+ { 0x38, 0x38, 0x38 }, { 0x58, 0x49, 0xD5 }, { 0x5F, 0xAD, 0x26 }, { 0x5B, 0xB9, 0xAC },
+ { 0xAA, 0x4A, 0x5E }, { 0xA7, 0x55, 0xD2 }, { 0xA2, 0xB9, 0x31 }, { 0xE2, 0xE2, 0xE2 },
+/* Composite hi-res, colour reg = 0 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 }, { 0x00, 0x00, 0x00 },
+/* Composite hi-res, colour reg = 1 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x04, 0x04 }, { 0x00, 0x00, 0x61 }, { 0x00, 0x00, 0x6b },
+ { 0x25, 0x00, 0x1E }, { 0x15, 0x00, 0x23 }, { 0x18, 0x00, 0x87 }, { 0x06, 0x00, 0x91 },
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x0b, 0x00 }, { 0x00, 0x00, 0x4C }, { 0x00, 0x02, 0x52 },
+ { 0x24, 0x00, 0x08 }, { 0x0E, 0x00, 0x0D }, { 0x18, 0x00, 0x6f }, { 0x07, 0x00, 0x7C },
+/* Composite hi-res, colour reg = 2 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x28, 0x00 }, { 0x01, 0x00, 0x46 }, { 0x00, 0x21, 0x36 },
+ { 0x22, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x1b, 0x00, 0x43 }, { 0x00, 0x22, 0x33 },
+ { 0x07, 0x0D, 0x00 }, { 0x00, 0x4B, 0x00 }, { 0x04, 0x0E, 0x00 }, { 0x00, 0x57, 0x00 },
+ { 0x25, 0x02, 0x00 }, { 0x01, 0x46, 0x00 }, { 0x30, 0x04, 0x00 }, { 0x04, 0x53, 0x00 },
+/* Composite hi-res, colour reg = 3 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x30, 0x00 }, { 0x00, 0x00, 0x8E }, { 0x00, 0x38, 0x87 },
+ { 0x2E, 0x00, 0x01 }, { 0x00, 0x21, 0x00 }, { 0x22, 0x00, 0x8C }, { 0x00, 0x35, 0x95 },
+ { 0x00, 0x0F, 0x00 }, { 0x00, 0x4F, 0x00 }, { 0x00, 0x0B, 0x3F }, { 0x00, 0x62, 0x45 },
+ { 0x29, 0x00, 0x00 }, { 0x00, 0x4E, 0x00 }, { 0x35, 0x04, 0x48 }, { 0x01, 0x62, 0x49 },
+/* Composite hi-res, colour reg = 4 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x06, 0x02 }, { 0x01, 0x00, 0x1f }, { 0x00, 0x00, 0x24 },
+ { 0x54, 0x00, 0x38 }, { 0x25, 0x00, 0x23 }, { 0x3A, 0x00, 0x4f }, { 0x29, 0x00, 0x56 },
+ { 0x10, 0x03, 0x00 }, { 0x06, 0x08, 0x00 }, { 0x15, 0x00, 0x00 }, { 0x02, 0x03, 0x00 },
+ { 0x82, 0x00, 0x00 }, { 0x49, 0x00, 0x00 }, { 0x5B, 0x00, 0x0b }, { 0x52, 0x00, 0x0c },
+/* Composite hi-res, colour reg = 5 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x2c, 0x00 }, { 0x06, 0x01, 0x57 }, { 0x00, 0x22, 0x42 },
+ { 0x33, 0x00, 0x01 }, { 0x00, 0x26, 0x00 }, { 0x3a, 0x00, 0x54 }, { 0x08, 0x1D, 0x54 },
+ { 0x13, 0x17, 0x00 }, { 0x00, 0x64, 0x00 }, { 0x29, 0x15, 0x00 }, { 0x00, 0x64, 0x00 },
+ { 0x59, 0x0A, 0x00 }, { 0x30, 0x61, 0x00 }, { 0x7A, 0x06, 0x00 }, { 0x4A, 0x64, 0x00 },
+/* Composite hi-res, colour reg = 6 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x33, 0x00 }, { 0x06, 0x00, 0x5E }, { 0x00, 0x22, 0x45 },
+ { 0x34, 0x00, 0x04 }, { 0x00, 0x1e, 0x00 }, { 0x3d, 0x00, 0x4c }, { 0x0c, 0x22, 0x58 },
+ { 0x18, 0x19, 0x00 }, { 0x00, 0x62, 0x00 }, { 0x2b, 0x14, 0x00 }, { 0x01, 0x64, 0x00 },
+ { 0x57, 0x0f, 0x00 }, { 0x29, 0x63, 0x00 }, { 0x78, 0x09, 0x00 }, { 0x51, 0x61, 0x00 },
+/* Composite hi-res, colour reg = 7 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x3C, 0x01 }, { 0x04, 0x00, 0xC5 }, { 0x00, 0x4C, 0xC7 },
+ { 0x6A, 0x00, 0x15 }, { 0x28, 0x28, 0x24 }, { 0x8A, 0x00, 0xF8 }, { 0x70, 0x61, 0xFF },
+ { 0x20, 0x33, 0x00 }, { 0x00, 0x85, 0x00 }, { 0x2E, 0x25, 0x28 }, { 0x00, 0x98, 0x3B },
+ { 0xb1, 0x11, 0x00 }, { 0x6A, 0x75, 0x00 }, { 0xcc, 0x16, 0x81 }, { 0x91, 0x8e, 0x91 },
+/* Composite hi-res, colour reg = 8 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x12, 0x0F }, { 0x04, 0x00, 0x5F }, { 0x00, 0x02, 0x67 },
+ { 0x31, 0x00, 0x01 }, { 0x04, 0x01, 0x04 }, { 0x37, 0x00, 0x52 }, { 0x17, 0x00, 0x6d },
+ { 0x00, 0x10, 0x00 }, { 0x00, 0x29, 0x00 }, { 0x04, 0x03, 0x04 }, { 0x00, 0x24, 0x16 },
+ { 0x2f, 0x00, 0x00 }, { 0x07, 0x23, 0x00 }, { 0x43, 0x00, 0x08 }, { 0x25, 0x23, 0x24 },
+/* Composite hi-res, colour reg = 9 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x19, 0x14 }, { 0x00, 0x00, 0xc2 }, { 0x00, 0x1c, 0xed },
+ { 0x5e, 0x00, 0x13 }, { 0x2c, 0x03, 0x3a }, { 0x78, 0x00, 0xfa }, { 0x49, 0x11, 0xff },
+ { 0x00, 0x15, 0x00 }, { 0x00, 0x40, 0x00 }, { 0x0d, 0x11, 0x68 }, { 0x00, 0x4f, 0x9c },
+ { 0x67, 0x00, 0x00 }, { 0x39, 0x36, 0x00 }, { 0x91, 0x05, 0xa6 }, { 0x62, 0x45, 0xdc },
+/* Composite hi-res, colour reg = A */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x4B, 0x08 }, { 0x05, 0x00, 0xAA }, { 0x00, 0x50, 0xc7 },
+ { 0x58, 0x00, 0x06 }, { 0x05, 0x44, 0x06 }, { 0x75, 0x00, 0xb0 }, { 0x2e, 0x4f, 0xdc },
+ { 0x0c, 0x2f, 0x00 }, { 0x00, 0xa7, 0x00 }, { 0x26, 0x2e, 0x03 }, { 0x00, 0xb4, 0x24 },
+ { 0x84, 0x1b, 0x00 }, { 0x2d, 0xa5, 0x00 }, { 0xa5, 0x2a, 0x16 }, { 0x5f, 0xb2, 0x2a },
+/* Composite hi-res, colour reg = B */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x59, 0x07 }, { 0x00, 0x08, 0xf0 }, { 0x00, 0x06, 0xfd },
+ { 0x69, 0x00, 0x09 }, { 0x0d, 0x4c, 0x10 }, { 0x8f, 0x00, 0xf4 }, { 0x38, 0x66, 0xff },
+ { 0x02, 0x27, 0x00 }, { 0x00, 0xac, 0x00 }, { 0x19, 0x2f, 0x6d }, { 0x00, 0xc5, 0x82 },
+ { 0x7b, 0x18, 0x00 }, { 0x30, 0xa7, 0x00 }, { 0xac, 0x2b, 0x81 }, { 0x5b, 0xc0, 0xa4 },
+/* Composite hi-res, colour reg = C */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x1C, 0x0C }, { 0x0a, 0x00, 0x7c }, { 0x00, 0x0d, 0x8f },
+ { 0x6e, 0x00, 0x18 }, { 0x48, 0x02, 0x4a }, { 0x95, 0x00, 0xc3 }, { 0x68, 0x01, 0xef },
+ { 0x12, 0x1d, 0x00 }, { 0x00, 0x53, 0x00 }, { 0x33, 0x21, 0x00 }, { 0x05, 0x52, 0x13 },
+ { 0xb4, 0x09, 0x00 }, { 0x87, 0x41, 0x00 }, { 0xd8, 0x07, 0x3a }, { 0xb0, 0x49, 0x63 },
+/* Composite hi-res, colour reg = D */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x1d, 0x17 }, { 0x00, 0x08, 0xcf }, { 0x00, 0x1b, 0xf2 },
+ { 0x83, 0x00, 0x30 }, { 0x4c, 0x08, 0x53 }, { 0xae, 0x00, 0xfa }, { 0x85, 0x0b, 0xff },
+ { 0x09, 0x19, 0x00 }, { 0x00, 0x57, 0x00 }, { 0x21, 0x15, 0x4f }, { 0x00, 0x5e, 0x89 },
+ { 0xb0, 0x04, 0x00 }, { 0x76, 0x4e, 0x00 }, { 0xe2, 0x0a, 0xa9 }, { 0xae, 0x56, 0xe1 },
+/* Composite hi-res, colour reg = E */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x57, 0x06 }, { 0x17, 0x00, 0xc3 }, { 0x00, 0x55, 0xd9 },
+ { 0x6f, 0x00, 0x06 }, { 0x18, 0x49, 0x0d }, { 0xa4, 0x00, 0xcd }, { 0x4e, 0x4c, 0xf7 },
+ { 0x1c, 0x3f, 0x00 }, { 0x00, 0xbf, 0x00 }, { 0x51, 0x35, 0x00 }, { 0x06, 0xc4, 0x1b },
+ { 0xb6, 0x2d, 0x00 }, { 0x73, 0xb2, 0x00 }, { 0xf5, 0x30, 0x21 }, { 0xaa, 0xbf, 0x2f },
+/* Composite hi-res, colour reg = F */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x68, 0x10 }, { 0x10, 0x00, 0xff }, { 0x00, 0x7c, 0xFF },
+ { 0xb3, 0x00, 0x2A }, { 0x53, 0x55, 0x51 }, { 0xf0, 0x00, 0xff }, { 0x95, 0x72, 0xff },
+ { 0x25, 0x3e, 0x00 }, { 0x00, 0xda, 0x00 }, { 0x58, 0x52, 0x56 }, { 0x00, 0xf8, 0x7f },
+ { 0xf8, 0x2c, 0x00 }, { 0xa8, 0xcf, 0x00 }, { 0xff, 0x41, 0xb8 }, { 0xed, 0xea, 0xed },
+/* Composite lo-res, colour reg = 0 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x26, 0x34 }, { 0x00, 0x00, 0x24 }, { 0x00, 0x25, 0x46 },
+ { 0x29, 0x03, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0e, 0x53, 0x03 },
+ { 0x50, 0x00, 0x00 }, { 0x33, 0x36, 0x2b }, { 0x51, 0x00, 0x0b }, { 0x43, 0x37, 0x44 },
+ { 0x60, 0x07, 0x00 }, { 0x3c, 0x61, 0x00 }, { 0x59, 0x1c, 0x00 }, { 0x4a, 0x64, 0x00 },
+/* Composite lo-res, colour reg = 1 */
+ { 0x07, 0x00, 0x7d }, { 0x00, 0x21, 0x4e }, { 0x15, 0x00, 0x36 }, { 0x04, 0x19, 0x77 },
+ { 0x16, 0x1a, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x23, 0x0b, 0x00 }, { 0x13, 0x51, 0x03 },
+ { 0x41, 0x02, 0x3e }, { 0x2e, 0x33, 0x24 }, { 0x51, 0x00, 0x14 }, { 0x41, 0x33, 0x46 },
+ { 0x51, 0x2b, 0x00 }, { 0x3f, 0x60, 0x00 }, { 0x60, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 2 */
+ { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 },
+ { 0x03, 0x55, 0x00 }, { 0x03, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x03 },
+ { 0x31, 0x37, 0x29 }, { 0x30, 0x36, 0x2a }, { 0x51, 0x00, 0x11 }, { 0x41, 0x34, 0x46 },
+ { 0x3c, 0x63, 0x00 }, { 0x3d, 0x63, 0x00 }, { 0x5f, 0x17, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 3 */
+ { 0x04, 0x61, 0x4e }, { 0x05, 0x49, 0x02 }, { 0x1f, 0x04, 0x00 }, { 0x12, 0x47, 0x13 },
+ { 0x03, 0x68, 0x2f }, { 0x05, 0x54, 0x00 }, { 0x1e, 0x0e, 0x00 }, { 0x0f, 0x51, 0x01 },
+ { 0x26, 0x46, 0x73 }, { 0x2f, 0x34, 0x27 }, { 0x50, 0x00, 0x0b }, { 0x48, 0x31, 0x47 },
+ { 0x3e, 0x70, 0x1e }, { 0x40, 0x5f, 0x00 }, { 0x57, 0x1d, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 4 */
+ { 0x52, 0x00, 0x14 }, { 0x2e, 0x32, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x46, 0x2f, 0x47 },
+ { 0x1f, 0x09, 0x00 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x11, 0x50, 0x02 },
+ { 0x52, 0x00, 0x14 }, { 0x2d, 0x33, 0x25 }, { 0x52, 0x00, 0x14 }, { 0x40, 0x36, 0x3f },
+ { 0x5c, 0x18, 0x00 }, { 0x40, 0x5f, 0x00 }, { 0x5e, 0x19, 0x00 }, { 0x4b, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 5 */
+ { 0x51, 0x00, 0x81 }, { 0x2a, 0x2a, 0x3f }, { 0x4f, 0x00, 0x1c }, { 0x3b, 0x2b, 0x5c },
+ { 0x22, 0x1b, 0x13 }, { 0x04, 0x55, 0x00 }, { 0x21, 0x0e, 0x00 }, { 0x0e, 0x52, 0x04 },
+ { 0x4c, 0x03, 0x59 }, { 0x2e, 0x32, 0x25 }, { 0x51, 0x00, 0x0b }, { 0x3e, 0x37, 0x3d },
+ { 0x5d, 0x2a, 0x03 }, { 0x3d, 0x60, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x4a, 0x63, 0x00 },
+/* Composite lo-res, colour reg = 6 */
+ { 0x4b, 0x60, 0x00 }, { 0x41, 0x5f, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x4b, 0x60, 0x00 },
+ { 0x0e, 0x51, 0x03 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x12, 0x51, 0x03 },
+ { 0x41, 0x34, 0x47 }, { 0x31, 0x37, 0x29 }, { 0x50, 0x00, 0x10 }, { 0x3f, 0x32, 0x43 },
+ { 0x4b, 0x60, 0x00 }, { 0x3d, 0x61, 0x00 }, { 0x62, 0x16, 0x00 }, { 0x4b, 0x60, 0x00 },
+/* Composite lo-res, colour reg = 7 */
+ { 0x8b, 0x8b, 0x8b }, { 0x83, 0x5b, 0x00 }, { 0xa4, 0x1b, 0x00 }, { 0x92, 0x5a, 0x09 },
+ { 0x07, 0x79, 0x6f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0d, 0x00 }, { 0x10, 0x52, 0x01 },
+ { 0x23, 0x62, 0xa4 }, { 0x2b, 0x33, 0x29 }, { 0x51, 0x00, 0x11 }, { 0x40, 0x36, 0x42 },
+ { 0x46, 0x86, 0x63 }, { 0x42, 0x5e, 0x00 }, { 0x5e, 0x17, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 8 */
+ { 0x26, 0x26, 0x26 }, { 0x0a, 0x49, 0x00 }, { 0x25, 0x07, 0x00 }, { 0x16, 0x4c, 0x0e },
+ { 0x1c, 0x29, 0x12 }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0c, 0x00 }, { 0x11, 0x51, 0x02 },
+ { 0x4d, 0x10, 0x5f }, { 0x2c, 0x33, 0x26 }, { 0x51, 0x00, 0x0f }, { 0x41, 0x35, 0x47 },
+ { 0x5a, 0x35, 0x00 }, { 0x43, 0x5f, 0x00 }, { 0x5f, 0x15, 0x00 }, { 0x4d, 0x62, 0x00 },
+/* Composite lo-res, colour reg = 9 */
+ { 0x92, 0x47, 0xd3 }, { 0x47, 0x47, 0x1b }, { 0x66, 0x00, 0x09 }, { 0x54, 0x44, 0x37 },
+ { 0x15, 0x4b, 0x8a }, { 0x05, 0x55, 0x00 }, { 0x00, 0x10, 0x00 }, { 0x10, 0x52, 0x02 },
+ { 0x40, 0x33, 0xd4 }, { 0x2f, 0x33, 0x26 }, { 0x51, 0x00, 0x0d }, { 0x3e, 0x37, 0x3e },
+ { 0x51, 0x59, 0x75 }, { 0x3b, 0x63, 0x00 }, { 0x5b, 0x1a, 0x00 }, { 0x49, 0x64, 0x00 },
+/* Composite lo-res, colour reg = A */
+ { 0x57, 0xac, 0x33 }, { 0x54, 0x7f, 0x00 }, { 0x7f, 0x2e, 0x00 }, { 0x6a, 0x77, 0x00 },
+ { 0x05, 0x80, 0x70 }, { 0x03, 0x54, 0x00 }, { 0x22, 0x0c, 0x00 }, { 0x13, 0x52, 0x00 },
+ { 0x31, 0x64, 0xbe }, { 0x30, 0x35, 0x2a }, { 0x52, 0x00, 0x12 }, { 0x41, 0x33, 0x46 },
+ { 0x3c, 0x91, 0x50 }, { 0x3c, 0x62, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x4f, 0x61, 0x00 },
+/* Composite lo-res, colour reg = B */
+ { 0x5b, 0xb9, 0xa7 }, { 0x5b, 0x6d, 0x00 }, { 0x7f, 0x29, 0x00 }, { 0x6c, 0x6e, 0x00 },
+ { 0x05, 0x95, 0xcb }, { 0x04, 0x54, 0x00 }, { 0x23, 0x0a, 0x00 }, { 0x12, 0x51, 0x02 },
+ { 0x28, 0x77, 0xfb }, { 0x32, 0x37, 0x2f }, { 0x52, 0x00, 0x12 }, { 0x3e, 0x34, 0x40 },
+ { 0x3a, 0xa3, 0xaf }, { 0x3c, 0x63, 0x00 }, { 0x60, 0x15, 0x00 }, { 0x50, 0x61, 0x00 },
+/* Composite lo-res, colour reg = C */
+ { 0xaa, 0x45, 0x6a }, { 0x8c, 0x59, 0x00 }, { 0xa8, 0x1a, 0x00 }, { 0x96, 0x60, 0x05 },
+ { 0x20, 0x35, 0x41 }, { 0x03, 0x55, 0x00 }, { 0x22, 0x0b, 0x00 }, { 0x10, 0x52, 0x02 },
+ { 0x4f, 0x1e, 0xa2 }, { 0x2e, 0x34, 0x25 }, { 0x50, 0x00, 0x10 }, { 0x42, 0x36, 0x45 },
+ { 0x56, 0x48, 0x2a }, { 0x41, 0x5e, 0x00 }, { 0x5d, 0x19, 0x00 }, { 0x49, 0x64, 0x00 },
+/* Composite lo-res, colour reg = D */
+ { 0xa9, 0x54, 0xd6 }, { 0x85, 0x52, 0x09 }, { 0xa5, 0x17, 0x00 }, { 0x96, 0x52, 0x23 },
+ { 0x1e, 0x48, 0x9f }, { 0x06, 0x55, 0x00 }, { 0x1f, 0x0c, 0x00 }, { 0x0f, 0x52, 0x01 },
+ { 0x46, 0x35, 0xe1 }, { 0x2b, 0x32, 0x26 }, { 0x51, 0x00, 0x0e }, { 0x3e, 0x39, 0x3e },
+ { 0x5d, 0x58, 0x88 }, { 0x41, 0x60, 0x00 }, { 0x57, 0x1c, 0x00 }, { 0x4a, 0x62, 0x00 },
+/* Composite lo-res, colour reg = E */
+ { 0xa4, 0xbb, 0x30 }, { 0x9d, 0x84, 0x00 }, { 0xb6, 0x3f, 0x00 }, { 0xa1, 0x8c, 0x00 },
+ { 0x14, 0x7b, 0x8a }, { 0x06, 0x55, 0x00 }, { 0x21, 0x0b, 0x00 }, { 0x13, 0x51, 0x02 },
+ { 0x3f, 0x67, 0xd5 }, { 0x2d, 0x36, 0x29 }, { 0x52, 0x00, 0x11 }, { 0x41, 0x33, 0x46 },
+ { 0x4c, 0x8e, 0x6e }, { 0x3e, 0x61, 0x00 }, { 0x5f, 0x16, 0x00 }, { 0x4c, 0x61, 0x00 },
+/* Composite lo-res, colour reg = F */
+ { 0xe3, 0xe3, 0xe3 }, { 0xdb, 0x82, 0x00 }, { 0xf5, 0x43, 0x00 }, { 0xee, 0x83, 0x00 },
+ { 0x08, 0xa6, 0xf5 }, { 0x04, 0x53, 0x00 }, { 0x1c, 0x0d, 0x00 }, { 0x13, 0x52, 0x00 },
+ { 0x25, 0x91, 0xfc }, { 0x2c, 0x35, 0x30 }, { 0x51, 0x00, 0x0e }, { 0x3b, 0x36, 0x38 },
+ { 0x43, 0xb5, 0xf7 }, { 0x3b, 0x62, 0x00 }, { 0x56, 0x1c, 0x00 }, { 0x4d, 0x61, 0x00 },
+/* Composite lo-res, colour reg = 10 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x58, 0xb9 }, { 0x00, 0x11, 0x8a }, { 0x00, 0x4a, 0xe1 },
+ { 0x73, 0x22, 0x00 }, { 0x5a, 0xad, 0x2e }, { 0x78, 0x61, 0x0d }, { 0x6a, 0xa9, 0x4c },
+ { 0xac, 0x0a, 0x00 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6c }, { 0x95, 0x8b, 0x97 },
+ { 0xac, 0x30, 0x00 }, { 0x91, 0xbc, 0x16 }, { 0xb8, 0x6d, 0x07 }, { 0xa7, 0xb9, 0x2d },
+/* Composite lo-res, colour reg = 11 */
+ { 0x60, 0x00, 0x7c }, { 0x01, 0x54, 0xdb }, { 0x09, 0x11, 0xb9 }, { 0x07, 0x47, 0xf8 },
+ { 0x76, 0x46, 0x02 }, { 0x5a, 0xae, 0x2e }, { 0x78, 0x62, 0x0c }, { 0x68, 0xa9, 0x4b },
+ { 0x99, 0x2a, 0x09 }, { 0x87, 0x8d, 0x80 }, { 0xab, 0x46, 0x6b }, { 0x93, 0x89, 0x95 },
+ { 0xa4, 0x54, 0x00 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6b, 0x04 }, { 0xa4, 0xb9, 0x30 },
+/* Composite lo-res, colour reg = 12 */
+ { 0x07, 0x55, 0x00 }, { 0x03, 0x83, 0x70 }, { 0x1c, 0x3a, 0x42 }, { 0x0e, 0x81, 0x82 },
+ { 0x58, 0x7e, 0x00 }, { 0x5b, 0xad, 0x2f }, { 0x77, 0x60, 0x0f }, { 0x67, 0xac, 0x49 },
+ { 0x87, 0x5a, 0x00 }, { 0x89, 0x8c, 0x81 }, { 0xa9, 0x49, 0x5e }, { 0x9b, 0x8a, 0x96 },
+ { 0x9f, 0x83, 0x00 }, { 0x94, 0xb9, 0x19 }, { 0xb0, 0x72, 0x03 }, { 0xa5, 0xbb, 0x30 },
+/* Composite lo-res, colour reg = 13 */
+ { 0x03, 0x63, 0x48 }, { 0x04, 0x76, 0x8c }, { 0x1d, 0x34, 0x5a }, { 0x0d, 0x7a, 0x9c },
+ { 0x5a, 0x8e, 0x03 }, { 0x58, 0xac, 0x33 }, { 0x76, 0x60, 0x0b }, { 0x68, 0xaa, 0x4b },
+ { 0x7e, 0x6e, 0x3b }, { 0x88, 0x8c, 0x80 }, { 0xaa, 0x48, 0x64 }, { 0x94, 0x91, 0x92 },
+ { 0x94, 0x9b, 0x00 }, { 0x96, 0xb9, 0x16 }, { 0xb0, 0x73, 0x01 }, { 0xa7, 0xb8, 0x2e },
+/* Composite lo-res, colour reg = 14 */
+ { 0x52, 0x00, 0x13 }, { 0x29, 0x61, 0xb6 }, { 0x52, 0x1e, 0xa1 }, { 0x41, 0x63, 0xdb },
+ { 0x7b, 0x2f, 0x00 }, { 0x5d, 0xac, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x67, 0xa9, 0x51 },
+ { 0xaf, 0x18, 0x00 }, { 0x83, 0x8a, 0x7d }, { 0xa9, 0x46, 0x66 }, { 0x9a, 0x8c, 0xa0 },
+ { 0xb1, 0x43, 0x00 }, { 0x9a, 0xb7, 0x19 }, { 0xb7, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 15 */
+ { 0x52, 0x00, 0x7a }, { 0x2e, 0x55, 0xdc }, { 0x4e, 0x1b, 0xb1 }, { 0x3c, 0x55, 0xec },
+ { 0x80, 0x3f, 0x00 }, { 0x5b, 0xad, 0x2e }, { 0x73, 0x61, 0x0a }, { 0x66, 0xaa, 0x50 },
+ { 0xa7, 0x29, 0x29 }, { 0x86, 0x8a, 0x7d }, { 0xa8, 0x48, 0x60 }, { 0x98, 0x8e, 0x9b },
+ { 0xc0, 0x4a, 0x00 }, { 0x9a, 0xb5, 0x18 }, { 0xb3, 0x72, 0x06 }, { 0xa2, 0xba, 0x31 },
+/* Composite lo-res, colour reg = 16 */
+ { 0x4d, 0x61, 0x00 }, { 0x3b, 0x91, 0x53 }, { 0x59, 0x46, 0x2c }, { 0x48, 0x95, 0x63 },
+ { 0x6c, 0x77, 0x00 }, { 0x5a, 0xac, 0x31 }, { 0x75, 0x63, 0x09 }, { 0x66, 0xa9, 0x4e },
+ { 0x8e, 0x6a, 0x0f }, { 0x87, 0x8b, 0x7f }, { 0xa9, 0x47, 0x66 }, { 0x9b, 0x8c, 0x9f },
+ { 0xab, 0x86, 0x00 }, { 0x9a, 0xb6, 0x18 }, { 0xae, 0x74, 0x01 }, { 0xa2, 0xba, 0x2f },
+/* Composite lo-res, colour reg = 17 */
+ { 0x8b, 0x8b, 0x8b }, { 0x7f, 0x89, 0x79 }, { 0xa4, 0x4a, 0x5c }, { 0x96, 0x8a, 0x95 },
+ { 0x5c, 0xa1, 0x36 }, { 0x5d, 0xad, 0x2b }, { 0x77, 0x62, 0x0a }, { 0x68, 0xa8, 0x4f },
+ { 0x83, 0x88, 0x6f }, { 0x85, 0x8d, 0x81 }, { 0xa9, 0x46, 0x69 }, { 0x99, 0x8b, 0x9f },
+ { 0x97, 0xb1, 0x22 }, { 0x99, 0xb7, 0x18 }, { 0xb8, 0x6c, 0x04 }, { 0xa2, 0xba, 0x2e },
+/* Composite lo-res, colour reg = 18 */
+ { 0x25, 0x25, 0x25 }, { 0x0b, 0x78, 0x8b }, { 0x25, 0x34, 0x5a }, { 0x14, 0x7d, 0x9d },
+ { 0x76, 0x4f, 0x00 }, { 0x5a, 0xac, 0x2e }, { 0x74, 0x64, 0x07 }, { 0x66, 0xaa, 0x49 },
+ { 0xa7, 0x37, 0x25 }, { 0x87, 0x8b, 0x80 }, { 0xa8, 0x48, 0x64 }, { 0x9a, 0x8f, 0x9a },
+ { 0xb6, 0x5a, 0x00 }, { 0x96, 0xba, 0x17 }, { 0xae, 0x73, 0x01 }, { 0xa2, 0xba, 0x30 },
+/* Composite lo-res, colour reg = 19 */
+ { 0x5d, 0x48, 0xd5 }, { 0x4a, 0x77, 0xb3 }, { 0x65, 0x35, 0x86 }, { 0x4d, 0x77, 0xc2 },
+ { 0x6f, 0x72, 0x53 }, { 0x5a, 0xac, 0x30 }, { 0x75, 0x62, 0x09 }, { 0x68, 0xa9, 0x48 },
+ { 0x9c, 0x57, 0xa1 }, { 0x87, 0x8b, 0x80 }, { 0xa7, 0x49, 0x62 }, { 0x92, 0x90, 0x92 },
+ { 0xab, 0x7d, 0x3a }, { 0x97, 0xb8, 0x17 }, { 0xb0, 0x74, 0x03 }, { 0xa2, 0xba, 0x2e },
+/* Composite lo-res, colour reg = 1A */
+ { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d },
+ { 0x59, 0xad, 0x2e }, { 0x59, 0xad, 0x2e }, { 0x75, 0x64, 0x08 }, { 0x69, 0xa7, 0x4d },
+ { 0x87, 0x8d, 0x82 }, { 0x85, 0x8b, 0x7d }, { 0xa9, 0x47, 0x67 }, { 0x99, 0x8c, 0x9d },
+ { 0x94, 0xba, 0x17 }, { 0x94, 0xba, 0x17 }, { 0xb6, 0x6e, 0x06 }, { 0xa2, 0xbb, 0x30 },
+/* Composite lo-res, colour reg = 1B */
+ { 0x5b, 0xb9, 0xa6 }, { 0x5c, 0xa2, 0x4a }, { 0x7a, 0x5c, 0x24 }, { 0x6a, 0x9a, 0x6c },
+ { 0x56, 0xbf, 0x8e }, { 0x59, 0xae, 0x31 }, { 0x78, 0x60, 0x0d }, { 0x68, 0xa9, 0x4f },
+ { 0x7f, 0xa3, 0xcd }, { 0x85, 0x8c, 0x80 }, { 0xaa, 0x47, 0x6a }, { 0x98, 0x8b, 0x9c },
+ { 0x93, 0xcd, 0x72 }, { 0x92, 0xbd, 0x14 }, { 0xb8, 0x6c, 0x06 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1C */
+ { 0xa9, 0x44, 0x63 }, { 0x85, 0x8a, 0x7f }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8e, 0x9d },
+ { 0x74, 0x5f, 0x0d }, { 0x5c, 0xad, 0x2c }, { 0x77, 0x63, 0x0a }, { 0x68, 0xa8, 0x4e },
+ { 0xa9, 0x44, 0x63 }, { 0x84, 0x8b, 0x7e }, { 0xa9, 0x44, 0x63 }, { 0x99, 0x8c, 0x9e },
+ { 0xad, 0x72, 0x01 }, { 0x9b, 0xb6, 0x1a }, { 0xb3, 0x6e, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1D */
+ { 0xaa, 0x55, 0xd4 }, { 0x83, 0x81, 0x9b }, { 0xa6, 0x43, 0x7b }, { 0x95, 0x80, 0xbd },
+ { 0x76, 0x72, 0x66 }, { 0x5a, 0xad, 0x2c }, { 0x7b, 0x61, 0x0c }, { 0x68, 0xa9, 0x50 },
+ { 0xa5, 0x59, 0xaa }, { 0x87, 0x8e, 0x7f }, { 0xa9, 0x45, 0x6a }, { 0x97, 0x8b, 0x98 },
+ { 0xb2, 0x82, 0x48 }, { 0x93, 0xbb, 0x16 }, { 0xb9, 0x6d, 0x05 }, { 0xa4, 0xb9, 0x2f },
+/* Composite lo-res, colour reg = 1E */
+ { 0xa5, 0xb8, 0x2d }, { 0xa5, 0xb8, 0x2d }, { 0xb4, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d },
+ { 0x64, 0xaa, 0x4e }, { 0x5b, 0xad, 0x2c }, { 0x77, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f },
+ { 0x94, 0x91, 0x95 }, { 0x83, 0x8a, 0x7b }, { 0xa9, 0x47, 0x67 }, { 0x98, 0x8a, 0x9e },
+ { 0xa5, 0xb8, 0x2d }, { 0x9a, 0xb6, 0x1a }, { 0xb2, 0x70, 0x05 }, { 0xa5, 0xb8, 0x2d },
+/* Composite lo-res, colour reg = 1F */
+ { 0xe3, 0xe3, 0xe3 }, { 0xde, 0xb1, 0x45 }, { 0xf8, 0x71, 0x3e }, { 0xeb, 0xb3, 0x5e },
+ { 0x58, 0xd3, 0xc4 }, { 0x5b, 0xad, 0x2d }, { 0x78, 0x63, 0x0b }, { 0x68, 0xa8, 0x4f },
+ { 0x7f, 0xb7, 0xf4 }, { 0x86, 0x8b, 0x7d }, { 0xa8, 0x46, 0x69 }, { 0x9a, 0x8c, 0x9f },
+ { 0x99, 0xe0, 0xbc }, { 0x99, 0xb6, 0x1a }, { 0xb8, 0x6d, 0x07 }, { 0xa5, 0xb8, 0x30 },
+/* Composite lo-res, colour reg = 20 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x3a, 0x85 }, { 0x00, 0x00, 0x6c }, { 0x00, 0x46, 0xce },
+ { 0x26, 0x01, 0x00 }, { 0x03, 0x61, 0x4a }, { 0x24, 0x16, 0x2a }, { 0x09, 0x72, 0x8d },
+ { 0x4d, 0x00, 0x00 }, { 0x2d, 0x45, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x30, 0x58, 0xe1 },
+ { 0x9e, 0x0f, 0x00 }, { 0x86, 0x7b, 0x45 }, { 0xab, 0x29, 0x2c }, { 0x8b, 0x89, 0x88 },
+/* Composite lo-res, colour reg = 21 */
+ { 0x06, 0x00, 0x7C }, { 0x00, 0x3B, 0xA0 }, { 0x14, 0x00, 0x93 }, { 0x00, 0x49, 0xF7 },
+ { 0x19, 0x12, 0x13 }, { 0x02, 0x63, 0x3f }, { 0x25, 0x16, 0x2b }, { 0x09, 0x71, 0x93 },
+ { 0x46, 0x00, 0x65 }, { 0x28, 0x45, 0x93 }, { 0x50, 0x00, 0x80 }, { 0x32, 0x55, 0xe6 },
+ { 0x9c, 0x2d, 0x0c }, { 0x86, 0x78, 0x44 }, { 0xaa, 0x29, 0x33 }, { 0x92, 0x84, 0x84 },
+/* Composite lo-res, colour reg = 22 */
+ { 0x05, 0x56, 0x00 }, { 0x04, 0x69, 0x32 }, { 0x21, 0x1d, 0x13 }, { 0x07, 0x76, 0x7e },
+ { 0x05, 0x48, 0x03 }, { 0x03, 0x64, 0x43 }, { 0x24, 0x16, 0x28 }, { 0x08, 0x70, 0x92 },
+ { 0x45, 0x41, 0x74 }, { 0x27, 0x44, 0x92 }, { 0x4f, 0x00, 0x7f }, { 0x36, 0x58, 0xe8 },
+ { 0x85, 0x57, 0x02 }, { 0x87, 0x77, 0x45 }, { 0xa6, 0x2c, 0x2c }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 23 */
+ { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 },
+ { 0x02, 0x61, 0x49 }, { 0x02, 0x61, 0x49 }, { 0x24, 0x15, 0x27 }, { 0x05, 0x73, 0x84 },
+ { 0x2a, 0x43, 0x96 }, { 0x2a, 0x43, 0x96 }, { 0x51, 0x00, 0x7d }, { 0x31, 0x5a, 0xdc },
+ { 0x86, 0x79, 0x3d }, { 0x86, 0x79, 0x3d }, { 0xa8, 0x2a, 0x21 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 24 */
+ { 0x51, 0x00, 0x0e }, { 0x2b, 0x49, 0x76 }, { 0x4c, 0x04, 0x53 }, { 0x23, 0x5a, 0xf5 },
+ { 0x22, 0x05, 0x00 }, { 0x04, 0x06, 0x4b }, { 0x22, 0x13, 0x22 }, { 0x03, 0x74, 0x82 },
+ { 0x4e, 0x00, 0x25 }, { 0x2d, 0x46, 0x9d }, { 0x52, 0x00, 0x7c }, { 0x34, 0x59, 0xe3 },
+ { 0xaa, 0x17, 0x00 }, { 0x85, 0x79, 0x3d }, { 0xa7, 0x2e, 0x24 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 25 */
+ { 0x50, 0x00, 0x7e }, { 0x2d, 0x45, 0x9d }, { 0x50, 0x00, 0x7e }, { 0x30, 0x57, 0xde },
+ { 0x23, 0x16, 0x29 }, { 0x05, 0x61, 0x49 }, { 0x23, 0x13, 0x26 }, { 0x04, 0x75, 0x87 },
+ { 0x50, 0x00, 0x7e }, { 0x28, 0x44, 0x96 }, { 0x50, 0x00, 0x7e }, { 0x31, 0x59, 0xdf },
+ { 0xac, 0x28, 0x33 }, { 0x85, 0x79, 0x3c }, { 0xa7, 0x2d, 0x23 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 26 */
+ { 0x4f, 0x62, 0x00 }, { 0x3d, 0x71, 0x1f }, { 0x60, 0x2a, 0x07 }, { 0x43, 0x88, 0x69 },
+ { 0x13, 0x42, 0x19 }, { 0x05, 0x63, 0x46 }, { 0x24, 0x16, 0x27 }, { 0x07, 0x72, 0x91 },
+ { 0x3c, 0x2b, 0x5f }, { 0x2a, 0x45, 0x92 }, { 0x4f, 0x00, 0x82 }, { 0x36, 0x57, 0xe9 },
+ { 0x92, 0x5a, 0x0b }, { 0x87, 0x78, 0x45 }, { 0xa7, 0x2c, 0x2a }, { 0x8b, 0x8b, 0x8c },
+/* Composite lo-res, colour reg = 27 */
+ { 0x8b, 0x8b, 0x8b }, { 0x89, 0x78, 0x47 }, { 0xa8, 0x2a, 0x2d }, { 0x8b, 0x8b, 0x8b },
+ { 0x08, 0x71, 0x93 }, { 0x02, 0x62, 0x4a }, { 0x26, 0x16, 0x2a }, { 0x06, 0x73, 0x87 },
+ { 0x35, 0x58, 0xe6 }, { 0x2f, 0x45, 0x9e }, { 0x50, 0x00, 0x78 }, { 0x2f, 0x59, 0xe0 },
+ { 0x8b, 0x8b, 0x8b }, { 0x87, 0x7a, 0x46 }, { 0xaa, 0x29, 0x30 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 28 */
+ { 0x25, 0x25, 0x25 }, { 0x08, 0x5f, 0x4b }, { 0x2b, 0x15, 0x25 }, { 0x09, 0x71, 0x88 },
+ { 0x1e, 0x23, 0x26 }, { 0x04, 0x62, 0x47 }, { 0x21, 0x19, 0x28 }, { 0x06, 0x74, 0x88 },
+ { 0x48, 0x0b, 0x70 }, { 0x26, 0x42, 0x95 }, { 0x52, 0x00, 0x7c }, { 0x34, 0x58, 0xe6 },
+ { 0xa1, 0x37, 0x1c }, { 0x85, 0x78, 0x3e }, { 0xa6, 0x2e, 0x23 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 29 */
+ { 0x5e, 0x44, 0xd3 }, { 0x45, 0x61, 0x73 }, { 0x6c, 0x18, 0x53 }, { 0x4c, 0x72, 0xbf },
+ { 0x14, 0x45, 0xa3 }, { 0x04, 0x61, 0x49 }, { 0x22, 0x15, 0x25 }, { 0x06, 0x72, 0x8d },
+ { 0x41, 0x2d, 0xf6 }, { 0x27, 0x43, 0x96 }, { 0x51, 0x00, 0x7c }, { 0x34, 0x58, 0xe4 },
+ { 0x9b, 0x5a, 0xa5 }, { 0x85, 0x78, 0x3d }, { 0xa6, 0x2e, 0x23 }, { 0x8c, 0x8c, 0x8c },
+/* Composite lo-res, colour reg = 2A */
+ { 0x5c, 0xae, 0x2a }, { 0x58, 0x91, 0x00 }, { 0x7b, 0x41, 0x00 }, { 0x5e, 0xa0, 0x36 },
+ { 0x06, 0x78, 0x86 }, { 0x03, 0x62, 0x49 }, { 0x25, 0x14, 0x28 }, { 0x03, 0x74, 0x82 },
+ { 0x25, 0x5b, 0xcc }, { 0x2a, 0x43, 0x97 }, { 0x52, 0x00, 0x79 }, { 0x31, 0x5b, 0xe0 },
+ { 0x7e, 0x88, 0x7b }, { 0x86, 0x7b, 0x3e }, { 0xa7, 0x2c, 0x22 }, { 0x89, 0x89, 0x89 },
+/* Composite lo-res, colour reg = 2B */
+ { 0x58, 0xbb, 0x98 }, { 0x5a, 0x8c, 0x0a }, { 0x7f, 0x3b, 0x02 }, { 0x60, 0x9a, 0x4b },
+ { 0x03, 0x96, 0xce }, { 0x04, 0x61, 0x4a }, { 0x23, 0x14, 0x24 }, { 0x04, 0x75, 0x86 },
+ { 0x23, 0x76, 0xfe }, { 0x28, 0x43, 0x95 }, { 0x51, 0x00, 0x7b }, { 0x30, 0x59, 0xdb },
+ { 0x80, 0xab, 0xd2 }, { 0x85, 0x7a, 0x3d }, { 0xa8, 0x2e, 0x26 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2C */
+ { 0xa9, 0x46, 0x66 }, { 0x7f, 0x6f, 0x37 }, { 0xa9, 0x27, 0x27 }, { 0x87, 0x82, 0x7f },
+ { 0x1e, 0x31, 0x5c }, { 0x04, 0x63, 0x44 }, { 0x23, 0x16, 0x2a }, { 0x08, 0x71, 0x92 },
+ { 0x4e, 0x1a, 0xb0 }, { 0x27, 0x46, 0x92 }, { 0x50, 0x00, 0x80 }, { 0x33, 0x56, 0xe7 },
+ { 0xa3, 0x4a, 0x58 }, { 0x87, 0x78, 0x46 }, { 0xab, 0x29, 0x34 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2D */
+ { 0xa8, 0x53, 0xd8 }, { 0x82, 0x6c, 0x5f }, { 0xac, 0x25, 0x3f }, { 0x8d, 0x7f, 0xa8 },
+ { 0x21, 0x46, 0xb9 }, { 0x04, 0x61, 0x4d }, { 0x24, 0x13, 0x23 }, { 0x04, 0x75, 0x87 },
+ { 0x4c, 0x2e, 0xfe }, { 0x2a, 0x45, 0x99 }, { 0x52, 0x00, 0x78 }, { 0x32, 0x5a, 0xde },
+ { 0xa8, 0x53, 0xd8 }, { 0x84, 0x7c, 0x3d }, { 0xa7, 0x2d, 0x22 }, { 0x8b, 0x8b, 0x8b },
+/* Composite lo-res, colour reg = 2E */
+ { 0xa4, 0xba, 0x2e }, { 0x8e, 0x9f, 0x00 }, { 0xbf, 0x4e, 0x00 }, { 0xa5, 0xae, 0x2d },
+ { 0x13, 0x71, 0xa6 }, { 0x03, 0x62, 0x4a }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x83 },
+ { 0x32, 0x5d, 0xe0 }, { 0x2e, 0x46, 0x9c }, { 0x51, 0x00, 0x7c }, { 0x2f, 0x59, 0xe0 },
+ { 0x8a, 0x8d, 0x94 }, { 0x86, 0x7b, 0x40 }, { 0xa8, 0x2c, 0x22 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 2F */
+ { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xa6, 0x0a }, { 0xf9, 0x53, 0x04 }, { 0xea, 0xae, 0x54 },
+ { 0x08, 0xa2, 0xfc }, { 0x03, 0x62, 0x48 }, { 0x24, 0x14, 0x28 }, { 0x05, 0x74, 0x84 },
+ { 0x27, 0x90, 0xff }, { 0x2a, 0x43, 0x95 }, { 0x52, 0x00, 0x79 }, { 0x34, 0x5a, 0xe3 },
+ { 0x85, 0xbb, 0xff }, { 0x85, 0x7a, 0x3d }, { 0xa7, 0x2c, 0x23 }, { 0x8a, 0x8a, 0x8a },
+/* Composite lo-res, colour reg = 30 */
+ { 0x00, 0x00, 0x00 }, { 0x00, 0x63, 0xfe }, { 0x00, 0x1d, 0xe9 }, { 0x00, 0x81, 0xff },
+ { 0x7e, 0x16, 0x00 }, { 0x5b, 0xb9, 0xa5 }, { 0x79, 0x6a, 0x79 }, { 0x59, 0xce, 0xdc },
+ { 0xa8, 0x05, 0x00 }, { 0x84, 0x9e, 0xf3 }, { 0xaa, 0x54, 0xd3 }, { 0x8c, 0xb1, 0xff },
+ { 0xfb, 0x28, 0x00 }, { 0xde, 0xd2, 0x94 }, { 0xfc, 0x85, 0x7b }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 31 */
+ { 0x07, 0x00, 0x7c }, { 0x00, 0x70, 0xfe }, { 0x0d, 0x20, 0xff }, { 0x04, 0x7f, 0xff },
+ { 0x6f, 0x3b, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x79, 0x6c, 0x81 }, { 0x5d, 0xcb, 0xe4 },
+ { 0x99, 0x26, 0x29 }, { 0x83, 0x9d, 0xf2 }, { 0xaa, 0x54, 0xd4 }, { 0x88, 0xb0, 0xff },
+ { 0xf4, 0x57, 0x00 }, { 0xdf, 0xd3, 0x9a }, { 0xfe, 0x81, 0x7f }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 32 */
+ { 0x06, 0x55, 0x00 }, { 0x03, 0x99, 0xbe }, { 0x22, 0x46, 0xa4 }, { 0x09, 0xa4, 0xfa },
+ { 0x62, 0x6d, 0x00 }, { 0x59, 0xbb, 0x9b }, { 0x7a, 0x6d, 0x7e }, { 0x5c, 0xc8, 0xe7 },
+ { 0x8a, 0x4f, 0x11 }, { 0x80, 0x9b, 0xea }, { 0xa7, 0x55, 0xda }, { 0x8c, 0xad, 0xff },
+ { 0xdf, 0x7f, 0x00 }, { 0xe2, 0xd1, 0x9c }, { 0xfd, 0x81, 0x87 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 33 */
+ { 0x03, 0x63, 0x47 }, { 0x06, 0x91, 0xda }, { 0x23, 0x41, 0xbc }, { 0x06, 0xa5, 0xfa },
+ { 0x5d, 0x8a, 0x07 }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6e, 0x80 }, { 0x5d, 0xc9, 0xe8 },
+ { 0x86, 0x6b, 0x60 }, { 0x81, 0x9d, 0xea }, { 0xa8, 0x55, 0xd8 }, { 0x8e, 0xae, 0xff },
+ { 0xdf, 0xa4, 0x0c }, { 0xe1, 0xd0, 0x9e }, { 0xfd, 0x81, 0x85 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 34 */
+ { 0x52, 0x00, 0x14 }, { 0x20, 0x7b, 0xf7 }, { 0x4e, 0x2f, 0xed }, { 0x22, 0x91, 0xff },
+ { 0x7f, 0x28, 0x00 }, { 0x5a, 0xbb, 0x9a }, { 0x79, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb },
+ { 0xac, 0x13, 0x02 }, { 0x7e, 0x9c, 0xea }, { 0xa8, 0x54, 0xd6 }, { 0x8e, 0xae, 0xff },
+ { 0xf5, 0x43, 0x00 }, { 0xdf, 0xcf, 0x9d }, { 0xfd, 0x81, 0x88 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 35 */
+ { 0x50, 0x00, 0x7b }, { 0x22, 0x76, 0xfe }, { 0x4c, 0x2f, 0xff }, { 0x36, 0x85, 0xff },
+ { 0x7b, 0x3d, 0x00 }, { 0x5b, 0xbc, 0xa1 }, { 0x7b, 0x6c, 0x7f }, { 0x5d, 0xca, 0xe8 },
+ { 0xa9, 0x26, 0x3c }, { 0x81, 0x9c, 0xec }, { 0xa7, 0x54, 0xdc }, { 0x8b, 0xad, 0xff },
+ { 0xf8, 0x57, 0x03 }, { 0xe1, 0xd4, 0x9e }, { 0xfd, 0x80, 0x82 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 36 */
+ { 0x4c, 0x61, 0x00 }, { 0x39, 0xa2, 0xaf }, { 0x5b, 0x5a, 0x8c }, { 0x42, 0xb6, 0xf4 },
+ { 0x66, 0x6b, 0x00 }, { 0x5b, 0xba, 0xa4 }, { 0x7a, 0x6c, 0x7e }, { 0x5e, 0xca, 0xe8 },
+ { 0x91, 0x51, 0x1f }, { 0x85, 0x9d, 0xf4 }, { 0xaa, 0x55, 0xd7 }, { 0x88, 0xaf, 0xff },
+ { 0xea, 0x87, 0x00 }, { 0xde, 0xd4, 0x98 }, { 0xfd, 0x7f, 0x81 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 37 */
+ { 0x8b, 0x8b, 0x8b }, { 0x86, 0xa7, 0xde }, { 0xa6, 0x5a, 0xbf }, { 0x85, 0xbb, 0xff },
+ { 0x5f, 0x9b, 0x51 }, { 0x5a, 0xb9, 0xa7 }, { 0x78, 0x6a, 0x7b }, { 0x5b, 0xce, 0xdb },
+ { 0x8b, 0x7c, 0xae }, { 0x82, 0x9c, 0xf2 }, { 0xaa, 0x54, 0xd3 }, { 0x87, 0xb2, 0xff },
+ { 0xe7, 0xb0, 0x54 }, { 0xdc, 0xd2, 0x95 }, { 0xfc, 0x84, 0x77 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 38 */
+ { 0x24, 0x24, 0x24 }, { 0x06, 0x91, 0xd8 }, { 0x2a, 0x44, 0xb9 }, { 0x0f, 0x9e, 0xfe },
+ { 0x7a, 0x49, 0x00 }, { 0x58, 0xbc, 0x98 }, { 0x7a, 0x6d, 0x7f }, { 0x5e, 0xc8, 0xeb },
+ { 0xa3, 0x36, 0x3a }, { 0x7f, 0x9c, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xad, 0xff },
+ { 0xf7, 0x64, 0x00 }, { 0xe1, 0xd1, 0x9c }, { 0xfd, 0x7f, 0x8b }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 39 */
+ { 0x62, 0x46, 0xd3 }, { 0x3d, 0x93, 0xf2 }, { 0x6b, 0x46, 0xeb }, { 0x4f, 0xa0, 0xff },
+ { 0x6f, 0x69, 0x6b }, { 0x58, 0xbb, 0x9b }, { 0x7b, 0x6e, 0x80 }, { 0x5e, 0xc8, 0xec },
+ { 0x9d, 0x53, 0xbd }, { 0x81, 0x9d, 0xf0 }, { 0xa8, 0x54, 0xd8 }, { 0x86, 0xb1, 0xff },
+ { 0xf4, 0x85, 0x5e }, { 0xdf, 0xd1, 0x9f }, { 0xfe, 0x7f, 0x88 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3A */
+ { 0x5a, 0xad, 0x2d }, { 0x58, 0xc1, 0x81 }, { 0x77, 0x74, 0x68 }, { 0x58, 0xcf, 0xd1 },
+ { 0x5d, 0xa0, 0x4d }, { 0x59, 0xbb, 0x9b }, { 0x7c, 0x6d, 0x7f }, { 0x5e, 0xc9, 0xeb },
+ { 0x83, 0x7d, 0x9e }, { 0x7f, 0x9c, 0xec }, { 0xa9, 0x54, 0xd6 }, { 0x8c, 0xae, 0xff },
+ { 0xde, 0xae, 0x4b }, { 0xdc, 0xd0, 0x98 }, { 0xfc, 0x81, 0x8a }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 3B */
+ { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6a, 0x79 }, { 0x59, 0xce, 0xd9 },
+ { 0x59, 0xbc, 0x9c }, { 0x59, 0xbc, 0x9c }, { 0x7b, 0x6b, 0x80 }, { 0x59, 0xcc, 0xd9 },
+ { 0x81, 0x9b, 0xec }, { 0x81, 0x9b, 0xec }, { 0xa9, 0x54, 0xd4 }, { 0x8e, 0xb2, 0xff },
+ { 0xdf, 0xcf, 0x9b }, { 0xdf, 0xcf, 0x9b }, { 0xfd, 0x85, 0x79 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3C */
+ { 0xaa, 0x46, 0x6a }, { 0x7a, 0xa3, 0xc7 }, { 0xa7, 0x58, 0xba }, { 0x84, 0xb5, 0xf8 },
+ { 0x78, 0x5b, 0x23 }, { 0x59, 0xbc, 0x9c }, { 0x7a, 0x6e, 0x81 }, { 0x5f, 0xc9, 0xeb },
+ { 0xa3, 0x44, 0x71 }, { 0x80, 0x9d, 0xec }, { 0xa8, 0x54, 0xd7 }, { 0x8a, 0xae, 0xff },
+ { 0xf8, 0x74, 0x1a }, { 0xdf, 0xd1, 0x9e }, { 0xfe, 0x81, 0x8b }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3D */
+ { 0xaa, 0x53, 0xd1 }, { 0x80, 0x9c, 0xec }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff },
+ { 0x7a, 0x6b, 0x7e }, { 0x58, 0xbb, 0x9d }, { 0x7a, 0x6d, 0x81 }, { 0x5f, 0xc9, 0xe5 },
+ { 0xaa, 0x53, 0xd1 }, { 0x84, 0x9d, 0xf2 }, { 0xaa, 0x53, 0xd1 }, { 0x88, 0xad, 0xff },
+ { 0xfd, 0x85, 0x78 }, { 0xe0, 0xd2, 0x9e }, { 0xfe, 0x80, 0x87 }, { 0xe3, 0xe3, 0xe3 },
+/* Composite lo-res, colour reg = 3E */
+ { 0xa1, 0xba, 0x2f }, { 0x90, 0xce, 0x70 }, { 0xb4, 0x80, 0x4b }, { 0x9d, 0xe0, 0xba },
+ { 0x6a, 0x9f, 0x68 }, { 0x5a, 0xba, 0x9f }, { 0x7a, 0x6b, 0x7a }, { 0x5a, 0xce, 0xdb },
+ { 0x91, 0x83, 0xae }, { 0x80, 0x9b, 0xef }, { 0xaa, 0x54, 0xd2 }, { 0x8c, 0xb1, 0xff },
+ { 0xeb, 0xb3, 0x59 }, { 0xdd, 0xd3, 0x94 }, { 0xfc, 0x85, 0x79 }, { 0xe4, 0xe4, 0xe4 },
+/* Composite lo-res, colour reg = 3F */
+ { 0xe4, 0xe4, 0xe4 }, { 0xdd, 0xd2, 0x93 }, { 0xfc, 0x85, 0x7a }, { 0xe4, 0xe4, 0xe4 },
+ { 0x59, 0xcc, 0xda }, { 0x59, 0xbb, 0x9c }, { 0x7b, 0x6d, 0x7f }, { 0x5c, 0xca, 0xe5 },
+ { 0x87, 0xb3, 0xff }, { 0x7f, 0x9a, 0xea }, { 0xa8, 0x54, 0xd4 }, { 0x8c, 0xb0, 0xff },
+ { 0xe4, 0xe4, 0xe4 }, { 0xdf, 0xd1, 0x98 }, { 0xfd, 0x84, 0x7d }, { 0xe4, 0xe4, 0xe4 },
+};
+
+
+static MC6845_UPDATE_ROW( cga_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ if ( cga->m_update_row )
+ {
+ cga->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+static MC6845_INTERFACE( mc6845_cga_intf )
+{
+ false, /* show border area */
+ 0,0,0,0, /* visarea adjustment */
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ cga_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_cga_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_cga_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+#define CGA_HCLK (XTAL_14_31818MHz/8)
+#define CGA_LCLK (XTAL_14_31818MHz/16)
+
+
+static MACHINE_CONFIG_FRAGMENT( cga )
+ MCFG_SCREEN_ADD(CGA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_14_31818MHz,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_DEVICE( DEVICE_SELF, isa8_cga_device, screen_update )
+
+ MCFG_PALETTE_ADD("palette", /* CGA_PALETTE_SETS * 16*/ 65536 )
+
+ MCFG_MC6845_ADD(CGA_MC6845_NAME, MC6845, CGA_SCREEN_NAME, XTAL_14_31818MHz/8, mc6845_cga_intf)
+MACHINE_CONFIG_END
+
+
+ROM_START( cga )
+ /* IBM 1501981(CGA) and 1501985(MDA) Character rom */
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD("5788005.u33", 0x00000, 0x2000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */
+ROM_END
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_CGA = &device_creator<isa8_cga_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_cga_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( cga );
+}
+
+ioport_constructor isa8_cga_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( cga );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_device::device_rom_region() const
+{
+ return ROM_NAME( cga );
+}
+
+
+//-------------------------------------------------
+// isa8_cga_device - constructor
+//-------------------------------------------------
+
+isa8_cga_device::isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_CGA, "IBM Color/Graphics Monitor Adapter", tag, owner, clock, "cga", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_cga_config(*this, "cga_config"),
+ m_vram_size( 0x4000 ),
+ m_palette(*this, "palette")
+{
+ m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800;
+ m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000;
+ m_font_selection_mask = 0x01;
+ m_start_offset = 0;
+}
+
+isa8_cga_device::isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this),
+ m_cga_config(*this, "cga_config"),
+ m_vram_size( 0x4000 ),
+ m_palette(*this, "palette")
+{
+ m_chr_gen_offset[0] = m_chr_gen_offset[2] = 0x1800;
+ m_chr_gen_offset[1] = m_chr_gen_offset[3] = 0x1000;
+ m_font_selection_mask = 0x01;
+ m_start_offset = 0;
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_cga_device::device_start()
+{
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ set_isa_device();
+ m_vram = auto_alloc_array(machine(), UINT8, m_vram_size);
+ m_update_row = NULL;
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_device::io_read), this ), write8_delegate( FUNC(isa8_cga_device::io_write), this ) );
+ m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", m_vram);
+ m_superimpose = false;
+
+ /* Initialise the cga palette */
+ int i;
+
+ for ( i = 0; i < CGA_PALETTE_SETS * 16; i++ )
+ {
+ m_palette->set_pen_color( i, cga_palette[i][0], cga_palette[i][1], cga_palette[i][2] );
+ }
+
+ i = 0x8000;
+ for ( int r = 0; r < 32; r++ )
+ {
+ for ( int g = 0; g < 32; g++ )
+ {
+ for ( int b = 0; b < 32; b++ )
+ {
+ m_palette->set_pen_color( i, r << 3, g << 3, b << 3 );
+ i++;
+ }
+ }
+ }
+
+ astring tempstring;
+ m_chr_gen_base = memregion(subtag(tempstring, "gfx1"))->base();
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1];
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_cga_device::device_reset()
+{
+ m_update_row = NULL;
+ m_framecnt = 0;
+ m_mode_control = 0;
+ m_vsync = 0;
+ m_hsync = 0;
+ m_color_select = 0;
+ memset(m_palette_lut_2bpp, 0, sizeof(m_palette_lut_2bpp));
+}
+
+/***************************************************************************
+
+ Methods
+
+***************************************************************************/
+
+
+UINT32 isa8_cga_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ mc6845->screen_update( screen, bitmap, cliprect);
+
+ /* Check for changes in font dipsetting */
+ switch ( CGA_FONT )
+ {
+ case 0:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[0];
+ break;
+ case 1:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[1];
+ break;
+ case 2:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[2];
+ break;
+ case 3:
+ m_chr_gen = m_chr_gen_base + m_chr_gen_offset[3];
+ break;
+ }
+ return 0;
+}
+
+
+const device_type ISA8_CGA_POISK2 = &device_creator<isa8_cga_poisk2_device>;
+
+//-------------------------------------------------
+// isa8_cga_poisk2_device - constructor
+//-------------------------------------------------
+
+isa8_cga_poisk2_device::isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_POISK2, "ISA8_CGA_POISK2", tag, owner, clock, "cga_poisk2", __FILE__)
+{
+ m_chr_gen_offset[0] = 0x0000;
+ m_chr_gen_offset[1] = 0x0800;
+}
+
+ROM_START( cga_poisk2 )
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD( "p2_ecga.rf4", 0x0000, 0x2000, CRC(d537f665) SHA1(d70f085b9b0cbd53df7c3122fbe7592998ba8fed))
+ROM_END
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_cga_poisk2_device::device_rom_region() const
+{
+ return ROM_NAME( cga_poisk2 );
+}
+
+
+/* for superimposing CGA over a different source video (i.e. tetriskr) */
+const device_type ISA8_CGA_SUPERIMPOSE = &device_creator<isa8_cga_superimpose_device>;
+
+//-------------------------------------------------
+// isa8_cga_superimpose_device - constructor
+//-------------------------------------------------
+
+isa8_cga_superimpose_device::isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_SUPERIMPOSE, "ISA8_CGA_SUPERIMPOSE", tag, owner, clock, "cga_superimpose", __FILE__)
+{
+ m_superimpose = true;
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = attr >> 4;
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8. Composite monitor, greyscale.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_comp_grey_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = 0x10 + ( attr & 0x0F );
+ UINT16 bg = 0x10 + ( ( attr >> 4 ) & 0x07 );
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) with high intensity bg.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_inten_alt_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_inten_alt_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+
+ if ( i == cursor_x && ( cga->m_framecnt & 0x08 ) )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) and blinking colors.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_blink_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = (attr >> 4) & 0x07;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+static MC6845_UPDATE_ROW( cga_text_blink_update_row_si )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x0F;
+ UINT16 bg = (attr >> 4) & 0x07;
+ UINT8 xi;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ for(xi=0;xi<8;xi++)
+ {
+ UINT8 pen_data, dot;
+
+ dot = (data & (1 << (7-xi)));
+ pen_data = dot ? fg : bg;
+ if(pen_data || dot)
+ *p = palette[pen_data];
+ p++;
+ }
+ }
+}
+
+/***************************************************************************
+ Draw text mode with 40x25 characters (default) and blinking colors.
+ The character cell size is 16x8
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_text_blink_alt_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_text_blink_alt_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x3fff;
+ UINT8 chr = videoram[ offset ];
+ UINT8 attr = videoram[ offset +1 ];
+ UINT8 data = cga->m_chr_gen[ chr * 8 + ra ];
+ UINT16 fg = attr & 0x07;
+ UINT16 bg = 0;
+
+ if ( i == cursor_x )
+ {
+ if ( cga->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( cga->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ bg = ( attr >> 4 ) & 0x07;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+}
+
+
+/* The lo-res (320x200) graphics mode on a colour composite monitor */
+
+static MC6845_UPDATE_ROW( cga_gfx_4bppl_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bppl_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+
+#if 0
+/* The hi-res graphics mode on a colour composite monitor
+ *
+ * The different scaling factors mean that the '160x200' versions of screens
+ * are the same size as the normal colour ones.
+ */
+
+static const UINT8 yc_lut2[4] = { 0, 182, 71, 255 };
+
+static const UINT8 yc_lut[16][8] =
+{
+ { 0, 0, 0, 0, 0, 0, 0, 0 }, /* black */
+ { 0, 0, 0, 0, 1, 1, 1, 1 }, /* blue */
+ { 0, 1, 1, 1, 1, 0, 0, 0 }, /* green */
+ { 0, 0, 1, 1, 1, 1, 0, 0 }, /* cyan */
+ { 1, 1, 0, 0, 0, 0, 1, 1 }, /* red */
+ { 1, 0, 0, 0, 0, 1, 1, 1 }, /* magenta */
+ { 1, 1, 1, 1, 0, 0, 0, 0 }, /* yellow */
+ { 1, 1, 1, 1, 1, 1, 1, 1 }, /* white */
+ /* Intensity set */
+ { 2, 2, 2, 2, 2, 2, 2, 2 }, /* black */
+ { 2, 2, 2, 2, 3, 3, 3, 3 }, /* blue */
+ { 2, 3, 3, 3, 3, 2, 2, 2 }, /* green */
+ { 2, 2, 3, 3, 3, 3, 2, 2 }, /* cyan */
+ { 3, 3, 2, 2, 2, 2, 3, 3 }, /* red */
+ { 3, 2, 2, 2, 2, 3, 3, 3 }, /* magenta */
+ { 3, 3, 3, 3, 2, 2, 2, 2 }, /* yellow */
+ { 3, 3, 3, 3, 3, 3, 3, 3 }, /* white */
+};
+#endif
+
+static MC6845_UPDATE_ROW( cga_gfx_4bpph_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_4bpph_update_row",("\n"));
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data >> 4]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ *p = palette[data & 0x0F]; p++;
+ }
+}
+
+
+/***************************************************************************
+ Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel.
+ Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+ cga fetches 2 byte per mc6845 access.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_gfx_2bpp_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_2bpp_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( y & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+
+ data = videoram[ offset+1 ];
+
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 6 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 4 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ ( data >> 2 ) & 0x03 ]]; p++;
+ *p = palette[cga->m_palette_lut_2bpp[ data & 0x03 ]]; p++;
+ }
+}
+
+
+
+/***************************************************************************
+ Draw graphics mode with 640x200 pixels (default).
+ The cell size is 1x1 (1 scanline is the real default)
+ Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( cga_gfx_1bpp_update_row )
+{
+ isa8_cga_device *cga = downcast<isa8_cga_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ UINT8 fg = cga->m_color_select & 0x0F;
+ int i;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"cga_gfx_1bpp_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ( ma + i ) << 1 ) & 0x1fff ) | ( ( ra & 1 ) << 13 );
+ UINT8 data = videoram[ offset ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+
+ data = videoram[ offset + 1 ];
+
+ *p = palette[( data & 0x80 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x40 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x20 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x10 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x08 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x04 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x02 ) ? fg : 0]; p++;
+ *p = palette[( data & 0x01 ) ? fg : 0]; p++;
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_cga_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_cga_device::vsync_changed )
+{
+ m_vsync = state ? 9 : 0;
+ if ( state )
+ {
+ m_framecnt++;
+ }
+}
+
+
+void isa8_cga_device::set_palette_luts(void)
+{
+ /* Setup 2bpp palette lookup table */
+ if ( m_mode_control & 0x10 )
+ {
+ m_palette_lut_2bpp[0] = 0;
+ }
+ else
+ {
+ m_palette_lut_2bpp[0] = m_color_select & 0x0F;
+ }
+ if ( m_mode_control & 0x04 )
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7;
+ }
+ else
+ {
+ if ( m_color_select & 0x20 )
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 3;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 5;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 7;
+ }
+ else
+ {
+ m_palette_lut_2bpp[1] = ( ( m_color_select & 0x10 ) >> 1 ) | 2;
+ m_palette_lut_2bpp[2] = ( ( m_color_select & 0x10 ) >> 1 ) | 4;
+ m_palette_lut_2bpp[3] = ( ( m_color_select & 0x10 ) >> 1 ) | 6;
+ }
+ }
+ //logerror("2bpp lut set to %d,%d,%d,%d\n", cga.palette_lut_2bpp[0], cga.palette_lut_2bpp[1], cga.palette_lut_2bpp[2], cga.palette_lut_2bpp[3]);
+}
+
+/*
+ * rW CGA mode control register (see #P138)
+ *
+ * x x x 0 1 0 0 0 - 320x200, 40x25 text. Colour on RGB and composite monitors.
+ * x x x 0 1 0 0 1 - 640x200, 80x25 text. Colour on RGB and composite monitors.
+ * x x x 0 1 0 1 0 - 320x200 graphics. Colour on RGB and composite monitors.
+ * x x x 0 1 0 1 1 - unknown/invalid.
+ * x x x 0 1 1 0 0 - 320x200, 40x25 text. Colour on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 0 1 - 640x200, 80x25 text. Colour on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 1 0 - 320x200 graphics. Alternative palette on RGB, greyscale on composite monitors.
+ * x x x 0 1 1 1 1 - unknown/invalid.
+ * x x x 1 1 0 0 0 - unknown/invalid.
+ * x x x 1 1 0 0 1 - unknown/invalid.
+ * x x x 1 1 0 1 0 - 160x200/640x200 graphics. 640x200 ?? on RGB monitor, 160x200 on composite monitor.
+ * x x x 1 1 0 1 1 - unknown/invalid.
+ * x x x 1 1 1 0 0 - unknown/invalid.
+ * x x x 1 1 1 0 1 - unknown/invalid.
+ * x x x 1 1 1 1 0 - 640x200 graphics. Colour on black on RGB monitor, monochrome on composite monitor.
+ * x x x 1 1 1 1 1 - unknown/invalid.
+ */
+void isa8_cga_device::mode_control_w(UINT8 data)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+ UINT8 monitor = CGA_MONITOR;
+
+ m_mode_control = data;
+
+ //logerror("mode set to %02X\n", cga.mode_control & 0x3F );
+ switch ( m_mode_control & 0x3F )
+ {
+ case 0x08: case 0x09: case 0x0C: case 0x0D:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ if ( m_mode_control & 0x04 )
+ {
+ /* Composite greyscale */
+ m_update_row = cga_text_inten_comp_grey_update_row;
+ }
+ else
+ {
+ /* Composite colour */
+ m_update_row = cga_text_inten_update_row;
+ }
+ }
+ else
+ {
+ /* RGB colour */
+ m_update_row = cga_text_inten_update_row;
+ }
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bppl_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_2bpp_update_row;
+ }
+ break;
+ case 0x0E: case 0x0F: case 0x2E: case 0x2F:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_gfx_2bpp_update_row;
+ break;
+ case 0x18: case 0x19: case 0x1C: case 0x1D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_alt_update_row;
+ break;
+ case 0x1A: case 0x1B: case 0x3A: case 0x3B:
+ mc6845->set_hpixels_per_column( 16 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bpph_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_1bpp_update_row;
+ }
+ break;
+ case 0x1E: case 0x1F: case 0x3E: case 0x3F:
+ mc6845->set_hpixels_per_column( 16 );
+ m_update_row = cga_gfx_1bpp_update_row;
+ break;
+ case 0x28: case 0x29: case 0x2C: case 0x2D:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( monitor == CGA_MONITOR_COMPOSITE )
+ {
+ if ( m_mode_control & 0x04 )
+ {
+ /* Composite greyscale */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ else
+ {
+ /* Composite colour */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ }
+ else
+ {
+ /* RGB colour */
+ m_update_row = m_superimpose ? cga_text_blink_update_row_si : cga_text_blink_update_row;
+ }
+ break;
+ case 0x38: case 0x39: case 0x3C: case 0x3D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_alt_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ break;
+ }
+
+ // The lowest bit of the mode register selects, among others, the
+ // input clock to the 6845.
+ mc6845->set_clock( ( m_mode_control & 1 ) ? CGA_HCLK : CGA_LCLK );
+
+ set_palette_luts();
+}
+
+
+
+/*
+ * Select Plantronics modes
+ */
+void isa8_cga_device::plantronics_w(UINT8 data)
+{
+ if ( ( CGA_CHIPSET ) != CGA_CHIPSET_ATI) return;
+
+ data &= 0x70; /* Only bits 6-4 are used */
+ m_plantronics = data;
+}
+
+
+
+/*************************************************************************
+ *
+ * CGA
+ * color graphics adapter
+ *
+ *************************************************************************/
+
+
+READ8_MEMBER( isa8_cga_device::io_read )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+ UINT8 data = 0xff;
+
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = m_vsync | ( ( data & 0x40 ) >> 4 ) | m_hsync;
+ break;
+ }
+ return data;
+}
+
+
+
+WRITE8_MEMBER( isa8_cga_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ switch(offset) {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(data);
+ break;
+ case 9:
+ m_color_select = data;
+ set_palette_luts();
+ break;
+ case 0x0d:
+ plantronics_w(data);
+ break;
+ }
+}
+
+
+
+/* Old plantronics rendering code, leaving it uncommented until we have re-implemented it */
+
+//
+// From choosevideomode:
+//
+// /* Plantronics high-res */
+// if ((cga.mode_control & 2) && (cga.plantronics & 0x20))
+// proc = cga_pgfx_2bpp;
+// /* Plantronics low-res */
+// if ((cga.mode_control & 2) && (cga.plantronics & 0x10))
+// proc = cga_pgfx_4bpp;
+//
+
+//INLINE void pgfx_plot_unit_4bpp(bitmap_ind16 &bitmap,
+// int x, int y, int offs)
+//{
+// int color, values[2];
+// int i;
+//
+// if (cga.plantronics & 0x40)
+// {
+// values[0] = videoram[offs | 0x4000];
+// values[1] = videoram[offs];
+// }
+// else
+// {
+// values[0] = videoram[offs];
+// values[1] = videoram[offs | 0x4000];
+// }
+// for (i=3; i>=0; i--)
+// {
+// color = ((values[0] & 0x3) << 1) |
+// ((values[1] & 2) >> 1) |
+// ((values[1] & 1) << 3);
+// bitmap.pix16(y, x+i) = Machine->pens[color];
+// values[0]>>=2;
+// values[1]>>=2;
+// }
+//}
+//
+//
+//
+///***************************************************************************
+// Draw graphics mode with 640x200 pixels (default) with 2 bits/pixel.
+// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+// Second plane at CGA_base + 0x4000 / 0x6000
+//***************************************************************************/
+//
+//static void cga_pgfx_4bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+//{
+// int i, sx, sy, sh;
+// int offs = mscrtc6845_get_start(crtc)*2;
+// int lines = mscrtc6845_get_char_lines(crtc);
+// int height = mscrtc6845_get_char_height(crtc);
+// int columns = mscrtc6845_get_char_columns(crtc)*2;
+//
+// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff)
+// {
+// for (sh=0; sh<height; sh++, offs|=0x2000)
+// {
+// // char line 0 used as a12 line in graphic mode
+// if (!(sh & 1))
+// {
+// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
+// {
+// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
+// }
+// }
+// else
+// {
+// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
+// {
+// pgfx_plot_unit_4bpp(bitmap, sx*4, sy*height+sh, i);
+// }
+// }
+// }
+// }
+//}
+//
+//
+//
+//INLINE void pgfx_plot_unit_2bpp(bitmap_ind16 &bitmap,
+// int x, int y, const UINT16 *palette, int offs)
+//{
+// int i;
+// UINT8 bmap[2], values[2];
+// UINT16 *dest;
+//
+// if (cga.plantronics & 0x40)
+// {
+// values[0] = videoram[offs];
+// values[1] = videoram[offs | 0x4000];
+// }
+// else
+// {
+// values[0] = videoram[offs | 0x4000];
+// values[1] = videoram[offs];
+// }
+// bmap[0] = bmap[1] = 0;
+// for (i=3; i>=0; i--)
+// {
+// bmap[0] = bmap[0] << 1; if (values[0] & 0x80) bmap[0] |= 1;
+// bmap[0] = bmap[0] << 1; if (values[1] & 0x80) bmap[0] |= 1;
+// bmap[1] = bmap[1] << 1; if (values[0] & 0x08) bmap[1] |= 1;
+// bmap[1] = bmap[1] << 1; if (values[1] & 0x08) bmap[1] |= 1;
+// values[0] = values[0] << 1;
+// values[1] = values[1] << 1;
+// }
+//
+// dest = &bitmap.pix16(y, x);
+// *(dest++) = palette[(bmap[0] >> 6) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 4) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 2) & 0x03];
+// *(dest++) = palette[(bmap[0] >> 0) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 6) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 4) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 2) & 0x03];
+// *(dest++) = palette[(bmap[1] >> 0) & 0x03];
+//}
+//
+//
+//
+///***************************************************************************
+// Draw graphics mode with 320x200 pixels (default) with 2 bits/pixel.
+// Even scanlines are from CGA_base + 0x0000, odd from CGA_base + 0x2000
+// cga fetches 2 byte per mscrtc6845 access (not modeled here)!
+//***************************************************************************/
+//
+//static void cga_pgfx_2bpp(bitmap_ind16 &bitmap, struct mscrtc6845 *crtc)
+//{
+// int i, sx, sy, sh;
+// int offs = mscrtc6845_get_start(crtc)*2;
+// int lines = mscrtc6845_get_char_lines(crtc);
+// int height = mscrtc6845_get_char_height(crtc);
+// int columns = mscrtc6845_get_char_columns(crtc)*2;
+// int colorset = cga.color_select & 0x3F;
+// const UINT16 *palette;
+//
+// /* Most chipsets use bit 2 of the mode control register to
+// * access a third palette. But not consistently. */
+// pc_cga_check_palette();
+// switch(CGA_CHIPSET)
+// {
+// /* The IBM Professional Graphics Controller behaves like
+// * the PC1512, btw. */
+// case CGA_CHIPSET_PC1512:
+// if ((colorset < 32) && (cga.mode_control & 4)) colorset += 64;
+// break;
+//
+// case CGA_CHIPSET_IBM:
+// case CGA_CHIPSET_PC200:
+// case CGA_CHIPSET_ATI:
+// case CGA_CHIPSET_PARADISE:
+// if (cga.mode_control & 4) colorset = (colorset & 0x1F) + 64;
+// break;
+// }
+//
+//
+// /* The fact that our palette is located in cga_colortable is a vestigial
+// * aspect from when we were doing that ugly trick where drawgfx() would
+// * handle graphics drawing. Truthfully, we should probably be using
+// * palette_set_color_rgb() here and not doing the palette lookup in the loop
+// */
+// palette = &cga_colortable[256*2 + 16*2] + colorset * 4;
+//
+// for (sy=0; sy<lines; sy++,offs=(offs+columns)&0x1fff) {
+//
+// for (sh=0; sh<height; sh++)
+// {
+// if (!(sh&1)) { // char line 0 used as a12 line in graphic mode
+// for (i=offs, sx=0; sx<columns; sx++, i=(i+1)&0x1fff)
+// {
+// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
+// }
+// }
+// else
+// {
+// for (i=offs|0x2000, sx=0; sx<columns; sx++, i=((i+1)&0x1fff)|0x2000)
+// {
+// pgfx_plot_unit_2bpp(bitmap, sx*8, sy*height+sh, palette, i);
+// }
+// }
+// }
+// }
+//}
+
+
+static MC6845_UPDATE_ROW( pc1512_gfx_4bpp_update_row )
+{
+ isa8_cga_pc1512_device *cga = downcast<isa8_cga_pc1512_device *>(device->owner());
+ UINT8 *videoram = cga->m_vram + cga->m_start_offset;
+ UINT32 *p = &bitmap.pix32(y);
+ const rgb_t *palette = cga->m_palette->palette()->entry_list_raw();
+ UINT16 offset_base = ra << 13;
+ int j;
+ running_machine &machine = device->machine();
+
+ if ( y == 0 ) CGA_LOG(1,"pc1512_gfx_4bpp_update_row",("\n"));
+ for ( j = 0; j < x_count; j++ )
+ {
+ UINT16 offset = offset_base | ( ( ma + j ) & 0x1FFF );
+ UINT16 i = ( cga->m_color_select & 8 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[3] | offset ] << 3 : 0;
+ UINT16 r = ( cga->m_color_select & 4 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[2] | offset ] << 2 : 0;
+ UINT16 g = ( cga->m_color_select & 2 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[1] | offset ] << 1 : 0;
+ UINT16 b = ( cga->m_color_select & 1 ) ? videoram[ isa8_cga_pc1512_device::vram_offset[0] | offset ] : 0;
+
+ *p = palette[( ( i & 0x400 ) | ( r & 0x200 ) | ( g & 0x100 ) | ( b & 0x80 ) ) >> 7]; p++;
+ *p = palette[( ( i & 0x200 ) | ( r & 0x100 ) | ( g & 0x080 ) | ( b & 0x40 ) ) >> 6]; p++;
+ *p = palette[( ( i & 0x100 ) | ( r & 0x080 ) | ( g & 0x040 ) | ( b & 0x20 ) ) >> 5]; p++;
+ *p = palette[( ( i & 0x080 ) | ( r & 0x040 ) | ( g & 0x020 ) | ( b & 0x10 ) ) >> 4]; p++;
+ *p = palette[( ( i & 0x040 ) | ( r & 0x020 ) | ( g & 0x010 ) | ( b & 0x08 ) ) >> 3]; p++;
+ *p = palette[( ( i & 0x020 ) | ( r & 0x010 ) | ( g & 0x008 ) | ( b & 0x04 ) ) >> 2]; p++;
+ *p = palette[( ( i & 0x010 ) | ( r & 0x008 ) | ( g & 0x004 ) | ( b & 0x02 ) ) >> 1]; p++;
+ *p = palette[ ( i & 0x008 ) | ( r & 0x004 ) | ( g & 0x002 ) | ( b & 0x01 ) ]; p++;
+ }
+}
+
+
+WRITE8_MEMBER( isa8_cga_pc1512_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(CGA_MC6845_NAME);
+
+ switch (offset)
+ {
+ case 0: case 2: case 4: case 6:
+ data &= 0x1F;
+ mc6845->address_w( space, offset, data );
+ m_mc6845_address = data;
+ break;
+
+ case 1: case 3: case 5: case 7:
+ if ( ! m_mc6845_locked_register[m_mc6845_address] )
+ {
+ mc6845->register_w( space, offset, data );
+ if ( isa8_cga_pc1512_device::mc6845_writeonce_register[m_mc6845_address] )
+ {
+ m_mc6845_locked_register[m_mc6845_address] = 1;
+ }
+ }
+ break;
+
+ case 0x8:
+ /* Check if we're changing to graphics mode 2 */
+ if ( ( m_mode_control & 0x12 ) != 0x12 && ( data & 0x12 ) == 0x12 )
+ {
+ m_write = 0x0F;
+ }
+ else
+ {
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[0]);
+ }
+ m_mode_control = data;
+ switch( m_mode_control & 0x3F )
+ {
+ case 0x08: case 0x09: case 0x0C: case 0x0D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_update_row;
+ break;
+ case 0x0A: case 0x0B: case 0x2A: case 0x2B:
+ mc6845->set_hpixels_per_column( 8 );
+ if ( ( CGA_MONITOR ) == CGA_MONITOR_COMPOSITE )
+ {
+ m_update_row = cga_gfx_4bppl_update_row;
+ }
+ else
+ {
+ m_update_row = cga_gfx_2bpp_update_row;
+ }
+ break;
+ case 0x0E: case 0x0F: case 0x2E: case 0x2F:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_gfx_2bpp_update_row;
+ break;
+ case 0x18: case 0x19: case 0x1C: case 0x1D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_inten_alt_update_row;
+ break;
+ case 0x1A: case 0x1B: case 0x3A: case 0x3B:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = pc1512_gfx_4bpp_update_row;
+ break;
+ case 0x1E: case 0x1F: case 0x3E: case 0x3F:
+ mc6845->set_hpixels_per_column( 16 );
+ m_update_row = cga_gfx_1bpp_update_row;
+ break;
+ case 0x28: case 0x29: case 0x2C: case 0x2D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_update_row;
+ break;
+ case 0x38: case 0x39: case 0x3C: case 0x3D:
+ mc6845->set_hpixels_per_column( 8 );
+ m_update_row = cga_text_blink_alt_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ break;
+ }
+ break;
+
+ case 0xd:
+ m_write = data;
+ break;
+
+ case 0xe:
+ m_read = data;
+ if ( ( m_mode_control & 0x12 ) == 0x12 )
+ {
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[data & 3]);
+ }
+ break;
+
+ default:
+ isa8_cga_device::io_write(space, offset,data);
+ break;
+ }
+}
+
+
+READ8_MEMBER( isa8_cga_pc1512_device::io_read )
+{
+ UINT8 data;
+
+ switch (offset)
+ {
+ case 0xd:
+ data = m_write;
+ break;
+
+ case 0xe:
+ data = m_read;
+ break;
+
+ default:
+ data = isa8_cga_device::io_read(space, offset);
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_MEMBER( isa8_cga_pc1512_device::vram_w )
+{
+ if ( ( m_mode_control & 0x12 ) == 0x12 )
+ {
+ if (m_write & 1)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[0]] = data; /* blue plane */
+ if (m_write & 2)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[1]] = data; /* green */
+ if (m_write & 4)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[2]] = data; /* red */
+ if (m_write & 8)
+ m_vram[offset+isa8_cga_pc1512_device::vram_offset[3]] = data; /* intensity (text, 4color) */
+ }
+ else
+ {
+ m_vram[offset + isa8_cga_pc1512_device::vram_offset[0]] = data;
+ }
+}
+
+
+const device_type ISA8_CGA_PC1512 = &device_creator<isa8_cga_pc1512_device>;
+
+const offs_t isa8_cga_pc1512_device::vram_offset[4]= { 0x0000, 0x4000, 0x8000, 0xC000 };
+const UINT8 isa8_cga_pc1512_device::mc6845_writeonce_register[31] =
+{
+ 1, 0, 1, 1, 1, 1, 0, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+};
+
+//-------------------------------------------------
+// isa8_cga_pc1512_device - constructor
+//-------------------------------------------------
+
+isa8_cga_pc1512_device::isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_CGA_PC1512, "ISA8_CGA_PC1512", tag, owner, clock, "cga_pc1512", __FILE__)
+{
+ m_vram_size = 0x10000;
+ m_chr_gen_offset[0] = 0x0000;
+ m_chr_gen_offset[1] = 0x0800;
+ m_chr_gen_offset[2] = 0x1000;
+ m_chr_gen_offset[3] = 0x1800;
+}
+
+
+const rom_entry *isa8_cga_pc1512_device::device_rom_region() const
+{
+ return NULL;
+}
+
+
+ioport_constructor isa8_cga_pc1512_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pc1512 );
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_cga_pc1512_device::device_start()
+{
+ isa8_cga_device::device_start();
+
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_cga_pc1512_device::io_read), this ), write8_delegate( FUNC(isa8_cga_pc1512_device::io_write), this ) );
+ m_isa->install_bank(0xb8000, 0xbbfff, 0, 0, "bank1", m_vram);
+
+ address_space &space = machine().firstcpu->space( AS_PROGRAM );
+
+ space.install_write_handler( 0xb8000, 0xbbfff, 0, 0x0C000, write8_delegate( FUNC(isa8_cga_pc1512_device::vram_w), this ) );
+}
+
+void isa8_cga_pc1512_device::device_reset()
+{
+ isa8_cga_device::device_reset();
+
+ m_write = 0x0f;
+ m_read = 0;
+ m_mc6845_address = 0;
+ for ( int i = 0; i < 31; i++ )
+ {
+ m_mc6845_locked_register[i] = 0;
+ }
+
+ membank("bank1")->set_base(m_vram + isa8_cga_pc1512_device::vram_offset[0]);
+}
+
+void isa8_wyse700_device::change_resolution(UINT8 mode)
+{
+ int width = 0, height = 0;
+ if (mode & 2) {
+ machine().root_device().membank("bank_wy1")->set_base(m_vram + 0x10000);
+ } else {
+ machine().root_device().membank("bank_wy1")->set_base(m_vram);
+ }
+ if ((m_control & 0xf0) == (mode & 0xf0)) return;
+
+ switch(mode & 0xf0) {
+ case 0xc0: width = 1280; height = 800; break;
+ case 0xa0: width = 1280; height = 400; break;
+ case 0x80: width = 640; height = 400; break;
+ case 0x00: width = 640; height = 400; break; // unhandled
+ }
+ rectangle visarea(0, width-1, 0, height-1);
+ subdevice<screen_device>(CGA_SCREEN_NAME)->configure(width, height, visarea, HZ_TO_ATTOSECONDS(60));
+
+}
+
+WRITE8_MEMBER( isa8_wyse700_device::io_write )
+{
+ switch (offset)
+ {
+ case 0xd:
+ m_bank_offset = data;
+ break;
+
+ case 0xe:
+ m_bank_base = data;
+ break;
+
+ case 0xf:
+ change_resolution(data);
+ m_control = data;
+ break;
+ default:
+ isa8_cga_device::io_write(space, offset,data);
+ break;
+ }
+}
+
+
+READ8_MEMBER( isa8_wyse700_device::io_read )
+{
+ UINT8 data;
+
+ switch (offset)
+ {
+ case 0xd:
+ data = m_bank_offset;
+ break;
+
+ case 0xe:
+ data = m_bank_base;
+ break;
+
+ case 0xf:
+ data = m_control;
+ break;
+ default:
+ data = isa8_cga_device::io_read(space, offset);
+ break;
+ }
+ return data;
+}
+
+
+const device_type ISA8_WYSE700 = &device_creator<isa8_wyse700_device>;
+
+
+//-------------------------------------------------
+// isa8_wyse700_device - constructor
+//-------------------------------------------------
+
+isa8_wyse700_device::isa8_wyse700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_WYSE700, "Wyse 700", tag, owner, clock, "wyse700", __FILE__)
+{
+ m_vram_size = 0x20000;
+ m_start_offset = 0x18000;
+}
+
+/*
+Character ROMs:
+
+250211-03.e5: Character ROM Label: "(C) WYSE TECH / REV.A / 250211-03"
+250212-03.f5: Character ROM Label: "(C) WYSE TECH / REV.A / 250212-03"
+
+Not dumped:
+
+250026-03.2d: MC68705 MCU Label: "(C) WYSE TECH / REV.1 / 250026-03"
+250270-01.8b: PAL? Label: "250270-01"
+250024-01.8g: PAL? Label: "250024-01"
+250210-01.c2: PAL? Label: "250210-01"
+*/
+ROM_START( wyse700 )
+ ROM_REGION(0x4000,"gfx1", 0)
+ ROM_LOAD( "250211-03.e5", 0x0000, 0x2000, CRC(58b61f63) SHA1(29ecb7cf7d07d692f0fc54e2dea8389f17a65f1a))
+ ROM_LOAD( "250212-03.f5", 0x2000, 0x2000, CRC(6930d741) SHA1(1beeb133c5e39eee9914bdc5924039d70b5edcad))
+ROM_END
+
+const rom_entry *isa8_wyse700_device::device_rom_region() const
+{
+ return ROM_NAME( wyse700 );
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_wyse700_device::device_start()
+{
+ isa8_cga_device::device_start();
+
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_wyse700_device::io_read), this ), write8_delegate( FUNC(isa8_wyse700_device::io_write), this ) );
+ m_isa->install_bank(0xa0000, 0xaffff, 0, 0, "bank_wy1", m_vram);
+ m_isa->install_bank(0xb0000, 0xbffff, 0, 0, "bank_cga", m_vram + 0x10000);
+}
+
+void isa8_wyse700_device::device_reset()
+{
+ isa8_cga_device::device_reset();
+ m_control = 0;
+ m_bank_offset = 0;
+ m_bank_base = 0;
+}
+
+UINT32 isa8_wyse700_device::screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect)
+{
+ if (m_control & 0x08) {
+ const rgb_t *palette = m_palette->palette()->entry_list_raw();
+ UINT8 fg = m_color_select & 0x0F;
+ UINT32 addr = 0;
+ for (int y = 0; y < 800; y++) {
+ UINT8 *src = m_vram + addr;
+
+ if (y & 1) {
+ src += 0x10000;
+ addr += 160;
+ }
+
+ for (int x = 0; x < (1280 / 8); x++) {
+ UINT8 val = src[x];
+
+ for (int i = 0; i < 8; i++) {
+ bitmap.pix32(y,x*8+i) = (val & 0x80) ? palette[fg] : palette[0x00];
+ val <<= 1;
+ }
+ }
+ }
+ } else {
+ return isa8_cga_device::screen_update(screen, bitmap, cliprect);
+ }
+ return 0;
+}
+
+
+const device_type ISA8_EC1841_0002 = &device_creator<isa8_ec1841_0002_device>;
+
+//-------------------------------------------------
+// isa8_ec1841_0002_device - constructor
+//-------------------------------------------------
+
+isa8_ec1841_0002_device::isa8_ec1841_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_cga_device( mconfig, ISA8_EC1841_0002, "EC 1841.0002 (CGA)", tag, owner, clock, "ec1841_0002", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_ec1841_0002_device::device_start()
+{
+ isa8_cga_device::device_start();
+
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate( FUNC(isa8_ec1841_0002_device::io_read), this ), write8_delegate( FUNC(isa8_ec1841_0002_device::io_write), this ) );
+}
+
+void isa8_ec1841_0002_device::device_reset()
+{
+ isa8_cga_device::device_reset();
+ m_p3df = 0;
+}
+
+ROM_START( iskr1031 )
+ ROM_REGION(0x2000,"gfx1", 0)
+ ROM_LOAD( "iskra-1031_font.bin", 0x0000, 0x2000, CRC(f4d62e80) SHA1(ad7e81a0c9abc224671422bbcf6f6262da92b510))
+ROM_END
+
+const rom_entry *isa8_ec1841_0002_device::device_rom_region() const
+{
+ return ROM_NAME( iskr1031 );
+}
+
+WRITE8_MEMBER( isa8_ec1841_0002_device::char_ram_write )
+{
+ offset ^= BIT(offset, 12);
+// logerror("write char ram %04x %02x\n",offset,data);
+ m_chr_gen_base[offset + 0x0000] = data;
+ m_chr_gen_base[offset + 0x0800] = data;
+ m_chr_gen_base[offset + 0x1000] = data;
+ m_chr_gen_base[offset + 0x1800] = data;
+}
+
+READ8_MEMBER( isa8_ec1841_0002_device::char_ram_read )
+{
+ offset ^= BIT(offset, 12);
+ return m_chr_gen_base[offset];
+}
+
+WRITE8_MEMBER( isa8_ec1841_0002_device::io_write )
+{
+ switch (offset)
+ {
+ case 0x0f:
+ m_p3df = data;
+ if (data & 1) {
+ m_isa->install_memory(0xb8000, 0xb9fff, 0, m_vram_size & 0x4000,
+ read8_delegate( FUNC(isa8_ec1841_0002_device::char_ram_read), this),
+ write8_delegate(FUNC(isa8_ec1841_0002_device::char_ram_write), this) );
+ } else {
+ m_isa->install_bank(0xb8000, 0xb8000 + MIN(0x8000,m_vram_size) - 1, 0, m_vram_size & 0x4000, "bank_cga", m_vram);
+ }
+ break;
+ default:
+ isa8_cga_device::io_write(space, offset, data);
+ break;
+ }
+}
+
+READ8_MEMBER( isa8_ec1841_0002_device::io_read )
+{
+ UINT8 data;
+
+ switch (offset)
+ {
+ case 0x0f:
+ data = m_p3df;
+ break;
+ default:
+ data = isa8_cga_device::io_read(space, offset);
+ break;
+ }
+ return data;
+}
diff --git a/src/emu/bus/isa/cga.h b/src/emu/bus/isa/cga.h
new file mode 100644
index 00000000000..d5f5755f30f
--- /dev/null
+++ b/src/emu/bus/isa/cga.h
@@ -0,0 +1,206 @@
+#pragma once
+
+#ifndef __ISA_CGA_H__
+#define __ISA_CGA_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/mc6845.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_cga_device
+
+class isa8_cga_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+ friend class isa8_cga_superimpose_device;
+// friend class isa8_ec1841_0002_device;
+ friend class isa8_cga_poisk2_device;
+ friend class isa8_cga_pc1512_device;
+
+public:
+ // construction/destruction
+ isa8_cga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_cga_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ required_ioport m_cga_config;
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+public:
+ void mode_control_w(UINT8 data);
+ void set_palette_luts();
+ void plantronics_w(UINT8 data);
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+ DECLARE_WRITE_LINE_MEMBER( hsync_changed );
+ DECLARE_WRITE_LINE_MEMBER( vsync_changed );
+ virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+
+public:
+ int m_framecnt;
+
+ UINT8 m_mode_control; /* wo 0x3d8 */
+ UINT8 m_color_select; /* wo 0x3d9 */
+ UINT8 m_status; /* ro 0x3da */
+
+ mc6845_update_row_func m_update_row;
+ UINT8 m_palette_lut_2bpp[4];
+ offs_t m_chr_gen_offset[4];
+ UINT8 m_font_selection_mask;
+ UINT8 *m_chr_gen_base;
+ UINT8 *m_chr_gen;
+ UINT8 m_vsync;
+ UINT8 m_hsync;
+ size_t m_vram_size;
+ UINT8 *m_vram;
+ bool m_superimpose;
+ UINT8 m_plantronics; /* This should be moved into the appropriate subclass */
+ offs_t m_start_offset;
+ required_device<palette_device> m_palette;
+};
+
+// device type definition
+extern const device_type ISA8_CGA;
+
+
+// ======================> isa8_cga_superimpose_device
+
+class isa8_cga_superimpose_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_superimpose_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+// device type definition
+extern const device_type ISA8_CGA_SUPERIMPOSE;
+
+
+// ======================> isa8_poisk2_device
+
+class isa8_cga_poisk2_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_poisk2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+};
+
+// device type definition
+extern const device_type ISA8_CGA_POISK2;
+
+
+// ======================> isa8_pc1512_device
+
+class isa8_cga_pc1512_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_cga_pc1512_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+public:
+ UINT8 m_write;
+ UINT8 m_read;
+ UINT8 m_mc6845_address;
+ UINT8 m_mc6845_locked_register[31];
+
+public:
+ // Static information
+ // mapping of the 4 planes into videoram
+ // (text data should be readable at videoram+0)
+ static const offs_t vram_offset[4];
+ static const UINT8 mc6845_writeonce_register[31];
+
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+
+ DECLARE_WRITE8_MEMBER( vram_w );
+};
+
+// device type definition
+extern const device_type ISA8_CGA_PC1512;
+
+// ======================> isa8_wyse700_device
+
+class isa8_wyse700_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_wyse700_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+public:
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+ virtual UINT32 screen_update(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
+ void change_resolution(UINT8 mode);
+
+ UINT8 m_bank_offset;
+ UINT8 m_bank_base;
+ UINT8 m_control;
+};
+
+// device type definition
+extern const device_type ISA8_WYSE700;
+
+// ======================> isa8_ec1841_0002_device
+
+class isa8_ec1841_0002_device :
+ public isa8_cga_device
+{
+public:
+ // construction/destruction
+ isa8_ec1841_0002_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+public:
+ virtual DECLARE_READ8_MEMBER( io_read );
+ virtual DECLARE_WRITE8_MEMBER( io_write );
+
+ UINT8 m_p3df;
+ DECLARE_READ8_MEMBER( char_ram_read );
+ DECLARE_WRITE8_MEMBER( char_ram_write );
+};
+
+// device type definition
+extern const device_type ISA8_EC1841_0002;
+
+
+#endif /* __ISA_CGA_H__ */
diff --git a/src/emu/bus/isa/com.c b/src/emu/bus/isa/com.c
new file mode 100644
index 00000000000..c4b1d292d28
--- /dev/null
+++ b/src/emu/bus/isa/com.c
@@ -0,0 +1,196 @@
+/***************************************************************************
+
+ ISA 8 bit Generic Communication Card
+
+***************************************************************************/
+
+#include "com.h"
+#include "bus/rs232/rs232.h"
+#include "bus/rs232/ser_mouse.h"
+#include "bus/rs232/terminal.h"
+#include "bus/rs232/null_modem.h"
+#include "machine/ins8250.h"
+
+static const ins8250_interface genpc_com_interface[2]=
+{
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, write_txd),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, write_dtr),
+ DEVCB_DEVICE_LINE_MEMBER("serport0", rs232_port_device, write_rts),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, write_txd),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, write_dtr),
+ DEVCB_DEVICE_LINE_MEMBER("serport1", rs232_port_device, write_rts),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ }/*,
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, write_txd),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, write_dtr),
+ DEVCB_DEVICE_LINE_MEMBER("serport2", rs232_port_device, write_rts),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_1),
+ DEVCB_NULL,
+ DEVCB_NULL
+ },
+ {
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, write_txd),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, write_dtr),
+ DEVCB_DEVICE_LINE_MEMBER("serport3", rs232_port_device, write_rts),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_com_device, pc_com_interrupt_2),
+ DEVCB_NULL,
+ DEVCB_NULL
+ }*/
+};
+
+static SLOT_INTERFACE_START(isa_com)
+ SLOT_INTERFACE("microsoft_mouse", MSFT_SERIAL_MOUSE)
+ SLOT_INTERFACE("msystems_mouse", MSYSTEM_SERIAL_MOUSE)
+ SLOT_INTERFACE("serial_terminal", SERIAL_TERMINAL)
+ SLOT_INTERFACE("null_modem", NULL_MODEM)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( com_config )
+ MCFG_INS8250_ADD( "uart_0", genpc_com_interface[0], XTAL_1_8432MHz )
+ MCFG_INS8250_ADD( "uart_1", genpc_com_interface[1], XTAL_1_8432MHz )
+ //MCFG_INS8250_ADD( "uart_2", genpc_com_interface[2], XTAL_1_8432MHz )
+ //MCFG_INS8250_ADD( "uart_3", genpc_com_interface[3], XTAL_1_8432MHz )
+
+ MCFG_RS232_PORT_ADD( "serport0", isa_com, "microsoft_mouse" )
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, rx_w))
+ MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dcd_w))
+ MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dsr_w))
+ MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, ri_w))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, cts_w))
+
+ MCFG_RS232_PORT_ADD( "serport1", isa_com, NULL )
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w))
+ MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w))
+ MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w))
+ MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w))
+
+ //MCFG_RS232_PORT_ADD( "serport2", isa_com, NULL )
+ //MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w))
+ //MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w))
+ //MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w))
+ //MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w))
+ //MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w))
+
+ //MCFG_RS232_PORT_ADD( "serport3", isa_com, NULL )
+ //MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, rx_w))
+ //MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, dcd_w))
+ //MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, dsr_w))
+ //MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, ri_w))
+ //MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_2", ins8250_uart_device, cts_w))
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_COM = &device_creator<isa8_com_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_com_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( com_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_com_device - constructor
+//-------------------------------------------------
+
+isa8_com_device::isa8_com_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_COM, "Communications Adapter PC/XT", tag, owner, clock, "isa_com", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+isa8_com_device::isa8_com_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_com_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x03f8, 0x03ff, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_0")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_0")) );
+ m_isa->install_device(0x02f8, 0x02ff, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_1")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_1")) );
+// m_isa->install_device(0x03e8, 0x03ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_2")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_2")) );
+// m_isa->install_device(0x02e8, 0x02ef, 0, 0, read8_delegate(FUNC(ins8250_device::ins8250_r), subdevice<ins8250_uart_device>("uart_3")), write8_delegate(FUNC(ins8250_device::ins8250_w), subdevice<ins8250_uart_device>("uart_3")) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_com_device::device_reset()
+{
+}
+
+static MACHINE_CONFIG_FRAGMENT( com_at_config )
+ MCFG_NS16450_ADD( "uart_0", genpc_com_interface[0], XTAL_1_8432MHz ) /* Verified: IBM P/N 6320947 Serial/Parallel card uses an NS16450N */
+ MCFG_NS16450_ADD( "uart_1", genpc_com_interface[1], XTAL_1_8432MHz )
+// MCFG_NS16450_ADD( "uart_2", genpc_com_interface[2], XTAL_1_8432MHz )
+// MCFG_NS16450_ADD( "uart_3", genpc_com_interface[3], XTAL_1_8432MHz )
+ MCFG_RS232_PORT_ADD( "serport0", isa_com, "microsoft_mouse" )
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, rx_w))
+ MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dcd_w))
+ MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, dsr_w))
+ MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, ri_w))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_0", ins8250_uart_device, cts_w))
+
+ MCFG_RS232_PORT_ADD( "serport1", isa_com, NULL )
+ MCFG_RS232_RXD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, rx_w))
+ MCFG_RS232_DCD_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dcd_w))
+ MCFG_RS232_DSR_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, dsr_w))
+ MCFG_RS232_RI_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, ri_w))
+ MCFG_RS232_CTS_HANDLER(DEVWRITELINE("uart_1", ins8250_uart_device, cts_w))
+
+// MCFG_RS232_PORT_ADD( "serport2", isa_com, NULL )
+// MCFG_RS232_PORT_ADD( "serport3", isa_com, NULL )
+MACHINE_CONFIG_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_COM_AT = &device_creator<isa8_com_at_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_com_at_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( com_at_config );
+}
+
+//-------------------------------------------------
+// isa8_com_device - constructor
+//-------------------------------------------------
+
+isa8_com_at_device::isa8_com_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_com_device(mconfig, ISA8_COM_AT, "Communications Adapter", tag, owner, clock, "isa_com_at", __FILE__)
+{
+}
diff --git a/src/emu/bus/isa/com.h b/src/emu/bus/isa/com.h
new file mode 100644
index 00000000000..baf390e4166
--- /dev/null
+++ b/src/emu/bus/isa/com.h
@@ -0,0 +1,56 @@
+#pragma once
+
+#ifndef __ISA_COM_H__
+#define __ISA_COM_H__
+
+#include "emu.h"
+#include "isa.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_com_device
+
+class isa8_com_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_com_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_com_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ DECLARE_WRITE_LINE_MEMBER(pc_com_interrupt_1) { m_isa->irq4_w(state); }
+ DECLARE_WRITE_LINE_MEMBER(pc_com_interrupt_2) { m_isa->irq3_w(state); }
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type ISA8_COM;
+
+// ======================> isa8_com_at_device
+
+class isa8_com_at_device :
+ public isa8_com_device
+{
+public:
+ // construction/destruction
+ isa8_com_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+
+// device type definition
+extern const device_type ISA8_COM_AT;
+
+#endif /* __ISA_COM_H__ */
diff --git a/src/emu/bus/isa/dectalk.c b/src/emu/bus/isa/dectalk.c
new file mode 100644
index 00000000000..aaae4c7285f
--- /dev/null
+++ b/src/emu/bus/isa/dectalk.c
@@ -0,0 +1,215 @@
+#include "dectalk.h"
+
+const device_type ISA8_DECTALK = &device_creator<dectalk_isa_device>;
+
+dectalk_isa_device::dectalk_isa_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
+ device_t(mconfig, ISA8_DECTALK, "DECTalk-PC", tag, owner, clock, "dectalk_isa", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_cpu(*this, "dectalk_cpu"),
+ m_dac(*this, "dac"),
+ m_dsp(*this, "dectalk_dsp")
+{
+}
+
+WRITE16_MEMBER(dectalk_isa_device::status_w)
+{
+ m_stat = data;
+}
+
+READ16_MEMBER(dectalk_isa_device::cmd_r)
+{
+ return m_cmd;
+}
+
+WRITE16_MEMBER(dectalk_isa_device::data_w)
+{
+ m_data = data;
+}
+
+READ16_MEMBER(dectalk_isa_device::data_r)
+{
+ return m_data;
+}
+
+READ16_MEMBER(dectalk_isa_device::host_irq_r)
+{
+ //m_isa->ir?_w(1);
+ return 0;
+}
+
+READ8_MEMBER(dectalk_isa_device::dma_r)
+{
+ return m_dma;
+}
+
+WRITE8_MEMBER(dectalk_isa_device::dma_w)
+{
+ m_dma = data;
+}
+
+WRITE16_MEMBER(dectalk_isa_device::dac_w)
+{
+ m_dac->write(data & 0xfff0);
+}
+
+WRITE16_MEMBER(dectalk_isa_device::output_ctl_w)
+{
+ // X9C503P potentiometer, 8-CS, 4-U/D, 2-INC
+ if(!(data & 8) && !(m_ctl & 2) && (data & 2))
+ {
+ if((data & 4) && (m_vol < 64))
+ m_vol++;
+ else if(!(data & 4) && m_vol)
+ m_vol--;
+
+ m_dac->set_output_gain(ALL_OUTPUTS, m_vol / 63.0);
+ }
+ m_dsp->set_input_line(INPUT_LINE_RESET, (data & 0x10) ? CLEAR_LINE : ASSERT_LINE);
+ m_ctl = data;
+}
+
+READ16_MEMBER(dectalk_isa_device::dsp_dma_r)
+{
+ m_bio = ASSERT_LINE;
+ return m_dsp_dma;
+}
+
+WRITE16_MEMBER(dectalk_isa_device::dsp_dma_w)
+{
+ m_bio = CLEAR_LINE;
+ m_dsp_dma = data;
+}
+
+READ16_MEMBER(dectalk_isa_device::bio_line_r)
+{
+ // TODO: reading the bio line doesn't cause any direct external effects so this is wrong
+ if(m_bio == ASSERT_LINE)
+ m_cpu->drq0_w(1);
+ return m_bio;
+}
+
+WRITE16_MEMBER(dectalk_isa_device::irq_line_w)
+{
+ m_cpu->int1_w(0);
+}
+
+WRITE_LINE_MEMBER(dectalk_isa_device::clock_w)
+{
+ m_dsp->set_input_line(INPUT_LINE_IRQ0, (!(m_ctl & 0x20) || state) ? CLEAR_LINE : ASSERT_LINE);
+}
+
+static ADDRESS_MAP_START(dectalk_cpu_io, AS_IO, 16, dectalk_isa_device)
+ AM_RANGE(0x0400, 0x0401) AM_READWRITE(cmd_r, status_w) //PCS0
+ AM_RANGE(0x0480, 0x0481) AM_READWRITE(data_r, data_w) //PCS1
+ AM_RANGE(0x0500, 0x0501) AM_WRITE(dsp_dma_w) //PCS2
+ AM_RANGE(0x0580, 0x0581) AM_READ(host_irq_r) //PCS3
+ AM_RANGE(0x0600, 0x0601) AM_WRITE(output_ctl_w) //PCS4
+ AM_RANGE(0x0680, 0x0681) AM_READWRITE8(dma_r, dma_w, 0xff) //PCS5
+ AM_RANGE(0x0700, 0x0701) AM_WRITE(irq_line_w) //PCS6
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(dectalk_cpu_map, AS_PROGRAM, 16, dectalk_isa_device)
+ AM_RANGE(0x00000, 0xFBFFF) AM_RAM
+ AM_RANGE(0xFC000, 0xFFFFF) AM_ROM AM_REGION("dectalk_cpu", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(dectalk_dsp_io, AS_IO, 16, dectalk_isa_device)
+ AM_RANGE(0x0, 0x0) AM_READ(dsp_dma_r)
+ AM_RANGE(0x1, 0x1) AM_READWRITE(dsp_dma_r, dac_w)
+ AM_RANGE(TMS32010_BIO, TMS32010_BIO) AM_READ(bio_line_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(dectalk_dsp_map, AS_PROGRAM, 16, dectalk_isa_device)
+ AM_RANGE(0x0000, 0x0FFF) AM_ROM AM_REGION("dectalk_dsp", 0)
+ADDRESS_MAP_END
+
+static MACHINE_CONFIG_FRAGMENT( dectalk_isa )
+ MCFG_CPU_ADD("dectalk_cpu", I80186, XTAL_20MHz)
+ MCFG_CPU_IO_MAP(dectalk_cpu_io)
+ MCFG_CPU_PROGRAM_MAP(dectalk_cpu_map)
+ MCFG_80186_TMROUT0_HANDLER(WRITELINE(dectalk_isa_device, clock_w));
+
+ MCFG_CPU_ADD("dectalk_dsp", TMS32015, XTAL_20MHz)
+ MCFG_CPU_IO_MAP(dectalk_dsp_io)
+ MCFG_CPU_PROGRAM_MAP(dectalk_dsp_map)
+
+ MCFG_SPEAKER_STANDARD_MONO("speaker")
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "speaker", 1.00)
+MACHINE_CONFIG_END
+
+ROM_START( dectalk_isa )
+ ROM_REGION( 0x4000, "dectalk_cpu", 0 )
+ ROM_LOAD16_BYTE("pc_boot_hxl.am27c64.d6.bin", 0x0000, 0x2000, CRC(7492f1e3) SHA1(fe6946a227f01c94f2b99220320a616445c96ee0))
+ ROM_LOAD16_BYTE("pc_boot_hxh.am27c64.d8.bin", 0x0001, 0x2000, CRC(1fe7fe40) SHA1(6e89c237f01aa22e0d21ff4d6fdf8137c6ace374))
+ ROM_REGION( 0x2000, "dectalk_dsp", 0 )
+ ROM_LOAD("spc_034c__2-1-92.tms320p15nl.d3.bin", 0x0000, 0x2000, CRC(d8b1201e) SHA1(4b873a5e882205fcac79a27562054b5c4d1a117c))
+ROM_END
+
+const rom_entry* dectalk_isa_device::device_rom_region() const
+{
+ return ROM_NAME( dectalk_isa );
+}
+
+machine_config_constructor dectalk_isa_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( dectalk_isa );
+}
+
+WRITE8_MEMBER(dectalk_isa_device::write)
+{
+ switch(offset)
+ {
+ case 0:
+ m_cmd = (m_cmd & 0xff00) | data;
+ break;
+ case 1:
+ m_cmd = (m_cmd & 0xff) | (data << 8);
+ break;
+ case 2:
+ m_data = (m_data & 0xff00) | data;
+ break;
+ case 3:
+ m_data = (m_data & 0xff) | (data << 8);
+ break;
+ case 4:
+ m_dma = data;
+ m_cpu->drq1_w(1);
+ break;
+ case 6:
+ m_cpu->int1_w(1);
+ break;
+ }
+}
+
+READ8_MEMBER(dectalk_isa_device::read)
+{
+ switch(offset)
+ {
+ case 0:
+ return m_stat & 0xff;
+ case 1:
+ return m_stat >> 8;
+ case 2:
+ return m_data & 0xff;
+ case 3:
+ return m_data >> 8;
+ case 4:
+ m_cpu->drq1_w(1);
+ return m_dma;
+ }
+ return 0;
+}
+
+void dectalk_isa_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x0250, 0x0257, 0, 0, read8_delegate(FUNC(dectalk_isa_device::read), this), write8_delegate(FUNC(dectalk_isa_device::write), this));
+}
+
+void dectalk_isa_device::device_reset()
+{
+ m_ctl = 0;
+ m_vol = 63;
+ m_bio = ASSERT_LINE;
+}
diff --git a/src/emu/bus/isa/dectalk.h b/src/emu/bus/isa/dectalk.h
new file mode 100644
index 00000000000..66168980a89
--- /dev/null
+++ b/src/emu/bus/isa/dectalk.h
@@ -0,0 +1,54 @@
+#ifndef ISA_DECTALK_H_
+#define ISA_DECTALK_H_
+
+#include "emu.h"
+#include "isa.h"
+#include "sound/dac.h"
+#include "cpu/i86/i186.h"
+#include "cpu/tms32010/tms32010.h"
+
+class dectalk_isa_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ dectalk_isa_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ DECLARE_WRITE8_MEMBER(write);
+ DECLARE_READ8_MEMBER(read);
+
+ DECLARE_WRITE16_MEMBER(status_w);
+ DECLARE_READ16_MEMBER(cmd_r);
+ DECLARE_WRITE16_MEMBER(data_w);
+ DECLARE_READ16_MEMBER(data_r);
+ DECLARE_READ16_MEMBER(host_irq_r);
+ DECLARE_READ8_MEMBER(dma_r);
+ DECLARE_WRITE8_MEMBER(dma_w);
+ DECLARE_WRITE16_MEMBER(dac_w);
+ DECLARE_READ16_MEMBER(dsp_dma_r);
+ DECLARE_WRITE16_MEMBER(dsp_dma_w);
+ DECLARE_WRITE16_MEMBER(output_ctl_w);
+ DECLARE_READ16_MEMBER(bio_line_r);
+ DECLARE_WRITE16_MEMBER(irq_line_w);
+ DECLARE_WRITE_LINE_MEMBER(clock_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ UINT16 m_cmd, m_stat, m_data, m_dsp_dma, m_ctl;
+ UINT8 m_dma, m_vol, m_bio;
+
+ required_device<i80186_cpu_device> m_cpu;
+ required_device<dac_device> m_dac;
+ required_device<cpu_device> m_dsp;
+};
+
+extern const device_type ISA8_DECTALK;
+
+#endif /* ISA_DECTALK_H_ */
diff --git a/src/emu/bus/isa/ega.c b/src/emu/bus/isa/ega.c
new file mode 100644
index 00000000000..ac1c12bf589
--- /dev/null
+++ b/src/emu/bus/isa/ega.c
@@ -0,0 +1,1409 @@
+/***************************************************************************
+
+ Enhanced Graphics Adapter (EGA) section
+
+TODO - Write documentation
+
+"Regular" register on an EGA graphics card:
+
+ 3C2 - 7 6 5 4 3 2 1 0 - Misc Output Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- 3Bx/3Dx I/O port select
+ | | | | | | | 0 = 3Bx for CRTC I/O, 3BA for status reg 1
+ | | | | | | | 1 = 3Dx for CRTC I/O, 3DA for status reg 1
+ | | | | | | +---- enable ram
+ | | | | | | 0 = disable ram from the processor
+ | | | | | | 1 = enable ram to respond to addresses
+ | | | | | | designated by the Control Data Select
+ | | | | | | value in the Graphics Controllers.
+ | | | | | +------ clock select bit 0
+ | | | | +-------- clock select bit 1
+ | | | | 00 = 14MHz from Processor I/O channel
+ | | | | 01 = 16MHz on-bord clock
+ | | | | 10 = External clock from feature connector
+ | | | | 11 = reserved/unused
+ | | | +---------- disable video drivers
+ | | | 0 = activate internal video drivers
+ | | | 1 = disable internal video drivers
+ | | +------------ page bit for odd/even. Selects between 2 pages
+ | | of 64KB of memory when in odd/even mode.
+ | | 0 = select low page
+ | | 1 = select high page
+ | +-------------- horizontal retrace polarity
+ | 0 = select positive
+ | 1 = select negative
+ +---------------- vertical retrace polarity
+ 0 = select positive
+ 1 = select negative
+
+
+ 3C2 - 7 6 5 4 3 2 1 0 - Input Status Reg 0 - Read Only
+ | | | | | | | |
+ | | | | | | | +-- reserved/unused
+ | | | | | | +---- reserved/unused
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- switch sense
+ | | | 0 = switch is closed
+ | | | 1 = allows processor to read the 4 config switches
+ | | | on the EGA adapter. The setting of CLKSEL determines
+ | | | switch to read.
+ | | +------------ input from FEAT0 on the feature connector
+ | +-------------- input from FEAT1 on the feature connector
+ +---------------- CRT Interrupt
+ 0 = vertical retrace if occuring
+ 1 = video is being displayed
+
+
+ Configuration switches
+ SW1 SW2 SW3 SW4
+ OFF OFF OFF ON - EGA, Color 80x25 (5153)
+ - EGA (primary) + MDA, Color 80x25 + Monochrome
+ OFF OFF ON OFF - EGA, Monochrome (5151)
+ - EGA (primary) + CGA, Monochrome + Color 80x25
+ OFF OFF ON ON - EGA + MDA (primary), 5154 + Enhanced Monochrome
+ OFF ON OFF ON - EGA + CGA (primary), Monochrome + Color 80x25
+ OFF ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154)
+ - EGA (primary) + MDA, 5154 monitor + Enhanced Monochrome
+ OFF ON ON ON - EGA + MDA (primary), Color 80x25 + Monochrome
+ ON OFF OFF ON - EGA, Color 40x25 (5153)
+ - EGA (primary) + MDA, Color 40x25 + Monochrome
+ ON OFF ON OFF - EGA (primary) + CGA, Monochrome + Color 40x25
+ ON OFF ON ON - EGA + MDA (primary), 5154 + Normal Monochrome
+ ON ON OFF ON - EGA + CGA (primary), Monochrome + Color 40x25
+ ON ON ON OFF - EGA, Enhanced Color - Enhanced Mode (5154)
+ - EGA (primary) + MDA, 5154 monitor + Normal Monochrome
+ ON ON ON ON - EGA + MDA (primary), Color 40x25 + Monochrome
+
+
+ 3XA - 7 6 5 4 3 2 1 0 - Feature Control Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- output to FEAT0 of the feature connector
+ | | | | | | +---- output to FEAT1 of the feature connector
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+ 3XA - 7 6 5 4 3 2 1 0 - Input Status Reg 1 - Read Only
+ | | | | | | | |
+ | | | | | | | +-- display enable
+ | | | | | | | 0 = indicates the CRT raster is in a horizontal or vertical retrace
+ | | | | | | | 1 = otherwise
+ | | | | | | +---- light pen strobe
+ | | | | | | 0 = light pen trigger has not been set
+ | | | | | | 1 = light pen trigger has been set
+ | | | | | +------ light pen switch
+ | | | | | 0 = switch is closed
+ | | | | | 1 = switch is open
+ | | | | +-------- vertical blank
+ | | | | 0 = video information is being displayed
+ | | | | 1 = CRT is in vertical blank
+ | | | +---------- diagnostic usage, output depends on AR12 video status mux bits
+ | | | mux bits - output
+ | | | 00 - blue
+ | | | 01 - I blue
+ | | | 10 - I red
+ | | | 11 - unknown
+ | | +------------ diagnostic usage, output depends on AR12 video status mux bits
+ | | mux bits - output
+ | | 00 - red
+ | | 01 - green
+ | | 10 - I green
+ | | 11 - unknown
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+
+The EGA graphics card introduces a lot of new indexed registers to handle the
+enhanced graphics. These new indexed registers can be divided into three
+groups:
+- attribute registers
+- sequencer registers
+- graphics controllers registers
+
+
+Attribute Registers AR00 - AR13
+
+The Attribute Registers are all accessed through I/O port 0x3C0. The first
+write to I/O port 0x3C0 sets the index register. The next write to I/O port
+0x3C0 actually sets the data to the indexed register.
+
+ 3C0 - 7 6 5 4 3 2 1 0 - Attribute Access Register
+ | | | | | | | |
+ | | | | | | | +-- index bit 0
+ | | | | | | +---- index bit 1
+ | | | | | +------ index bit 2
+ | | | | +-------- index bit 3
+ | | | +---------- index bit 4
+ | | +------------ palette source
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR00-AR0F - 7 6 5 4 3 2 1 0 - Palette Register #00 - #0F
+ | | | | | | | |
+ | | | | | | | +-- MSB B
+ | | | | | | +---- MSB G
+ | | | | | +------ MSB R
+ | | | | +-------- LSB B
+ | | | +---------- LSB G
+ | | +------------ LSB R
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR10 - 7 6 5 4 3 2 1 0 - Mode Control Register
+ | | | | | | | |
+ | | | | | | | +-- Text/Graphics select
+ | | | | | | +---- Monochrome/Color select
+ | | | | | +------ 9th dot setting
+ | | | | +-------- Blink Enable
+ | | | +---------- reserved/unsued
+ | | +------------ 0 = line compare does not affect pixel output
+ | | 1 = line compare does affect pixel output
+ | +-------------- 0 = pixel changes every dot clock
+ | 1 = pixel changes every other dot clock
+ +---------------- reserved/unused
+
+
+ AR11 - 7 6 5 4 3 2 1 0 - Overscan Color Register
+ | | | | | | | |
+ | | | | | | | +-- MSB B
+ | | | | | | +---- MSB G
+ | | | | | +------ MSB R
+ | | | | +-------- LSB B
+ | | | +---------- LSB G
+ | | +------------ LSB R
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR12 - 7 6 5 4 3 2 1 0 - Color Plane Enable Register
+ | | | | | | | |
+ | | | | | | | +-- Enable plane 0
+ | | | | | | +---- Enable plane 1
+ | | | | | +------ Enable plane 2
+ | | | | +-------- Enable plane 3
+ | | | +---------- Video Status Mux bit 0
+ | | +------------ Video Status Mux bit 1
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ AR13 - 7 6 5 4 3 2 1 0 - Horizontal Panning Register
+ | | | | | | | |
+ | | | | | | | +-- Pixel left shift bit 0
+ | | | | | | +---- Pixel left shift bit 1
+ | | | | | +------ Pixel left shift bit 2
+ | | | | +-------- Pixel left shift bit 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+Sequencer Registers SR00 - SR04
+
+The Sequencer Registers are accessed through an index register located at I/O
+port 0x3C4, and a data register located at I/O port 0x3C5.
+
+ 3C4 - 7 6 5 4 3 2 1 0 - Sequencer Index Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- index bit 0
+ | | | | | | +---- index bit 1
+ | | | | | +------ index bit 2
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ 3C5 - 7 6 5 4 3 2 1 0 - Sequencer Data Register - Write Only
+ | | | | | | | |
+ | | | | | | | +-- data bit 0
+ | | | | | | +---- data bit 1
+ | | | | | +------ data bit 2
+ | | | | +-------- data bit 3
+ | | | +---------- data bit 4
+ | | +------------ data bit 5
+ | +-------------- data bit 6
+ +---------------- data bit 7
+
+
+ SR00 - 7 6 5 4 3 2 1 0 - Reset Control Register
+ | | | | | | | |
+ | | | | | | | +-- Must be 1 for normal operation
+ | | | | | | +---- Must be 1 for normal operation
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR01 - 7 6 5 4 3 2 1 0 - Clocking Mode
+ | | | | | | | |
+ | | | | | | | +-- 0 = 9 dots per char, 1 = 8 dots per char
+ | | | | | | +---- clock frequency, 0 = 4 out of 5 memory cycles, 1 = 2 out of 5 memory cycles
+ | | | | | +------ shift load
+ | | | | +-------- 0 = normal dot clock, 1 = master dot clock / 2
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR02 - 7 6 5 4 3 2 1 0 - Map Mask
+ | | | | | | | |
+ | | | | | | | +-- 1 = enable map 0 for writing
+ | | | | | | +---- 1 = enable map 1 for writing
+ | | | | | +------ 1 = enable map 2 for writing
+ | | | | +-------- 1 = enable map 3 for writing
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR03 - 7 6 5 4 3 2 1 0 - Character Map Select
+ | | | | | | | |
+ | | | | | | | +-- character map select B bit 0
+ | | | | | | +---- character map select B bit 1
+ | | | | | | Selects the map used to generate alpha characters when
+ | | | | | | attribute bit 3 is set to 0
+ | | | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0
+ | | | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1
+ | | | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2
+ | | | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3
+ | | | | | +------ character map select A bit 0
+ | | | | +-------- character map select A bit 1
+ | | | | Selects the map used to generate alpha characters when
+ | | | | attribute bit 3 is set to 1
+ | | | | 00 = map 0 - 1st 8KB of plane 2 bank 0
+ | | | | 01 = map 1 - 2nd 8KB of plane 2 bank 1
+ | | | | 10 = map 2 - 3rd 8KB of plane 2 bank 2
+ | | | | 11 = map 3 - 4th 8KB of plane 2 bank 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ SR04 - 7 6 5 4 3 2 1 0 - Memory Mode Register
+ | | | | | | | |
+ | | | | | | | +-- 0 = graphics mode, 1 = text mode
+ | | | | | | +---- 0 = no memory extension, 1 = memory extension
+ | | | | | +------ 0 = odd/even storage, 1 = sequential storage
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+Graphics Controller Registers GR00 - GR08
+
+The Graphics Controller Registers are accessed through an index register
+located at I/O port 0x3CE, and a data register located at I/O port 0x3CF.
+
+ GR00 - 7 6 5 4 3 2 1 0 - Set/Reset Register
+ | | | | | | | |
+ | | | | | | | +-- set/reset for plane 0
+ | | | | | | +---- set/reset for plane 1
+ | | | | | +------ set/reset for plane 2
+ | | | | +-------- set/reset for plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR01 - 7 6 5 4 3 2 1 0 - Enable Set/Reset Register
+ | | | | | | | |
+ | | | | | | | +-- enable set/reset for plane 0
+ | | | | | | +---- enable set/reset for plane 1
+ | | | | | +------ enable set/reset for plane 2
+ | | | | +-------- enable set/reset for plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR02 - 7 6 5 4 3 2 1 0 - Color Compare Register
+ | | | | | | | |
+ | | | | | | | +-- color compare 0
+ | | | | | | +---- color compare 1
+ | | | | | +------ color compare 2
+ | | | | +-------- color compare 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR03 - 7 6 5 4 3 2 1 0 - Data Rotate Register
+ | | | | | | | |
+ | | | | | | | +-- number of positions to rotate bit 0
+ | | | | | | +---- number of positions to rotate bit 1
+ | | | | | +------ number of positions to rotate bit 2
+ | | | | +-------- function select bit 0
+ | | | +---------- function select bit 1
+ | | | 00 = data overwrites in specified color
+ | | | 01 = data ANDed with latched data
+ | | | 10 = data ORed with latched data
+ | | | 11 = data XORed with latched data
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR04 - 7 6 5 4 3 2 1 0 - Read Map Select Register
+ | | | | | | | |
+ | | | | | | | +-- plane select bit 0
+ | | | | | | +---- plane select bit 1
+ | | | | | +------ reserved/unused
+ | | | | +-------- reserved/unused
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR05 - 7 6 5 4 3 2 1 0 - Mode Register
+ | | | | | | | |
+ | | | | | | | +-- write mode bit 0
+ | | | | | | +---- write mode bit 1
+ | | | | | | 00 = write 8 bits of value in set/reset register if enabled,
+ | | | | | | otherwise write rotated processor data
+ | | | | | | 01 = write with contents of processor latches
+ | | | | | | 10 = memory plane 0-3 filled with 8 bits of value of data bit 0-3
+ | | | | | | 11 = reserved/unused
+ | | | | | +------ test condition
+ | | | | | 0 = normal operation
+ | | | | | 1 = put outputs in high impedance state
+ | | | | +-------- read mode
+ | | | | 0 = read from plane selected by GR04
+ | | | | 1 = do color compare
+ | | | +---------- odd/even addressing mode
+ | | +------------ shift register mode
+ | | 0 = sequential
+ | | 1 = even bits from even maps, odd bits from odd maps
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR06 - 7 6 5 4 3 2 1 0 - Miscellaneous Register
+ | | | | | | | |
+ | | | | | | | +-- 0 = text mode, 1 = graphics mode
+ | | | | | | +---- chain odd maps to even
+ | | | | | +------ memory map bit 0
+ | | | | +-------- memory map bit 1
+ | | | | 00 = 0xA0000, 128KB
+ | | | | 01 = 0xA0000, 64KB
+ | | | | 10 = 0xB0000, 32KB
+ | | | | 11 = 0xB8000, 32KB
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR07 - 7 6 5 4 3 2 1 0 - Color Plane Ignore Register
+ | | | | | | | |
+ | | | | | | | +-- ignore color plane 0
+ | | | | | | +---- ignore color plane 1
+ | | | | | +------ ignore color plane 2
+ | | | | +-------- ignore color plane 3
+ | | | +---------- reserved/unused
+ | | +------------ reserved/unused
+ | +-------------- reserved/unused
+ +---------------- reserved/unused
+
+
+ GR08 - 7 6 5 4 3 2 1 0 - Bit Mask Register
+ | | | | | | | |
+ | | | | | | | +-- write enable bit 0
+ | | | | | | +---- write enable bit 1
+ | | | | | +------ write enable bit 2
+ | | | | +-------- write enable bit 3
+ | | | +---------- write enable bit 4
+ | | +------------ write enable bit 5
+ | +-------------- write enable bit 6
+ +---------------- write enable bit 7
+
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ega.h"
+
+#define VERBOSE_EGA 1
+
+#define EGA_SCREEN_NAME "ega_screen"
+#define EGA_CRTC_NAME "crtc_ega_ega"
+
+/*
+ Prototypes
+*/
+static CRTC_EGA_UPDATE_ROW( ega_update_row );
+
+static CRTC_EGA_INTERFACE( crtc_ega_ega_intf )
+{
+ 8, /* numbers of pixels per video memory address */
+ NULL, /* begin_update */
+ ega_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, de_changed), /* on_de_chaged */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, vsync_changed), /* on vsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_ega_device, vblank_changed) /* on_vblank_changed */
+};
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_ega )
+ MCFG_SCREEN_ADD(EGA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(16257000,912,0,640,262,0,200)
+ MCFG_SCREEN_UPDATE_DEVICE(EGA_CRTC_NAME, crtc_ega_device, screen_update)
+
+ MCFG_PALETTE_ADD( "palette", 64 )
+ MCFG_CRTC_EGA_ADD(EGA_CRTC_NAME, 16257000/8, crtc_ega_ega_intf)
+ MCFG_CRTC_EGA_SET_SCREEN(EGA_SCREEN_NAME)
+MACHINE_CONFIG_END
+
+ROM_START( ega )
+ ROM_REGION(0x4000, "user1", 0)
+ ROM_LOAD("6277356.u44", 0x0000, 0x4000, CRC(dc146448) SHA1(dc0794499b3e499c5777b3aa39554bbf0f2cc19b))
+ ROM_REGION(0x4000, "user2", ROMREGION_ERASE00)
+ROM_END
+
+/*
+0000 - MONOC PRIMARY, EGA COLOR, 40x25
+0001 - MONOC PRIMARY, EGA COLOR, 80x25
+0010 - MONOC PRIMARY, EGA HI RES EMULATE (SAME AS 0001)
+0011 - MONOC PRIMARY, EGA HI RES ENHANCED
+0100 - COLOR 40 PRIMARY, EGA MONOCHROME
+0101 - COLOR 80 PRIMARY, EGA MONOCHROME
+
+0110 - MONOC SECONDARY, EGA COLOR, 40x24
+0111 - MONOC SECONDARY, EGA COLOR, 80x25
+1000 - MONOC SECONDARY, EGA HI RES EMULATE (SAME AS 0111)
+1001 - MONOC SECONDARY, EGA HI RES ENHANCED
+1010 - COLOR 40 SECONDARY, EGA
+1011 - COLOR 80 SECONDARY, EGA
+
+1100 - RESERVED
+1101 - RESERVED
+1110 - RESERVED
+1111 - RESERVED
+*/
+
+INPUT_PORTS_START( ega )
+ PORT_START( "config" )
+ PORT_CONFNAME( 0x0f, 0x09, "dipswitches" )
+ PORT_CONFSETTING( 0x00, "0000 - MDA PRIMARY, EGA COLOR, 40x25" ) /* DIAG: ?? 40 cols, RGBI */
+ PORT_CONFSETTING( 0x08, "0001 - MDA PRIMARY, EGA COLOR, 80x25" ) /* DIAG: ?? 80 cols, RGBI */
+ PORT_CONFSETTING( 0x04, "0010 - MDA PRIMARY, EGA HI RES EMULATE (SAME AS 0001)" ) /* DIAG: ?? 80 cols, RGBI */
+ PORT_CONFSETTING( 0x0c, "0011 - MDA PRIMARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */
+ PORT_CONFSETTING( 0x02, "0100 - CGA 40 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */
+ PORT_CONFSETTING( 0x0a, "0101 - CGA 80 PRIMARY, EGA MONOCHROME" ) /* DIAG: ??, Mono RGBI */
+ PORT_CONFSETTING( 0x06, "0110 - MDA SECONDARY, EGA COLOR, 40x25" ) /* DIAG: Color Display 40 cols, RGBI */
+ PORT_CONFSETTING( 0x0e, "0111 - MDA SECONDARY, EGA COLOR, 80x25" ) /* DIAG: Color Display 80 cols, RGBI */
+ PORT_CONFSETTING( 0x01, "1000 - MDA SECONDARY, EGA HI RES EMULATE (SAME AS 0111)" ) /* DIAG: Color Display 80 cols, RGBI */
+ PORT_CONFSETTING( 0x09, "1001 - MDA SECONDARY, EGA HI RES ENHANCED" ) /* DIAG: Color Display 40 cols, RrGgBb */
+ PORT_CONFSETTING( 0x05, "1010 - COLOR 40 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */
+ PORT_CONFSETTING( 0x0d, "1011 - COLOR 80 SECONDARY, EGA" ) /* DIAG: Monochrome display, Mono RGBI */
+ PORT_CONFSETTING( 0x03, "1100 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x0b, "1101 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x07, "1110 - RESERVED" ) /* ??, RGBI */
+ PORT_CONFSETTING( 0x0f, "1111 - RESERVED" ) /* ??, RGBI */
+INPUT_PORTS_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_EGA = &device_creator<isa8_ega_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_ega_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_ega );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_ega_device::device_rom_region() const
+{
+ return ROM_NAME( ega );
+}
+
+ioport_constructor isa8_ega_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ega );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_ega_device - constructor
+//-------------------------------------------------
+
+isa8_ega_device::isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_EGA, "IBM Enhanced Graphics Adapter", tag, owner, clock, "ega", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_misc_output(0),
+ m_palette(*this, "palette")
+{
+}
+
+isa8_ega_device::isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this),
+ m_misc_output(0),
+ m_palette(*this, "palette")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_ega_device::device_start()
+{
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ astring tempstring;
+
+ set_isa_device();
+
+ for (int i = 0; i < 64; i++ )
+ {
+ UINT8 r = ( ( i & 0x04 ) ? 0xAA : 0x00 ) + ( ( i & 0x20 ) ? 0x55 : 0x00 );
+ UINT8 g = ( ( i & 0x02 ) ? 0xAA : 0x00 ) + ( ( i & 0x10 ) ? 0x55 : 0x00 );
+ UINT8 b = ( ( i & 0x01 ) ? 0xAA : 0x00 ) + ( ( i & 0x08 ) ? 0x55 : 0x00 );
+
+ m_palette->set_pen_color( i, r, g, b );
+ }
+
+ UINT8 *dst = memregion(subtag(tempstring, "user2" ))->base() + 0x0000;
+ UINT8 *src = memregion(subtag(tempstring, "user1" ))->base() + 0x3fff;
+ int i;
+
+ /* Perform the EGA bios address line swaps */
+ for( i = 0; i < 0x4000; i++ )
+ {
+ *dst++ = *src--;
+ }
+ /* Install 256KB Video ram on our EGA card */
+ m_vram = machine().memory().region_alloc(subtag(tempstring,"vram"), 256*1024, 1, ENDIANNESS_LITTLE);
+
+ m_videoram = m_vram->base();
+ m_plane[0] = m_videoram + 0x00000;
+ memset(m_plane[0], 0, sizeof(UINT8) * 0x10000);
+ m_plane[1] = m_videoram + 0x10000;
+ memset(m_plane[1], 0, sizeof(UINT8) * 0x10000);
+ m_plane[2] = m_videoram + 0x20000;
+ memset(m_plane[2], 0, sizeof(UINT8) * 0x10000);
+ m_plane[3] = m_videoram + 0x30000;
+ memset(m_plane[3], 0, sizeof(UINT8) * 0x10000);
+
+ m_crtc_ega = subdevice<crtc_ega_device>(EGA_CRTC_NAME);
+
+ m_isa->install_rom(this, 0xc0000, 0xc3fff, 0, 0, "ega", "user2");
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_w), this));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_w), this));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_w), this));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_ega_device::device_reset()
+{
+ m_feature_control = 0;
+
+ memset(&m_attribute,0,sizeof(m_attribute));
+ memset(&m_sequencer,0,sizeof(m_sequencer));
+ memset(&m_graphics_controller,0,sizeof(m_graphics_controller));
+
+ m_frame_cnt = 0;
+ m_hsync = 0;
+ m_vsync = 0;
+ m_vblank = 0;
+ m_display_enable = 0;
+
+ install_banks();
+
+ m_update_row = NULL;
+ m_misc_output = 0;
+ m_attribute.index_write = 1;
+
+ /* Set up default palette */
+ m_attribute.data[0] = 0;
+ m_attribute.data[1] = 1;
+ m_attribute.data[2] = 2;
+ m_attribute.data[3] = 3;
+ m_attribute.data[4] = 4;
+ m_attribute.data[5] = 5;
+ m_attribute.data[6] = 0x14;
+ m_attribute.data[7] = 7;
+ m_attribute.data[8] = 0x38;
+ m_attribute.data[9] = 0x39;
+ m_attribute.data[10] = 0x3A;
+ m_attribute.data[11] = 0x3B;
+ m_attribute.data[12] = 0x3C;
+ m_attribute.data[13] = 0x3D;
+ m_attribute.data[14] = 0x3E;
+ m_attribute.data[15] = 0x3F;
+
+}
+
+void isa8_ega_device::install_banks()
+{
+ switch ( m_graphics_controller.data[6] & 0x0c )
+ {
+ case 0x00: /* 0xA0000, 128KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ }
+ break;
+ case 0x04: /* 0xA0000, 64KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xa0000, 0xaffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ break;
+ case 0x08: /* 0xB0000, 32KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xb0000, 0xb7fff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ break;
+ case 0x0c: /* 0xB8000, 32KB */
+ if ( m_misc_output & 0x02 )
+ {
+ m_isa->install_memory(0xb8000, 0xbffff, 0, 0, read8_delegate(FUNC(isa8_ega_device::read), this), write8_delegate(FUNC(isa8_ega_device::write), this));
+ }
+ else
+ {
+ m_isa->unmap_bank(0xb8000, 0xbffff,0,0);
+ }
+ /* These unmaps may break multi graphics card support */
+ m_isa->unmap_bank(0xa0000, 0xaffff,0,0);
+ m_isa->unmap_bank(0xb0000, 0xb7fff,0,0);
+ break;
+ }
+}
+
+static CRTC_EGA_UPDATE_ROW( ega_update_row )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ if ( ega->m_update_row )
+ {
+ ega->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::de_changed )
+{
+ m_display_enable = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::vsync_changed )
+{
+ m_vsync = state ? 1 : 0;
+ if ( state )
+ {
+ m_frame_cnt++;
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_ega_device::vblank_changed )
+{
+ m_vblank = state ? 8 : 0;
+}
+
+
+static CRTC_EGA_UPDATE_ROW( pc_ega_graphics )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ UINT16 *p = &bitmap.pix16(y);
+
+// logerror( "pc_ega_graphics: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+
+ if ( ega->m_graphics_controller.data[5] & 0x10 )
+ {
+ // Odd/Even mode (CGA compatible)
+
+ for ( int i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) & 0x1fff ) | ( ( y & 1 ) << 12 );
+ UINT8 data = ega->m_plane[0][offset];
+
+ *p = ega->m_attribute.data[ ( data >> 6 ) ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ data & 0x03 ]; p++;
+
+ data = ega->m_plane[1][offset];
+
+ *p = ega->m_attribute.data[ ( data >> 6 ) ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 4 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ ( data >> 2 ) & 0x03 ]; p++;
+ *p = ega->m_attribute.data[ data & 0x03 ]; p++;
+ }
+ }
+ else
+ {
+ // EGA mode
+
+ UINT8 mask = ega->m_attribute.data[0x12] & 0x0f;
+
+ for ( int i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ma + i;
+ UINT16 data0 = ega->m_plane[0][offset];
+ UINT16 data1 = ega->m_plane[1][offset] << 1;
+ UINT16 data2 = ega->m_plane[2][offset] << 2;
+ UINT16 data3 = ega->m_plane[3][offset] << 3;
+
+ for ( int j = 7; j >= 0; j-- )
+ {
+ UINT16 col = ( data0 & 0x01 ) | ( data1 & 0x02 ) | ( data2 & 0x04 ) | ( data3 & 0x08 );
+
+ col &= mask;
+
+ p[j] = ega->m_attribute.data[col];
+
+ data0 >>= 1;
+ data1 >>= 1;
+ data2 >>= 1;
+ data3 >>= 1;
+ }
+ p += 8;
+ }
+ }
+}
+
+
+static CRTC_EGA_UPDATE_ROW( pc_ega_text )
+{
+ isa8_ega_device *ega = dynamic_cast<isa8_ega_device*>(device->owner());
+ UINT16 *p = &bitmap.pix16(y);
+ int i;
+
+// logerror( "pc_ega_text: y = %d, x_count = %d, ma = %d, ra = %d\n", y, x_count, ma, ra );
+
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ma + i;
+ UINT8 chr = ega->m_plane[0][ offset ];
+ UINT8 attr = ega->m_plane[1][ offset ];
+ UINT8 data = 0;
+ UINT16 fg = ega->m_attribute.data[ attr & 0x07 ];
+ UINT16 bg = ega->m_attribute.data[ ( attr >> 4 ) & 0x07 ];
+
+ /* If character set A and B are equal attribute bit 3 is used as intensity */
+ if ( ega->m_charA == ega->m_charB )
+ {
+ /* intensity selector */
+ data = ega->m_charB[ chr * 32 + ra ];
+ fg += ( attr & 0x08 ) ? 0x38 : 0x00;
+ }
+ else
+ {
+ /* character set selector */
+ data = ( attr & 0x08 ) ? ega->m_charA[ chr * 32 + ra ] : ega->m_charB[ chr * 32 + ra ];
+ }
+
+ if ( i == cursor_x )
+ {
+ if ( ega->m_frame_cnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ /* Check for blinking */
+ if ( ( ega->m_attribute.data[0x10] & 0x08 ) && ( attr & 0x80 ) && ( ega->m_frame_cnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = ( data & 0x80 ) ? fg : bg; p++;
+ *p = ( data & 0x40 ) ? fg : bg; p++;
+ *p = ( data & 0x20 ) ? fg : bg; p++;
+ *p = ( data & 0x10 ) ? fg : bg; p++;
+ *p = ( data & 0x08 ) ? fg : bg; p++;
+ *p = ( data & 0x04 ) ? fg : bg; p++;
+ *p = ( data & 0x02 ) ? fg : bg; p++;
+ *p = ( data & 0x01 ) ? fg : bg; p++;
+ }
+}
+
+
+void isa8_ega_device::change_mode()
+{
+ int clock, pixels;
+
+ m_update_row = NULL;
+
+ /* Check for graphics mode */
+ if ( ( m_attribute.data[0x10] & 0x01 ) &&
+ ! ( m_sequencer.data[0x04] & 0x01 ) &&
+ ( m_graphics_controller.data[0x06] & 0x01 ) )
+ {
+ if ( VERBOSE_EGA )
+ {
+ logerror("change_mode(): Switch to graphics mode\n");
+ }
+
+ m_update_row = pc_ega_graphics;
+ }
+
+ /* Check for text mode */
+ if ( ! ( m_attribute.data[0x10] & 0x01 ) &&
+ ( m_sequencer.data[0x04] & 0x01 ) &&
+ ! ( m_graphics_controller.data[0x06] & 0x01 ) )
+ {
+ if ( VERBOSE_EGA )
+ {
+ logerror("chnage_mode(): Switching to text mode\n");
+ }
+
+ m_update_row = pc_ega_text;
+
+ /* Set character maps */
+ if ( m_sequencer.data[0x04] & 0x02 )
+ {
+ m_charA = m_plane[2] + ( ( m_sequencer.data[0x03] & 0x0c ) >> 1 ) * 0x2000;
+ m_charB = m_plane[2] + ( m_sequencer.data[0x03] & 0x03 ) * 0x2000;
+ }
+ else
+ {
+ m_charA = m_plane[2];
+ m_charB = m_plane[2];
+ }
+ }
+
+ /* Check for changes to the crtc input clock and number of pixels per clock */
+ clock = ( ( m_misc_output & 0x0c ) ? 16257000 : XTAL_14_31818MHz );
+ pixels = ( ( m_sequencer.data[0x01] & 0x01 ) ? 8 : 9 );
+
+ if ( m_sequencer.data[0x01] & 0x08 )
+ {
+ clock >>= 1;
+ }
+ m_crtc_ega->set_clock( clock / pixels );
+ m_crtc_ega->set_hpixels_per_column( pixels );
+
+if ( ! m_update_row )
+ logerror("unknown video mode\n");
+}
+
+
+READ8_MEMBER( isa8_ega_device::read )
+{
+ UINT8 data = 0xFF;
+
+ if ( !space.debugger_access() && ! ( m_sequencer.data[4] & 0x04 ) )
+ {
+ /* Fill read latches */
+ m_read_latch[0] = m_plane[0][offset & 0xffff];
+ m_read_latch[1] = m_plane[1][offset & 0xffff];
+ m_read_latch[2] = m_plane[2][offset & 0xffff];
+ m_read_latch[3] = m_plane[3][offset & 0xffff];
+ }
+
+ if ( m_graphics_controller.data[5] & 0x08 )
+ {
+ // Read mode #1
+ popmessage("ega: Read mode 1 not supported yet!");
+ printf("EGA: Read mode 1 not supported yet!\n");
+ }
+ else
+ {
+ // Read mode #0
+ if ( m_sequencer.data[4] & 0x04 )
+ {
+ // Normal addressing mode
+ data = m_plane[ m_graphics_controller.data[4] & 0x03 ][offset & 0xffff];
+ }
+ else
+ {
+ // Odd/Even addressing mode
+ data = m_plane[offset & 1][(offset & 0xffff) >> 1];
+ }
+ }
+
+ return data;
+}
+
+
+UINT8 isa8_ega_device::alu_op( UINT8 data, UINT8 latch_data )
+{
+ UINT8 mask = m_graphics_controller.data[8];
+
+ switch( m_graphics_controller.data[3] & 0x18 )
+ {
+ case 0x00: // Unmodified
+ return ( data & mask ) | ( latch_data & ~mask );
+
+ case 0x08: // AND
+ return ( data | ~mask ) & latch_data;
+
+ case 0x10: // OR
+ return ( data & mask ) | latch_data;
+
+ case 0x18: // XOR
+ return ( data & mask ) ^ latch_data;
+ }
+ return 0;
+}
+
+
+WRITE8_MEMBER( isa8_ega_device::write )
+{
+ UINT8 d[4];
+ UINT8 alu[4];
+ UINT8 target_mask = m_graphics_controller.data[8];
+
+ alu[0] =alu[1] = alu[2] = alu[3] = 0;
+
+ switch( m_graphics_controller.data[5] & 0x03 )
+ {
+ case 0: // Write mode 0
+ // Pass through barrel shifter
+ data = ( ( ( data << 8 ) | data ) >> ( m_graphics_controller.data[3] & 0x07 ) ) & 0xFF;
+
+ d[0] = d[1] = d[2] = d[3] = data;
+
+ /* Apply Set/Reset settings */
+ if ( m_graphics_controller.data[1] & 0x01 )
+ {
+ d[0] = ( m_graphics_controller.data[0] & 0x01 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x02 )
+ {
+ d[1] = ( m_graphics_controller.data[0] & 0x02 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x04 )
+ {
+ d[2] = ( m_graphics_controller.data[0] & 0x04 ) ? 0xff : 0x00;
+ }
+ if ( m_graphics_controller.data[1] & 0x08 )
+ {
+ d[3] = ( m_graphics_controller.data[0] & 0x08 ) ? 0xff : 0x00;
+ }
+
+ // Pass through ALUs
+ alu[0] = alu_op( d[0], m_read_latch[0] );
+ alu[1] = alu_op( d[1], m_read_latch[1] );
+ alu[2] = alu_op( d[2], m_read_latch[2] );
+ alu[3] = alu_op( d[3], m_read_latch[3] );
+
+ break;
+
+ case 1: // Write mode 1
+ alu[0] = m_read_latch[0];
+ alu[1] = m_read_latch[1];
+ alu[2] = m_read_latch[2];
+ alu[3] = m_read_latch[3];
+ target_mask = 0xff;
+ return;
+
+ case 2: // Write mode 2
+ d[0] = ( data & 0x01 ) ? 0xff : 0x00;
+ d[1] = ( data & 0x02 ) ? 0xff : 0x00;
+ d[2] = ( data & 0x04 ) ? 0xff : 0x00;
+ d[3] = ( data & 0x08 ) ? 0xff : 0x00;
+
+ alu[0] = alu_op( d[0], m_read_latch[0] );
+ alu[1] = alu_op( d[1], m_read_latch[1] );
+ alu[2] = alu_op( d[2], m_read_latch[2] );
+ alu[3] = alu_op( d[3], m_read_latch[3] );
+ break;
+
+ case 3: // Write mode 3
+ popmessage("EGA: Write mode 3 not supported!");
+ return;
+ }
+
+ offset &= 0xffff;
+
+ //
+ // Plane selection
+ // TODO: Get this logic clearer. The documentation is unclear on the exact magic combination of bits.
+ //
+ if ( m_sequencer.data[4] & 0x04 )
+ {
+ // Sequential addressing mode
+ if ( m_sequencer.data[2] & 0x01 )
+ {
+ // Plane 0
+ // Bit selection
+ m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x02 )
+ {
+ // Plane 1
+ // Bit selection
+ m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x04 )
+ {
+ // Plane 2
+ // Bit selection
+ m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask );
+ }
+ if ( m_sequencer.data[2] & 0x08 )
+ {
+ // Plane 3
+ // Bit selection
+ m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask );
+ }
+ }
+ else
+ {
+ // Odd/Even addressing mode
+ if ( offset & 1 )
+ {
+ // Odd addresses go to planes 1 and 3
+
+ offset >>= 1;
+
+ if ( m_sequencer.data[2] & 0x02 )
+ {
+ // Plane 1
+ // Bit selection
+ m_plane[1][offset] = ( m_plane[1][offset] & ~ target_mask ) | ( alu[1] & target_mask );
+ }
+ if ( ( m_sequencer.data[2] & 0x08 ) && ! ( m_sequencer.data[4] & 0x01 ) )
+ {
+ // Plane 3
+ // Bit selection
+ m_plane[3][offset] = ( m_plane[3][offset] & ~ target_mask ) | ( alu[3] & target_mask );
+ }
+ }
+ else
+ {
+ // Even addresses go to planes 0 and 2
+
+ offset >>= 1;
+
+ if ( m_sequencer.data[2] & 0x01 )
+ {
+ // Plane 0
+ // Bit selection
+ m_plane[0][offset] = ( m_plane[0][offset] & ~ target_mask ) | ( alu[0] & target_mask );
+ }
+ if ( ( m_sequencer.data[2] & 0x04 ) && ! ( m_sequencer.data[4] & 0x01 ) )
+ {
+ // Plane 2
+ // Bit selection
+ m_plane[2][offset] = ( m_plane[2][offset] & ~ target_mask ) | ( alu[2] & target_mask );
+ }
+ }
+ }
+}
+
+
+READ8_MEMBER( isa8_ega_device::pc_ega8_3X0_r )
+{
+ int data = 0xff;
+
+ switch ( offset )
+ {
+ /* CRT Controller - address register */
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+
+ /* CRT Controller - data register */
+ case 1: case 3: case 5: case 7:
+ data = m_crtc_ega->register_r( space, offset );
+ break;
+
+ /* Input Status Register 1 */
+ case 10:
+ data = m_vblank | ( m_hsync | m_vsync ); // m_display_enable;
+
+ if ( m_display_enable )
+ {
+ /* For the moment i'm putting in some bogus data */
+ static int pixel_data;
+
+ pixel_data = ( pixel_data + 1 ) & 0x03;
+ data |= ( pixel_data << 4 );
+ }
+
+ /* Reset the attirubte writing flip flop to let the next write go to the index reigster */
+ m_attribute.index_write = 1;
+ break;
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( isa8_ega_device::pc_ega8_3X0_w )
+{
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3X0_w: offset = %02x, data = %02x\n", offset, data );
+ }
+
+ switch ( offset )
+ {
+ /* CRT Controller - address register */
+ case 0: case 2: case 4: case 6:
+ m_crtc_ega->address_w( space, offset, data );
+ break;
+
+ /* CRT Controller - data register */
+ case 1: case 3: case 5: case 7:
+ m_crtc_ega->register_w( space, offset, data );
+ break;
+
+ /* Set Light Pen Flip Flop */
+ case 9:
+ break;
+
+ /* Feature Control */
+ case 10:
+ m_feature_control = data;
+ break;
+
+ /* Clear Light Pen Flip Flop */
+ case 11:
+ break;
+ }
+}
+
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3b0_r )
+{
+ return ( m_misc_output & 0x01 ) ? 0xFF : pc_ega8_3X0_r(space, offset);
+}
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3d0_r )
+{
+ return ( m_misc_output & 0x01 ) ? pc_ega8_3X0_r(space, offset) : 0xFF;
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3b0_w )
+{
+ if ( ! ( m_misc_output & 0x01 ) )
+ {
+ pc_ega8_3X0_w( space, offset, data );
+ }
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3d0_w )
+{
+ if ( m_misc_output & 0x01 )
+ {
+ pc_ega8_3X0_w( space, offset, data );
+ }
+}
+
+
+READ8_MEMBER(isa8_ega_device::pc_ega8_3c0_r )
+{
+ int data = 0xff;
+
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3c0_r: offset = %02x\n", offset );
+ }
+
+ switch ( offset )
+ {
+ /* Attributes Controller */
+ case 0:
+ break;
+
+ /* Feature Read */
+ case 2:
+ {
+ UINT8 dips = ioport("config")->read();
+
+ data = ( data & 0x0f );
+ data |= ( ( m_feature_control & 0x03 ) << 5 );
+ data |= ( m_vsync ? 0x00 : 0x80 );
+ data |= ( ( ( dips >> ( ( ( m_misc_output & 0x0c ) >> 2 ) ) ) & 0x01 ) << 4 );
+ }
+ break;
+
+ /* Sequencer */
+ case 4:
+ break;
+ case 5:
+ break;
+
+ /* Graphics Controller */
+ case 14:
+ break;
+ case 15:
+ break;
+ }
+ return data;
+}
+
+
+WRITE8_MEMBER(isa8_ega_device::pc_ega8_3c0_w )
+{
+ static const UINT8 ar_reg_mask[0x20] =
+ {
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F, 0x3F,
+ 0x7F, 0x3F, 0x3F, 0x0F, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ static const UINT8 sr_reg_mask[0x08] =
+ {
+ 0x03, 0x0F, 0x0F, 0x0F, 0x07, 0x00, 0x00, 0x00
+ };
+ static const UINT8 gr_reg_mask[0x10] =
+ {
+ 0x0F, 0x0F, 0x0F, 0x1F, 0x07, 0x3F, 0x0F, 0x0F,
+ 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+ };
+ int index = 0;
+
+ if ( VERBOSE_EGA )
+ {
+// logerror("pc_ega_3c0_w: offset = %02x, data = %02x\n", offset, data );
+ }
+
+ switch ( offset )
+ {
+ /* Attributes Controller */
+ case 0:
+ if ( m_attribute.index_write )
+ {
+ m_attribute.index = data;
+ }
+ else
+ {
+ index = m_attribute.index & 0x1F;
+
+ logerror("AR%02X = 0x%02x\n", index, data );
+
+ /* Clear unused bits */
+ m_attribute.data[ index ] = data & ar_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x10: /* AR10 */
+ change_mode();
+ break;
+ }
+ }
+ m_attribute.index_write ^= 0x01;
+ break;
+
+ /* Misccellaneous Output */
+ case 2:
+ m_misc_output = data;
+ install_banks();
+ change_mode();
+ break;
+
+ /* Sequencer */
+ case 4:
+ m_sequencer.index = data;
+ break;
+ case 5:
+ index = m_sequencer.index & 0x07;
+
+ logerror("SR%02X = 0x%02x\n", index & 0x07, data );
+
+ /* Clear unused bits */
+ m_sequencer.data[ index ] = data & sr_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x01: /* SR01 */
+ case 0x03: /* SR03 */
+ case 0x04: /* SR04 */
+ change_mode();
+ break;
+ }
+ break;
+
+ /* Graphics Controller */
+ case 14:
+ m_graphics_controller.index = data;
+ break;
+ case 15:
+ index = m_graphics_controller.index & 0x0F;
+
+ logerror("GR%02X = 0x%02x\n", index, data );
+
+ /* Clear unused bits */
+ m_graphics_controller.data[ index ] = data & gr_reg_mask[ index ];
+
+ switch ( index )
+ {
+ case 0x06: /* GR06 */
+ change_mode();
+ install_banks();
+ break;
+ }
+ break;
+ }
+}
diff --git a/src/emu/bus/isa/ega.h b/src/emu/bus/isa/ega.h
new file mode 100644
index 00000000000..2914e13abbd
--- /dev/null
+++ b/src/emu/bus/isa/ega.h
@@ -0,0 +1,106 @@
+#pragma once
+
+#ifndef __ISA_EGA_H__
+#define __ISA_EGA_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/crtc_ega.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_ega_device
+
+class isa8_ega_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_ega_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_READ8_MEMBER(read);
+ DECLARE_WRITE8_MEMBER(write);
+ DECLARE_READ8_MEMBER(pc_ega8_3b0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3b0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3c0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3c0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3d0_r);
+ DECLARE_WRITE8_MEMBER(pc_ega8_3d0_w);
+ DECLARE_WRITE_LINE_MEMBER(de_changed);
+ DECLARE_WRITE_LINE_MEMBER(hsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vblank_changed);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ UINT8 alu_op( UINT8 data, UINT8 latch_data );
+
+public:
+ crtc_ega_device *m_crtc_ega;
+
+ void install_banks();
+ void change_mode();
+ DECLARE_WRITE8_MEMBER(pc_ega8_3X0_w);
+ DECLARE_READ8_MEMBER(pc_ega8_3X0_r);
+
+ crtc_ega_update_row_func m_update_row;
+
+ /* Video memory and related variables */
+ memory_region *m_vram;
+ UINT8 *m_plane[4];
+ UINT8 m_read_latch[4];
+ UINT8 *m_videoram;
+ UINT8 *m_charA;
+ UINT8 *m_charB;
+
+ /* Registers */
+ UINT8 m_misc_output;
+ UINT8 m_feature_control;
+
+ /* Attribute registers AR00 - AR14
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[32];
+ UINT8 index_write;
+ } m_attribute;
+
+ /* Sequencer registers SR00 - SR04
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[8];
+ } m_sequencer;
+
+ /* Graphics controller registers GR00 - GR08
+ */
+ struct {
+ UINT8 index;
+ UINT8 data[16];
+ } m_graphics_controller;
+
+ UINT8 m_frame_cnt;
+ UINT8 m_hsync;
+ UINT8 m_vsync;
+ UINT8 m_vblank;
+ UINT8 m_display_enable;
+ required_device<palette_device> m_palette;
+};
+
+
+// device type definition
+extern const device_type ISA8_EGA;
+
+#endif /* __ISA_EGA_H__ */
diff --git a/src/emu/bus/isa/fdc.c b/src/emu/bus/isa/fdc.c
new file mode 100644
index 00000000000..303f832d078
--- /dev/null
+++ b/src/emu/bus/isa/fdc.c
@@ -0,0 +1,158 @@
+/**********************************************************************
+
+ ISA 8 bit Floppy Disk Controller
+
+**********************************************************************/
+
+#include "emu.h"
+#include "fdc.h"
+#include "machine/pc_fdc.h"
+#include "imagedev/flopdrv.h"
+#include "formats/pc_dsk.h"
+#include "formats/naslite_dsk.h"
+
+
+FLOPPY_FORMATS_MEMBER( isa8_fdc_device::floppy_formats )
+ FLOPPY_PC_FORMAT,
+ FLOPPY_NASLITE_FORMAT
+FLOPPY_FORMATS_END
+
+static SLOT_INTERFACE_START( pc_dd_floppies )
+ SLOT_INTERFACE( "525dd", FLOPPY_525_DD )
+ SLOT_INTERFACE( "35dd", FLOPPY_35_DD )
+SLOT_INTERFACE_END
+
+static SLOT_INTERFACE_START( pc_hd_floppies )
+ SLOT_INTERFACE( "525hd", FLOPPY_525_HD )
+ SLOT_INTERFACE( "35hd", FLOPPY_35_HD )
+ SLOT_INTERFACE( "525dd", FLOPPY_525_DD )
+ SLOT_INTERFACE( "35dd", FLOPPY_35_DD )
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( cfg_xt )
+ MCFG_PC_FDC_XT_ADD("fdc")
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_dd_floppies, "525dd", isa8_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_dd_floppies, "525dd", isa8_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( cfg_at )
+ MCFG_PC_FDC_AT_ADD("fdc")
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( cfg_smc )
+ MCFG_SMC37C78_ADD("fdc")
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( cfg_ps2 )
+ MCFG_N82077AA_ADD("fdc", n82077aa_device::MODE_PS2)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( cfg_superio )
+ MCFG_PC_FDC_SUPERIO_ADD("fdc")
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", pc_hd_floppies, "35hd", isa8_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+
+isa8_fdc_device::isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this),
+ fdc(*this, "fdc")
+{
+}
+
+void isa8_fdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x03f0, 0x03f7, *fdc, &pc_fdc_interface::map);
+ m_isa->set_dma_channel(2, this, TRUE);
+
+ fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(isa8_fdc_device::irq_w), this));
+ fdc->setup_drq_cb(pc_fdc_interface::line_cb(FUNC(isa8_fdc_device::drq_w), this));
+}
+
+void isa8_fdc_device::device_reset()
+{
+}
+
+void isa8_fdc_device::irq_w(bool state)
+{
+ m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void isa8_fdc_device::drq_w(bool state)
+{
+ m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+UINT8 isa8_fdc_device::dack_r(int line)
+{
+ return fdc->dma_r();
+}
+
+void isa8_fdc_device::dack_w(int line, UINT8 data)
+{
+ return fdc->dma_w(data);
+}
+
+void isa8_fdc_device::eop_w(int state)
+{
+ fdc->tc_w(state == ASSERT_LINE);
+}
+
+isa8_fdc_xt_device::isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits XT FDC hookup", tag, owner, clock, "isa8_fdc_xt", __FILE__)
+{
+}
+
+machine_config_constructor isa8_fdc_xt_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg_xt);
+}
+
+isa8_fdc_at_device::isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_AT, "ISA 8bits AT FDC hookup", tag, owner, clock, "isa8_fdc_at", __FILE__)
+{
+}
+
+machine_config_constructor isa8_fdc_at_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg_at);
+}
+
+isa8_fdc_smc_device::isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_XT, "ISA 8bits SMC FDC hookup", tag, owner, clock, "isa8_fdc_smc", __FILE__)
+{
+}
+
+machine_config_constructor isa8_fdc_smc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg_smc);
+}
+
+isa8_fdc_ps2_device::isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_PS2, "ISA 8bits PS/2 FDC hookup", tag, owner, clock, "isa8_fdc_ps2", __FILE__)
+{
+}
+
+machine_config_constructor isa8_fdc_ps2_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg_ps2);
+}
+
+isa8_fdc_superio_device::isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : isa8_fdc_device(mconfig, ISA8_FDC_SUPERIO, "ISA 8bits SUPERIO FDC hookup", tag, owner, clock, "isa8_fdc_superio", __FILE__)
+{
+}
+
+machine_config_constructor isa8_fdc_superio_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg_superio);
+}
+
+const device_type ISA8_FDC_XT = &device_creator<isa8_fdc_xt_device>;
+const device_type ISA8_FDC_AT = &device_creator<isa8_fdc_at_device>;
+const device_type ISA8_FDC_SMC = &device_creator<isa8_fdc_smc_device>;
+const device_type ISA8_FDC_PS2 = &device_creator<isa8_fdc_ps2_device>;
+const device_type ISA8_FDC_SUPERIO = &device_creator<isa8_fdc_superio_device>;
diff --git a/src/emu/bus/isa/fdc.h b/src/emu/bus/isa/fdc.h
new file mode 100644
index 00000000000..f0b3423f673
--- /dev/null
+++ b/src/emu/bus/isa/fdc.h
@@ -0,0 +1,85 @@
+/**********************************************************************
+
+ ISA 8 bit Floppy Disk Controller
+
+**********************************************************************/
+#pragma once
+
+#ifndef ISA_FDC_H
+#define ISA_FDC_H
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/upd765.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_fdc_device
+
+class isa8_fdc_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_fdc_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ required_device<pc_fdc_interface> fdc;
+
+ DECLARE_FLOPPY_FORMATS( floppy_formats );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line, UINT8 data);
+ virtual void eop_w(int state);
+
+private:
+ void irq_w(bool state);
+ void drq_w(bool state);
+
+};
+
+class isa8_fdc_xt_device : public isa8_fdc_device {
+public:
+ isa8_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+class isa8_fdc_at_device : public isa8_fdc_device {
+public:
+ isa8_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+class isa8_fdc_smc_device : public isa8_fdc_device {
+public:
+ isa8_fdc_smc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+class isa8_fdc_ps2_device : public isa8_fdc_device {
+public:
+ isa8_fdc_ps2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+class isa8_fdc_superio_device : public isa8_fdc_device {
+public:
+ isa8_fdc_superio_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+};
+
+// device type definition
+extern const device_type ISA8_FDC_XT;
+extern const device_type ISA8_FDC_AT;
+extern const device_type ISA8_FDC_SMC;
+extern const device_type ISA8_FDC_PS2;
+extern const device_type ISA8_FDC_SUPERIO;
+
+#endif /* ISA_FDC_H */
diff --git a/src/emu/bus/isa/finalchs.c b/src/emu/bus/isa/finalchs.c
new file mode 100644
index 00000000000..f3acb8cadcd
--- /dev/null
+++ b/src/emu/bus/isa/finalchs.c
@@ -0,0 +1,125 @@
+/***************************************************************************
+
+ Final Chess Card by TASC
+
+ TODO:
+ - skeleton, just boots the CPU
+
+***************************************************************************/
+
+#include "emu.h"
+#include "finalchs.h"
+#include "cpu/m6502/m65c02.h"
+
+WRITE8_MEMBER( isa8_finalchs_device::io7ff8_write )
+{
+ m_FCH_latch_data = data;
+}
+
+READ8_MEMBER( isa8_finalchs_device::io7ff8_read )
+{
+ static unsigned char table[] = { 0xff, 0xfd, 0xfe };
+ static int i = -1;
+ i++;
+ if (i == 3) i = 0;
+ return table[i]; // exercise the NMI handler for now with known commands
+}
+
+READ8_MEMBER( isa8_finalchs_device::io6000_read )
+{
+ return 0x55;
+}
+
+WRITE8_MEMBER( isa8_finalchs_device::io6000_write )
+{
+ m_FCH_latch_data = data;
+}
+
+static ADDRESS_MAP_START(finalchs_mem , AS_PROGRAM, 8, isa8_finalchs_device)
+ AM_RANGE( 0x0000, 0x1fff ) AM_RAM
+ AM_RANGE( 0x7ff8, 0x7ff8 ) AM_READ(io7ff8_read)
+ AM_RANGE( 0x7ff8, 0x7ff8 ) AM_WRITE(io7ff8_write)
+ AM_RANGE( 0x6000, 0x6000 ) AM_READ(io6000_read)
+ AM_RANGE( 0x6000, 0x6000 ) AM_WRITE(io6000_write)
+ AM_RANGE( 0x8000, 0xffff ) AM_ROM
+ADDRESS_MAP_END
+
+static MACHINE_CONFIG_FRAGMENT( finalchs_config )
+ MCFG_CPU_ADD("maincpu",M65C02,5000000)
+ MCFG_CPU_PROGRAM_MAP(finalchs_mem)
+MACHINE_CONFIG_END
+
+ROM_START(finalchs)
+ ROM_REGION(0x10000,"maincpu",0)
+ ROM_LOAD("finalchs.bin", 0x8000, 0x8000, CRC(c8e72dff) SHA1(f422b19a806cef4fadd580caefaaf8c32b644098))
+ROM_END
+
+READ8_MEMBER( isa8_finalchs_device::finalchs_r )
+{
+ return 0;
+}
+
+WRITE8_MEMBER( isa8_finalchs_device::finalchs_w )
+{
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_FINALCHS = &device_creator<isa8_finalchs_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_finalchs_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( finalchs_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_finalchs_device - constructor
+//-------------------------------------------------
+
+isa8_finalchs_device::isa8_finalchs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_FINALCHS, "Final Chess Card", tag, owner, clock, "finalchs", __FILE__),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_finalchs_device::device_start()
+{
+ set_isa_device();
+ //the included setup program allows any port from 0x100 to 0x1F0 to be selected, at increments of 0x10
+ //picked the following at random until we get dips hooked up
+ m_isa->install_device(0x160, 0x0161, 0, 0, read8_delegate(FUNC(isa8_finalchs_device::finalchs_r), this), write8_delegate(FUNC(isa8_finalchs_device::finalchs_w), this));
+// timer_pulse(machine, ATTOTIME_IN_HZ(1), NULL, 0, cause_M6502_irq);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_finalchs_device::device_reset()
+{
+ m_FCH_latch_data = 0;
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_finalchs_device::device_rom_region() const
+{
+ return ROM_NAME( finalchs );
+}
diff --git a/src/emu/bus/isa/finalchs.h b/src/emu/bus/isa/finalchs.h
new file mode 100644
index 00000000000..3016095fd6c
--- /dev/null
+++ b/src/emu/bus/isa/finalchs.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifndef __ISA_FINALCHS_H__
+#define __ISA_FINALCHS_H__
+
+#include "emu.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_finalchs_device
+
+class isa8_finalchs_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_finalchs_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER(finalchs_r);
+ DECLARE_WRITE8_MEMBER(finalchs_w);
+
+ DECLARE_WRITE8_MEMBER( io7ff8_write );
+ DECLARE_READ8_MEMBER( io7ff8_read );
+ DECLARE_READ8_MEMBER( io6000_read );
+ DECLARE_WRITE8_MEMBER( io6000_write );
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ // internal state
+ UINT8 m_FCH_latch_data;
+};
+
+
+// device type definition
+extern const device_type ISA8_FINALCHS;
+
+#endif /* __ISA_FINALCHS_H__ */
diff --git a/src/emu/bus/isa/gblaster.c b/src/emu/bus/isa/gblaster.c
new file mode 100644
index 00000000000..bde6d1b36ce
--- /dev/null
+++ b/src/emu/bus/isa/gblaster.c
@@ -0,0 +1,89 @@
+/***************************************************************************
+
+ ISA 8 bit Creative Labs Game Blaster Sound Card
+
+***************************************************************************/
+
+#include "emu.h"
+#include "gblaster.h"
+#include "sound/speaker.h"
+#include "sound/saa1099.h"
+
+/*
+ creative labs game blaster (CMS creative music system)
+ 2 x saa1099 chips
+ also on sound blaster 1.0
+ option on sound blaster 1.5
+
+ jumperable? normally 0x220
+*/
+static MACHINE_CONFIG_FRAGMENT( game_blaster_config )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SAA1099_ADD("saa1099.1", 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ MCFG_SAA1099_ADD("saa1099.2", 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+static READ8_DEVICE_HANDLER( saa1099_16_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( saa1099_16_w )
+{
+ switch(offset)
+ {
+ case 0 : dynamic_cast<saa1099_device*>(device)->saa1099_control_w( space, offset, data ); break;
+ case 1 : dynamic_cast<saa1099_device*>(device)->saa1099_data_w( space, offset, data ); break;
+ }
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_GAME_BLASTER = &device_creator<isa8_gblaster_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_gblaster_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( game_blaster_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_gblaster_device - constructor
+//-------------------------------------------------
+
+isa8_gblaster_device::isa8_gblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_GAME_BLASTER, "Game Blaster Sound Card", tag, owner, clock, "isa_gblaster", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_gblaster_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(subdevice("saa1099.1"), 0x0220, 0x0221, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ m_isa->install_device(subdevice("saa1099.2"), 0x0222, 0x0223, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_gblaster_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/gblaster.h b/src/emu/bus/isa/gblaster.h
new file mode 100644
index 00000000000..b846ee0f81a
--- /dev/null
+++ b/src/emu/bus/isa/gblaster.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#ifndef __ISA_GAME_BLASTER_H__
+#define __ISA_GAME_BLASTER_H__
+
+#include "emu.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_gblaster_device
+
+class isa8_gblaster_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_gblaster_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_GAME_BLASTER;
+
+#endif /* __ISA_GAME_BLASTER_H__ */
diff --git a/src/emu/bus/isa/gus.c b/src/emu/bus/isa/gus.c
new file mode 100644
index 00000000000..694fba1d991
--- /dev/null
+++ b/src/emu/bus/isa/gus.c
@@ -0,0 +1,1740 @@
+/*
+ * Gravis Ultrasound ISA card
+ *
+ * Started: 28/01/2012
+ */
+
+
+#include "gus.h"
+#include "bus/midi/midi.h"
+#include "machine/clock.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+// uncomment this to save wave RAM content to a file
+//#define SAVE_WAVE_RAM 1
+//#define LOG_SOUND 1
+
+static const UINT16 rate_table[33] =
+{
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 44100, 41160, 38587, 36317, 34300, 32494, 30870, 29400,
+ 28063, 26843, 25725, 24696, 23746, 22866, 22050, 21289,
+ 20580, 19916, 19293
+};
+
+static const UINT16 volume_ramp_table[4] =
+{
+ 1, 8, 64, 512
+};
+
+const device_type GGF1 = &device_creator<gf1_device>;
+const device_type ISA16_GUS = &device_creator<isa16_gus_device>;
+
+#ifdef LOG_SOUND
+FILE* f;
+#endif
+
+void gf1_device::update_irq()
+{
+ int txirq = calculate_txirq();
+
+ if (m_txirq != txirq)
+ {
+ m_txirq = txirq;
+ m_txirq_handler(!m_txirq);
+ }
+
+ int rxirq = calculate_rxirq();
+
+ if (m_rxirq != rxirq)
+ {
+ m_rxirq = rxirq;
+ m_rxirq_handler(!m_rxirq);
+ }
+}
+
+/* only the Adlib timers are implemented in hardware */
+READ8_MEMBER( gf1_device::adlib_r )
+{
+ UINT8 retVal = 0xff;
+ switch(offset)
+ {
+ case 0:
+// if(m_timer_ctrl & 0x01)
+ return m_adlib_status;
+// return m_fake_adlib_status;
+ case 1:
+ return m_adlib_data;
+ }
+ return retVal;
+}
+
+WRITE8_MEMBER( gf1_device::adlib_w )
+{
+ switch(offset)
+ {
+ case 0:
+ m_adlib_cmd = data;
+ break;
+ case 1:
+ if(m_adlib_cmd == 0x04 && !(m_timer_ctrl & 0x01))
+ {
+ if(data & 0x80)
+ {
+ m_timer1_irq_func(0);
+ m_timer2_irq_func(0);
+ m_adlib_status &= ~0xe0;
+ logerror("GUS: Timer flags reset\n");
+ }
+ else
+ {
+ if((data & 0x01) && !(data & 0x40))
+ {
+ m_adlib_timer1_enable = 1;
+ m_timer1->adjust(attotime::zero,0,attotime::from_usec(80));
+ }
+ if((data & 0x02) && !(data & 0x20))
+ {
+ m_adlib_timer2_enable = 1;
+ m_timer2->adjust(attotime::zero,0,attotime::from_usec(320));
+ }
+ if(!(data & 0x01) && !(data & 0x40))
+ {
+ m_adlib_timer1_enable = 0;
+ m_timer1->reset();
+ }
+ if(!(data & 0x02) && !(data & 0x20))
+ {
+ m_adlib_timer2_enable = 0;
+ m_timer2->reset();
+ }
+ logerror("GUS: Timer enable - %02x\n",data);
+ }
+ m_adlib_timer_cmd = data;
+ }
+ else
+ {
+ m_adlib_data = data;
+ if(m_timer_ctrl & 0x02)
+ {
+ m_adlib_status |= 0x01;
+ m_nmi_func(1);
+ logerror("GUS: 2X9 Timer triggered!\n");
+ }
+ }
+ break;
+ }
+}
+
+void gf1_device::update_volume_ramps()
+{
+ int x;
+
+ for(x=0;x<32;x++)
+ {
+ if(!(m_voice[x].vol_ramp_ctrl & 0x01)) // if ramping is enabled
+ {
+ m_voice[x].vol_count++;
+ if(m_voice[x].vol_count % volume_ramp_table[(m_voice[x].vol_ramp_rate & 0xc0)>>6] == 0)
+ {
+ // increase/decrease volume
+ if(m_voice[x].vol_ramp_ctrl & 0x40)
+ {
+ //m_voice[x].current_vol = (m_voice[x].current_vol & 0xf000) | ((m_voice[x].current_vol & 0x0ff0) + ((m_voice[x].vol_ramp_rate & 0x0f)<<8));
+ m_voice[x].current_vol -= ((m_voice[x].vol_ramp_rate & 0x3f) << 4);
+ if(m_voice[x].current_vol <= (m_voice[x].vol_ramp_start << 8)) // end of ramp?
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x08)
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x10)
+ {
+ m_voice[x].vol_ramp_ctrl &= ~0x40; // change direction and continue
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8);
+ }
+ else
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8);
+ }
+ else
+ {
+ m_voice[x].vol_ramp_ctrl |= 0x01; // stop volume ramp
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8);
+ }
+ if(m_voice[x].vol_ramp_ctrl & 0x20)
+ set_irq(IRQ_VOLUME_RAMP,x);
+ }
+ }
+ else
+ {
+ //m_voice[x].current_vol = (m_voice[x].current_vol & 0xf000) | ((m_voice[x].current_vol & 0x0ff0) - ((m_voice[x].vol_ramp_rate & 0x0f)<<8));
+ m_voice[x].current_vol += ((m_voice[x].vol_ramp_rate & 0x3f) << 4);
+ if(m_voice[x].current_vol >= (m_voice[x].vol_ramp_end << 8)) // end of ramp?
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x08)
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x10)
+ {
+ m_voice[x].vol_ramp_ctrl |= 0x40; // change direction and continue
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8);
+ }
+ else
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_start << 8);
+ }
+ else
+ {
+ m_voice[x].vol_ramp_ctrl |= 0x01; // stop volume ramp
+ m_voice[x].current_vol = (m_voice[x].vol_ramp_end << 8);
+ }
+ if(m_voice[x].vol_ramp_ctrl & 0x20)
+ set_irq(IRQ_VOLUME_RAMP,x);
+ }
+ }
+ }
+ }
+ }
+}
+
+void gf1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch(id)
+ {
+ case ADLIB_TIMER1:
+ if(m_adlib_timer1_enable != 0)
+ {
+ if(m_timer1_count == 0xff)
+ {
+ m_adlib_status |= 0xc0;
+ m_timer1_count = m_timer1_value;
+ if(m_timer_ctrl & 0x04)
+ m_timer1_irq_func(1);
+ }
+ m_timer1_count++;
+ }
+ break;
+ case ADLIB_TIMER2:
+ if(m_adlib_timer2_enable != 0)
+ {
+ if(m_timer2_count == 0xff)
+ {
+ m_adlib_status |= 0xa0;
+ m_timer2_count = m_timer2_value;
+ if(m_timer_ctrl & 0x08)
+ m_timer2_irq_func(1);
+ }
+ m_timer2_count++;
+ }
+ break;
+ case DMA_TIMER:
+ m_drq1(1);
+ break;
+ case VOL_RAMP_TIMER:
+ update_volume_ramps();
+ break;
+ }
+}
+
+void gf1_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
+{
+ int x,y;
+ //UINT32 count;
+
+ stream_sample_t* outputl = outputs[0];
+ stream_sample_t* outputr = outputs[1];
+ memset( outputl, 0x00, samples * sizeof(*outputl) );
+ memset( outputr, 0x00, samples * sizeof(*outputr) );
+
+ for(x=0;x<32;x++) // for each voice
+ {
+ stream_sample_t* left = outputl;
+ stream_sample_t* right = outputr;
+ UINT16 vol = (m_volume_table[(m_voice[x].current_vol & 0xfff0) >> 4]);
+ for(y=samples-1; y>=0; y--)
+ {
+ UINT32 current = m_voice[x].current_addr >> 9;
+ // TODO: implement proper panning
+ (*left) += ((m_voice[x].sample) * (vol/8192.0));
+ (*right) += ((m_voice[x].sample) * (vol/8192.0));
+ left++;
+ right++;
+ if((!(m_voice[x].voice_ctrl & 0x40)) && (m_voice[x].current_addr >= m_voice[x].end_addr) && !m_voice[x].rollover && !(m_voice[x].voice_ctrl & 0x01))
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x04)
+ {
+ m_voice[x].rollover = true; // set roll over condition - generate IRQ, but keep voice playing
+ }
+
+ if(m_voice[x].voice_ctrl & 0x20)
+ set_irq(IRQ_WAVETABLE,x);
+
+ // end voice, unless looping, or rollover is active, which disables looping
+ if(!m_voice[x].rollover)
+ {
+ if(!(m_voice[x].voice_ctrl & 0x08))
+ {
+ m_voice[x].voice_ctrl |= 0x01;
+// m_voice[x].current_addr = m_voice[x].end_addr;
+ }
+ }
+ // looping is not supposed to happen when rollover is active, but the Windows drivers have other ideas...
+ if(m_voice[x].voice_ctrl & 0x08)
+ {
+ if(m_voice[x].voice_ctrl & 0x10)
+ m_voice[x].voice_ctrl |= 0x40; // change direction
+ else
+ m_voice[x].current_addr = m_voice[x].start_addr; // start sample again
+ }
+ }
+ if((m_voice[x].voice_ctrl & 0x40) && (m_voice[x].current_addr <= m_voice[x].start_addr) && !m_voice[x].rollover && !(m_voice[x].voice_ctrl & 0x01))
+ {
+ if(m_voice[x].vol_ramp_ctrl & 0x04)
+ {
+ m_voice[x].rollover = true; // set roll over condition - generate IRQ, but keep voice playing
+ }
+
+ if(m_voice[x].voice_ctrl & 0x20)
+ set_irq(IRQ_WAVETABLE,x);
+
+ // end voice, unless looping, or rollover is active, which disables looping
+ if(!m_voice[x].rollover)
+ {
+ // end voice, unless looping
+ if(!(m_voice[x].voice_ctrl & 0x08))
+ {
+ m_voice[x].voice_ctrl |= 0x01;
+// m_voice[x].current_addr = m_voice[x].start_addr;
+ }
+ }
+ // looping is not supposed to happen when rollover is active, but the Windows drivers have other ideas...
+ if(m_voice[x].voice_ctrl & 0x08)
+ {
+ if(m_voice[x].voice_ctrl & 0x10)
+ m_voice[x].voice_ctrl &= ~0x40; // change direction
+ else
+ m_voice[x].current_addr = m_voice[x].end_addr; // start sample again
+ }
+ }
+ if(!(m_voice[x].voice_ctrl & 0x01))
+ {
+ if(m_voice[x].voice_ctrl & 0x04)
+ { // 16-bit PCM
+ current = ((m_voice[x].current_addr >> 9) & 0xc0000) + (((m_voice[x].current_addr >> 9) & 0x1ffff) << 1);
+ m_voice[x].sample = (INT16)((m_wave_ram[current & 0xffffe]) | ((m_wave_ram[(current & 0xffffe)+1])<<8));
+ }
+ else
+ { // 8-bit PCM
+ m_voice[x].sample = (INT16)(m_wave_ram[current & 0xfffff] << 8);
+ }
+ if(m_voice[x].voice_ctrl & 0x40) // voice direction
+ m_voice[x].current_addr -= (m_voice[x].freq_ctrl >> 1);
+ else
+ m_voice[x].current_addr += (m_voice[x].freq_ctrl >> 1);
+ }
+#ifdef LOG_SOUND
+ INT16 smp = (m_voice[x].sample) * (vol / 8192.0);
+ fwrite(&smp,4,1,f);
+#endif
+ }
+ }
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// gf1_device - constructor
+//-------------------------------------------------
+
+gf1_device::gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ acia6850_device(mconfig, GGF1, "Gravis GF1", tag, owner, clock, "gf1", __FILE__),
+ device_sound_interface( mconfig, *this ),
+ m_txirq_handler(*this),
+ m_rxirq_handler(*this)
+{
+}
+
+void gf1_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const gf1_interface *intf = reinterpret_cast<const gf1_interface *>(static_config());
+ if (intf != NULL)
+ *static_cast<gf1_interface *>(this) = *intf;
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&wave_irq_cb, 0, sizeof(wave_irq_cb));
+ memset(&ramp_irq_cb, 0, sizeof(ramp_irq_cb));
+ memset(&timer1_irq_cb, 0, sizeof(timer1_irq_cb));
+ memset(&timer2_irq_cb, 0, sizeof(timer2_irq_cb));
+ memset(&sb_irq_cb, 0, sizeof(sb_irq_cb));
+ memset(&dma_irq_cb, 0, sizeof(dma_irq_cb));
+ memset(&drq1_cb, 0, sizeof(drq1_cb));
+ memset(&drq2_cb, 0, sizeof(drq2_cb));
+ memset(&nmi_cb, 0, sizeof(nmi_cb));
+ }
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void gf1_device::device_start()
+{
+ int i;
+ double out = (double)(1 << 13);
+
+ m_txirq_handler.resolve_safe();
+ m_rxirq_handler.resolve_safe();
+
+ // TODO: make DRAM size configurable. Can be 256k, 512k, 768k, or 1024k
+ m_wave_ram = auto_alloc_array(machine(),UINT8,1024*1024);
+ memset(m_wave_ram,0,1024*1024);
+
+ m_stream = stream_alloc(0,2,44100);
+
+ // init timers
+ m_timer1 = timer_alloc(ADLIB_TIMER1);
+ m_timer2 = timer_alloc(ADLIB_TIMER2);
+ m_dmatimer = timer_alloc(DMA_TIMER);
+ m_voltimer = timer_alloc(VOL_RAMP_TIMER);
+
+ save_pointer(NAME(m_wave_ram),1024*1024);
+
+ m_wave_irq_func.resolve(wave_irq_cb, *this);
+ m_ramp_irq_func.resolve(ramp_irq_cb, *this);
+ m_timer1_irq_func.resolve(timer1_irq_cb, *this);
+ m_timer2_irq_func.resolve(timer2_irq_cb, *this);
+ m_sb_irq_func.resolve(sb_irq_cb, *this);
+ m_dma_irq_func.resolve(dma_irq_cb, *this);
+ m_drq1.resolve(drq1_cb,*this);
+ m_drq2.resolve(drq2_cb,*this);
+ m_nmi_func.resolve(nmi_cb, *this);
+
+ m_voice_irq_current = 0;
+ m_voice_irq_ptr = 0;
+ m_dma_channel1 = 0;
+ m_dma_channel2 = 0;
+ m_gf1_irq = 0;
+ m_midi_irq = 0;
+
+ for (i=4095;i>=0;i--)
+ {
+ m_volume_table[i] = (INT16)out;
+ out /= 1.002709201; /* 0.0235 dB Steps */
+ }
+
+#ifdef LOG_SOUND
+ f = fopen("soundlog.bin","wb");
+#endif
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void gf1_device::device_reset()
+{
+ int x;
+
+ // init voices
+ for(x=0;x<32;x++)
+ {
+ m_voice[x].voice_ctrl = 0x01; // stop all voices
+ m_voice[x].vol_ramp_ctrl = 0x01; // stop all volume ramps
+ m_voice[x].current_vol = 0; // silence all voices
+ }
+ m_irq_source = 0xe0;
+ m_reg_ctrl = 0;
+ m_active_voices = 14;
+ m_stream->set_sample_rate(44100);
+ m_voltimer->adjust(attotime::zero,0,attotime::from_usec(1000/(1.6*m_active_voices)));
+}
+
+void gf1_device::device_stop()
+{
+#ifdef SAVE_WAVE_RAM
+ FILE* f;
+ f=fopen("waveout.bin","wb");
+ fwrite(m_wave_ram,1024*1024,1,f);
+ fclose(f);
+#endif
+#ifdef LOG_SOUND
+ fclose(f);
+#endif
+}
+// ------------------------------------------------
+// device I/O handlers
+// ------------------------------------------------
+
+READ8_MEMBER(gf1_device::global_reg_select_r)
+{
+ if(offset == 0)
+ return m_current_voice;
+ else
+ return m_current_reg | 0xc0;
+}
+
+WRITE8_MEMBER(gf1_device::global_reg_select_w)
+{
+ if(offset == 0)
+ m_current_voice = data & 0x1f;
+ else
+ m_current_reg = data;
+}
+
+READ8_MEMBER(gf1_device::global_reg_data_r)
+{
+ UINT16 ret = 0x00;
+
+ switch(m_current_reg)
+ {
+ case 0x41: // DMA DRAM control
+ if(offset == 1)
+ {
+ ret = m_dma_dram_ctrl;
+ m_dma_dram_ctrl &= ~0x40;
+ m_dma_irq_func(0);
+ return ret;
+ }
+ case 0x45: // Timer control
+ if(offset == 1)
+ return m_timer_ctrl & 0x0c;
+ break;
+ case 0x49: // Sampling control
+ if(offset == 1)
+ return m_sampling_ctrl & 0xe7;
+ case 0x4c: // Reset
+ if(offset == 1)
+ return m_reset;
+ case 0x80: // Voice control
+/* bit 0 - 1 if voice is stopped
+ * bit 6 - 1 if addresses are decreasing, can change when looping is enabled
+ * bit 7 - 1 if Wavetable IRQ is pending */
+ if(offset == 1)
+ return m_voice[m_current_voice].voice_ctrl & 0xff;
+ case 0x81: // Frequency Control
+ ret = m_voice[m_current_voice].freq_ctrl;
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x82: // Starting address (high 13 bits)
+ ret = (m_voice[m_current_voice].start_addr >> 16);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x83: // Starting address (low 7 bits plus 4 bits fractional)
+ ret = (m_voice[m_current_voice].start_addr & 0xffff);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x84: // End address (high 13 bits)
+ ret = (m_voice[m_current_voice].end_addr >> 16);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x85: // End address (low 7 bits plus 4 bits fractional)
+ ret = (m_voice[m_current_voice].end_addr & 0xffff);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x86: // Volume Ramp rate
+ if(offset == 1)
+ return m_voice[m_current_voice].vol_ramp_rate;
+ case 0x87: // Volume Ramp start (high 4 bits = exponent, low 4 bits = mantissa)
+ if(offset == 1)
+ return m_voice[m_current_voice].vol_ramp_start;
+ case 0x88: // Volume Ramp end (high 4 bits = exponent, low 4 bits = mantissa)
+ if(offset == 1)
+ return m_voice[m_current_voice].vol_ramp_end;
+ case 0x89: // Current Volume (high 4 bits = exponent, middle 8 bits = mantissa, low 4 bits = 0 [reserved])
+ ret = m_voice[m_current_voice].current_vol;
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x8a: // Current position (high 13 bits)
+ ret = (m_voice[m_current_voice].current_addr >> 16);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x8b: // Current position (low 7 bits, plus 9 bit fractional)
+ ret = (m_voice[m_current_voice].current_addr & 0xffff);
+ if(offset == 0)
+ return ret & 0x00ff;
+ else
+ return (ret >> 8) & 0x00ff;
+ case 0x8c: // Pan position (4 bits, 0=full left, 15=full right)
+ if(offset == 1)
+ return m_voice[m_current_voice].pan_position;
+ case 0x8d: // Volume Ramp control
+/* bit 0 - Ramp has stopped
+ * bit 6 - Ramp direction
+ * bit 7 - Ramp IRQ pending */
+ if(offset == 1)
+ return m_voice[m_current_voice].vol_ramp_ctrl;
+ case 0x8e: // Active voices (6 bits, high 2 bits are always 1)
+ if(offset == 1)
+ return m_active_voices | 0xc0;
+ case 0x8f: // IRQ source register
+ if(offset == 1)
+ {
+ ret = m_voice_irq_fifo[m_voice_irq_current % 32];
+ if((m_voice_irq_current % 32) != (m_voice_irq_ptr % 32))
+ m_voice_irq_current++;
+ else
+ ret = 0xe0;
+ m_wave_irq_func(0);
+ m_ramp_irq_func(0);
+ return ret;
+ }
+ break;
+ default:
+ logerror("GUS: Read from unimplemented or unknown global register %02x\n",m_current_reg);
+ return 0xff;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(gf1_device::global_reg_data_w)
+{
+ switch(m_current_reg)
+ {
+ case 0x00: // Voice control
+/* bit 1 - set to 1 to stop current voice
+ * bit 2 - set to 1 for 16-bit wave data, otherwise is 8-bit
+ * bit 3 - set to 1 to loop to start address when the end address is reached
+ * bit 4 - set to 1 to enable bi-directional looping
+ * bit 5 - set to 1 to enable wavetable IRQ when end address is reached */
+ if(offset == 1)
+ {
+ m_voice[m_current_voice].voice_ctrl = data & 0xff;
+ m_voice[m_current_voice].rollover = false;
+ if(data & 0x02)
+ m_voice[m_current_voice].voice_ctrl |= 0x01;
+ }
+ logerror("GUS: Ch%i Voice control write %02x\n", m_current_voice,data);
+ break;
+ case 0x01: // Frequency Control
+/* bits 15-10 - Integer portion
+ * bits 9-1 - Fractional portion
+ * bit 0 - not used */
+ if(offset == 0)
+ m_voice[m_current_voice].freq_ctrl = (m_voice[m_current_voice].freq_ctrl & 0xff00) | data;
+ else
+ m_voice[m_current_voice].freq_ctrl = (m_voice[m_current_voice].freq_ctrl & 0x00ff) | (data << 8);
+ logerror("GUS: Ch%i Frequency control write %04x\n", m_current_voice, m_voice[m_current_voice].freq_ctrl);
+ break;
+ case 0x02: // Starting address (high 13 bits)
+ if(offset == 0)
+ m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xff00ffff) | (data << 16);
+ else
+ m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0x00ffffff) | (data << 24);
+ logerror("GUS: Ch%i [high] Start address set to %08x\n", m_current_voice,m_voice[m_current_voice].start_addr);
+ break;
+ case 0x03: // Starting address (low 7 bits plus 4 bits fractional)
+ if(offset == 0)
+ m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xffffff00) | data;
+ else
+ m_voice[m_current_voice].start_addr = (m_voice[m_current_voice].start_addr & 0xffff00ff) | (data << 8);
+ logerror("GUS: Ch%i [low] Start address set to %08x\n", m_current_voice,m_voice[m_current_voice].start_addr);
+ break;
+ case 0x04: // End address (high 13 bits)
+ if(offset == 0)
+ m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xff00ffff) | (data << 16);
+ else
+ m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0x00ffffff) | (data << 24);
+ logerror("GUS: Ch%i [high] End address set to %08x\n", m_current_voice,m_voice[m_current_voice].end_addr);
+ break;
+ case 0x05: // End address (low 7 bits plus 4 bits fractional)
+ if(offset == 0)
+ m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xffffff00) | data;
+ else
+ m_voice[m_current_voice].end_addr = (m_voice[m_current_voice].end_addr & 0xffff00ff) | (data << 8);
+ logerror("GUS: Ch%i [low] End address set to %08x\n", m_current_voice,m_voice[m_current_voice].end_addr);
+ break;
+ case 0x06: // Volume Ramp rate
+ if(offset == 1)
+ m_voice[m_current_voice].vol_ramp_rate = data;
+ logerror("GUS: Ch%i Volume ramp rate write %02x\n", m_current_voice,data);
+ break;
+ case 0x07: // Volume Ramp start (high 4 bits = exponent, low 4 bits = mantissa)
+ if(offset == 1)
+ m_voice[m_current_voice].vol_ramp_start = data;
+ logerror("GUS: Ch%i Volume ramp start write %02x\n", m_current_voice, data);
+ break;
+ case 0x08: // Volume Ramp end (high 4 bits = exponent, low 4 bits = mantissa)
+ if(offset == 1)
+ m_voice[m_current_voice].vol_ramp_end = data;
+ logerror("GUS: Ch%i Volume ramp end write %02x\n", m_current_voice, data);
+ break;
+ case 0x09: // Current Volume (high 4 bits = exponent, middle 8 bits = mantissa, low 4 bits = 0 [reserved])
+ if(offset == 0)
+ m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].current_vol & 0xff00) | data;
+ else
+ m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].current_vol & 0x00ff) | (data << 8);
+ logerror("GUS: Ch%i Current volume write %02x\n", m_current_voice, data);
+ break;
+ case 0x0a: // Current position (high 13 bits)
+ if(offset == 0)
+ m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xff00ffff) | (data << 16);
+ else
+ m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0x00ffffff) | (data << 24);
+ logerror("GUS: Ch%i Current address write %08x\n", m_current_voice, m_voice[m_current_voice].current_addr);
+ break;
+ case 0x0b: // Current position (low 7 bits, plus 9 bit fractional)
+ if(offset == 0)
+ m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xffffff00) | data;
+ else
+ m_voice[m_current_voice].current_addr = (m_voice[m_current_voice].current_addr & 0xffff00ff) | (data << 8);
+ logerror("GUS: Ch%i Current address write %08x\n", m_current_voice, m_voice[m_current_voice].current_addr);
+ break;
+ case 0x0c: // Pan position (4 bits, 0=full left, 15=full right)
+ if(offset == 1)
+ m_voice[m_current_voice].pan_position = data & 0x0f;
+ logerror("GUS: Ch%i Pan Position write %02x\n", m_current_voice, data);
+ break;
+ case 0x0d: // Volume Ramp control
+/* bit 1 - set to 1 to stop the ramp
+ * bit 2 - roll over condition (generate IRQ, and not stop playing voice, no looping)
+ * bit 3 - enable looping
+ * bit 4 - enable bi-directional looping
+ * bit 5 - rnable IRQ at end of ramp */
+ if(offset == 1)
+ {
+ m_voice[m_current_voice].vol_ramp_ctrl = data & 0x7f;
+ if(!(data & 0x01))
+ {
+ m_voice[m_current_voice].vol_count = 0;
+ if(m_voice[m_current_voice].vol_ramp_ctrl & 0x40)
+ m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].vol_ramp_end << 8);
+ else
+ m_voice[m_current_voice].current_vol = (m_voice[m_current_voice].vol_ramp_start << 8);
+ }
+ if(data & 0x02)
+ {
+ m_voice[m_current_voice].vol_ramp_ctrl |= 0x01;
+ }
+ }
+ logerror("GUS: Ch%i Volume Ramp control write %02x\n", m_current_voice, data);
+ break;
+ case 0x0e: // Active voices (6 bits, high 2 bits are always 1)
+ if(offset == 1)
+ {
+ m_active_voices = data & 0x3f;
+ if((data & 0x3f) < 14)
+ m_active_voices = 14;
+ if((data & 0x3f) > 32)
+ m_active_voices = 32;
+ m_stream->set_sample_rate(rate_table[m_active_voices]);
+ m_voltimer->adjust(attotime::zero,0,attotime::from_usec(1000/(1.6*m_active_voices)));
+ }
+ logerror("GUS: Active Voices write %02x (%i Hz)\n", data, rate_table[m_active_voices]);
+ break;
+ case 0x41:
+/* bit 0 - Enable the DMA channel.
+ * bit 1 - DMA transfer direction (1 = read from the GUS)
+ * bit 2 - DMA channel width (0=8-bit, 1=16-bit)
+ * bits 3,4 - DMA rate divider
+ * bit 5 - DMA terminal count IRQ enable
+ * bit 6 - DMA terminal count IRQ pending (read), Data size (write, 0=8bit, 1=16-bit, independant of channel size)
+ * bit 7 - Invert MSB of data
+ */
+ if(offset == 1)
+ {
+ m_dma_dram_ctrl = data & 0xbf;
+ m_dma_16bit = data & 0x40;
+ if(data & 0x01)
+ {
+ m_dmatimer->adjust(attotime::zero,0,attotime::from_nsec(11489)); // based on 680Kb/sec mentioned in UltraMID docs
+ logerror("GUS: DMA start from DRAM address 0x%05x\n",m_dma_start_addr<<4);
+ }
+ else
+ {
+ m_dmatimer->reset(); // stop transfer
+ logerror("GUS: DMA aborted.\n");
+ }
+ }
+ logerror("GUS: DMA DRAM control write %02x\n",data);
+ break;
+ case 0x42: // DMA start address (high 16 bits, address lines 4-19)
+ if(offset == 0)
+ m_dma_start_addr = (m_dma_start_addr & 0xff00) | data;
+ else
+ m_dma_start_addr = (m_dma_start_addr & 0x00ff) | (data << 8);
+ m_dma_current = m_dma_start_addr << 4;
+ logerror("GUS: DMA start address set to %08x\n",m_dma_start_addr);
+ break;
+ case 0x43: // DRAM I/O address (low 16 bits)
+ if(offset == 0)
+ m_dram_addr = (m_dram_addr & 0x000fff00) | data;
+ else
+ m_dram_addr = (m_dram_addr & 0x000f00ff) | (data << 8);
+ //logerror("GUS: [low] DRAM I/O address set to %08x\n",m_dram_addr);
+ break;
+ case 0x44: // DRAM I/O address (high 4 bits)
+ if(offset == 1)
+ m_dram_addr = (m_dram_addr & 0x0000ffff) | (data << 16);
+ //logerror("GUS: [high] DRAM I/O address set to %08x\n",m_dram_addr);
+ break;
+ case 0x45: // Timer control
+/* bit 3 - Enable timer 1 IRQ
+ * bit 4 - Enable timer 2 IRQ */
+ if(offset == 1)
+ {
+ m_timer_ctrl = data;
+ if(!(data & 0x20))
+ m_adlib_status &= ~0x18;
+ if(!(data & 0x02))
+ m_adlib_status &= ~0x01;
+ if(!(m_adlib_status & 0x19))
+ m_sb_irq_func(0);
+ if(!(data & 0x04))
+ {
+ m_adlib_status &= ~0x40;
+ m_timer1_irq_func(0);
+ }
+ if(!(data & 0x08))
+ {
+ m_adlib_status &= ~0x20;
+ m_timer2_irq_func(0);
+ }
+ if((m_adlib_status & 0x60) != 0)
+ m_adlib_status &= ~0x80;
+ }
+ logerror("GUS: Timer control write %02x\n",data);
+ break;
+ case 0x46: // Timer 1 count
+ if(offset == 1)
+ {
+ m_timer1_count = data;
+ m_timer1_value = data;
+ logerror("GUS: Timer 1 count write %02x\n",data);
+ }
+ break;
+ case 0x47: // Timer 2 count
+ if(offset == 1)
+ {
+ m_timer2_count = data;
+ m_timer2_value = data;
+ logerror("GUS: Timer 2 count write %02x\n",data);
+ }
+ break;
+ case 0x48: // Sampling Frequency - 9878400/(16*(FREQ+2))
+ if(offset == 0)
+ m_sampling_freq = (m_sampling_freq & 0xff00) | data;
+ else
+ m_sampling_freq = (m_sampling_freq & 0x00ff) | (data << 8);
+ logerror("GUS: Sampling frequency write %02x\n",data);
+ break;
+ case 0x49: // Sampling control
+/* bit 0 - Start sampling
+ * bit 1 - Mode (0=mono, 1=stereo)
+ * bit 2 - DMA width (0=8-bit, 1=16-bit)
+ * bit 5 - DMA IRQ enable
+ * bit 6 - DMA IRQ pending (read only)
+ * bit 7 - Invert MSB */
+ if(offset == 1)
+ m_sampling_ctrl = data;
+ logerror("GUS: Sampling control write %02x\n",data);
+ break;
+ case 0x4b: // Joystick trim DAC
+ if(offset == 1)
+ m_joy_trim_dac = data;
+ logerror("GUS: Joystick trim DAC write %02x\n",data);
+ break;
+ case 0x4c: // Reset
+ if(offset == 1)
+ {
+ if(!(data & 0x01))
+ device_reset();
+ m_reset = data & 0xf9;
+ }
+ logerror("GUS: Reset write %02x\n",data);
+ break;
+ default:
+ logerror("GUS: Write %02x to unimplemented or unknown global register %02x\n",data,m_current_reg);
+ }
+}
+
+/* port 0x3X7 - DRAM I/O
+ * read and write bytes directly to wavetable DRAM */
+READ8_MEMBER(gf1_device::dram_r)
+{
+ if(offset == 1)
+ {
+ return m_wave_ram[m_dram_addr & 0xfffff];
+ }
+ else
+ return 0xff;
+}
+
+WRITE8_MEMBER(gf1_device::dram_w)
+{
+ if(offset == 1)
+ {
+ m_wave_ram[m_dram_addr & 0xfffff] = data;
+ }
+}
+
+/* port 2XA - read selected adlib command?
+ * the GUS driver installation writes 0x55 to port 0x388, then expects to reads the same from 0x2XA */
+READ8_MEMBER(gf1_device::adlib_cmd_r)
+{
+ if(offset == 0)
+ {
+ return m_adlib_cmd;
+ }
+ else
+ {
+ // TODO
+ return 0xff;
+ }
+}
+
+/* port 0x2XB - set IRQ/DMA latch
+ * if IRQ (bit 6 of 0x2X0 = 1)
+ * bits 2-0 = channel 1 (GF1) IRQ selector
+ * 0 = reserved, 1 = IRQ2, 2 = IRQ5, 3 = IRQ3, 4 = IRQ7, 5 = IRQ11, 6 = IRQ12, 7 = IRQ13
+ * bits 5-3 = channel 2 (MIDI) IRQ selector
+ * 0 = No interrupt selected, rest are as for the GF1
+ * bit 6 = combine both IRQs using channel 1 IRQ
+ * if DMA (bit 6 of 0x2X0 = 0)
+ * bits 2-0 = DMA select register 1
+ * 0 = No DMA, 1 = DMA1, 2 = DMA3, 3 = DMA5, 4 = DMA6, 5 = DMA7
+ * bits 5-3 = DMA select register 2 (values same as reg 1)
+ * bit 6 = combine both on same DMA channel
+ */
+WRITE8_MEMBER(gf1_device::adlib_cmd_w)
+{
+ if(offset == 1)
+ {
+ switch(m_reg_ctrl & 0x07)
+ {
+ case 0x00:
+ if(m_mix_ctrl & 0x40)
+ {
+ switch(data & 0x07)
+ {
+ case 1:
+ m_gf1_irq = 2;
+ break;
+ case 2:
+ m_gf1_irq = 5;
+ break;
+ case 3:
+ m_gf1_irq = 3;
+ break;
+ case 4:
+ m_gf1_irq = 7;
+ break;
+ case 5:
+ m_gf1_irq = 11;
+ break;
+ case 6:
+ m_gf1_irq = 12;
+ break;
+ case 7:
+ m_gf1_irq = 15;
+ break;
+ default:
+ m_gf1_irq = 0;
+ logerror("GUS: Invalid GF1 IRQ set! [%02x]\n",data);
+ }
+ switch((data >> 3) & 0x07)
+ {
+ case 0:
+ m_midi_irq = 0;
+ break;
+ case 1:
+ m_midi_irq = 2;
+ break;
+ case 2:
+ m_midi_irq = 5;
+ break;
+ case 3:
+ m_midi_irq = 3;
+ break;
+ case 4:
+ m_midi_irq = 7;
+ break;
+ case 5:
+ m_midi_irq = 11;
+ break;
+ case 6:
+ m_midi_irq = 12;
+ break;
+ case 7:
+ m_midi_irq = 15;
+ break;
+ default:
+ logerror("GUS: Invalid MIDI IRQ set! [%02x]\n",data);
+ }
+ if(data & 0x40)
+ m_irq_combine = 1;
+ else
+ m_irq_combine = 0;
+ logerror("GUS: IRQs set: GF1 = IRQ%i, MIDI = IRQ%i\n",m_gf1_irq,m_midi_irq);
+ }
+ else
+ {
+ switch(data & 0x07)
+ {
+ case 0:
+ m_dma_channel1 = 0;
+ break;
+ case 1:
+ m_dma_channel1 = 1;
+ break;
+ case 2:
+ m_dma_channel1 = 3;
+ break;
+ case 3:
+ m_dma_channel1 = 5;
+ break;
+ case 4:
+ m_dma_channel1 = 6;
+ break;
+ case 5:
+ m_dma_channel1 = 7;
+ break;
+ default:
+ logerror("GUS: Invalid DMA channel #1 set! [%02x]\n",data);
+ }
+ switch((data >> 3) & 0x07)
+ {
+ case 0:
+ m_dma_channel2 = 0;
+ break;
+ case 1:
+ m_dma_channel2 = 1;
+ break;
+ case 2:
+ m_dma_channel2 = 3;
+ break;
+ case 3:
+ m_dma_channel2 = 5;
+ break;
+ case 4:
+ m_dma_channel2 = 6;
+ break;
+ case 5:
+ m_dma_channel2 = 7;
+ break;
+ default:
+ logerror("GUS: Invalid DMA channel #2 set! [%02x]\n",data);
+ }
+ if(data & 0x40)
+ m_dma_combine = 1;
+ else
+ m_dma_combine = 0;
+ logerror("GUS: DMA channels set: DMA%i, DMA%i\n",m_dma_channel1,m_dma_channel2);
+ }
+ break;
+ case 0x05:
+ m_statread = 0;
+ //m_other_irq_func(0);
+ break;
+ case 0x06:
+ // TODO: Jumper register (joy/MIDI enable)
+ break;
+ }
+ }
+ else
+ {
+ m_fake_adlib_status = data;
+ logerror("GUS: Adlib status set to %02x\n",data);
+ }
+}
+
+/* port 0x2X0 - Mix control register
+ * bit 0 - 0=Enable Line In
+ * bit 1 - 0=Enable Line Out
+ * bit 2 - 1=Enable MIC In
+ * bit 3 - Enable latches (once enabled, must remain enabled)
+ * bit 4 - Combine GF1 IRQs with MIDI IRQs
+ * bit 5 - Enable MIDI TxD to RxD loopback
+ * bit 6 - Control Reg Select - set next I/O write to 0x2XB to be DMA (0) or IRQ (1) channel latches */
+READ8_MEMBER(gf1_device::mix_ctrl_r)
+{
+ return 0xff; // read only
+}
+
+WRITE8_MEMBER(gf1_device::mix_ctrl_w)
+{
+ if(offset == 0)
+ m_mix_ctrl = data;
+}
+
+READ8_MEMBER(gf1_device::sb_r)
+{
+ UINT8 val;
+
+ switch(offset)
+ {
+ case 0x00:
+ val = m_sb_data_2xc;
+ if(m_statread & 0x20)
+ m_sb_data_2xc ^= 0x80; // flip MSB on read
+ return val;
+ // port 0x2XD is write-only
+ case 0x02:
+ if(m_reg_ctrl & 0x80)
+ {
+ m_statread |= 0x80;
+ m_nmi_func(1);
+ }
+ return m_sb_data_2xe;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(gf1_device::sb_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+ if(m_timer_ctrl & 0x20)
+ {
+ m_adlib_status |= 0x10;
+ m_nmi_func(1);
+ logerror("GUS: SB 0x2XC IRQ active\n");
+ }
+ break;
+ case 0x01:
+ m_sb_data_2xc = data;
+ break;
+ case 0x02:
+ m_sb_data_2xe = data;
+ break;
+ }
+}
+
+WRITE8_MEMBER(gf1_device::sb2x6_w)
+{
+ if(offset==0)
+ {
+ if(m_timer_ctrl & 0x20)
+ {
+ m_adlib_status |= 0x08;
+ m_nmi_func(1);
+ logerror("GUS: SB 0x2X6 IRQ active\n");
+ }
+ }
+}
+
+READ8_MEMBER(gf1_device::stat_r)
+{
+ UINT8 val = m_statread & 0xf9;
+ if(m_mix_ctrl & 0x08)
+ val |= 0x02;
+ return val;
+}
+
+WRITE8_MEMBER(gf1_device::stat_w)
+{
+ m_reg_ctrl = data;
+}
+
+void gf1_device::set_irq(UINT8 source, UINT8 voice)
+{
+ if(source & IRQ_WAVETABLE)
+ {
+ m_irq_source = 0xe0 | (voice & 0x1f);
+ m_irq_source &= ~0x80;
+ m_wave_irq_func(1);
+ m_voice_irq_fifo[m_voice_irq_ptr % 32] = m_irq_source;
+ m_voice_irq_ptr++;
+ m_voice[voice].voice_ctrl |= 0x80;
+ }
+ if(source & IRQ_VOLUME_RAMP)
+ {
+ m_irq_source = 0xe0 | (voice & 0x1f);
+ m_irq_source &= ~0x40;
+ m_ramp_irq_func(1);
+ m_voice_irq_fifo[m_voice_irq_ptr % 32] = m_irq_source;
+ m_voice_irq_ptr++;
+ }
+}
+
+void gf1_device::reset_irq(UINT8 source)
+{
+ if(source & IRQ_WAVETABLE)
+ {
+ m_irq_source |= 0x80;
+ m_wave_irq_func(0);
+ }
+ if(source & IRQ_VOLUME_RAMP)
+ {
+ m_irq_source |= 0x40;
+ m_ramp_irq_func(0);
+ }
+}
+
+// TODO: support 16-bit transfers
+UINT8 gf1_device::dack_r(int line)
+{
+ return m_wave_ram[m_dma_current++ & 0xfffff];
+}
+
+void gf1_device::dack_w(int line,UINT8 data)
+{
+ if(m_dma_dram_ctrl & 0x80) // flip data MSB
+ {
+ if(m_dma_16bit != 0) // if data is 16-bit
+ {
+ if((m_dma_current & 1))
+ data ^= 0x80;
+ }
+ else // data is 8-bit
+ {
+ data ^= 0x80;
+ }
+ }
+ m_wave_ram[m_dma_current & 0xfffff] = data;
+ m_dma_current++;
+ m_drq1(0);
+}
+
+void gf1_device::eop_w(int state)
+{
+ if(state == ASSERT_LINE) {
+ // end of transfer
+ m_dmatimer->reset();
+ //m_drq1(0);
+ if(m_dma_dram_ctrl & 0x20)
+ {
+ m_dma_dram_ctrl |= 0x40;
+ m_dma_irq_func(1);
+ }
+ logerror("GUS: End of transfer. (%05x)\n",m_dma_current);
+ }
+}
+
+
+/* 16-bit ISA card device implementation */
+
+static const gf1_interface gus_gf1_config =
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,wavetable_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,volumeramp_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,timer1_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,timer2_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,sb_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,dma_irq),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,drq1_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,drq2_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER,isa16_gus_device,nmi_w)
+};
+
+static MACHINE_CONFIG_FRAGMENT( gus_config )
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker","rspeaker")
+ MCFG_SOUND_ADD("gf1",GGF1,GF1_CLOCK)
+ MCFG_SOUND_CONFIG(gus_gf1_config)
+ MCFG_SOUND_ROUTE(0,"lspeaker",0.50)
+ MCFG_SOUND_ROUTE(1,"rspeaker",0.50)
+
+ MCFG_ACIA6850_TXD_HANDLER(DEVWRITELINE("mdout", midi_port_device, write_txd))
+ MCFG_GF1_TXIRQ_HANDLER(WRITELINE(isa16_gus_device, midi_txirq))
+ MCFG_GF1_RXIRQ_HANDLER(WRITELINE(isa16_gus_device, midi_txirq))
+
+ MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin")
+ MCFG_MIDI_RX_HANDLER(DEVWRITELINE("gf1", acia6850_device, write_rxd))
+
+ MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout")
+
+ MCFG_DEVICE_ADD("acia_clock", CLOCK, 31250*16)
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(isa16_gus_device, write_acia_clock))
+MACHINE_CONFIG_END
+
+static INPUT_PORTS_START( gus_joy )
+ PORT_START("gus_joy")
+ PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // x/y ad stick to digital converters
+ PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("GUS Joystick Button 1")
+ PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("GUS Joystick Button 2")
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("GUS Joystick Button 3")
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("GUS Joystick Button 4")
+
+ PORT_START("gus_joy_1")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_LEFT) PORT_CODE_INC(KEYCODE_RIGHT) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH)
+
+ PORT_START("gus_joy_2")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_UP) PORT_CODE_INC(KEYCODE_DOWN) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH)
+INPUT_PORTS_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_gus_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( gus_config );
+}
+
+ioport_constructor isa16_gus_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( gus_joy );
+}
+
+
+isa16_gus_device::isa16_gus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA16_GUS, "Gravis Ultrasound", tag, owner, clock, "isa_gus", __FILE__),
+ device_isa16_card_interface( mconfig, *this ),
+ m_gf1(*this, "gf1")
+{
+}
+
+void isa16_gus_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x0200, 0x0201, 0, 0, read8_delegate(FUNC(isa16_gus_device::joy_r),this), write8_delegate(FUNC(isa16_gus_device::joy_w),this) );
+ m_isa->install_device(0x0220, 0x022f, 0, 0, read8_delegate(FUNC(isa16_gus_device::board_r),this), write8_delegate(FUNC(isa16_gus_device::board_w),this) );
+ m_isa->install_device(0x0320, 0x0327, 0, 0, read8_delegate(FUNC(isa16_gus_device::synth_r),this), write8_delegate(FUNC(isa16_gus_device::synth_w),this) );
+ m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate(FUNC(isa16_gus_device::adlib_r),this), write8_delegate(FUNC(isa16_gus_device::adlib_w),this) );
+}
+
+void isa16_gus_device::device_reset()
+{
+}
+
+void isa16_gus_device::device_stop()
+{
+}
+
+READ8_MEMBER(isa16_gus_device::board_r)
+{
+ switch(offset)
+ {
+ case 0x00:
+ case 0x01:
+ return m_gf1->mix_ctrl_r(space,offset);
+ /* port 0x2X6 - IRQ status (active high)
+ * bit 0 - MIDI transmit IRQ
+ * bit 1 - MIDI receive IRQ
+ * bit 2 - Timer 1 IRQ
+ * bit 3 - Timer 2 IRQ
+ * bit 4 - reserved (always 0)
+ * bit 5 - wavetable IRQ
+ * bit 6 - volume ramp IRQ
+ * bit 7 - DRAM TC DMA IRQ
+ */
+ case 0x06:
+ return m_irq_status;
+ case 0x08:
+ case 0x09:
+ return m_gf1->adlib_r(space,offset-8);
+ case 0x0a:
+ case 0x0b:
+ return m_gf1->adlib_cmd_r(space,offset-10);
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ return m_gf1->sb_r(space,offset-12);
+ case 0x0f:
+ return m_gf1->stat_r(space,offset-15);
+ default:
+ logerror("GUS: Invalid or unimplemented read of port 0x2X%01x\n",offset);
+ return 0xff;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(isa16_gus_device::board_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+ case 0x01:
+ m_gf1->mix_ctrl_w(space,offset,data);
+ break;
+ case 0x06:
+ m_gf1->sb2x6_w(space,offset-6,data);
+ break;
+ case 0x08:
+ case 0x09:
+ m_gf1->adlib_w(space,offset-8,data);
+ break;
+ case 0x0a:
+ case 0x0b:
+ m_gf1->adlib_cmd_w(space,offset-10,data);
+ break;
+ case 0x0c:
+ case 0x0d:
+ case 0x0e:
+ m_gf1->sb_w(space,offset-12,data);
+ break;
+ case 0x0f:
+ m_gf1->stat_w(space,offset-15,data);
+ break;
+ default:
+ logerror("GUS: Invalid or unimplemented register write %02x of port 0x2X%01x\n",data,offset);
+ }
+}
+
+READ8_MEMBER(isa16_gus_device::synth_r)
+{
+ switch(offset)
+ {
+ case 0x00:
+ return m_gf1->status_r(space,0);
+ case 0x01:
+ return m_gf1->data_r(space,0);
+ case 0x02:
+ case 0x03:
+ return m_gf1->global_reg_select_r(space,offset-2);
+ case 0x04:
+ case 0x05:
+ return m_gf1->global_reg_data_r(space,offset-4);
+ case 0x06:
+ case 0x07:
+ return m_gf1->dram_r(space,offset-6);
+ default:
+ logerror("GUS: Invalid or unimplemented register read of port 0x3X%01x\n",offset);
+ return 0xff;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(isa16_gus_device::synth_w)
+{
+ switch(offset)
+ {
+ case 0x00:
+ m_gf1->control_w(space,0,data);
+ break;
+ case 0x01:
+ m_gf1->data_w(space,0,data);
+ break;
+ case 0x02:
+ case 0x03:
+ m_gf1->global_reg_select_w(space,offset-2,data);
+ break;
+ case 0x04:
+ case 0x05:
+ m_gf1->global_reg_data_w(space,offset-4,data);
+ break;
+ case 0x06:
+ case 0x07:
+ m_gf1->dram_w(space,offset-6,data);
+ break;
+ default:
+ logerror("GUS: Invalid or unimplemented register write %02x of port 0x3X%01x\n",data,offset);
+ }
+}
+
+READ8_MEMBER(isa16_gus_device::adlib_r)
+{
+ return m_gf1->adlib_r(space,offset);
+}
+
+WRITE8_MEMBER(isa16_gus_device::adlib_w)
+{
+ m_gf1->adlib_w(space,offset,data);
+}
+
+READ8_MEMBER(isa16_gus_device::joy_r)
+{
+ if(offset == 1)
+ {
+ UINT8 data = 0;
+ int delta;
+ attotime new_time = machine().time();
+
+ {
+ data = ioport("gus_joy")->read() | 0x0f;
+
+ {
+ delta = ((new_time - m_joy_time) * 256 * 1000).seconds;
+
+ if (ioport("gus_joy_1")->read() < delta) data &= ~0x01;
+ if (ioport("gus_joy_2")->read() < delta) data &= ~0x02;
+ }
+ }
+ return data;
+ }
+ return 0xff;
+}
+
+WRITE8_MEMBER(isa16_gus_device::joy_w)
+{
+ m_joy_time = machine().time();
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::wavetable_irq)
+{
+ if(state)
+ set_irq(IRQ_WAVETABLE);
+ else
+ reset_irq(IRQ_WAVETABLE);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::volumeramp_irq)
+{
+ if(state)
+ set_irq(IRQ_VOLUME_RAMP);
+ else
+ reset_irq(IRQ_VOLUME_RAMP);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::timer1_irq)
+{
+ if(state)
+ set_irq(IRQ_TIMER1);
+ else
+ reset_irq(IRQ_TIMER1);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::timer2_irq)
+{
+ if(state)
+ set_irq(IRQ_TIMER2);
+ else
+ reset_irq(IRQ_TIMER2);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::dma_irq)
+{
+ if(state)
+ set_irq(IRQ_DRAM_TC_DMA);
+ else
+ reset_irq(IRQ_DRAM_TC_DMA);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::sb_irq)
+{
+ if(state)
+ set_midi_irq(IRQ_SB);
+ else
+ reset_midi_irq(IRQ_SB);
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::drq1_w)
+{
+ m_isa->set_dma_channel(m_gf1->dma_channel1(), this, TRUE);
+ switch(m_gf1->dma_channel1())
+ {
+ case 1:
+ m_isa->drq1_w(state);
+ break;
+ case 3:
+ m_isa->drq3_w(state);
+ break;
+ case 5:
+ m_isa->drq5_w(state);
+ break;
+ case 6:
+ m_isa->drq6_w(state);
+ break;
+ case 7:
+ m_isa->drq7_w(state);
+ break;
+ default:
+ logerror("GUS: Invalid DMA channel %i, ignoring.\n",m_gf1->dma_channel1());
+ }
+}
+
+WRITE_LINE_MEMBER(isa16_gus_device::drq2_w)
+{
+ m_isa->set_dma_channel(m_gf1->dma_channel2(), this, TRUE);
+ switch(m_gf1->dma_channel2())
+ {
+ case 1:
+ m_isa->drq1_w(state);
+ break;
+ case 3:
+ m_isa->drq3_w(state);
+ break;
+ case 5:
+ m_isa->drq5_w(state);
+ break;
+ case 6:
+ m_isa->drq6_w(state);
+ break;
+ case 7:
+ m_isa->drq7_w(state);
+ break;
+ default:
+ logerror("GUS: Invalid DMA channel %i, ignoring.\n",m_gf1->dma_channel2());
+ }
+}
+
+void isa16_gus_device::set_irq(UINT8 source)
+{
+ m_irq_status |= source;
+
+ switch(m_gf1->gf1_irq())
+ {
+ case 2:
+ m_isa->irq2_w(1);
+ break;
+ case 3:
+ m_isa->irq3_w(1);
+ break;
+ case 5:
+ m_isa->irq5_w(1);
+ break;
+ case 7:
+ m_isa->irq7_w(1);
+ break;
+ case 11:
+ m_isa->irq11_w(1);
+ break;
+ case 12:
+ m_isa->irq12_w(1);
+ break;
+ case 15:
+ m_isa->irq15_w(1);
+ break;
+ }
+ logerror("GUS: Set IRQ %02x\n",source);
+}
+
+void isa16_gus_device::reset_irq(UINT8 source)
+{
+ m_irq_status &= ~source;
+
+ switch(m_gf1->gf1_irq())
+ {
+ case 2:
+ m_isa->irq2_w(0);
+ break;
+ case 3:
+ m_isa->irq3_w(0);
+ break;
+ case 5:
+ m_isa->irq5_w(0);
+ break;
+ case 7:
+ m_isa->irq7_w(0);
+ break;
+ case 11:
+ m_isa->irq11_w(0);
+ break;
+ case 12:
+ m_isa->irq12_w(0);
+ break;
+ case 15:
+ m_isa->irq15_w(0);
+ break;
+ }
+ logerror("GUS: Reset IRQ %02x\n",source);
+}
+
+void isa16_gus_device::set_midi_irq(UINT8 source)
+{
+ m_irq_status |= source;
+
+ switch(m_gf1->midi_irq())
+ {
+ case 2:
+ m_isa->irq2_w(1);
+ break;
+ case 3:
+ m_isa->irq3_w(1);
+ break;
+ case 5:
+ m_isa->irq5_w(1);
+ break;
+ case 7:
+ m_isa->irq7_w(1);
+ break;
+ case 11:
+ m_isa->irq11_w(1);
+ break;
+ case 12:
+ m_isa->irq12_w(1);
+ break;
+ case 15:
+ m_isa->irq15_w(1);
+ break;
+ }
+ logerror("GUS: Set MIDI IRQ %02x\n",source);
+}
+
+void isa16_gus_device::reset_midi_irq(UINT8 source)
+{
+ m_irq_status &= ~source;
+
+ switch(m_gf1->midi_irq())
+ {
+ case 2:
+ m_isa->irq2_w(0);
+ break;
+ case 3:
+ m_isa->irq3_w(0);
+ break;
+ case 5:
+ m_isa->irq5_w(0);
+ break;
+ case 7:
+ m_isa->irq7_w(0);
+ break;
+ case 11:
+ m_isa->irq11_w(0);
+ break;
+ case 12:
+ m_isa->irq12_w(0);
+ break;
+ case 15:
+ m_isa->irq15_w(0);
+ break;
+ }
+ logerror("GUS: Reset MIDI IRQ %02x\n",source);
+}
+
+WRITE_LINE_MEMBER( isa16_gus_device::midi_txirq )
+{
+ if (state)
+ set_midi_irq(IRQ_MIDI_TRANSMIT);
+ else
+ reset_midi_irq(IRQ_MIDI_TRANSMIT | IRQ_MIDI_RECEIVE);
+}
+
+WRITE_LINE_MEMBER( isa16_gus_device::midi_rxirq )
+{
+ if (state)
+ set_midi_irq(IRQ_MIDI_RECEIVE);
+ else
+ reset_midi_irq(IRQ_MIDI_TRANSMIT | IRQ_MIDI_RECEIVE);
+}
+
+WRITE_LINE_MEMBER( isa16_gus_device::write_acia_clock )
+{
+ m_gf1->write_txc(state);
+ m_gf1->write_rxc(state);
+}
+
+WRITE_LINE_MEMBER( isa16_gus_device::nmi_w)
+{
+ m_irq_status |= IRQ_SB;
+ m_isa->nmi();
+}
+
+UINT8 isa16_gus_device::dack_r(int line)
+{
+ if(line == m_gf1->dma_channel1())
+ return m_gf1->dack_r(line);
+ else
+ return 0;
+}
+
+void isa16_gus_device::dack_w(int line,UINT8 data)
+{
+ if(line == m_gf1->dma_channel1())
+ m_gf1->dack_w(line,data);
+}
+
+void isa16_gus_device::eop_w(int state)
+{
+ m_gf1->eop_w(state);
+}
diff --git a/src/emu/bus/isa/gus.h b/src/emu/bus/isa/gus.h
new file mode 100644
index 00000000000..01e63685874
--- /dev/null
+++ b/src/emu/bus/isa/gus.h
@@ -0,0 +1,301 @@
+/*
+ * Gravis Ultrasound ISA card
+ *
+ * Started: 28/01/2012
+ *
+ * I/O port map (info from the Gravis Ultrasound SDK documentation):
+ * Base port is 0x2X0 - where X is defined by a jumper
+ *
+ * MIDI:
+ * 0x3X0 - MIDI Control (read), MIDI Status (write)
+ * 0x3X1 - MIDI Transmit (write), MIDI Receive (read)
+ * MIDI operates identically to a 6850 UART
+ *
+ * Joystick:
+ * 0x201 - Joystick trigger timer (write), Joystick data (read)
+ *
+ * GF1 Synthesiser:
+ * 0x3X2 - Page register (voice select)
+ * 0x3X3 - Global Register select
+ * 0x3X4 - Global Data (low byte)
+ * 0x3X5 - Global Data (high byte)
+ * 0x2X6 - IRQ status register (read only, active high)
+ * 0x2X8 - Timer control register
+ * 0x2X9 - Timer data
+ * 0x3X7 - DRAM data (can be via DMA also)
+ *
+ * Board:
+ * 0x2X0: Mix control register (write only)
+ * 0x2XB: IRQ/DMA control register (write only) - dependant on mix control bit 6
+ * 0x2XF: Register controls (board rev 3.4+ only)
+ * 0x7X6: Board version (read only, board rev 3.7+ only)
+ *
+ * Mixer Control:
+ * 0x7X6: Control port (write only)
+ * 0x3X6: Data port (write only)
+ */
+
+#pragma once
+
+#ifndef __ISA_GUS_H__
+#define __ISA_GUS_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/6850acia.h"
+
+#define MCFG_GF1_TXIRQ_HANDLER(_devcb) \
+ devcb = &gf1_device::set_txirq_handler(*device, DEVCB2_##_devcb);
+
+#define MCFG_GF1_RXIRQ_HANDLER(_devcb) \
+ devcb = &gf1_device::set_rxirq_handler(*device, DEVCB2_##_devcb);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> gf1_device
+
+#define GF1_CLOCK 9878400
+
+#define IRQ_2XF 0x00
+#define IRQ_MIDI_TRANSMIT 0x01
+#define IRQ_MIDI_RECEIVE 0x02
+#define IRQ_TIMER1 0x04
+#define IRQ_TIMER2 0x08
+#define IRQ_SB 0x10
+#define IRQ_WAVETABLE 0x20
+#define IRQ_VOLUME_RAMP 0x40
+#define IRQ_DRAM_TC_DMA 0x80
+
+struct gus_voice
+{
+ UINT8 voice_ctrl;
+ UINT16 freq_ctrl;
+ UINT32 start_addr;
+ UINT32 end_addr;
+ UINT8 vol_ramp_rate;
+ UINT8 vol_ramp_start;
+ UINT8 vol_ramp_end;
+ UINT16 current_vol;
+ UINT32 current_addr;
+ UINT8 pan_position;
+ UINT8 vol_ramp_ctrl;
+ UINT32 vol_count;
+ bool rollover;
+ INT16 sample; // current sample data
+};
+
+struct gf1_interface
+{
+ devcb_write_line wave_irq_cb;
+ devcb_write_line ramp_irq_cb;
+ devcb_write_line timer1_irq_cb;
+ devcb_write_line timer2_irq_cb;
+ devcb_write_line sb_irq_cb;
+ devcb_write_line dma_irq_cb;
+ devcb_write_line drq1_cb;
+ devcb_write_line drq2_cb;
+ devcb_write_line nmi_cb;
+};
+
+class gf1_device :
+ public acia6850_device,
+ public device_sound_interface,
+ public gf1_interface
+{
+public:
+ // construction/destruction
+ gf1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ template<class _Object> static devcb2_base &set_txirq_handler(device_t &device, _Object object) { return downcast<gf1_device &>(device).m_txirq_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_rxirq_handler(device_t &device, _Object object) { return downcast<gf1_device &>(device).m_rxirq_handler.set_callback(object); }
+
+ // current IRQ/DMA channel getters
+ UINT8 gf1_irq() { if(m_gf1_irq != 0) return m_gf1_irq; else return m_midi_irq; } // workaround for win95 loading dumb values
+ UINT8 midi_irq() { if(m_irq_combine == 0) return m_midi_irq; else return m_gf1_irq; }
+ UINT8 dma_channel1() { return m_dma_channel1; }
+ UINT8 dma_channel2() { if(m_dma_combine == 0) return m_dma_channel2; else return m_dma_channel1; }
+
+ DECLARE_READ8_MEMBER(global_reg_select_r);
+ DECLARE_WRITE8_MEMBER(global_reg_select_w);
+ DECLARE_READ8_MEMBER(global_reg_data_r);
+ DECLARE_WRITE8_MEMBER(global_reg_data_w);
+ DECLARE_READ8_MEMBER(dram_r);
+ DECLARE_WRITE8_MEMBER(dram_w);
+ DECLARE_READ8_MEMBER(adlib_r);
+ DECLARE_WRITE8_MEMBER(adlib_w);
+ DECLARE_READ8_MEMBER(adlib_cmd_r);
+ DECLARE_WRITE8_MEMBER(adlib_cmd_w);
+ DECLARE_READ8_MEMBER(mix_ctrl_r);
+ DECLARE_WRITE8_MEMBER(mix_ctrl_w);
+ DECLARE_READ8_MEMBER(stat_r);
+ DECLARE_WRITE8_MEMBER(stat_w);
+ DECLARE_READ8_MEMBER(sb_r);
+ DECLARE_WRITE8_MEMBER(sb_w);
+ DECLARE_WRITE8_MEMBER(sb2x6_w);
+
+ // DMA signals
+ UINT8 dack_r(int line);
+ void dack_w(int line,UINT8 data);
+ void eop_w(int state);
+
+ // optional information overrides
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
+ virtual void device_config_complete();
+
+ // voice-specific registers
+ gus_voice m_voice[32];
+
+ // global registers (not voice-specific)
+ UINT8 m_dma_dram_ctrl;
+ UINT16 m_dma_start_addr;
+ UINT32 m_dram_addr;
+ UINT8 m_timer_ctrl;
+ UINT8 m_timer1_count;
+ UINT8 m_timer2_count;
+ UINT8 m_timer1_value;
+ UINT8 m_timer2_value;
+ UINT16 m_sampling_freq;
+ UINT8 m_sampling_ctrl;
+ UINT8 m_joy_trim_dac;
+ UINT8 m_reset;
+ UINT8 m_active_voices;
+ UINT8 m_irq_source;
+
+ void set_irq(UINT8 source, UINT8 voice);
+ void reset_irq(UINT8 source);
+ void update_volume_ramps();
+
+ UINT8* m_wave_ram;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_stop();
+
+ virtual void update_irq();
+
+ devcb_resolved_write_line m_wave_irq_func;
+ devcb_resolved_write_line m_ramp_irq_func;
+ devcb_resolved_write_line m_timer1_irq_func;
+ devcb_resolved_write_line m_timer2_irq_func;
+ devcb_resolved_write_line m_sb_irq_func;
+ devcb_resolved_write_line m_dma_irq_func;
+ devcb_resolved_write_line m_drq1;
+ devcb_resolved_write_line m_drq2;
+ devcb_resolved_write_line m_nmi_func;
+
+private:
+ // internal state
+ sound_stream* m_stream;
+
+ emu_timer* m_timer1;
+ emu_timer* m_timer2;
+ emu_timer* m_dmatimer;
+ emu_timer* m_voltimer;
+
+ UINT8 m_current_voice;
+ UINT8 m_current_reg;
+ //UINT8 m_port;
+ //UINT8 m_irq;
+ //UINT8 m_dma;
+
+ UINT8 m_adlib_cmd;
+ UINT8 m_mix_ctrl;
+ UINT8 m_gf1_irq;
+ UINT8 m_midi_irq;
+ UINT8 m_dma_channel1;
+ UINT8 m_dma_channel2;
+ UINT8 m_irq_combine;
+ UINT8 m_dma_combine;
+ UINT8 m_adlib_timer_cmd;
+ UINT8 m_adlib_timer1_enable;
+ UINT8 m_adlib_timer2_enable;
+ UINT8 m_adlib_status;
+ UINT8 m_adlib_data;
+ UINT8 m_voice_irq_fifo[32];
+ UINT8 m_voice_irq_ptr;
+ UINT8 m_voice_irq_current;
+ UINT8 m_dma_16bit; // set by bit 6 of the DMA DRAM control reg
+ UINT8 m_statread;
+ UINT8 m_sb_data_2xc;
+ UINT8 m_sb_data_2xe;
+ UINT8 m_reg_ctrl;
+ UINT8 m_fake_adlib_status;
+ UINT32 m_dma_current;
+ UINT16 m_volume_table[4096];
+
+ static const device_timer_id ADLIB_TIMER1 = 0;
+ static const device_timer_id ADLIB_TIMER2 = 1;
+ static const device_timer_id DMA_TIMER = 2;
+ static const device_timer_id VOL_RAMP_TIMER = 3;
+
+ int m_txirq;
+ int m_rxirq;
+
+ devcb2_write_line m_txirq_handler;
+ devcb2_write_line m_rxirq_handler;
+};
+
+class isa16_gus_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ isa16_gus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ void set_irq(UINT8 source);
+ void reset_irq(UINT8 source);
+ void set_midi_irq(UINT8 source);
+ void reset_midi_irq(UINT8 source);
+
+ DECLARE_READ8_MEMBER(board_r);
+ DECLARE_READ8_MEMBER(synth_r);
+ DECLARE_WRITE8_MEMBER(board_w);
+ DECLARE_WRITE8_MEMBER(synth_w);
+ DECLARE_READ8_MEMBER(adlib_r);
+ DECLARE_WRITE8_MEMBER(adlib_w);
+ DECLARE_READ8_MEMBER(joy_r);
+ DECLARE_WRITE8_MEMBER(joy_w);
+ DECLARE_WRITE_LINE_MEMBER(midi_txirq);
+ DECLARE_WRITE_LINE_MEMBER(midi_rxirq);
+ DECLARE_WRITE_LINE_MEMBER(wavetable_irq);
+ DECLARE_WRITE_LINE_MEMBER(volumeramp_irq);
+ DECLARE_WRITE_LINE_MEMBER(timer1_irq);
+ DECLARE_WRITE_LINE_MEMBER(timer2_irq);
+ DECLARE_WRITE_LINE_MEMBER(sb_irq);
+ DECLARE_WRITE_LINE_MEMBER(dma_irq);
+ DECLARE_WRITE_LINE_MEMBER(drq1_w);
+ DECLARE_WRITE_LINE_MEMBER(drq2_w);
+ DECLARE_WRITE_LINE_MEMBER(nmi_w);
+ DECLARE_WRITE_LINE_MEMBER(write_acia_clock);
+
+ // DMA overrides
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line,UINT8 data);
+ virtual void eop_w(int state);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_stop();
+
+private:
+ required_device<gf1_device> m_gf1;
+
+ UINT8 m_irq_status;
+ attotime m_joy_time;
+};
+
+// device type definition
+extern const device_type GGF1;
+extern const device_type ISA16_GUS;
+
+#endif /* __ISA_GUS_H__ */
diff --git a/src/emu/bus/isa/hdc.c b/src/emu/bus/isa/hdc.c
new file mode 100644
index 00000000000..658f9e857ad
--- /dev/null
+++ b/src/emu/bus/isa/hdc.c
@@ -0,0 +1,827 @@
+/**********************************************************************
+
+ ISA 8 bit XT Hard Disk Controller
+
+**********************************************************************/
+
+#include "emu.h"
+#include "hdc.h"
+
+#define LOG_HDC_STATUS 0
+#define LOG_HDC_CALL 0
+#define LOG_HDC_DATA 0
+
+#define CMD_TESTREADY 0x00
+#define CMD_RECALIBRATE 0x01
+#define CMD_SENSE 0x03
+#define CMD_FORMATDRV 0x04
+#define CMD_VERIFY 0x05
+#define CMD_FORMATTRK 0x06
+#define CMD_FORMATBAD 0x07
+#define CMD_READ 0x08
+#define CMD_WRITE 0x0a
+#define CMD_SEEK 0x0b
+
+#define CMD_SETPARAM 0x0c
+#define CMD_GETECC 0x0d
+
+#define CMD_READSBUFF 0x0e
+#define CMD_WRITESBUFF 0x0f
+
+#define CMD_RAMDIAG 0xe0
+#define CMD_DRIVEDIAG 0xe3
+#define CMD_INTERNDIAG 0xe4
+#define CMD_READLONG 0xe5
+#define CMD_WRITELONG 0xe6
+
+/* Bits for command status byte */
+#define CSB_ERROR 0x02
+#define CSB_LUN 0x20
+
+/* XT hard disk controller status bits */
+#define STA_READY 0x01
+#define STA_INPUT 0x02
+#define STA_COMMAND 0x04
+#define STA_SELECT 0x08
+#define STA_REQUEST 0x10
+#define STA_INTERRUPT 0x20
+
+/* XT hard disk controller control bits */
+#define CTL_PIO 0x00
+#define CTL_DMA 0x01
+
+static const char *const hdc_command_names[] =
+{
+ "CMD_TESTREADY", /* 0x00 */
+ "CMD_RECALIBRATE", /* 0x01 */
+ NULL, /* 0x02 */
+ "CMD_SENSE", /* 0x03 */
+ "CMD_FORMATDRV", /* 0x04 */
+ "CMD_VERIFY", /* 0x05 */
+ "CMD_FORMATTRK", /* 0x06 */
+ "CMD_FORMATBAD", /* 0x07 */
+ "CMD_READ", /* 0x08 */
+ NULL, /* 0x09 */
+ "CMD_WRITE", /* 0x0A */
+ "CMD_SEEK", /* 0x0B */
+ "CMD_SETPARAM", /* 0x0C */
+ "CMD_GETECC", /* 0x0D */
+ "CMD_READSBUFF", /* 0x0E */
+ "CMD_WRITESBUFF", /* 0x0F */
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x10-0x17 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x18-0x1F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x20-0x27 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x28-0x2F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x30-0x37 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x38-0x3F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x40-0x47 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x48-0x4F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x50-0x57 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x58-0x5F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x60-0x67 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x68-0x6F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x70-0x77 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x78-0x7F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x80-0x87 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x88-0x8F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x90-0x97 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0x98-0x9F */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA0-0xA7 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xA8-0xAF */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB0-0xB7 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xB8-0xBF */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC0-0xC7 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xC8-0xCF */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD0-0xD7 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xD8-0xDF */
+
+ "CMD_RAMDIAG", /* 0xE0 */
+ NULL, /* 0xE1 */
+ NULL, /* 0xE2 */
+ "CMD_DRIVEDIAG", /* 0xE3 */
+ "CMD_INTERNDIAG", /* 0xE4 */
+ "CMD_READLONG", /* 0xE5 */
+ "CMD_WRITELONG", /* 0xE6 */
+ NULL, /* 0xE7 */
+
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xE8-0xEF */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, /* 0xF0-0xF7 */
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL /* 0xF8-0xFF */
+};
+
+static DECLARE_READ8_DEVICE_HANDLER(pc_HDC_r);
+static DECLARE_WRITE8_DEVICE_HANDLER(pc_HDC_w);
+
+static MACHINE_CONFIG_FRAGMENT( hdc_config )
+ MCFG_HARDDISK_ADD("primary")
+ MCFG_HARDDISK_ADD("slave")
+MACHINE_CONFIG_END
+
+ROM_START( hdc )
+ ROM_REGION(0x02000,"hdc", 0)
+ // Bios taken from WD1002A-WX1
+ ROM_LOAD("wdbios.rom", 0x00000, 0x02000, CRC(8e9e2bd4) SHA1(601d7ceab282394ebab50763c267e915a6a2166a)) /* WDC IDE Superbios 2.0 (06/28/89) Expansion Rom C8000-C9FFF */
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_HDC = &device_creator<isa8_hdc_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_hdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( hdc_config );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_hdc_device::device_rom_region() const
+{
+ return ROM_NAME( hdc );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_hdc_device - constructor
+//-------------------------------------------------
+
+isa8_hdc_device::isa8_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_HDC, "Fixed Disk Controller Card", tag, owner, clock, "hdc", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_hdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc");
+ m_isa->install_device(this, 0x0320, 0x0323, 0, 0, FUNC(pc_HDC_r), FUNC(pc_HDC_w) );
+ m_isa->set_dma_channel(3, this, FALSE);
+ buffer = auto_alloc_array(machine(), UINT8, 17*4*512);
+ timer = machine().scheduler().timer_alloc(FUNC(pc_hdc_command), this);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_hdc_device::device_reset()
+{
+ drv = 0;
+ data_cnt = 0;
+ buffer_ptr = NULL;
+ hdc_control = 0;
+ for (int i = 0; i < 2; i++)
+ {
+ cylinders[i] = 612;
+ rwc[i] = 613;
+ wp[i] = 613;
+ heads[i] = 4;
+ ecc[i] = 11;
+
+ /* indexes */
+ cylinder[i] = 0;
+ head[i] = 0;
+ sector[i] = 0;
+ sector_cnt[i] = 0;
+ control[i] = 0;
+ }
+
+ csb = 0;
+ status = 0;
+ error = 0;
+ dip = 0xff;
+
+}
+
+hard_disk_file *isa8_hdc_device::pc_hdc_file(int id)
+{
+ harddisk_image_device *img = NULL;
+ astring tempstring;
+ switch( id )
+ {
+ case 0:
+ img = dynamic_cast<harddisk_image_device *>(machine().device(subtag(tempstring,"primary")));
+ break;
+ case 1:
+ img = dynamic_cast<harddisk_image_device *>(machine().device(subtag(tempstring,"slave")));
+ break;
+ }
+ if ( img == NULL )
+ return NULL;
+
+ if (!img->exists())
+ return NULL;
+
+ return img->get_hard_disk_file();
+}
+
+void isa8_hdc_device::pc_hdc_result(int set_error_info)
+{
+ if ( ( hdc_control & 0x02 )) {
+ // dip switch selected IRQ 5 or 2
+ if (BIT(dip, 6))
+ m_isa->irq5_w(1);
+ else
+ m_isa->irq2_w(1);
+ }
+
+ if (LOG_HDC_STATUS)
+ logerror("pc_hdc_result(): $%02x to $%04x\n", csb, data_cnt);
+
+ buffer[data_cnt++] = csb;
+
+ if (set_error_info && ( csb & CSB_ERROR ) )
+ {
+ buffer[data_cnt++] = error;
+ if (error & 0x80)
+ {
+ buffer[data_cnt++] = (drv << 5) | head[drv];
+ buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv];
+ buffer[data_cnt++] = cylinder[drv] & 0xff;
+
+ if (LOG_HDC_STATUS)
+ {
+ logerror("pc_hdc_result(): result [%02x %02x %02x %02x]\n",
+ buffer[data_cnt-4], buffer[data_cnt-3], buffer[data_cnt-2], buffer[data_cnt-1]);
+ }
+ }
+ else
+ {
+ if (LOG_HDC_STATUS)
+ logerror("pc_hdc_result(): result [%02x]\n", buffer[data_cnt-1]);
+ }
+ }
+ status |= STA_INTERRUPT | STA_INPUT | STA_REQUEST | STA_COMMAND | STA_READY;
+}
+
+
+
+int isa8_hdc_device::no_dma(void)
+{
+ return (hdc_control & CTL_DMA) == 0;
+}
+
+
+
+int isa8_hdc_device::get_lbasector()
+{
+ hard_disk_info *info;
+ hard_disk_file *file;
+ int lbasector;
+
+ file = pc_hdc_file(drv);
+ info = hard_disk_get_info(file);
+
+ lbasector = cylinder[drv];
+ lbasector *= info->heads;
+ lbasector += head[drv];
+ lbasector *= info->sectors;
+ lbasector += sector[drv];
+ return lbasector;
+}
+
+
+
+/********************************************************************
+ *
+ * Read a number of sectors to the address set up for DMA chan #3
+ *
+ ********************************************************************/
+
+/* the following crap is an abomination; it is a relic of the old crappy DMA
+ * implementation that threw the idea of "emulating the hardware" to the wind
+ */
+
+int isa8_hdc_device::pc_hdc_dack_r()
+{
+ UINT8 result;
+ hard_disk_info *info;
+ hard_disk_file *file;
+
+ file = pc_hdc_file(drv);
+ if (!file)
+ return 0;
+ info = hard_disk_get_info(file);
+
+ if (hdcdma_read == 0)
+ {
+ hard_disk_read(file, get_lbasector(), hdcdma_data);
+ hdcdma_read = 512;
+ hdcdma_size -= 512;
+ hdcdma_src = hdcdma_data;
+ sector[drv]++;
+ }
+
+ result = *(hdcdma_src++);
+
+ if( --hdcdma_read == 0 )
+ {
+ /* end of cylinder ? */
+ if (sector[drv] >= info->sectors)
+ {
+ sector[drv] = 0;
+ if (++head[drv] >= info->heads) /* beyond heads? */
+ {
+ head[drv] = 0; /* reset head */
+ cylinder[drv]++; /* next cylinder */
+ }
+ }
+ }
+
+ if (!no_dma())
+ {
+ m_isa->drq3_w((hdcdma_read || hdcdma_size ) ? 1 : 0);
+ if(!(hdcdma_read || hdcdma_size)) pc_hdc_result(0);
+ }
+
+ return result;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_dack_w(int data)
+{
+ hard_disk_info *info;
+ hard_disk_file *file;
+
+ file = pc_hdc_file(drv);
+ if (!file)
+ return;
+ info = hard_disk_get_info(file);
+
+ *(hdcdma_dst++) = data;
+
+ if( --hdcdma_write == 0 )
+ {
+ hard_disk_write(file, get_lbasector(), hdcdma_data);
+ hdcdma_write = 512;
+ hdcdma_size -= 512;
+
+ /* end of cylinder ? */
+ if( ++sector[drv] >= info->sectors )
+ {
+ sector[drv] = 0;
+ if (++head[drv] >= info->heads) /* beyond heads? */
+ {
+ head[drv] = 0; /* reset head */
+ cylinder[drv]++; /* next cylinder */
+ }
+ }
+ hdcdma_dst = hdcdma_data;
+ }
+
+ if (!no_dma())
+ {
+ m_isa->drq3_w(hdcdma_size ? 1 : 0);
+ if(!hdcdma_size) pc_hdc_result(1);
+ }
+}
+
+
+
+void isa8_hdc_device::execute_read()
+{
+ hard_disk_file *disk = NULL;
+ int size = sector_cnt[drv] * 512;
+ int read_ = 0;
+
+ disk = pc_hdc_file(drv);
+ if (!disk)
+ return;
+
+ hdcdma_src = hdcdma_data;
+ hdcdma_read = read_;
+ hdcdma_size = size;
+
+ if (no_dma())
+ {
+ do
+ {
+ buffer[data_cnt++] = pc_hdc_dack_r();
+ } while (hdcdma_read || hdcdma_size);
+ }
+ else
+ {
+ m_isa->drq3_w(1);
+ }
+}
+
+
+
+void isa8_hdc_device::execute_write()
+{
+ hard_disk_file *disk = NULL;
+ int size = sector_cnt[drv] * 512;
+ int write_ = 512;
+
+ disk = pc_hdc_file(drv);
+ if (!disk)
+ return;
+
+ hdcdma_dst = hdcdma_data;
+ hdcdma_write = write_;
+ hdcdma_size = size;
+
+ if (no_dma())
+ {
+ do
+ {
+ pc_hdc_dack_w(buffer[data_cnt++]);
+ }
+ while (hdcdma_write || hdcdma_size);
+ }
+ else
+ {
+ m_isa->drq3_w(1);
+ }
+}
+
+
+
+void isa8_hdc_device::get_drive()
+{
+ drv = (buffer[1] >> 5) & 1;
+ csb = (drv) ? CSB_LUN : 0x00;
+}
+
+
+
+void isa8_hdc_device::get_chsn()
+{
+ head[drv] = buffer[1] & 0x1f;
+ sector[drv] = buffer[2] & 0x3f;
+ cylinder[drv] = (buffer[2] & 0xc0) << 2;
+ cylinder[drv] |= buffer[3];
+ sector_cnt[drv] = buffer[4];
+ control[drv] = buffer[5]; /* 7: no retry, 6: no ecc retry, 210: step rate */
+
+ error = 0x80; /* a potential error has C/H/S/N info */
+}
+
+int isa8_hdc_device::test_ready()
+{
+ if( !pc_hdc_file(drv) )
+ {
+ csb |= CSB_ERROR;
+ error |= 0x04; /* drive not ready */
+ return 0;
+ }
+ return 1;
+}
+
+void isa8_hdc_device::hdc_command()
+{
+ int set_error_info = 1;
+ int old_error = error; /* Previous error data is needed for CMD_SENSE */
+ UINT8 cmd;
+ const char *command_name;
+
+ csb = 0x00;
+ error = 0;
+
+ buffer_ptr = buffer;
+ cmd = buffer[0];
+
+ get_drive();
+
+ if (LOG_HDC_STATUS)
+ {
+ command_name = hdc_command_names[cmd] ? hdc_command_names[cmd] : "Unknown";
+ logerror("%s pc_hdc_command(): Executing command; cmd=0x%02x (%s) drv=%d\n",
+ machine().describe_context(), cmd, command_name, drv);
+ }
+
+ switch (cmd)
+ {
+ case CMD_TESTREADY:
+ set_error_info = 0;
+ test_ready();
+ break;
+ case CMD_SENSE:
+ /* Perform error code translation. This may need to be expanded in the future. */
+ buffer[data_cnt++] = ( old_error & 0xC0 ) | ( ( old_error & 0x04 ) ? 0x04 : 0x00 ) ;
+ buffer[data_cnt++] = (drv << 5) | head[drv];
+ buffer[data_cnt++] = ((cylinder[drv] >> 2) & 0xc0) | sector[drv];
+ buffer[data_cnt++] = cylinder[drv] & 0xff;
+ set_error_info = 0;
+ break;
+ case CMD_RECALIBRATE:
+ get_chsn();
+ break;
+
+ case CMD_FORMATDRV:
+ case CMD_VERIFY:
+ case CMD_FORMATTRK:
+ case CMD_FORMATBAD:
+ case CMD_SEEK:
+ case CMD_DRIVEDIAG:
+ get_chsn();
+ test_ready();
+ break;
+
+ case CMD_READ:
+ case CMD_READLONG:
+ get_chsn();
+
+ if (LOG_HDC_STATUS)
+ {
+ logerror("%s hdc read D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n",
+ machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]);
+ }
+
+ if (test_ready())
+ execute_read();
+ set_error_info = 0;
+ break;
+
+ case CMD_WRITE:
+ case CMD_WRITELONG:
+ get_chsn();
+
+ if (LOG_HDC_STATUS)
+ {
+ logerror("%s hdc write D:%d C:%d H:%d S:%d N:%d CTL:$%02x\n",
+ machine().describe_context(), drv, cylinder[drv], head[drv], sector[drv], sector_cnt[drv], control[drv]);
+ }
+
+ if (test_ready())
+ execute_write();
+ break;
+
+ case CMD_SETPARAM:
+ get_chsn();
+ cylinders[drv] = ((buffer[6]&3)<<8) | buffer[7];
+ heads[drv] = buffer[8] & 0x1f;
+ rwc[drv] = ((buffer[9]&3)<<8) | buffer[10];
+ wp[drv] = ((buffer[11]&3)<<8) | buffer[12];
+ ecc[drv] = buffer[13];
+ break;
+
+ case CMD_GETECC:
+ buffer[data_cnt++] = ecc[drv];
+ break;
+
+ case CMD_READSBUFF:
+ case CMD_WRITESBUFF:
+ case CMD_RAMDIAG:
+ case CMD_INTERNDIAG:
+ break;
+
+ }
+ if(no_dma()) pc_hdc_result(set_error_info);
+}
+
+TIMER_CALLBACK(isa8_hdc_device::pc_hdc_command)
+{
+ reinterpret_cast<isa8_hdc_device *>(ptr)->hdc_command();
+}
+
+
+/* Command format
+ * Bits Description
+ * 7 0
+ * xxxxxxxx command
+ * dddhhhhh drive / head
+ * ccssssss cylinder h / sector
+ * cccccccc cylinder l
+ * nnnnnnnn count
+ * xxxxxxxx control
+ *
+ * Command format extra for set drive characteristics
+ * 000000cc cylinders h
+ * cccccccc cylinders l
+ * 000hhhhh heads
+ * 000000cc reduced write h
+ * cccccccc reduced write l
+ * 000000cc write precomp h
+ * cccccccc write precomp l
+ * eeeeeeee ecc
+ */
+void isa8_hdc_device::pc_hdc_data_w(int data)
+{
+ if( data_cnt == 0 )
+ {
+ if (LOG_HDC_DATA)
+ logerror("hdc_data_w $%02x: ", data);
+
+ buffer_ptr = buffer;
+ data_cnt = 6; /* expect 6 bytes including this one */
+ status &= ~STA_READY;
+ status &= ~STA_INPUT;
+ switch (data)
+ {
+ case CMD_SETPARAM:
+ data_cnt += 8;
+ break;
+
+ case CMD_TESTREADY:
+ case CMD_RECALIBRATE:
+ case CMD_SENSE:
+ case CMD_FORMATDRV:
+ case CMD_VERIFY:
+ case CMD_FORMATTRK:
+ case CMD_FORMATBAD:
+ case CMD_READ:
+ case CMD_WRITE:
+ case CMD_SEEK:
+ case CMD_GETECC:
+ case CMD_READSBUFF:
+ case CMD_WRITESBUFF:
+ case CMD_RAMDIAG:
+ case CMD_DRIVEDIAG:
+ case CMD_INTERNDIAG:
+ case CMD_READLONG:
+ case CMD_WRITELONG:
+ break;
+
+ default:
+ data_cnt = 0;
+ status |= STA_INPUT;
+ csb |= CSB_ERROR | 0x20; /* unknown command */
+ pc_hdc_result(1);
+ break;
+ }
+ if( data_cnt )
+ status |= STA_REQUEST;
+ }
+
+ if (data_cnt)
+ {
+ if (LOG_HDC_DATA)
+ logerror("hdc_data_w $%02x\n", data);
+
+ *buffer_ptr++ = data;
+ status |= STA_READY;
+ if (--data_cnt == 0)
+ {
+ if (LOG_HDC_STATUS)
+ logerror("%s pc_hdc_data_w(): Launching command\n", machine().describe_context());
+
+ status &= ~STA_COMMAND;
+ status &= ~STA_REQUEST;
+ status &= ~STA_READY;
+ status |= STA_INPUT;
+
+ timer->adjust(attotime::from_msec(1),0);
+ }
+ }
+}
+
+
+
+void isa8_hdc_device::pc_hdc_reset_w(int data)
+{
+ cylinder[0] = cylinder[1] = 0;
+ head[0] = head[1] = 0;
+ sector[0] = sector[1] = 0;
+ csb = 0;
+ status = STA_COMMAND | STA_READY;
+ memset(buffer, 0, 17*4*512);
+ buffer_ptr = buffer;
+ data_cnt = 0;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_select_w(int data)
+{
+ status &= ~STA_INTERRUPT;
+ status |= STA_SELECT;
+}
+
+
+
+void isa8_hdc_device::pc_hdc_control_w(int data)
+{
+ if (LOG_HDC_STATUS)
+ logerror("%s: pc_hdc_control_w(): control write %d\n", machine().describe_context(), data);
+
+ hdc_control = data;
+
+ if (!(hdc_control & 0x02))
+ {
+ if (BIT(dip, 6))
+ m_isa->irq5_w(0);
+ else
+ m_isa->irq2_w(0);
+ }
+}
+
+
+
+UINT8 isa8_hdc_device::pc_hdc_data_r()
+{
+ UINT8 data = 0xff;
+ if( data_cnt )
+ {
+ data = *buffer_ptr++;
+ status &= ~STA_INTERRUPT;
+ if( --data_cnt == 0 )
+ {
+ status &= ~STA_INPUT;
+ status &= ~STA_REQUEST;
+ status &= ~STA_SELECT;
+ status |= STA_COMMAND;
+ }
+ }
+ return data;
+}
+
+
+
+UINT8 isa8_hdc_device::pc_hdc_status_r()
+{
+ return status;
+}
+
+
+
+/*
+ Dipswitch configuration
+
+
+ Tandon/Western Digital Fixed Disk Controller
+ bit0-1 : Determine disk size(?)
+ Causes geometry data to be read from c8043, c8053, c8063, c8073 (?)
+ 00 - 40 Mbytes
+ 01 - 30 Mbytes
+ 10 - 10 Mbytes
+ 11 - 20 Mbytes
+ bit2-7 : unknown
+
+ */
+
+UINT8 isa8_hdc_device::pc_hdc_dipswitch_r()
+{
+ return dip;
+}
+
+
+
+/*************************************************************************
+ *
+ * HDC
+ * hard disk controller
+ *
+ *************************************************************************/
+static READ8_DEVICE_HANDLER(pc_HDC_r )
+{
+ UINT8 data = 0xff;
+ isa8_hdc_device *hdc = downcast<isa8_hdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: data = hdc->pc_hdc_data_r(); break;
+ case 1: data = hdc->pc_hdc_status_r(); break;
+ case 2: data = hdc->pc_hdc_dipswitch_r(); break;
+ case 3: break;
+ }
+
+ if (LOG_HDC_CALL)
+ logerror("%s pc_HDC_r(): offs=%d result=0x%02x\n", space.machine().describe_context(), offset, data);
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( pc_HDC_w )
+{
+ isa8_hdc_device *hdc = downcast<isa8_hdc_device *>(device);
+ if (LOG_HDC_CALL)
+ logerror("%s pc_HDC_w(): offs=%d data=0x%02x\n", space.machine().describe_context(), offset, data);
+
+ switch( offset )
+ {
+ case 0: hdc->pc_hdc_data_w(data); break;
+ case 1: hdc->pc_hdc_reset_w(data); break;
+ case 2: hdc->pc_hdc_select_w(data); break;
+ case 3: hdc->pc_hdc_control_w(data); break;
+ }
+}
+
+
+UINT8 isa8_hdc_device::dack_r(int line)
+{
+ return pc_hdc_dack_r();
+}
+
+void isa8_hdc_device::dack_w(int line,UINT8 data)
+{
+ pc_hdc_dack_w(data);
+}
diff --git a/src/emu/bus/isa/hdc.h b/src/emu/bus/isa/hdc.h
new file mode 100644
index 00000000000..35e9a0feb8a
--- /dev/null
+++ b/src/emu/bus/isa/hdc.h
@@ -0,0 +1,102 @@
+/**********************************************************************
+
+ ISA 8 bit XT Hard Disk Controller
+
+**********************************************************************/
+#pragma once
+
+#ifndef ISA_HDC_H
+#define ISA_HDC_H
+
+#include "emu.h"
+#include "isa.h"
+#include "imagedev/harddriv.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_hdc_device
+
+class isa8_hdc_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ int drv; /* 0 master, 1 slave drive */
+ int cylinders[2]; /* number of cylinders */
+ int rwc[2]; /* reduced write current from cyl */
+ int wp[2]; /* write precompensation from cyl */
+ int heads[2]; /* heads */
+ int ecc[2]; /* ECC bytes */
+
+ /* indexes */
+ int cylinder[2]; /* current cylinder */
+ int head[2]; /* current head */
+ int sector[2]; /* current sector */
+ int sector_cnt[2]; /* sector count */
+ int control[2]; /* control */
+
+ int csb; /* command status byte */
+ int status; /* drive status */
+ int error; /* error code */
+ int dip; /* dip switches */
+ emu_timer *timer;
+
+ int data_cnt; /* data count */
+ UINT8 *buffer; /* data buffer */
+ UINT8 *buffer_ptr; /* data pointer */
+ UINT8 hdc_control;
+
+ UINT8 hdcdma_data[512];
+ UINT8 *hdcdma_src;
+ UINT8 *hdcdma_dst;
+ int hdcdma_read;
+ int hdcdma_write;
+ int hdcdma_size;
+
+ // internal state
+public:
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line,UINT8 data);
+protected:
+ hard_disk_file *pc_hdc_file(int id);
+ void pc_hdc_result(int set_error_info);
+ int no_dma(void);
+ int get_lbasector();
+ int pc_hdc_dack_r();
+ void pc_hdc_dack_w(int data);
+ void execute_read();
+ void execute_write();
+ void get_drive();
+ void get_chsn();
+ int test_ready();
+ static TIMER_CALLBACK(pc_hdc_command);
+public:
+ void hdc_command();
+ void pc_hdc_data_w(int data);
+ void pc_hdc_reset_w(int data);
+ void pc_hdc_select_w(int data);
+ void pc_hdc_control_w(int data);
+ UINT8 pc_hdc_data_r();
+ UINT8 pc_hdc_status_r();
+ UINT8 pc_hdc_dipswitch_r();
+};
+
+
+// device type definition
+extern const device_type ISA8_HDC;
+
+#endif /* ISA_HDC_H */
diff --git a/src/emu/bus/isa/ibm_mfc.c b/src/emu/bus/isa/ibm_mfc.c
new file mode 100644
index 00000000000..24868f6da01
--- /dev/null
+++ b/src/emu/bus/isa/ibm_mfc.c
@@ -0,0 +1,496 @@
+/***************************************************************************
+
+ ISA 8 bit IBM PC Music Feature Card
+
+ TODO:
+ - YM-2164
+ - MIDI
+ - IRQ/base address selection
+
+ Notes:
+ - Some software does not function correctly at higher CPU speeds
+ (e.g. the Sierra games and Yamaha Compose/PlayRec)
+
+***************************************************************************/
+
+
+#include "emu.h"
+#include "ibm_mfc.h"
+#include "cpu/z80/z80.h"
+#include "machine/clock.h"
+#include "machine/pit8253.h"
+
+
+//-------------------------------------------------
+// Constants
+//-------------------------------------------------
+
+#define TCR_TAC 0x01
+#define TCR_TBC 0x02
+#define TCR_TAE 0x04
+#define TCR_TBE 0x08
+#define TCR_EXT8 0x10
+#define TCR_TMSK 0x40
+#define TCR_IBE 0x80
+
+#define TSR_TAS 0x01
+#define TSR_TBS 0x02
+#define TSR_TCS 0x80
+
+enum
+{
+ PC_IRQ_TIMERA,
+ PC_IRQ_TIMERB,
+ PC_IRQ_RXRDY,
+ PC_IRQ_TXRDY,
+};
+
+enum
+{
+ Z80_IRQ_YM,
+ Z80_IRQ_RXRDY,
+ Z80_IRQ_TXRDY,
+ Z80_IRQ_MIDI_RXRDY,
+ Z80_IRQ_MIDI_TXRDY,
+};
+
+
+//-------------------------------------------------
+// Globals
+//-------------------------------------------------
+
+const device_type ISA8_IBM_MFC = &device_creator<isa8_ibm_mfc_device>;
+
+
+//-------------------------------------------------
+// Interrupt handling
+//-------------------------------------------------
+
+void isa8_ibm_mfc_device::set_pc_interrupt(int src, int state)
+{
+ if (state)
+ m_pc_irq_state |= 1 << src;
+ else
+ m_pc_irq_state &= ~(1 << src);
+
+ update_pc_interrupts();
+}
+
+void isa8_ibm_mfc_device::update_pc_interrupts(void)
+{
+ // IRQs enabled?
+ if (m_tcr & TCR_IBE)
+ {
+ // IRQs unmasked?
+ if (m_tcr & TCR_TMSK)
+ {
+ m_isa->irq3_w(m_pc_irq_state ? ASSERT_LINE : CLEAR_LINE);
+ }
+ }
+}
+
+void isa8_ibm_mfc_device::set_z80_interrupt(int src, int state)
+{
+ if (state)
+ m_z80_irq_state |= 1 << src;
+ else
+ m_z80_irq_state &= ~(1 << src);
+
+ update_z80_interrupts();
+}
+
+void isa8_ibm_mfc_device::update_z80_interrupts(void)
+{
+ m_cpu->set_input_line(0, m_z80_irq_state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// Z80 memory map
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( prg_map, AS_PROGRAM, 8, isa8_ibm_mfc_device )
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0x8000) AM_RAM // Unknown - tested on startup
+ AM_RANGE(0xbfff, 0xbfff) AM_RAM // Unknown - tested on startup
+ AM_RANGE(0xc000, 0xdfff) AM_RAM
+ AM_RANGE(0xe000, 0xffff) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( io_map, AS_IO, 8, isa8_ibm_mfc_device )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0x01) AM_DEVREADWRITE("ym2151", ym2151_device, read, write)
+ AM_RANGE(0x10, 0x10) AM_DEVREADWRITE("d71051", i8251_device, data_r, data_w)
+ AM_RANGE(0x11, 0x11) AM_DEVREADWRITE("d71051", i8251_device, status_r, control_w)
+ AM_RANGE(0x20, 0x23) AM_DEVREADWRITE("d71055c_1", i8255_device, read, write)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// Jumpers and DIP switches
+//-------------------------------------------------
+
+static INPUT_PORTS_START( ibm_mfc )
+ PORT_START("J1")
+ PORT_DIPNAME( 0x07, 0x03, "IBM MFC J1: IRQ" )
+ PORT_DIPSETTING( 0x02, "2" )
+ PORT_DIPSETTING( 0x03, "3" )
+ PORT_DIPSETTING( 0x04, "4" )
+ PORT_DIPSETTING( 0x05, "5" )
+ PORT_DIPSETTING( 0x06, "6" )
+ PORT_DIPSETTING( 0x07, "7" )
+
+ PORT_START("SW1")
+ PORT_DIPNAME( 0x03, 0x00, "IBM MFC SW1: Base Address" )
+ PORT_DIPSETTING( 0x00, "2A00" )
+ PORT_DIPSETTING( 0x01, "2A10" )
+ PORT_DIPSETTING( 0x02, "2A20" )
+ PORT_DIPSETTING( 0x03, "2A30" )
+INPUT_PORTS_END
+
+//-------------------------------------------------
+// D71055C PPI (PC)
+//-------------------------------------------------
+
+READ8_MEMBER( isa8_ibm_mfc_device::ppi0_i_a )
+{
+ // Read data from the Z80 PIU
+ return m_d71055c_1->pa_r();
+}
+
+WRITE8_MEMBER( isa8_ibm_mfc_device::ppi0_o_b )
+{
+ // Write data to the Z80 PIU - no action required
+}
+
+WRITE8_MEMBER( isa8_ibm_mfc_device::ppi0_o_c )
+{
+ // PC Port B /OBF (C1) -> Z80 Port B /STB (C2)
+ m_d71055c_1->pc2_w(BIT(data, 1));
+
+ // PC Port A IBF (C5) -> Z80 Port A /ACK (C6)
+#if 0 // TODO
+ m_d71055c_1->pc6_w(!BIT(data, 5));
+#else
+ if (!BIT(data, 5) && BIT(m_pc_ppi_c, 5))
+ m_d71055c_1->pc6_w(0);
+#endif
+
+ // Bit 0 (INTRB) is TxRDY
+ set_pc_interrupt(PC_IRQ_TXRDY, BIT(data, 0));
+
+ // Bit 3 (INTRA) is RxRDY
+ set_pc_interrupt(PC_IRQ_RXRDY, BIT(data, 3));
+
+ m_pc_ppi_c = data;
+}
+
+READ8_MEMBER( isa8_ibm_mfc_device::ppi0_i_c )
+{
+ // Receive data bit 8
+ return BIT(m_z80_ppi_c, 5) << 7;
+}
+
+static I8255_INTERFACE( d71055c_0_intf )
+{
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_i_a),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_o_b),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_i_c),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi0_o_c),
+};
+
+
+//-------------------------------------------------
+// D71055C PPI (Z80)
+//-------------------------------------------------
+
+WRITE8_MEMBER( isa8_ibm_mfc_device::ppi1_o_a )
+{
+ // Write data to the PC PIU - no action required
+}
+
+READ8_MEMBER( isa8_ibm_mfc_device::ppi1_i_b )
+{
+ // Read data from the PC PIU
+ return m_d71055c_0->pb_r();
+}
+
+WRITE8_MEMBER( isa8_ibm_mfc_device::ppi1_o_c )
+{
+ // PortA /OBF (C7) -> PortA /STB (C2)
+ m_d71055c_0->pc4_w(BIT(data, 7));
+
+ // PortB IBF (C1) -> PortB /ACK (C2)
+#if 0 // TODO
+ m_d71055c_0->pc2_w(!BIT(data, 1));
+#else
+ if (!BIT(data, 1) && BIT(m_z80_ppi_c, 1))
+ m_d71055c_0->pc2_w(0);
+#endif
+
+ set_z80_interrupt(Z80_IRQ_TXRDY, BIT(data, 3));
+ set_z80_interrupt(Z80_IRQ_RXRDY, BIT(data, 0));
+
+ m_z80_ppi_c = data;
+}
+
+static I8255_INTERFACE( d71055c_1_intf )
+{
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_o_a),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_i_b),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, isa8_ibm_mfc_device, ppi1_o_c),
+};
+
+
+//-------------------------------------------------
+// D8253 PIT
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_out0 )
+{
+ if (m_tcr & TCR_TAE)
+ set_pc_interrupt(PC_IRQ_TIMERA, 1);
+}
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::d8253_out1 )
+{
+ if (m_tcr & TCR_TBE)
+ set_pc_interrupt(PC_IRQ_TIMERB, 1);
+}
+
+
+//-------------------------------------------------
+// uPD71051 USART
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( isa8_ibm_mfc_device::write_usart_clock )
+{
+ m_d71051->write_txc(state);
+ m_d71051->write_rxc(state);
+}
+
+//-------------------------------------------------
+// YM-2164
+//-------------------------------------------------
+
+
+WRITE_LINE_MEMBER(isa8_ibm_mfc_device::ibm_mfc_ym_irq)
+{
+ set_z80_interrupt(Z80_IRQ_YM, state);
+}
+
+
+//-------------------------------------------------
+// Machine config
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( ibm_mfc )
+ MCFG_CPU_ADD("ibm_mfc", Z80, XTAL_11_8MHz / 2)
+ MCFG_CPU_PROGRAM_MAP(prg_map)
+ MCFG_CPU_IO_MAP(io_map)
+
+ MCFG_I8255_ADD("d71055c_0", d71055c_0_intf)
+ MCFG_I8255_ADD("d71055c_1", d71055c_1_intf)
+
+ MCFG_DEVICE_ADD("d71051", I8251, 0)
+
+ MCFG_DEVICE_ADD("usart_clock", CLOCK, XTAL_4MHz / 8) // 500KHz
+ MCFG_CLOCK_SIGNAL_HANDLER(WRITELINE(isa8_ibm_mfc_device, write_usart_clock))
+
+ MCFG_DEVICE_ADD("d8253", PIT8253, 0)
+ MCFG_PIT8253_CLK0(XTAL_4MHz / 8)
+ MCFG_PIT8253_OUT0_HANDLER(WRITELINE(isa8_ibm_mfc_device, d8253_out0))
+ MCFG_PIT8253_CLK1(0)
+ MCFG_PIT8253_OUT1_HANDLER(WRITELINE(isa8_ibm_mfc_device, d8253_out1))
+ MCFG_PIT8253_CLK2(XTAL_4MHz / 2)
+ MCFG_PIT8253_OUT2_HANDLER(DEVWRITELINE("d8253", pit8253_device, write_clk1))
+
+ MCFG_SPEAKER_STANDARD_STEREO("ymleft", "ymright")
+ MCFG_YM2151_ADD("ym2151", XTAL_4MHz)
+ MCFG_YM2151_IRQ_HANDLER(WRITELINE(isa8_ibm_mfc_device, ibm_mfc_ym_irq))
+ MCFG_SOUND_ROUTE(0, "ymleft", 1.00)
+ MCFG_SOUND_ROUTE(1, "ymright", 1.00)
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// ISA interface
+//-------------------------------------------------
+
+READ8_MEMBER( isa8_ibm_mfc_device::ibm_mfc_r )
+{
+ UINT8 val = 0xff;
+
+ switch (offset)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ {
+ val = m_d71055c_0->read(space, offset);
+ break;
+ }
+
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ {
+ val = (m_pc_irq_state ? 0x80 : 0) | (m_pc_irq_state & 3);
+ break;
+ }
+
+ default:
+ {
+ fatalerror("Unhandled IBM MFC read from %d\n", offset);
+ }
+ }
+
+ return val;
+}
+
+WRITE8_MEMBER( isa8_ibm_mfc_device::ibm_mfc_w )
+{
+ switch (offset)
+ {
+ case 0x0:
+ case 0x1:
+ case 0x2:
+ case 0x3:
+ {
+ machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(1000));
+ m_d71055c_0->write(space, offset, data);
+ break;
+ }
+
+ case 0x4:
+ case 0x5:
+ case 0x6:
+ case 0x7:
+ {
+ m_d8253->write(space, offset & 3, data);
+ break;
+ }
+
+ case 0x8:
+ case 0x9:
+ case 0xa:
+ case 0xb:
+ {
+ m_tcr = data;
+
+ if (~m_tcr & TCR_TAC)
+ set_pc_interrupt(PC_IRQ_TIMERA, 0);
+
+ if (~m_tcr & TCR_TBC)
+ set_pc_interrupt(PC_IRQ_TIMERB, 0);
+
+ m_d71051->write_dsr((m_tcr & TCR_EXT8) ? 1 : 0);
+
+ break;
+ }
+
+ case 0xc:
+ case 0xd:
+ case 0xe:
+ case 0xf:
+ {
+ // TSR is read-only but Yamaha software attempts to write to it
+ break;
+ }
+ }
+}
+
+
+//-------------------------------------------------
+// ROM definition
+//-------------------------------------------------
+
+ROM_START( ibm_mfc )
+ ROM_REGION( 0x8000, "ibm_mfc", 0 )
+ ROM_LOAD( "xc215 c 0.bin", 0x0000, 0x8000, CRC(28c58a4f) SHA1(e7edf28d20e6c146e3144526c89cd6beea64663b) )
+ROM_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_ibm_mfc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ibm_mfc );
+}
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor isa8_ibm_mfc_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ibm_mfc );
+}
+
+
+//-------------------------------------------------
+// rom_region - return a pointer to the device's
+// internal ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_ibm_mfc_device::device_rom_region() const
+{
+ return ROM_NAME( ibm_mfc );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_ibm_mfc_device - constructor
+//-------------------------------------------------
+
+isa8_ibm_mfc_device::isa8_ibm_mfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_IBM_MFC, "IBM PC Music Feature Card", tag, owner, clock, "ibm_mfc", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_cpu(*this, "ibm_mfc"),
+ m_ym2151(*this, "ym2151"),
+ m_d8253(*this, "d8253"),
+ m_d71051(*this, "d71051"),
+ m_d71055c_0(*this, "d71055c_0"),
+ m_d71055c_1(*this, "d71055c_1")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_ibm_mfc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x2a20, 0x2a20 + 15, 0, 0, read8_delegate(FUNC(isa8_ibm_mfc_device::ibm_mfc_r), this), write8_delegate(FUNC(isa8_ibm_mfc_device::ibm_mfc_w), this));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_ibm_mfc_device::device_reset()
+{
+ m_tcr = 0;
+ m_d71051->write_dsr(0);
+ m_pc_irq_state = 0;
+ m_z80_irq_state = 0;
+}
diff --git a/src/emu/bus/isa/ibm_mfc.h b/src/emu/bus/isa/ibm_mfc.h
new file mode 100644
index 00000000000..5eb4b4331da
--- /dev/null
+++ b/src/emu/bus/isa/ibm_mfc.h
@@ -0,0 +1,88 @@
+/***************************************************************************
+
+ ISA 8 bit IBM PC Music Feature Card
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ISA_IBM_MUSIC_FEATURE_CARD_H__
+#define __ISA_IBM_MUSIC_FEATURE_CARD_H__
+
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/i8255.h"
+#include "machine/i8251.h"
+#include "machine/pit8253.h"
+#include "sound/2151intf.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_ibm_mfc_device
+
+class isa8_ibm_mfc_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // Construction/destruction
+ isa8_ibm_mfc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER( ppi0_i_a );
+ DECLARE_WRITE8_MEMBER( ppi0_o_b );
+ DECLARE_READ8_MEMBER( ppi0_i_c );
+ DECLARE_WRITE8_MEMBER( ppi0_o_c );
+
+ DECLARE_WRITE8_MEMBER( ppi1_o_a );
+ DECLARE_READ8_MEMBER( ppi1_i_b );
+
+ DECLARE_WRITE8_MEMBER( ppi1_o_c );
+
+ DECLARE_READ8_MEMBER( ibm_mfc_r );
+ DECLARE_WRITE8_MEMBER( ibm_mfc_w );
+
+ DECLARE_WRITE_LINE_MEMBER( d8253_out0 );
+ DECLARE_WRITE_LINE_MEMBER( d8253_out1 );
+
+ DECLARE_WRITE_LINE_MEMBER( write_usart_clock );
+
+ DECLARE_WRITE_LINE_MEMBER( ibm_mfc_ym_irq );
+
+protected:
+ // Device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ virtual const rom_entry* device_rom_region() const;
+
+private:
+ void set_z80_interrupt(int src, int state);
+ void set_pc_interrupt(int src, int state);
+ void update_pc_interrupts(void);
+ void update_z80_interrupts(void);
+
+ UINT8 m_tcr;
+ UINT8 m_pc_ppi_c;
+ UINT8 m_z80_ppi_c;
+
+ UINT8 m_pc_irq_state;
+ UINT8 m_z80_irq_state;
+
+ required_device<cpu_device> m_cpu;
+ required_device<ym2151_device> m_ym2151;
+ required_device<pit8253_device> m_d8253;
+ required_device<i8251_device> m_d71051;
+ required_device<i8255_device> m_d71055c_0;
+ required_device<i8255_device> m_d71055c_1;
+};
+
+
+// Device type definition
+extern const device_type ISA8_IBM_MFC;
+
+#endif /* __ISA_IBM_MUSIC_FEATURE_CARD_H__ */
diff --git a/src/emu/bus/isa/ide.c b/src/emu/bus/isa/ide.c
new file mode 100644
index 00000000000..a45721b1a76
--- /dev/null
+++ b/src/emu/bus/isa/ide.c
@@ -0,0 +1,118 @@
+/***************************************************************************
+
+ ISA 16 bit IDE controller
+
+***************************************************************************/
+
+#include "emu.h"
+#include "ide.h"
+#include "machine/idectrl.h"
+#include "imagedev/harddriv.h"
+
+READ8_MEMBER(isa16_ide_device::ide16_alt_r )
+{
+ return m_ide->read_cs1(space, 6/2, 0xff);
+}
+
+WRITE8_MEMBER(isa16_ide_device::ide16_alt_w )
+{
+ m_ide->write_cs1(space, 6/2, data, 0xff);
+}
+
+DEVICE_ADDRESS_MAP_START(map, 16, isa16_ide_device)
+ AM_RANGE(0x0, 0x7) AM_DEVREADWRITE("ide", ide_controller_device, read_cs0, write_cs0)
+ADDRESS_MAP_END
+
+DEVICE_ADDRESS_MAP_START(alt_map, 8, isa16_ide_device)
+ AM_RANGE(0x6, 0x6) AM_READWRITE(ide16_alt_r, ide16_alt_w)
+ADDRESS_MAP_END
+
+WRITE_LINE_MEMBER(isa16_ide_device::ide_interrupt)
+{
+ if (is_primary())
+ {
+ m_isa->irq14_w(state);
+ }
+ else
+ {
+ m_isa->irq15_w(state);
+ }
+}
+
+static MACHINE_CONFIG_FRAGMENT( ide )
+ MCFG_IDE_CONTROLLER_ADD("ide", ata_devices, "hdd", NULL, false)
+ MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(isa16_ide_device, ide_interrupt))
+MACHINE_CONFIG_END
+
+static INPUT_PORTS_START( ide )
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x01, 0x00, "IDE Configuration")
+ PORT_DIPSETTING( 0x00, "Primary" )
+ PORT_DIPSETTING( 0x01, "Secondary" )
+INPUT_PORTS_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_IDE = &device_creator<isa16_ide_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_ide_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ide );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor isa16_ide_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( ide );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_ide_device - constructor
+//-------------------------------------------------
+
+isa16_ide_device::isa16_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA16_IDE, "IDE Fixed Drive Adapter", tag, owner, clock, "isa_ide", __FILE__),
+ device_isa16_card_interface( mconfig, *this ),
+ m_is_primary(true),
+ m_ide(*this, "ide")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa16_ide_device::device_start()
+{
+ set_isa_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_ide_device::device_reset()
+{
+ m_is_primary = (ioport("DSW")->read() & 1) ? false : true;
+ if (m_is_primary) {
+ m_isa->install_device(0x01f0, 0x01f7, *this, &isa16_ide_device::map, 16);
+ m_isa->install_device(0x03f0, 0x03f7, *this, &isa16_ide_device::alt_map);
+ } else {
+ m_isa->install_device(0x0170, 0x0177, *this, &isa16_ide_device::map, 16);
+ m_isa->install_device(0x0370, 0x0377, *this, &isa16_ide_device::alt_map);
+ }
+}
diff --git a/src/emu/bus/isa/ide.h b/src/emu/bus/isa/ide.h
new file mode 100644
index 00000000000..cc38fd1c868
--- /dev/null
+++ b/src/emu/bus/isa/ide.h
@@ -0,0 +1,48 @@
+#pragma once
+
+#ifndef __ISA_IDE_H__
+#define __ISA_IDE_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/idectrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa16_ide_device
+
+class isa16_ide_device : public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_ide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ bool is_primary() { return m_is_primary; }
+ DECLARE_WRITE_LINE_MEMBER(ide_interrupt);
+ DECLARE_ADDRESS_MAP(map, 16);
+ DECLARE_ADDRESS_MAP(alt_map, 8);
+ READ8_MEMBER(ide16_alt_r);
+ WRITE8_MEMBER(ide16_alt_w);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ // internal state
+ bool m_is_primary;
+ required_device<ide_controller_device> m_ide;
+};
+
+
+// device type definition
+extern const device_type ISA16_IDE;
+
+#endif /* __ISA_IDE_H__ */
diff --git a/src/emu/bus/isa/isa.c b/src/emu/bus/isa/isa.c
new file mode 100644
index 00000000000..9dc1c05b3f8
--- /dev/null
+++ b/src/emu/bus/isa/isa.c
@@ -0,0 +1,790 @@
+/***************************************************************************
+
+ ISA bus device
+
+***************************************************************************/
+
+#include "emu.h"
+#include "emuopts.h"
+#include "isa.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SLOT = &device_creator<isa8_slot_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_slot_device - constructor
+//-------------------------------------------------
+isa8_slot_device::isa8_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SLOT, "ISA8_SLOT", tag, owner, clock, "isa8_slot", __FILE__),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+isa8_slot_device::isa8_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+void isa8_slot_device::static_set_isa8_slot(device_t &device, device_t *owner, const char *isa_tag)
+{
+ isa8_slot_device &isa_card = dynamic_cast<isa8_slot_device &>(device);
+ isa_card.m_owner = owner;
+ isa_card.m_isa_tag = isa_tag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_slot_device::device_start()
+{
+ device_isa8_card_interface *dev = dynamic_cast<device_isa8_card_interface *>(get_card_device());
+ const device_isa16_card_interface *intf;
+ if (get_card_device()->interface(intf))
+ fatalerror("Error ISA16 device in ISA8 slot\n");
+
+ if (dev) device_isa8_card_interface::static_set_isabus(*dev,m_owner->subdevice(m_isa_tag));
+}
+
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_SLOT = &device_creator<isa16_slot_device>;
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_slot_device - constructor
+//-------------------------------------------------
+isa16_slot_device::isa16_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_slot_device(mconfig, ISA16_SLOT, "ISA16_SLOT", tag, owner, clock, "isa16_slot", __FILE__)
+{
+}
+
+void isa16_slot_device::static_set_isa16_slot(device_t &device, device_t *owner, const char *isa_tag)
+{
+ isa16_slot_device &isa_card = dynamic_cast<isa16_slot_device &>(device);
+ isa_card.m_owner = owner;
+ isa_card.m_isa_tag = isa_tag;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa16_slot_device::device_start()
+{
+ device_isa8_card_interface *dev = dynamic_cast<device_isa8_card_interface *>(get_card_device());
+ if (dev) device_isa8_card_interface::static_set_isabus(*dev,m_owner->subdevice(m_isa_tag));
+}
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8 = &device_creator<isa8_device>;
+
+void isa8_device::static_set_cputag(device_t &device, const char *tag)
+{
+ isa8_device &isa = downcast<isa8_device &>(device);
+ isa.m_cputag = tag;
+}
+
+void isa8_device::static_set_custom_spaces(device_t &device)
+{
+ isa8_device &isa = downcast<isa8_device &>(device);
+
+ isa.m_allocspaces = true;
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void isa8_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const isa8bus_interface *intf = reinterpret_cast<const isa8bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<isa8bus_interface *>(this) = *intf;
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&m_out_irq2_cb, 0, sizeof(m_out_irq2_cb));
+ memset(&m_out_irq3_cb, 0, sizeof(m_out_irq3_cb));
+ memset(&m_out_irq4_cb, 0, sizeof(m_out_irq4_cb));
+ memset(&m_out_irq5_cb, 0, sizeof(m_out_irq5_cb));
+ memset(&m_out_irq6_cb, 0, sizeof(m_out_irq6_cb));
+ memset(&m_out_irq7_cb, 0, sizeof(m_out_irq7_cb));
+ memset(&m_out_drq1_cb, 0, sizeof(m_out_drq1_cb));
+ memset(&m_out_drq2_cb, 0, sizeof(m_out_drq2_cb));
+ memset(&m_out_drq3_cb, 0, sizeof(m_out_drq3_cb));
+ }
+ m_maincpu = subdevice<cpu_device>(m_cputag);
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_device - constructor
+//-------------------------------------------------
+
+isa8_device::isa8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8, "ISA8", tag, owner, clock, "isa8", __FILE__),
+ device_memory_interface(mconfig, *this),
+ m_program_config("ISA 8-bit program", ENDIANNESS_LITTLE, 8, 24, 0, NULL),
+ m_io_config("ISA 8-bit I/O", ENDIANNESS_LITTLE, 8, 16, 0, NULL),
+ m_program16_config("ISA 16-bit program", ENDIANNESS_LITTLE, 16, 24, 0, NULL),
+ m_io16_config("ISA 16-bit I/O", ENDIANNESS_LITTLE, 16, 16, 0, NULL),
+ m_write_iochck(*this)
+{
+ for(int i=0;i<8;i++)
+ {
+ m_dma_device[i] = NULL;
+ m_dma_eop[i] = false;
+ }
+ m_nmi_enabled = false;
+ m_iowidth = m_prgwidth = 0;
+ m_allocspaces = false;
+}
+
+isa8_device::isa8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_memory_interface(mconfig, *this),
+ m_program_config("ISA 8-bit program", ENDIANNESS_LITTLE, 8, 24, 0, NULL),
+ m_io_config("ISA 8-bit I/O", ENDIANNESS_LITTLE, 8, 16, 0, NULL),
+ m_program16_config("ISA 16-bit program", ENDIANNESS_LITTLE, 16, 24, 0, NULL),
+ m_io16_config("ISA 16-bit I/O", ENDIANNESS_LITTLE, 16, 16, 0, NULL),
+ m_write_iochck(*this)
+{
+ for(int i=0;i<8;i++)
+ {
+ m_dma_device[i] = NULL;
+ m_dma_eop[i] = false;
+ }
+ m_nmi_enabled = false;
+ m_iowidth = m_prgwidth = 0;
+ m_allocspaces = false;
+}
+
+READ8_MEMBER(isa8_device::prog_r)
+{
+ return m_prgspace->read_byte(offset);
+}
+
+WRITE8_MEMBER(isa8_device::prog_w)
+{
+ m_prgspace->write_byte(offset, data);
+}
+
+READ8_MEMBER(isa8_device::io_r)
+{
+ return m_iospace->read_byte(offset);
+}
+
+WRITE8_MEMBER(isa8_device::io_w)
+{
+ m_iospace->write_byte(offset, data);
+}
+
+void isa8_device::set_dma_channel(UINT8 channel, device_isa8_card_interface *dev, bool do_eop)
+{
+ m_dma_device[channel] = dev;
+ m_dma_eop[channel] = do_eop;
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_device::device_start()
+{
+ // resolve callbacks
+ m_write_iochck.resolve_safe();
+
+ m_out_irq2_func.resolve(m_out_irq2_cb, *this);
+ m_out_irq3_func.resolve(m_out_irq3_cb, *this);
+ m_out_irq4_func.resolve(m_out_irq4_cb, *this);
+ m_out_irq5_func.resolve(m_out_irq5_cb, *this);
+ m_out_irq6_func.resolve(m_out_irq6_cb, *this);
+ m_out_irq7_func.resolve(m_out_irq7_cb, *this);
+ m_out_drq1_func.resolve(m_out_drq1_cb, *this);
+ m_out_drq2_func.resolve(m_out_drq2_cb, *this);
+ m_out_drq3_func.resolve(m_out_drq3_cb, *this);
+
+ m_maincpu = subdevice<cpu_device>(m_cputag);
+
+ if (m_allocspaces)
+ {
+ m_iospace = &space(AS_IO);
+ m_prgspace = &space(AS_PROGRAM);
+ m_iowidth = m_iospace->data_width();
+ m_prgwidth = m_prgspace->data_width();
+ }
+ else // use host CPU's program and I/O spaces directly
+ {
+ m_iospace = &m_maincpu->space(AS_IO);
+ m_iowidth = m_maincpu->space_config(AS_IO)->m_databus_width;
+ m_prgspace = &m_maincpu->space(AS_PROGRAM);
+ m_prgwidth = m_maincpu->space_config(AS_PROGRAM)->m_databus_width;
+ }
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_device::device_reset()
+{
+}
+
+
+void isa8_device::install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name)
+{
+ int buswidth;
+ address_space *space;
+
+ if (spacenum == AS_IO)
+ {
+ space = m_iospace;
+ buswidth = m_iowidth;
+ }
+ else if (spacenum == AS_PROGRAM)
+ {
+ space = m_prgspace;
+ buswidth = m_prgwidth;
+ }
+ else
+ {
+ fatalerror("Unknown space passed to isa8_device::install_space!\n");
+ }
+
+ switch(buswidth)
+ {
+ case 8:
+ space->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0);
+ break;
+ case 16:
+ space->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ space->install_legacy_readwrite_handler(start, end+2, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0x0000ffff);
+ } else {
+ space->install_legacy_readwrite_handler(start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ space->install_legacy_readwrite_handler(start-2, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported\n", buswidth);
+ break;
+ }
+}
+
+
+void isa8_device::install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler)
+{
+ int buswidth;
+ address_space *space;
+
+ if (spacenum == AS_IO)
+ {
+ space = m_iospace;
+ buswidth = m_iowidth;
+ }
+ else if (spacenum == AS_PROGRAM)
+ {
+ space = m_prgspace;
+ buswidth = m_prgwidth;
+ }
+ else
+ {
+ fatalerror("Unknown space passed to isa8_device::install_space!\n");
+ }
+
+ switch(buswidth)
+ {
+ case 8:
+ space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0);
+ break;
+ case 16:
+ space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ space->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff);
+ } else {
+ space->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ space->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported\n", buswidth);
+ break;
+ }
+}
+
+
+void isa8_device::install_space(address_spacenum spacenum, device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ int buswidth;
+ address_space *space;
+
+ if (spacenum == AS_IO)
+ {
+ space = m_iospace;
+ buswidth = m_iowidth;
+ }
+ else if (spacenum == AS_PROGRAM)
+ {
+ space = m_prgspace;
+ buswidth = m_prgwidth;
+ }
+ else
+ {
+ fatalerror("Unknown space passed to isa8_device::install_space!\n");
+ }
+
+ switch(buswidth)
+ {
+ case 8:
+ space->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0);
+ break;
+ case 16:
+ space->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff);
+ break;
+ case 32:
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ space->install_legacy_readwrite_handler(*dev, start, end+2, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0x0000ffff);
+ } else {
+ space->install_legacy_readwrite_handler(*dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ space->install_legacy_readwrite_handler(*dev, start-2, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name,0xffff0000);
+ }
+ break;
+ default:
+ fatalerror("ISA8: Bus width %d not supported\n", buswidth);
+ break;
+ }
+}
+
+
+void isa8_device::install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler)
+{
+ install_space(AS_PROGRAM, start, end, mask, mirror, rhandler, whandler);
+}
+
+
+void isa8_device::install_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name)
+{
+ install_space(AS_IO, dev, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+void isa8_device::install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name)
+{
+ install_space(AS_IO, start, end, mask, mirror, rhandler, rhandler_name, whandler, whandler_name);
+}
+
+
+void isa8_device::install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler)
+{
+ install_space(AS_IO, start, end, mask, mirror, rhandler, whandler);
+}
+
+
+void isa8_device::install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data)
+{
+ m_prgspace->install_readwrite_bank(start, end, mask, mirror, tag );
+ machine().root_device().membank(tag)->set_base(data);
+}
+
+void isa8_device::unmap_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror)
+{
+ m_prgspace->unmap_readwrite(start, end, mask, mirror);
+}
+
+void isa8_device::install_rom(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, const char *region)
+{
+ astring tempstring;
+ if (machine().root_device().memregion("isa")) {
+ UINT8 *src = dev->memregion(region)->base();
+ UINT8 *dest = machine().root_device().memregion("isa")->base() + start - 0xc0000;
+ memcpy(dest,src, end - start + 1);
+ } else {
+ m_prgspace->install_read_bank(start, end, mask, mirror, tag);
+ m_prgspace->unmap_write(start, end, mask, mirror);
+ machine().root_device().membank(tag)->set_base(machine().root_device().memregion(dev->subtag(tempstring, region))->base());
+ }
+}
+
+void isa8_device::unmap_rom(offs_t start, offs_t end, offs_t mask, offs_t mirror)
+{
+ m_prgspace->unmap_read(start, end, mask, mirror);
+}
+
+bool isa8_device::is_option_rom_space_available(offs_t start, int size)
+{
+ m_maincpu = machine().device<cpu_device>(m_cputag);
+ for(int i = 0; i < size; i += 4096) // 4KB granularity should be enough
+ if(m_prgspace->get_read_ptr(start + i)) return false;
+ return true;
+}
+
+// interrupt request from isa card
+WRITE_LINE_MEMBER( isa8_device::irq2_w ) { m_out_irq2_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq3_w ) { m_out_irq3_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq4_w ) { m_out_irq4_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq5_w ) { m_out_irq5_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq6_w ) { m_out_irq6_func(state); }
+WRITE_LINE_MEMBER( isa8_device::irq7_w ) { m_out_irq7_func(state); }
+
+// dma request from isa card
+WRITE_LINE_MEMBER( isa8_device::drq1_w ) { m_out_drq1_func(state); }
+WRITE_LINE_MEMBER( isa8_device::drq2_w ) { m_out_drq2_func(state); }
+WRITE_LINE_MEMBER( isa8_device::drq3_w ) { m_out_drq3_func(state); }
+
+UINT8 isa8_device::dack_r(int line)
+{
+ if (m_dma_device[line])
+ return m_dma_device[line]->dack_r(line);
+ return 0xff;
+}
+
+void isa8_device::dack_w(int line,UINT8 data)
+{
+ if (m_dma_device[line])
+ return m_dma_device[line]->dack_w(line,data);
+}
+
+void isa8_device::eop_w(int channel, int state)
+{
+ if (m_dma_eop[channel] && m_dma_device[channel])
+ m_dma_device[channel]->eop_w(state);
+}
+
+void isa8_device::nmi()
+{
+ if (m_write_iochck.isnull())
+ {
+ if (m_nmi_enabled)
+ {
+ m_maincpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE );
+ }
+ }
+ else
+ {
+ m_write_iochck(0);
+ m_write_iochck(1);
+ }
+}
+
+//**************************************************************************
+// DEVICE CONFIG ISA8 CARD INTERFACE
+//**************************************************************************
+
+
+//**************************************************************************
+// DEVICE ISA8 CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_isa8_card_interface - constructor
+//-------------------------------------------------
+
+device_isa8_card_interface::device_isa8_card_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig, device),
+ m_isa(NULL)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_isa8_card_interface - destructor
+//-------------------------------------------------
+
+device_isa8_card_interface::~device_isa8_card_interface()
+{
+}
+
+UINT8 device_isa8_card_interface::dack_r(int line)
+{
+ return 0;
+}
+void device_isa8_card_interface::dack_w(int line,UINT8 data)
+{
+}
+void device_isa8_card_interface::eop_w(int state)
+{
+}
+
+void device_isa8_card_interface::static_set_isabus(device_t &device, device_t *isa_device)
+{
+ device_isa8_card_interface &isa_card = dynamic_cast<device_isa8_card_interface &>(device);
+ isa_card.m_isa_dev = isa_device;
+}
+
+void device_isa8_card_interface::set_isa_device()
+{
+ m_isa = dynamic_cast<isa8_device *>(m_isa_dev);
+}
+
+
+const device_type ISA16 = &device_creator<isa16_device>;
+
+//-------------------------------------------------
+// isa16_device - constructor
+//-------------------------------------------------
+
+isa16_device::isa16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_device(mconfig, ISA16, "ISA16", tag, owner, clock, "isa16", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void isa16_device::device_config_complete()
+{
+ // inherit a copy of the static data
+ const isa16bus_interface *intf = reinterpret_cast<const isa16bus_interface *>(static_config());
+ if (intf != NULL)
+ {
+ *static_cast<isa16bus_interface *>(this) = *intf;
+ memcpy(&(isa8bus_interface::m_out_irq2_cb),&(isa16bus_interface::m_out_irq2_cb), sizeof(isa16bus_interface::m_out_irq2_cb));
+ memcpy(&(isa8bus_interface::m_out_irq3_cb),&(isa16bus_interface::m_out_irq3_cb), sizeof(isa16bus_interface::m_out_irq3_cb));
+ memcpy(&(isa8bus_interface::m_out_irq4_cb),&(isa16bus_interface::m_out_irq4_cb), sizeof(isa16bus_interface::m_out_irq4_cb));
+ memcpy(&(isa8bus_interface::m_out_irq5_cb),&(isa16bus_interface::m_out_irq5_cb), sizeof(isa16bus_interface::m_out_irq5_cb));
+ memcpy(&(isa8bus_interface::m_out_irq6_cb),&(isa16bus_interface::m_out_irq6_cb), sizeof(isa16bus_interface::m_out_irq6_cb));
+ memcpy(&(isa8bus_interface::m_out_irq7_cb),&(isa16bus_interface::m_out_irq7_cb), sizeof(isa16bus_interface::m_out_irq7_cb));
+ memcpy(&(isa8bus_interface::m_out_drq1_cb),&(isa16bus_interface::m_out_drq1_cb), sizeof(isa16bus_interface::m_out_drq1_cb));
+ memcpy(&(isa8bus_interface::m_out_drq2_cb),&(isa16bus_interface::m_out_drq2_cb), sizeof(isa16bus_interface::m_out_drq2_cb));
+ memcpy(&(isa8bus_interface::m_out_drq3_cb),&(isa16bus_interface::m_out_drq3_cb), sizeof(isa16bus_interface::m_out_drq3_cb));
+ }
+
+ // or initialize to defaults if none provided
+ else
+ {
+ memset(&(isa8bus_interface::m_out_irq2_cb), 0, sizeof(isa8bus_interface::m_out_irq2_cb));
+ memset(&(isa8bus_interface::m_out_irq3_cb), 0, sizeof(isa8bus_interface::m_out_irq3_cb));
+ memset(&(isa8bus_interface::m_out_irq4_cb), 0, sizeof(isa8bus_interface::m_out_irq4_cb));
+ memset(&(isa8bus_interface::m_out_irq5_cb), 0, sizeof(isa8bus_interface::m_out_irq5_cb));
+ memset(&(isa8bus_interface::m_out_irq6_cb), 0, sizeof(isa8bus_interface::m_out_irq6_cb));
+ memset(&(isa8bus_interface::m_out_irq7_cb), 0, sizeof(isa8bus_interface::m_out_irq7_cb));
+
+ memset(&m_out_irq10_cb, 0, sizeof(m_out_irq10_cb));
+ memset(&m_out_irq11_cb, 0, sizeof(m_out_irq11_cb));
+ memset(&m_out_irq12_cb, 0, sizeof(m_out_irq12_cb));
+ memset(&m_out_irq14_cb, 0, sizeof(m_out_irq14_cb));
+ memset(&m_out_irq15_cb, 0, sizeof(m_out_irq15_cb));
+
+ memset(&m_out_drq0_cb, 0, sizeof(m_out_drq0_cb));
+ memset(&(isa8bus_interface::m_out_drq1_cb), 0, sizeof(isa8bus_interface::m_out_drq1_cb));
+ memset(&(isa8bus_interface::m_out_drq2_cb), 0, sizeof(isa8bus_interface::m_out_drq2_cb));
+ memset(&(isa8bus_interface::m_out_drq3_cb), 0, sizeof(isa8bus_interface::m_out_drq3_cb));
+
+ memset(&m_out_drq5_cb, 0, sizeof(m_out_drq5_cb));
+ memset(&m_out_drq6_cb, 0, sizeof(m_out_drq6_cb));
+ memset(&m_out_drq7_cb, 0, sizeof(m_out_drq7_cb));
+ }
+ m_maincpu = mconfig().device<cpu_device>(m_cputag);
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa16_device::device_start()
+{
+ isa8_device::device_start();
+
+ // resolve callbacks
+ m_out_irq10_func.resolve(m_out_irq10_cb, *this);
+ m_out_irq11_func.resolve(m_out_irq11_cb, *this);
+ m_out_irq12_func.resolve(m_out_irq12_cb, *this);
+ m_out_irq14_func.resolve(m_out_irq14_cb, *this);
+ m_out_irq15_func.resolve(m_out_irq15_cb, *this);
+
+ m_out_drq0_func.resolve(m_out_drq0_cb, *this);
+ m_out_drq5_func.resolve(m_out_drq5_cb, *this);
+ m_out_drq6_func.resolve(m_out_drq6_cb, *this);
+ m_out_drq7_func.resolve(m_out_drq7_cb, *this);
+}
+
+void isa16_device::install16_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_delegate rhandler, write16_delegate whandler)
+{
+ int buswidth = m_prgwidth;
+ switch(buswidth)
+ {
+ case 16:
+ m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0);
+ break;
+ case 32:
+ m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ if ((start % 4) == 0) {
+ if ((end-start)==1) {
+ m_iospace->install_readwrite_handler(start, end+2, mask, mirror, rhandler, whandler, 0x0000ffff);
+ } else {
+ m_iospace->install_readwrite_handler(start, end, mask, mirror, rhandler, whandler, 0xffffffff);
+ }
+ } else {
+ // we handle just misalligned by 2
+ m_iospace->install_readwrite_handler(start-2, end, mask, mirror, rhandler, whandler, 0xffff0000);
+ }
+
+ break;
+ default:
+ fatalerror("ISA16: Bus width %d not supported\n", buswidth);
+ break;
+ }
+}
+
+READ16_MEMBER(isa16_device::prog16_r)
+{
+ return m_prgspace->read_word(offset<<1, mem_mask);
+}
+
+WRITE16_MEMBER(isa16_device::prog16_w)
+{
+ m_prgspace->write_word(offset<<1, data, mem_mask);
+}
+
+READ16_MEMBER(isa16_device::io16_r)
+{
+ return m_iospace->read_word(offset<<1, mem_mask);
+}
+
+WRITE16_MEMBER(isa16_device::io16_w)
+{
+ m_iospace->write_word(offset<<1, data, mem_mask);
+}
+
+READ16_MEMBER(isa16_device::prog16_swap_r)
+{
+ UINT16 rv;
+ mem_mask = (mem_mask<<8) | (mem_mask>>8);
+
+ rv = m_prgspace->read_word(offset<<1, mem_mask);
+
+ return (rv<<8) | (rv>>8);
+}
+
+WRITE16_MEMBER(isa16_device::prog16_swap_w)
+{
+ mem_mask = (mem_mask<<8) | (mem_mask>>8);
+ data = (data<<8) | (data>>8);
+ m_prgspace->write_word(offset<<1, data, mem_mask);
+}
+
+READ16_MEMBER(isa16_device::io16_swap_r)
+{
+ UINT16 rv;
+ mem_mask = (mem_mask<<8) | (mem_mask>>8);
+
+ rv = m_iospace->read_word(offset<<1, mem_mask);
+
+ return (rv<<8) | (rv>>8);
+}
+
+WRITE16_MEMBER(isa16_device::io16_swap_w)
+{
+ mem_mask = (mem_mask<<8) | (mem_mask>>8);
+ data = (data<<8) | (data>>8);
+ m_iospace->write_word(offset<<1, data, mem_mask);
+}
+
+// interrupt request from isa card
+WRITE_LINE_MEMBER( isa16_device::irq10_w ) { m_out_irq10_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq11_w ) { m_out_irq11_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq12_w ) { m_out_irq12_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq14_w ) { m_out_irq14_func(state); }
+WRITE_LINE_MEMBER( isa16_device::irq15_w ) { m_out_irq15_func(state); }
+
+// dma request from isa card
+WRITE_LINE_MEMBER( isa16_device::drq0_w ) { m_out_drq0_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq5_w ) { m_out_drq5_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq6_w ) { m_out_drq6_func(state); }
+WRITE_LINE_MEMBER( isa16_device::drq7_w ) { m_out_drq7_func(state); }
+
+UINT16 isa16_device::dack16_r(int line)
+{
+ if (m_dma_device[line])
+ return dynamic_cast<device_isa16_card_interface *>(m_dma_device[line])->dack16_r(line);
+ return 0xffff;
+}
+
+void isa16_device::dack16_w(int line,UINT16 data)
+{
+ if (m_dma_device[line])
+ return dynamic_cast<device_isa16_card_interface *>(m_dma_device[line])->dack16_w(line,data);
+}
+
+//-------------------------------------------------
+// device_isa16_card_interface - constructor
+//-------------------------------------------------
+
+device_isa16_card_interface::device_isa16_card_interface(const machine_config &mconfig, device_t &device)
+ : device_isa8_card_interface(mconfig,device)
+{
+}
+
+
+//-------------------------------------------------
+// ~device_isa16_card_interface - destructor
+//-------------------------------------------------
+
+device_isa16_card_interface::~device_isa16_card_interface()
+{
+}
+
+void device_isa16_card_interface::set_isa_device()
+{
+ m_isa = dynamic_cast<isa16_device *>(m_isa_dev);
+}
+
+UINT16 device_isa16_card_interface::dack16_r(int line)
+{
+ return 0;
+}
+
+void device_isa16_card_interface::dack16_w(int line,UINT16 data)
+{
+}
+
+
diff --git a/src/emu/bus/isa/isa.h b/src/emu/bus/isa/isa.h
new file mode 100644
index 00000000000..8a991804243
--- /dev/null
+++ b/src/emu/bus/isa/isa.h
@@ -0,0 +1,415 @@
+/***************************************************************************
+
+ ISA bus device
+
+
+ 8 bit ISA bus connector:
+
+ A1 O I/O CH CHK B1 GND
+ A2 IO D7 B2 I RESET
+ A3 IO D6 B3 +5V
+ A4 IO D5 B4 O IRQ2
+ A5 IO D4 B5 -5V
+ A6 IO D3 B6 O DRQ2
+ A7 IO D2 B7 -12V
+ A8 IO D1 B8 O /NOWS
+ A9 IO D0 B9 +12V
+ A10 O I/O CH RDY B10 GND
+ A11 I AEN B11 I /SMEMW
+ A12 IO A19 B12 I /SMEMR
+ A13 IO A18 B13 I /IOW
+ A14 IO A17 B14 I /IOR
+ A15 IO A16 B15 I /DACK3
+ A16 IO A15 B16 O DRQ3
+ A17 IO A14 B17 I /DACK1
+ A18 IO A13 B18 O DRQ1
+ A19 IO A12 B19 IO /REFRESH
+ A20 IO A11 B20 I CLOCK
+ A21 IO A10 B21 O IRQ7
+ A22 IO A9 B22 O IRQ6
+ A23 IO A8 B23 O IRQ5
+ A24 IO A7 B24 O IRQ4
+ A25 IO A6 B25 O IRQ3
+ A26 IO A5 B26 I /DACK2
+ A27 IO A4 B27 I T/C
+ A28 IO A3 B28 I ALE
+ A29 IO A2 B29 +5V
+ A30 IO A1 B30 I OSC
+ A31 IO A0 B31 GND
+
+ 16 bit ISA bus extension
+
+ C1 I SBHE D1 I /MEM CS 16
+ C2 IO A23 D2 I /I/O CS 16
+ C3 IO A22 D3 O IRQ10
+ C4 IO A21 D4 O IRQ11
+ C5 IO A20 D5 O IRQ12
+ C6 IO A19 D6 O IRQ15
+ C7 IO A18 D7 O IRQ14
+ C8 IO A17 D8 I /DACK0
+ C9 I /MEMR D9 O DRQ0
+ C10 I /MEMW D10 I /DACK5
+ C11 IO D8 D11 O DRQ5
+ C12 IO D9 D12 I /DACK6
+ C13 IO D10 D13 O DRQ6
+ C14 IO D11 D14 I /DACK7
+ C15 IO D12 D15 O DRQ7
+ C16 IO D13 D16 +5V
+ C17 IO D14 D17 I MASTER
+ C18 IO D15 D18 GND
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ISA_H__
+#define __ISA_H__
+
+#include "emu.h"
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_ISA8_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, ISA8, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ isa8_device::static_set_cputag(*device, _cputag);
+// include this in a driver to have ISA allocate it's own address spaces (e.g. non-x86)
+#define MCFG_ISA8_BUS_CUSTOM_SPACES() \
+ isa8_device::static_set_custom_spaces(*device);
+#define MCFG_ISA8_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _fixed) \
+ MCFG_DEVICE_ADD(_tag, ISA8_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) \
+ isa8_slot_device::static_set_isa8_slot(*device, owner, _isatag);
+#define MCFG_ISA16_BUS_ADD(_tag, _cputag, _config) \
+ MCFG_DEVICE_ADD(_tag, ISA16, 0) \
+ MCFG_DEVICE_CONFIG(_config) \
+ isa8_device::static_set_cputag(*device, _cputag);
+#define MCFG_ISA16_BUS_CUSTOM_SPACES() \
+ isa8_device::static_set_custom_spaces(*device);
+#define MCFG_ISA16_SLOT_ADD(_isatag, _tag, _slot_intf, _def_slot, _fixed) \
+ MCFG_DEVICE_ADD(_tag, ISA16_SLOT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, _fixed) \
+ isa16_slot_device::static_set_isa16_slot(*device, owner, _isatag);
+
+#define MCFG_ISA_BUS_IOCHCK(_iochck) \
+ downcast<isa8_device *>(device)->set_iochck_callback(DEVCB2_##_iochck);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class isa8_device;
+
+class isa8_slot_device : public device_t,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ isa8_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_slot_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void static_set_isa8_slot(device_t &device, device_t *owner, const char *isa_tag);
+protected:
+ // configuration
+ device_t *m_owner;
+ const char *m_isa_tag;
+};
+
+// device type definition
+extern const device_type ISA8_SLOT;
+
+// ======================> isa8bus_interface
+
+struct isa8bus_interface
+{
+ devcb_write_line m_out_irq2_cb;
+ devcb_write_line m_out_irq3_cb;
+ devcb_write_line m_out_irq4_cb;
+ devcb_write_line m_out_irq5_cb;
+ devcb_write_line m_out_irq6_cb;
+ devcb_write_line m_out_irq7_cb;
+ devcb_write_line m_out_drq1_cb;
+ devcb_write_line m_out_drq2_cb;
+ devcb_write_line m_out_drq3_cb;
+};
+
+class device_isa8_card_interface;
+// ======================> isa8_device
+class isa8_device : public device_t,
+ public isa8bus_interface,
+ public device_memory_interface
+{
+public:
+ // construction/destruction
+ isa8_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+ // inline configuration
+ static void static_set_cputag(device_t &device, const char *tag);
+ static void static_set_custom_spaces(device_t &device);
+ template<class _iochck> void set_iochck_callback(_iochck iochck) { m_write_iochck.set_callback(iochck); }
+
+ // for ISA8, put the 8-bit configs in the primary slots and the 16-bit configs in the secondary
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum) const
+ {
+ switch (spacenum)
+ {
+ case AS_PROGRAM: return &m_program_config;
+ case AS_IO: return &m_io_config;
+ case AS_DATA: return &m_program16_config;
+ case AS_3: return &m_io16_config;
+ default: fatalerror("isa: invalid memory space!\n");
+ }
+ }
+
+ ATTR_DEPRECATED void install_device(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name);
+ void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler);
+ ATTR_DEPRECATED void install_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name);
+ template<typename T> void install_device(offs_t addrstart, offs_t addrend, T &device, void (T::*map)(class address_map &map, device_t &device), int bits = 8, UINT64 unitmask = U64(0xffffffffffffffff))
+ {
+ m_iospace->install_device(addrstart, addrend, device, map, bits, unitmask);
+ }
+ void install_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, UINT8 *data);
+ void install_rom(device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, const char *tag, const char *region);
+ void install_memory(offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler);
+
+ void unmap_bank(offs_t start, offs_t end, offs_t mask, offs_t mirror);
+ void unmap_rom(offs_t start, offs_t end, offs_t mask, offs_t mirror);
+ bool is_option_rom_space_available(offs_t start, int size);
+
+ DECLARE_WRITE_LINE_MEMBER( irq2_w );
+ DECLARE_WRITE_LINE_MEMBER( irq3_w );
+ DECLARE_WRITE_LINE_MEMBER( irq4_w );
+ DECLARE_WRITE_LINE_MEMBER( irq5_w );
+ DECLARE_WRITE_LINE_MEMBER( irq6_w );
+ DECLARE_WRITE_LINE_MEMBER( irq7_w );
+
+ DECLARE_WRITE_LINE_MEMBER( drq1_w );
+ DECLARE_WRITE_LINE_MEMBER( drq2_w );
+ DECLARE_WRITE_LINE_MEMBER( drq3_w );
+
+ // 8 bit accessors for ISA-defined address spaces
+ DECLARE_READ8_MEMBER(prog_r);
+ DECLARE_WRITE8_MEMBER(prog_w);
+ DECLARE_READ8_MEMBER(io_r);
+ DECLARE_WRITE8_MEMBER(io_w);
+
+ UINT8 dack_r(int line);
+ void dack_w(int line,UINT8 data);
+ void eop_w(int channels, int state);
+
+ void nmi();
+ void set_nmi_state(bool enabled) { m_nmi_enabled = enabled; }
+
+ virtual void set_dma_channel(UINT8 channel, device_isa8_card_interface *dev, bool do_eop);
+
+ const address_space_config m_program_config, m_io_config, m_program16_config, m_io16_config;
+
+protected:
+ ATTR_DEPRECATED void install_space(address_spacenum spacenum, device_t *dev, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_device_func rhandler, const char* rhandler_name, write8_device_func whandler, const char *whandler_name);
+ ATTR_DEPRECATED void install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_space_func rhandler, const char* rhandler_name, write8_space_func whandler, const char *whandler_name);
+ void install_space(address_spacenum spacenum, offs_t start, offs_t end, offs_t mask, offs_t mirror, read8_delegate rhandler, write8_delegate whandler);
+
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+
+ // internal state
+ cpu_device *m_maincpu;
+
+ // address spaces
+ address_space *m_iospace, *m_prgspace;
+ int m_iowidth, m_prgwidth;
+ bool m_allocspaces;
+
+ devcb_resolved_write_line m_out_irq2_func;
+ devcb_resolved_write_line m_out_irq3_func;
+ devcb_resolved_write_line m_out_irq4_func;
+ devcb_resolved_write_line m_out_irq5_func;
+ devcb_resolved_write_line m_out_irq6_func;
+ devcb_resolved_write_line m_out_irq7_func;
+
+ devcb_resolved_write_line m_out_drq1_func;
+ devcb_resolved_write_line m_out_drq2_func;
+ devcb_resolved_write_line m_out_drq3_func;
+
+ device_isa8_card_interface *m_dma_device[8];
+ bool m_dma_eop[8];
+ const char *m_cputag;
+ bool m_nmi_enabled;
+
+private:
+ devcb2_write_line m_write_iochck;
+};
+
+
+// device type definition
+extern const device_type ISA8;
+
+// ======================> device_isa8_card_interface
+
+// class representing interface-specific live isa8 card
+class device_isa8_card_interface : public device_slot_card_interface
+{
+ friend class isa8_device;
+public:
+ // construction/destruction
+ device_isa8_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_isa8_card_interface();
+
+ device_isa8_card_interface *next() const { return m_next; }
+
+ void set_isa_device();
+ // configuration access
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line,UINT8 data);
+ virtual void eop_w(int state);
+
+ // inline configuration
+ static void static_set_isabus(device_t &device, device_t *isa_device);
+public:
+ isa8_device *m_isa;
+ device_t *m_isa_dev;
+ device_isa8_card_interface *m_next;
+};
+
+// ======================> isa16bus_interface
+
+struct isa16bus_interface
+{
+ devcb_write_line m_out_irq2_cb; // this goes to IRQ 9 on pic
+ devcb_write_line m_out_irq3_cb;
+ devcb_write_line m_out_irq4_cb;
+ devcb_write_line m_out_irq5_cb;
+ devcb_write_line m_out_irq6_cb;
+ devcb_write_line m_out_irq7_cb;
+
+ devcb_write_line m_out_irq10_cb;
+ devcb_write_line m_out_irq11_cb;
+ devcb_write_line m_out_irq12_cb;
+ devcb_write_line m_out_irq14_cb;
+ devcb_write_line m_out_irq15_cb;
+
+ devcb_write_line m_out_drq0_cb;
+ devcb_write_line m_out_drq1_cb;
+ devcb_write_line m_out_drq2_cb;
+ devcb_write_line m_out_drq3_cb;
+ devcb_write_line m_out_drq5_cb;
+ devcb_write_line m_out_drq6_cb;
+ devcb_write_line m_out_drq7_cb;
+};
+
+class isa16_device;
+
+class isa16_slot_device : public isa8_slot_device
+{
+public:
+ // construction/destruction
+ isa16_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // device-level overrides
+ virtual void device_start();
+
+ // inline configuration
+ static void static_set_isa16_slot(device_t &device, device_t *owner, const char *isa_tag);
+};
+
+
+// device type definition
+extern const device_type ISA16_SLOT;
+
+// ======================> isa16_device
+class isa16_device : public isa8_device,
+ public isa16bus_interface
+{
+public:
+ // construction/destruction
+ isa16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ void install16_device(offs_t start, offs_t end, offs_t mask, offs_t mirror, read16_delegate rhandler, write16_delegate whandler);
+
+ // for ISA16, put the 16-bit configs in the primary slots and the 8-bit configs in the secondary
+ virtual const address_space_config *memory_space_config(address_spacenum spacenum) const
+ {
+ switch (spacenum)
+ {
+ case AS_PROGRAM: return &m_program16_config;
+ case AS_IO: return &m_io16_config;
+ case AS_DATA: return &m_program_config;
+ case AS_3: return &m_io_config;
+ default: fatalerror("isa: invalid memory space!\n");
+ }
+ }
+
+ DECLARE_WRITE_LINE_MEMBER( irq10_w );
+ DECLARE_WRITE_LINE_MEMBER( irq11_w );
+ DECLARE_WRITE_LINE_MEMBER( irq12_w );
+ DECLARE_WRITE_LINE_MEMBER( irq14_w );
+ DECLARE_WRITE_LINE_MEMBER( irq15_w );
+
+ DECLARE_WRITE_LINE_MEMBER( drq0_w );
+ DECLARE_WRITE_LINE_MEMBER( drq5_w );
+ DECLARE_WRITE_LINE_MEMBER( drq6_w );
+ DECLARE_WRITE_LINE_MEMBER( drq7_w );
+
+ UINT16 dack16_r(int line);
+ void dack16_w(int line,UINT16 data);
+
+ // 16 bit accessors for ISA-defined address spaces
+ DECLARE_READ16_MEMBER(prog16_r);
+ DECLARE_WRITE16_MEMBER(prog16_w);
+ DECLARE_READ16_MEMBER(io16_r);
+ DECLARE_WRITE16_MEMBER(io16_w);
+ // byte-swapped versions of 16-bit accessors
+ DECLARE_READ16_MEMBER(prog16_swap_r);
+ DECLARE_WRITE16_MEMBER(prog16_swap_w);
+ DECLARE_READ16_MEMBER(io16_swap_r);
+ DECLARE_WRITE16_MEMBER(io16_swap_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_config_complete();
+
+private:
+ // internal state
+ devcb_resolved_write_line m_out_irq10_func;
+ devcb_resolved_write_line m_out_irq11_func;
+ devcb_resolved_write_line m_out_irq12_func;
+ devcb_resolved_write_line m_out_irq14_func;
+ devcb_resolved_write_line m_out_irq15_func;
+
+ devcb_resolved_write_line m_out_drq0_func;
+ devcb_resolved_write_line m_out_drq5_func;
+ devcb_resolved_write_line m_out_drq6_func;
+ devcb_resolved_write_line m_out_drq7_func;
+};
+
+
+// device type definition
+extern const device_type ISA16;
+
+// ======================> device_isa16_card_interface
+
+// class representing interface-specific live isa16 card
+class device_isa16_card_interface : public device_isa8_card_interface
+{
+ friend class isa16_device;
+public:
+ // construction/destruction
+ device_isa16_card_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_isa16_card_interface();
+ virtual UINT16 dack16_r(int line);
+ virtual void dack16_w(int line,UINT16 data);
+
+ void set_isa_device();
+ isa16_device *m_isa;
+};
+
+#endif /* __ISA_H__ */
diff --git a/src/emu/bus/isa/isa_cards.c b/src/emu/bus/isa/isa_cards.c
new file mode 100644
index 00000000000..ab1bfe449c6
--- /dev/null
+++ b/src/emu/bus/isa/isa_cards.c
@@ -0,0 +1,88 @@
+/**********************************************************************
+
+ ISA cards
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+**********************************************************************/
+
+#include "isa_cards.h"
+
+SLOT_INTERFACE_START( pc_isa8_cards )
+ SLOT_INTERFACE("mda", ISA8_MDA)
+ SLOT_INTERFACE("cga", ISA8_CGA)
+ SLOT_INTERFACE("cga_ec1841", ISA8_EC1841_0002)
+ SLOT_INTERFACE("ega", ISA8_EGA)
+ SLOT_INTERFACE("svga_et4k", ISA8_SVGA_ET4K)
+ SLOT_INTERFACE("com", ISA8_COM)
+ SLOT_INTERFACE("fdc", ISA8_FDC_SUPERIO)
+ SLOT_INTERFACE("fdc_xt", ISA8_FDC_XT)
+ SLOT_INTERFACE("fdc_at", ISA8_FDC_AT)
+ SLOT_INTERFACE("fdc_smc", ISA8_FDC_SMC)
+ SLOT_INTERFACE("fdc_ps2", ISA8_FDC_PS2)
+ SLOT_INTERFACE("fdc344", ISA8_FDC344)
+ SLOT_INTERFACE("fdcmag", ISA8_FDCMAG)
+ SLOT_INTERFACE("wdxt_gen", ISA8_WDXT_GEN)
+ SLOT_INTERFACE("finalchs", ISA8_FINALCHS)
+ SLOT_INTERFACE("xtide", ISA8_XTIDE)
+ SLOT_INTERFACE("side116", ISA8_SIDE116)
+ SLOT_INTERFACE("hdc", ISA8_HDC)
+ SLOT_INTERFACE("adlib", ISA8_ADLIB)
+ SLOT_INTERFACE("hercules", ISA8_HERCULES)
+ SLOT_INTERFACE("gblaster", ISA8_GAME_BLASTER)
+ SLOT_INTERFACE("sblaster1_0", ISA8_SOUND_BLASTER_1_0)
+ SLOT_INTERFACE("sblaster1_5", ISA8_SOUND_BLASTER_1_5)
+ SLOT_INTERFACE("stereo_fx", ISA8_STEREO_FX)
+ SLOT_INTERFACE("mpu401", ISA8_MPU401)
+ SLOT_INTERFACE("ne1000", NE1000)
+ SLOT_INTERFACE("3c503", EL2_3C503)
+ SLOT_INTERFACE("lpt", ISA8_LPT)
+ SLOT_INTERFACE("ibm_mfc", ISA8_IBM_MFC)
+ SLOT_INTERFACE("wd1002a_wx1", ISA8_WD1002A_WX1)
+ SLOT_INTERFACE("dectalk", ISA8_DECTALK)
+ SLOT_INTERFACE("pds", ISA8_PDS)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( pc_isa16_cards )
+ // 8-bit
+ SLOT_INTERFACE("mda", ISA8_MDA)
+ SLOT_INTERFACE("cga", ISA8_CGA)
+ SLOT_INTERFACE("wyse700", ISA8_WYSE700)
+ SLOT_INTERFACE("ega", ISA8_EGA)
+ SLOT_INTERFACE("vga", ISA8_VGA)
+ SLOT_INTERFACE("svga_et4k", ISA8_SVGA_ET4K)
+ SLOT_INTERFACE("svga_dm",ISA8_SVGA_CIRRUS)
+ SLOT_INTERFACE("com", ISA8_COM)
+ SLOT_INTERFACE("comat", ISA8_COM_AT)
+ SLOT_INTERFACE("fdc", ISA8_FDC_AT)
+ SLOT_INTERFACE("fdc344", ISA8_FDC344)
+ SLOT_INTERFACE("fdcmag", ISA8_FDCMAG)
+ SLOT_INTERFACE("hdc", ISA8_HDC)
+ SLOT_INTERFACE("side116", ISA8_SIDE116)
+ SLOT_INTERFACE("adlib", ISA8_ADLIB)
+ SLOT_INTERFACE("hercules", ISA8_HERCULES)
+ SLOT_INTERFACE("gblaster", ISA8_GAME_BLASTER)
+ SLOT_INTERFACE("sblaster1_0", ISA8_SOUND_BLASTER_1_0)
+ SLOT_INTERFACE("sblaster1_5", ISA8_SOUND_BLASTER_1_5)
+ SLOT_INTERFACE("stereo_fx", ISA8_STEREO_FX)
+ SLOT_INTERFACE("ssi2001", ISA8_SSI2001)
+ SLOT_INTERFACE("ne1000", NE1000)
+ SLOT_INTERFACE("3c503", EL2_3C503)
+ SLOT_INTERFACE("mpu401", ISA8_MPU401)
+ SLOT_INTERFACE("lpt", ISA8_LPT)
+ SLOT_INTERFACE("ibm_mfc", ISA8_IBM_MFC)
+ SLOT_INTERFACE("fdcsmc", ISA8_FDC_SMC)
+ SLOT_INTERFACE("dectalk", ISA8_DECTALK)
+ SLOT_INTERFACE("pds", ISA8_PDS)
+ // 16-bit
+ SLOT_INTERFACE("ide", ISA16_IDE)
+ SLOT_INTERFACE("ne2000", NE2000)
+ SLOT_INTERFACE("aha1542", AHA1542)
+ SLOT_INTERFACE("gus",ISA16_GUS)
+ SLOT_INTERFACE("sblaster_16", ISA16_SOUND_BLASTER_16)
+ SLOT_INTERFACE("svga_s3", ISA16_SVGA_S3)
+ SLOT_INTERFACE("s3virge", ISA16_S3VIRGE)
+ SLOT_INTERFACE("s3virgedx", ISA16_S3VIRGEDX)
+ SLOT_INTERFACE("gfxultra", ISA16_VGA_GFXULTRA)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/isa/isa_cards.h b/src/emu/bus/isa/isa_cards.h
new file mode 100644
index 00000000000..e7af7dd9116
--- /dev/null
+++ b/src/emu/bus/isa/isa_cards.h
@@ -0,0 +1,66 @@
+/**********************************************************************
+
+ ISA cards
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ISA_CARDS_H__
+#define __ISA_CARDS_H__
+
+#include "emu.h"
+
+// video
+#include "mda.h"
+#include "cga.h"
+#include "ega.h"
+#include "vga.h"
+#include "vga_ati.h"
+#include "svga_cirrus.h"
+#include "svga_s3.h"
+#include "svga_tseng.h"
+
+// storage
+#include "fdc.h"
+#include "mufdc.h"
+#include "hdc.h"
+#include "wdxt_gen.h"
+#include "ide.h"
+#include "xtide.h"
+#include "side116.h"
+#include "aha1542.h"
+#include "wd1002a_wx1.h"
+
+// sound
+#include "adlib.h"
+#include "gblaster.h"
+#include "gus.h"
+#include "ibm_mfc.h"
+#include "mpu401.h"
+#include "sblaster.h"
+#include "ssi2001.h"
+#include "stereo_fx.h"
+#include "dectalk.h"
+
+// network
+#include "3c503.h"
+#include "ne1000.h"
+#include "ne2000.h"
+
+// communication ports
+#include "lpt.h"
+#include "com.h"
+#include "pds.h"
+
+// other
+#include "finalchs.h"
+
+// supported devices
+SLOT_INTERFACE_EXTERN( pc_isa8_cards );
+SLOT_INTERFACE_EXTERN( pc_isa16_cards );
+
+#endif // __ISA_CARDS_H__
diff --git a/src/emu/bus/isa/lpt.c b/src/emu/bus/isa/lpt.c
new file mode 100644
index 00000000000..6dc19606a49
--- /dev/null
+++ b/src/emu/bus/isa/lpt.c
@@ -0,0 +1,67 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#include "emu.h"
+#include "lpt.h"
+#include "machine/pc_lpt.h"
+#include "bus/centronics/covox.h"
+#include "bus/centronics/image.h"
+
+const device_type ISA8_LPT = &device_creator<isa8_lpt_device>;
+
+isa8_lpt_device::isa8_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_LPT, "Printer Adapter", tag, owner, clock, "isa_lpt", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+static MACHINE_CONFIG_FRAGMENT( lpt_config )
+ MCFG_DEVICE_ADD("lpt", PC_LPT, 0)
+ MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_lpt_device, pc_cpu_line))
+MACHINE_CONFIG_END
+
+machine_config_constructor isa8_lpt_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( lpt_config );
+}
+
+static INPUT_PORTS_START( lpt_dsw )
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x01, 0x00, "Base address")
+ PORT_DIPSETTING( 0x00, "0x378" )
+ PORT_DIPSETTING( 0x01, "0x278" )
+INPUT_PORTS_END
+
+ioport_constructor isa8_lpt_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( lpt_dsw );
+}
+
+void isa8_lpt_device::device_start()
+{
+ set_isa_device();
+}
+
+void isa8_lpt_device::device_reset()
+{
+ m_is_primary = (ioport("DSW")->read() & 1) ? false : true;
+ if (m_is_primary)
+ {
+ m_isa->install_device(0x0378, 0x037b, 0, 0, read8_delegate(FUNC(pc_lpt_device::read), subdevice<pc_lpt_device>("lpt")), write8_delegate(FUNC(pc_lpt_device::write), subdevice<pc_lpt_device>("lpt")));
+ }
+ else
+ {
+ m_isa->install_device(0x0278, 0x027b, 0, 0, read8_delegate(FUNC(pc_lpt_device::read), subdevice<pc_lpt_device>("lpt")), write8_delegate(FUNC(pc_lpt_device::write), subdevice<pc_lpt_device>("lpt")));
+ }
+}
+
+WRITE_LINE_MEMBER(isa8_lpt_device::pc_cpu_line)
+{
+ if (is_primary())
+ m_isa->irq7_w(state);
+ else
+ m_isa->irq5_w(state);
+}
diff --git a/src/emu/bus/isa/lpt.h b/src/emu/bus/isa/lpt.h
new file mode 100644
index 00000000000..28d239e208b
--- /dev/null
+++ b/src/emu/bus/isa/lpt.h
@@ -0,0 +1,48 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#ifndef __ISA_LPT_H__
+#define __ISA_LPT_H__
+
+#include "isa.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_lpt_device
+
+class isa8_lpt_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ bool is_primary() { return m_is_primary; }
+
+ WRITE_LINE_MEMBER(pc_cpu_line);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+
+ // internal state
+ bool m_is_primary;
+};
+
+// device type definition
+extern const device_type ISA8_LPT;
+
+#endif /* __ISA_LPT_H__ */
diff --git a/src/emu/bus/isa/mc1502_fdc.c b/src/emu/bus/isa/mc1502_fdc.c
new file mode 100644
index 00000000000..6fbf87681f7
--- /dev/null
+++ b/src/emu/bus/isa/mc1502_fdc.c
@@ -0,0 +1,240 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Electronika MC 1502 FDC device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "mc1502_fdc.h"
+
+#include "cpu/i86/i86.h"
+#include "formats/dsk_dsk.h"
+#include "formats/pc_dsk.h"
+
+#define VERBOSE_DBG 0
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_DBG>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MC1502_FDC = &device_creator<mc1502_fdc_device>;
+
+static DECLARE_READ8_DEVICE_HANDLER(mc1502_FDC_r);
+static DECLARE_WRITE8_DEVICE_HANDLER(mc1502_FDC_w);
+
+FLOPPY_FORMATS_MEMBER( mc1502_fdc_device::floppy_formats )
+ FLOPPY_PC_FORMAT,
+ FLOPPY_DSK_FORMAT
+FLOPPY_FORMATS_END
+
+static SLOT_INTERFACE_START( mc1502_floppies )
+ SLOT_INTERFACE( "525qd", FLOPPY_525_QD )
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( mc1502_fdc )
+ MCFG_FD1793x_ADD("fdc", XTAL_16MHz / 16)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", mc1502_floppies, "525qd", mc1502_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", mc1502_floppies, "525qd", mc1502_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// ROM( mc1502_fdc )
+//-------------------------------------------------
+
+ROM_START( mc1502_fdc )
+ROM_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor mc1502_fdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( mc1502_fdc );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *mc1502_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( mc1502_fdc );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+TIMER_CALLBACK_MEMBER(mc1502_fdc_device::motor_callback)
+{
+ m_fdc->subdevice<floppy_connector>("0")->get_device()->mon_w(ASSERT_LINE);
+ m_fdc->subdevice<floppy_connector>("1")->get_device()->mon_w(ASSERT_LINE);
+ motor_on = 0;
+}
+
+UINT8 mc1502_fdc_device::mc1502_wd17xx_aux_r()
+{
+ UINT8 data;
+
+ data = 0;
+
+ return data;
+}
+
+void mc1502_fdc_device::mc1502_wd17xx_aux_w(UINT8 data)
+{
+ floppy_image_device *floppy0 = m_fdc->subdevice<floppy_connector>("0")->get_device();
+ floppy_image_device *floppy1 = m_fdc->subdevice<floppy_connector>("1")->get_device();
+ floppy_image_device *floppy = ((data & 0x10)?floppy1:floppy0);
+
+ // master reset
+ if((data & 1) == 0)
+ m_fdc->reset();
+
+ m_fdc->set_floppy(floppy);
+
+ // SIDE ONE
+ floppy->ss_w((data & 2)?1:0);
+
+ // bits 2, 3 -- motor on (drive 0, 1)
+ floppy0->mon_w(!(data & 4));
+ floppy1->mon_w(!(data & 8));
+
+ if (data & 12) {
+ motor_timer->adjust(attotime::from_msec( 3000 ));
+ motor_on = 1;
+ }
+
+}
+
+/*
+ * Accesses to this port block (halt the CPU until DRQ, INTRQ or MOTOR ON)
+ */
+UINT8 mc1502_fdc_device::mc1502_wd17xx_drq_r()
+{
+ cpu_device *maincpu = machine().device<cpu_device>("maincpu");
+
+ if (!m_fdc->drq_r() && !m_fdc->intrq_r()) {
+ // fake cpu wait by resetting PC one insn back
+ maincpu->set_state_int(I8086_IP, maincpu->state_int(I8086_IP) - 1);
+ maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+ }
+
+ return m_fdc->drq_r();
+}
+
+UINT8 mc1502_fdc_device::mc1502_wd17xx_motor_r()
+{
+ return motor_on;
+}
+
+void mc1502_fdc_device::mc1502_fdc_irq_drq(bool state)
+{
+ cpu_device *maincpu = machine().device<cpu_device>("maincpu");
+
+ if(state)
+ maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+}
+
+static READ8_DEVICE_HANDLER( mc1502_FDC_r )
+{
+ UINT8 data = 0xff;
+ mc1502_fdc_device *fdc = downcast<mc1502_fdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: data = fdc->mc1502_wd17xx_aux_r(); break;
+ case 8: data = fdc->mc1502_wd17xx_drq_r(); break;
+ case 10: data = fdc->mc1502_wd17xx_motor_r(); break;
+ }
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( mc1502_FDC_w )
+{
+ mc1502_fdc_device *fdc = downcast<mc1502_fdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: fdc->mc1502_wd17xx_aux_w(data); break;
+ }
+}
+
+//-------------------------------------------------
+// mc1502_fdc_device - constructor
+//-------------------------------------------------
+
+mc1502_fdc_device::mc1502_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, MC1502_FDC, "MC-1502 floppy", tag, owner, clock, "mc1502_fdc", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_fdc(*this, "fdc")
+{
+}
+
+#if 0
+ AM_RANGE(0x004c, 0x004c) AM_READWRITE(mc1502_wd17xx_aux_r, mc1502_wd17xx_aux_w)
+ AM_RANGE(0x004d, 0x004d) AM_READ(mc1502_wd17xx_motor_r)
+ AM_RANGE(0x004e, 0x004e) AM_READ(mc1502_wd17xx_drq_r) // blocking read!
+ AM_RANGE(0x0048, 0x004b) AM_DEVREADWRITE("vg93", fd1793_t, read, write)
+
+ AM_RANGE(0x0100, 0x0100) AM_READWRITE(mc1502_wd17xx_aux_r, mc1502_wd17xx_aux_w)
+ AM_RANGE(0x0108, 0x0108) AM_READ(mc1502_wd17xx_drq_r) // blocking read!
+ AM_RANGE(0x010a, 0x010a) AM_READ(mc1502_wd17xx_motor_r)
+ AM_RANGE(0x010c, 0x010f) AM_DEVREADWRITE("vg93", fd1793_t, read, write)
+#endif
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc1502_fdc_device::device_start()
+{
+ set_isa_device();
+
+ // BIOS 5.0, 5.2
+ m_isa->install_device(0x010c, 0x010f, 0, 0,
+ READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read),
+ WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) );
+ m_isa->install_device(this, 0x0100, 0x010b, 0, 0, FUNC(mc1502_FDC_r), FUNC(mc1502_FDC_w) );
+ // BIOS 5.31, 5.33
+/*
+ m_isa->install_device(0x010c, 0x010f, 0, 0,
+ READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read),
+ WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) );
+ m_isa->install_device(this, 0x0100, 0x010b, 0, 0, FUNC(mc1502_FDC_r), FUNC(mc1502_FDC_w) );
+*/
+ m_fdc->setup_drq_cb(fd1793_t::line_cb(FUNC(mc1502_fdc_device::mc1502_fdc_irq_drq), this));
+ m_fdc->setup_intrq_cb(fd1793_t::line_cb(FUNC(mc1502_fdc_device::mc1502_fdc_irq_drq), this));
+
+ motor_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(mc1502_fdc_device::motor_callback),this));
+ motor_on = 0;
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc1502_fdc_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/mc1502_fdc.h b/src/emu/bus/isa/mc1502_fdc.h
new file mode 100644
index 00000000000..8454eb88b5d
--- /dev/null
+++ b/src/emu/bus/isa/mc1502_fdc.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Electronika MC 1502 FDC device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MC1502_FDC__
+#define __MC1502_FDC__
+
+#include "emu.h"
+
+#include "imagedev/flopdrv.h"
+#include "isa.h"
+#include "machine/wd_fdc.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class mc1502_fdc_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ mc1502_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_FLOPPY_FORMATS( floppy_formats );
+ TIMER_CALLBACK_MEMBER( motor_callback );
+
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_device<fd1793_t> m_fdc;
+ int motor_on;
+ emu_timer *motor_timer;
+
+public:
+ void mc1502_wd17xx_aux_w(UINT8 data);
+ UINT8 mc1502_wd17xx_aux_r();
+ UINT8 mc1502_wd17xx_drq_r();
+ UINT8 mc1502_wd17xx_motor_r();
+ void mc1502_fdc_irq_drq(bool state);
+
+};
+
+
+// device type definition
+extern const device_type MC1502_FDC;
+
+
+#endif
diff --git a/src/emu/bus/isa/mc1502_rom.c b/src/emu/bus/isa/mc1502_rom.c
new file mode 100644
index 00000000000..6dfc16f7799
--- /dev/null
+++ b/src/emu/bus/isa/mc1502_rom.c
@@ -0,0 +1,74 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ MC-1502 ROM cartridge device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "mc1502_rom.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type MC1502_ROM = &device_creator<mc1502_rom_device>;
+
+
+//-------------------------------------------------
+// ROM( mc1502_rom )
+//-------------------------------------------------
+
+ROM_START( mc1502_rom )
+ ROM_REGION( 0x8000, "mc1502_rom", 0 )
+ ROM_LOAD( "basic.rom", 0x00000, 0x8000, CRC(173d69fa) SHA1(003f872e12f00800e22ab6bbc009d36bfde67b9d))
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *mc1502_rom_device::device_rom_region() const
+{
+ return ROM_NAME( mc1502_rom );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mc1502_rom_device - constructor
+//-------------------------------------------------
+
+mc1502_rom_device::mc1502_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, MC1502_ROM, "MC-1502 ROM cart", tag, owner, clock, "mc1502_rom", __FILE__),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mc1502_rom_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xe8000, 0xeffff, 0, 0, "XXX", "mc1502_rom");
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mc1502_rom_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/mc1502_rom.h b/src/emu/bus/isa/mc1502_rom.h
new file mode 100644
index 00000000000..dbf00713c76
--- /dev/null
+++ b/src/emu/bus/isa/mc1502_rom.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ MC-1502 ROM cartridge device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __MC1502_ROM__
+#define __MC1502_ROM__
+
+#include "emu.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class mc1502_rom_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ mc1502_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type MC1502_ROM;
+
+
+#endif
diff --git a/src/emu/bus/isa/mda.c b/src/emu/bus/isa/mda.c
new file mode 100644
index 00000000000..f0088c9fede
--- /dev/null
+++ b/src/emu/bus/isa/mda.c
@@ -0,0 +1,745 @@
+/***************************************************************************
+
+ Monochrome Display Adapter (MDA) section
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mda.h"
+#include "video/mc6845.h"
+#include "machine/pc_lpt.h"
+
+#define MDA_SCREEN_NAME "mda_screen"
+#define MDA_MC6845_NAME "mc6845_mda"
+
+/*
+ Hercules video card
+ */
+#define HERCULES_SCREEN_NAME "hercules_screen"
+#define HERCULES_MC6845_NAME "mc6845_hercules"
+
+#define VERBOSE_MDA 0 /* MDA (Monochrome Display Adapter) */
+
+#define MDA_CLOCK 16257000
+
+#define MDA_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_MDA>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",device->machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+static const unsigned char mda_palette[4][3] =
+{
+ { 0x00,0x00,0x00 },
+ { 0x00,0x55,0x00 },
+ { 0x00,0xaa,0x00 },
+ { 0x00,0xff,0x00 }
+};
+
+static MC6845_UPDATE_ROW( mda_update_row );
+
+/* F4 Character Displayer */
+static const gfx_layout pc_16_charlayout =
+{
+ 8, 16, /* 8 x 16 characters */
+ 256, /* 256 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8, 2048*8, 2049*8, 2050*8, 2051*8, 2052*8, 2053*8, 2054*8, 2055*8 },
+ 8*8 /* every char takes 2 x 8 bytes */
+};
+
+static const gfx_layout pc_8_charlayout =
+{
+ 8, 8, /* 8 x 8 characters */
+ 512, /* 512 characters */
+ 1, /* 1 bits per pixel */
+ { 0 }, /* no bitplanes */
+ /* x offsets */
+ { 0, 1, 2, 3, 4, 5, 6, 7 },
+ /* y offsets */
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8 /* every char takes 8 bytes */
+};
+
+static GFXDECODE_START( pcmda )
+ GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 )
+ GFXDECODE_ENTRY( "gfx1", 0x1000, pc_8_charlayout, 1, 1 )
+GFXDECODE_END
+
+
+static MC6845_INTERFACE( mc6845_mda_intf )
+{
+ false, /* show border area */
+ 0,0,0,0, /* visarea adjustment */
+ 9, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ mda_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+WRITE_LINE_MEMBER(isa8_mda_device::pc_cpu_line)
+{
+ m_isa->irq7_w(state);
+}
+
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_mda )
+ MCFG_SCREEN_ADD( MDA_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 )
+ MCFG_SCREEN_UPDATE_DEVICE( MDA_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_ADD( "palette", 4 )
+
+ MCFG_MC6845_ADD( MDA_MC6845_NAME, MC6845, MDA_SCREEN_NAME, MDA_CLOCK/9, mc6845_mda_intf)
+
+ MCFG_GFXDECODE_ADD("gfxdecode", pcmda)
+
+ MCFG_DEVICE_ADD("lpt", PC_LPT, 0)
+ MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_mda_device, pc_cpu_line))
+MACHINE_CONFIG_END
+
+ROM_START( mda )
+ /* IBM 1501981(CGA) and 1501985(MDA) Character rom */
+ ROM_REGION(0x08100,"gfx1", 0)
+ ROM_LOAD("5788005.u33", 0x00000, 0x02000, CRC(0bf56d70) SHA1(c2a8b10808bf51a3c123ba3eb1e9dd608231916f)) /* "AMI 8412PI // 5788005 // (C) IBM CORP. 1981 // KOREA" */
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_MDA = &device_creator<isa8_mda_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_mda_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_mda );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_mda_device::device_rom_region() const
+{
+ return ROM_NAME( mda );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_mda_device - constructor
+//-------------------------------------------------
+
+isa8_mda_device::isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_MDA, "IBM Monochrome Display and Printer Adapter", tag, owner, clock, "isa_ibm_mda", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_palette(*this, "palette")
+{
+}
+
+isa8_mda_device::isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_isa8_card_interface(mconfig, *this),
+ m_palette(*this, "palette")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_mda_device::device_start()
+{
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ set_isa_device();
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x1000);
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_mda_device::io_read), this ), write8_delegate( FUNC(isa8_mda_device::io_write), this ) );
+ m_isa->install_bank(0xb0000, 0xb0fff, 0, 0x07000, "bank_mda", m_videoram);
+
+ /* Initialise the mda palette */
+ for(int i = 0; i < 4; i++)
+ m_palette->set_pen_color(i, rgb_t(mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_mda_device::device_reset()
+{
+ m_update_row = NULL;
+ m_framecnt = 0;
+ m_mode_control = 0;
+ m_vsync = 0;
+ m_hsync = 0;
+ m_pixel = 0;
+
+ astring tempstring;
+ m_chr_gen = memregion(subtag(tempstring, "gfx1"))->base();
+}
+
+/***************************************************************************
+
+ Monochrome Display Adapter (MDA) section
+
+***************************************************************************/
+
+/***************************************************************************
+ Draw text mode with 80x25 characters (default) and intense background.
+ The character cell size is 9x15. Column 9 is column 8 repeated for
+ character codes 176 to 223.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( mda_text_inten_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ const rgb_t *palette = mda->m_palette->palette()->entry_list_raw();
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) MDA_LOG(1,"mda_text_inten_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = mda->m_videoram[ offset ];
+ UINT8 attr = mda->m_videoram[ offset + 1 ];
+ UINT8 data = mda->m_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 )
+ {
+ data = 0x00;
+ }
+
+ switch( attr )
+ {
+ case 0x70:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ bg = 2;
+ fg = 1;
+ break;
+ case 0xF0:
+ bg = 3;
+ fg = 0;
+ break;
+ case 0xF8:
+ bg = 3;
+ fg = 1;
+ break;
+ }
+
+ if ( ( i == cursor_x && ( mda->m_framecnt & 0x08 ) ) || ( attr & 0x07 ) == 0x01 )
+ {
+ data = 0xFF;
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 )
+ {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+ else
+ {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+/***************************************************************************
+ Draw text mode with 80x25 characters (default) and blinking characters.
+ The character cell size is 9x15. Column 9 is column 8 repeated for
+ character codes 176 to 223.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( mda_text_blink_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ const rgb_t *palette = mda->m_palette->palette()->entry_list_raw();
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 chr_base = ( ra & 0x08 ) ? 0x800 | ( ra & 0x07 ) : ra;
+ int i;
+
+ if ( y == 0 ) MDA_LOG(1,"mda_text_blink_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT16 offset = ( ( ma + i ) << 1 ) & 0x0FFF;
+ UINT8 chr = mda->m_videoram[ offset ];
+ UINT8 attr = mda->m_videoram[ offset + 1 ];
+ UINT8 data = mda->m_chr_gen[ chr_base + chr * 8 ];
+ UINT8 fg = ( attr & 0x08 ) ? 3 : 2;
+ UINT8 bg = 0;
+
+ if ( ( attr & ~0x88 ) == 0 )
+ {
+ data = 0x00;
+ }
+
+ switch( attr )
+ {
+ case 0x70:
+ case 0xF0:
+ bg = 2;
+ fg = 0;
+ break;
+ case 0x78:
+ case 0xF8:
+ bg = 2;
+ fg = 1;
+ break;
+ }
+
+ if ( ( attr & 0x07 ) == 0x01 )
+ {
+ data = 0xFF;
+ }
+
+ if ( i == cursor_x )
+ {
+ if ( mda->m_framecnt & 0x08 )
+ {
+ data = 0xFF;
+ }
+ }
+ else
+ {
+ if ( ( attr & 0x80 ) && ( mda->m_framecnt & 0x10 ) )
+ {
+ data = 0x00;
+ }
+ }
+
+ *p = palette[( data & 0x80 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x40 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x20 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x10 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x08 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x04 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x02 ) ? fg : bg]; p++;
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ if ( ( chr & 0xE0 ) == 0xC0 )
+ {
+ *p = palette[( data & 0x01 ) ? fg : bg]; p++;
+ }
+ else
+ {
+ *p = palette[bg]; p++;
+ }
+ }
+}
+
+
+static MC6845_UPDATE_ROW( mda_update_row )
+{
+ isa8_mda_device *mda = downcast<isa8_mda_device *>(device->owner());
+ if ( mda->m_update_row )
+ {
+ mda->m_update_row( device, bitmap, cliprect, ma, ra, y, x_count, cursor_x, param );
+ }
+}
+
+
+WRITE_LINE_MEMBER( isa8_mda_device::hsync_changed )
+{
+ m_hsync = state ? 1 : 0;
+}
+
+
+WRITE_LINE_MEMBER( isa8_mda_device::vsync_changed )
+{
+ m_vsync = state ? 0x80 : 0;
+ if ( state )
+ {
+ m_framecnt++;
+ }
+}
+
+
+/*
+ * rW MDA mode control register (see #P138)
+ */
+WRITE8_MEMBER( isa8_mda_device::mode_control_w )
+{
+ m_mode_control = data;
+
+ switch( m_mode_control & 0x2a )
+ {
+ case 0x08:
+ m_update_row = mda_text_inten_update_row;
+ break;
+ case 0x28:
+ m_update_row = mda_text_blink_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ }
+}
+
+
+/* R- CRT status register (see #P139)
+ * (EGA/VGA) input status 1 register
+ * 7 HGC vertical sync in progress
+ * 6-4 adapter 000 hercules
+ * 001 hercules+
+ * 101 hercules InColor
+ * else unknown
+ * 3 pixel stream (0 black, 1 white)
+ * 2-1 reserved
+ * 0 horizontal drive enable
+ */
+READ8_MEMBER( isa8_mda_device::status_r)
+{
+ // Faking pixel stream here
+ m_pixel++;
+
+ return 0xF0 | (m_pixel & 0x08) | m_hsync;
+}
+
+
+/*************************************************************************
+ *
+ * MDA
+ * monochrome display adapter
+ *
+ *************************************************************************/
+WRITE8_MEMBER( isa8_mda_device::io_write)
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(MDA_MC6845_NAME);
+ pc_lpt_device *lpt = subdevice<pc_lpt_device>("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(space, offset, data);
+ break;
+ case 12: case 13: case 14:
+ lpt->write(space, offset - 12, data);
+ break;
+ }
+}
+
+READ8_MEMBER( isa8_mda_device::io_read)
+{
+ int data = 0xff;
+ mc6845_device *mc6845 = subdevice<mc6845_device>(MDA_MC6845_NAME);
+ pc_lpt_device *lpt = subdevice<pc_lpt_device>("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = status_r(space, offset);
+ break;
+ /* 12, 13, 14 are the LPT ports */
+ case 12: case 13: case 14:
+ data = lpt->read(space, offset - 12);
+ break;
+ }
+ return data;
+}
+
+
+/***************************************************************************
+
+ Hercules Display Adapter section (re-uses parts from the MDA section)
+
+***************************************************************************/
+
+/*
+When the Hercules changes to graphics mode, the number of pixels per access and
+clock divider should be changed. The currect mc6845 implementation does not
+allow this.
+
+The divder/pixels per 6845 clock is 9 for text mode and 16 for graphics mode.
+*/
+
+static MC6845_INTERFACE( mc6845_hercules_intf )
+{
+ false, /* show border area */
+ 0,0,0,0, /* visarea adjustment */
+ 9, /* number of pixels per video memory address */
+ NULL, /* begin_update */
+ mda_update_row, /* update_row */
+ NULL, /* end_update */
+ DEVCB_NULL, /* on_de_changed */
+ DEVCB_NULL, /* on_cur_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, hsync_changed), /* on_hsync_changed */
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, isa8_mda_device, vsync_changed), /* on_vsync_changed */
+ NULL
+};
+
+static GFXDECODE_START( pcherc )
+ GFXDECODE_ENTRY( "gfx1", 0x0000, pc_16_charlayout, 1, 1 )
+GFXDECODE_END
+
+MACHINE_CONFIG_FRAGMENT( pcvideo_hercules )
+ MCFG_SCREEN_ADD( HERCULES_SCREEN_NAME, RASTER)
+ MCFG_SCREEN_RAW_PARAMS(MDA_CLOCK, 882, 0, 720, 370, 0, 350 )
+ MCFG_SCREEN_UPDATE_DEVICE( HERCULES_MC6845_NAME, mc6845_device, screen_update )
+
+ MCFG_PALETTE_ADD( "palette", 4 )
+
+ MCFG_MC6845_ADD( HERCULES_MC6845_NAME, MC6845, HERCULES_SCREEN_NAME, MDA_CLOCK/9, mc6845_hercules_intf)
+
+ MCFG_GFXDECODE_ADD("gfxdecode", pcherc)
+
+ MCFG_DEVICE_ADD("lpt", PC_LPT, 0)
+ MCFG_PC_LPT_IRQ_HANDLER(WRITELINE(isa8_mda_device, pc_cpu_line))
+MACHINE_CONFIG_END
+
+ROM_START( hercules )
+ ROM_REGION(0x1000,"gfx1", 0)
+ ROM_LOAD("um2301.bin", 0x00000, 0x1000, CRC(0827bdac) SHA1(15f1aceeee8b31f0d860ff420643e3c7f29b5ffc))
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_HERCULES = &device_creator<isa8_hercules_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_hercules_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_hercules );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_hercules_device::device_rom_region() const
+{
+ return ROM_NAME( hercules );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_hercules_device - constructor
+//-------------------------------------------------
+
+isa8_hercules_device::isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ isa8_mda_device(mconfig, ISA8_HERCULES, "Hercules Graphics Card", tag, owner, clock, "isa_hercules", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_hercules_device::device_start()
+{
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ m_videoram = auto_alloc_array(machine(), UINT8, 0x10000);
+ set_isa_device();
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate( FUNC(isa8_hercules_device::io_read), this ), write8_delegate( FUNC(isa8_hercules_device::io_write), this ) );
+ m_isa->install_bank(0xb0000, 0xbffff, 0, 0, "bank_hercules", m_videoram);
+
+ /* Initialise the mda palette */
+ for(int i = 0; i < (sizeof(mda_palette) / 3); i++)
+ m_palette->set_pen_color(i, mda_palette[i][0], mda_palette[i][1], mda_palette[i][2]);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_hercules_device::device_reset()
+{
+ isa8_mda_device::device_reset();
+ m_configuration_switch = 0;
+
+ astring tempstring;
+ m_chr_gen = memregion(subtag(tempstring, "gfx1"))->base();
+}
+
+/***************************************************************************
+ Draw graphics with 720x348 pixels (default); so called Hercules gfx.
+ The memory layout is divided into 4 banks where of size 0x2000.
+ Every bank holds data for every n'th scanline, 8 pixels per byte,
+ bit 7 being the leftmost.
+***************************************************************************/
+
+static MC6845_UPDATE_ROW( hercules_gfx_update_row )
+{
+ isa8_hercules_device *herc = downcast<isa8_hercules_device *>(device->owner());
+ const rgb_t *palette = herc->m_palette->palette()->entry_list_raw();
+ UINT32 *p = &bitmap.pix32(y);
+ UINT16 gfx_base = ( ( herc->m_mode_control & 0x80 ) ? 0x8000 : 0x0000 ) | ( ( ra & 0x03 ) << 13 );
+ int i;
+ if ( y == 0 ) MDA_LOG(1,"hercules_gfx_update_row",("\n"));
+ for ( i = 0; i < x_count; i++ )
+ {
+ UINT8 data = herc->m_videoram[ gfx_base + ( ( ma + i ) << 1 ) ];
+
+ *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
+
+ data = herc->m_videoram[ gfx_base + ( ( ma + i ) << 1 ) + 1 ];
+
+ *p = palette[( data & 0x80 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x40 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x20 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x10 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x08 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x04 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x02 ) ? 2 : 0]; p++;
+ *p = palette[( data & 0x01 ) ? 2 : 0]; p++;
+ }
+}
+
+
+WRITE8_MEMBER( isa8_hercules_device::mode_control_w )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+
+ m_mode_control = data;
+
+ switch( m_mode_control & 0x2a )
+ {
+ case 0x08:
+ m_update_row = mda_text_inten_update_row;
+ break;
+ case 0x28:
+ m_update_row = mda_text_blink_update_row;
+ break;
+ case 0x0A: /* Hercules modes */
+ case 0x2A:
+ m_update_row = hercules_gfx_update_row;
+ break;
+ default:
+ m_update_row = NULL;
+ }
+
+ mc6845->set_clock( m_mode_control & 0x02 ? MDA_CLOCK / 16 : MDA_CLOCK / 9 );
+ mc6845->set_hpixels_per_column( m_mode_control & 0x02 ? 16 : 9 );
+}
+
+
+WRITE8_MEMBER( isa8_hercules_device::io_write )
+{
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+ pc_lpt_device *lpt = subdevice<pc_lpt_device>("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ mc6845->address_w( space, offset, data );
+ break;
+ case 1: case 3: case 5: case 7:
+ mc6845->register_w( space, offset, data );
+ break;
+ case 8:
+ mode_control_w(space, offset, data);
+ break;
+ case 12: case 13: case 14:
+ lpt->write(space, offset - 12, data);
+ break;
+ case 15:
+ m_configuration_switch = data;
+ break;
+ }
+}
+
+
+/* R- CRT status register (see #P139)
+ * (EGA/VGA) input status 1 register
+ * 7 HGC vertical sync in progress
+ * 6-4 adapter 000 hercules
+ * 001 hercules+
+ * 101 hercules InColor
+ * else unknown
+ * 3 pixel stream (0 black, 1 white)
+ * 2-1 reserved
+ * 0 horizontal drive enable
+ */
+READ8_MEMBER( isa8_hercules_device::status_r )
+{
+ // Faking pixel stream here
+ m_pixel++;
+
+ return m_vsync | ( m_pixel & 0x08 ) | m_hsync;
+}
+
+
+READ8_MEMBER( isa8_hercules_device::io_read )
+{
+ int data = 0xff;
+ mc6845_device *mc6845 = subdevice<mc6845_device>(HERCULES_MC6845_NAME);
+ pc_lpt_device *lpt = subdevice<pc_lpt_device>("lpt");
+ switch( offset )
+ {
+ case 0: case 2: case 4: case 6:
+ /* return last written mc6845 address value here? */
+ break;
+ case 1: case 3: case 5: case 7:
+ data = mc6845->register_r( space, offset );
+ break;
+ case 10:
+ data = status_r(space, offset);
+ break;
+ /* 12, 13, 14 are the LPT ports */
+ case 12: case 13: case 14:
+ data = lpt->read(space, offset - 12);
+ break;
+ }
+ return data;
+}
diff --git a/src/emu/bus/isa/mda.h b/src/emu/bus/isa/mda.h
new file mode 100644
index 00000000000..08ef8c9e403
--- /dev/null
+++ b/src/emu/bus/isa/mda.h
@@ -0,0 +1,93 @@
+#pragma once
+
+#ifndef __ISA_MDA_H__
+#define __ISA_MDA_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/mc6845.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_mda_device
+
+class isa8_mda_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ friend class isa8_hercules_device;
+
+ // construction/destruction
+ isa8_mda_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ isa8_mda_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_WRITE_LINE_MEMBER(hsync_changed);
+ DECLARE_WRITE_LINE_MEMBER(vsync_changed);
+ virtual DECLARE_READ8_MEMBER(io_read);
+ virtual DECLARE_WRITE8_MEMBER(io_write);
+ virtual DECLARE_READ8_MEMBER(status_r);
+ virtual DECLARE_WRITE8_MEMBER(mode_control_w);
+
+ WRITE_LINE_MEMBER(pc_cpu_line);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+public:
+ int m_framecnt;
+
+ UINT8 m_mode_control;
+
+ mc6845_update_row_func m_update_row;
+ UINT8 *m_chr_gen;
+ UINT8 m_vsync;
+ UINT8 m_hsync;
+ UINT8 *m_videoram;
+ UINT8 m_pixel;
+ required_device<palette_device> m_palette;
+};
+
+
+// device type definition
+extern const device_type ISA8_MDA;
+
+// ======================> isa8_hercules_device
+
+class isa8_hercules_device :
+ public isa8_mda_device
+{
+public:
+ // construction/destruction
+ isa8_hercules_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ virtual DECLARE_READ8_MEMBER(io_read);
+ virtual DECLARE_WRITE8_MEMBER(io_write);
+ virtual DECLARE_READ8_MEMBER(status_r);
+ virtual DECLARE_WRITE8_MEMBER(mode_control_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ // internal state
+public:
+ UINT8 m_configuration_switch; //hercules
+};
+
+
+// device type definition
+extern const device_type ISA8_HERCULES;
+
+#endif /* __ISA_MDA_H__ */
diff --git a/src/emu/bus/isa/mpu401.c b/src/emu/bus/isa/mpu401.c
new file mode 100644
index 00000000000..d52cfc3d6c5
--- /dev/null
+++ b/src/emu/bus/isa/mpu401.c
@@ -0,0 +1,91 @@
+/***************************************************************************
+
+ MPU-401 MIDI device interface
+
+ TODO:
+ - skeleton, doesn't do anything
+
+***************************************************************************/
+
+#include "emu.h"
+#include "mpu401.h"
+#include "machine/pic8259.h"
+
+#define MPU_CORE_TAG "mpu401"
+
+MACHINE_CONFIG_FRAGMENT( isa8mpu401 )
+ MCFG_MPU401_ADD(MPU_CORE_TAG, WRITELINE(isa8_mpu401_device, mpu_irq_out))
+MACHINE_CONFIG_END
+
+/*
+DIP-SWs
+1-2-3-4
+ 0x200
+ 1 0x210
+ 1 0x220
+...
+1 1 1 0x330 (default)
+...
+1 1 1 1 0x370
+
+5-6-7-8
+1 irq2 (default)
+ 1 irq3
+ 1 irq5
+ 1 irq7
+*/
+
+WRITE_LINE_MEMBER( isa8_mpu401_device::mpu_irq_out )
+{
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_MPU401 = &device_creator<isa8_mpu401_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_mpu401_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( isa8mpu401 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_adlib_device - constructor
+//-------------------------------------------------
+
+isa8_mpu401_device::isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_MPU401, "Roland MPU-401 MIDI Interface", tag, owner, clock, "isa_mpu401", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_mpu401(*this, MPU_CORE_TAG)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_mpu401_device::device_start()
+{
+ set_isa_device();
+
+ m_isa->install_device(0x330, 0x0331, 0, 0, READ8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_r), WRITE8_DEVICE_DELEGATE(m_mpu401, mpu401_device, mpu_w));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_mpu401_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/mpu401.h b/src/emu/bus/isa/mpu401.h
new file mode 100644
index 00000000000..1b521931ff4
--- /dev/null
+++ b/src/emu/bus/isa/mpu401.h
@@ -0,0 +1,44 @@
+#pragma once
+
+#ifndef __ISA_MPU401_H__
+#define __ISA_MPU401_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/mpu401.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_mpu401_device
+
+class isa8_mpu401_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ required_device<mpu401_device> m_mpu401;
+
+ // called back by the MPU401 core to set the IRQ line state
+ DECLARE_WRITE_LINE_MEMBER(mpu_irq_out);
+
+ // optional information overrides
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ // internal state
+};
+
+
+// device type definition
+extern const device_type ISA8_MPU401;
+
+#endif /* __ISA_MPU401_H__ */
diff --git a/src/emu/bus/isa/mufdc.c b/src/emu/bus/isa/mufdc.c
new file mode 100644
index 00000000000..837cc2e7950
--- /dev/null
+++ b/src/emu/bus/isa/mufdc.c
@@ -0,0 +1,205 @@
+/***************************************************************************
+
+ Multi Unique FDC
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ 8-bit floppy controller, supports 4 drives with 360k, 720k,
+ 1.2MB or 1.44MB. It was sold under a few different names:
+
+ - Ably-Tech FDC-344
+ - Magitronic Multi Floppy Controller Card
+ - Micro-Q (same as FDC-344?)
+ - Modular Circuit Technology MCT-FDC-HD4 (not dumped)
+
+***************************************************************************/
+
+#include "mufdc.h"
+#include "formats/naslite_dsk.h"
+#include "formats/pc_dsk.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ISA8_FDC344 = &device_creator<fdc344_device>;
+const device_type ISA8_FDCMAG = &device_creator<fdcmag_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+FLOPPY_FORMATS_MEMBER( mufdc_device::floppy_formats )
+ FLOPPY_PC_FORMAT,
+ FLOPPY_NASLITE_FORMAT
+FLOPPY_FORMATS_END
+
+static SLOT_INTERFACE_START( drives )
+ SLOT_INTERFACE("525hd", FLOPPY_525_HD)
+ SLOT_INTERFACE("35hd", FLOPPY_35_HD)
+ SLOT_INTERFACE("525dd", FLOPPY_525_DD)
+ SLOT_INTERFACE("35dd", FLOPPY_35_DD)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( mufdc_device )
+ MCFG_MCS3201_ADD("fdc")
+ MCFG_MCS3201_INPUT_HANDLER(READ8(mufdc_device, fdc_input_r))
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", drives, "35hd", mufdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", drives, "35hd", mufdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:2", drives, NULL, mufdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:3", drives, NULL, mufdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+machine_config_constructor mufdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( mufdc_device );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( mufdc_device )
+ PORT_START("configuration")
+ PORT_DIPNAME(0x03, 0x02, "FDC FDD 1")
+ PORT_DIPLOCATION("SW:1,2")
+ PORT_DIPSETTING(0x01, "360KB")
+ PORT_DIPSETTING(0x03, "720KB")
+ PORT_DIPSETTING(0x00, "1.2MB")
+ PORT_DIPSETTING(0x02, "1.44MB")
+ PORT_DIPNAME(0x0c, 0x08, "FDC FDD 2")
+ PORT_DIPLOCATION("SW:3,4")
+ PORT_DIPSETTING(0x04, "360KB")
+ PORT_DIPSETTING(0x0c, "720KB")
+ PORT_DIPSETTING(0x00, "1.2MB")
+ PORT_DIPSETTING(0x08, "1.44MB")
+ PORT_DIPNAME(0x30, 0x20, "FDC FDD 3")
+ PORT_DIPLOCATION("SW:5,6")
+ PORT_DIPSETTING(0x10, "360KB")
+ PORT_DIPSETTING(0x30, "720KB")
+ PORT_DIPSETTING(0x00, "1.2MB")
+ PORT_DIPSETTING(0x20, "1.44MB")
+ PORT_DIPNAME(0xc0, 0x80, "FDC FDD 4")
+ PORT_DIPLOCATION("SW:7,8")
+ PORT_DIPSETTING(0x40, "360KB")
+ PORT_DIPSETTING(0xc0, "720KB")
+ PORT_DIPSETTING(0x00, "1.2MB")
+ PORT_DIPSETTING(0x80, "1.44MB")
+INPUT_PORTS_END
+
+ioport_constructor mufdc_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( mufdc_device );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( fdc344 )
+ ROM_REGION(0x4000, "option", 0)
+ ROM_LOAD("fdc344_42.u2", 0x0000, 0x4000, CRC(3e02567c) SHA1(b639d92435ecf2a6d4aefd3576a6955028f6bde7))
+ROM_END
+
+const rom_entry *fdc344_device::device_rom_region() const
+{
+ return ROM_NAME( fdc344 );
+}
+
+ROM_START( fdcmag )
+ ROM_REGION(0x2000, "option", 0)
+ ROM_LOAD("magitronic_40.u2", 0x0000, 0x2000, CRC(41a5371b) SHA1(9c4443169a0b104395404274470e62b8b65efcf4))
+ROM_END
+
+const rom_entry *fdcmag_device::device_rom_region() const
+{
+ return ROM_NAME( fdcmag );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mufdc_device - constructor
+//-------------------------------------------------
+
+mufdc_device::mufdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_fdc(*this, "fdc"),
+ m_config(*this, "configuration")
+{
+}
+
+fdc344_device::fdc344_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ mufdc_device(mconfig, ISA8_FDC344, tag, owner, clock, "Ably-Tech FDC-344", "fdc344")
+{
+}
+
+fdcmag_device::fdcmag_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ mufdc_device(mconfig, ISA8_FDCMAG, tag, owner, clock, "Magitronic Multi Floppy Controller Card", "fdcmag")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mufdc_device::device_start()
+{
+ set_isa_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mufdc_device::device_reset()
+{
+ m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, m_shortname, "option");
+ m_isa->install_device(0x3f0, 0x3f7, *m_fdc, &pc_fdc_interface::map);
+ m_isa->set_dma_channel(2, this, true);
+
+ m_fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(mufdc_device::fdc_irq_w), this));
+ m_fdc->setup_drq_cb(pc_fdc_interface::line_cb(FUNC(mufdc_device::fdc_drq_w), this));
+}
+
+
+//**************************************************************************
+// FDC INTERFACE
+//**************************************************************************
+
+READ8_MEMBER( mufdc_device::fdc_input_r )
+{
+ return ~m_config->read();
+}
+
+void mufdc_device::fdc_irq_w(bool state)
+{
+ m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void mufdc_device::fdc_drq_w(bool state)
+{
+ m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+UINT8 mufdc_device::dack_r(int line)
+{
+ return m_fdc->dma_r();
+}
+
+void mufdc_device::dack_w(int line, UINT8 data)
+{
+ return m_fdc->dma_w(data);
+}
+
+void mufdc_device::eop_w(int state)
+{
+ m_fdc->tc_w(state == ASSERT_LINE);
+}
diff --git a/src/emu/bus/isa/mufdc.h b/src/emu/bus/isa/mufdc.h
new file mode 100644
index 00000000000..e258bcadc09
--- /dev/null
+++ b/src/emu/bus/isa/mufdc.h
@@ -0,0 +1,95 @@
+/***************************************************************************
+
+ Multi Unique FDC
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ 8-bit floppy controller, supports 4 drives with 360k, 720k,
+ 1.2MB or 1.44MB. It was sold under a few different names:
+
+ - Ably-Tech FDC-344
+ - Magitronic Multi Floppy Controller Card
+ - Micro-Q (same as FDC-344?)
+ - Modular Circuit Technology MCT-FDC-HD4 (not dumped)
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ISA_MUFDC_H__
+#define __ISA_MUFDC_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "imagedev/floppy.h"
+#include "machine/upd765.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> mufdc_device
+
+class mufdc_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ mufdc_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ DECLARE_FLOPPY_FORMATS( floppy_formats );
+
+ DECLARE_READ8_MEMBER( fdc_input_r );
+ void fdc_irq_w(bool state);
+ void fdc_drq_w(bool state);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_isa8_card_interface
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line, UINT8 data);
+ virtual void eop_w(int state);
+
+private:
+ required_device<pc_fdc_interface> m_fdc;
+ required_ioport m_config;
+};
+
+class fdc344_device : public mufdc_device
+{
+public:
+ // construction/destruction
+ fdc344_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ virtual void device_config_complete() { m_shortname = "fdc344"; }
+};
+
+class fdcmag_device : public mufdc_device
+{
+public:
+ // construction/destruction
+ fdcmag_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ virtual void device_config_complete() { m_shortname = "fdcmag"; }
+};
+
+// device type definition
+extern const device_type ISA8_FDC344;
+extern const device_type ISA8_FDCMAG;
+
+#endif
diff --git a/src/emu/bus/isa/ne1000.c b/src/emu/bus/isa/ne1000.c
new file mode 100644
index 00000000000..156fae044f2
--- /dev/null
+++ b/src/emu/bus/isa/ne1000.c
@@ -0,0 +1,135 @@
+#include "emu.h"
+#include "ne1000.h"
+
+static const dp8390_interface ne1000_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne1000_device, ne1000_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(ne1000_config)
+ MCFG_DP8390D_ADD("dp8390d", ne1000_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type NE1000 = &device_creator<ne1000_device>;
+
+machine_config_constructor ne1000_device::device_mconfig_additions() const {
+ return MACHINE_CONFIG_NAME(ne1000_config);
+}
+
+ne1000_device::ne1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NE1000, "NE1000 Network Adapter", tag, owner, clock, "ne1000", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_dp8390(*this, "dp8390d") {
+}
+
+void ne1000_device::device_start() {
+ char mac[7];
+ UINT32 num = rand();
+ memset(m_prom, 0x57, 16);
+ sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff);
+ mac[0] = 0; mac[1] = 0; // avoid gcc warning
+ memcpy(m_prom, mac, 6);
+ m_dp8390->set_mac(mac);
+ set_isa_device();
+ m_isa->install_device(0x0300, 0x031f, 0, 0, read8_delegate(FUNC(ne1000_device::ne1000_port_r), this), write8_delegate(FUNC(ne1000_device::ne1000_port_w), this));
+}
+
+void ne1000_device::device_reset() {
+ memcpy(m_prom, m_dp8390->get_mac(), 6);
+ m_irq = ioport("CONFIG")->read() & 3;
+}
+
+READ8_MEMBER(ne1000_device::ne1000_port_r) {
+ if(offset < 16) {
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ return m_dp8390->dp8390_r(space, offset, mem_mask);
+ }
+ switch(offset) {
+ case 16:
+ m_dp8390->dp8390_cs(ASSERT_LINE);
+ return m_dp8390->dp8390_r(space, offset, mem_mask);
+ case 31:
+ m_dp8390->dp8390_reset(CLEAR_LINE);
+ return 0;
+ default:
+ logerror("ne1000: invalid register read %02X\n", offset);
+ }
+ return 0;
+}
+
+WRITE8_MEMBER(ne1000_device::ne1000_port_w) {
+ if(offset < 16) {
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ m_dp8390->dp8390_w(space, offset, data, mem_mask);
+ return;
+ }
+ switch(offset) {
+ case 16:
+ m_dp8390->dp8390_cs(ASSERT_LINE);
+ m_dp8390->dp8390_w(space, offset, data, mem_mask);
+ return;
+ case 31:
+ m_dp8390->dp8390_reset(ASSERT_LINE);
+ return;
+ default:
+ logerror("ne1000: invalid register write %02X\n", offset);
+ }
+ return;
+}
+
+WRITE_LINE_MEMBER(ne1000_device::ne1000_irq_w) {
+ switch(m_irq) {
+ case 0:
+ m_isa->irq2_w(state);
+ break;
+ case 1:
+ m_isa->irq3_w(state);
+ break;
+ case 2:
+ m_isa->irq4_w(state);
+ break;
+ case 3:
+ m_isa->irq5_w(state);
+ break;
+ }
+}
+
+READ8_MEMBER(ne1000_device::ne1000_mem_read) {
+ offset &= ~0xc000; // verify
+ if(offset < 16) return m_prom[offset];
+ if((offset < (8*1024)) || (offset >= (16*1024))) {
+ logerror("ne1000: invalid memory read %04X\n", offset);
+ return 0xff;
+ }
+ return m_board_ram[offset - (8*1024)];
+}
+
+WRITE8_MEMBER(ne1000_device::ne1000_mem_write) {
+ offset &= ~0xc000; // verify
+ if((offset < (8*1024)) || (offset >= (16*1024))) {
+ logerror("ne1000: invalid memory write %04X\n", offset);
+ return;
+ }
+ m_board_ram[offset - (8*1024)] = data;
+}
+
+static INPUT_PORTS_START( ne1000 )
+ PORT_START("CONFIG")
+ PORT_CONFNAME(0x03, 0x01, "NE1000 IRQ jumper (W12-15)")
+ PORT_CONFSETTING( 0x00, "IRQ2/9")
+ PORT_CONFSETTING( 0x01, "IRQ3")
+ PORT_CONFSETTING( 0x02, "IRQ4")
+ PORT_CONFSETTING( 0x03, "IRQ5")
+ //PORT_CONFNAME(0x30, 0x00, "NE1000 IO port jumper (W9-10)")
+ //PORT_CONFSETTING( 0x00, "300")
+ //PORT_CONFSETTING( 0x10, "320")
+ //PORT_CONFSETTING( 0x20, "340")
+ //PORT_CONFSETTING( 0x30, "360")
+INPUT_PORTS_END
+
+ioport_constructor ne1000_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(ne1000);
+}
diff --git a/src/emu/bus/isa/ne1000.h b/src/emu/bus/isa/ne1000.h
new file mode 100644
index 00000000000..b92f561f958
--- /dev/null
+++ b/src/emu/bus/isa/ne1000.h
@@ -0,0 +1,35 @@
+#ifndef __NE1000_H__
+#define __NE1000_H__
+
+// NE1000 is 8bit has 8KB ram; NE2000 is 16bit has 16KB ram
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/dp8390.h"
+
+class ne1000_device: public device_t,
+ public device_isa8_card_interface
+{
+public:
+ ne1000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ void ne1000_irq_w(int state);
+ DECLARE_READ8_MEMBER(ne1000_mem_read);
+ DECLARE_WRITE8_MEMBER(ne1000_mem_write);
+ DECLARE_READ8_MEMBER(ne1000_port_r);
+ DECLARE_WRITE8_MEMBER(ne1000_port_w);
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ required_device<dp8390d_device> m_dp8390;
+ UINT8 m_irq;
+ UINT8 m_board_ram[8*1024];
+ UINT8 m_prom[16];
+};
+
+extern const device_type NE1000;
+
+#endif
diff --git a/src/emu/bus/isa/ne2000.c b/src/emu/bus/isa/ne2000.c
new file mode 100644
index 00000000000..9d572665f56
--- /dev/null
+++ b/src/emu/bus/isa/ne2000.c
@@ -0,0 +1,145 @@
+#include "emu.h"
+#include "ne2000.h"
+
+static const dp8390_interface ne2000_dp8390_interface = {
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_irq_w),
+ DEVCB_NULL,
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_mem_read),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, ne2000_device, ne2000_mem_write)
+};
+
+static MACHINE_CONFIG_FRAGMENT(ne2000_config)
+ MCFG_DP8390D_ADD("dp8390d", ne2000_dp8390_interface)
+MACHINE_CONFIG_END
+
+const device_type NE2000 = &device_creator<ne2000_device>;
+
+machine_config_constructor ne2000_device::device_mconfig_additions() const {
+ return MACHINE_CONFIG_NAME(ne2000_config);
+}
+
+ne2000_device::ne2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, NE2000, "NE2000 Network Adapter", tag, owner, clock, "ne2000", __FILE__),
+ device_isa16_card_interface(mconfig, *this),
+ m_dp8390(*this, "dp8390d") {
+}
+
+void ne2000_device::device_start() {
+ char mac[7];
+ UINT32 num = rand();
+ memset(m_prom, 0x57, 16);
+ sprintf(mac+2, "\x1b%c%c%c", (num >> 16) & 0xff, (num >> 8) & 0xff, num & 0xff);
+ mac[0] = 0; mac[1] = 0; // avoid gcc warning
+ memcpy(m_prom, mac, 6);
+ m_dp8390->set_mac(mac);
+ set_isa_device();
+ m_isa->install16_device(0x0300, 0x031f, 0, 0, read16_delegate(FUNC(ne2000_device::ne2000_port_r), this), write16_delegate(FUNC(ne2000_device::ne2000_port_w), this));
+}
+
+void ne2000_device::device_reset() {
+ memcpy(m_prom, m_dp8390->get_mac(), 6);
+ m_irq = ioport("CONFIG")->read() & 3;
+}
+
+READ16_MEMBER(ne2000_device::ne2000_port_r) {
+ offset <<= 1;
+ if(offset < 16) {
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ return m_dp8390->dp8390_r(space, offset, 0xff) |
+ m_dp8390->dp8390_r(space, offset+1, 0xff) << 8;
+ }
+ if(mem_mask == 0xff00) offset++;
+ switch(offset) {
+ case 16:
+ m_dp8390->dp8390_cs(ASSERT_LINE);
+ return m_dp8390->dp8390_r(space, offset, mem_mask);
+ case 31:
+ m_dp8390->dp8390_reset(CLEAR_LINE);
+ return 0;
+ default:
+ logerror("ne2000: invalid register read %02X\n", offset);
+ }
+ return 0;
+}
+
+WRITE16_MEMBER(ne2000_device::ne2000_port_w) {
+ offset <<= 1;
+ if(offset < 16) {
+ m_dp8390->dp8390_cs(CLEAR_LINE);
+ if(mem_mask == 0xff00) {
+ data >>= 8;
+ offset++;
+ }
+ m_dp8390->dp8390_w(space, offset, data & 0xff, 0xff);
+ if(mem_mask == 0xffff) m_dp8390->dp8390_w(space, offset+1, data>>8, 0xff);
+ return;
+ }
+ if(mem_mask == 0xff00) offset++;
+ switch(offset) {
+ case 16:
+ m_dp8390->dp8390_cs(ASSERT_LINE);
+ m_dp8390->dp8390_w(space, offset, data, mem_mask);
+ return;
+ case 31:
+ m_dp8390->dp8390_reset(ASSERT_LINE);
+ return;
+ default:
+ logerror("ne2000: invalid register write %02X\n", offset);
+ }
+ return;
+}
+
+WRITE_LINE_MEMBER(ne2000_device::ne2000_irq_w) {
+ switch(m_irq) {
+ case 0:
+ m_isa->irq2_w(state);
+ break;
+ case 1:
+ m_isa->irq3_w(state);
+ break;
+ case 2:
+ m_isa->irq4_w(state);
+ break;
+ case 3:
+ m_isa->irq5_w(state);
+ break;
+ }
+}
+
+READ8_MEMBER(ne2000_device::ne2000_mem_read) {
+ offset &= ~0x8000;
+ if(offset < 32) return m_prom[offset>>1];
+ if((offset < (16*1024)) || (offset >= (32*1024))) {
+ logerror("ne2000: invalid memory read %04X\n", offset);
+ return 0xff;
+ }
+ return m_board_ram[offset - (16*1024)];
+}
+
+WRITE8_MEMBER(ne2000_device::ne2000_mem_write) {
+ offset &= ~0x8000;
+ if((offset < (16*1024)) || (offset >= (32*1024))) {
+ logerror("ne2000: invalid memory write %04X\n", offset);
+ return;
+ }
+ m_board_ram[offset - (16*1024)] = data;
+}
+
+static INPUT_PORTS_START( ne2000 )
+ PORT_START("CONFIG")
+ PORT_CONFNAME(0x03, 0x01, "NE2000 IRQ jumper (W12-15)")
+ PORT_CONFSETTING( 0x00, "IRQ2/9")
+ PORT_CONFSETTING( 0x01, "IRQ3")
+ PORT_CONFSETTING( 0x02, "IRQ4")
+ PORT_CONFSETTING( 0x03, "IRQ5")
+ //PORT_CONFNAME(0x30, 0x00, "NE2000 IO port jumper (W9-10)")
+ //PORT_CONFSETTING( 0x00, "300")
+ //PORT_CONFSETTING( 0x10, "320")
+ //PORT_CONFSETTING( 0x20, "340")
+ //PORT_CONFSETTING( 0x30, "360")
+INPUT_PORTS_END
+
+ioport_constructor ne2000_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME(ne2000);
+}
diff --git a/src/emu/bus/isa/ne2000.h b/src/emu/bus/isa/ne2000.h
new file mode 100644
index 00000000000..855400ad6e6
--- /dev/null
+++ b/src/emu/bus/isa/ne2000.h
@@ -0,0 +1,33 @@
+#ifndef __NE2000_H__
+#define __NE2000_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/dp8390.h"
+
+class ne2000_device: public device_t,
+ public device_isa16_card_interface
+{
+public:
+ ne2000_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ void ne2000_irq_w(int state);
+ DECLARE_READ8_MEMBER(ne2000_mem_read);
+ DECLARE_WRITE8_MEMBER(ne2000_mem_write);
+ DECLARE_READ16_MEMBER(ne2000_port_r);
+ DECLARE_WRITE16_MEMBER(ne2000_port_w);
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ required_device<dp8390d_device> m_dp8390;
+ UINT8 m_irq;
+ UINT8 m_board_ram[16*1024];
+ UINT8 m_prom[16];
+};
+
+extern const device_type NE2000;
+
+#endif
diff --git a/src/emu/bus/isa/omti8621.c b/src/emu/bus/isa/omti8621.c
new file mode 100644
index 00000000000..59a84038781
--- /dev/null
+++ b/src/emu/bus/isa/omti8621.c
@@ -0,0 +1,1393 @@
+/*
+ * omti8621.c - SMS OMTI 8621 disk controller (for Apollo DN3x00)
+ *
+ * Created on: August 30, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Converted to ISA device by R. Belmont
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ * see also:
+ * * http://www.bitsavers.org/pdf/sms/pc/OMTI_AT_Controller_Series_Jan87.pdf
+ */
+
+#define VERBOSE 0
+
+static int verbose = VERBOSE;
+
+#include "omti8621.h"
+#include "image.h"
+#include "formats/pc_dsk.h"
+#include "formats/naslite_dsk.h"
+#include "formats/apollo_dsk.h"
+
+#define LOG(x) { logerror ("%s: ", cpu_context(this)); logerror x; logerror ("\n"); }
+#define LOG1(x) { if (verbose > 0) LOG(x)}
+#define LOG2(x) { if (verbose > 1) LOG(x)}
+#define LOG3(x) { if (verbose > 2) LOG(x)}
+
+#define DLOG(x) { logerror ("%s: ", cpu_context(disk->device)); logerror x; logerror ("\n"); }
+#define DLOG1(x) { if (verbose > 0) DLOG(x)}
+#define DLOG2(x) { if (verbose > 1) DLOG(x)}
+
+#define OMTI_DISK_SECTOR_SIZE 1056
+
+#define OMTI_DISK_TYPE_155_MB 0x607 // Micropolis 1355 (170 MB Dtype = 607)
+#define OMTI_DISK_TYPE_348_MB 0x604 // Maxtor EXT-4380-E (380 MB Dtype = 604)
+#define OMTI_DISK_TYPE_DEFAULT OMTI_DISK_TYPE_348_MB // new disks will have this type (and size)
+
+#define OMTI_MAX_BLOCK_COUNT 32
+
+#define OMTI_DISK0_TAG "omti_disk0"
+#define OMTI_DISK1_TAG "omti_disk1"
+
+#define OMTI_FDC_TAG "omti_fdc"
+
+#define OMTI_CPU_REGION "omti_cpu"
+#define OMTI_BIOS_REGION "omti_bios"
+
+// forward declaration of image class
+extern const device_type OMTI_DISK;
+
+class omti_disk_image_device : public device_t,
+ public device_image_interface
+{
+public:
+ // construction/destruction
+ omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // image-level overrides
+ virtual iodevice_t image_type() const { return IO_HARDDISK; }
+
+ virtual bool is_readable() const { return 1; }
+ virtual bool is_writeable() const { return 1; }
+ virtual bool is_creatable() const { return 1; }
+ virtual bool must_be_loaded() const { return 0; }
+ virtual bool is_reset_on_load() const { return 0; }
+ virtual const char *image_interface() const { return NULL; }
+ virtual const char *file_extensions() const { return "awd"; }
+ virtual const option_guide *create_option_guide() const { return NULL; }
+
+ virtual bool call_create(int format_type, option_resolution *format_options);
+
+ disk_data *token() { return &m_token; }
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+
+ disk_data m_token;
+};
+
+/*
+ * I/O register offsets
+ */
+
+#define OMTI_PORT_DATA_IN 0x00 /* read, 8-bit */
+#define OMTI_PORT_DATA_OUT 0x00 /* write, 8-bit */
+#define OMTI_PORT_STATUS 0x01 /* read, 8-bit */
+#define OMTI_PORT_RESET 0x01 /* write, 8-bit */
+#define OMTI_PORT_CONFIG 0x02 /* read, 8-bit */
+#define OMTI_PORT_SELECT 0x02 /* write, 8-bit */
+#define OMTI_PORT_MASK 0x03 /* write only, 8-bit */
+
+// port status
+
+#define OMTI_STATUS_REQ 0x01 // Request (1 = request transfer of data via data in/out register)
+#define OMTI_STATUS_IO 0x02 // In/Out (1 = direction of transfer is from controller to host)
+#define OMTI_STATUS_CD 0x04 // Command/Data ( 1 = byte transfered is command or status byte)
+#define OMTI_STATUS_BUSY 0x08 // Busy (0 = controller is idle, 1 = controller selected)
+#define OMTI_STATUS_DREQ 0x10 // Data Request (0 = no DMA request, 1 = DMA cycle requested)
+#define OMTI_STATUS_IREQ 0x20 // Interrupt Request (0 = no interrupt, 1 = command complete)
+#define OMTI_STATUS_NU6 0x40 // not used
+#define OMTI_STATUS_NU7 0x80 // not used
+
+#define OMTI_CONFIG_W23 0x01 // jumper W23
+#define OMTI_CONFIG_W22 0x02 // jumper W22
+#define OMTI_CONFIG_W21 0x04 // jumper W21
+#define OMTI_CONFIG_W20 0x08 // jumper W20
+
+#define OMTI_MASK_DMAE 0x01 // DMA enable
+#define OMTI_MASK_INTE 0x02 // Interrupt enable
+
+#define OMTI_COMMAND_STATUS_ERROR 0x02 // error bit
+#define OMTI_COMMAND_STATUS_LUN 0x20 // drive 0 is 0
+
+#define OMTI_SENSE_CODE_NO_ERROR 0x00
+#define OMTI_SENSE_CODE_DRIVE_NOT_READY 0x04
+#define OMTI_SENSE_CODE_ADDRESS_VALID 0x80
+#define OMTI_SENSE_CODE_SECTOR_NOT_FOUND 0x14
+#define OMTI_SENSE_CODE_ECC_ERROR 0x11
+#define OMTI_SENSE_CODE_BAD_TRACK 0x19
+#define OMTI_SENSE_CODE_ALTERNATE_TRACK 0x1C
+#define OMTI_SENSE_CODE_INVALID_COMMAND 0x20
+#define OMTI_SENSE_CODE_ILLEGAL_ADDRESS 0x21
+
+enum {
+ OMTI_STATE_RESET,
+ OMTI_STATE_IDLE,
+ OMTI_STATE_SELECTION,
+ OMTI_STATE_COMMAND,
+ OMTI_STATE_DATA,
+ OMTI_STATE_STATUS,
+};
+
+// OMTI commands
+
+#define OMTI_CMD_TEST_DRIVE_READY 0x00
+#define OMTI_CMD_RECALIBRATE 0x01
+
+#define OMTI_CMD_REQUEST_SENSE 0x03
+#define OMTI_CMD_FORMAT_DRIVEUNIT 0x04
+#define OMTI_CMD_READ_VERIFY 0x05
+#define OMTI_CMD_FORMAT_TRACK 0x06
+#define OMTI_CMD_FORMAT_BAD_TRACK 0x07
+#define OMTI_CMD_READ 0x08
+
+#define OMTI_CMD_WRITE 0x0a
+#define OMTI_CMD_SEEK 0x0b
+
+#define OMTI_CMD_READ_SECTOR_BUFFER 0x0e
+#define OMTI_CMD_WRITE_SECTOR_BUFFER 0x0f
+
+#define OMTI_CMD_ASSIGN_ALTERNATE_TRACK 0x11
+
+#define OMTI_CMD_READ_DATA_TO_BUFFER 0x1e
+#define OMTI_CMD_WRITE_DATA_FROM_BUFFER 0x1f
+#define OMTI_CMD_COPY 0x20
+
+#define OMTI_CMD_READ_ESDI_DEFECT_LIST 0x37
+
+#define OMTI_CMD_RAM_DIAGNOSTICS 0xe0
+#define OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC 0xe4
+#define OMTI_CMD_READ_LONG 0xe5
+#define OMTI_CMD_WRITE_LONG 0xe6
+
+#define OMTI_CMD_READ_CONFIGURATION 0xec
+#define OMTI_CMD_INVALID_COMMAND 0xff
+
+/***************************************************************************
+ cpu_context - return a string describing the current CPU context
+ ***************************************************************************/
+
+static const char *cpu_context(const device_t *device) {
+ static char statebuf[64]; /* string buffer containing state description */
+
+ device_t *cpu = device->machine().firstcpu;
+
+ /* if we have an executing CPU, output data */
+ if (cpu != NULL) {
+ osd_ticks_t t = osd_ticks();
+ int s = t / osd_ticks_per_second();
+ int ms = (t % osd_ticks_per_second()) / 1000;
+
+ sprintf(statebuf, "%d.%03d %s pc=%08x - %s", s, ms, cpu->tag(),
+ cpu->safe_pcbase(), device->tag());
+ } else {
+ strcpy(statebuf, "(no context)");
+ }
+ return statebuf;
+}
+
+static SLOT_INTERFACE_START( pc_hd_floppies )
+ SLOT_INTERFACE( "525hd", FLOPPY_525_HD )
+ SLOT_INTERFACE( "35hd", FLOPPY_35_HD )
+ SLOT_INTERFACE( "525dd", FLOPPY_525_DD )
+ SLOT_INTERFACE( "35dd", FLOPPY_35_DD )
+SLOT_INTERFACE_END
+
+MACHINE_CONFIG_FRAGMENT( omti_disk )
+ MCFG_DEVICE_ADD(OMTI_DISK0_TAG, OMTI_DISK, 0)
+ MCFG_DEVICE_ADD(OMTI_DISK1_TAG, OMTI_DISK, 0)
+
+ MCFG_PC_FDC_AT_ADD(OMTI_FDC_TAG)
+ MCFG_FLOPPY_DRIVE_ADD(OMTI_FDC_TAG":0", pc_hd_floppies, "525hd", omti8621_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD(OMTI_FDC_TAG":1", pc_hd_floppies, "525hd", omti8621_device::floppy_formats)
+MACHINE_CONFIG_END
+
+FLOPPY_FORMATS_MEMBER( omti8621_device::floppy_formats )
+ FLOPPY_APOLLO_FORMAT,
+ FLOPPY_PC_FORMAT,
+ FLOPPY_NASLITE_FORMAT
+FLOPPY_FORMATS_END
+
+// this card has two EPROMs: a program for the on-board Z8 CPU,
+// and a PC BIOS to make the card bootable on a PC.
+// we need both!
+ROM_START( omti8621 )
+ ROM_REGION(0x1000, OMTI_CPU_REGION, 0)
+ ROM_LOAD("omti_z8.bin", 0x0000, 0x1000, NO_DUMP)
+
+ ROM_REGION(0x1000, OMTI_BIOS_REGION, 0)
+ ROM_LOAD("omti_bios", 0x0000, 0x1000, NO_DUMP)
+ROM_END
+
+static INPUT_PORTS_START( omti_port )
+ PORT_START("IO_BASE")
+ PORT_DIPNAME( 0x07, 0x04, "ESDI I/O base")
+ PORT_DIPSETTING( 0x00, "0320h" )
+ PORT_DIPSETTING( 0x01, "0324h" )
+ PORT_DIPSETTING( 0x02, "0328h" )
+ PORT_DIPSETTING( 0x03, "032Ch" )
+ PORT_DIPSETTING( 0x04, "01A0h" )
+ PORT_DIPSETTING( 0x05, "01A4h" )
+ PORT_DIPSETTING( 0x06, "01A8h" )
+ PORT_DIPSETTING( 0x07, "01ACh" )
+ PORT_DIPNAME( 0x08, 0x00, "Floppy I/O base")
+ PORT_DIPSETTING( 0x00, "03F0h" )
+ PORT_DIPSETTING( 0x01, "0370h" )
+
+ PORT_START("BIOS_OPTS")
+ PORT_DIPNAME( 0x01, 0x00, "BIOS control")
+ PORT_DIPSETTING( 0x00, "Disabled" )
+ PORT_DIPSETTING( 0x01, "Enabled" )
+ PORT_DIPNAME( 0x02, 0x00, "BIOS base")
+ PORT_DIPSETTING( 0x00, "C8000h" )
+ PORT_DIPSETTING( 0x01, "CA000h" )
+INPUT_PORTS_END
+
+machine_config_constructor omti8621_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( omti_disk );
+}
+
+const rom_entry *omti8621_device::device_rom_region() const
+{
+ return ROM_NAME( omti8621 );
+}
+
+ioport_constructor omti8621_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( omti_port );
+}
+
+/*-------------------------------------------------
+ device start callback
+-------------------------------------------------*/
+
+void omti8621_device::device_start()
+{
+ set_isa_device();
+
+ m_installed = false;
+
+ sector_buffer = auto_alloc_array(machine(), UINT8, OMTI_DISK_SECTOR_SIZE*OMTI_MAX_BLOCK_COUNT);
+ assert(sector_buffer != NULL);
+
+ m_timer = timer_alloc(0, NULL);
+
+ device_t *device0 = subdevice(OMTI_DISK0_TAG);
+ our_disks[0] = (disk_data *) downcast<omti_disk_image_device *>(device0)->token();
+
+ device_t *device1 = subdevice(OMTI_DISK1_TAG);
+ our_disks[1] = (disk_data *) downcast<omti_disk_image_device *>(device1)->token();
+}
+
+/*-------------------------------------------------
+ device reset callback
+-------------------------------------------------*/
+
+void omti8621_device::device_reset()
+{
+ static const int io_bases[8] = { 0x320, 0x324, 0x328, 0x32c, 0x1a0, 0x1a4, 0x1a8, 0x1ac };
+
+ LOG2(("device_reset_omti8621"));
+
+ // you can't read I/O ports in device_start() even if they're required_ioport<> in your class!
+ if (!m_installed)
+ {
+ int esdi_base = io_bases[m_iobase->read() & 7];
+
+ // install the ESDI ports
+ m_isa->install16_device(esdi_base, esdi_base + 7, 0, 0, read16_delegate(FUNC(omti8621_device::read), this), write16_delegate(FUNC(omti8621_device::write), this));
+
+ // and the onboard AT FDC ports
+ if (m_iobase->read() & 8)
+ {
+ m_isa->install_device(0x0370, 0x0377, *m_fdc, &pc_fdc_interface::map);
+ }
+ else
+ {
+ m_isa->install_device(0x03f0, 0x03f7, *m_fdc, &pc_fdc_interface::map);
+ }
+
+ m_fdc->setup_intrq_cb(pc_fdc_interface::line_cb(FUNC(omti8621_device::fdc_irq_w), this));
+ m_fdc->setup_drq_cb(pc_fdc_interface::line_cb(FUNC(omti8621_device::fdc_drq_w), this));
+
+ m_installed = true;
+ }
+
+ set_jumper(our_disks[0]->type);
+
+ // should go from reset to idle after 100 us
+ // state->omti_state = OMTI_STATE_RESET;
+ omti_state = OMTI_STATE_IDLE;
+
+ status_port = OMTI_STATUS_NU6 | OMTI_STATUS_NU7;
+ config_port = ~jumper;
+ mask_port = 0;
+
+ // default the sector data buffer with model and status information
+ // (i.e. set sector data buffer for cmd=0x0e READ SECTOR BUFFER)
+
+ memset(sector_buffer, 0, OMTI_DISK_SECTOR_SIZE);
+ memcpy(sector_buffer, "8621VB.4060487xx", 0x10);
+ sector_buffer[0x10] = 0; // ROM Checksum error
+ sector_buffer[0x11] = 0; // Processor Register error
+ sector_buffer[0x12] = 0; // Buffer RAM error
+ sector_buffer[0x13] = 0; // Sequencer Register File error
+ sector_buffer[0x14] = 0xc0; // 32K buffer size
+ // TODO: add missing Default values for LUN 0, 1 and 3
+
+ command_length = 0;
+ command_index = 0;
+ command_status = 0;
+
+ data_index = 0;
+ data_length = 0;
+
+ clear_sense_data();
+
+ diskaddr_ecc_error = 0;
+ diskaddr_format_bad_track = 0;
+ alternate_track_address[0] = 0;
+ alternate_track_address[1] = 0;
+}
+
+const device_type ISA16_OMTI8621 = &device_creator<omti8621_device>;
+
+omti8621_device::omti8621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA16_OMTI8621, "OMTI 8621 ESDI/floppy controller", tag, owner, clock, "omti8621", __FILE__),
+ device_isa16_card_interface(mconfig, *this),
+ m_fdc(*this, OMTI_FDC_TAG),
+ m_iobase(*this, "IO_BASE"),
+ m_biosopts(*this, "BIOS_OPTS")
+{
+}
+
+//-------------------------------------------------
+// device_config_complete - perform any
+// operations now that the configuration is
+// complete
+//-------------------------------------------------
+
+void omti8621_device::device_config_complete()
+{
+}
+
+/*-------------------------------------------------
+ set_interrupt - update the IRQ state
+ -------------------------------------------------*/
+
+void omti8621_device::set_interrupt(enum line_state line_state)
+{
+ LOG2(("set_interrupt: status_port=%x, line_state %d", status_port, line_state));
+ m_isa->irq14_w(line_state);
+}
+
+void omti8621_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ set_interrupt(ASSERT_LINE);
+}
+
+/***************************************************************************
+ clear_sense_data - clear the sense data
+ ***************************************************************************/
+
+void omti8621_device::clear_sense_data() {
+ LOG2(("clear_sense_data"));
+ memset(sense_data, 0, sizeof(sense_data));
+}
+
+/***************************************************************************
+ set_sense_data - set the sense data from code and command descriptor block
+ ***************************************************************************/
+
+void omti8621_device::set_sense_data(UINT8 code, const UINT8 * cdb) {
+ LOG2(("set_sense_data code=%x", code));
+ sense_data[0]=code;
+ sense_data[1]=cdb[1];
+ sense_data[2]=cdb[2];
+ sense_data[3]=cdb[3];
+}
+
+/***************************************************************************
+ set_configuration_data - set the configuration data for drive lun
+ ***************************************************************************/
+
+void omti8621_device::set_configuration_data(UINT8 lun) {
+ LOG2(("set_configuration_data lun=%x", lun));
+
+ // initialize the configuration data
+ disk_data *disk = our_disks[lun];
+
+ disk->config_data[0] = (disk->cylinders - 1) >> 8; // Number of Cylinders (MSB)
+ disk->config_data[1] = (disk->cylinders - 1) & 0xff; // Number of Cylinders (LSB) (-1)
+ disk->config_data[2] = disk->heads - 1; // Number of Heads (-1)
+ disk->config_data[3] = disk->sectors - 1; // Number of Sectors (-1)
+ disk->config_data[4] = 0x02; // Drive Configuration Word (MSB)
+ disk->config_data[5] = 0x44; // Drive Configuration Word (LSB)
+ disk->config_data[6] = 0x00; // ISG AFTER INDEX
+ disk->config_data[7] = 0x00; // PLO SYN Field (ID)
+ disk->config_data[8] = 0x00; // PLO SYN Field (DATA)
+ disk->config_data[9] = 0x00; // ISG AFTER SECTOR
+}
+
+/***************************************************************************
+ get_lun - get logical unit number from a command descriptor block (in bit 5)
+ ***************************************************************************/
+
+UINT8 omti8621_device::get_lun(const UINT8 * cdb)
+{
+ return (cdb[1] & 0x20) >> 5;
+}
+
+/***************************************************************************
+ check_disk_address - check disk address, set sense data and return true for no error
+ ***************************************************************************/
+
+UINT8 omti8621_device::check_disk_address(const UINT8 *cdb)
+{
+ UINT8 sense_code = OMTI_SENSE_CODE_NO_ERROR;
+ UINT8 lun = get_lun(cdb);
+ UINT16 head = cdb[1] & 0x1f;
+ UINT16 sector = cdb[2] & 0x3f;
+ UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
+ UINT8 block_count = cdb[4];
+ disk_data *disk = our_disks[lun];
+
+ UINT32 disk_track = cylinder * disk->heads + head;
+ UINT32 disk_addr = (disk_track * disk->sectors) + sector;
+
+ if (block_count > OMTI_MAX_BLOCK_COUNT) {
+ LOG(("########### check_disk_address: unexpected block count %x", block_count));
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ }
+
+ if (lun > OMTI_MAX_LUN) {
+ sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
+ } else if (!disk->image->exists()) {
+ sense_code = OMTI_SENSE_CODE_DRIVE_NOT_READY;
+ } else if (sector >= OMTI_MAX_BLOCK_COUNT) {
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ } else if (head >= disk->heads) {
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ } else if (cylinder >= disk->cylinders) {
+ sense_code = OMTI_SENSE_CODE_ILLEGAL_ADDRESS | OMTI_SENSE_CODE_ADDRESS_VALID;
+ } else if ( disk_track == diskaddr_format_bad_track && disk_track != 0) {
+ sense_code = OMTI_SENSE_CODE_BAD_TRACK;
+ } else if (disk_addr == diskaddr_ecc_error && disk_addr != 0) {
+ sense_code = OMTI_SENSE_CODE_ECC_ERROR;
+ } else if (disk_track == alternate_track_address[1] && disk_track != 0) {
+ sense_code = OMTI_SENSE_CODE_ALTERNATE_TRACK;
+ }
+
+ if (sense_code == OMTI_SENSE_CODE_NO_ERROR) {
+ clear_sense_data();
+ } else {
+ command_status |= OMTI_COMMAND_STATUS_ERROR;
+ set_sense_data(sense_code, cdb);
+ }
+ return sense_code == OMTI_SENSE_CODE_NO_ERROR;
+}
+
+/***************************************************************************
+ get_disk_track - get disk track from a command descriptor block
+ ***************************************************************************/
+
+UINT32 omti8621_device::get_disk_track(const UINT8 * cdb) {
+ UINT8 lun = get_lun(cdb);
+ UINT16 head = cdb[1] & 0x1f;
+ UINT32 cylinder = cdb[3] + ((cdb[2] & 0xc0) << 2) + ((cdb[1] & 0x80) << 3);
+ return cylinder * our_disks[lun]->heads + head;
+}
+
+/***************************************************************************
+ get_disk_address - get disk address from a command descriptor block
+ ***************************************************************************/
+
+UINT32 omti8621_device::get_disk_address(const UINT8 * cdb) {
+ UINT8 lun = get_lun(cdb);
+ UINT16 sector = cdb[2] & 0x3f;
+ return get_disk_track(cdb) * our_disks[lun]->sectors + sector;
+}
+
+/***************************************************************************
+ set_data_transfer - setup for data transfer from/to data
+ ***************************************************************************/
+
+void omti8621_device::set_data_transfer(UINT8 *data, UINT16 length)
+{
+ // set controller for read data transfer
+ omti_state = OMTI_STATE_DATA;
+ status_port |= OMTI_STATUS_REQ | OMTI_STATUS_IO | OMTI_STATUS_BUSY;
+ status_port &= ~OMTI_STATUS_CD;
+
+ data_buffer = data;
+ data_length = length;
+ data_index = 0;
+}
+
+/***************************************************************************
+ read_sectors_from_disk - read sectors starting at diskaddr into sector_buffer
+ ***************************************************************************/
+
+void omti8621_device::read_sectors_from_disk(INT32 diskaddr, UINT8 count, UINT8 lun)
+{
+ UINT8 *data_buffer = sector_buffer;
+ device_image_interface *image = our_disks[lun]->image;
+
+ while (count-- > 0) {
+ LOG2(("read_sectors_from_disk lun=%d diskaddr=%x", lun, diskaddr));
+
+ image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ image->fread( data_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ diskaddr++;
+ data_buffer += OMTI_DISK_SECTOR_SIZE;
+ }
+}
+
+/***************************************************************************
+ write_sectors_to_disk - write sectors starting at diskaddr from sector_buffer
+ ***************************************************************************/
+
+void omti8621_device::write_sectors_to_disk(INT32 diskaddr, UINT8 count, UINT8 lun)
+{
+ UINT8 *data_buffer = sector_buffer;
+ device_image_interface *image = our_disks[lun]->image;
+
+ while (count-- > 0) {
+ LOG2(("write_sectors_to_disk lun=%d diskaddr=%x", lun, diskaddr));
+
+ image->fseek( diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ image->fwrite( data_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ if (diskaddr == diskaddr_ecc_error) {
+ // reset previous ECC error
+ diskaddr_ecc_error = 0;
+ }
+
+ diskaddr++;
+ data_buffer += OMTI_DISK_SECTOR_SIZE;
+ }
+}
+
+/***************************************************************************
+ copy_sectors - copy sectors
+ ***************************************************************************/
+
+void omti8621_device::copy_sectors(INT32 dst_addr, INT32 src_addr, UINT8 count, UINT8 lun)
+{
+ device_image_interface *image = our_disks[lun]->image;
+
+ LOG2(("copy_sectors lun=%d src_addr=%x dst_addr=%x count=%x", lun, src_addr, dst_addr, count));
+
+ while (count-- > 0) {
+ image->fseek( src_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ image->fread( sector_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ image->fseek( dst_addr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ image->fwrite( sector_buffer, OMTI_DISK_SECTOR_SIZE);
+
+ if (dst_addr == diskaddr_ecc_error) {
+ // reset previous ECC error
+ diskaddr_ecc_error = 0;
+ }
+
+ src_addr++;
+ dst_addr++;
+ }
+}
+
+/***************************************************************************
+ format track - format a track
+ ***************************************************************************/
+
+void omti8621_device::format_track(const UINT8 * cdb)
+{
+ UINT8 lun = get_lun(cdb);
+ UINT32 disk_addr = get_disk_address(cdb);
+ UINT32 disk_track = get_disk_track(cdb);
+
+ if (diskaddr_ecc_error == disk_addr) {
+ // reset previous ECC error
+ diskaddr_ecc_error = 0;
+ }
+
+ if (diskaddr_format_bad_track == disk_track) {
+ // reset previous bad track formatting
+ diskaddr_format_bad_track = 0;
+ }
+
+ if (alternate_track_address[0] == disk_track) {
+ // reset source of alternate track address
+ alternate_track_address[0] = 0;
+ }
+
+ if (alternate_track_address[1] == disk_track) {
+ // reset alternate track address
+ alternate_track_address[1] = 0;
+ }
+
+ if (check_disk_address(cdb) ) {
+ if ((cdb[5] & 0x40) == 0) {
+ memset(sector_buffer, 0x6C, OMTI_DISK_SECTOR_SIZE * our_disks[lun]->sectors);
+ }
+ write_sectors_to_disk(disk_addr, our_disks[lun]->sectors, lun);
+ }
+
+}
+
+/***************************************************************************
+ set_esdi_defect_list - setup the (emty) ESDI defect list
+ ***************************************************************************/
+
+void omti8621_device::set_esdi_defect_list(UINT8 lun, UINT8 head)
+{
+ disk_data *disk = our_disks[lun];
+
+ memset(disk->esdi_defect_list, 0, sizeof(disk->esdi_defect_list));
+ disk->esdi_defect_list[0] = 1; // month
+ disk->esdi_defect_list[1] = 1; // day
+ disk->esdi_defect_list[2] = 90; // year
+ disk->esdi_defect_list[3] = head;
+ memset(disk->esdi_defect_list+6, 0xff, 5); // end of defect list
+}
+
+/***************************************************************************
+ log_command - log command from a command descriptor block
+ ***************************************************************************/
+
+void omti8621_device::log_command(const UINT8 cdb[], const UINT16 cdb_length)
+{
+ if (verbose > 0) {
+ int i;
+ logerror("%s: OMTI command ", cpu_context(this));
+ switch (cdb[0]) {
+ case OMTI_CMD_TEST_DRIVE_READY: // 0x00
+ logerror("Test Drive Ready");
+ break;
+ case OMTI_CMD_RECALIBRATE: // 0x01
+ logerror("Recalibrate");
+ break;
+ case OMTI_CMD_REQUEST_SENSE: // 0x03
+ logerror("Request Sense");
+ break;
+ case OMTI_CMD_READ_VERIFY: // 0x05
+ logerror("Read Verify");
+ break;
+ case OMTI_CMD_FORMAT_TRACK: // 0x06
+ logerror("Format Track");
+ break;
+ case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
+ logerror("Format Bad Track");
+ break;
+ case OMTI_CMD_READ: // 0x08
+ logerror("Read");
+ break;
+ case OMTI_CMD_WRITE: // 0x0A
+ logerror("Write");
+ break;
+ case OMTI_CMD_SEEK: // 0x0B
+ logerror("Seek");
+ break;
+ case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
+ logerror("Read Sector Buffer");
+ break;
+ case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
+ logerror("Write Sector Buffer");
+ break;
+ case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
+ logerror("Assign Alternate Track");
+ break;
+ case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
+ logerror("Read Data to Buffer");
+ break;
+ case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
+ logerror("Write Data from Buffer");
+ break;
+ case OMTI_CMD_COPY: // 0x20
+ logerror("Copy");
+ break;
+ case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
+ logerror("Read ESDI Defect List");
+ break;
+ case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
+ logerror("RAM. Diagnostic");
+ break;
+ case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
+ logerror("Controller Int. Diagnostic");
+ break;
+ case OMTI_CMD_READ_LONG: // 0xE5
+ logerror("Read Long");
+ break;
+ case OMTI_CMD_WRITE_LONG: // 0xE6
+ logerror("Write Long");
+ break;
+ case OMTI_CMD_READ_CONFIGURATION: // 0xEC
+ logerror("Read Configuration");
+ break;
+ case OMTI_CMD_INVALID_COMMAND: // 0xFF
+ logerror("Invalid Command");
+ break;
+ default:
+ logerror("!!! Unexpected Command !!!");
+ }
+// logerror(" (%02x, length=%02x)", cdb[0], cdb_length);
+ for (i = 0; i < cdb_length; i++) {
+ logerror(" %02x", cdb[i]);
+ }
+
+ switch (cdb[0]) {
+ case OMTI_CMD_READ_VERIFY: // 0x05
+ case OMTI_CMD_READ: // 0x08
+ case OMTI_CMD_WRITE: // 0x0a
+ case OMTI_CMD_SEEK: // 0x0b
+ case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
+ case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
+ case OMTI_CMD_COPY: // 0x20
+ logerror(" (diskaddr=%x count=%x)", get_disk_address(cdb), cdb[4]);
+ break;
+ }
+ logerror("\n");
+ }
+}
+
+/***************************************************************************
+ log_data - log data in the common data buffer
+ ***************************************************************************/
+
+void omti8621_device::log_data()
+{
+ if (verbose > 0) {
+ int i;
+ logerror("%s: OMTI data (length=%02x)", cpu_context(this),
+ data_length);
+ for (i = 0; i < data_length && i < OMTI_DISK_SECTOR_SIZE; i++) {
+ logerror(" %02x", data_buffer[i]);
+ }
+
+ if (i < data_length) {
+ logerror(" ...");
+ }
+ logerror("\n");
+ }
+}
+
+/***************************************************************************
+ do_command
+ ***************************************************************************/
+
+void omti8621_device::do_command(const UINT8 cdb[], const UINT16 cdb_length)
+{
+ UINT8 lun = get_lun(cdb);
+ disk_data *disk = our_disks[lun];
+ int command_duration = 0; // ms
+
+ log_command( cdb, cdb_length);
+
+ // default to read status and status is successful completion
+ omti_state = OMTI_STATE_STATUS;
+ status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
+ command_status = lun ? OMTI_COMMAND_STATUS_LUN : 0;
+
+ if (mask_port & OMTI_MASK_INTE) {
+ set_interrupt(CLEAR_LINE);
+ }
+
+ if (!disk->image->exists()) {
+ command_status |= OMTI_COMMAND_STATUS_ERROR; // no such drive
+ }
+
+ switch (cdb[0]) {
+ case OMTI_CMD_TEST_DRIVE_READY: // 0x00
+ if (!disk->image->exists())
+ {
+ set_sense_data(OMTI_SENSE_CODE_DRIVE_NOT_READY, cdb);
+ }
+ break;
+
+ case OMTI_CMD_RECALIBRATE: // 0x01
+ break;
+
+ case OMTI_CMD_REQUEST_SENSE: // 0x03
+ set_data_transfer(sense_data, sizeof(sense_data));
+ break;
+
+ case OMTI_CMD_READ_VERIFY: // 0x05
+ check_disk_address(cdb);
+ break;
+
+ case OMTI_CMD_FORMAT_TRACK: // 0x06
+ format_track(cdb);
+ break;
+
+ case OMTI_CMD_FORMAT_BAD_TRACK: // 0x07
+ diskaddr_format_bad_track = get_disk_address(cdb);
+ break;
+
+ case OMTI_CMD_READ: // 0x08
+ if (check_disk_address(cdb)) {
+ // read data from controller
+ read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun);
+ set_data_transfer(sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]);
+ }
+ break;
+
+ case OMTI_CMD_WRITE: // 0x0A
+ log_data();
+ if (check_disk_address(cdb)) {
+ write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun);
+ }
+ break;
+
+ case OMTI_CMD_SEEK: // 0x0B
+ check_disk_address(cdb);
+ break;
+
+ case OMTI_CMD_READ_SECTOR_BUFFER: // 0x0E
+ set_data_transfer(sector_buffer, OMTI_DISK_SECTOR_SIZE*cdb[4]);
+ break;
+
+ case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
+ log_data();
+ break;
+
+ case OMTI_CMD_COPY: // 0x20
+ if (check_disk_address(cdb) && check_disk_address(cdb+4)) {
+ // copy sectors
+ copy_sectors (get_disk_address(cdb+4), get_disk_address(cdb), cdb[4], lun);
+ }
+ break;
+
+ case OMTI_CMD_READ_ESDI_DEFECT_LIST: // 0x37
+ set_esdi_defect_list(get_lun(cdb), cdb[1] & 0x1f);
+ set_data_transfer(disk->esdi_defect_list, sizeof(disk->esdi_defect_list));
+ break;
+
+ case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
+ log_data();
+ alternate_track_address[0] = get_disk_track(cdb);
+ alternate_track_address[1] = get_disk_track(alternate_track_buffer-1);;
+ break;
+
+ case OMTI_CMD_READ_DATA_TO_BUFFER: // 0x1E
+ if (check_disk_address(cdb)) {
+ // read data from controller
+ read_sectors_from_disk (get_disk_address(cdb), cdb[4], lun);
+ // Domain/OS doesn't expect zero access time
+ command_duration += 1; // 1 ms is enough, average time would be 30 ms)
+ }
+ break;
+
+ case OMTI_CMD_WRITE_DATA_FROM_BUFFER: // 0x1F
+ log_data();
+ if (check_disk_address(cdb)) {
+ write_sectors_to_disk(get_disk_address(cdb), cdb[4], lun);
+ }
+ break;
+
+ case OMTI_CMD_RAM_DIAGNOSTICS: // 0xE0
+ break;
+
+ case OMTI_CMD_CONTROLLER_INT_DIAGNOSTIC: // 0xE4
+ break;
+
+ case OMTI_CMD_READ_LONG: // 0xE5
+ if (check_disk_address(cdb)) {
+ // read data from controller
+ read_sectors_from_disk(get_disk_address(cdb), cdb[4], lun);
+ set_data_transfer(sector_buffer, OMTI_DISK_SECTOR_SIZE+6);
+ }
+ break;
+
+ case OMTI_CMD_WRITE_LONG: // 0xE6
+ log_data();
+ if (check_disk_address(cdb)) {
+ UINT32 diskaddr = get_disk_address(cdb);
+ write_sectors_to_disk(diskaddr, cdb[4], lun);
+ // this will spoil the ECC code
+ diskaddr_ecc_error = diskaddr;
+ }
+ break;
+
+ case OMTI_CMD_READ_CONFIGURATION: // 0xEC
+ set_configuration_data(get_lun(cdb));
+ set_data_transfer(disk->config_data, sizeof(disk->config_data));
+ break;
+
+ case OMTI_CMD_INVALID_COMMAND: // 0xFF
+ set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
+ command_status |= OMTI_COMMAND_STATUS_ERROR;
+ break;
+
+ default:
+ LOG(("do_command: UNEXPECTED command %02x",cdb[0]));
+ set_sense_data(OMTI_SENSE_CODE_INVALID_COMMAND, cdb);
+ command_status |= OMTI_COMMAND_STATUS_ERROR;
+ break;
+ }
+
+ if (mask_port & OMTI_MASK_INTE) {
+// if (omti_state != OMTI_STATE_STATUS) {
+// LOG(("do_command: UNEXPECTED omti_state %02x",omti_state));
+// }
+ status_port |= OMTI_STATUS_IREQ;
+ if (command_duration == 0)
+ {
+ set_interrupt(ASSERT_LINE);
+ }
+ else
+ {
+ // FIXME: should delay omti_state and status_port as well
+ m_timer->adjust(attotime::from_msec(command_duration), 0);
+ }
+ }
+}
+
+/***************************************************************************
+ get_command_length
+ ***************************************************************************/
+
+UINT8 omti8621_device::get_command_length(UINT8 command_byte)
+{
+ return command_byte == OMTI_CMD_COPY ? 10 : 6;
+}
+
+/***************************************************************************
+ get_data
+ ***************************************************************************/
+
+UINT16 omti8621_device::get_data()
+{
+ UINT16 data = 0xff;
+ if (data_index < data_length) {
+ data = data_buffer[data_index++] << 8;
+ data |= data_buffer[data_index++];
+ if (data_index >= data_length) {
+ omti_state = OMTI_STATE_STATUS;
+ status_port |= OMTI_STATUS_IO | OMTI_STATUS_CD;
+ log_data();
+ }
+ } else {
+ LOG(("UNEXPECTED reading OMTI 8621 data (buffer length exceeded)"));
+ }
+ return data;
+}
+
+/***************************************************************************
+ set_data
+ ***************************************************************************/
+
+void omti8621_device::set_data(UINT16 data)
+{
+ if (data_index < data_length) {
+ data_buffer[data_index++] = data >> 8;
+ data_buffer[data_index++] = data & 0xff;
+ if (data_index >= data_length) {
+ do_command(command_buffer, command_index);
+ }
+ } else {
+ LOG(("UNEXPECTED writing OMTI 8621 data (buffer length exceeded)"));
+ }
+}
+
+/***************************************************************************
+ OMTI8621 Disk Controller-AT Registers
+***************************************************************************/
+
+WRITE16_MEMBER(omti8621_device::write)
+{
+ switch (mem_mask)
+ {
+ case 0x00ff:
+ write8(space, offset*2+1, data, mem_mask);
+ break;
+
+ case 0xff00:
+ write8(space, offset*2, data>>8, mem_mask>>8);
+ break;
+
+ default:
+ set_data(data);
+ break;
+ }
+}
+
+WRITE8_MEMBER(omti8621_device::write8)
+{
+ switch (offset)
+ {
+ case OMTI_PORT_DATA_OUT: // 0x00
+ switch (omti_state) {
+ case OMTI_STATE_COMMAND:
+ LOG2(("writing OMTI 8621 Command Register at offset %02x = %02x", offset, data));
+ if (command_index == 0) {
+ command_length = get_command_length(data);
+ }
+
+ if (command_index < command_length) {
+ command_buffer[command_index++] = data;
+ } else {
+ LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (command length exceeded)", offset, data));
+ }
+
+ if (command_index == command_length) {
+ switch (command_buffer[0]) {
+ case OMTI_CMD_WRITE: // 0x0A
+ // TODO: check diskaddr
+ // Fall through
+ case OMTI_CMD_WRITE_SECTOR_BUFFER: // 0x0F
+ set_data_transfer(sector_buffer,
+ OMTI_DISK_SECTOR_SIZE * command_buffer[4]);
+ status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ case OMTI_CMD_ASSIGN_ALTERNATE_TRACK: // 0x11
+ set_data_transfer(alternate_track_buffer, sizeof(alternate_track_buffer));
+ status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ case OMTI_CMD_WRITE_LONG: // 0xE6
+ // TODO: check diskaddr
+ set_data_transfer(sector_buffer,
+ (OMTI_DISK_SECTOR_SIZE +6) * command_buffer[4]);
+ status_port &= ~OMTI_STATUS_IO;
+ break;
+
+ default:
+ do_command(command_buffer, command_index);
+ break;
+ }
+ }
+ break;
+
+ case OMTI_STATE_DATA:
+ LOG(("UNEXPECTED: writing OMTI 8621 Data Register at offset %02x = %02x", offset, data));
+ break;
+
+ default:
+ LOG(("UNEXPECTED writing OMTI 8621 Data Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
+ break;
+ }
+ break;
+
+ case OMTI_PORT_RESET: // 0x01
+ LOG2(("writing OMTI 8621 Reset Register at offset %02x = %02x", offset, data));
+ device_reset();
+ break;
+
+ case OMTI_PORT_SELECT: // 0x02
+ LOG2(("writing OMTI 8621 Select Register at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
+ omti_state = OMTI_STATE_COMMAND;
+
+ status_port |= OMTI_STATUS_BUSY | OMTI_STATUS_REQ | OMTI_STATUS_CD;
+ status_port &= ~OMTI_STATUS_IO;
+
+ command_status = 0;
+ command_index = 0;
+ break;
+
+ case OMTI_PORT_MASK: // 0x03
+ LOG2(("writing OMTI 8621 Mask Register at offset %02x = %02x", offset, data));
+ mask_port = data;
+
+ if ((data & OMTI_MASK_INTE) == 0) {
+ status_port &= ~OMTI_STATUS_IREQ;
+ set_interrupt(CLEAR_LINE);
+ }
+
+ if ((data & OMTI_MASK_DMAE) == 0) {
+ status_port &= ~OMTI_STATUS_DREQ;
+ }
+ break;
+
+ default:
+ LOG(("UNEXPECTED writing OMTI 8621 Register at offset %02x = %02x", offset, data));
+ break;
+ }
+}
+
+READ16_MEMBER(omti8621_device::read)
+{
+ switch (mem_mask)
+ {
+ case 0x00ff:
+ return read8(space, offset*2+1, mem_mask);
+ case 0xff00:
+ return read8(space, offset*2, mem_mask >> 8) << 8;
+ default:
+ return get_data();
+ }
+}
+
+READ8_MEMBER(omti8621_device::read8)
+{
+ UINT8 data = 0xff;
+ static UINT8 last_data = 0xff;
+
+ switch (offset) {
+ case OMTI_PORT_DATA_IN: // 0x00
+ if (status_port & OMTI_STATUS_CD)
+ {
+ data = command_status;
+ switch (omti_state)
+ {
+ case OMTI_STATE_COMMAND:
+ LOG2(("reading OMTI 8621 Data Status Register 1 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
+ break;
+ case OMTI_STATE_STATUS:
+ omti_state = OMTI_STATE_IDLE;
+ status_port &= ~(OMTI_STATUS_BUSY | OMTI_STATUS_CD | OMTI_STATUS_IO | OMTI_STATUS_REQ);
+ LOG2(("reading OMTI 8621 Data Status Register 2 at offset %02x = %02x", offset, data));
+ break;
+ default:
+ LOG(("UNEXPECTED reading OMTI 8621 Data Status Register 3 at offset %02x = %02x (omti state = %02x)", offset, data, omti_state));
+ break;
+ }
+ }
+ else
+ {
+ LOG(("UNEXPECTED reading OMTI 8621 Data Register 4 at offset %02x = %02x (status bit C/D = 0)", offset, data));
+ }
+ break;
+
+ case OMTI_PORT_STATUS: // 0x01
+ data = status_port;
+ // omit excessive logging
+ if (data != last_data)
+ {
+ LOG2(("reading OMTI 8621 Status Register 5 at offset %02x = %02x", offset, data));
+// last_data = data;
+ }
+ break;
+
+ case OMTI_PORT_CONFIG: // 0x02
+ data = config_port;
+ LOG2(("reading OMTI 8621 Configuration Register at offset %02x = %02x", offset, data));
+ break;
+
+ case OMTI_PORT_MASK: // 0x03
+ data = mask_port ;
+ // win.dex will update the mask register with read-modify-write
+ // LOG2(("reading OMTI 8621 Mask Register at offset %02x = %02x (UNEXPECTED!)", offset, data));
+ break;
+
+ default:
+ LOG(("UNEXPECTED reading OMTI 8621 Register at offset %02x = %02x", offset, data));
+ break;
+ }
+
+ return data;
+}
+
+void omti8621_device::set_verbose(int on_off)
+{
+ verbose = on_off == 0 ? 0 : VERBOSE > 1 ? VERBOSE : 1;
+}
+
+/***************************************************************************
+ get_sector - get sector diskaddr of logical unit lun into data_buffer
+ ***************************************************************************/
+
+UINT32 omti8621_device::get_sector(INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun)
+{
+ disk_data *disk = our_disks[lun];
+
+ if (disk->image == NULL || !disk->image->exists())
+ {
+ return 0;
+ }
+ else
+ {
+ LOG1(("omti8621_get_sector %x on lun %d", diskaddr, lun));
+
+ // restrict length to size of 1 sector (i.e. 1024 Byte)
+ length = length < OMTI_DISK_SECTOR_SIZE ? length : OMTI_DISK_SECTOR_SIZE;
+
+ disk->image->fseek(diskaddr * OMTI_DISK_SECTOR_SIZE, SEEK_SET);
+ disk->image->fread(data_buffer, length);
+
+ return length;
+ }
+}
+
+
+/***************************************************************************
+ omti_set_jumper - set OMI jumpers
+ ***************************************************************************/
+
+void omti8621_device::set_jumper(UINT16 disk_type)
+{
+ LOG1(("set_jumper: disk type=%x", disk_type));
+
+ switch (disk_type)
+ {
+ case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
+ jumper = OMTI_CONFIG_W22 | OMTI_CONFIG_W23;
+ break;
+
+ case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
+ default:
+ jumper = OMTI_CONFIG_W20;
+ break;
+ }
+}
+
+// FDC uses the standard IRQ 6 / DMA 2, doesn't appear to be configurable
+void omti8621_device::fdc_irq_w(bool state)
+{
+ m_isa->irq6_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+void omti8621_device::fdc_drq_w(bool state)
+{
+ m_isa->drq2_w(state ? ASSERT_LINE : CLEAR_LINE);
+}
+
+UINT8 omti8621_device::dack_r(int line)
+{
+ return m_fdc->dma_r();
+}
+
+void omti8621_device::dack_w(int line, UINT8 data)
+{
+ return m_fdc->dma_w(data);
+}
+
+void omti8621_device::eop_w(int state)
+{
+ m_fdc->tc_w(state == ASSERT_LINE);
+}
+
+//##########################################################################
+
+// device type definition
+const device_type OMTI_DISK = &device_creator<omti_disk_image_device>;
+
+omti_disk_image_device::omti_disk_image_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, OMTI_DISK, "OMTI8621 ESDI disk", tag, owner, clock, "omti_disk_image", __FILE__),
+ device_image_interface(mconfig, *this)
+{
+}
+
+void omti_disk_image_device::device_config_complete()
+{
+ update_names(OMTI_DISK, "disk", "disk");
+};
+
+
+/***************************************************************************
+ get_safe_disk_token - makes sure that the passed in device is a OMTI disk
+ ***************************************************************************/
+
+INLINE disk_data *get_safe_disk_token(device_t *device) {
+ assert(device != NULL);
+ assert(device->type() == OMTI_DISK);
+ return (disk_data *) downcast<omti_disk_image_device *>(device)->token();
+}
+
+/***************************************************************************
+ omti_disk_config - configure disk parameters
+ ***************************************************************************/
+
+static void omti_disk_config(disk_data *disk, UINT16 disk_type)
+{
+ DLOG1(("omti_disk_config: configuring disk with type %x", disk_type));
+
+ switch (disk_type)
+ {
+ case OMTI_DISK_TYPE_348_MB: // Maxtor 380 MB (348-MB FA formatted)
+ disk->cylinders = 1223;
+ disk->heads = 15;
+ disk->sectors = 18;
+ break;
+
+ case OMTI_DISK_TYPE_155_MB: // Micropolis 170 MB (155-MB formatted)
+ default:
+ disk->cylinders = 1023;
+ disk->heads = 8;
+ disk->sectors = 18;
+ break;
+ }
+
+ disk->type = disk_type;
+ disk->sectorbytes = OMTI_DISK_SECTOR_SIZE;
+ disk->sector_count = disk->cylinders * disk->heads * disk->sectors;
+}
+
+/*-------------------------------------------------
+ device start callback
+-------------------------------------------------*/
+
+void omti_disk_image_device::device_start()
+{
+ disk_data *disk = get_safe_disk_token(this);
+
+ disk->device = this;
+ // note: we must have disk->device before we can log
+
+ disk->image = this;
+
+ if (disk->image->image_core_file() == NULL)
+ {
+ DLOG1(("device_start_omti_disk: no disk"));
+ }
+ else
+ {
+ DLOG1(("device_start_omti_disk: with disk image %s",disk->image->basename() ));
+ }
+
+ // default disk type
+ omti_disk_config(disk, OMTI_DISK_TYPE_DEFAULT);
+}
+
+/*-------------------------------------------------
+ device reset callback
+-------------------------------------------------*/
+
+void omti_disk_image_device::device_reset()
+{
+ disk_data *disk = get_safe_disk_token(this);
+ DLOG1(("device_reset_omti_disk"));
+
+ if (exists() && fseek(0, SEEK_END) == 0)
+ {
+ UINT32 disk_size = (UINT32)(ftell() / OMTI_DISK_SECTOR_SIZE);
+ UINT16 disk_type = disk_size >= 300000 ? OMTI_DISK_TYPE_348_MB : OMTI_DISK_TYPE_155_MB;
+ if (disk_type != disk->type) {
+ DLOG1(("device_reset_omti_disk: disk size=%d blocks, disk type=%x", disk_size, disk_type ));
+ omti_disk_config(disk, disk_type);
+ }
+ }
+}
+
+/*-------------------------------------------------
+ disk image create callback
+-------------------------------------------------*/
+
+bool omti_disk_image_device::call_create(int format_type, option_resolution *format_options)
+{
+ disk_data *disk = get_safe_disk_token(this);
+ DLOG(("device_create_omti_disk: creating OMTI Disk with %d blocks", disk->sector_count));
+
+ int x;
+ unsigned char sectordata[OMTI_DISK_SECTOR_SIZE]; // empty block data
+
+
+ memset(sectordata, 0x55, sizeof(sectordata));
+ for (x = 0; x < disk->sector_count; x++)
+ {
+ if (fwrite(sectordata, OMTI_DISK_SECTOR_SIZE)
+ < OMTI_DISK_SECTOR_SIZE)
+ {
+ return IMAGE_INIT_FAIL;
+ }
+ }
+ return IMAGE_INIT_PASS;
+}
+
diff --git a/src/emu/bus/isa/omti8621.h b/src/emu/bus/isa/omti8621.h
new file mode 100644
index 00000000000..b89bf2b91d9
--- /dev/null
+++ b/src/emu/bus/isa/omti8621.h
@@ -0,0 +1,154 @@
+/*
+ * omti8621.h - SMS OMTI 8621 disk controller
+ *
+ * Created on: August 30, 2010
+ * Author: Hans Ostermeyer
+ *
+ * Converted to ISA device March 3, 2014 by R. Belmont
+ *
+ * Released for general non-commercial use under the MAME license
+ * Visit http://mamedev.org for licensing and usage restrictions.
+ *
+ */
+
+#pragma once
+
+#ifndef ISA_OMTI8621_H_
+#define ISA_OMTI8621_H_
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/pc_fdc.h"
+
+#define OMTI_MAX_LUN 1
+#define CDB_SIZE 10
+
+/***************************************************************************
+ FUNCTION PROTOTYPES
+ ***************************************************************************/
+
+struct disk_data
+{
+ device_t *device;
+ UINT16 type;
+ UINT16 cylinders;
+ UINT16 heads;
+ UINT16 sectors;
+ UINT32 sectorbytes;
+ UINT32 sector_count;
+
+ device_image_interface *image;
+
+ // configuration data
+ UINT8 config_data[10];
+
+ // ESDI defect list data
+ UINT8 esdi_defect_list[256];
+};
+
+/* ----- device interface ----- */
+
+class omti8621_device : public device_t, public device_isa16_card_interface
+{
+public:
+ omti8621_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ ~omti8621_device() {}
+
+ DECLARE_READ16_MEMBER(read);
+ DECLARE_WRITE16_MEMBER(write);
+
+ void set_verbose(int on_off);
+
+ // get sector diskaddr of logical unit lun into data_buffer
+ UINT32 get_sector(INT32 diskaddr, UINT8 *data_buffer, UINT32 length, UINT8 lun);
+
+ required_device<pc_fdc_interface> m_fdc;
+ required_ioport m_iobase;
+ required_ioport m_biosopts;
+
+ DECLARE_FLOPPY_FORMATS( floppy_formats );
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line, UINT8 data);
+ virtual void eop_w(int state);
+
+ void set_interrupt(enum line_state line_state);
+
+private:
+ disk_data *our_disks[OMTI_MAX_LUN+1];
+
+ UINT16 jumper;
+
+ UINT8 omti_state;
+
+ UINT8 status_port;
+ UINT8 config_port;
+ UINT8 mask_port;
+
+ // command descriptor block
+ UINT8 command_buffer[CDB_SIZE];
+ int command_length;
+ int command_index;
+ int command_status;
+
+ // data buffer
+ UINT8 *sector_buffer;
+ UINT8 *data_buffer;
+ int data_length;
+ int data_index;
+
+ // sense data
+ UINT8 sense_data[4];
+
+ // these are used only to satisfy dex
+ UINT32 diskaddr_ecc_error;
+ UINT32 diskaddr_format_bad_track;
+ UINT8 alternate_track_buffer[4];
+ UINT32 alternate_track_address[2];
+
+ emu_timer *m_timer;
+
+ bool m_installed;
+
+ void clear_sense_data();
+ void set_sense_data(UINT8 code, const UINT8 * cdb);
+ void set_configuration_data(UINT8 lun);
+ UINT8 get_lun(const UINT8 * cdb);
+ UINT8 check_disk_address(const UINT8 *cdb);
+ UINT32 get_disk_track(const UINT8 * cdb);
+ UINT32 get_disk_address(const UINT8 * cdb);
+ void set_data_transfer(UINT8 *data, UINT16 length);
+ void read_sectors_from_disk(INT32 diskaddr, UINT8 count, UINT8 lun);
+ void write_sectors_to_disk(INT32 diskaddr, UINT8 count, UINT8 lun);
+ void copy_sectors(INT32 dst_addr, INT32 src_addr, UINT8 count, UINT8 lun);
+ void format_track(const UINT8 * cdb);
+ void set_esdi_defect_list(UINT8 lun, UINT8 head);
+ void log_command(const UINT8 cdb[], const UINT16 cdb_length);
+ void log_data();
+ void do_command(const UINT8 cdb[], const UINT16 cdb_length);
+ UINT8 get_command_length(UINT8 command_byte);
+ UINT16 get_data();
+ void set_data(UINT16 data);
+ void set_jumper(UINT16 disk_type);
+ DECLARE_READ8_MEMBER(read8);
+ DECLARE_WRITE8_MEMBER(write8);
+ void fdc_irq_w(bool state);
+ void fdc_drq_w(bool state);
+
+};
+
+extern const device_type ISA16_OMTI8621;
+
+//###############################################################
+
+#endif /* OMTI8621_H_ */
diff --git a/src/emu/bus/isa/p1_fdc.c b/src/emu/bus/isa/p1_fdc.c
new file mode 100644
index 00000000000..6035b677463
--- /dev/null
+++ b/src/emu/bus/isa/p1_fdc.c
@@ -0,0 +1,214 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 FDC device (model B504)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "p1_fdc.h"
+
+#include "cpu/i86/i86.h"
+#include "formats/dsk_dsk.h"
+#include "formats/pc_dsk.h"
+
+#define VERBOSE_DBG 0
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_DBG>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type P1_FDC = &device_creator<p1_fdc_device>;
+
+static DECLARE_READ8_DEVICE_HANDLER(p1_FDC_r);
+static DECLARE_WRITE8_DEVICE_HANDLER(p1_FDC_w);
+
+FLOPPY_FORMATS_MEMBER( p1_fdc_device::floppy_formats )
+ FLOPPY_PC_FORMAT,
+ FLOPPY_DSK_FORMAT
+FLOPPY_FORMATS_END
+
+static SLOT_INTERFACE_START( poisk1_floppies )
+ SLOT_INTERFACE( "525qd", FLOPPY_525_QD )
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( fdc_b504 )
+ MCFG_FD1793x_ADD("fdc", XTAL_16MHz / 16)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:0", poisk1_floppies, "525qd", p1_fdc_device::floppy_formats)
+ MCFG_FLOPPY_DRIVE_ADD("fdc:1", poisk1_floppies, "525qd", p1_fdc_device::floppy_formats)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// ROM( p1_fdc )
+//-------------------------------------------------
+
+ROM_START( p1_fdc )
+ ROM_REGION( 0x0800, "p1_fdc", 0 )
+ ROM_DEFAULT_BIOS("a302")
+ ROM_SYSTEM_BIOS(0, "normal", "B504 standard ROM")
+ ROMX_LOAD( "b_ngmd_n.rf2", 0x00000, 0x0800, CRC(967e172a) SHA1(95117c40fd9f624fee08ccf37f615b16ff249688), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "a302", "v3.02") // Additional ROM BIOS v3.02 for DISKETTE service (c) Moscow 1991
+ ROMX_LOAD( "b_ngmd_t.rf2", 0x00000, 0x0800, CRC(630010b1) SHA1(50876fe4f5f4f32a242faa70f9154574cd315ec4), ROM_BIOS(2))
+ ROM_SYSTEM_BIOS(2, "ae304", "v3.04") // Additional enhanced ROM BIOS v3.04 for DISKETTE service (c) V.Rusakow Moscow 1992
+ ROMX_LOAD( "p_fdd_nm.bin", 0x00000, 0x0800, CRC(0b7f867d) SHA1(9fe7e0ab2242e50394d1162cf1a619b6f2994bfb), ROM_BIOS(3))
+ ROM_SYSTEM_BIOS(3, "ae308", "v3.08") // Additional enhanced ROM BIOS v3.08 for DISKETTE service (c) V.Rusakov Tarasovka 1992
+ ROMX_LOAD( "p_fdd_my.bin", 0x00000, 0x0800, CRC(da5d0eaf) SHA1(b188ba856bd28e4964a88feb0b0b2ba7eb320efc), ROM_BIOS(4))
+ROM_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor p1_fdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( fdc_b504 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *p1_fdc_device::device_rom_region() const
+{
+ return ROM_NAME( p1_fdc );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+UINT8 p1_fdc_device::p1_wd17xx_motor_r()
+{
+ DBG_LOG(1,"p1_fdc_motor_r",("R = $%02x\n", 0));
+ // XXX always on for now
+ return 0;
+}
+
+UINT8 p1_fdc_device::p1_wd17xx_aux_r()
+{
+ cpu_device *maincpu = machine().device<cpu_device>("maincpu");
+
+ if (!m_fdc->drq_r() && !m_fdc->intrq_r()) {
+ // fake cpu wait by resetting PC one insn back
+ maincpu->set_state_int(I8086_IP, maincpu->state_int(I8086_IP) - 2);
+ maincpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE);
+ }
+
+ return m_fdc->drq_r();
+}
+
+/*
+; D0 - DRIVE SELECT 0
+; D1 - DRIVE SELECT 1
+; D2 - MOTOR ON 0
+; D3 - MOTOR ON 1
+; D4 - SIDE (HEAD) SELECT
+; D5 - DOUBLE DENSITY
+; D6 - FDC RESET
+; D7 - NO USE
+*/
+void p1_fdc_device::p1_wd17xx_aux_w(int data)
+{
+ DBG_LOG(1,"p1_fdc_aux_w",("W $%02x\n", data));
+
+ floppy_image_device *floppy0 = m_fdc->subdevice<floppy_connector>("0")->get_device();
+ floppy_image_device *floppy1 = m_fdc->subdevice<floppy_connector>("1")->get_device();
+ floppy_image_device *floppy = ((data & 2)?floppy1:floppy0);
+
+ if(!BIT(data, 6))
+ m_fdc->reset();
+
+ m_fdc->set_floppy(floppy);
+
+ floppy->ss_w(BIT(data, 4));
+ m_fdc->dden_w(BIT(data, 5));
+
+ floppy0->mon_w(!(data & 4));
+ floppy1->mon_w(!(data & 8));
+}
+
+void p1_fdc_device::p1_fdc_irq_drq(bool state)
+{
+ cpu_device *maincpu = machine().device<cpu_device>("maincpu");
+
+ if(state)
+ maincpu->set_input_line(INPUT_LINE_HALT, CLEAR_LINE);
+}
+
+static READ8_DEVICE_HANDLER( p1_FDC_r )
+{
+ UINT8 data = 0xff;
+ p1_fdc_device *fdc = downcast<p1_fdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: data = fdc->p1_wd17xx_aux_r(); break;
+ case 2: data = fdc->p1_wd17xx_motor_r(); break;
+ }
+
+ return data;
+}
+
+static WRITE8_DEVICE_HANDLER( p1_FDC_w )
+{
+ p1_fdc_device *fdc = downcast<p1_fdc_device *>(device);
+
+ switch( offset )
+ {
+ case 0: fdc->p1_wd17xx_aux_w(data); break;
+ }
+}
+
+//-------------------------------------------------
+// p1_fdc_device - constructor
+//-------------------------------------------------
+
+p1_fdc_device::p1_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, P1_FDC, "Poisk-1 floppy B504", tag, owner, clock, "p1_fdc", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_fdc(*this, "fdc")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void p1_fdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xe0000, 0xe07ff, 0, 0, "XXX", "p1_fdc");
+ m_isa->install_device(0x00c0, 0x00c3, 0, 0,
+ READ8_DEVICE_DELEGATE(m_fdc, fd1793_t, read),
+ WRITE8_DEVICE_DELEGATE(m_fdc, fd1793_t, write) );
+ m_isa->install_device(this, 0x00c4, 0x00c7, 0, 0, FUNC(p1_FDC_r), FUNC(p1_FDC_w) );
+ m_fdc->setup_drq_cb(fd1793_t::line_cb(FUNC(p1_fdc_device::p1_fdc_irq_drq), this));
+ m_fdc->setup_intrq_cb(fd1793_t::line_cb(FUNC(p1_fdc_device::p1_fdc_irq_drq), this));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void p1_fdc_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/p1_fdc.h b/src/emu/bus/isa/p1_fdc.h
new file mode 100644
index 00000000000..b85a6812b99
--- /dev/null
+++ b/src/emu/bus/isa/p1_fdc.h
@@ -0,0 +1,61 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 FDC device (model B504)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __P1_FDC__
+#define __P1_FDC__
+
+#include "emu.h"
+
+#include "imagedev/flopdrv.h"
+#include "isa.h"
+#include "machine/wd_fdc.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class p1_fdc_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ p1_fdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_FLOPPY_FORMATS( floppy_formats );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_device<fd1793_t> m_fdc;
+
+public:
+ void p1_wd17xx_aux_w(int data);
+ UINT8 p1_wd17xx_aux_r();
+ UINT8 p1_wd17xx_motor_r();
+ void p1_fdc_irq_drq(bool state);
+
+};
+
+
+// device type definition
+extern const device_type P1_FDC;
+
+
+#endif
diff --git a/src/emu/bus/isa/p1_hdc.c b/src/emu/bus/isa/p1_hdc.c
new file mode 100644
index 00000000000..5a52d9df534
--- /dev/null
+++ b/src/emu/bus/isa/p1_hdc.c
@@ -0,0 +1,159 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 HDC device (model B942)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "p1_hdc.h"
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define VERBOSE_DBG 1
+
+#define DBG_LOG(N,M,A) \
+ do { \
+ if(VERBOSE_DBG>=N) \
+ { \
+ if( M ) \
+ logerror("%11.6f: %-24s",machine().time().as_double(),(char*)M ); \
+ logerror A; \
+ } \
+ } while (0)
+
+#define KM1809VG7_TAG "d17"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type P1_HDC = &device_creator<p1_hdc_device>;
+
+static WD2010_INTERFACE( hdc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC
+};
+
+static MACHINE_CONFIG_FRAGMENT( hdc_b942 )
+ MCFG_WD2010_ADD(KM1809VG7_TAG, 5000000, hdc_intf) // XXX clock?
+
+ MCFG_HARDDISK_ADD("hard0")
+ MCFG_HARDDISK_ADD("hard1")
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// ROM( p1_hdc )
+//-------------------------------------------------
+
+ROM_START( p1_hdc )
+ ROM_REGION( 0x0800, "p1_hdc", 0 )
+ ROM_DEFAULT_BIOS("v14")
+ ROM_SYSTEM_BIOS(0, "v11", "ver 1.1")
+ ROMX_LOAD( "b_hd_v11.rf2", 0x00000, 0x0800, CRC(a19c39b2) SHA1(57faa56b320abf801fedbed578cf97d253e5b777), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "v12", "ver 1.2")
+ ROMX_LOAD( "p_hdd_nm.bin", 0x00000, 0x0800, CRC(d5f8e4cc) SHA1(5b533642df30958539715f87a7f25b0d66dd0861), ROM_BIOS(2))
+ ROM_SYSTEM_BIOS(2, "v14", "ver 1.4") // (c) `.lesnyh. , 1992
+ ROMX_LOAD( "b942_5mb.bin", 0x00000, 0x0800, CRC(a3cfa240) SHA1(0b0aa1ce839a957153bfbbe70310480ca9fe21b6), ROM_BIOS(3))
+ROM_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor p1_hdc_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( hdc_b942 );
+}
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *p1_hdc_device::device_rom_region() const
+{
+ return ROM_NAME( p1_hdc );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+
+READ8_MEMBER(p1_hdc_device::p1_HDC_r)
+{
+ UINT8 data = 0x00;
+
+ switch (offset >> 8) {
+ case 8: data = m_hdc->read(space, offset & 255);
+ }
+ DBG_LOG(1,"hdc",("R $%04x == $%02x\n", offset, data));
+
+ return data;
+}
+
+WRITE8_MEMBER(p1_hdc_device::p1_HDC_w)
+{
+ DBG_LOG(1,"hdc",("W $%04x <- $%02x\n", offset, data));
+ switch (offset >> 8) {
+ case 8: m_hdc->write(space, offset & 255, data, 0);
+ }
+}
+
+//-------------------------------------------------
+// p1_hdc_device - constructor
+//-------------------------------------------------
+
+p1_hdc_device::p1_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, P1_HDC, "Poisk-1 MFM disk B942", tag, owner, clock, "p1_hdc", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_hdc(*this, KM1809VG7_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void p1_hdc_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xe2000, 0xe27ff, 0, 0, "XXX", "p1_hdc");
+ m_isa->install_memory(0xd0000, 0xd0fff, 0, 0,
+ READ8_DELEGATE(p1_hdc_device, p1_HDC_r),
+ WRITE8_DELEGATE(p1_hdc_device, p1_HDC_w) );
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void p1_hdc_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/p1_hdc.h b/src/emu/bus/isa/p1_hdc.h
new file mode 100644
index 00000000000..0d27af123ec
--- /dev/null
+++ b/src/emu/bus/isa/p1_hdc.h
@@ -0,0 +1,58 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 HDC device (model B942)
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __P1_HDC__
+#define __P1_HDC__
+
+#include "emu.h"
+
+#include "imagedev/harddriv.h"
+#include "isa.h"
+#include "machine/wd2010.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class p1_hdc_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ p1_hdc_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+private:
+ required_device<wd2010_device> m_hdc;
+
+ //UINT8 m_ram[0x800];
+
+public:
+ DECLARE_READ8_MEMBER(p1_HDC_r);
+ DECLARE_WRITE8_MEMBER(p1_HDC_w);
+};
+
+
+// device type definition
+extern const device_type P1_HDC;
+
+
+#endif
diff --git a/src/emu/bus/isa/p1_rom.c b/src/emu/bus/isa/p1_rom.c
new file mode 100644
index 00000000000..4da8ca0f89d
--- /dev/null
+++ b/src/emu/bus/isa/p1_rom.c
@@ -0,0 +1,79 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 ROM cartridge device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "p1_rom.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type P1_ROM = &device_creator<p1_rom_device>;
+
+
+//-------------------------------------------------
+// ROM( p1_rom )
+//-------------------------------------------------
+
+ROM_START( p1_rom )
+ ROM_REGION( 0x2000, "p1_rom", 0 )
+ ROM_SYSTEM_BIOS(0, "ram", "Test 3 -- RAM test")
+ ROMX_LOAD( "p1_t_ram.rf4", 0x00000, 0x2000, CRC(e42f5a61) SHA1(ce2554eae8f0d2b6d482890dd198cf7e2d29c655), ROM_BIOS(1))
+ ROM_SYSTEM_BIOS(1, "io", "Test 4 -- I/O test")
+ ROMX_LOAD( "p1_t_i_o.rf4", 0x00000, 0x2000, CRC(18a781de) SHA1(7267970ee27e3ea1d972bee8e74b17bac1051619), ROM_BIOS(2))
+ ROM_SYSTEM_BIOS(2, "pls", "\"MB test\"")
+ ROMX_LOAD( "p1_t_pls.rf4", 0x00000, 0x2000, CRC(c8210ffb) SHA1(f2d1a6c90e4708bcc56186b2fb906fa852667084), ROM_BIOS(3))
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *p1_rom_device::device_rom_region() const
+{
+ return ROM_NAME( p1_rom );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// p1_rom_device - constructor
+//-------------------------------------------------
+
+p1_rom_device::p1_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, P1_ROM, "Poisk-1 ROM cart", tag, owner, clock, "p1_rom", __FILE__),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void p1_rom_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xc0000, 0xc1fff, 0, 0, "XXX", "p1_rom");
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void p1_rom_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/p1_rom.h b/src/emu/bus/isa/p1_rom.h
new file mode 100644
index 00000000000..8228c8df052
--- /dev/null
+++ b/src/emu/bus/isa/p1_rom.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:XXX
+/**********************************************************************
+
+ Poisk-1 ROM cartridge device
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __P1_ROM__
+#define __P1_ROM__
+
+#include "emu.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class p1_rom_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ p1_rom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type P1_ROM;
+
+
+#endif
diff --git a/src/emu/bus/isa/pc1640_iga.c b/src/emu/bus/isa/pc1640_iga.c
new file mode 100644
index 00000000000..e456266d33b
--- /dev/null
+++ b/src/emu/bus/isa/pc1640_iga.c
@@ -0,0 +1,120 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Amstrad PC1640 Integrated Graphics Adapter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ This display controller is integrated on the PC1640 motherboard
+ but wired to the ISA bus, and can be disabled with a DIP switch.
+
+ WD Paradise PEGA 1A 38304B 2116-002 8745AAA JAPAN (84 pin PLCC)
+
+ Single chip multimode EGA video controller with
+ integral 6845 CRTC. Provides 100% IBM EGA, CGA,
+ MDA, Hercules graphics and Plantronics COLORPLUS*
+ compatibility
+
+**********************************************************************/
+
+#include "pc1640_iga.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define PEGA1A_TAG "ic910"
+#define EGA_CRTC_NAME "crtc_ega_ega"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ISA8_PC1640_IGA = &device_creator<isa8_pc1640_iga_device>;
+
+
+//-------------------------------------------------
+// ROM( pc1640_iga )
+//-------------------------------------------------
+
+ROM_START( pc1640_iga )
+ ROM_REGION16_LE( 0x8000, "iga", 0)
+ ROM_LOAD( "40100.ic913", 0x0000, 0x8000, CRC(d2d1f1ae) SHA1(98302006ee38a17c09bd75504cc18c0649174e33) ) // 8736 E
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_pc1640_iga_device::device_rom_region() const
+{
+ return ROM_NAME( pc1640_iga );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_pc1640_iga_device - constructor
+//-------------------------------------------------
+
+isa8_pc1640_iga_device::isa8_pc1640_iga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : isa8_ega_device(mconfig, ISA8_PC1640_IGA, "Amstrad PC1640 IGA", tag, owner, clock, "pc1640_iga", __FILE__)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_pc1640_iga_device::device_start()
+{
+ if (m_palette != NULL && !m_palette->started())
+ throw device_missing_dependencies();
+
+ astring tempstring;
+
+ set_isa_device();
+
+ for (int i = 0; i < 64; i++ )
+ {
+ UINT8 r = ( ( i & 0x04 ) ? 0xAA : 0x00 ) + ( ( i & 0x20 ) ? 0x55 : 0x00 );
+ UINT8 g = ( ( i & 0x02 ) ? 0xAA : 0x00 ) + ( ( i & 0x10 ) ? 0x55 : 0x00 );
+ UINT8 b = ( ( i & 0x01 ) ? 0xAA : 0x00 ) + ( ( i & 0x08 ) ? 0x55 : 0x00 );
+
+ m_palette->set_pen_color( i, r, g, b );
+ }
+
+ /* Install 256KB Video ram on our EGA card */
+ m_vram = machine().memory().region_alloc(subtag(tempstring,"vram"), 256*1024, 1, ENDIANNESS_LITTLE);
+
+ m_videoram = m_vram->base();
+ m_plane[0] = m_videoram + 0x00000;
+ memset(m_plane[0], 0, sizeof(UINT8) * 0x10000);
+ m_plane[1] = m_videoram + 0x10000;
+ memset(m_plane[1], 0, sizeof(UINT8) * 0x10000);
+ m_plane[2] = m_videoram + 0x20000;
+ memset(m_plane[2], 0, sizeof(UINT8) * 0x10000);
+ m_plane[3] = m_videoram + 0x30000;
+ memset(m_plane[3], 0, sizeof(UINT8) * 0x10000);
+
+ m_crtc_ega = subdevice<crtc_ega_device>(EGA_CRTC_NAME);
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "ega", "iga");
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3b0_w), this));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3c0_w), this));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_r), this), write8_delegate(FUNC(isa8_ega_device::pc_ega8_3d0_w), this));
+}
diff --git a/src/emu/bus/isa/pc1640_iga.h b/src/emu/bus/isa/pc1640_iga.h
new file mode 100644
index 00000000000..6ec42730150
--- /dev/null
+++ b/src/emu/bus/isa/pc1640_iga.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Amstrad PC1640 Integrated Graphics Adapter emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ISA8_PC1640_IGA__
+#define __ISA8_PC1640_IGA__
+
+#include "emu.h"
+#include "isa.h"
+#include "ega.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_pc1640_iga_device
+
+class isa8_pc1640_iga_device : public isa8_ega_device
+{
+public:
+ // construction/destruction
+ isa8_pc1640_iga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+};
+
+
+// device type definition
+extern const device_type ISA8_PC1640_IGA;
+
+
+
+#endif
diff --git a/src/emu/bus/isa/pds.c b/src/emu/bus/isa/pds.c
new file mode 100644
index 00000000000..054e4fad750
--- /dev/null
+++ b/src/emu/bus/isa/pds.c
@@ -0,0 +1,76 @@
+/*
+ * isa_pds.c - Programmers Development System 8-bit ISA card
+ *
+ * Used to connect up to two 8-bit systems to the PC, allowing the download of assembled code directly to the
+ * target 8-bit system (Spectrum, CPC, MSX, C64 and maybe the BBC?)
+ *
+ * The editor software require the ISA card to be present.
+ *
+ * The PC end hardware consists of an 8-bit ISA card containing an 8255 PPI hooked up to the two connectors on the
+ * back of the card.
+ *
+ * The 8-bit end hardware consists of an expansion device containing a Z80PIO.
+ *
+ * Created on: 31/01/2014
+ */
+
+#include "pds.h"
+
+const device_type ISA8_PDS = &device_creator<isa8_pds_device>;
+
+isa8_pds_device::isa8_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_PDS, "Programmers Development System", tag, owner, clock, "isa_pds", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_ppi(*this,"pds_ppi")
+{
+}
+
+
+READ8_MEMBER(isa8_pds_device::ppi_r)
+{
+ if(!(offset & 0x01))
+ return m_ppi->read(space,offset/2);
+ return 0xff;
+}
+
+WRITE8_MEMBER(isa8_pds_device::ppi_w)
+{
+ if(!(offset & 0x01))
+ m_ppi->write(space,offset/2,data);
+}
+
+void isa8_pds_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x0300, 0x0307, 0, 0, read8_delegate(FUNC(isa8_pds_device::ppi_r),this), write8_delegate(FUNC(isa8_pds_device::ppi_w),this) );
+}
+
+void isa8_pds_device::device_reset()
+{
+
+}
+
+void isa8_pds_device::device_stop()
+{
+
+}
+
+I8255_INTERFACE(pds_ppi_intf)
+{
+ DEVCB_NULL, //m_in_pa_cb;
+ DEVCB_NULL, //m_out_pa_cb;
+ DEVCB_NULL, //m_in_pb_cb;
+ DEVCB_NULL, //m_out_pb_cb;
+ DEVCB_NULL, //m_in_pc_cb;
+ DEVCB_NULL, //m_out_pc_cb;
+};
+
+static MACHINE_CONFIG_FRAGMENT( pds_config )
+ MCFG_I8255_ADD("pds_ppi", pds_ppi_intf)
+MACHINE_CONFIG_END
+
+machine_config_constructor isa8_pds_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pds_config );
+}
+
diff --git a/src/emu/bus/isa/pds.h b/src/emu/bus/isa/pds.h
new file mode 100644
index 00000000000..c0d111f296a
--- /dev/null
+++ b/src/emu/bus/isa/pds.h
@@ -0,0 +1,38 @@
+/*
+ * isa_pds.h
+ *
+ * Created on: 31/01/2014
+ */
+
+#ifndef ISA_PDS_H_
+#define ISA_PDS_H_
+
+#include "emu.h"
+#include "isa.h"
+#include "machine/i8255.h"
+
+class isa8_pds_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ isa8_pds_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER(ppi_r);
+ DECLARE_WRITE8_MEMBER(ppi_w);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ required_device<i8255_device> m_ppi;
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_stop();
+
+};
+
+extern const device_type ISA8_PDS;
+
+#endif /* ISA_PDS_H_ */
diff --git a/src/emu/bus/isa/s3virge.c b/src/emu/bus/isa/s3virge.c
new file mode 100644
index 00000000000..a0c1d5ec5fe
--- /dev/null
+++ b/src/emu/bus/isa/s3virge.c
@@ -0,0 +1,651 @@
+/*
+ * s3virge.c
+ *
+ * Implementation of the S3 Virge series of video card
+ *
+ * Current status:
+ * - Working on getting VESA video modes working better - 800x600 and higher skip every other line at
+ * 8-bit depth, but are fine at 15/16-bit depth.
+ * - S3D is not implemented at all, so no 2D/3D acceleration yet.
+ */
+
+#include "s3virge.h"
+
+#define CRTC_PORT_ADDR ((vga.miscellaneous_output&1)?0x3d0:0x3b0)
+#define LOG_REG 1
+
+const device_type S3VIRGE = &device_creator<s3virge_vga_device>;
+
+s3virge_vga_device::s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : s3_vga_device(mconfig, S3VIRGE, "S3VIRGE", tag, owner, clock, "s3virge_vga", __FILE__)
+{
+}
+
+void s3virge_vga_device::device_start()
+{
+ memset(&vga, 0, sizeof(vga));
+ memset(&svga, 0, sizeof(svga));
+
+ int x;
+ int i;
+ for (i = 0; i < 0x100; i++)
+ m_palette->set_pen_color(i, 0, 0, 0);
+
+ // Avoid an infinite loop when displaying. 0 is not possible anyway.
+ vga.crtc.maximum_scan_line = 1;
+
+ // copy over interfaces
+ vga.read_dipswitch = read8_delegate(); //read_dipswitch;
+ vga.svga_intf.seq_regcount = 0x1c;
+ vga.svga_intf.crtc_regcount = 0x19;
+ vga.svga_intf.vram_size = 0x400000;
+ vga.memory = auto_alloc_array_clear(machine(), UINT8, vga.svga_intf.vram_size);
+ save_pointer(vga.memory,"Video RAM",vga.svga_intf.vram_size);
+ save_pointer(vga.crtc.data,"CRTC Registers",0x100);
+ save_pointer(vga.sequencer.data,"Sequencer Registers",0x100);
+ save_pointer(vga.attribute.data,"Attribute Registers", 0x15);
+
+ m_vblank_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(vga_device::vblank_timer_cb),this));
+
+ memset(&s3, 0, sizeof(s3));
+ // Initialise hardware graphics cursor colours, Windows 95 doesn't touch the registers for some reason
+ for(x=0;x<4;x++)
+ {
+ s3.cursor_fg[x] = 0xff;
+ s3.cursor_bg[x] = 0x00;
+ }
+ // set device ID
+ s3.id_high = 0x56; // CR2D
+ s3.id_low = 0x31; // CR2E
+ s3.revision = 0x00; // CR2F (value unknown)
+ s3.id_cr30 = 0xe1; // CR30
+}
+
+UINT8 s3virge_vga_device::s3_crtc_reg_read(UINT8 index)
+{
+ UINT8 res;
+
+ if(index <= 0x18)
+ res = crtc_reg_read(index);
+ else
+ {
+ switch(index)
+ {
+ case 0x2d:
+ res = s3.id_high;
+ break;
+ case 0x2e:
+ res = s3.id_low;
+ break;
+ case 0x2f:
+ res = s3.revision;
+ break;
+ case 0x30: // CR30 Chip ID/REV register
+ res = s3.id_cr30;
+ break;
+ case 0x31:
+ res = s3.memory_config;
+ break;
+ case 0x35:
+ res = s3.crt_reg_lock;
+ break;
+ case 0x38:
+ res = s3.reg_lock1;
+ break;
+ case 0x39:
+ res = s3.reg_lock2;
+ break;
+ case 0x42: // CR42 Mode Control
+ res = s3.cr42 & 0x0f; // bit 5 set if interlaced, leave it unset for now.
+ break;
+ case 0x43:
+ res = s3.cr43;
+ break;
+ case 0x45:
+ res = s3.cursor_mode;
+ break;
+ case 0x46:
+ res = (s3.cursor_x & 0xff00) >> 8;
+ break;
+ case 0x47:
+ res = s3.cursor_x & 0x00ff;
+ break;
+ case 0x48:
+ res = (s3.cursor_y & 0xff00) >> 8;
+ break;
+ case 0x49:
+ res = s3.cursor_y & 0x00ff;
+ break;
+ case 0x4a:
+ res = s3.cursor_fg[s3.cursor_fg_ptr];
+ s3.cursor_fg_ptr = 0;
+ break;
+ case 0x4b:
+ res = s3.cursor_bg[s3.cursor_bg_ptr];
+ s3.cursor_bg_ptr = 0;
+ break;
+ case 0x4c:
+ res = (s3.cursor_start_addr & 0xff00) >> 8;
+ break;
+ case 0x4d:
+ res = s3.cursor_start_addr & 0x00ff;
+ break;
+ case 0x4e:
+ res = s3.cursor_pattern_x;
+ break;
+ case 0x4f:
+ res = s3.cursor_pattern_y;
+ break;
+ case 0x51:
+ res = (vga.crtc.start_addr_latch & 0x0c0000) >> 18;
+ res |= ((svga.bank_w & 0x30) >> 2);
+ break;
+ case 0x55:
+ res = s3.extended_dac_ctrl;
+ break;
+ case 0x5c:
+ // if VGA dot clock is set to 3 (misc reg bits 2-3), then selected dot clock is read, otherwise read VGA clock select
+ if((vga.miscellaneous_output & 0xc) == 0x0c)
+ res = s3.cr42 & 0x0f;
+ else
+ res = (vga.miscellaneous_output & 0xc) >> 2;
+ break;
+ case 0x67:
+ res = s3.ext_misc_ctrl_2;
+ break;
+ case 0x69:
+ res = vga.crtc.start_addr_latch >> 16;
+ break;
+ case 0x6a:
+ res = svga.bank_r & 0x7f;
+ break;
+ default:
+ res = vga.crtc.data[index];
+ //debugger_break(machine);
+ //printf("%02x\n",index);
+ break;
+ }
+ }
+
+ return res;
+}
+
+void s3virge_vga_device::s3_define_video_mode()
+{
+ int divisor = 1;
+ int xtal = (vga.miscellaneous_output & 0xc) ? XTAL_28_63636MHz : XTAL_25_1748MHz;
+ double m,n;
+ int r;
+
+ if((vga.miscellaneous_output & 0xc) == 0x0c)
+ {
+ // Dot clock is set via SR12 and SR13
+ m = vga.sequencer.data[0x13] & 0x7f;
+ n = vga.sequencer.data[0x12] & 0x1f;
+ r = (vga.sequencer.data[0x12] & 0x60) >> 5;
+ xtal = (double)((m+2.0f) / ((n+2.0f)*(double)(1<<r))) * 16000000;
+ //printf("DCLK set to %dHz M=%f N=%f R=%i\n",xtal,m,n,r);
+ }
+
+ if((s3.ext_misc_ctrl_2) >> 4)
+ {
+ svga.rgb8_en = 0;
+ svga.rgb15_en = 0;
+ svga.rgb16_en = 0;
+ svga.rgb32_en = 0;
+ switch((s3.ext_misc_ctrl_2) >> 4)
+ {
+ case 0x01: svga.rgb8_en = 1; divisor = 2; break;
+ case 0x03: svga.rgb15_en = 1; divisor = 2; break;
+ case 0x05: svga.rgb16_en = 1; divisor = 2; break;
+ case 0x0d: svga.rgb32_en = 1; divisor = 2; break;
+ default: fatalerror("TODO: s3 video mode not implemented %02x\n",((s3.ext_misc_ctrl_2) >> 4)); break;
+ }
+ }
+ else
+ {
+ svga.rgb8_en = (s3.cr3a & 0x10) >> 4;
+ svga.rgb15_en = 0;
+ svga.rgb16_en = 0;
+ svga.rgb32_en = 0;
+ }
+ if(s3.cr43 & 0x80) // Horizontal clock doubling (techincally, doubles horizontal CRT parameters)
+ divisor *= 2;
+ recompute_params_clock(divisor, xtal);
+}
+
+void s3virge_vga_device::s3_crtc_reg_write(UINT8 index, UINT8 data)
+{
+ if(index <= 0x18)
+ {
+ crtc_reg_write(index,data);
+ s3_define_video_mode();
+ }
+ else
+ {
+ switch(index)
+ {
+ case 0x31: // CR31 Memory Configuration Register
+ s3.memory_config = data;
+ vga.crtc.start_addr_latch &= ~0x30000;
+ vga.crtc.start_addr_latch |= ((data & 0x30) << 12);
+ s3_define_video_mode();
+ break;
+ case 0x35:
+ if((s3.reg_lock1 & 0xc) != 8 || ((s3.reg_lock1 & 0xc0) == 0)) // lock register
+ return;
+ s3.crt_reg_lock = data;
+ svga.bank_w = data & 0xf;
+ svga.bank_r = svga.bank_w;
+ break;
+ case 0x38:
+ s3.reg_lock1 = data;
+ break;
+ case 0x39:
+ /* TODO: reg lock mechanism */
+ s3.reg_lock2 = data;
+ break;
+ case 0x3a:
+ s3.cr3a = data;
+ break;
+ case 0x40:
+ s3.enable_s3d = data & 0x01; // enable S3D registers
+ break;
+ case 0x42:
+ s3.cr42 = data; // bit 5 = interlace, bits 0-3 = dot clock (seems to be undocumented)
+ break;
+ case 0x43:
+ s3.cr43 = data; // bit 2 = bit 8 of offset register, but only if bits 4-5 of CR51 are 00h.
+ vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x04) << 6);
+ s3_define_video_mode();
+ break;
+/*
+3d4h index 45h (R/W): CR45 Hardware Graphics Cursor Mode
+bit 0 HWGC ENB. Hardware Graphics Cursor Enable. Set to enable the
+ HardWare Cursor in VGA and enhanced modes.
+ 1 (911/24) Delay Timing for Pattern Data Fetch
+ 2 (801/5,928) Hardware Cursor Horizontal Stretch 2. If set the cursor
+ pixels are stretched horizontally to two bytes and items 0 and 1 of
+ the fore/background stacks in 3d4h index 4Ah/4Bh are used.
+ 3 (801/5,928) Hardware Cursor Horizontal Stretch 3. If set the cursor
+ pixels are stretched horizontally to three bytes and items 0,1 and
+ 2 of the fore/background stacks in 3d4h index 4Ah/4Bh are used.
+ 2-3 (805i,864/964) HWC-CSEL. Hardware Cursor Color Select.
+ 0: 4/8bit, 1: 15/16bt, 2: 24bit, 3: 32bit
+ Note: So far I've had better luck with: 0: 8/15/16bit, 1: 32bit??
+ 4 (80x +) Hardware Cursor Right Storage. If set the cursor data is
+ stored in the last 256 bytes of 4 1Kyte lines (4bits/pixel) or the
+ last 512 bytes of 2 2Kbyte lines (8bits/pixel). Intended for
+ 1280x1024 modes where there are no free lines at the bottom.
+ 5 (928) Cursor Control Enable for Brooktree Bt485 DAC. If set and 3d4h
+ index 55h bit 5 is set the HC1 output becomes the ODF and the HC0
+ output becomes the CDE
+ (964) BT485 ODF Selection for Bt485A RAMDAC. If set pin 185 (RS3
+ /ODF) is the ODF output to a Bt485A compatible RamDAC (low for even
+ fields and high for odd fields), if clear pin185 is the RS3 output.
+ */
+ case 0x45:
+ s3.cursor_mode = data;
+ break;
+/*
+3d4h index 46h M(R/W): CR46/7 Hardware Graphics Cursor Origin-X
+bit 0-10 The HardWare Cursor X position. For 64k modes this value should be
+ twice the actual X co-ordinate.
+ */
+ case 0x46:
+ s3.cursor_x = (s3.cursor_x & 0x00ff) | (data << 8);
+ break;
+ case 0x47:
+ s3.cursor_x = (s3.cursor_x & 0xff00) | data;
+ break;
+/*
+3d4h index 48h M(R/W): CR48/9 Hardware Graphics Cursor Origin-Y
+bit 0-9 (911/24) The HardWare Cursor Y position.
+ 0-10 (80x +) The HardWare Cursor Y position.
+Note: The position is activated when the high byte of the Y coordinate (index
+ 48h) is written, so this byte should be written last (not 911/924 ?)
+ */
+ case 0x48:
+ s3.cursor_y = (s3.cursor_y & 0x00ff) | (data << 8);
+ break;
+ case 0x49:
+ s3.cursor_y = (s3.cursor_y & 0xff00) | data;
+ break;
+
+/*
+3d4h index 4Ah (R/W): Hardware Graphics Cursor Foreground Stack (80x +)
+bit 0-7 The Foreground Cursor color. Three bytes (4 for the 864/964) are
+ stacked here. When the Cursor Mode register (3d4h index 45h) is read
+ the stackpointer is reset. When a byte is written the byte is
+ written into the current top of stack and the stackpointer is
+ increased. The first byte written (item 0) is allways used, the
+ other two(3) only when Hardware Cursor Horizontal Stretch (3d4h
+ index 45h bit 2-3) is enabled.
+ */
+ case 0x4a:
+ s3.cursor_fg[s3.cursor_fg_ptr++] = data;
+ s3.cursor_fg_ptr %= 4;
+ break;
+/*
+3d4h index 4Bh (R/W): Hardware Graphics Cursor Background Stack (80x +)
+bit 0-7 The Background Cursor color. Three bytes (4 for the 864/964) are
+ stacked here. When the Cursor Mode register (3d4h index 45h) is read
+ the stackpointer is reset. When a byte is written the byte is
+ written into the current top of stack and the stackpointer is
+ increased. The first byte written (item 0) is allways used, the
+ other two(3) only when Hardware Cursor Horizontal Stretch (3d4h
+ index 45h bit 2-3) is enabled.
+ */
+ case 0x4b:
+ s3.cursor_bg[s3.cursor_bg_ptr++] = data;
+ s3.cursor_bg_ptr %= 4;
+ break;
+/*
+3d4h index 4Ch M(R/W): CR4C/D Hardware Graphics Cursor Storage Start Address
+bit 0-9 (911,924) HCS_STADR. Hardware Graphics Cursor Storage Start Address
+ 0-11 (80x,928) HWGC_STA. Hardware Graphics Cursor Storage Start Address
+ 0-12 (864,964) HWGC_STA. Hardware Graphics Cursor Storage Start Address
+ Address of the HardWare Cursor Map in units of 1024 bytes (256 bytes
+ for planar modes). The cursor map is a 64x64 bitmap with 2 bits (A
+ and B) per pixel. The map is stored as one word (16 bits) of bit A,
+ followed by one word with the corresponding 16 B bits.
+ The bits are interpreted as:
+ A B MS-Windows: X-11:
+ 0 0 Background Screen data
+ 0 1 Foreground Screen data
+ 1 0 Screen data Background
+ 1 1 Inverted screen Foreground
+ The Windows/X11 switch is only available for the 80x +.
+ (911/24) For 64k color modes the cursor is stored as one byte (8
+ bits) of A bits, followed by the 8 B-bits, and each bit in the
+ cursor should be doubled to provide a consistent cursor image.
+ (801/5,928) For Hi/True color modes use the Horizontal Stretch bits
+ (3d4h index 45h bits 2 and 3).
+ */
+ case 0x4c:
+ s3.cursor_start_addr = (s3.cursor_start_addr & 0x00ff) | (data << 8);
+ break;
+ case 0x4d:
+ s3.cursor_start_addr = (s3.cursor_start_addr & 0xff00) | data;
+ break;
+/*
+3d4h index 4Eh (R/W): CR4E HGC Pattern Disp Start X-Pixel Position
+bit 0-5 Pattern Display Start X-Pixel Position.
+ */
+ case 0x4e:
+ s3.cursor_pattern_x = data;
+ break;
+/*
+3d4h index 4Fh (R/W): CR4F HGC Pattern Disp Start Y-Pixel Position
+bit 0-5 Pattern Display Start Y-Pixel Position.
+ */
+ case 0x4f:
+ s3.cursor_pattern_y = data;
+ break;
+ case 0x51:
+ vga.crtc.start_addr_latch &= ~0xc0000;
+ vga.crtc.start_addr_latch |= ((data & 0x3) << 18);
+ svga.bank_w = (svga.bank_w & 0xcf) | ((data & 0x0c) << 2);
+ svga.bank_r = svga.bank_w;
+ if((data & 0x30) != 0x00)
+ vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((data & 0x30) << 4);
+ else
+ vga.crtc.offset = (vga.crtc.offset & 0x00ff) | ((s3.cr43 & 0x04) << 6);
+ s3_define_video_mode();
+ break;
+ case 0x53:
+ s3.cr53 = data;
+ break;
+/*
+3d4h index 55h (R/W): Extended Video DAC Control Register (80x +)
+bit 0-1 DAC Register Select Bits. Passed to the RS2 and RS3 pins on the
+ RAMDAC, allowing access to all 8 or 16 registers on advanced RAMDACs.
+ If this field is 0, 3d4h index 43h bit 1 is active.
+ 2 Enable General Input Port Read. If set DAC reads are disabled and the
+ STRD strobe for reading the General Input Port is enabled for reading
+ while DACRD is active, if clear DAC reads are enabled.
+ 3 (928) Enable External SID Operation if set. If set video data is
+ passed directly from the VRAMs to the DAC rather than through the
+ VGA chip
+ 4 Hardware Cursor MS/X11 Mode. If set the Hardware Cursor is in X11
+ mode, if clear in MS-Windows mode
+ 5 (80x,928) Hardware Cursor External Operation Mode. If set the two
+ bits of cursor data ,is output on the HC[0-1] pins for the video DAC
+ The SENS pin becomes HC1 and the MID2 pin becomes HC0.
+ 6 ??
+ 7 (80x,928) Disable PA Output. If set PA[0-7] and VCLK are tristated.
+ (864/964) TOFF VCLK. Tri-State Off VCLK Output. VCLK output tri
+ -stated if set
+ */
+ case 0x55:
+ s3.extended_dac_ctrl = data;
+ break;
+/*
+3d4h index 5Dh (R/W): Extended Horizontal Overflow Register (80x +)
+bit 0 Horizontal Total bit 8. Bit 8 of the Horizontal Total register (3d4h
+ index 0)
+ 1 Horizontal Display End bit 8. Bit 8 of the Horizontal Display End
+ register (3d4h index 1)
+ 2 Start Horizontal Blank bit 8. Bit 8 of the Horizontal Start Blanking
+ register (3d4h index 2).
+ 3 (864,964) EHB+64. End Horizontal Blank +64. If set the /BLANK pulse
+ is extended by 64 DCLKs. Note: Is this bit 6 of 3d4h index 3 or
+ does it really extend by 64 ?
+ 4 Start Horizontal Sync Position bit 8. Bit 8 of the Horizontal Start
+ Retrace register (3d4h index 4).
+ 5 (864,964) EHS+32. End Horizontal Sync +32. If set the HSYNC pulse
+ is extended by 32 DCLKs. Note: Is this bit 5 of 3d4h index 5 or
+ does it really extend by 32 ?
+ 6 (928,964) Data Transfer Position bit 8. Bit 8 of the Data Transfer
+ Position register (3d4h index 3Bh)
+ 7 (928,964) Bus-Grant Terminate Position bit 8. Bit 8 of the Bus Grant
+ Termination register (3d4h index 5Fh).
+*/
+ case 0x5d:
+ vga.crtc.horz_total = (vga.crtc.horz_total & 0xfeff) | ((data & 0x01) << 8);
+ vga.crtc.horz_disp_end = (vga.crtc.horz_disp_end & 0xfeff) | ((data & 0x02) << 7);
+ vga.crtc.horz_blank_start = (vga.crtc.horz_blank_start & 0xfeff) | ((data & 0x04) << 6);
+ vga.crtc.horz_blank_end = (vga.crtc.horz_blank_end & 0xffbf) | ((data & 0x08) << 3);
+ vga.crtc.horz_retrace_start = (vga.crtc.horz_retrace_start & 0xfeff) | ((data & 0x10) << 4);
+ vga.crtc.horz_retrace_end = (vga.crtc.horz_retrace_end & 0xffdf) | (data & 0x20);
+ s3_define_video_mode();
+ break;
+/*
+3d4h index 5Eh (R/W): Extended Vertical Overflow Register (80x +)
+bit 0 Vertical Total bit 10. Bit 10 of the Vertical Total register (3d4h
+ index 6). Bits 8 and 9 are in 3d4h index 7 bit 0 and 5.
+ 1 Vertical Display End bit 10. Bit 10 of the Vertical Display End
+ register (3d4h index 12h). Bits 8 and 9 are in 3d4h index 7 bit 1
+ and 6
+ 2 Start Vertical Blank bit 10. Bit 10 of the Vertical Start Blanking
+ register (3d4h index 15h). Bit 8 is in 3d4h index 7 bit 3 and bit 9
+ in 3d4h index 9 bit 5
+ 4 Vertical Retrace Start bit 10. Bit 10 of the Vertical Start Retrace
+ register (3d4h index 10h). Bits 8 and 9 are in 3d4h index 7 bit 2
+ and 7.
+ 6 Line Compare Position bit 10. Bit 10 of the Line Compare register
+ (3d4h index 18h). Bit 8 is in 3d4h index 7 bit 4 and bit 9 in 3d4h
+ index 9 bit 6.
+ */
+ case 0x5e:
+ vga.crtc.vert_total = (vga.crtc.vert_total & 0xfbff) | ((data & 0x01) << 10);
+ vga.crtc.vert_disp_end = (vga.crtc.vert_disp_end & 0xfbff) | ((data & 0x02) << 9);
+ vga.crtc.vert_blank_start = (vga.crtc.vert_blank_start & 0xfbff) | ((data & 0x04) << 8);
+ vga.crtc.vert_retrace_start = (vga.crtc.vert_retrace_start & 0xfbff) | ((data & 0x10) << 6);
+ vga.crtc.line_compare = (vga.crtc.line_compare & 0xfbff) | ((data & 0x40) << 4);
+ s3_define_video_mode();
+ break;
+ case 0x67:
+ s3.ext_misc_ctrl_2 = data;
+ s3_define_video_mode();
+ //printf("%02x X\n",data);
+ break;
+ case 0x69:
+ vga.crtc.start_addr_latch &= ~0x1f0000;
+ vga.crtc.start_addr_latch |= ((data & 0x1f) << 16);
+ s3_define_video_mode();
+ break;
+ case 0x6a:
+ svga.bank_w = data & 0x3f;
+ svga.bank_r = svga.bank_w;
+ break;
+ default:
+ if(LOG_REG) logerror("S3: CR%02X write %02x\n",index,data);
+ break;
+ }
+ }
+}
+
+
+READ8_MEMBER(s3virge_vga_device::port_03b0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = s3_crtc_reg_read(vga.crtc.index);
+ break;
+ default:
+ res = vga_device::port_03b0_r(space,offset,mem_mask);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_MEMBER(s3virge_vga_device::port_03b0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3b0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ s3_crtc_reg_write(vga.crtc.index,data);
+ break;
+ default:
+ vga_device::port_03b0_w(space,offset,data,mem_mask);
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(s3virge_vga_device::port_03c0_r)
+{
+ UINT8 res;
+
+ switch(offset)
+ {
+ default:
+ res = vga_device::port_03c0_r(space,offset,mem_mask);
+ break;
+ }
+
+ return res;
+}
+
+WRITE8_MEMBER(s3virge_vga_device::port_03c0_w)
+{
+ switch(offset)
+ {
+ default:
+ vga_device::port_03c0_w(space,offset,data,mem_mask);
+ break;
+ }
+}
+
+READ8_MEMBER(s3virge_vga_device::port_03d0_r)
+{
+ UINT8 res = 0xff;
+
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ res = s3_crtc_reg_read(vga.crtc.index);
+ break;
+ default:
+ res = vga_device::port_03d0_r(space,offset,mem_mask);
+ break;
+ }
+ }
+
+ return res;
+}
+
+WRITE8_MEMBER(s3virge_vga_device::port_03d0_w)
+{
+ if (CRTC_PORT_ADDR == 0x3d0)
+ {
+ switch(offset)
+ {
+ case 5:
+ vga.crtc.data[vga.crtc.index] = data;
+ s3_crtc_reg_write(vga.crtc.index,data);
+ break;
+ default:
+ vga_device::port_03d0_w(space,offset,data,mem_mask);
+ break;
+ }
+ }
+}
+
+READ8_MEMBER(s3virge_vga_device::mem_r)
+{
+ if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
+ {
+ int data;
+ if(offset & 0x10000)
+ return 0;
+ data = 0;
+ if(vga.sequencer.data[4] & 0x8)
+ data = vga.memory[offset + (svga.bank_r*0x10000)];
+ else
+ {
+ int i;
+
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ data |= vga.memory[offset*4+i+(svga.bank_r*0x10000)];
+ }
+ }
+ return data;
+ }
+ return vga_device::mem_r(space,offset,mem_mask);
+}
+
+WRITE8_MEMBER(s3virge_vga_device::mem_w)
+{
+ // bit 4 of CR53 enables memory-mapped I/O
+ if(s3.cr53 & 0x10)
+ {
+ // TODO
+ }
+
+ if (svga.rgb8_en || svga.rgb15_en || svga.rgb16_en || svga.rgb32_en)
+ {
+ // printf("%08x %02x (%02x %02x) %02X\n",offset,data,vga.sequencer.map_mask,svga.bank_w,(vga.sequencer.data[4] & 0x08));
+ if(offset & 0x10000)
+ return;
+ if(vga.sequencer.data[4] & 0x8)
+ vga.memory[(offset + (svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data;
+ else
+ {
+ int i;
+ for(i=0;i<4;i++)
+ {
+ if(vga.sequencer.map_mask & 1 << i)
+ vga.memory[(offset*4+i+(svga.bank_w*0x10000)) % vga.svga_intf.vram_size] = data;
+ }
+ }
+ return;
+ }
+
+ vga_device::mem_w(space,offset,data,mem_mask);
+}
diff --git a/src/emu/bus/isa/s3virge.h b/src/emu/bus/isa/s3virge.h
new file mode 100644
index 00000000000..b714c77773e
--- /dev/null
+++ b/src/emu/bus/isa/s3virge.h
@@ -0,0 +1,46 @@
+/*
+ * s3virge.h
+ *
+ * S3 ViRGE 2D/3D video card
+ *
+ */
+
+#ifndef S3VIRGE_H_
+#define S3VIRGE_H_
+
+#include "emu.h"
+#include "video/pc_vga.h"
+
+// ======================> s3virge_vga_device
+
+class s3virge_vga_device : public s3_vga_device
+{
+public:
+ // construction/destruction
+ s3virge_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual READ8_MEMBER(port_03b0_r);
+ virtual WRITE8_MEMBER(port_03b0_w);
+ virtual READ8_MEMBER(port_03c0_r);
+ virtual WRITE8_MEMBER(port_03c0_w);
+ virtual READ8_MEMBER(port_03d0_r);
+ virtual WRITE8_MEMBER(port_03d0_w);
+ virtual READ8_MEMBER(mem_r);
+ virtual WRITE8_MEMBER(mem_w);
+
+ ibm8514a_device* get_8514() { fatalerror("s3virge requested non-existant 8514/A device\n"); return NULL; }
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ virtual UINT8 s3_crtc_reg_read(UINT8 index);
+ virtual void s3_define_video_mode(void);
+ virtual void s3_crtc_reg_write(UINT8 index, UINT8 data);
+ // has no 8514/A device
+};
+
+// device type definition
+extern const device_type S3VIRGE;
+
+#endif /* S3VIRGE_H_ */
diff --git a/src/emu/bus/isa/sblaster.c b/src/emu/bus/isa/sblaster.c
new file mode 100644
index 00000000000..5046e90ecef
--- /dev/null
+++ b/src/emu/bus/isa/sblaster.c
@@ -0,0 +1,1673 @@
+/***************************************************************************
+
+ ISA 8/16 bit Creative Labs Sound Blaster Sound Card
+
+ TODO:
+ - implement DAC
+ - DSP type is a MCS-51 family, it has an internal ROM that needs decapping;
+ - implement jumpers DIP-SWs;
+
+***************************************************************************/
+
+#include "sblaster.h"
+#include "sound/speaker.h"
+#include "sound/3812intf.h"
+#include "sound/262intf.h"
+#include "sound/saa1099.h"
+#include "sound/dac.h"
+#include "machine/pic8259.h"
+
+/*
+ adlib (YM3812/OPL2 chip), part of many many soundcards (soundblaster)
+ soundblaster: YM3812 also accessible at 0x228/9 (address jumperable)
+ soundblaster pro version 1: 2 YM3812 chips
+ at 0x388 both accessed,
+ at 0x220/1 left?, 0x222/3 right? (jumperable)
+ soundblaster pro version 2: 1 OPL3 chip
+
+ pro audio spectrum +: 2 OPL2
+ pro audio spectrum 16: 1 OPL3
+
+ 2 x saa1099 chips
+ also on sound blaster 1.0
+ option on sound blaster 1.5
+
+ jumperable? normally 0x220
+*/
+#define ym3812_StdClock XTAL_3_579545MHz
+#define ymf262_StdClock XTAL_14_31818MHz
+
+static const int m_cmd_fifo_length[256] =
+{
+/* 0 1 2 3 4 5 6 7 8 9 A B C D E F */
+ -1, -1, -1, -1, 1, 3, -1, -1, -1, -1, -1, -1, -1, -1, 2, 1, /* 0x */
+ 2, -1, -1, -1, 3, -1, 3, 3, -1, -1, -1, -1, 1, -1, -1, 1, /* 1x */
+ -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 2x */
+ 1, 1, -1, -1, 1, 1, 1, 1, 1, -1, -1, -1, -1, -1, -1, -1, /* 3x */
+ 2, 3, 3, -1, -1, -1, -1, -1, 3, -1, -1, -1, -1, -1, -1, -1, /* 4x */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 5x */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 6x */
+ -1, -1, -1, -1, 3, 3, 3, 3, -1, -1, -1, -1, -1, 1, -1, 1, /* 7x */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 8x */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* 9x */
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, /* Ax */
+ 4, -1, -1, -1, -1, -1, 4, -1, 4, -1, -1, -1, -1, -1, 4, -1, /* Bx */
+ 4, -1, -1, -1, -1, -1, 4, -1, 4, -1, -1, -1, -1, -1, 4, -1, /* Cx */
+ 1, 1, -1, 1, -1, 1, 1, -1, 1, 1, 1, -1, -1, -1, -1, -1, /* Dx */
+ 2, 1, 2, 1, 2, -1, -1, -1, 1, -1, -1, -1, -1, -1, -1, -1, /* Ex */
+ -1, -1, 1, -1, -1, -1, -1, -1, 1, -1, -1, -1, 1, -1, -1, -1 /* Fx */
+};
+
+static const int protection_magic[4] = { 0x96, 0xa5, 0x69, 0x5a };
+
+static MACHINE_CONFIG_FRAGMENT( sblaster1_0_config )
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 3.00)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 3.00)
+ MCFG_SAA1099_ADD("saa1099.1", 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.50)
+ MCFG_SAA1099_ADD("saa1099.2", 4772720)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 0.50)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 0.50)
+
+ MCFG_SOUND_ADD("sbdacl", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ADD("sbdacr", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+
+ MCFG_PC_JOY_ADD("pc_joy")
+ MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin")
+ MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w))
+
+ MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout")
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( sblaster1_5_config )
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("ym3812", YM3812, ym3812_StdClock)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+ /* no CM/S support (empty sockets) */
+
+ MCFG_SOUND_ADD("sbdacl", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ADD("sbdacr", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+
+ MCFG_PC_JOY_ADD("pc_joy")
+ MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin")
+ MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w))
+
+ MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout")
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_FRAGMENT( sblaster_16_config )
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("ymf262", YMF262, ymf262_StdClock)
+ MCFG_SOUND_ROUTE(0, "lspeaker", 1.00)
+ MCFG_SOUND_ROUTE(1, "rspeaker", 1.00)
+ MCFG_SOUND_ROUTE(2, "lspeaker", 1.00)
+ MCFG_SOUND_ROUTE(3, "rspeaker", 1.00)
+ MCFG_SOUND_ADD("sbdacl", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ADD("sbdacr", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+
+ MCFG_PC_JOY_ADD("pc_joy")
+ MCFG_MIDI_PORT_ADD("mdin", midiin_slot, "midiin")
+ MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, sb_device, midi_rx_w))
+
+ MCFG_MIDI_PORT_ADD("mdout", midiout_slot, "midiout")
+MACHINE_CONFIG_END
+
+static READ8_DEVICE_HANDLER( ym3812_16_r )
+{
+ ym3812_device *ym3812 = (ym3812_device *) device;
+
+ UINT8 retVal = 0xff;
+ switch(offset)
+ {
+ case 0 : retVal = ym3812->status_port_r( space, offset ); break;
+ }
+ return retVal;
+}
+
+static WRITE8_DEVICE_HANDLER( ym3812_16_w )
+{
+ ym3812_device *ym3812 = (ym3812_device *) device;
+
+ switch(offset)
+ {
+ case 0 : ym3812->control_port_w( space, offset, data ); break;
+ case 1 : ym3812->write_port_w( space, offset, data ); break;
+ }
+}
+
+static READ8_DEVICE_HANDLER( saa1099_16_r )
+{
+ return 0xff;
+}
+
+static WRITE8_DEVICE_HANDLER( saa1099_16_w )
+{
+ switch(offset)
+ {
+ case 0 : dynamic_cast<saa1099_device*>(device)->saa1099_control_w( space, offset, data ); break;
+ case 1 : dynamic_cast<saa1099_device*>(device)->saa1099_data_w( space, offset, data ); break;
+ }
+}
+
+void sb_device::queue(UINT8 data)
+{
+ if (m_dsp.fifo_ptr < 15)
+ {
+ m_dsp.fifo[m_dsp.fifo_ptr] = data;
+
+ m_dsp.fifo_ptr++;
+ }
+ else
+ {
+ // FIFO gets to la-la-land
+ //logerror("FIFO?\n");
+ }
+}
+
+void sb_device::queue_r(UINT8 data)
+{
+ m_dsp.rbuf_status |= 0x80;
+
+ if (m_dsp.fifo_r_ptr < 52)
+ {
+ m_dsp.fifo_r[m_dsp.fifo_r_ptr] = data;
+
+ m_dsp.fifo_r_ptr++;
+ }
+ else
+ {
+ // FIFO gets to la-la-land
+ //logerror("FIFO?\n");
+ }
+}
+
+UINT8 sb_device::dequeue_r()
+{
+ UINT8 data = m_dsp.fifo_r[0];
+
+ if (m_dsp.fifo_r_ptr > 0)
+ {
+ for (int i = 0; i < 51; i++)
+ m_dsp.fifo_r[i] = m_dsp.fifo_r[i + 1];
+
+ m_dsp.fifo_r[51] = 0;
+
+ m_dsp.fifo_r_ptr--;
+ }
+
+ if(m_dsp.fifo_r_ptr == 0)
+ m_dsp.rbuf_status &= ~0x80;
+
+ return data;
+}
+
+
+READ8_MEMBER( sb_device::dsp_reset_r )
+{
+// printf("read DSP reset @ %x\n", offset);
+ if(offset)
+ return 0xff;
+ logerror("Soundblaster DSP Reset port undocumented read\n");
+ return 0xff;
+}
+
+WRITE8_MEMBER( sb_device::dsp_reset_w )
+{
+// printf("%02x to DSP reset @ %x\n", data, offset);
+ if(offset)
+ return;
+
+ // a reset while in UART MIDI mode simply restores the previous
+ // operating state (page 5-3 of the Creative manual).
+ if (!m_uart_midi)
+ {
+ if(data == 0 && m_dsp.reset_latch == 1)
+ {
+ // reset routine
+ m_dsp.fifo_ptr = 0;
+ m_dsp.fifo_r_ptr = 0;
+ for(int i=0;i < 15; i++)
+ {
+ m_dsp.fifo[i] = 0;
+ m_dsp.fifo_r[i] = 0;
+ }
+ queue_r(0xaa); // reset OK ID
+ }
+
+ m_dsp.reset_latch = data;
+ drq_w(0);
+ m_dsp.dma_autoinit = 0;
+ irq_w(0, IRQ_ALL);
+ m_timer->adjust(attotime::never, 0);
+ m_dsp.d_rptr = 0;
+ m_dsp.d_wptr = 0;
+ m_dsp.dma_throttled = false;
+ m_dsp.dma_timer_started = false;
+ }
+
+ m_onebyte_midi = false;
+ m_uart_midi = false;
+ m_uart_irq = false;
+ m_mpu_midi = false;
+ m_tx_busy = false;
+ m_xmit_read = m_xmit_write = 0;
+ m_recv_read = m_recv_write = 0;
+ m_rx_waiting = m_tx_waiting = 0;
+
+ //printf("%02x\n",data);
+}
+
+READ8_MEMBER( sb_device::dsp_data_r )
+{
+// printf("read DSP data @ %x\n", offset);
+ if(offset)
+ return 0xff;
+
+ if (m_uart_midi)
+ {
+ UINT8 rv = m_recvring[m_recv_read++];
+ if (m_recv_read >= MIDI_RING_SIZE)
+ {
+ m_recv_read = 0;
+ }
+
+ if (m_rx_waiting)
+ {
+ m_rx_waiting--;
+ }
+
+ return rv;
+ }
+
+ return dequeue_r();
+}
+
+WRITE8_MEMBER( sb_device::dsp_data_w )
+{
+// printf("%02x to DSP data @ %x\n", data, offset);
+ if(offset)
+ return;
+ logerror("Soundblaster DSP data port undocumented write\n");
+}
+
+READ8_MEMBER(sb_device::dsp_rbuf_status_r)
+{
+// printf("read Rbufstat @ %x\n", offset);
+
+ if(offset)
+ {
+ if(m_dsp.version > 0x0400)
+ irq_w(0, IRQ_DMA16);
+ return 0xff;
+ }
+
+// printf("Clear IRQ5\n");
+ irq_w(0, IRQ_DMA8); // reading this port ACKs the card's IRQ, 8-bit dma only?
+
+ // in either SB-MIDI mode, bit 7 indicates if a character is available
+ // to read.
+ if (m_uart_midi || m_onebyte_midi)
+ {
+ if (m_rx_waiting)
+ {
+ return 0x80;
+ }
+
+ return 0x00;
+ }
+
+ return m_dsp.rbuf_status;
+}
+
+READ8_MEMBER(sb_device::dsp_wbuf_status_r)
+{
+// printf("read Wbufstat @ %x\n", offset);
+
+ if(offset)
+ return 0xff;
+
+ // in either SB-MIDI mode, bit 7 indicates if there's space to write.
+ // set = buffer full
+ if (m_uart_midi || m_onebyte_midi)
+ {
+ if (m_tx_waiting >= MIDI_RING_SIZE)
+ {
+ return 0x80;
+ }
+
+ return 0x00;
+ }
+
+ return m_dsp.wbuf_status;
+}
+
+WRITE8_MEMBER(sb_device::dsp_rbuf_status_w)
+{
+// printf("%02x to Rbufstat @ %x\n", data, offset);
+ if(offset)
+ return;
+
+ logerror("Soundblaster DSP Read Buffer status undocumented write\n");
+}
+
+void sb_device::process_fifo(UINT8 cmd)
+{
+ if (m_cmd_fifo_length[cmd] == -1)
+ {
+ logerror("SB: unemulated or undefined fifo command %02x\n",cmd);
+ m_dsp.fifo_ptr = 0;
+ }
+ else if(m_dsp.fifo_ptr == m_cmd_fifo_length[cmd])
+ {
+ /* get FIFO params */
+// printf("SB FIFO command: %02x\n", cmd);
+ switch(cmd)
+ {
+ case 0x10: // Direct DAC
+ break;
+
+ case 0x14: // 8-bit DMA, no autoinit
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+// printf("Start DMA (not autoinit, size = %x)\n", m_dsp.dma_length);
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 0;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = 0;
+ break;
+
+ case 0x17: // 2-bit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ case 0x16: // 2-bit ADPCM
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 0;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM2;
+ break;
+
+ case 0x1c: // 8-bit DMA with autoinit
+ // printf("Start DMA (autoinit, size = %x)\n", m_dsp.dma_length);
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 1;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = 0;
+ break;
+
+ case 0x24: // 8-bit ADC DMA
+ m_dsp.adc_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ // printf("Start DMA (not autoinit, size = %x)\n", m_dsp.adc_length);
+ m_dsp.adc_transferred = 0;
+ m_dsp.dma_autoinit = 0;
+ drq_w(1);
+ logerror("SB: ADC capture unimplemented\n");
+ break;
+
+ case 0x34:
+ m_uart_midi = true;
+ m_uart_irq = false;
+ break;
+
+ case 0x35:
+ m_uart_midi = true;
+ m_uart_irq = true;
+ break;
+
+ case 0x36:
+ case 0x37: // Enter UART mode
+ printf("timestamp MIDI mode not supported, contact MESSDEV!\n");
+ break;
+
+ case 0x38: // single-byte MIDI send
+ m_onebyte_midi = true;
+ break;
+
+ case 0x40: // set time constant
+ m_dsp.frequency = (1000000 / (256 - m_dsp.fifo[1]));
+ //printf("Set time constant: %02x -> %d\n", m_dsp.fifo[1], m_dsp.frequency);
+ break;
+
+ case 0x48: // set DMA block size (for auto-init)
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ break;
+
+ case 0x75: // 4-bit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ case 0x74: // 4-bit ADPCM
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 0;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM4;
+ break;
+
+ case 0x77: // 2.6-bit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ case 0x76: // 2.6-bit ADPCM
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 0;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM3;
+ break;
+
+ case 0xd0: // halt 8-bit DMA
+ m_timer->adjust(attotime::never, 0);
+ drq_w(0); // drop DRQ
+ m_dsp.dma_throttled = false;
+ m_dsp.dma_timer_started = false;
+ break;
+
+ case 0xd1: // speaker on
+ // ...
+ m_dsp.speaker_on = 1;
+ break;
+
+ case 0xd3: // speaker off
+ // ...
+ m_dsp.speaker_on = 0;
+ break;
+
+ case 0xd8: // speaker status
+ queue_r(m_dsp.speaker_on ? 0xff : 0x00);
+ break;
+
+ case 0xe0: // get DSP identification
+ queue_r(m_dsp.fifo[1] ^ 0xff);
+ break;
+
+ case 0xe1: // get DSP version
+ queue_r(m_dsp.version >> 8);
+ queue_r(m_dsp.version & 0xff);
+ break;
+
+ case 0xe2: // DSP protection
+ m_dsp.prot_value += protection_magic[m_dsp.prot_count++] ^ m_dsp.fifo[1];
+ m_dsp.prot_count &= 3;
+ m_dsp.adc_transferred = 0;
+ m_dsp.adc_length = 1;
+ m_dsp.wbuf_status = 0x80;
+ m_dsp.dma_no_irq = true;
+ m_dack_out = (UINT8)(m_dsp.prot_value & 0xff);
+ drq_w(1);
+ break;
+
+ case 0xe4: // write test register
+ m_dsp.test_reg = m_dsp.fifo[1];
+ break;
+
+ case 0xe8: // read test register
+ queue_r(m_dsp.test_reg);
+ break;
+
+ case 0xf2: // send PIC irq
+ irq_w(1, IRQ_DMA8);
+ break;
+
+ case 0xf8: // ???
+ logerror("SB: Unknown command write 0xf8\n");
+ queue_r(0);
+ break;
+ default:
+ if(m_dsp.version >= 0x0201) // SB 2.0
+ {
+ switch(cmd)
+ {
+ case 0x1f: // 2-bit autoinit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 1;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM2;
+ break;
+ case 0x7d: // 4-bit autoinit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 1;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM4;
+ break;
+ case 0x7f: // 2.6-bit autoinit ADPCM w/new reference
+ m_dsp.adpcm_new_ref = true;
+ m_dsp.adpcm_step = 0;
+ m_dsp.adpcm_count = 0;
+ m_dsp.dma_length = (m_dsp.fifo[1] + (m_dsp.fifo[2]<<8)) + 1;
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_autoinit = 1;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ drq_w(1);
+ m_dsp.flags = ADPCM3;
+ break;
+ case 0xda: // stop 8-bit autoinit
+ m_dsp.dma_autoinit = 0;
+ break;
+ }
+ }
+ if(m_dsp.version >= 0x0301) // SB Pro 2
+ {
+ switch(cmd)
+ {
+ case 0xe3: // copyright notice, check if in pro 2
+ const char* copyright = "NOT COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.";
+ int j = strlen(copyright);
+ for(int k = 4; k <= j; k++)
+ queue_r(copyright[k]);
+ break;
+ }
+ }
+ if(m_dsp.version >= 0x0400) // SB16
+ {
+ int mode;
+ switch(cmd)
+ {
+ case 0x0f: // read asp reg
+ queue_r(0);
+ case 0x0e: // write asp reg
+ case 0x02: // get asp version
+ case 0x04: // set asp mode register
+ case 0x05: // set asp codec param
+ logerror("SB16: unimplemented ASP command\n");
+ break;
+ case 0x41: // set output sample rate
+ m_dsp.frequency = m_dsp.fifo[2] + (m_dsp.fifo[1] << 8);
+ break;
+ case 0x42: // set input sample rate
+ m_dsp.adc_freq = m_dsp.fifo[2] + (m_dsp.fifo[1] << 8);
+ break;
+ case 0xd5: // pause 16-bit dma
+ m_timer->adjust(attotime::never, 0);
+ drq16_w(0); // drop DRQ
+ m_dsp.dma_throttled = false;
+ m_dsp.dma_timer_started = false;
+ break;
+ case 0xd6: // resume 16-bit dma
+ logerror("SB: 16-bit dma resume\n");
+ break;
+ case 0xd9: // stop 16-bit autoinit
+ m_dsp.dma_autoinit = 0;
+ break;
+ case 0xb0:
+ case 0xb6:
+ case 0xc0:
+ case 0xc6:
+ mode = m_dsp.fifo[1];
+ m_dsp.flags = 0;
+ m_dsp.dma_length = (m_dsp.fifo[2] + (m_dsp.fifo[3]<<8)) + 1;
+ if((cmd & 0xf0) == 0xb0)
+ {
+ m_dsp.flags |= SIXTEENBIT;
+ m_dsp.dma_length <<= 1;
+ drq16_w(1);
+ }
+ else
+ drq_w(1);
+ if(cmd & 0x04)
+ m_dsp.dma_autoinit = 1;
+ if(mode & 0x10)
+ m_dsp.flags |= SIGNED;
+ if(mode & 0x20)
+ {
+ m_dsp.flags |= STEREO;
+ m_dsp.dma_length <<= 1;
+ }
+ m_dsp.dma_transferred = 0;
+ m_dsp.dma_timer_started = false;
+ m_dsp.dma_throttled = false;
+ break;
+ case 0xb8:
+ case 0xbe:
+ case 0xc8:
+ case 0xce:
+ mode = m_dsp.fifo[1];
+ m_dsp.adc_length = (m_dsp.fifo[2] + (m_dsp.fifo[3]<<8)) + 1;
+ m_dsp.adc_transferred = 0;
+ if(cmd & 0x04)
+ m_dsp.dma_autoinit = 1;
+ if(mode & 0x20)
+ m_dsp.adc_length <<= 1;
+ if((cmd & 0xf0) == 0xb0)
+ {
+ m_dsp.adc_length <<= 1;
+ drq16_w(1);
+ }
+ else
+ drq_w(1);
+ logerror("SB: ADC capture unimplemented\n");
+ break;
+ case 0xf3: // send PIC irq
+ irq_w(1, IRQ_DMA16);
+ break;
+ case 0xfc:
+ queue_r((((m_dsp.flags & SIXTEENBIT) && m_dsp.dma_autoinit) << 4) | ((!(m_dsp.flags & SIXTEENBIT) && m_dsp.dma_autoinit) << 2));
+ break;
+ }
+ }
+ }
+ m_dsp.fifo_ptr = 0;
+ }
+}
+
+WRITE8_MEMBER(sb_device::dsp_cmd_w)
+{
+// printf("%02x to DSP command @ %x\n", data, offset);
+
+ if(offset)
+ return;
+
+ if (m_uart_midi || m_onebyte_midi)
+ {
+ xmit_char(data);
+ m_onebyte_midi = false; // clear onebyte (if this is uart, that's harmless)
+ return;
+ }
+
+ queue(data);
+
+ process_fifo(m_dsp.fifo[0]);
+}
+
+void sb_device::adpcm_decode(UINT8 sample, int size)
+{
+ const UINT8 adpcm_2_table[] = {0, 1, 1, 3, 2, 6, 4, 12, 8, 24, 16, 48};
+ const UINT8 step_2_table[] = {0, 2, 0, 4, 2, 6, 4, 8, 6, 10, 8, 10};
+
+ const UINT8 adpcm_3_table[] = {0, 1, 2, 3, 1, 3, 5, 7,
+ 2, 6, 10, 14, 4, 12, 20, 28,
+ 8, 24, 40, 56};
+ const UINT8 step_3_table[] = {0, 0, 0, 4, 0, 4, 4, 8,
+ 4, 8, 8, 12, 8, 12, 12, 16,
+ 12, 16, 16, 16};
+
+ const UINT8 adpcm_4_table[] = {0, 1, 2, 3, 4, 5, 6, 7,
+ 1, 3, 5, 7, 9, 11, 13, 15,
+ 2, 6, 10, 14, 18, 22, 26, 30,
+ 4, 12, 20, 28, 36, 44, 52, 60};
+ const UINT8 step_4_table[] = {0, 0, 0, 0, 0, 8, 8, 8,
+ 0, 8, 8, 8, 8, 16, 16, 16,
+ 8, 16, 16, 16, 16, 24, 24, 24,
+ 16, 24, 24, 24, 24, 24, 24, 24};
+
+ INT16 dec_sample = m_dsp.adpcm_ref;
+ UINT8 index;
+ switch(size)
+ {
+ case 2:
+ index = (sample & 1) | m_dsp.adpcm_step;
+ dec_sample += ((sample & 2)?-1:1) * adpcm_2_table[index];
+ m_dsp.adpcm_step = step_2_table[index];
+ break;
+ case 3:
+ index = (sample & 3) | m_dsp.adpcm_step;
+ dec_sample += ((sample & 4)?-1:1) * adpcm_3_table[index];
+ m_dsp.adpcm_step = step_3_table[index];
+ break;
+ case 4:
+ index = (sample & 7) | m_dsp.adpcm_step;
+ dec_sample += ((sample & 8)?-1:1) * adpcm_4_table[index];
+ m_dsp.adpcm_step = step_4_table[index];
+ break;
+ }
+
+ if(dec_sample > 255)
+ dec_sample = 255;
+ else if(dec_sample < 0)
+ dec_sample = 0;
+ m_dsp.adpcm_ref = dec_sample;
+ m_dacl->write_unsigned8(m_dsp.adpcm_ref);
+ m_dacr->write_unsigned8(m_dsp.adpcm_ref);
+}
+
+READ8_MEMBER( sb16_device::mpu401_r )
+{
+ UINT8 res;
+
+ irq_w(0, IRQ_MPU);
+ if(offset == 0) // data
+ {
+ res = m_recvring[m_recv_read++];
+ if (m_recv_read >= MIDI_RING_SIZE)
+ {
+ m_recv_read = 0;
+ }
+
+ if (m_rx_waiting)
+ {
+ m_rx_waiting--;
+ }
+ }
+ else // status
+ {
+ res = 0;
+ if (m_tx_waiting >= MIDI_RING_SIZE)
+ {
+ res |= 0x40; // tx full
+ }
+ if (m_rx_waiting == 0)
+ {
+ res |= 0x80; // rx empty
+ }
+ }
+
+ return res;
+}
+
+WRITE8_MEMBER( sb16_device::mpu401_w )
+{
+ if(offset == 0) // data
+ {
+ logerror("SB MPU401:%02x %02x\n",offset,data);
+ if (m_mpu_midi)
+ {
+ xmit_char(data);
+ }
+ }
+ else // command
+ {
+ logerror("SB MPU401:%02x %02x\n",offset,data);
+
+ switch(data)
+ {
+ case 0x3f: // enter MPU-401 UART mode
+ irq_w(1, IRQ_MPU);
+ m_recv_read = m_recv_write = 0;
+ m_xmit_read = m_xmit_write = m_tx_waiting = 0;
+ m_recvring[m_recv_write++] = 0xfe;
+ m_rx_waiting = 1;
+ m_mpu_midi = true;
+ break;
+
+ case 0xff: // reset
+ irq_w(1, IRQ_MPU);
+ m_recv_read = m_recv_write = 0;
+ m_recvring[m_recv_write++] = 0xfe;
+ m_rx_waiting = 1;
+ m_mpu_midi = false;
+ break;
+ }
+ }
+
+}
+
+void sb16_device::mixer_set()
+{
+ ymf262_device *ymf = subdevice<ymf262_device>("ymf262");
+ float lmain = m_mixer.main_vol[0]/248.0;
+ float rmain = m_mixer.main_vol[1]/248.0;
+ m_dacl->set_output_gain(ALL_OUTPUTS, lmain*(m_mixer.dac_vol[0]/248.0));
+ m_dacr->set_output_gain(ALL_OUTPUTS, rmain*(m_mixer.dac_vol[1]/248.0));
+ ymf->set_output_gain(0, lmain*(m_mixer.fm_vol[0]/248.0));
+ ymf->set_output_gain(1, rmain*(m_mixer.fm_vol[1]/248.0));
+ ymf->set_output_gain(2, lmain*(m_mixer.fm_vol[0]/248.0));
+ ymf->set_output_gain(3, rmain*(m_mixer.fm_vol[1]/248.0));
+}
+
+void sb16_device::mixer_reset()
+{
+ m_mixer.status = 0x80;
+ m_mixer.main_vol[0] = 0xc0;
+ m_mixer.main_vol[1] = 0xc0;
+ m_mixer.dac_vol[0] = 0xc0;
+ m_mixer.dac_vol[1] = 0xc0;
+ m_mixer.fm_vol[0] = 0xc0;
+ m_mixer.fm_vol[1] = 0xc0;
+ m_mixer.cd_vol[0] = 0x00;
+ m_mixer.cd_vol[1] = 0x00;
+ m_mixer.line_vol[0] = 0x00;
+ m_mixer.line_vol[1] = 0x00;
+ m_mixer.mic_vol = 0x00;
+ m_mixer.pc_speaker_vol = 0x00;
+ m_mixer.output_ctl = 0x1f;
+ m_mixer.input_ctl[0] = 0x15;
+ m_mixer.input_ctl[1] = 0x0b;
+ m_mixer.input_gain[0] = 0x00;
+ m_mixer.input_gain[1] = 0x00;
+ m_mixer.output_gain[0] = 0x00;
+ m_mixer.output_gain[1] = 0x00;
+ m_mixer.agc = 0x00;
+ m_mixer.treble[0] = 0x80;
+ m_mixer.treble[1] = 0x80;
+ m_mixer.bass[0] = 0x80;
+ m_mixer.bass[1] = 0x80;
+ mixer_set();
+}
+
+READ8_MEMBER( sb16_device::mixer_r )
+{
+ if(offset == 0)
+ return m_mixer.status;
+ return m_mixer.data;
+}
+
+WRITE8_MEMBER( sb16_device::mixer_w )
+{
+ if(offset == 0)
+ {
+ switch(data)
+ {
+ case 0x00:
+ mixer_reset();
+ return;
+ case 0x01:
+ m_mixer.data = m_mixer.status;
+ break;
+ case 0x04:
+ m_mixer.data = (m_mixer.dac_vol[0] & 0xf0) | (m_mixer.dac_vol[1] >> 4);
+ break;
+ case 0x0a:
+ m_mixer.data = m_mixer.mic_vol >> 5;
+ break;
+ case 0x22:
+ m_mixer.data = (m_mixer.main_vol[0] & 0xf0) | (m_mixer.main_vol[1] >> 4);
+ break;
+ case 0x26:
+ m_mixer.data = (m_mixer.fm_vol[0] & 0xf0) | (m_mixer.fm_vol[1] >> 4);
+ break;
+ case 0x28:
+ m_mixer.data = (m_mixer.cd_vol[0] & 0xf0) | (m_mixer.cd_vol[1] >> 4);
+ break;
+ case 0x2e:
+ m_mixer.data = (m_mixer.line_vol[0] & 0xf0) | (m_mixer.line_vol[1] >> 4);
+ break;
+ case 0x30:
+ case 0x31:
+ m_mixer.data = m_mixer.main_vol[data & 1];
+ break;
+ case 0x32:
+ case 0x33:
+ m_mixer.data = m_mixer.dac_vol[data & 1];
+ break;
+ case 0x34:
+ case 0x35:
+ m_mixer.data = m_mixer.fm_vol[data & 1];
+ break;
+ case 0x36:
+ case 0x37:
+ m_mixer.data = m_mixer.cd_vol[data & 1];
+ break;
+ case 0x38:
+ case 0x39:
+ m_mixer.data = m_mixer.line_vol[data & 1];
+ break;
+ case 0x3a:
+ m_mixer.data = m_mixer.mic_vol;
+ break;
+ case 0x3b:
+ m_mixer.data = m_mixer.pc_speaker_vol;
+ break;
+ case 0x3c:
+ m_mixer.data = m_mixer.output_ctl;
+ break;
+ case 0x3d:
+ case 0x3e:
+ m_mixer.data = m_mixer.input_ctl[(data + 1) & 1];
+ break;
+ case 0x3f:
+ case 0x40:
+ m_mixer.data = m_mixer.input_gain[(data + 1) & 1];
+ break;
+ case 0x41:
+ case 0x42:
+ m_mixer.data = m_mixer.output_gain[(data + 1) & 1];
+ break;
+ case 0x43:
+ m_mixer.data = m_mixer.agc;
+ break;
+ case 0x44:
+ case 0x45:
+ m_mixer.data = m_mixer.treble[data & 1];
+ break;
+ case 0x46:
+ case 0x47:
+ m_mixer.data = m_mixer.bass[data & 1];
+ break;
+ case 0x80:
+ m_mixer.data = 0x12; // irq5
+ break;
+ case 0x81:
+ m_mixer.data = 0x22; // dma1&5
+ break;
+ case 0x82:
+ m_mixer.data = m_dsp.irq_active | 0x20;
+ break;
+ default:
+ logerror("SB: Unimplemented mixer index %02x\n", data);
+ m_mixer.status = data | 0x80;
+ m_mixer.data = 0x0a;
+ return;
+ }
+ m_mixer.status = data;
+ return;
+ }
+ switch(m_mixer.status)
+ {
+ case 0x04:
+ m_mixer.dac_vol[0] = (data & 0xf0) | 8;
+ m_mixer.dac_vol[1] = (data << 4) | 8;
+ break;
+ case 0x0a:
+ m_mixer.mic_vol = (data << 5) | 0x18;
+ break;
+ case 0x22:
+ m_mixer.main_vol[0] = (data & 0xf0) | 8;
+ m_mixer.main_vol[1] = (data << 4) | 8;
+ break;
+ case 0x26:
+ m_mixer.fm_vol[0] = (data & 0xf0) | 8;
+ m_mixer.fm_vol[1] = (data << 4) | 8;
+ break;
+ case 0x28:
+ m_mixer.cd_vol[0] = (data & 0xf0) | 8;
+ m_mixer.cd_vol[1] = (data << 4) | 8;
+ break;
+ case 0x2e:
+ m_mixer.line_vol[0] = (data & 0xf0) | 8;
+ m_mixer.line_vol[1] = (data << 4) | 8;
+ break;
+ case 0x30:
+ case 0x31:
+ m_mixer.main_vol[m_mixer.status & 1] = data & 0xf8;
+ break;
+ case 0x32:
+ case 0x33:
+ m_mixer.dac_vol[m_mixer.status & 1] = data & 0xf8;
+ break;
+ case 0x34:
+ case 0x35:
+ m_mixer.fm_vol[m_mixer.status & 1] = data & 0xf8;
+ break;
+ case 0x36:
+ case 0x37:
+ m_mixer.cd_vol[m_mixer.status & 1] = data & 0xf8;
+ break;
+ case 0x38:
+ case 0x39:
+ m_mixer.line_vol[m_mixer.status & 1] = data & 0xf8;
+ break;
+ case 0x3a:
+ m_mixer.mic_vol = data & 0xf8;
+ break;
+ case 0x3b:
+ m_mixer.pc_speaker_vol = data & 0xc0;
+ break;
+ case 0x3c:
+ m_mixer.output_ctl = data & 0x1f;
+ break;
+ case 0x3d:
+ case 0x3e:
+ m_mixer.input_ctl[(m_mixer.status + 1) & 1] = data & 0x7f;
+ break;
+ case 0x3f:
+ case 0x40:
+ m_mixer.input_gain[(m_mixer.status + 1) & 1] = data & 0xc0;
+ break;
+ case 0x41:
+ case 0x42:
+ m_mixer.output_gain[(m_mixer.status + 1) & 1] = data & 0xc0;
+ break;
+ case 0x43:
+ m_mixer.agc = data & 1;
+ break;
+ case 0x44:
+ case 0x45:
+ m_mixer.treble[m_mixer.status & 1] = data & 0xf0;
+ break;
+ case 0x46:
+ case 0x47:
+ m_mixer.bass[m_mixer.status & 1] = data & 0xf0;
+ break;
+ case 0x80:
+ case 0x81:
+ // don't support these yet
+ break;
+ default:
+ return;
+ }
+ m_mixer.data = data;
+ mixer_set();
+ return;
+}
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SOUND_BLASTER_1_0 = &device_creator<isa8_sblaster1_0_device>;
+const device_type ISA8_SOUND_BLASTER_1_5 = &device_creator<isa8_sblaster1_5_device>;
+const device_type ISA16_SOUND_BLASTER_16 = &device_creator<isa16_sblaster16_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_sblaster1_0_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sblaster1_0_config );
+}
+
+machine_config_constructor isa8_sblaster1_5_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sblaster1_5_config );
+}
+
+machine_config_constructor isa16_sblaster16_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( sblaster_16_config );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+sb_device::sb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) :
+ device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_serial_interface(mconfig, *this),
+ m_dacl(*this, "sbdacl"),
+ m_dacr(*this, "sbdacr"),
+ m_joy(*this, "pc_joy"),
+ m_mdout(*this, "mdout")
+{
+}
+
+sb8_device::sb8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) :
+ sb_device(mconfig, type, tag, owner, clock, name, shortname, source),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+sb16_device::sb16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source) :
+ sb_device(mconfig, type, tag, owner, clock, name, shortname, source),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// isa8_sblaster_device - constructor
+//-------------------------------------------------
+
+isa8_sblaster1_0_device::isa8_sblaster1_0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ sb8_device(mconfig, ISA8_SOUND_BLASTER_1_0, tag, owner, clock, "Sound Blaster 1.0", "isa_sblaster1_0", __FILE__)
+{
+}
+
+isa8_sblaster1_5_device::isa8_sblaster1_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ sb8_device(mconfig, ISA8_SOUND_BLASTER_1_5, tag, owner, clock, "Sound Blaster 1.5", "isa_sblaster1_5", __FILE__)
+{
+}
+
+isa16_sblaster16_device::isa16_sblaster16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ sb16_device(mconfig, ISA16_SOUND_BLASTER_16, tag, owner, clock, "Sound Blaster 16", "isa_sblaster_16", __FILE__)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void sb8_device::device_start()
+{
+ m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice<pc_joy_device>("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice<pc_joy_device>("pc_joy")));
+ m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb_device::dsp_reset_r), this), write8_delegate(FUNC(sb_device::dsp_reset_w), this));
+ m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb_device::dsp_data_r), this), write8_delegate(FUNC(sb_device::dsp_data_w), this) );
+ m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_cmd_w), this) );
+ m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_rbuf_status_w), this) );
+ if(m_dsp.version >= 0x0301)
+ {
+ ymf262_device *ymf262 = subdevice<ymf262_device>("ymf262");
+
+ m_isa->install_device(0x0388, 0x038b, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+ m_isa->install_device(0x0220, 0x0223, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+ m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+ }
+ else
+ {
+ m_isa->install_device(subdevice("ym3812"), 0x0388, 0x0389, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+ m_isa->install_device(subdevice("ym3812"), 0x0228, 0x0229, 0, 0, FUNC(ym3812_16_r), FUNC(ym3812_16_w) );
+ }
+
+ m_timer = timer_alloc(0, NULL);
+
+ save_item(NAME(m_dack_out));
+ save_item(NAME(m_onebyte_midi));
+ save_item(NAME(m_uart_midi));
+ save_item(NAME(m_uart_irq));
+ save_item(NAME(m_mpu_midi));
+ save_item(NAME(m_rx_waiting));
+ save_item(NAME(m_tx_waiting));
+ save_item(NAME(m_recvring));
+ save_item(NAME(m_xmitring));
+ save_item(NAME(m_xmit_read));
+ save_item(NAME(m_xmit_write));
+ save_item(NAME(m_recv_read));
+ save_item(NAME(m_recv_write));
+ save_item(NAME(m_tx_busy));
+}
+
+void isa8_sblaster1_0_device::device_start()
+{
+ set_isa_device();
+ // 1.0 always has the SAA1099s for CMS back-compatibility
+ m_isa->install_device(subdevice("saa1099.1"), 0x0220, 0x0221, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ m_isa->install_device(subdevice("saa1099.2"), 0x0222, 0x0223, 0, 0, FUNC(saa1099_16_r), FUNC(saa1099_16_w) );
+ m_isa->set_dma_channel(1, this, FALSE);
+ m_dsp.version = 0x0105;
+ sb8_device::device_start();
+}
+
+void isa8_sblaster1_5_device::device_start()
+{
+ set_isa_device();
+ /* 1.5 makes CM/S support optional (empty sockets, but they work if the user populates them!) */
+ m_isa->set_dma_channel(1, this, FALSE);
+ m_dsp.version = 0x0200;
+ sb8_device::device_start();
+}
+
+void sb16_device::device_start()
+{
+ ymf262_device *ymf262 = subdevice<ymf262_device>("ymf262");
+
+ m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice<pc_joy_device>("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice<pc_joy_device>("pc_joy")));
+ m_isa->install_device(0x0224, 0x0225, 0, 0, read8_delegate(FUNC(sb16_device::mixer_r), this), write8_delegate(FUNC(sb16_device::mixer_w), this));
+ m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(sb_device::dsp_reset_r), this), write8_delegate(FUNC(sb_device::dsp_reset_w), this));
+ m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(sb_device::dsp_data_r), this), write8_delegate(FUNC(sb_device::dsp_data_w), this) );
+ m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(sb_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_cmd_w), this) );
+ m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(sb_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(sb_device::dsp_rbuf_status_w), this) );
+ m_isa->install_device(0x0330, 0x0331, 0, 0, read8_delegate(FUNC(sb16_device::mpu401_r), this), write8_delegate(FUNC(sb16_device::mpu401_w), this));
+ m_isa->install_device(0x0388, 0x038b, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+ m_isa->install_device(0x0220, 0x0223, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+ m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ymf262_device::read), ymf262), write8_delegate(FUNC(ymf262_device::write), ymf262));
+
+ m_timer = timer_alloc(0, NULL);
+
+ save_item(NAME(m_mixer.data));
+ save_item(NAME(m_mixer.status));
+ save_item(NAME(m_mixer.main_vol));
+ save_item(NAME(m_mixer.dac_vol));
+ save_item(NAME(m_mixer.fm_vol));
+ save_item(NAME(m_mixer.cd_vol));
+ save_item(NAME(m_mixer.line_vol));
+ save_item(NAME(m_mixer.mic_vol));
+ save_item(NAME(m_mixer.pc_speaker_vol));
+ save_item(NAME(m_mixer.output_ctl));
+ save_item(NAME(m_mixer.input_ctl));
+ save_item(NAME(m_mixer.input_gain));
+ save_item(NAME(m_mixer.output_gain));
+ save_item(NAME(m_mixer.agc));
+ save_item(NAME(m_mixer.treble));
+ save_item(NAME(m_mixer.bass));
+}
+
+void isa16_sblaster16_device::device_start()
+{
+ set_isa_device();
+ m_isa->set_dma_channel(1, this, FALSE);
+ m_isa->set_dma_channel(5, this, FALSE);
+ m_dsp.version = 0x0405; // diagnose.exe rejects anything lower than 0x0402
+ sb16_device::device_start();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void sb_device::device_reset()
+{
+ m_dsp.prot_value = 0xaa;
+ m_dsp.prot_count = 0;
+ m_dack_out = 0;
+ m_dsp.fifo_ptr = 0;
+ m_dsp.fifo_r_ptr = 0;
+ m_dsp.wbuf_status = 0;
+ m_dsp.rbuf_status = 0;
+ m_dsp.frequency = 8000; // per stereo-fx
+ m_dsp.irq_active = 0;
+ m_dsp.dma_no_irq = false;
+ mixer_reset();
+
+ m_onebyte_midi = false;
+ m_uart_midi = false;
+ m_uart_irq = false;
+ m_mpu_midi = false;
+ m_tx_busy = false;
+ m_xmit_read = m_xmit_write = 0;
+ m_recv_read = m_recv_write = 0;
+ m_rx_waiting = m_tx_waiting = 0;
+
+ // MIDI is 31250 baud, 8-N-1
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+ set_rate(31250);
+}
+
+UINT8 sb_device::dack_r(int line)
+{
+ m_dsp.adc_transferred++;
+ if(m_dsp.adc_transferred >= m_dsp.adc_length)
+ {
+ drq_w(0);
+
+ if (m_dsp.dma_autoinit)
+ {
+ m_dsp.adc_transferred = 0;
+ drq_w(1);
+ }
+ else
+ m_dsp.wbuf_status = 0;
+ if(!m_dsp.dma_no_irq)
+ irq_w(1, IRQ_DMA8);
+ else
+ m_dsp.dma_no_irq = false;
+ }
+ else
+ drq_w(1);
+ return m_dack_out;
+}
+
+UINT16 sb16_device::dack16_r(int line)
+{
+ m_dsp.adc_transferred += 2;
+ if (m_dsp.adc_transferred >= m_dsp.adc_length)
+ {
+ drq16_w(0);
+
+ if (m_dsp.dma_autoinit)
+ {
+ m_dsp.adc_transferred = 0;
+ drq16_w(1);
+ }
+ irq_w(1, IRQ_DMA16);
+ }
+ else
+ drq16_w(1);
+ return m_dack_out;
+}
+
+void sb16_device::dack16_w(int line, UINT16 data)
+{
+ // set the transfer timer on the 1st byte
+ if (!m_dsp.dma_timer_started)
+ {
+ m_timer->adjust(attotime::from_hz((double)m_dsp.frequency), 0, attotime::from_hz((double)m_dsp.frequency));
+ m_dsp.d_rptr = m_dsp.d_wptr = 0;
+ m_dsp.dma_timer_started = true;
+ }
+
+ m_dsp.data[m_dsp.d_wptr++] = data & 0xff;
+ m_dsp.data[m_dsp.d_wptr++] = data >> 8;
+ m_dsp.d_wptr %= 128;
+
+ if (m_dsp.d_wptr == m_dsp.d_rptr)
+ {
+// printf("throttling DRQ\n");
+ drq16_w(0); // drop DRQ here
+ m_dsp.dma_throttled = true;
+ }
+
+ m_dsp.dma_transferred += 2;
+ if (m_dsp.dma_transferred >= m_dsp.dma_length)
+ {
+// printf("DMA fill completed (%d out of %d)\n", m_dsp.dma_transferred, m_dsp.dma_length);
+
+ drq16_w(0); // drop DRQ here
+
+ if (m_dsp.dma_autoinit)
+ {
+// printf("autoinit reset\n");
+ m_dsp.dma_transferred = 0;
+ if (!m_dsp.dma_throttled) // if we're not throttled, re-raise DRQ right now
+ {
+ drq16_w(1); // raise DRQ again (page 3-15 of the Creative manual indicates auto-init will keep going until you stop it)
+ }
+ }
+
+ irq_w(1, IRQ_DMA16); // raise IRQ as per the Creative manual
+ }
+}
+
+/* TODO: this mustn't be instant! */
+void sb_device::dack_w(int line, UINT8 data)
+{
+// printf("dack_w: line %x data %02x\n", line, data);
+// if(data != 0x80)
+// printf("%02x\n",data);
+
+ // set the transfer timer on the 1st byte
+ if (!m_dsp.dma_timer_started)
+ {
+ m_timer->adjust(attotime::from_hz((double)m_dsp.frequency), 0, attotime::from_hz((double)m_dsp.frequency));
+ m_dsp.d_rptr = m_dsp.d_wptr = 0;
+ m_dsp.dma_timer_started = true;
+ }
+
+ m_dsp.data[m_dsp.d_wptr++] = data;
+ m_dsp.d_wptr %= 128;
+
+ if (m_dsp.d_wptr == m_dsp.d_rptr)
+ {
+// printf("throttling DRQ\n");
+ drq_w(0); // drop DRQ here
+ m_dsp.dma_throttled = true;
+ }
+
+ m_dsp.dma_transferred++;
+ if (m_dsp.dma_transferred >= m_dsp.dma_length)
+ {
+// printf("DMA fill completed (%d out of %d)\n", m_dsp.dma_transferred, m_dsp.dma_length);
+
+ drq_w(0); // drop DRQ here
+
+ if (m_dsp.dma_autoinit)
+ {
+// printf("autoinit reset\n");
+ m_dsp.dma_transferred = 0;
+ if (!m_dsp.dma_throttled) // if we're not throttled, re-raise DRQ right now
+ {
+ drq_w(1); // raise DRQ again (page 3-15 of the Creative manual indicates auto-init will keep going until you stop it)
+ }
+ }
+
+ irq_w(1, IRQ_DMA8); // raise IRQ as per the Creative manual
+ }
+}
+
+void sb_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+// printf("DMA timer expire\n");
+ if (tid)
+ {
+ device_serial_interface::device_timer(timer, tid, param, ptr);
+ return;
+ }
+
+ UINT16 lsample, rsample;
+ switch (m_dsp.flags) {
+ case 0: // 8-bit unsigned mono
+ m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr]);
+ m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr]);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ break;
+ case SIGNED: // 8-bit signed mono
+ m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128);
+ m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ break;
+ case STEREO: // 8-bit unsigned stereo
+ m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr]);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr]);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ break;
+ case SIGNED | STEREO: // 8-bit signed stereo
+ m_dacl->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dacr->write_unsigned8(m_dsp.data[m_dsp.d_rptr] + 128);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ break;
+ case SIXTEENBIT: // 16-bit unsigned mono
+ lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dacl->write_unsigned16(lsample);
+ m_dacr->write_unsigned16(lsample);
+ break;
+ case SIXTEENBIT | SIGNED: // 16-bit signed mono
+ lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dacl->write_unsigned16(lsample + 32768);
+ m_dacr->write_unsigned16(lsample + 32768);
+ break;
+ case SIXTEENBIT | STEREO: // 16-bit unsigned stereo
+ lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dsp.d_rptr %= 128;
+ rsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dacl->write_unsigned16(lsample);
+ m_dacr->write_unsigned16(rsample);
+ break;
+ case SIXTEENBIT | SIGNED | STEREO: // 16-bit signed stereo
+ lsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.d_rptr %= 128;
+ rsample = m_dsp.data[m_dsp.d_rptr] | (m_dsp.data[m_dsp.d_rptr+1] << 8);
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dsp.data[m_dsp.d_rptr++] = 0x00;
+ m_dacl->write_unsigned16(lsample + 32768);
+ m_dacr->write_unsigned16(rsample + 32768);
+ break;
+ case ADPCM2:
+ if(m_dsp.adpcm_new_ref)
+ {
+ m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++];
+ m_dsp.adpcm_new_ref = false;
+ m_dacl->write_unsigned8(m_dsp.adpcm_ref);
+ m_dacr->write_unsigned8(m_dsp.adpcm_ref);
+ break;
+ }
+ lsample = m_dsp.data[m_dsp.d_rptr];
+ switch(m_dsp.adpcm_count++)
+ {
+ case 0:
+ adpcm_decode(lsample >> 6, 2);
+ break;
+ case 1:
+ adpcm_decode((lsample >> 4) & 3, 2);
+ break;
+ case 2:
+ adpcm_decode((lsample >> 2) & 3, 2);
+ break;
+ case 3:
+ adpcm_decode(lsample & 3, 2);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dsp.adpcm_count = 0;
+ break;
+ }
+ break;
+ case ADPCM3:
+ if(m_dsp.adpcm_new_ref)
+ {
+ m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++];
+ m_dsp.adpcm_new_ref = false;
+ m_dacl->write_unsigned8(m_dsp.adpcm_ref);
+ m_dacr->write_unsigned8(m_dsp.adpcm_ref);
+ break;
+ }
+ lsample = m_dsp.data[m_dsp.d_rptr];
+ switch(m_dsp.adpcm_count++)
+ {
+ case 0:
+ adpcm_decode(lsample >> 5, 3);
+ break;
+ case 1:
+ adpcm_decode((lsample >> 2) & 7, 3);
+ break;
+ case 2:
+ adpcm_decode(((lsample & 2) << 1) | (lsample & 1), 3);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dsp.adpcm_count = 0;
+ break;
+ }
+ break;
+ case ADPCM4:
+ if(m_dsp.adpcm_new_ref)
+ {
+ m_dsp.adpcm_ref = m_dsp.data[m_dsp.d_rptr++];
+ m_dsp.adpcm_new_ref = false;
+ m_dacl->write_unsigned8(m_dsp.adpcm_ref);
+ m_dacr->write_unsigned8(m_dsp.adpcm_ref);
+ break;
+ }
+ lsample = m_dsp.data[m_dsp.d_rptr];
+ switch(m_dsp.adpcm_count++)
+ {
+ case 0:
+ adpcm_decode(lsample >> 4, 4);
+ break;
+ case 1:
+ adpcm_decode(lsample & 15, 4);
+ m_dsp.data[m_dsp.d_rptr++] = 0x80;
+ m_dsp.adpcm_count = 0;
+ break;
+ }
+ break;
+ default:
+ logerror("SB: unimplemented sample type %x\n", m_dsp.flags);
+ }
+ m_dsp.d_rptr %= 128;
+
+ if (m_dsp.dma_throttled)
+ {
+ if (m_dsp.d_rptr == m_dsp.d_wptr)
+ {
+// printf("unthrottling DRQ\n");
+ if(m_dsp.flags & SIXTEENBIT) // 16-bit audio through 8-bit dma?
+ drq16_w(1);
+ else
+ drq_w(1); // raise DRQ
+ m_dsp.dma_throttled = false;
+ }
+ }
+}
+
+void sb_device::rcv_complete() // Rx completed receiving byte
+{
+ receive_register_extract();
+ UINT8 data = get_received_char();
+
+ // in UART MIDI mode, we set the DMA8 IRQ on receiving a character
+ if (m_uart_midi)
+ {
+ m_recvring[m_recv_write++] = data;
+ if (m_recv_write >= MIDI_RING_SIZE)
+ {
+ m_recv_write = 0;
+ }
+
+ if (m_recv_write != m_recv_read)
+ {
+ m_rx_waiting++;
+ }
+ if (m_uart_irq)
+ {
+ irq_w(1, IRQ_DMA8);
+ }
+ }
+}
+
+void sb16_device::rcv_complete() // Rx completed receiving byte
+{
+ receive_register_extract();
+ UINT8 data = get_received_char();
+
+ // for UART or MPU, add character to the receive queue
+ if (m_uart_midi || m_mpu_midi)
+ {
+ m_recvring[m_recv_write++] = data;
+ if (m_recv_write >= MIDI_RING_SIZE)
+ {
+ m_recv_write = 0;
+ }
+
+ if (m_recv_write != m_recv_read)
+ {
+ m_rx_waiting++;
+ }
+
+ if (m_uart_irq)
+ {
+ irq_w(1, IRQ_DMA8);
+ }
+
+ if (m_mpu_midi)
+ {
+ irq_w(1, IRQ_MPU);
+ }
+ }
+}
+
+void sb_device::tra_complete() // Tx completed sending byte
+{
+// printf("Tx complete\n");
+ // is there more waiting to send?
+ if (m_tx_waiting)
+ {
+ transmit_register_setup(m_xmitring[m_xmit_read++]);
+ if (m_xmit_read >= MIDI_RING_SIZE)
+ {
+ m_xmit_read = 0;
+ }
+ m_tx_waiting--;
+ }
+ else
+ {
+ m_tx_busy = false;
+ }
+}
+
+void sb_device::tra_callback() // Tx send bit
+{
+ int bit = transmit_register_get_data_bit();
+ m_mdout->write_txd(bit);
+}
+
+void sb_device::xmit_char(UINT8 data)
+{
+// printf("SB: xmit %02x\n", data);
+
+ // if tx is busy it'll pick this up automatically when it completes
+ if (!m_tx_busy)
+ {
+ m_tx_busy = true;
+ transmit_register_setup(data);
+ }
+ else
+ {
+ // tx is busy, it'll pick this up next time
+ m_xmitring[m_xmit_write++] = data;
+ if (m_xmit_write >= MIDI_RING_SIZE)
+ {
+ m_xmit_write = 0;
+ }
+ m_tx_waiting++;
+ }
+}
diff --git a/src/emu/bus/isa/sblaster.h b/src/emu/bus/isa/sblaster.h
new file mode 100644
index 00000000000..7772f94cb62
--- /dev/null
+++ b/src/emu/bus/isa/sblaster.h
@@ -0,0 +1,242 @@
+#pragma once
+
+#ifndef __ISA_SOUND_BLASTER_H__
+#define __ISA_SOUND_BLASTER_H__
+
+#include "bus/midi/midi.h"
+#include "isa.h"
+#include "sound/dac.h"
+#include "bus/pc_joy/pc_joy.h"
+
+#define SIXTEENBIT 0x01
+#define STEREO 0x02
+#define SIGNED 0x04
+#define ADPCM2 0x08
+#define ADPCM3 0x10
+#define ADPCM4 0x20
+
+#define IRQ_DMA8 0x01
+#define IRQ_DMA16 0x02
+#define IRQ_MPU 0x04
+#define IRQ_ALL 0xff
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+struct sb8_dsp_state
+{
+ UINT8 reset_latch;
+ UINT8 rbuf_status;
+ UINT8 wbuf_status;
+ UINT8 fifo[16],fifo_ptr;
+ UINT8 fifo_r[52],fifo_r_ptr;
+ UINT16 version;
+ UINT8 test_reg;
+ UINT8 speaker_on;
+ bool dma_no_irq;
+ UINT32 prot_count;
+ INT32 prot_value;
+ UINT32 frequency;
+ UINT32 adc_freq;
+ UINT32 dma_length, dma_transferred;
+ UINT32 adc_length, adc_transferred;
+ UINT8 dma_autoinit;
+ UINT8 data[128], d_wptr, d_rptr;
+ bool dma_timer_started;
+ bool dma_throttled;
+ UINT8 flags;
+ UINT8 irq_active;
+ bool adpcm_new_ref;
+ UINT8 adpcm_ref;
+ UINT8 adpcm_step;
+ UINT8 adpcm_count;
+};
+
+struct sb8_mixer
+{
+ UINT8 status;
+ UINT8 main_vol;
+ UINT8 dac_vol;
+ UINT8 fm_vol;
+ UINT8 mic_vol;
+ UINT8 in_filter;
+ UINT8 stereo_sel;
+ UINT8 cd_vol;
+ UINT8 line_vol;
+};
+
+struct sb16_mixer
+{
+ UINT8 data;
+ UINT8 status;
+ UINT8 main_vol[2];
+ UINT8 dac_vol[2];
+ UINT8 fm_vol[2];
+ UINT8 cd_vol[2];
+ UINT8 line_vol[2];
+ UINT8 mic_vol;
+ UINT8 pc_speaker_vol;
+ UINT8 output_ctl;
+ UINT8 input_ctl[2];
+ UINT8 input_gain[2];
+ UINT8 output_gain[2];
+ UINT8 agc;
+ UINT8 treble[2];
+ UINT8 bass[2];
+};
+
+// ======================> sb_device (parent)
+
+class sb_device :
+ public device_t, public device_serial_interface
+{
+public:
+ // construction/destruction
+ sb_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source);
+
+ required_device<dac_device> m_dacl;
+ required_device<dac_device> m_dacr;
+ required_device<pc_joy_device> m_joy;
+ required_device<midi_port_device> m_mdout;
+
+ void process_fifo(UINT8 cmd);
+ void queue(UINT8 data);
+ void queue_r(UINT8 data);
+ UINT8 dequeue_r();
+
+ DECLARE_READ8_MEMBER(dsp_reset_r);
+ DECLARE_WRITE8_MEMBER(dsp_reset_w);
+ DECLARE_READ8_MEMBER(dsp_data_r);
+ DECLARE_WRITE8_MEMBER(dsp_data_w);
+ DECLARE_READ8_MEMBER(dsp_rbuf_status_r);
+ DECLARE_READ8_MEMBER(dsp_wbuf_status_r);
+ DECLARE_WRITE8_MEMBER(dsp_rbuf_status_w);
+ DECLARE_WRITE8_MEMBER(dsp_cmd_w);
+
+ DECLARE_WRITE_LINE_MEMBER( midi_rx_w ) { device_serial_interface::rx_w((UINT8)state); }
+
+protected:
+ // device-level overrides
+ virtual void device_reset();
+ UINT8 dack_r(int line);
+ void dack_w(int line, UINT8 data);
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual void drq16_w(int state) { }
+ virtual void drq_w(int state) { }
+ virtual void irq_w(int state, int source) { }
+ virtual void mixer_reset() {}
+ void adpcm_decode(UINT8 sample, int size);
+
+ // serial overrides
+ virtual void rcv_complete(); // Rx completed receiving byte
+ virtual void tra_complete(); // Tx completed sending byte
+ virtual void tra_callback(); // Tx send bit
+
+ static const int MIDI_RING_SIZE = 2048;
+
+ struct sb8_dsp_state m_dsp;
+ UINT8 m_dack_out;
+ void xmit_char(UINT8 data);
+ bool m_onebyte_midi, m_uart_midi, m_uart_irq, m_mpu_midi;
+ int m_rx_waiting, m_tx_waiting;
+ UINT8 m_recvring[MIDI_RING_SIZE];
+ UINT8 m_xmitring[MIDI_RING_SIZE];
+ int m_xmit_read, m_xmit_write;
+ int m_recv_read, m_recv_write;
+ bool m_tx_busy;
+
+ emu_timer *m_timer;
+};
+
+class sb8_device : public sb_device,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ sb8_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source);
+protected:
+ virtual void device_start();
+ virtual void drq_w(int state) { m_isa->drq1_w(state); }
+ virtual void irq_w(int state, int source) { m_isa->irq5_w(state); }
+ virtual UINT8 dack_r(int line) { return sb_device::dack_r(line); }
+ virtual void dack_w(int line, UINT8 data) { sb_device::dack_w(line, data); }
+};
+
+class isa8_sblaster1_0_device : public sb8_device
+{
+public:
+ // construction/destruction
+ isa8_sblaster1_0_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+private:
+ // internal state
+};
+
+class isa8_sblaster1_5_device : public sb8_device
+{
+public:
+ // construction/destruction
+ isa8_sblaster1_5_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+private:
+ // internal state
+};
+
+class sb16_device : public sb_device,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ sb16_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, UINT32 clock, const char *name, const char *shortname, const char *source);
+ DECLARE_READ8_MEMBER(mpu401_r);
+ DECLARE_WRITE8_MEMBER(mpu401_w);
+ DECLARE_READ8_MEMBER(mixer_r);
+ DECLARE_WRITE8_MEMBER(mixer_w);
+protected:
+ virtual void device_start();
+ virtual UINT16 dack16_r(int line);
+ virtual UINT8 dack_r(int line) { return sb_device::dack_r(line); }
+ virtual void dack_w(int line, UINT8 data) { sb_device::dack_w(line, data); }
+ virtual void dack16_w(int line, UINT16 data);
+ virtual void drq16_w(int state) { m_isa->drq5_w(state); }
+ virtual void drq_w(int state) { m_isa->drq1_w(state); }
+ virtual void irq_w(int state, int source) { (state?m_dsp.irq_active|=source:m_dsp.irq_active&=~source); m_isa->irq5_w(m_dsp.irq_active); }
+ virtual void mixer_reset();
+ void mixer_set();
+ virtual void rcv_complete(); // Rx completed receiving byte
+private:
+ struct sb16_mixer m_mixer;
+};
+
+class isa16_sblaster16_device : public sb16_device
+{
+public:
+ // construction/destruction
+ isa16_sblaster16_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+protected:
+ // device-level overrides
+ virtual void device_start();
+private:
+ // internal state
+};
+
+// device type definition
+extern const device_type ISA8_SOUND_BLASTER_1_0;
+extern const device_type ISA8_SOUND_BLASTER_1_5;
+extern const device_type ISA16_SOUND_BLASTER_16;
+
+#endif /* __ISA_SOUND_BLASTER_H__ */
diff --git a/src/emu/bus/isa/side116.c b/src/emu/bus/isa/side116.c
new file mode 100644
index 00000000000..6036f3faa2e
--- /dev/null
+++ b/src/emu/bus/isa/side116.c
@@ -0,0 +1,191 @@
+/***************************************************************************
+
+ Acculogic sIDE-1/16
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ IDE Disk Controller for IBM PC, XT and compatibles
+
+***************************************************************************/
+
+#include "side116.h"
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ISA8_SIDE116 = &device_creator<side116_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( side116 )
+ MCFG_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, false)
+ MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(side116_device, ide_interrupt))
+MACHINE_CONFIG_END
+
+machine_config_constructor side116_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( side116 );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+static INPUT_PORTS_START( side116 )
+ PORT_START("configuration")
+ PORT_DIPNAME(0x01, 0x00, "sIDE-1/16 ROM")
+ PORT_DIPLOCATION("JP:1")
+ PORT_DIPSETTING(0x00, "Enabled")
+ PORT_DIPSETTING(0x01, "Disabled")
+ PORT_DIPNAME(0x06, 0x00, "sIDE-1/16 ROM Address")
+ PORT_DIPLOCATION("JP:2,3")
+ PORT_DIPSETTING(0x00, "Range C800h")
+ PORT_DIPSETTING(0x04, "Range CC00h")
+ PORT_DIPSETTING(0x02, "Range D800h")
+ PORT_DIPSETTING(0x06, "Range DC00h")
+ PORT_DIPNAME(0x18, 0x10, "sIDE-1/16 IDE IRQ")
+ PORT_DIPLOCATION("JP:4,5")
+ PORT_DIPSETTING(0x10, "Level 5")
+ PORT_DIPSETTING(0x08, "Level 2")
+ PORT_DIPNAME(0x20, 0x20, "sIDE-1/16 IDE")
+ PORT_DIPLOCATION("JP:6")
+ PORT_DIPSETTING(0x00, "Disabled")
+ PORT_DIPSETTING(0x20, "Enabled")
+INPUT_PORTS_END
+
+ioport_constructor side116_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( side116 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+ROM_START( side116 )
+ ROM_REGION(0x2000, "option", 0)
+ ROM_LOAD("bios12.u2", 0x0000, 0x2000, CRC(c202a0e6) SHA1(a5b130a6d17c972d6c378cb2cd8113a4039631fe))
+ROM_END
+
+const rom_entry *side116_device::device_rom_region() const
+{
+ return ROM_NAME( side116 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// side116_device - constructor
+//-------------------------------------------------
+
+side116_device::side116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SIDE116, "Acculogic sIDE-1/16 IDE Disk Controller", tag, owner, clock, "side116", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_ata(*this, "ata"),
+ m_config(*this, "configuration"),
+ m_latch(0xff)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void side116_device::device_start()
+{
+ set_isa_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void side116_device::device_reset()
+{
+ // install option rom
+ if ((m_config->read() & 0x01) == 0x00)
+ {
+ switch ((m_config->read() >> 1) & 0x03)
+ {
+ case 0: m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "side116", "option"); break;
+ case 1: m_isa->install_rom(this, 0xd8000, 0xd9fff, 0, 0, "side116", "option"); break;
+ case 2: m_isa->install_rom(this, 0xcc000, 0xcdfff, 0, 0, "side116", "option"); break;
+ case 3: m_isa->install_rom(this, 0xdc000, 0xddfff, 0, 0, "side116", "option"); break;
+ }
+ }
+
+ // install io access
+ if ((m_config->read() & 0x20) == 0x20)
+ m_isa->install_device(0x360, 0x36f, 0, 0, read8_delegate(FUNC(side116_device::read), this), write8_delegate(FUNC(side116_device::write), this));
+}
+
+
+//**************************************************************************
+// IDE INTERFACE
+//**************************************************************************
+
+READ8_MEMBER( side116_device::read )
+{
+ UINT8 data;
+
+ if (offset == 0)
+ {
+ UINT16 ide_data = m_ata->read_cs0(space, 0, 0xffff);
+ data = ide_data & 0xff;
+ m_latch = ide_data >> 8;
+ }
+ else if (offset < 8)
+ {
+ data = m_ata->read_cs0(space, offset & 7, 0xff);
+ }
+ else if (offset == 8)
+ {
+ data = m_latch;
+ }
+ else
+ {
+ data = m_ata->read_cs1(space, offset & 7, 0xff);
+ }
+
+ return data;
+}
+
+WRITE8_MEMBER( side116_device::write )
+{
+ if (offset == 0)
+ {
+ UINT16 ide_data = (m_latch << 8) | data;
+ m_ata->write_cs0(space, 0, ide_data, 0xffff);
+ }
+ else if (offset < 8)
+ {
+ m_ata->write_cs0(space, offset & 7, data, 0xff);
+ }
+ else if (offset == 8)
+ {
+ m_latch = data;
+ }
+ else
+ {
+ m_ata->write_cs1(space, offset & 7, data, 0xff);
+ }
+}
+
+WRITE_LINE_MEMBER( side116_device::ide_interrupt )
+{
+ UINT8 level = m_config->read() & 0x18;
+
+ if (level == 0x08)
+ m_isa->irq2_w(state);
+ else if (level == 0x10)
+ m_isa->irq5_w(state);
+}
diff --git a/src/emu/bus/isa/side116.h b/src/emu/bus/isa/side116.h
new file mode 100644
index 00000000000..588d0b2aedb
--- /dev/null
+++ b/src/emu/bus/isa/side116.h
@@ -0,0 +1,60 @@
+/***************************************************************************
+
+ Acculogic sIDE-1/16
+
+ license: MAME, GPL-2.0+
+ copyright-holders: Dirk Best
+
+ IDE Disk Controller for IBM PC, XT and compatibles
+
+***************************************************************************/
+
+#pragma once
+
+#ifndef __ISA_SIDE116_H__
+#define __ISA_SIDE116_H__
+
+#include "emu.h"
+#include "machine/ataintf.h"
+#include "isa.h"
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> side116_device
+
+class side116_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ side116_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+ DECLARE_WRITE_LINE_MEMBER( ide_interrupt );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "side116"; }
+
+private:
+ required_device<ata_interface_device> m_ata;
+ required_ioport m_config;
+ UINT8 m_latch;
+};
+
+
+// device type definition
+extern const device_type ISA8_SIDE116;
+
+#endif
diff --git a/src/emu/bus/isa/ssi2001.c b/src/emu/bus/isa/ssi2001.c
new file mode 100644
index 00000000000..172f4f0be65
--- /dev/null
+++ b/src/emu/bus/isa/ssi2001.c
@@ -0,0 +1,37 @@
+// Innovation SSI-2001
+
+#include "ssi2001.h"
+
+const device_type ISA8_SSI2001 = &device_creator<ssi2001_device>;
+
+static MACHINE_CONFIG_FRAGMENT( ssi2001 )
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_SOUND_ADD("sid6581", MOS6581, XTAL_14_31818MHz/16)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
+ MCFG_PC_JOY_ADD("pc_joy")
+MACHINE_CONFIG_END
+
+machine_config_constructor ssi2001_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( ssi2001 );
+}
+
+ssi2001_device::ssi2001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SSI2001, "Innovation SSI-2001 Audio Adapter", tag, owner, clock, "ssi2001", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_joy(*this, "pc_joy"),
+ m_sid(*this, "sid6581")
+{
+}
+
+void ssi2001_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice<pc_joy_device>("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice<pc_joy_device>("pc_joy")));
+ m_isa->install_device(0x0280, 0x029F, 0, 0, read8_delegate(FUNC(mos6581_device::read), subdevice<mos6581_device>("sid6581")), write8_delegate(FUNC(mos6581_device::write), subdevice<mos6581_device>("sid6581")));
+}
+
+
+void ssi2001_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/ssi2001.h b/src/emu/bus/isa/ssi2001.h
new file mode 100644
index 00000000000..8454d63fd5b
--- /dev/null
+++ b/src/emu/bus/isa/ssi2001.h
@@ -0,0 +1,38 @@
+#ifndef __SSI2001__
+#define __SSI2001__
+
+#include "emu.h"
+#include "isa.h"
+#include "sound/mos6581.h"
+#include "bus/pc_joy/pc_joy.h"
+
+//*********************************************************************
+// TYPE DEFINITIONS
+//*********************************************************************
+
+// ====================> ssi2001_device
+
+class ssi2001_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ ssi2001_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ required_device<pc_joy_device> m_joy;
+ required_device<mos6581_device> m_sid;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+// device type definition
+
+extern const device_type ISA8_SSI2001;
+
+#endif
diff --git a/src/emu/bus/isa/stereo_fx.c b/src/emu/bus/isa/stereo_fx.c
new file mode 100644
index 00000000000..344fbadddb3
--- /dev/null
+++ b/src/emu/bus/isa/stereo_fx.c
@@ -0,0 +1,231 @@
+// ATI Stereo F/X
+//
+// TODO: UART is connected to MIDI port
+
+#include "stereo_fx.h"
+
+const device_type ISA8_STEREO_FX = &device_creator<stereo_fx_device>;
+
+READ8_MEMBER( stereo_fx_device::dev_dsp_data_r )
+{
+ m_data_in = false;
+ return m_in_byte;
+}
+
+WRITE8_MEMBER( stereo_fx_device::dev_dsp_data_w )
+{
+ m_data_out = true;
+ m_out_byte = data;
+}
+
+// port 1 is the left DAC but is written and read bitwise during capture
+READ8_MEMBER( stereo_fx_device::p1_r )
+{
+ return 0x80;
+}
+
+READ8_MEMBER( stereo_fx_device::p3_r )
+{
+ UINT8 ret = 0;
+
+ ret |= m_data_out << 2; // INT0
+ ret |= m_data_in << 3; // INT1
+ ret |= m_t0 << 4; // T0
+ ret |= m_t1 << 5; // T1
+ return ret;
+}
+
+WRITE8_MEMBER( stereo_fx_device::p3_w )
+{
+ m_t1 = (data & 0x20) >> 5;
+}
+
+WRITE8_MEMBER( stereo_fx_device::dev_host_irq_w )
+{
+ m_isa->irq5_w(1);
+}
+
+WRITE8_MEMBER( stereo_fx_device::raise_drq_w )
+{
+ m_isa->drq1_w(1);
+}
+
+/* port 0x20 - in ROM (usually) stored in RAM 0x22
+ * bit0 -
+ * bit1 -
+ * bit2 -
+ * bit3 -
+ * bit4 -
+ * bit5 -
+ * bit6 -
+ * bit7 -
+*/
+WRITE8_MEMBER( stereo_fx_device::port20_w )
+{
+ m_port20 = data;
+}
+
+/* port 0x00 - in ROM (usually) stored in RAM 0x21
+ * bit0 - bits 0-4 related to sample rate
+ * bit1 - are set to 0x09-0x1e
+ * bit2 -
+ * bit3 -
+ * bit4 -
+ * bit5 -
+ * bit6 -
+ * bit7 -
+*/
+WRITE8_MEMBER( stereo_fx_device::port00_w )
+{
+ m_port00 = data;
+}
+
+ROM_START( stereo_fx )
+ ROM_REGION( 0x8000, "stereo_fx_cpu", 0 )
+ ROM_LOAD("ati_stereo_fx.bin", 0x0000, 0x8000, CRC(1BEBFFA6) SHA1(e66c2619a6c05199554b5702d67877ae3799d415))
+ROM_END
+
+static ADDRESS_MAP_START(stereo_fx_io, AS_IO, 8, stereo_fx_device)
+ AM_RANGE(0xFF00, 0xFF00) AM_WRITE(port00_w)
+ AM_RANGE(0xFF10, 0xFF10) AM_DEVWRITE("dacr", dac_device, write_unsigned8)
+ AM_RANGE(0xFF20, 0xFF20) AM_WRITE(port20_w)
+ //AM_RANGE(0xFF30, 0xFF30) AM_WRITE() // used only on reset and undocumented cmd 0xc4
+ AM_RANGE(0xFF40, 0xFF40) AM_READWRITE(dev_dsp_data_r, dev_dsp_data_w)
+ AM_RANGE(0xFF50, 0xFF50) AM_WRITE(raise_drq_w)
+ AM_RANGE(0xFF60, 0xFF60) AM_WRITE(dev_host_irq_w)
+ AM_RANGE(MCS51_PORT_P1, MCS51_PORT_P1) AM_READ(p1_r) AM_DEVWRITE("dacl", dac_device, write_unsigned8)
+ AM_RANGE(MCS51_PORT_P3, MCS51_PORT_P3) AM_READWRITE(p3_r, p3_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START(stereo_fx_rom, AS_PROGRAM, 8, stereo_fx_device)
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ADDRESS_MAP_END
+
+static MACHINE_CONFIG_FRAGMENT( stereo_fx )
+ MCFG_CPU_ADD("stereo_fx_cpu", I80C31, XTAL_30MHz)
+ MCFG_CPU_IO_MAP(stereo_fx_io)
+ MCFG_CPU_PROGRAM_MAP(stereo_fx_rom)
+
+ MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
+ MCFG_SOUND_ADD("ym3812", YM3812, XTAL_3_579545MHz)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+ /* no CM/S support (empty sockets) */
+
+ MCFG_SOUND_ADD("dacl", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "lspeaker", 1.00)
+ MCFG_SOUND_ADD("dacr", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "rspeaker", 1.00)
+
+ MCFG_PC_JOY_ADD("pc_joy")
+MACHINE_CONFIG_END
+
+const rom_entry *stereo_fx_device::device_rom_region() const
+{
+ return ROM_NAME( stereo_fx );
+}
+
+machine_config_constructor stereo_fx_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( stereo_fx );
+}
+
+READ8_MEMBER( stereo_fx_device::dsp_data_r )
+{
+ m_data_out = false;
+ return m_out_byte;
+}
+
+WRITE8_MEMBER( stereo_fx_device::dsp_cmd_w )
+{
+ m_data_in = true;
+ m_in_byte = data;
+}
+
+UINT8 stereo_fx_device::dack_r(int line)
+{
+ m_data_out = false;
+ m_isa->drq1_w(0);
+ return m_out_byte;
+}
+
+void stereo_fx_device::dack_w(int line, UINT8 data)
+{
+ m_data_in = true;
+ m_isa->drq1_w(0);
+ m_in_byte = data;
+}
+
+WRITE8_MEMBER( stereo_fx_device::dsp_reset_w )
+{
+ device_reset();
+ m_cpu->set_input_line(INPUT_LINE_RESET, PULSE_LINE);
+}
+
+READ8_MEMBER( stereo_fx_device::dsp_wbuf_status_r )
+{
+ return m_data_in << 7;
+}
+
+READ8_MEMBER( stereo_fx_device::dsp_rbuf_status_r )
+{
+ m_isa->irq5_w(0);
+ return m_data_out << 7;
+}
+
+WRITE8_MEMBER( stereo_fx_device::invalid_w )
+{
+ logerror("stereo fx: invalid port write\n");
+}
+
+READ8_MEMBER( stereo_fx_device::invalid_r )
+{
+ logerror("stereo fx: invalid port read\n");
+ return 0xff;
+}
+
+stereo_fx_device::stereo_fx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_STEREO_FX, "ATI Stereo F/X Audio Adapter", tag, owner, clock, "stereo_fx", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_dacl(*this, "dacl"),
+ m_dacr(*this, "dacr"),
+ m_joy(*this, "pc_joy"),
+ m_cpu(*this, "stereo_fx_cpu")
+{
+ m_t1 = 0;
+}
+
+void stereo_fx_device::device_start()
+{
+ ym3812_device *ym3812 = subdevice<ym3812_device>("ym3812");
+ set_isa_device();
+
+ m_isa->install_device(0x0200, 0x0207, 0, 0, read8_delegate(FUNC(pc_joy_device::joy_port_r), subdevice<pc_joy_device>("pc_joy")), write8_delegate(FUNC(pc_joy_device::joy_port_w), subdevice<pc_joy_device>("pc_joy")));
+ m_isa->install_device(0x0226, 0x0227, 0, 0, read8_delegate(FUNC(stereo_fx_device::invalid_r), this), write8_delegate(FUNC(stereo_fx_device::dsp_reset_w), this));
+ m_isa->install_device(0x022a, 0x022b, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_data_r), this), write8_delegate(FUNC(stereo_fx_device::invalid_w), this) );
+ m_isa->install_device(0x022c, 0x022d, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_wbuf_status_r), this), write8_delegate(FUNC(stereo_fx_device::dsp_cmd_w), this) );
+ m_isa->install_device(0x022e, 0x022f, 0, 0, read8_delegate(FUNC(stereo_fx_device::dsp_rbuf_status_r), this), write8_delegate(FUNC(stereo_fx_device::invalid_w), this) );
+ m_isa->install_device(0x0388, 0x0389, 0, 0, read8_delegate(FUNC(ym3812_device::read), ym3812), write8_delegate(FUNC(ym3812_device::write), ym3812));
+ m_isa->install_device(0x0228, 0x0229, 0, 0, read8_delegate(FUNC(ym3812_device::read), ym3812), write8_delegate(FUNC(ym3812_device::write), ym3812));
+ m_timer = timer_alloc();
+ m_timer->adjust(attotime::from_hz(2000000), 0, attotime::from_hz(2000000));
+ m_isa->set_dma_channel(1, this, FALSE);
+}
+
+
+void stereo_fx_device::device_reset()
+{
+ m_isa->drq1_w(0);
+ m_isa->irq5_w(0);
+ m_data_out = false;
+ m_data_in = false;
+ m_port20 = 0;
+ m_port00 = 0;
+ m_t0 = CLEAR_LINE;
+}
+
+void stereo_fx_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ m_t0 = !m_t0;
+ m_cpu->set_input_line(MCS51_T0_LINE, m_t0);
+}
diff --git a/src/emu/bus/isa/stereo_fx.h b/src/emu/bus/isa/stereo_fx.h
new file mode 100644
index 00000000000..4910979463c
--- /dev/null
+++ b/src/emu/bus/isa/stereo_fx.h
@@ -0,0 +1,79 @@
+#ifndef __STEREO_FX__
+#define __STEREO_FX__
+
+#include "emu.h"
+#include "isa.h"
+#include "sound/dac.h"
+#include "bus/pc_joy/pc_joy.h"
+#include "cpu/mcs51/mcs51.h"
+#include "sound/3812intf.h"
+
+//*********************************************************************
+// TYPE DEFINITIONS
+//*********************************************************************
+
+// ====================> stereo_fx_device
+
+class stereo_fx_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ stereo_fx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ required_device<dac_device> m_dacl;
+ required_device<dac_device> m_dacr;
+ required_device<pc_joy_device> m_joy;
+ required_device<cpu_device> m_cpu;
+
+ // mcu ports
+ DECLARE_READ8_MEMBER( dev_dsp_data_r );
+ DECLARE_WRITE8_MEMBER( dev_dsp_data_w );
+ DECLARE_READ8_MEMBER( p1_r );
+ DECLARE_READ8_MEMBER( p3_r );
+ DECLARE_WRITE8_MEMBER( p3_w );
+ DECLARE_WRITE8_MEMBER( dev_host_irq_w );
+ DECLARE_WRITE8_MEMBER( raise_drq_w );
+ DECLARE_WRITE8_MEMBER( port20_w );
+ DECLARE_WRITE8_MEMBER( port00_w );
+
+ // host ports
+ DECLARE_READ8_MEMBER( dsp_data_r );
+ DECLARE_WRITE8_MEMBER( dsp_cmd_w );
+ DECLARE_WRITE8_MEMBER( dsp_reset_w );
+ DECLARE_READ8_MEMBER( dsp_wbuf_status_r );
+ DECLARE_READ8_MEMBER( dsp_rbuf_status_r );
+ DECLARE_READ8_MEMBER( invalid_r );
+ DECLARE_WRITE8_MEMBER( invalid_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ UINT8 dack_r(int line);
+ void dack_w(int line, UINT8 data);
+private:
+ // internal state
+ bool m_data_in;
+ UINT8 m_in_byte;
+ bool m_data_out;
+ UINT8 m_out_byte;
+
+ UINT8 m_port20;
+ UINT8 m_port00;
+ emu_timer *m_timer;
+ UINT8 m_t0;
+ UINT8 m_t1;
+};
+
+// device type definition
+
+extern const device_type ISA8_STEREO_FX;
+
+#endif
diff --git a/src/emu/bus/isa/svga_cirrus.c b/src/emu/bus/isa/svga_cirrus.c
new file mode 100644
index 00000000000..1c766ee6511
--- /dev/null
+++ b/src/emu/bus/isa/svga_cirrus.c
@@ -0,0 +1,93 @@
+/***************************************************************************
+
+ ISA SVGA Cirrus Logic wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "svga_cirrus.h"
+#include "video/pc_vga.h"
+
+ROM_START( dm_clgd5430 )
+ ROM_REGION(0x8000,"dm_clgd5430", 0)
+ ROM_LOAD("speedstar_pro_se_v1.00.u2", 0x00000, 0x8000, CRC(ed79572c) SHA1(15131e2b2db7a34971083a250e4a21ab7bd64a9d) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SVGA_CIRRUS = &device_creator<isa8_svga_cirrus_device>;
+
+static MACHINE_CONFIG_FRAGMENT( vga_cirrus )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_DEVICE("vga", cirrus_vga_device, screen_update)
+
+ MCFG_PALETTE_ADD("palette", 0x100)
+
+ MCFG_DEVICE_ADD("vga", CIRRUS_VGA, 0)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_svga_cirrus_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_cirrus );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_svga_cirrus_device::device_rom_region() const
+{
+ return ROM_NAME( dm_clgd5430 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_svga_cirrus_device::isa8_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SVGA_CIRRUS, "Diamond Multimedia Graphics Card", tag, owner, clock, "dm_clgd5430", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa8_svga_cirrus_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa8_svga_cirrus_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<cirrus_vga_device>("vga");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "dm_clgd5430");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(cirrus_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(cirrus_vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(cirrus_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(cirrus_vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(cirrus_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(cirrus_vga_device::port_03d0_w),m_vga));
+// m_isa->install_device(0x9ae8, 0x9aeb, 0, 0, read8_delegate(FUNC(cirrus_vga_device::s3_port_9ae8_r),m_vga), write8_delegate(FUNC(cirrus_vga_device::s3_port_9ae8_w),m_vga));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(cirrus_vga_device::mem_r),m_vga), write8_delegate(FUNC(cirrus_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_svga_cirrus_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/svga_cirrus.h b/src/emu/bus/isa/svga_cirrus.h
new file mode 100644
index 00000000000..099c00eeb6c
--- /dev/null
+++ b/src/emu/bus/isa/svga_cirrus.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __ISA_SVGA_CIRRUS_H__
+#define __ISA_SVGA_CIRRUS_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/pc_vga.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_svga_cirrus_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_svga_cirrus_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ cirrus_vga_device *m_vga;
+};
+
+
+// device type definition
+extern const device_type ISA8_SVGA_CIRRUS;
+
+#endif /* __ISA_VGA_H__ */
diff --git a/src/emu/bus/isa/svga_s3.c b/src/emu/bus/isa/svga_s3.c
new file mode 100644
index 00000000000..5494ae4ccb0
--- /dev/null
+++ b/src/emu/bus/isa/svga_s3.c
@@ -0,0 +1,275 @@
+/***************************************************************************
+
+ ISA SVGA S3 wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "svga_s3.h"
+
+ROM_START( s3_764 )
+ ROM_REGION(0x8000,"s3_764", 0)
+ ROM_LOAD("s3_764.bin", 0x00000, 0x8000, CRC(4f10aac7) SHA1(c77b3f11cc15679121314823588887dd547cd715) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_SVGA_S3 = &device_creator<isa16_svga_s3_device>;
+
+
+static MACHINE_CONFIG_FRAGMENT( vga_s3 )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_DEVICE("vga", s3_vga_device, screen_update)
+
+ MCFG_PALETTE_ADD("palette", 0x100)
+
+ MCFG_DEVICE_ADD("vga", S3_VGA, 0)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_svga_s3_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_s3 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa16_svga_s3_device::device_rom_region() const
+{
+ return ROM_NAME( s3_764 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_vga_device - constructor
+//-------------------------------------------------
+
+isa16_svga_s3_device::isa16_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA16_SVGA_S3, "Number Nine 9FX Vision 330 (S3 764) Graphics Card", tag, owner, clock, "s3_764", __FILE__),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa16_svga_s3_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa16_svga_s3_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<s3_vga_device>("vga");
+ m_8514 = subdevice<ibm8514a_device>("vga:8514a");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3_764");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3_vga_device::port_03d0_w),m_vga));
+ m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_currenty_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_currenty_w),m_8514));
+ m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_currentx_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_currentx_w),m_8514));
+ m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_desty_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_desty_w),m_8514));
+ m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_destx_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_destx_w),m_8514));
+ m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_line_error_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_line_error_w),m_8514));
+ m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_width_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_width_w),m_8514));
+ m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_gpstatus_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_cmd_w),m_8514));
+ m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_ssv_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_ssv_w),m_8514));
+ m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_bgcolour_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_bgcolour_w),m_8514));
+ m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_fgcolour_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_fgcolour_w),m_8514));
+ m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_w),m_8514));
+ m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_w),m_8514));
+ m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_backmix_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_backmix_w),m_8514));
+ m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_foremix_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_foremix_w),m_8514));
+ m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_multifunc_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_multifunc_w),m_8514));
+ m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_pixel_xfer_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_pixel_xfer_w),m_8514));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_svga_s3_device::device_reset()
+{
+}
+
+
+/*
+ * S3 Virge 2D/3D accelerator
+ */
+
+ROM_START( s3virge )
+ ROM_REGION(0x8000,"s3virge", 0)
+ ROM_LOAD("s3virge.bin", 0x00000, 0x8000, CRC(a7983a85) SHA1(e885371816d3237f7badd57ccd602cd863c9c9f8) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_S3VIRGE = &device_creator<isa16_s3virge_device>;
+
+
+static MACHINE_CONFIG_FRAGMENT( vga_s3virge )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_DEVICE("vga", s3virge_vga_device, screen_update)
+
+ MCFG_PALETTE_ADD("palette", 0x100)
+
+ MCFG_DEVICE_ADD("vga", S3VIRGE, 0)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_s3virge_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_s3virge );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa16_s3virge_device::device_rom_region() const
+{
+ return ROM_NAME( s3virge );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_vga_device - constructor
+//-------------------------------------------------
+
+isa16_s3virge_device::isa16_s3virge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA16_S3VIRGE, "S3 ViRGE Graphics Card", tag, owner, clock, "s3virge", __FILE__),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa16_s3virge_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa16_s3virge_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<s3virge_vga_device>("vga");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3virge");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03d0_w),m_vga));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3virge_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_s3virge_device::device_reset()
+{
+}
+
+/*
+ * S3 ViRGE/DX
+ */
+
+ROM_START( s3virgedx )
+ ROM_REGION(0x8000,"s3virgedx", 0)
+ ROM_LOAD("s3virgedx.bin", 0x00000, 0x8000, CRC(0da83bd3) SHA1(228a2d644e1732cb5a2eb1291608c7050cf39229) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_S3VIRGEDX = &device_creator<isa16_s3virgedx_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_s3virgedx_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_s3virge );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa16_s3virgedx_device::device_rom_region() const
+{
+ return ROM_NAME( s3virgedx );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa16_vga_device - constructor
+//-------------------------------------------------
+
+isa16_s3virgedx_device::isa16_s3virgedx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA16_S3VIRGEDX, "S3 ViRGE/DX Graphics Card", tag, owner, clock, "s3virgedx", __FILE__),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa16_s3virgedx_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa16_s3virgedx_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<s3virge_vga_device>("vga");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "svga", "s3virgedx");
+
+ m_isa->install_device(0x03b0, 0x03bf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x03c0, 0x03cf, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x03d0, 0x03df, 0, 0, read8_delegate(FUNC(s3virge_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::port_03d0_w),m_vga));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(s3virge_vga_device::mem_r),m_vga), write8_delegate(FUNC(s3virge_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_s3virgedx_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/svga_s3.h b/src/emu/bus/isa/svga_s3.h
new file mode 100644
index 00000000000..bd01043e3c5
--- /dev/null
+++ b/src/emu/bus/isa/svga_s3.h
@@ -0,0 +1,87 @@
+#pragma once
+
+#ifndef __ISA_SVGA_S3_H__
+#define __ISA_SVGA_S3_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/pc_vga.h"
+#include "s3virge.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa16_vga_device
+
+class isa16_svga_s3_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_svga_s3_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ s3_vga_device *m_vga;
+ ibm8514a_device *m_8514;
+};
+
+class isa16_s3virge_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_s3virge_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ s3virge_vga_device *m_vga;
+};
+
+class isa16_s3virgedx_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_s3virgedx_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ s3virge_vga_device *m_vga;
+};
+
+
+// device type definition
+extern const device_type ISA16_SVGA_S3;
+extern const device_type ISA16_S3VIRGE;
+extern const device_type ISA16_S3VIRGEDX;
+
+#endif /* __ISA_VGA_H__ */
diff --git a/src/emu/bus/isa/svga_tseng.c b/src/emu/bus/isa/svga_tseng.c
new file mode 100644
index 00000000000..58bdf6fff8d
--- /dev/null
+++ b/src/emu/bus/isa/svga_tseng.c
@@ -0,0 +1,92 @@
+/***************************************************************************
+
+ ISA SVGA Tseng wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "svga_tseng.h"
+#include "video/pc_vga.h"
+
+ROM_START( et4000 )
+ ROM_REGION(0x8000,"et4000", 0)
+ ROM_LOAD("et4000.bin", 0x00000, 0x8000, CRC(f1e817a8) SHA1(945d405b0fb4b8f26830d495881f8587d90e5ef9) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_SVGA_ET4K = &device_creator<isa8_svga_et4k_device>;
+
+
+static MACHINE_CONFIG_FRAGMENT( vga_tseng )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_DEVICE("vga", tseng_vga_device, screen_update)
+
+ MCFG_PALETTE_ADD("palette", 0x100)
+
+ MCFG_DEVICE_ADD("vga", TSENG_VGA, 0)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_svga_et4k_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_tseng );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_svga_et4k_device::device_rom_region() const
+{
+ return ROM_NAME( et4000 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_svga_et4k_device::isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_SVGA_ET4K, "SVGA Tseng ET4000 Graphics Card", tag, owner, clock, "et4000", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa8_svga_et4k_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa8_svga_et4k_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<tseng_vga_device>("vga");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "et4000", "et4000");
+
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(tseng_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(tseng_vga_device::port_03d0_w),m_vga));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(tseng_vga_device::mem_r),m_vga), write8_delegate(FUNC(tseng_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_svga_et4k_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/svga_tseng.h b/src/emu/bus/isa/svga_tseng.h
new file mode 100644
index 00000000000..ecaf8982e55
--- /dev/null
+++ b/src/emu/bus/isa/svga_tseng.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __ISA_SVGA_ET4K_H__
+#define __ISA_SVGA_ET4K_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/pc_vga.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_svga_et4k_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_svga_et4k_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ tseng_vga_device *m_vga;
+};
+
+
+// device type definition
+extern const device_type ISA8_SVGA_ET4K;
+
+#endif /* __ISA_SVGA_ET4K_H__ */
diff --git a/src/emu/bus/isa/vga.c b/src/emu/bus/isa/vga.c
new file mode 100644
index 00000000000..4f04d6bc166
--- /dev/null
+++ b/src/emu/bus/isa/vga.c
@@ -0,0 +1,82 @@
+/***************************************************************************
+
+ ISA VGA wrapper
+
+***************************************************************************/
+
+#include "emu.h"
+#include "vga.h"
+#include "video/pc_vga.h"
+
+ROM_START( ibm_vga )
+ ROM_REGION(0x8000,"ibm_vga", 0)
+ ROM_LOAD("ibm-vga.bin", 0x00000, 0x8000, BAD_DUMP CRC(74e3fadb) SHA1(dce6491424f1726203776dfae9a967a98a4ba7b5) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_VGA = &device_creator<isa8_vga_device>;
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa8_vga_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pcvideo_vga );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_vga_device::device_rom_region() const
+{
+ return ROM_NAME( ibm_vga );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa8_vga_device::isa8_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA8_VGA, "IBM VGA Graphics Card", tag, owner, clock, "ibm_vga", __FILE__),
+ device_isa8_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER( isa8_vga_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa8_vga_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<vga_device>("vga");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "ibm_vga", "ibm_vga");
+
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(vga_device::port_03d0_w),m_vga));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(vga_device::mem_r),m_vga), write8_delegate(FUNC(vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_vga_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/vga.h b/src/emu/bus/isa/vga.h
new file mode 100644
index 00000000000..7614bbdb0ff
--- /dev/null
+++ b/src/emu/bus/isa/vga.h
@@ -0,0 +1,41 @@
+#pragma once
+
+#ifndef __ISA_VGA_H__
+#define __ISA_VGA_H__
+
+#include "emu.h"
+#include "isa.h"
+#include "video/pc_vga.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa8_vga_device
+
+class isa8_vga_device :
+ public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_vga_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ vga_device *m_vga;
+};
+
+
+// device type definition
+extern const device_type ISA8_VGA;
+
+#endif /* __ISA_VGA_H__ */
diff --git a/src/emu/bus/isa/vga_ati.c b/src/emu/bus/isa/vga_ati.c
new file mode 100644
index 00000000000..4637a99ac14
--- /dev/null
+++ b/src/emu/bus/isa/vga_ati.c
@@ -0,0 +1,133 @@
+/*
+ * isa_vga_ati.c
+ *
+ * Implementation of the ATi Graphics Ultra ISA Video card
+ * - Uses ATi 28800-6 (VGA Wonder) and ATi 38800-1 (Mach8, 8514/A clone)
+ *
+ * Created on: 9/09/2012
+ */
+
+#include "emu.h"
+#include "vga_ati.h"
+#include "video/pc_vga.h"
+
+ROM_START( gfxultra )
+ ROM_REGION(0x8000,"gfxultra", 0)
+ ROM_LOAD("113-11504-002.bin", 0x00000, 0x8000, CRC(f498b36a) SHA1(117cfc972ce4645538ba7262222d8ff38bc2c58c) )
+ ROM_IGNORE( 0x8000 )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA16_VGA_GFXULTRA = &device_creator<isa16_vga_gfxultra_device>;
+
+static MACHINE_CONFIG_FRAGMENT( vga_ati )
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(XTAL_25_1748MHz,900,0,640,526,0,480)
+ MCFG_SCREEN_UPDATE_DEVICE("vga", ati_vga_device, screen_update)
+
+ MCFG_PALETTE_ADD("palette", 0x100)
+
+ MCFG_DEVICE_ADD("vga", ATI_VGA, 0)
+MACHINE_CONFIG_END
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor isa16_vga_gfxultra_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( vga_ati );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa16_vga_gfxultra_device::device_rom_region() const
+{
+ return ROM_NAME( gfxultra );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_vga_device - constructor
+//-------------------------------------------------
+
+isa16_vga_gfxultra_device::isa16_vga_gfxultra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, ISA16_VGA_GFXULTRA, "ATi Graphics Ultra Graphics Card", tag, owner, clock, "gfxultra", __FILE__),
+ device_isa16_card_interface(mconfig, *this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+READ8_MEMBER(isa16_vga_gfxultra_device::input_port_0_r ) { return 0xff; } //return space.machine().root_device().ioport("IN0")->read(); }
+
+void isa16_vga_gfxultra_device::device_start()
+{
+ set_isa_device();
+
+ m_vga = subdevice<ati_vga_device>("vga");
+ m_8514 = subdevice<mach8_device>("vga:8514a");
+
+ m_isa->install_rom(this, 0xc0000, 0xc7fff, 0, 0, "vga", "gfxultra");
+
+ m_isa->install_device(0x1ce, 0x1cf, 0, 0, read8_delegate(FUNC(ati_vga_device::ati_port_ext_r),m_vga), write8_delegate(FUNC(ati_vga_device::ati_port_ext_w),m_vga));
+ m_isa->install16_device(0x2e8, 0x2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_status_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_htotal_w),m_8514));
+ m_isa->install_device(0x3b0, 0x3bf, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03b0_r),m_vga), write8_delegate(FUNC(vga_device::port_03b0_w),m_vga));
+ m_isa->install_device(0x3c0, 0x3cf, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03c0_r),m_vga), write8_delegate(FUNC(vga_device::port_03c0_w),m_vga));
+ m_isa->install_device(0x3d0, 0x3df, 0, 0, read8_delegate(FUNC(ati_vga_device::port_03d0_r),m_vga), write8_delegate(FUNC(vga_device::port_03d0_w),m_vga));
+ m_isa->install16_device(0x12e8, 0x12eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vtotal_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vtotal_w),m_8514));
+ m_isa->install16_device(0x12ec, 0x12ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_config1_r),m_8514), write16_delegate());
+ m_isa->install16_device(0x16e8, 0x16eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vdisp_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vdisp_w),m_8514));
+ m_isa->install16_device(0x16ec, 0x16ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_config2_r),m_8514), write16_delegate());
+ m_isa->install16_device(0x1ae8, 0x1aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_vsync_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_vsync_w),m_8514));
+ m_isa->install16_device(0x26e8, 0x26eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_htotal_r),m_8514),write16_delegate());
+ m_isa->install16_device(0x2ee8, 0x2eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_subcontrol_r),m_8514),write16_delegate());
+ m_isa->install16_device(0x42e8, 0x42eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_substatus_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_subcontrol_w),m_8514));
+ m_isa->install16_device(0x52e8, 0x52eb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec0_w),m_8514));
+ m_isa->install16_device(0x52ec, 0x52ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_scratch0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_scratch0_w),m_8514));
+ m_isa->install16_device(0x56e8, 0x56eb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec1_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec1_w),m_8514));
+ m_isa->install16_device(0x56ec, 0x56ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_scratch0_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_scratch0_w),m_8514));
+ m_isa->install16_device(0x5ae8, 0x5aeb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec2_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec2_w),m_8514));
+ m_isa->install16_device(0x5ee8, 0x5eeb, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ec3_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ec3_w),m_8514));
+ m_isa->install16_device(0x82e8, 0x82eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_currenty_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_currenty_w),m_8514));
+ m_isa->install16_device(0x86e8, 0x86eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_currentx_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_currentx_w),m_8514));
+ m_isa->install16_device(0x8ae8, 0x8aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_desty_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_desty_w),m_8514));
+ m_isa->install16_device(0x8ee8, 0x8eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_destx_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_destx_w),m_8514));
+ m_isa->install16_device(0x92e8, 0x92eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_line_error_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_line_error_w),m_8514));
+ m_isa->install16_device(0x96e8, 0x96eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_width_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_width_w),m_8514));
+ m_isa->install16_device(0x96ec, 0x96ef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_bresenham_count_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_bresenham_count_w),m_8514));
+ m_isa->install16_device(0x9ae8, 0x9aeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_gpstatus_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_cmd_w),m_8514));
+ m_isa->install16_device(0x9aec, 0x9aef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_ext_fifo_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_linedraw_index_w),m_8514));
+ m_isa->install16_device(0x9ee8, 0x9eeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_ssv_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_ssv_w),m_8514));
+ m_isa->install16_device(0xa2e8, 0xa2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_bgcolour_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_bgcolour_w),m_8514));
+ m_isa->install16_device(0xa6e8, 0xa6eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_fgcolour_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_fgcolour_w),m_8514));
+ m_isa->install16_device(0xaae8, 0xaaeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_write_mask_w),m_8514));
+ m_isa->install16_device(0xaee8, 0xaeeb, 0, 0, read16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_r),m_8514), write16_delegate(FUNC(ibm8514a_device::ibm8514_read_mask_w),m_8514));
+ m_isa->install16_device(0xb6e8, 0xb6eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_backmix_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_backmix_w),m_8514));
+ m_isa->install16_device(0xbae8, 0xbaeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_foremix_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_foremix_w),m_8514));
+ m_isa->install16_device(0xbee8, 0xbeeb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_multifunc_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_multifunc_w),m_8514));
+ m_isa->install16_device(0xe2e8, 0xe2eb, 0, 0, read16_delegate(FUNC(mach8_device::ibm8514_pixel_xfer_r),m_8514), write16_delegate(FUNC(mach8_device::ibm8514_pixel_xfer_w),m_8514));
+ m_isa->install16_device(0xdaec, 0xdaef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_sourcex_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ext_leftscissor_w),m_8514));
+ m_isa->install16_device(0xdeec, 0xdeef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_sourcey_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_ext_topscissor_w),m_8514));
+ m_isa->install16_device(0xfeec, 0xfeef, 0, 0, read16_delegate(FUNC(mach8_device::mach8_linedraw_r),m_8514), write16_delegate(FUNC(mach8_device::mach8_linedraw_w),m_8514));
+
+ m_isa->install_memory(0xa0000, 0xbffff, 0, 0, read8_delegate(FUNC(ati_vga_device::mem_r),m_vga), write8_delegate(FUNC(ati_vga_device::mem_w),m_vga));
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa16_vga_gfxultra_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/vga_ati.h b/src/emu/bus/isa/vga_ati.h
new file mode 100644
index 00000000000..4f7161cc6a1
--- /dev/null
+++ b/src/emu/bus/isa/vga_ati.h
@@ -0,0 +1,50 @@
+/*
+ * isa_vga_ati.h
+ *
+ * Header for ATi Graphics Ultra ISA video card
+ *
+ * Created on: 9/09/2012
+ */
+#pragma once
+
+#ifndef ISA_VGA_ATI_H_
+#define ISA_VGA_ATI_H_
+
+#include "emu.h"
+#include "isa.h"
+#include "video/pc_vga.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa16_vga_device
+
+class isa16_vga_gfxultra_device :
+ public device_t,
+ public device_isa16_card_interface
+{
+public:
+ // construction/destruction
+ isa16_vga_gfxultra_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(input_port_0_r);
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+private:
+ ati_vga_device *m_vga;
+ mach8_device *m_8514;
+};
+
+
+// device type definition
+extern const device_type ISA16_VGA_GFXULTRA;
+
+
+#endif /* ISA_VGA_ATI_H_ */
diff --git a/src/emu/bus/isa/wd1002a_wx1.c b/src/emu/bus/isa/wd1002a_wx1.c
new file mode 100644
index 00000000000..449ab6ce5c6
--- /dev/null
+++ b/src/emu/bus/isa/wd1002a_wx1.c
@@ -0,0 +1,73 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Western Digital WD1002A-WX1 Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "wd1002a_wx1.h"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ISA8_WD1002A_WX1 = &device_creator<isa8_wd1002a_wx1_device>;
+
+
+//-------------------------------------------------
+// ROM( wd1002a_wx1 )
+//-------------------------------------------------
+
+ROM_START( wd1002a_wx1 )
+ ROM_REGION( 0x2000, "wd1002a_wx1", 0 )
+ ROM_LOAD( "600693-001 type 5.u12", 0x0000, 0x2000, CRC(f3daf85f) SHA1(3bd29538832d3084cbddeec92593988772755283) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *isa8_wd1002a_wx1_device::device_rom_region() const
+{
+ return ROM_NAME( wd1002a_wx1 );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// isa8_wd1002a_wx1_device - constructor
+//-------------------------------------------------
+
+isa8_wd1002a_wx1_device::isa8_wd1002a_wx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_WD1002A_WX1, "WD1002A-WX1", tag, owner, clock, "wd1002a_wx1", __FILE__),
+ device_isa8_card_interface( mconfig, *this )
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void isa8_wd1002a_wx1_device::device_start()
+{
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void isa8_wd1002a_wx1_device::device_reset()
+{
+}
diff --git a/src/emu/bus/isa/wd1002a_wx1.h b/src/emu/bus/isa/wd1002a_wx1.h
new file mode 100644
index 00000000000..e0cb75f18b6
--- /dev/null
+++ b/src/emu/bus/isa/wd1002a_wx1.h
@@ -0,0 +1,49 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Western Digital WD1002A-WX1 Winchester Disk Controller emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ISA_WD1002A_WX1__
+#define __ISA_WD1002A_WX1__
+
+#include "emu.h"
+#include "isa.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> isa16_ide_device
+
+class isa8_wd1002a_wx1_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ isa8_wd1002a_wx1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual const rom_entry *device_rom_region() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+};
+
+
+// device type definition
+extern const device_type ISA8_WD1002A_WX1;
+
+
+#endif
diff --git a/src/emu/bus/isa/wdxt_gen.c b/src/emu/bus/isa/wdxt_gen.c
new file mode 100644
index 00000000000..3bd03013eae
--- /dev/null
+++ b/src/emu/bus/isa/wdxt_gen.c
@@ -0,0 +1,400 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+/*
+
+PCB Layout
+----------
+
+ASSY 61-000222-00
+
+|-------------------------------------------|
+| CN2 CN1 |
+| CN3 7406 TMM2016 |
+| LS38 LS14 |
+| MC3486 |
+| WD1015 WD11C00 |
+| 33.04MHz |
+| MC3487 |
+| WD2010 LS244 |
+| WD10C20 |
+| LS260 LS13 ROM |
+| |
+|---| |---|
+ |-----------------------------------|
+
+Notes:
+ All IC's shown.
+
+ ROM - Toshiba TMM2464AP 8Kx8 ROM "3"
+ TMM2016 - Toshiba TMM2016BP-10 2Kx8 SRAM
+ WD1015 - Western Digital WD1015-PL-54-02 Buffer Manager Control Processor
+ WD11C00 - Western Digital WD11C00L-JT-17-02 PC/XT Host Interface Logic Device
+ WD10C20 - Western Digital WD10C20B-PH-05-05 Self-Adjusting Data Separator
+ WD2010 - Western Digital WD2010A-PL-05-02 Winchester Disk Controller
+ CN1 - 2x17 pin PCB header, control
+ CN2 - 2x10 pin PCB header, drive 0 data
+ CN3 - 2x10 pin PCB header, drive 1 data
+
+*/
+
+#include "wdxt_gen.h"
+
+
+
+//**************************************************************************
+// MACROS / CONSTANTS
+//**************************************************************************
+
+#define WD1015_TAG "u6"
+#define WD11C00_17_TAG "u11"
+#define WD2010A_TAG "u7"
+
+
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type ISA8_WDXT_GEN = &device_creator<wdxt_gen_device>;
+
+
+//-------------------------------------------------
+// ROM( wdxt_gen )
+//-------------------------------------------------
+
+ROM_START( wdxt_gen )
+ ROM_REGION( 0x800, WD1015_TAG, 0 )
+ ROM_LOAD( "wd1015-pl-54-02.u6", 0x000, 0x800, CRC(116e0608) SHA1(bcbd6b39c5a7e16e3bae9372b53d54d6761ba6bc) )
+
+ ROM_REGION( 0x2000, "hdc", 0 )
+ ROM_LOAD( "3.u13", 0x0000, 0x2000, CRC(fbcb5f91) SHA1(8c22bd664177eb6126f3011eda8c5655fffe0ef2) )
+ROM_END
+
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *wdxt_gen_device::device_rom_region() const
+{
+ return ROM_NAME( wdxt_gen );
+}
+
+
+//-------------------------------------------------
+// ADDRESS_MAP( wd1015_io )
+//-------------------------------------------------
+
+static ADDRESS_MAP_START( wd1015_io, AS_IO, 8, wdxt_gen_device )
+ AM_RANGE(0x00, 0xff) AM_DEVREADWRITE(WD11C00_17_TAG, wd11c00_17_device, read, write)
+ AM_RANGE(MCS48_PORT_T0, MCS48_PORT_T0) AM_READ(wd1015_t0_r)
+ AM_RANGE(MCS48_PORT_T1, MCS48_PORT_T1) AM_READ(wd1015_t1_r)
+ AM_RANGE(MCS48_PORT_P1, MCS48_PORT_P1) AM_READWRITE(wd1015_p1_r, wd1015_p1_w)
+ AM_RANGE(MCS48_PORT_P2, MCS48_PORT_P2) AM_READWRITE(wd1015_p2_r, wd1015_p2_w)
+ADDRESS_MAP_END
+
+
+//-------------------------------------------------
+// WD11C00_17_INTERFACE( host_intf )
+//-------------------------------------------------
+
+WRITE_LINE_MEMBER( wdxt_gen_device::irq5_w )
+{
+ m_isa->irq5_w(state);
+}
+
+WRITE_LINE_MEMBER( wdxt_gen_device::drq3_w )
+{
+ m_isa->drq3_w(state);
+}
+
+WRITE_LINE_MEMBER( wdxt_gen_device::mr_w )
+{
+ if (state == ASSERT_LINE)
+ {
+ device_reset();
+ }
+}
+
+READ8_MEMBER( wdxt_gen_device::rd322_r )
+{
+ return 0xff;
+}
+
+READ8_MEMBER( wdxt_gen_device::ram_r )
+{
+ return m_ram[offset];
+}
+
+WRITE8_MEMBER( wdxt_gen_device::ram_w )
+{
+ m_ram[offset] = data;
+}
+
+static WD11C00_17_INTERFACE( host_intf )
+{
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, irq5_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, drq3_w),
+ DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, mr_w),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_CPU_INPUT_LINE(WD1015_TAG, MCS48_INPUT_IRQ),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, rd322_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_r),
+ DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, wdxt_gen_device, ram_w),
+ DEVCB_DEVICE_MEMBER(WD2010A_TAG, wd2010_device, read),
+ DEVCB_DEVICE_MEMBER(WD2010A_TAG, wd2010_device, write)
+};
+
+
+//-------------------------------------------------
+// WD2010_INTERFACE( hdc_intf )
+//-------------------------------------------------
+
+static WD2010_INTERFACE( hdc_intf )
+{
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_LINE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, clct_w),
+ DEVCB_DEVICE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, read),
+ DEVCB_DEVICE_MEMBER(WD11C00_17_TAG, wd11c00_17_device, write),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC,
+ DEVCB_LINE_VCC
+};
+
+
+//-------------------------------------------------
+// MACHINE_DRIVER( wdxt_gen )
+//-------------------------------------------------
+
+static MACHINE_CONFIG_FRAGMENT( wdxt_gen )
+ MCFG_CPU_ADD(WD1015_TAG, I8049, 5000000)
+ MCFG_CPU_IO_MAP(wd1015_io)
+
+ MCFG_WD11C00_17_ADD(WD11C00_17_TAG, 5000000, host_intf)
+ MCFG_WD2010_ADD(WD2010A_TAG, 5000000, hdc_intf)
+
+ MCFG_HARDDISK_ADD("hard0")
+ MCFG_HARDDISK_ADD("hard1")
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor wdxt_gen_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( wdxt_gen );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// wdxt_gen_device - constructor
+//-------------------------------------------------
+
+wdxt_gen_device::wdxt_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_WDXT_GEN, "Western Digital WDXT-GEN (Amstrad PC1512/1640)", tag, owner, clock, "wdxt_gen", __FILE__),
+ device_isa8_card_interface(mconfig, *this),
+ m_maincpu(*this, WD1015_TAG),
+ m_host(*this, WD11C00_17_TAG),
+ m_hdc(*this, WD2010A_TAG)
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void wdxt_gen_device::device_start()
+{
+ set_isa_device();
+ m_isa->install_rom(this, 0xc8000, 0xc9fff, 0, 0, "hdc", "hdc");
+ m_isa->install_device(0x0320, 0x0323, 0, 0, READ8_DEVICE_DELEGATE(m_host, wd11c00_17_device, io_r), WRITE8_DEVICE_DELEGATE(m_host, wd11c00_17_device, io_w));
+ m_isa->set_dma_channel(3, this, FALSE);
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void wdxt_gen_device::device_reset()
+{
+ m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
+ m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
+}
+
+
+//-------------------------------------------------
+// dack_r -
+//-------------------------------------------------
+
+UINT8 wdxt_gen_device::dack_r(int line)
+{
+ return m_host->dack_r();
+}
+
+
+//-------------------------------------------------
+// dack_w -
+//-------------------------------------------------
+
+void wdxt_gen_device::dack_w(int line, UINT8 data)
+{
+ m_host->dack_w(data);
+}
+
+//-------------------------------------------------
+// wd1015_t0_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_t0_r )
+{
+ return m_host->busy_r();
+}
+
+
+//-------------------------------------------------
+// wd1015_t1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_t1_r )
+{
+ return 0; // TODO
+}
+
+
+//-------------------------------------------------
+// wd1015_p1_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_p1_r )
+{
+ /*
+
+ bit description
+
+ P10
+ P11
+ P12
+ P13
+ P14
+ P15
+ P16
+ P17
+
+ */
+
+ UINT8 data = 0;
+
+ logerror("%s P1 read %02x\n", machine().describe_context(), data);
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// wd1015_p1_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_p1_w )
+{
+ /*
+
+ bit description
+
+ P10 HSEL0
+ P11 HSEL1
+ P12 HSEL2
+ P13 _DSEL0
+ P14 _DSEL1
+ P15
+ P16 IREQ
+ P17 _DIRIN
+
+ */
+
+ logerror("%s P1 %02x\n", machine().describe_context(), data);
+
+ m_host->ireq_w(BIT(data, 6));
+}
+
+
+//-------------------------------------------------
+// wd1015_p2_r -
+//-------------------------------------------------
+
+READ8_MEMBER( wdxt_gen_device::wd1015_p2_r )
+{
+ /*
+
+ bit description
+
+ P20
+ P21
+ P22
+ P23
+ P24
+ P25
+ P26 TK000
+ P27 ECC NOT 0
+
+ */
+
+ UINT8 data = 0x40;
+
+ data |= m_host->ecc_not_0_r() << 7;
+
+ logerror("%s P2 read %02x\n", machine().describe_context(), data);
+
+ return data;
+}
+
+
+//-------------------------------------------------
+// wd1015_p2_w -
+//-------------------------------------------------
+
+WRITE8_MEMBER( wdxt_gen_device::wd1015_p2_w )
+{
+ /*
+
+ bit description
+
+ P20 STEP
+ P21 ?
+ P22 MODE?
+ P23 ?
+ P24 ?
+ P25 ?
+ P26
+ P27
+
+ */
+
+ logerror("%s P2 %02x\n", machine().describe_context(), data);
+
+ m_host->mode_w(BIT(data, 2));
+}
diff --git a/src/emu/bus/isa/wdxt_gen.h b/src/emu/bus/isa/wdxt_gen.h
new file mode 100644
index 00000000000..b5019cd8800
--- /dev/null
+++ b/src/emu/bus/isa/wdxt_gen.h
@@ -0,0 +1,88 @@
+// license:BSD-3-Clause
+// copyright-holders:Curt Coder
+/**********************************************************************
+
+ Western Digital WDXT-GEN ISA XT MFM Hard Disk Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************
+
+ Emulated here is the variant supplied with Amstrad PC1512/1640,
+ which has a custom BIOS and is coupled with a Tandom TM262 HDD.
+
+ chdman -createblankhd tandon_tm262.chd 615 4 17 512
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __ISA8_WDXT_GEN__
+#define __ISA8_WDXT_GEN__
+
+
+#include "emu.h"
+#include "cpu/mcs48/mcs48.h"
+#include "isa.h"
+#include "machine/wd11c00_17.h"
+#include "machine/wd2010.h"
+#include "imagedev/harddriv.h"
+
+
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> wdxt_gen_device
+
+class wdxt_gen_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ wdxt_gen_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ // not really public
+ DECLARE_WRITE_LINE_MEMBER( irq5_w );
+ DECLARE_WRITE_LINE_MEMBER( drq3_w );
+ DECLARE_WRITE_LINE_MEMBER( mr_w );
+ DECLARE_READ8_MEMBER( rd322_r );
+ DECLARE_READ8_MEMBER( ram_r );
+ DECLARE_WRITE8_MEMBER( ram_w );
+ DECLARE_READ8_MEMBER( wd1015_t0_r );
+ DECLARE_READ8_MEMBER( wd1015_t1_r );
+ DECLARE_READ8_MEMBER( wd1015_p1_r );
+ DECLARE_WRITE8_MEMBER( wd1015_p1_w );
+ DECLARE_READ8_MEMBER( wd1015_p2_r );
+ DECLARE_WRITE8_MEMBER( wd1015_p2_w );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_isa8_card_interface
+ virtual UINT8 dack_r(int line);
+ virtual void dack_w(int line, UINT8 data);
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<wd11c00_17_device> m_host;
+ required_device<wd2010_device> m_hdc;
+
+ UINT8 m_ram[0x800];
+
+ //UINT8 m_hdc_addr;
+};
+
+
+// device type definition
+extern const device_type ISA8_WDXT_GEN;
+
+#endif
diff --git a/src/emu/bus/isa/xsu_cards.c b/src/emu/bus/isa/xsu_cards.c
new file mode 100644
index 00000000000..b93ccc9a406
--- /dev/null
+++ b/src/emu/bus/isa/xsu_cards.c
@@ -0,0 +1,36 @@
+/**********************************************************************
+
+ ISA bus cards for ex-USSR PC clones
+
+ license: MAME, GPL-2.0+
+ copyright-holders: XXX
+
+**********************************************************************/
+
+#include "xsu_cards.h"
+
+SLOT_INTERFACE_START( p1_isa8_cards )
+ SLOT_INTERFACE("rom", P1_ROM)
+ SLOT_INTERFACE("fdc", P1_FDC) // B504
+ SLOT_INTERFACE("hdc", P1_HDC) // B942
+/*
+ SLOT_INTERFACE("comlpt", P1_COMLPT) // B620
+ SLOT_INTERFACE("joy", P1_JOY) // B621
+ SLOT_INTERFACE("mouse", P1_MOUSE) // B943
+ SLOT_INTERFACE("lan", P1_LAN) // B944
+*/
+ SLOT_INTERFACE("pccom", ISA8_COM)
+ SLOT_INTERFACE("pclpt", ISA8_LPT)
+ SLOT_INTERFACE("xtide", ISA8_XTIDE)
+SLOT_INTERFACE_END
+
+SLOT_INTERFACE_START( mc1502_isa8_cards )
+ SLOT_INTERFACE("rom", MC1502_ROM)
+ SLOT_INTERFACE("fdc", MC1502_FDC)
+/*
+ SLOT_INTERFACE("hdc", MC1502_HDC)
+*/
+ SLOT_INTERFACE("pccom", ISA8_COM)
+ SLOT_INTERFACE("pclpt", ISA8_LPT)
+ SLOT_INTERFACE("xtide", ISA8_XTIDE)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/isa/xsu_cards.h b/src/emu/bus/isa/xsu_cards.h
new file mode 100644
index 00000000000..966b89ff07e
--- /dev/null
+++ b/src/emu/bus/isa/xsu_cards.h
@@ -0,0 +1,35 @@
+/**********************************************************************
+
+ ISA bus cards for ex-USSR PC clones
+
+ license: MAME, GPL-2.0+
+ copyright-holders: XXX
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __XSU_CARDS_H__
+#define __XSU_CARDS_H__
+
+#include "emu.h"
+
+// storage
+#include "mc1502_fdc.h"
+#include "p1_fdc.h"
+#include "p1_hdc.h"
+
+// misc
+#include "mc1502_rom.h"
+#include "p1_rom.h"
+
+// non-native
+#include "com.h"
+#include "xtide.h"
+#include "lpt.h"
+
+// supported devices
+SLOT_INTERFACE_EXTERN( p1_isa8_cards );
+SLOT_INTERFACE_EXTERN( mc1502_isa8_cards );
+
+#endif // __XSU_CARDS_H__
diff --git a/src/emu/bus/isa/xtide.c b/src/emu/bus/isa/xtide.c
new file mode 100644
index 00000000000..137fd00f631
--- /dev/null
+++ b/src/emu/bus/isa/xtide.c
@@ -0,0 +1,331 @@
+/***************************************************************************
+
+The XT-IDE project is a Vintage Computer forum driven project to develop and manufacturer an 8-bit ISA IDE controller.
+It allows any PC/XT class machine to use modern IDE hard drives or Compact Flash devices for long term storage.
+
+http://www.vintage-computer.com/vcforum/showwiki.php?title=XTIDE+project
+
+Card has jumpers for I/O base address, and ROM base address, the default
+rom images being we'll emulate an I/O base of 0x300 and a ROM base of 0xC8000.
+
+If the I/O address is changed then you will need to use XTIDECFG to configure the ROM.
+The opensource bios is available from :
+http://code.google.com/p/xtideuniversalbios/
+
+The data high register is connected to a pair of latches that have the MSB of
+the 16 bit data word latched into so that 16 bit IO may be performmed, this
+involves the following :
+
+A Data read will read the data register first, and obtain the bottom 8 bits
+of the data word, the top 8 bits will be latched at the same time these are
+then read from the latch to the processor.
+
+A data write will first write the top 8 bits to the latch, and then the bottom
+8 bits to the normal data register, this will also transfer the top 8 bits to
+the drive.
+
+A modded r1 has A0 & A3 swapped, AKA chuckmod, which puts the high & low bytes together.
+This also affects the eeprom, so the BIOS would need to be shuffled (or the plain images flashed using XTIDECFG).
+
+IDE Register XTIDE rev 1 rev 2 or modded rev 1
+Data (XTIDE Data Low) 0 0
+Error (in), Features (out) 1 8
+Sector Count 2 2
+Sector Number,
+LBA bits 0...7,
+LBA48 bits 24...31 3 10
+Low Cylinder,
+LBA bits 8...15,
+LBA48 bits 32...39 4 4
+High Cylinder,
+LBA bits 16...23,
+LBA48 bits 40...47 5 12
+Drive and Head Select,
+LBA28 bits 24...27 6 6
+Status (in), Command (out) 7 14
+XTIDE Data High 8 1
+Alternative Status (in),
+Device Control (out) 14 7
+
+***************************************************************************/
+
+
+
+#include "xtide.h"
+
+
+READ8_MEMBER( xtide_device::read )
+{
+ UINT8 result;
+
+ if (offset == 0)
+ {
+ UINT16 data16 = m_ata->read_cs0(space, offset & 7, 0xffff);
+ result = data16 & 0xff;
+ m_d8_d15_latch = data16 >> 8;
+ }
+ else if (offset < 8)
+ {
+ result = m_ata->read_cs0(space, offset & 7, 0xff);
+ }
+ else if (offset == 8)
+ {
+ result = m_d8_d15_latch;
+ }
+ else
+ {
+ result = m_ata->read_cs1(space, offset & 7, 0xff);
+ }
+
+// logerror("%s xtide_device::read: offset=%d, result=%2X\n",device->machine().describe_context(),offset,result);
+
+ return result;
+}
+
+WRITE8_MEMBER( xtide_device::write )
+{
+// logerror("%s xtide_device::write: offset=%d, data=%2X\n",device->machine().describe_context(),offset,data);
+
+ if (offset == 0)
+ {
+ // Data register transfer low byte and latched high
+ UINT16 data16 = (m_d8_d15_latch << 8) | data;
+ m_ata->write_cs0(space, offset & 7, data16, 0xffff);
+ }
+ else if (offset < 8)
+ {
+ m_ata->write_cs0(space, offset & 7, data, 0xff);
+ }
+ else if (offset == 8)
+ {
+ m_d8_d15_latch = data;
+ }
+ else
+ {
+ m_ata->write_cs1(space, offset & 7, data, 0xff);
+ }
+}
+
+
+WRITE_LINE_MEMBER(xtide_device::ide_interrupt)
+{
+ switch (m_irq_number)
+ {
+ case 0x02: m_isa->irq2_w(state); break;
+ case 0x03: m_isa->irq3_w(state); break;
+ case 0x04: m_isa->irq4_w(state); break;
+ case 0x05: m_isa->irq5_w(state); break;
+ case 0x07: m_isa->irq7_w(state); break;
+ }
+}
+
+static MACHINE_CONFIG_FRAGMENT( xtide_config )
+ MCFG_ATA_INTERFACE_ADD("ata", ata_devices, "hdd", NULL, false)
+ MCFG_ATA_INTERFACE_IRQ_HANDLER(WRITELINE(xtide_device, ide_interrupt))
+
+ MCFG_EEPROM_2864_ADD("eeprom")
+MACHINE_CONFIG_END
+
+static INPUT_PORTS_START( xtide_port )
+ PORT_START("BIOS_BASE")
+ PORT_DIPNAME( 0x0F, 0x02, "XT-IDE ROM base segment")
+ PORT_DIPSETTING( 0x00, "C000" )
+ PORT_DIPSETTING( 0x01, "C400" )
+ PORT_DIPSETTING( 0x02, "C800" )
+ PORT_DIPSETTING( 0x03, "CC00" )
+ PORT_DIPSETTING( 0x04, "D000" )
+ PORT_DIPSETTING( 0x05, "D400" )
+ PORT_DIPSETTING( 0x06, "D800" )
+ PORT_DIPSETTING( 0x07, "DC00" )
+ PORT_DIPSETTING( 0x08, "E000" )
+ PORT_DIPSETTING( 0x09, "E400" )
+ PORT_DIPSETTING( 0x0A, "E800" )
+ PORT_DIPSETTING( 0x0B, "EC00" )
+ PORT_DIPSETTING( 0x0C, "F000" )
+ PORT_DIPSETTING( 0x0D, "F400" )
+ PORT_DIPSETTING( 0x0E, "F800" )
+ PORT_DIPSETTING( 0x0F, "FC00" )
+
+ PORT_START("IO_ADDRESS")
+ PORT_DIPNAME( 0x0F, 0x08, "XT-IDE I/O address")
+ PORT_DIPSETTING( 0x00, "200" )
+ PORT_DIPSETTING( 0x01, "220" )
+ PORT_DIPSETTING( 0x02, "240" )
+ PORT_DIPSETTING( 0x03, "260" )
+ PORT_DIPSETTING( 0x04, "280" )
+ PORT_DIPSETTING( 0x05, "2A0" )
+ PORT_DIPSETTING( 0x06, "2C0" )
+ PORT_DIPSETTING( 0x07, "2E0" )
+ PORT_DIPSETTING( 0x08, "300" )
+ PORT_DIPSETTING( 0x09, "320" )
+ PORT_DIPSETTING( 0x0A, "340" )
+ PORT_DIPSETTING( 0x0B, "360" )
+ PORT_DIPSETTING( 0x0C, "380" )
+ PORT_DIPSETTING( 0x0D, "3A0" )
+ PORT_DIPSETTING( 0x0E, "3C0" )
+ PORT_DIPSETTING( 0x0F, "3E0" )
+
+ PORT_START("IRQ")
+ PORT_DIPNAME( 0x07, 0x05, "XT-IDE IRQ")
+ PORT_DIPSETTING( 0x02, "IRQ 2" )
+ PORT_DIPSETTING( 0x03, "IRQ 3" )
+ PORT_DIPSETTING( 0x04, "IRQ 4" )
+ PORT_DIPSETTING( 0x05, "IRQ 5" )
+ PORT_DIPSETTING( 0x07, "IRQ 7" )
+INPUT_PORTS_END
+
+ROM_START( xtide )
+ ROM_REGION(0x02000,"eeprom", 0)
+
+ ROM_DEFAULT_BIOS("xub200b3xt")
+
+ ROM_SYSTEM_BIOS( 0, "xtide_010", "Hargle's Bios v0.10" )
+ ROMX_LOAD( "oprom.bin(v0.10)", 0x000000, 0x002000, CRC(56075ac2) SHA1(f55285a1ed8414c8ddf2364421552e0548cf548f), ROM_BIOS(1) )
+
+ ROM_SYSTEM_BIOS( 1, "xtide_011", "Hargle's Bios v0.11" )
+ ROMX_LOAD( "oprom.bin(v0.11)", 0x000000, 0x002000, CRC(c5fee6c5) SHA1(cc3a015d8d36208d99de8500c962828d2daea939), ROM_BIOS(2) )
+
+ ROM_SYSTEM_BIOS( 2, "xub110xt", "XTIDE_Universal_BIOS_v1.1.0 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v1.1.0)", 0x000000, 0x002000, CRC(d13f6ae7) SHA1(42c7e7cbf949af718abbd279e9a33680b8428400), ROM_BIOS(3) )
+
+ ROM_SYSTEM_BIOS( 3, "xub110xtp", "XTIDE_Universal_BIOS_v1.1.0 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v1.1.0)", 0x000000, 0x002000, CRC(4dd9124b) SHA1(af9e5742f57cccd16a580efcbda519314afd272d), ROM_BIOS(4) )
+
+ ROM_SYSTEM_BIOS( 4, "xub110at", "XTIDE_Universal_BIOS_v1.1.0 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v1.1.0)", 0x000000, 0x002000, CRC(673ebf69) SHA1(3960c0be39a787e740d14c8667fc09437bd56ff7), ROM_BIOS(5) )
+
+ ROM_SYSTEM_BIOS( 5, "xub111xt", "XTIDE_Universal_BIOS_v1.1.1 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v1.1.1)", 0x000000, 0x002000, CRC(6c15f095) SHA1(007db7dc16ccbbd9d297e13b81dee4785ac9fa9b), ROM_BIOS(6) )
+
+ ROM_SYSTEM_BIOS( 6, "xub111xtp", "XTIDE_Universal_BIOS_v1.1.1 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v1.1.1)", 0x000000, 0x002000, CRC(3eb1210d) SHA1(1d2e1cd20d548f794c889cdcfa7ebf224d073052), ROM_BIOS(7) )
+
+ ROM_SYSTEM_BIOS( 7, "xub111at", "XTIDE_Universal_BIOS_v1.1.1 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v1.1.1)", 0x000000, 0x002000, CRC(c808b718) SHA1(215903c68784c886a3117662c735a84d203b7858), ROM_BIOS(8) )
+
+ ROM_SYSTEM_BIOS( 8, "xub113xt", "XTIDE_Universal_BIOS_v1.1.3 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v1.1.3)", 0x000000, 0x002000, CRC(3158452f) SHA1(1363f370196a12c6770de5a76e8daf283b561625), ROM_BIOS(9) )
+
+ ROM_SYSTEM_BIOS( 9, "xub113xtp", "XTIDE_Universal_BIOS_v1.1.3 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v1.1.3)", 0x000000, 0x002000, CRC(d994fa2f) SHA1(68bdc24cc9878a09a77d6420b9565e51bb08e9b1), ROM_BIOS(10) )
+
+ ROM_SYSTEM_BIOS( 10, "xub113at", "XTIDE_Universal_BIOS_v1.1.3 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v1.1.3)", 0x000000, 0x002000, CRC(14ce1ced) SHA1(3eea39ffcb9a796c30f48d12ec8ff13572b3b9dc), ROM_BIOS(11) )
+
+ ROM_SYSTEM_BIOS( 11, "xub114xt", "XTIDE_Universal_BIOS_v1.1.4 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v1.1.4)", 0x000000, 0x002000, CRC(c73d2dcc) SHA1(335a79be455ef856f2b0c7444fc0b1dfeccc649c), ROM_BIOS(12) )
+
+ ROM_SYSTEM_BIOS( 12, "xub114at", "XTIDE_Universal_BIOS_v1.1.4 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v1.1.4)", 0x000000, 0x002000, CRC(ebb3deda) SHA1(bcab1743e37f5c0a252d7b127b13e64d5c65baf3), ROM_BIOS(13) )
+
+ ROM_SYSTEM_BIOS( 13, "xub115xt", "XTIDE_Universal_BIOS_v1.1.5 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v1.1.5)", 0x000000, 0x002000, CRC(33a7e0ee) SHA1(b610fd8ea31f5b0568b8b3f2c3ef682be4897a3d), ROM_BIOS(14) )
+
+ ROM_SYSTEM_BIOS( 14, "xub115xtp", "XTIDE_Universal_BIOS_v1.1.3 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v1.1.5)", 0x000000, 0x002000, CRC(44ad9ee9) SHA1(9cd275469703cadb85b6654c56e421a151324ac0), ROM_BIOS(15) )
+
+ ROM_SYSTEM_BIOS( 15, "xub115at", "XTIDE_Universal_BIOS_v1.1.5 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v1.1.5)", 0x000000, 0x002000, CRC(434286ce) SHA1(3fc07d174924e7c48b4758a7ba76ecd5362bd75b), ROM_BIOS(16) )
+
+ ROM_SYSTEM_BIOS( 16, "xub200b1xt", "XTIDE_Universal_BIOS_v2.0.0_beta1 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(379579e7) SHA1(da5ee7b9c43a55592fe909451d31a6766d0ab977), ROM_BIOS(17) )
+
+ ROM_SYSTEM_BIOS( 17, "xub200b1xtp", "XTIDE_Universal_BIOS_v2.0.0_beta1 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(a887ed63) SHA1(fb33d9e8e8824f61a8d247610d7bd215b7e306b4), ROM_BIOS(18) )
+
+ ROM_SYSTEM_BIOS( 18, "xub200b1at", "XTIDE_Universal_BIOS_v2.0.0_beta1 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v2.0.0_beta1)", 0x000000, 0x002000, CRC(cd2d8791) SHA1(2f831e7701d181d719a777b63dbd61d87036ee21), ROM_BIOS(19) )
+
+ ROM_SYSTEM_BIOS( 19, "xub200b2xt", "XTIDE_Universal_BIOS_v2.0.0_beta2 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(61ae1143) SHA1(de5f04b71f2614a0c3db6ec01a5dc7546205100a), ROM_BIOS(20) )
+
+ ROM_SYSTEM_BIOS( 20, "xub200b2xtp", "XTIDE_Universal_BIOS_v2.0.0_beta2 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(58883399) SHA1(582718d6dcd8a4367ee86da3201fb966dc4fffcd), ROM_BIOS(21) )
+
+ ROM_SYSTEM_BIOS( 21, "xub200b2at", "XTIDE_Universal_BIOS_v2.0.0_beta2 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v2.0.0_beta2)", 0x000000, 0x002000, CRC(33fe9336) SHA1(723de092af44e2b709b620f3b591ec12bdca53cd), ROM_BIOS(22) )
+
+ ROM_SYSTEM_BIOS( 22, "xub200b3xt", "XTIDE_Universal_BIOS_v2.0.0_beta3 (XT)" )
+ ROMX_LOAD( "ide_xt.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(0a8d4bb4) SHA1(509504c1c54842bcd24cdd318bcf6fb0ece09c33), ROM_BIOS(23) )
+
+ ROM_SYSTEM_BIOS( 23, "xub200b3xtp", "XTIDE_Universal_BIOS_v2.0.0_beta3 (XT 80186+)" )
+ ROMX_LOAD( "ide_xtp.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(a58658f8) SHA1(f3a4c1dfc8e2b56eeaf0e39aa192125bc05af626), ROM_BIOS(24) )
+
+ ROM_SYSTEM_BIOS( 24, "xub200b3at", "XTIDE_Universal_BIOS_v2.0.0_beta3 (AT)" )
+ ROMX_LOAD( "ide_at.bin(v2.0.0_beta3)", 0x000000, 0x002000, CRC(fc228f41) SHA1(c0053710ebac15284e740889967d73a6657734c7), ROM_BIOS(25) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type ISA8_XTIDE = &device_creator<xtide_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor xtide_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( xtide_config );
+}
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor xtide_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( xtide_port );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *xtide_device::device_rom_region() const
+{
+ return ROM_NAME( xtide );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// xtide_device - constructor
+//-------------------------------------------------
+
+xtide_device::xtide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, ISA8_XTIDE, "XT-IDE Fixed Drive Adapter", tag, owner, clock, "isa8_xtide", __FILE__),
+ device_isa8_card_interface( mconfig, *this ),
+ m_ata(*this, "ata"),
+ m_eeprom(*this, "eeprom")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void xtide_device::device_start()
+{
+ set_isa_device();
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void xtide_device::device_reset()
+{
+ int base_address = ((ioport("BIOS_BASE")->read() & 0x0F) * 16 * 1024) + 0xC0000;
+ int io_address = ((ioport("IO_ADDRESS")->read() & 0x0F) * 0x20) + 0x200;
+ m_irq_number = (ioport("IRQ")->read() & 0x07);
+
+ m_isa->install_memory(base_address, base_address + 0x1fff, 0, 0, read8_delegate(FUNC(eeprom_parallel_28xx_device::read), &(*m_eeprom)), write8_delegate(FUNC(eeprom_parallel_28xx_device::write), &(*m_eeprom)));
+ m_isa->install_device(io_address, io_address + 0xf, 0, 0, read8_delegate(FUNC(xtide_device::read), this), write8_delegate(FUNC(xtide_device::write), this));
+
+ //logerror("xtide_device::device_reset(), bios_base=0x%5X to 0x%5X, I/O=0x%3X, IRQ=%d\n",base_address,base_address + (16*1024) -1 ,io_address,irq);
+}
diff --git a/src/emu/bus/isa/xtide.h b/src/emu/bus/isa/xtide.h
new file mode 100644
index 00000000000..6c17dc8bc14
--- /dev/null
+++ b/src/emu/bus/isa/xtide.h
@@ -0,0 +1,49 @@
+#pragma once
+
+#ifndef __XTIDE_H__
+#define __XTIDE_H__
+
+#include "emu.h"
+#include "machine/ataintf.h"
+#include "machine/eeprompar.h"
+#include "isa.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class xtide_device : public device_t,
+ public device_isa8_card_interface
+{
+public:
+ // construction/destruction
+ xtide_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+ virtual ioport_constructor device_input_ports() const;
+ virtual const rom_entry *device_rom_region() const;
+
+ DECLARE_READ8_MEMBER(read);
+ DECLARE_WRITE8_MEMBER(write);
+ DECLARE_WRITE_LINE_MEMBER(ide_interrupt);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete() { m_shortname = "xtide"; }
+
+private:
+ required_device<ata_interface_device> m_ata;
+ required_device<eeprom_parallel_28xx_device> m_eeprom;
+
+ UINT8 m_irq_number;
+ UINT8 m_d8_d15_latch;
+};
+
+
+// device type definition
+extern const device_type ISA8_XTIDE;
+
+#endif /* __XTIDE__ */
diff --git a/src/emu/bus/pc_joy/pc_joy.c b/src/emu/bus/pc_joy/pc_joy.c
new file mode 100644
index 00000000000..665bd68d42b
--- /dev/null
+++ b/src/emu/bus/pc_joy/pc_joy.c
@@ -0,0 +1,91 @@
+/*************************************************************************
+ *
+ * pc_joy.h
+ *
+ * joystick port
+ *
+ *************************************************************************/
+
+#include "pc_joy.h"
+#include "pc_joy_sw.h"
+
+const device_type PC_JOY = &device_creator<pc_joy_device>;
+
+pc_joy_device::pc_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, PC_JOY, "PC joystick port", tag, owner, clock, "pc_joy", __FILE__),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+READ8_MEMBER ( pc_joy_device::joy_port_r )
+{
+ int delta = ((machine().time() - m_stime) * 256 * 1000).seconds;
+
+ if(!m_dev)
+ return 0xf0;
+
+ return (m_dev->btn() << 4) | (m_dev->y2(delta) << 3) | (m_dev->x2(delta) << 2) | (m_dev->y1(delta) << 1) | m_dev->x1(delta);
+}
+
+WRITE8_MEMBER ( pc_joy_device::joy_port_w )
+{
+ m_stime = machine().time();
+ m_dev->port_write();
+}
+
+void pc_joy_device::device_config_complete()
+{
+ m_dev = dynamic_cast<device_pc_joy_interface *>(get_card_device());
+}
+
+device_pc_joy_interface::device_pc_joy_interface(const machine_config &mconfig, device_t &device) :
+ device_slot_card_interface(mconfig, device)
+{
+}
+
+device_pc_joy_interface::~device_pc_joy_interface()
+{
+}
+
+static INPUT_PORTS_START( pc_joystick )
+ PORT_START("btn")
+ PORT_BIT( 0x1, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 1 Button 1")
+ PORT_BIT( 0x2, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Joystick 1 Button 2")
+ PORT_BIT( 0x4, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("Joystick 2 Button 1") PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(2)
+ PORT_BIT( 0x8, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("Joystick 2 Button 2") PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2)
+
+ PORT_START("x1")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_LEFT) PORT_CODE_INC(KEYCODE_RIGHT) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH)
+
+ PORT_START("y1")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(KEYCODE_UP) PORT_CODE_INC(KEYCODE_DOWN) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH)
+
+ PORT_START("x2")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_X_LEFT_SWITCH) PORT_CODE_INC(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2)
+
+ PORT_START("y2")
+ PORT_BIT(0xff,0x80,IPT_AD_STICK_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(1) PORT_MINMAX(1,0xff) PORT_CODE_DEC(JOYCODE_Y_UP_SWITCH) PORT_CODE_INC(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2)
+INPUT_PORTS_END
+
+ioport_constructor pc_basic_joy_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( pc_joystick );
+}
+
+const device_type PC_BASIC_JOY = &device_creator<pc_basic_joy_device>;
+
+pc_basic_joy_device::pc_basic_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, PC_BASIC_JOY, "PC basic joystick", tag, owner, clock, "basic_joy", __FILE__),
+ device_pc_joy_interface(mconfig, *this),
+ m_btn(*this, "btn"),
+ m_x1(*this, "x1"),
+ m_y1(*this, "y1"),
+ m_x2(*this, "x2"),
+ m_y2(*this, "y2")
+{
+}
+
+SLOT_INTERFACE_START(pc_joysticks)
+ SLOT_INTERFACE("basic_joy", PC_BASIC_JOY)
+ SLOT_INTERFACE("mssw_pad", PC_MSSW_PAD)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/pc_joy/pc_joy.h b/src/emu/bus/pc_joy/pc_joy.h
new file mode 100644
index 00000000000..8247bdfd87a
--- /dev/null
+++ b/src/emu/bus/pc_joy/pc_joy.h
@@ -0,0 +1,76 @@
+/*************************************************************************
+ *
+ * pc_joy.h
+ *
+ * joystick port
+ *
+ *************************************************************************/
+
+#ifndef PC_JOY_H
+#define PC_JOY_H
+
+#include "emu.h"
+
+#define MCFG_PC_JOY_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PC_JOY, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(pc_joysticks, "basic_joy", false)
+
+SLOT_INTERFACE_EXTERN(pc_joysticks);
+
+class device_pc_joy_interface: public device_slot_card_interface
+{
+public:
+ device_pc_joy_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_pc_joy_interface();
+
+ virtual UINT8 x1(int delta) { return 0; }
+ virtual UINT8 x2(int delta) { return 0; }
+ virtual UINT8 y1(int delta) { return 0; }
+ virtual UINT8 y2(int delta) { return 0; }
+ virtual UINT8 btn() { return 0xf; }
+ virtual void port_write() { }
+};
+
+class pc_joy_device : public device_t,
+ public device_slot_interface
+{
+public:
+ pc_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ DECLARE_READ8_MEMBER(joy_port_r);
+ DECLARE_WRITE8_MEMBER(joy_port_w);
+protected:
+ virtual void device_start() { m_stime = machine().time(); }
+ virtual void device_config_complete();
+private:
+ attotime m_stime;
+ device_pc_joy_interface *m_dev;
+};
+
+extern const device_type PC_JOY;
+
+class pc_basic_joy_device : public device_t,
+ public device_pc_joy_interface
+{
+public:
+ pc_basic_joy_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ioport_constructor device_input_ports() const;
+
+ virtual UINT8 x1(int delta) { return (m_x1->read() > delta); }
+ virtual UINT8 x2(int delta) { return (m_x2->read() > delta); }
+ virtual UINT8 y1(int delta) { return (m_y1->read() > delta); }
+ virtual UINT8 y2(int delta) { return (m_y2->read() > delta); }
+ virtual UINT8 btn() { return m_btn->read(); }
+
+protected:
+ virtual void device_start() {}
+
+private:
+ required_ioport m_btn;
+ required_ioport m_x1;
+ required_ioport m_y1;
+ required_ioport m_x2;
+ required_ioport m_y2;
+};
+
+#endif /* PC_JOY_H */
diff --git a/src/emu/bus/pc_joy/pc_joy_sw.c b/src/emu/bus/pc_joy/pc_joy_sw.c
new file mode 100644
index 00000000000..06b9e792a07
--- /dev/null
+++ b/src/emu/bus/pc_joy/pc_joy_sw.c
@@ -0,0 +1,175 @@
+//TODO: determine when to switch modes and add single bit mode
+
+#include "pc_joy_sw.h"
+
+const device_type PC_MSSW_PAD = &device_creator<pc_mssw_pad_device>;
+
+pc_mssw_pad_device::pc_mssw_pad_device(const machine_config& mconfig, const char* tag, device_t* owner, UINT32 clock) :
+ device_t(mconfig, PC_MSSW_PAD, "Microsoft Sidewinder Pad", tag, owner, clock, "mssw_pad", __FILE__),
+ device_pc_joy_interface(mconfig, *this),
+ m_btn1(*this, "btn1"),
+ m_btn2(*this, "btn2"),
+ m_btn3(*this, "btn3"),
+ m_btn4(*this, "btn4"),
+ m_conf(*this, "CONFIG")
+{
+}
+
+void pc_mssw_pad_device::device_start()
+{
+ m_timer = timer_alloc();
+}
+
+void pc_mssw_pad_device::device_reset()
+{
+ m_count = 0;
+ m_state = 0xf;
+ m_active = false;
+ m_timer->adjust(attotime::never, 0);
+}
+
+void pc_mssw_pad_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ UINT16 pad_state = 0;
+ // only multibit mode for now
+ if(m_count == -1)
+ {
+ reset();
+ return;
+ }
+
+ if((m_count / 5) > m_conf->read())
+ {
+ m_timer->adjust(attotime::from_usec(50), 0);
+ m_state &= ~1;
+ m_count = -1;
+ return;
+ }
+
+ if(m_state & 1)
+ {
+ m_state &= ~1;
+ return;
+ }
+
+ switch(m_count / 5)
+ {
+ case 0:
+ pad_state = m_btn1->read();
+ break;
+ case 1:
+ pad_state = m_btn2->read();
+ break;
+ case 2:
+ pad_state = m_btn3->read();
+ break;
+ case 3:
+ pad_state = m_btn4->read();
+ break;
+ }
+
+ switch(m_count % 5)
+ {
+ case 0:
+ m_state = ((pad_state & 7) << 1) | 1;
+ break;
+ case 1:
+ m_state = ((pad_state & 0x38) >> 2) | 1;
+ break;
+ case 2:
+ m_state = ((pad_state & 0x1c0) >> 5) | 1;
+ break;
+ case 3:
+ m_state = ((pad_state & 0xe00) >> 8) | 1;
+ break;
+ case 4:
+ {
+ UINT8 parity = (pad_state >> 8) ^ pad_state;
+ parity = (parity >> 4) ^ parity;
+ parity = (parity >> 2) ^ parity;
+ parity = (((parity >> 1) ^ parity) & 1);
+
+ m_state = ((pad_state & 0x3000) >> 11) | (parity << 3) | 1;
+ break;
+ }
+ }
+ m_count++;
+}
+
+static INPUT_PORTS_START( sidewinder_pad )
+ PORT_START("btn1")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP )
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A")
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B")
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C")
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X")
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y")
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z")
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L")
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R")
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start")
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M")
+ PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_START("btn2")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(2)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(2)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(2)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(2)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(2)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(2)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(2)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(2)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(2)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(2)
+ PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_START("btn3")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(3)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(3)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(3)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(3)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(3)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(3)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(3)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(3)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(3)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(3)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(3)
+ PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_START("btn4")
+ PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(4)
+ PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4)
+ PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4)
+ PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4)
+ PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("A") PORT_PLAYER(4)
+ PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("B") PORT_PLAYER(4)
+ PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("C") PORT_PLAYER(4)
+ PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("X") PORT_PLAYER(4)
+ PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("Y") PORT_PLAYER(4)
+ PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("Z") PORT_PLAYER(4)
+ PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_NAME("L") PORT_PLAYER(4)
+ PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_NAME("R") PORT_PLAYER(4)
+ PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON9 ) PORT_NAME("Start") PORT_PLAYER(4)
+ PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON10 ) PORT_NAME("M") PORT_PLAYER(4)
+ PORT_BIT( 0xc000, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_START("CONFIG")
+ PORT_CONFNAME(0x03, 0x00, "Number of Sidewinder Pads")
+ PORT_CONFSETTING( 0x00, "1")
+ PORT_CONFSETTING( 0x01, "2")
+ PORT_CONFSETTING( 0x02, "3")
+ PORT_CONFSETTING( 0x03, "4")
+INPUT_PORTS_END
+
+ioport_constructor pc_mssw_pad_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( sidewinder_pad );
+}
diff --git a/src/emu/bus/pc_joy/pc_joy_sw.h b/src/emu/bus/pc_joy/pc_joy_sw.h
new file mode 100644
index 00000000000..654b10f63c6
--- /dev/null
+++ b/src/emu/bus/pc_joy/pc_joy_sw.h
@@ -0,0 +1,36 @@
+#ifndef PC_JOY_SW_H_
+#define PC_JOY_SW_H_
+
+#include "pc_joy.h"
+
+class pc_mssw_pad_device : public device_t,
+ public device_pc_joy_interface
+{
+public:
+ pc_mssw_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ioport_constructor device_input_ports() const;
+
+ virtual UINT8 btn() { return m_state; }
+ // timing is guessed, calibrated for at486
+ virtual void port_write() { if(!m_active) { m_timer->adjust(attotime::from_usec(50), 0, attotime::from_usec(5)); m_active = true; } }
+
+protected:
+ virtual void device_start();
+ virtual void device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr);
+ virtual void device_reset();
+
+private:
+ required_ioport m_btn1;
+ required_ioport m_btn2;
+ required_ioport m_btn3;
+ required_ioport m_btn4;
+ required_ioport m_conf;
+ emu_timer *m_timer;
+ int m_count;
+ UINT8 m_state;
+ bool m_active;
+};
+
+extern const device_type PC_MSSW_PAD;
+
+#endif /* PC_JOY_SW_H_ */
diff --git a/src/emu/emu.mak b/src/emu/emu.mak
index 5c1704b7bcb..423aef3f902 100644
--- a/src/emu/emu.mak
+++ b/src/emu/emu.mak
@@ -42,8 +42,10 @@ OBJDIRS += \
$(EMUOBJ)/bus/ep64 \
$(EMUOBJ)/bus/ieee488 \
$(EMUOBJ)/bus/imi7000 \
+ $(EMUOBJ)/bus/isa \
$(EMUOBJ)/bus/isbx \
$(EMUOBJ)/bus/midi \
+ $(EMUOBJ)/bus/pc_joy \
$(EMUOBJ)/bus/pc_kbd \
$(EMUOBJ)/bus/pet \
$(EMUOBJ)/bus/plus4 \
diff --git a/src/emu/machine/dp8390.c b/src/emu/machine/dp8390.c
new file mode 100644
index 00000000000..a1ac879b12c
--- /dev/null
+++ b/src/emu/machine/dp8390.c
@@ -0,0 +1,485 @@
+#include "emu.h"
+#include "dp8390.h"
+
+#define DP8390_BYTE_ORDER(w) ((m_regs.dcr & 3) == 3 ? ((data << 8) | (data >> 8)) : data)
+#define LOOPBACK (!(m_regs.dcr & 8) && (m_regs.tcr & 6))
+
+const device_type DP8390D = &device_creator<dp8390d_device>;
+const device_type RTL8019A = &device_creator<rtl8019a_device>;
+
+void dp8390_device::device_config_complete() {
+ const dp8390_interface *intf = reinterpret_cast<const dp8390_interface *>(static_config());
+ if(intf != NULL)
+ *static_cast<dp8390_interface *>(this) = *intf;
+ else {
+ memset(&irq_cb, 0, sizeof(irq_cb));
+ memset(&breq_cb, 0, sizeof(breq_cb));
+ memset(&mem_read_cb, 0, sizeof(mem_read_cb));
+ memset(&mem_write_cb, 0, sizeof(mem_write_cb));
+ }
+}
+
+dp8390d_device::dp8390d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : dp8390_device(mconfig, DP8390D, "DP8390D", tag, owner, clock, 10.0f, "dp8390d", __FILE__) {
+ m_type = TYPE_DP8390D;
+}
+
+rtl8019a_device::rtl8019a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : dp8390_device(mconfig, RTL8019A, "RTL8019A", tag, owner, clock, 10.0f, "rtl8019a", __FILE__) {
+ m_type = TYPE_RTL8019A;
+}
+
+dp8390_device::dp8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, float bandwidth, const char *shortname, const char *source)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, source),
+ device_network_interface(mconfig, *this, bandwidth) {
+}
+
+void dp8390_device::device_start() {
+ irq_func.resolve(irq_cb, *this);
+ breq_func.resolve(breq_cb, *this);
+ mem_read.resolve(mem_read_cb, *this);
+ mem_write.resolve(mem_write_cb, *this);
+}
+
+void dp8390_device::stop() {
+ m_regs.isr = 0x80; // is this right?
+ m_regs.cr |= 1;
+ irq_func(CLEAR_LINE);
+ m_reset = 1;
+}
+
+void dp8390_device::device_reset() {
+ memset(&m_regs, 0, sizeof(m_regs));
+ m_regs.cr = 0x21;
+ m_regs.isr = 0x80;
+ m_regs.dcr = 0x04;
+ memset(&m_8019regs, 0, sizeof(m_8019regs));
+ m_8019regs.config1 = 0x80;
+ m_8019regs.config3 = 0x01;
+ irq_func(CLEAR_LINE);
+
+ m_reset = 1;
+}
+
+void dp8390_device::check_dma_complete() {
+ if(m_regs.rbcr) return;
+ m_regs.isr |= 0x40;
+ check_irq();
+ m_rdma_active = 0;
+}
+
+void dp8390_device::do_tx() {
+ UINT8 *buf;
+ int i;
+ UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0;
+ if(m_reset) return;
+ if(LOOPBACK) return; // TODO: loopback
+ m_regs.tsr = 0;
+ if(m_regs.tbcr > 1518) logerror("dp8390: trying to send overlong frame\n");
+ if(!m_regs.tbcr) { // ? Bochs says solaris actually does this
+ m_regs.tsr = 1;
+ m_regs.cr &= ~4;
+ return;
+ }
+
+ buf = global_alloc_array(UINT8, m_regs.tbcr);
+ for(i = 0; i < m_regs.tbcr; i++) buf[i] = mem_read(high16 + (m_regs.tpsr << 8) + i);
+
+ if(send(buf, m_regs.tbcr)) {
+ m_regs.tsr = 1;
+ m_regs.isr |= 2;
+ } else {
+ m_regs.tsr = 8; // not quite right but there isn't a generic "tx failed"
+ m_regs.isr |= 8;
+ }
+ m_regs.cr &= ~4;
+ check_irq();
+ global_free(buf);
+}
+
+void dp8390_device::set_cr(UINT8 newcr) {
+ int ostate = ((m_regs.cr & 3) == 2);
+ m_regs.cr = newcr;
+ if((newcr & 1) && (ostate == 1)) return stop();
+ if((newcr & 3) == 2) {
+ m_reset = 0;
+ m_regs.isr &= ~0x80;
+ }
+ if(newcr & 0x20) m_rdma_active = 0;
+ if(m_reset) return;
+ if(newcr & 4) do_tx();
+ if((newcr & 0x38) == 8) {
+ m_rdma_active = 1;
+ check_dma_complete();
+ }
+ if((newcr & 0x38) == 0x10) m_rdma_active = 2;
+}
+
+void dp8390_device::recv_overflow() {
+ m_regs.rsr = 0x10;
+ m_regs.isr |= 0x10;
+ check_irq();
+ m_regs.cntr2++;
+ return;
+}
+
+void dp8390_device::recv(UINT8 *buf, int len) {
+ int i;
+ UINT16 start = (m_regs.curr << 8), offset;
+ UINT32 high16;
+ if(m_reset) return;
+ if(m_regs.curr == m_regs.pstop) start = m_regs.pstart << 8;
+ offset = start + 4;
+ high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0;
+ if(buf[0] & 1) {
+ if(!memcmp((const char *)buf, "\xff\xff\xff\xff\xff\xff", 6)) {
+ if(!(m_regs.rcr & 4)) return;
+ } else return; // multicast
+ m_regs.rsr = 0x20;
+ } else m_regs.rsr = 0;
+ len &= 0xffff;
+
+ for(i = 0; i < len; i++) {
+ mem_write(high16 + offset, buf[i]);
+ offset++;
+ if(!(offset & 0xff)) {
+ if((offset >> 8) == m_regs.pstop) offset = m_regs.pstart << 8;
+ if((offset >> 8) == m_regs.bnry) return recv_overflow();
+ }
+ }
+ if(len < 60) {
+ // this can't pass to the next page
+ for(; i < 60; i++) {
+ mem_write(high16 + offset, 0);
+ offset++;
+ }
+ len = 60;
+ }
+
+ m_regs.rsr |= 1;
+ m_regs.isr |= 1;
+ m_regs.curr = (offset >> 8) + ((offset & 0xff)?1:0);
+ if(m_regs.curr == m_regs.pstop) m_regs.curr = m_regs.pstart;
+ len += 4;
+ mem_write(start, m_regs.rsr);
+ mem_write(start+1, m_regs.curr);
+ mem_write(start+2, len & 0xff);
+ mem_write(start+3, len >> 8);
+ check_irq();
+}
+
+void dp8390_device::recv_cb(UINT8 *buf, int len) {
+ if(!LOOPBACK) recv(buf, len);
+}
+
+WRITE_LINE_MEMBER(dp8390_device::dp8390_cs) {
+ m_cs = state;
+}
+
+WRITE_LINE_MEMBER(dp8390_device::dp8390_reset) {
+ if(!state) device_reset();
+}
+
+READ16_MEMBER(dp8390_device::dp8390_r) {
+ UINT16 data;
+ if(m_cs) {
+ UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0;
+ if(m_regs.dcr & 1) {
+ m_regs.crda &= ~1;
+ data = mem_read(high16 + m_regs.crda++);
+ data |= mem_read(high16 + m_regs.crda++) << 8;
+ m_regs.rbcr -= (m_regs.rbcr < 2)?m_regs.rbcr:2;
+ check_dma_complete();
+ return DP8390_BYTE_ORDER(data);
+ } else {
+ m_regs.rbcr -= (m_regs.rbcr)?1:0;
+ data = mem_read(high16 + m_regs.crda++);
+ check_dma_complete();
+ return data;
+ }
+ }
+
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ case 0x00:
+ case 0x40:
+ case 0x80:
+ data = m_regs.cr;
+ break;
+ case 0x01:
+ data = m_regs.clda & 0xff;
+ break;
+ case 0x02:
+ data = m_regs.clda >> 8;
+ break;
+ case 0x03:
+ data = m_regs.bnry;
+ break;
+ case 0x04:
+ data = m_regs.tsr;
+ break;
+ case 0x05:
+ data = m_regs.ncr;
+ break;
+ case 0x06:
+ data = m_regs.fifo;
+ break;
+ case 0x07:
+ data = m_regs.isr;
+ break;
+ case 0x08:
+ data = m_regs.crda & 0xff;
+ break;
+ case 0x09:
+ data = m_regs.crda >> 8;
+ break;
+ case 0x0c:
+ data = m_regs.rsr;
+ break;
+ case 0x0d:
+ data = m_regs.cntr0;
+ break;
+ case 0x0e:
+ data = m_regs.cntr1;
+ break;
+ case 0x0f:
+ data = m_regs.cntr2;
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ data = m_regs.par[(offset & 0x7)-1];
+ break;
+ case 0x47:
+ data = m_regs.curr;
+ break;
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ data = m_regs.mar[offset & 0x7];
+ break;
+ case 0x81:
+ data = m_regs.pstart;
+ break;
+ case 0x82:
+ data = m_regs.pstop;
+ break;
+ case 0x83:
+ data = m_regs.rnpp;
+ break;
+ case 0x84:
+ data = m_regs.tpsr;
+ break;
+ case 0x85:
+ data = m_regs.lnpp;
+ break;
+ case 0x86:
+ data = m_regs.ac >> 8;
+ break;
+ case 0x87:
+ data = m_regs.ac & 0xff;
+ break;
+ case 0x8c:
+ data = m_regs.rcr;
+ break;
+ case 0x8d:
+ data = m_regs.tcr;
+ break;
+ case 0x8e:
+ data = m_regs.dcr;
+ break;
+ case 0x8f:
+ data = m_regs.imr;
+ break;
+ case 0xc0:
+ data = m_regs.cr;
+ break;
+ default:
+ if(m_type == TYPE_RTL8019A) {
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ case 0x0a:
+ data = 'P';
+ break;
+ case 0x0b:
+ data = 'p';
+ break;
+
+ case 0xc1:
+ data = m_8019regs.cr9346;
+ break;
+ case 0xc2:
+ data = m_8019regs.bpage;
+ break;
+ case 0xc3:
+ data = m_8019regs.config0;
+ break;
+ case 0xc4:
+ data = m_8019regs.config1;
+ break;
+ case 0xc5:
+ data = m_8019regs.config2;
+ break;
+ case 0xc6:
+ data = m_8019regs.config3;
+ break;
+ case 0xcd:
+ data = m_8019regs.config4;
+ break;
+ case 0xc8:
+ data = m_8019regs.csnsav;
+ break;
+ case 0xcb:
+ data = m_8019regs.intr;
+ break;
+ default:
+ logerror("rtl8019: invalid read page %01X reg %02X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f);
+ return 0;
+ }
+ } else {
+ logerror("dp8390: invalid read page %01X reg %02X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f);
+ return 0;
+ }
+ }
+ return data;
+}
+
+WRITE16_MEMBER(dp8390_device::dp8390_w) {
+ if(m_cs) {
+ UINT32 high16 = (m_regs.dcr & 4)?m_regs.rsar<<16:0;
+ if(m_regs.dcr & 1) {
+ data = DP8390_BYTE_ORDER(data);
+ m_regs.crda &= ~1;
+ mem_write(high16 + m_regs.crda++, data & 0xff);
+ mem_write(high16 + m_regs.crda++, data >> 8);
+ m_regs.rbcr -= (m_regs.rbcr < 2)?m_regs.rbcr:2;
+ check_dma_complete();
+ } else {
+ data &= 0xff;
+ mem_write(high16 + m_regs.crda++, data);
+ m_regs.rbcr -= (m_regs.rbcr)?1:0;
+ check_dma_complete();
+ }
+ return;
+ }
+
+ data &= 0xff;
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ case 0x00:
+ case 0x40:
+ case 0x80:
+ set_cr(data);
+ break;
+ case 0x01:
+ m_regs.pstart = data;
+ break;
+ case 0x02:
+ m_regs.pstop = data;
+ break;
+ case 0x03:
+ m_regs.bnry = data;
+ break;
+ case 0x04:
+ m_regs.tpsr = data;
+ break;
+ case 0x05:
+ m_regs.tbcr = (m_regs.tbcr & 0xff00) | data;
+ break;
+ case 0x06:
+ m_regs.tbcr = (m_regs.tbcr & 0xff) | (data << 8);
+ break;
+ case 0x07:
+ m_regs.isr &= ~data;
+ check_irq();
+ break;
+ case 0x08:
+ m_regs.rsar = (m_regs.rsar & 0xff00) | data;
+ m_regs.crda = m_regs.rsar;
+ break;
+ case 0x09:
+ m_regs.rsar = (m_regs.rsar & 0xff) | (data << 8);
+ m_regs.crda = m_regs.rsar;
+ break;
+ case 0x0a:
+ m_regs.rbcr = (m_regs.rbcr & 0xff00) | data;
+ break;
+ case 0x0b:
+ m_regs.rbcr = (m_regs.rbcr & 0xff) | (data << 8);
+ break;
+ case 0x0c:
+ m_regs.rcr = data;
+ set_promisc((data & 0x10)?true:false);
+ break;
+ case 0x0d:
+ m_regs.tcr = data;
+ break;
+ case 0x0e:
+ m_regs.dcr = data;
+ break;
+ case 0x0f:
+ m_regs.imr = data;
+ check_irq();
+ break;
+ case 0x41:
+ case 0x42:
+ case 0x43:
+ case 0x44:
+ case 0x45:
+ case 0x46:
+ m_regs.par[(offset & 0x7)-1] = data;
+ set_mac((const char *)m_regs.par);
+ break;
+ case 0x47:
+ m_regs.curr = data;
+ break;
+ case 0x48:
+ case 0x49:
+ case 0x4a:
+ case 0x4b:
+ case 0x4c:
+ case 0x4d:
+ case 0x4e:
+ case 0x4f:
+ m_regs.mar[offset & 0x7] = data;
+ break;
+ case 0x81:
+ m_regs.clda = (m_regs.clda & 0xff00) | data;
+ break;
+ case 0x82:
+ m_regs.clda = (m_regs.clda & 0xff) | (data << 8);
+ break;
+ case 0x83:
+ m_regs.rnpp = data;
+ break;
+ case 0x85:
+ m_regs.lnpp = data;
+ break;
+ case 0x86:
+ m_regs.ac = (m_regs.ac & 0xff) | (data << 8);
+ break;
+ case 0x87:
+ m_regs.ac = (m_regs.ac & 0xff00) | data;
+ break;
+ case 0xc0:
+ set_cr(data);
+ break;
+ default:
+ if(m_type == TYPE_RTL8019A) {
+ switch((offset & 0x0f)|(m_regs.cr & 0xc0)) {
+ // XXX: rest of the regs
+ default:
+ logerror("rtl8019: invalid write page %01X reg %02X data %04X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f, data);
+ return;
+ }
+ } else {
+ logerror("dp8390: invalid write page %01X reg %02X data %04X\n", (m_regs.cr & 0xc0) >> 6, offset & 0x0f, data);
+ return;
+ }
+ }
+}
diff --git a/src/emu/machine/dp8390.h b/src/emu/machine/dp8390.h
new file mode 100644
index 00000000000..f98b5411eab
--- /dev/null
+++ b/src/emu/machine/dp8390.h
@@ -0,0 +1,130 @@
+#ifndef _DP8390_H_
+#define _DP8390_H_
+
+#include "emu.h"
+
+struct dp8390_interface
+{
+ devcb_write_line irq_cb;
+ devcb_write_line breq_cb;
+ devcb_read8 mem_read_cb;
+ devcb_write8 mem_write_cb;
+};
+
+// device stuff
+#define MCFG_DP8390D_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, DP8390D, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_RTL8019A_ADD(_tag, _intrf) \
+ MCFG_DEVICE_ADD(_tag, RTL8019A, 0) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+class dp8390_device : public device_t,
+ public device_network_interface,
+ public dp8390_interface
+{
+public:
+ // construction/destruction
+ dp8390_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, float bandwidth, const char *shortname, const char *source);
+
+ DECLARE_WRITE16_MEMBER( dp8390_w );
+ DECLARE_READ16_MEMBER( dp8390_r );
+ DECLARE_WRITE_LINE_MEMBER( dp8390_cs );
+ DECLARE_WRITE_LINE_MEMBER( dp8390_reset );
+ void recv_cb(UINT8 *buf, int len);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_config_complete();
+ int m_type;
+
+ enum {
+ TYPE_DP8390D = 0,
+ TYPE_RTL8019A
+ };
+
+private:
+ devcb_resolved_write_line irq_func;
+ devcb_resolved_write_line breq_func;
+ devcb_resolved_read8 mem_read;
+ devcb_resolved_write8 mem_write;
+
+ void set_cr(UINT8 newcr);
+ void check_dma_complete();
+ void do_tx();
+ bool mcast_ck(const UINT8 *buf, int len);
+ void check_irq() { irq_func((m_regs.imr & m_regs.isr & 0x7f)?ASSERT_LINE:CLEAR_LINE); }
+ void recv_overflow();
+ void stop();
+ void recv(UINT8 *buf, int len);
+
+ int m_reset;
+ bool m_cs;
+ int m_rdma_active;
+
+ struct {
+ UINT8 cr;
+ UINT16 clda;
+ UINT8 pstart;
+ UINT8 pstop;
+ UINT8 bnry;
+ UINT8 tsr;
+ UINT8 tpsr;
+ UINT8 ncr;
+ UINT8 fifo;
+ UINT16 tbcr;
+ UINT8 isr;
+ UINT16 crda;
+ UINT16 rsar;
+ UINT16 rbcr;
+ UINT8 rsr;
+ UINT8 rcr;
+ UINT8 cntr0;
+ UINT8 tcr;
+ UINT8 cntr1;
+ UINT8 dcr;
+ UINT8 cntr2;
+ UINT8 imr;
+
+ UINT8 par[6];
+ UINT8 curr;
+ UINT8 mar[8];
+
+ UINT8 rnpp;
+ UINT8 lnpp;
+ UINT16 ac;
+ } m_regs;
+
+ struct {
+ UINT8 cr9346;
+ UINT8 bpage;
+ UINT8 config0;
+ UINT8 config1;
+ UINT8 config2;
+ UINT8 config3;
+ UINT8 config4;
+ UINT8 csnsav;
+ UINT8 intr;
+ } m_8019regs;
+};
+
+class rtl8019a_device : public dp8390_device
+{
+public:
+ rtl8019a_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+class dp8390d_device : public dp8390_device
+{
+public:
+ dp8390d_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+};
+
+// device type definition
+extern const device_type DP8390D;
+extern const device_type RTL8019A;
+
+#endif
diff --git a/src/emu/machine/machine.mak b/src/emu/machine/machine.mak
index 5ee7139cfa3..15300e77c2b 100644
--- a/src/emu/machine/machine.mak
+++ b/src/emu/machine/machine.mak
@@ -1615,3 +1615,40 @@ ifneq ($(filter MM58167,$(MACHINES)),)
MACHINEOBJS += $(MACHINEOBJ)/mm58167.o
endif
+
+#-------------------------------------------------
+#
+#@src/emu/machine/dp8390.h,MACHINES += DP8390
+#-------------------------------------------------
+
+ifneq ($(filter DP8390,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/dp8390.o
+endif
+
+#-------------------------------------------------
+#
+#@src/emu/machine/pc_lpt.h,MACHINES += PC_LPT
+#-------------------------------------------------
+
+ifneq ($(filter PC_LPT,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/pc_lpt.o
+endif
+
+#-------------------------------------------------
+#
+#@src/emu/machine/pc_fdc.h,MACHINES += PC_FDC
+#-------------------------------------------------
+
+ifneq ($(filter PC_FDC,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/pc_fdc.o
+endif
+
+#-------------------------------------------------
+#
+#@src/emu/machine/mpu401.h,MACHINES += MPU401
+#-------------------------------------------------
+
+ifneq ($(filter MPU401,$(MACHINES)),)
+MACHINEOBJS += $(MACHINEOBJ)/mpu401.o
+endif
+
diff --git a/src/emu/machine/mpu401.c b/src/emu/machine/mpu401.c
new file mode 100644
index 00000000000..7e654cb0662
--- /dev/null
+++ b/src/emu/machine/mpu401.c
@@ -0,0 +1,287 @@
+/***************************************************************************
+
+ Roland MPU-401 core
+
+ This emulates the MPU-401 external box with the 6801, ASIC, and RAM in it.
+
+ We do it this way to facilitate the various PC, Apple II, C64, and other
+ possible hookups.
+
+ 6801 GPIO port hookups (from the schematics)
+
+ P10 / P11 / P12: drive the metronome and speaker
+ P13 / P14 / P15: drive 3 pins on the SYNC OUT connector
+ P16: to DSRD on gate array
+ P17: to DRRD on gate array
+
+ P20: to SYC OUT on gate array
+ P21: to SYC IN on gate array, pulled up to Vcc via 4.7K resistor
+ programmed as output of timer (OLVL)
+ P22: to SRCK on gate array, inverted
+ P23: MIDI IN serial data (SCI in)
+ P24: MIDI OUT serial data (SCI out)
+
+ ASIC addresses from the 6801:
+ 0x20: (r) read pending byte from the PC (w) apparently nothing
+ 0x21: (r) ASIC status, see STAT_xxx bits below (w) send new byte to PC data port
+
+ Theory of operation: 6801's timer/counter is set up to drive a pulse stream
+ out P21 to the ASIC's SYC IN pin. The ASIC in turn generates the MIDI baud
+ rate (times 8) and returns that on pin P22.
+
+ The 6801 is believed to run in mode 2, based on a combination of the
+ schematics and the behavior (ie, internal RAM from 80-FF is clearly
+ present from the program's behavior, and ports 3/4 are obviously external
+ address/data buses)
+
+***************************************************************************/
+
+#include "machine/mpu401.h"
+#include "bus/midi/midi.h"
+
+#define M6801_TAG "mpu6801"
+#define ROM_TAG "mpurom"
+#define MIDIIN_TAG "mdin"
+#define MIDIOUT_TAG "mdout"
+
+#define P2_SYNC_OUT (0x01)
+#define P2_SYNC_IN (0x02)
+#define P2_SRCK_OUT (0x04)
+#define P2_MIDI_IN (0x08)
+#define P2_MIDI_OUT (0x10)
+
+#define STAT_CMD_PORT (0x01) // set if the new byte indicated by TX FULL was written to the command port, clear for data port
+#define STAT_TX_FULL (0x40) // indicates the PC has written a new byte we haven't read yet
+#define STAT_RX_EMPTY (0x80) // indicates we've written a new byte the PC hasn't read yet
+
+static ADDRESS_MAP_START( mpu401_map, AS_PROGRAM, 8, mpu401_device )
+ AM_RANGE(0x0000, 0x001f) AM_READWRITE(regs_mode2_r, regs_mode2_w)
+ AM_RANGE(0x0020, 0x0021) AM_READWRITE(asic_r, asic_w)
+ AM_RANGE(0x0080, 0x00ff) AM_RAM // on-chip RAM
+ AM_RANGE(0x0800, 0x0fff) AM_RAM // external RAM
+ AM_RANGE(0xf000, 0xffff) AM_ROM AM_REGION(ROM_TAG, 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( mpu401_io_map, AS_IO, 8, mpu401_device )
+ AM_RANGE(M6801_PORT1, M6801_PORT1) AM_READWRITE(port1_r, port1_w)
+ AM_RANGE(M6801_PORT2, M6801_PORT2) AM_READWRITE(port2_r, port2_w)
+ADDRESS_MAP_END
+
+MACHINE_CONFIG_FRAGMENT( mpu401 )
+ MCFG_CPU_ADD(M6801_TAG, M6801, 4000000) /* 4 MHz as per schematics */
+ MCFG_CPU_PROGRAM_MAP(mpu401_map)
+ MCFG_CPU_IO_MAP(mpu401_io_map)
+ MCFG_M6801_SER_TX(DEVWRITELINE(MIDIOUT_TAG, midi_port_device, write_txd))
+
+ MCFG_MIDI_PORT_ADD(MIDIIN_TAG, midiin_slot, "midiin")
+ MCFG_MIDI_RX_HANDLER(DEVWRITELINE(DEVICE_SELF, mpu401_device, midi_rx_w))
+
+ MCFG_MIDI_PORT_ADD(MIDIOUT_TAG, midiout_slot, "midiout")
+MACHINE_CONFIG_END
+
+ROM_START( mpu401 )
+ ROM_REGION(0x1000, ROM_TAG, 0)
+ ROM_LOAD( "roland_6801v0b55p.bin", 0x000000, 0x001000, CRC(65d3a151) SHA1(00efbfb96aeb997b69bb16981c6751d3c784bb87) )
+ROM_END
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type MPU401 = &device_creator<mpu401_device>;
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor mpu401_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( mpu401 );
+}
+
+//-------------------------------------------------
+// rom_region - device-specific ROM region
+//-------------------------------------------------
+
+const rom_entry *mpu401_device::device_rom_region() const
+{
+ return ROM_NAME( mpu401 );
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// mpu401_device - constructor
+//-------------------------------------------------
+
+mpu401_device::mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, MPU401, "Roland MPU-401 I/O box", tag, owner, clock, "mpu401", __FILE__),
+ m_ourcpu(*this, M6801_TAG),
+ write_irq(*this)
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void mpu401_device::device_start()
+{
+ write_irq.resolve_safe();
+ m_timer = timer_alloc(0, NULL);
+}
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void mpu401_device::device_reset()
+{
+ m_port2 = 0xff & ~(P2_SRCK_OUT | P2_MIDI_IN); // prevent spurious reception
+ m_command = 0;
+ m_mpudata = 0;
+ m_gatearrstat = 0;
+
+ m_timer->adjust(attotime::zero, 0, attotime::from_hz(31250*8));
+}
+
+//-------------------------------------------------
+// device_timer - called when our device timer expires
+//-------------------------------------------------
+
+void mpu401_device::device_timer(emu_timer &timer, device_timer_id tid, int param, void *ptr)
+{
+ m_ourcpu->m6801_clock_serial();
+}
+
+READ8_MEMBER(mpu401_device::regs_mode2_r)
+{
+ switch (offset)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 0xf:
+// printf("MPU401: read @ unk %x (PC=%x)\n", offset, space.device().safe_pc());
+ break;
+
+ default:
+ return m_ourcpu->m6801_io_r(space, offset);
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(mpu401_device::regs_mode2_w)
+{
+ switch (offset)
+ {
+ case 4:
+ case 5:
+ case 6:
+ case 7:
+ case 0xf:
+// printf("MPU401: %02x @ unk %x (PC=%x)\n", data, offset, space.device().safe_pc());
+ break;
+
+ default:
+ return m_ourcpu->m6801_io_w(space, offset, data);
+ }
+}
+
+READ8_MEMBER(mpu401_device::port1_r)
+{
+ return 0xff;
+}
+
+WRITE8_MEMBER(mpu401_device::port1_w)
+{
+// printf("port1_w: %02x met %x syncout %x DSRD %d DRRD %d\n", data, data & 3, (data>>3) & 3, (data>>6) & 1, (data>>7) & 1);
+}
+
+READ8_MEMBER(mpu401_device::port2_r)
+{
+// printf("Read P2 (PC=%x)\n", space.device().safe_pc());
+ return m_port2;
+}
+
+WRITE8_MEMBER(mpu401_device::port2_w)
+{
+// printf("port2_w: %02x SYCOUT %d SYCIN %d SRCK %d MIDI OUT %d\n", data, (data & 1), (data>>1) & 1, (data>>2) & 1, (data>>4) & 1);
+}
+
+READ8_MEMBER(mpu401_device::mpu_r)
+{
+// printf("mpu_r @ %d\n", offset);
+
+ if (offset == 1) // status
+ {
+ return m_gatearrstat;
+ }
+ else // data
+ {
+ write_irq(CLEAR_LINE);
+ m_gatearrstat |= STAT_RX_EMPTY;
+ return m_mpudata;
+ }
+}
+
+WRITE8_MEMBER(mpu401_device::mpu_w)
+{
+// printf("%02x to MPU-401 @ %d\n", data, offset);
+ m_command = data;
+ m_gatearrstat |= STAT_TX_FULL;
+
+ if (offset == 1)
+ {
+ m_gatearrstat |= STAT_CMD_PORT;
+ }
+ else
+ {
+ m_gatearrstat &= ~STAT_CMD_PORT;
+ }
+}
+
+READ8_MEMBER(mpu401_device::asic_r)
+{
+ if (offset == 0)
+ {
+ m_gatearrstat &= ~STAT_TX_FULL;
+ return m_command;
+ }
+ else if (offset == 1)
+ {
+ return m_gatearrstat;
+ }
+
+ return 0xff;
+}
+
+WRITE8_MEMBER(mpu401_device::asic_w)
+{
+// printf("MPU401: %02x to gate array @ %d\n", data, offset);
+
+ if (offset == 1)
+ {
+ m_mpudata = data;
+ m_gatearrstat &= ~STAT_RX_EMPTY;
+ write_irq(ASSERT_LINE);
+ }
+}
+
+// MIDI receive
+WRITE_LINE_MEMBER( mpu401_device::midi_rx_w )
+{
+ if (state == ASSERT_LINE)
+ {
+ m_port2 |= P2_MIDI_IN;
+ }
+ else
+ {
+ m_port2 &= ~P2_MIDI_IN;
+ }
+}
diff --git a/src/emu/machine/mpu401.h b/src/emu/machine/mpu401.h
new file mode 100644
index 00000000000..972484cb27c
--- /dev/null
+++ b/src/emu/machine/mpu401.h
@@ -0,0 +1,70 @@
+#pragma once
+
+#ifndef __MPU401_H__
+#define __MPU401_H__
+
+#include "emu.h"
+#include "cpu/m6800/m6800.h"
+
+#define MCFG_MPU401_ADD(_tag, _irqf ) \
+ MCFG_DEVICE_ADD(_tag, MPU401, 0) \
+ MCFG_IRQ_FUNC(_irqf)
+
+#define MCFG_IRQ_FUNC(_irqf) \
+ downcast<mpu401_device *>(device)->set_irqf(DEVCB2_##_irqf);
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class mpu401_device : public device_t
+{
+public:
+ // construction/destruction
+ mpu401_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ required_device<m6801_cpu_device> m_ourcpu;
+
+ template<class _write> void set_irqf(_write wr)
+ {
+ write_irq.set_callback(wr);
+ }
+
+ devcb2_write_line write_irq;
+
+ DECLARE_READ8_MEMBER(regs_mode2_r);
+ DECLARE_WRITE8_MEMBER(regs_mode2_w);
+ DECLARE_READ8_MEMBER(asic_r);
+ DECLARE_WRITE8_MEMBER(asic_w);
+ DECLARE_READ8_MEMBER(port1_r);
+ DECLARE_WRITE8_MEMBER(port1_w);
+ DECLARE_READ8_MEMBER(port2_r);
+ DECLARE_WRITE8_MEMBER(port2_w);
+ DECLARE_WRITE_LINE_MEMBER(midi_rx_w);
+
+ // public API - call for reads/writes at I/O 330/331 on PC, C0n0/C0n1 on Apple II, etc.
+ DECLARE_READ8_MEMBER(mpu_r);
+ DECLARE_WRITE8_MEMBER(mpu_w);
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual const rom_entry *device_rom_region() const;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ UINT8 m_port2;
+ UINT8 m_command;
+ UINT8 m_mpudata;
+ UINT8 m_gatearrstat;
+ emu_timer *m_timer;
+};
+
+// device type definition
+extern const device_type MPU401;
+
+#endif /* __MPU401_H__ */
diff --git a/src/emu/machine/pc_fdc.c b/src/emu/machine/pc_fdc.c
new file mode 100644
index 00000000000..6fd182d01ef
--- /dev/null
+++ b/src/emu/machine/pc_fdc.c
@@ -0,0 +1,195 @@
+/**********************************************************************
+
+ PC-style floppy disk controller emulation
+
+ TODO:
+ - check how the drive select from DOR register, and the drive select
+ from the fdc are related !!!!
+ - if all drives do not have a disk in them, and the fdc is reset, is a int generated?
+ (if yes, indicates drives are ready without discs, if no indicates no drives are ready)
+ - status register a, status register b
+
+**********************************************************************/
+
+#include "emu.h"
+#include "machine/pc_fdc.h"
+
+const device_type PC_FDC_XT = &device_creator<pc_fdc_xt_device>;
+const device_type PC_FDC_AT = &device_creator<pc_fdc_at_device>;
+
+static MACHINE_CONFIG_FRAGMENT( cfg )
+ MCFG_UPD765A_ADD("upd765", false, false)
+MACHINE_CONFIG_END
+
+DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_family_device)
+ADDRESS_MAP_END
+
+// The schematics show address decoding is minimal
+DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_xt_device)
+ AM_RANGE(0x0, 0x0) AM_DEVREAD("upd765", upd765a_device, msr_r) AM_WRITE(dor_w)
+ AM_RANGE(0x1, 0x1) AM_DEVREAD("upd765", upd765a_device, fifo_r) AM_WRITE(dor_fifo_w)
+ AM_RANGE(0x2, 0x2) AM_WRITE(dor_w)
+ AM_RANGE(0x3, 0x3) AM_WRITE(dor_w)
+ AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map)
+ADDRESS_MAP_END
+
+
+// Decoding is through a PAL, so presumably complete
+DEVICE_ADDRESS_MAP_START(map, 8, pc_fdc_at_device)
+ AM_RANGE(0x2, 0x2) AM_READWRITE(dor_r, dor_w)
+ AM_RANGE(0x4, 0x5) AM_DEVICE("upd765", upd765a_device, map)
+ AM_RANGE(0x7, 0x7) AM_READWRITE(dir_r, ccr_w)
+ADDRESS_MAP_END
+
+pc_fdc_family_device::pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source) : pc_fdc_interface(mconfig, type, name, tag, owner, clock, shortname, source), fdc(*this, "upd765")
+{
+}
+
+void pc_fdc_family_device::setup_intrq_cb(line_cb cb)
+{
+ intrq_cb = cb;
+}
+
+void pc_fdc_family_device::setup_drq_cb(line_cb cb)
+{
+ drq_cb = cb;
+}
+
+void pc_fdc_family_device::tc_w(bool state)
+{
+ fdc->tc_w(state);
+}
+
+UINT8 pc_fdc_family_device::dma_r()
+{
+ return fdc->dma_r();
+}
+
+void pc_fdc_family_device::dma_w(UINT8 data)
+{
+ fdc->dma_w(data);
+}
+
+machine_config_constructor pc_fdc_family_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(cfg);
+}
+
+void pc_fdc_family_device::device_start()
+{
+ fdc->setup_intrq_cb(upd765a_device::line_cb(FUNC(pc_fdc_family_device::irq_w), this));
+ fdc->setup_drq_cb(upd765a_device::line_cb(FUNC(pc_fdc_family_device::drq_w), this));
+
+ for(int i=0; i<4; i++) {
+ char name[2] = {'0'+i, 0};
+ floppy_connector *conn = subdevice<floppy_connector>(name);
+ floppy[i] = conn ? conn->get_device() : NULL;
+ }
+
+ irq = drq = false;
+ fdc_irq = fdc_drq = false;
+ dor = 0x00;
+}
+
+void pc_fdc_family_device::device_reset()
+{
+}
+
+// Bits 0-1 select one of the 4 drives, but only if the associated
+// motor bit is on
+
+// Bit 2 is tied to the upd765 reset line
+
+// Bit 3 enables the irq and drq lines
+
+// Bit 4-7 control the drive motors
+
+WRITE8_MEMBER( pc_fdc_family_device::dor_w )
+{
+ logerror("%s: dor = %02x\n", tag(), data);
+ UINT8 pdor = dor;
+ dor = data;
+
+ for(int i=0; i<4; i++)
+ if(floppy[i])
+ floppy[i]->mon_w(!(dor & (0x10 << i)));
+
+ int fid = dor & 3;
+ if(dor & (0x10 << fid))
+ fdc->set_floppy(floppy[fid]);
+ else
+ fdc->set_floppy(NULL);
+
+ check_irq();
+ check_drq();
+ if((pdor^dor) & 4)
+ fdc->reset();
+}
+
+READ8_MEMBER( pc_fdc_family_device::dor_r )
+{
+ return dor;
+}
+
+READ8_MEMBER( pc_fdc_family_device::dir_r )
+{
+ return do_dir_r();
+}
+
+WRITE8_MEMBER( pc_fdc_family_device::ccr_w )
+{
+ static const int rates[4] = { 500000, 300000, 250000, 1000000 };
+ logerror("%s: ccr = %02x\n", tag(), data);
+ fdc->set_rate(rates[data & 3]);
+}
+
+UINT8 pc_fdc_family_device::do_dir_r()
+{
+ if(floppy[dor & 3])
+ return floppy[dor & 3]->dskchg_r() ? 0x00 : 0x80;
+ return 0x00;
+}
+
+WRITE8_MEMBER( pc_fdc_xt_device::dor_fifo_w)
+{
+ fdc->fifo_w(space, 0, data, mem_mask);
+ dor_w(space, 0, data, mem_mask);
+}
+
+void pc_fdc_family_device::irq_w(bool state)
+{
+ fdc_irq = state;
+ check_irq();
+}
+
+void pc_fdc_family_device::drq_w(bool state)
+{
+ fdc_drq = state;
+ check_drq();
+}
+
+void pc_fdc_family_device::check_irq()
+{
+ bool pirq = irq;
+ irq = fdc_irq && (dor & 4) && (dor & 8);
+ if(irq != pirq && !intrq_cb.isnull()) {
+ logerror("%s: pc_irq = %d\n", tag(), irq);
+ intrq_cb(irq);
+ }
+}
+
+void pc_fdc_family_device::check_drq()
+{
+ bool pdrq = drq;
+ drq = fdc_drq && (dor & 4) && (dor & 8);
+ if(drq != pdrq && !drq_cb.isnull())
+ drq_cb(drq);
+}
+
+pc_fdc_xt_device::pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_XT, "PC FDC XT", tag, owner, clock, "pc_fdc_xt", __FILE__)
+{
+}
+
+pc_fdc_at_device::pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : pc_fdc_family_device(mconfig, PC_FDC_AT, "PC FDC AT", tag, owner, clock, "pc_fdc_at", __FILE__)
+{
+}
diff --git a/src/emu/machine/pc_fdc.h b/src/emu/machine/pc_fdc.h
new file mode 100644
index 00000000000..b081f95d221
--- /dev/null
+++ b/src/emu/machine/pc_fdc.h
@@ -0,0 +1,75 @@
+/**********************************************************************
+
+ PC-style floppy disk controller emulation
+
+**********************************************************************/
+
+#ifndef PC_FDC_H
+#define PC_FDC_H
+
+#include "emu.h"
+#include "machine/upd765.h"
+
+#define MCFG_PC_FDC_XT_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PC_FDC_XT, 0)
+
+#define MCFG_PC_FDC_AT_ADD(_tag) \
+ MCFG_DEVICE_ADD(_tag, PC_FDC_AT, 0)
+
+class pc_fdc_family_device : public pc_fdc_interface {
+public:
+ pc_fdc_family_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock, const char *shortname, const char *source);
+
+ required_device<upd765a_device> fdc;
+
+ virtual void setup_intrq_cb(line_cb cb);
+ virtual void setup_drq_cb(line_cb cb);
+
+ virtual DECLARE_ADDRESS_MAP(map, 8);
+
+ virtual void tc_w(bool state);
+ virtual UINT8 dma_r();
+ virtual void dma_w(UINT8 data);
+ virtual UINT8 do_dir_r();
+
+ READ8_MEMBER(dor_r);
+ WRITE8_MEMBER(dor_w);
+ READ8_MEMBER(dir_r);
+ WRITE8_MEMBER(ccr_w);
+
+protected:
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+ line_cb intrq_cb, drq_cb;
+ bool irq, drq, fdc_drq, fdc_irq;
+ UINT8 dor;
+
+ floppy_image_device *floppy[4];
+
+ void irq_w(bool state);
+ void drq_w(bool state);
+ void check_irq();
+ void check_drq();
+};
+
+class pc_fdc_xt_device : public pc_fdc_family_device {
+public:
+ pc_fdc_xt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual DECLARE_ADDRESS_MAP(map, 8);
+ WRITE8_MEMBER(dor_fifo_w);
+};
+
+class pc_fdc_at_device : public pc_fdc_family_device {
+public:
+ pc_fdc_at_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual DECLARE_ADDRESS_MAP(map, 8);
+};
+
+extern const device_type PC_FDC_XT;
+extern const device_type PC_FDC_AT;
+
+#endif /* PC_FDC_H */
diff --git a/src/emu/machine/pc_lpt.c b/src/emu/machine/pc_lpt.c
new file mode 100644
index 00000000000..e5558835e21
--- /dev/null
+++ b/src/emu/machine/pc_lpt.c
@@ -0,0 +1,170 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#include "emu.h"
+#include "pc_lpt.h"
+#include "bus/centronics/covox.h"
+#include "bus/centronics/image.h"
+
+
+const device_type PC_LPT = &device_creator<pc_lpt_device>;
+
+pc_lpt_device::pc_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, PC_LPT, "PC-LPT", tag, owner, clock, "pc_lpt", __FILE__),
+ m_irq(1),
+ m_data(0xff),
+ m_irq_enabled(1),
+ m_centronics_ack(1),
+ m_irq_handler(*this),
+ m_cent_data_in(*this, "cent_data_in"),
+ m_cent_data_out(*this, "cent_data_out"),
+ m_cent_status_in(*this, "cent_status_in"),
+ m_cent_ctrl_in(*this, "cent_ctrl_in"),
+ m_cent_ctrl_out(*this, "cent_ctrl_out")
+{
+}
+
+void pc_lpt_device::device_start()
+{
+ m_irq_handler.resolve_safe();
+
+ save_item(NAME(m_irq));
+ save_item(NAME(m_data));
+ save_item(NAME(m_control));
+ save_item(NAME(m_centronics_ack));
+ save_item(NAME(m_irq_enabled));
+
+ m_cent_data_out->write(m_data);
+}
+
+void pc_lpt_device::device_reset()
+{
+ m_control = ~(0 ^ CONTROL_INIT);
+ m_cent_ctrl_out->write(m_control);
+}
+
+static SLOT_INTERFACE_START(pc_centronics)
+ SLOT_INTERFACE("image", CENTRONICS_PRINTER_IMAGE)
+ SLOT_INTERFACE("covox", CENTRONICS_COVOX)
+ SLOT_INTERFACE("covox_stereo", CENTRONICS_COVOX_STEREO)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( pc_lpt )
+ MCFG_CENTRONICS_ADD("centronics", pc_centronics, "image")
+ MCFG_CENTRONICS_DATA_INPUT_BUFFER("cent_data_in")
+ MCFG_CENTRONICS_FAULT_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit3))
+ MCFG_CENTRONICS_SELECT_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit4))
+ MCFG_CENTRONICS_PERROR_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit5))
+ MCFG_CENTRONICS_ACK_HANDLER(WRITELINE(pc_lpt_device, write_centronics_ack))
+ MCFG_CENTRONICS_BUSY_HANDLER(DEVWRITELINE("cent_status_in", input_buffer_device, write_bit7))
+
+ MCFG_CENTRONICS_STROBE_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit0))
+ MCFG_CENTRONICS_AUTOFD_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit1))
+ MCFG_CENTRONICS_INIT_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit2))
+ MCFG_CENTRONICS_SELECT_IN_HANDLER(DEVWRITELINE("cent_ctrl_in", input_buffer_device, write_bit3))
+
+ MCFG_DEVICE_ADD("cent_data_in", INPUT_BUFFER, 0)
+ MCFG_DEVICE_ADD("cent_ctrl_in", INPUT_BUFFER, 0)
+ MCFG_DEVICE_ADD("cent_status_in", INPUT_BUFFER, 0)
+
+ MCFG_CENTRONICS_OUTPUT_LATCH_ADD("cent_data_out", "centronics")
+
+ MCFG_DEVICE_ADD("cent_ctrl_out", OUTPUT_LATCH, 0)
+ MCFG_OUTPUT_LATCH_BIT0_HANDLER(DEVWRITELINE("centronics", centronics_device, write_strobe))
+ MCFG_OUTPUT_LATCH_BIT1_HANDLER(DEVWRITELINE("centronics", centronics_device, write_autofd))
+ MCFG_OUTPUT_LATCH_BIT2_HANDLER(DEVWRITELINE("centronics", centronics_device, write_init))
+ MCFG_OUTPUT_LATCH_BIT3_HANDLER(DEVWRITELINE("centronics", centronics_device, write_select_in))
+ MCFG_OUTPUT_LATCH_BIT4_HANDLER(WRITELINE(pc_lpt_device, write_irq_enabled))
+MACHINE_CONFIG_END
+
+machine_config_constructor pc_lpt_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( pc_lpt );
+}
+
+READ8_MEMBER( pc_lpt_device::data_r )
+{
+ // pull up mechanism for input lines, zeros are provided by peripheral
+ return m_data & m_cent_data_in->read();
+}
+
+WRITE8_MEMBER( pc_lpt_device::data_w )
+{
+ m_data = data;
+ m_cent_data_out->write(m_data);
+}
+
+READ8_MEMBER( pc_lpt_device::status_r )
+{
+ return m_cent_status_in->read() ^ STATUS_BUSY;
+}
+
+READ8_MEMBER( pc_lpt_device::control_r )
+{
+ return ~((m_control & m_cent_ctrl_in->read() & 0x3f) ^ CONTROL_INIT);
+}
+
+WRITE8_MEMBER( pc_lpt_device::control_w )
+{
+ // logerror("pc_lpt_control_w: 0x%02x\n", data);
+
+ m_control = ~(data ^ CONTROL_INIT);
+ m_cent_ctrl_out->write(m_control);
+}
+
+READ8_MEMBER( pc_lpt_device::read )
+{
+ switch (offset)
+ {
+ case 0: return data_r(space, 0);
+ case 1: return status_r(space, 0);
+ case 2: return control_r(space, 0);
+ }
+
+ /* if we reach this its an error */
+ logerror("PC-LPT %s: Read from invalid offset %x\n", tag(), offset);
+
+ return 0xff;
+}
+
+WRITE8_MEMBER( pc_lpt_device::write )
+{
+ switch (offset)
+ {
+ case 0: data_w(space, 0, data); break;
+ case 1: break;
+ case 2: control_w(space, 0, data); break;
+ }
+}
+
+void pc_lpt_device::update_irq()
+{
+ int irq = 1; // high impedance
+ if (!m_irq_enabled)
+ {
+ irq = m_centronics_ack;
+ }
+
+ if (m_irq != irq)
+ {
+ m_irq = irq;
+ m_irq_handler(!irq);
+ }
+}
+
+WRITE_LINE_MEMBER( pc_lpt_device::write_irq_enabled )
+{
+ m_irq_enabled = state;
+ update_irq();
+}
+
+WRITE_LINE_MEMBER( pc_lpt_device::write_centronics_ack )
+{
+ m_centronics_ack = state;
+ m_cent_status_in->write_bit6(state);
+ update_irq();
+}
+
diff --git a/src/emu/machine/pc_lpt.h b/src/emu/machine/pc_lpt.h
new file mode 100644
index 00000000000..04e8e9a8105
--- /dev/null
+++ b/src/emu/machine/pc_lpt.h
@@ -0,0 +1,85 @@
+/***************************************************************************
+
+ IBM-PC printer interface
+
+***************************************************************************/
+
+#ifndef __PC_LPT_H__
+#define __PC_LPT_H__
+
+#include "bus/centronics/ctronics.h"
+
+#define MCFG_PC_LPT_IRQ_HANDLER(_devcb) \
+ devcb = &pc_lpt_device::set_irq_handler(*device, DEVCB2_##_devcb);
+
+/***************************************************************************
+ DEVICE CONFIGURATION MACROS
+***************************************************************************/
+
+class pc_lpt_device : public device_t
+{
+public:
+ pc_lpt_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // static configuration helpers
+ template<class _Object> static devcb2_base &set_irq_handler(device_t &device, _Object object) { return downcast<pc_lpt_device &>(device).m_irq_handler.set_callback(object); }
+
+ DECLARE_READ8_MEMBER( read );
+ DECLARE_WRITE8_MEMBER( write );
+
+ DECLARE_READ8_MEMBER( data_r );
+ DECLARE_WRITE8_MEMBER( data_w );
+ DECLARE_READ8_MEMBER( status_r );
+ DECLARE_READ8_MEMBER( control_r );
+ DECLARE_WRITE8_MEMBER( control_w );
+
+ DECLARE_WRITE_LINE_MEMBER( write_irq_enabled );
+ DECLARE_WRITE_LINE_MEMBER( write_centronics_ack );
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+private:
+ void update_irq();
+
+ enum
+ {
+ CONTROL_STROBE = 1,
+ CONTROL_AUTOFD = 2,
+ CONTROL_INIT = 4,
+ CONTROL_SELECT = 8,
+ CONTROL_IRQ_ENABLED = 16,
+ CONTROL_OUTPUT_ENABLED = 32
+ };
+
+ enum
+ {
+ STATUS_FAULT = 8,
+ STATUS_SELECT = 16,
+ STATUS_PERROR = 32,
+ STATUS_ACK = 64,
+ STATUS_BUSY = 128
+ };
+
+ // internal state
+
+ int m_irq;
+ UINT8 m_data;
+ UINT8 m_control;
+ int m_irq_enabled;
+ int m_centronics_ack;
+
+ devcb2_write_line m_irq_handler;
+ required_device<input_buffer_device> m_cent_data_in;
+ required_device<output_latch_device> m_cent_data_out;
+ required_device<input_buffer_device> m_cent_status_in;
+ required_device<input_buffer_device> m_cent_ctrl_in;
+ required_device<output_latch_device> m_cent_ctrl_out;
+};
+
+extern const device_type PC_LPT;
+
+#endif /* __PC_LPT__ */
diff --git a/src/emu/video/crtc_ega.c b/src/emu/video/crtc_ega.c
new file mode 100644
index 00000000000..b7ba092c75b
--- /dev/null
+++ b/src/emu/video/crtc_ega.c
@@ -0,0 +1,740 @@
+/**********************************************************************
+
+ IBM EGA CRT Controller emulation
+
+ This controller is very loosely based on the mc6845.
+
+**********************************************************************/
+
+#include "emu.h"
+#include "crtc_ega.h"
+
+
+#define LOG (1)
+
+
+const device_type CRTC_EGA = &device_creator<crtc_ega_device>;
+
+
+void crtc_ega_device::device_config_complete()
+{
+ const crtc_ega_interface *intf = reinterpret_cast<const crtc_ega_interface *>(static_config());
+
+ if ( intf != NULL )
+ {
+ *static_cast<crtc_ega_interface *>(this) = *intf;
+ }
+ else
+ {
+ m_hpixels_per_column = 0;
+ m_begin_update = NULL;
+ m_update_row = NULL;
+ m_end_update = NULL;
+ memset(&m_out_de_func, 0, sizeof(m_out_de_func));
+ memset(&m_out_hsync_func, 0, sizeof(m_out_hsync_func));
+ memset(&m_out_vsync_func, 0, sizeof(m_out_vsync_func));
+ memset(&m_out_vblank_func, 0, sizeof(m_out_vblank_func));
+ }
+}
+
+
+crtc_ega_device::crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, CRTC_EGA, "crtc_EGA", tag, owner, clock, "crtc_ega", __FILE__),
+ device_video_interface(mconfig, *this, false)
+{
+}
+
+
+void crtc_ega_device::device_post_load()
+{
+ recompute_parameters(true);
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::address_w )
+{
+ m_register_address_latch = data & 0x1f;
+}
+
+
+READ8_MEMBER( crtc_ega_device::register_r )
+{
+ UINT8 ret = 0;
+
+ switch (m_register_address_latch)
+ {
+ case 0x0c: ret = (m_disp_start_addr >> 8) & 0xff; break;
+ case 0x0d: ret = (m_disp_start_addr >> 0) & 0xff; break;
+ case 0x0e: ret = (m_cursor_addr >> 8) & 0xff; break;
+ case 0x0f: ret = (m_cursor_addr >> 0) & 0xff; break;
+ case 0x10: ret = (m_light_pen_addr >> 8) & 0xff; m_light_pen_latched = FALSE; break;
+ case 0x11: ret = (m_light_pen_addr >> 0) & 0xff; m_light_pen_latched = FALSE; break;
+
+ /* all other registers are write only and return 0 */
+ default: break;
+ }
+
+ return ret;
+}
+
+
+WRITE8_MEMBER( crtc_ega_device::register_w )
+{
+ if (LOG) logerror("%s CRTC_EGA: reg 0x%02x = 0x%02x\n", machine().describe_context(), m_register_address_latch, data);
+
+ switch (m_register_address_latch)
+ {
+ case 0x00: m_horiz_char_total = data & 0xff; break;
+ case 0x01: m_horiz_disp = data & 0xff; break;
+ case 0x02: m_horiz_blank_start = data & 0xff; break;
+ case 0x03: m_horiz_blank_end = ((data & 0x1f) << 0) | (m_horiz_blank_end & 0x20);
+ m_de_skew = ((data & 0x60) >> 5);
+ m_ena_vert_access = data & 0x80;
+ break;
+ case 0x04: m_horiz_retr_start = data & 0xff; break;
+ case 0x05: m_horiz_retr_end = data & 0x1f;
+ m_horiz_retr_skew = ((data & 0x60) >> 5);
+ m_horiz_blank_end = ((data & 0x80) >> 2) | (m_horiz_blank_end & 0x1f);
+ break;
+ case 0x06: m_vert_total = ((data & 0xff) << 0) | (m_vert_total & 0x0300); break;
+ case 0x07: m_vert_total = ((data & 0x01) << 8) | (m_vert_total & 0x02ff);
+ m_vert_disp_end = ((data & 0x02) << 7) | (m_vert_disp_end & 0x02ff);
+ m_vert_retr_start = ((data & 0x04) << 6) | (m_vert_retr_start & 0x02ff);
+ m_vert_blank_start = ((data & 0x08) << 5) | (m_vert_blank_start & 0x02ff);
+ m_line_compare = ((data & 0x10) << 4) | (m_line_compare & 0x02ff);
+ m_vert_total = ((data & 0x20) << 4) | (m_vert_total & 0x01ff);
+ m_vert_disp_end = ((data & 0x40) << 3) | (m_vert_disp_end & 0x1ff);
+ m_vert_retr_start = ((data & 0x80) << 2) | (m_vert_retr_start & 0x01ff);
+ break;
+ case 0x08: m_preset_row_scan = data & 0x1f;
+ m_byte_panning = ((data & 0x60) >> 5);
+ break;
+ case 0x09: m_max_ras_addr = data & 0x1f;
+ m_vert_blank_start = ((data & 0x20) << 4) | (m_vert_blank_start & 0x01ff);
+ m_line_compare = ((data & 0x40) << 3) | (m_line_compare & 0x01ff);
+ m_scan_doubling = data & 0x80;
+ break;
+ case 0x0a: m_cursor_start_ras = data & 0x1f;
+ m_cursor_disable = data & 0x20;
+ break;
+ case 0x0b: m_cursor_end_ras = data & 0x1f;
+ m_cursor_skew = ((data & 0x60) >> 5);
+ break;
+ case 0x0c: m_disp_start_addr = ((data & 0xff) << 8) | (m_disp_start_addr & 0x00ff); break;
+ case 0x0d: m_disp_start_addr = ((data & 0xff) << 0) | (m_disp_start_addr & 0xff00); break;
+ case 0x0e: m_cursor_addr = ((data & 0xff) << 8) | (m_cursor_addr & 0x00ff); break;
+ case 0x0f: m_cursor_addr = ((data & 0xff) << 0) | (m_cursor_addr & 0xff00); break;
+ case 0x10: m_vert_retr_start = ((data & 0xff) << 0) | (m_vert_retr_start & 0x0300); break;
+ case 0x11: m_vert_retr_end = data & 0x0f;
+ m_bandwidth = data & 0x40;
+ m_protect = data & 0x80;
+ break;
+ case 0x12: m_vert_disp_end = ((data & 0xff) << 0) | (m_vert_disp_end & 0x0300); break;
+ case 0x13: m_offset = data & 0xff; break;
+ case 0x14: m_underline_loc = data & 0x7f; break;
+ case 0x15: m_vert_blank_start = ((data & 0xff) << 0) | (m_vert_blank_start & 0x0300); break;
+ case 0x16: m_vert_blank_end = data & 0x7f; break;
+ case 0x17: m_mode_control = data & 0xff; break;
+ case 0x18: m_line_compare = ((data & 0xff) << 0) | (m_line_compare & 0x0300); break;
+ default: break;
+ }
+
+ recompute_parameters(false);
+}
+
+
+void crtc_ega_device::recompute_parameters(bool postload)
+{
+ UINT16 hsync_on_pos, hsync_off_pos, vsync_on_pos, vsync_off_pos;
+
+ /* compute the screen sizes */
+ UINT16 horiz_pix_total = (m_horiz_char_total + 2) * m_hpixels_per_column;
+ UINT16 vert_pix_total = m_vert_total + 1;
+
+ /* determine the visible area, avoid division by 0 */
+ UINT16 max_visible_x = ( m_horiz_disp + 1 ) * m_hpixels_per_column - 1;
+ UINT16 max_visible_y = m_vert_disp_end;
+
+ /* determine the syncing positions */
+ int horiz_sync_char_width = ( m_horiz_retr_end + 1 ) - ( m_horiz_retr_start & 0x1f );
+ int vert_sync_pix_width = m_vert_retr_end - ( m_vert_retr_start & 0x0f );
+
+ if (horiz_sync_char_width <= 0)
+ horiz_sync_char_width += 0x10;
+
+ if (vert_sync_pix_width <= 0)
+ vert_sync_pix_width += 0x10;
+
+ hsync_on_pos = m_horiz_retr_start * m_hpixels_per_column;
+ hsync_off_pos = hsync_on_pos + (horiz_sync_char_width * m_hpixels_per_column);
+ vsync_on_pos = m_vert_retr_start; /* + 1 ?? */
+ vsync_off_pos = vsync_on_pos + vert_sync_pix_width;
+
+ if (hsync_off_pos > horiz_pix_total)
+ hsync_off_pos = horiz_pix_total;
+
+ if (vsync_off_pos > vert_pix_total)
+ vsync_off_pos = vert_pix_total;
+
+ if ( vsync_on_pos >= vsync_off_pos )
+ {
+ vsync_on_pos = vsync_off_pos - 2;
+ }
+
+ /* update only if screen parameters changed, unless we are coming here after loading the saved state */
+ if (postload ||
+ (horiz_pix_total != m_horiz_pix_total) || (vert_pix_total != m_vert_pix_total) ||
+ (max_visible_x != m_max_visible_x) || (max_visible_y != m_max_visible_y) ||
+ (hsync_on_pos != m_hsync_on_pos) || (vsync_on_pos != m_vsync_on_pos) ||
+ (hsync_off_pos != m_hsync_off_pos) || (vsync_off_pos != m_vsync_off_pos))
+ {
+ /* update the screen if we have valid data */
+ if ((horiz_pix_total > 0) && (max_visible_x < horiz_pix_total) &&
+ (vert_pix_total > 0) && (max_visible_y < vert_pix_total) &&
+ (hsync_on_pos <= horiz_pix_total) && (vsync_on_pos <= vert_pix_total) &&
+ (hsync_on_pos != hsync_off_pos))
+ {
+ attoseconds_t refresh = HZ_TO_ATTOSECONDS(m_clock) * (m_horiz_char_total + 2) * vert_pix_total;
+
+ rectangle visarea(0, max_visible_x, 0, max_visible_y);
+
+ if (LOG) logerror("CRTC_EGA config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x Freq: %ffps\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1, 1 / ATTOSECONDS_TO_DOUBLE(refresh));
+
+ if ( m_screen != NULL )
+ m_screen->configure(horiz_pix_total, vert_pix_total, visarea, refresh);
+
+ m_has_valid_parameters = true;
+ }
+ else
+ {
+ m_has_valid_parameters = false;
+ if (LOG) logerror("CRTC_EGA bad config screen: HTOTAL: 0x%x VTOTAL: 0x%x MAX_X: 0x%x MAX_Y: 0x%x HSYNC: 0x%x-0x%x VSYNC: 0x%x-0x%x\n",
+ horiz_pix_total, vert_pix_total, max_visible_x, max_visible_y, hsync_on_pos, hsync_off_pos - 1, vsync_on_pos, vsync_off_pos - 1);
+
+ }
+
+ m_horiz_pix_total = horiz_pix_total;
+ m_vert_pix_total = vert_pix_total;
+ m_max_visible_x = max_visible_x;
+ m_max_visible_y = max_visible_y;
+ m_hsync_on_pos = hsync_on_pos;
+ m_hsync_off_pos = hsync_off_pos;
+ m_vsync_on_pos = vsync_on_pos;
+ m_vsync_off_pos = vsync_off_pos;
+ }
+}
+
+
+void crtc_ega_device::update_counters()
+{
+ m_character_counter = m_line_timer->elapsed().as_ticks( m_clock );
+
+ if ( m_hsync_off_timer->enabled() )
+ {
+ m_hsync_width_counter = m_hsync_off_timer->elapsed().as_ticks( m_clock );
+ }
+}
+
+
+void crtc_ega_device::set_de(int state)
+{
+ if ( m_de != state )
+ {
+ m_de = state;
+
+ if ( !m_res_out_de_func.isnull() )
+ m_res_out_de_func( m_de );
+ }
+}
+
+
+void crtc_ega_device::set_hsync(int state)
+{
+ if ( m_hsync != state )
+ {
+ m_hsync = state;
+
+ if ( !m_res_out_hsync_func.isnull() )
+ m_res_out_hsync_func( m_hsync );
+ }
+}
+
+
+void crtc_ega_device::set_vsync(int state)
+{
+ if ( m_vsync != state )
+ {
+ m_vsync = state;
+
+ if ( !m_res_out_vsync_func.isnull() )
+ m_res_out_vsync_func( m_vsync );
+ }
+}
+
+
+void crtc_ega_device::set_vblank(int state)
+{
+ if ( m_vblank != state )
+ {
+ m_vblank = state;
+
+ if ( !m_res_out_vblank_func.isnull() )
+ m_res_out_vblank_func( m_vblank );
+ }
+}
+
+
+void crtc_ega_device::set_cur(int state)
+{
+ if ( m_cur != state )
+ {
+ m_cur = state;
+
+// if ( !m_res_out_cur_func.isnull() )
+// m_res_out_cur_func( m_cur );
+ }
+}
+
+
+void crtc_ega_device::handle_line_timer()
+{
+ int new_vsync = m_vsync;
+
+ m_character_counter = 0;
+ m_cursor_x = -1;
+
+ /* Check if VSYNC is active */
+ if ( m_vsync_ff )
+ {
+ m_vsync_width_counter = ( m_vsync_width_counter + 1 ) & 0x0F;
+
+ /* Check if we've reached end of VSYNC */
+ if ( m_vsync_width_counter == m_vert_retr_end )
+ {
+ m_vsync_ff = 0;
+
+ new_vsync = FALSE;
+ }
+ }
+
+ if ( m_raster_counter == m_max_ras_addr )
+ {
+ m_raster_counter = 0;
+ m_line_address = ( m_line_address + m_horiz_disp + 1 ) & 0xffff;
+ }
+ else
+ {
+ m_raster_counter = ( m_raster_counter + 1 ) & 0x1F;
+ }
+
+ m_line_counter = ( m_line_counter + 1 ) & 0x3ff;
+
+ /* Check if we've reached the end of active display */
+ if ( m_line_counter == m_vert_disp_end )
+ {
+ m_line_enable_ff = false;
+ }
+
+ /* Check if VSYNC should be enabled */
+ if ( m_line_counter == m_vert_retr_start )
+ {
+ m_vsync_width_counter = 0;
+ m_vsync_ff = 1;
+
+ new_vsync = TRUE;
+ }
+
+ /* Check if we have reached the end of the vertical area */
+ if ( m_line_counter == m_vert_total )
+ {
+ m_line_counter = 0;
+ m_line_address = m_disp_start_addr;
+ m_line_enable_ff = true;
+ set_vblank( FALSE );
+ /* also update the cursor state now */
+ update_cursor_state();
+
+ if (m_screen != NULL)
+ m_screen->reset_origin();
+ }
+
+ if ( m_line_enable_ff )
+ {
+ /* Schedule DE off signal change */
+ m_de_off_timer->adjust(attotime::from_ticks( m_horiz_disp + 1, m_clock ));
+
+ /* Is cursor visible on this line? */
+ if ( m_cursor_state &&
+ (m_raster_counter >= (m_cursor_start_ras & 0x1f)) &&
+ (m_raster_counter <= m_cursor_end_ras) &&
+ (m_cursor_addr >= m_line_address) &&
+ (m_cursor_addr < (m_line_address + m_horiz_disp + 1)) )
+ {
+ m_cursor_x = m_cursor_addr - m_line_address;
+
+ /* Schedule CURSOR ON signal */
+ m_cur_on_timer->adjust( attotime::from_ticks( m_cursor_x, m_clock ) );
+ }
+ }
+
+ /* Schedule HSYNC on signal */
+ m_hsync_on_timer->adjust( attotime::from_ticks( m_horiz_blank_start, m_clock ) );
+
+ /* Set VBlank signal */
+ if ( m_line_counter == m_vert_disp_end + 1 )
+ {
+ set_vblank( TRUE );
+ }
+
+ /* Schedule our next callback */
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+
+ /* Set VSYNC and DE signals */
+ set_vsync( new_vsync );
+ set_de( m_line_enable_ff ? TRUE : FALSE );
+}
+
+
+void crtc_ega_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_LINE:
+ handle_line_timer();
+ break;
+
+ case TIMER_DE_OFF:
+ set_de( FALSE );
+ break;
+
+ case TIMER_CUR_ON:
+ set_cur( TRUE );
+
+ /* Schedule CURSOR off signal */
+ m_cur_off_timer->adjust( attotime::from_ticks( 1, m_clock ) );
+ break;
+
+ case TIMER_CUR_OFF:
+ set_cur( FALSE );
+ break;
+
+ case TIMER_HSYNC_ON:
+ {
+ INT8 hsync_width = ( 0x20 | m_horiz_blank_end ) - ( m_horiz_blank_start & 0x1f );
+
+ if ( hsync_width <= 0 )
+ {
+ hsync_width += 0x20;
+ }
+
+ m_hsync_width_counter = 0;
+ set_hsync( TRUE );
+
+ /* Schedule HSYNC off signal */
+ m_hsync_off_timer->adjust( attotime::from_ticks( hsync_width, m_clock ) );
+ }
+ break;
+
+ case TIMER_HSYNC_OFF:
+ set_hsync( FALSE );
+ break;
+
+ case TIMER_LIGHT_PEN_LATCH:
+ m_light_pen_addr = get_ma();
+ m_light_pen_latched = true;
+ break;
+ }
+}
+
+
+UINT16 crtc_ega_device::get_ma()
+{
+ update_counters();
+
+ return m_line_address + m_character_counter;
+}
+
+
+UINT8 crtc_ega_device::get_ra()
+{
+ return m_raster_counter;
+}
+
+
+void crtc_ega_device::assert_light_pen_input()
+{
+ /* compute the pixel coordinate of the NEXT character -- this is when the light pen latches */
+ /* set the timer that will latch the display address into the light pen registers */
+ m_light_pen_latch_timer->adjust(attotime::from_ticks( 1, m_clock ));
+}
+
+
+void crtc_ega_device::set_clock(int clock)
+{
+ /* validate arguments */
+ assert(clock > 0);
+
+ if (clock != m_clock)
+ {
+ m_clock = clock;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::set_hpixels_per_column(int hpixels_per_column)
+{
+ /* validate arguments */
+ assert(hpixels_per_column > 0);
+
+ if (hpixels_per_column != m_hpixels_per_column)
+ {
+ m_hpixels_per_column = hpixels_per_column;
+ recompute_parameters(true);
+ }
+}
+
+
+void crtc_ega_device::update_cursor_state()
+{
+ /* save and increment cursor counter */
+ UINT8 last_cursor_blink_count = m_cursor_blink_count;
+ m_cursor_blink_count = m_cursor_blink_count + 1;
+
+ /* switch on cursor blinking mode */
+ switch (m_cursor_start_ras & 0x60)
+ {
+ /* always on */
+ case 0x00: m_cursor_state = true; break;
+
+ /* always off */
+ case 0x20: m_cursor_state = false; break;
+
+ /* fast blink */
+ case 0x40:
+ if ((last_cursor_blink_count & 0x10) != (m_cursor_blink_count & 0x10))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+
+ /* slow blink */
+ case 0x60:
+ if ((last_cursor_blink_count & 0x20) != (m_cursor_blink_count & 0x20))
+ {
+ m_cursor_state = !m_cursor_state;
+ }
+ break;
+ }
+}
+
+
+UINT32 crtc_ega_device::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ assert(bitmap.valid());
+
+ if (m_has_valid_parameters)
+ {
+ UINT16 y;
+
+ void *param = NULL;
+
+ assert(m_update_row != NULL);
+
+ /* call the set up function if any */
+ if (m_begin_update != NULL)
+ param = m_begin_update(this, bitmap, cliprect);
+
+ if (cliprect.min_y == 0)
+ {
+ /* read the start address at the beginning of the frame */
+ m_current_disp_addr = m_disp_start_addr;
+ }
+
+ /* for each row in the visible region */
+ for (y = cliprect.min_y; y <= cliprect.max_y; y++)
+ {
+ /* compute the current raster line */
+ UINT8 ra = y % (m_max_ras_addr + 1);
+
+ /* check if the cursor is visible and is on this scanline */
+ int cursor_visible = m_cursor_state &&
+ (ra >= (m_cursor_start_ras & 0x1f)) &&
+ ( (ra <= (m_cursor_end_ras & 0x1f)) || ((m_cursor_end_ras & 0x1f) == 0x00 )) &&
+ (m_cursor_addr >= m_current_disp_addr) &&
+ (m_cursor_addr < (m_current_disp_addr + ( m_horiz_disp + 1 )));
+
+ /* compute the cursor X position, or -1 if not visible */
+ INT8 cursor_x = cursor_visible ? (m_cursor_addr - m_current_disp_addr) : -1;
+
+ /* call the external system to draw it */
+ m_update_row(this, bitmap, cliprect, m_current_disp_addr, ra, y, m_horiz_disp + 1, cursor_x, param);
+
+ /* update MA if the last raster address */
+ if (ra == m_max_ras_addr)
+ m_current_disp_addr = (m_current_disp_addr + m_horiz_disp + 1) & 0xffff;
+ }
+
+ /* call the tear down function if any */
+ if (m_end_update != NULL)
+ m_end_update(this, bitmap, cliprect, param);
+ }
+ else
+ logerror("Invalid crtc_ega screen parameters - display disabled!!!\n");
+
+ return 0;
+}
+
+
+/* device interface */
+void crtc_ega_device::device_start()
+{
+ /* validate arguments */
+ assert(m_clock > 0);
+ assert(m_hpixels_per_column > 0);
+
+ /* resolve callbacks */
+ m_res_out_de_func.resolve(m_out_de_func, *this);
+ m_res_out_hsync_func.resolve(m_out_hsync_func, *this);
+ m_res_out_vsync_func.resolve(m_out_vsync_func, *this);
+ m_res_out_vblank_func.resolve(m_out_vblank_func, *this);
+
+ /* create the timers */
+ m_line_timer = timer_alloc(TIMER_LINE);
+ m_de_off_timer = timer_alloc(TIMER_DE_OFF);
+ m_cur_on_timer = timer_alloc(TIMER_CUR_ON);
+ m_cur_off_timer = timer_alloc(TIMER_CUR_OFF);
+ m_hsync_on_timer = timer_alloc(TIMER_HSYNC_ON);
+ m_hsync_off_timer = timer_alloc(TIMER_HSYNC_OFF);
+ m_light_pen_latch_timer = timer_alloc(TIMER_LIGHT_PEN_LATCH);
+
+ /* Use some large startup values */
+ m_horiz_char_total = 0xff;
+ m_max_ras_addr = 0x1f;
+ m_vert_total = 0x3ff;
+
+ m_ena_vert_access = 0;
+ m_de_skew = 0;
+ m_horiz_retr_start = 0;
+ m_horiz_retr_end = 0;
+ m_horiz_retr_skew = 0;
+ m_preset_row_scan = 0;
+ m_byte_panning = 0;
+ m_scan_doubling = 0;
+ m_cursor_start_ras = 0x20;
+ m_cursor_disable = 0;
+ m_cursor_end_ras = 0;
+ m_cursor_skew = 0;
+ m_disp_start_addr = 0;
+ m_light_pen_addr = 0;
+ m_vert_retr_end = 0;
+ m_protect = 0;
+ m_bandwidth = 0;
+ m_offset = 0;
+ m_underline_loc = 0;
+ m_vert_blank_end = 0;
+ m_mode_control = 0;
+ m_line_compare = 0;
+ m_register_address_latch = 0;
+ m_cursor_state = false;
+ m_cursor_blink_count = 0;
+ m_cur = 0;
+ m_hsync = 0;
+ m_vsync = 0;
+ m_vblank = 0;
+ m_de = 0;
+ m_character_counter = 0;
+ m_hsync_width_counter = 0;
+ m_vsync_width_counter = 0;
+ m_line_enable_ff = false;
+ m_vsync_ff = 0;
+ m_adjust_active = 0;
+
+ m_current_disp_addr = 0;
+ m_light_pen_latched = FALSE;
+ m_has_valid_parameters = false;
+
+ /* register for state saving */
+ save_item(NAME(m_hpixels_per_column));
+ save_item(NAME(m_register_address_latch));
+ save_item(NAME(m_horiz_char_total));
+ save_item(NAME(m_horiz_disp));
+ save_item(NAME(m_horiz_blank_start));
+ save_item(NAME(m_mode_control));
+ save_item(NAME(m_cursor_start_ras));
+ save_item(NAME(m_cursor_end_ras));
+ save_item(NAME(m_disp_start_addr));
+ save_item(NAME(m_cursor_addr));
+ save_item(NAME(m_light_pen_addr));
+ save_item(NAME(m_light_pen_latched));
+ save_item(NAME(m_cursor_state));
+ save_item(NAME(m_cursor_blink_count));
+ save_item(NAME(m_horiz_blank_end));
+ save_item(NAME(m_ena_vert_access));
+ save_item(NAME(m_de_skew));
+ save_item(NAME(m_horiz_retr_start));
+ save_item(NAME(m_horiz_retr_end));
+ save_item(NAME(m_horiz_retr_skew));
+ save_item(NAME(m_vert_total));
+ save_item(NAME(m_preset_row_scan));
+ save_item(NAME(m_byte_panning));
+ save_item(NAME(m_max_ras_addr));
+ save_item(NAME(m_scan_doubling));
+ save_item(NAME(m_cursor_disable));
+ save_item(NAME(m_cursor_skew));
+ save_item(NAME(m_vert_retr_start));
+ save_item(NAME(m_vert_retr_end));
+ save_item(NAME(m_protect));
+ save_item(NAME(m_bandwidth));
+ save_item(NAME(m_vert_disp_end));
+ save_item(NAME(m_offset));
+ save_item(NAME(m_underline_loc));
+ save_item(NAME(m_vert_blank_start));
+ save_item(NAME(m_vert_blank_end));
+ save_item(NAME(m_line_compare));
+}
+
+
+void crtc_ega_device::device_reset()
+{
+ /* internal registers other than status remain unchanged, all outputs go low */
+ if ( !m_res_out_de_func.isnull() )
+ m_res_out_de_func( FALSE );
+
+ if ( !m_res_out_hsync_func.isnull() )
+ m_res_out_hsync_func( FALSE );
+
+ if ( !m_res_out_vsync_func.isnull() )
+ m_res_out_vsync_func( FALSE );
+
+ if ( !m_res_out_vblank_func.isnull() )
+ m_res_out_vblank_func( FALSE );
+
+ if ( ! m_line_timer->enabled( ) )
+ {
+ m_line_timer->adjust( attotime::from_ticks( m_horiz_char_total + 2, m_clock ) );
+ }
+
+ m_light_pen_latched = false;
+
+ m_cursor_addr = 0;
+ m_line_address = 0;
+ m_horiz_disp = 0;
+ m_cursor_x = 0;
+ m_horiz_blank_start = 0;
+ m_horiz_blank_end = 0;
+ m_vert_disp_end = 0;
+ m_vert_retr_start = 0;
+ m_vert_blank_start = 0;
+ m_line_counter = 0;
+ m_raster_counter = 0;
+ m_horiz_pix_total = 0;
+ m_vert_pix_total = 0;
+ m_max_visible_x = 0;
+ m_max_visible_y = 0;
+ m_hsync_on_pos = 0;
+ m_vsync_on_pos = 0;
+ m_hsync_off_pos = 0;
+ m_vsync_off_pos = 0;
+}
diff --git a/src/emu/video/crtc_ega.h b/src/emu/video/crtc_ega.h
new file mode 100644
index 00000000000..d211a63b888
--- /dev/null
+++ b/src/emu/video/crtc_ega.h
@@ -0,0 +1,223 @@
+/**********************************************************************
+
+ IBM EGA CRT Controller emulation
+
+**********************************************************************/
+
+#ifndef __CRTC_EGA__
+#define __CRTC_EGA__
+
+#include "emu.h"
+
+#define CRTC_EGA_INTERFACE(name) \
+ const crtc_ega_interface (name) =
+
+#define MCFG_CRTC_EGA_ADD(_tag, _clock, _intrf) \
+ MCFG_DEVICE_ADD(_tag, CRTC_EGA, _clock) \
+ MCFG_DEVICE_CONFIG(_intrf)
+
+#define MCFG_CRTC_EGA_SET_SCREEN MCFG_VIDEO_SET_SCREEN
+
+
+class crtc_ega_device;
+
+/* callback definitions */
+typedef void * (*crtc_ega_begin_update_func)(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect);
+#define CRTC_EGA_BEGIN_UPDATE(name) void *name(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect)
+
+typedef void (*crtc_ega_update_row_func)(crtc_ega_device *device, bitmap_ind16 &bitmap,
+ const rectangle &cliprect, UINT16 ma, UINT8 ra,
+ UINT16 y, UINT8 x_count, INT8 cursor_x, void *param);
+#define CRTC_EGA_UPDATE_ROW(name) void name(crtc_ega_device *device, bitmap_ind16 &bitmap, \
+ const rectangle &cliprect, UINT16 ma, UINT8 ra, \
+ UINT16 y, UINT8 x_count, INT8 cursor_x, void *param)
+
+typedef void (*crtc_ega_end_update_func)(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect, void *param);
+#define CRTC_EGA_END_UPDATE(name) void name(crtc_ega_device *device, bitmap_ind16 &bitmap, const rectangle &cliprect, void *param)
+
+
+/* interface */
+struct crtc_ega_interface
+{
+ int m_hpixels_per_column; /* number of pixels per video memory address */
+
+ /* if specified, this gets called before any pixel update,
+ optionally return a pointer that will be passed to the
+ update and tear down callbacks */
+ crtc_ega_begin_update_func m_begin_update;
+
+ /* this gets called for every row, the driver must output
+ x_count * hpixels_per_column pixels.
+ cursor_x indicates the character position where the cursor is, or -1
+ if there is no cursor on this row */
+ crtc_ega_update_row_func m_update_row;
+
+ /* if specified, this gets called after all row updating is complete */
+ crtc_ega_end_update_func m_end_update;
+
+ /* if specified, this gets called for every change of the disply enable signal */
+ devcb_write_line m_out_de_func;
+
+ /* if specified, this gets called for every change of the HSYNC signal */
+ devcb_write_line m_out_hsync_func;
+
+ /* if specified, this gets called for every change of the VSYNC signal */
+ devcb_write_line m_out_vsync_func;
+
+ devcb_write_line m_out_vblank_func;
+};
+
+
+class crtc_ega_device : public device_t,
+ public device_video_interface,
+ public crtc_ega_interface
+{
+public:
+ crtc_ega_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ /* select one of the registers for reading or writing */
+ DECLARE_WRITE8_MEMBER( address_w );
+
+ /* read from the currently selected register */
+ DECLARE_READ8_MEMBER( register_r );
+
+ /* write to the currently selected register */
+ DECLARE_WRITE8_MEMBER( register_w );
+
+ /* return the current value on the MA0-MA15 pins */
+ UINT16 get_ma();
+
+ /* return the current value on the RA0-RA4 pins */
+ UINT8 get_ra();
+
+ /* simulates the LO->HI clocking of the light pen pin */
+ void assert_light_pen_input();
+
+ /* set the clock of the chip */
+ void set_clock(int clock);
+
+ /* set number of pixels per video memory address */
+ void set_hpixels_per_column(int hpixels_per_column);
+
+ /* updates the screen -- this will call begin_update(), */
+ /* followed by update_row() reapeatedly and after all row */
+ /* updating is complete, end_update() */
+ UINT32 screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+protected:
+ // device-level overrides
+ virtual void device_config_complete();
+ virtual void device_start();
+ virtual void device_reset();
+ virtual void device_post_load();
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+private:
+ devcb_resolved_write_line m_res_out_de_func;
+ devcb_resolved_write_line m_res_out_cur_func;
+ devcb_resolved_write_line m_res_out_hsync_func;
+ devcb_resolved_write_line m_res_out_vsync_func;
+ devcb_resolved_write_line m_res_out_vblank_func;
+
+ /* ega/vga register file */
+ UINT8 m_horiz_char_total; /* 0x00 */
+ UINT8 m_horiz_disp; /* 0x01 */
+ UINT8 m_horiz_blank_start; /* 0x02 */
+ UINT8 m_horiz_blank_end; /* 0x03/0x05 */
+ UINT8 m_ena_vert_access; /* 0x03 */
+ UINT8 m_de_skew; /* 0x03 */
+ UINT8 m_horiz_retr_start; /* 0x04 */
+ UINT8 m_horiz_retr_end; /* 0x05 */
+ UINT8 m_horiz_retr_skew; /* 0x05 */
+ UINT16 m_vert_total; /* 0x06/0x07 */
+ UINT8 m_preset_row_scan; /* 0x08 */
+ UINT8 m_byte_panning; /* 0x08 */
+ UINT8 m_max_ras_addr; /* 0x09 */
+ UINT8 m_scan_doubling; /* 0x09 */
+ UINT8 m_cursor_start_ras; /* 0x0a */
+ UINT8 m_cursor_disable; /* 0x0a */
+ UINT8 m_cursor_end_ras; /* 0x0b */
+ UINT8 m_cursor_skew; /* 0x0b */
+ UINT16 m_disp_start_addr; /* 0x0c/0x0d */
+ UINT16 m_cursor_addr; /* 0x0e/0x0f */
+ UINT16 m_light_pen_addr; /* 0x10/0x11 */
+ UINT16 m_vert_retr_start; /* 0x10/0x07 */
+ UINT8 m_vert_retr_end; /* 0x11 */
+ UINT8 m_protect; /* 0x11 */
+ UINT8 m_bandwidth; /* 0x11 */
+ UINT16 m_vert_disp_end; /* 0x12/0x07 */
+ UINT8 m_offset; /* 0x13 */
+ UINT8 m_underline_loc; /* 0x14 */
+ UINT16 m_vert_blank_start; /* 0x15/0x07/0x09 */
+ UINT8 m_vert_blank_end; /* 0x16 */
+ UINT8 m_mode_control; /* 0x17 */
+ UINT16 m_line_compare; /* 0x18/0x07/0x09 */
+
+ /* other internal state */
+ UINT8 m_register_address_latch;
+ bool m_cursor_state; /* 0 = off, 1 = on */
+ UINT8 m_cursor_blink_count;
+
+ /* output signals */
+ int m_cur;
+ int m_hsync;
+ int m_vsync;
+ int m_vblank;
+ int m_de;
+
+ /* internal counters */
+ UINT8 m_character_counter;
+ UINT8 m_hsync_width_counter;
+ UINT16 m_line_counter;
+ UINT8 m_raster_counter;
+ UINT8 m_vsync_width_counter;
+ bool m_line_enable_ff; /* Internal flip flop which is set when the line_counter is reset and reset when vert_disp is reached */
+ UINT8 m_vsync_ff;
+ UINT8 m_adjust_active;
+ UINT16 m_line_address;
+ INT16 m_cursor_x;
+
+ /* timers */
+ static const device_timer_id TIMER_LINE = 0;
+ static const device_timer_id TIMER_DE_OFF = 1;
+ static const device_timer_id TIMER_CUR_ON = 2;
+ static const device_timer_id TIMER_CUR_OFF = 3;
+ static const device_timer_id TIMER_HSYNC_ON = 4;
+ static const device_timer_id TIMER_HSYNC_OFF = 5;
+ static const device_timer_id TIMER_LIGHT_PEN_LATCH = 6;
+
+ emu_timer *m_line_timer;
+ emu_timer *m_de_off_timer;
+ emu_timer *m_cur_on_timer;
+ emu_timer *m_cur_off_timer;
+ emu_timer *m_hsync_on_timer;
+ emu_timer *m_hsync_off_timer;
+ emu_timer *m_light_pen_latch_timer;
+
+ /* computed values - do NOT state save these! */
+ UINT16 m_horiz_pix_total;
+ UINT16 m_vert_pix_total;
+ UINT16 m_max_visible_x;
+ UINT16 m_max_visible_y;
+ UINT16 m_hsync_on_pos;
+ UINT16 m_hsync_off_pos;
+ UINT16 m_vsync_on_pos;
+ UINT16 m_vsync_off_pos;
+ UINT16 m_current_disp_addr; /* the display address currently drawn */
+ UINT8 m_light_pen_latched;
+ bool m_has_valid_parameters;
+
+ void recompute_parameters(bool postload);
+ void update_counters();
+ void set_de(int state);
+ void set_hsync(int state);
+ void set_vsync(int state);
+ void set_vblank(int state);
+ void set_cur(int state);
+ void handle_line_timer();
+ void update_cursor_state();
+};
+
+extern const device_type CRTC_EGA;
+
+#endif
diff --git a/src/emu/video/video.mak b/src/emu/video/video.mak
index cf95ea7b813..19df5c86abd 100644
--- a/src/emu/video/video.mak
+++ b/src/emu/video/video.mak
@@ -507,3 +507,13 @@ endif
ifneq ($(filter VOODOO,$(VIDEOS)),)
VIDEOOBJS+= $(VIDEOOBJ)/voodoo.o
endif
+
+
+#-------------------------------------------------
+#
+#@src/emu/video/crtc_ega.h,VIDEOS += CRTC_EGA
+#-------------------------------------------------
+
+ifneq ($(filter CRTC_EGA,$(VIDEOS)),)
+VIDEOOBJS+= $(VIDEOOBJ)/crtc_ega.o
+endif