summaryrefslogtreecommitdiffstatshomepage
path: root/src/emu
diff options
context:
space:
mode:
author smf- <smf-@users.noreply.github.com>2013-05-14 10:21:05 +0000
committer smf- <smf-@users.noreply.github.com>2013-05-14 10:21:05 +0000
commitd700c1f372a451a08cd7737be70372efdbdb1fa8 (patch)
treeeecbe8dfb684f585736c17c902e9b84cb00abef5 /src/emu
parent25cb3c0cdaaaffeee62bd8e5528a9c9ecfc48219 (diff)
modernised TMS5220 [smf]
Diffstat (limited to 'src/emu')
-rw-r--r--src/emu/machine/spchrom.c115
-rw-r--r--src/emu/machine/spchrom.h37
-rw-r--r--src/emu/sound/sound.mak2
-rw-r--r--src/emu/sound/tms5220.c2575
-rw-r--r--src/emu/sound/tms5220.h404
5 files changed, 829 insertions, 2304 deletions
diff --git a/src/emu/machine/spchrom.c b/src/emu/machine/spchrom.c
new file mode 100644
index 00000000000..27f1960e172
--- /dev/null
+++ b/src/emu/machine/spchrom.c
@@ -0,0 +1,115 @@
+/*
+ spchroms.c - This is an emulator for "typical" speech ROMs from TI, as used by TI99/4(a).
+
+ In order to support its speech processor, TI designed some ROMs with a 1-bit data bus
+ and 4-bit address bus (multiplexed 5 times to provide a 18-bit address).
+ A fairly complete description of such a ROM (tms6100) is found in the tms5220 datasheet.
+
+ One notable thing is that the address is a byte address (*NOT* a bit address).
+
+ This file is designed to be interfaced with the tms5220 core.
+ Interfacing it with the tms5110 would make sense, too.
+*/
+
+#include "emu.h"
+#include "spchrom.h"
+
+#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */
+
+// device type definition
+const device_type SPEECHROM = &device_creator<speechrom_device>;
+
+speechrom_device::speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
+ : device_t(mconfig, SPEECHROM, "SPEECHROM", tag, owner, clock),
+ m_speechROMaddr(0),
+ m_load_pointer(0),
+ m_ROM_bits_count(0)
+{
+}
+
+/*
+ Read 'count' bits serially from speech ROM
+*/
+int speechrom_device::read(int count)
+{
+ int val;
+
+ if (m_load_pointer)
+ { /* first read after load address is ignored */
+ m_load_pointer = 0;
+ count--;
+ }
+
+ if (m_speechROMaddr < m_speechROMlen)
+ if (count < m_ROM_bits_count)
+ {
+ m_ROM_bits_count -= count;
+ val = (m_speechrom_data[m_speechROMaddr] >> m_ROM_bits_count) & (0xFF >> (8 - count));
+ }
+ else
+ {
+ val = ((int) m_speechrom_data[m_speechROMaddr]) << 8;
+
+ m_speechROMaddr = (m_speechROMaddr + 1) & TMS5220_ADDRESS_MASK;
+
+ if (m_speechROMaddr < m_speechROMlen)
+ val |= m_speechrom_data[m_speechROMaddr];
+
+ m_ROM_bits_count += 8 - count;
+
+ val = (val >> m_ROM_bits_count) & (0xFF >> (8 - count));
+ }
+ else
+ val = 0;
+
+ return val;
+}
+
+/*
+ Write an address nibble to speech ROM
+*/
+void speechrom_device::load_address(int data)
+{
+ /* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
+ This code does not care about this. */
+ m_speechROMaddr = ( (m_speechROMaddr & ~(0xf << m_load_pointer))
+ | (((unsigned long) (data & 0xf)) << m_load_pointer) ) & TMS5220_ADDRESS_MASK;
+ m_load_pointer += 4;
+ m_ROM_bits_count = 8;
+}
+
+/*
+ Perform a read and branch command
+*/
+void speechrom_device::read_and_branch()
+{
+ /* tms5220 data sheet says that if more than one speech ROM (tms6100) is present,
+ there is a bus contention. This code does not care about this. */
+ if (m_speechROMaddr < m_speechROMlen-1)
+ m_speechROMaddr = (m_speechROMaddr & 0x3c000UL)
+ | (((((unsigned long) m_speechrom_data[m_speechROMaddr]) << 8)
+ | m_speechrom_data[m_speechROMaddr+1]) & 0x3fffUL);
+ else if (m_speechROMaddr == m_speechROMlen-1)
+ m_speechROMaddr = (m_speechROMaddr & 0x3c000UL)
+ | ((((unsigned long) m_speechrom_data[m_speechROMaddr]) << 8) & 0x3fffUL);
+ else
+ m_speechROMaddr = (m_speechROMaddr & 0x3c000UL);
+
+ m_ROM_bits_count = 8;
+}
+
+void speechrom_device::device_start()
+{
+ memory_region *region = memregion(tag());
+ if (region == NULL)
+ {
+ throw emu_fatalerror("No region for device '%s'\n", tag());
+ }
+
+ m_speechrom_data = region->base();
+ m_speechROMlen = region->bytes();
+
+ save_item(NAME(m_speechROMaddr));
+ save_item(NAME(m_load_pointer));
+ save_item(NAME(m_ROM_bits_count));
+}
diff --git a/src/emu/machine/spchrom.h b/src/emu/machine/spchrom.h
new file mode 100644
index 00000000000..c9401379e19
--- /dev/null
+++ b/src/emu/machine/spchrom.h
@@ -0,0 +1,37 @@
+/*
+ * Voice Synthesis Memory
+ *
+ */
+
+#ifndef __SPCHROMS_H
+#define __SPCHROMS_H
+
+#include "emu.h"
+
+class speechrom_device : public device_t
+{
+public:
+ // construction/destruction
+ speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ /// TODO: implement bus behaviour
+ int read(int count);
+ void load_address(int data);
+ void read_and_branch();
+
+ // device-level overrides
+ virtual void device_start();
+
+private:
+ UINT8 *m_speechrom_data; /* pointer to speech ROM data */
+ unsigned long m_speechROMlen; /* length of data pointed by speechrom_data, from 0 to 2^18 */
+ unsigned long m_speechROMaddr; /* 18 bit pointer in ROM */
+ int m_load_pointer; /* which 4-bit nibble will be affected by load address */
+ int m_ROM_bits_count; /* current bit position in ROM */
+};
+
+
+// device type definition
+extern const device_type SPEECHROM;
+
+#endif
diff --git a/src/emu/sound/sound.mak b/src/emu/sound/sound.mak
index f162cac0444..e60a5fa9842 100644
--- a/src/emu/sound/sound.mak
+++ b/src/emu/sound/sound.mak
@@ -644,7 +644,7 @@ $(SOUNDOBJ)/tms5110.o: $(SOUNDSRC)/tms5110r.c
# Texas Instruments TMS5200-series speech synthesizers
#-------------------------------------------------
ifneq ($(filter TMS5220,$(SOUNDS)),)
-SOUNDOBJS += $(SOUNDOBJ)/tms5220.o
+SOUNDOBJS += $(SOUNDOBJ)/tms5220.o $(EMUMACHINE)/spchrom.o
endif
$(SOUNDOBJ)/tms5220.o: $(SOUNDSRC)/tms5110r.c
diff --git a/src/emu/sound/tms5220.c b/src/emu/sound/tms5220.c
index 68e6c611f41..03123d28a5e 100644
--- a/src/emu/sound/tms5220.c
+++ b/src/emu/sound/tms5220.c
@@ -251,6 +251,8 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
#include "emu.h"
#include "tms5220.h"
+static INT16 clip_analog(INT16 cliptemp);
+
/* *****optional defines***** */
/* Hacky improvements which don't match patent: */
@@ -258,8 +260,8 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
* One of the following two lines should be used, and the other commented
* The second line is more accurate mathematically but not accurate to the patent
*/
-#define INTERP_SHIFT >> tms->coeff->interp_coeff[tms->IP]
-//define INTERP_SHIFT / (1<<tms->coeff->interp_coeff[tms->IP])
+#define INTERP_SHIFT >> m_coeff->interp_coeff[m_IP]
+//define INTERP_SHIFT / (1<<m_coeff->interp_coeff[m_IP])
/* Other hacks */
/* HACK?: if defined, outputs the low 4 bits of the lattice filter to the i/o
@@ -267,9 +269,6 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
* ...actually the tms5220c might legitamately do this! */
#undef ALLOW_4_LSB
-/* HACK: if defined, uses impossibly perfect 'straight line' interpolation */
-#undef PERFECT_INTERPOLATION_HACK
-
/* *****configuration of chip connection stuff***** */
/* must be defined; if 0, output the waveform as if it was tapped on the speaker pin as usual, if 1, output the waveform as if it was tapped on the i/o pin (volume is much lower in the latter case) */
@@ -323,222 +322,85 @@ in MCU code). Look for a 16-pin chip at U6 labeled "ECHO-3 SN".
static const UINT8 reload_table[4] = { 0, 2, 4, 6 }; //sample count reload for 5220c only; 5200 and 5220 always reload with 0; keep in mind this is loaded on IP=0 PC=12 subcycle=1 so it immediately will increment after one sample, effectively being 1,3,5,7 as in the comments above.
-struct tms5220_state
-{
- /* coefficient tables */
- int variant; /* Variant of the 5xxx - see tms5110r.h */
-
- /* coefficient tables */
- const struct tms5100_coeffs *coeff;
-
- /* callbacks */
- devcb_resolved_write_line irq_func;
- devcb_resolved_write_line readyq_func;
-
- /* these contain data that describes the 128-bit data FIFO */
- UINT8 fifo[FIFO_SIZE];
- UINT8 fifo_head;
- UINT8 fifo_tail;
- UINT8 fifo_count;
- UINT8 fifo_bits_taken;
-
-
- /* these contain global status bits */
- UINT8 speaking_now; /* True only if actual speech is being generated right now. Is set when a speak vsm command happens OR when speak external happens and buffer low becomes nontrue; Is cleared when speech halts after the last stop frame or the last frame after talk status is otherwise cleared.*/
- UINT8 speak_external; /* If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO. */
- UINT8 talk_status; /* If 1, TS status bit is 1, i.e. speak or speak external is in progress and we have not encountered a stop frame yet; talk_status differs from speaking_now in that speaking_now is set as soon as a speak or speak external command is started; talk_status does NOT go active until after 8 bytes are written to the fifo on a speak external command, otherwise the two are the same. TS is cleared by 3 things: 1. when a STOP command has just been processed as a new frame in the speech stream; 2. if the fifo runs out in speak external mode; 3. on power-up/during a reset command; When it gets cleared, speak_external is also cleared, an interrupt is generated, and speaking_now will be cleared when the next frame starts. */
- UINT8 buffer_low; /* If 1, FIFO has less than 8 bytes in it */
- UINT8 buffer_empty; /* If 1, FIFO is empty */
- UINT8 irq_pin; /* state of the IRQ pin (output) */
- UINT8 ready_pin; /* state of the READY pin (output) */
-
- /* these contain data describing the current and previous voice frames */
-#define OLD_FRAME_SILENCE_FLAG tms->OLDE // 1 if E=0, 0 otherwise.
-#define OLD_FRAME_UNVOICED_FLAG tms->OLDP // 1 if P=0 (unvoiced), 0 if voiced
- UINT8 OLDE;
- UINT8 OLDP;
-
-#define NEW_FRAME_STOP_FLAG (tms->new_frame_energy_idx == 0xF) // 1 if this is a stop (Energy = 0xF) frame
-#define NEW_FRAME_SILENCE_FLAG (tms->new_frame_energy_idx == 0) // ditto as above
-#define NEW_FRAME_UNVOICED_FLAG (tms->new_frame_pitch_idx == 0) // ditto as above
- UINT8 new_frame_energy_idx;
- UINT8 new_frame_pitch_idx;
- UINT8 new_frame_k_idx[10];
-
-
- /* these are all used to contain the current state of the sound generation */
-#ifndef PERFECT_INTERPOLATION_HACK
- INT16 current_energy;
- INT16 current_pitch;
- INT16 current_k[10];
-
- INT16 target_energy;
- INT16 target_pitch;
- INT16 target_k[10];
-#else
- UINT8 old_frame_energy_idx;
- UINT8 old_frame_pitch_idx;
- UINT8 old_frame_k_idx[10];
-
- INT32 current_energy;
- INT32 current_pitch;
- INT32 current_k[10];
-
- INT32 target_energy;
- INT32 target_pitch;
- INT32 target_k[10];
-#endif
-
- UINT16 previous_energy; /* needed for lattice filter to match patent */
-
- UINT8 subcycle; /* contains the current subcycle for a given PC: 0 is A' (only used on SPKSLOW mode on 51xx), 1 is A, 2 is B */
- UINT8 subc_reload; /* contains 1 for normal speech, 0 when SPKSLOW is active */
- UINT8 PC; /* current parameter counter (what param is being interpolated), ranges from 0 to 12 */
- /* TODO/NOTE: the current interpolation period, counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1 */
- UINT8 IP; /* the current interpolation period */
- UINT8 inhibit; /* If 1, interpolation is inhibited until the DIV1 period */
- UINT8 tms5220c_rate; /* only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command */
- UINT16 pitch_count; /* pitch counter; provides chirp rom address */
-
- INT32 u[11];
- INT32 x[10];
-
- UINT16 RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 */
- INT16 excitation_data;
-
- /* R Nabet : These have been added to emulate speech Roms */
- UINT8 schedule_dummy_read; /* set after each load address, so that next read operation is preceded by a dummy read */
- UINT8 data_register; /* data register, used by read command */
- UINT8 RDB_flag; /* whether we should read data register or status register */
-
- /* io_ready: page 3 of the datasheet specifies that READY will be asserted until
- * data is available or processed by the system.
- */
- UINT8 io_ready;
-
- /* flag for "true" timing involving rs/ws */
- UINT8 true_timing;
-
- /* rsws - state, rs bit 1, ws bit 0 */
- UINT8 rs_ws;
- UINT8 read_latch;
- UINT8 write_latch;
-
- /* The TMS52xx has two different ways of providing output data: the
- analog speaker pin (which was usually used) and the Digital I/O pin.
- 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
- */
- UINT8 digital_select;
- device_t *device;
-
- const tms5220_interface *intf;
- sound_stream *stream;
- int clock;
-};
-
-
// Pull in the ROM tables
#include "tms5110r.c"
-INLINE tms5220_state *get_safe_token(device_t *device)
-{
- assert(device != NULL);
- assert(device->type() == TMS5220 ||
- device->type() == TMS5220C ||
- device->type() == TMC0285 ||
- device->type() == TMS5200);
- return (tms5220_state *)downcast<tms5220_device *>(device)->token();
-}
-
-/* Static function prototypes */
-static void process_command(tms5220_state *tms, unsigned char data);
-static void parse_frame(tms5220_state *tms);
-static void update_status_and_ints(tms5220_state *tms);
-static void set_interrupt_state(tms5220_state *tms, int state);
-static INT32 lattice_filter(tms5220_state *tms);
-static INT16 clip_analog(INT16 clip);
-static void update_ready_state(tms5220_state *tms);
-static STREAM_UPDATE( tms5220_update );
-
-static void tms5220_set_variant(tms5220_state *tms, int variant)
+void tms5220_device::set_variant(int variant)
{
switch (variant)
{
case TMS5220_IS_5200:
- tms->coeff = &tms5200_coeff;
+ m_coeff = &tms5200_coeff;
break;
case TMS5220_IS_5220C:
case TMS5220_IS_5220:
- tms->coeff = &tms5220_coeff;
+ m_coeff = &tms5220_coeff;
break;
default:
fatalerror("Unknown variant in tms5220_set_variant\n");
}
- tms->variant = variant;
+ m_variant = variant;
}
-static void register_for_save_states(tms5220_state *tms)
+void tms5220_device::register_for_save_states()
{
- tms->device->save_item(NAME(tms->fifo));
- tms->device->save_item(NAME(tms->fifo_head));
- tms->device->save_item(NAME(tms->fifo_tail));
- tms->device->save_item(NAME(tms->fifo_count));
- tms->device->save_item(NAME(tms->fifo_bits_taken));
-
- tms->device->save_item(NAME(tms->speaking_now));
- tms->device->save_item(NAME(tms->speak_external));
- tms->device->save_item(NAME(tms->talk_status));
- tms->device->save_item(NAME(tms->buffer_low));
- tms->device->save_item(NAME(tms->buffer_empty));
- tms->device->save_item(NAME(tms->irq_pin));
- tms->device->save_item(NAME(tms->ready_pin));
-
- tms->device->save_item(NAME(tms->OLDE));
- tms->device->save_item(NAME(tms->OLDP));
-
- tms->device->save_item(NAME(tms->new_frame_energy_idx));
- tms->device->save_item(NAME(tms->new_frame_pitch_idx));
- tms->device->save_item(NAME(tms->new_frame_k_idx));
+ 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_speaking_now));
+ save_item(NAME(m_speak_external));
+ save_item(NAME(m_talk_status));
+ save_item(NAME(m_buffer_low));
+ save_item(NAME(m_buffer_empty));
+ save_item(NAME(m_irq_pin));
+ save_item(NAME(m_ready_pin));
+
+ save_item(NAME(m_OLDE));
+ save_item(NAME(m_OLDP));
+
+ save_item(NAME(m_new_frame_energy_idx));
+ save_item(NAME(m_new_frame_pitch_idx));
+ save_item(NAME(m_new_frame_k_idx));
#ifdef PERFECT_INTERPOLATION_HACK
- tms->device->save_item(NAME(tms->old_frame_energy_idx));
- tms->device->save_item(NAME(tms->old_frame_pitch_idx));
- tms->device->save_item(NAME(tms->old_frame_k_idx));
+ save_item(NAME(m_old_frame_energy_idx));
+ save_item(NAME(m_old_frame_pitch_idx));
+ save_item(NAME(m_old_frame_k_idx));
#endif
- tms->device->save_item(NAME(tms->current_energy));
- tms->device->save_item(NAME(tms->current_pitch));
- tms->device->save_item(NAME(tms->current_k));
+ save_item(NAME(m_current_energy));
+ save_item(NAME(m_current_pitch));
+ save_item(NAME(m_current_k));
- tms->device->save_item(NAME(tms->target_energy));
- tms->device->save_item(NAME(tms->target_pitch));
- tms->device->save_item(NAME(tms->target_k));
+ save_item(NAME(m_target_energy));
+ save_item(NAME(m_target_pitch));
+ save_item(NAME(m_target_k));
- tms->device->save_item(NAME(tms->previous_energy));
+ save_item(NAME(m_previous_energy));
- tms->device->save_item(NAME(tms->subcycle));
- tms->device->save_item(NAME(tms->subc_reload));
- tms->device->save_item(NAME(tms->PC));
- tms->device->save_item(NAME(tms->IP));
- tms->device->save_item(NAME(tms->inhibit));
- tms->device->save_item(NAME(tms->tms5220c_rate));
- tms->device->save_item(NAME(tms->pitch_count));
+ save_item(NAME(m_subcycle));
+ save_item(NAME(m_subc_reload));
+ save_item(NAME(m_PC));
+ save_item(NAME(m_IP));
+ save_item(NAME(m_inhibit));
+ save_item(NAME(m_tms5220c_rate));
+ save_item(NAME(m_pitch_count));
- tms->device->save_item(NAME(tms->u));
- tms->device->save_item(NAME(tms->x));
+ save_item(NAME(m_u));
+ save_item(NAME(m_x));
- tms->device->save_item(NAME(tms->RNG));
- tms->device->save_item(NAME(tms->excitation_data));
+ save_item(NAME(m_RNG));
+ save_item(NAME(m_excitation_data));
- tms->device->save_item(NAME(tms->schedule_dummy_read));
- tms->device->save_item(NAME(tms->data_register));
- tms->device->save_item(NAME(tms->RDB_flag));
- tms->device->save_item(NAME(tms->digital_select));
+ 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));
- tms->device->save_item(NAME(tms->io_ready));
+ save_item(NAME(m_io_ready));
}
@@ -586,24 +448,24 @@ static void printbits(long data, int num)
***********************************************************************************************/
-static void tms5220_data_write(tms5220_state *tms, int data)
+void tms5220_device::data_write(int data)
{
#ifdef DEBUG_DUMP_INPUT_DATA
fprintf(stdout, "%c",data);
#endif
- if (tms->speak_external) // If we're in speak external mode
+ if (m_speak_external) // If we're in speak external mode
{
// add this byte to the FIFO
- if (tms->fifo_count < FIFO_SIZE)
+ if (m_fifo_count < FIFO_SIZE)
{
- tms->fifo[tms->fifo_tail] = data;
- tms->fifo_tail = (tms->fifo_tail + 1) % FIFO_SIZE;
- tms->fifo_count++;
+ 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", tms->fifo_count);
+ logerror("data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count);
#endif
- update_status_and_ints(tms);
- if ((tms->talk_status == 0) && (tms->buffer_low == 0)) // we just unset buffer low with that last write, and talk status *was* zero...
+ update_status_and_ints();
+ if ((m_talk_status == 0) && (m_buffer_low == 0)) // we just unset buffer low with that last write, and talk status *was* zero...
{
int i;
#ifdef DEBUG_FIFO
@@ -611,18 +473,18 @@ static void tms5220_data_write(tms5220_state *tms, int data)
#endif
// ...then we now have enough bytes to start talking; clear out the new frame parameters (it will become old frame just before the first call to parse_frame() )
// TODO: the 3 lines below (and others) are needed for victory to not fail its selftest due to a sample ending too late, may require additional investigation
- tms->subcycle = tms->subc_reload;
- tms->PC = 0;
- tms->IP = reload_table[tms->tms5220c_rate&0x3]; // is this correct? should this be always 7 instead, so that the new frame is loaded quickly?
- tms->new_frame_energy_idx = 0;
- tms->new_frame_pitch_idx = 0;
+ m_subcycle = m_subc_reload;
+ m_PC = 0;
+ m_IP = reload_table[m_tms5220c_rate&0x3]; // is this correct? should this be always 7 instead, so that the new frame is loaded quickly?
+ m_new_frame_energy_idx = 0;
+ m_new_frame_pitch_idx = 0;
for (i = 0; i < 4; i++)
- tms->new_frame_k_idx[i] = 0;
+ m_new_frame_k_idx[i] = 0;
for (i = 4; i < 7; i++)
- tms->new_frame_k_idx[i] = 0xF;
- for (i = 7; i < tms->coeff->num_k; i++)
- tms->new_frame_k_idx[i] = 0x7;
- tms->talk_status = tms->speaking_now = 1;
+ m_new_frame_k_idx[i] = 0xF;
+ for (i = 7; i < m_coeff->num_k; i++)
+ m_new_frame_k_idx[i] = 0x7;
+ m_talk_status = m_speaking_now = 1;
}
}
else
@@ -635,9 +497,9 @@ static void tms5220_data_write(tms5220_state *tms, int data)
}
- else //(! tms->speak_external)
+ else //(! m_speak_external)
// R Nabet : we parse commands at once. It is necessary for such commands as read.
- process_command(tms,data);
+ process_command(data);
}
/**********************************************************************************************
@@ -663,47 +525,47 @@ static void tms5220_data_write(tms5220_state *tms, int data)
***********************************************************************************************/
-static void update_status_and_ints(tms5220_state *tms)
+void tms5220_device::update_status_and_ints()
{
/* update flags and set ints if needed */
- update_ready_state(tms);
+ update_ready_state();
/* BL is set if neither byte 9 nor 8 of the fifo are in use; this
translates to having fifo_count (which ranges from 0 bytes in use to 16
bytes used) being less than or equal to 8. Victory/Victorba depends on this. */
- if (tms->fifo_count <= 8)
+ if (m_fifo_count <= 8)
{
// generate an interrupt if necessary; if /BL was inactive and is now active, set int.
- if (!tms->buffer_low)
- set_interrupt_state(tms, 1);
- tms->buffer_low = 1;
+ if (!m_buffer_low)
+ set_interrupt_state(1);
+ m_buffer_low = 1;
}
else
- tms->buffer_low = 0;
+ m_buffer_low = 0;
/* 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 */
- if (tms->fifo_count == 0)
+ if (m_fifo_count == 0)
{
// generate an interrupt if necessary; if /BE was inactive and is now active, set int.
- if (!tms->buffer_empty)
- set_interrupt_state(tms, 1);
- tms->buffer_empty = 1;
+ if (!m_buffer_empty)
+ set_interrupt_state(1);
+ m_buffer_empty = 1;
}
else
- tms->buffer_empty = 0;
+ m_buffer_empty = 0;
/* TS is talk status and is set elsewhere in the fifo parser and in
the SPEAK command handler; however, if /BE is true during speak external
mode, it is immediately unset here. */
- if ((tms->speak_external == 1) && (tms->buffer_empty == 1))
+ if ((m_speak_external == 1) && (m_buffer_empty == 1))
{
// generate an interrupt: /TS was active, and is now inactive.
- if (tms->talk_status == 1)
+ if (m_talk_status == 1)
{
- tms->talk_status = tms->speak_external = 0;
- set_interrupt_state(tms, 1);
+ m_talk_status = m_speak_external = 0;
+ set_interrupt_state(1);
}
}
/* Note that TS being unset will also generate an interrupt when a STOP
@@ -716,32 +578,32 @@ static void update_status_and_ints(tms5220_state *tms)
***********************************************************************************************/
-static int extract_bits(tms5220_state *tms, int count)
+int tms5220_device::extract_bits(int count)
{
int val = 0;
- if (tms->speak_external)
+ if (m_speak_external)
{
// extract from FIFO
while (count--)
{
- val = (val << 1) | ((tms->fifo[tms->fifo_head] >> tms->fifo_bits_taken) & 1);
- tms->fifo_bits_taken++;
- if (tms->fifo_bits_taken >= 8)
+ val = (val << 1) | ((m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 1);
+ m_fifo_bits_taken++;
+ if (m_fifo_bits_taken >= 8)
{
- tms->fifo_count--;
- tms->fifo[tms->fifo_head] = 0; // zero the newly depleted fifo head byte
- tms->fifo_head = (tms->fifo_head + 1) % FIFO_SIZE;
- tms->fifo_bits_taken = 0;
- update_status_and_ints(tms);
+ m_fifo_count--;
+ m_fifo[m_fifo_head] = 0; // zero the newly depleted fifo head byte
+ m_fifo_head = (m_fifo_head + 1) % FIFO_SIZE;
+ m_fifo_bits_taken = 0;
+ update_status_and_ints();
}
}
}
else
{
// extract from VSM (speech ROM)
- if (tms->intf->read)
- val = (* tms->intf->read)(tms->device, count);
+ if (m_speechrom)
+ val = m_speechrom->read(count);
}
return val;
@@ -753,23 +615,23 @@ static int extract_bits(tms5220_state *tms, int count)
***********************************************************************************************/
-static int tms5220_status_read(tms5220_state *tms)
+int tms5220_device::status_read()
{
- if (tms->RDB_flag)
+ if (m_RDB_flag)
{ /* if last command was read, return data register */
- tms->RDB_flag = FALSE;
- return(tms->data_register);
+ m_RDB_flag = FALSE;
+ return(m_data_register);
}
else
{ /* read status */
/* clear the interrupt pin on status read */
- set_interrupt_state(tms, 0);
+ set_interrupt_state(0);
#ifdef DEBUG_PIN_READS
- logerror("Status read: TS=%d BL=%d BE=%d\n", tms->talk_status, tms->buffer_low, tms->buffer_empty);
+ logerror("Status read: TS=%d BL=%d BE=%d\n", m_talk_status, m_buffer_low, m_buffer_empty);
#endif
- return (tms->talk_status << 7) | (tms->buffer_low << 6) | (tms->buffer_empty << 5);
+ return (m_talk_status << 7) | (m_buffer_low << 6) | (m_buffer_empty << 5);
}
}
@@ -780,12 +642,12 @@ static int tms5220_status_read(tms5220_state *tms)
***********************************************************************************************/
-static int tms5220_ready_read(tms5220_state *tms)
+int tms5220_device::ready_read()
{
#ifdef DEBUG_PIN_READS
- logerror("ready_read: ready pin read, io_ready is %d, fifo count is %d\n", tms->io_ready, tms->fifo_count);
+ logerror("ready_read: ready pin read, io_ready is %d, fifo count is %d\n", m_io_ready, m_fifo_count);
#endif
- return ((tms->fifo_count < FIFO_SIZE)||(!tms->speak_external)) && tms->io_ready;
+ return ((m_fifo_count < FIFO_SIZE)||(!m_speak_external)) && m_io_ready;
}
@@ -797,31 +659,31 @@ static int tms5220_ready_read(tms5220_state *tms)
***********************************************************************************************/
-static int tms5220_cycles_to_ready(tms5220_state *tms)
+int tms5220_device::cycles_to_ready()
{
int answer;
- if (tms5220_ready_read(tms))
+ if (ready_read())
answer = 0;
else
{
int val;
- int samples_per_frame = tms->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 = ((tms->PC*(3-tms->subc_reload))+((tms->subc_reload?38:25)*tms->IP));
+ 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 - tms->fifo_bits_taken)
+ // 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 (tms->fifo_bits_taken < 4)
+ if (m_fifo_bits_taken < 4)
{
// read energy
- val = (tms->fifo[tms->fifo_head] >> tms->fifo_bits_taken) & 0xf;
+ 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 += tms->subc_reload?200:304;
+ 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. */
@@ -838,12 +700,12 @@ static int tms5220_cycles_to_ready(tms5220_state *tms)
***********************************************************************************************/
-static int tms5220_int_read(tms5220_state *tms)
+int tms5220_device::int_read()
{
#ifdef DEBUG_PIN_READS
- logerror("int_read: irq pin read, state is %d\n", tms->irq_pin);
+ logerror("int_read: irq pin read, state is %d\n", m_irq_pin);
#endif
- return tms->irq_pin;
+ return m_irq_pin;
}
@@ -853,7 +715,7 @@ static int tms5220_int_read(tms5220_state *tms)
***********************************************************************************************/
-static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size)
+void tms5220_device::process(INT16 *buffer, unsigned int size)
{
int buf_count=0;
int i, bitout, zpar;
@@ -861,61 +723,61 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
/* the following gotos are probably safe to remove */
/* if we're empty and still not speaking, fill with nothingness */
- if (!tms->speaking_now)
+ if (!m_speaking_now)
goto empty;
/* if speak external is set, but talk status is not (yet) set,
wait for buffer low to clear */
- if (!tms->talk_status && tms->speak_external && tms->buffer_low)
+ if (!m_talk_status && m_speak_external && m_buffer_low)
goto empty;
/* loop until the buffer is full or we've stopped speaking */
- while ((size > 0) && tms->speaking_now)
+ while ((size > 0) && m_speaking_now)
{
/* if it is the appropriate time to update the old energy/pitch idxes,
* i.e. when IP=7, PC=12, T=17, subcycle=2, do so. Since IP=7 PC=12 T=17
* is JUST BEFORE the transition to IP=0 PC=0 T=0 sybcycle=(0 or 1),
* which happens 4 T-cycles later), we change on the latter.*/
- if ((tms->IP == 0) && (tms->PC == 0) && (tms->subcycle < 2))
+ if ((m_IP == 0) && (m_PC == 0) && (m_subcycle < 2))
{
- tms->OLDE = (tms->new_frame_energy_idx == 0);
- tms->OLDP = (tms->new_frame_pitch_idx == 0);
+ m_OLDE = (m_new_frame_energy_idx == 0);
+ m_OLDP = (m_new_frame_pitch_idx == 0);
}
/* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1
* (In reality, the frame was really loaded incrementally during the entire IP=0
* PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens)
*/
- if ((tms->IP == 0) && (tms->PC == 12) && (tms->subcycle == 1))
+ if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1))
{
// HACK for regression testing, be sure to comment out before release!
- //tms->RNG = 0x1234;
+ //m_RNG = 0x1234;
// end HACK
/* appropriately override the interp count if needed; this will be incremented after the frame parse! */
- tms->IP = reload_table[tms->tms5220c_rate&0x3];
+ m_IP = reload_table[m_tms5220c_rate&0x3];
#ifdef PERFECT_INTERPOLATION_HACK
/* remember previous frame energy, pitch, and coefficients */
- tms->old_frame_energy_idx = tms->new_frame_energy_idx;
- tms->old_frame_pitch_idx = tms->new_frame_pitch_idx;
- for (i = 0; i < tms->coeff->num_k; i++)
- tms->old_frame_k_idx[i] = tms->new_frame_k_idx[i];
+ m_old_frame_energy_idx = m_new_frame_energy_idx;
+ m_old_frame_pitch_idx = m_new_frame_pitch_idx;
+ for (i = 0; i < m_coeff->num_k; i++)
+ m_old_frame_k_idx[i] = m_new_frame_k_idx[i];
#endif
/* if the talk status was clear last frame, halt speech now. */
- if (tms->talk_status == 0)
+ if (m_talk_status == 0)
{
#ifdef DEBUG_GENERATION
fprintf(stderr,"tms5220_process: processing frame: talk status = 0 caused by stop frame or buffer empty, halting speech.\n");
#endif
- tms->speaking_now = 0; // finally halt speech
+ m_speaking_now = 0; // finally halt speech
goto empty;
}
/* Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] */
- parse_frame(tms);
+ parse_frame();
#ifdef DEBUG_PARSE_FRAME_DUMP
fprintf(stderr,"\n");
#endif
@@ -923,9 +785,9 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
/* if the new frame is a stop frame, set an interrupt and set talk status to 0 */
if (NEW_FRAME_STOP_FLAG == 1)
{
- tms->talk_status = tms->speak_external = 0;
- set_interrupt_state(tms, 1);
- update_status_and_ints(tms);
+ m_talk_status = m_speak_external = 0;
+ set_interrupt_state(1);
+ update_status_and_ints();
}
/* in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it.
@@ -937,87 +799,87 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
if ( ((OLD_FRAME_UNVOICED_FLAG == 0) && (NEW_FRAME_UNVOICED_FLAG == 1))
|| ((OLD_FRAME_UNVOICED_FLAG == 1) && (NEW_FRAME_UNVOICED_FLAG == 0)) /* this line needs further investigation, starwars tie fighters may sound better without it */
|| ((OLD_FRAME_SILENCE_FLAG == 1) && (NEW_FRAME_SILENCE_FLAG == 0)) )
- tms->inhibit = 1;
+ m_inhibit = 1;
else // normal frame, normal interpolation
- tms->inhibit = 0;
+ m_inhibit = 0;
/* load new frame targets from tables, using parsed indices */
- tms->target_energy = tms->coeff->energytable[tms->new_frame_energy_idx];
- tms->target_pitch = tms->coeff->pitchtable[tms->new_frame_pitch_idx];
+ m_target_energy = m_coeff->energytable[m_new_frame_energy_idx];
+ m_target_pitch = m_coeff->pitchtable[m_new_frame_pitch_idx];
zpar = NEW_FRAME_UNVOICED_FLAG; // find out if parameters k5-k10 should be zeroed
for (i = 0; i < 4; i++)
- tms->target_k[i] = tms->coeff->ktable[i][tms->new_frame_k_idx[i]];
- for (i = 4; i < tms->coeff->num_k; i++)
- tms->target_k[i] = (tms->coeff->ktable[i][tms->new_frame_k_idx[i]] * (1-zpar));
+ m_target_k[i] = m_coeff->ktable[i][m_new_frame_k_idx[i]];
+ for (i = 4; i < m_coeff->num_k; i++)
+ m_target_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-zpar));
#ifdef DEBUG_GENERATION
/* Debug info for current parsed frame */
- fprintf(stderr, "OLDE: %d; OLDP: %d; ", tms->OLDE, tms->OLDP);
+ fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP);
fprintf(stderr,"Processing frame: ");
- if (tms->inhibit == 0)
+ if (m_inhibit == 0)
fprintf(stderr, "Normal Frame\n");
else
fprintf(stderr,"Interpolation Inhibited\n");
- fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",tms->current_energy, tms->current_pitch, tms->current_k[0], tms->current_k[1], tms->current_k[2], tms->current_k[3], tms->current_k[4], tms->current_k[5], tms->current_k[6], tms->current_k[7], tms->current_k[8], tms->current_k[9]);
- fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",tms->target_energy, tms->new_frame_energy_idx, tms->target_pitch, tms->target_k[0], tms->target_k[1], tms->target_k[2], tms->target_k[3], tms->target_k[4], tms->target_k[5], tms->target_k[6], tms->target_k[7], tms->target_k[8], tms->target_k[9]);
+ fprintf(stderr,"*** 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]);
+ fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_target_energy, m_new_frame_energy_idx, m_target_pitch, m_target_k[0], m_target_k[1], m_target_k[2], m_target_k[3], m_target_k[4], m_target_k[5], m_target_k[6], m_target_k[7], m_target_k[8], m_target_k[9]);
#endif
/* if TS is now 0, ramp the energy down to 0. Is this really correct to hardware? */
- if (tms->talk_status == 0)
+ if (m_talk_status == 0)
{
#ifdef DEBUG_GENERATION
fprintf(stderr,"Talk status is 0, forcing target energy to 0\n");
#endif
- tms->target_energy = 0;
+ m_target_energy = 0;
}
}
else // Not a new frame, just interpolate the existing frame.
{
- int inhibit_state = ((tms->inhibit==1)&&(tms->IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the tms->inhibit value
+ 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
#ifdef PERFECT_INTERPOLATION_HACK
- int samples_per_frame = tms->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 = tms->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 = (tms->subcycle - tms->subc_reload)+(tms->PC*(3-tms->subc_reload))+((tms->subc_reload?25:38)*((tms->IP-1)&7));
+ 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
+ int current_sample = (m_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7));
zpar = OLD_FRAME_UNVOICED_FLAG;
//fprintf(stderr, "CS: %03d", current_sample);
// reset the current energy, pitch, etc to what it was at frame start
- tms->current_energy = tms->coeff->energytable[tms->old_frame_energy_idx];
- tms->current_pitch = tms->coeff->pitchtable[tms->old_frame_pitch_idx];
+ m_current_energy = m_coeff->energytable[m_old_frame_energy_idx];
+ m_current_pitch = m_coeff->pitchtable[m_old_frame_pitch_idx];
for (i = 0; i < 4; i++)
- tms->current_k[i] = tms->coeff->ktable[i][tms->old_frame_k_idx[i]];
- for (i = 4; i < tms->coeff->num_k; i++)
- tms->current_k[i] = (tms->coeff->ktable[i][tms->old_frame_k_idx[i]] * (1-zpar));
+ m_current_k[i] = m_coeff->ktable[i][m_old_frame_k_idx[i]];
+ for (i = 4; i < m_coeff->num_k; i++)
+ m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-zpar));
// now adjust each value to be exactly correct for each of the samples per frame
- if (tms->IP != 0) // if we're still interpolating...
+ if (m_IP != 0) // if we're still interpolating...
{
- tms->current_energy += (((tms->target_energy - tms->current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame;
- tms->current_pitch += (((tms->target_pitch - tms->current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame;
- for (i = 0; i < tms->coeff->num_k; i++)
- tms->current_k[i] += (((tms->target_k[i] - tms->current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame;
+ m_current_energy += (((m_target_energy - m_current_energy)*(1-inhibit_state))*current_sample)/samples_per_frame;
+ m_current_pitch += (((m_target_pitch - m_current_pitch)*(1-inhibit_state))*current_sample)/samples_per_frame;
+ for (i = 0; i < m_coeff->num_k; i++)
+ m_current_k[i] += (((m_target_k[i] - m_current_k[i])*(1-inhibit_state))*current_sample)/samples_per_frame;
}
else // we're done, play this frame for 1/8 frame.
{
- tms->current_energy = tms->target_energy;
- tms->current_pitch = tms->target_pitch;
- for (i = 0; i < tms->coeff->num_k; i++)
- tms->current_k[i] = tms->target_k[i];
+ m_current_energy = m_target_energy;
+ m_current_pitch = m_target_pitch;
+ for (i = 0; i < m_coeff->num_k; i++)
+ m_current_k[i] = m_target_k[i];
}
#else
//Updates to parameters only happen on subcycle '2' (B cycle) of PCs.
- if (tms->subcycle == 2)
+ if (m_subcycle == 2)
{
- switch(tms->PC)
+ switch(m_PC)
{
case 0: /* PC = 0, B cycle, write updated energy */
- tms->current_energy += (((tms->target_energy - tms->current_energy)*(1-inhibit_state)) INTERP_SHIFT);
+ m_current_energy += (((m_target_energy - m_current_energy)*(1-inhibit_state)) INTERP_SHIFT);
break;
case 1: /* PC = 1, B cycle, write updated pitch */
- tms->current_pitch += (((tms->target_pitch - tms->current_pitch)*(1-inhibit_state)) INTERP_SHIFT);
+ m_current_pitch += (((m_target_pitch - m_current_pitch)*(1-inhibit_state)) INTERP_SHIFT);
break;
case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11:
/* PC = 2 through 11, B cycle, write updated K1 through K10 */
- tms->current_k[tms->PC-2] += (((tms->target_k[tms->PC-2] - tms->current_k[tms->PC-2])*(1-inhibit_state)) INTERP_SHIFT);
+ m_current_k[m_PC-2] += (((m_target_k[m_PC-2] - m_current_k[m_PC-2])*(1-inhibit_state)) INTERP_SHIFT);
break;
case 12: /* PC = 12, do nothing */
break;
@@ -1030,10 +892,10 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
if (OLD_FRAME_UNVOICED_FLAG == 1)
{
// generate unvoiced samples here
- if (tms->RNG & 1)
- tms->excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/
+ if (m_RNG & 1)
+ m_excitation_data = ~0x3F; /* according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)*/
else
- tms->excitation_data = 0x40;
+ m_excitation_data = 0x40;
}
else /* (OLD_FRAME_UNVOICED_FLAG == 0) */
{
@@ -1044,36 +906,36 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
* and if the address reaches that point the ADDRESS incrementer is
* disabled, forcing all samples beyond 51d to be == 51d
*/
- if (tms->pitch_count >= 51)
- tms->excitation_data = tms->coeff->chirptable[51];
- else /*tms->pitch_count < 51*/
- tms->excitation_data = tms->coeff->chirptable[tms->pitch_count];
+ if (m_pitch_count >= 51)
+ m_excitation_data = m_coeff->chirptable[51];
+ else /*m_pitch_count < 51*/
+ m_excitation_data = m_coeff->chirptable[m_pitch_count];
}
// Update LFSR *20* times every sample (once per T cycle), like patent shows
for (i=0; i<20; i++)
{
- bitout = ((tms->RNG >> 12) & 1) ^
- ((tms->RNG >> 3) & 1) ^
- ((tms->RNG >> 2) & 1) ^
- ((tms->RNG >> 0) & 1);
- tms->RNG <<= 1;
- tms->RNG |= bitout;
+ bitout = ((m_RNG >> 12) & 1) ^
+ ((m_RNG >> 3) & 1) ^
+ ((m_RNG >> 2) & 1) ^
+ ((m_RNG >> 0) & 1);
+ m_RNG <<= 1;
+ m_RNG |= bitout;
}
- this_sample = lattice_filter(tms); /* execute lattice filter */
+ this_sample = lattice_filter(); /* execute lattice filter */
#ifdef DEBUG_GENERATION_VERBOSE
- //fprintf(stderr,"C:%01d; ",tms->subcycle);
- fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",tms->IP, tms->PC, tms->excitation_data, tms->current_energy, tms->current_pitch, tms->pitch_count);
- //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", tms->excitation_data, tms->current_energy, tms->current_pitch, tms->pitch_count);
+ //fprintf(stderr,"C:%01d; ",m_subcycle);
+ fprintf(stderr,"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);
+ //fprintf(stderr,"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++)
- fprintf(stderr,"K%d:%04d ", i+1, tms->current_k[i]);
+ fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]);
fprintf(stderr,"Out:%06d", this_sample);
fprintf(stderr,"\n");
#endif
/* 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;
- if (tms->digital_select == 0) // analog SPK pin output is only 8 bits, with clipping
+ if (m_digital_select == 0) // analog SPK pin output is only 8 bits, with clipping
buffer[buf_count] = clip_analog(this_sample);
else // digital I/O pin output is 12 bits
{
@@ -1092,31 +954,31 @@ static void tms5220_process(tms5220_state *tms, INT16 *buffer, unsigned int size
}
// Update all counts
- tms->subcycle++;
- if ((tms->subcycle == 2) && (tms->PC == 12))
+ m_subcycle++;
+ if ((m_subcycle == 2) && (m_PC == 12))
{
/* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0
* if INHIBIT was true during the most recent frame transition.
* The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12
- * and tms->IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles,
+ * and m_IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles,
* which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17
* (and hence INHIBIT itself 2 t-cycles later). We do it here because it is
* convenient and should make no difference in output.
*/
- if ((tms->IP == 7)&&(tms->inhibit==1)) tms->pitch_count = 0;
- tms->subcycle = tms->subc_reload;
- tms->PC = 0;
- tms->IP++;
- tms->IP&=0x7;
+ if ((m_IP == 7)&&(m_inhibit==1)) m_pitch_count = 0;
+ m_subcycle = m_subc_reload;
+ m_PC = 0;
+ m_IP++;
+ m_IP&=0x7;
}
- else if (tms->subcycle == 3)
+ else if (m_subcycle == 3)
{
- tms->subcycle = tms->subc_reload;
- tms->PC++;
+ m_subcycle = m_subc_reload;
+ m_PC++;
}
- tms->pitch_count++;
- if (tms->pitch_count >= tms->current_pitch) tms->pitch_count = 0;
- tms->pitch_count &= 0x1FF;
+ m_pitch_count++;
+ if (m_pitch_count >= m_current_pitch) m_pitch_count = 0;
+ m_pitch_count &= 0x1FF;
buf_count++;
size--;
}
@@ -1125,18 +987,18 @@ empty:
while (size > 0)
{
- tms->subcycle++;
- if ((tms->subcycle == 2) && (tms->PC == 12))
+ m_subcycle++;
+ if ((m_subcycle == 2) && (m_PC == 12))
{
- tms->subcycle = tms->subc_reload;
- tms->PC = 0;
- tms->IP++;
- tms->IP&=0x7;
+ m_subcycle = m_subc_reload;
+ m_PC = 0;
+ m_IP++;
+ m_IP&=0x7;
}
- else if (tms->subcycle == 3)
+ else if (m_subcycle == 3)
{
- tms->subcycle = tms->subc_reload;
- tms->PC++;
+ m_subcycle = m_subc_reload;
+ m_PC++;
}
buffer[buf_count] = -1; /* should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) */
buf_count++;
@@ -1215,49 +1077,49 @@ static INT32 matrix_multiply(INT32 a, INT32 b)
***********************************************************************************************/
-static INT32 lattice_filter(tms5220_state *tms)
+INT32 tms5220_device::lattice_filter()
{
// Lattice filter here
// Aug/05/07: redone as unrolled loop, for clarity - LN
/* Originally Copied verbatim from table I in US patent 4,209,804, now updated to be in same order as the actual chip does it, not that it matters.
notation equivalencies from table:
- Yn(i) == tms->u[n-1]
- Kn = tms->current_k[n-1]
- bn = tms->x[n-1]
+ Yn(i) == m_u[n-1]
+ Kn = m_current_k[n-1]
+ bn = m_x[n-1]
*/
- tms->u[10] = matrix_multiply(tms->previous_energy, (tms->excitation_data<<6)); //Y(11)
- tms->u[9] = tms->u[10] - matrix_multiply(tms->current_k[9], tms->x[9]);
- tms->u[8] = tms->u[9] - matrix_multiply(tms->current_k[8], tms->x[8]);
- tms->u[7] = tms->u[8] - matrix_multiply(tms->current_k[7], tms->x[7]);
- tms->u[6] = tms->u[7] - matrix_multiply(tms->current_k[6], tms->x[6]);
- tms->u[5] = tms->u[6] - matrix_multiply(tms->current_k[5], tms->x[5]);
- tms->u[4] = tms->u[5] - matrix_multiply(tms->current_k[4], tms->x[4]);
- tms->u[3] = tms->u[4] - matrix_multiply(tms->current_k[3], tms->x[3]);
- tms->u[2] = tms->u[3] - matrix_multiply(tms->current_k[2], tms->x[2]);
- tms->u[1] = tms->u[2] - matrix_multiply(tms->current_k[1], tms->x[1]);
- tms->u[0] = tms->u[1] - matrix_multiply(tms->current_k[0], tms->x[0]);
- tms->x[9] = tms->x[8] + matrix_multiply(tms->current_k[8], tms->u[8]);
- tms->x[8] = tms->x[7] + matrix_multiply(tms->current_k[7], tms->u[7]);
- tms->x[7] = tms->x[6] + matrix_multiply(tms->current_k[6], tms->u[6]);
- tms->x[6] = tms->x[5] + matrix_multiply(tms->current_k[5], tms->u[5]);
- tms->x[5] = tms->x[4] + matrix_multiply(tms->current_k[4], tms->u[4]);
- tms->x[4] = tms->x[3] + matrix_multiply(tms->current_k[3], tms->u[3]);
- tms->x[3] = tms->x[2] + matrix_multiply(tms->current_k[2], tms->u[2]);
- tms->x[2] = tms->x[1] + matrix_multiply(tms->current_k[1], tms->u[1]);
- tms->x[1] = tms->x[0] + matrix_multiply(tms->current_k[0], tms->u[0]);
- tms->x[0] = tms->u[0];
- tms->previous_energy = tms->current_energy;
+ m_u[10] = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11)
+ m_u[9] = m_u[10] - matrix_multiply(m_current_k[9], m_x[9]);
+ m_u[8] = m_u[9] - matrix_multiply(m_current_k[8], m_x[8]);
+ m_u[7] = m_u[8] - matrix_multiply(m_current_k[7], m_x[7]);
+ m_u[6] = m_u[7] - matrix_multiply(m_current_k[6], m_x[6]);
+ m_u[5] = m_u[6] - matrix_multiply(m_current_k[5], m_x[5]);
+ m_u[4] = m_u[5] - matrix_multiply(m_current_k[4], m_x[4]);
+ m_u[3] = m_u[4] - matrix_multiply(m_current_k[3], m_x[3]);
+ 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]);
+ 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]);
+ m_x[6] = m_x[5] + matrix_multiply(m_current_k[5], m_u[5]);
+ m_x[5] = m_x[4] + matrix_multiply(m_current_k[4], m_u[4]);
+ m_x[4] = m_x[3] + matrix_multiply(m_current_k[3], m_u[3]);
+ m_x[3] = m_x[2] + matrix_multiply(m_current_k[2], m_u[2]);
+ m_x[2] = m_x[1] + matrix_multiply(m_current_k[1], m_u[1]);
+ 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;
- fprintf(stderr,"V:%04d ", tms->u[10]);
+ fprintf(stderr,"V:%04d ", m_u[10]);
for (i = 9; i >= 0; i--)
{
- fprintf(stderr,"Y%d:%04d ", i+1, tms->u[i]);
- fprintf(stderr,"b%d:%04d ", i+1, tms->x[i]);
+ fprintf(stderr,"Y%d:%04d ", i+1, m_u[i]);
+ fprintf(stderr,"b%d:%04d ", i+1, m_x[i]);
if ((i % 5) == 0) fprintf(stderr,"\n");
}
#endif
- return tms->u[0];
+ return m_u[0];
}
@@ -1267,7 +1129,7 @@ static INT32 lattice_filter(tms5220_state *tms)
***********************************************************************************************/
-static void process_command(tms5220_state *tms, unsigned char cmd)
+void tms5220_device::process_command(unsigned char cmd)
{
#ifdef DEBUG_COMMAND_DUMP
fprintf(stderr,"process_command called with parameter %02X\n",cmd);
@@ -1276,96 +1138,96 @@ static void process_command(tms5220_state *tms, unsigned char cmd)
switch (cmd & 0x70)
{
case 0x10 : /* read byte */
- if (tms->talk_status == 0) /* TALKST must be clear for RDBY */
+ if (m_talk_status == 0) /* TALKST must be clear for RDBY */
{
- if (tms->schedule_dummy_read)
+ if (m_schedule_dummy_read)
{
- tms->schedule_dummy_read = FALSE;
- if (tms->intf->read)
- (*tms->intf->read)(tms->device, 1);
+ m_schedule_dummy_read = FALSE;
+ if (m_speechrom)
+ m_speechrom->read(1);
}
- if (tms->intf->read)
- tms->data_register = (*tms->intf->read)(tms->device, 8); /* read one byte from speech ROM... */
- tms->RDB_flag = TRUE;
+ 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 only), otherwise NOP */
- if (tms->variant == TMS5220_IS_5220C)
+ if (m_variant == TMS5220_IS_5220C)
{
- tms->tms5220c_rate = cmd&0x0F;
+ m_tms5220c_rate = cmd&0x0F;
}
break;
case 0x30 : /* read and branch */
- if (tms->talk_status == 0) /* TALKST must be clear for RB */
+ if (m_talk_status == 0) /* TALKST must be clear for RB */
{
#ifdef VERBOSE
logerror("read and branch command received\n");
#endif
- tms->RDB_flag = FALSE;
- if (tms->intf->read_and_branch)
- (*tms->intf->read_and_branch)(tms->device);
+ m_RDB_flag = FALSE;
+ if (m_speechrom)
+ m_speechrom->read_and_branch();
}
break;
case 0x40 : /* load address */
- if (tms->talk_status == 0) /* TALKST must be clear for LA */
+ if (m_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 (tms->intf->load_address)
- (*tms->intf->load_address)(tms->device, cmd & 0x0f);
- tms->schedule_dummy_read = TRUE;
+ if (m_speechrom)
+ m_speechrom->load_address(cmd & 0x0f);
+ m_schedule_dummy_read = TRUE;
}
break;
case 0x50 : /* speak */
- if (tms->schedule_dummy_read)
+ if (m_schedule_dummy_read)
{
- tms->schedule_dummy_read = FALSE;
- if (tms->intf->read)
- (*tms->intf->read)(tms->device, 1);
+ m_schedule_dummy_read = FALSE;
+ if (m_speechrom)
+ m_speechrom->read(1);
}
- tms->speaking_now = 1;
- tms->speak_external = 0;
- tms->talk_status = 1; /* start immediately */
+ m_speaking_now = 1;
+ m_speak_external = 0;
+ m_talk_status = 1; /* start immediately */
/* clear out variables before speaking */
// TODO: similar to the victory case described above, but for VSM speech
- tms->subcycle = tms->subc_reload;
- tms->PC = 0;
- tms->IP = reload_table[tms->tms5220c_rate&0x3];
- tms->new_frame_energy_idx = 0;
- tms->new_frame_pitch_idx = 0;
+ m_subcycle = m_subc_reload;
+ m_PC = 0;
+ m_IP = reload_table[m_tms5220c_rate&0x3];
+ m_new_frame_energy_idx = 0;
+ m_new_frame_pitch_idx = 0;
int i;
for (i = 0; i < 4; i++)
- tms->new_frame_k_idx[i] = 0;
+ m_new_frame_k_idx[i] = 0;
for (i = 4; i < 7; i++)
- tms->new_frame_k_idx[i] = 0xF;
- for (i = 7; i < tms->coeff->num_k; i++)
- tms->new_frame_k_idx[i] = 0x7;
+ m_new_frame_k_idx[i] = 0xF;
+ for (i = 7; i < m_coeff->num_k; i++)
+ m_new_frame_k_idx[i] = 0x7;
break;
case 0x60 : /* speak external */
//SPKEXT going active activates SPKEE which clears the fifo
- tms->fifo_head = tms->fifo_tail = tms->fifo_count = tms->fifo_bits_taken = 0;
- tms->speak_external = 1;
- tms->RDB_flag = FALSE;
+ m_fifo_head = m_fifo_tail = m_fifo_count = m_fifo_bits_taken = 0;
+ m_speak_external = 1;
+ m_RDB_flag = FALSE;
break;
case 0x70 : /* reset */
- if (tms->schedule_dummy_read)
+ if (m_schedule_dummy_read)
{
- tms->schedule_dummy_read = FALSE;
- if (tms->intf->read)
- (*tms->intf->read)(tms->device, 1);
+ m_schedule_dummy_read = FALSE;
+ if (m_speechrom)
+ m_speechrom->read(1);
}
- tms->device->reset();
+ reset();
break;
}
/* update the buffer low state */
- update_status_and_ints(tms);
+ update_status_and_ints();
}
/******************************************************************************************
@@ -1374,7 +1236,7 @@ static void process_command(tms5220_state *tms, unsigned char cmd)
******************************************************************************************/
-static void parse_frame(tms5220_state *tms)
+void tms5220_device::parse_frame()
{
int indx, i, rep_flag;
@@ -1382,49 +1244,49 @@ static void parse_frame(tms5220_state *tms)
/* if the chip is a tms5220C, and the rate mode is set to that each frame (0x04 bit set)
has a 2 bit rate preceding it, grab two bits here and store them as the rate; */
- if ((tms->variant == TMS5220_IS_5220C) && (tms->tms5220c_rate & 0x04))
+ if ((m_variant == TMS5220_IS_5220C) && (m_tms5220c_rate & 0x04))
{
- indx = extract_bits(tms, 2);
+ indx = extract_bits(2);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(indx,2);
fprintf(stderr," ");
#endif
- tms->IP = reload_table[indx];
+ m_IP = reload_table[indx];
}
else // non-5220C and 5220C in fixed rate mode
- tms->IP = reload_table[tms->tms5220c_rate&0x3];
+ m_IP = reload_table[m_tms5220c_rate&0x3];
- update_status_and_ints(tms);
- if (!tms->talk_status) goto ranout;
+ update_status_and_ints();
+ if (!m_talk_status) goto ranout;
// attempt to extract the energy index
- tms->new_frame_energy_idx = extract_bits(tms,tms->coeff->energy_bits);
+ m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits);
#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(tms->new_frame_energy_idx,tms->coeff->energy_bits);
+ printbits(m_new_frame_energy_idx,m_coeff->energy_bits);
fprintf(stderr," ");
#endif
- update_status_and_ints(tms);
- if (!tms->talk_status) goto ranout;
+ update_status_and_ints();
+ if (!m_talk_status) goto ranout;
// if the energy index is 0 or 15, we're done
- if ((tms->new_frame_energy_idx == 0) || (tms->new_frame_energy_idx == 15))
+ if ((m_new_frame_energy_idx == 0) || (m_new_frame_energy_idx == 15))
return;
// attempt to extract the repeat flag
- rep_flag = extract_bits(tms,1);
+ rep_flag = extract_bits(1);
#ifdef DEBUG_PARSE_FRAME_DUMP
printbits(rep_flag, 1);
fprintf(stderr," ");
#endif
// attempt to extract the pitch
- tms->new_frame_pitch_idx = extract_bits(tms,tms->coeff->pitch_bits);
+ m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits);
#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(tms->new_frame_pitch_idx,tms->coeff->pitch_bits);
+ printbits(m_new_frame_pitch_idx,m_coeff->pitch_bits);
fprintf(stderr," ");
#endif
- update_status_and_ints(tms);
- if (!tms->talk_status) goto ranout;
+ update_status_and_ints();
+ if (!m_talk_status) goto ranout;
// if this is a repeat frame, just do nothing, it will reuse the old coefficients
if (rep_flag)
return;
@@ -1432,36 +1294,36 @@ static void parse_frame(tms5220_state *tms)
// extract first 4 K coefficients
for (i = 0; i < 4; i++)
{
- tms->new_frame_k_idx[i] = extract_bits(tms,tms->coeff->kbits[i]);
+ m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]);
#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(tms->new_frame_k_idx[i],tms->coeff->kbits[i]);
+ printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]);
fprintf(stderr," ");
#endif
- update_status_and_ints(tms);
- if (!tms->talk_status) goto ranout;
+ update_status_and_ints();
+ if (!m_talk_status) goto ranout;
}
// if the pitch index was zero, we only need 4 K's...
- if (tms->new_frame_pitch_idx == 0)
+ if (m_new_frame_pitch_idx == 0)
{
/* and the rest of the coefficients are zeroed, but that's done in the generator code */
return;
}
// If we got here, we need the remaining 6 K's
- for (i = 4; i < tms->coeff->num_k; i++)
+ for (i = 4; i < m_coeff->num_k; i++)
{
- tms->new_frame_k_idx[i] = extract_bits(tms, tms->coeff->kbits[i]);
+ m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]);
#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(tms->new_frame_k_idx[i],tms->coeff->kbits[i]);
+ printbits(m_new_frame_k_idx[i],m_coeff->kbits[i]);
fprintf(stderr," ");
#endif
- update_status_and_ints(tms);
- if (!tms->talk_status) goto ranout;
+ update_status_and_ints();
+ if (!m_talk_status) goto ranout;
}
#ifdef VERBOSE
- if (tms->speak_external)
- logerror("Parsed a frame successfully in FIFO - %d bits remaining\n", (tms->fifo_count*8)-(tms->fifo_bits_taken));
+ if (m_speak_external)
+ logerror("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
@@ -1480,14 +1342,14 @@ static void parse_frame(tms5220_state *tms)
***********************************************************************************************/
-static void set_interrupt_state(tms5220_state *tms, int state)
+void tms5220_device::set_interrupt_state(int state)
{
#ifdef DEBUG_PIN_READS
logerror("irq pin set to state %d\n", state);
#endif
- if (!tms->irq_func.isnull() && state != tms->irq_pin)
- tms->irq_func(!state);
- tms->irq_pin = state;
+ if (!m_irq_handler.isnull() && state != m_irq_pin)
+ m_irq_handler(!state);
+ m_irq_pin = state;
}
/**********************************************************************************************
@@ -1496,15 +1358,15 @@ static void set_interrupt_state(tms5220_state *tms, int state)
***********************************************************************************************/
-static void update_ready_state(tms5220_state *tms)
+void tms5220_device::update_ready_state()
{
- int state = tms5220_ready_read(tms);
+ int state = ready_read();
#ifdef DEBUG_PIN_READS
logerror("ready pin set to state %d\n", state);
#endif
- if (!tms->readyq_func.isnull() && state != tms->ready_pin)
- tms->readyq_func(!state);
- tms->ready_pin = state;
+ if (!m_readyq_handler.isnull() && state != m_ready_pin)
+ m_readyq_handler(!state);
+ m_ready_pin = state;
}
@@ -1514,113 +1376,121 @@ static void update_ready_state(tms5220_state *tms)
***********************************************************************************************/
-static DEVICE_START( tms5220 )
-{
- static const tms5220_interface dummy = { DEVCB_NULL };
- tms5220_state *tms = get_safe_token(device);
-
- tms->intf = device->static_config() ? (const tms5220_interface *)device->static_config() : &dummy;
- //tms->table = *device->region();
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
- tms->device = device;
- tms5220_set_variant(tms, TMS5220_IS_5220);
- tms->clock = device->clock();
+void tms5220_device::device_start()
+{
+ if (m_speechrom_tag)
+ {
+ m_speechrom = siblingdevice<speechrom_device>( m_speechrom_tag );
+ if( !m_speechrom )
+ {
+ throw new emu_fatalerror("Error: %s '%s' can't find speechrom '%s'\n", shortname(), tag(), m_speechrom_tag );
+ }
+ }
+ else
+ {
+ m_speechrom = NULL;
+ }
- assert_always(tms != NULL, "Error creating TMS5220 chip");
+ set_variant(TMS5220_IS_5220);
+ m_clock = clock();
/* resolve irq and readyq line */
- tms->irq_func.resolve(tms->intf->irq_func, *device);
- tms->readyq_func.resolve(tms->intf->readyq_func, *device);
+ m_irq_handler.resolve();
+ m_readyq_handler.resolve();
/* initialize a stream */
- tms->stream = device->machine().sound().stream_alloc(*device, 0, 1, device->clock() / 80, tms, tms5220_update);
+ m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80);
- /*if (tms->table == NULL)
- {
- assert_always(tms->intf->M0_callback != NULL, "Missing _mandatory_ 'M0_callback' function pointer in the TMS5110 interface\n This function is used by TMS5220 to call for a new single bit\n needed to generate the speech when in VSM mode\n Aborting startup...\n");
- tms->M0_callback = tms->intf->M0_callback;
- tms->set_load_address = tms->intf->load_address;
- }
- else
- {
- tms->M0_callback = speech_rom_read_bit;
- tms->set_load_address = speech_rom_set_addr;
- }*/
+ m_timer_io_ready = timer_alloc(0);
/* not during reset which is called frm within a write! */
- tms->io_ready = 1;
- tms->true_timing = 0;
- tms->rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup
+ m_io_ready = 1;
+ m_true_timing = 0;
+ m_rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup
- register_for_save_states(tms);
+ register_for_save_states();
}
-static DEVICE_START( tms5220c )
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tms5220c_device::device_start()
{
- tms5220_state *tms = get_safe_token(device);
- DEVICE_START_CALL( tms5220 );
- tms5220_set_variant(tms, TMS5220_IS_5220C);
+ tms5220_device::device_start();
+ set_variant(TMS5220_IS_5220C);
}
-static DEVICE_START( tmc0285 )
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void tmc0285_device::device_start()
{
- tms5220_state *tms = get_safe_token(device);
- DEVICE_START_CALL( tms5220 );
- tms5220_set_variant(tms, TMS5220_IS_TMC0285);
+ tms5220_device::device_start();
+ set_variant(TMS5220_IS_TMC0285);
}
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
-static DEVICE_START( tms5200 )
+void tms5200_device::device_start()
{
- tms5220_state *tms = get_safe_token(device);
- DEVICE_START_CALL( tms5220 );
- tms5220_set_variant(tms, TMS5220_IS_5200);
+ tms5220_device::device_start();
+ set_variant(TMS5220_IS_5200);
}
-static DEVICE_RESET( tms5220 )
-{
- tms5220_state *tms = get_safe_token(device);
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
- tms->digital_select = FORCE_DIGITAL; // assume analog output
+void tms5220_device::device_reset()
+{
+ m_digital_select = FORCE_DIGITAL; // assume analog output
/* initialize the FIFO */
- /*memset(tms->fifo, 0, sizeof(tms->fifo));*/
- tms->fifo_head = tms->fifo_tail = tms->fifo_count = tms->fifo_bits_taken = 0;
+ /*memset(m_fifo, 0, sizeof(m_fifo));*/
+ 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 tms->buffer_empty or tms->buffer_low are 0 */
- tms->speaking_now = tms->speak_external = tms->talk_status = tms->irq_pin = tms->ready_pin = 0;
- set_interrupt_state(tms, 0);
- update_ready_state(tms);
- tms->buffer_empty = tms->buffer_low = 1;
+ /* 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_speaking_now = m_speak_external = m_talk_status = m_irq_pin = m_ready_pin = 0;
+ set_interrupt_state(0);
+ update_ready_state();
+ m_buffer_empty = m_buffer_low = 1;
- tms->RDB_flag = FALSE;
+ m_RDB_flag = FALSE;
/* initialize the energy/pitch/k states */
#ifdef PERFECT_INTERPOLATION_HACK
- tms->old_frame_energy_idx = tms->old_frame_pitch_idx = 0;
- memset(tms->old_frame_k_idx, 0, sizeof(tms->old_frame_k_idx));
+ m_old_frame_energy_idx = m_old_frame_pitch_idx = 0;
+ memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx));
#endif
- tms->new_frame_energy_idx = tms->current_energy = tms->target_energy = 0;
- tms->new_frame_pitch_idx = tms->current_pitch = tms->target_pitch = 0;
- memset(tms->new_frame_k_idx, 0, sizeof(tms->new_frame_k_idx));
- memset(tms->current_k, 0, sizeof(tms->current_k));
- memset(tms->target_k, 0, sizeof(tms->target_k));
+ m_new_frame_energy_idx = m_current_energy = m_target_energy = 0;
+ m_new_frame_pitch_idx = m_current_pitch = m_target_pitch = 0;
+ memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx));
+ memset(m_current_k, 0, sizeof(m_current_k));
+ memset(m_target_k, 0, sizeof(m_target_k));
/* initialize the sample generators */
- tms->inhibit = 1;
- tms->subcycle = tms->tms5220c_rate = tms->pitch_count = tms->PC = 0;
- tms->subc_reload = FORCE_SUBC_RELOAD;
- tms->OLDE = tms->OLDP = 1;
- tms->IP = reload_table[tms->tms5220c_rate&0x3];
- tms->RNG = 0x1FFF;
- memset(tms->u, 0, sizeof(tms->u));
- memset(tms->x, 0, sizeof(tms->x));
-
- if (tms->intf->load_address)
- (*tms->intf->load_address)(tms->device, 0);
-
- tms->schedule_dummy_read = TRUE;
+ m_inhibit = 1;
+ m_subcycle = m_tms5220c_rate = m_pitch_count = m_PC = 0;
+ m_subc_reload = FORCE_SUBC_RELOAD;
+ m_OLDE = m_OLDP = 1;
+ m_IP = reload_table[m_tms5220c_rate&0x3];
+ m_RNG = 0x1FFF;
+ memset(m_u, 0, sizeof(m_u));
+ memset(m_x, 0, sizeof(m_x));
+
+ if (m_speechrom)
+ m_speechrom->load_address(0);
+
+ m_schedule_dummy_read = TRUE;
}
/**********************************************************************************************
@@ -1629,61 +1499,65 @@ static DEVICE_RESET( tms5220 )
***********************************************************************************************/
-static TIMER_CALLBACK( io_ready_cb )
+void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
- tms5220_state *tms = (tms5220_state *) ptr;
- if (param)
+ switch(id)
{
- switch (tms->rs_ws)
+ case 0:
+ if (param)
{
- case 0x02:
- /* Write */
- /* bring up to date first */
+ switch (m_rs_ws)
+ {
+ case 0x02:
+ /* Write */
+ /* bring up to date first */
#ifdef DEBUG_IO_READY
- logerror("Serviced write: %02x\n", tms->write_latch);
- //fprintf(stderr, "Processed write data: %02X\n", tms->write_latch);
-#endif
- tms->stream->update();
- tms5220_data_write(tms, tms->write_latch);
- break;
- case 0x01:
- /* Read */
- /* bring up to date first */
- tms->stream->update();
- tms->read_latch = tms5220_status_read(tms);
- break;
- case 0x03:
- /* High Impedance */
- case 0x00:
- /* illegal */
- break;
+ logerror("Serviced write: %02x\n", m_write_latch);
+ //fprintf(stderr, "Processed write data: %02X\n", m_write_latch);
+#endif
+ m_stream->update();
+ data_write(m_write_latch);
+ break;
+ case 0x01:
+ /* Read */
+ /* bring up to date first */
+ m_stream->update();
+ m_read_latch = status_read();
+ break;
+ case 0x03:
+ /* High Impedance */
+ case 0x00:
+ /* illegal */
+ break;
+ }
}
+
+ m_io_ready = param;
+ update_ready_state();
+ break;
}
- tms->io_ready = param;
- update_ready_state(tms);
}
/*
* /RS line write handler
*/
-WRITE_LINE_DEVICE_HANDLER( tms5220_rsq_w )
+WRITE_LINE_MEMBER( tms5220_device::rsq_w )
{
- tms5220_state *tms = get_safe_token(device);
UINT8 new_val;
- tms->true_timing = 1;
+ m_true_timing = 1;
state &= 0x01;
#ifdef DEBUG_RS_WS
logerror("/RS written with data: %d\n", state);
#endif
- new_val = (tms->rs_ws & 0x01) | (state<<1);
- if (new_val != tms->rs_ws)
+ new_val = (m_rs_ws & 0x01) | (state<<1);
+ if (new_val != m_rs_ws)
{
- tms->rs_ws = new_val;
+ m_rs_ws = new_val;
if (new_val == 0)
{
- if (tms->variant == TMS5220_IS_5220C)
- device->reset();
+ if (m_variant == TMS5220_IS_5220C)
+ reset();
#ifdef DEBUG_RS_WS
else
/* illegal */
@@ -1694,7 +1568,7 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_rsq_w )
else if ( new_val == 3)
{
/* high impedance */
- tms->read_latch = 0xff;
+ m_read_latch = 0xff;
return;
}
if (state)
@@ -1708,10 +1582,10 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_rsq_w )
logerror("Scheduling ready cycle for /RS...\n");
#endif
/* 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. */
- tms->io_ready = 0;
- update_ready_state(tms);
+ 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) */
- tms->device->machine().scheduler().timer_set(attotime::from_hz(device->clock()/16), FUNC(io_ready_cb), 1, tms); // this should take around 10-16 (closer to ~11?) cycles to complete
+ m_timer_io_ready->adjust(attotime::from_hz(clock()/16), 1); // this should take around 10-16 (closer to ~11?) cycles to complete
}
}
}
@@ -1719,24 +1593,23 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_rsq_w )
/*
* /WS line write handler
*/
-WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w )
+WRITE_LINE_MEMBER( tms5220_device::wsq_w )
{
- tms5220_state *tms = get_safe_token(device);
UINT8 new_val;
- tms->true_timing = 1;
+ m_true_timing = 1;
state &= 0x01;
#ifdef DEBUG_RS_WS
logerror("/WS written with data: %d\n", state);
#endif
- new_val = (tms->rs_ws & 0x02) | (state<<0);
- if (new_val != tms->rs_ws)
+ new_val = (m_rs_ws & 0x02) | (state<<0);
+ if (new_val != m_rs_ws)
{
- tms->rs_ws = new_val;
+ m_rs_ws = new_val;
if (new_val == 0)
{
- if (tms->variant == TMS5220_IS_5220C)
- device->reset();
+ if (m_variant == TMS5220_IS_5220C)
+ reset();
#ifdef DEBUG_RS_WS
else
/* illegal */
@@ -1747,7 +1620,7 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w )
else if ( new_val == 3)
{
/* high impedance */
- tms->read_latch = 0xff;
+ m_read_latch = 0xff;
return;
}
if (state)
@@ -1761,8 +1634,8 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w )
logerror("Scheduling ready cycle for /WS...\n");
#endif
/* 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. */
- tms->io_ready = 0;
- update_ready_state(tms);
+ m_io_ready = 0;
+ update_ready_state();
/* Now comes the complicated part: 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:
@@ -1774,7 +1647,7 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w )
SET RATE (5220C only): ? cycles (probably ~16)
*/
// TODO: actually HANDLE the timing differences! currently just assuming always 16 cycles
- tms->device->machine().scheduler().timer_set(attotime::from_hz(device->clock()/16), FUNC(io_ready_cb), 1, tms); // this should take around 10-16 (closer to ~15) cycles to complete for fifo writes, TODO: but actually depends on what command is written if in command mode
+ m_timer_io_ready->adjust(attotime::from_hz(clock()/16), 1); // this should take around 10-16 (closer to ~15) cycles to complete for fifo writes, TODO: but actually depends on what command is written if in command mode
}
}
}
@@ -1785,26 +1658,25 @@ WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w )
***********************************************************************************************/
-WRITE8_DEVICE_HANDLER( tms5220_data_w )
+WRITE8_MEMBER( tms5220_device::data_w )
{
- tms5220_state *tms = get_safe_token(device);
#ifdef DEBUG_RS_WS
logerror("tms5220_data_w: data %02x\n", data);
#endif
- if (!tms->true_timing)
+ if (!m_true_timing)
{
/* bring up to date first */
- tms->stream->update();
- tms5220_data_write(tms, data);
+ m_stream->update();
+ data_write(data);
}
else
{
/* actually in a write ? */
#ifdef DEBUG_RS_WS
- if (!(tms->rs_ws == 0x02))
- logerror("tms5220_data_w: data written outside ws, status: %02x!\n", tms->rs_ws);
+ if (!(m_rs_ws == 0x02))
+ logerror("tms5220_data_w: data written outside ws, status: %02x!\n", m_rs_ws);
#endif
- tms->write_latch = data;
+ m_write_latch = data;
}
}
@@ -1816,20 +1688,19 @@ WRITE8_DEVICE_HANDLER( tms5220_data_w )
***********************************************************************************************/
-READ8_DEVICE_HANDLER( tms5220_status_r )
+READ8_MEMBER( tms5220_device::status_r )
{
- tms5220_state *tms = get_safe_token(device);
- if (!tms->true_timing)
+ if (!m_true_timing)
{
/* bring up to date first */
- tms->stream->update();
- return tms5220_status_read(tms);
+ m_stream->update();
+ return status_read();
}
else
{
/* actually in a read ? */
- if (tms->rs_ws == 0x01)
- return tms->read_latch;
+ if (m_rs_ws == 0x01)
+ return m_read_latch;
#ifdef DEBUG_RS_WS
else
logerror("tms5220_status_r: data read outside rs!\n");
@@ -1846,12 +1717,11 @@ READ8_DEVICE_HANDLER( tms5220_status_r )
***********************************************************************************************/
-READ_LINE_DEVICE_HANDLER( tms5220_readyq_r )
+READ_LINE_MEMBER( tms5220_device::readyq_r )
{
- tms5220_state *tms = get_safe_token(device);
/* bring up to date first */
- tms->stream->update();
- return !tms5220_ready_read(tms);
+ m_stream->update();
+ return !ready_read();
}
@@ -1862,15 +1732,14 @@ READ_LINE_DEVICE_HANDLER( tms5220_readyq_r )
***********************************************************************************************/
-double tms5220_time_to_ready(device_t *device)
+double tms5220_device::time_to_ready()
{
- tms5220_state *tms = get_safe_token(device);
double cycles;
/* bring up to date first */
- tms->stream->update();
- cycles = tms5220_cycles_to_ready(tms);
- return cycles * 80.0 / tms->clock;
+ m_stream->update();
+ cycles = cycles_to_ready();
+ return cycles * 80.0 / m_clock;
}
@@ -1881,12 +1750,11 @@ double tms5220_time_to_ready(device_t *device)
***********************************************************************************************/
-READ_LINE_DEVICE_HANDLER( tms5220_intq_r )
+READ_LINE_MEMBER( tms5220_device::intq_r )
{
- tms5220_state *tms = get_safe_token(device);
/* bring up to date first */
- tms->stream->update();
- return !tms5220_int_read(tms);
+ m_stream->update();
+ return !int_read();
}
@@ -1897,9 +1765,12 @@ READ_LINE_DEVICE_HANDLER( tms5220_intq_r )
***********************************************************************************************/
-static STREAM_UPDATE( tms5220_update )
+//-------------------------------------------------
+// sound_stream_update - handle a stream update
+//-------------------------------------------------
+
+void tms5220_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
{
- tms5220_state *tms = (tms5220_state *)param;
INT16 sample_data[MAX_SAMPLE_CHUNK];
stream_sample_t *buffer = outputs[0];
@@ -1910,7 +1781,7 @@ static STREAM_UPDATE( tms5220_update )
int index;
/* generate the samples and copy to the target buffer */
- tms5220_process(tms, sample_data, length);
+ process(sample_data, length);
for (index = 0; index < length; index++)
*buffer++ = sample_data[index];
@@ -1927,11 +1798,10 @@ static STREAM_UPDATE( tms5220_update )
***********************************************************************************************/
-void tms5220_set_frequency(device_t *device, int frequency)
+void tms5220_device::set_frequency(int frequency)
{
- tms5220_state *tms = get_safe_token(device);
- tms->stream->set_sample_rate(frequency / 80);
- tms->clock = frequency;
+ m_stream->set_sample_rate(frequency / 80);
+ m_clock = frequency;
}
const device_type TMS5220C = &device_creator<tms5220c_device>;
@@ -1941,39 +1811,25 @@ tms5220c_device::tms5220c_device(const machine_config &mconfig, const char *tag,
{
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void tms5220c_device::device_start()
-{
- DEVICE_START_NAME( tms5220c )(this);
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void tms5220c_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update called; not applicable to legacy sound devices\n");
-}
-
const device_type TMS5220 = &device_creator<tms5220_device>;
tms5220_device::tms5220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, TMS5220, "TMS5220", tag, owner, clock),
- device_sound_interface(mconfig, *this)
+ device_sound_interface(mconfig, *this),
+ m_irq_handler(*this),
+ m_readyq_handler(*this),
+ m_speechrom_tag(NULL)
{
- m_token = global_alloc_clear(tms5220_state);
}
+
tms5220_device::tms5220_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock)
: device_t(mconfig, type, name, tag, owner, clock),
- device_sound_interface(mconfig, *this)
+ device_sound_interface(mconfig, *this),
+ m_irq_handler(*this),
+ m_readyq_handler(*this),
+ m_speechrom_tag(NULL)
{
- m_token = global_alloc_clear(tms5220_state);
}
//-------------------------------------------------
@@ -1986,34 +1842,6 @@ void tms5220_device::device_config_complete()
{
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void tms5220_device::device_start()
-{
- DEVICE_START_NAME( tms5220 )(this);
-}
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void tms5220_device::device_reset()
-{
- DEVICE_RESET_NAME( tms5220 )(this);
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void tms5220_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update called; not applicable to legacy sound devices\n");
-}
-
const device_type TMC0285 = &device_creator<tmc0285_device>;
@@ -2022,25 +1850,6 @@ tmc0285_device::tmc0285_device(const machine_config &mconfig, const char *tag, d
{
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void tmc0285_device::device_start()
-{
- DEVICE_START_NAME( tmc0285 )(this);
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void tmc0285_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update called; not applicable to legacy sound devices\n");
-}
-
const device_type TMS5200 = &device_creator<tms5200_device>;
@@ -2048,1367 +1857,3 @@ tms5200_device::tms5200_device(const machine_config &mconfig, const char *tag, d
: tms5220_device(mconfig, TMS5200, "TMS5200", tag, owner, clock)
{
}
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void tms5200_device::device_start()
-{
- DEVICE_START_NAME( tms5200 )(this);
-}
-
-//-------------------------------------------------
-// sound_stream_update - handle a stream update
-//-------------------------------------------------
-
-void tms5200_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- // should never get here
- fatalerror("sound_stream_update called; not applicable to legacy sound devices\n");
-}
-
-
-
-
-/******************************************************************************
- New class implementation
-******************************************************************************/
-
-#define M_INTERP_SHIFT >> m_coeff->interp_coeff[m_IP]
-
-tms52xx_device::tms52xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, const struct tms5100_coeffs* coeffs, const int var, device_t *owner, UINT32 clock)
- : device_t(mconfig, type, name, tag, owner, clock),
- device_sound_interface(mconfig, *this),
- m_variant(var),
- m_coeff(coeffs)
-{
-}
-
-
-tms5220n_device::tms5220n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms52xx_device(mconfig, TMS5220N, "TMS5220N", tag, &tms5220_coeff, TMS5220_IS_5220, owner, clock)
-{
-}
-
-tms5220cn_device::tms5220cn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms52xx_device(mconfig, TMS5220CN, "TMS5220CN", tag, &tms5220_coeff, TMS5220_IS_5220C, owner, clock)
-{
-}
-
-tmc0285n_device::tmc0285n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms52xx_device(mconfig, TMC0285N, "TMC0285N", tag, &tms5200_coeff, TMS5220_IS_TMC0285, owner, clock)
-{
-}
-
-tms5200n_device::tms5200n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock)
- : tms52xx_device(mconfig, TMS5200N, "TMS5200N", tag, &tms5200_coeff, TMS5220_IS_5200, owner, clock)
-{
-}
-
-void tms52xx_device::device_start()
-{
- const tms52xx_config *conf = reinterpret_cast<const tms52xx_config *>(static_config());
- //m_table = region();
-
- /* resolve irq and readyq line */
- m_irq_func.resolve(conf->irq_func, *this);
- m_readyq_func.resolve(conf->readyq_func, *this);
- m_read_mem.resolve(conf->read_mem, *this);
- m_load_address.resolve(conf->load_address, *this);
- m_read_and_branch.resolve(conf->read_and_branch, *this);
-
- /* initialize a stream */
- m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80, this);
-
- /*if (m_table == NULL)
- {
- assert_always(m_conf->M0_callback != NULL, "Missing _mandatory_ 'M0_callback' function pointer in the TMS5110 interface\n This function is used by TMS5220 to call for a new single bit\n needed to generate the speech when in VSM mode\n Aborting startup...\n");
- m_M0_callback = conf->M0_callback;
- m_set_load_address = conf->load_address;
- }
- else
- {
- m_M0_callback = speech_rom_read_bit;
- m_set_load_address = speech_rom_set_addr;
- }*/
-
- /* not during reset which is called frm within a write! */
- m_io_ready = true;
- m_true_timing = false;
- m_rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup
-
- m_ready_timer = timer_alloc(0);
-
- register_for_save_states();
-}
-
-void tms52xx_device::device_reset()
-{
- m_digital_select = FORCE_DIGITAL; // assume analog output
- // initialize the FIFO
- // should we do a memset here to clear the fifo contents?
- m_fifo_head = 0;
- m_fifo_tail = 0;
- m_fifo_count = 0;
- 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_speaking_now = false;
- m_speak_external = false;
- m_talk_status = false;
- m_irq_pin = 0; // CLEAR_LINE
- m_ready_pin = 0; // CLEAR_LINE
-
- set_interrupt_state(0); // CLEAR_LINE
- update_ready_state();
- m_buffer_empty = true;
- m_buffer_low = true;
-
- m_RDB_flag = false;
-
- /* initialize the energy/pitch/k states */
-#ifdef PERFECT_INTERPOLATION_HACK
- m_old_frame_energy_idx = 0;
- m_old_frame_pitch_idx = 0;
- memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx));
-#endif
-
- m_new_frame_energy_idx = 0;
- m_current_energy = 0;
- m_target_energy = 0;
- m_new_frame_pitch_idx = 0;
- m_current_pitch = 0;
- m_target_pitch = 0;
-
- memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx));
- memset(m_current_k, 0, sizeof(m_current_k));
- memset(m_target_k, 0, sizeof(m_target_k));
-
- /* initialize the sample generators */
- m_inhibit = true;
- m_subcycle = 0;
- m_tms5220c_rate = 0;
- m_pitch_count = 0;
- m_PC = 0;
-
- m_subc_reload = FORCE_SUBC_RELOAD;
- m_OLDE = 1;
- m_OLDP = 1;
-
- m_IP = reload_table[m_tms5220c_rate&0x3];
- m_RNG = 0x1FFF;
- memset(m_u, 0, sizeof(m_u));
- memset(m_x, 0, sizeof(m_x));
-
- m_load_address(0, 0);
- m_schedule_dummy_read = true;
-}
-
-/******************************************************************************
- set_interrupt_state -- generate an interrupt
-*******************************************************************************/
-
-void tms52xx_device::set_interrupt_state(int state)
-{
-#ifdef DEBUG_PIN_READS
- logerror("tms52xx: irq pin set to state %d\n", state);
-#endif
- if (state != m_irq_pin) m_irq_func(!state);
- m_irq_pin = state;
-}
-
-/******************************************************************************
- update_ready_state -- update the ready line
-*******************************************************************************/
-
-void tms52xx_device::update_ready_state()
-{
- int state = ready_read();
-#ifdef DEBUG_PIN_READS
- logerror("tms52xx: ready pin set to state %d\n", state);
-#endif
- if (state != m_ready_pin) m_readyq_func(!state);
- m_ready_pin = state;
-}
-
-/******************************************************************************
- tms5220_set_frequency -- adjusts the playback frequency
-*******************************************************************************/
-
-void tms52xx_device::set_frequency(int frequency)
-{
- m_stream->set_sample_rate(frequency / 80);
- m_clock = frequency;
-}
-
-/******************************************************************************
- tms5220_update -- update the sound chip so that it is in sync with CPU execution
-*******************************************************************************/
-
-void tms52xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples)
-{
- INT16 sample_data[MAX_SAMPLE_CHUNK];
- stream_sample_t *buffer = outputs[0];
-
- /* loop while we still have samples to generate */
- while (samples>0)
- {
- int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples;
- int index;
-
- /* generate the samples and copy to the target buffer */
- process(sample_data, length);
- for (index = 0; index < length; index++)
- *buffer++ = sample_data[index];
-
- /* account for the samples */
- samples -= length;
- }
-}
-
-/******************************************************************************
- process -- fill the buffer with a specific number of samples
-*******************************************************************************/
-
-void tms52xx_device::process(INT16 *buffer, unsigned int size)
-{
- int buf_count=0;
- int i, bitout;
- bool zpar;
- INT32 this_sample;
-
- // The following gotos are probably safe to remove
- // if we're empty and still not speaking, fill with nothingness
- if (!m_speaking_now) goto empty;
-
- // if speak external is set, but talk status is not (yet) set,
- // wait for buffer low to clear
- if (!m_talk_status && m_speak_external && m_buffer_low) goto empty;
-
- // loop until the buffer is full or we've stopped speaking
- while ((size > 0) && m_speaking_now)
- {
- /* if it is the appropriate time to update the old energy/pitch idxes,
- * i.e. when IP=7, PC=12, T=17, subcycle=2, do so. Since IP=7 PC=12 T=17
- * is JUST BEFORE the transition to IP=0 PC=0 T=0 sybcycle=(0 or 1),
- * which happens 4 T-cycles later), we change on the latter.
- */
- if ((m_IP == 0) && (m_PC == 0) && (m_subcycle < 2))
- {
- m_OLDE = (m_new_frame_energy_idx == 0);
- m_OLDP = (m_new_frame_pitch_idx == 0);
- }
-
- /* if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1
- * (In reality, the frame was really loaded incrementally during the
- * entire IP=0 PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens)
- */
- if ((m_IP == 0) && (m_PC == 12) && (m_subcycle == 1))
- {
- // HACK for regression testing, be sure to comment out before release!
- // m_RNG = 0x1234;
- // end HACK
-
- // appropriately override the interp count if needed; this will be incremented after the frame parse!
- m_IP = reload_table[m_tms5220c_rate & 0x3];
-
-#ifdef PERFECT_INTERPOLATION_HACK
- // remember previous frame energy, pitch, and coefficients
- m_old_frame_energy_idx = m_new_frame_energy_idx;
- m_old_frame_pitch_idx = m_new_frame_pitch_idx;
- for (i = 0; i < m_coeff->num_k; i++)
- m_old_frame_k_idx[i] = m_new_frame_k_idx[i];
-#endif
-
- // if the talk status was clear last frame, halt speech now.
- if (m_talk_status == false)
- {
-#ifdef DEBUG_GENERATION
- fprintf(stderr,"tms5220_process: processing frame: talk status = 0 caused by stop frame or buffer empty, halting speech.\n");
-#endif
- m_speaking_now = false; // finally halt speech
- goto empty;
- }
-
- // Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[]
- parse_frame();
-#ifdef DEBUG_PARSE_FRAME_DUMP
- fprintf(stderr,"\n");
-#endif
- // if the new frame is a stop frame, set an interrupt and set talk status to 0
- if (M_NEW_FRAME_STOP_FLAG == 1)
- {
- m_talk_status = false;
- m_speak_external = false;
- set_interrupt_state(1);
- update_status_and_ints();
- }
-
- // in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it.
- // Interpolation inhibit cases:
- // * Old frame was voiced, new is unvoiced
- // * Old frame was silence/zero energy, new has nonzero energy
- // * Old frame was unvoiced, new is voiced
-
- if ( ((M_OLD_FRAME_UNVOICED_FLAG == false) && (M_NEW_FRAME_UNVOICED_FLAG == true))
- || ((M_OLD_FRAME_UNVOICED_FLAG == true) && (M_NEW_FRAME_UNVOICED_FLAG == false)) /* this line needs further investigation, starwars tie fighters may sound better without it */
- || ((M_OLD_FRAME_SILENCE_FLAG == true) && (M_NEW_FRAME_SILENCE_FLAG == false)) )
- m_inhibit = true;
- else // normal frame, normal interpolation
- m_inhibit = false;
-
- // load new frame targets from tables, using parsed indices
- m_target_energy = m_coeff->energytable[m_new_frame_energy_idx];
- m_target_pitch = m_coeff->pitchtable[m_new_frame_pitch_idx];
- zpar = M_NEW_FRAME_UNVOICED_FLAG; // find out if parameters k5-k10 should be zeroed
- for (i = 0; i < 4; i++)
- m_target_k[i] = m_coeff->ktable[i][m_new_frame_k_idx[i]];
- for (i = 4; i < m_coeff->num_k; i++)
- m_target_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-zpar));
-
-#ifdef DEBUG_GENERATION
- /* Debug info for current parsed frame */
- fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP);
- fprintf(stderr,"Processing frame: ");
- if (m_inhibit == 0)
- fprintf(stderr, "Normal Frame\n");
- else
- fprintf(stderr,"Interpolation Inhibited\n");
- fprintf(stderr,"*** 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]);
- fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",
- m_target_energy, m_new_frame_energy_idx, m_target_pitch,
- m_target_k[0], m_target_k[1], m_target_k[2], m_target_k[3],
- m_target_k[4], m_target_k[5], m_target_k[6], m_target_k[7],
- m_target_k[8], m_target_k[9]);
-#endif
-
- /* if TS is now 0, ramp the energy down to 0. Is this really correct to hardware? */
- if (!m_talk_status)
- {
-#ifdef DEBUG_GENERATION
- fprintf(stderr,"Talk status is 0, forcing target energy to 0\n");
-#endif
- m_target_energy = 0;
- }
- }
- else // Not a new frame, just interpolate the existing frame.
- {
- bool inhibit_state = (m_inhibit && (m_IP != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the tms->inhibit value
-#ifdef PERFECT_INTERPOLATION_HACK
- int samples_per_frame = (m_subc_reload!=0)? 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!=0)?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_subcycle - m_subc_reload)+(m_PC*(3-m_subc_reload))+((m_subc_reload?25:38)*((m_IP-1)&7));
-
- zpar = M_OLD_FRAME_UNVOICED_FLAG;
- //fprintf(stderr, "CS: %03d", current_sample);
- // reset the current energy, pitch, etc to what it was at frame start
- m_current_energy = m_coeff->energytable[m_old_frame_energy_idx];
- m_current_pitch = m_coeff->pitchtable[m_old_frame_pitch_idx];
- for (i = 0; i < 4; i++)
- m_current_k[i] = m_coeff->ktable[i][m_old_frame_k_idx[i]];
- for (i = 4; i < m_coeff->num_k; i++)
- m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-zpar));
- // now adjust each value to be exactly correct for each of the samples per frame
- if (m_IP != 0) // if we're still interpolating...
- {
- if (!inhibit_state)
- {
- m_current_energy += ((m_target_energy - m_current_energy)*current_sample)/samples_per_frame;
- m_current_pitch += ((m_target_pitch - m_current_pitch)*current_sample)/samples_per_frame;
- for (i = 0; i < m_coeff->num_k; i++)
- {
- m_current_k[i] += ((m_target_k[i] - m_current_k[i])*current_sample)/samples_per_frame;
- }
- }
- }
- else // we're done, play this frame for 1/8 frame.
- {
- m_current_energy = m_target_energy;
- m_current_pitch = m_target_pitch;
- for (i = 0; i < m_coeff->num_k; i++)
- m_current_k[i] = m_target_k[i];
- }
-#else
- // Updates to parameters only happen on subcycle '2' (B cycle) of PCs.
- if (m_subcycle == 2)
- {
- if (!inhibit_state)
- {
- switch(m_PC)
- {
- case 0: // PC = 0, B cycle, write updated energy
- m_current_energy += ((m_target_energy - m_current_energy) M_INTERP_SHIFT);
- break;
- case 1: /* PC = 1, B cycle, write updated pitch */
- m_current_pitch += ((m_target_pitch - m_current_pitch) M_INTERP_SHIFT);
- break;
- case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11:
- /* PC = 2 through 11, B cycle, write updated K1 through K10 */
- m_current_k[m_PC-2] += ((m_target_k[m_PC-2] - m_current_k[m_PC-2]) M_INTERP_SHIFT);
- break;
- case 12: /* PC = 12, do nothing */
- break;
- }
- }
- }
-#endif
- }
-
- // calculate the output
- if (M_OLD_FRAME_UNVOICED_FLAG == true)
- {
- // generate unvoiced samples here
- if (m_RNG & 1)
- m_excitation_data = ~0x3F; // according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0)
- else
- m_excitation_data = 0x40;
- }
- else // (M_OLD_FRAME_UNVOICED_FLAG == false)
- {
- // generate voiced samples here
- // US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp
- // function has a chirp/peak and then a long chain of zeroes.
- // The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample,
- // and if the address reaches that point the ADDRESS incrementer is
- // disabled, forcing all samples beyond 51d to be == 51d
-
- if (m_pitch_count >= 51)
- m_excitation_data = m_coeff->chirptable[51];
- else // tms->pitch_count < 51
- m_excitation_data = m_coeff->chirptable[m_pitch_count];
- }
-
- // Update LFSR *20* times every sample (once per T cycle), like patent shows
- for (i=0; i<20; i++)
- {
- bitout = ((m_RNG >> 12) & 1) ^
- ((m_RNG >> 3) & 1) ^
- ((m_RNG >> 2) & 1) ^
- ((m_RNG >> 0) & 1);
- m_RNG <<= 1;
- m_RNG |= bitout;
- }
-
- this_sample = lattice_filter(); // execute lattice filter
-#ifdef DEBUG_GENERATION_VERBOSE
- //fprintf(stderr,"C:%01d; ",tms->subcycle);
- fprintf(stderr,"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);
- //fprintf(stderr,"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++)
- fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]);
- fprintf(stderr,"Out:%06d", this_sample);
- fprintf(stderr,"\n");
-#endif
- // 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;
- if (!m_digital_select) // analog SPK pin output is only 8 bits, with clipping
- buffer[buf_count] = clip_analog(this_sample);
- else // digital I/O pin output is 12 bits
- {
-#ifdef ALLOW_4_LSB
- // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn
- // N taps: ^ = 0x2000;
- // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN
- buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13);
-#else
- this_sample &= ~0xF;
- // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000
- // N taps: ^^ ^^^ = 0x3E00;
- // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN
- buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9);
-#endif
- }
-
- // Update all counts
- m_subcycle++;
- if ((m_subcycle == 2) && (m_PC == 12))
- {
- /* Circuit 412 in the patent acts a reset, resetting the pitch counter to 0
- * if INHIBIT was true during the most recent frame transition.
- * The exact time this occurs is betwen IP=7, PC=12 sub=0, T=t12
- * and tms->IP = 0, PC=0 sub=0, T=t12, a period of exactly 20 cycles,
- * which overlaps the time OLDE and OLDP are updated at IP=7 PC=12 T17
- * (and hence INHIBIT itself 2 t-cycles later). We do it here because it is
- * convenient and should make no difference in output.
- */
- if ((m_IP == 7) && m_inhibit) m_pitch_count = 0;
- m_subcycle = m_subc_reload;
- m_PC = 0;
- m_IP++;
- m_IP &= 0x7;
- }
- else if (m_subcycle == 3)
- {
- m_subcycle = m_subc_reload;
- m_PC++;
- }
- m_pitch_count++;
- if (m_pitch_count >= m_current_pitch) m_pitch_count = 0;
- m_pitch_count &= 0x1FF;
- buf_count++;
- size--;
- }
-
-empty:
-
- while (size > 0)
- {
- m_subcycle++;
- if ((m_subcycle == 2) && (m_PC == 12))
- {
- m_subcycle = m_subc_reload;
- m_PC = 0;
- m_IP++;
- m_IP &= 0x7;
- }
- else if (m_subcycle == 3)
- {
- m_subcycle = m_subc_reload;
- m_PC++;
- }
- buffer[buf_count] = -1; // should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4)
- buf_count++;
- size--;
- }
-}
-
-/******************************************************************************
- lattice_filter -- executes one 'full run' of the lattice filter on a
- specific byte of excitation data, and specific values of all the current k
- constants, and returns the resulting sample.
-******************************************************************************/
-
-INT32 tms52xx_device::lattice_filter()
-{
- /* Lattice filter here */
- /* Aug/05/07: redone as unrolled loop, for clarity - LN
- * Originally Copied verbatim from table I in US patent 4,209,804, now updated
- * to be in same order as the actual chip does it, not that it matters.
- * notation equivalencies from table:
- * Yn(i) == m_u[n-1]
- * Kn = m_current_k[n-1]
- * bn = m_x[n-1]
- */
-
- m_u[10] = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11)
- m_u[9] = m_u[10] - matrix_multiply(m_current_k[9], m_x[9]);
- m_u[8] = m_u[9] - matrix_multiply(m_current_k[8], m_x[8]);
- m_u[7] = m_u[8] - matrix_multiply(m_current_k[7], m_x[7]);
- m_u[6] = m_u[7] - matrix_multiply(m_current_k[6], m_x[6]);
- m_u[5] = m_u[6] - matrix_multiply(m_current_k[5], m_x[5]);
- m_u[4] = m_u[5] - matrix_multiply(m_current_k[4], m_x[4]);
- m_u[3] = m_u[4] - matrix_multiply(m_current_k[3], m_x[3]);
- 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]);
- 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]);
- m_x[6] = m_x[5] + matrix_multiply(m_current_k[5], m_u[5]);
- m_x[5] = m_x[4] + matrix_multiply(m_current_k[4], m_u[4]);
- m_x[4] = m_x[3] + matrix_multiply(m_current_k[3], m_u[3]);
- m_x[3] = m_x[2] + matrix_multiply(m_current_k[2], m_u[2]);
- m_x[2] = m_x[1] + matrix_multiply(m_current_k[1], m_u[1]);
- 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;
- fprintf(stderr,"V:%04d ", m_u[10]);
- for (i = 9; i >= 0; i--)
- {
- fprintf(stderr,"Y%d:%04d ", i+1, m_u[i]);
- fprintf(stderr,"b%d:%04d ", i+1, m_x[i]);
- if ((i % 5) == 0) fprintf(stderr,"\n");
- }
-#endif
- return m_u[0];
-}
-
-/**********************************************************************************************
- data_write -- handle a write to the TMS5220
-***********************************************************************************************/
-
-void tms52xx_device::data_write(int data)
-{
-#ifdef DEBUG_DUMP_INPUT_DATA
- fprintf(stdout, "%c",data);
-#endif
- if (m_speak_external) // If we're in speak external mode
- {
- /* add this byte to the FIFO */
- if (m_fifo_count < FIFO_SIZE)
- {
- m_fifo[m_fifo_tail] = data;
- m_fifo_tail = (m_fifo_tail + 1) % FIFO_SIZE;
- m_fifo_count++;
-#ifdef DEBUG_FIFO
- logerror("tms52xx: data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count);
-#endif
- update_status_and_ints();
- if ((!m_talk_status) && (!m_buffer_low)) // we just unset buffer low with that last write, and talk status *was* zero...
- {
- int i;
-#ifdef DEBUG_FIFO
- logerror("tms52xx: data_write triggered talk status to go active!\n");
-#endif
- /* ...then we now have enough bytes to start talking; clear out
- * the new frame parameters (it will become old frame just before the first call to parse_frame())
- * TODO: the 3 lines below (and others) are needed for victory
- * to not fail its selftest due to a sample ending too late, may require additional investigation */
- m_subcycle = m_subc_reload;
- m_PC = 0;
- m_IP = reload_table[m_tms5220c_rate & 0x3]; // is this correct? should this be always 7 instead, so that the new frame is loaded quickly?
- 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;
- m_talk_status = m_speaking_now = true;
- }
- }
- else
- {
-#ifdef DEBUG_FIFO
- logerror("tms52xx: 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
- }
-
-
- }
- else //(! m_speak_external)
- /* R Nabet : we parse commands at once. It is necessary for such commands as read. */
- process_command(data);
-}
-
-/******************************************************************************
- process_command -- extract a byte from the FIFO and interpret it as a command
-*******************************************************************************/
-
-void tms52xx_device::process_command(unsigned char cmd)
-{
-#ifdef DEBUG_COMMAND_DUMP
- fprintf(stderr,"process_command called with parameter %02X\n",cmd);
-#endif
- // parse the command
- switch (cmd & 0x70)
- {
- case 0x10 : // read byte
- if (!m_talk_status) // TALKST must be clear for RDBY
- {
- if (m_schedule_dummy_read)
- {
- m_schedule_dummy_read = false;
- (void)m_read_mem(1);
- }
- m_data_register = m_read_mem(8); // read one byte from speech ROM...
- m_RDB_flag = true;
- }
- break;
-
- case 0x00:
- case 0x20: // set rate (tms5220c only), otherwise NOP
- if (m_variant == TMS5220_IS_5220C)
- {
- m_tms5220c_rate = cmd & 0x0F;
- }
- break;
-
- case 0x30: // read and branch
- if (!m_talk_status) // TALKST must be clear for RB
- {
-#ifdef VERBOSE
- logerror("tms5520: read and branch command received\n");
-#endif
- m_RDB_flag = false;
- m_read_and_branch(0, 0);
- }
- break;
-
- case 0x40 : // load address
- if (!m_talk_status) // 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.
- m_load_address(0, cmd & 0x0f);
- m_schedule_dummy_read = true;
- }
- break;
-
- case 0x50: // speak
- if (m_schedule_dummy_read)
- {
- m_schedule_dummy_read = false;
- (void)m_read_mem(1);
- }
- m_speaking_now = true;
- m_speak_external = false;
- m_talk_status = true; // start immediately
- // clear out variables before speaking
- // TODO: similar to the victory case described above, but for VSM speech
- m_subcycle = m_subc_reload;
- m_PC = 0;
- m_IP = reload_table[m_tms5220c_rate & 0x3];
- m_new_frame_energy_idx = 0;
- m_new_frame_pitch_idx = 0;
-
- int i;
- 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;
-
- case 0x60: // speak external
- //SPKEXT going active activates SPKEE which clears the fifo
- m_fifo_head = m_fifo_tail = 0;
- m_fifo_count = m_fifo_bits_taken = 0;
- m_speak_external = true;
- m_RDB_flag = false;
- break;
-
- case 0x70: // reset
- if (m_schedule_dummy_read)
- {
- m_schedule_dummy_read = false;
- (void)m_read_mem(1);
- }
- device_reset();
- break;
- }
-
- // update the buffer low state
- update_status_and_ints();
-}
-
-/******************************************************************************
- parse_frame -- parse a new frame's worth of data; returns 0 if not
- enough bits in buffer
-*******************************************************************************/
-
-void tms52xx_device::parse_frame()
-{
- int indx, i, rep_flag;
-
- /* We actually don't care how many bits are left in the fifo here; the
- * frame subpart will be processed normally, and any bits extracted 'past
- * the end' of the fifo will be read as zeroes; the fifo being emptied will
- * set the /BE latch which will halt speech exactly as if a stop frame had
- * been encountered (instead of whatever partial frame was read); the same
- * exact circuitry is used for both on the real chip, see us patent 4335277
- * sheet 16, gates 232a (decode stop frame) and 232b (decode /BE plus DDIS
- * (decode disable) which is active during speak external). */
-
- /* if the chip is a tms5220C, and the rate mode is set to that each frame (0x04 bit set)
- * has a 2 bit rate preceding it, grab two bits here and store them as the rate; */
- if ((m_variant == TMS5220_IS_5220C) && (m_tms5220c_rate & 0x04))
- {
- indx = extract_bits(2);
-#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(indx,2);
- fprintf(stderr," ");
-#endif
- m_IP = reload_table[indx];
- }
- else // non-5220C and 5220C in fixed rate mode
- m_IP = reload_table[m_tms5220c_rate & 0x3];
-
- update_status_and_ints();
- if (!m_talk_status) goto ranout;
-
- // 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);
- fprintf(stderr," ");
-#endif
- update_status_and_ints();
- if (!m_talk_status) goto ranout;
- // if the energy index is 0 or 15, we're done
- if ((m_new_frame_energy_idx == 0) || (m_new_frame_energy_idx == 15))
- return;
-
- // attempt to extract the repeat flag
- rep_flag = extract_bits(1);
-#ifdef DEBUG_PARSE_FRAME_DUMP
- printbits(rep_flag, 1);
- fprintf(stderr," ");
-#endif
-
- // 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);
- fprintf(stderr," ");
-#endif
- update_status_and_ints();
- if (!m_talk_status) goto ranout;
- /* if this is a repeat frame, just do nothing, it will reuse the
- * old coefficients */
- if (rep_flag) return;
-
- // extract first 4 K coefficients
- 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]);
- fprintf(stderr," ");
-#endif
- update_status_and_ints();
- if (!m_talk_status) goto ranout;
- }
-
- // if the pitch index was zero, we only need 4 K's...
- if (m_new_frame_pitch_idx == 0)
- {
- // and the rest of the coefficients are zeroed, but that's done in the generator code
- return;
- }
-
- // If we got here, we need the remaining 6 K's
- 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]);
- fprintf(stderr," ");
-#endif
- update_status_and_ints();
- if (!m_talk_status) goto ranout;
- }
-#ifdef VERBOSE
- if (m_speak_external)
- logerror("tms52xx: Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken));
- else
- logerror("tms52xx: Parsed a frame successfully in ROM\n");
-#endif
- return;
-
- ranout:
-#ifdef DEBUG_FRAME_ERRORS
- logerror("tms52xx: Ran out of bits on a parse!\n");
-#endif
- return;
-}
-
-/**********************************************************************************************
-
- update_status_and_ints -- check to see if the various flags should be on or off
- Description of flags, and their position in the status register:
- From the data sheet:
- bit D0(bit 7) = TS - Talk Status is active (high) when the VSP is processing speech data.
- Talk Status goes active at the initiation of a Speak command or after nine
- bytes of data are loaded into the FIFO following a Speak External command. It
- goes inactive (low) when the stop code (Energy=1111) is processed, or
- immediately by a buffer empty condition or a reset command.
- bit D1(bit 6) = BL - Buffer Low is active (high) when the FIFO buffer is more than half empty.
- Buffer Low is set when the "Last-In" byte is shifted down past the half-full
- boundary of the stack. Buffer Low is cleared when data is loaded to the stack
- so that the "Last-In" byte lies above the half-full boundary and becomes the
- eighth data byte of the stack.
- bit D2(bit 5) = BE - Buffer Empty is active (high) when the FIFO buffer has run out of data
- while executing a Speak External command. Buffer Empty is set when the last bit
- of the "Last-In" byte is shifted out to the Synthesis Section. This causes
- Talk Status to be cleared. Speech is terminated at some abnormal point and the
- Speak External command execution is terminated.
-
-***********************************************************************************************/
-
-void tms52xx_device::update_status_and_ints()
-{
- // update flags and set ints if needed
- update_ready_state();
-
- /* BL is set if neither byte 9 nor 8 of the fifo are in use; this
- * translates to having fifo_count (which ranges from 0 bytes in use to 16
- * bytes used) being less than or equal to 8. Victory/Victorba depends on this. */
- if (m_fifo_count <= 8)
- {
- // generate an interrupt if necessary; if /BL was inactive and is now active, set int.
- if (!m_buffer_low) set_interrupt_state(1);
- m_buffer_low = true;
- }
- else
- 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 */
- if (m_fifo_count == 0)
- {
- // generate an interrupt if necessary; if /BE was inactive and is now active, set int.
- if (!m_buffer_empty) set_interrupt_state(1);
- m_buffer_empty = true;
- }
- else
- m_buffer_empty = false;
-
- /* TS is talk status and is set elsewhere in the fifo parser and in
- * the SPEAK command handler; however, if /BE is true during speak external
- * mode, it is immediately unset here. */
- if (m_speak_external && m_buffer_empty)
- {
- // generate an interrupt: /TS was active, and is now inactive.
- if (m_talk_status)
- {
- m_talk_status = m_speak_external = false;
- set_interrupt_state(1);
- }
- }
- /* Note that TS being unset will also generate an interrupt when a STOP
- * frame is encountered; this is handled in the sample generator code and not here */
-}
-
-/******************************************************************************
- extract_bits -- extract a specific number of bits from the current input stream (FIFO or VSM)
-*******************************************************************************/
-
-int tms52xx_device::extract_bits(int count)
-{
- int val = 0;
-
- if (m_speak_external)
- {
- // extract from FIFO
- while (count--)
- {
- val = (val << 1) | ((m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 1);
- m_fifo_bits_taken++;
- if (m_fifo_bits_taken >= 8)
- {
- m_fifo_count--;
- m_fifo[m_fifo_head] = 0; // zero the newly depleted fifo head byte
- m_fifo_head = (m_fifo_head + 1) % FIFO_SIZE;
- m_fifo_bits_taken = 0;
- update_status_and_ints();
- }
- }
- }
- else
- {
- // extract from VSM (speech ROM)
- val = m_read_mem(count);
- }
- return val;
-}
-
-/******************************************************************************
- status_read -- read status or data from the TMS5220
-*******************************************************************************/
-
-int tms52xx_device::status_read()
-{
- if (m_RDB_flag)
- { // if last command was read, return data register
- m_RDB_flag = false;
- return m_data_register;
- }
- else
- { // read status
- // clear the interrupt pin on status read
- set_interrupt_state(0);
-#ifdef DEBUG_PIN_READS
- logerror("tms52xx: Status read: TS=%d BL=%d BE=%d\n", m_talk_status, m_buffer_low, m_buffer_empty);
-#endif
-
- int retvalue = 0;
- if (m_talk_status) retvalue |= 0x80;
- if (m_buffer_low) retvalue |= 0x40;
- if (m_buffer_empty) retvalue |= 0x20;
- return retvalue;
- }
-}
-
-/******************************************************************************
- ready_read -- returns the ready state of the TMS5220
-*******************************************************************************/
-
-inline bool tms52xx_device::ready_read()
-{
-#ifdef DEBUG_PIN_READS
- logerror("tms52xx: ready_read: ready pin read, io_ready is %d, fifo count is %d\n", m_io_ready, m_fifo_count);
-#endif
- return ((m_fifo_count < FIFO_SIZE)||(!m_speak_external)) && m_io_ready;
-}
-
-/******************************************************************************
- int_read -- returns the interrupt state of the TMS5220
-*******************************************************************************/
-
-inline int tms52xx_device::int_read()
-{
-#ifdef DEBUG_PIN_READS
- logerror("tms52xx: int_read: irq pin read, state is %d\n", m_irq_pin);
-#endif
- return m_irq_pin;
-}
-
-/******************************************************************************
- 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 tms52xx_device::cycles_to_ready()
-{
- int answer;
-
- if (ready_read()) answer = 0;
- else
- {
- int val;
- int samples_per_frame = (m_subc_reload!=0)?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!=0)? 38:25) * m_IP));
- answer = samples_per_frame - current_sample + 8;
-
- // total number of bits available in current byte is (8 - tms->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!=0)?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;
-}
-
-/******************************************************************************
- True timing
-*******************************************************************************/
-
-void tms52xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- if (param)
- {
- switch (m_rs_ws)
- {
- case 0x02:
- // Write
- // bring up to date first
-#ifdef DEBUG_IO_READY
- logerror("tms52xx: Serviced write: %02x\n", tms->write_latch);
- //fprintf(stderr, "Processed write data: %02X\n", tms->write_latch);
-#endif
- m_stream->update();
- data_write(m_write_latch);
- break;
- case 0x01:
- // Read
- // bring up to date first
- m_stream->update();
- m_read_latch = status_read();
- break;
- case 0x03:
- // High Impedance
- case 0x00:
- // illegal
- break;
- }
- }
- m_io_ready = param;
- update_ready_state();
-}
-
-/*****************************************************
- /RS line write handler
-*****************************************************/
-
-WRITE_LINE_MEMBER( tms52xx_device::rsq_w )
-{
- UINT8 new_val;
-
- m_true_timing = true;
- state &= 0x01;
-#ifdef DEBUG_RS_WS
- logerror("tms52xx: /RS written with data: %d\n", state);
-#endif
- new_val = (m_rs_ws & 0x01) | (state<<1);
- if (new_val != m_rs_ws)
- {
- m_rs_ws = new_val;
- if (new_val == 0)
- {
- if (m_variant == TMS5220_IS_5220C)
- reset();
-#ifdef DEBUG_RS_WS
- else
- // illegal
- logerror("tms52xx: illegal line setting /RS=0 and /WS=0\n");
-#endif
- return;
- }
- else if (new_val == 3)
- {
- // high impedance
- m_read_latch = 0xff;
- return;
- }
- if (state)
- {
- // low to high
- }
- else
- {
- // high to low - schedule ready cycle
-#ifdef DEBUG_RS_WS
- logerror("tms52xx: Scheduling ready cycle for /RS...\n");
-#endif
- /* 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_ready_timer->adjust(attotime::from_hz(clock()/16));
- }
- }
-}
-
-/*****************************************************
- /WS line write handler
-*****************************************************/
-
-WRITE_LINE_MEMBER( tms52xx_device::wsq_w )
-{
- UINT8 new_val;
-
- m_true_timing = true;
- state &= 0x01;
-#ifdef DEBUG_RS_WS
- logerror("tms52xx: /WS written with data: %d\n", state);
-#endif
- new_val = (m_rs_ws & 0x02) | (state<<0);
- if (new_val != m_rs_ws)
- {
- m_rs_ws = new_val;
- if (new_val == 0)
- {
- if (m_variant == TMS5220_IS_5220C)
- reset();
-#ifdef DEBUG_RS_WS
- else
- // illegal
- logerror("tms52xx: illegal line setting /RS=0 and /WS=0\n");
-#endif
- return;
- }
- else if ( new_val == 3)
- {
- // high impedance
- m_read_latch = 0xff;
- return;
- }
- if (state)
- {
- // low to high
- }
- else
- {
- // high to low - schedule ready cycle
-#ifdef DEBUG_RS_WS
- logerror("tms52xx: Scheduling ready cycle for /WS...\n");
-#endif
- /* 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: 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:
- * SPK: ? cycles
- * SPKEXT: ? cycles
- * RDBY: between 60 and 140 cycles
- * RB: ? cycles (80?)
- * RST: between 60 and 140 cycles
- * SET RATE (5220C only): ? cycles (probably ~16) */
-
- // TODO: actually HANDLE the timing differences! currently just assuming always 16 cycles
- m_ready_timer->adjust(attotime::from_hz(clock()/16));
- }
- }
-}
-
-/*****************************************************************************
- write -- write data to the sound chip
-*******************************************************************************/
-
-WRITE8_MEMBER( tms52xx_device::write )
-{
-#ifdef DEBUG_RS_WS
- logerror("tms52xx: write data %02x\n", data);
-#endif
- if (!m_true_timing)
- {
- // bring up to date first
- m_stream->update();
- data_write(data);
- }
- else
- {
- // actually in a write?
-#ifdef DEBUG_RS_WS
- if (!(m_rs_ws == 0x02))
- logerror("tms52xx: write data written outside ws, status: %02x!\n", m_rs_ws);
-#endif
- m_write_latch = data;
- }
-}
-
-/******************************************************************************
- read -- read status or data from the sound chip
-*******************************************************************************/
-
-READ8_MEMBER( tms52xx_device::read )
-{
- if (!m_true_timing)
- {
- // bring up-to-date first
- m_stream->update();
- return status_read();
- }
- else
- {
- // actually in a read?
- if (m_rs_ws == 0x01)
- return m_read_latch;
-#ifdef DEBUG_RS_WS
- else
- logerror("tms52xx: data read outside rs!\n");
-#endif
- return 0xff;
- }
-}
-
-/*******************************************************************************
- ready -- return the not ready status from the sound chip
-*******************************************************************************/
-
-READ_LINE_MEMBER( tms52xx_device::readyq )
-{
- // bring up-to-date first
- m_stream->update();
- return !ready_read();
-}
-
-
-/******************************************************************************
- time_to_ready -- return the time in seconds until the
- ready line is asserted
-*******************************************************************************/
-
-double tms52xx_device::time_to_ready()
-{
- double cycles;
-
- // bring up-to-date
- m_stream->update();
- cycles = cycles_to_ready();
- return cycles * 80.0 / m_clock;
-}
-
-/******************************************************************************
- intq -- return the interrupt status from the sound chip
-******************************************************************************/
-
-READ_LINE_MEMBER( tms52xx_device::intq )
-{
- // bring up-to-date first
- m_stream->update();
- return !int_read();
-}
-
-void tms52xx_device::register_for_save_states()
-{
- 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_speaking_now));
- save_item(NAME(m_speak_external));
- save_item(NAME(m_talk_status));
- save_item(NAME(m_buffer_low));
- save_item(NAME(m_buffer_empty));
- save_item(NAME(m_irq_pin));
- save_item(NAME(m_ready_pin));
-
- save_item(NAME(m_OLDE));
- save_item(NAME(m_OLDP));
-
- save_item(NAME(m_new_frame_energy_idx));
- save_item(NAME(m_new_frame_pitch_idx));
- save_item(NAME(m_new_frame_k_idx));
-#ifdef PERFECT_INTERPOLATION_HACK
- save_item(NAME(m_old_frame_energy_idx));
- save_item(NAME(m_old_frame_pitch_idx));
- save_item(NAME(m_old_frame_k_idx));
-#endif
- save_item(NAME(m_current_energy));
- save_item(NAME(m_current_pitch));
- save_item(NAME(m_current_k));
-
- save_item(NAME(m_target_energy));
- save_item(NAME(m_target_pitch));
- save_item(NAME(m_target_k));
-
- save_item(NAME(m_previous_energy));
-
- save_item(NAME(m_subcycle));
- save_item(NAME(m_subc_reload));
- save_item(NAME(m_PC));
- save_item(NAME(m_IP));
- save_item(NAME(m_inhibit));
- save_item(NAME(m_tms5220c_rate));
- save_item(NAME(m_pitch_count));
-
- save_item(NAME(m_u));
- save_item(NAME(m_x));
-
- 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));
-}
-
-
-const device_type TMS5220N = &device_creator<tms5220n_device>;
-const device_type TMS5220CN = &device_creator<tms5220cn_device>;
-const device_type TMC0285N = &device_creator<tmc0285n_device>;
-const device_type TMS5200N = &device_creator<tms5200n_device>;
diff --git a/src/emu/sound/tms5220.h b/src/emu/sound/tms5220.h
index 59859153776..4979d284d08 100644
--- a/src/emu/sound/tms5220.h
+++ b/src/emu/sound/tms5220.h
@@ -3,7 +3,11 @@
#ifndef __TMS5220_H__
#define __TMS5220_H__
-#include "devlegcy.h"
+#include "emu.h"
+#include "machine/spchrom.h"
+
+/* HACK: if defined, uses impossibly perfect 'straight line' interpolation */
+#undef PERFECT_INTERPOLATION_HACK
#define FIFO_SIZE 16
@@ -11,35 +15,16 @@
/* usually 640000 for 8000 Hz sample rate or */
/* usually 800000 for 10000 Hz sample rate. */
-struct tms5220_interface
-{
- devcb_write_line irq_func; /* IRQ callback function, active low, i.e. state=0 */
- devcb_write_line readyq_func; /* Ready callback function, active low, i.e. state=0 */
-
- int (*read)(device_t *device, int count); /* speech ROM read callback */
- void (*load_address)(device_t *device, int data); /* speech ROM load address callback */
- void (*read_and_branch)(device_t *device); /* speech ROM read and branch callback */
-};
-
-/* Control lines - once written to will switch interface into
- * "true" timing behaviour.
- */
-
-/* all lines with suffix q are active low! */
-
-WRITE_LINE_DEVICE_HANDLER( tms5220_rsq_w );
-WRITE_LINE_DEVICE_HANDLER( tms5220_wsq_w );
-
-DECLARE_WRITE8_DEVICE_HANDLER( tms5220_data_w );
-DECLARE_READ8_DEVICE_HANDLER( tms5220_status_r );
+/* IRQ callback function, active low, i.e. state=0 */
+#define MCFG_TMS52XX_IRQ_HANDLER(_devcb) \
+ devcb = &tms5220_device::set_irq_handler(*device, DEVCB2_##_devcb);
-READ_LINE_DEVICE_HANDLER( tms5220_readyq_r );
-READ_LINE_DEVICE_HANDLER( tms5220_intq_r );
+/* Ready callback function, active low, i.e. state=0 */
+#define MCFG_TMS52XX_READYQ_HANDLER(_devcb) \
+ devcb = &tms5220_device::set_readyq_handler(*device, DEVCB2_##_devcb);
-
-double tms5220_time_to_ready(device_t *device);
-
-void tms5220_set_frequency(device_t *device, int frequency);
+#define MCFG_TMS52XX_SPEECHROM(_tag) \
+ tms5220_device::set_speechrom_tag(*device, _tag);
class tms5220_device : public device_t,
public device_sound_interface
@@ -47,267 +32,210 @@ class tms5220_device : public device_t,
public:
tms5220_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
tms5220_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, device_t *owner, UINT32 clock);
- ~tms5220_device() { global_free(m_token); }
- // access to legacy token
- void *token() const { assert(m_token != NULL); return m_token; }
-protected:
- // device-level overrides
- virtual void device_config_complete();
- virtual void device_start();
- virtual void device_reset();
+ // static configuration helpers
+ template<class _Object> static devcb2_base &set_irq_handler(device_t &device, _Object object) { return downcast<tms5220_device &>(device).m_irq_handler.set_callback(object); }
+ template<class _Object> static devcb2_base &set_readyq_handler(device_t &device, _Object object) { return downcast<tms5220_device &>(device).m_readyq_handler.set_callback(object); }
+ static void set_speechrom_tag(device_t &device, const char *_tag) { downcast<tms5220_device &>(device).m_speechrom_tag = _tag; }
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
-private:
- // internal state
- void *m_token;
-};
+ /* Control lines - once written to will switch interface into
+ * "true" timing behaviour.
+ */
-extern const device_type TMS5220;
+ /* all lines with suffix q are active low! */
-class tms5220c_device : public tms5220_device
-{
-public:
- tms5220c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
-protected:
- // device-level overrides
- virtual void device_start();
-
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
-};
+ WRITE_LINE_MEMBER( rsq_w );
+ WRITE_LINE_MEMBER( wsq_w );
-extern const device_type TMS5220C;
+ DECLARE_WRITE8_MEMBER( data_w );
+ DECLARE_READ8_MEMBER( status_r );
-class tmc0285_device : public tms5220_device
-{
-public:
- tmc0285_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
-protected:
- // device-level overrides
- virtual void device_start();
+ READ_LINE_MEMBER( readyq_r );
+ READ_LINE_MEMBER( intq_r );
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
-};
+ double time_to_ready();
-extern const device_type TMC0285;
+ void set_frequency(int frequency);
-class tms5200_device : public tms5220_device
-{
-public:
- tms5200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
protected:
// device-level overrides
+ virtual void device_config_complete();
virtual void device_start();
+ virtual void device_reset();
- // sound stream update overrides
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
-};
-
-extern const device_type TMS5200;
-
-
-
-/***************************************************************************
- New class implementation
- Michael Zapf, June 2012
-***************************************************************************/
-
-extern const device_type TMS5220N;
-extern const device_type TMS5220CN;
-extern const device_type TMC0285N;
-extern const device_type TMS5200N;
-
-
-struct tms52xx_config
-{
- devcb_write_line irq_func; // IRQ callback function, active low, i.e. state=0 (TODO: change to ASSERT/CLEAR)
- devcb_write_line readyq_func; // Ready callback function, active low, i.e. state=0
-
- devcb_read8 read_mem; // speech ROM read callback
- devcb_write8 load_address; // speech ROM load address callback
- devcb_write8 read_and_branch; // speech ROM read and branch callback
-
-};
-
-// Change back from 5220n to 5220 when all client drivers will be converted
-class tms52xx_device : public device_t, public device_sound_interface
-{
-public:
- tms52xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, const struct tms5100_coeffs* coeffs, const int var, device_t *owner, UINT32 clock);
- virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
- DECLARE_WRITE_LINE_MEMBER( rsq_w );
- DECLARE_WRITE_LINE_MEMBER( wsq_w );
- DECLARE_WRITE8_MEMBER( write );
- DECLARE_READ8_MEMBER( read );
- DECLARE_READ_LINE_MEMBER( readyq );
- DECLARE_READ_LINE_MEMBER( intq );
-
- double time_to_ready();
+ // sound stream update overrides
+ virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples);
-protected:
- virtual void device_start();
- virtual void device_reset();
+ void set_variant(int variant);
private:
- // Methods
- void set_interrupt_state(int state);
void register_for_save_states();
- void update_ready_state();
- void set_frequency(int frequency);
- void process(INT16 *buffer, unsigned int size);
void data_write(int data);
void update_status_and_ints();
- void parse_frame();
-
int extract_bits(int count);
int status_read();
+ int ready_read();
int cycles_to_ready();
+ int int_read();
+ void process(INT16 *buffer, unsigned int size);
INT32 lattice_filter();
void process_command(unsigned char cmd);
+ void parse_frame();
+ void set_interrupt_state(int state);
+ void update_ready_state();
- inline bool ready_read();
- inline int int_read();
+ // internal state
- // coefficient tables
- const int m_variant; // Variant of the 5xxx - see tms5110r.h
+ /* coefficient tables */
+ int m_variant; /* Variant of the 5xxx - see tms5110r.h */
- // coefficient tables
+ /* coefficient tables */
const struct tms5100_coeffs *m_coeff;
- // callbacks
- devcb_resolved_write_line m_irq_func;
- devcb_resolved_write_line m_readyq_func;
- devcb_resolved_read8 m_read_mem;
- devcb_resolved_write8 m_load_address;
- devcb_resolved_write8 m_read_and_branch;
-
- // these contain data that describes the 128-bit data FIFO
- UINT8 m_fifo[FIFO_SIZE];
- UINT8 m_fifo_head;
- UINT8 m_fifo_tail;
- int m_fifo_count;
- int m_fifo_bits_taken;
-
- // these contain global status bits
- bool m_speaking_now; // True only if actual speech is being generated right now. Is set when a speak vsm command happens OR when speak external happens and buffer low becomes nontrue; Is cleared when speech halts after the last stop frame or the last frame after talk status is otherwise cleared.
- bool m_speak_external; // If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO.
- bool m_talk_status; // If 1, TS status bit is 1, i.e. speak or speak external is in progress and we have not encountered a stop frame yet; talk_status differs from speaking_now in that speaking_now is set as soon as a speak or speak external command is started; talk_status does NOT go active until after 8 bytes are written to the fifo on a speak external command, otherwise the two are the same. TS is cleared by 3 things: 1. when a STOP command has just been processed as a new frame in the speech stream; 2. if the fifo runs out in speak external mode; 3. on power-up/during a reset command; When it gets cleared, speak_external is also cleared, an interrupt is generated, and speaking_now will be cleared when the next frame starts.
- bool m_buffer_low; // If 1, FIFO has less than 8 bytes in it
- bool m_buffer_empty; // If 1, FIFO is empty
- int m_irq_pin; // state of the IRQ pin (output)
- int m_ready_pin; // state of the READY pin (output)
-
- // these contain data describing the current and previous voice frames
-#define M_OLD_FRAME_SILENCE_FLAG m_OLDE // 1 if E=0, 0 otherwise.
-#define M_OLD_FRAME_UNVOICED_FLAG m_OLDP // 1 if P=0 (unvoiced), 0 if voiced
- bool m_OLDE;
- bool m_OLDP;
-
-#define M_NEW_FRAME_STOP_FLAG (m_new_frame_energy_idx == 0xF) // 1 if this is a stop (Energy = 0xF) frame
-#define M_NEW_FRAME_SILENCE_FLAG (m_new_frame_energy_idx == 0) // ditto as above
-#define M_NEW_FRAME_UNVOICED_FLAG (m_new_frame_pitch_idx == 0) // ditto as above
- int m_new_frame_energy_idx;
- int m_new_frame_pitch_idx;
- int m_new_frame_k_idx[10];
-
- // these are all used to contain the current state of the sound generation
+ /* these contain data that describes the 128-bit data FIFO */
+ UINT8 m_fifo[FIFO_SIZE];
+ UINT8 m_fifo_head;
+ UINT8 m_fifo_tail;
+ UINT8 m_fifo_count;
+ UINT8 m_fifo_bits_taken;
+
+
+ /* these contain global status bits */
+ UINT8 m_speaking_now; /* True only if actual speech is being generated right now. Is set when a speak vsm command happens OR when speak external happens and buffer low becomes nontrue; Is cleared when speech halts after the last stop frame or the last frame after talk status is otherwise cleared.*/
+ UINT8 m_speak_external; /* If 1, DDIS is 1, i.e. Speak External command in progress, writes go to FIFO. */
+ UINT8 m_talk_status; /* If 1, TS status bit is 1, i.e. speak or speak external is in progress and we have not encountered a stop frame yet; talk_status differs from speaking_now in that speaking_now is set as soon as a speak or speak external command is started; talk_status does NOT go active until after 8 bytes are written to the fifo on a speak external command, otherwise the two are the same. TS is cleared by 3 things: 1. when a STOP command has just been processed as a new frame in the speech stream; 2. if the fifo runs out in speak external mode; 3. on power-up/during a reset command; When it gets cleared, speak_external is also cleared, an interrupt is generated, and speaking_now will be cleared when the next frame starts. */
+ UINT8 m_buffer_low; /* If 1, FIFO has less than 8 bytes in it */
+ UINT8 m_buffer_empty; /* If 1, FIFO is empty */
+ UINT8 m_irq_pin; /* state of the IRQ pin (output) */
+ UINT8 m_ready_pin; /* state of the READY pin (output) */
+
+ /* these contain data describing the current and previous voice frames */
+#define OLD_FRAME_SILENCE_FLAG m_OLDE // 1 if E=0, 0 otherwise.
+#define OLD_FRAME_UNVOICED_FLAG m_OLDP // 1 if P=0 (unvoiced), 0 if voiced
+ UINT8 m_OLDE;
+ UINT8 m_OLDP;
+
+#define NEW_FRAME_STOP_FLAG (m_new_frame_energy_idx == 0xF) // 1 if this is a stop (Energy = 0xF) frame
+#define NEW_FRAME_SILENCE_FLAG (m_new_frame_energy_idx == 0) // ditto as above
+#define NEW_FRAME_UNVOICED_FLAG (m_new_frame_pitch_idx == 0) // ditto as above
+ UINT8 m_new_frame_energy_idx;
+ UINT8 m_new_frame_pitch_idx;
+ UINT8 m_new_frame_k_idx[10];
+
+
+ /* these are all used to contain the current state of the sound generation */
#ifndef PERFECT_INTERPOLATION_HACK
- INT16 m_current_energy;
- INT16 m_current_pitch;
- INT16 m_current_k[10];
+ INT16 m_current_energy;
+ INT16 m_current_pitch;
+ INT16 m_current_k[10];
- INT16 m_target_energy;
- INT16 m_target_pitch;
- INT16 m_target_k[10];
+ INT16 m_target_energy;
+ INT16 m_target_pitch;
+ INT16 m_target_k[10];
#else
- int m_old_frame_energy_idx;
- int m_old_frame_pitch_idx;
- int m_old_frame_k_idx[10];
+ UINT8 m_old_frame_energy_idx;
+ UINT8 m_old_frame_pitch_idx;
+ UINT8 m_old_frame_k_idx[10];
- INT32 m_current_energy;
- INT32 m_current_pitch;
- INT32 m_current_k[10];
+ INT32 m_current_energy;
+ INT32 m_current_pitch;
+ INT32 m_current_k[10];
- INT32 m_target_energy;
- INT32 m_target_pitch;
- INT32 m_target_k[10];
+ INT32 m_target_energy;
+ INT32 m_target_pitch;
+ INT32 m_target_k[10];
#endif
- UINT16 m_previous_energy; // needed for lattice filter to match patent
- int m_subcycle; // contains the current subcycle for a given PC: 0 is A' (only used on SPKSLOW mode on 51xx), 1 is A, 2 is B
- int m_subc_reload; // contains 1 for normal speech, 0 when SPKSLOW is active
- int m_PC; // current parameter counter (what param is being interpolated), ranges from 0 to 12
-
- // TODO/NOTE: the current interpolation period, counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1
- int m_IP; // the current interpolation period
- bool m_inhibit; // If 1, interpolation is inhibited until the DIV1 period
- UINT8 m_tms5220c_rate; // only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command
- UINT16 m_pitch_count; // pitch counter; provides chirp rom address
-
- INT32 m_u[11];
- INT32 m_x[10];
-
- UINT16 m_RNG; // the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13
- INT16 m_excitation_data;
-
- // R Nabet : These have been added to emulate speech Roms
- bool m_schedule_dummy_read; // set after each load address, so that next read operation is preceded by a dummy read
- UINT8 m_data_register; // data register, used by read command
- bool m_RDB_flag; // whether we should read data register or status register
-
- // io_ready: page 3 of the datasheet specifies that READY will be asserted until
- // data is available or processed by the system.
- int m_io_ready;
-
- // flag for "true" timing involving rs/ws
- bool m_true_timing;
-
- // rsws - state, rs bit 1, ws bit 0
- int m_rs_ws;
- UINT8 m_read_latch;
- UINT8 m_write_latch;
-
- // The TMS52xx has two different ways of providing output data: the
- // analog speaker pin (which was usually used) and the Digital I/O pin.
- // 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 12? bit
- // resolution of the output data.
- // TODO: add a way to set/reset this other than the FORCE_DIGITAL define
- bool m_digital_select;
-
- sound_stream *m_stream;
-
- emu_timer *m_ready_timer;
+ UINT16 m_previous_energy; /* needed for lattice filter to match patent */
+
+ UINT8 m_subcycle; /* contains the current subcycle for a given PC: 0 is A' (only used on SPKSLOW mode on 51xx), 1 is A, 2 is B */
+ UINT8 m_subc_reload; /* contains 1 for normal speech, 0 when SPKSLOW is active */
+ UINT8 m_PC; /* current parameter counter (what param is being interpolated), ranges from 0 to 12 */
+ /* TODO/NOTE: the current interpolation period, counts 1,2,3,4,5,6,7,0 for divide by 8,8,8,4,4,2,2,1 */
+ UINT8 m_IP; /* the current interpolation period */
+ UINT8 m_inhibit; /* If 1, interpolation is inhibited until the DIV1 period */
+ UINT8 m_tms5220c_rate; /* only relevant for tms5220C's multi frame rate feature; is the actual 4 bit value written on a 0x2* or 0x0* command */
+ UINT16 m_pitch_count; /* pitch counter; provides chirp rom address */
+
+ INT32 m_u[11];
+ INT32 m_x[10];
+
+ UINT16 m_RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 */
+ INT16 m_excitation_data;
+
+ /* R Nabet : These have been added to emulate speech Roms */
+ UINT8 m_schedule_dummy_read; /* set after each load address, so that next read operation is preceded by a dummy read */
+ UINT8 m_data_register; /* data register, used by read command */
+ UINT8 m_RDB_flag; /* whether we should read data register or status register */
+
+ /* io_ready: page 3 of the datasheet specifies that READY will be asserted until
+ * data is available or processed by the system.
+ */
+ UINT8 m_io_ready;
+
+ /* flag for "true" timing involving rs/ws */
+ UINT8 m_true_timing;
+
+ /* rsws - state, rs bit 1, ws bit 0 */
+ UINT8 m_rs_ws;
+ UINT8 m_read_latch;
+ UINT8 m_write_latch;
+
+ /* The TMS52xx has two different ways of providing output data: the
+ analog speaker pin (which was usually used) and the Digital I/O pin.
+ 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
+ */
+ UINT8 m_digital_select;
+
+ sound_stream *m_stream;
+ int m_clock;
+ emu_timer *m_timer_io_ready;
+
+ /* callbacks */
+ devcb2_write_line m_irq_handler;
+ devcb2_write_line m_readyq_handler;
+ const char *m_speechrom_tag;
+ speechrom_device *m_speechrom;
};
-class tms5220n_device : public tms52xx_device
-{
-public:
- tms5220n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
-};
+extern const device_type TMS5220;
-class tms5220cn_device : public tms52xx_device
+class tms5220c_device : public tms5220_device
{
public:
- tms5220cn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ tms5220c_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+protected:
+ // device-level overrides
+ virtual void device_start();
};
-class tmc0285n_device : public tms52xx_device
+extern const device_type TMS5220C;
+
+class tmc0285_device : public tms5220_device
{
public:
- tmc0285n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ tmc0285_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+protected:
+ // device-level overrides
+ virtual void device_start();
};
-class tms5200n_device : public tms52xx_device
+extern const device_type TMC0285;
+
+class tms5200_device : public tms5220_device
{
public:
- tms5200n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ tms5200_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+protected:
+ // device-level overrides
+ virtual void device_start();
};
+extern const device_type TMS5200;
-#endif /* __TMS5220_H__ */
+#endif