diff options
Diffstat (limited to 'src/devices/bus/msx/module/sfg.cpp')
-rw-r--r-- | src/devices/bus/msx/module/sfg.cpp | 211 |
1 files changed, 211 insertions, 0 deletions
diff --git a/src/devices/bus/msx/module/sfg.cpp b/src/devices/bus/msx/module/sfg.cpp new file mode 100644 index 00000000000..a9ba98068a5 --- /dev/null +++ b/src/devices/bus/msx/module/sfg.cpp @@ -0,0 +1,211 @@ +// license:BSD-3-Clause +// copyright-holders:Wilbert Pol +/************************************************************************** + +Yamaha SFG01/SFG05 emulation + +**************************************************************************/ + +#include "emu.h" +#include "sfg.h" + +#include "bus/midi/midi.h" +#include "bus/msx/cart/msx_audio_kb.h" +#include "machine/ym2148.h" +#include "sound/ymopm.h" + +#include "speaker.h" + + +namespace { + +class msx_cart_sfg_device : public device_t, public msx_cart_interface +{ +protected: + msx_cart_sfg_device(const machine_config &mconfig, const device_type type, const char *tag, device_t *owner, u32 clock); + + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + + IRQ_CALLBACK_MEMBER(irq_callback); + + void ym2151_irq_w(int state); + void ym2148_irq_w(int state); + + void check_irq(); + + required_memory_region m_region_sfg; + required_device<ym_generic_device> m_ym2151; + required_device<msx_audio_kbdc_port_device> m_kbdc; + required_device<ym2148_device> m_ym2148; + int m_ym2151_irq_state; + int m_ym2148_irq_state; + u32 m_rom_mask; +}; + +msx_cart_sfg_device::msx_cart_sfg_device(const machine_config &mconfig, const device_type type, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, type, tag, owner, clock) + , msx_cart_interface(mconfig, *this) + , m_region_sfg(*this, "sfg") + , m_ym2151(*this, "ym2151") + , m_kbdc(*this, "kbdc") + , m_ym2148(*this, "ym2148") + , m_ym2151_irq_state(CLEAR_LINE) + , m_ym2148_irq_state(CLEAR_LINE) + , m_rom_mask(0) +{ +} + +void msx_cart_sfg_device::device_add_mconfig(machine_config &config) +{ + // YM2151 (OPM) + // YM3012 (DAC) + // YM2148 (MKS) + + SPEAKER(config, "speaker", 2).front(); + ym2151_device &ym2151(YM2151(config, m_ym2151, DERIVED_CLOCK(1, 1))); // The SFG01 uses a YM2151, the SFG05 uses a YM2164, input clock comes from the main cpu frequency + ym2151.irq_handler().set(FUNC(msx_cart_sfg_device::ym2151_irq_w)); + ym2151.add_route(0, "speaker", 0.80, 0); + ym2151.add_route(1, "speaker", 0.80, 1); + + YM2148(config, m_ym2148, XTAL(4'000'000)); + m_ym2148->txd_handler().set("mdout", FUNC(midi_port_device::write_txd)); + m_ym2148->port_write_handler().set("kbdc", FUNC(msx_audio_kbdc_port_device::write)); + m_ym2148->port_read_handler().set("kbdc", FUNC(msx_audio_kbdc_port_device::read)); + m_ym2148->irq_handler().set(FUNC(msx_cart_sfg_device::ym2148_irq_w)); + + MSX_AUDIO_KBDC_PORT(config, m_kbdc, msx_audio_keyboards, nullptr); + + MIDI_PORT(config, "mdout", midiout_slot, "midiout"); + MIDI_PORT(config, "mdin", midiin_slot, "midiin").rxd_handler().set("ym2148", FUNC(ym2148_device::write_rxd)); +} + +void msx_cart_sfg_device::device_start() +{ + // Set rom mask + m_rom_mask = m_region_sfg->bytes() - 1; + + maincpu().set_irq_acknowledge_callback(*this, FUNC(msx_cart_sfg_device::irq_callback)); + + page(0)->install_rom(0x0000, 0x3fff, m_region_sfg->base()); + if (m_region_sfg->bytes() == 0x8000) + { + page(1)->install_rom(0x4000, 0x7fff, m_region_sfg->base() + 0x4000); + } + else + { + page(1)->install_rom(0x4000, 0x7fff, m_region_sfg->base()); + } + + for (int i = 0; i < 4; i++) + { + // These addresses deliberately overlap + page(i)->install_read_handler(0x4000 * i + 0x3ff0, 0x4000 * i + 0x3ff6, emu::rw_delegate(*m_ym2148, FUNC(ym2148_device::read))); + page(i)->install_read_handler(0x4000 * i + 0x3ff0, 0x4000 * i + 0x3ff1, emu::rw_delegate(*m_ym2151, FUNC(ym_generic_device::read))); + page(i)->install_write_handler(0x4000 * i + 0x3ff0, 0x4000 * i + 0x3ff6, emu::rw_delegate(*m_ym2148, FUNC(ym2148_device::write))); + page(i)->install_write_handler(0x4000 * i + 0x3ff0, 0x4000 * i + 0x3ff1, emu::rw_delegate(*m_ym2151, FUNC(ym_generic_device::write))); + } +} + +IRQ_CALLBACK_MEMBER(msx_cart_sfg_device::irq_callback) +{ + return m_ym2148->get_irq_vector(); +} + +void msx_cart_sfg_device::ym2151_irq_w(int state) +{ + m_ym2151_irq_state = state ? ASSERT_LINE : CLEAR_LINE; + check_irq(); +} + +void msx_cart_sfg_device::ym2148_irq_w(int state) +{ + m_ym2148_irq_state = state ? ASSERT_LINE : CLEAR_LINE; + check_irq(); +} + +void msx_cart_sfg_device::check_irq() +{ + if (m_ym2151_irq_state != CLEAR_LINE || m_ym2148_irq_state != CLEAR_LINE) + { + irq_out(ASSERT_LINE); + } + else + { + irq_out(CLEAR_LINE); + } +} + + +class msx_cart_sfg01_device : public msx_cart_sfg_device +{ +public: + msx_cart_sfg01_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; +}; + +msx_cart_sfg01_device::msx_cart_sfg01_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : msx_cart_sfg_device(mconfig, MSX_CART_SFG01, tag, owner, clock) +{ +} + +ROM_START(msx_sfg01) + ROM_REGION(0x4000, "sfg", 0) + ROM_LOAD("sfg01.rom", 0x0, 0x4000, CRC(0995fb36) SHA1(434651305f92aa770a89e40b81125fb22d91603d)) // correct label is almost certainly "yamaha__ym2211-22702__48_18_89_b.ic104" though the datecode portion may vary between late 1983 and mid 1984 +ROM_END + +const tiny_rom_entry *msx_cart_sfg01_device::device_rom_region() const +{ + return ROM_NAME(msx_sfg01); +} + + + +class msx_cart_sfg05_device : public msx_cart_sfg_device +{ +public: + msx_cart_sfg05_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + +protected: + virtual void device_add_mconfig(machine_config &config) override ATTR_COLD; + virtual const tiny_rom_entry *device_rom_region() const override ATTR_COLD; +}; + +msx_cart_sfg05_device::msx_cart_sfg05_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : msx_cart_sfg_device(mconfig, MSX_CART_SFG05, tag, owner, clock) +{ +} + +void msx_cart_sfg05_device::device_add_mconfig(machine_config &config) +{ + msx_cart_sfg_device::device_add_mconfig(config); + + ym2164_device &ym2164(YM2164(config.replace(), m_ym2151, DERIVED_CLOCK(1, 1))); + ym2164.irq_handler().set(FUNC(msx_cart_sfg05_device::ym2151_irq_w)); + ym2164.add_route(0, "speaker", 0.80, 0); + ym2164.add_route(1, "speaker", 0.80, 1); +} + +ROM_START(msx_sfg05) + ROM_REGION(0x8000, "sfg", 0) + // Version string starts at $02BD + ROM_SYSTEM_BIOS(0, "m5.01.011", "SFG05 (original) M5.01.011") + ROMX_LOAD( "sfg05.rom", 0x0, 0x8000, CRC(2425c279) SHA1(d956167e234f60ad916120437120f86fc8c3c321), ROM_BIOS(0)) // correct label MIGHT be "yamaha__ym2301-23959.ic104" but this needs redump/verification + ROM_SYSTEM_BIOS(1, "m5.00.013", "SFG05 (SFG01 upgrade) M5.00.013") // SFG01 PCB, Yamaha official upgrade, has YM2151 instead of YM2164 + ROMX_LOAD( "sfg05a.rom", 0x0, 0x8000, CRC(5bc237f8) SHA1(930338f45c08228108c0831cc4a26014c2674718), ROM_BIOS(1)) // this came on a single eprom on a daughterboard on an SFG01 board which had been factory upgraded to SFG05 + ROM_SYSTEM_BIOS(2, "m5.00.011", "SFG05 M5.00.011") // Found in Sakhr AX-200M + ROMX_LOAD("sfg05_m5_00_011.rom", 0x0, 0x8000, BAD_DUMP CRC(9d5e20c9) SHA1(fcc385b90c65575e29fc009aa00b5120fc4c251a), ROM_BIOS(2)) // Still seems to have I/O reads at $7ff0 - $7fff +ROM_END + +const tiny_rom_entry *msx_cart_sfg05_device::device_rom_region() const +{ + return ROM_NAME(msx_sfg05); +} + +} // anonymous namespace + +DEFINE_DEVICE_TYPE_PRIVATE(MSX_CART_SFG01, msx_cart_interface, msx_cart_sfg01_device, "msx_cart_sfg01", "MSX Cartridge - SFG01") +DEFINE_DEVICE_TYPE_PRIVATE(MSX_CART_SFG05, msx_cart_interface, msx_cart_sfg05_device, "msx_cart_sfg05", "MSX Cartridge - SFG05") |