From 8874b3d7c50fad53b231dcff29d30fc6bcacdb6f Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Mon, 23 Sep 2024 22:17:15 -0400 Subject: [PATCH 1/3] New working machines ---------- Casio WK-1800 [Edward d-tech, Devin Acker] New working clones ---------- Casio WK-1600 [Edward d-tech, Devin Acker] --- scripts/src/sound.lua | 12 + src/devices/cpu/h8/h83048.cpp | 10 +- src/devices/cpu/h8/h83048.h | 7 +- src/devices/cpu/h8/h8_adc.cpp | 2 +- src/devices/cpu/h8/h8_dma.cpp | 3 +- src/devices/cpu/h8/h8_dtc.cpp | 1 - src/devices/machine/upd765.cpp | 6 + src/devices/machine/upd765.h | 1 + src/devices/sound/gt155.cpp | 404 ++++++++++++++++++++++ src/devices/sound/gt155.h | 104 ++++++ src/mame/casio/wk1800.cpp | 615 +++++++++++++++++++++++++++++++++ src/mame/mame.lst | 4 + 12 files changed, 1163 insertions(+), 6 deletions(-) create mode 100644 src/devices/sound/gt155.cpp create mode 100644 src/devices/sound/gt155.h create mode 100644 src/mame/casio/wk1800.cpp diff --git a/scripts/src/sound.lua b/scripts/src/sound.lua index 06589a4fad97a..407b33fea99c3 100644 --- a/scripts/src/sound.lua +++ b/scripts/src/sound.lua @@ -1765,3 +1765,15 @@ if (SOUNDS["UPD65043GFU01"]~=null) then MAME_DIR .. "src/devices/sound/upd65043gfu01.h", } end + +--------------------------------------------------- +-- Casio GT155 +--@src/devices/sound/gt155.h,SOUNDS["GT155"] = true +--------------------------------------------------- + +if (SOUNDS["GT155"]~=null) then + files { + MAME_DIR .. "src/devices/sound/gt155.cpp", + MAME_DIR .. "src/devices/sound/gt155.h", + } +end diff --git a/src/devices/cpu/h8/h83048.cpp b/src/devices/cpu/h8/h83048.cpp index f04b8f6cea79a..4dec80b7074e0 100644 --- a/src/devices/cpu/h8/h83048.cpp +++ b/src/devices/cpu/h8/h83048.cpp @@ -33,6 +33,7 @@ h83048_device::h83048_device(const machine_config &mconfig, device_type type, co m_timer16_3(*this, "timer16:3"), m_timer16_4(*this, "timer16:4"), m_watchdog(*this, "watchdog"), + m_tend_cb(*this), m_ram_start(start), m_syscr(0) { @@ -206,7 +207,12 @@ void h83048_device::device_add_mconfig(machine_config &config) void h83048_device::execute_set_input(int inputnum, int state) { - m_intc->set_input(inputnum, state); + if(inputnum == H8_INPUT_LINE_TEND0 || inputnum == H8_INPUT_LINE_TEND1) + m_tend_cb[inputnum - H8_INPUT_LINE_TEND0](state); + else if(inputnum == H8_INPUT_LINE_DREQ0 || inputnum == H8_INPUT_LINE_DREQ1) + m_dma->set_input(inputnum, state); + else + m_intc->set_input(inputnum, state); } int h83048_device::trapa_setup() @@ -284,6 +290,7 @@ void h83048_device::notify_standby(int state) void h83048_device::device_start() { h8h_device::device_start(); + m_dma_device = m_dma; save_item(NAME(m_syscr)); } @@ -301,6 +308,7 @@ u8 h83048_device::syscr_r() void h83048_device::syscr_w(u8 data) { m_syscr = data; + m_intc->set_nmi_edge(BIT(data, 2)); update_irq_filter(); logerror("syscr = %02x\n", data); } diff --git a/src/devices/cpu/h8/h83048.h b/src/devices/cpu/h8/h83048.h index 52c726cb09e2a..02444221e8256 100644 --- a/src/devices/cpu/h8/h83048.h +++ b/src/devices/cpu/h8/h83048.h @@ -12,7 +12,7 @@ H8/3044 32K 2K H8/3045 64K 2K H8/3047 96K 4K - H8/3048 192K 4K + H8/3048 128K 4K The 3394, 3396, and 3997 variants are the mask-rom versions. @@ -35,6 +35,9 @@ class h83048_device : public h8h_device { public: h83048_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock); + auto tend0() { return m_tend_cb[0].bind(); } + auto tend1() { return m_tend_cb[1].bind(); } + auto read_port1() { return m_read_port [PORT_1].bind(); } auto write_port1() { return m_write_port[PORT_1].bind(); } auto read_port2() { return m_read_port [PORT_2].bind(); } @@ -90,6 +93,8 @@ class h83048_device : public h8h_device { required_device m_timer16_4; required_device m_watchdog; + devcb_write_line::array<2> m_tend_cb; + u32 m_ram_start; u8 m_syscr; diff --git a/src/devices/cpu/h8/h8_adc.cpp b/src/devices/cpu/h8/h8_adc.cpp index c4d80ba0b4a07..05c012017f334 100644 --- a/src/devices/cpu/h8/h8_adc.cpp +++ b/src/devices/cpu/h8/h8_adc.cpp @@ -292,7 +292,7 @@ void h8_adc_3337_device::mode_update() m_trigger = m_adcr & 0x80 ? T_EXT : T_SOFT; if(m_adcsr & 0x10) { - m_start_mode = ACTIVE | ROTATE; + m_start_mode = ACTIVE | REPEAT | ROTATE; m_start_channel = m_adcsr & 4; m_end_channel = m_adcsr & 7; } else { diff --git a/src/devices/cpu/h8/h8_dma.cpp b/src/devices/cpu/h8/h8_dma.cpp index 3edb36c70e05b..7cb057e60ee4b 100644 --- a/src/devices/cpu/h8/h8_dma.cpp +++ b/src/devices/cpu/h8/h8_dma.cpp @@ -78,8 +78,7 @@ void h8gen_dma_device::start_stop_test() } else { if(m_dmach[i >> 1] && (m_dmach[i >> 1]->m_state[i & 1].m_flags & h8_dma_state::ACTIVE)) { - logerror("forced abort %d\n", i); - exit(0); + logerror("%s: forced abort %d\n", machine().describe_context(), i); } } } diff --git a/src/devices/cpu/h8/h8_dtc.cpp b/src/devices/cpu/h8/h8_dtc.cpp index 7844c9cec922d..3dd276fca11d4 100644 --- a/src/devices/cpu/h8/h8_dtc.cpp +++ b/src/devices/cpu/h8/h8_dtc.cpp @@ -214,7 +214,6 @@ void h8_dtc_device::writeback_done(int vector) m_intc->internal_interrupt(vector); } else { logerror("Software dtc done\n"); - exit(0); } } diff --git a/src/devices/machine/upd765.cpp b/src/devices/machine/upd765.cpp index 1fc0cb588117b..6585c23fff52e 100644 --- a/src/devices/machine/upd765.cpp +++ b/src/devices/machine/upd765.cpp @@ -3311,6 +3311,12 @@ void hd63266f_device::map(address_map &map) map(0x2, 0x2).r(FUNC(hd63266f_device::extstat_r)); } +uint8_t hd63266f_device::get_st3(floppy_info &fi) +{ + // wk1800 seems to expect TS to be inverted (or possibly the bit is actually something else?) + return upd765_family_device::get_st3(fi) ^ ST3_TS; +} + void hd63266f_device::soft_reset() { upd765_family_device::soft_reset(); diff --git a/src/devices/machine/upd765.h b/src/devices/machine/upd765.h index ad5324019ee0b..0f5ae9a1b05b1 100644 --- a/src/devices/machine/upd765.h +++ b/src/devices/machine/upd765.h @@ -595,6 +595,7 @@ class hd63266f_device : public upd765_family_device { hd63266f_device(const machine_config &mconfig, const char *tag, device_t* owner, uint32_t clock); virtual void map(address_map &map) override ATTR_COLD; + virtual uint8_t get_st3(floppy_info &fi) override; auto inp_rd_callback() { return inp_cb.bind(); } // this is really the ts signal void rate_w(u8 state) { state ? set_rate(500000) : set_rate(250000); } diff --git a/src/devices/sound/gt155.cpp b/src/devices/sound/gt155.cpp new file mode 100644 index 0000000000000..6f868b4e7b2f9 --- /dev/null +++ b/src/devices/sound/gt155.cpp @@ -0,0 +1,404 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +/*************************************************************************** + + Casio GT155 (HG51B155FD) + + This is the sound generator and DSP used in various higher-end + "A-Squared Sound Source" keyboards and pianos between roughly 1994-2001. + + TODO: + - verify per-voice lowpass filter behavior + - DSP (architecture/instruction set seems to be the same as the standalone + "GD277" DSP used in other contemporary keyboards) + +***************************************************************************/ + +#include "emu.h" +#include "gt155.h" + +#include + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +DEFINE_DEVICE_TYPE(GT155, gt155_device, "gt155", "Casio GT155") + +gt155_device::gt155_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) + : device_t(mconfig, GT155, tag, owner, clock) + , device_sound_interface(mconfig, *this) + , device_rom_interface(mconfig, *this) +{ +} + +/**************************************************************************/ +void gt155_device::device_start() +{ + m_stream = stream_alloc(0, 2, clock() / CLOCKS_PER_SAMPLE); // 16.384 MHz -> 32 kHz, or 24.576 MHz -> 48 kHz + + for (int i = 0; i < 0x800; i++) + { + const double frac = 1.0 - ((double)i / 0x7ff); + m_volume[i] = 0x800 * pow(10, -2.15 * frac) * cos(0.5 * M_PI * frac * frac * frac); + } + + save_item(NAME(m_data)); + save_item(NAME(m_dsp_data)); + save_item(NAME(m_rom_addr)); + + save_item(STRUCT_MEMBER(m_voices, m_enable)); + save_item(STRUCT_MEMBER(m_voices, m_format)); + + save_item(STRUCT_MEMBER(m_voices, m_addr)); + save_item(STRUCT_MEMBER(m_voices, m_addr_frac)); + save_item(STRUCT_MEMBER(m_voices, m_addr_end)); + save_item(STRUCT_MEMBER(m_voices, m_addr_loop)); + save_item(STRUCT_MEMBER(m_voices, m_addr_loop_frac)); + + save_item(STRUCT_MEMBER(m_voices, m_pitch)); + + save_item(STRUCT_MEMBER(m_voices, m_filter_gain)); + save_item(STRUCT_MEMBER(m_voices, m_filter)); + save_item(STRUCT_MEMBER(m_voices, m_filter_out)); + save_item(STRUCT_MEMBER(m_voices, m_filter_unk)); + + save_item(STRUCT_MEMBER(m_voices, m_sample_last)); + save_item(STRUCT_MEMBER(m_voices, m_sample)); + + save_item(STRUCT_MEMBER(m_voices, m_env_current)); + save_item(STRUCT_MEMBER(m_voices, m_env_target)); + save_item(STRUCT_MEMBER(m_voices, m_env_level)); + save_item(STRUCT_MEMBER(m_voices, m_env_scale)); + save_item(STRUCT_MEMBER(m_voices, m_env_rate)); + + save_item(STRUCT_MEMBER(m_voices, m_balance)); + save_item(STRUCT_MEMBER(m_voices, m_dsp_send)); + +} + +/**************************************************************************/ +void gt155_device::device_reset() +{ + std::fill(std::begin(m_data), std::end(m_data), 0); + std::fill(std::begin(m_dsp_data), std::end(m_dsp_data), 0); + std::fill(std::begin(m_voices), std::end(m_voices), voice_t()); +} + +/**************************************************************************/ +void gt155_device::device_clock_changed() +{ + m_stream->set_sample_rate(clock() / CLOCKS_PER_SAMPLE); +} + +/**************************************************************************/ +void gt155_device::sound_stream_update(sound_stream& stream, std::vector const& inputs, std::vector& outputs) +{ + for (int i = 0; i < outputs[0].samples(); i++) + { + s64 left = 0, right = 0; + + for (auto& voice : m_voices) + { + if (voice.m_enable) + { + mix_sample(voice, left, right); + voice.update_envelope(); + } + } + + outputs[0].put_int_clamp(i, left >> 11, 32678); + outputs[1].put_int_clamp(i, right >> 11, 32768); + } +} + +/**************************************************************************/ +void gt155_device::rom_bank_pre_change() +{ + m_stream->update(); +} + +/**************************************************************************/ +void gt155_device::mix_sample(voice_t &voice, s64 &left, s64 &right) +{ + // update sample position + voice.m_addr_frac += voice.m_pitch; + if (voice.m_addr_frac >= (1 << 15)) + update_sample(voice); + + // interpolate, apply envelope + channel gain and lowpass, and mix into output + s64 sample = voice.m_sample_last + (s64(voice.m_sample - voice.m_sample_last) * voice.m_addr_frac >> 15); + + // TODO: does this produce accurate filter output? + sample = sample * voice.m_filter_gain; + sample += (s32)voice.m_filter_out * (voice.m_filter ^ 0xffff); + sample >>= 16; + voice.m_filter_out = sample; + + const u16 env_level = voice.m_env_current >> (ENV_SHIFT + 4); + sample *= m_volume[env_level]; + + left += (sample * voice.m_balance[0]) / 0x1f; + right += (sample * voice.m_balance[1]) / 0x1f; +} + +/**************************************************************************/ +void gt155_device::voice_t::update_envelope() +{ + if (m_env_target > m_env_current + && (m_env_target - m_env_current) > m_env_rate) + { + m_env_current += m_env_rate; + } + else if (m_env_target < m_env_current + && (m_env_current - m_env_target) > m_env_rate) + { + m_env_current -= m_env_rate; + } + else + { + m_env_current = m_env_target; + } +} + +/**************************************************************************/ +void gt155_device::update_sample(voice_t &voice) +{ + voice.m_sample_last = voice.m_sample; + + while (voice.m_addr_frac >= (1 << 15)) + { + voice.m_addr += (voice.m_addr_frac >> 15) * (voice.m_format ? 2 : 1); + voice.m_addr_frac &= 0x7fff; + + if (voice.m_addr >= voice.m_addr_end) + { + if (voice.m_addr_loop == voice.m_addr_end) + { + // if this is a one-shot sample, just disable it now + voice.m_enable = 0; + voice.m_env_current = voice.m_env_target = 0; + return; + } + + // apply the fractional component of the loop + if (voice.m_format) + { + voice.m_addr -= (voice.m_addr_end - (voice.m_addr_loop & ~1)); + voice.m_addr_frac += (voice.m_addr_loop_frac >> 1); + if (BIT(voice.m_addr_loop, 0)) + voice.m_addr_frac += 1 << 14; + } + else + { + voice.m_addr -= (voice.m_addr_end - voice.m_addr_loop); + voice.m_addr_frac += voice.m_addr_loop_frac; + } + } + } + + if (voice.m_format) + voice.m_sample = read_word(voice.m_addr & ~1); + else + // wk1800 apparently expects 8bit samples to only be expanded to 9 bits + // (with m_filter_gain then boosted to compensate) + voice.m_sample = (s16)(s8)read_byte(voice.m_addr) << 1; +} + +/**************************************************************************/ +void gt155_device::write(offs_t offset, u8 data) +{ + offset &= 0xf; + + if (offset < 6) + { + m_data[offset] = data; + } + else if (offset == 6) + { + switch (data) + { + case 0x00: + m_rom_addr = (m_data[0] << 1) | (m_data[1] << 9) | (m_data[2] << 17); + break; + + case 0x06: + m_dsp_data[m_data[5] & 0x7f] &= 0xffff; + m_dsp_data[m_data[5] & 0x7f] |= ((m_data[0] << 16) | (m_data[1] << 24)); + break; + + case 0x07: + m_dsp_data[m_data[5] & 0x7f] &= 0xffff0000; + m_dsp_data[m_data[5] & 0x7f] |= (m_data[0] | (m_data[1] << 8)); + return; + + default: + voice_command(data); + break; + } + + } + else + { + logerror("%s: write offset %u = %02x\n", machine().describe_context(), offset, data); + } +} + +/**************************************************************************/ +u8 gt155_device::read(offs_t offset) +{ + u8 data = 0; + offset &= 0xf; + + if (offset < 0x6) + { + data = m_data[offset]; + } + else if (offset == 0xe) + { + data = read_byte(m_rom_addr); + } + else if (offset == 0xf) + { + data = read_byte(m_rom_addr + 1); + if (!machine().side_effects_disabled()) + m_rom_addr += 2; + } + else if (!machine().side_effects_disabled()) + { + logerror("%s: read offset %u\n", machine().describe_context(), offset); + } + + return data; +} + +/**************************************************************************/ +u16 gt155_device::reg16(u8 num) const +{ + return m_data[num] | (m_data[num+1] << 8); +} + +/**************************************************************************/ +u32 gt155_device::reg24(u8 num) const +{ + return m_data[num] | (m_data[num+1] << 8) | (m_data[num+2] << 16); +} + +/**************************************************************************/ +u32 gt155_device::reg32(u8 num) const +{ + return m_data[num] | (m_data[num+1] << 8) | (m_data[num+2] << 16) | (m_data[num+3] << 24); +} + +/**************************************************************************/ +void gt155_device::voice_command(u8 data) +{ + m_stream->update(); + + voice_t &voice = m_voices[m_data[5] & 0x1f]; + const u16 cmd = data | ((m_data[5] & 0xe0) << 8); + + switch (cmd) + { + case 0x0001: // sample start address + voice.m_addr = reg32(1) >> 7; + voice.m_addr_frac = reg16(0) & 0x7fff; + break; + + case 0x2001: // sample loop address + voice.m_addr_loop = reg32(1) >> 7; + voice.m_addr_loop_frac = reg16(0) & 0x7fff; + break; + + case 0x0002: // sample envelope step + case 0x2002: // sample envelope step (double rate?) used when forcing a voice off + voice.m_env_rate = reg16(0) & 0x7fff; + if (cmd == 0x2002) + voice.m_env_rate <<= 1; + voice.m_env_level = reg16(2); + voice.m_env_target = (u32)voice.m_env_level * voice.m_env_scale; + break; + + case 0x0003: // sample end address and envelope scale + voice.m_addr_end = reg24(0) << 1; + voice.m_env_scale = m_data[3]; + voice.m_env_target = (u32)voice.m_env_level * voice.m_env_scale; + break; + + case 0x0004: + /* + * params used by wk1800: + * ff ff 00 00 (on boot) + * fe 07 0c 00 (before note on) + * f5 0d 0a 02 (starting 8-bit sample) + * f5 05 0a 0a (starting 16-bit sample) + * 00 20 00 00 (before note off) + * 14 00 08 02 (after envelope update) + * + * TODO: is any of this related to how 8bit samples are expanded? + * (see comment at bottom of update_sample) + */ + if (!voice.m_enable && !BIT(m_data[0], 1)) + { + voice.m_format = BIT(m_data[3], 3); + voice.m_sample_last = voice.m_sample = 0; + } + voice.m_enable = BIT(~m_data[0], 1); + break; + + case 0x0005: // sample pitch + voice.m_pitch = reg16(0); + break; + + case 0x2005: + { + // this is actually gain premultiplied by filter level, so the sound HW does one fewer mult when applying the filter. + const u16 gain = reg16(0); + voice.m_filter_gain = (gain & 0x1fff) << (3 + (gain >> 13)); + break; + } + + case 0x4005: + /* + filter coefficient (bit 15 inverted) - this is also premultiplied into the value written to m_filter_gain, + with this value probably only being used as a coefficient for the previous filter output? + */ + voice.m_filter = reg16(0) ^ 0x8000; + break; + + case 0x6005: + voice.m_filter_unk = reg16(0); + break; + + case 0x000e: + voice.m_balance[0] = m_data[0] & 0x1f; + voice.m_balance[1] = m_data[1] & 0x1f; + break; + + case 0x200e: + voice.m_dsp_send[0] = m_data[0] & 0x1f; + voice.m_dsp_send[1] = m_data[1] & 0x1f; + break; + + case 0x0014: // read envelope ready status + if (voice.m_env_current == voice.m_env_target) + m_data[2] = 0x00; + else + m_data[2] = 0x08; + break; + + case 0x2018: // read envelope output & current sample output + m_data[1] = voice.m_env_current >> ENV_SHIFT; + m_data[2] = voice.m_env_current >> (ENV_SHIFT + 8); + m_data[3] = voice.m_sample; + m_data[4] = voice.m_sample >> 8; + break; + + default: + logerror("%s: sound cmd %02x%02x, param = %02x %02x %02x %02x %02x\n", machine().describe_context(), + m_data[5], data, + m_data[0], m_data[1], m_data[2], m_data[3], m_data[4]); + break; + } +} diff --git a/src/devices/sound/gt155.h b/src/devices/sound/gt155.h new file mode 100644 index 0000000000000..6584b0714f4f1 --- /dev/null +++ b/src/devices/sound/gt155.h @@ -0,0 +1,104 @@ +// license:BSD-3-Clause +// copyright-holders: Devin Acker +/*************************************************************************** + Casio GT913 sound (HLE) +***************************************************************************/ + +#ifndef MAME_DEVICES_SOUND_GT155_H +#define MAME_DEVICES_SOUND_GT155_H + +#pragma once + +#include "dirom.h" + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> gt913_sound_device + +class gt155_device : public device_t, + public device_sound_interface, + public device_rom_interface<23> +{ +public: + static constexpr feature_type imperfect_features() { return feature::SOUND; } + + // construction/destruction + gt155_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0); + + void write(offs_t offset, u8 data); + u8 read(offs_t offset); + +protected: + // device_t overrides + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + virtual void device_clock_changed() override; + + // device_sound_interface 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: + static constexpr unsigned CLOCKS_PER_SAMPLE = 512; + static constexpr unsigned ENV_SHIFT = 8; + + u16 reg16(u8 num) const; + u32 reg24(u8 num) const; + u32 reg32(u8 num) const; + + void voice_command(u8 data); + + sound_stream *m_stream; + + u16 m_volume[0x800]; + + u8 m_data[6]; + u32 m_dsp_data[128]; + u32 m_rom_addr; + + struct voice_t + { + u8 m_enable = 0; + u8 m_format = 0; + + u32 m_addr = 0; + u32 m_addr_frac = 0; + u32 m_addr_end = 0; + u32 m_addr_loop = 0; + u32 m_addr_loop_frac = 0; + + u32 m_pitch = 0; + + u32 m_filter_gain = 0; + u16 m_filter = 0; + s16 m_filter_out = 0; + u16 m_filter_unk = 0; + + s16 m_sample_last = 0; + s16 m_sample = 0; + + u32 m_env_current = 0; + u32 m_env_target = 0; + u16 m_env_level = 0; + u8 m_env_scale = 0; + u16 m_env_rate = 0; + + u8 m_balance[2] = {0}; + u8 m_dsp_send[2] = {0}; + + void update_envelope(); + }; + + void mix_sample(voice_t &voice, s64 &left, s64 &right); + void update_sample(voice_t &voice); + + voice_t m_voices[32]; +}; + +DECLARE_DEVICE_TYPE(GT155, gt155_device) + +#endif // MAME_DEVICES_SOUND_GT155_H diff --git a/src/mame/casio/wk1800.cpp b/src/mame/casio/wk1800.cpp new file mode 100644 index 0000000000000..3fb5ce00838ff --- /dev/null +++ b/src/mame/casio/wk1800.cpp @@ -0,0 +1,615 @@ +// license:BSD-3-Clause +// copyright-holders:Devin Acker + +/* + Casio WK-1600/1800 series keyboards + + Models on this hardware: + - CTK-711EX (1998) + 61 keys, 5MB wave ROM + - CTK-811EX (1998), CTK-731 (1999) + 61 keys, 5MB wave ROM, floppy drive + - WK-1600, WK-1630 (2000) + 73 keys, 8MB wave ROM + - WK-1800 (2000) + 73 keys, 8MB wave ROM, floppy drive + - AP-60R (1999), AP-65R (2001) + 88 keys, 8MB wave ROM, floppy drive + + TODO: + - fix floppy controller hookup for wk1800 + - add software list for style/program disks + */ + +#include "emu.h" + +#include "bus/midi/midiinport.h" +#include "bus/midi/midioutport.h" +#include "cpu/h8/h83048.h" +#include "imagedev/floppy.h" +#include "machine/nvram.h" +#include "machine/gt913_kbd.h" +#include "machine/upd765.h" +#include "sound/gt155.h" +#include "video/hd44780.h" + +#include "emupal.h" +#include "screen.h" +#include "softlist_dev.h" +#include "speaker.h" + +#include + +namespace { + +class wk1800_state : public driver_device +{ +public: + wk1800_state(machine_config const &mconfig, device_type type, char const *tag) + : driver_device(mconfig, type, tag) + , m_maincpu(*this, "maincpu") + , m_gt155(*this, "gt155") + , m_lcdc(*this, "lcdc") + , m_fdc(*this, "fdc") + , m_floppy(*this, "fdc:0") + , m_sound_rom(*this, "gt155") + , m_inputs(*this, "KC%u", 0U) + , m_outputs(*this, "%02x.%d.%d", 0U, 0U, 0U) + , m_led(*this, "led%d", 0U) + , m_led_power(*this, "led_power") + { + } + + void wk1600(machine_config &config); + void wk1800(machine_config &config); + + TIMER_CALLBACK_MEMBER(nmi_clear) { m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); } + + ioport_value lcd_r() { return m_lcdc->db_r() >> 4; } + void lcd_w(int state) { m_lcdc->db_w(state << 4); } + + void fdc_rate_w(int state) { if (m_fdc) m_fdc->rate_w(state); } + + void shift_data_w(int state) { m_shift_data = state; } + void led_clk_w(int state); + void input_clk_w(int state); + + DECLARE_INPUT_CHANGED_MEMBER(power_w); + + template ioport_value inputs_r(); + + void apo_w(int state); + +private: + void wk1600_map(address_map& map); + void wk1800_map(address_map& map); + + virtual void driver_start() override; + + void render_w(int state); + + required_device m_maincpu; + required_device m_gt155; + required_device m_lcdc; + optional_device m_fdc; + optional_device m_floppy; + + required_memory_region m_sound_rom; + + emu_timer* m_nmi_timer = nullptr; + + optional_ioport_array<8> m_inputs; + + output_finder<64, 8, 5> m_outputs; + output_finder<8> m_led; + output_finder<> m_led_power; + + u8 m_sound_regs[16]; + u32 m_sound_rom_addr; + u32 m_dsp_data[128]; + + u8 m_led_sel, m_input_sel; + u8 m_led_clk, m_input_clk, m_shift_data; +}; + +/**************************************************************************/ +void wk1800_state::led_clk_w(int state) +{ + if (state && !m_led_clk) + { + m_led_sel <<= 1; + m_led_sel |= (m_shift_data & 1); + + for (int i = 0; i < 8; i++) + m_led[i] = BIT(~m_led_sel, i); + } + + m_led_clk = state; +} + +/**************************************************************************/ +void wk1800_state::input_clk_w(int state) +{ + if (state && !m_input_clk) + { + m_input_sel <<= 1; + m_input_sel |= (m_shift_data & 1); + } + + m_input_clk = state; +} + +/**************************************************************************/ +INPUT_CHANGED_MEMBER(wk1800_state::power_w) +{ + if (newval) + { + m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_nmi_timer->adjust(attotime::never); + } + else + { + // give the CPU enough time to switch NMI to active-high so it fires again + // otherwise, releasing the power button too quickly may be ignored + m_nmi_timer->adjust(attotime::from_msec(100)); + } +} + +/**************************************************************************/ +template +ioport_value wk1800_state::inputs_r() +{ + ioport_value result = 0; + for (unsigned i = 0U; i < m_inputs.size(); i++) + if (BIT(m_input_sel, i)) + result |= m_inputs[i].read_safe(0); + + return result >> StartBit; +} + +/**************************************************************************/ +void wk1800_state::apo_w(int state) +{ + logerror("apo_w: %x\n", state); + if (!state) + m_lcdc->reset(); + + m_led_power = state; + m_gt155->set_output_gain(ALL_OUTPUTS, state ? 1.0 : 0.0); +} + +/**************************************************************************/ +void wk1800_state::render_w(int state) +{ + 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 wk1800_state::wk1600_map(address_map& map) +{ + map(0x00000, 0x1ffff).rom(); + map(0x20000, 0x2ffff).rw(m_gt155, NAME(gt155_device::read), NAME(gt155_device::write)); + map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::read)); + map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::status_r)); + map(0x80000, 0x9ffff).mirror(0x60000).ram().share("nvram"); +} + +/**************************************************************************/ +void wk1800_state::wk1800_map(address_map& map) +{ + map(0x00000, 0x1ffff).rom(); + map(0x20000, 0x2ffff).rw(m_gt155, NAME(gt155_device::read), NAME(gt155_device::write)); + map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::read)); + map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::status_r)); + map(0x40000, 0x40003).mirror(0x1fffc).m(m_fdc, FUNC(hd63266f_device::map)); + map(0x60000, 0x7ffff).rw(m_fdc, NAME(hd63266f_device::dma_r), NAME(hd63266f_device::dma_w)); + map(0x80000, 0xbffff).mirror(0x40000).ram().share("nvram"); +} + + +/**************************************************************************/ +void wk1800_state::driver_start() +{ + m_led.resolve(); + m_led_power.resolve(); + m_outputs.resolve(); + + m_nmi_timer = timer_alloc(FUNC(wk1800_state::nmi_clear), this); + + std::fill(std::begin(m_sound_regs), std::end(m_sound_regs), 0); + std::fill(std::begin(m_dsp_data), std::end(m_dsp_data), 0); + m_sound_rom_addr = 0; + + m_led_sel = 0xff; + m_input_sel = 0; + + m_led_clk = m_input_clk = m_shift_data = 0; + + save_item(NAME(m_sound_regs)); + save_item(NAME(m_dsp_data)); + save_item(NAME(m_sound_rom_addr)); + + save_item(NAME(m_led_sel)); + save_item(NAME(m_input_sel)); + + save_item(NAME(m_led_clk)); + save_item(NAME(m_input_clk)); + save_item(NAME(m_shift_data)); +} + + +/**************************************************************************/ +void wk1800_state::wk1600(machine_config &config) +{ + H83048(config, m_maincpu, 16'000'000).set_mode_a20(); + m_maincpu->set_addrmap(AS_PROGRAM, &wk1800_state::wk1600_map); + m_maincpu->read_adc<0>().set_constant(0); + m_maincpu->read_adc<1>().set_ioport("AN1"); + m_maincpu->read_adc<2>().set_constant(0); + m_maincpu->read_adc<3>().set_ioport("AN3"); + m_maincpu->read_port6().set_ioport("P6"); + m_maincpu->read_port7().set_ioport("P7"); + m_maincpu->read_port8().set_ioport("P8"); + m_maincpu->write_port8().set_ioport("P8"); + m_maincpu->read_port9().set_ioport("P9"); + m_maincpu->read_porta().set_ioport("PA"); + m_maincpu->write_porta().set_ioport("PA"); + m_maincpu->read_portb().set(FUNC(wk1800_state::lcd_r)); + m_maincpu->write_portb().set_ioport("PB"); + + NVRAM(config, "nvram"); + + GT913_KBD_HLE(config, "kbd"); // actually TC190C020AF-001 gate array + + auto& mdin(MIDI_PORT(config, "mdin")); + midiin_slot(mdin); + mdin.rxd_handler().set(m_maincpu, FUNC(h83048_device::sci_rx_w<0>)); + + auto& mdout(MIDI_PORT(config, "mdout")); + midiout_slot(mdout); + m_maincpu->write_sci_tx<0>().set(mdout, FUNC(midi_port_device::write_txd)); + + HD44780(config, m_lcdc, 270'000); // TODO: Wrong device type, should be SED1278F2A; clock not measured, datasheet typical clock used + m_lcdc->set_lcd_size(2, 8); + + auto& screen = SCREEN(config, "screen", SCREEN_TYPE_SVG); + screen.set_refresh_hz(60); + screen.set_size(1755, 450); + screen.set_visarea_full(); + screen.screen_vblank().set(FUNC(wk1800_state::render_w)); + + SPEAKER(config, "lspeaker").front_left(); + SPEAKER(config, "rspeaker").front_right(); + + GT155(config, m_gt155, 24.576_MHz_XTAL); + m_gt155->add_route(0, "lspeaker", 1.0); + m_gt155->add_route(1, "rspeaker", 1.0); +} + +/**************************************************************************/ +[[maybe_unused]] static void wk1800_floppies(device_slot_interface& device) +{ + device.option_add("35hd", FLOPPY_35_HD); +} + +/**************************************************************************/ +void wk1800_state::wk1800(machine_config &config) +{ + wk1600(config); + m_maincpu->set_addrmap(AS_PROGRAM, &wk1800_state::wk1800_map); + + HD63266F(config, m_fdc, 16'000'000); + m_fdc->set_ready_line_connected(false); + m_fdc->drq_wr_callback().set_inputline(m_maincpu, H8_INPUT_LINE_DREQ0); + m_maincpu->tend0().set(m_fdc, FUNC(upd765a_device::tc_line_w)); + + FLOPPY_CONNECTOR(config, m_floppy, wk1800_floppies, "35hd", floppy_image_device::default_pc_floppy_formats); + m_floppy->enable_sound(true); + SOFTWARE_LIST(config, "flop_list").set_compatible("midi_flop"); +} + + +INPUT_PORTS_START(wk1600) + PORT_START("kbd:FI0") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E1") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F1#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G1#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A1#") + + PORT_START("kbd:FI1") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B1") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C2#") + 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("E2") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F2#") + + PORT_START("kbd:FI2") + 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( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C3#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3") + + PORT_START("kbd:FI3") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D3#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E3") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F3#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G3#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A3#") + + PORT_START("kbd:FI4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B3") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C4#") + 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("E4") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F4#") + + PORT_START("kbd:FI5") + 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( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C5#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5") + + PORT_START("kbd:FI6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D5#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E5") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F5#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G5#") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A5#") + + PORT_START("kbd:FI7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B5") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C6#") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D6") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D6#") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E6") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F6") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F6#") + + PORT_START("kbd:FI8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G6") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G6#") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A6") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("A6#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("B6") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C7") + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("C7#") + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D7") + + PORT_START("kbd:FI9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("D7#") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("E7") + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F7") + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("F7#") + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("G7") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("kbd:FI10") + PORT_START("kbd:KI0") + PORT_START("kbd:KI1") + PORT_START("kbd:KI2") + + PORT_START("kbd:VELOCITY") + PORT_BIT( 0xff, 0xff, IPT_POSITIONAL ) PORT_NAME("Key Velocity") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_CENTERDELTA(0) PORT_CODE_DEC(KEYCODE_PGDN) PORT_CODE_INC(KEYCODE_PGUP) + + PORT_START("KC0") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Mode") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Intro") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Mixer Select") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 8 / Chord 3") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration A") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 16 / Track 6") + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Split") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad - / No") PORT_CODE(KEYCODE_MINUS_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Demo") + + PORT_START("KC1") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Record") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Normal / Fill-In") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 1 / Upper 1") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 9 / Bass") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration B") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Auto Harmonize") + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Layer") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 2") PORT_CODE(KEYCODE_2_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Synth") + + PORT_START("KC2") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Song") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Variation / Fill-In") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 2 / Upper 2") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 10 / Rhythm") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration C") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Enter") PORT_CODE(KEYCODE_ENTER_PAD) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Rhythm") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 5") PORT_CODE(KEYCODE_5_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tune") + + PORT_START("KC3") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Pattern") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Synchro / Ending") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 3 / Lower 1") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 11 / Track 1") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration D") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Left") PORT_CODE(KEYCODE_LEFT) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tone") + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 8") PORT_CODE(KEYCODE_8_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("MIDI") + + PORT_START("KC4") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("DSP") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Start / Stop") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 4 / Lower 2") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 12 / Track 2") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration E") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Up") PORT_CODE(KEYCODE_UP) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 0") PORT_CODE(KEYCODE_0_PAD) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad + / Yes") PORT_CODE(KEYCODE_PLUS_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KC5") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Contrast") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Down") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 5 / Acc. Vol.") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 13 / Track 3") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration Store") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Down") PORT_CODE(KEYCODE_DOWN) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 1") PORT_CODE(KEYCODE_1_PAD) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 3") PORT_CODE(KEYCODE_3_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KC6") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Free Session") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tempo Up") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 6 / Chord 1") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 14 / Track 4") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose Down") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Cursor Right") PORT_CODE(KEYCODE_RIGHT) + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 4") PORT_CODE(KEYCODE_4_PAD) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 6") PORT_CODE(KEYCODE_6_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("KC7") + PORT_BIT( 0x001, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("One Touch Preset") + PORT_BIT( 0x002, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Registration Bank") + PORT_BIT( 0x004, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 7 / Chord 2") + PORT_BIT( 0x008, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Channel 15 / Track 5") + PORT_BIT( 0x010, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Transpose Up") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Touch Response") + PORT_BIT( 0x040, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 7") PORT_CODE(KEYCODE_7_PAD) + PORT_BIT( 0x080, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Keypad 9") PORT_CODE(KEYCODE_9_PAD) + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("SWITCH") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_POWER_ON ) PORT_NAME("Power") PORT_CHANGED_MEMBER(DEVICE_SELF, FUNC(wk1800_state::power_w), 0) + + PORT_START("AN1") + PORT_BIT( 0x3ff, 0x200, IPT_PADDLE ) PORT_NAME("Pitch Wheel") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_MINMAX(0x00, 0x3ff) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) + + PORT_START("AN3") + PORT_BIT( 0x3ff, 0x000, IPT_POSITIONAL_V ) PORT_NAME("Modulation Wheel") PORT_SENSITIVITY(100) PORT_KEYDELTA(10) PORT_MINMAX(0x00, 0x3ff) PORT_PLAYER(2) PORT_CODE_DEC(JOYCODE_Y_DOWN_SWITCH) PORT_CODE_INC(JOYCODE_Y_UP_SWITCH) + + PORT_START("P6") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x06, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<1>)) + PORT_BIT( 0xf8, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("P7") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<0>)) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_CONFNAME( 0x04, 0x00, "Power Source" ) + PORT_CONFSETTING( 0x00, "AC Adapter" ) + PORT_CONFSETTING( 0x04, "Battery" ) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME("Pedal") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<4>)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("P8") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OUTPUT ) // reset sound, LCD, FDC + PORT_BIT( 0x0e, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_CUSTOM ) // high = WK-1800, low = WK-1600 + PORT_BIT( 0xe0, IP_ACTIVE_HIGH, IPT_UNUSED ) + + PORT_START("P9") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<3>)) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x38, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<5>)) + + PORT_START("PA") + PORT_BIT( 0x03, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(FUNC(wk1800_state::inputs_r<8>)) + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::input_clk_w)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::shift_data_w)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::led_clk_w)) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::apo_w)) + + PORT_START("PB") + PORT_BIT( 0x0f, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::lcd_w)) + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", FUNC(hd44780_device::e_w)) + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", FUNC(hd44780_device::rw_w)) + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER("lcdc", FUNC(hd44780_device::rs_w)) +INPUT_PORTS_END + +INPUT_PORTS_START( wk1800 ) + PORT_INCLUDE(wk1600) + + PORT_MODIFY("KC2") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Tune / MIDI") + + PORT_MODIFY("KC3") + PORT_BIT( 0x100, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Touch Response") + + PORT_MODIFY("KC7") + PORT_BIT( 0x020, IP_ACTIVE_HIGH, IPT_KEYPAD ) PORT_NAME("Disk") + + PORT_MODIFY("P7") + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_CUSTOM ) // TODO: disk HD/DD detect + + PORT_MODIFY("P8") + PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_CUSTOM ) // high = WK-1800, low = WK-1600 + + PORT_MODIFY("PA") + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(FUNC(wk1800_state::fdc_rate_w)) +INPUT_PORTS_END + + +ROM_START(wk1800) + ROM_REGION(0x20000, "maincpu", 0) // "Ver.1.61" + ROM_LOAD("hd6433048sa89f.lsi9", 0x00000, 0x20000, CRC(bd5bfab3) SHA1(2731b5ab1cb288553bfee9b856264a5d1eb0ef1a)) + + ROM_REGION16_LE(0x800000, "gt155", 0) // "Ver.1.60" + ROM_LOAD("lhmn5kpn.lsi2", 0x000000, 0x400000, CRC(f75d21f0) SHA1(e08937ce2fa152db85fa96cef53f81351e690666)) + ROM_LOAD("lhmn5kpp.lsi1", 0x400000, 0x400000, CRC(f6cc5048) SHA1(9f48730a5bd3582f6fe08cb937848907d11aa804)) + + ROM_REGION(585110, "screen", 0) + ROM_LOAD("wk1800.svg", 0, 585110, CRC(5fab0b26) SHA1(6181b9eb950cd30474efb37b8cd660cba4b0b914)) +ROM_END + +#define rom_wk1600 rom_wk1800 + +} // anonymous namespace + +// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS +SYST( 2000, wk1800, 0, 0, wk1800, wk1800, wk1800_state, empty_init, "Casio", "WK-1800", MACHINE_SUPPORTS_SAVE ) +SYST( 2000, wk1600, wk1800, 0, wk1600, wk1600, wk1800_state, empty_init, "Casio", "WK-1600", MACHINE_SUPPORTS_SAVE ) diff --git a/src/mame/mame.lst b/src/mame/mame.lst index 139680b3b400b..0ee5e743a27bf 100644 --- a/src/mame/mame.lst +++ b/src/mame/mame.lst @@ -16135,6 +16135,10 @@ sk10 // @source:casio/sx1000.cpp sx1010 // Casio SX1010 +@source:casio/wk1800.cpp +wk1600 // 2000 Casio +wk1800 // 2000 Casio + @source:casio/zoomer.cpp zoomer // 1993 Casio/Tandy From fba1f772b93fb85b20d331cac7d38d05802f2504 Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Sat, 9 Nov 2024 20:48:57 -0500 Subject: [PATCH 2/3] fix NAME/FUNC mixup --- src/mame/casio/wk1800.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/mame/casio/wk1800.cpp b/src/mame/casio/wk1800.cpp index 3fb5ce00838ff..30f9529727fb6 100644 --- a/src/mame/casio/wk1800.cpp +++ b/src/mame/casio/wk1800.cpp @@ -200,9 +200,9 @@ void wk1800_state::render_w(int state) void wk1800_state::wk1600_map(address_map& map) { map(0x00000, 0x1ffff).rom(); - map(0x20000, 0x2ffff).rw(m_gt155, NAME(gt155_device::read), NAME(gt155_device::write)); - map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::read)); - map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::status_r)); + map(0x20000, 0x2ffff).rw(m_gt155, FUNC(gt155_device::read), FUNC(gt155_device::write)); + map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", FUNC(gt913_kbd_hle_device::read)); + map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", FUNC(gt913_kbd_hle_device::status_r)); map(0x80000, 0x9ffff).mirror(0x60000).ram().share("nvram"); } @@ -210,11 +210,11 @@ void wk1800_state::wk1600_map(address_map& map) void wk1800_state::wk1800_map(address_map& map) { map(0x00000, 0x1ffff).rom(); - map(0x20000, 0x2ffff).rw(m_gt155, NAME(gt155_device::read), NAME(gt155_device::write)); - map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::read)); - map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", NAME(gt913_kbd_hle_device::status_r)); + map(0x20000, 0x2ffff).rw(m_gt155, FUNC(gt155_device::read), FUNC(gt155_device::write)); + map(0x30000, 0x30001).mirror(0x0fff0).r("kbd", FUNC(gt913_kbd_hle_device::read)); + map(0x30002, 0x30003).mirror(0x0fff0).r("kbd", FUNC(gt913_kbd_hle_device::status_r)); map(0x40000, 0x40003).mirror(0x1fffc).m(m_fdc, FUNC(hd63266f_device::map)); - map(0x60000, 0x7ffff).rw(m_fdc, NAME(hd63266f_device::dma_r), NAME(hd63266f_device::dma_w)); + map(0x60000, 0x7ffff).rw(m_fdc, FUNC(hd63266f_device::dma_r), FUNC(hd63266f_device::dma_w)); map(0x80000, 0xbffff).mirror(0x40000).ram().share("nvram"); } From 1bb037fb985d87e48954babae1480a00211f91f4 Mon Sep 17 00:00:00 2001 From: Devin Acker Date: Sun, 10 Nov 2024 13:38:18 -0500 Subject: [PATCH 3/3] cleanup [skip ci] --- src/devices/sound/gt155.h | 39 +++++++++++++++++++-------------------- src/mame/casio/wk1800.cpp | 14 ++++++++------ 2 files changed, 27 insertions(+), 26 deletions(-) diff --git a/src/devices/sound/gt155.h b/src/devices/sound/gt155.h index 6584b0714f4f1..fe1d4d96691b7 100644 --- a/src/devices/sound/gt155.h +++ b/src/devices/sound/gt155.h @@ -1,11 +1,12 @@ // license:BSD-3-Clause // copyright-holders: Devin Acker + /*************************************************************************** - Casio GT913 sound (HLE) + Casio GT155 (HG51B155FD) ***************************************************************************/ -#ifndef MAME_DEVICES_SOUND_GT155_H -#define MAME_DEVICES_SOUND_GT155_H +#ifndef MAME_SOUND_GT155_H +#define MAME_SOUND_GT155_H #pragma once @@ -15,8 +16,6 @@ // TYPE DEFINITIONS //************************************************************************** -// ======================> gt913_sound_device - class gt155_device : public device_t, public device_sound_interface, public device_rom_interface<23> @@ -46,20 +45,6 @@ class gt155_device : public device_t, static constexpr unsigned CLOCKS_PER_SAMPLE = 512; static constexpr unsigned ENV_SHIFT = 8; - u16 reg16(u8 num) const; - u32 reg24(u8 num) const; - u32 reg32(u8 num) const; - - void voice_command(u8 data); - - sound_stream *m_stream; - - u16 m_volume[0x800]; - - u8 m_data[6]; - u32 m_dsp_data[128]; - u32 m_rom_addr; - struct voice_t { u8 m_enable = 0; @@ -96,9 +81,23 @@ class gt155_device : public device_t, void mix_sample(voice_t &voice, s64 &left, s64 &right); void update_sample(voice_t &voice); + u16 reg16(u8 num) const; + u32 reg24(u8 num) const; + u32 reg32(u8 num) const; + + void voice_command(u8 data); + + sound_stream *m_stream; + + u16 m_volume[0x800]; + + u8 m_data[6]; + u32 m_dsp_data[128]; + u32 m_rom_addr; + voice_t m_voices[32]; }; DECLARE_DEVICE_TYPE(GT155, gt155_device) -#endif // MAME_DEVICES_SOUND_GT155_H +#endif // MAME_SOUND_GT155_H diff --git a/src/mame/casio/wk1800.cpp b/src/mame/casio/wk1800.cpp index 30f9529727fb6..e2d61d8878793 100644 --- a/src/mame/casio/wk1800.cpp +++ b/src/mame/casio/wk1800.cpp @@ -181,14 +181,16 @@ void wk1800_state::apo_w(int state) /**************************************************************************/ void wk1800_state::render_w(int state) { - if(!state) + if (!state) return; const u8 *render = m_lcdc->render(); - for(int x = 0; x < 64; x++) { - for(int y = 0; y < 8; y++) { + for (int x = 0; x < 64; x++) + { + for (int y = 0; y < 8; y++) + { u8 v = *render++; - for(int z = 0; z < 5; z++) + for (int z = 0; z < 5; z++) m_outputs[x][y][z] = (v >> z) & 1; } render += 8; @@ -284,7 +286,7 @@ void wk1800_state::wk1600(machine_config &config) HD44780(config, m_lcdc, 270'000); // TODO: Wrong device type, should be SED1278F2A; clock not measured, datasheet typical clock used m_lcdc->set_lcd_size(2, 8); - auto& screen = SCREEN(config, "screen", SCREEN_TYPE_SVG); + auto& screen(SCREEN(config, "screen", SCREEN_TYPE_SVG)); screen.set_refresh_hz(60); screen.set_size(1755, 450); screen.set_visarea_full(); @@ -299,7 +301,7 @@ void wk1800_state::wk1600(machine_config &config) } /**************************************************************************/ -[[maybe_unused]] static void wk1800_floppies(device_slot_interface& device) +static void wk1800_floppies(device_slot_interface& device) { device.option_add("35hd", FLOPPY_35_HD); }