Added more accurate SSi S14001A speech chip emulation, written by one of the people at SSi who originally laid out the S14001a silicon in 1974/5! [Ed Bernard]

This commit is contained in:
hap 2016-01-19 01:02:42 +01:00
parent f49e9b5ce3
commit 5d66ee8e6d
9 changed files with 596 additions and 9 deletions

View File

@ -925,6 +925,7 @@ if (SOUNDS["SP0250"]~=null) then
end
---------------------------------------------------
-- S14001A speech synthesizer
--@src/devices/sound/s14001a.h,SOUNDS["S14001A"] = true
@ -939,6 +940,20 @@ end
---------------------------------------------------
-- S14001A_NEW speech synthesizer
--@src/devices/sound/s14001a_new.h,SOUNDS["S14001A_NEW"] = true
---------------------------------------------------
if (SOUNDS["S14001A_NEW"]~=null) then
files {
MAME_DIR .. "src/devices/sound/s14001a_new.cpp",
MAME_DIR .. "src/devices/sound/s14001a_new.h",
}
end
---------------------------------------------------
-- Texas Instruments SN76477 analog chip
--@src/devices/sound/sn76477.h,SOUNDS["SN76477"] = true

View File

@ -226,6 +226,7 @@ SOUNDS["VOTRAX"] = true
SOUNDS["ES8712"] = true
SOUNDS["CDP1869"] = true
SOUNDS["S14001A"] = true
SOUNDS["S14001A_NEW"] = true
SOUNDS["WAVE"] = true
SOUNDS["SID6581"] = true
SOUNDS["SID8580"] = true

View File

@ -228,6 +228,7 @@ SOUNDS["VOTRAX"] = true
--SOUNDS["ES8712"] = true
SOUNDS["CDP1869"] = true
SOUNDS["S14001A"] = true
SOUNDS["S14001A_NEW"] = true
SOUNDS["WAVE"] = true
SOUNDS["SID6581"] = true
SOUNDS["SID8580"] = true

View File

@ -0,0 +1,423 @@
// license:BSD-3-Clause
// copyright-holders:Ed Bernard
// http://www.vintagecalculators.com/html/speech-.html
#include "emu.h"
#include "s14001a_new.h"
const device_type S14001A_NEW = &device_creator<s14001a_new_device>;
s14001a_new_device::s14001a_new_device(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock)
: device_t(mconfig, S14001A_NEW, "S14001A_NEW", tag, owner, clock, "s14001a_new", __FILE__),
device_sound_interface(mconfig, *this),
m_SpeechRom(*this, DEVICE_SELF),
m_stream(nullptr),
m_bsy_handler(*this),
m_ext_read_handler(*this)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void s14001a_new_device::device_start()
{
m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() ? clock() : machine().sample_rate());
// resolve callbacks
m_ext_read_handler.resolve();
m_bsy_handler.resolve();
m_uOutputP1 = m_uOutputP2 = 7;
//m_uPrintLevel = 10;
}
//-------------------------------------------------
// sound_stream_update - handle a stream update
//-------------------------------------------------
void s14001a_new_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
for (int i = 0; i < samples; i++)
{
Clock();
outputs[0][i] = ((((INT16)GetOutput())-7)<<10)*15;
}
}
UINT8 s14001a_new_device::readmem(UINT16 offset, bool phase)
{
offset &= 0xfff; // 11-bit internal
return ((m_ext_read_handler.isnull()) ? m_SpeechRom[offset & (m_SpeechRom.bytes() - 1)] : m_ext_read_handler(offset));
}
void s14001a_new_device::force_update()
{
m_stream->update();
}
int s14001a_new_device::bsy_r()
{
m_stream->update();
return (GetBusy()) ? 1 : 0;
}
void s14001a_new_device::reg_w(int data)
{
m_stream->update();
SetWord(data);
}
void s14001a_new_device::rst_w(int data)
{
m_stream->update();
SetStart(data != 0);
if (m_bStart) m_uStateP1 = WORDWAIT;
}
void s14001a_new_device::set_clock(int clock)
{
m_stream->update();
m_stream->set_sample_rate(clock);
}
bool s14001a_new_device::Clock()
{
// effectively toggles external clock twice, one cycle
// internal clock toggles on external clock transition from 0 to 1 so internal clock will always transition here
// return false if some emulator problem detected
// On the actual chip, all register phase 1 values needed to be refreshed from phase 2 values
// or else risk losing their state due to charge loss.
// But on a computer the values are static.
// So to reduce code clutter, phase 1 values are only modified if they are different
// from the preceeding phase 2 values.
if (m_bPhase1)
{
// transition to phase2
m_bPhase1 = false;
// transfer phase1 variables to phase2
m_uStateP2 = m_uStateP1;
m_uDAR13To05P2 = m_uDAR13To05P1;
m_uDAR04To00P2 = m_uDAR04To00P1;
m_uCWARP2 = m_uCWARP1;
m_bStopP2 = m_bStopP1;
m_bVoicedP2 = m_bVoicedP1;
m_bSilenceP2 = m_bSilenceP1;
m_uLengthP2 = m_uLengthP1;
m_uXRepeatP2 = m_uXRepeatP1;
m_uDeltaOldP2 = m_uDeltaOldP1;
m_uOutputP2 = m_uOutputP1;
m_uRomAddrP2 = m_RomAddrP1;
// setup carries from phase 2 values
m_bDAR04To00CarryP2 = m_uDAR04To00P2 == 0x1F;
m_bPPQCarryP2 = m_bDAR04To00CarryP2 && ((m_uLengthP2&0x03) == 0x03); // pitch period quarter
m_bRepeatCarryP2 = m_bPPQCarryP2 && ((m_uLengthP2&0x0C) == 0x0C);
m_bLengthCarryP2 = m_bRepeatCarryP2 && ( m_uLengthP2 == 0x7F);
return true;
}
m_bPhase1 = true;
// logic done during phase 1
switch (m_uStateP1)
{
// 0
case IDLE:
m_bBusyP1 = false;
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
break;
// 1
case WORDWAIT:
// the delta address register latches the word number into bits 03 to 08
// all other bits forced to 0. 04 to 08 makes a multiply by two.
m_uDAR13To05P1 = (m_uWord&0x3C)>>2;
m_uDAR04To00P1 = (m_uWord&0x03)<<3;
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
m_bBusyP1 = true;
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = CWARMSB;
break;
// 2
case CWARMSB:
if (m_uPrintLevel >= 1)
printf("\n speaking word %02x",m_uWord);
// use uDAR to load uCWAR 8 msb
m_uCWARP1 = readmem(m_uRomAddrP2,m_bPhase1)<<4; // note use of rom address setup in previous state
// increment DAR by 4, 2 lsb's count deltas within a byte
m_uDAR04To00P1 += 4;
if (m_uDAR04To00P1 >= 32) m_uDAR04To00P1 = 0; // emulate 5 bit counter
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = CWARLSB;
break;
// 3
case CWARLSB:
m_uCWARP1 = m_uCWARP2|(readmem(m_uRomAddrP2,m_bPhase1)>>4); // setup in previous state
m_RomAddrP1 = m_uCWARP1;
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = DARMSB;
break;
// 4
case DARMSB:
m_uDAR13To05P1 = readmem(m_uRomAddrP2,m_bPhase1)<<1; // 9 bit counter, 8 MSBs from ROM, lsb zeroed
m_uDAR04To00P1 = 0;
m_uCWARP1++;
m_RomAddrP1 = m_uCWARP1;
m_uNControlWords++; // statistics
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = CTRLBITS;
break;
// 5
case CTRLBITS:
m_bStopP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x80? true: false;
m_bVoicedP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x40? true: false;
m_bSilenceP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x20? true: false;
m_uXRepeatP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x03;
m_uLengthP1 =(readmem(m_uRomAddrP2,m_bPhase1)&0x1F)<<2; // includes external length and repeat
m_uDAR04To00P1 = 0;
m_uCWARP1++; // gets ready for next DARMSB
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = PLAY;
if (m_uPrintLevel >= 2)
printf("\n cw %d %d %d %d %d",m_bStopP1,m_bVoicedP1,m_bSilenceP1,m_uLengthP1>>4,m_uXRepeatP1);
break;
// 6
case PLAY:
{
// statistics
if (m_bPPQCarryP2)
{
// pitch period end
if (m_uPrintLevel >= 3)
printf("\n ppe: RomAddr %03x",m_uRomAddrP2);
m_uNPitchPeriods++;
if (m_bVoicedP2) m_uNVoiced++;
}
// end statistics
// modify output
UINT8 uDeltaP2; // signal line
UINT8 uIncrementP2; // signal lines
bool bAddP2; // signal line
uDeltaP2 = Mux8To2(m_bVoicedP2,
m_uLengthP2 & 0x03, // pitch period quater counter
m_uDAR04To00P2 & 0x03, // two bit delta address within byte
readmem(m_uRomAddrP2,m_bPhase1)
);
CalculateIncrement(m_bVoicedP2,
m_uLengthP2 & 0x03, // pitch period quater counter
m_uDAR04To00P2 == 0, // pitch period quarter start
uDeltaP2,
m_uDeltaOldP2, // input
m_uDeltaOldP1, // output
uIncrementP2, // output 0, 1, or 3
bAddP2 // output
);
m_uOutputP1 = CalculateOutput(m_bVoicedP2,
m_bSilenceP2,
m_uLengthP2 & 0x03, // pitch period quater counter
m_uDAR04To00P2 == 0, // pitch period quarter start
m_uOutputP2, // last output
uIncrementP2,
bAddP2
);
// advance counters
m_uDAR04To00P1++;
if (m_bDAR04To00CarryP2) // pitch period quarter end
{
m_uDAR04To00P1 = 0; // emulate 5 bit counter
m_uLengthP1++; // lower two bits of length count quarter pitch periods
if (m_uLengthP1 >= 0x80)
{
m_uLengthP1 = 0; // emulate 7 bit counter
}
}
if (m_bVoicedP2 && m_bRepeatCarryP2) // repeat complete
{
m_uLengthP1 &= 0x70; // keep current "length"
m_uLengthP1 |= (m_uXRepeatP1<<2); // load repeat from external repeat
m_uDAR13To05P1++; // advances ROM address 8 bytes
if (m_uDAR13To05P1 >= 0x200) m_uDAR13To05P1 = 0; // emulate 9 bit counter
}
if (!m_bVoicedP2 && m_bDAR04To00CarryP2)
{
// unvoiced advances each quarter pitch period
// note repeat counter not reloaded for non voiced speech
m_uDAR13To05P1++; // advances ROM address 8 bytes
if (m_uDAR13To05P1 >= 0x200) m_uDAR13To05P1 = 0; // emulate 9 bit counter
}
// construct m_RomAddrP1
m_RomAddrP1 = m_uDAR04To00P1;
if (m_bVoicedP2 && m_uLengthP1&0x1) // mirroring
{
m_RomAddrP1 ^= 0x1f; // count backwards
}
m_RomAddrP1 = (m_uDAR13To05P1<<3) | m_RomAddrP1>>2;
// next state
if (m_bStart) m_uStateP1 = WORDWAIT;
else if (m_bStopP2 && m_bLengthCarryP2) m_uStateP1 = DELAY;
else if (m_bLengthCarryP2)
{
m_uStateP1 = DARMSB;
m_RomAddrP1 = m_uCWARP1; // output correct address
}
else m_uStateP1 = PLAY;
break;
}
// 7
case DELAY:
m_uOutputP1 = 7;
if (m_bStart) m_uStateP1 = WORDWAIT;
else m_uStateP1 = IDLE;
break;
}
return true;
}
UINT8 s14001a_new_device::Mux8To2(bool bVoicedP2, UINT8 uPPQtrP2, UINT8 uDeltaAdrP2, UINT8 uRomDataP2)
{
// pick two bits of rom data as delta
if (bVoicedP2 && uPPQtrP2&0x01) // mirroring
{
uDeltaAdrP2 ^= 0x03; // count backwards
}
// emulate 8 to 2 mux to obtain delta from byte (bigendian)
switch (uDeltaAdrP2)
{
case 0x00:
return (uRomDataP2&0xC0)>>6;
case 0x01:
return (uRomDataP2&0x30)>>4;
case 0x02:
return (uRomDataP2&0x0C)>>2;
case 0x03:
return (uRomDataP2&0x03)>>0;
}
return 0xFF;
}
void s14001a_new_device::CalculateIncrement(bool bVoicedP2, UINT8 uPPQtrP2, bool bPPQStartP2, UINT8 uDelta, UINT8 uDeltaOldP2, UINT8 &uDeltaOldP1, UINT8 &uIncrementP2, bool &bAddP2)
{
// uPPQtr, pitch period quarter counter; 2 lsb of uLength
// bPPStart, start of a pitch period
// implemented to mimic silicon (a bit)
// beginning of a pitch period
if (uPPQtrP2 == 0x00 && bPPQStartP2) // note this is done for voiced and unvoiced
{
uDeltaOldP2 = 0x02;
}
static UINT8 uIncrements[4][4] =
{
// 00 01 10 11
{ 3, 3, 1, 1,}, // 00
{ 1, 1, 0, 0,}, // 01
{ 0, 0, 1, 1,}, // 10
{ 1, 1, 3, 3 }, // 11
};
#define MIRROR (uPPQtrP2&0x01)
// calculate increment from delta, always done even if silent to update uDeltaOld
// in silicon a PLA determined 0,1,3 and add/subtract and passed uDelta to uDeltaOld
if (!bVoicedP2 || !MIRROR)
{
uIncrementP2 = uIncrements[uDelta][uDeltaOldP2];
bAddP2 = uDelta >= 0x02;
}
else
{
uIncrementP2 = uIncrements[uDeltaOldP2][uDelta];
bAddP2 = uDeltaOldP2 < 0x02;
}
uDeltaOldP1 = uDelta;
if (bVoicedP2 && bPPQStartP2 && MIRROR) uIncrementP2 = 0; // no change when first starting mirroring
}
UINT8 s14001a_new_device::CalculateOutput(bool bVoiced, bool bXSilence, UINT8 uPPQtr, bool bPPQStart, UINT8 uLOutput, UINT8 uIncrementP2, bool bAddP2)
{
// implemented to mimic silicon (a bit)
// limits output to 0x00 and 0x0f
UINT8 uTmp; // used for subtraction
#define SILENCE (uPPQtr&0x02)
// determine output
if (bXSilence || (bVoiced && SILENCE)) return 7;
// beginning of a pitch period
if (uPPQtr == 0x00 && bPPQStart) // note this is done for voiced and nonvoiced
{
uLOutput = 7;
}
// adder
uTmp = uLOutput;
if (!bAddP2) uTmp ^= 0x0F; // turns subtraction into addition
// add 0, 1, 3; limit at 15
uTmp += uIncrementP2;
if (uTmp > 15) uTmp = 15;
if (!bAddP2) uTmp ^= 0x0F; // turns addition back to subtraction
return uTmp;
}
void s14001a_new_device::ClearStatistics()
{
m_uNPitchPeriods = 0;
m_uNVoiced = 0;
m_uPrintLevel = 0;
m_uNControlWords = 0;
}
void s14001a_new_device::GetStatistics(UINT32 &uNPitchPeriods, UINT32 &uNVoiced, UINT32 uNControlWords)
{
uNPitchPeriods = m_uNPitchPeriods;
uNVoiced = m_uNVoiced;
uNControlWords = m_uNControlWords;
}

View File

@ -0,0 +1,145 @@
// license:BSD-3-Clause
// copyright-holders:Ed Bernard
#ifndef __S14001A_H__
#define __S14001A_H__
#define MCFG_S14001A_BSY_HANDLER(_devcb) \
devcb = &s14001a_new_device::set_bsy_handler(*device, DEVCB_##_devcb);
#define MCFG_S14001A_EXT_READ_HANDLER(_devcb) \
devcb = &s14001a_new_device::set_ext_read_handler(*device, DEVCB_##_devcb);
class s14001a_new_device : public device_t,
public device_sound_interface
{
public:
s14001a_new_device(const machine_config &mconfig, std::string tag, device_t *owner, UINT32 clock);
~s14001a_new_device() {}
// static configuration helpers
template<class _Object> static devcb_base &set_bsy_handler(device_t &device, _Object object) { return downcast<s14001a_new_device &>(device).m_bsy_handler.set_callback(object); }
template<class _Object> static devcb_base &set_ext_read_handler(device_t &device, _Object object) { return downcast<s14001a_new_device &>(device).m_ext_read_handler.set_callback(object); }
bool Clock(); // called once to toggle external clock twice
// output pin data
UINT16 GetRomAddr() { return m_uRomAddrP2; }
UINT8 GetOutput() { return m_uOutputP2; }
bool GetAddressRead() { return m_bPhase1; }
bool GetBusy() { return m_bBusyP1; }
// input pin data
void SetStart(bool bStart) { m_bStart = bStart; }
void SetWord(UINT8 uWord) { m_uWord = uWord; }
// emulator helper functions
UINT8 Mux8To2(bool bVoicedP2, UINT8 uPPQtrP2, UINT8 uDeltaAdrP2, UINT8 uRomDataP2);
void CalculateIncrement(bool bVoicedP2, UINT8 uPPQtrP2, bool bPPQStartP2, UINT8 uDeltaP2, UINT8 uDeltaOldP2, UINT8 &uDeltaOldP1, UINT8 &uIncrementP2, bool &bAddP2);
UINT8 CalculateOutput(bool bVoicedP2, bool bXSilenceP2, UINT8 uPPQtrP2, bool bPPQStartP2, UINT8 uLOutputP2, UINT8 uIncrementP2, bool bAddP2);
void ClearStatistics();
void GetStatistics(UINT32 &uNPitchPeriods, UINT32 &uNVoiced, UINT32 uNControlWords);
void SetPrintLevel(UINT32 uPrintLevel) { m_uPrintLevel = uPrintLevel; }
int bsy_r(); /* read BUSY pin */
void reg_w(int data); /* write to input latch */
void rst_w(int data); /* write to RESET pin */
void set_clock(int clock); /* set VSU-1000 clock */
// void set_volume(int volume); /* set VSU-1000 volume control */
void force_update();
protected:
// device-level overrides
virtual void device_start() override;
// sound stream update overrides
virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) override;
private:
// internal state
required_region_ptr<UINT8> m_SpeechRom;
sound_stream * m_stream;
devcb_write_line m_bsy_handler;
devcb_read8 m_ext_read_handler;
UINT8 readmem(UINT16 offset, bool phase);
bool m_bPhase1; // 1 bit internal clock
enum states
{
IDLE = 0,
WORDWAIT,
CWARMSB, // read 8 CWAR MSBs
CWARLSB, // read 4 CWAR LSBs from rom d7-d4
DARMSB, // read 8 DAR MSBs
CTRLBITS, // read Stop, Voiced, Silence, Length, XRepeat
PLAY,
DELAY
};
// registers
states m_uStateP1; // 3 bits
states m_uStateP2;
UINT16 m_uDAR13To05P1; // 9 MSBs of delta address register
UINT16 m_uDAR13To05P2; // incrementing uDAR05To13 advances ROM address by 8 bytes
UINT16 m_uDAR04To00P1; // 5 LSBs of delta address register
UINT16 m_uDAR04To00P2; // 3 address ROM, 2 mux 8 bits of data into 2 bit delta
// carry indicates end of quarter pitch period (32 cycles)
UINT16 m_uCWARP1; // 12 bits Control Word Address Register (syllable)
UINT16 m_uCWARP2;
bool m_bStopP1;
bool m_bStopP2;
bool m_bVoicedP1;
bool m_bVoicedP2;
bool m_bSilenceP1;
bool m_bSilenceP2;
UINT8 m_uLengthP1; // 7 bits, upper three loaded from ROM length
UINT8 m_uLengthP2; // middle two loaded from ROM repeat and/or uXRepeat
// bit 0 indicates mirror in voiced mode
// bit 1 indicates internal silence in voiced mode
// incremented each pitch period quarter
UINT8 m_uXRepeatP1; // 2 bits, loaded from ROM repeat
UINT8 m_uXRepeatP2;
UINT8 m_uDeltaOldP1; // 2 bit old delta
UINT8 m_uDeltaOldP2;
UINT8 m_uOutputP1; // 4 bits audio output, calculated during phase 1
// derived signals
bool m_bDAR04To00CarryP2;
bool m_bPPQCarryP2;
bool m_bRepeatCarryP2;
bool m_bLengthCarryP2;
UINT16 m_RomAddrP1; // rom address
// output pins
UINT8 m_uOutputP2; // output changes on phase2
UINT16 m_uRomAddrP2; // address pins change on phase 2
bool m_bBusyP1; // busy changes on phase 1
// input pins
bool m_bStart;
UINT8 m_uWord; // 6 bit word noumber to be spoken
// emulator variables
// statistics
UINT32 m_uNPitchPeriods;
UINT32 m_uNVoiced;
UINT32 m_uNControlWords;
// diagnostic output
UINT32 m_uPrintLevel;
};
extern const device_type S14001A_NEW;
#endif /* __S14001A_H__ */

View File

@ -20,7 +20,7 @@ WIP: plan to move to main fidelity chess driver^Z^Z^Z^Z - move magnet board sens
#include "emu.h"
#include "cpu/m6502/m6502.h"
#include "machine/6821pia.h"
#include "sound/s14001a.h"
#include "sound/s14001a_new.h"
// same layout of Sensory Chess Challenger
//extern const char layout_vsc[];
@ -35,7 +35,7 @@ public:
{ }
required_device<cpu_device> m_maincpu;
required_device<s14001a_device> m_speech;
required_device<s14001a_new_device> m_speech;
virtual void machine_start() override;
@ -325,7 +325,7 @@ static MACHINE_CONFIG_START( csc, csc_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("speech", S14001A, 25000) // around 25khz
MCFG_SOUND_ADD("speech", S14001A_NEW, 25000) // around 25khz
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MACHINE_CONFIG_END

View File

@ -1354,7 +1354,7 @@ static MACHINE_CONFIG_START( vcc, fidelz80_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("speech", S14001A, 25000) // R/C circuit, around 25khz
MCFG_SOUND_ADD("speech", S14001A_NEW, 25000) // R/C circuit, around 25khz
MCFG_S14001A_EXT_READ_HANDLER(READ8(fidelz80_state, vcc_speech_r))
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MACHINE_CONFIG_END
@ -1382,7 +1382,7 @@ static MACHINE_CONFIG_START( vsc, fidelz80_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("speech", S14001A, 25000) // R/C circuit, around 25khz
MCFG_SOUND_ADD("speech", S14001A_NEW, 25000) // R/C circuit, around 25khz
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
@ -1407,7 +1407,7 @@ static MACHINE_CONFIG_START( bridgec, fidelz80_state )
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("speech", S14001A, 25000) // R/C circuit, around 25khz
MCFG_SOUND_ADD("speech", S14001A_NEW, 25000) // R/C circuit, around 25khz
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
MACHINE_CONFIG_END

View File

@ -13,6 +13,7 @@
--------------------------------------------------------------------
@CP0904A TMS0970 1977, Milton Bradley Comp IV
@MP0905B TMS0970 1977, Parker Brothers Codename Sector
*MP0057 TMS1000 1978, APH Student Speech+ (same ROM contents as TSI Speech+?)
*MP0168 TMS1000? 1979, Conic Basketball
@MP0914 TMS1000 1979, Entex Baseball 1
@MP0923 TMS1000 1979, Entex Baseball 2
@ -77,8 +78,9 @@
inconsistent:
*M95041 ? 1983, Tsukuda Game Pachinko (? note: 40-pin, VFD-capable)
*TMC1007 TMS1000 1976, TSI Speech+ (S14002-A)
@CD7282SL TMS1100 1981, Tandy/RadioShack Tandy-12 (serial is similar to TI Speak & Spell series?)
*M95041 ? 1983, Tsukuda Game Pachinko (? note: 40-pin, VFD-capable)
(* denotes not yet emulated by MAME, @ denotes it's in this driver)

View File

@ -13,7 +13,7 @@
#include "machine/i8243.h"
#include "machine/z80pio.h"
#include "sound/speaker.h"
#include "sound/s14001a.h"
#include "sound/s14001a_new.h"
class fidelz80base_state : public driver_device
{
@ -41,7 +41,7 @@ public:
optional_device<i8255_device> m_ppi8255;
optional_device<i8243_device> m_i8243;
optional_ioport_array<10> m_inp_matrix; // max 10
optional_device<s14001a_device> m_speech;
optional_device<s14001a_new_device> m_speech;
optional_region_ptr<UINT8> m_speech_rom;
optional_device<speaker_sound_device> m_speaker;