tms52xx: Remove legacy spchrom implementation.

This commit is contained in:
Michael Zapf 2025-02-27 22:56:59 +01:00
parent 16817fba26
commit d96222a3f0
13 changed files with 193 additions and 340 deletions

View File

@ -1123,8 +1123,6 @@ if (SOUNDS["TMS5220"]~=null) then
MAME_DIR .. "src/devices/sound/tms5220.cpp",
MAME_DIR .. "src/devices/sound/tms5220.h",
MAME_DIR .. "src/devices/sound/tms5110r.hxx",
MAME_DIR .. "src/devices/machine/spchrom.cpp",
MAME_DIR .. "src/devices/machine/spchrom.h",
}
end

View File

@ -114,16 +114,20 @@ void electron_m2105_device::device_add_mconfig(machine_config &config)
output_latch_device &latch(OUTPUT_LATCH(config, "cent_data_out"));
centronics.set_output_latch(latch);
SPEECHROM(config, "vsm", 0).set_reverse_bit_order(true);
tms5220_device &tms(TMS5220(config, "vsp", 640000));
tms.set_speechrom_tag("vsm");
tms.ready_cb().set(m_via[0], FUNC(via6522_device::write_ca1));
tms.ready_cb().append(m_via[0], FUNC(via6522_device::write_pb2));
tms.irq_cb().set(m_via[0], FUNC(via6522_device::write_ca2));
tms.irq_cb().append(m_via[0], FUNC(via6522_device::write_pb3));
tms.add_route(ALL_OUTPUTS, "mono", 0.5);
TMS6100(config, "vsm", 0);
tms.m0_cb().set("vsm", FUNC(tms6100_device::m0_w));
tms.m1_cb().set("vsm", FUNC(tms6100_device::m1_w));
tms.addr_cb().set("vsm", FUNC(tms6100_device::add_w));
tms.data_cb().set("vsm", FUNC(tms6100_device::data_line_r));
tms.romclk_cb().set("vsm", FUNC(tms6100_device::clk_w));
SPEAKER(config, "mono").front_center();
}

View File

@ -14,7 +14,6 @@
#include "emu.h"
#include "ssb.h"
#include "machine/spchrom.h"
#include "sound/tms5220.h"
#include "bus/generic/carts.h"
#include "bus/generic/slot.h"

View File

@ -25,6 +25,7 @@
#include "machine/ram.h"
#include "machine/tmc0430.h"
#include "machine/tms9901.h"
#include "machine/tms6100.h"
#include "sound/sn76496.h"
#include "sound/tms5220.h"
#include "video/tms9928a.h"

View File

@ -23,8 +23,6 @@
#include "emu.h"
#include "spchsyn.h"
#include "machine/spchrom.h"
#include "speaker.h"
#define LOG_WARN (1U << 1) // Warnings
@ -154,22 +152,18 @@ ROM_END
void ti_speech_synthesizer_device::device_add_mconfig(machine_config& config)
{
SPEECHROM(config, "vsm", 0).set_reverse_bit_order(true);
SPEAKER(config, "speech_out").front_center();
CD2501E(config, m_vsp, 640000L);
m_vsp->set_speechrom_tag("vsm");
m_vsp->ready_cb().set(FUNC(ti_speech_synthesizer_device::speech_ready));
m_vsp->add_route(ALL_OUTPUTS, "speech_out", 0.50);
/*
// FIXME: Make it work. Guess we need two VSM circuits @16K.
TMS6100(config, "vsm", 640_kHz_XTAL/4);
m_vsp->m0_cb().set("vsm", FUNC(tms6100_device::m0_w));
m_vsp->m1_cb().set("vsm", FUNC(tms6100_device::m1_w));
m_vsp->addr_cb().set("vsm", FUNC(tms6100_device::add_w));
m_vsp->data_cb().set("vsm", FUNC(tms6100_device::data_line_r));
m_vsp->romclk_cb().set("vsm", FUNC(tms6100_device::clk_w));
*/
TMS6100(config, "vsm", 0);
m_vsp->m0_cb().set("vsm", FUNC(tms6100_device::m0_w));
m_vsp->m1_cb().set("vsm", FUNC(tms6100_device::m1_w));
m_vsp->addr_cb().set("vsm", FUNC(tms6100_device::add_w));
m_vsp->data_cb().set("vsm", FUNC(tms6100_device::data_line_r));
m_vsp->romclk_cb().set("vsm", FUNC(tms6100_device::clk_w));
}
INPUT_PORTS_START( ti99_speech )

View File

@ -1,139 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf
/*
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.
TODO:
Create separate devices for TMS6100 & TMS6125
Implement the serial protocol
*/
#include "emu.h"
#include "spchrom.h"
#define TMS5220_ADDRESS_MASK 0x3FFFFUL /* 18-bit mask for tms5220 address */
// device type definition
DEFINE_DEVICE_TYPE(SPEECHROM, speechrom_device, "speechrom", "TI Speech ROM")
speechrom_device::speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SPEECHROM, tag, owner, clock), m_speechrom_data(nullptr), m_speechROMlen(0),
m_speechROMaddr(0),
m_load_pointer(0),
m_ROM_bits_count(0),
m_reverse(false)
{
}
/*
Read 'count' bits serially from speech ROM
Actually, the ROM is expected to have reversed bit order, but there are
many dumps with normal bit order.
compatibility mode: 01234567 01234567 01234567 ...
correct mode: 76543210 76543210 76543210 ...
*/
int speechrom_device::read(int count)
{
int val;
int spchbyte;
int pos;
if (m_load_pointer)
{ /* first read after load address is ignored */
m_load_pointer = 0;
count--;
}
if (m_speechROMaddr < m_speechROMlen)
{
val = 0;
pos = 8 - m_ROM_bits_count;
spchbyte = (m_reverse? (m_speechrom_data[m_speechROMaddr] >> pos) : (m_speechrom_data[m_speechROMaddr] << pos)) & 0xff;
while (count > 0)
{
val = val << 1;
if ((spchbyte & (m_reverse? 0x01:0x80))!=0) val |= 1;
spchbyte = m_reverse? (spchbyte >> 1) : (spchbyte << 1);
count--;
if (pos == 7)
{
pos = 0;
m_speechROMaddr = (m_speechROMaddr + 1) & TMS5220_ADDRESS_MASK;
if (m_speechROMaddr >= m_speechROMlen)
count = 0;
else
spchbyte = m_speechrom_data[m_speechROMaddr];
}
else pos++;
}
m_ROM_bits_count = 8 - pos;
}
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 == nullptr)
{
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));
}

View File

@ -1,43 +0,0 @@
// license:BSD-3-Clause
// copyright-holders:Frank Palazzolo, Aaron Giles, Jonathan Gevaryahu, Raphael Nabet, Couriersud, Michael Zapf
/*
* Voice Synthesis Memory
*
*/
#ifndef MAME_MACHINE_SPCHROM_H
#define MAME_MACHINE_SPCHROM_H
#pragma once
class speechrom_device : public device_t
{
public:
// construction/destruction
speechrom_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
/// TODO: implement bus behaviour
int read(int count);
void load_address(int data);
void read_and_branch();
void set_reverse_bit_order(bool reverse) { m_reverse = reverse; }
protected:
// device-level overrides
virtual void device_start() override ATTR_COLD;
private:
uint8_t *m_speechrom_data; /* pointer to speech ROM data */
unsigned int m_speechROMlen; /* length of data pointed by speechrom_data, from 0 to 2^18 */
unsigned int 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 */
bool m_reverse;
};
// device type definition
DECLARE_DEVICE_TYPE(SPEECHROM, speechrom_device)
#endif // MAME_MACHINE_SPCHROM_H

View File

@ -366,41 +366,69 @@ emulating the tms5220 in MCU code). Look for a 16-pin chip at U6 labeled
one B cycle per interpolation step) */
#define FORCE_SUBC_RELOAD 1
/* *****debugging defines***** */
/* 5220 only; above dumps the data written to the tms52xx to the error log, useful
for making logged data dumps for real hardware tests */
#define LOG_DUMP_INPUT_DATA (1U << 1)
// 5220 only; above debugs FIFO stuff: writes, reads and flag updates
#define LOG_FIFO (1U << 2)
// Show parsing events
#define LOG_PARSE (1U << 3)
// dumps each speech frame as binary
#define LOG_PARSE_FRAME_DUMP_BIN (1U << 3)
#define LOG_PARSE_FRAME_DUMP_BIN (1U << 4)
// dumps each speech frame as hex
#define LOG_PARSE_FRAME_DUMP_HEX (1U << 4)
#define LOG_PARSE_FRAME_DUMP_HEX (1U << 5)
// dumps info if a frame ran out of data
#define LOG_FRAME_ERRORS (1U << 6)
// dumps all non-speech-data command writes
#define LOG_COMMAND_DUMP (1U << 7)
// dumps decoded info about command writes
#define LOG_COMMAND_VERBOSE (1U << 8)
// spams the error log with i/o ready messages whenever the ready or irq pin is read
#define LOG_PIN_READS (1U << 9)
// dumps debug information related to the sample generation loop, i.e. whether interpolation is inhibited or not, and what the current and target values for each frame are.
#define LOG_GENERATION (1U << 10)
// dumps MUCH MORE debug information related to the sample generation loop, namely the excitation, energy, pitch, k*, and output values for EVERY SINGLE SAMPLE during a frame.
#define LOG_GENERATION_VERBOSE (1U << 11)
// dumps the lattice filter state data each sample.
#define LOG_LATTICE (1U << 12)
// dumps info to the error log whenever the analog clip hardware is (or would be) clipping the signal.
#define LOG_CLIP (1U << 13)
// debugs the io ready callback timer
#define LOG_IO_READY (1U << 14)
// debugs the tms5220_data_r and data_w access methods which actually respect rs and ws
#define LOG_RS_WS (1U << 15)
// shows the byte being written by the CPU to the VSP
#define LOG_DATA_W (1U << 16)
//#define VERBOSE (LOG_GENERAL | LOG_DUMP_INPUT_DATA | LOG_FIFO | LOG_PARSE_FRAME_DUMP_HEX | LOG_FRAME_ERRORS | LOG_COMMAND_DUMP | LOG_COMMAND_VERBOSE | LOG_PIN_READS | LOG_GENERATION | LOG_GENERATION_VERBOSE | LOG_LATTICE | LOG_CLIP | LOG_IO_READY | LOG_RS_WS | LOG_DATA_W)
// dumps all non-speech-data command writes
#define LOG_COMMAND (1U << 7)
// Additional information about command processing
#define LOG_COMMAND_VERBOSE (1U << 8)
// Show NOP command (tends to be noisy)
#define LOG_COMMAND_NOP (1U << 9)
// spams the error log with i/o ready messages whenever the ready or irq pin is read
#define LOG_PIN_READS (1U << 10)
// dumps debug information related to the sample generation loop, i.e. whether interpolation is inhibited or not, and what the current and target values for each frame are.
#define LOG_GENERATION (1U << 11)
// dumps MUCH MORE debug information related to the sample generation loop, namely the excitation, energy, pitch, k*, and output values for EVERY SINGLE SAMPLE during a frame.
#define LOG_GENERATION_VERBOSE (1U << 12)
// dumps the lattice filter state data each sample.
#define LOG_LATTICE (1U << 13)
// Show errors in matrix multiplication
#define LOG_MULTIPLY (1U << 14)
// dumps info to the error log whenever the analog clip hardware is (or would be) clipping the signal.
#define LOG_CLIP (1U << 15)
// debugs the io ready callback timer
#define LOG_IO_READY (1U << 16)
// debugs the tms5220_data_r and data_w access methods which actually respect rs and ws
#define LOG_RS_WS (1U << 17)
// Show the byte being written by the CPU to the VSP
#define LOG_DATA_W (1U << 18)
// Show interactions with speech rom
#define LOG_VSM (1U << 19)
// Show state changes
#define LOG_STATE (1U << 20)
#define VERBOSE ( LOG_GENERAL )
#include "logmacro.h"
#define MAX_SAMPLE_CHUNK 512
@ -570,10 +598,10 @@ void tms5220_device::printbits(long data, int num)
/**********************************************************************************************
tms5220_device::new_int_write -- wrap a write to the VSM
tms5220_device::vsm_write -- wrap a write sent to the VSM
***********************************************************************************************/
void tms5220_device::new_int_write(uint8_t rc, uint8_t m0, uint8_t m1, uint8_t addr)
void tms5220_device::vsm_write(uint8_t rc, uint8_t m0, uint8_t m1, uint8_t addr)
{
m_m0_cb(m0);
m_m1_cb(m1);
@ -587,32 +615,52 @@ void tms5220_device::new_int_write(uint8_t rc, uint8_t m0, uint8_t m1, uint8_t a
/**********************************************************************************************
tms5220_device::new_int_write_addr -- wrap a 'load address' set of writes to the VSM
tms5220_device::vsm_write_addr -- wrap a 'load address' set of writes sent to the VSM
***********************************************************************************************/
void tms5220_device::new_int_write_addr(uint8_t addr)
void tms5220_device::vsm_write_addr(uint8_t addr)
{
new_int_write(1, 0, 1, addr); // romclk 1, m0 0, m1 1, addr bus nybble = xxxx
new_int_write(0, 0, 1, addr); // romclk 0, m0 0, m1 1, addr bus nybble = xxxx
new_int_write(1, 0, 0, addr); // romclk 1, m0 0, m1 0, addr bus nybble = xxxx
new_int_write(0, 0, 0, addr); // romclk 0, m0 0, m1 0, addr bus nybble = xxxx
vsm_write(1, 0, 1, addr); // romclk 1, m0 0, m1 1, addr bus nybble = xxxx
vsm_write(0, 0, 1, addr); // romclk 0, m0 0, m1 1, addr bus nybble = xxxx
vsm_write(1, 0, 0, addr); // romclk 1, m0 0, m1 0, addr bus nybble = xxxx
vsm_write(0, 0, 0, addr); // romclk 0, m0 0, m1 0, addr bus nybble = xxxx
}
/**********************************************************************************************
tms5220_device::new_int_write_addr -- wrap a 'read bit' set of writes to the VSM
tms5220_device::vsm_read -- wrap a 'read bit' set of writes sent to the VSM
***********************************************************************************************/
uint8_t tms5220_device::new_int_read()
uint8_t tms5220_device::vsm_read()
{
new_int_write(1, 1, 0, 0); // romclk 1, m0 1, m1 0, addr bus nybble = 0/open bus
new_int_write(0, 1, 0, 0); // romclk 0, m0 1, m1 0, addr bus nybble = 0/open bus
new_int_write(1, 0, 0, 0); // romclk 1, m0 0, m1 0, addr bus nybble = 0/open bus
new_int_write(0, 0, 0, 0); // romclk 0, m0 0, m1 0, addr bus nybble = 0/open bus
vsm_write(1, 1, 0, 0); // romclk 1, m0 1, m1 0, addr bus nybble = 0/open bus
vsm_write(0, 1, 0, 0); // romclk 0, m0 1, m1 0, addr bus nybble = 0/open bus
vsm_write(1, 0, 0, 0); // romclk 1, m0 0, m1 0, addr bus nybble = 0/open bus
vsm_write(0, 0, 0, 0); // romclk 0, m0 0, m1 0, addr bus nybble = 0/open bus
uint8_t val = 0;
if (!m_data_cb.isunset())
return m_data_cb();
LOG("WARNING: CALLBACK MISSING, RETURNING 0!\n");
return 0;
val = m_data_cb();
else
LOGMASKED(LOG_VSM, "Warning: No speech memory attached, returning 0.\n");
return val;
}
/**********************************************************************************************
tms5220_device::vsm_read_and_branch -- wrap a 'read-and-branch' set of writes sent to the VSM
***********************************************************************************************/
void tms5220_device::vsm_read_and_branch()
{
vsm_write(0, 1, 1, 0); // see tms5110.cpp
vsm_write(1, 1, 1, 0); // romclk 1, m0 1, m1 1, addr bus nybble = 0/open bus
vsm_write(0, 1, 1, 0); // romclk 0, m0 1, m1 1, addr bus nybble = 0/open bus
vsm_write(0, 0, 0, 0); // see tms5110.cpp
vsm_write(1, 0, 0, 0); // romclk 1, m0 0, m1 0, addr bus nybble = 0/open bus
vsm_write(0, 0, 0, 0); // romclk 0, m0 0, m1 0, addr bus nybble = 0/open bus
}
/**********************************************************************************************
@ -745,7 +793,7 @@ void tms5220_device::update_fifo_status_and_ints()
// also, in this case, regardless if DDIS was set, unset it.
if (m_previous_talk_status && !talk_status())
{
LOG("Talk status 1 -> 0, unsetting DDIS and firing an interrupt.\n");
LOGMASKED(LOG_STATE, "Talk status 1 -> 0, unsetting DDIS and firing an interrupt.\n");
set_interrupt_state(1);
m_DDIS = false;
@ -755,13 +803,13 @@ void tms5220_device::update_fifo_status_and_ints()
// Then resume it.
if (m_command_register != NOCOMMAND)
{
LOGMASKED(LOG_COMMAND_DUMP, "Resume command execution: %02X\n", m_command_register);
LOGMASKED(LOG_STATE, "Resume command execution: %02X\n", m_command_register);
process_command(m_command_register);
// Is there another data transfer pending? Resume it as well.
if (m_data_latched)
{
LOGMASKED(LOG_COMMAND_DUMP, "Pending byte write: %02X\n", m_write_latch);
LOGMASKED(LOG_STATE, "Pending byte write: %02X\n", m_write_latch);
m_timer_io_ready->adjust(clocks_to_attotime(16), 1);
}
else
@ -806,32 +854,33 @@ int tms5220_device::read_bits(int count)
}
else
{
#ifndef USE_NEW_TMS6100_CODE
/** TODO: get rid of this old code */
// extract from VSM (speech ROM)
if (m_speechrom)
val = m_speechrom->read(count);
else
val = (1<<count)-1; // assume the input floats high if nothing is connected, so a spurious speak vsm command will eventually return a 0xF (STOP) frame which will halt speech
#else
while (count--)
if (!m_m0_cb.isunset())
{
val = (val << 1) | new_int_read();
LOG("bit read: %d\n", val&1);
while (count--)
{
val = (val << 1) | vsm_read();
LOGMASKED(LOG_VSM, "bit read: %d\n", val&1);
}
}
else
{
// assume the input floats high if nothing is connected, so a
// spurious speak vsm command will eventually return a 0xF (STOP)
// frame which will halt speech
val = (1<<count)-1;
}
#endif
}
return val;
}
/** TODO: dummy reads should be auto-done for tms52xx for the first read after an address load, but not tms51xx where they need to be done manually, if needed */
void tms5220_device::perform_dummy_read()
{
if (m_schedule_dummy_read)
m_schedule_dummy_read = false;
if (!m_m0_cb.isunset())
{
int data = new_int_read();
LOG("TMS5110 performing dummy read; value read = %1i\n", data & 1);
m_schedule_dummy_read = false;
LOGMASKED(LOG_VSM, "TMS52xx performing dummy read\n");
vsm_write_addr(0);
vsm_read();
}
}
@ -1243,8 +1292,8 @@ int32_t tms5220_device::matrix_multiply(int32_t a, int32_t b) const
while (b>16383) { b-=32768; }
while (b<-16384) { b+=32768; }
result = ((a*b)>>9); /** TODO: this isn't technically right to the chip, which truncates the lowest result bit, but it causes glitches otherwise. **/
if (result>16383) LOG("matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result);
if (result<-16384) LOG("matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result);
if (result>16383) LOGMASKED(LOG_MULTIPLY, "matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result);
if (result<-16384) LOGMASKED(LOG_MULTIPLY, "matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result);
return result;
}
@ -1343,25 +1392,22 @@ int32_t tms5220_device::lattice_filter()
void tms5220_device::process_command(uint8_t cmd)
{
LOGMASKED(LOG_COMMAND_DUMP, "process_command called with parameter %02X\n", cmd);
m_command_register = cmd;
/* parse the command */
switch (cmd & 0x70)
{
case 0x10 : /* read byte */
LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received\n");
LOGMASKED(LOG_COMMAND, "Read Byte command received (%02X)\n", cmd);
if (!talk_status()) /* TALKST must be clear for RDBY */
{
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
perform_dummy_read();
}
if (m_speechrom)
m_read_byte_register = m_speechrom->read(8); /* read one byte from speech ROM... */
m_read_byte_register = read_bits(8);
m_RDB_flag = true;
m_command_register = NOCOMMAND;
}
@ -1373,11 +1419,11 @@ void tms5220_device::process_command(uint8_t cmd)
case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */
if (TMS5220_HAS_RATE_CONTROL)
{
LOGMASKED(LOG_COMMAND_VERBOSE, "Set Rate (or NOP) command received\n");
LOGMASKED(LOG_COMMAND_NOP, "Set Rate (or NOP) command received (%02X)\n", cmd);
m_c_variant_rate = cmd&0x0F;
}
else
LOGMASKED(LOG_COMMAND_VERBOSE, "NOP command received\n");
LOGMASKED(LOG_COMMAND_NOP, "NOP command received (%02X)\n", cmd);
m_command_register = NOCOMMAND;
break;
@ -1385,10 +1431,20 @@ void tms5220_device::process_command(uint8_t cmd)
case 0x30 : /* read and branch */
if (!talk_status()) /* TALKST must be clear for RB */
{
LOGMASKED(LOG_COMMAND_VERBOSE, "Read and Branch command received\n");
LOGMASKED(LOG_COMMAND, "Read and Branch command received (%02X)\n", cmd);
m_RDB_flag = false;
if (m_speechrom)
m_speechrom->read_and_branch();
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
perform_dummy_read();
}
if (!m_m0_cb.isunset())
vsm_read_and_branch();
else
LOGMASKED(LOG_VSM, "WARNING: Read-and-branch: No memory attached to VSP\n");
m_command_register = NOCOMMAND;
}
break;
@ -1396,11 +1452,13 @@ void tms5220_device::process_command(uint8_t cmd)
case 0x40 : /* load address */
if (!talk_status()) /* TALKST must be clear for LA */
{
LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received\n");
/* tms5220 data sheet says that if we load only one 4-bit nibble, it won't work.
This code does not care about this. */
if (m_speechrom)
m_speechrom->load_address(cmd & 0x0f);
LOGMASKED(LOG_COMMAND, "Load Address command received (%02X)\n", cmd);
// tms5220 data sheet says that if we load only one 4-bit nibble,
// it won't work. This code does not care about this.
if (!m_m0_cb.isunset())
vsm_write_addr(cmd & 0x0f);
m_schedule_dummy_read = true;
m_command_register = NOCOMMAND;
}
@ -1414,13 +1472,13 @@ void tms5220_device::process_command(uint8_t cmd)
break;
case 0x50 : /* speak */
LOGMASKED(LOG_COMMAND_VERBOSE, "Speak (VSM) command received\n");
LOGMASKED(LOG_COMMAND, "Speak (VSM) command received (%02X)\n", cmd);
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
perform_dummy_read();
}
m_SPEN = 1;
#ifdef FAST_START_HACK
m_TALK = 1;
@ -1448,7 +1506,7 @@ void tms5220_device::process_command(uint8_t cmd)
break;
case 0x60 : /* speak external */
LOGMASKED(LOG_COMMAND_VERBOSE, "Speak External command received\n");
LOGMASKED(LOG_COMMAND, "Speak External command received (%02X)\n", cmd);
// SPKEXT going active asserts /SPKEE for 2 clocks, which clears the FIFO and its counters
std::fill(std::begin(m_fifo), std::end(m_fifo), 0);
@ -1478,13 +1536,13 @@ void tms5220_device::process_command(uint8_t cmd)
break;
case 0x70 : /* reset */
LOGMASKED(LOG_COMMAND_VERBOSE, "Reset command received\n");
LOGMASKED(LOG_COMMAND, "Reset command received (%02X)\n", cmd);
if (m_schedule_dummy_read)
{
m_schedule_dummy_read = false;
if (m_speechrom)
m_speechrom->read(1);
perform_dummy_read();
}
reset();
m_command_register = NOCOMMAND;
break;
@ -1595,9 +1653,9 @@ void tms5220_device::parse_frame()
LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, "\n");
if (m_DDIS)
LOG("Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken));
LOGMASKED(LOG_PARSE, "Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken));
else
LOG("Parsed a frame successfully in ROM\n");
LOGMASKED(LOG_PARSE, "Parsed a frame successfully in ROM\n");
return;
ranout:
@ -1648,19 +1706,6 @@ void tms5220_device::update_ready_state()
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 = nullptr;
}
switch (m_variant)
{
case TMS5220_IS_TMC0281:
@ -1751,18 +1796,8 @@ void tms5220_device::device_reset()
m_RNG = 0x1FFF;
std::fill(std::begin(m_u), std::end(m_u), 0);
std::fill(std::begin(m_x), std::end(m_x), 0);
m_schedule_dummy_read = false;
if (m_speechrom)
{
m_speechrom->load_address(0);
// MZ: Do the dummy read immediately. The previous line will cause a
// shift in the address pointer in the VSM. When the next command is a
// load_address, no dummy read will occur, hence the address will be
// incorrectly shifted.
m_speechrom->read(1);
m_schedule_dummy_read = false;
}
perform_dummy_read();
// 5110 specific stuff
m_PDC = 0;
@ -2160,7 +2195,6 @@ tms5220_device::tms5220_device(const machine_config &mconfig, device_type type,
, m_variant(variant)
, m_irq_handler(*this)
, m_readyq_handler(*this)
, m_speechrom_tag(nullptr)
, m_m0_cb(*this)
, m_m1_cb(*this)
, m_addr_cb(*this)

View File

@ -5,8 +5,6 @@
#pragma once
#include "machine/spchrom.h"
/* HACK: if defined, uses impossibly perfect 'straight line' interpolation */
#undef TMS5220_PERFECT_INTERPOLATION_HACK
@ -31,9 +29,6 @@ public:
// Ready callback function, active low, i.e. state=0
auto ready_cb() { return m_readyq_handler.bind(); }
// old VSM support, remove me!
void set_speechrom_tag(const char *_tag) { m_speechrom_tag = _tag; }
// new VSM support
auto m0_cb() { return m_m0_cb.bind(); }
auto m1_cb() { return m_m1_cb.bind(); }
@ -80,10 +75,11 @@ protected:
private:
static constexpr unsigned FIFO_SIZE = 16;
// 51xx and VSM related
void new_int_write(uint8_t rc, uint8_t m0, uint8_t m1, uint8_t addr);
void new_int_write_addr(uint8_t addr);
uint8_t new_int_read();
void vsm_write(uint8_t rc, uint8_t m0, uint8_t m1, uint8_t addr);
void vsm_write_addr(uint8_t addr);
uint8_t vsm_read();
void vsm_read_and_branch();
void perform_dummy_read();
// 52xx or common
void register_for_save_states();
@ -237,10 +233,8 @@ private:
/* callbacks */
devcb_write_line m_irq_handler;
devcb_write_line m_readyq_handler;
// next 2 lines are old speechrom handler, remove me!
const char *m_speechrom_tag;
speechrom_device *m_speechrom;
// next lines are new speechrom handler
// Speech ROM handler
devcb_write_line m_m0_cb; // the M0 line
devcb_write_line m_m1_cb; // the M1 line
devcb_write8 m_addr_cb; // Write to ADD1,2,4,8 - 4 address bits

View File

@ -1201,11 +1201,16 @@ void bbc_state::bbcb(machine_config &config)
m_ram->set_default_size("32K");
/* speech hardware */
SPEECHROM(config, "vsm", 0);
TMS5220(config, m_tms, 640000);
m_tms->set_speechrom_tag("vsm");
m_tms->add_route(ALL_OUTPUTS, "mono", 1.0);
TMS6100(config, "vsm", 0);
m_tms->m0_cb().set("vsm", FUNC(tms6100_device::m0_w));
m_tms->m1_cb().set("vsm", FUNC(tms6100_device::m1_w));
m_tms->addr_cb().set("vsm", FUNC(tms6100_device::add_w));
m_tms->data_cb().set("vsm", FUNC(tms6100_device::data_line_r));
m_tms->romclk_cb().set("vsm", FUNC(tms6100_device::clk_w));
/* user via */
MOS6522(config, m_via6522_1, 16_MHz_XTAL / 16);
m_via6522_1->writepa_handler().set("cent_data_out", FUNC(output_latch_device::write));

View File

@ -27,6 +27,7 @@
#include "machine/i2cmem.h"
#include "machine/bankdev.h"
#include "machine/input_merger.h"
#include "machine/tms6100.h"
#include "video/mc6845.h"
#include "video/saa5050.h"
#include "sound/sn76496.h"

View File

@ -99,7 +99,7 @@ TODO:
#include "cpu/tms7000/tms7000.h"
#include "imagedev/cassette.h"
#include "machine/spchrom.h"
#include "machine/tms6100.h"
#include "machine/timer.h"
#include "sound/tms5220.h"
#include "sound/spkrdev.h"
@ -923,13 +923,17 @@ void exelv_state::exeltel(machine_config &config)
PALETTE(config, "palette", palette_device::RGB_3BIT);
SPEECHROM(config, "vsm", 0);
/* sound */
SPEAKER(config, "mono").front_center();
TMS5220C(config, m_tms5220c, 9.8304_MHz_XTAL / 15); // unknown divider for "VSPCLK" (generated by TAHC06 gate array)
m_tms5220c->set_speechrom_tag("vsm");
m_tms5220c->add_route(ALL_OUTPUTS, "mono", 1.00);
TMS6100(config, "vsm", 640_kHz_XTAL/4);
m_tms5220c->m0_cb().set("vsm", FUNC(tms6100_device::m0_w));
m_tms5220c->m1_cb().set("vsm", FUNC(tms6100_device::m1_w));
m_tms5220c->addr_cb().set("vsm", FUNC(tms6100_device::add_w));
m_tms5220c->data_cb().set("vsm", FUNC(tms6100_device::data_line_r));
m_tms5220c->romclk_cb().set("vsm", FUNC(tms6100_device::clk_w));
}

View File

@ -652,10 +652,6 @@ void ti99_8_state::clock_out(int state)
void ti99_8_state::driver_start()
{
// Need to configure the speech ROM for inverse bit order
// speechrom_device* mem = subdevice<speechrom_device>(TI998_SPEECHROM_REG);
// mem->set_reverse_bit_order(true);
save_item(NAME(m_keyboard_column));
save_item(NAME(m_ready_old));
save_item(NAME(m_int1));
@ -743,14 +739,19 @@ void ti99_8_state::ti99_8(machine_config& config)
// Speech hardware
// Note: SPEECHROM uses its tag for referencing the region
SPEECHROM(config, TI998_SPEECHROM_REG, 0).set_reverse_bit_order(true);
SPEAKER(config, "speech_out").front_center();
cd2501ecd_device& vsp(CD2501ECD(config, TI998_SPEECHSYN_TAG, 640000L));
vsp.ready_cb().set(TI998_MAINBOARD_TAG, FUNC(mainboard8_device::speech_ready));
vsp.set_speechrom_tag(TI998_SPEECHROM_REG);
vsp.add_route(ALL_OUTPUTS, "speech_out", 0.50);
TMS6100(config, TI998_SPEECHROM_REG, 0);
vsp.m0_cb().set(TI998_SPEECHROM_REG, FUNC(tms6100_device::m0_w));
vsp.m1_cb().set(TI998_SPEECHROM_REG, FUNC(tms6100_device::m1_w));
vsp.addr_cb().set(TI998_SPEECHROM_REG, FUNC(tms6100_device::add_w));
vsp.data_cb().set(TI998_SPEECHROM_REG, FUNC(tms6100_device::data_line_r));
vsp.romclk_cb().set(TI998_SPEECHROM_REG, FUNC(tms6100_device::clk_w));
// Cassette drive
SPEAKER(config, "cass_out").front_center();
CASSETTE(config, "cassette", 0).add_route(ALL_OUTPUTS, "cass_out", 0.25);