diff options
author | 2014-03-07 13:35:21 +0000 | |
---|---|---|
committer | 2014-03-07 13:35:21 +0000 | |
commit | 250dac1722b9f9f2ff602b4e40c2cd63cd97e504 (patch) | |
tree | f49e429b7d123f381c09b5b8e457860af49e48c8 /src/emu | |
parent | a190ceefc53d10fcbb8b2a3b8fc7749975b7a987 (diff) |
Shuffle ISA and some more PC related devices around (nw)
Diffstat (limited to 'src/emu')
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 |