From 35cb398d8a4d2aa7d5324e922f23957f429a6c10 Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Sat, 22 Apr 2023 08:07:03 -0400 Subject: yamaha: new GEW7 and GEW12 machines, various GEW8/MultiPCM improvements (#11105) * yamaha: implement GEW7, partially implement GEW12, some GEW8/MultiPCM fixes (envelope behavior, sample lengths, stream updates, save state members) New working machines ---------- Yamaha PSR-150 [Edward d-tech, Devin Acker] Yamaha PSR-180 [Edward d-tech, Devin Acker] Yamaha PSR-78 [Edward d-tech, Devin Acker] New working clones ---------- Yamaha PSR-110 [Edward d-tech, Devin Acker] Yamaha PSR-75 [Edward d-tech, Devin Acker] Yamaha PSR-76 [Edward d-tech, Devin Acker] Yamaha PSS-11 [Edward d-tech, Devin Acker] Yamaha PSS-21 [Edward d-tech, Devin Acker] Yamaha PSS-31 [Edward d-tech, Devin Acker] Yamaha PSS-6 [Devin Acker] Machines promoted to working ---------- Yamaha PSS-12 [Devin Acker] New NOT_WORKING machines ---------- Yamaha PSR-260 [Edward d-tech, Devin Acker] Yamaha PSR-79 [Edward d-tech, Devin Acker] New NOT_WORKING clones ---------- Yamaha PSR-160 [Edward d-tech, Devin Acker] --- scripts/src/cpu.lua | 8 +- scripts/src/sound.lua | 35 +- src/devices/cpu/m6502/gew12.cpp | 230 ++++++ src/devices/cpu/m6502/gew12.h | 78 ++ src/devices/cpu/m6502/gew7.cpp | 217 ++++++ src/devices/cpu/m6502/gew7.h | 74 ++ src/devices/sound/gew.cpp | 632 +++++++++++++++ src/devices/sound/gew.h | 159 ++++ src/devices/sound/gew7.cpp | 205 +++++ src/devices/sound/gew7.h | 30 + src/devices/sound/multipcm.cpp | 656 +--------------- src/devices/sound/multipcm.h | 139 +--- src/mame/layout/psr110.lay | 273 +++++++ src/mame/layout/psr150.lay | 347 +++++++++ src/mame/layout/psr180.lay | 493 ++++++++++++ src/mame/layout/psr75.lay | 285 +++++++ src/mame/layout/psr76.lay | 427 ++++++++++ src/mame/layout/pss11.lay | 260 +++++++ src/mame/layout/pss12.lay | 439 +++++++++++ src/mame/layout/pss21.lay | 256 ++++++ src/mame/layout/pss31.lay | 270 +++++++ src/mame/layout/pss6.lay | 402 ++++++++++ src/mame/mame.lst | 21 +- src/mame/yamaha/ympsr150.cpp | 1637 +++++++++++++++++++++++++++++++++++++++ src/mame/yamaha/ympsr260.cpp | 128 +++ src/mame/yamaha/ympss12.cpp | 58 -- 26 files changed, 6924 insertions(+), 835 deletions(-) create mode 100644 src/devices/cpu/m6502/gew12.cpp create mode 100644 src/devices/cpu/m6502/gew12.h create mode 100644 src/devices/cpu/m6502/gew7.cpp create mode 100644 src/devices/cpu/m6502/gew7.h create mode 100644 src/devices/sound/gew.cpp create mode 100644 src/devices/sound/gew.h create mode 100644 src/devices/sound/gew7.cpp create mode 100644 src/devices/sound/gew7.h create mode 100644 src/mame/layout/psr110.lay create mode 100644 src/mame/layout/psr150.lay create mode 100644 src/mame/layout/psr180.lay create mode 100644 src/mame/layout/psr75.lay create mode 100644 src/mame/layout/psr76.lay create mode 100644 src/mame/layout/pss11.lay create mode 100644 src/mame/layout/pss12.lay create mode 100644 src/mame/layout/pss21.lay create mode 100644 src/mame/layout/pss31.lay create mode 100644 src/mame/layout/pss6.lay create mode 100644 src/mame/yamaha/ympsr150.cpp create mode 100644 src/mame/yamaha/ympsr260.cpp delete mode 100644 src/mame/yamaha/ympss12.cpp diff --git a/scripts/src/cpu.lua b/scripts/src/cpu.lua index 849c9633dfd..fc099343c24 100644 --- a/scripts/src/cpu.lua +++ b/scripts/src/cpu.lua @@ -1590,8 +1590,10 @@ if opt_tool(CPUS, "M37710") then end -------------------------------------------------- --- Mostek 6502 and its many derivatives +-- MOS Technology 6502 and its many derivatives --@src/devices/cpu/m6502/deco16.h,CPUS["M6502"] = true +--@src/devices/cpu/m6502/gew7.h,CPUS["M6502"] = true +--@src/devices/cpu/m6502/gew12.h,CPUS["M6502"] = true --@src/devices/cpu/m6502/m3745x.h,CPUS["M6502"] = true --@src/devices/cpu/m6502/m4510.h,CPUS["M6502"] = true --@src/devices/cpu/m6502/m50734.h,CPUS["M6502"] = true @@ -1625,6 +1627,10 @@ if CPUS["M6502"] then files { MAME_DIR .. "src/devices/cpu/m6502/deco16.cpp", MAME_DIR .. "src/devices/cpu/m6502/deco16.h", + MAME_DIR .. "src/devices/cpu/m6502/gew7.cpp", + MAME_DIR .. "src/devices/cpu/m6502/gew7.h", + MAME_DIR .. "src/devices/cpu/m6502/gew12.cpp", + MAME_DIR .. "src/devices/cpu/m6502/gew12.h", MAME_DIR .. "src/devices/cpu/m6502/m3745x.cpp", MAME_DIR .. "src/devices/cpu/m6502/m3745x.h", MAME_DIR .. "src/devices/cpu/m6502/m4510.cpp", diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua index 00e5d9f4c43..09f2c24e81d 100644 --- a/scripts/src/sound.lua +++ b/scripts/src/sound.lua @@ -817,7 +817,6 @@ end --------------------------------------------------- -- Sega custom sound chips --@src/devices/sound/segapcm.h,SOUNDS["SEGAPCM"] = true ---@src/devices/sound/multipcm.h,SOUNDS["MULTIPCM"] = true --@src/devices/sound/scsp.h,SOUNDS["SCSP"] = true --@src/devices/sound/aica.h,SOUNDS["AICA"] = true --------------------------------------------------- @@ -829,13 +828,6 @@ if (SOUNDS["SEGAPCM"]~=null) then } end -if (SOUNDS["MULTIPCM"]~=null) then - files { - MAME_DIR .. "src/devices/sound/multipcm.cpp", - MAME_DIR .. "src/devices/sound/multipcm.h", - } -end - if (SOUNDS["SCSP"]~=null) then files { MAME_DIR .. "src/devices/sound/scsp.cpp", @@ -1267,6 +1259,33 @@ if (SOUNDS["YMZ770"]~=null) then } end +--------------------------------------------------- +-- Yamaha GEW series PCM +--@src/devices/sound/gew7.h,SOUNDS["GEW7"] = true +--@src/devices/sound/multipcm.h,SOUNDS["MULTIPCM"] = true +--------------------------------------------------- + +if (SOUNDS["GEW7"]~=null or SOUNDS["MULTIPCM"]~=null) then + files { + MAME_DIR .. "src/devices/sound/gew.cpp", + MAME_DIR .. "src/devices/sound/gew.h", + } +end + +if (SOUNDS["GEW7"]~=null) then + files { + MAME_DIR .. "src/devices/sound/gew7.cpp", + MAME_DIR .. "src/devices/sound/gew7.h", + } +end + +if (SOUNDS["MULTIPCM"]~=null) then + files { + MAME_DIR .. "src/devices/sound/multipcm.cpp", + MAME_DIR .. "src/devices/sound/multipcm.h", + } +end + --------------------------------------------------- -- MPEG AUDIO --@src/devices/sound/mpeg_audio.h,SOUNDS["MPEG_AUDIO"] = true diff --git a/src/devices/cpu/m6502/gew12.cpp b/src/devices/cpu/m6502/gew12.cpp new file mode 100644 index 00000000000..e880d28b714 --- /dev/null +++ b/src/devices/cpu/m6502/gew12.cpp @@ -0,0 +1,230 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +/*************************************************************************** + + gew7.cpp + + Yamaha GEW2 (65c02-based) + +***************************************************************************/ + +#include "emu.h" +#include "gew12.h" + +#include "m6502mcu.ipp" +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(GEW12, gew12_device, "gew12", "Yamaha YMW728-F (GEW12)") + +gew12_device::gew12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : m6502_mcu_device_base(mconfig, GEW12, tag, owner, clock) + , device_mixer_interface(mconfig, *this, 2) + , m_in_cb(*this), m_out_cb(*this) + , m_rom(*this, DEVICE_SELF) + , m_bank(*this, "bank%u", 0U) +{ + program_config.m_internal_map = address_map_constructor(FUNC(gew12_device::internal_map), this); +} + + +void gew12_device::device_add_mconfig(machine_config &config) +{ + // TODO: PCM, UART +} + +void gew12_device::device_start() +{ + m65c02_device::device_start(); + + m_in_cb.resolve_all_safe(0xff); + m_out_cb.resolve_all_safe(); + + m_bank_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(m_rom->bytes() >> 14), + [this, base = &m_rom->as_u8()](unsigned entry, unsigned page) + { + m_bank[0]->configure_entry(entry, &base[page << 14]); + m_bank[1]->configure_entry(entry, &base[page << 14]); + }); + + m_timer_base[0] = m_timer_base[1] = 0; + + std::fill(std::begin(m_port_data), std::end(m_port_data), 0); + std::fill(std::begin(m_port_ddr), std::end(m_port_ddr), 0); + + save_item(NAME(m_irq_pending)); + save_item(NAME(m_irq_enable)); + save_item(NAME(m_timer_count)); + save_item(NAME(m_timer_base)); + save_item(NAME(m_port_data)); + save_item(NAME(m_port_ddr)); +} + +void gew12_device::device_reset() +{ + m6502_mcu_device_base::device_reset(); + + internal_update(); + m_irq_pending = 0; + m_irq_enable = 0; + + m_timer_count[0] = m_timer_count[1] = 0; + internal_update(); +} + + +void gew12_device::internal_map(address_map &map) +{ + map(0x0000, 0x07ff).ram(); + + // TODO: sound registers + map(0x1000, 0x103f).ram(); + + map(0x1f00, 0x1f00).rw(FUNC(gew12_device::irq_stat_r), FUNC(gew12_device::irq_en_w)); + map(0x1f01, 0x1f01).w(FUNC(gew12_device::timer_stat_w)); + + // TODO: UART + // map(0x1f11, 0x1f11) Rx data + // map(0x1f12, 0x1f12) status (bits 0-1: error, bit 2: Rx ready, bit 3: Tx ready) + // map(0x1f13, 0x1f13) Tx data + + map(0x1f20, 0x1f23).w(FUNC(gew12_device::timer_count_w)); + map(0x1f24, 0x1f25).r(FUNC(gew12_device::timer_count_r)); + + // TODO - only the last port (PL) is known for sure + // on psr160/260, the rest seem to all be handled by built-in key/button scanning + map(0x1f2a, 0x1f2f).rw(FUNC(gew12_device::port_r), FUNC(gew12_device::port_w)); + map(0x1f3a, 0x1f3f).rw(FUNC(gew12_device::port_ddr_r), FUNC(gew12_device::port_ddr_w)); + + map(0x1f52, 0x1f52).lw8(NAME([this](uint8_t data) { m_bank[0]->set_entry(data & m_bank_mask); })); + map(0x1f53, 0x1f53).nopw(); // bank 0 MSB? (always zero) + map(0x1f54, 0x1f54).lw8(NAME([this](uint8_t data) { m_bank[1]->set_entry(data & m_bank_mask); })); + map(0x1f55, 0x1f55).nopw(); // bank 1 MSB? (always zero) + + map(0x4000, 0x7fff).bankr(m_bank[0]); + map(0x8000, 0xbfff).bankr(m_bank[1]); + map(0xc000, 0xffff).rom().region(DEVICE_SELF, 0); +} + + +void gew12_device::internal_update(u64 current_time) +{ + u64 event_time(0U); + add_event(event_time, timer_update(0, current_time)); + add_event(event_time, timer_update(1, current_time)); + recompute_bcount(event_time); +} + + +u8 gew12_device::irq_stat_r() +{ + internal_update(); + return m_irq_pending & m_irq_enable; +} + +void gew12_device::irq_en_w(u8 data) +{ + internal_update(); + m_irq_enable = data; + irq_update(); + internal_update(); +} + +void gew12_device::internal_irq(int num, int state) +{ + if (state == ASSERT_LINE) + m_irq_pending |= (1 << num); + else + m_irq_pending &= ~(1 << num); + + irq_update(); +} + +void gew12_device::irq_update() +{ + if (m_irq_pending & m_irq_enable) + set_input_line(M65C02_IRQ_LINE, ASSERT_LINE); + else + set_input_line(M65C02_IRQ_LINE, CLEAR_LINE); +} + + +void gew12_device::timer_stat_w(u8 data) +{ + internal_update(); + if (BIT(data, 0)) + internal_irq(INTERNAL_IRQ_TIMER0, CLEAR_LINE); + if (BIT(data, 1)) + internal_irq(INTERNAL_IRQ_TIMER1, CLEAR_LINE); + internal_update(); +} + +u8 gew12_device::timer_count_r(offs_t offset) +{ + // both timer IRQ handlers read the current count from the same registers + // apparently reading timer 1 count if its IRQ is pending, else timer 0 count + internal_update(); + const unsigned timer = BIT(m_irq_pending, INTERNAL_IRQ_TIMER1); + + if (!BIT(offset, 0)) + return m_timer_count[timer]; + else + return m_timer_count[timer] >> 8; +} + +void gew12_device::timer_count_w(offs_t offset, u8 data) +{ + const unsigned timer = offset >> 1; + + internal_update(); + if (!BIT(offset, 0)) + m_timer_count[timer] = (m_timer_count[timer] & 0xff00) | data; + else + m_timer_count[timer] = (m_timer_count[timer] & 0x00ff) | (data << 8); + internal_update(); +} + +u64 gew12_device::timer_update(int num, u64 current_time) +{ + static constexpr unsigned tick_rate = 48; + + const u64 ticks = current_time / tick_rate; + const u64 elapsed = ticks - m_timer_base[num]; + m_timer_base[num] = ticks; + + // TODO: how are the timers enabled/disabled? + // for now, just have 'timer IRQ enable' double as 'timer enable' + if (!BIT(m_irq_enable, INTERNAL_IRQ_TIMER0 + num)) + return 0; + + if (elapsed > m_timer_count[num]) + internal_irq(INTERNAL_IRQ_TIMER0 + num, ASSERT_LINE); + + m_timer_count[num] -= elapsed; + + return (m_timer_base[num] + m_timer_count[num] + 1) * tick_rate; +} + + +u8 gew12_device::port_r(offs_t offset) +{ + const u8 out_data = m_port_data[offset] & ~m_port_ddr[offset]; + return out_data | (m_in_cb[offset]() & m_port_ddr[offset]); +} + +void gew12_device::port_w(offs_t offset, u8 data) +{ + m_port_data[offset] = data; + m_out_cb[offset](0, m_port_data[offset], ~m_port_ddr[offset]); +} + +u8 gew12_device::port_ddr_r(offs_t offset) +{ + return m_port_ddr[offset]; +} + +void gew12_device::port_ddr_w(offs_t offset, u8 data) +{ + m_port_ddr[offset] = data; + m_out_cb[offset](0, m_port_data[offset], ~m_port_ddr[offset]); +} diff --git a/src/devices/cpu/m6502/gew12.h b/src/devices/cpu/m6502/gew12.h new file mode 100644 index 00000000000..aeb4db9c040 --- /dev/null +++ b/src/devices/cpu/m6502/gew12.h @@ -0,0 +1,78 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +/*************************************************************************** + + gew12.h + + Yamaha GEW12 (65c02-based) + +***************************************************************************/ +#ifndef MAME_CPU_M6502_GEW12_H +#define MAME_CPU_M6502_GEW12_H + +#include "m6502mcu.h" +#include "m65c02.h" + +class gew12_device : public m6502_mcu_device_base, public device_mixer_interface { +public: + gew12_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + + template auto port_in_cb() { return m_in_cb[Num].bind(); } + template auto port_out_cb() { return m_out_cb[Num].bind(); } + +protected: + virtual void device_add_mconfig(machine_config &config) override; + + virtual void device_start() override; + virtual void device_reset() override; + + virtual void internal_update(u64 current_time) override; + using m6502_mcu_device_base::internal_update; + + enum + { + INTERNAL_IRQ_TIMER0, + INTERNAL_IRQ_TIMER1, + INTERNAL_IRQ_MIDI_TX, + INTERNAL_IRQ_MIDI_RX + }; + + u8 irq_stat_r(); + void irq_en_w(u8 data); + void timer_stat_w(u8 data); + + u8 timer_count_r(offs_t offset); + void timer_count_w(offs_t offset, u8 data); + u64 timer_update(int num, u64 current_time); + + u8 port_r(offs_t offset); + void port_w(offs_t offset, u8 data); + u8 port_ddr_r(offs_t offset); + void port_ddr_w(offs_t offset, u8 data); + + template + void internal_irq(int state) { internal_irq(Num, state); } + void internal_irq(int num, int state); + + void irq_update(); + + void internal_map(address_map &map); + + u8 m_irq_pending, m_irq_enable; + + u16 m_timer_count[2]; + u64 m_timer_base[2]; + + devcb_read8::array<6> m_in_cb; + devcb_write8::array<6> m_out_cb; + u8 m_port_data[6]; + u8 m_port_ddr[6]; + + required_memory_region m_rom; + required_memory_bank_array<2> m_bank; + u8 m_bank_mask; +}; + +DECLARE_DEVICE_TYPE(GEW12, gew12_device) + +#endif // MAME_CPU_M6502_GEW12_H diff --git a/src/devices/cpu/m6502/gew7.cpp b/src/devices/cpu/m6502/gew7.cpp new file mode 100644 index 00000000000..96b6a03a2df --- /dev/null +++ b/src/devices/cpu/m6502/gew7.cpp @@ -0,0 +1,217 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +/*************************************************************************** + + gew7.cpp + + Yamaha GEW7, GEW7I, GEW7S (65c02-based) + +***************************************************************************/ + +#include "emu.h" +#include "gew7.h" + +#include "m6502mcu.ipp" +#include "bus/generic/slot.h" + +DEFINE_DEVICE_TYPE(GEW7, gew7_device, "gew7", "Yamaha YMW270-F (GEW7)") + +gew7_device::gew7_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) + : m6502_mcu_device_base(mconfig, GEW7, tag, owner, clock) + , device_mixer_interface(mconfig, *this, 2) + , m_in_cb(*this), m_out_cb(*this) + , m_rom(*this, DEVICE_SELF) + , m_bank(*this, "bank%u", 0U) + , m_pcm(*this, "pcm") +{ + program_config.m_internal_map = address_map_constructor(FUNC(gew7_device::internal_map), this); + + std::fill(std::begin(m_port_force_bits), std::end(m_port_force_bits), 0); + std::fill(std::begin(m_port_force_mask), std::end(m_port_force_mask), 0); +} + + +void gew7_device::device_add_mconfig(machine_config &config) +{ + GEW7_PCM(config, m_pcm, DERIVED_CLOCK(1, 1)); + m_pcm->set_device_rom_tag(m_rom); + m_pcm->add_route(0, *this, 1.0, AUTO_ALLOC_INPUT, 0); + m_pcm->add_route(1, *this, 1.0, AUTO_ALLOC_INPUT, 1); +} + +void gew7_device::device_start() +{ + m6502_mcu_device_base::device_start(); + + m_in_cb.resolve_all_safe(0xff); + m_out_cb.resolve_all_safe(); + + m_bank_mask = device_generic_cart_interface::map_non_power_of_two( + unsigned(m_rom->bytes() >> 14), + [this, base = &m_rom->as_u8()](unsigned entry, unsigned page) + { + m_bank[0]->configure_entry(entry, &base[page << 14]); + m_bank[1]->configure_entry(entry, &base[page << 14]); + }); + + m_timer_base[0] = m_timer_base[1] = 0; + + std::fill(std::begin(m_port_data), std::end(m_port_data), 0); + std::fill(std::begin(m_port_ddr), std::end(m_port_ddr), 0); + + save_item(NAME(m_timer_stat)); + save_item(NAME(m_timer_en)); + save_item(NAME(m_timer_count)); + save_item(NAME(m_timer_base)); + save_item(NAME(m_port_data)); + save_item(NAME(m_port_ddr)); +} + +void gew7_device::device_reset() +{ + m6502_mcu_device_base::device_reset(); + + internal_update(); + m_timer_stat = m_timer_en = 0; + m_timer_count[0] = m_timer_count[1] = 0; + internal_update(); +} + + +void gew7_device::internal_map(address_map &map) +{ + map(0x0000, 0x005f).rw(m_pcm, FUNC(gew7_pcm_device::read), FUNC(gew7_pcm_device::write)); + map(0x0060, 0x00ff).mirror(0x0100).ram(); + map(0x0200, 0x022f).rw(m_pcm, FUNC(gew7_pcm_device::read_hi), FUNC(gew7_pcm_device::write_hi)); + map(0x0230, 0x023f).ram(); + + map(0x0400, 0x0400).rw(FUNC(gew7_device::timer_stat_r), FUNC(gew7_device::timer_stat_w)); + map(0x0401, 0x0401).w(FUNC(gew7_device::timer_en_w)); + map(0x0402, 0x0405).rw(FUNC(gew7_device::timer_count_r), FUNC(gew7_device::timer_count_w)); + map(0x0408, 0x0409).w(FUNC(gew7_device::bank_w)); + map(0x040a, 0x040f).rw(FUNC(gew7_device::port_r), FUNC(gew7_device::port_w)); + map(0x0410, 0x0415).rw(FUNC(gew7_device::port_ddr_r), FUNC(gew7_device::port_ddr_w)); + + map(0x4000, 0x7fff).bankr(m_bank[0]); + map(0x8000, 0xbfff).bankr(m_bank[1]); + map(0xc000, 0xffff).rom().region(DEVICE_SELF, 0); +} + + +void gew7_device::internal_update(u64 current_time) +{ + u64 event_time(0U); + add_event(event_time, timer_update(0, current_time)); + add_event(event_time, timer_update(1, current_time)); + recompute_bcount(event_time); +} + +u8 gew7_device::timer_stat_r() +{ + internal_update(); + return m_timer_stat; +} + +void gew7_device::timer_stat_w(u8 data) +{ + internal_update(); + m_timer_stat &= ~data; + + if (!(m_timer_stat & 3)) + set_input_line(M65C02_IRQ_LINE, CLEAR_LINE); + internal_update(); +} + +void gew7_device::timer_en_w(u8 data) +{ + internal_update(); + m_timer_en = data; + internal_update(); +} + +u8 gew7_device::timer_count_r(offs_t offset) +{ + const unsigned timer = offset >> 1; + + internal_update(); + if (!BIT(offset, 0)) + return m_timer_count[timer]; + else + return m_timer_count[timer] >> 8; +} + +void gew7_device::timer_count_w(offs_t offset, u8 data) +{ + const unsigned timer = offset >> 1; + + internal_update(); + if (!BIT(offset, 0)) + m_timer_count[timer] = (m_timer_count[timer] & 0xff00) | data; + else + m_timer_count[timer] = (m_timer_count[timer] & 0x00ff) | (data << 8); + internal_update(); +} + +u64 gew7_device::timer_update(int num, u64 current_time) +{ + static constexpr unsigned tick_rate = 48; + + const u64 ticks = current_time / tick_rate; + const u64 elapsed = ticks - m_timer_base[num]; + m_timer_base[num] = ticks; + + if (!BIT(m_timer_en, num)) + return 0; // timer disabled + + if (elapsed > m_timer_count[num]) + { + m_timer_stat |= (1 << num); + set_input_line(M65C02_IRQ_LINE, ASSERT_LINE); + } + + m_timer_count[num] -= elapsed; + + return (m_timer_base[num] + m_timer_count[num] + 1) * tick_rate; +} + + +void gew7_device::bank_w(offs_t offset, u8 data) +{ + m_bank[offset]->set_entry(data & m_bank_mask); +} + + +void gew7_device::port_force_bits(offs_t num, u8 bits, u8 mask) +{ + // Evidently (at least on the original YMW270F), tying a port pin to +5V or ground is expected + // to affect the value read from the port even when the pin is configured as output. + // PSS-11, PSS-21, PSS-31, and PSR-75 (which all use the same ROM) all rely on this in order to + // correctly detect what model they are. + m_port_force_bits[num] = bits; + m_port_force_mask[num] = mask; +} + +u8 gew7_device::port_r(offs_t offset) +{ + const u8 out_data = m_port_data[offset] & m_port_ddr[offset]; + const u8 in_data = m_in_cb[offset]() & ~m_port_ddr[offset]; + + return ((out_data | in_data) & ~m_port_force_mask[offset]) | m_port_force_bits[offset]; +} + +void gew7_device::port_w(offs_t offset, u8 data) +{ + m_port_data[offset] = data; + m_out_cb[offset](0, m_port_data[offset], m_port_ddr[offset]); +} + +u8 gew7_device::port_ddr_r(offs_t offset) +{ + return m_port_ddr[offset]; +} + +void gew7_device::port_ddr_w(offs_t offset, u8 data) +{ + m_port_ddr[offset] = data; + m_out_cb[offset](0, m_port_data[offset], m_port_ddr[offset]); +} diff --git a/src/devices/cpu/m6502/gew7.h b/src/devices/cpu/m6502/gew7.h new file mode 100644 index 00000000000..fd29e7402c8 --- /dev/null +++ b/src/devices/cpu/m6502/gew7.h @@ -0,0 +1,74 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +/*************************************************************************** + + gew7.h + + Yamaha GEW7, GEW7I, GEW7S (65c02-based) + +***************************************************************************/ +#ifndef MAME_CPU_M6502_GEW7_H +#define MAME_CPU_M6502_GEW7_H + +#include "m6502mcu.h" +#include "m65c02.h" +#include "sound/gew7.h" + +class gew7_device : public m6502_mcu_device_base, public device_mixer_interface +{ +public: + gew7_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock); + + template auto port_in_cb() { return m_in_cb[Num].bind(); } + template auto port_out_cb() { return m_out_cb[Num].bind(); } + + void port_force_bits(offs_t num, u8 bits, u8 mask); + +protected: + + virtual void device_add_mconfig(machine_config &config) override; + + virtual void device_start() override; + virtual void device_reset() override; + + virtual void internal_update(u64 current_time) override; + using m6502_mcu_device_base::internal_update; + + u8 timer_stat_r(); + void timer_stat_w(u8 data); + void timer_en_w(u8 data); + + u8 timer_count_r(offs_t offset); + void timer_count_w(offs_t offset, u8 data); + u64 timer_update(int num, u64 current_time); + + void bank_w(offs_t offset, u8 data); + + u8 port_r(offs_t offset); + void port_w(offs_t offset, u8 data); + u8 port_ddr_r(offs_t offset); + void port_ddr_w(offs_t offset, u8 data); + + void internal_map(address_map &map); + + u8 m_timer_stat, m_timer_en; + u16 m_timer_count[2]; + u64 m_timer_base[2]; + + devcb_read8::array<6> m_in_cb; + devcb_write8::array<6> m_out_cb; + u8 m_port_data[6]; + u8 m_port_ddr[6]; + u8 m_port_force_bits[6]; + u8 m_port_force_mask[6]; + + required_memory_region m_rom; + required_memory_bank_array<2> m_bank; + u8 m_bank_mask; + + required_device m_pcm; +}; + +DECLARE_DEVICE_TYPE(GEW7, gew7_device) + +#endif // MAME_CPU_M6502_GEW7_H diff --git a/src/devices/sound/gew.cpp b/src/devices/sound/gew.cpp new file mode 100644 index 00000000000..8517f40bc72 --- /dev/null +++ b/src/devices/sound/gew.cpp @@ -0,0 +1,632 @@ +// license:BSD-3-Clause +// copyright-holders:Miguel Angel Horna + +#include "emu.h" +#include "gew.h" +#include "wavwrite.h" + +ALLOW_SAVE_TYPE(gew_pcm_device::state_t); // allow save_item on a non-fundamental type + +/******************************* + ENVELOPE SECTION +*******************************/ + +// Times are based on a 44100Hz timebase. It's adjusted to the actual sampling rate on startup + +const double gew_pcm_device::BASE_TIMES[64] = { + 0, 0, 0, 0, + 6222.95, 4978.37, 4148.66, 3556.01, + 3111.47, 2489.21, 2074.33, 1778.00, + 1555.74, 1244.63, 1037.19, 889.02, + 777.87, 622.31, 518.59, 444.54, + 388.93, 311.16, 259.32, 222.27, + 194.47, 155.60, 129.66, 111.16, + 97.23, 77.82, 64.85, 55.60, + 48.62, 38.91, 32.43, 27.80, + 24.31, 19.46, 16.24, 13.92, + 12.15, 9.75, 8.12, 6.98, + 6.08, 4.90, 4.08, 3.49, + 3.04, 2.49, 2.13, 1.90, + 1.72, 1.41, 1.18, 1.04, + 0.91, 0.73, 0.59, 0.50, + 0.45, 0.45, 0.45, 0.45 +}; + +constexpr uint32_t gew_pcm_device::TL_SHIFT; +constexpr uint32_t gew_pcm_device::EG_SHIFT; + +void gew_pcm_device::retrigger_sample(slot_t &slot) +{ + slot.m_offset = 0; + slot.m_prev_sample = 0; + slot.m_total_level = slot.m_dest_total_level << TL_SHIFT; + + envelope_generator_calc(slot); + slot.m_envelope_gen.m_state = state_t::ATTACK; + slot.m_envelope_gen.m_volume = 0; + +#if MULTIPCM_LOG_SAMPLES + dump_sample(slot); +#endif +} + +void gew_pcm_device::update_step(slot_t &slot) +{ + const uint8_t oct = (slot.m_octave - 1) & 0xf; + uint32_t pitch = m_freq_step_table[slot.m_pitch]; + if (oct & 0x8) + { + pitch >>= (16 - oct); + } + else + { + pitch <<= oct; + } + slot.m_step = pitch / m_rate; +} + +void gew_pcm_device::envelope_generator_init(const double (&rates)[64], double attack_decay_ratio) +{ + for (int32_t i = 4; i < 0x40; ++i) + { + // Times are based on 44100Hz clock, adjust to real chip clock + m_attack_step[i] = (float)(0x400 << EG_SHIFT) / (float)(rates[i] * 44100.0 / 1000.0); + m_decay_release_step[i] = (float)(0x400 << EG_SHIFT) / (float)(rates[i] * attack_decay_ratio * 44100.0 / 1000.0); + } + m_attack_step[0] = m_attack_step[1] = m_attack_step[2] = m_attack_step[3] = 0; + m_attack_step[0x3f] = 0x400 << EG_SHIFT; + m_decay_release_step[0] = m_decay_release_step[1] = m_decay_release_step[2] = m_decay_release_step[3] = 0; +} + +int32_t gew_pcm_device::envelope_generator_update(slot_t &slot) +{ + switch (slot.m_envelope_gen.m_state) + { + case state_t::ATTACK: + slot.m_envelope_gen.m_volume += slot.m_envelope_gen.m_attack_rate; + if (slot.m_envelope_gen.m_volume >= (0x3ff << EG_SHIFT)) + { + slot.m_envelope_gen.m_state = state_t::DECAY1; + if (slot.m_envelope_gen.m_decay1_rate >= (0x400 << EG_SHIFT)) //Skip DECAY1, go directly to DECAY2 + { + slot.m_envelope_gen.m_state = state_t::DECAY2; + } + slot.m_envelope_gen.m_volume = 0x3ff << EG_SHIFT; + } + break; + case state_t::DECAY1: + slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_decay1_rate; + if (slot.m_envelope_gen.m_volume <= 0) + { + slot.m_envelope_gen.m_volume = 0; + } + if (slot.m_envelope_gen.m_volume >> (EG_SHIFT + 6) <= slot.m_envelope_gen.m_decay_level) + { + slot.m_envelope_gen.m_state = state_t::DECAY2; + } + break; + case state_t::DECAY2: + slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_decay2_rate; + if (slot.m_envelope_gen.m_volume <= 0) + { + slot.m_envelope_gen.m_volume = 0; + } + break; + case state_t::RELEASE: + slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_release_rate; + if (slot.m_envelope_gen.m_volume <= 0) + { + slot.m_envelope_gen.m_volume = 0; + slot.m_playing = false; + } + break; + default: + return 1 << TL_SHIFT; + } + + // TODO: this is currently only implemented for GEW7, it's probably not accurate + if (slot.m_envelope_gen.m_reverb && slot.m_envelope_gen.m_state != state_t::ATTACK + && (slot.m_envelope_gen.m_volume >> EG_SHIFT) <= 0x300) + { + slot.m_envelope_gen.m_decay1_rate = m_decay_release_step[17]; + slot.m_envelope_gen.m_decay2_rate = m_decay_release_step[17]; + slot.m_envelope_gen.m_release_rate = m_decay_release_step[17]; + } + + return m_linear_to_exp_volume[slot.m_envelope_gen.m_volume >> EG_SHIFT]; +} + +uint32_t gew_pcm_device::get_rate(uint32_t *steps, int32_t rate, uint32_t val) +{ + if (val == 0) + { + return steps[0]; + } + if (val == 0xf) + { + return steps[0x3f]; + } + + const int r = std::clamp(4 * (int)val + rate, 0, 0x3f); + return steps[r]; +} + +void gew_pcm_device::envelope_generator_calc(slot_t &slot) +{ + int32_t octave = slot.m_octave; + if (octave & 8) { + octave = octave - 16; + } + + int32_t rate; + if (slot.m_sample.m_key_rate_scale != 0xf) + { + rate = (octave + slot.m_sample.m_key_rate_scale) * 2 + BIT(slot.m_pitch, 9); + } + else + { + rate = 0; + } + + slot.m_envelope_gen.m_attack_rate = get_rate(m_attack_step.get(), rate, slot.m_sample.m_attack_reg); + slot.m_envelope_gen.m_decay1_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_decay1_reg); + slot.m_envelope_gen.m_decay2_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_decay2_reg); + slot.m_envelope_gen.m_release_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_release_reg); + slot.m_envelope_gen.m_decay_level = 0xf - slot.m_sample.m_decay_level; + slot.m_envelope_gen.m_reverb = false; +} + +/***************************** + LFO SECTION +*****************************/ + +constexpr uint32_t gew_pcm_device::LFO_SHIFT; + +const float gew_pcm_device::LFO_FREQ[8] = // In Hertz +{ + 0.168f, + 2.019f, + 3.196f, + 4.206f, + 5.215f, + 5.888f, + 6.224f, + 7.066f +}; + +const float gew_pcm_device::PHASE_SCALE_LIMIT[8] = // In Cents +{ + 0.0f, + 3.378f, + 5.065f, + 6.750f, + 10.114f, + 20.170f, + 40.180f, + 79.307f +}; + +const float gew_pcm_device::AMPLITUDE_SCALE_LIMIT[8] = // In Decibels +{ + 0.0f, + 0.4f, + 0.8f, + 1.5f, + 3.0f, + 6.0f, + 12.0f, + 24.0f +}; + +void gew_pcm_device::lfo_init() +{ + m_pitch_table = make_unique_clear(256); + m_amplitude_table = make_unique_clear(256); + for (int32_t i = 0; i < 256; ++i) + { + if (i < 64) + { + m_pitch_table[i] = i * 2 + 128; + } + else if (i < 128) + { + m_pitch_table[i] = 383 - i * 2; + } + else if (i < 192) + { + m_pitch_table[i] = 384 - i * 2; + } + else + { + m_pitch_table[i] = i * 2 - 383; + } + + if (i < 128) + { + m_amplitude_table[i] = 255 - (i * 2); + } + else + { + m_amplitude_table[i] = (i * 2) - 256; + } + } + + for (int32_t table = 0; table < 8; ++table) + { + float limit = PHASE_SCALE_LIMIT[table]; + m_pitch_scale_tables[table] = make_unique_clear(256); + for (int32_t i = -128; i < 128; ++i) + { + const float value = (limit * (float)i) / 128.0f; + const float converted = powf(2.0f, value / 1200.0f); + m_pitch_scale_tables[table][i + 128] = value_to_fixed(LFO_SHIFT, converted); + } + + limit = -AMPLITUDE_SCALE_LIMIT[table]; + m_amplitude_scale_tables[table] = make_unique_clear(256); + for (int32_t i = 0; i < 256; ++i) + { + const float value = (limit * (float)i) / 256.0f; + const float converted = powf(10.0f, value / 20.0f); + m_amplitude_scale_tables[table][i] = value_to_fixed(LFO_SHIFT, converted); + } + } +} + +uint32_t gew_pcm_device::value_to_fixed(const uint32_t bits, const float value) +{ + const float float_shift = float(1 << bits); + return uint32_t(float_shift * value); +} + +int32_t gew_pcm_device::pitch_lfo_step(lfo_t &lfo) +{ + lfo.m_phase += lfo.m_phase_step; + int32_t p = lfo.m_table[(lfo.m_phase >> LFO_SHIFT) & 0xff]; + p = lfo.m_scale[p]; + return p << (TL_SHIFT - LFO_SHIFT); +} + +int32_t gew_pcm_device::amplitude_lfo_step(lfo_t &lfo) +{ + lfo.m_phase += lfo.m_phase_step; + int32_t p = lfo.m_table[(lfo.m_phase >> LFO_SHIFT) & 0xff]; + p = lfo.m_scale[p]; + return p << (TL_SHIFT - LFO_SHIFT); +} + +void gew_pcm_device::lfo_compute_step(lfo_t &lfo, uint32_t lfo_frequency, uint32_t lfo_scale, int32_t amplitude_lfo) +{ + float step = (float)LFO_FREQ[lfo_frequency] * 256.0f / (float)m_rate; + lfo.m_phase_step = uint32_t(float(1 << LFO_SHIFT) * step); + if (amplitude_lfo) + { + lfo.m_table = m_amplitude_table.get(); + lfo.m_scale = m_amplitude_scale_tables[lfo_scale].get(); + } + else + { + lfo.m_table = m_pitch_table.get(); + lfo.m_scale = m_pitch_scale_tables[lfo_scale].get(); + } +} + +/* MAME access functions */ + +gew_pcm_device::gew_pcm_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, + uint32_t voices, uint32_t clock_divider) : + device_t(mconfig, type, tag, owner, clock), + device_sound_interface(mconfig, *this), + device_rom_interface(mconfig, *this), + m_stream(nullptr), + m_slots(nullptr), + m_rate(0), + m_voices(voices), + m_clock_divider(clock_divider), + m_attack_step(nullptr), + m_decay_release_step(nullptr), + m_freq_step_table(nullptr), + m_left_pan_table(nullptr), + m_right_pan_table(nullptr), + m_linear_to_exp_volume(nullptr), + m_total_level_steps(nullptr) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gew_pcm_device::device_start() +{ + m_rate = (float)clock() / m_clock_divider; + + m_stream = stream_alloc(0, 2, m_rate); + + // Volume + pan table + m_left_pan_table = make_unique_clear(0x800); + m_right_pan_table = make_unique_clear(0x800); + for (int32_t level = 0; level < 0x80; ++level) + { + const float vol_db = (float)level * (-24.0f) / 64.0f; + const float total_level = powf(10.0f, vol_db / 20.0f) / 4.0f; + + for (int32_t pan = 0; pan < 0x10; ++pan) + { + float pan_left, pan_right; + if (pan == 0x8) + { + pan_left = 0.0; + pan_right = 0.0; + } + else if (pan == 0x0) + { + pan_left = 1.0; + pan_right = 1.0; + } + else if (pan & 0x8) + { + pan_left = 1.0; + + const int32_t inverted_pan = 0x10 - pan; + const float pan_vol_db = (float)inverted_pan * (-12.0f) / 4.0f; + + pan_right = pow(10.0f, pan_vol_db / 20.0f); + + if ((inverted_pan & 0x7) == 7) + { + pan_right = 0.0; + } + } + else + { + pan_right = 1.0; + + const float pan_vol_db = (float)pan * (-12.0f) / 4.0f; + + pan_left = pow(10.0f, pan_vol_db / 20.0f); + + if ((pan & 0x7) == 7) + { + pan_left = 0.0; + } + } + + m_left_pan_table[(pan << 7) | level] = value_to_fixed(TL_SHIFT, pan_left * total_level); + m_right_pan_table[(pan << 7) | level] = value_to_fixed(TL_SHIFT, pan_right * total_level); + } + } + + // Pitch steps + m_freq_step_table = make_unique_clear(0x400); + for (int32_t i = 0; i < 0x400; ++i) + { + const float fcent = m_rate * (1024.0f + (float)i) / 1024.0f; + m_freq_step_table[i] = value_to_fixed(TL_SHIFT, fcent); + } + + // Envelope steps + m_attack_step = make_unique_clear(0x40); + m_decay_release_step = make_unique_clear(0x40); + envelope_generator_init(BASE_TIMES, 14.32833); + + // Total level interpolation steps + m_total_level_steps = make_unique_clear(2); + m_total_level_steps[0] = -(float)(0x80 << TL_SHIFT) / (78.2f * 44100.0f / 1000.0f); // lower + m_total_level_steps[1] = (float)(0x80 << TL_SHIFT) / (78.2f * 2 * 44100.0f / 1000.0f); // raise + + // build the linear->exponential ramps + m_linear_to_exp_volume = make_unique_clear(0x400); + for (int32_t i = 0; i < 0x400; ++i) + { + const float db = -(96.0f - (96.0f * (float)i / (float)0x400)); + const float exp_volume = powf(10.0f, db / 20.0f); + m_linear_to_exp_volume[i] = value_to_fixed(TL_SHIFT, exp_volume); + } + + // Slots + m_slots = std::make_unique(m_voices); + + save_pointer(STRUCT_MEMBER(m_slots, m_regs), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_playing), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_offset), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_octave), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_pitch), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_step), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_pan), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_total_level), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_dest_total_level), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_total_level_step), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_prev_sample), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_lfo_frequency), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_vibrato), m_voices); + save_pointer(STRUCT_MEMBER(m_slots, m_tremolo), m_voices); + + for (int32_t slot = 0; slot < m_voices; ++slot) + { + save_item(NAME(m_slots[slot].m_sample.m_start), slot); + save_item(NAME(m_slots[slot].m_sample.m_loop), slot); + save_item(NAME(m_slots[slot].m_sample.m_end), slot); + save_item(NAME(m_slots[slot].m_sample.m_attack_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_decay1_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_decay2_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_decay_level), slot); + save_item(NAME(m_slots[slot].m_sample.m_release_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_key_rate_scale), slot); + save_item(NAME(m_slots[slot].m_sample.m_lfo_vibrato_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_lfo_amplitude_reg), slot); + save_item(NAME(m_slots[slot].m_sample.m_format), slot); + + save_item(NAME(m_slots[slot].m_envelope_gen.m_volume), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_state), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_reverb), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.step), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_attack_rate), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_decay1_rate), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_decay2_rate), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_release_rate), slot); + save_item(NAME(m_slots[slot].m_envelope_gen.m_decay_level), slot); + + save_item(NAME(m_slots[slot].m_pitch_lfo.m_phase), slot); + save_item(NAME(m_slots[slot].m_pitch_lfo.m_phase_step), slot); + save_item(NAME(m_slots[slot].m_amplitude_lfo.m_phase), slot); + save_item(NAME(m_slots[slot].m_amplitude_lfo.m_phase_step), slot); + } + + lfo_init(); +} + +void gew_pcm_device::device_reset() +{ + for (int32_t slot = 0; slot < m_voices; ++slot) + { + m_slots[slot].m_playing = false; + } +} + +//------------------------------------------------- +// device_clock_changed - called if the clock +// changes +//------------------------------------------------- + +void gew_pcm_device::device_clock_changed() +{ + m_rate = (float)clock() / m_clock_divider; + m_stream->set_sample_rate(m_rate); + + for (int32_t i = 0; i < 0x400; ++i) + { + const float fcent = m_rate * (1024.0f + (float)i) / 1024.0f; + m_freq_step_table[i] = value_to_fixed(TL_SHIFT, fcent); + } +} + +//----------------------------------------------------- +// dump_sample - dump current sample to WAV file +//----------------------------------------------------- + +#if MULTIPCM_LOG_SAMPLES +void gew_pcm_device::dump_sample(slot_t &slot) +{ + if (m_logged_map[slot.m_sample.m_start]) + return; + + m_logged_map[slot.m_sample.m_start] = true; + + char filebuf[256]; + snprintf(filebuf, 256, "multipcm%08x.wav", slot.m_sample.m_start); + util::wav_file_ptr file = util::wav_open(filebuf, m_stream->sample_rate(), 1); + if (file == nullptr) + return; + + uint32_t offset = slot.m_offset; + bool done = false; + while (!done) + { + int16_t sample = (int16_t)(read_byte(slot.m_sample.m_start + (offset >> TL_SHIFT)) << 8); + util::wav_add_data_16(*file.get(), &sample, 1); + + offset += 1 << TL_SHIFT; + if (offset >= (slot.m_sample.m_end << TL_SHIFT)) + { + done = true; + } + } + + util::wav_close(file.get()); +} +#endif + +//------------------------------------------------- +// sound_stream_update - handle a stream update +//------------------------------------------------- + +void gew_pcm_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) +{ + for (int32_t i = 0; i < outputs[0].samples(); ++i) + { + int32_t smpl = 0; + int32_t smpr = 0; + for (int32_t sl = 0; sl < m_voices; ++sl) + { + slot_t& slot = m_slots[sl]; + if (slot.m_playing) + { + uint32_t vol = (slot.m_total_level >> TL_SHIFT) | (slot.m_pan << 7); + uint32_t spos = slot.m_offset >> TL_SHIFT; + uint32_t step = slot.m_step; + int32_t csample = 0; + int32_t fpart = slot.m_offset & ((1 << TL_SHIFT) - 1); + + if (slot.m_sample.m_format & 4) // 12-bit linear + { + offs_t adr = slot.m_sample.m_start + (spos >> 1) * 3; + if (!(spos & 1)) + { // ab.c .. + s16 w0 = read_byte(adr) << 8 | ((read_byte(adr + 1) & 0xf) << 4); + csample = w0; + } + else + { // ..C. AB + s16 w0 = (read_byte(adr + 2) << 8) | (read_byte(adr + 1) & 0xf0); + csample = w0; + } + } + else + { + csample = (int16_t)(read_byte(slot.m_sample.m_start + spos) << 8); + } + + int32_t sample = (csample * fpart + slot.m_prev_sample * ((1 << TL_SHIFT) - fpart)) >> TL_SHIFT; + + if (slot.m_vibrato) // Vibrato enabled + { + step = step * pitch_lfo_step(slot.m_pitch_lfo); + step >>= TL_SHIFT; + } + + slot.m_offset += step; + if (slot.m_offset >= (slot.m_sample.m_end << TL_SHIFT)) + { + slot.m_offset -= (slot.m_sample.m_end - slot.m_sample.m_loop) << TL_SHIFT; + } + + if (spos ^ (slot.m_offset >> TL_SHIFT)) + { + slot.m_prev_sample = csample; + } + + if ((slot.m_total_level >> TL_SHIFT) != slot.m_dest_total_level) + { + slot.m_total_level += slot.m_total_level_step; + } + + if (slot.m_tremolo) // Tremolo enabled + { + sample = sample * amplitude_lfo_step(slot.m_amplitude_lfo); + sample >>= TL_SHIFT; + } + + sample = (sample * envelope_generator_update(slot)) >> 10; + + smpl += (m_left_pan_table[vol] * sample) >> TL_SHIFT; + smpr += (m_right_pan_table[vol] * sample) >> TL_SHIFT; + } + } + + outputs[0].put_int_clamp(i, smpl, 32768); + outputs[1].put_int_clamp(i, smpr, 32768); + } +} + + +//------------------------------------------------- +// rom_bank_pre_change - refresh the stream if the +// ROM banking changes +//------------------------------------------------- + +void gew_pcm_device::rom_bank_pre_change() +{ + m_stream->update(); +} diff --git a/src/devices/sound/gew.h b/src/devices/sound/gew.h new file mode 100644 index 00000000000..a162ec69650 --- /dev/null +++ b/src/devices/sound/gew.h @@ -0,0 +1,159 @@ +// license:BSD-3-Clause +// copyright-holders:Miguel Angel Horna +#ifndef MAME_SOUND_GEW_H +#define MAME_SOUND_GEW_H + +#pragma once + +#include "dirom.h" + +#define MULTIPCM_LOG_SAMPLES 0 + +#if MULTIPCM_LOG_SAMPLES +#include +#endif + +class gew_pcm_device : public device_t, + public device_sound_interface, + public device_rom_interface<22, 0, 0, ENDIANNESS_BIG> +{ +public: + static constexpr feature_type imperfect_features() { return feature::SOUND; } + +protected: + gew_pcm_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, + uint32_t voices, uint32_t clock_divider); + + virtual void device_start() override; + virtual void device_reset() override; + virtual void device_clock_changed() override; + + // sound stream update overrides + virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; + + // device_rom_interface overrides + virtual void rom_bank_pre_change() override; + + struct sample_t + { + uint32_t m_start = 0; + uint32_t m_loop = 0; + uint32_t m_end = 0; + uint8_t m_attack_reg = 0; + uint8_t m_decay1_reg = 0; + uint8_t m_decay2_reg = 0; + uint8_t m_decay_level = 0; + uint8_t m_release_reg = 0; + uint8_t m_key_rate_scale = 0; + uint8_t m_lfo_vibrato_reg = 0; + uint8_t m_lfo_amplitude_reg = 0; + uint8_t m_format = 0; + }; + + enum class state_t : u8 + { + ATTACK, + DECAY1, + DECAY2, + RELEASE + }; + + struct envelope_gen_t + { + int32_t m_volume = 0; + state_t m_state = state_t::ATTACK; + uint8_t m_reverb = 0; + int32_t step = 0; + //step vals + int32_t m_attack_rate = 0; // Attack + int32_t m_decay1_rate = 0; // Decay1 + int32_t m_decay2_rate = 0; // Decay2 + int32_t m_release_rate = 0; // Release + int32_t m_decay_level = 0; // Decay level + }; + + struct lfo_t + { + uint16_t m_phase = 0; + uint32_t m_phase_step = 0; + int32_t *m_table = nullptr; + int32_t *m_scale = nullptr; + }; + + struct slot_t + { + uint8_t m_regs[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; + bool m_playing = false; + sample_t m_sample; + uint32_t m_offset = 0; + uint8_t m_octave = 0; + uint16_t m_pitch = 0; + uint32_t m_step = 0; + uint32_t m_pan = 0; + uint32_t m_total_level = 0; + uint32_t m_dest_total_level = 0; + int32_t m_total_level_step = 0; + int32_t m_prev_sample = 0; + envelope_gen_t m_envelope_gen; + uint8_t m_lfo_frequency; + lfo_t m_pitch_lfo; // Pitch lfo + uint8_t m_vibrato = 0; + lfo_t m_amplitude_lfo; // AM lfo + uint8_t m_tremolo = 0; + }; + + uint32_t value_to_fixed(const uint32_t bits, const float value); + + void retrigger_sample(slot_t &slot); + void update_step(slot_t &slot); + + static constexpr uint32_t TL_SHIFT = 12; + static constexpr uint32_t EG_SHIFT = 16; + static constexpr uint32_t LFO_SHIFT = 8; + + // Internal LFO functions + void lfo_init(); + void lfo_compute_step(lfo_t &lfo, uint32_t lfo_frequency, uint32_t LFOS, int32_t amplitude_lfo); + int32_t pitch_lfo_step(lfo_t &lfo); + int32_t amplitude_lfo_step(lfo_t &lfo); + + // Internal envelope functions + void envelope_generator_init(const double (&rates)[64], double attack_decay_ratio); + int32_t envelope_generator_update(slot_t &slot); + void envelope_generator_calc(slot_t &slot); + uint32_t get_rate(uint32_t *steps, int32_t rate, uint32_t val); + +#if MULTIPCM_LOG_SAMPLES + void dump_sample(slot_t &slot); + std::map m_logged_map; +#endif + + static const double BASE_TIMES[64]; + + static const float LFO_FREQ[8]; + static const float PHASE_SCALE_LIMIT[8]; + static const float AMPLITUDE_SCALE_LIMIT[8]; + + // internal state + sound_stream* m_stream; + std::unique_ptr m_slots; + float m_rate; + uint32_t m_voices; + uint32_t m_clock_divider; + + std::unique_ptr m_attack_step; + std::unique_ptr m_decay_release_step; // Envelope step tables + std::unique_ptr m_freq_step_table; // Frequency step table + + std::unique_ptr m_left_pan_table; + std::unique_ptr m_right_pan_table; + std::unique_ptr m_linear_to_exp_volume; + std::unique_ptr m_total_level_steps; + + std::unique_ptr m_pitch_table; + std::unique_ptr m_pitch_scale_tables[8]; + std::unique_ptr m_amplitude_table; + std::unique_ptr m_amplitude_scale_tables[8]; +}; + +#endif // MAME_SOUND_GEW_H diff --git a/src/devices/sound/gew7.cpp b/src/devices/sound/gew7.cpp new file mode 100644 index 00000000000..38d97f169a4 --- /dev/null +++ b/src/devices/sound/gew7.cpp @@ -0,0 +1,205 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +#include "emu.h" +#include "gew7.h" + +DEFINE_DEVICE_TYPE(GEW7_PCM, gew7_pcm_device, "gew7_pcm", "Yamaha GEW7 PCM") + +gew7_pcm_device::gew7_pcm_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock) : + gew_pcm_device(mconfig, GEW7_PCM, tag, owner, clock, 12, 72) +{ +} + +void gew7_pcm_device::device_start() +{ + gew_pcm_device::device_start(); + + // fudge the default envelope step values to make them more like how they sound on this chip + // TODO: get some measurements from real hardware and try to make this more accurate + static const unsigned steps[] = { 0x99, 0xaa, 0xcc, 0x100 }; + + for (int32_t i = 4; i < 0x40; ++i) + { + m_attack_step[i] = steps[i % 4] << (i / 4); + m_decay_release_step[i] = m_attack_step[i] >> 5; + } + m_attack_step[0x3f] = 0x400 << EG_SHIFT; + + // stereo channels are reversed compared to GEW8 + std::swap(m_left_pan_table, m_right_pan_table); +} + +void gew7_pcm_device::init_sample(sample_t& sample, uint32_t index) +{ + uint32_t address = 0x4000 | index * 12; + + // format & address parts are mostly the same as GEW8 + sample.m_start = (read_byte(address) << 16) | (read_byte(address + 1) << 8) | read_byte(address + 2); + sample.m_format = (sample.m_start >> 20) & 0xfe; + sample.m_start &= 0x1fffff; + sample.m_loop = (read_byte(address + 3) << 8) | read_byte(address + 4); + sample.m_end = 0x4000 - ((read_byte(address + 5) << 8) | read_byte(address + 6)); + + // TODO: bytes 7 & 8 control LFO, reverse playback, etc (verify the details) + // the LFO bits are laid out a little differently than they are for GEW8 + sample.m_lfo_vibrato_reg = read_byte(address + 7); + sample.m_lfo_amplitude_reg = read_byte(address + 8); + + // ADSR bits are arranged differently compared to GEW8 + sample.m_attack_reg = read_byte(address + 9) >> 4; + sample.m_decay1_reg = read_byte(address + 9) & 0xf; + sample.m_decay2_reg = read_byte(address + 10) >> 4; + sample.m_release_reg = read_byte(address + 10) & 0xf; + sample.m_key_rate_scale = read_byte(address + 11) >> 4; + sample.m_decay_level = read_byte(address + 11) & 0xf; +} + +uint8_t gew7_pcm_device::read(offs_t offset) +{ + if (offset >= 0x60) return 0; + + if (!machine().side_effects_disabled()) + m_stream->update(); + + slot_t& slot = m_slots[offset >> 3]; + const uint8_t reg = offset & 7; + + switch (reg) + { + case 3: + // at least some GEW7-based keyboards seem to expect the key-on flag to go off by itself + // for certain "one-shot" sounds (i.e. the beeps when changing volume/tempo) + if (!slot.m_playing) + return slot.m_regs[reg] & 0x7f; + break; + + case 6: + // uppermost bits of current envelope level (inverted) + if (!slot.m_playing) + return 0xff; + + return ~slot.m_envelope_gen.m_volume >> (EG_SHIFT + 2); + + case 7: + // next 2 lower bits of envelope level (inverted) + 2 bits of envelope state + if (!slot.m_playing) + return 0xf0; + + return ((~slot.m_envelope_gen.m_volume >> EG_SHIFT) << 6) + | ((uint8_t)slot.m_envelope_gen.m_state << 4); + } + + return slot.m_regs[reg]; +} + +void gew7_pcm_device::write(offs_t offset, uint8_t data) +{ + if (offset >= 0x60) return; + + m_stream->update(); + + const uint8_t voice = offset >> 3; + const uint8_t reg = offset & 7; + slot_t& slot = m_slots[voice]; + slot.m_regs[reg] = data; + + switch (reg) + { + case 0: // sample + init_sample(slot.m_sample, slot.m_regs[0] | ((slot.m_regs[1] & 1) << 8)); + + slot.m_lfo_frequency = slot.m_sample.m_lfo_amplitude_reg & 7; + write_hi((voice << 2) | 3, slot.m_sample.m_lfo_vibrato_reg); + + // retrigger if key is on + if (slot.m_playing) + retrigger_sample(slot); + break; + + case 1: // pitch + case 2: + slot.m_octave = slot.m_regs[2] >> 4; + slot.m_pitch = ((slot.m_regs[2] & 0xf) << 6) | (slot.m_regs[1] >> 2); + update_step(slot); + // adjust pitch step for oversampling + slot.m_step >>= 1; + break; + + case 3: // key on + reverb + panpot + if (data & 0x80) + { + slot.m_playing = true; + retrigger_sample(slot); + } + else if (slot.m_playing) + { + slot.m_envelope_gen.m_state = state_t::RELEASE; + } + + slot.m_envelope_gen.m_reverb = BIT(data, 4); + slot.m_pan = data & 0xf; + break; + + case 4: // TL + slot.m_dest_total_level = data & 0x7f; + slot.m_total_level = slot.m_dest_total_level << TL_SHIFT; + break; + } +} + +uint8_t gew7_pcm_device::read_hi(offs_t offset) +{ + if (offset >= 0x30) return 0; + + if (!machine().side_effects_disabled()) + m_stream->update(); + + slot_t& slot = m_slots[offset >> 2]; + switch (offset & 3) + { + case 0: // TODO: unverified, just a guess based on reg 1 + return (slot.m_sample.m_attack_reg << 4) | slot.m_sample.m_decay1_reg; + + case 1: // TODO: unverified, but gets ORed with 0x0f when killing a voice before waiting for envelope to end + return (slot.m_sample.m_decay2_reg << 4) | slot.m_sample.m_release_reg; + + case 3: + return (slot.m_tremolo << 3) | slot.m_vibrato; + } + + return 0; +} + +void gew7_pcm_device::write_hi(offs_t offset, uint8_t data) +{ + if (offset >= 0x30) return; + + m_stream->update(); + + slot_t& slot = m_slots[offset >> 2]; + switch (offset & 3) + { + case 0: + slot.m_sample.m_attack_reg = data >> 4; + slot.m_sample.m_decay1_reg = data & 0xf; + envelope_generator_calc(slot); + break; + + case 1: + slot.m_sample.m_decay2_reg = data >> 4; + slot.m_sample.m_release_reg = data & 0xf; + envelope_generator_calc(slot); + break; + + case 2: // TODO: ??? (probably related to unknown bits of sample table) + break; + + case 3: + slot.m_vibrato = data & 7; + slot.m_tremolo = (data >> 3) & 7; + lfo_compute_step(slot.m_pitch_lfo, slot.m_lfo_frequency, slot.m_vibrato, 0); + lfo_compute_step(slot.m_amplitude_lfo, slot.m_lfo_frequency, slot.m_tremolo, 1); + break; + } +} diff --git a/src/devices/sound/gew7.h b/src/devices/sound/gew7.h new file mode 100644 index 00000000000..5d50b2872f4 --- /dev/null +++ b/src/devices/sound/gew7.h @@ -0,0 +1,30 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker +#ifndef MAME_SOUND_GEW7_H +#define MAME_SOUND_GEW7_H + +#pragma once + +#include "gew.h" + +class gew7_pcm_device : public gew_pcm_device +{ +public: + gew7_pcm_device(const machine_config& mconfig, const char* tag, device_t* owner, uint32_t clock); + + void write(offs_t offset, uint8_t data); + uint8_t read(offs_t offset); + + void write_hi(offs_t offset, uint8_t data); + uint8_t read_hi(offs_t offset); + +protected: + virtual void device_start() override; + +private: + void init_sample(sample_t& sample, uint32_t index); +}; + +DECLARE_DEVICE_TYPE(GEW7_PCM, gew7_pcm_device) + +#endif // MAME_SOUND_GEW7_H diff --git a/src/devices/sound/multipcm.cpp b/src/devices/sound/multipcm.cpp index e8564f22698..e73d290f648 100644 --- a/src/devices/sound/multipcm.cpp +++ b/src/devices/sound/multipcm.cpp @@ -37,34 +37,6 @@ #include "emu.h" #include "multipcm.h" -#include "wavwrite.h" - -ALLOW_SAVE_TYPE(multipcm_device::state_t); // allow save_item on a non-fundamental type - -/******************************* - ENVELOPE SECTION -*******************************/ - -// Times are based on a 44100Hz timebase. It's adjusted to the actual sampling rate on startup - -const double multipcm_device::BASE_TIMES[64] = { - 0, 0, 0, 0, - 6222.95, 4978.37, 4148.66, 3556.01, - 3111.47, 2489.21, 2074.33, 1778.00, - 1555.74, 1244.63, 1037.19, 889.02, - 777.87, 622.31, 518.59, 444.54, - 388.93, 311.16, 259.32, 222.27, - 194.47, 155.60, 129.66, 111.16, - 97.23, 77.82, 64.85, 55.60, - 48.62, 38.91, 32.43, 27.80, - 24.31, 19.46, 16.24, 13.92, - 12.15, 9.75, 8.12, 6.98, - 6.08, 4.90, 4.08, 3.49, - 3.04, 2.49, 2.13, 1.90, - 1.72, 1.41, 1.18, 1.04, - 0.91, 0.73, 0.59, 0.50, - 0.45, 0.45, 0.45, 0.45 -}; const int32_t multipcm_device::VALUE_TO_CHANNEL[32] = { @@ -74,272 +46,28 @@ const int32_t multipcm_device::VALUE_TO_CHANNEL[32] = 21,22,23,24,25,26,27, -1, }; -constexpr uint32_t multipcm_device::TL_SHIFT; -constexpr uint32_t multipcm_device::EG_SHIFT; - -void multipcm_device::init_sample(sample_t *sample, uint32_t index) +void multipcm_device::init_sample(sample_t &sample, uint32_t index) { uint32_t address = index * 12; - sample->m_start = (read_byte(address) << 16) | (read_byte(address + 1) << 8) | read_byte(address + 2); - sample->m_format = (sample->m_start>>20) & 0xfe; - sample->m_start &= 0x3fffff; - sample->m_loop = (read_byte(address + 3) << 8) | read_byte(address + 4); - sample->m_end = 0xffff - ((read_byte(address + 5) << 8) | read_byte(address + 6)); - sample->m_attack_reg = (read_byte(address + 8) >> 4) & 0xf; - sample->m_decay1_reg = read_byte(address + 8) & 0xf; - sample->m_decay2_reg = read_byte(address + 9) & 0xf; - sample->m_decay_level = (read_byte(address + 9) >> 4) & 0xf; - sample->m_release_reg = read_byte(address + 10) & 0xf; - sample->m_key_rate_scale = (read_byte(address + 10) >> 4) & 0xf; - sample->m_lfo_vibrato_reg = read_byte(address + 7); - sample->m_lfo_amplitude_reg = read_byte(address + 11) & 0xf; -} - -void multipcm_device::retrigger_sample(slot_t &slot) -{ - slot.m_offset = 0; - slot.m_prev_sample = 0; - slot.m_total_level = slot.m_dest_total_level << TL_SHIFT; - - envelope_generator_calc(slot); - slot.m_envelope_gen.m_state = state_t::ATTACK; - slot.m_envelope_gen.m_volume = 0; - -#if MULTIPCM_LOG_SAMPLES - dump_sample(slot); -#endif -} - -int32_t multipcm_device::envelope_generator_update(slot_t &slot) -{ - switch(slot.m_envelope_gen.m_state) - { - case state_t::ATTACK: - slot.m_envelope_gen.m_volume += slot.m_envelope_gen.m_attack_rate; - if (slot.m_envelope_gen.m_volume >= (0x3ff << EG_SHIFT)) - { - slot.m_envelope_gen.m_state = state_t::DECAY1; - if (slot.m_envelope_gen.m_decay1_rate >= (0x400 << EG_SHIFT)) //Skip DECAY1, go directly to DECAY2 - { - slot.m_envelope_gen.m_state = state_t::DECAY2; - } - slot.m_envelope_gen.m_volume = 0x3ff << EG_SHIFT; - } - break; - case state_t::DECAY1: - slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_decay1_rate; - if (slot.m_envelope_gen.m_volume <= 0) - { - slot.m_envelope_gen.m_volume = 0; - } - if (slot.m_envelope_gen.m_volume >> EG_SHIFT <= (slot.m_envelope_gen.m_decay_level << 6)) - { - slot.m_envelope_gen.m_state = state_t::DECAY2; - } - break; - case state_t::DECAY2: - slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_decay2_rate; - if (slot.m_envelope_gen.m_volume <= 0) - { - slot.m_envelope_gen.m_volume = 0; - } - break; - case state_t::RELEASE: - slot.m_envelope_gen.m_volume -= slot.m_envelope_gen.m_release_rate; - if (slot.m_envelope_gen.m_volume <= 0) - { - slot.m_envelope_gen.m_volume = 0; - slot.m_playing = false; - } - break; - default: - return 1 << TL_SHIFT; - } - - return m_linear_to_exp_volume[slot.m_envelope_gen.m_volume >> EG_SHIFT]; -} - -uint32_t multipcm_device::get_rate(uint32_t *steps, uint32_t rate, uint32_t val) -{ - int32_t r = 4 * val + rate; - if (val == 0) - { - return steps[0]; - } - if (val == 0xf) - { - return steps[0x3f]; - } - if (r > 0x3f) - { - r = 0x3f; - } - return steps[r]; -} - -void multipcm_device::envelope_generator_calc(slot_t &slot) -{ - int32_t octave = ((slot.m_regs[3] >> 4) - 1) & 0xf; - if (octave & 8) { - octave = octave - 16; - } - - int32_t rate; - if (slot.m_sample.m_key_rate_scale != 0xf) - { - rate = (octave + slot.m_sample.m_key_rate_scale) * 2 + ((slot.m_regs[3] >> 3) & 1); - } - else - { - rate = 0; - } - - slot.m_envelope_gen.m_attack_rate = get_rate(m_attack_step.get(), rate, slot.m_sample.m_attack_reg); - slot.m_envelope_gen.m_decay1_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_decay1_reg); - slot.m_envelope_gen.m_decay2_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_decay2_reg); - slot.m_envelope_gen.m_release_rate = get_rate(m_decay_release_step.get(), rate, slot.m_sample.m_release_reg); - slot.m_envelope_gen.m_decay_level = 0xf - slot.m_sample.m_decay_level; - -} - -/***************************** - LFO SECTION -*****************************/ - -constexpr uint32_t multipcm_device::LFO_SHIFT; - -const float multipcm_device::LFO_FREQ[8] = // In Hertz -{ - 0.168f, - 2.019f, - 3.196f, - 4.206f, - 5.215f, - 5.888f, - 6.224f, - 7.066f -}; - -const float multipcm_device::PHASE_SCALE_LIMIT[8] = // In Cents -{ - 0.0f, - 3.378f, - 5.065f, - 6.750f, - 10.114f, - 20.170f, - 40.180f, - 79.307f -}; - -const float multipcm_device::AMPLITUDE_SCALE_LIMIT[8] = // In Decibels -{ - 0.0f, - 0.4f, - 0.8f, - 1.5f, - 3.0f, - 6.0f, - 12.0f, - 24.0f -}; - -void multipcm_device::lfo_init() -{ - m_pitch_table = make_unique_clear(256); - m_amplitude_table = make_unique_clear(256); - for (int32_t i = 0; i < 256; ++i) - { - if (i < 64) - { - m_pitch_table[i] = i * 2 + 128; - } - else if (i < 128) - { - m_pitch_table[i] = 383 - i * 2; - } - else if (i < 192) - { - m_pitch_table[i] = 384 - i * 2; - } - else - { - m_pitch_table[i] = i * 2 - 383; - } - - if (i < 128) - { - m_amplitude_table[i] = 255 - (i * 2); - } - else - { - m_amplitude_table[i] = (i * 2) - 256; - } - } - - for (int32_t table = 0; table < 8; ++table) - { - float limit = PHASE_SCALE_LIMIT[table]; - m_pitch_scale_tables[table] = make_unique_clear(256); - for(int32_t i = -128; i < 128; ++i) - { - const float value = (limit * (float)i) / 128.0f; - const float converted = powf(2.0f, value / 1200.0f); - m_pitch_scale_tables[table][i + 128] = value_to_fixed(LFO_SHIFT, converted); - } - - limit = -AMPLITUDE_SCALE_LIMIT[table]; - m_amplitude_scale_tables[table] = make_unique_clear(256); - for(int32_t i = 0; i < 256; ++i) - { - const float value = (limit * (float)i) / 256.0f; - const float converted = powf(10.0f, value / 20.0f); - m_amplitude_scale_tables[table][i] = value_to_fixed(LFO_SHIFT, converted); - } - } -} - -uint32_t multipcm_device::value_to_fixed(const uint32_t bits, const float value) -{ - const float float_shift = float(1 << bits); - return uint32_t(float_shift * value); -} - -int32_t multipcm_device::pitch_lfo_step(lfo_t &lfo) -{ - lfo.m_phase += lfo.m_phase_step; - int32_t p = lfo.m_table[(lfo.m_phase >> LFO_SHIFT) & 0xff]; - p = lfo.m_scale[p]; - return p << (TL_SHIFT - LFO_SHIFT); -} - -int32_t multipcm_device::amplitude_lfo_step(lfo_t &lfo) -{ - lfo.m_phase += lfo.m_phase_step; - int32_t p = lfo.m_table[(lfo.m_phase >> LFO_SHIFT) & 0xff]; - p = lfo.m_scale[p]; - return p << (TL_SHIFT - LFO_SHIFT); -} - -void multipcm_device::lfo_compute_step(lfo_t &lfo, uint32_t lfo_frequency, uint32_t lfo_scale, int32_t amplitude_lfo) -{ - float step = (float)LFO_FREQ[lfo_frequency] * 256.0f / (float)m_rate; - lfo.m_phase_step = uint32_t(float(1 << LFO_SHIFT) * step); - if (amplitude_lfo) - { - lfo.m_table = m_amplitude_table.get(); - lfo.m_scale = m_amplitude_scale_tables[lfo_scale].get(); - } - else - { - lfo.m_table = m_pitch_table.get(); - lfo.m_scale = m_pitch_scale_tables[lfo_scale].get(); - } + sample.m_start = (read_byte(address) << 16) | (read_byte(address + 1) << 8) | read_byte(address + 2); + sample.m_format = (sample.m_start>>20) & 0xfe; + sample.m_start &= 0x3fffff; + sample.m_loop = (read_byte(address + 3) << 8) | read_byte(address + 4); + sample.m_end = 0x10000 - ((read_byte(address + 5) << 8) | read_byte(address + 6)); + sample.m_attack_reg = (read_byte(address + 8) >> 4) & 0xf; + sample.m_decay1_reg = read_byte(address + 8) & 0xf; + sample.m_decay2_reg = read_byte(address + 9) & 0xf; + sample.m_decay_level = (read_byte(address + 9) >> 4) & 0xf; + sample.m_release_reg = read_byte(address + 10) & 0xf; + sample.m_key_rate_scale = (read_byte(address + 10) >> 4) & 0xf; + sample.m_lfo_vibrato_reg = read_byte(address + 7); + sample.m_lfo_amplitude_reg = read_byte(address + 11) & 0xf; } void multipcm_device::write_slot(slot_t &slot, int32_t reg, uint8_t data) { + m_stream->update(); slot.m_regs[reg] = data; switch(reg) @@ -351,13 +79,10 @@ void multipcm_device::write_slot(slot_t &slot, int32_t reg, uint8_t data) case 1: // Sample { // according to YMF278 sample write causes some base params written to the regs (envelope+lfos) - init_sample(&slot.m_sample, slot.m_regs[1] | ((slot.m_regs[2] & 1) << 8)); + init_sample(slot.m_sample, slot.m_regs[1] | ((slot.m_regs[2] & 1) << 8)); write_slot(slot, 6, slot.m_sample.m_lfo_vibrato_reg); write_slot(slot, 7, slot.m_sample.m_lfo_amplitude_reg); - slot.m_base = slot.m_sample.m_start; - slot.m_format = slot.m_sample.m_format; - // retrigger if key is on if (slot.m_playing) retrigger_sample(slot); @@ -367,18 +92,9 @@ void multipcm_device::write_slot(slot_t &slot, int32_t reg, uint8_t data) case 2: // Pitch case 3: { - uint32_t oct = ((slot.m_regs[3] >> 4) - 1) & 0xf; - uint32_t pitch = ((slot.m_regs[3] & 0xf) << 6) | (slot.m_regs[2] >> 2); - pitch = m_freq_step_table[pitch]; - if (oct & 0x8) - { - pitch >>= (16 - oct); - } - else - { - pitch <<= oct; - } - slot.m_step = pitch / m_rate; + slot.m_octave = slot.m_regs[3] >> 4; + slot.m_pitch = ((slot.m_regs[3] & 0xf) << 6) | (slot.m_regs[2] >> 2); + update_step(slot); } break; case 4: // KeyOn/Off @@ -421,17 +137,14 @@ void multipcm_device::write_slot(slot_t &slot, int32_t reg, uint8_t data) } break; case 6: // LFO frequency + Pitch LFO - if (data) - { - lfo_compute_step(slot.m_pitch_lfo, (slot.m_regs[6] >> 3) & 7, slot.m_regs[6] & 7, 0); - lfo_compute_step(slot.m_amplitude_lfo, (slot.m_regs[6] >> 3) & 7, slot.m_regs[7] & 7, 1); - } - break; case 7: // Amplitude LFO + slot.m_lfo_frequency = (slot.m_regs[6] >> 3) & 7; + slot.m_vibrato = slot.m_regs[6] & 7; + slot.m_tremolo = slot.m_regs[7] & 7; if (data) { - lfo_compute_step(slot.m_pitch_lfo, (slot.m_regs[6] >> 3) & 7, slot.m_regs[6] & 7, 0); - lfo_compute_step(slot.m_amplitude_lfo, (slot.m_regs[6] >> 3) & 7, slot.m_regs[7] & 7, 1); + lfo_compute_step(slot.m_pitch_lfo, slot.m_lfo_frequency, slot.m_vibrato, 0); + lfo_compute_step(slot.m_amplitude_lfo, slot.m_lfo_frequency, slot.m_tremolo, 1); } break; } @@ -465,325 +178,8 @@ void multipcm_device::write(offs_t offset, uint8_t data) DEFINE_DEVICE_TYPE(MULTIPCM, multipcm_device, "ymw258f", "Yamaha YMW-258-F") multipcm_device::multipcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, MULTIPCM, tag, owner, clock), - device_sound_interface(mconfig, *this), - device_rom_interface(mconfig, *this), - m_stream(nullptr), - m_slots(nullptr), + gew_pcm_device(mconfig, MULTIPCM, tag, owner, clock, 28, 224), m_cur_slot(0), - m_address(0), - m_rate(0), - m_attack_step(nullptr), - m_decay_release_step(nullptr), - m_freq_step_table(nullptr), - m_left_pan_table(nullptr), - m_right_pan_table(nullptr), - m_linear_to_exp_volume(nullptr), - m_total_level_steps(nullptr) -{ -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void multipcm_device::device_start() -{ - const float clock_divider = 224.0f; - m_rate = (float)clock() / clock_divider; - - m_stream = stream_alloc(0, 2, m_rate); - - // Volume + pan table - m_left_pan_table = make_unique_clear(0x800); - m_right_pan_table = make_unique_clear(0x800); - for (int32_t level = 0; level < 0x80; ++level) - { - const float vol_db = (float)level * (-24.0f) / 64.0f; - const float total_level = powf(10.0f, vol_db / 20.0f) / 4.0f; - - for (int32_t pan = 0; pan < 0x10; ++pan) - { - float pan_left, pan_right; - if (pan == 0x8) - { - pan_left = 0.0; - pan_right = 0.0; - } - else if (pan == 0x0) - { - pan_left = 1.0; - pan_right = 1.0; - } - else if (pan & 0x8) - { - pan_left = 1.0; - - const int32_t inverted_pan = 0x10 - pan; - const float pan_vol_db = (float)inverted_pan * (-12.0f) / 4.0f; - - pan_right = pow(10.0f, pan_vol_db / 20.0f); - - if ((inverted_pan & 0x7) == 7) - { - pan_right = 0.0; - } - } - else - { - pan_right = 1.0; - - const float pan_vol_db = (float)pan * (-12.0f) / 4.0f; - - pan_left = pow(10.0f, pan_vol_db / 20.0f); - - if ((pan & 0x7) == 7) - { - pan_left = 0.0; - } - } - - m_left_pan_table[(pan << 7) | level] = value_to_fixed(TL_SHIFT, pan_left * total_level); - m_right_pan_table[(pan << 7) | level] = value_to_fixed(TL_SHIFT, pan_right * total_level); - } - } - - // Pitch steps - m_freq_step_table = make_unique_clear(0x400); - for (int32_t i = 0; i < 0x400; ++i) - { - const float fcent = m_rate * (1024.0f + (float)i) / 1024.0f; - m_freq_step_table[i] = value_to_fixed(TL_SHIFT, fcent); - } - - // Envelope steps - m_attack_step = make_unique_clear(0x40); - m_decay_release_step = make_unique_clear(0x40); - const double attack_rate_to_decay_rate = 14.32833; - for (int32_t i = 4; i < 0x40; ++i) - { - // Times are based on 44100Hz clock, adjust to real chip clock - m_attack_step[i] = (float)(0x400 << EG_SHIFT) / (float)(BASE_TIMES[i] * 44100.0 / 1000.0); - m_decay_release_step[i] = (float)(0x400 << EG_SHIFT) / (float)(BASE_TIMES[i] * attack_rate_to_decay_rate * 44100.0 / 1000.0); - } - m_attack_step[0] = m_attack_step[1] = m_attack_step[2] = m_attack_step[3] = 0; - m_attack_step[0x3f] = 0x400 << EG_SHIFT; - m_decay_release_step[0] = m_decay_release_step[1] = m_decay_release_step[2] = m_decay_release_step[3] = 0; - - // Total level interpolation steps - m_total_level_steps = make_unique_clear(2); - m_total_level_steps[0] = -(float)(0x80 << TL_SHIFT) / (78.2f * 44100.0f / 1000.0f); // lower - m_total_level_steps[1] = (float)(0x80 << TL_SHIFT) / (78.2f * 2 * 44100.0f / 1000.0f); // raise - - // build the linear->exponential ramps - m_linear_to_exp_volume = make_unique_clear(0x400); - for(int32_t i = 0; i < 0x400; ++i) - { - const float db = -(96.0f - (96.0f * (float)i / (float)0x400)); - const float exp_volume = powf(10.0f, db / 20.0f); - m_linear_to_exp_volume[i] = value_to_fixed(TL_SHIFT, exp_volume); - } - - save_item(NAME(m_cur_slot)); - save_item(NAME(m_address)); - - // Slots - m_slots = std::make_unique(28); - - save_pointer(STRUCT_MEMBER(m_slots, m_regs), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_playing), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_base), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_offset), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_step), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_pan), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_total_level), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_dest_total_level), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_total_level_step), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_prev_sample), 28); - save_pointer(STRUCT_MEMBER(m_slots, m_format), 28); - - for (int32_t slot = 0; slot < 28; ++slot) - { - m_slots[slot].m_playing = false; - - save_item(NAME(m_slots[slot].m_envelope_gen.m_volume), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_state), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.step), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_attack_rate), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_decay1_rate), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_decay2_rate), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_release_rate), slot); - save_item(NAME(m_slots[slot].m_envelope_gen.m_decay_level), slot); - save_item(NAME(m_slots[slot].m_pitch_lfo.m_phase), slot); - save_item(NAME(m_slots[slot].m_pitch_lfo.m_phase_step), slot); - save_item(NAME(m_slots[slot].m_amplitude_lfo.m_phase), slot); - save_item(NAME(m_slots[slot].m_amplitude_lfo.m_phase_step), slot); - } - - lfo_init(); -} - -//------------------------------------------------- -// device_clock_changed - called if the clock -// changes -//------------------------------------------------- - -void multipcm_device::device_clock_changed() + m_address(0) { - const float clock_divider = 224.0f; - m_rate = (float)clock() / clock_divider; - m_stream->set_sample_rate(m_rate); - - for (int32_t i = 0; i < 0x400; ++i) - { - const float fcent = m_rate * (1024.0f + (float)i) / 1024.0f; - m_freq_step_table[i] = value_to_fixed(TL_SHIFT, fcent); - } -} - -//----------------------------------------------------- -// dump_sample - dump current sample to WAV file -//----------------------------------------------------- - -#if MULTIPCM_LOG_SAMPLES -void multipcm_device::dump_sample(slot_t &slot) -{ - if (m_logged_map[slot.m_base]) - return; - - m_logged_map[slot.m_base] = true; - - char filebuf[256]; - snprintf(filebuf, 256, "multipcm%08x.wav", slot.m_base); - wav_file *file = wav_open(filebuf, m_stream->sample_rate(), 1); - if (file == nullptr) - return; - - uint32_t offset = slot.m_offset; - bool done = false; - while (!done) - { - int16_t sample = (int16_t) (read_byte(slot.m_base + (offset >> TL_SHIFT)) << 8); - wav_add_data_16(file, &sample, 1); - - offset += 1 << TL_SHIFT; - if (offset >= (slot.m_sample.m_end << TL_SHIFT)) - { - done = true; - } - } - - wav_close(file); -} -#endif - -//------------------------------------------------- -// sound_stream_update - handle a stream update -//------------------------------------------------- - -void multipcm_device::sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) -{ - for (int32_t i = 0; i < outputs[0].samples(); ++i) - { - int32_t smpl = 0; - int32_t smpr = 0; - for (int32_t sl = 0; sl < 28; ++sl) - { - slot_t &slot = m_slots[sl]; - if (slot.m_playing) - { - uint32_t vol = (slot.m_total_level >> TL_SHIFT) | (slot.m_pan << 7); - uint32_t spos = slot.m_offset >> TL_SHIFT; - uint32_t step = slot.m_step; - int32_t csample = 0; - int32_t fpart = slot.m_offset & ((1 << TL_SHIFT) - 1); - - if (slot.m_format & 4) // 12-bit linear - { - offs_t adr = slot.m_base + (spos >> 2) * 6; - switch (spos & 3) - { - case 0: - { // ab.c .... .... - s16 w0 = read_byte(adr) << 8 | ((read_byte(adr + 1) & 0xf) << 4); - csample = w0; - break; - } - case 1: - { // ..C. AB.. .... - s16 w0 = (read_byte(adr + 2) << 8) | (read_byte(adr + 1) & 0xf0); - csample = w0; - break; - } - case 2: - { // .... ..ab .c.. - s16 w0 = read_byte(adr + 3) << 8 | ((read_byte(adr + 4) & 0xf) << 4); - csample = w0; - break; - } - case 3: - { // .... .... C.AB - s16 w0 = (read_byte(adr + 5) << 8) | (read_byte(adr + 4) & 0xf0); - csample = w0; - break; - } - } - } - else - { - csample = (int16_t)(read_byte(slot.m_base + spos) << 8); - } - - int32_t sample = (csample * fpart + slot.m_prev_sample * ((1 << TL_SHIFT) - fpart)) >> TL_SHIFT; - - if (slot.m_regs[6] & 7) // Vibrato enabled - { - step = step * pitch_lfo_step(slot.m_pitch_lfo); - step >>= TL_SHIFT; - } - - slot.m_offset += step; - if (slot.m_offset >= (slot.m_sample.m_end << TL_SHIFT)) - { - slot.m_offset = slot.m_sample.m_loop << TL_SHIFT; - } - - if (spos ^ (slot.m_offset >> TL_SHIFT)) - { - slot.m_prev_sample = csample; - } - - if ((slot.m_total_level >> TL_SHIFT) != slot.m_dest_total_level) - { - slot.m_total_level += slot.m_total_level_step; - } - - if (slot.m_regs[7] & 7) // Tremolo enabled - { - sample = sample * amplitude_lfo_step(slot.m_amplitude_lfo); - sample >>= TL_SHIFT; - } - - sample = (sample * envelope_generator_update(slot)) >> 10; - - smpl += (m_left_pan_table[vol] * sample) >> TL_SHIFT; - smpr += (m_right_pan_table[vol] * sample) >> TL_SHIFT; - } - } - - outputs[0].put_int_clamp(i, smpl, 32768); - outputs[1].put_int_clamp(i, smpr, 32768); - } -} - - -//------------------------------------------------- -// rom_bank_pre_change - refresh the stream if the -// ROM banking changes -//------------------------------------------------- - -void multipcm_device::rom_bank_pre_change() -{ - m_stream->update(); } diff --git a/src/devices/sound/multipcm.h b/src/devices/sound/multipcm.h index 786b5a3f02c..c6b5ed8d4b1 100644 --- a/src/devices/sound/multipcm.h +++ b/src/devices/sound/multipcm.h @@ -5,17 +5,9 @@ #pragma once -#include "dirom.h" +#include "gew.h" -#define MULTIPCM_LOG_SAMPLES 0 - -#if MULTIPCM_LOG_SAMPLES -#include -#endif - -class multipcm_device : public device_t, - public device_sound_interface, - public device_rom_interface<22, 0, 0, ENDIANNESS_BIG> +class multipcm_device : public gew_pcm_device { public: multipcm_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -23,139 +15,16 @@ public: void write(offs_t offset, uint8_t data); uint8_t read(); -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_clock_changed() override; - - // sound stream update overrides - virtual void sound_stream_update(sound_stream &stream, std::vector const &inputs, std::vector &outputs) override; - - // device_rom_interface overrides - virtual void rom_bank_pre_change() override; - private: - struct sample_t - { - uint32_t m_start = 0; - uint32_t m_loop = 0; - uint32_t m_end = 0; - uint8_t m_attack_reg = 0; - uint8_t m_decay1_reg = 0; - uint8_t m_decay2_reg = 0; - uint8_t m_decay_level = 0; - uint8_t m_release_reg = 0; - uint8_t m_key_rate_scale = 0; - uint8_t m_lfo_vibrato_reg = 0; - uint8_t m_lfo_amplitude_reg = 0; - uint8_t m_format = 0; - }; - - enum class state_t : u8 - { - ATTACK, - DECAY1, - DECAY2, - RELEASE - }; - - struct envelope_gen_t - { - int32_t m_volume = 0; - state_t m_state = state_t::ATTACK; - int32_t step = 0; - //step vals - int32_t m_attack_rate = 0; // Attack - int32_t m_decay1_rate = 0; // Decay1 - int32_t m_decay2_rate = 0; // Decay2 - int32_t m_release_rate = 0; // Release - int32_t m_decay_level = 0; // Decay level - }; - - struct lfo_t - { - uint16_t m_phase = 0; - uint32_t m_phase_step = 0; - int32_t *m_table = nullptr; - int32_t *m_scale = nullptr; - }; - - struct slot_t - { - uint8_t m_regs[8] = { 0, 0, 0, 0, 0, 0, 0, 0 }; - bool m_playing = false; - sample_t m_sample; - uint32_t m_base = 0; - uint32_t m_offset = 0; - uint32_t m_step = 0; - uint32_t m_pan = 0; - uint32_t m_total_level = 0; - uint32_t m_dest_total_level = 0; - int32_t m_total_level_step = 0; - int32_t m_prev_sample = 0; - envelope_gen_t m_envelope_gen; - lfo_t m_pitch_lfo; // Pitch lfo - lfo_t m_amplitude_lfo; // AM lfo - uint8_t m_format; - }; - // internal state - sound_stream *m_stream; - std::unique_ptr m_slots; uint32_t m_cur_slot; uint32_t m_address; - float m_rate; - - std::unique_ptr m_attack_step; - std::unique_ptr m_decay_release_step; // Envelope step tables - std::unique_ptr m_freq_step_table; // Frequency step table - - std::unique_ptr m_left_pan_table; - std::unique_ptr m_right_pan_table; - std::unique_ptr m_linear_to_exp_volume; - std::unique_ptr m_total_level_steps; - - std::unique_ptr m_pitch_table; - std::unique_ptr m_pitch_scale_tables[8]; - std::unique_ptr m_amplitude_table; - std::unique_ptr m_amplitude_scale_tables[8]; - - uint32_t value_to_fixed(const uint32_t bits, const float value); - - void init_sample(sample_t *sample, uint32_t index); - void retrigger_sample(slot_t &slot); - - // Internal LFO functions - void lfo_init(); - void lfo_compute_step(lfo_t &lfo, uint32_t lfo_frequency, uint32_t LFOS, int32_t amplitude_lfo); - int32_t pitch_lfo_step(lfo_t &lfo); - int32_t amplitude_lfo_step(lfo_t &lfo); - - // Internal envelope functions - int32_t envelope_generator_update(slot_t &slot); - void envelope_generator_calc(slot_t &slot); - uint32_t get_rate(uint32_t *steps, uint32_t rate, uint32_t val); - - void write_slot(slot_t &slot, int32_t reg, uint8_t data); - - stream_buffer::sample_t convert_to_stream_sample(int32_t value); - -#if MULTIPCM_LOG_SAMPLES - void dump_sample(slot_t &slot); - std::map m_logged_map; -#endif - - static constexpr uint32_t TL_SHIFT = 12; static const int32_t VALUE_TO_CHANNEL[32]; - static constexpr uint32_t EG_SHIFT = 16; - static const double BASE_TIMES[64]; + void init_sample(sample_t &sample, uint32_t index); - static constexpr uint32_t LFO_SHIFT = 8; - static const float LFO_FREQ[8]; - static const float PHASE_SCALE_LIMIT[8]; - static const float AMPLITUDE_SCALE_LIMIT[8]; + void write_slot(slot_t &slot, int32_t reg, uint8_t data); }; DECLARE_DEVICE_TYPE(MULTIPCM, multipcm_device) diff --git a/src/mame/layout/psr110.lay b/src/mame/layout/psr110.lay new file mode 100644 index 00000000000..fd9d8814805 --- /dev/null +++ b/src/mame/layout/psr110.lay @@ -0,0 +1,273 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/psr150.lay b/src/mame/layout/psr150.lay new file mode 100644 index 00000000000..bf5be3c4f50 --- /dev/null +++ b/src/mame/layout/psr150.lay @@ -0,0 +1,347 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/psr180.lay b/src/mame/layout/psr180.lay new file mode 100644 index 00000000000..78d2ead22d7 --- /dev/null +++ b/src/mame/layout/psr180.lay @@ -0,0 +1,493 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/psr75.lay b/src/mame/layout/psr75.lay new file mode 100644 index 00000000000..997504b30a5 --- /dev/null +++ b/src/mame/layout/psr75.lay @@ -0,0 +1,285 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/psr76.lay b/src/mame/layout/psr76.lay new file mode 100644 index 00000000000..a7dea8610dd --- /dev/null +++ b/src/mame/layout/psr76.lay @@ -0,0 +1,427 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ]]> + + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + ]]> + + + + + + + + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/pss11.lay b/src/mame/layout/pss11.lay new file mode 100644 index 00000000000..6cfec55f972 --- /dev/null +++ b/src/mame/layout/pss11.lay @@ -0,0 +1,260 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/pss12.lay b/src/mame/layout/pss12.lay new file mode 100644 index 00000000000..df727034e3f --- /dev/null +++ b/src/mame/layout/pss12.lay @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/pss21.lay b/src/mame/layout/pss21.lay new file mode 100644 index 00000000000..19403e50573 --- /dev/null +++ b/src/mame/layout/pss21.lay @@ -0,0 +1,256 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/pss31.lay b/src/mame/layout/pss31.lay new file mode 100644 index 00000000000..1ad150be935 --- /dev/null +++ b/src/mame/layout/pss31.lay @@ -0,0 +1,270 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/layout/pss6.lay b/src/mame/layout/pss6.lay new file mode 100644 index 00000000000..f4f2e203e92 --- /dev/null +++ b/src/mame/layout/pss6.lay @@ -0,0 +1,402 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 3fe2898bd2e..1709938f937 100755 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -45332,15 +45332,30 @@ psr40 // 1985 PSR-40 psr60 // 1985 PSR-60 psr70 // 1985 PSR-70 +@source:yamaha/ympsr150.cpp +psr110 // 1993 +psr150 // 1992 +psr180 // 1994 +psr75 // 1992 +psr76 // 1994 +psr78 // 1996 +pss11 // 1992 +pss12 // 1994 +pss21 // 1992 +pss31 // 1992 +pss6 // 1994 + +@source:yamaha/ympsr260.cpp +psr160 // 2000 +psr260 // 2000 +psr79 // 1998 + @source:yamaha/ympsr340.cpp psr340 // 1999 PSR-340 @source:yamaha/ympsr400.cpp psr500 // 1991 PSR-500 -@source:yamaha/ympss12.cpp -pss12 // - @source:yamaha/ymqy70.cpp qy70 // 1997 QY-70 diff --git a/src/mame/yamaha/ympsr150.cpp b/src/mame/yamaha/ympsr150.cpp new file mode 100644 index 00000000000..6c9139a9001 --- /dev/null +++ b/src/mame/yamaha/ympsr150.cpp @@ -0,0 +1,1637 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +/* + + Driver for Yamaha YMW270-F (GEW7) and YMW282-F (GEW7S) keyboards + + A few different "families" are covered by this driver: + + - "Music Mode Selector" dial (1992-1993) + - PSR-150: 61 keys, stereo, 4 drum pads + 4 sound effect pads + - PSR-110: 49 keys, stereo, 4 drum/sound effect pads + - PSR-75: 49 keys, mono, no pads + - PSS-31: 49 mini keys, stereo, 4 drum pads + - PSS-21: 37 mini keys, stereo, 4 drum pads + - PSS-11: 32 mini keys, mono, no pads + + - Circular control panel w/ 7-segment display (1994) + - PSR-180: 61 keys, stereo, 4 drum/sound effect pads + later released as PSR-185 (1995) + - PSR-76: 49 keys, mono, no pads + later released as PSR-73/77 (1995), PSR-74 (1999), PSR-125 (2002) + + - Mini keyboards w/ tone variation button (1994) + - PSS-12: 32 mini keys, mono, 2Mbit ROM + - PSS-6: 32 "ultra mini" keys, mono, 1Mbit ROM, some tone differences + + - LCD with large icons, metronome, volume display (1996) + - PSR-190: 61 keys, stereo (currently not dumped) + - PSR-78: 49 keys, mono + + Other known undumped models: + - DD-9 Digital Percussion (1994, later released as DD-20) + - PSR-130 (1997, 61 keys, two dials for tone & rhythm selection) + +*/ + +#include "emu.h" + +#include "cpu/m6502/gew7.h" +#include "sound/flt_rc.h" +#include "video/hd44780.h" +#include "video/pwm.h" +#include "screen.h" +#include "speaker.h" + +#include "psr110.lh" +#include "psr150.lh" +#include "psr180.lh" +#include "psr75.lh" +#include "psr76.lh" +#include "pss11.lh" +#include "pss12.lh" +#include "pss21.lh" +#include "pss31.lh" +#include "pss6.lh" + +namespace { + +class psr150_state : public driver_device +{ +public: + psr150_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_pwm(*this, "pwm") + , m_lcdc(*this, "lcdc") + , m_port(*this, "P%c", 'A') + , m_keys(*this, "KEY%u", 0U) + , m_outputs(*this, "%02x.%d.%d", 0U, 0U, 0U) + , m_switch(*this, "switch_pos") + , m_led(*this, "led%u", 0U) + { } + + void psr150(machine_config& config); + void psr110(machine_config& config); + void pss21(machine_config& config); + void pss31(machine_config& config); + void psr75(machine_config& config); + void pss11(machine_config& config); + void psr180_base(machine_config& config); + void psr180(machine_config& config); + void psr76(machine_config& config); + void pss12(machine_config &config); + void pss6(machine_config& config); + void psr190_base(machine_config& config); + void psr78(machine_config& config); + + template + void port_pullup_w(offs_t offset, u8 data, u8 mem_mask); + + // most of these keyboards have key matrix rows & columns split across multiple ports each, + // so use templates to be able to generate multiple r/w methods as appropriate + template + DECLARE_WRITE_LINE_MEMBER(keys_w); + template + DECLARE_CUSTOM_INPUT_MEMBER(keys_r); + + DECLARE_INPUT_CHANGED_MEMBER(switch_w); + DECLARE_CUSTOM_INPUT_MEMBER(switch_r) { return m_switch; } + + DECLARE_WRITE_LINE_MEMBER(apo_w) { if (state) m_maincpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE); } + DECLARE_INPUT_CHANGED_MEMBER(power_w) { if (!newval) m_maincpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE); } + + template + DECLARE_WRITE_LINE_MEMBER(led_w) { m_led[Num] = (state ? 1 : 0); } + + DECLARE_WRITE_LINE_MEMBER(pwm_row_w); + template + DECLARE_WRITE_LINE_MEMBER(pwm_col_w); + + DECLARE_CUSTOM_INPUT_MEMBER(lcd_r) { return m_lcdc->db_r() >> 4; } + DECLARE_WRITE_LINE_MEMBER(lcd_w) { m_lcdc->db_w(state << 4); } + +private: + virtual void driver_start() override; + + DECLARE_WRITE_LINE_MEMBER(render_w); + + required_device m_maincpu; + optional_device m_pwm; + optional_device m_lcdc; + + optional_ioport_array<6> m_port; + optional_ioport_array<19> m_keys; + output_finder<64, 8, 5> m_outputs; + output_finder<> m_switch; + output_finder<4> m_led; + + ioport_value m_key_sel{}; + ioport_value m_pwm_col{}; +}; + +template +void psr150_state::port_pullup_w(offs_t offset, u8 data, u8 mem_mask) +{ + // these keyboards scan the buttons by setting one matrix row to output, the rest to input, + // and relying on external pullup resistors to keep the 'input' rows deselected + m_port[Num]->write((data & mem_mask) | (PullUps & ~mem_mask)); +} + +template +WRITE_LINE_MEMBER(psr150_state::keys_w) +{ + constexpr auto mask = make_bitmask(Count); + + m_key_sel &= ~(mask << StartBit); + m_key_sel |= (state & mask) << StartBit; +} + +template +CUSTOM_INPUT_MEMBER(psr150_state::keys_r) +{ + ioport_value result = 0; + for (unsigned i = 0U; i < m_keys.size(); i++) + if (BIT(m_key_sel, i)) + result |= m_keys[i].read_safe(0); + + return result >> StartBit; +} + +INPUT_CHANGED_MEMBER(psr150_state::switch_w) +{ + if (!oldval && newval) + m_switch = param; +} + +WRITE_LINE_MEMBER(psr150_state::pwm_row_w) +{ + m_pwm->matrix(state, m_pwm_col); +} + +template +WRITE_LINE_MEMBER(psr150_state::pwm_col_w) +{ + keys_w<11 + Bit, 1>(state); + m_pwm_col = m_key_sel >> 11; + + if (m_pwm->read_my() != 0) + m_pwm->write_mx(m_pwm_col); +} + +WRITE_LINE_MEMBER(psr150_state::render_w) +{ + if (!state) + return; + + const u8* render = m_lcdc->render(); + for (int x = 0; x != 64; x++) { + for (int y = 0; y != 8; y++) { + u8 v = *render++; + for (int z = 0; z != 5; z++) + m_outputs[x][y][z] = (v >> z) & 1; + } + render += 8; + } +} + + +void psr150_state::driver_start() +{ + m_outputs.resolve(); + m_led.resolve(); + m_switch.resolve(); + + m_switch = 0x2; // "Voice Play" mode + + save_item(NAME(m_key_sel)); + save_item(NAME(m_pwm_col)); +} + + +void psr150_state::psr150(machine_config& config) +{ + GEW7(config, m_maincpu, 8_MHz_XTAL); + m_maincpu->port_in_cb<0>().set_ioport("PA"); + m_maincpu->port_out_cb<0>().set_ioport("PA"); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC"); + m_maincpu->port_in_cb<5>().set_ioport("PF"); + m_maincpu->port_out_cb<5>().set(FUNC(psr150_state::port_pullup_w<5>)); + m_maincpu->add_route(0, "lfilter", 1.0); + m_maincpu->add_route(1, "rfilter", 1.0); + + // set up AC filters since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=3.3mH, C=0.33uF (or R=150 for psr110) + FILTER_RC(config, "lfilter").set_ac().add_route(ALL_OUTPUTS, "lspeaker", 1.0); + FILTER_RC(config, "rfilter").set_ac().add_route(ALL_OUTPUTS, "rspeaker", 1.0); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + config.set_default_layout(layout_psr150); +} + +void psr150_state::psr110(machine_config& config) +{ + psr150(config); + config.set_default_layout(layout_psr110); +} + +void psr150_state::pss21(machine_config& config) +{ + psr150(config); + // bits 6-7 indicate model (see also pss11, pss31, psr75) + m_maincpu->port_force_bits(5, 0x40, 0xc0); + + config.set_default_layout(layout_pss21); +} + +void psr150_state::pss31(machine_config& config) +{ + psr150(config); + // bits 6-7 indicate model (see also pss11, pss21, psr75) + m_maincpu->port_force_bits(5, 0x80, 0xc0); + + config.set_default_layout(layout_pss31); +} + +void psr150_state::psr75(machine_config& config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_in_cb<0>().set_ioport("PA"); + m_maincpu->port_out_cb<0>().set_ioport("PA"); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC"); + m_maincpu->port_in_cb<5>().set_ioport("PF"); + m_maincpu->port_out_cb<5>().set(FUNC(psr150_state::port_pullup_w<5>)); + // bits 6-7 indicate model (see also pss11, pss21, pss31) + m_maincpu->port_force_bits(5, 0xc0, 0xc0); + m_maincpu->add_route(0, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + // TODO: there is probably also a RLC lowpass, check schematic if available (also for pss21 and pss31) + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); + + config.set_default_layout(layout_psr75); +} + +void psr150_state::pss11(machine_config& config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_out_cb<0>().set_ioport("PA"); + m_maincpu->port_in_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC"); + m_maincpu->port_out_cb<2>().set(FUNC(psr150_state::port_pullup_w<2>)); + m_maincpu->port_in_cb<5>().set_ioport("PF"); + // bits 6-7 indicate model (see also pss21, pss31, psr75) + m_maincpu->port_force_bits(5, 0x00, 0xc0); + m_maincpu->add_route(0, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=3.3mH, C=0.1uF + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); + + config.set_default_layout(layout_pss11); +} + +void psr150_state::psr180_base(machine_config& config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_out_cb<0>().set_ioport("PA"); + m_maincpu->port_in_cb<1>().set_ioport("PB"); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC"); + m_maincpu->port_out_cb<2>().set_ioport("PC"); + m_maincpu->port_in_cb<5>().set_ioport("PF"); + m_maincpu->port_out_cb<5>().set_ioport("PF"); + + PWM_DISPLAY(config, m_pwm); + m_pwm->set_size(3, 8); + m_pwm->set_segmask(0x6, 0xff); +} + +void psr150_state::psr180(machine_config& config) +{ + psr180_base(config); + m_maincpu->add_route(0, "lfilter", 1.0); + m_maincpu->add_route(1, "rfilter", 1.0); + + // set up AC filters since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=3.3mH, C=0.39uF + FILTER_RC(config, "lfilter").set_ac().add_route(ALL_OUTPUTS, "lspeaker", 1.0); + FILTER_RC(config, "rfilter").set_ac().add_route(ALL_OUTPUTS, "rspeaker", 1.0); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + config.set_default_layout(layout_psr180); +} + +void psr150_state::psr76(machine_config& config) +{ + psr180_base(config); + m_maincpu->add_route(0, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=1mH, C=0.33uF + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); + + config.set_default_layout(layout_psr76); +} + +void psr150_state::pss12(machine_config &config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_in_cb<0>().set_ioport("PA"); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC"); + m_maincpu->port_out_cb<2>().set(FUNC(psr150_state::port_pullup_w<2>)); + m_maincpu->port_out_cb<5>().set_ioport("PF"); + m_maincpu->add_route(1, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=3.3mH, C=0.33uF + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); + + config.set_default_layout(layout_pss12); +} + +void psr150_state::pss6(machine_config& config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_out_cb<2>().set(FUNC(psr150_state::port_pullup_w<2>)); + m_maincpu->port_in_cb<5>().set_ioport("PF"); + m_maincpu->add_route(0, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); + + config.set_default_layout(layout_pss6); +} + +void psr150_state::psr190_base(machine_config& config) +{ + GEW7(config, m_maincpu, 8'000'000); + m_maincpu->port_out_cb<0>().set_ioport("PA"); + m_maincpu->port_in_cb<1>().set_ioport("PB"); + m_maincpu->port_out_cb<1>().set_ioport("PB"); + m_maincpu->port_in_cb<2>().set_ioport("PC_R"); + m_maincpu->port_out_cb<2>().set_ioport("PC_W"); + // pull up the button select bits, but not the LCD enable bit + m_maincpu->port_out_cb<5>().set(&psr150_state::port_pullup_w<5, 0x1f>, "port_pullup_w"); + + HD44780(config, m_lcdc); + m_lcdc->set_lcd_size(2, 8); + + screen_device& screen(SCREEN(config, "screen", SCREEN_TYPE_SVG)); + screen.set_refresh_hz(60); + screen.set_size(1000, 775); + screen.set_visarea_full(); + screen.screen_vblank().set(FUNC(psr150_state::render_w)); +} + +void psr150_state::psr78(machine_config& config) +{ + psr190_base(config); + m_maincpu->add_route(0, "filter", 1.0); + + // set up AC filter since the keyboard purposely outputs a DC offset when idle + // TODO: there is also a RLC lowpass with R=120, L=1mH, C=0.33uF + FILTER_RC(config, "filter").set_ac().add_route(ALL_OUTPUTS, "speaker", 1.0); + + SPEAKER(config, "speaker").front_center(); +} + +// helper to use keys_w with PORT_WRITE_LINE_MEMBER +#define KEY_OUT_BITS(start, count) keys_w + +INPUT_PORTS_START(psr150) + PORT_START("PA") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_OUTPUT) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(8, 2)) + + PORT_START("PB") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 8)) + + PORT_START("PC") + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<6>) + PORT_BIT( 0x1c, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, switch_r) + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PF") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(11, 4)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(10, 1)) + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Song)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Voice)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Style)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x4) + + PORT_START("KEY0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E5") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("SE Pad 1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("SE Pad -") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Demo") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("SE Pad 2") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + + PORT_START("KEY12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("SE Pad 3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("SE Pad +") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Start / Stop") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("SE Pad 4") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + + PORT_START("KEY13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Drum Pad 1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Drum Pad -") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Drum Pad 2") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + + PORT_START("KEY14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Drum Pad 3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Drum Pad +") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Volume Up") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Volume Down") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Drum Pad 4") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") +INPUT_PORTS_END + +INPUT_PORTS_START(psr110) + PORT_START("PA") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_OUTPUT) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(7, 2)) + + PORT_START("PB") + PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 7)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("PC") + PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<6>) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, switch_r) + + PORT_START("PF") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(9, 6)) + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Style)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Voice)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Song)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x4) + + PORT_START("KEY0") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY9") + PORT_BIT( 0x07f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Volume Down") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + + PORT_START("KEY10") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + + PORT_START("KEY11") + PORT_BIT( 0x07f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + + PORT_START("KEY12") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Demo") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Start / Stop") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Volume Up") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + + PORT_START("KEY13") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Drum/SE Pad +") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Drum/SE Pad -") + PORT_BIT( 0x700, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY14") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Drum/SE Pad 3") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Drum/SE Pad 2") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Drum/SE Pad 1") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Drum/SE Pad 4") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr75) + PORT_START("PA") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(8, 1)) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("PB") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 8)) + + PORT_START("PC") + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<6>) + PORT_BIT( 0x1c, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, switch_r) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("PF") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(9, 4)) + PORT_BIT( 0xf0, IP_ACTIVE_LOW, IPT_UNUSED ) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Song)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Voice)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Style)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x4) + + PORT_START("KEY0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0xfe, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY9") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Demo") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + + PORT_START("KEY10") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Start/Stop") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + + PORT_START("KEY11") + PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + + PORT_START("KEY12") + PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Volume Up") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Volume Down") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") +INPUT_PORTS_END + +INPUT_PORTS_START(pss31) + PORT_INCLUDE(psr110) + + PORT_MODIFY("KEY13") + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Drum Pad +") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Drum Pad -") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Drum Pad 4") + + PORT_MODIFY("KEY14") + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Drum Pad 3") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Drum Pad 2") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Drum Pad 1") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(pss21) + PORT_INCLUDE(pss31) + + PORT_MODIFY("PA") // in & out bits are swapped + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(7, 2)) + PORT_BIT( 0xfc, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + + PORT_MODIFY("KEY7") + PORT_BIT( 0x7ff, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_MODIFY("KEY8") + PORT_BIT( 0x7ff, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(pss11) + PORT_START("PA") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 6)) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PB") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PC") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(6, 4)) + PORT_BIT( 0x70, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, switch_r) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<6>) + + PORT_START("PF") + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<7>) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) // bits 6-7 indicate model + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Style)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x1) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Voice)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x2) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Mode (Song)") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, switch_w, 0x4) + + PORT_START("KEY0") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x7c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x7fc, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Volume Up") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_SPACE) PORT_NAME("Start / Stop") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Demo") + + PORT_START("KEY7") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + + PORT_START("KEY9") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Volume Down") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0x200, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + PORT_BIT( 0x400, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START( pss12 ) + PORT_START("PA") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PB") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 6)) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PC") + PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(6, 5)) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<6>) + + PORT_START("PF") // LEDs use two bits each and are numbered highest to lowest + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<3>) + PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<2>) + PORT_BIT( 0x30, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<1>) + PORT_BIT( 0xc0, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<0>) + + PORT_START("KEY0") + PORT_BIT( 0x00f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x1c0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Voice/Song 1") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("One Touch Setting") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + + PORT_START("KEY7") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Voice/Song 2") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Minus One") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Volume Up") + + PORT_START("KEY8") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Voice/Song 3") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Mode Select") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + + PORT_START("KEY9") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Voice/Song 4") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Start / Stop") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Volume Down") + + PORT_START("KEY10") + PORT_BIT( 0x03f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("Voice/Song 5") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Voice/Song 6 / Variation") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START( pss6 ) + PORT_START("PB") // LEDs use two bits each + PORT_BIT( 0x03, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<0>) + PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, led_w<1>) + PORT_BIT( 0xf0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PC") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 8)) + + PORT_START("PF") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Voice/Song 6 / Variation") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Voice/Song 2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Start / Stop") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Tempo") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("Voice/Song 5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Voice/Song 3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Mode Select") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Voice/Song 4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Voice/Song 1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Minus One") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Volume") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr180_keys) // also psr190 + PORT_START("PA") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 8)) + + PORT_START("PB") + PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PF") + PORT_BIT( 0x1f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0xe0, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(8, 3)) + + PORT_START("KEY0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E5") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr76_keys) // also psr78 + PORT_START("PA") + PORT_BIT( 0xff, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(0, 8)) + + PORT_START("PB") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(8, 1)) + PORT_BIT( 0x7e, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, keys_r<0>) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G4#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A4#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G2#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A2#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D2#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E2") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY4") + PORT_BIT( 0x1f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY5") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C1#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D1#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D4#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E4") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr180) + PORT_INCLUDE(psr180_keys) + + PORT_START("PC") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, apo_w) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POWER_ON ) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, power_w, 0) + PORT_BIT( 0x1c, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_row_w) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<7>) // H + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<3>) // D + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<4>) // E + + PORT_MODIFY("PF") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<1>) // B + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<0>) // A + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<5>) // F + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<6>) // G + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<2>) // C + + PORT_START("KEY11") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Drum") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("Drum/SE Pad 3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY12") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Sound Effect") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Drum/SE Pad 4") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Voice") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("One Touch Setting") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Start / Stop") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Minus One") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Song") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY16") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Sync Start / Fill In") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Drum/SE Pad 2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY17") + PORT_BIT( 0x1f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Drum/SE Pad 1") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY18") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Style") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr76) + PORT_INCLUDE(psr76_keys) + + PORT_START("PC") + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, apo_w) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_POWER_ON ) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, psr150_state, power_w, 0) + PORT_BIT( 0x1c, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_row_w) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<6>) // G + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<5>) // F + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<0>) // A + + PORT_START("PF") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<1>) // B + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<4>) // E + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<3>) // D + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<7>) // H + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, pwm_col_w<2>) // C + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY12") + PORT_BIT( 0x1f, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Sync Start / Fill In") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Voice") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY14") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY15") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Song / Demo") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Minus One") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Start / Stop") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("One Touch Setting") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY18") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Style") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +INPUT_PORTS_START(psr78) + PORT_INCLUDE(psr76_keys) + + PORT_START("PC_R") + PORT_BIT( 0x07, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x78, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(psr150_state, lcd_r) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PC_W") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, rs_w) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, rw_w) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x78, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, lcd_w) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("PF") + PORT_BIT( 0x1f, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(psr150_state, KEY_OUT_BITS(9, 5)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", hd44780_device, e_w) + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_PLUS_PAD) PORT_NAME("Keypad +") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6_PAD) PORT_NAME("Keypad 6") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1) PORT_NAME("Demo") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2) PORT_NAME("Sync Start") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_6) PORT_NAME("Main / Auto Fill B") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_RIGHT) PORT_NAME("Tempo Up") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY10") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0_PAD) PORT_NAME("Keypad 0") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS_PAD) PORT_NAME("Keypad -") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_EQUALS) PORT_NAME("Voice") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3) PORT_NAME("Start / Stop") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7) PORT_NAME("Ending") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_0) PORT_NAME("One Touch Setting") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY11") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9_PAD) PORT_NAME("Keypad 9") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5_PAD) PORT_NAME("Keypad 5") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_DOWN) PORT_NAME("Acc. Volume Down") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4) PORT_NAME("Intro") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8) PORT_NAME("Jam Track") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_MINUS) PORT_NAME("Style") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY12") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_8_PAD) PORT_NAME("Keypad 8") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_4_PAD) PORT_NAME("Keypad 4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_1_PAD) PORT_NAME("Keypad 1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_UP) PORT_NAME("Acc. Volume Up") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_9) PORT_NAME("Large/Small / Minus One") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_BACKSPACE) PORT_NAME("Song") + PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KEY13") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_7_PAD) PORT_NAME("Keypad 7") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_3_PAD) PORT_NAME("Keypad 3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_2_PAD) PORT_NAME("Keypad 2") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_5) PORT_NAME("Main / Auto Fill A") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_CODE(KEYCODE_LEFT) PORT_NAME("Tempo Down") + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) +INPUT_PORTS_END + +#undef KEY_OUT_BITS + + +ROM_START( psr150 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD( "xl561a00.ic4", 0x00000, 0x80000, CRC(ccb11ccf) SHA1(d4c00e4ee07e4bbe919e3cbeaf397ae1601533e3)) +ROM_END + +ROM_START( psr110 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD( "xm041a00.ic2", 0x00000, 0x80000, CRC(b2db9672) SHA1(dee46ca980f88a4f06fd88437e39c9a6b8cec7bf)) +ROM_END + +ROM_START( psr75 ) + ROM_REGION( 0x40000, "maincpu", 0 ) + ROM_LOAD( "xl437a00.ic4", 0x00000, 0x40000, CRC(75fba08f) SHA1(ad79cdc7026ed621004e8f600d61ee62c598fa1a)) +ROM_END + +#define rom_pss11 rom_psr75 +#define rom_pss21 rom_psr75 +#define rom_pss31 rom_psr75 + +ROM_START( psr180 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD( "xp687a00.ic6", 0x00000, 0x80000, CRC(df3a568d) SHA1(ddc260d55d874987950817817117df141668f1f2)) +ROM_END + +ROM_START( psr76 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD( "xp686a00.ic6", 0x00000, 0x80000, CRC(0d5299fc) SHA1(744e63edc1089cb2ece2105fd53993a66c6dc2ab)) +ROM_END + +ROM_START( pss12 ) + ROM_REGION( 0x40000, "maincpu", 0 ) + ROM_LOAD( "xp598a00.ic2", 0x00000, 0x40000, CRC(7e05f1cb) SHA1(1a05996002bb7bfdde215349d235269795c88693)) +ROM_END + +ROM_START( pss6 ) + ROM_REGION( 0x20000, "maincpu", 0 ) + ROM_LOAD( "xp733a00.ic2", 0x00000, 0x20000, CRC(5a7ad160) SHA1(01e7b988db37a2553c71d51f585736df286a245c)) +ROM_END + +ROM_START( psr78 ) + ROM_REGION( 0x80000, "maincpu", 0 ) + ROM_LOAD( "xr813100.ic6", 0x00000, 0x80000, CRC(cf1b959c) SHA1(6459a322789285ab203bbbd29ddfe0d877514b41)) + + ROM_REGION( 175935, "screen", 0 ) + ROM_LOAD( "psr190.svg", 0, 175935, CRC(1382c3df) SHA1(504ca22300f220785d1d7476e39cf2077684bb70)) +ROM_END + +} // anonymous namespace + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +SYST( 1992, psr150, 0, 0, psr150, psr150, psr150_state, empty_init, "Yamaha", "PSR-150", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1993, psr110, psr150, 0, psr110, psr110, psr150_state, empty_init, "Yamaha", "PSR-110", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1992, psr75, psr150, 0, psr75, psr75, psr150_state, empty_init, "Yamaha", "PSR-75", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1992, pss11, psr150, 0, pss11, pss11, psr150_state, empty_init, "Yamaha", "PSS-11", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1992, pss21, psr150, 0, pss21, pss21, psr150_state, empty_init, "Yamaha", "PSS-21", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1992, pss31, psr150, 0, pss31, pss31, psr150_state, empty_init, "Yamaha", "PSS-31", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1994, psr180, 0, 0, psr180, psr180, psr150_state, empty_init, "Yamaha", "PSR-180", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1994, psr76, psr180, 0, psr76, psr76, psr150_state, empty_init, "Yamaha", "PSR-76", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1994, pss12, 0, 0, pss12, pss12, psr150_state, empty_init, "Yamaha", "PSS-12", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1994, pss6, pss12, 0, pss6, pss6, psr150_state, empty_init, "Yamaha", "PSS-6", MACHINE_SUPPORTS_SAVE | MACHINE_CLICKABLE_ARTWORK ) +SYST( 1996, psr78, 0, 0, psr78, psr78, psr150_state, empty_init, "Yamaha", "PSR-78", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/yamaha/ympsr260.cpp b/src/mame/yamaha/ympsr260.cpp new file mode 100644 index 00000000000..ba95682f69c --- /dev/null +++ b/src/mame/yamaha/ympsr260.cpp @@ -0,0 +1,128 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +/* + + Skeleton driver for Yamaha YMW728-F (GEW12) keyboards + +*/ + +#include "emu.h" + +#include "cpu/m6502/gew12.h" +#include "video/hd44780.h" +#include "emupal.h" +#include "screen.h" +#include "speaker.h" + +namespace { + +class psr260_state : public driver_device +{ +public: + psr260_state(const machine_config &mconfig, device_type type, const char *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_lcdc(*this, "lcdc") + , m_keys(*this, "KEY%u", 0U) + , m_buttons(*this, "BTN%u", 0U) + { } + + void psr260(machine_config& config); + + void lcd_w(u8 data); + +private: + virtual void driver_start() override; + + HD44780_PIXEL_UPDATE(lcd_update); + void palette_init(palette_device& palette); + + required_device m_maincpu; + optional_device m_lcdc; + + optional_ioport_array<11> m_keys; + optional_ioport_array<6> m_buttons; + + ioport_value m_key_sel{}; + ioport_value m_btn_sel{}; +}; + +void psr260_state::driver_start() +{ + save_item(NAME(m_key_sel)); + save_item(NAME(m_btn_sel)); +} + +void psr260_state::lcd_w(u8 data) +{ + m_lcdc->db_w(BIT(data, 1, 4) << 4); + m_lcdc->rs_w(BIT(data, 6)); + m_lcdc->e_w(BIT(data, 5)); +} + +HD44780_PIXEL_UPDATE(psr260_state::lcd_update) +{ + if (x < 6 && y < 8 && line < 2 && pos < 8) + bitmap.pix(line * 8 + y, pos * 6 + x) = state; +} + +void psr260_state::palette_init(palette_device& palette) +{ + palette.set_pen_color(0, rgb_t(255, 255, 255)); + palette.set_pen_color(1, rgb_t(0, 0, 0)); +} + + +void psr260_state::psr260(machine_config &config) +{ + GEW12(config, m_maincpu, 14'000'000); + m_maincpu->port_out_cb<5>().set(FUNC(psr260_state::lcd_w)); + + // TODO: MIDI in/out + + // LCD + HD44780(config, m_lcdc, 0); + m_lcdc->set_lcd_size(2, 8); + m_lcdc->set_pixel_update_cb(FUNC(psr260_state::lcd_update)); + // code never checks the busy flag, it just delays for a fixed amount and assumes it's ready + m_lcdc->set_busy_factor(0.5f); + + // screen (for testing only) + // TODO: the actual LCD with custom segments + screen_device& screen(SCREEN(config, "screen", SCREEN_TYPE_LCD)); + screen.set_refresh_hz(60); + screen.set_vblank_time(ATTOSECONDS_IN_USEC(2500)); /* not accurate */ + screen.set_screen_update("lcdc", FUNC(hd44780_device::screen_update)); + screen.set_size(6 * 8, 8 * 2); + screen.set_visarea_full(); + screen.set_palette("palette"); + + PALETTE(config, "palette", FUNC(psr260_state::palette_init), 2); +} + + +INPUT_PORTS_START(psr260) +INPUT_PORTS_END + +ROM_START( psr79 ) + ROM_REGION( 0x100000, "maincpu", 0 ) + ROM_LOAD( "xu66710.bin", 0x00000, 0x100000, CRC(d48f57f1) SHA1(587bfe518e83490e1885c88871c39ff042af9429)) +ROM_END + +ROM_START( psr260 ) + ROM_REGION( 0x200000, "maincpu", 0 ) + ROM_LOAD( "xy43530.bin", 0x00000, 0x200000, CRC(51edbc10) SHA1(fcd2c5b247895c1bd4a185572a60115872763f63)) +ROM_END + +ROM_START( psr160 ) + ROM_REGION( 0x200000, "maincpu", 0 ) + ROM_LOAD( "xy43430.bin", 0x00000, 0x200000, CRC(e234e79b) SHA1(4af36344c2dcc858db110d0ddc5535dbc47a25eb)) +ROM_END + +} // anonymous namespace + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +SYST( 1998, psr79, 0, 0, psr260, psr260, psr260_state, empty_init, "Yamaha", "PSR-79", MACHINE_SUPPORTS_SAVE | MACHINE_IS_SKELETON ) +SYST( 2000, psr260, 0, 0, psr260, psr260, psr260_state, empty_init, "Yamaha", "PSR-260", MACHINE_SUPPORTS_SAVE | MACHINE_IS_SKELETON ) +SYST( 2000, psr160, psr260, 0, psr260, psr260, psr260_state, empty_init, "Yamaha", "PSR-160", MACHINE_SUPPORTS_SAVE | MACHINE_IS_SKELETON ) diff --git a/src/mame/yamaha/ympss12.cpp b/src/mame/yamaha/ympss12.cpp deleted file mode 100644 index 5dc8cde7674..00000000000 --- a/src/mame/yamaha/ympss12.cpp +++ /dev/null @@ -1,58 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Devin Acker - -/* - - Skeleton driver for Yamaha YMW270-F (GEW7) and YMW282-F (GEW7S) keyboards - -*/ - -#include "emu.h" - -#include "cpu/m6502/m65c02.h" -#include "speaker.h" - -namespace { - -class pss12_state : public driver_device -{ -public: - pss12_state(const machine_config &mconfig, device_type type, const char *tag) - : driver_device(mconfig, type, tag) - , m_maincpu(*this, "maincpu") - { } - - void pss12(machine_config &config); - -private: - void pss12_map(address_map &map); - - required_device m_maincpu; -}; - -void pss12_state::pss12_map(address_map &map) -{ - map(0x0000, 0x03ff).ram(); - map(0x4000, 0xbfff).rom().region("maincpu", 0x8000); // probably bankswitched (regs at $0408-0409?) - map(0xc000, 0xffff).rom().region("maincpu", 0x0000); -} - -INPUT_PORTS_START( pss12 ) -INPUT_PORTS_END - -void pss12_state::pss12(machine_config &config) -{ - M65C02(config, m_maincpu, 2'000'000); // TODO: YMW282-F, clock unknown - m_maincpu->set_addrmap(AS_PROGRAM, &pss12_state::pss12_map); - - SPEAKER(config, "speaker", 0).front_center(); -} - -ROM_START( pss12 ) - ROM_REGION( 0x40000, "maincpu", 0 ) - ROM_LOAD( "yamaha_pss12.bin", 0x00000, 0x40000, CRC(7e05f1cb) SHA1(1a05996002bb7bfdde215349d235269795c88693)) -ROM_END - -} // anonymous namespace - -SYST( 1994, pss12, 0, 0, pss12, pss12, pss12_state, empty_init, "Yamaha", "PSS-12", MACHINE_IS_SKELETON ) -- cgit v1.2.3