mks3: first hle

This commit is contained in:
Olivier Galibert 2024-03-18 22:46:37 +01:00
parent d73c21c097
commit 3b7969802f
5 changed files with 327 additions and 4 deletions

View File

@ -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);
}

View File

@ -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);

237
src/mame/yamaha/mks3.cpp Normal file
View File

@ -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();
}

53
src/mame/yamaha/mks3.h Normal file
View File

@ -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<u8, 3> m_bytes;
std::array<u32, 4> m_sent_state;
std::array<u32, 4> 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

View File

@ -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<swx00_device> m_maincpu;
required_device<mks3_device> m_mks3;
required_device<hd44780_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);