ctk551: implement sound, promote to working (#8960)

This commit is contained in:
Devin Acker 2021-12-14 10:25:57 -05:00 committed by GitHub
parent 6d9b8c9c75
commit 7ce27dadde
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 340 additions and 99 deletions

View File

@ -11,7 +11,7 @@
- Two timers, three 8-bit ports, two 8-bit ADCs - Two timers, three 8-bit ports, two 8-bit ADCs
- Keyboard controller w/ key velocity detection - Keyboard controller w/ key velocity detection
- MIDI UART - MIDI UART
- 24-voice PCM sound (currently not emulated / fully understood) - 24-voice DPCM sound
Earlier and later Casio keyboard models contain "uPD912" and "uPD914" chips, Earlier and later Casio keyboard models contain "uPD912" and "uPD914" chips,
which are presumably similar. which are presumably similar.
@ -52,9 +52,9 @@ void gt913_device::map(address_map &map)
map(0xfac0, 0xffbf).ram(); // CTK-551 zeroes out this range at $0418 map(0xfac0, 0xffbf).ram(); // CTK-551 zeroes out this range at $0418
/* ffc0-ffcb: sound */ /* ffc0-ffcb: sound */
map(0xffc0, 0xffc5).rw(m_sound, FUNC(gt913_sound_hle_device::data_r), FUNC(gt913_sound_hle_device::data_w)); map(0xffc0, 0xffc5).rw(m_sound, FUNC(gt913_sound_device::data_r), FUNC(gt913_sound_device::data_w));
map(0xffc6, 0xffc7).w(m_sound, FUNC(gt913_sound_hle_device::command_w)); map(0xffc6, 0xffc7).w(m_sound, FUNC(gt913_sound_device::command_w));
map(0xffca, 0xffcb).r(m_sound, FUNC(gt913_sound_hle_device::status_r)); map(0xffca, 0xffcb).r(m_sound, FUNC(gt913_sound_device::status_r));
/* ffd0-ffd5: key controller */ /* ffd0-ffd5: key controller */
map(0xffd0, 0xffd1).r(m_kbd, FUNC(gt913_kbd_hle_device::read)); map(0xffd0, 0xffd1).r(m_kbd, FUNC(gt913_kbd_hle_device::read));
@ -88,7 +88,14 @@ void gt913_device::device_add_mconfig(machine_config &config)
{ {
GT913_INTC(config, "intc"); GT913_INTC(config, "intc");
GT913_SOUND_HLE(config, m_sound, 0); /*
generate sound at 104 cycles per sample (= 144.231 kHz sample clock to the DAC)
on keyboard models that include a DSP, this also results in a multiple
of the 36.058 kHz CPU->DSP sync signal shown in some schematics (WK-1200 and others)
*/
GT913_SOUND(config, m_sound, std::round(clock() / 104.0f));
m_sound->set_device_rom_tag(tag());
GT913_KBD_HLE(config, m_kbd, 0); GT913_KBD_HLE(config, m_kbd, 0);
m_kbd->irq_cb().set([this](int val) { if (val) m_intc->internal_interrupt(5); }); m_kbd->irq_cb().set([this](int val) { if (val) m_intc->internal_interrupt(5); });
GT913_IO_HLE(config, m_io_hle, "intc", 6, 7); GT913_IO_HLE(config, m_io_hle, "intc", 6, 7);
@ -102,7 +109,7 @@ void gt913_device::device_add_mconfig(machine_config &config)
void gt913_device::uart_rate_w(uint8_t data) void gt913_device::uart_rate_w(uint8_t data)
{ {
m_sci->brr_w(data >> 1); m_sci->brr_w(data >> 2);
} }
void gt913_device::uart_control_w(uint8_t data) void gt913_device::uart_control_w(uint8_t data)

View File

@ -62,7 +62,7 @@ protected:
required_device<gt913_intc_device> m_intc; required_device<gt913_intc_device> m_intc;
/* sound */ /* sound */
required_device<gt913_sound_hle_device> m_sound; required_device<gt913_sound_device> m_sound;
/* key controller */ /* key controller */
required_device<gt913_kbd_hle_device> m_kbd; required_device<gt913_kbd_hle_device> m_kbd;

View File

@ -107,7 +107,7 @@
5e00 ff00 0 bsr rel8 - 5e00 ff00 0 bsr rel8 -
5f00 fff0 0 mov.w imm16 r16l 5f00 fff0 0 mov.w imm16 r16l
66000000 ff00ff8f 0 btst imm3 abs8 66000000 ff00ff8f 0 btst imm3 r16ihh
6800 ff80 0 mov.b r16ih r8l 6800 ff80 0 mov.b r16ih r8l
6900 ff88 0 mov.w r16ih r16l 6900 ff88 0 mov.w r16ih r16l

View File

@ -108,9 +108,9 @@ void gt913_io_hle_device::timer_adjust(offs_t num)
logerror("unknown timer %u prescaler %u (pc = %04x)\n", num, m_timer_control[num] & 0x7, m_cpu->pc()); logerror("unknown timer %u prescaler %u (pc = %04x)\n", num, m_timer_control[num] & 0x7, m_cpu->pc());
[[fallthrough]]; [[fallthrough]];
case 0: case 0:
clocks <<= 1; break; break;
case 2: case 2:
clocks <<= 10; break; clocks <<= 9; break;
} }
attotime period = m_cpu->clocks_to_attotime(clocks); attotime period = m_cpu->clocks_to_attotime(clocks);

View File

@ -8,13 +8,13 @@
which is then input to either a serial DAC or a HG51B-based DSP, which is then input to either a serial DAC or a HG51B-based DSP,
depending on the model of keyboard. depending on the model of keyboard.
Currently, the actual sample format in ROM is unknown. The sample format, as well as other details such as the linear interpolation,
The serial output is twos-complement 16-bit PCM, but the data in ROM are covered in these two Japanese patents:
doesn't seem to be - reading it as such produces sounds that are https://patents.google.com/patent/JP3603343B2/en
somewhat recognizable, but highly distorted. https://patents.google.com/patent/JPH07199996A/en
For now, all known (and unknown) register writes are just logged TODO: Volume envelope rates still need adjusting.
without generating any sound. (See comment in gt913_sound_device::command_w regarding command 6007)
***************************************************************************/ ***************************************************************************/
@ -26,140 +26,319 @@
// DEVICE DEFINITIONS // DEVICE DEFINITIONS
//************************************************************************** //**************************************************************************
DEFINE_DEVICE_TYPE(GT913_SOUND_HLE, gt913_sound_hle_device, "gt913_sound_hle", "Casio GT913F sound (HLE)") DEFINE_DEVICE_TYPE(GT913_SOUND, gt913_sound_device, "gt913_sound_hle", "Casio GT913F sound")
gt913_sound_hle_device::gt913_sound_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : // expand 2-bit exponent deltas
device_t(mconfig, GT913_SOUND_HLE, tag, owner, clock) const u8 gt913_sound_device::exp_2_to_3[4] = { 0, 1, 2, 7 };
// sign-extend 7-bit sample deltas
const s8 gt913_sound_device::sample_7_to_8[128] =
{
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
-64, -63, -62, -61, -60, -59, -58, -57, -56, -55, -54, -53, -52, -51, -50, -49,
-48, -47, -46, -45, -44, -43, -42, -41, -40, -39, -38, -37, -36, -35, -34, -33,
-32, -31, -30, -29, -28, -27, -26, -25, -24, -23, -22, -21, -20, -19, -18, -17,
-16, -15, -14, -13, -12, -11, -10, -9, -8, -7, -6, -5, -4, -3, -2, -1
};
gt913_sound_device::gt913_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, GT913_SOUND, tag, owner, clock)
, device_sound_interface(mconfig, *this)
, device_rom_interface(mconfig, *this)
{ {
} }
void gt913_sound_hle_device::device_start() void gt913_sound_device::device_start()
{ {
m_stream = stream_alloc(0, 2, clock());
save_item(NAME(m_gain)); save_item(NAME(m_gain));
save_item(NAME(m_data)); save_item(NAME(m_data));
save_item(NAME(m_volume_target)); save_item(STRUCT_MEMBER(m_voices, m_enable));
save_item(NAME(m_volume_rate));
save_item(STRUCT_MEMBER(m_voices, m_addr_start));
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_current));
save_item(STRUCT_MEMBER(m_voices, m_addr_frac));
save_item(STRUCT_MEMBER(m_voices, m_pitch));
save_item(STRUCT_MEMBER(m_voices, m_sample));
save_item(STRUCT_MEMBER(m_voices, m_sample_next));
save_item(STRUCT_MEMBER(m_voices, m_exp));
save_item(STRUCT_MEMBER(m_voices, m_volume_current));
save_item(STRUCT_MEMBER(m_voices, m_volume_target));
save_item(STRUCT_MEMBER(m_voices, m_volume_rate));
save_item(STRUCT_MEMBER(m_voices, m_volume_end));
save_item(STRUCT_MEMBER(m_voices, m_balance));
save_item(STRUCT_MEMBER(m_voices, m_gain));
} }
void gt913_sound_hle_device::device_reset() void gt913_sound_device::device_reset()
{ {
m_gain = 0; m_gain = 0;
std::memset(m_data, 0, sizeof(m_data)); std::memset(m_data, 0, sizeof(m_data));
std::memset(m_volume_target, 0, sizeof(m_volume_target));
std::memset(m_volume_rate, 0, sizeof(m_volume_rate)); std::memset(m_voices, 0, sizeof(m_voices));
} }
void gt913_sound_hle_device::data_w(offs_t offset, uint16_t data) void gt913_sound_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);
}
outputs[0].put_int_clamp(i, (left * m_gain) >> 26, 32678);
outputs[1].put_int_clamp(i, (right * m_gain) >> 26, 32768);
}
}
void gt913_sound_device::rom_bank_updated()
{
m_stream->update();
}
void gt913_sound_device::mix_sample(voice_t& voice, s64& left, s64& right)
{
// update sample position
voice.m_addr_frac += voice.m_pitch;
while (voice.m_addr_frac >= (1 << 25))
{
voice.m_addr_frac -= (1 << 25);
update_sample(voice);
}
// update volume envelope
if (voice.m_volume_target > voice.m_volume_current
&& (voice.m_volume_target - voice.m_volume_current) > voice.m_volume_rate)
{
voice.m_volume_current += voice.m_volume_rate;
}
else if (voice.m_volume_target < voice.m_volume_current
&& (voice.m_volume_current - voice.m_volume_target) > voice.m_volume_rate)
{
voice.m_volume_current -= voice.m_volume_rate;
}
else
{
voice.m_volume_current = voice.m_volume_target;
}
// interpolate, apply envelope + channel gain, and mix into output
const u8 step = (voice.m_addr_frac >> 22) & 7;
const u8 env = (voice.m_volume_current >> 24);
/*
the current envelope level effects amplitude non-linearly, just apply the value twice
(this hardware family is branded as "A² (A-Square) Sound Source" in some of Casio's
promotional materials, possibly for this reason?)
*/
const s64 sample = ((s64)voice.m_sample + (voice.m_sample_next * step / 8)) * voice.m_gain * env * env;
left += sample * voice.m_balance[0];
right += sample * voice.m_balance[1];
}
void gt913_sound_device::update_sample(voice_t& voice)
{
voice.m_sample += voice.m_sample_next;
if (voice.m_addr_current == (voice.m_addr_loop | 1))
{
/*
The last 12 bytes of each sample are a table containing five sample and exponent value pairs
for the data words immediately after the loop point. The first pair corresponds to what the
sample and exponent value will be _after_ processing the first word after the loop,
so once we've reached that point, use those values to reload the current sample and exponent
*/
const u32 addr_loop_data = (voice.m_addr_end + 1) & ~1;
voice.m_sample_next = read_word(addr_loop_data) - voice.m_sample;
voice.m_exp = read_word(addr_loop_data + 10) & 7;
}
else
{
/*
For all other samples, just get the next sample delta value.
For even-numbered samples, also update the exponent/shift value.
*/
const u16 word = read_word(voice.m_addr_current & ~1);
s16 delta = 0;
if (!BIT(voice.m_addr_current, 0))
{
voice.m_exp += exp_2_to_3[word & 3];
voice.m_exp &= 7;
delta = sample_7_to_8[(word >> 2) & 0x7f];
}
else
{
delta = sample_7_to_8[word >> 9];
}
voice.m_sample_next = delta * (1 << voice.m_exp);
}
voice.m_addr_current++;
if (voice.m_addr_current == voice.m_addr_end)
{
voice.m_addr_current = voice.m_addr_loop;
if (voice.m_addr_loop == voice.m_addr_end)
voice.m_enable = false;
}
}
void gt913_sound_device::data_w(offs_t offset, u16 data)
{ {
assert(offset < 3); assert(offset < 3);
m_data[offset] = data; m_data[offset] = data;
} }
uint16_t gt913_sound_hle_device::data_r(offs_t offset) u16 gt913_sound_device::data_r(offs_t offset)
{ {
assert(offset < 3); assert(offset < 3);
return m_data[offset]; return m_data[offset];
} }
void gt913_sound_hle_device::command_w(uint16_t data) void gt913_sound_device::command_w(u16 data)
{ {
uint8_t voicenum = (data & 0x1f00) >> 8; m_stream->update();
uint16_t voicecmd = data & 0x60ff;
const uint8_t voicenum = (data & 0x1f00) >> 8;
const uint16_t voicecmd = data & 0x60ff;
if (data == 0x0012) if (data == 0x0012)
{ {
uint8_t gain = m_data[0] & 0x3f; m_gain = m_data[0] & 0x3f;
if (gain != m_gain) return;
logerror("gain %u\n", gain);
m_gain = gain;
} }
else if (voicenum >= 24) else if (voicenum >= 24)
{ {
return; return;
} }
else if (voicecmd == 0x0008)
auto& voice = m_voices[voicenum];
if (voicecmd == 0x0008)
{ {
/* /*
Set the voice's sample start point as a ROM address. sample start addresses seem to need to be word-aligned to decode properly
This is usually word-aligned, but not always (see: ctk551 "Trumpet" patch, which will have a bad exponent value otherwise)
(e.g. ctk551's lowest piano sample is at address 0x5a801) this apparently doesn't apply to end/loop addresses, though, or else samples
may loop badly or even become noticeably detuned
TODO: is the LSB of start addresses supposed to indicate something else, then?
*/ */
uint32_t samplestart = (m_data[1] | (m_data[2] << 16)) & 0x1fffff; voice.m_addr_start = (m_data[1] | (m_data[2] << 16)) & 0x1ffffe;
logerror("voice %u sample start 0x%06x\n", voicenum, samplestart);
} }
else if (voicecmd == 0x0000) else if (voicecmd == 0x0000)
{ {
/* voice.m_addr_end = (m_data[0] | (m_data[1] << 16)) & 0x1fffff;
Set the voice's sample end point as a ROM address.
*/
uint32_t sampleend = (m_data[0] | (m_data[1] << 16)) & 0x1fffff;
logerror("voice %u sample end 0x%06x\n", voicenum, sampleend);
} }
else if (voicecmd == 0x2000) else if (voicecmd == 0x2000)
{ {
/* voice.m_addr_loop = (m_data[0] | (m_data[1] << 16)) & 0x1fffff;
Set the voice's sample loop point as a ROM address.
*/
uint32_t sampleloop = (m_data[0] | (m_data[1] << 16)) & 0x1fffff;
logerror("voice %u sample loop 0x%06x\n", voicenum, sampleloop);
} }
else if (voicecmd == 0x200a) else if (voicecmd == 0x200a)
{ {
logerror("voice %u cmd 0x200a (data = %02x)\n", voicenum, m_data[2] & 0xff); /* TODO: what does bit 4 of data[2] do? ctk551 sets it unconditionally */
voice.m_exp = m_data[2] & 7;
} }
else if (voicecmd == 0x200b) else if (voicecmd == 0x200b)
{ {
/* bool enable = BIT(m_data[2], 7);
Turn this voice on/off. if (enable && !m_voices[voicenum].m_enable)
ctk551 turns output off before assigning a new note or instrument to this voice, {
then turns output back on afterward voice.m_addr_current = voice.m_addr_start;
*/ voice.m_addr_frac = 0;
logerror("voice %u output %s\n", voicenum, BIT(m_data[2], 7) ? "on" : "off"); voice.m_sample = 0;
}
voice.m_enable = enable;
voice.m_volume_end &= enable;
} }
else if (voicecmd == 0x4004) else if (voicecmd == 0x4004)
{ {
/* voice.m_balance[0] = (m_data[1] & 0xe0) >> 5;
Set this voice's panning, in the form of left and right volume levels (3 bits each) voice.m_balance[1] = (m_data[1] & 0x1c) >> 2;
*/
uint8_t left = (m_data[1] & 0xe0) >> 5;
uint8_t right = (m_data[1] & 0x1c) >> 2;
logerror("voice %u left %u right %u\n", voicenum, left, right);
} }
else if (voicecmd == 0x4005) else if (voicecmd == 0x4005)
{ {
/* /*
Set the current pitch of this voice. for pitch, data[1] apparently contains both the most and least significant of 4 bytes,
The actual format of the value is unknown, but presumably some kind of fixed point with data0 in the middle. strange, but apparently correct (see higher octaves of ctk551 E.Piano2)
*/ */
uint32_t pitch = (m_data[0] << 8) | (m_data[1] >> 8); voice.m_pitch = (m_data[1] << 24) | (m_data[0] << 8) | (m_data[1] >> 8);
logerror("voice %u pitch 0x%06x\n", voicenum, pitch);
} }
else if (voicecmd == 0x6006) else if (voicecmd == 0x6006)
{ {
logerror("voice %u cmd 0x6006 (data = %02x)\n", voicenum, m_data[1] & 0xff); /*
per-voice gain used for normalizing samples
currently treated such that the lower 3 bits are fractional
*/
voice.m_gain = m_data[1] & 0xff;
} }
else if (voicecmd == 0x6007) else if (voicecmd == 0x6007)
{ {
logerror("voice %u volume %u rate %u\n", voicenum, (m_data[0] >> 8), m_data[0] & 0xff);
/* /*
Raise or lower the volume to a specified level at a specified rate. only set a new volume level/rate if we haven't previously indicated the end of an envelope,
The actual volume level is probably 7.8 fixed point or something like that, but this command unless the new level also has the high bit set. otherwise, a timer irq may try to update the
only sets the most significant bits. normal envelope while other code is trying to force a note off
*/ */
logerror("voice %u volume %u rate %u\n", voicenum, (m_data[0] >> 8) & 0x7f, m_data[0] & 0xff); const bool end = BIT(m_data[0], 15);
m_volume_target[voicenum] = m_data[0] & 0x7f00; if (!voice.m_volume_end || end)
m_volume_rate[voicenum] = m_data[0] & 0xff; {
voice.m_volume_end = end;
voice.m_volume_target = (m_data[0] & 0x7f00) << 16;
/*
In addition to volume levels applying non-linearly, envelope rates
are also non-linear. Unfortunately, with the ctk-551's limited patch set and
lack of editing features, figuring out the correct behavior isn't easy.
This is essentially a rough estimate until a higher-end model (ctk-601 series, etc)
can be dumped and used for more detailed testing.
*/
const u8 x = m_data[0] & 0xff;
if (x >= 127)
voice.m_volume_rate = x << 21;
else if (x >= 63)
voice.m_volume_rate = x << 16;
else if (x >= 47)
voice.m_volume_rate = x << 14;
else if (x >= 31)
voice.m_volume_rate = x << 11;
else if (x >= 23)
voice.m_volume_rate = x << 9;
else if (x >= 15)
voice.m_volume_rate = x << 7;
else
voice.m_volume_rate = x << 5;
}
} }
else if (voicecmd == 0x2028) else if (voicecmd == 0x2028)
{ {
/* /*
ctk551 issues this command and then reads the voice's current volume from data0 ctk551 issues this command and then reads the voice's current volume from data0
to determine if it's time to start the next part of the volume envelope or not. to determine if it's time to start the next part of the volume envelope or not.
For now, just return the "target" volume immediately
(TODO: also figure out what it expects to be returned in data1)
*/ */
m_data[0] = m_volume_target[voicenum]; m_data[0] = voice.m_enable ? (voice.m_volume_current >> 16) : 0;
m_data[1] = 0; /*
data1 is used to read consecutive output sample and detect zero crossings when
applying volume or expression changes to a MIDI channel
*/
m_data[1] = voice.m_sample;
} }
else else
{ {
@ -167,9 +346,11 @@ void gt913_sound_hle_device::command_w(uint16_t data)
} }
} }
uint16_t gt913_sound_hle_device::status_r() u16 gt913_sound_device::status_r()
{ {
/* ctk551 reads the current gain level out of the lower 6 bits and ignores the rest /*
it's unknown what, if anything, the other bits are supposed to contain */ ctk551 reads the current gain level out of the lower 6 bits and ignores the rest
it's unknown what, if anything, the other bits are supposed to contain
*/
return m_gain & 0x3f; return m_gain & 0x3f;
} }

View File

@ -9,37 +9,78 @@
#pragma once #pragma once
#include "dirom.h"
//************************************************************************** //**************************************************************************
// TYPE DEFINITIONS // TYPE DEFINITIONS
//************************************************************************** //**************************************************************************
// ======================> gt913_sound_hle_device // ======================> gt913_sound_device
class gt913_sound_hle_device : public device_t class gt913_sound_device : public device_t,
public device_sound_interface,
public device_rom_interface<21, 1, 0, ENDIANNESS_BIG>
{ {
public: public:
// construction/destruction static constexpr feature_type imperfect_features() { return feature::SOUND; }
gt913_sound_hle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0);
void data_w(offs_t offset, uint16_t data); // construction/destruction
uint16_t data_r(offs_t offset); gt913_sound_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock = 0);
void command_w(uint16_t data);
uint16_t status_r(); void data_w(offs_t offset, u16 data);
u16 data_r(offs_t offset);
void command_w(u16 data);
u16 status_r();
protected: protected:
// device_t overrides // device_t overrides
virtual void device_start() override; virtual void device_start() override;
virtual void device_reset() override; virtual void device_reset() override;
private: // device_sound_interface overrides
uint8_t m_gain; virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
uint16_t m_data[3];
uint16_t m_volume_target[24]; // device_rom_interface overrides
uint8_t m_volume_rate[24]; virtual void rom_bank_updated() override;
private:
sound_stream *m_stream;
u8 m_gain;
u16 m_data[3];
static const u8 exp_2_to_3[4];
static const s8 sample_7_to_8[128];
struct voice_t
{
bool m_enable;
u32 m_addr_start;
u32 m_addr_end;
u32 m_addr_loop;
u32 m_addr_current;
u32 m_addr_frac, m_pitch;
s16 m_sample, m_sample_next;
u8 m_exp;
u32 m_volume_current, m_volume_target;
u32 m_volume_rate;
bool m_volume_end;
u8 m_balance[2];
u8 m_gain;
};
void mix_sample(voice_t& voice, s64& left, s64& right);
void update_sample(voice_t& voice);
voice_t m_voices[24];
}; };
// device type definition // device type definition
DECLARE_DEVICE_TYPE(GT913_SOUND_HLE, gt913_sound_hle_device) DECLARE_DEVICE_TYPE(GT913_SOUND, gt913_sound_device)
#endif // MAME_AUDIO_GT913_H #endif // MAME_AUDIO_GT913_H

View File

@ -53,6 +53,7 @@
#include "video/hd44780.h" #include "video/hd44780.h"
#include "emupal.h" #include "emupal.h"
#include "screen.h" #include "screen.h"
#include "speaker.h"
namespace { namespace {
@ -64,6 +65,7 @@ public:
, m_maincpu(*this, "maincpu") , m_maincpu(*this, "maincpu")
, m_lcdc(*this, "lcdc") , m_lcdc(*this, "lcdc")
, m_led_touch(*this, "led_touch") , m_led_touch(*this, "led_touch")
, m_led_power(*this, "led_power")
{ {
} }
@ -90,6 +92,7 @@ private:
required_device<hd44780_device> m_lcdc; required_device<hd44780_device> m_lcdc;
output_finder<> m_led_touch; output_finder<> m_led_touch;
output_finder<> m_led_power;
ioport_value m_switch; ioport_value m_switch;
}; };
@ -97,7 +100,6 @@ private:
INPUT_CHANGED_MEMBER(ctk551_state::switch_w) INPUT_CHANGED_MEMBER(ctk551_state::switch_w)
{ {
logerror("switch_w: %x\n", param);
if (!oldval && newval) if (!oldval && newval)
{ {
if (m_switch == 0x1 && param != m_switch) if (m_switch == 0x1 && param != m_switch)
@ -112,8 +114,11 @@ INPUT_CHANGED_MEMBER(ctk551_state::switch_w)
WRITE_LINE_MEMBER(ctk551_state::apo_w) WRITE_LINE_MEMBER(ctk551_state::apo_w)
{ {
logerror("apo_w: %x\n", state); logerror("apo_w: %x\n", state);
/* TODO: when 1, this should turn off the LCD, speakers, etc. /* auto power off - disable the LCD
the CPU will go to sleep until the power switch triggers a NMI */ the CPU will go to sleep until the power switch triggers a NMI */
if (state)
m_lcdc->reset();
m_led_power = !state;
} }
HD44780_PIXEL_UPDATE(ctk551_state::lcd_update) HD44780_PIXEL_UPDATE(ctk551_state::lcd_update)
@ -140,6 +145,7 @@ void ctk551_state::ctk551_io_map(address_map &map)
void ctk551_state::driver_start() void ctk551_state::driver_start()
{ {
m_led_touch.resolve(); m_led_touch.resolve();
m_led_power.resolve();
m_switch = 0x2; m_switch = 0x2;
@ -149,8 +155,11 @@ void ctk551_state::driver_start()
void ctk551_state::ctk551(machine_config &config) void ctk551_state::ctk551(machine_config &config)
{ {
// CPU // CPU
GT913(config, m_maincpu, 30'000'000); // 30MHz oscillator, divided down internally (otherwise the test mode's OK/NG sounds play at double speed)
GT913(config, m_maincpu, 30'000'000 / 2);
m_maincpu->set_addrmap(AS_IO, &ctk551_state::ctk551_io_map); m_maincpu->set_addrmap(AS_IO, &ctk551_state::ctk551_io_map);
m_maincpu->subdevice<gt913_sound_device>("gt_sound")->add_route(0, "lspeaker", 1.0);
m_maincpu->subdevice<gt913_sound_device>("gt_sound")->add_route(1, "rspeaker", 1.0);
// MIDI // MIDI
auto &mdin(MIDI_PORT(config, "mdin")); auto &mdin(MIDI_PORT(config, "mdin"));
@ -177,6 +186,9 @@ void ctk551_state::ctk551(machine_config &config)
screen.set_palette("palette"); screen.set_palette("palette");
PALETTE(config, "palette", FUNC(ctk551_state::palette_init), 2); PALETTE(config, "palette", FUNC(ctk551_state::palette_init), 2);
SPEAKER(config, "lspeaker").front_left();
SPEAKER(config, "rspeaker").front_right();
} }
INPUT_PORTS_START(ctk551) INPUT_PORTS_START(ctk551)
@ -356,4 +368,4 @@ ROM_END
} // anonymous namespace } // anonymous namespace
// YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS
SYST( 1999, ctk551, 0, 0, ctk551, ctk551, ctk551_state, empty_init, "Casio", "CTK-551", MACHINE_NO_SOUND | MACHINE_NOT_WORKING | MACHINE_SUPPORTS_SAVE ) SYST( 1999, ctk551, 0, 0, ctk551, ctk551, ctk551_state, empty_init, "Casio", "CTK-551", MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )