From 1e79fda5b22726ea3389e3f61cb6c40ae92d3fb6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C3=ABl=20Banaan=20Ananas?= Date: Wed, 9 May 2012 21:10:28 +0000 Subject: [PATCH] preliminary Toshiba TC8830F emulation [hap] --- src/emu/sound/tc8830f.c | 157 ++++++++++++++++++++++++++++++++++++- src/emu/sound/tc8830f.h | 15 +++- src/mame/drivers/timeplt.c | 6 +- 3 files changed, 169 insertions(+), 9 deletions(-) diff --git a/src/emu/sound/tc8830f.c b/src/emu/sound/tc8830f.c index 29be3fc7a70..7426d889996 100644 --- a/src/emu/sound/tc8830f.c +++ b/src/emu/sound/tc8830f.c @@ -1,13 +1,15 @@ /*************************************************************************** tc8830f.c - Toshiba TC8830F, CMOS voice recording/reproducing LSI + 1-bit ADM (Adaptive Delta Modulation), similar to TC8801 and T6668. Very preliminary... TODO: + - ADM decoder - remaining commands - - cpu manual mode - - status read + - manual control + - chip read - RAM - recording @@ -35,26 +37,173 @@ void tc8830f_device::device_start() m_mem_base = (UINT8 *)device().machine().root_device().memregion(":tc8830f")->base(); m_mem_mask = device().machine().root_device().memregion(":tc8830f")->bytes() - 1; + // register for savestates + save_item(NAME(m_playing)); + save_item(NAME(m_address)); + save_item(NAME(m_stop_address)); + save_item(NAME(m_bitcount)); + save_item(NAME(m_bitrate)); + save_item(NAME(m_command)); + save_item(NAME(m_cmd_rw)); + save_item(NAME(m_phrase)); + reset(); } +void tc8830f_device::device_post_load() +{ + device_clock_changed(); +} + + +void tc8830f_device::device_clock_changed() +{ + int divisor = 0x10 * (4 - (m_bitrate & 3)); + m_stream->set_sample_rate(clock() / divisor); +} + + + void tc8830f_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) { for (int i = 0; i < samples; i++) { - outputs[0][i] = 0; + int mix = 0; + if (m_playing) + { + // get bit + int bit = m_mem_base[m_address] >> m_bitcount & 1; + m_bitcount = (m_bitcount + 1) & 7; + if (m_bitcount == 0) + { + m_address = (m_address + 1) & m_mem_mask; + if (m_address == m_stop_address) + m_playing = false; + } + + // compute sample + // this is a placeholder until ADM is implemented + mix = bit * 0x7fff; + } + outputs[0][i] = mix; } } void tc8830f_device::reset() { - ; + m_stream->update(); + + m_playing = false; + m_address = 0x100; + m_bitcount = 0; + m_cmd_rw = 0; + + // in cpu control, enter play mode and reset bitrate + write_p(1); + write_p(6); + write_p(0); } void tc8830f_device::write_p(UINT8 data) { m_stream->update(); + data &= 0xf; + + if (m_cmd_rw == 0) + { + // select command + m_command = data; + switch (m_command) + { + // immediate commands + case 0x1: + break; + + case 0x2: + m_playing = true; + break; + + case 0x3: + m_playing = false; + break; + + // multi-nibble commands + case 0x4: case 0x5: case 0x6: case 0x7: + m_cmd_rw = 1; + break; + + case 0x8: case 0x9: case 0xa: case 0xb: + logerror("tc8830f: Unemulated command %X\n", m_command); + break; + + default: + logerror("tc8830f: Invalid command %X\n", m_command); + break; + } + } + + else + { + // write command + switch (m_command) + { + case 0x4: + // ADLD1: set address counter + m_address = (m_address & ~(0xf << (m_cmd_rw*4))) | (data << (m_cmd_rw*4)); + if (m_cmd_rw == 5) + { + m_address &= m_mem_mask; + m_bitcount = 0; + m_cmd_rw = -1; + } + break; + + case 0x5: + // ADLD2: set address stop + m_stop_address = (m_stop_address & ~(0xf << (m_cmd_rw*4))) | (data << (m_cmd_rw*4)); + if (m_cmd_rw == 5) + { + m_stop_address &= m_mem_mask; + m_cmd_rw = -1; + } + break; + + case 0x6: + // CNDT: d0-d1: bitrate, d2: enable overflow + m_bitrate = data & 3; + device_clock_changed(); + m_cmd_rw = -1; + break; + + case 0x7: + // LABEL: set phrase + if (m_cmd_rw == 1) + { + m_phrase = (m_phrase & 0x30) | data; + } + else + { + m_phrase = (m_phrase & 0x0f) | (data << 4 & 0x30); + + // update addresses and start + UINT8 offs = m_phrase * 4; + m_address = (m_mem_base[offs] | m_mem_base[offs|1]<<8 | m_mem_base[offs|2]<<16) & m_mem_mask; + offs += 4; + m_stop_address = (m_mem_base[offs] | m_mem_base[offs|1]<<8 | m_mem_base[offs|2]<<16) & m_mem_mask; + + m_bitcount = 0; + m_playing = true; + m_cmd_rw = -1; + } + break; + + default: + m_cmd_rw = -1; + break; + } + m_cmd_rw++; + } } diff --git a/src/emu/sound/tc8830f.h b/src/emu/sound/tc8830f.h index 6c8b371a6b5..23200938316 100644 --- a/src/emu/sound/tc8830f.h +++ b/src/emu/sound/tc8830f.h @@ -14,10 +14,10 @@ // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define MCFG_TC8830F_SND_ADD(_tag, _clock) \ +#define MCFG_TC8830F_ADD(_tag, _clock) \ MCFG_DEVICE_ADD(_tag, TC8830F, _clock) -#define MCFG_TC8830F_SND_REPLACE(_tag, _clock) \ +#define MCFG_TC8830F_REPLACE(_tag, _clock) \ MCFG_DEVICE_REPLACE(_tag, TC8830F, _clock) @@ -40,10 +40,21 @@ public: protected: // device-level overrides virtual void device_start(); + virtual void device_post_load(); + virtual void device_clock_changed(); virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); private: + bool m_playing; + UINT32 m_address; + UINT32 m_stop_address; + UINT8 m_bitcount; + UINT8 m_bitrate; + UINT8 m_command; + int m_cmd_rw; + UINT8 m_phrase; + UINT8 *m_mem_base; UINT32 m_mem_mask; }; diff --git a/src/mame/drivers/timeplt.c b/src/mame/drivers/timeplt.c index 2f1178a51a4..c47043cb9f5 100644 --- a/src/mame/drivers/timeplt.c +++ b/src/mame/drivers/timeplt.c @@ -101,7 +101,7 @@ static WRITE8_DEVICE_HANDLER(chkun_sound_w) // d0-d3: P0-P3 // d5: /R (unused?) // d6: /W - if (data & 0x40) + if (~data & 0x40) state->m_tc8830f->write_p(data); // d4 (or d7?): /ACL @@ -515,8 +515,8 @@ static MACHINE_CONFIG_DERIVED( chkun, bikkuric ) MCFG_SOUND_MODIFY("ay2") MCFG_SOUND_CONFIG(chkun_ay2_interface) - MCFG_TC8830F_SND_ADD("tc8830f", 500000) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + MCFG_TC8830F_ADD("tc8830f", XTAL_18_432MHz/3/12) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.10) MACHINE_CONFIG_END