// license:MAME|LGPL-2.1+ // copyright-holders:Michael Zapf /**************************************************************************** TI-99/8 Speech synthesizer subsystem The TI-99/8 contains a speech synthesizer inside the console, so we cannot reuse the spchsyn implementation of the P-Box speech synthesizer. Accordingly, this is not a ti_expansion_card_device. Michael Zapf February 2012: Rewritten as class *****************************************************************************/ #include "speech8.h" #include "sound/wave.h" #include "machine/spchrom.h" #define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */ #define VERBOSE 1 #define LOG logerror #define SPEECHSYN_TAG "speechsyn" #define REAL_TIMING 0 /* For comments on real timing see ti99/spchsyn.c Note that before the REAL_TIMING can be used we must first establish the set_address logic in mapper8. */ /****************************************************************************/ ti998_spsyn_device::ti998_spsyn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) : bus8z_device(mconfig, TI99_SPEECH8, "TI-99/8 Speech synthesizer (onboard)", tag, owner, clock, "ti99_speech8", __FILE__), m_ready(*this) { } /* Memory read */ #if REAL_TIMING // ====== This is the version with real timing ======= READ8Z_MEMBER( ti998_spsyn_device::readz ) { m_vsp->wsq_w(TRUE); m_vsp->rsq_w(FALSE); *value = m_vsp->read(offset) & 0xff; if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value); } /* Memory write */ WRITE8_MEMBER( ti998_spsyn_device::write ) { m_vsp->rsq_w(m_vsp, TRUE); m_vsp->wsq_w(m_vsp, FALSE); if (VERBOSE>4) LOG("speech8: write value = %02x\n", data); m_vsp->write(offset, data); } #else // ====== This is the version without real timing ======= READ8Z_MEMBER( ti998_spsyn_device::readz ) { machine().device("maincpu")->execute().adjust_icount(-(18+3)); /* this is just a minimum, it can be more */ *value = m_vsp->status_r(space, offset, 0xff) & 0xff; if (VERBOSE>4) LOG("speech8: read value = %02x\n", *value); } /* Memory write */ WRITE8_MEMBER( ti998_spsyn_device::write ) { machine().device("maincpu")->execute().adjust_icount(-(54+3)); /* this is just an approx. minimum, it can be much more */ /* RN: the stupid design of the tms5220 core means that ready is cleared */ /* when there are 15 bytes in FIFO. It should be 16. Of course, if */ /* it were the case, we would need to store the value on the bus, */ /* which would be more complex. */ if (!m_vsp->readyq_r()) { attotime time_to_ready = attotime::from_double(m_vsp->time_to_ready()); int cycles_to_ready = machine().device("maincpu")->attotime_to_cycles(time_to_ready); if (VERBOSE>8) LOG("speech8: time to ready: %f -> %d\n", time_to_ready.as_double(), (int) cycles_to_ready); machine().device("maincpu")->execute().adjust_icount(-cycles_to_ready); machine().scheduler().timer_set(attotime::zero, FUNC_NULL); } if (VERBOSE>4) LOG("speech8: write value = %02x\n", data); m_vsp->data_w(space, offset, data); } #endif /**************************************************************************/ WRITE_LINE_MEMBER( ti998_spsyn_device::speech8_ready ) { // The TMS5200 implementation uses TRUE/FALSE, not ASSERT/CLEAR semantics m_ready((state==0)? ASSERT_LINE : CLEAR_LINE); if (VERBOSE>5) LOG("spchsyn: READY = %d\n", (state==0)); #if REAL_TIMING // Need to do that here (see explanations in spchsyn.c) if (state==0) { m_vsp->rsq_w(TRUE); m_vsp->wsq_w(TRUE); } #endif } void ti998_spsyn_device::device_start() { m_ready.resolve_safe(); m_vsp = subdevice(SPEECHSYN_TAG); speechrom_device* mem = subdevice("vsm"); mem->set_reverse_bit_order(true); } void ti998_spsyn_device::device_reset() { if (VERBOSE>4) LOG("speech8: reset\n"); } // Unlike the TI-99/4A, the 99/8 uses the CD2501ECD // The CD2501ECD is a tms5200/cd2501e with the rate control from the tms5220c added in. // (it's probably actually a tms5220c die with the cd2501e/tms5200 lpc rom masked onto it) MACHINE_CONFIG_FRAGMENT( ti998_speech ) MCFG_DEVICE_ADD("vsm", SPEECHROM, 0) MCFG_SPEAKER_STANDARD_MONO("mono") MCFG_SOUND_ADD(SPEECHSYN_TAG, CD2501ECD, 640000L) MCFG_TMS52XX_READYQ_HANDLER(WRITELINE(ti998_spsyn_device, speech8_ready)) MCFG_TMS52XX_SPEECHROM("vsm") MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) MACHINE_CONFIG_END /* Verified on a real machine: TI-99/8 uses the same speech rom contents as the TI speech synthesizer. */ ROM_START( ti998_speech ) ROM_REGION(0x8000, "vsm", 0) ROM_LOAD("cd2325a.vsm", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe)) ROM_LOAD("cd2326a.vsm", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020)) ROM_END machine_config_constructor ti998_spsyn_device::device_mconfig_additions() const { return MACHINE_CONFIG_NAME( ti998_speech ); } const rom_entry *ti998_spsyn_device::device_rom_region() const { return ROM_NAME( ti998_speech ); } const device_type TI99_SPEECH8 = &device_creator;