Skip to content

Add skeleton for Casio CPS-2000 #13591

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 16, 2025
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 23 additions & 7 deletions src/devices/machine/msm6200.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ msm6200_device::msm6200_device(const machine_config &mconfig, const char *tag, d
/**************************************************************************/
void msm6200_device::device_start()
{
m_timer = timer_alloc(FUNC(msm6200_device::scan_timer), this);

m_cmd = 0xf;

save_item(NAME(m_cmd));
Expand All @@ -39,6 +41,18 @@ void msm6200_device::device_reset()
std::fill(std::begin(m_last_state), std::end(m_last_state), 0);
}

/**************************************************************************/
TIMER_CALLBACK_MEMBER(msm6200_device::scan_timer)
{
(++m_row) %= m_keys.size();
m_key_state = m_keys[m_row].read_safe(0);
if (m_key_state != m_last_state[m_row])
{
m_irq_cb(1);
m_timer->adjust(attotime::never);
}
}

/**************************************************************************/
void msm6200_device::write(offs_t offset, u8 data)
{
Expand All @@ -60,30 +74,32 @@ void msm6200_device::write(offs_t offset, u8 data)
}
}
if (m_key_state == m_last_state[m_row])
{
m_irq_cb(0);
m_timer->adjust(attotime::zero, 0, attotime::from_ticks(TIMER_RATE, clock()));
}
break;

case 1: // read velocity
m_key_data = m_velocity.read_safe(0x3f);
break;

case 2: // next row?
(++m_row) %= m_keys.size();
case 2:
// TODO: what should this one actually be?
// the cz1/ht6000 key MCU code outputs the result to port 1 for debugging
m_key_data = m_row;
break;

case 7: // capture current row?
m_key_state = m_keys[m_row].read_safe(0);
if (m_key_state != m_last_state[m_row])
m_irq_cb(1);
case 7: // ?
// cz1/ht6000 writes this constantly, cps2000 much less frequently
break;

case 8: // init all rows
case 8: // init all rows, start scanning
for (int i = 0; i < m_keys.size(); i++)
m_last_state[i] = m_keys[i].read_safe(0);

m_irq_cb(0);
m_timer->adjust(attotime::zero, 0, attotime::from_ticks(TIMER_RATE, clock()));
break;

default:
Expand Down
6 changes: 6 additions & 0 deletions src/devices/machine/msm6200.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,17 @@ class msm6200_device : public device_t
virtual void device_reset() override ATTR_COLD;

private:
static constexpr unsigned TIMER_RATE = 256; // arbitrary

TIMER_CALLBACK_MEMBER(scan_timer);

optional_ioport_array<38> m_keys;
optional_ioport m_velocity;

devcb_write_line m_irq_cb;

emu_timer *m_timer;

u8 m_cmd, m_row, m_key_data;
u8 m_key_state;
u8 m_last_state[38];
Expand Down
45 changes: 25 additions & 20 deletions src/devices/sound/upd934g.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ void upd934g_device::device_start()
m_stream = stream_alloc(0, 4, 20000);

// register for save states
save_pointer(NAME(m_addr), 16);
save_item(NAME(m_addr));
save_item(NAME(m_valid));

save_item(STRUCT_MEMBER(m_channel, pos));
save_item(STRUCT_MEMBER(m_channel, playing));
Expand All @@ -71,8 +72,15 @@ void upd934g_device::device_reset()
{
m_ready = false;

for (unsigned i = 0; i < 16; i++)
m_addr[i] = m_valid[i] = 0;

for (unsigned i = 0; i < 4; i++)
{
m_channel[i].pos = 0;
m_channel[i].playing = -1;
m_channel[i].effect = 0;
}
}

//-------------------------------------------------
Expand All @@ -86,14 +94,15 @@ void upd934g_device::sound_stream_update(sound_stream &stream, std::vector<read_
{
if (m_ready && m_channel[ch].playing != -1)
{
uint16_t end = m_addr[m_channel[ch].playing + 1] - 1;
uint16_t end = m_addr[(m_channel[ch].playing + 1) & 0xf] - 1;

for (unsigned i = 0; i < outputs[ch].samples(); i++)
{
int16_t raw = static_cast<int8_t>(read_byte(m_channel[ch].pos)) * 4;

// normal, muted, accented
const double adjust[] = { 0, 0.7, 0.4, 1.0 };
// TODO: cps2000 regularly sets effect bits to 0 instead of 2 - are these the same?
const double adjust[] = { 0.4, 0.7, 0.4, 1.0 };
raw *= adjust[m_channel[ch].effect];

outputs[ch].put_int(i, raw, 32768 / 64);
Expand All @@ -118,38 +127,34 @@ void upd934g_device::sound_stream_update(sound_stream &stream, std::vector<read_

void upd934g_device::write(offs_t offset, uint8_t data)
{
switch (offset)
switch (offset & 3)
{
case 0:
// format of data written here is:
// 76------ command
// 76------ effect
// --5432-- sample number
// ------10 output channel
m_sample = (data >> 2) & 0x0f;

switch (data >> 6)
// don't play a sample unless we're sure it's actually supposed to play:
// - all models write this with effect=0 to select which sample to set the address of
// - cps2000 writes this with effect=0 to play muted(?) samples
// - cps2000 also writes this with effect=1 and sample=f on boot even though there are only 12 valid samples
if (m_valid[m_sample])
{
case 0:
LOG("CMD STORE ADDRESS sample %x\n", m_sample);
break;
case 1: // normal
case 2: // muted
case 3: // accented
{
const u8 ch = (data & 3) ^ 2; // effective order seems to be "2, 3, 0, 1"
LOG("CMD PLAY sample %x (channel %d, effect %d)\n", m_sample, ch, data >> 6);
m_channel[ch].pos = m_addr[m_sample];
m_channel[ch].playing = m_sample;
m_channel[ch].effect = data >> 6;
}
break;
const u8 ch = (data & 3) ^ 2; // effective order seems to be "2, 3, 0, 1"
LOG("CMD PLAY sample %x (channel %d, effect %d)\n", m_sample, ch, data >> 6);
m_channel[ch].pos = m_addr[m_sample];
m_channel[ch].playing = m_sample;
m_channel[ch].effect = data >> 6;
}
break;
case 1:
m_addr[m_sample] = (m_addr[m_sample] & 0xff00) | (data << 0);
break;
case 2:
m_addr[m_sample] = (m_addr[m_sample] & 0x00ff) | (data << 8);
m_valid[m_sample] = 1;
LOG(" sample %x address = %04x\n", m_sample, m_addr[m_sample]);
break;
case 3:
Expand Down
15 changes: 8 additions & 7 deletions src/devices/sound/upd934g.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ class upd934g_device : public device_t, public device_sound_interface, public de
// construction/destruction
upd934g_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

void write(offs_t offset, uint8_t data);
void write(offs_t offset, u8 data);

protected:
// device-level overrides
Expand All @@ -39,18 +39,19 @@ class upd934g_device : public device_t, public device_sound_interface, public de
private:
sound_stream *m_stream;

uint16_t m_addr[16];
u16 m_addr[16];
u8 m_valid[16];

struct
{
uint16_t pos;
int playing;
int effect;
u16 pos;
s8 playing;
u8 effect;
}
m_channel[4];

int m_sample;
bool m_ready;
u8 m_sample;
u8 m_ready;
};

// device type definition
Expand Down
1 change: 1 addition & 0 deletions src/emu/xtal.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,7 @@ const double XTAL::known_xtals[] = {
4'433'619, // 4.433619_MHz_XTAL PAL color subcarrier (technically 4.43361875mhz)
4'608'000, // 4.608_MHz_XTAL Luxor ABC-77 keyboard (Keytronic custom part #48-300-107 is equivalent)
4'915'200, // 4.9152_MHz_XTAL -
4'946'800, // 4.9468_MHz_XTAL Casio CPS-2000
4'946'864, // 4.946864_MHz_XTAL Casiotone 8000
4'952'000, // 4.952_MHz_XTAL IGS M036 based mahjong games, for TT5665 sound chip
5'000'000, // 5_MHz_XTAL Mutant Night
Expand Down
Loading
Loading