tms5220: Convert logging calls to logmacro.h standard (nw)

This also reinstates the command logging improvements from 62fc2e8f06.
This commit is contained in:
AJR 2018-06-12 10:20:47 -04:00
parent d94e8b2664
commit 4c62c8a48f
2 changed files with 273 additions and 338 deletions

View File

@ -330,8 +330,6 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
#include "emu.h"
#include "tms5220.h"
static int16_t clip_analog(int16_t cliptemp);
/* *****optional defines***** */
/* Hacky improvements which don't match patent: */
@ -365,38 +363,41 @@ static int16_t clip_analog(int16_t cliptemp);
/* *****debugging defines***** */
#undef VERBOSE
#define LOG_GENERAL (1 << 0)
// above is general, somewhat obsolete, catch all for debugs which don't fit elsewhere
#undef DEBUG_DUMP_INPUT_DATA
#define LOG_DUMP_INPUT_DATA (1 << 1)
/* 5220 only; above dumps the data written to the tms52xx to stdout, useful
for making logged data dumps for real hardware tests */
#undef DEBUG_FIFO
#define LOG_FIFO (1 << 2)
// 5220 only; above debugs fifo stuff: writes, reads and flag updates
#undef DEBUG_PARSE_FRAME_DUMP
// above dumps each frame to stderr: be sure to select one of the options below if you define it!
#undef DEBUG_PARSE_FRAME_DUMP_BIN
#define LOG_PARSE_FRAME_DUMP_BIN (1 << 3)
// dumps each speech frame as binary
#undef DEBUG_PARSE_FRAME_DUMP_HEX
#define LOG_PARSE_FRAME_DUMP_HEX (1 << 4)
// dumps each speech frame as hex
#undef DEBUG_FRAME_ERRORS
#define LOG_FRAME_ERRORS (1 << 6)
// above dumps info if a frame ran out of data
#undef DEBUG_COMMAND_DUMP
#define LOG_COMMAND_DUMP (1 << 7)
// above dumps all non-speech-data command writes
#undef DEBUG_PIN_READS
#define LOG_COMMAND_VERBOSE (1 << 8)
// above dumps decoded info about command writes
#define LOG_PIN_READS (1 << 9)
// above spams the errorlog with i/o ready messages whenever the ready or irq pin is read
#undef DEBUG_GENERATION
#define LOG_GENERATION (1 << 10)
// above dumps debug information related to the sample generation loop, i.e. whether interpolation is inhibited or not, and what the current and target values for each frame are.
#undef DEBUG_GENERATION_VERBOSE
#define LOG_GENERATION_VERBOSE (1 << 11)
// above dumps MUCH MORE debug information related to the sample generation loop, namely the excitation, energy, pitch, k*, and output values for EVERY SINGLE SAMPLE during a frame.
#undef DEBUG_LATTICE
#define LOG_LATTICE (1 << 12)
// above dumps the lattice filter state data each sample.
#undef DEBUG_CLIP
#define LOG_CLIP (1 << 13)
// above dumps info to stderr whenever the analog clip hardware is (or would be) clipping the signal.
#undef DEBUG_IO_READY
// above debugs the io ready callback
#undef DEBUG_RS_WS
#define LOG_IO_READY (1 << 14)
// above debugs the io ready callback timer
#define LOG_RS_WS (1 << 15)
// above debugs the tms5220_data_r and data_w access methods which actually respect rs and ws
//#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"
#define MAX_SAMPLE_CHUNK 512
/* 6+4 Variants, from tms5110r.inc */
@ -522,37 +523,30 @@ void tms5220_device::register_for_save_states()
***********************************************************************************************/
#ifdef DEBUG_PARSE_FRAME_DUMP_BIN
static void printbits(long data, int num)
void tms5220_device::printbits(long data, int num)
{
int i;
for (i=(num-1); i>=0; i--)
logerror("%0ld", (data>>i)&1);
}
#endif
#ifdef DEBUG_PARSE_FRAME_DUMP_HEX
static void printbits(long data, int num)
{
switch((num-1)&0xFC)
for (int i = num - 1; i >= 0; i--)
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN, "%0ld", (data>>i)&1);
switch ((num - 1) & 0xfc)
{
case 0:
logerror("%0lx", data);
break;
case 4:
logerror("%02lx", data);
break;
case 8:
logerror("%03lx", data);
break;
case 12:
logerror("%04lx", data);
break;
default:
logerror("%04lx", data);
break;
case 0:
LOGMASKED(LOG_PARSE_FRAME_DUMP_HEX, "%0lx", data);
break;
case 4:
LOGMASKED(LOG_PARSE_FRAME_DUMP_HEX, "%02lx", data);
break;
case 8:
LOGMASKED(LOG_PARSE_FRAME_DUMP_HEX, "%03lx", data);
break;
case 12:
LOGMASKED(LOG_PARSE_FRAME_DUMP_HEX, "%04lx", data);
break;
default:
LOGMASKED(LOG_PARSE_FRAME_DUMP_HEX, "%04lx", data);
break;
}
}
#endif
/**********************************************************************************************
@ -600,9 +594,7 @@ uint8_t tms5220_device::new_int_read()
new_int_write(0, 0, 0, 0); // romclk 0, m0 0, m1 0, addr bus nybble = 0/open bus
if (!m_data_cb.isnull())
return m_data_cb();
#ifdef VERBOSE
logerror("WARNING: CALLBACK MISSING, RETURNING 0!\n");
#endif
LOGMASKED(LOG_GENERAL, "WARNING: CALLBACK MISSING, RETURNING 0!\n");
return 0;
}
@ -615,9 +607,8 @@ uint8_t tms5220_device::new_int_read()
void tms5220_device::data_write(int data)
{
int old_buffer_low = m_buffer_low;
#ifdef DEBUG_DUMP_INPUT_DATA
fprintf(stdout, "%c",data);
#endif
LOGMASKED(LOG_DUMP_INPUT_DATA, "%c", data);
if (m_DDIS) // If we're in speak external mode
{
// add this byte to the FIFO
@ -626,17 +617,13 @@ void tms5220_device::data_write(int data)
m_fifo[m_fifo_tail] = data;
m_fifo_tail = (m_fifo_tail + 1) % FIFO_SIZE;
m_fifo_count++;
#ifdef DEBUG_FIFO
logerror("data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count);
#endif
LOGMASKED(LOG_FIFO, "data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count);
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
{
int i;
#ifdef DEBUG_FIFO
logerror("data_write triggered SPEN to go active!\n");
#endif
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
@ -652,21 +639,19 @@ void tms5220_device::data_write(int data)
#endif
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
for (i = 0; i < 4; i++)
for (int i = 0; i < 4; i++)
m_new_frame_k_idx[i] = 0;
for (i = 4; i < 7; i++)
for (int i = 4; i < 7; i++)
m_new_frame_k_idx[i] = 0xF;
for (i = 7; i < m_coeff->num_k; i++)
for (int i = 7; i < m_coeff->num_k; i++)
m_new_frame_k_idx[i] = 0x7;
}
}
else
{
#ifdef DEBUG_FIFO
logerror("data_write: Ran out of room in the tms52xx FIFO! this should never happen!\n");
LOGMASKED(LOG_FIFO, "data_write: Ran out of room in the tms52xx FIFO! this should never happen!\n");
// at this point, /READY should remain HIGH/inactive until the fifo has at least one byte open in it.
#endif
}
@ -737,9 +722,7 @@ void tms5220_device::update_fifo_status_and_ints()
// also, in this case, regardless if DDIS was set, unset it.
if ((m_previous_TALK_STATUS == 1) && (TALK_STATUS() == 0))
{
#ifdef VERBOSE
logerror("Talk status WAS 1, is now 0, unsetting DDIS and firing an interrupt!\n");
#endif
LOGMASKED(LOG_GENERAL, "Talk status WAS 1, is now 0, unsetting DDIS and firing an interrupt!\n");
set_interrupt_state(1);
m_DDIS = 0;
}
@ -785,9 +768,7 @@ int tms5220_device::extract_bits(int count)
while (count--)
{
val = (val << 1) | new_int_read();
#ifdef VERBOSE
logerror("bit read: %d\n", val&1);
#endif
LOGMASKED(LOG_GENERAL, "bit read: %d\n", val&1);
}
#endif
}
@ -799,12 +780,8 @@ void tms5220_device::perform_dummy_read()
{
if (m_schedule_dummy_read)
{
#ifdef VERBOSE
int data = new_int_read();
logerror("TMS5110 performing dummy read; value read = %1i\n", data & 1);
#else
new_int_read();
#endif
LOGMASKED(LOG_GENERAL, "TMS5110 performing dummy read; value read = %1i\n", data & 1);
m_schedule_dummy_read = false;
}
}
@ -826,9 +803,7 @@ int tms5220_device::status_read()
{ /* read status */
/* clear the interrupt pin on status read */
set_interrupt_state(0);
#ifdef DEBUG_PIN_READS
logerror("Status read: TS=%d BL=%d BE=%d\n", TALK_STATUS(), m_buffer_low, m_buffer_empty);
#endif
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);
}
}
@ -842,9 +817,8 @@ int tms5220_device::status_read()
int tms5220_device::ready_read()
{
#ifdef DEBUG_PIN_READS
logerror("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);
#endif
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;
}
@ -900,9 +874,8 @@ int tms5220_device::cycles_to_ready()
int tms5220_device::int_read()
{
#ifdef DEBUG_PIN_READS
logerror("int_read: irq pin read, state is %d\n", m_irq_pin);
#endif
LOGMASKED(LOG_PIN_READS, "int_read: irq pin read, state is %d\n", m_irq_pin);
return m_irq_pin;
}
@ -919,9 +892,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
int i, bitout;
int32_t this_sample;
#ifdef VERBOSE
logerror("process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD);
#endif
LOGMASKED(LOG_GENERAL, "process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD);
/* loop until the buffer is full or we've stopped speaking */
while (size > 0)
@ -975,16 +946,15 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
else // normal frame, normal interpolation
m_inhibit = 0;
#ifdef DEBUG_GENERATION
/* Debug info for current parsed frame */
logerror( "OLDE: %d; NEWE: %d; OLDP: %d; NEWP: %d ", OLD_FRAME_SILENCE_FLAG(), NEW_FRAME_SILENCE_FLAG(), OLD_FRAME_UNVOICED_FLAG(), NEW_FRAME_UNVOICED_FLAG());
logerror("Processing new 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, "Processing new frame: ");
if (m_inhibit == 0)
logerror( "Normal Frame\n");
LOGMASKED(LOG_GENERATION, "Normal Frame\n");
else
logerror("Interpolation Inhibited\n");
logerror("*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]);
logerror("*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",
LOGMASKED(LOG_GENERATION, "Interpolation Inhibited\n");
LOGMASKED(LOG_GENERATION, "*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]);
LOGMASKED(LOG_GENERATION, "*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",
(m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)),
m_new_frame_energy_idx,
(m_coeff->pitchtable[m_new_frame_pitch_idx] * (1-m_zpar)),
@ -998,8 +968,6 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
(m_coeff->ktable[7][m_new_frame_k_idx[7]] * (1-m_uv_zpar)),
(m_coeff->ktable[8][m_new_frame_k_idx[8]] * (1-m_uv_zpar)),
(m_coeff->ktable[9][m_new_frame_k_idx[9]] * (1-m_uv_zpar)) );
#endif
}
else // Not a new frame, just interpolate the existing frame.
{
@ -1090,20 +1058,20 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
m_RNG |= bitout;
}
this_sample = lattice_filter(); /* execute lattice filter */
#ifdef DEBUG_GENERATION_VERBOSE
//logerror("C:%01d; ",m_subcycle);
logerror("IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count);
//logerror("X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count);
//LOGMASKED(LOG_GENERATION_VERBOSE, "C:%01d; ",m_subcycle);
LOGMASKED(LOG_GENERATION_VERBOSE, "IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_IP, m_PC, m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count);
//LOGMASKED(LOG_GENERATION_VERBOSE, "X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count);
for (i=0; i<10; i++)
logerror("K%d:%04d ", i+1, m_current_k[i]);
logerror("Out:%06d ", this_sample);
LOGMASKED(LOG_GENERATION_VERBOSE, "K%d:%04d ", i+1, m_current_k[i]);
LOGMASKED(LOG_GENERATION_VERBOSE, "Out:%06d ", this_sample);
//#ifdef TMS5220_PERFECT_INTERPOLATION_HACK
// logerror("%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar);
// LOGMASKED(LOG_GENERATION_VERBOSE, "%d%d%d%d",m_old_zpar,m_zpar,m_old_uv_zpar,m_uv_zpar);
//#else
// logerror("x%dx%d",m_zpar,m_uv_zpar);
// LOGMASKED(LOG_GENERATION_VERBOSE, "x%dx%d",m_zpar,m_uv_zpar);
//#endif
logerror("\n");
#endif
LOGMASKED(LOG_GENERATION_VERBOSE, "\n");
/* next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) */
while (this_sample > 16383) this_sample -= 32768;
while (this_sample < -16384) this_sample += 32768;
@ -1146,19 +1114,16 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
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 TALK was clear last frame, halt speech now, since TALKD (latched from TALK on new frame) just went inactive. */
#ifdef DEBUG_GENERATION
logerror("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);
#endif
#ifdef DEBUG_GENERATION
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);
if ((!m_TALK) && (!m_SPEN))
logerror("tms5220_process: processing frame: TALKD = 0 caused by stop frame or buffer empty, halting speech.\n");
#endif
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).
#ifdef DEBUG_GENERATION
logerror("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);
#endif
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;
@ -1208,7 +1173,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size)
***********************************************************************************************/
static int16_t clip_analog(int16_t cliptemp)
int16_t tms5220_device::clip_analog(int16_t cliptemp) const
{
/* clipping, just like the patent shows:
* the top 10 bits of this result are visible on the digital output IO pin.
@ -1218,9 +1183,8 @@ static int16_t clip_analog(int16_t cliptemp)
* 00 0bcd efgh xxxx -> 0b0bcdefgh
* 0x xxxx xxxx xxxx -> 0b01111111
*/
#ifdef DEBUG_CLIP
if ((cliptemp > 2047) || (cliptemp < -2048)) logerror("clipping cliptemp to range; was %d\n", cliptemp);
#endif
if ((cliptemp > 2047) || (cliptemp < -2048))
LOGMASKED(LOG_CLIP, "clipping cliptemp to range; was %d\n", cliptemp);
if (cliptemp > 2047) cliptemp = 2047;
else if (cliptemp < -2048) cliptemp = -2048;
/* at this point the analog output is tapped */
@ -1250,7 +1214,7 @@ static int16_t clip_analog(int16_t cliptemp)
output, this makes almost no difference in the computation.
**********************************************************************************************/
static int32_t matrix_multiply(int32_t a, int32_t b)
int32_t tms5220_device::matrix_multiply(int32_t a, int32_t b) const
{
int32_t result;
while (a>511) { a-=1024; }
@ -1258,10 +1222,8 @@ static int32_t matrix_multiply(int32_t a, int32_t b)
while (b>16383) { b-=32768; }
while (b<-16384) { b+=32768; }
result = ((a*b)>>9); /** TODO: this isn't technically right to the chip, which truncates the lowest result bit, but it causes glitches otherwise. **/
#ifdef VERBOSE
if (result>16383) logerror("matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result);
if (result<-16384) logerror("matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result);
#endif
if (result>16383) LOGMASKED(LOG_GENERAL, "matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result);
if (result<-16384) LOGMASKED(LOG_GENERAL, "matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result);
return result;
}
@ -1307,9 +1269,7 @@ int32_t tms5220_device::lattice_filter()
m_u[2] = m_u[3] - matrix_multiply(m_current_k[2], m_x[2]);
m_u[1] = m_u[2] - matrix_multiply(m_current_k[1], m_x[1]);
m_u[0] = m_u[1] - matrix_multiply(m_current_k[0], m_x[0]);
#ifdef DEBUG_LATTICE
int32_t err = m_x[9] + matrix_multiply(m_current_k[9], m_u[9]); //x_10, real chip doesn't use or calculate this
#endif
m_x[9] = m_x[8] + matrix_multiply(m_current_k[8], m_u[8]);
m_x[8] = m_x[7] + matrix_multiply(m_current_k[7], m_u[7]);
m_x[7] = m_x[6] + matrix_multiply(m_current_k[6], m_u[6]);
@ -1321,21 +1281,20 @@ int32_t tms5220_device::lattice_filter()
m_x[1] = m_x[0] + matrix_multiply(m_current_k[0], m_u[0]);
m_x[0] = m_u[0];
m_previous_energy = m_current_energy;
#ifdef DEBUG_LATTICE
int i;
logerror("V:%04d ", m_u[10]);
for (i = 9; i >= 0; i--)
LOGMASKED(LOG_LATTICE, "V:%04d ", m_u[10]);
for (int i = 9; i >= 0; i--)
{
logerror("Y%d:%04d ", i+1, m_u[i]);
LOGMASKED(LOG_LATTICE, "Y%d:%04d ", i+1, m_u[i]);
}
logerror("\n");
logerror("E:%04d ", err);
for (i = 9; i >= 0; i--)
LOGMASKED(LOG_LATTICE, "\n");
LOGMASKED(LOG_LATTICE, "E:%04d ", err);
for (int i = 9; i >= 0; i--)
{
logerror("b%d:%04d ", i+1, m_x[i]);
LOGMASKED(LOG_LATTICE, "b%d:%04d ", i+1, m_x[i]);
}
logerror("\n");
#endif
LOGMASKED(LOG_LATTICE, "\n");
return m_u[0];
}
@ -1348,123 +1307,135 @@ int32_t tms5220_device::lattice_filter()
void tms5220_device::process_command(unsigned char cmd)
{
int i;
#ifdef DEBUG_COMMAND_DUMP
logerror("process_command called with parameter %02X\n",cmd);
#endif
/* parse the command */
switch (cmd & 0x70)
LOGMASKED(LOG_COMMAND_DUMP, "process_command called with parameter %02X\n", cmd);
/* parse the command */
switch (cmd & 0x70)
{
case 0x10 : /* read byte */
if (TALK_STATUS() == 0) /* TALKST must be clear for RDBY */
{
case 0x10 : /* read byte */
if (TALK_STATUS() == 0) /* TALKST must be clear for RDBY */
{
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
}
if (m_speechrom)
m_data_register = m_speechrom->read(8); /* read one byte from speech ROM... */
m_RDB_flag = true;
}
break;
case 0x00: case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */
if (TMS5220_HAS_RATE_CONTROL)
{
m_c_variant_rate = cmd&0x0F;
}
break;
case 0x30 : /* read and branch */
if (TALK_STATUS() == 0) /* TALKST must be clear for RB */
{
#ifdef VERBOSE
logerror("read and branch command received\n");
#endif
m_RDB_flag = false;
if (m_speechrom)
m_speechrom->read_and_branch();
}
break;
case 0x40 : /* load address */
if (TALK_STATUS() == 0) /* TALKST must be clear for LA */
{
/* 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)
m_speechrom->load_address(cmd & 0x0f);
m_schedule_dummy_read = true;
}
break;
case 0x50 : /* speak */
LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received\n");
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
}
m_SPEN = 1;
#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
#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
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
for (i = 0; i < 4; i++)
m_new_frame_k_idx[i] = 0;
for (i = 4; i < 7; i++)
m_new_frame_k_idx[i] = 0xF;
for (i = 7; i < m_coeff->num_k; i++)
m_new_frame_k_idx[i] = 0x7;
break;
if (m_speechrom)
m_data_register = m_speechrom->read(8); /* read one byte from speech ROM... */
m_RDB_flag = true;
}
else
LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received during TALK state, ignoring!\n");
break;
case 0x60 : /* speak external */
// SPKEXT going active activates SPKEE which clears the fifo
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
#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
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
for (i = 0; i < 4; i++)
m_new_frame_k_idx[i] = 0;
for (i = 4; i < 7; i++)
m_new_frame_k_idx[i] = 0xF;
for (i = 7; i < m_coeff->num_k; i++)
m_new_frame_k_idx[i] = 0x7;
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");
m_c_variant_rate = cmd&0x0F;
}
else
LOGMASKED(LOG_COMMAND_VERBOSE, "NOP command received\n");
break;
case 0x30 : /* read and branch */
if (TALK_STATUS() == 0) /* TALKST must be clear for RB */
{
LOGMASKED(LOG_COMMAND_VERBOSE, "Read and Branch command received\n");
m_RDB_flag = false;
break;
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 0x70 : /* reset */
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
}
reset();
break;
case 0x40 : /* load address */
if (TALK_STATUS() == 0) /* 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)
m_speechrom->load_address(cmd & 0x0f);
m_schedule_dummy_read = true;
}
else
LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received during TALK state, ignoring!\n");
break;
case 0x50 : /* speak */
LOGMASKED(LOG_COMMAND_VERBOSE, "Speak (VSM) command received\n");
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
}
m_SPEN = 1;
#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
#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
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
for (int i = 0; i < 4; i++)
m_new_frame_k_idx[i] = 0;
for (int i = 4; i < 7; i++)
m_new_frame_k_idx[i] = 0xF;
for (int i = 7; i < m_coeff->num_k; i++)
m_new_frame_k_idx[i] = 0x7;
break;
case 0x60 : /* speak external */
LOGMASKED(LOG_COMMAND_VERBOSE, "Speak External command received\n");
// SPKEXT going active activates SPKEE which clears the fifo
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
#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
#endif
// following is semi-hack but matches idle state observed on chip
m_new_frame_energy_idx = 0;
m_new_frame_pitch_idx = 0;
for (int i = 0; i < 4; i++)
m_new_frame_k_idx[i] = 0;
for (int i = 4; i < 7; i++)
m_new_frame_k_idx[i] = 0xF;
for (int i = 7; i < m_coeff->num_k; i++)
m_new_frame_k_idx[i] = 0x7;
m_RDB_flag = false;
break;
case 0x70 : /* reset */
LOGMASKED(LOG_COMMAND_VERBOSE, "Reset command received\n");
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
}
reset();
break;
}
/* update the buffer low state */
@ -1495,10 +1466,8 @@ void tms5220_device::parse_frame()
if ((TMS5220_HAS_RATE_CONTROL) && (m_c_variant_rate & 0x04))
{
i = extract_bits(2);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(i,2);
logerror(" ");
#endif
printbits(i, 2);
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
m_IP = reload_table[i];
}
else // non-5220C and 5220C in fixed rate mode
@ -1509,10 +1478,8 @@ void tms5220_device::parse_frame()
// attempt to extract the energy index
m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(m_new_frame_energy_idx,m_coeff->energy_bits);
logerror(" ");
#endif
printbits(m_new_frame_energy_idx, m_coeff->energy_bits);
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
update_fifo_status_and_ints();
if (m_DDIS && m_buffer_empty) goto ranout;
// if the energy index is 0 or 15, we're done
@ -1522,17 +1489,13 @@ void tms5220_device::parse_frame()
// attempt to extract the repeat flag
rep_flag = extract_bits(1);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(rep_flag, 1);
logerror(" ");
#endif
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
// attempt to extract the pitch
m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(m_new_frame_pitch_idx,m_coeff->pitch_bits);
logerror(" ");
#endif
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;
update_fifo_status_and_ints();
@ -1545,10 +1508,8 @@ void tms5220_device::parse_frame()
for (i = 0; i < 4; i++)
{
m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]);
logerror(" ");
#endif
printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]);
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
update_fifo_status_and_ints();
if (m_DDIS && m_buffer_empty) goto ranout;
}
@ -1564,28 +1525,21 @@ void tms5220_device::parse_frame()
for (i = 4; i < m_coeff->num_k; i++)
{
m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]);
logerror(" ");
#endif
printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]);
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " ");
update_fifo_status_and_ints();
if (m_DDIS && m_buffer_empty) goto ranout;
}
#ifdef DEBUG_PARSE_FRAME_DUMP
logerror("\n");
#endif
#ifdef VERBOSE
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, "\n");
if (m_DDIS)
logerror("Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken));
LOGMASKED(LOG_GENERAL, "Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken));
else
logerror("Parsed a frame successfully in ROM\n");
#endif
LOGMASKED(LOG_GENERAL, "Parsed a frame successfully in ROM\n");
return;
ranout:
#ifdef DEBUG_FRAME_ERRORS
logerror("Ran out of bits on a parse!\n");
#endif
LOGMASKED(LOG_FRAME_ERRORS, "Ran out of bits on a parse!\n");
return;
}
@ -1598,9 +1552,9 @@ void tms5220_device::parse_frame()
void tms5220_device::set_interrupt_state(int state)
{
if (!TMS5220_IS_52xx) return; // bail out if not a 52xx chip, since there's no int pin
#ifdef DEBUG_PIN_READS
logerror("irq pin set to state %d\n", state);
#endif
LOGMASKED(LOG_PIN_READS, "irq pin set to state %d\n", state);
if (!m_irq_handler.isnull() && state != m_irq_pin)
m_irq_handler(!state);
m_irq_pin = state;
@ -1615,9 +1569,9 @@ void tms5220_device::set_interrupt_state(int state)
void tms5220_device::update_ready_state()
{
int state = ready_read();
#ifdef DEBUG_PIN_READS
logerror("ready pin set to state %d\n", state);
#endif
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;
@ -1780,10 +1734,8 @@ void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int para
case 0x02:
/* Write */
/* bring up to date first */
#ifdef DEBUG_IO_READY
logerror("Serviced write: %02x\n", m_write_latch);
//logerror( "Processed write data: %02X\n", m_write_latch);
#endif
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;
@ -1792,9 +1744,7 @@ void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int para
/* bring up to date first */
m_stream->update();
m_read_latch = status_read();
#ifdef DEBUG_IO_READY
logerror("Serviced read, returning %02x\n", m_read_latch);
#endif
LOGMASKED(LOG_IO_READY, "Serviced read, returning %02x\n", m_read_latch);
break;
case 0x03:
/* High Impedance */
@ -1815,14 +1765,11 @@ void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int para
*/
WRITE_LINE_MEMBER( tms5220_device::rsq_w )
{
uint8_t new_val;
m_true_timing = 1;
state &= 0x01;
#ifdef DEBUG_RS_WS
logerror("/RS written with data: %d\n", state);
#endif
new_val = (m_rs_ws & 0x01) | (state<<1);
LOGMASKED(LOG_RS_WS, "/RS written with data: %d\n", state);
uint8_t new_val = (m_rs_ws & 0x01) | (state<<1);
if (new_val != m_rs_ws)
{
m_rs_ws = new_val;
@ -1830,11 +1777,9 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
{
if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd
reset();
#ifdef DEBUG_RS_WS
else
/* illegal */
logerror("tms5220_rsq_w: illegal\n");
#endif
LOGMASKED(LOG_RS_WS, "tms5220_rsq_w: illegal\n");
return;
}
else if ( new_val == 3)
@ -1850,9 +1795,7 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
else
{
/* high to low - schedule ready cycle */
#ifdef DEBUG_RS_WS
logerror("Scheduling ready cycle for /RS...\n");
#endif
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;
update_ready_state();
@ -1867,14 +1810,11 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w )
*/
WRITE_LINE_MEMBER( tms5220_device::wsq_w )
{
uint8_t new_val;
m_true_timing = 1;
state &= 0x01;
#ifdef DEBUG_RS_WS
logerror("/WS written with data: %d\n", state);
#endif
new_val = (m_rs_ws & 0x02) | (state<<0);
LOGMASKED(LOG_RS_WS, "/WS written with data: %d\n", state);
uint8_t new_val = (m_rs_ws & 0x02) | (state<<0);
if (new_val != m_rs_ws)
{
m_rs_ws = new_val;
@ -1882,11 +1822,9 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w )
{
if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, probably also correct for cd2501ecd
reset();
#ifdef DEBUG_RS_WS
else
/* illegal */
logerror("tms5220_wsq_w: illegal\n");
#endif
LOGMASKED(LOG_RS_WS, "tms5220_wsq_w: illegal\n");
return;
}
else if ( new_val == 3)
@ -1902,9 +1840,8 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w )
else
{
/* high to low - schedule ready cycle */
#ifdef DEBUG_RS_WS
logerror("Scheduling ready cycle for /WS...\n");
#endif
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;
update_ready_state();
@ -1931,13 +1868,11 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w )
*/
WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
{
uint8_t new_val;
uint8_t falling_edges;
m_true_timing = 1;
#ifdef DEBUG_RS_WS
logerror("/RS and /WS written with %d and %d respectively\n", (data&2)>>1, data&1);
#endif
new_val = data&0x03;
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;
if (new_val != m_rs_ws)
{
falling_edges = ((m_rs_ws^new_val)&(~new_val));
@ -1947,11 +1882,9 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
case 0:
if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, probably also correct for cd2501ecd
reset();
#ifdef DEBUG_RS_WS
else
/* illegal */
logerror("tms5220_combined_rsq_wsq_w: illegal\n");
#endif
LOGMASKED(LOG_RS_WS, "tms5220_combined_rsq_wsq_w: illegal\n");
return;
case 3:
/* high impedance */
@ -1960,13 +1893,14 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
case 2: // /WS active, /RS not
/* check for falling or rising edge */
if (!(falling_edges&0x01)) return; /* low to high, do nothing */
/* high to low - schedule ready cycle */
#ifdef DEBUG_RS_WS
logerror("Scheduling ready cycle for /WS...\n");
#endif
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;
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
Command Mode:
@ -1983,13 +1917,14 @@ WRITE8_MEMBER( tms5220_device::combined_rsq_wsq_w )
case 1: // /RS active, /WS not
/* check for falling or rising edge */
if (!(falling_edges&0x02)) return; /* low to high, do nothing */
/* high to low - schedule ready cycle */
#ifdef DEBUG_RS_WS
logerror("Scheduling ready cycle for /RS...\n");
#endif
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;
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
return;
@ -2009,9 +1944,8 @@ void tms5220_device::write_data(uint8_t data)
// prevent debugger from changing the internal state
if (machine().side_effects_disabled()) return;
#ifdef DEBUG_RS_WS
logerror("tms5220_data_w: data %02x\n", data);
#endif
LOGMASKED(LOG_RS_WS, "tms5220_data_w: data %02x\n", data);
if (!m_true_timing)
{
/* bring up to date first */
@ -2021,10 +1955,8 @@ void tms5220_device::write_data(uint8_t data)
else
{
/* actually in a write ? */
#ifdef DEBUG_RS_WS
if (!(m_rs_ws == 0x02))
logerror("tms5220_data_w: data written outside ws, status: %02x!\n", m_rs_ws);
#endif
LOGMASKED(LOG_RS_WS, "tms5220_data_w: data written outside ws, status: %02x!\n", m_rs_ws);
m_write_latch = data;
}
}
@ -2053,10 +1985,8 @@ uint8_t tms5220_device::read_status()
/* actually in a read ? */
if (m_rs_ws == 0x01)
return m_read_latch;
#ifdef DEBUG_RS_WS
else
logerror("tms5220_status_r: data read outside rs!\n");
#endif
LOGMASKED(LOG_RS_WS, "tms5220_status_r: data read outside rs!\n");
return 0xff;
}
}

View File

@ -123,6 +123,8 @@ private:
int cycles_to_ready();
int 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;
int32_t lattice_filter();
void process_command(unsigned char cmd);
void parse_frame();
@ -136,6 +138,9 @@ private:
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);
// internal state
/* coefficient tables */