casio/wk1800.cpp, sound/gt155.cpp: Added Casio WK-1800/WK-1600 music keyboards. (#12957)
WK-1800 floppy support is not implemented. New working systems ---------- Casio WK-1800 [Edward d-tech, Devin Acker] New working clones ---------- Casio WK-1600 [Edward d-tech, Devin Acker]
This commit is contained in:
parent
6d32d33567
commit
752c45b42b
@ -1766,3 +1766,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
|
||||
|
@ -301,6 +301,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);
|
||||
}
|
||||
|
@ -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 {
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
408
src/devices/sound/gt155.cpp
Normal file
408
src/devices/sound/gt155.cpp
Normal file
@ -0,0 +1,408 @@
|
||||
// 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 <algorithm>
|
||||
|
||||
//**************************************************************************
|
||||
// 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<read_stream_view> const& inputs, std::vector<write_stream_view>& 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;
|
||||
}
|
||||
}
|
103
src/devices/sound/gt155.h
Normal file
103
src/devices/sound/gt155.h
Normal file
@ -0,0 +1,103 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders: Devin Acker
|
||||
|
||||
/***************************************************************************
|
||||
Casio GT155 (HG51B155FD)
|
||||
***************************************************************************/
|
||||
|
||||
#ifndef MAME_SOUND_GT155_H
|
||||
#define MAME_SOUND_GT155_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "dirom.h"
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
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<read_stream_view> const &inputs, std::vector<write_stream_view> &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;
|
||||
|
||||
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);
|
||||
|
||||
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_SOUND_GT155_H
|
637
src/mame/casio/wk1800.cpp
Normal file
637
src/mame/casio/wk1800.cpp
Normal file
@ -0,0 +1,637 @@
|
||||
// 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. current issues:
|
||||
- pressing the Disk button with the drive empty starts the drive motor,
|
||||
then the firmware waits forever on some status bit that is never set
|
||||
- pressing the Disk button with a disk inserted results in several 'forced abort'
|
||||
errors from the H8 DMA controller
|
||||
- wk1800 firmware seems to rely on different TS bit behavior from the HD63266
|
||||
compared to a standard uPD765
|
||||
- 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 <algorithm>
|
||||
|
||||
namespace {
|
||||
|
||||
class wk1800_state : public driver_device
|
||||
{
|
||||
public:
|
||||
static constexpr feature_type unemulated_features() { return feature::DISK; }
|
||||
|
||||
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) ATTR_COLD;
|
||||
void wk1800(machine_config &config) ATTR_COLD;
|
||||
|
||||
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<int StartBit> ioport_value inputs_r();
|
||||
|
||||
void apo_w(int state);
|
||||
|
||||
private:
|
||||
void wk1600_map(address_map &map) ATTR_COLD;
|
||||
void wk1800_map(address_map &map) ATTR_COLD;
|
||||
|
||||
virtual void driver_start() override ATTR_COLD;
|
||||
|
||||
void render_w(int state);
|
||||
|
||||
required_device<h83048_device> m_maincpu;
|
||||
required_device<gt155_device> m_gt155;
|
||||
required_device<hd44780_device> m_lcdc;
|
||||
optional_device<hd63266f_device> m_fdc;
|
||||
optional_device<floppy_connector> 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;
|
||||
};
|
||||
|
||||
class wk1600_state : public wk1800_state
|
||||
{
|
||||
public:
|
||||
static constexpr feature_type unemulated_features() { return feature::NONE; }
|
||||
|
||||
using wk1800_state::wk1800_state;
|
||||
};
|
||||
|
||||
/**************************************************************************/
|
||||
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<int StartBit>
|
||||
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, 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");
|
||||
}
|
||||
|
||||
/**************************************************************************/
|
||||
void wk1800_state::wk1800_map(address_map &map)
|
||||
{
|
||||
map(0x00000, 0x1ffff).rom();
|
||||
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, FUNC(hd63266f_device::dma_r), FUNC(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);
|
||||
|
||||
#if 0
|
||||
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");
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
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, wk1600_state, empty_init, "Casio", "WK-1600", MACHINE_SUPPORTS_SAVE )
|
@ -16219,6 +16219,10 @@ sk10
|
||||
@source:casio/sx1000.cpp
|
||||
sx1010
|
||||
|
||||
@source:casio/wk1800.cpp
|
||||
wk1600 // 2000 Casio
|
||||
wk1800 // 2000 Casio
|
||||
|
||||
@source:casio/zoomer.cpp
|
||||
zoomer
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user