From 3b7969802f84e98d53456403931d94338962b007 Mon Sep 17 00:00:00 2001 From: Olivier Galibert Date: Mon, 18 Mar 2024 22:46:37 +0100 Subject: [PATCH] mks3: first hle --- src/devices/cpu/h8/swx00.cpp | 17 ++- src/devices/cpu/h8/swx00.h | 4 + src/mame/yamaha/mks3.cpp | 237 +++++++++++++++++++++++++++++++++++ src/mame/yamaha/mks3.h | 53 ++++++++ src/mame/yamaha/ympsr340.cpp | 20 ++- 5 files changed, 327 insertions(+), 4 deletions(-) create mode 100644 src/mame/yamaha/mks3.cpp create mode 100644 src/mame/yamaha/mks3.h diff --git a/src/devices/cpu/h8/swx00.cpp b/src/devices/cpu/h8/swx00.cpp index ef34d4196e4..b00cd3e72ca 100644 --- a/src/devices/cpu/h8/swx00.cpp +++ b/src/devices/cpu/h8/swx00.cpp @@ -41,6 +41,7 @@ swx00_device::swx00_device(const machine_config &mconfig, const char *tag, devic m_read_pad(*this, 0xff), m_write_pad(*this), m_write_cmah(*this), + m_write_txd(*this), m_s_config("s", ENDIANNESS_BIG, 16, 24, -1), m_mode(mode), m_syscr(0) @@ -53,6 +54,7 @@ swx00_device::swx00_device(const machine_config &mconfig, const char *tag, devic m_read_pad.bind().set(*this, FUNC(swx00_device::pad_default_r)); m_write_pad.bind().set(*this, FUNC(swx00_device::pad_default_w)); m_write_cmah.bind().set(*this, FUNC(swx00_device::cmah_default_w)); + m_write_txd.bind().set(*this, FUNC(swx00_device::txd_default_w)); } u16 swx00_device::s_r(offs_t offset) @@ -71,7 +73,7 @@ void swx00_device::map(address_map &map) map(0xffe028, 0xffe029).w(FUNC(swx00_device::pdt_ddr_w)); map(0xffe02a, 0xffe02b).rw(FUNC(swx00_device::pdt_r), FUNC(swx00_device::pdt_w)); map(0xffe02d, 0xffe02d).w(FUNC(swx00_device::cmah_w)); - + map(0xffe02e, 0xffe02e).w(FUNC(swx00_device::txd_w)); map(0xffe02f, 0xffe02f).lr8(NAME([]() -> uint8_t { return 0xff; })); map(0xfff000, 0xfffbff).ram(); @@ -305,10 +307,11 @@ void swx00_device::device_add_mconfig(machine_config &config) h8_timer16_channel_device::INPUT_C, h8_timer16_channel_device::DIV_256, h8_timer16_channel_device::INPUT_D); - H8_SCI(config, m_sci[2], 2, *this, m_intc, 88, 89, 90, 91); + H8_WATCHDOG(config, m_watchdog, *this, m_intc, 25, h8_watchdog_device::S); H8_SCI(config, m_sci[0], 0, *this, m_intc, 80, 81, 82, 83); H8_SCI(config, m_sci[1], 1, *this, m_intc, 84, 85, 86, 87); + H8_SCI(config, m_sci[2], 2, *this, m_intc, 88, 89, 90, 91); SWX00_SOUND(config, m_swx00); m_swx00->set_space(DEVICE_SELF, AS_S); @@ -516,6 +519,11 @@ void swx00_device::cmah_default_w(u8 data) logerror("write of un-hooked port cmah %02x\n", data); } +void swx00_device::txd_default_w(u8 data) +{ + logerror("write of un-hooked port txd %02x\n", data); +} + void swx00_device::pdt_ddr_w(offs_t, u16 data, u16 mem_mask) { COMBINE_DATA(&m_pdt_ddr); @@ -547,3 +555,8 @@ void swx00_device::cmah_w(u8 data) m_write_cmah(data); } +void swx00_device::txd_w(u8 data) +{ + m_write_txd(data); +} + diff --git a/src/devices/cpu/h8/swx00.h b/src/devices/cpu/h8/swx00.h index d60b4c26945..b1f3d03e5e6 100644 --- a/src/devices/cpu/h8/swx00.h +++ b/src/devices/cpu/h8/swx00.h @@ -58,6 +58,7 @@ public: auto read_pad() { return m_read_pad.bind(); } auto write_pad() { return m_write_pad.bind(); } auto write_cmah() { return m_write_cmah.bind(); } + auto write_txd() { return m_write_txd.bind(); } u8 syscr_r(); void syscr_w(u8 data); @@ -99,6 +100,7 @@ protected: devcb_read8 m_read_pad; devcb_write8 m_write_pad; devcb_write8 m_write_cmah; + devcb_write8 m_write_txd; address_space_config m_s_config; @@ -129,12 +131,14 @@ protected: u8 pad_r(); void pad_w(u8 data); void cmah_w(u8 data); + void txd_w(u8 data); u16 pdt_default_r(); void pdt_default_w(u16 data); u8 pad_default_r(); void pad_default_w(u8 data); void cmah_default_w(u8 data); + void txd_default_w(u8 data); void map(address_map &map); diff --git a/src/mame/yamaha/mks3.cpp b/src/mame/yamaha/mks3.cpp new file mode 100644 index 00000000000..223416461b9 --- /dev/null +++ b/src/mame/yamaha/mks3.cpp @@ -0,0 +1,237 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// HLE emulation of the MKS3 keyboard scanning PCB used in the psr340 +// and psr540 among others. + +// Uses a 63B05 with a not-yet-dumped internal rom + +// Messages 0x81 and 0x82 are special, but not understood. + +// What should happen so that the test mode works is not understood either. + +#include "emu.h" +#include "mks3.h" + +DEFINE_DEVICE_TYPE(MKS3, mks3_device, "mks3", "Yamaha MKS3 piano keyboard scanner") + +static INPUT_PORTS_START(piano) + PORT_START("P0") + PORT_BIT(0xffffffff, IP_ACTIVE_HIGH, IPT_UNUSED) + + PORT_START("P1") + PORT_BIT(0x0000000f, IP_ACTIVE_HIGH, IPT_UNUSED) + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C2") + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C2#") + PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D2") + PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D2#") + PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("E2") + PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F2") + PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F2#") + PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G2") + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G2#") + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A2") + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A2#") + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("B2") + PORT_BIT(0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C3") + PORT_BIT(0x00020000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C3#") + PORT_BIT(0x00040000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D3") + PORT_BIT(0x00080000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D3#") + PORT_BIT(0x00100000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("E3") + PORT_BIT(0x00200000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F3") + PORT_BIT(0x00400000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F3#") + PORT_BIT(0x00800000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G3") + PORT_BIT(0x01000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G3#") + PORT_BIT(0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A3") + PORT_BIT(0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A3#") + PORT_BIT(0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("B3") + PORT_BIT(0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C4") + PORT_BIT(0x20000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C4#") + PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D4") + PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D4#") + + PORT_START("P2") + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("E4") + PORT_BIT(0x00000002, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F4") + PORT_BIT(0x00000004, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F4#") + PORT_BIT(0x00000008, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G4") + PORT_BIT(0x00000010, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G4#") + PORT_BIT(0x00000020, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A4") + PORT_BIT(0x00000040, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A4#") + PORT_BIT(0x00000080, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("B4") + PORT_BIT(0x00000100, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C5") + PORT_BIT(0x00000200, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C5#") + PORT_BIT(0x00000400, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D5") + PORT_BIT(0x00000800, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D5#") + PORT_BIT(0x00001000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("E5") + PORT_BIT(0x00002000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F5") + PORT_BIT(0x00004000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F5#") + PORT_BIT(0x00008000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G5") + PORT_BIT(0x00010000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G5#") + PORT_BIT(0x00020000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A5") + PORT_BIT(0x00040000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A5#") + PORT_BIT(0x00080000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("B5") + PORT_BIT(0x00100000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C6") + PORT_BIT(0x00200000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C6#") + PORT_BIT(0x00400000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D6") + PORT_BIT(0x00800000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("D6#") + PORT_BIT(0x01000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("E6") + PORT_BIT(0x02000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F6") + PORT_BIT(0x04000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("F6#") + PORT_BIT(0x08000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G6") + PORT_BIT(0x10000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("G6#") + PORT_BIT(0x20000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A6") + PORT_BIT(0x40000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("A6#") + PORT_BIT(0x80000000, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("B6") + + PORT_START("P3") + PORT_BIT(0x00000001, IP_ACTIVE_HIGH, IPT_UNUSED) PORT_NAME("C7") + PORT_BIT(0xfffffffe, IP_ACTIVE_HIGH, IPT_UNUSED) +INPUT_PORTS_END + + +mks3_device::mks3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : + device_t(mconfig, MKS3, tag, owner, clock), + m_port(*this, "P%d", 0), + m_write_da(*this), + m_write_clk(*this) +{ +} + +ioport_constructor mks3_device::device_input_ports() const +{ + return INPUT_PORTS_NAME(piano); +} + +void mks3_device::device_start() +{ + save_item(NAME(m_ic)); + save_item(NAME(m_req)); + save_item(NAME(m_step)); + save_item(NAME(m_byte)); + save_item(NAME(m_bytes)); + save_item(NAME(m_byte_count)); + save_item(NAME(m_sent_state)); + save_item(NAME(m_current_state)); + + m_ic = 1; + m_req = 1; + + m_scan_timer = timer_alloc(FUNC(mks3_device::scan_tick), this); + m_transmit_timer = timer_alloc(FUNC(mks3_device::transmit_tick), this); +} + +void mks3_device::device_reset() +{ + m_write_da(1); + m_write_clk(1); + m_step = 0xff; + m_byte = 0; + m_byte_count = 0; + std::fill(m_bytes.begin(), m_bytes.end(), 0); + std::fill(m_sent_state.begin(), m_sent_state.end(), 0); + + for(int i=0; i != 4; i++) + m_current_state[i] = m_port[i]->read(); + + + m_scan_timer->adjust(attotime::from_hz(100), 0, attotime::from_hz(100)); +} + +void mks3_device::ic_w(int state) +{ + if(state == m_ic) + return; + + m_ic = state; + if(!m_ic) + reset(); +} + +void mks3_device::req_w(int state) +{ + if(state == m_req) + return; + + m_req = state; + if(m_req == 0) + transmit_next(); +} + +TIMER_CALLBACK_MEMBER(mks3_device::transmit_tick) +{ + if(m_step == 15) { + transmit_next(); + return; + } + + if(m_step & 1) { + m_write_clk(0); + m_write_da(BIT(m_byte, 6 - (m_step >> 1))); + } else + m_write_clk(1); + m_step++; + + m_transmit_timer->adjust(attotime::from_hz(500000)); +} + +void mks3_device::transmit_next() +{ + if(m_byte_count == 0) { + m_step = 0xff; + send_next(); + return; + } + + m_byte = m_bytes[0]; + m_byte_count --; + if(m_byte_count) + memmove(m_bytes.data(), m_bytes.data() + 1, m_byte_count); + + logerror("start %02x\n", m_byte); + m_write_clk(0); + m_write_da(BIT(m_byte, 7)); + m_step = 0; + m_transmit_timer->adjust(attotime::from_hz(500000)); +} + +u32 mks3_device::find_next() +{ + for(int i=0; i != 4; i++) + if(m_current_state[i] != m_sent_state[i]) + for(int j=0; j != 32; j++) + if(BIT(m_current_state[i]^m_sent_state[i], j)) { + m_sent_state[i] ^= 1 << j; + return (i << 5) | j | (BIT(m_current_state[i], j) ? 0x100 : 0); + } + return 0xffffffff; +} + +void mks3_device::send_next() +{ + u32 key = find_next(); + if(key == 0xffffffff) + return; + + // velocity is 10 bits, 0 = max, 3ff = min + // + // 80 | key number + // 20 for keyoff, velocity >> 5 otherwise + // 60 | (velocity & 1f) + + m_bytes[0] = 0x80 | (key & 0x7f); + m_bytes[1] = key & 0x100 ? 0 : 0x20; + m_bytes[2] = 0x60; + m_byte_count = 3; + transmit_next(); +} + + +TIMER_CALLBACK_MEMBER(mks3_device::scan_tick) +{ + for(int i=0; i != 4; i++) + m_current_state[i] = m_port[i]->read(); + + if(m_step == 0xff) + send_next(); +} diff --git a/src/mame/yamaha/mks3.h b/src/mame/yamaha/mks3.h new file mode 100644 index 00000000000..f650c89c241 --- /dev/null +++ b/src/mame/yamaha/mks3.h @@ -0,0 +1,53 @@ +// license:BSD-3-Clause +// copyright-holders:Olivier Galibert + +// HLE emulation of the MKS3 keyboard scanning PCB used in the psr340 +// and psr540 among others. + +// Uses a 63B05 with a not-yet-dumped internal rom + + +#ifndef MAME_YAMAHA_MKS3_H +#define MAME_YAMAHA_MKS3_H + +#pragma once + +DECLARE_DEVICE_TYPE(MKS3, mks3_device) + +class mks3_device : public device_t +{ +public: + mks3_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); + + void ic_w(int state); + void req_w(int state); + auto write_da() { return m_write_da.bind(); } + auto write_clk() { return m_write_clk.bind(); } + +protected: + virtual void device_start() override; + virtual void device_reset() override; + virtual ioport_constructor device_input_ports() const override; + +private: + required_ioport_array<4> m_port; + devcb_write_line m_write_da; + devcb_write_line m_write_clk; + emu_timer *m_scan_timer, *m_transmit_timer; + + std::array m_bytes; + + std::array m_sent_state; + std::array m_current_state; + + int m_ic, m_req; + u8 m_step, m_byte, m_byte_count; + + u32 find_next(); + void send_next(); + void transmit_next(); + TIMER_CALLBACK_MEMBER(transmit_tick); + TIMER_CALLBACK_MEMBER(scan_tick); +}; + +#endif diff --git a/src/mame/yamaha/ympsr340.cpp b/src/mame/yamaha/ympsr340.cpp index cda7f13c463..100c51b277b 100644 --- a/src/mame/yamaha/ympsr340.cpp +++ b/src/mame/yamaha/ympsr340.cpp @@ -22,6 +22,8 @@ #include "video/hd44780.h" #include "bus/midi/midi.h" +#include "mks3.h" + #include "emupal.h" #include "screen.h" #include "speaker.h" @@ -35,6 +37,7 @@ public: psr340_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), m_maincpu(*this, "maincpu"), + m_mks3(*this, "mks3"), m_lcdc(*this, "ks0066"), m_outputs(*this, "%02d.%x.%x", 0U, 0U, 0U), m_key(*this, "S%c", 'A') @@ -48,6 +51,7 @@ protected: private: required_device m_maincpu; + required_device m_mks3; required_device m_lcdc; output_finder<80, 8, 5> m_outputs; required_ioport_array<8> m_key; @@ -57,11 +61,11 @@ private: void pdt_w(u16 data); u8 pad_r(); + void txd_w(u8 data); void render_w(int state); u8 m_matrixsel = 0U; - u8 matrix_r(); }; u8 psr340_state::pad_r() @@ -81,14 +85,20 @@ u8 psr340_state::pad_r() void psr340_state::pdt_w(u16 data) { - // bit 11 = E, bit 12 = RS, R/W is connected to GND so write-only + // bit 14 = mks3 ic, bit 11 = E, bit 12 = RS, R/W is connected to GND so write-only // all bits are also matrix select for reading the controls + m_mks3->ic_w(BIT(data, 14)); m_lcdc->rs_w(BIT(data, 12)); m_lcdc->e_w(BIT(data, 11)); m_lcdc->db_w(data); m_matrixsel = data; } +void psr340_state::txd_w(u8 data) +{ + m_mks3->req_w(BIT(data, 1)); +} + void psr340_state::c_map(address_map &map) { map(0x000000, 0x1fffff).rom().region("maincpu", 0); // cs0 @@ -104,6 +114,7 @@ void psr340_state::s_map(address_map &map) void psr340_state::machine_start() { + save_item(NAME(m_matrixsel)); m_outputs.resolve(); } @@ -269,11 +280,16 @@ void psr340_state::psr340(machine_config &config) m_maincpu->write_pdt().set(FUNC(psr340_state::pdt_w)); m_maincpu->read_pad().set(FUNC(psr340_state::pad_r)); + m_maincpu->write_txd().set(FUNC(psr340_state::txd_w)); // mks3 is connected to sclki, sync comms on sci1 // something generates 500K for sci0, probably internal to the swx00 m_maincpu->sci_set_external_clock_period(0, attotime::from_hz(500000)); + MKS3(config, m_mks3); + m_mks3->write_da().set(m_maincpu, FUNC(swx00_device::sci_rx_w<1>)); + m_mks3->write_clk().set(m_maincpu, FUNC(swx00_device::sci_clk_w<1>)); + KS0066(config, m_lcdc, 270'000); // 91K resistor m_lcdc->set_default_bios_tag("f05"); m_lcdc->set_lcd_size(2, 40);