summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Jonathan Gevaryahu <Lord-Nightmare@users.noreply.github.com>2018-06-16 12:31:52 -0400
committer Vas Crabb <cuavas@users.noreply.github.com>2018-06-17 02:31:52 +1000
commit395599a6fe08368d9ebff8843671b22e3329b0ca (patch)
tree32b4be325f57296c0276879d800646179f559637
parent58e5fb225ba7795e184ddaa3c1ca3e866f7ccdb0 (diff)
TMS5220 changes, bugfixes and updates (#3654)
* 5220 changes part 1: comments * 5220 changes part 2: renaming improperly capitalized pseudo-macros, and remove pseudo-macros from lvalues * 5220 part 3: reorganize savestate values into a sane, maintainable order * 5220 changes part 4: remove the unused, deprecated time_to_ready and cycles_to_ready functions * 5220 changes part 5: fix the race condition bug with m_buffer_low and m_buffer_empty flags not being updated before setting the interrupt state * 5220 changes part 6: fix the issue where if no VSM is actually attached to the 5220, the chip will get stuck speaking silence forever if it gets a Speak VSM command. In reality (at least on the tms51xx and probably the same here) the pin reads as open bus/noise, but will eventually hit a stop frame by reading 4 ones in a row. * (missed lines from parts 1 and 2) * 5220 changes part 7: add/fix debugger fences for read functions where they were missing, and a write function where it was unnecessary and caused issues when issuing manual writes from the debugger * 5220 changes part 8: change the types of the flag variables already used for boolean values to bool, and simplified comparisons with them; also renamed the ambiguous m_data_register variable to the more descriptive name of m_read_byte_register * (more missed lines from parts 1 and 2) * 5220 changes part 9: change status_read such that reading the status register from the debugger returns a valid value instead of 0, but doesn't otherwise affect the emulation * 5220 changes 10: make it so the /READY(readyq) callback only changes state to ready after a write during speak external mode, if the write actually completed because there was room in the FIFO. If not, it polls the fifo state every 16 cycles until there is room, and only then asserts the readyq callback. * 5220 changes part 11: actually zero the fifo during initialization and when speak external goes active. replace memset calls with std::fill * commit two forgotten lines
-rw-r--r--src/devices/sound/tms5220.cpp421
-rw-r--r--src/devices/sound/tms5220.h79
2 files changed, 238 insertions, 262 deletions
diff --git a/src/devices/sound/tms5220.cpp b/src/devices/sound/tms5220.cpp
index 7d6ac1abc93..2dca33fa337 100644
--- a/src/devices/sound/tms5220.cpp
+++ b/src/devices/sound/tms5220.cpp
@@ -198,6 +198,10 @@ Interpolation is inhibited (i.e. interpolation at IP frames will not happen
****Documentation of chip commands:***
+ 76543210 (these are in logical 7 thru 0 order with MSB (7) first; TI calls
+ these bits by the opposite order, D0 thru D7, on the datasheet,
+ with D0 being the MSB)
+
x0x0xbcc: on 5200/5220: NOP (does nothing)
on 5220C and CD2501ECD: Select frame length by cc, and b selects
whether every frame is preceded by 2 bits to select the frame
@@ -321,9 +325,10 @@ this), mostly on later pinballs with LPC speech)
module (6511 based), IBM PS/2 Speech adapter (parallel port connection
device), PES Speech adapter (serial port connection)
-Street electronics had a later 1989-era ECHO appleII card which is TSP50c0x/1x
-MCU based speech and not tms5xxx based (though it is likely emulating the tms5220
-in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
+Street electronics had two later 1988-1990-era ECHO appleII cards which are
+TSP50c0x/1x MCU based speech and not tms52xx based (though it is likely
+emulating the tms5220 in MCU code). Look for a 16-pin chip at U6 labeled
+"ECHO-2 SN" or "ECHO-3 SN".
***********************************************************************************************/
@@ -397,6 +402,7 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
//#define VERBOSE (LOG_GENERAL | LOG_DUMP_INPUT_DATA | LOG_FIFO | LOG_PARSE_FRAME_DUMP_HEX | LOG_FRAME_ERRORS | LOG_COMMAND_DUMP | LOG_COMMAND_VERBOSE | LOG_PIN_READS | LOG_GENERATION | LOG_GENERATION_VERBOSE | LOG_LATTICE | LOG_CLIP | LOG_IO_READY | LOG_RS_WS)
#include "logmacro.h"
+// TODO: switch the comments to be above the defines instead of below them
#define MAX_SAMPLE_CHUNK 512
@@ -441,13 +447,33 @@ static const uint8_t reload_table[4] = { 0, 2, 4, 6 }; //sample count reload for
void tms5220_device::register_for_save_states()
{
+ // for sanity purposes these variables should be in the same order as in tms5220.h!
+
+ // 5110 specific stuff
+ save_item(NAME(m_PDC));
+ save_item(NAME(m_CTL_pins));
+ save_item(NAME(m_state));
+
+ // new VSM stuff
+ save_item(NAME(m_address));
+ save_item(NAME(m_next_is_address));
+ save_item(NAME(m_schedule_dummy_read));
+ save_item(NAME(m_addr_bit));
+ save_item(NAME(m_CTL_buffer));
+
+ // old VSM stuff
+ save_item(NAME(m_read_byte_register));
+ save_item(NAME(m_RDB_flag));
+
+ // FIFO
save_item(NAME(m_fifo));
save_item(NAME(m_fifo_head));
save_item(NAME(m_fifo_tail));
save_item(NAME(m_fifo_count));
save_item(NAME(m_fifo_bits_taken));
- save_item(NAME(m_previous_TALK_STATUS));
+ // global status bits (booleans)
+ save_item(NAME(m_previous_talk_status));
save_item(NAME(m_SPEN));
save_item(NAME(m_DDIS));
save_item(NAME(m_TALK));
@@ -457,6 +483,7 @@ void tms5220_device::register_for_save_states()
save_item(NAME(m_irq_pin));
save_item(NAME(m_ready_pin));
+ // current and previous frames
save_item(NAME(m_OLDE));
save_item(NAME(m_OLDP));
@@ -493,27 +520,16 @@ void tms5220_device::register_for_save_states()
save_item(NAME(m_RNG));
save_item(NAME(m_excitation_data));
- save_item(NAME(m_schedule_dummy_read));
- save_item(NAME(m_data_register));
- save_item(NAME(m_RDB_flag));
save_item(NAME(m_digital_select));
save_item(NAME(m_io_ready));
+ // "proper" rs+ws emulation
save_item(NAME(m_true_timing));
save_item(NAME(m_rs_ws));
save_item(NAME(m_read_latch));
save_item(NAME(m_write_latch));
-
- // 5110 specific stuff
- save_item(NAME(m_PDC));
- save_item(NAME(m_CTL_pins));
- save_item(NAME(m_state));
- save_item(NAME(m_address));
- save_item(NAME(m_next_is_address));
- save_item(NAME(m_addr_bit));
- save_item(NAME(m_CTL_buffer));
}
@@ -606,7 +622,7 @@ uint8_t tms5220_device::new_int_read()
void tms5220_device::data_write(int data)
{
- int old_buffer_low = m_buffer_low;
+ bool old_buffer_low = m_buffer_low;
LOGMASKED(LOG_DUMP_INPUT_DATA, "%c", data);
if (m_DDIS) // If we're in speak external mode
@@ -621,21 +637,21 @@ void tms5220_device::data_write(int data)
update_fifo_status_and_ints();
// if we just unset buffer low with that last write, and SPEN *was* zero (see circuit 251, sheet 12)
- if ((m_SPEN == 0) && ((old_buffer_low == 1) && (m_buffer_low == 0))) // MUST HAVE EDGE DETECT
+ if ((!m_SPEN) && (old_buffer_low && (!m_buffer_low))) // MUST HAVE EDGE DETECT
{
LOGMASKED(LOG_FIFO, "data_write triggered SPEN to go active!\n");
// ...then we now have enough bytes to start talking; set zpar and clear out the new frame parameters (it will become old frame just before the first call to parse_frame() )
- m_zpar = 1;
- m_uv_zpar = 1; // zero k4-k10 as well
- m_OLDE = 1; // 'silence/zpar' frames are zero energy
- m_OLDP = 1; // 'silence/zpar' frames are zero pitch
+ m_zpar = true;
+ m_uv_zpar = true; // zero k4-k10 as well
+ m_OLDE = true; // 'silence/zpar' frames are zero energy
+ m_OLDP = true; // 'silence/zpar' frames are zero pitch
#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
- m_old_zpar = 1; // zero all the old parameters
- m_old_uv_zpar = 1; // zero old k4-k10 as well
+ m_old_zpar = true; // zero all the old parameters
+ m_old_uv_zpar = true; // zero old k4-k10 as well
#endif
- m_SPEN = 1;
+ m_SPEN = true;
#ifdef FAST_START_HACK
- m_TALK = 1;
+ m_TALK = true;
#endif
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
@@ -697,11 +713,13 @@ void tms5220_device::update_fifo_status_and_ints()
{
// generate an interrupt if necessary; if /BL was inactive and is now active, set int.
if (!m_buffer_low)
+ {
+ m_buffer_low = true;
set_interrupt_state(1);
- m_buffer_low = 1;
+ }
}
else
- m_buffer_low = 0;
+ m_buffer_low = false;
/* BE is set if neither byte 15 nor 14 of the fifo are in use; this
translates to having fifo_count equal to exactly 0
@@ -710,23 +728,25 @@ void tms5220_device::update_fifo_status_and_ints()
{
// generate an interrupt if necessary; if /BE was inactive and is now active, set int.
if (!m_buffer_empty)
+ {
+ m_buffer_empty = true;
set_interrupt_state(1);
- m_buffer_empty = 1;
+ }
if (m_DDIS)
- m_TALK = m_SPEN = 0; // /BE being active clears the TALK status via TCON, which in turn clears SPEN, but ONLY if m_DDIS is set! See patent page 16, gate 232b
+ m_TALK = m_SPEN = false; // /BE being active clears the TALK status via TCON, which in turn clears SPEN, but ONLY if m_DDIS is set! See patent page 16, gate 232b
}
else
- m_buffer_empty = 0;
+ m_buffer_empty = false;
// generate an interrupt if /TS was active, and is now inactive.
// also, in this case, regardless if DDIS was set, unset it.
- if ((m_previous_TALK_STATUS == 1) && (TALK_STATUS() == 0))
+ if (m_previous_talk_status && !talk_status())
{
LOGMASKED(LOG_GENERAL, "Talk status WAS 1, is now 0, unsetting DDIS and firing an interrupt!\n");
set_interrupt_state(1);
- m_DDIS = 0;
+ m_DDIS = false;
}
- m_previous_TALK_STATUS = TALK_STATUS();
+ m_previous_talk_status = talk_status();
}
@@ -764,6 +784,8 @@ int tms5220_device::extract_bits(int count)
// extract from VSM (speech ROM)
if (m_speechrom)
val = m_speechrom->read(count);
+ else
+ val = (1<<count)-1; // assume the input floats high if nothing is connected, so a spurious speak vsm command will eventually return a 0xF (STOP) frame which will halt speech
#else
while (count--)
{
@@ -788,23 +810,25 @@ void tms5220_device::perform_dummy_read()
/**********************************************************************************************
- tms5220_status_read -- read status or data from the TMS5220
+ tms5220_status_read -- read status or data from the TMS5220; if the bool is 1, clear interrupt
+ state.
***********************************************************************************************/
-int tms5220_device::status_read()
+uint8_t tms5220_device::status_read(bool clear_int)
{
if (m_RDB_flag)
{ /* if last command was read, return data register */
m_RDB_flag = false;
- return(m_data_register);
+ return(m_read_byte_register);
}
else
{ /* read status */
/* clear the interrupt pin on status read */
- set_interrupt_state(0);
- LOGMASKED(LOG_PIN_READS, "Status read: TS=%d BL=%d BE=%d\n", TALK_STATUS(), m_buffer_low, m_buffer_empty);
- return (TALK_STATUS() << 7) | (m_buffer_low << 6) | (m_buffer_empty << 5);
+ if (clear_int)
+ set_interrupt_state(0);
+ LOGMASKED(LOG_PIN_READS, "Status read: TS=%d BL=%d BE=%d\n", talk_status(), m_buffer_low, m_buffer_empty);
+ return (talk_status() << 7) | (m_buffer_low << 6) | (m_buffer_empty << 5);// | (m_write_latch & 0x1f); // low 5 bits are open bus, so use the m_write_latch value.
}
}
@@ -815,54 +839,14 @@ int tms5220_device::status_read()
***********************************************************************************************/
-int tms5220_device::ready_read()
+bool tms5220_device::ready_read()
{
LOGMASKED(LOG_PIN_READS, "ready_read: ready pin read, io_ready is %d, fifo count is %d, DDIS(speak external) is %d\n", m_io_ready, m_fifo_count, m_DDIS);
-
- return ((m_fifo_count < FIFO_SIZE)||(!m_DDIS)) && m_io_ready;
-}
-
-
-/**********************************************************************************************
-
- tms5220_cycles_to_ready -- returns the number of cycles until ready is asserted
- NOTE: this function is deprecated and is known to be VERY inaccurate.
- Use at your own peril!
-
-***********************************************************************************************/
-
-int tms5220_device::cycles_to_ready()
-{
- int answer;
-
-
- if (ready_read())
- answer = 0;
+ // if m_true_timing is NOT set (we're in 'hacky instant write mode'), the m_timer_io_ready doesn't run and will never de-assert m_io_ready if the fifo is full, so we need to explicitly check for fifo full here and return the proper value.
+ if (!m_true_timing)
+ return ((m_fifo_count < FIFO_SIZE)||(!m_DDIS)) && m_io_ready; // SEVERE CAVEAT: this makes the assumption that the ready_read was after wsq was 'virtually asserted', so if the fifo has no room in it ready will always return inactive, even if no write happened (i.e., after a read command when the fifo was exactly filled but no write attempted to overfill it) which is inaccurate to hardware and may cause issues! you have been warned!
else
- {
- int val;
- int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW
- int current_sample = ((m_PC*(3-m_subc_reload))+((m_subc_reload?38:25)*m_IP));
- answer = samples_per_frame-current_sample+8;
-
- // total number of bits available in current byte is (8 - m_fifo_bits_taken)
- // if more than 4 are available, we need to check the energy
- if (m_fifo_bits_taken < 4)
- {
- // read energy
- val = (m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 0xf;
- if (val == 0)
- /* 0 -> silence frame: we will only read 4 bits, and we will
- * therefore need to read another frame before the FIFO is not
- * full any more */
- answer += m_subc_reload?200:304;
- /* 15 -> stop frame, we will only read 4 bits, but the FIFO will
- * we cleared; otherwise, we need to parse the repeat flag (1 bit)
- * and the pitch (6 bits), so everything will be OK. */
- }
- }
-
- return answer;
+ return m_io_ready;
}
@@ -872,7 +856,7 @@ int tms5220_device::cycles_to_ready()
***********************************************************************************************/
-int tms5220_device::int_read()
+bool tms5220_device::int_read()
{
LOGMASKED(LOG_PIN_READS, "int_read: irq pin read, state is %d\n", m_irq_pin);
@@ -888,7 +872,7 @@ int tms5220_device::int_read()
void tms5220_device::process(int16_t *buffer, unsigned int size)
{
- int buf_count=0;
+ int buf_count = 0;
int i, bitout;
int32_t this_sample;
@@ -924,9 +908,9 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
parse_frame();
/* if the new frame is a stop frame, unset both TALK and SPEN (via TCON). TALKD remains active while the energy is ramping to 0. */
- if (NEW_FRAME_STOP_FLAG())
+ if (new_frame_stop_flag())
{
- m_TALK = m_SPEN = 0;
+ m_TALK = m_SPEN = false;
update_fifo_status_and_ints(); // probably not necessary...
}
@@ -937,19 +921,19 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
* Old frame was unvoiced, new is voiced
* Old frame was unvoiced, new frame is silence/zero energy (non-existent on tms51xx rev D and F (present and working on tms52xx, present but buggy on tms51xx rev A and B))
*/
- if ( ((OLD_FRAME_UNVOICED_FLAG() == 0) && NEW_FRAME_UNVOICED_FLAG())
- || ((OLD_FRAME_UNVOICED_FLAG() == 1) && !NEW_FRAME_UNVOICED_FLAG())
- || ((OLD_FRAME_SILENCE_FLAG() == 1) && !NEW_FRAME_SILENCE_FLAG())
- //|| ((m_inhibit == 1) && (OLD_FRAME_UNVOICED_FLAG() == 1) && NEW_FRAME_SILENCE_FLAG()) ) //TMS51xx INTERP BUG1
- || ((OLD_FRAME_UNVOICED_FLAG() == 1) && NEW_FRAME_SILENCE_FLAG()) )
- m_inhibit = 1;
+ if ( (!old_frame_unvoiced_flag() && new_frame_unvoiced_flag())
+ || (old_frame_unvoiced_flag() && !new_frame_unvoiced_flag())
+ || (old_frame_silence_flag() && !new_frame_silence_flag())
+ //|| (m_inhibit && old_frame_unvoiced_flag() && new_frame_silence_flag()) ) //TMS51xx INTERP BUG1
+ || (old_frame_unvoiced_flag() && new_frame_silence_flag()) )
+ m_inhibit = true;
else // normal frame, normal interpolation
- m_inhibit = 0;
+ m_inhibit = false;
/* Debug info for current parsed frame */
- LOGMASKED(LOG_GENERATION, "OLDE: %d; NEWE: %d; OLDP: %d; NEWP: %d ", OLD_FRAME_SILENCE_FLAG(), NEW_FRAME_SILENCE_FLAG(), OLD_FRAME_UNVOICED_FLAG(), NEW_FRAME_UNVOICED_FLAG());
+ LOGMASKED(LOG_GENERATION, "OLDE: %d; NEWE: %d; OLDP: %d; NEWP: %d ", old_frame_silence_flag(), new_frame_silence_flag(), old_frame_unvoiced_flag(), new_frame_unvoiced_flag());
LOGMASKED(LOG_GENERATION, "Processing new frame: ");
- if (m_inhibit == 0)
+ if (!m_inhibit)
LOGMASKED(LOG_GENERATION, "Normal Frame\n");
else
LOGMASKED(LOG_GENERATION, "Interpolation Inhibited\n");
@@ -971,7 +955,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
}
else // Not a new frame, just interpolate the existing frame.
{
- int inhibit_state = ((m_inhibit==1)&&(m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value
+ bool inhibit_state = (m_inhibit && (m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the m_inhibit value
#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
int samples_per_frame = m_subc_reload?175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW
//int samples_per_frame = m_subc_reload?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW
@@ -992,7 +976,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
}
else // we're done, play this frame for 1/8 frame.
{
- if (m_subcycle == 2) m_pitch_zero = 0; // this reset happens around the second subcycle during IP=0
+ if (m_subcycle == 2) m_pitch_zero = false; // this reset happens around the second subcycle during IP=0
m_current_energy = (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar));
m_current_pitch = (m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar));
for (i = 0; i < m_coeff->num_k; i++)
@@ -1024,7 +1008,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
}
// calculate the output
- if (OLD_FRAME_UNVOICED_FLAG() == 1)
+ if (old_frame_unvoiced_flag())
{
// generate unvoiced samples here
if (m_RNG & 1)
@@ -1032,7 +1016,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
else
m_excitation_data = 0x40;
}
- else /* (OLD_FRAME_UNVOICED_FLAG() == 0) */
+ else /* (!old_frame_unvoiced_flag()) */
{
// generate voiced samples here
/* US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp
@@ -1106,13 +1090,13 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
* According to testing the pitch zeroing lasts approximately 2 samples.
* We set the zeroing latch here, and unset it on PC=1 in the generator.
*/
- if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_zero = 1;
+ if ((m_IP == 7) && m_inhibit) m_pitch_zero = true;
if (m_IP == 7) // RESETL4
{
// Latch OLDE and OLDP
- //if (OLD_FRAME_SILENCE_FLAG()) m_uv_zpar = 0; // TMS51xx INTERP BUG2
- OLD_FRAME_SILENCE_FLAG() = NEW_FRAME_SILENCE_FLAG() ? 1 : 0; // m_OLDE
- OLD_FRAME_UNVOICED_FLAG() = NEW_FRAME_UNVOICED_FLAG() ? 1 : 0; // m_OLDP
+ //if (old_frame_silence_flag()) m_uv_zpar = false; // TMS51xx INTERP BUG2
+ m_OLDE = new_frame_silence_flag(); // old_frame_silence_flag()
+ m_OLDP = new_frame_unvoiced_flag(); // old_frame_unvoiced_flag()
/* if TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */
LOGMASKED(LOG_GENERATION, "RESETL4, about to update status: IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD);
@@ -1120,15 +1104,15 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
LOGMASKED(LOG_GENERATION, "tms5220_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n");
m_TALKD = m_TALK; // TALKD is latched from TALK
- update_fifo_status_and_ints(); // to trigger an interrupt if TALK_STATUS has changed
- if ((!m_TALK) && m_SPEN) m_TALK = 1; // TALK is only activated if it wasn't already active, if m_SPEN is active, and if we're in RESETL4 (which we are).
+ update_fifo_status_and_ints(); // to trigger an interrupt if talk_status has changed
+ if ((!m_TALK) && m_SPEN) m_TALK = true; // TALK is only activated if it wasn't already active, if m_SPEN is active, and if we're in RESETL4 (which we are).
LOGMASKED(LOG_GENERATION, "RESETL4, status updated: IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD);
}
m_subcycle = m_subc_reload;
m_PC = 0;
m_IP++;
- m_IP&=0x7;
+ m_IP &= 0x7;
}
else if (m_subcycle == 3)
{
@@ -1136,7 +1120,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
m_PC++;
}
m_pitch_count++;
- if ((m_pitch_count >= m_current_pitch)||(m_pitch_zero == 1)) m_pitch_count = 0;
+ if ((m_pitch_count >= m_current_pitch) || m_pitch_zero) m_pitch_count = 0;
m_pitch_count &= 0x1FF;
}
else // m_TALKD == 0
@@ -1148,7 +1132,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
{
m_TALKD = m_TALK; // TALKD is latched from TALK
update_fifo_status_and_ints(); // probably not necessary
- if ((!m_TALK) && m_SPEN) m_TALK = 1; // TALK is only activated if it wasn't already active, if m_SPEN is active, and if we're in RESETL4 (which we are).
+ if ((!m_TALK) && m_SPEN) m_TALK = true; // TALK is only activated if it wasn't already active, if m_SPEN is active, and if we're in RESETL4 (which we are).
}
m_subcycle = m_subc_reload;
m_PC = 0;
@@ -1313,9 +1297,9 @@ void tms5220_device::process_command(unsigned char cmd)
switch (cmd & 0x70)
{
case 0x10 : /* read byte */
- if (TALK_STATUS() == 0) /* TALKST must be clear for RDBY */
+ LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received\n");
+ if (!talk_status()) /* TALKST must be clear for RDBY */
{
- LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received\n");
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
@@ -1323,7 +1307,7 @@ void tms5220_device::process_command(unsigned char cmd)
m_speechrom->read(1);
}
if (m_speechrom)
- m_data_register = m_speechrom->read(8); /* read one byte from speech ROM... */
+ m_read_byte_register = m_speechrom->read(8); /* read one byte from speech ROM... */
m_RDB_flag = true;
}
else
@@ -1333,7 +1317,7 @@ void tms5220_device::process_command(unsigned char cmd)
case 0x00: case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */
if (TMS5220_HAS_RATE_CONTROL)
{
- LOGMASKED(LOG_COMMAND_VERBOSE, "Set Rate command received\n");
+ LOGMASKED(LOG_COMMAND_VERBOSE, "Set Rate (or NOP) command received\n");
m_c_variant_rate = cmd&0x0F;
}
else
@@ -1341,22 +1325,19 @@ void tms5220_device::process_command(unsigned char cmd)
break;
case 0x30 : /* read and branch */
- if (TALK_STATUS() == 0) /* TALKST must be clear for RB */
+ if (!talk_status()) /* TALKST must be clear for RB */
{
LOGMASKED(LOG_COMMAND_VERBOSE, "Read and Branch command received\n");
m_RDB_flag = false;
if (m_speechrom)
m_speechrom->read_and_branch();
}
- else
- LOGMASKED(LOG_COMMAND_VERBOSE, "Read and Branch command received during TALK state, ignoring!\n");
break;
case 0x40 : /* load address */
- if (TALK_STATUS() == 0) /* TALKST must be clear for LA */
+ LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received\n");
+ if (!talk_status()) /* TALKST must be clear for LA */
{
- LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received\n");
-
/* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
This code does not care about this. */
if (m_speechrom)
@@ -1379,14 +1360,14 @@ void tms5220_device::process_command(unsigned char cmd)
#ifdef FAST_START_HACK
m_TALK = 1;
#endif
- m_DDIS = 0;
- m_zpar = 1; // zero all the parameters
- m_uv_zpar = 1; // zero k4-k10 as well
- m_OLDE = 1; // 'silence/zpar' frames are zero energy
- m_OLDP = 1; // 'silence/zpar' frames are zero pitch
+ m_DDIS = false; // speak using VSM
+ m_zpar = true; // zero all the parameters
+ m_uv_zpar = true; // zero k4-k10 as well
+ m_OLDE = true; // 'silence/zpar' frames are zero energy
+ m_OLDP = true; // 'silence/zpar' frames are zero pitch
#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
- m_old_zpar = 1; // zero all the old parameters
- m_old_uv_zpar = 1; // zero old k4-k10 as well
+ m_old_zpar = true; // zero all the old parameters
+ m_old_uv_zpar = true; // zero old k4-k10 as well
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
@@ -1402,17 +1383,18 @@ void tms5220_device::process_command(unsigned char cmd)
case 0x60 : /* speak external */
LOGMASKED(LOG_COMMAND_VERBOSE, "Speak External command received\n");
- // SPKEXT going active activates SPKEE which clears the fifo
+ // SPKEXT going active asserts /SPKEE for 2 clocks, which clears the FIFO and its counters
+ std::fill(std::begin(m_fifo), std::end(m_fifo), 0);
m_fifo_head = m_fifo_tail = m_fifo_count = m_fifo_bits_taken = 0;
- // SPEN is enabled when the fifo passes half full (falling edge of BL signal)
- m_DDIS = 1;
- m_zpar = 1; // zero all the parameters
- m_uv_zpar = 1; // zero k4-k10 as well
- m_OLDE = 1; // 'silence/zpar' frames are zero energy
- m_OLDP = 1; // 'silence/zpar' frames are zero pitch
+ // SPEN is enabled when the FIFO passes half full (falling edge of BL signal)
+ m_DDIS = true; // speak using FIFO
+ m_zpar = true; // zero all the parameters
+ m_uv_zpar = true; // zero k4-k10 as well
+ m_OLDE = true; // 'silence/zpar' frames are zero energy
+ m_OLDP = true; // 'silence/zpar' frames are zero pitch
#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
- m_old_zpar = 1; // zero all the old parameters
- m_old_uv_zpar = 1; // zero old k4-k10 as well
+ m_old_zpar = true; // zero all the old parameters
+ m_old_uv_zpar = true; // zero old k4-k10 as well
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
@@ -1497,7 +1479,7 @@ void tms5220_device::parse_frame()
printbits(m_new_frame_pitch_idx, m_coeff->pitch_bits);
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
// if the new frame is unvoiced, be sure to zero out the k5-k10 parameters
- m_uv_zpar = NEW_FRAME_UNVOICED_FLAG() ? 1 : 0;
+ m_uv_zpar = new_frame_unvoiced_flag();
update_fifo_status_and_ints();
if (m_DDIS && m_buffer_empty) goto ranout;
// if this is a repeat frame, just do nothing, it will reuse the old coefficients
@@ -1568,13 +1550,14 @@ void tms5220_device::set_interrupt_state(int state)
void tms5220_device::update_ready_state()
{
- int state = ready_read();
-
- LOGMASKED(LOG_PIN_READS, "ready pin set to state %d\n", state);
-
- if (!m_readyq_handler.isnull() && state != m_ready_pin)
- m_readyq_handler(!state);
- m_ready_pin = state;
+ bool state = m_io_ready;
+ if (m_ready_pin != state)
+ {
+ LOGMASKED(LOG_PIN_READS, "ready pin set to state %d\n", state);
+ if (!m_readyq_handler.isnull())
+ m_readyq_handler(!state);
+ m_ready_pin = state;
+ }
}
@@ -1644,9 +1627,10 @@ void tms5220_device::device_start()
m_timer_io_ready = timer_alloc(0);
/* not during reset which is called from within a write! */
- m_io_ready = 1;
- m_true_timing = 0;
+ m_io_ready = true;
+ m_true_timing = false;
m_rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup
+ m_write_latch = 0; // assume on start that nothing is driving the data bus
register_for_save_states();
}
@@ -1659,40 +1643,40 @@ void tms5220_device::device_reset()
{
m_digital_select = FORCE_DIGITAL; // assume analog output
/* initialize the FIFO */
- /*memset(m_fifo, 0, sizeof(m_fifo));*/
+ std::fill(std::begin(m_fifo), std::end(m_fifo), 0);
m_fifo_head = m_fifo_tail = m_fifo_count = m_fifo_bits_taken = 0;
/* initialize the chip state */
/* Note that we do not actually clear IRQ on start-up : IRQ is even raised if m_buffer_empty or m_buffer_low are 0 */
- m_SPEN = m_DDIS = m_TALK = m_TALKD = m_previous_TALK_STATUS = m_irq_pin = m_ready_pin = 0;
+ m_SPEN = m_DDIS = m_TALK = m_TALKD = m_previous_talk_status = m_irq_pin = m_ready_pin = false;
set_interrupt_state(0);
update_ready_state();
- m_buffer_empty = m_buffer_low = 1;
+ m_buffer_empty = m_buffer_low = true;
m_RDB_flag = false;
/* initialize the energy/pitch/k states */
#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
m_old_frame_energy_idx = m_old_frame_pitch_idx = 0;
- memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx));
- m_old_zpar = 0;
+ std::fill(std::begin(m_old_frame_k_idx), std::end(m_old_frame_k_idx), 0);
+ m_old_zpar = false;
#endif
m_new_frame_energy_idx = m_current_energy = m_previous_energy = 0;
m_new_frame_pitch_idx = m_current_pitch = 0;
- m_zpar = m_uv_zpar = 0;
- memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx));
- memset(m_current_k, 0, sizeof(m_current_k));
+ m_zpar = m_uv_zpar = false;
+ std::fill(std::begin(m_new_frame_k_idx), std::end(m_new_frame_k_idx), 0);
+ std::fill(std::begin(m_current_k), std::end(m_current_k), 0);
/* initialize the sample generators */
- m_inhibit = 1;
+ m_inhibit = true;
m_subcycle = m_c_variant_rate = m_pitch_count = m_PC = 0;
m_subc_reload = FORCE_SUBC_RELOAD;
- m_OLDE = m_OLDP = 1;
+ m_OLDE = m_OLDP = true;
m_IP = reload_table[m_c_variant_rate&0x3];
m_RNG = 0x1FFF;
- memset(m_u, 0, sizeof(m_u));
- memset(m_x, 0, sizeof(m_x));
- m_schedule_dummy_read = 0;
+ std::fill(std::begin(m_u), std::end(m_u), 0);
+ std::fill(std::begin(m_x), std::end(m_x), 0);
+ m_schedule_dummy_read = false;
if (m_speechrom)
{
@@ -1700,7 +1684,7 @@ void tms5220_device::device_reset()
// MZ: Do the dummy read immediately. The previous line will cause a
// shift in the address pointer in the VSM. When the next command is a
// load_address, no dummy read will occur, hence the address will be
- // falsely shifted.
+ // incorrectly shifted.
m_speechrom->read(1);
m_schedule_dummy_read = false;
}
@@ -1726,35 +1710,46 @@ void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int para
{
switch(id)
{
- case 0:
- if (param)
+ case 0: // m_timer_io_ready
+ /* bring up to date first */
+ m_stream->update();
+ LOGMASKED(LOG_IO_READY, "m_timer_io_ready timer fired, param = %02x, m_rs_ws = %02x\n", param, m_rs_ws);
+ if (param) // low->high ready state
{
switch (m_rs_ws)
{
case 0x02:
/* Write */
- /* bring up to date first */
- LOGMASKED(LOG_IO_READY, "Serviced write: %02x\n", m_write_latch);
- //LOGMASKED(LOG_IO_READY, "Processed write data: %02X\n", m_write_latch);
- m_stream->update();
- data_write(m_write_latch);
- break;
+ LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Attempting to service write...\n");
+ if ((m_fifo_count >= FIFO_SIZE) && m_DDIS) // if fifo is full and we're in speak external mode
+ {
+ LOGMASKED(LOG_IO_READY, "m_timer_io_ready: in SPKEXT and FIFO was full! cannot service write now, delaying 16 cycles...\n");
+ m_timer_io_ready->adjust(clocks_to_attotime(16), 1);
+ break;
+ }
+ else
+ {
+ LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced write: %02x\n", m_write_latch);
+ data_write(m_write_latch);
+ m_io_ready = param;
+ break;
+ }
case 0x01:
/* Read */
- /* bring up to date first */
- m_stream->update();
- m_read_latch = status_read();
- LOGMASKED(LOG_IO_READY, "Serviced read, returning %02x\n", m_read_latch);
+ m_read_latch = status_read(true);
+ LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced read, returning %02x\n", m_read_latch);
+ m_io_ready = param;
break;
case 0x03:
/* High Impedance */
+ m_io_ready = param;
case 0x00:
/* illegal */
+ m_io_ready = param;
break;
}
}
- m_io_ready = param;
update_ready_state();
break;
}
@@ -1765,7 +1760,7 @@ void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int para
*/
WRITE_LINE_MEMBER( tms5220_device::rsq_w )
{
- m_true_timing = 1;
+ m_true_timing = true;
state &= 0x01;
LOGMASKED(LOG_RS_WS, "/RS written with data: %d\n", state);
@@ -1775,14 +1770,14 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
m_rs_ws = new_val;
if (new_val == 0)
{
- if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd
+ if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, probably also correct for cd2501ecd
reset();
else
/* illegal */
LOGMASKED(LOG_RS_WS, "tms5220_rsq_w: illegal\n");
return;
}
- else if ( new_val == 3)
+ else if (new_val == 3)
{
/* high impedance */
m_read_latch = 0xff;
@@ -1797,10 +1792,11 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
/* high to low - schedule ready cycle */
LOGMASKED(LOG_RS_WS, "Scheduling ready cycle for /RS...\n");
/* upon /RS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */
- m_io_ready = 0;
+ m_io_ready = false;
update_ready_state();
- /* How long does /READY stay inactive, when /RS is pulled low? I believe its almost always ~16 clocks (25 usec at 800khz as shown on the datasheet) */
- m_timer_io_ready->adjust(clocks_to_attotime(16), 1); // this should take around 10-16 (closer to ~11?) cycles to complete
+ /* How long does /READY stay inactive, when /RS is pulled low? It might be always ~16 clocks (25 usec at 800khz as shown on the datasheet)
+ but the patent schematic implies it might be as short as 4 clock cycles. */
+ m_timer_io_ready->adjust(clocks_to_attotime(16), 1);
}
}
}
@@ -1810,7 +1806,7 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
*/
WRITE_LINE_MEMBER( tms5220_device::wsq_w )
{
- m_true_timing = 1;
+ m_true_timing = true;
state &= 0x01;
LOGMASKED(LOG_RS_WS, "/WS written with data: %d\n", state);
@@ -1843,7 +1839,7 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w )
LOGMASKED(LOG_RS_WS, "Scheduling ready cycle for /WS...\n");
/* upon /WS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */
- m_io_ready = 0;
+ m_io_ready = false;
update_ready_state();
/* Now comes the complicated part: how long does /READY stay inactive, when /WS is pulled low? This depends ENTIRELY on the command written, or whether the chip is in speak external mode or not...
Speak external mode: ~16 cycles
@@ -1869,7 +1865,7 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w )
WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
{
uint8_t falling_edges;
- m_true_timing = 1;
+ m_true_timing = true;
LOGMASKED(LOG_RS_WS, "/RS and /WS written with %d and %d respectively\n", (data&2)>>1, data&1);
uint8_t new_val = data & 0x03;
@@ -1898,7 +1894,7 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
LOGMASKED(LOG_RS_WS, "Scheduling ready cycle for /WS...\n");
/* upon /WS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */
- m_io_ready = 0;
+ m_io_ready = false;
update_ready_state();
/* Now comes the complicated part: how long does /READY stay inactive, when /WS is pulled low? This depends ENTIRELY on the command written, or whether the chip is in speak external mode or not...
@@ -1922,7 +1918,7 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
LOGMASKED(LOG_RS_WS, "Scheduling ready cycle for /RS...\n");
/* upon /RS being activated, /READY goes inactive after 100 nsec from data sheet, through 3 asynchronous gates on patent. This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. */
- m_io_ready = 0;
+ m_io_ready = false;
update_ready_state();
/* How long does /READY stay inactive, when /RS is pulled low? I believe its almost always ~16 clocks (25 usec at 800khz as shown on the datasheet) */
@@ -1941,23 +1937,17 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
void tms5220_device::write_data(uint8_t data)
{
- // prevent debugger from changing the internal state
- if (machine().side_effects_disabled()) return;
-
- LOGMASKED(LOG_RS_WS, "tms5220_data_w: data %02x\n", data);
-
- if (!m_true_timing)
- {
- /* bring up to date first */
- m_stream->update();
- data_write(data);
- }
+ LOGMASKED(LOG_RS_WS, "tms5220_write_data: data %02x\n", data);
+ /* bring up to date first */
+ m_stream->update();
+ m_write_latch = data;
+ if (!m_true_timing) // if we're in the default hacky mode where we don't bother with rsq_w and wsq_w...
+ data_write(m_write_latch); // ...force the write through instantly.
else
{
/* actually in a write ? */
if (!(m_rs_ws == 0x02))
LOGMASKED(LOG_RS_WS, "tms5220_data_w: data written outside ws, status: %02x!\n", m_rs_ws);
- m_write_latch = data;
}
}
@@ -1972,13 +1962,15 @@ void tms5220_device::write_data(uint8_t data)
uint8_t tms5220_device::read_status()
{
// prevent debugger from changing the internal state
- if (machine().side_effects_disabled()) return 0;
+ if (!machine().side_effects_disabled())
+ m_stream->update(); /* bring up to date first */
if (!m_true_timing)
{
- /* bring up to date first */
- m_stream->update();
- return status_read();
+ // prevent debugger from changing the internal state
+ if (machine().side_effects_disabled())
+ return status_read(false);
+ return status_read(true);
}
else
{
@@ -1987,7 +1979,7 @@ uint8_t tms5220_device::read_status()
return m_read_latch;
else
LOGMASKED(LOG_RS_WS, "tms5220_status_r: data read outside rs!\n");
- return 0xff;
+ return 0xff; // m_write_latch; // TODO: return open bus?
}
}
@@ -2001,8 +1993,9 @@ uint8_t tms5220_device::read_status()
READ_LINE_MEMBER( tms5220_device::readyq_r )
{
- /* bring up to date first */
- m_stream->update();
+ // prevent debugger from changing the internal state
+ if (!machine().side_effects_disabled())
+ m_stream->update(); /* bring up to date first */
return !ready_read();
}
@@ -2010,29 +2003,15 @@ READ_LINE_MEMBER( tms5220_device::readyq_r )
/**********************************************************************************************
- tms5220_time_to_ready -- return the time until the ready line is asserted
-
-***********************************************************************************************/
-
-attotime tms5220_device::time_to_ready()
-{
- /* bring up to date first */
- m_stream->update();
- return clocks_to_attotime(cycles_to_ready() * 80);
-}
-
-
-
-/**********************************************************************************************
-
tms5220_int_r -- return the int status from the sound chip
***********************************************************************************************/
READ_LINE_MEMBER( tms5220_device::intq_r )
{
- /* bring up to date first */
- m_stream->update();
+ // prevent debugger from changing the internal state
+ if (!machine().side_effects_disabled())
+ m_stream->update(); /* bring up to date first */
return !int_read();
}
diff --git a/src/devices/sound/tms5220.h b/src/devices/sound/tms5220.h
index b48ca8d9b9a..f06777c3dae 100644
--- a/src/devices/sound/tms5220.h
+++ b/src/devices/sound/tms5220.h
@@ -90,8 +90,6 @@ public:
READ_LINE_MEMBER( readyq_r );
READ_LINE_MEMBER( intq_r );
- attotime time_to_ready();
-
protected:
tms5220_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock, int variant);
@@ -118,10 +116,9 @@ private:
void data_write(int data);
void update_fifo_status_and_ints();
int extract_bits(int count);
- int status_read();
- int ready_read();
- int cycles_to_ready();
- int int_read();
+ uint8_t status_read(bool clear_int);
+ bool ready_read();
+ bool int_read();
void process(int16_t *buffer, unsigned int size);
int16_t clip_analog(int16_t cliptemp) const;
int32_t matrix_multiply(int32_t a, int32_t b) const;
@@ -131,12 +128,12 @@ private:
void set_interrupt_state(int state);
void update_ready_state();
- uint8_t TALK_STATUS() const { return m_SPEN | m_TALKD; }
- uint8_t &OLD_FRAME_SILENCE_FLAG() { return m_OLDE; } // 1 if E=0, 0 otherwise.
- uint8_t &OLD_FRAME_UNVOICED_FLAG() { return m_OLDP; } // 1 if P=0 (unvoiced), 0 if voiced
- bool NEW_FRAME_STOP_FLAG() const { return m_new_frame_energy_idx == 0x0F; } // 1 if this is a stop (Energy = 0xF) frame
- bool NEW_FRAME_SILENCE_FLAG() const { return m_new_frame_energy_idx == 0; } // ditto as above
- bool NEW_FRAME_UNVOICED_FLAG() const { return m_new_frame_pitch_idx == 0; } // ditto as above
+ bool talk_status() const { return m_SPEN || m_TALKD; }
+ bool &old_frame_silence_flag() { return m_OLDE; } // 1 if E=0, 0 otherwise.
+ bool &old_frame_unvoiced_flag() { return m_OLDP; } // 1 if P=0 (unvoiced), 0 if voiced
+ bool new_frame_stop_flag() const { return m_new_frame_energy_idx == 0x0F; } // 1 if this is a stop (Energy = 0xF) frame
+ bool new_frame_silence_flag() const { return m_new_frame_energy_idx == 0; } // ditto as above
+ bool new_frame_unvoiced_flag() const { return m_new_frame_pitch_idx == 0; } // ditto as above
// debugging helper
void printbits(long data, int num);
@@ -149,23 +146,23 @@ private:
/* coefficient tables */
const struct tms5100_coeffs *m_coeff;
- /* these contain global status bits */
+ /* these contain global status bits for the 5100 */
uint8_t m_PDC;
uint8_t m_CTL_pins;
uint8_t m_state;
/* New VSM interface */
uint32_t m_address;
- uint8_t m_next_is_address;
- uint8_t m_schedule_dummy_read;
+ bool m_next_is_address;
+ bool m_schedule_dummy_read;
uint8_t m_addr_bit;
/* read byte */
uint8_t m_CTL_buffer;
/* Old VSM interface; R Nabet : These have been added to emulate speech Roms */
- //uint8_t m_schedule_dummy_read; /* set after each load address, so that next read operation is preceded by a dummy read */
- uint8_t m_data_register; /* data register, used by read command */
- uint8_t m_RDB_flag; /* whether we should read data register or status register */
+ //bool m_schedule_dummy_read; /* set after each load address, so that next read operation is preceded by a dummy read */
+ uint8_t m_read_byte_register; /* a serial->parallel shifter, used by "read byte" command to store 8 bits from the VSM */
+ bool m_RDB_flag; /* whether we should read data register or status register */
/* these contain data that describes the 128-bit data FIFO */
uint8_t m_fifo[FIFO_SIZE];
@@ -175,20 +172,20 @@ private:
uint8_t m_fifo_bits_taken;
- /* these contain global status bits */
- uint8_t m_previous_TALK_STATUS; /* this is the OLD value of TALK_STATUS (i.e. previous value of m_SPEN|m_TALKD), needed for generating interrupts on a falling TALK_STATUS edge */
- uint8_t m_SPEN; /* set on speak(or speak external and BL falling edge) command, cleared on stop command, reset command, or buffer out */
- uint8_t m_DDIS; /* If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO. */
- uint8_t m_TALK; /* set on SPEN & RESETL4(pc12->pc0 transition), cleared on stop command or reset command */
- uint8_t m_TALKD; /* TALK(TCON) value, latched every RESETL4 */
- uint8_t m_buffer_low; /* If 1, FIFO has less than 8 bytes in it */
- uint8_t m_buffer_empty; /* If 1, FIFO is empty */
- uint8_t m_irq_pin; /* state of the IRQ pin (output) */
- uint8_t m_ready_pin; /* state of the READY pin (output) */
+ /* these contain global status bits (booleans) */
+ bool m_previous_talk_status;/* this is the OLD value of talk_status (i.e. previous value of m_SPEN|m_TALKD), needed for generating interrupts on a falling talk_status edge */
+ bool m_SPEN; /* set on speak(or speak external and BL falling edge) command, cleared on stop command, reset command, or buffer out */
+ bool m_DDIS; /* If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO. */
+ bool m_TALK; /* set on SPEN & RESETL4(pc12->pc0 transition), cleared on stop command or reset command */
+ bool m_TALKD; /* TALK(TCON) value, latched every RESETL4 */
+ bool m_buffer_low; /* If 1, FIFO has less than 8 bytes in it */
+ bool m_buffer_empty; /* If 1, FIFO is empty */
+ bool m_irq_pin; /* state of the IRQ pin (output) */
+ bool m_ready_pin; /* state of the READY pin (output) */
/* these contain data describing the current and previous voice frames */
- uint8_t m_OLDE;
- uint8_t m_OLDP;
+ bool m_OLDE;
+ bool m_OLDP;
uint8_t m_new_frame_energy_idx;
uint8_t m_new_frame_pitch_idx;
@@ -204,8 +201,8 @@ private:
uint8_t m_old_frame_energy_idx;
uint8_t m_old_frame_pitch_idx;
uint8_t m_old_frame_k_idx[10];
- uint8_t m_old_zpar;
- uint8_t m_old_uv_zpar;
+ bool m_old_zpar;
+ bool m_old_uv_zpar;
int32_t m_current_energy;
int32_t m_current_pitch;
@@ -219,11 +216,11 @@ private:
uint8_t m_PC; /* current parameter counter (what param is being interpolated), ranges from 0 to 12 */
/* NOTE: the interpolation period counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1 */
uint8_t m_IP; /* the current interpolation period */
- uint8_t m_inhibit; /* If 1, interpolation is inhibited until the DIV1 period */
- uint8_t m_uv_zpar; /* If 1, zero k5 thru k10 coefficients */
- uint8_t m_zpar; /* If 1, zero ALL parameters. */
- uint8_t m_pitch_zero; /* circuit 412; pitch is forced to zero under certain circumstances */
- uint8_t m_c_variant_rate; /* only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command */
+ bool m_inhibit; /* If 1, interpolation is inhibited until the DIV1 period */
+ bool m_uv_zpar; /* If 1, zero k5 thru k10 coefficients */
+ bool m_zpar; /* If 1, zero ALL parameters. */
+ bool m_pitch_zero; /* circuit 412; pitch is forced to zero under certain circumstances */
+ uint8_t m_c_variant_rate; /* only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command */
uint16_t m_pitch_count; /* pitch counter; provides chirp rom address */
int32_t m_u[11];
@@ -237,17 +234,17 @@ private:
The internal DAC used to feed the analog pin is only 8 bits, and has the
funny clipping/clamping logic, while the digital pin gives full 10 bit
resolution of the output data.
- TODO: add a way to set/reset this other than the FORCE_DIGITAL define
+ TODO: add an MCFG macro to set this other than the FORCE_DIGITAL define
*/
- uint8_t m_digital_select;
+ bool m_digital_select;
/* io_ready: page 3 of the datasheet specifies that READY will be asserted until
* data is available or processed by the system.
*/
- uint8_t m_io_ready;
+ bool m_io_ready;
/* flag for "true" timing involving rs/ws */
- uint8_t m_true_timing;
+ bool m_true_timing;
/* rsws - state, rs bit 1, ws bit 0 */
uint8_t m_rs_ws;