mirror of
https://github.com/holub/mame
synced 2025-07-06 10:29:38 +03:00
s14001a: shorthand variable types, small cleanup
This commit is contained in:
parent
a8d909a02a
commit
d352702d22
@ -2,22 +2,20 @@
|
|||||||
// copyright-holders:Ed Bernard, Jonathan Gevaryahu, hap
|
// copyright-holders:Ed Bernard, Jonathan Gevaryahu, hap
|
||||||
// thanks-to:Kevin Horton
|
// thanks-to:Kevin Horton
|
||||||
/*
|
/*
|
||||||
SSi TSI S14001A speech IC emulator
|
|
||||||
aka CRC: Custom ROM Controller, designed in 1975, first usage in 1976 on TSI Speech+ calculator
|
|
||||||
Originally written for MAME by Jonathan Gevaryahu(Lord Nightmare) 2006-2013,
|
|
||||||
replaced with near-complete rewrite by Ed Bernard in 2016
|
|
||||||
|
|
||||||
TODO:
|
SSi TSI S14001A speech IC emulator
|
||||||
- nothing at the moment?
|
aka CRC: Custom ROM Controller, designed in 1975, first usage in 1976 on TSI Speech+ calculator
|
||||||
|
Originally written for MAME by Jonathan Gevaryahu(Lord Nightmare) 2006-2013,
|
||||||
|
replaced with near-complete rewrite by Ed Bernard in 2016
|
||||||
|
|
||||||
Further reading:
|
Further reading:
|
||||||
- http://www.vintagecalculators.com/html/speech-.html
|
- http://www.vintagecalculators.com/html/speech-.html
|
||||||
- http://www.vintagecalculators.com/html/development_of_the_tsi_speech-.html
|
- http://www.vintagecalculators.com/html/development_of_the_tsi_speech-.html
|
||||||
- http://www.vintagecalculators.com/html/speech-_state_machine.html
|
- http://www.vintagecalculators.com/html/speech-_state_machine.html
|
||||||
- https://archive.org/stream/pdfy-QPCSwTWiFz1u9WU_/david_djvu.txt
|
- https://archive.org/stream/pdfy-QPCSwTWiFz1u9WU_/david_djvu.txt
|
||||||
*/
|
|
||||||
|
Chip Pinout:
|
||||||
|
|
||||||
/* Chip Pinout:
|
|
||||||
The original datasheet (which is lost as far as I know) clearly called the
|
The original datasheet (which is lost as far as I know) clearly called the
|
||||||
s14001a chip the 'CRC chip', or 'Custom Rom Controller', as it appears with
|
s14001a chip the 'CRC chip', or 'Custom Rom Controller', as it appears with
|
||||||
this name on the Stern and Canon schematics, as well as on some TSI speech
|
this name on the Stern and Canon schematics, as well as on some TSI speech
|
||||||
@ -101,6 +99,7 @@ line is held high, the first address byte of the first word will be read repeate
|
|||||||
every clock, with the rom enable line enabled constantly (i.e. it doesn't toggle on
|
every clock, with the rom enable line enabled constantly (i.e. it doesn't toggle on
|
||||||
and off as it normally does during speech). Once START has gone low-high-low, the
|
and off as it normally does during speech). Once START has gone low-high-low, the
|
||||||
/BUSY line will go low until 3 clocks after the chip is done speaking.
|
/BUSY line will go low until 3 clocks after the chip is done speaking.
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "emu.h"
|
#include "emu.h"
|
||||||
@ -108,7 +107,7 @@ and off as it normally does during speech). Once START has gone low-high-low, th
|
|||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
uint8_t Mux8To2(bool bVoicedP2, uint8_t uPPQtrP2, uint8_t uDeltaAdrP2, uint8_t uRomDataP2)
|
u8 Mux8To2(bool bVoicedP2, u8 uPPQtrP2, u8 uDeltaAdrP2, u8 uRomDataP2)
|
||||||
{
|
{
|
||||||
// pick two bits of rom data as delta
|
// pick two bits of rom data as delta
|
||||||
|
|
||||||
@ -120,7 +119,7 @@ uint8_t Mux8To2(bool bVoicedP2, uint8_t uPPQtrP2, uint8_t uDeltaAdrP2, uint8_t u
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void CalculateIncrement(bool bVoicedP2, uint8_t uPPQtrP2, bool bPPQStartP2, uint8_t uDelta, uint8_t uDeltaOldP2, uint8_t &uDeltaOldP1, uint8_t &uIncrementP2, bool &bAddP2)
|
void CalculateIncrement(bool bVoicedP2, u8 uPPQtrP2, bool bPPQStartP2, u8 uDelta, u8 uDeltaOldP2, u8 &uDeltaOldP1, u8 &uIncrementP2, bool &bAddP2)
|
||||||
{
|
{
|
||||||
// uPPQtr, pitch period quarter counter; 2 lsb of uLength
|
// uPPQtr, pitch period quarter counter; 2 lsb of uLength
|
||||||
// bPPStart, start of a pitch period
|
// bPPStart, start of a pitch period
|
||||||
@ -130,7 +129,7 @@ void CalculateIncrement(bool bVoicedP2, uint8_t uPPQtrP2, bool bPPQStartP2, uint
|
|||||||
if ((uPPQtrP2 == 0x00) && bPPQStartP2) // note this is done for voiced and unvoiced
|
if ((uPPQtrP2 == 0x00) && bPPQStartP2) // note this is done for voiced and unvoiced
|
||||||
uDeltaOldP2 = 0x02;
|
uDeltaOldP2 = 0x02;
|
||||||
|
|
||||||
static constexpr uint8_t uIncrements[4][4] =
|
static constexpr u8 uIncrements[4][4] =
|
||||||
{
|
{
|
||||||
// 00 01 10 11
|
// 00 01 10 11
|
||||||
{ 3, 3, 1, 1,}, // 00
|
{ 3, 3, 1, 1,}, // 00
|
||||||
@ -159,7 +158,7 @@ void CalculateIncrement(bool bVoicedP2, uint8_t uPPQtrP2, bool bPPQStartP2, uint
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
uint8_t CalculateOutput(bool bVoiced, bool bXSilence, uint8_t uPPQtr, bool bPPQStart, uint8_t uLOutput, uint8_t uIncrementP2, bool bAddP2)
|
u8 CalculateOutput(bool bVoiced, bool bXSilence, u8 uPPQtr, bool bPPQStart, u8 uLOutput, u8 uIncrementP2, bool bAddP2)
|
||||||
{
|
{
|
||||||
// implemented to mimic silicon (a bit)
|
// implemented to mimic silicon (a bit)
|
||||||
// limits output to 0x00 and 0x0f
|
// limits output to 0x00 and 0x0f
|
||||||
@ -175,9 +174,9 @@ uint8_t CalculateOutput(bool bVoiced, bool bXSilence, uint8_t uPPQtr, bool bPPQS
|
|||||||
uLOutput = 7;
|
uLOutput = 7;
|
||||||
|
|
||||||
// adder
|
// adder
|
||||||
uint8_t uTmp = uLOutput;
|
u8 uTmp = uLOutput;
|
||||||
if (!bAddP2)
|
if (!bAddP2)
|
||||||
uTmp ^= 0x0F; // turns subtraction into addition
|
uTmp ^= 0x0f; // turns subtraction into addition
|
||||||
|
|
||||||
// add 0, 1, 3; limit at 15
|
// add 0, 1, 3; limit at 15
|
||||||
uTmp += uIncrementP2;
|
uTmp += uIncrementP2;
|
||||||
@ -185,7 +184,7 @@ uint8_t CalculateOutput(bool bVoiced, bool bXSilence, uint8_t uPPQtr, bool bPPQS
|
|||||||
uTmp = 15;
|
uTmp = 15;
|
||||||
|
|
||||||
if (!bAddP2)
|
if (!bAddP2)
|
||||||
uTmp ^= 0x0F; // turns addition back to subtraction
|
uTmp ^= 0x0f; // turns addition back to subtraction
|
||||||
|
|
||||||
return uTmp;
|
return uTmp;
|
||||||
}
|
}
|
||||||
@ -196,7 +195,7 @@ uint8_t CalculateOutput(bool bVoiced, bool bXSilence, uint8_t uPPQtr, bool bPPQS
|
|||||||
// device definition
|
// device definition
|
||||||
DEFINE_DEVICE_TYPE(S14001A, s14001a_device, "s14001a", "SSi TSI S14001A")
|
DEFINE_DEVICE_TYPE(S14001A, s14001a_device, "s14001a", "SSi TSI S14001A")
|
||||||
|
|
||||||
s14001a_device::s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
|
s14001a_device::s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock) :
|
||||||
device_t(mconfig, S14001A, tag, owner, clock),
|
device_t(mconfig, S14001A, tag, owner, clock),
|
||||||
device_sound_interface(mconfig, *this),
|
device_sound_interface(mconfig, *this),
|
||||||
m_SpeechRom(*this, DEVICE_SELF),
|
m_SpeechRom(*this, DEVICE_SELF),
|
||||||
@ -303,7 +302,7 @@ void s14001a_device::sound_stream_update(sound_stream &stream, std::vector<read_
|
|||||||
for (int i = 0; i < outputs[0].samples(); i++)
|
for (int i = 0; i < outputs[0].samples(); i++)
|
||||||
{
|
{
|
||||||
Clock();
|
Clock();
|
||||||
int16_t sample = m_uOutputP2 - 7; // range -7..8
|
s16 sample = m_uOutputP2 - 7; // range -7..8
|
||||||
outputs[0].put_int(i, sample, 8);
|
outputs[0].put_int(i, sample, 8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -330,7 +329,7 @@ int s14001a_device::busy_r()
|
|||||||
return (m_bBusyP1) ? 1 : 0;
|
return (m_bBusyP1) ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void s14001a_device::data_w(uint8_t data)
|
void s14001a_device::data_w(u8 data)
|
||||||
{
|
{
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
m_uWord = data & 0x3f; // C0-C5
|
m_uWord = data & 0x3f; // C0-C5
|
||||||
@ -340,10 +339,11 @@ void s14001a_device::start_w(int state)
|
|||||||
{
|
{
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
m_bStart = (state != 0);
|
m_bStart = (state != 0);
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
if (m_bStart)
|
||||||
|
m_uStateP1 = states::WORDWAIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
void s14001a_device::set_clock(uint32_t clock)
|
void s14001a_device::set_clock(u32 clock)
|
||||||
{
|
{
|
||||||
m_stream->update();
|
m_stream->update();
|
||||||
m_stream->set_sample_rate(clock);
|
m_stream->set_sample_rate(clock);
|
||||||
@ -354,7 +354,7 @@ void s14001a_device::set_clock(uint32_t clock)
|
|||||||
Device emulation
|
Device emulation
|
||||||
**************************************************************************/
|
**************************************************************************/
|
||||||
|
|
||||||
uint8_t s14001a_device::readmem(uint16_t offset, bool phase)
|
u8 s14001a_device::readmem(u16 offset, bool phase)
|
||||||
{
|
{
|
||||||
offset &= 0xfff; // 11-bit internal
|
offset &= 0xfff; // 11-bit internal
|
||||||
return (m_ext_read_handler.isunset()) ? m_SpeechRom[offset & (m_SpeechRom.bytes() - 1)] : m_ext_read_handler(offset);
|
return (m_ext_read_handler.isunset()) ? m_SpeechRom[offset & (m_SpeechRom.bytes() - 1)] : m_ext_read_handler(offset);
|
||||||
@ -393,10 +393,10 @@ bool s14001a_device::Clock()
|
|||||||
m_uRomAddrP2 = m_RomAddrP1;
|
m_uRomAddrP2 = m_RomAddrP1;
|
||||||
|
|
||||||
// setup carries from phase 2 values
|
// setup carries from phase 2 values
|
||||||
m_bDAR04To00CarryP2 = m_uDAR04To00P2 == 0x1F;
|
m_bDAR04To00CarryP2 = m_uDAR04To00P2 == 0x1f;
|
||||||
m_bPPQCarryP2 = m_bDAR04To00CarryP2 && ((m_uLengthP2&0x03) == 0x03); // pitch period quarter
|
m_bPPQCarryP2 = m_bDAR04To00CarryP2 && ((m_uLengthP2 & 0x03) == 0x03); // pitch period quarter
|
||||||
m_bRepeatCarryP2 = m_bPPQCarryP2 && ((m_uLengthP2&0x0C) == 0x0C);
|
m_bRepeatCarryP2 = m_bPPQCarryP2 && ((m_uLengthP2 & 0x0c) == 0x0c);
|
||||||
m_bLengthCarryP2 = m_bRepeatCarryP2 && ( m_uLengthP2 == 0x7F);
|
m_bLengthCarryP2 = m_bRepeatCarryP2 && ( m_uLengthP2 == 0x7f);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -407,7 +407,8 @@ bool s14001a_device::Clock()
|
|||||||
{
|
{
|
||||||
case states::IDLE:
|
case states::IDLE:
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
if (m_bStart)
|
||||||
|
m_uStateP1 = states::WORDWAIT;
|
||||||
|
|
||||||
if (m_bBusyP1)
|
if (m_bBusyP1)
|
||||||
m_bsy_handler(0);
|
m_bsy_handler(0);
|
||||||
@ -417,12 +418,12 @@ bool s14001a_device::Clock()
|
|||||||
case states::WORDWAIT:
|
case states::WORDWAIT:
|
||||||
// the delta address register latches the word number into bits 03 to 08
|
// 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.
|
// all other bits forced to 0. 04 to 08 makes a multiply by two.
|
||||||
m_uDAR13To05P1 = (m_uWord&0x3C)>>2;
|
m_uDAR13To05P1 = (m_uWord & 0x3c) >> 2;
|
||||||
m_uDAR04To00P1 = (m_uWord&0x03)<<3;
|
m_uDAR04To00P1 = (m_uWord & 0x03) << 3;
|
||||||
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
|
m_RomAddrP1 = (m_uDAR13To05P1 << 3) | (m_uDAR04To00P1 >> 2); // remove lower two bits
|
||||||
|
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::CWARMSB;
|
||||||
else m_uStateP1 = states::CWARMSB;
|
|
||||||
|
|
||||||
if (!m_bBusyP1)
|
if (!m_bBusyP1)
|
||||||
m_bsy_handler(1);
|
m_bsy_handler(1);
|
||||||
@ -431,59 +432,60 @@ bool s14001a_device::Clock()
|
|||||||
|
|
||||||
case states::CWARMSB:
|
case states::CWARMSB:
|
||||||
if (m_uPrintLevel >= 1)
|
if (m_uPrintLevel >= 1)
|
||||||
printf("\n speaking word %02x",m_uWord);
|
logerror("\n speaking word %02x",m_uWord);
|
||||||
|
|
||||||
// use uDAR to load uCWAR 8 msb
|
// use uDAR to load uCWAR 8 msb
|
||||||
m_uCWARP1 = readmem(m_uRomAddrP2,m_bPhase1)<<4; // note use of rom address setup in previous state
|
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
|
// increment DAR by 4, 2 lsb's count deltas within a byte
|
||||||
m_uDAR04To00P1 += 4;
|
m_uDAR04To00P1 += 4;
|
||||||
if (m_uDAR04To00P1 >= 32) m_uDAR04To00P1 = 0; // emulate 5 bit counter
|
if (m_uDAR04To00P1 >= 32)
|
||||||
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
|
m_uDAR04To00P1 = 0; // emulate 5 bit counter
|
||||||
|
m_RomAddrP1 = (m_uDAR13To05P1 << 3) | (m_uDAR04To00P1 >> 2); // remove lower two bits
|
||||||
|
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::CWARLSB;
|
||||||
else m_uStateP1 = states::CWARLSB;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case states::CWARLSB:
|
case states::CWARLSB:
|
||||||
m_uCWARP1 = m_uCWARP2|(readmem(m_uRomAddrP2,m_bPhase1)>>4); // setup in previous state
|
m_uCWARP1 = m_uCWARP2 | (readmem(m_uRomAddrP2, m_bPhase1) >> 4); // setup in previous state
|
||||||
m_RomAddrP1 = m_uCWARP1;
|
m_RomAddrP1 = m_uCWARP1;
|
||||||
|
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::DARMSB;
|
||||||
else m_uStateP1 = states::DARMSB;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case states::DARMSB:
|
case states::DARMSB:
|
||||||
m_uDAR13To05P1 = readmem(m_uRomAddrP2,m_bPhase1)<<1; // 9 bit counter, 8 MSBs from ROM, lsb zeroed
|
m_uDAR13To05P1 = readmem(m_uRomAddrP2, m_bPhase1) << 1; // 9 bit counter, 8 MSBs from ROM, lsb zeroed
|
||||||
m_uDAR04To00P1 = 0;
|
m_uDAR04To00P1 = 0;
|
||||||
m_uCWARP1++;
|
m_uCWARP1++;
|
||||||
m_RomAddrP1 = m_uCWARP1;
|
m_RomAddrP1 = m_uCWARP1;
|
||||||
m_uNControlWords++; // statistics
|
m_uNControlWords++; // statistics
|
||||||
|
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::CTRLBITS;
|
||||||
else m_uStateP1 = states::CTRLBITS;
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case states::CTRLBITS:
|
case states::CTRLBITS:
|
||||||
m_bStopP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x80? true: false;
|
{
|
||||||
m_bVoicedP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x40? true: false;
|
u8 data = readmem(m_uRomAddrP2, m_bPhase1);
|
||||||
m_bSilenceP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x20? true: false;
|
|
||||||
m_uXRepeatP1 = readmem(m_uRomAddrP2,m_bPhase1)&0x03;
|
m_bStopP1 = bool(data & 0x80);
|
||||||
m_uLengthP1 =(readmem(m_uRomAddrP2,m_bPhase1)&0x1F)<<2; // includes external length and repeat
|
m_bVoicedP1 = bool(data & 0x40);
|
||||||
|
m_bSilenceP1 = bool(data & 0x20);
|
||||||
|
m_uXRepeatP1 = data & 0x03;
|
||||||
|
m_uLengthP1 = (data & 0x1f) << 2; // includes external length and repeat
|
||||||
m_uDAR04To00P1 = 0;
|
m_uDAR04To00P1 = 0;
|
||||||
m_uCWARP1++; // gets ready for next DARMSB
|
m_uCWARP1++; // gets ready for next DARMSB
|
||||||
m_RomAddrP1 = (m_uDAR13To05P1<<3)|(m_uDAR04To00P1>>2); // remove lower two bits
|
m_RomAddrP1 = (m_uDAR13To05P1 << 3) | (m_uDAR04To00P1 >> 2); // remove lower two bits
|
||||||
|
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::PLAY;
|
||||||
else m_uStateP1 = states::PLAY;
|
|
||||||
|
|
||||||
if (m_uPrintLevel >= 2)
|
if (m_uPrintLevel >= 2)
|
||||||
printf("\n cw %d %d %d %d %d",m_bStopP1,m_bVoicedP1,m_bSilenceP1,m_uLengthP1>>4,m_uXRepeatP1);
|
logerror("\n cw %d %d %d %d %d", m_bStopP1, m_bVoicedP1, m_bSilenceP1, m_uLengthP1 >> 4, m_uXRepeatP1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case states::PLAY:
|
case states::PLAY:
|
||||||
{
|
{
|
||||||
@ -492,38 +494,39 @@ bool s14001a_device::Clock()
|
|||||||
{
|
{
|
||||||
// pitch period end
|
// pitch period end
|
||||||
if (m_uPrintLevel >= 3)
|
if (m_uPrintLevel >= 3)
|
||||||
printf("\n ppe: RomAddr %03x",m_uRomAddrP2);
|
logerror("\n ppe: RomAddr %03x", m_uRomAddrP2);
|
||||||
|
|
||||||
m_uNPitchPeriods++;
|
m_uNPitchPeriods++;
|
||||||
if (m_bVoicedP2) m_uNVoiced++;
|
if (m_bVoicedP2)
|
||||||
|
m_uNVoiced++;
|
||||||
}
|
}
|
||||||
// end statistics
|
// end statistics
|
||||||
|
|
||||||
// modify output
|
// modify output
|
||||||
uint8_t uDeltaP2; // signal line
|
u8 uDeltaP2; // signal line
|
||||||
uint8_t uIncrementP2; // signal lines
|
u8 uIncrementP2; // signal lines
|
||||||
bool bAddP2; // signal line
|
bool bAddP2; // signal line
|
||||||
uDeltaP2 = Mux8To2(m_bVoicedP2,
|
uDeltaP2 = Mux8To2(m_bVoicedP2,
|
||||||
m_uLengthP2 & 0x03, // pitch period quater counter
|
m_uLengthP2 & 0x03, // pitch period quater counter
|
||||||
m_uDAR04To00P2 & 0x03, // two bit delta address within byte
|
m_uDAR04To00P2 & 0x03, // two bit delta address within byte
|
||||||
readmem(m_uRomAddrP2,m_bPhase1)
|
readmem(m_uRomAddrP2, m_bPhase1)
|
||||||
);
|
);
|
||||||
CalculateIncrement(m_bVoicedP2,
|
CalculateIncrement(m_bVoicedP2,
|
||||||
m_uLengthP2 & 0x03, // pitch period quater counter
|
m_uLengthP2 & 0x03, // pitch period quater counter
|
||||||
m_uDAR04To00P2 == 0, // pitch period quarter start
|
m_uDAR04To00P2 == 0, // pitch period quarter start
|
||||||
uDeltaP2,
|
uDeltaP2,
|
||||||
m_uDeltaOldP2, // input
|
m_uDeltaOldP2, // input
|
||||||
m_uDeltaOldP1, // output
|
m_uDeltaOldP1, // output
|
||||||
uIncrementP2, // output 0, 1, or 3
|
uIncrementP2, // output 0, 1, or 3
|
||||||
bAddP2 // output
|
bAddP2 // output
|
||||||
);
|
);
|
||||||
m_uOutputP1 = CalculateOutput(m_bVoicedP2,
|
m_uOutputP1 = CalculateOutput(m_bVoicedP2,
|
||||||
m_bSilenceP2,
|
m_bSilenceP2,
|
||||||
m_uLengthP2 & 0x03, // pitch period quater counter
|
m_uLengthP2 & 0x03, // pitch period quater counter
|
||||||
m_uDAR04To00P2 == 0, // pitch period quarter start
|
m_uDAR04To00P2 == 0, // pitch period quarter start
|
||||||
m_uOutputP2, // last output
|
m_uOutputP2, // last output
|
||||||
uIncrementP2,
|
uIncrementP2,
|
||||||
bAddP2
|
bAddP2
|
||||||
);
|
);
|
||||||
|
|
||||||
// advance counters
|
// advance counters
|
||||||
@ -542,42 +545,44 @@ bool s14001a_device::Clock()
|
|||||||
if (m_bVoicedP2 && m_bRepeatCarryP2) // repeat complete
|
if (m_bVoicedP2 && m_bRepeatCarryP2) // repeat complete
|
||||||
{
|
{
|
||||||
m_uLengthP1 &= 0x70; // keep current "length"
|
m_uLengthP1 &= 0x70; // keep current "length"
|
||||||
m_uLengthP1 |= (m_uXRepeatP1<<2); // load repeat from external repeat
|
m_uLengthP1 |= (m_uXRepeatP1 << 2); // load repeat from external repeat
|
||||||
m_uDAR13To05P1++; // advances ROM address 8 bytes
|
m_uDAR13To05P1++; // advances ROM address 8 bytes
|
||||||
if (m_uDAR13To05P1 >= 0x200) m_uDAR13To05P1 = 0; // emulate 9 bit counter
|
if (m_uDAR13To05P1 >= 0x200)
|
||||||
|
m_uDAR13To05P1 = 0; // emulate 9 bit counter
|
||||||
}
|
}
|
||||||
if (!m_bVoicedP2 && m_bDAR04To00CarryP2)
|
if (!m_bVoicedP2 && m_bDAR04To00CarryP2)
|
||||||
{
|
{
|
||||||
// unvoiced advances each quarter pitch period
|
// unvoiced advances each quarter pitch period
|
||||||
// note repeat counter not reloaded for non voiced speech
|
// note repeat counter not reloaded for non voiced speech
|
||||||
m_uDAR13To05P1++; // advances ROM address 8 bytes
|
m_uDAR13To05P1++; // advances ROM address 8 bytes
|
||||||
if (m_uDAR13To05P1 >= 0x200) m_uDAR13To05P1 = 0; // emulate 9 bit counter
|
if (m_uDAR13To05P1 >= 0x200)
|
||||||
|
m_uDAR13To05P1 = 0; // emulate 9 bit counter
|
||||||
}
|
}
|
||||||
|
|
||||||
// construct m_RomAddrP1
|
// construct m_RomAddrP1
|
||||||
m_RomAddrP1 = m_uDAR04To00P1;
|
m_RomAddrP1 = m_uDAR04To00P1;
|
||||||
if (m_bVoicedP2 && m_uLengthP1&0x1) // mirroring
|
if (m_bVoicedP2 && m_uLengthP1 & 0x1) // mirroring
|
||||||
{
|
|
||||||
m_RomAddrP1 ^= 0x1f; // count backwards
|
m_RomAddrP1 ^= 0x1f; // count backwards
|
||||||
}
|
m_RomAddrP1 = (m_uDAR13To05P1 << 3) | m_RomAddrP1 >> 2;
|
||||||
m_RomAddrP1 = (m_uDAR13To05P1<<3) | m_RomAddrP1>>2;
|
|
||||||
|
|
||||||
// next state
|
// next state
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
if (m_bStart)
|
||||||
else if (m_bStopP2 && m_bLengthCarryP2) m_uStateP1 = states::DELAY;
|
m_uStateP1 = states::WORDWAIT;
|
||||||
|
else if (m_bStopP2 && m_bLengthCarryP2)
|
||||||
|
m_uStateP1 = states::DELAY;
|
||||||
else if (m_bLengthCarryP2)
|
else if (m_bLengthCarryP2)
|
||||||
{
|
{
|
||||||
m_uStateP1 = states::DARMSB;
|
m_uStateP1 = states::DARMSB;
|
||||||
m_RomAddrP1 = m_uCWARP1; // output correct address
|
m_RomAddrP1 = m_uCWARP1; // output correct address
|
||||||
}
|
}
|
||||||
else m_uStateP1 = states::PLAY;
|
else
|
||||||
|
m_uStateP1 = states::PLAY;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
case states::DELAY:
|
case states::DELAY:
|
||||||
m_uOutputP1 = 7;
|
m_uOutputP1 = 7;
|
||||||
if (m_bStart) m_uStateP1 = states::WORDWAIT;
|
m_uStateP1 = m_bStart ? states::WORDWAIT : states::IDLE;
|
||||||
else m_uStateP1 = states::IDLE;
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -592,7 +597,7 @@ void s14001a_device::ClearStatistics()
|
|||||||
m_uNControlWords = 0;
|
m_uNControlWords = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void s14001a_device::GetStatistics(uint32_t &uNPitchPeriods, uint32_t &uNVoiced, uint32_t &uNControlWords)
|
void s14001a_device::GetStatistics(u32 &uNPitchPeriods, u32 &uNVoiced, u32 &uNControlWords)
|
||||||
{
|
{
|
||||||
uNPitchPeriods = m_uNPitchPeriods;
|
uNPitchPeriods = m_uNPitchPeriods;
|
||||||
uNVoiced = m_uNVoiced;
|
uNVoiced = m_uNVoiced;
|
||||||
|
@ -8,10 +8,12 @@
|
|||||||
#ifndef MAME_SOUND_S14001A_H
|
#ifndef MAME_SOUND_S14001A_H
|
||||||
#define MAME_SOUND_S14001A_H
|
#define MAME_SOUND_S14001A_H
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
class s14001a_device : public device_t, public device_sound_interface
|
class s14001a_device : public device_t, public device_sound_interface
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
|
s14001a_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||||
|
|
||||||
// configuration helpers
|
// configuration helpers
|
||||||
auto bsy() { return m_bsy_handler.bind(); }
|
auto bsy() { return m_bsy_handler.bind(); }
|
||||||
@ -20,11 +22,11 @@ public:
|
|||||||
int busy_r(); // /BUSY (pin 40)
|
int busy_r(); // /BUSY (pin 40)
|
||||||
int romen_r(); // ROM /EN (pin 9)
|
int romen_r(); // ROM /EN (pin 9)
|
||||||
void start_w(int state); // START (pin 10)
|
void start_w(int state); // START (pin 10)
|
||||||
void data_w(uint8_t data); // 6-bit word
|
void data_w(u8 data); // 6-bit word
|
||||||
|
|
||||||
void set_clock(uint32_t clock); // set new CLK frequency
|
void set_clock(u32 clock); // set new CLK frequency
|
||||||
void set_clock(const XTAL &xtal) { set_clock(xtal.value()); }
|
void set_clock(const XTAL &xtal) { set_clock(xtal.value()); }
|
||||||
void force_update(); // update stream, eg. before external ROM bankswitch
|
void force_update(); // update stream, eg. before external ROM bankswitch
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// device-level overrides
|
// device-level overrides
|
||||||
@ -34,13 +36,13 @@ protected:
|
|||||||
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
|
virtual void sound_stream_update(sound_stream &stream, std::vector<read_stream_view> const &inputs, std::vector<write_stream_view> &outputs) override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint8_t readmem(uint16_t offset, bool phase);
|
u8 readmem(u16 offset, bool phase);
|
||||||
bool Clock(); // called once to toggle external clock twice
|
bool Clock(); // called once to toggle external clock twice
|
||||||
|
|
||||||
// emulator helper functions
|
// emulator helper functions
|
||||||
void ClearStatistics();
|
void ClearStatistics();
|
||||||
void GetStatistics(uint32_t &uNPitchPeriods, uint32_t &uNVoiced, uint32_t &uNControlWords);
|
void GetStatistics(u32 &uNPitchPeriods, u32 &uNVoiced, u32 &uNControlWords);
|
||||||
void SetPrintLevel(uint32_t uPrintLevel) { m_uPrintLevel = uPrintLevel; }
|
void SetPrintLevel(u32 uPrintLevel) { m_uPrintLevel = uPrintLevel; }
|
||||||
|
|
||||||
enum class states : u8
|
enum class states : u8
|
||||||
{
|
{
|
||||||
@ -54,28 +56,28 @@ private:
|
|||||||
DELAY
|
DELAY
|
||||||
};
|
};
|
||||||
|
|
||||||
required_region_ptr<uint8_t> m_SpeechRom;
|
required_region_ptr<u8> m_SpeechRom;
|
||||||
sound_stream * m_stream;
|
sound_stream * m_stream;
|
||||||
|
|
||||||
devcb_write_line m_bsy_handler;
|
devcb_write_line m_bsy_handler;
|
||||||
devcb_read8 m_ext_read_handler;
|
devcb_read8 m_ext_read_handler;
|
||||||
|
|
||||||
// internal state
|
// internal state
|
||||||
bool m_bPhase1; // 1 bit internal clock
|
bool m_bPhase1; // 1 bit internal clock
|
||||||
|
|
||||||
// registers
|
// registers
|
||||||
states m_uStateP1; // 3 bits
|
states m_uStateP1; // 3 bits
|
||||||
states m_uStateP2;
|
states m_uStateP2;
|
||||||
|
|
||||||
uint16_t m_uDAR13To05P1; // 9 MSBs of delta address register
|
u16 m_uDAR13To05P1; // 9 MSBs of delta address register
|
||||||
uint16_t m_uDAR13To05P2; // incrementing uDAR05To13 advances ROM address by 8 bytes
|
u16 m_uDAR13To05P2; // incrementing uDAR05To13 advances ROM address by 8 bytes
|
||||||
|
|
||||||
uint16_t m_uDAR04To00P1; // 5 LSBs of delta address register
|
u16 m_uDAR04To00P1; // 5 LSBs of delta address register
|
||||||
uint16_t m_uDAR04To00P2; // 3 address ROM, 2 mux 8 bits of data into 2 bit delta
|
u16 m_uDAR04To00P2; // 3 address ROM, 2 mux 8 bits of data into 2 bit delta
|
||||||
// carry indicates end of quarter pitch period (32 cycles)
|
// carry indicates end of quarter pitch period (32 cycles)
|
||||||
|
|
||||||
uint16_t m_uCWARP1; // 12 bits Control Word Address Register (syllable)
|
u16 m_uCWARP1; // 12 bits Control Word Address Register (syllable)
|
||||||
uint16_t m_uCWARP2;
|
u16 m_uCWARP2;
|
||||||
|
|
||||||
bool m_bStopP1;
|
bool m_bStopP1;
|
||||||
bool m_bStopP2;
|
bool m_bStopP2;
|
||||||
@ -83,42 +85,42 @@ private:
|
|||||||
bool m_bVoicedP2;
|
bool m_bVoicedP2;
|
||||||
bool m_bSilenceP1;
|
bool m_bSilenceP1;
|
||||||
bool m_bSilenceP2;
|
bool m_bSilenceP2;
|
||||||
uint8_t m_uLengthP1; // 7 bits, upper three loaded from ROM length
|
u8 m_uLengthP1; // 7 bits, upper three loaded from ROM length
|
||||||
uint8_t m_uLengthP2; // middle two loaded from ROM repeat and/or uXRepeat
|
u8 m_uLengthP2; // middle two loaded from ROM repeat and/or uXRepeat
|
||||||
// bit 0 indicates mirror in voiced mode
|
// bit 0 indicates mirror in voiced mode
|
||||||
// bit 1 indicates internal silence in voiced mode
|
// bit 1 indicates internal silence in voiced mode
|
||||||
// incremented each pitch period quarter
|
// incremented each pitch period quarter
|
||||||
|
|
||||||
uint8_t m_uXRepeatP1; // 2 bits, loaded from ROM repeat
|
u8 m_uXRepeatP1; // 2 bits, loaded from ROM repeat
|
||||||
uint8_t m_uXRepeatP2;
|
u8 m_uXRepeatP2;
|
||||||
uint8_t m_uDeltaOldP1; // 2 bit old delta
|
u8 m_uDeltaOldP1; // 2 bit old delta
|
||||||
uint8_t m_uDeltaOldP2;
|
u8 m_uDeltaOldP2;
|
||||||
uint8_t m_uOutputP1; // 4 bits audio output, calculated during phase 1
|
u8 m_uOutputP1; // 4 bits audio output, calculated during phase 1
|
||||||
|
|
||||||
// derived signals
|
// derived signals
|
||||||
bool m_bDAR04To00CarryP2;
|
bool m_bDAR04To00CarryP2;
|
||||||
bool m_bPPQCarryP2;
|
bool m_bPPQCarryP2;
|
||||||
bool m_bRepeatCarryP2;
|
bool m_bRepeatCarryP2;
|
||||||
bool m_bLengthCarryP2;
|
bool m_bLengthCarryP2;
|
||||||
uint16_t m_RomAddrP1; // rom address
|
u16 m_RomAddrP1; // rom address
|
||||||
|
|
||||||
// output pins
|
// output pins
|
||||||
uint8_t m_uOutputP2; // output changes on phase2
|
u8 m_uOutputP2; // output changes on phase2
|
||||||
uint16_t m_uRomAddrP2; // address pins change on phase 2
|
u16 m_uRomAddrP2; // address pins change on phase 2
|
||||||
bool m_bBusyP1; // busy changes on phase 1
|
bool m_bBusyP1; // busy changes on phase 1
|
||||||
|
|
||||||
// input pins
|
// input pins
|
||||||
bool m_bStart;
|
bool m_bStart;
|
||||||
uint8_t m_uWord; // 6 bit word number to be spoken
|
u8 m_uWord; // 6 bit word number to be spoken
|
||||||
|
|
||||||
// emulator variables
|
// emulator variables
|
||||||
// statistics
|
// statistics
|
||||||
uint32_t m_uNPitchPeriods;
|
u32 m_uNPitchPeriods;
|
||||||
uint32_t m_uNVoiced;
|
u32 m_uNVoiced;
|
||||||
uint32_t m_uNControlWords;
|
u32 m_uNControlWords;
|
||||||
|
|
||||||
// diagnostic output
|
// diagnostic output
|
||||||
uint32_t m_uPrintLevel;
|
u32 m_uPrintLevel;
|
||||||
};
|
};
|
||||||
|
|
||||||
DECLARE_DEVICE_TYPE(S14001A, s14001a_device)
|
DECLARE_DEVICE_TYPE(S14001A, s14001a_device)
|
||||||
|
Loading…
Reference in New Issue
Block a user