// 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(*this, FUNC(isa8_pcmidi_device::host_r)),
write8sm_delegate(*this, FUNC(isa8_pcmidi_device::host_w)));
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, 7));
// 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);
}