diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index d068bf9a1de..46d11bfdb81 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -1257,6 +1257,8 @@ if (BUSES["ISA"]~=null) then MAME_DIR .. "src/devices/bus/isa/cl_sh260.h", MAME_DIR .. "src/devices/bus/isa/mpu401.cpp", MAME_DIR .. "src/devices/bus/isa/mpu401.h", + MAME_DIR .. "src/devices/bus/isa/pcmidi.cpp", + MAME_DIR .. "src/devices/bus/isa/pcmidi.h", MAME_DIR .. "src/devices/bus/isa/sblaster.cpp", MAME_DIR .. "src/devices/bus/isa/sblaster.h", MAME_DIR .. "src/devices/bus/isa/stereo_fx.cpp", diff --git a/src/devices/bus/isa/isa_cards.cpp b/src/devices/bus/isa/isa_cards.cpp index 4c0a41f430d..33973211c7d 100644 --- a/src/devices/bus/isa/isa_cards.cpp +++ b/src/devices/bus/isa/isa_cards.cpp @@ -53,6 +53,7 @@ #include "gus.h" #include "ibm_mfc.h" #include "mpu401.h" +#include "pcmidi.h" #include "sblaster.h" #include "ssi2001.h" #include "stereo_fx.h" @@ -114,6 +115,7 @@ void pc_isa8_cards(device_slot_interface &device) device.option_add("stereo_fx", ISA8_STEREO_FX); device.option_add("ssi2001", ISA8_SSI2001); device.option_add("mpu401", ISA8_MPU401); + device.option_add("pcmidi", ISA8_PCMIDI); device.option_add("ne1000", NE1000); device.option_add("3c503", EL2_3C503); device.option_add("lpt", ISA8_LPT); @@ -158,6 +160,7 @@ void pc_isa16_cards(device_slot_interface &device) device.option_add("ne1000", NE1000); device.option_add("3c503", EL2_3C503); device.option_add("mpu401", ISA8_MPU401); + device.option_add("pcmidi", ISA8_PCMIDI); device.option_add("lpt", ISA8_LPT); device.option_add("ibm_mfc", ISA8_IBM_MFC); device.option_add("fdcsmc", ISA8_FDC_SMC); diff --git a/src/devices/bus/isa/pcmidi.cpp b/src/devices/bus/isa/pcmidi.cpp new file mode 100644 index 00000000000..0d2fad075b6 --- /dev/null +++ b/src/devices/bus/isa/pcmidi.cpp @@ -0,0 +1,262 @@ +// license:BSD-3-Clause +// copyright-holders:AJR +/*************************************************************************** + + PC MIDI Card + Copyright (C) 1989 Music Quest, Inc. + FCC ID: IH9MQ9 + + This is one of several Z8681-based MIDI cards by Music Quest. Its + interface is more or less compatible with the Roland MPU401. + +**************************************************************************** + +Music Quest PC MIDI CARD IH9MQ9 component list: + +C1 : 2.2uf 50v electrolytic capacitor +C2 : 100nf tantalum capacitor +C3 : 100nf tantalum capacitor +C4 : 100nf tantalum capacitor +C5 : 100nf tantalum capacitor +C6 : 100nf tantalum capacitor +C7 : 100nf tantalum capacitor +C9 : 100nf tantalum capacitor + +D1 : diode (IN4148 ?) +Y1 : 12,000 MHz crystal 2 pin + +R1 : 15K ohm resistor +-5% +R2 : 390 ohm resistor +-5% + +RP1 : 10K ohm Commoned (?) resistor network 2% SIP package (code used A103GA) +RP2 : 220 ohm Commoned (?) resistor network 2% SIP package (code used B221GA) + + + +U1 : 74LS374N +U2 : Zilog Z8 ROMLESS MCU Z0868112PSC +U3 : 74LS139N +U4 : 74LS74AN +U5 : PAL-16L8-25N - read protected , unknown code +U6 : OTP firmware rom chip compatible with 27C512 eproms/eeproms , 64kbyte +U7 : HYUNDAI HY611ALP-10 or compatible 2K x8bits CMOS SRAM IC +U8 : 74LS125AN +U9 : 74LS374N +U10 : 74LS374N +U11 : SHARP PC900V or compatible photocoupler + +***************************************************************************/ + +#include "emu.h" +#include "pcmidi.h" + +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +DEFINE_DEVICE_TYPE(ISA8_PCMIDI, isa8_pcmidi_device, "isa_pcmidi", "Music Quest PC MIDI Card (IHQMQ9)") + + +//************************************************************************** +// DEVICE SETUP +//************************************************************************** + +//------------------------------------------------- +// isa8_pcmidi_device - constructor +//------------------------------------------------- + +isa8_pcmidi_device::isa8_pcmidi_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, ISA8_PCMIDI, tag, owner, clock) + , device_isa8_card_interface(mconfig, *this) + , m_mpu(*this, "mpu") + , m_cmdlatch(*this, "cmdlatch") + , m_statlatch(*this, "statlatch") + , m_midiout(*this, "midiout") + , m_config(*this, "CONFIG") + , m_mpu_p3(0) + , m_host_irq(false) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void isa8_pcmidi_device::device_start() +{ + set_isa_device(); + + save_item(NAME(m_mpu_p3)); + save_item(NAME(m_host_irq)); +} + + +//------------------------------------------------- +// device_reset - device-specific reset +//------------------------------------------------- + +void isa8_pcmidi_device::device_reset() +{ + offs_t ioaddr = BIT(m_config->read(), 0) ? 0x300 : 0x330; + m_isa->install_device(ioaddr, ioaddr + 1, + read8sm_delegate(FUNC(isa8_pcmidi_device::host_r), this), + write8sm_delegate(FUNC(isa8_pcmidi_device::host_w), this)); + + set_host_irq(false); +} + + +//************************************************************************** +// LATCHES AND IRQS +//************************************************************************** + +//------------------------------------------------- +// set_host_irq - update the host IRQ level +//------------------------------------------------- + +void isa8_pcmidi_device::set_host_irq(bool state) +{ + if (m_host_irq != state) + { + m_host_irq = state; + + ioport_value config = m_config->read(); + if (!BIT(config, 1)) + m_isa->irq3_w(state); + if (!BIT(config, 2)) + m_isa->irq5_w(state); + if (!BIT(config, 3)) + m_isa->irq7_w(state); + if (!BIT(config, 4)) + m_isa->irq2_w(state); + } +} + + +//------------------------------------------------- +// host_r - read from data or status port +//------------------------------------------------- + +u8 isa8_pcmidi_device::host_r(offs_t offset) +{ + if (!machine().side_effects_disabled()) + { + set_host_irq(false); + m_mpu->set_input_line(INPUT_LINE_IRQ1, ASSERT_LINE); + } + return m_statlatch->read(); +} + + +//------------------------------------------------- +// host_w - write to data or command port +//------------------------------------------------- + +void isa8_pcmidi_device::host_w(offs_t offset, u8 data) +{ + m_cmdlatch->write(data); + + // IRQs are latched and acknowledged internally + m_mpu->pulse_input_line(offset ? INPUT_LINE_IRQ0 : INPUT_LINE_IRQ2, attotime::zero); +} + + +//------------------------------------------------- +// status_w - mailbox write from local processor +//------------------------------------------------- + +void isa8_pcmidi_device::status_w(u8 data) +{ + m_statlatch->write(data); + if (!BIT(m_mpu_p3, 5)) + { + set_host_irq(true); + m_mpu->set_input_line(INPUT_LINE_IRQ1, CLEAR_LINE); + } +} + + +//------------------------------------------------- +// mpu_p3_w - write to output port +//------------------------------------------------- + +void isa8_pcmidi_device::mpu_p3_w(u8 data) +{ + m_midiout->write_txd(BIT(data, 4)); + + // P36 = error LED output? + + if (BIT(m_mpu_p3, 5) && !BIT(data, 5)) + set_host_irq(false); + + m_mpu_p3 = data; +} + + +//------------------------------------------------- +// mpu_map - Z8681 address map +//------------------------------------------------- + +void isa8_pcmidi_device::mpu_map(address_map &map) +{ + map(0x0000, 0x1fff).rom().region("microcode", 0); + map(0x6000, 0x7fff).rom().mirror(0x8000).region("microcode", 0); + map(0xa000, 0xa7ff).ram(); + map(0xc000, 0xc000).mirror(0xff).r(m_cmdlatch, FUNC(generic_latch_8_device::read)).w(FUNC(isa8_pcmidi_device::status_w)); +} + + +//************************************************************************** +// DEVICE CONFIGURATION +//************************************************************************** + +static INPUT_PORTS_START(isa_pcmidi) + PORT_START("CONFIG") // dual inline block of jumpers with idiosyncratic numbering + PORT_DIPNAME(0x01, 0x00, "I/O Address (P)") PORT_DIPLOCATION("J1:1") + PORT_DIPSETTING(0x01, "300") + PORT_DIPSETTING(0x00, "330") + PORT_DIPNAME(0x1e, 0x0e, "Interrupt") PORT_DIPLOCATION("J1:2,3,4,5") + PORT_DIPSETTING(0x0e, "IRQ2") + PORT_DIPSETTING(0x1c, "IRQ3") + PORT_DIPSETTING(0x1a, "IRQ5") + PORT_DIPSETTING(0x16, "IRQ7") +INPUT_PORTS_END + +ioport_constructor isa8_pcmidi_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(isa_pcmidi); +} + + +//------------------------------------------------- +// device_add_mconfig - add device configuration +//------------------------------------------------- + +void isa8_pcmidi_device::device_add_mconfig(machine_config &config) +{ + Z8681(config, m_mpu, 12_MHz_XTAL); + m_mpu->set_addrmap(AS_PROGRAM, &isa8_pcmidi_device::mpu_map); + m_mpu->p3_out_cb().set(FUNC(isa8_pcmidi_device::mpu_p3_w)); + + GENERIC_LATCH_8(config, m_cmdlatch); + GENERIC_LATCH_8(config, m_statlatch); + + MIDI_PORT(config, m_midiout, midiout_slot, "midiout"); + MIDI_PORT(config, "midiin", midiin_slot, "midiin").rxd_handler().set_inputline(m_mpu, INPUT_LINE_IRQ3).invert(); +} + + +//************************************************************************** +// ROM DEFINITION +//************************************************************************** + +ROM_START(isa_pcmidi) + ROM_REGION(0x10000, "microcode", 0) + ROM_LOAD("ih9mq9_firmware_v010.bin", 0x00000, 0x10000, CRC(d4cab098) SHA1(9446c4939de557f839a74ca6fe7f41df46752e25)) +ROM_END + +const tiny_rom_entry *isa8_pcmidi_device::device_rom_region() const +{ + return ROM_NAME(isa_pcmidi); +} diff --git a/src/devices/bus/isa/pcmidi.h b/src/devices/bus/isa/pcmidi.h new file mode 100644 index 00000000000..90bca2b5752 --- /dev/null +++ b/src/devices/bus/isa/pcmidi.h @@ -0,0 +1,47 @@ +// license:BSD-3-Clause +// copyright-holders:AJR + +#ifndef MAME_BUS_ISA_PCMIDI_H +#define MAME_BUS_ISA_PCMIDI_H + +#pragma once + +#include "isa.h" +#include "bus/midi/midi.h" +#include "cpu/z8/z8.h" +#include "machine/gen_latch.h" + +class isa8_pcmidi_device : public device_t, public device_isa8_card_interface +{ +public: + isa8_pcmidi_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + virtual void device_add_mconfig(machine_config &config) override; + virtual const tiny_rom_entry *device_rom_region() const override; + +private: + void set_host_irq(bool state); + u8 host_r(offs_t offset); + void host_w(offs_t offset, u8 data); + void status_w(u8 data); + void mpu_p3_w(u8 data); + + void mpu_map(address_map &map); + + required_device m_mpu; + required_device m_cmdlatch; + required_device m_statlatch; + required_device m_midiout; + required_ioport m_config; + + u8 m_mpu_p3; + bool m_host_irq; +}; + +DECLARE_DEVICE_TYPE(ISA8_PCMIDI, isa8_pcmidi_device) + +#endif // MAME_BUS_ISA_PCMIDI_H