diff --git a/src/devices/sound/tms5220.cpp b/src/devices/sound/tms5220.cpp index ac512ffb004..b31e4734751 100644 --- a/src/devices/sound/tms5220.cpp +++ b/src/devices/sound/tms5220.cpp @@ -46,7 +46,55 @@ Note the standard naming for d* data bits with 7 as MSB and 0 as LSB is in lowercase. TI's naming has D7 as LSB and D0 as MSB and is in uppercase + TMS5100: + + +-----------------+ + TST | 1 28 | CS + PDC | 2 27 | CTL8 + ROM CK | 3 26 | ADD8 + CPU CK | 4 25 | CTL1 + VDD | 5 24 | ADD1 + CR OSC | 6 23 | CTL2 + RC OSC | 7 22 | ADD2 + T11 | 8 21 | ADD4 + NC | 9 20 | CTL4 + I/O | 10 19 | M1 + SPK1 | 11 18 | NC + SPK2 | 12 17 | NC + PROM OUT | 13 16 | NC + VSS | 14 15 | M0 + +-----------------+ + + T11: Sync for serial data out + + + M58817 + + The following connections could be derived from radar scope schematics. + The M58817 is not 100% pin compatible to the 5100, but really close. + + +-----------------+ + (NC) | 1 28 | CS + PDC | 2 27 | CTL8 + ROM CK | 3 26 | ADD8 (to 58819) + (NC) | 4 25 | CTL1 + (VDD,-5) | 5 24 | ADD1 (to 58819) + (GND) | 6 23 | CTL2 + Xin | 7 22 | ADD2 (to 58819) + Xout | 8 21 | ADD4 (to 58819) + (NC) | 9 20 | CTL4 + (VDD,-5) | 10 19 | Status back to CPU + (NC) | 11 18 | C1 (to 58819) + SPKR | 12 17 | (NC) + SPKR | 13 16 | C0 (to 58819) + (NC) | 14 15 | (5V) + +-----------------+ + TODO: + 5110: + * implement CS + * TMS5110_CMD_TEST_TALK is only partially implemented + 5220: * Samples repeat over and over in the 'eprom' test mode. Needs investigation. * Implement a ready callback for pc interfaces - this will be quite a challenge since for it to be really accurate @@ -272,7 +320,7 @@ static INT16 clip_analog(INT16 cliptemp); /* 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) */ #define FORCE_DIGITAL 0 -/* must be defined; if 1, normal speech (one A cycle, one B cycle per interpolation step); if 0; speak as if SPKSLOW was used (two A cycles, one B cycle per interpolation step) */ +/* 5220 only; must be defined; if 1, normal speech (one A cycle, one B cycle per interpolation step); if 0; speak as if SPKSLOW was used (two A cycles, one B cycle per interpolation step) */ #define FORCE_SUBC_RELOAD 1 @@ -280,9 +328,9 @@ static INT16 clip_analog(INT16 cliptemp); #undef VERBOSE // above is general, somewhat obsolete, catch all for debugs which don't fit elsewhere #undef DEBUG_DUMP_INPUT_DATA -// above dumps the data input to the tms52xx to stdout, useful for making logged data dumps for real hardware tests +// 5220 only; above dumps the data written to the tms52xx to stdout, useful for making logged data dumps for real hardware tests #undef DEBUG_FIFO -// above debugs fifo stuff: writes, reads and flag updates +// 5220 only; above debugs fifo stuff: writes, reads and flag updates #undef DEBUG_PARSE_FRAME_DUMP // above dumps each frame to stderr: be sure to select one of the options below if you define it! #undef DEBUG_PARSE_FRAME_DUMP_BIN @@ -310,18 +358,39 @@ static INT16 clip_analog(INT16 cliptemp); #define MAX_SAMPLE_CHUNK 512 -/* Variants */ +/* 6+4 Variants, from tms5110r.inc */ -#define TMS5220_IS_5220C (4) -#define TMS5220_IS_5200 (5) -#define TMS5220_IS_5220 (6) -#define TMS5220_IS_CD2501ECD (7) +#define TMS5220_IS_TMC0281 (1) +#define TMS5220_IS_TMC0281D (2) +#define TMS5220_IS_CD2801 (3) +#define TMS5220_IS_CD2802 (4) +#define TMS5220_IS_TMS5110A (5) +#define TMS5220_IS_M58817 (6) +#define TMS5220_IS_5220C (7) +#define TMS5220_IS_5200 (8) +#define TMS5220_IS_5220 (9) +#define TMS5220_IS_CD2501ECD (10) #define TMS5220_IS_CD2501E TMS5220_IS_5200 +// 52xx: decide whether we have rate control or not #define TMS5220_HAS_RATE_CONTROL ((m_variant == TMS5220_IS_5220C) || (m_variant == TMS5220_IS_CD2501ECD)) + +// All: decide whether we are a 51xx or a 52xx #define TMS5220_IS_52xx ((m_variant == TMS5220_IS_5220C) || (m_variant == TMS5220_IS_5200) || (m_variant == TMS5220_IS_5220) || (m_variant == TMS5220_IS_CD2501ECD)) +/* 51xx: States for CTL */ +// ctl bus is input to tms51xx +#define CTL_STATE_INPUT (0) +// ctl bus is outputting a test talk command on CTL1(bit 0) +#define CTL_STATE_TTALK_OUTPUT (1) +// ctl bus is switching direction, next will be above +#define CTL_STATE_NEXT_TTALK_OUTPUT (2) +// ctl bus is outputting a read nybble 'output' command on CTL1,2,4,8 (bits 0-3) +#define CTL_STATE_OUTPUT (3) +// ctl bus is switching direction, next will be above +#define CTL_STATE_NEXT_OUTPUT (4) + static const UINT8 reload_table[4] = { 0, 2, 4, 6 }; //sample count reload for 5220c and cd2501ecd 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. // Pull in the ROM tables @@ -332,6 +401,24 @@ void tms5220_device::set_variant(int variant) { switch (variant) { + case TMS5220_IS_TMC0281: + m_coeff = &T0280B_0281A_coeff; + break; + case TMS5220_IS_TMC0281D: + m_coeff = &T0280D_0281D_coeff; + break; + case TMS5220_IS_CD2801: + m_coeff = &T0280F_2801A_coeff; + break; + case TMS5220_IS_M58817: + m_coeff = &M58817_coeff; + break; + case TMS5220_IS_CD2802: + m_coeff = &T0280F_2802_coeff; + break; + case TMS5220_IS_TMS5110A: + m_coeff = &tms5110a_coeff; + break; case TMS5220_IS_5200: case TMS5220_IS_CD2501ECD: m_coeff = &T0285_2501E_coeff; @@ -458,7 +545,59 @@ static void printbits(long data, int num) /********************************************************************************************** - tms5220_data_write -- handle a write to the TMS5220 + tms5220_device::new_int_write -- wrap a write to the VSM + +***********************************************************************************************/ +void tms5220_device::new_int_write(UINT8 rc, UINT8 m0, UINT8 m1, UINT8 addr) +{ + if (!m_m0_cb.isnull()) + m_m0_cb(m0); + if (!m_m1_cb.isnull()) + m_m1_cb(m1); + if (!m_addr_cb.isnull()) + m_addr_cb((offs_t)0, addr); + if (!m_romclk_cb.isnull()) + { + //printf("rc %d\n", rc); + m_romclk_cb(rc); + } +} + +/********************************************************************************************** + + tms5220_device::new_int_write_addr -- wrap a 'load address' set of writes to the VSM + +***********************************************************************************************/ +void tms5220_device::new_int_write_addr(UINT8 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 +} + +/********************************************************************************************** + + tms5220_device::new_int_write_addr -- wrap a 'read bit' set of writes to the VSM + +***********************************************************************************************/ +UINT8 tms5220_device::new_int_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 + if (!m_data_cb.isnull()) + return m_data_cb(); +#ifdef VERBOSE + logerror("WARNING: CALLBACK MISSING, RETURNING 0!\n"); +#endif + return 0; +} + +/********************************************************************************************** + + tms5220_device::data_write -- handle a write to the TMS5220 ***********************************************************************************************/ @@ -626,13 +765,39 @@ int tms5220_device::extract_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 + while (count--) + { + val = (val << 1) | new_int_read(); +#ifdef VERBOSE + logerror("bit read: %d\n", val&1); +#endif + } +#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) + { +#ifdef VERBOSE + int data = new_int_read(); + logerror("TMS5110 performing dummy read; value read = %1i\n", data & 1); +#else + new_int_read(); +#endif + m_schedule_dummy_read = FALSE; + } +} + /********************************************************************************************** tms5220_status_read -- read status or data from the TMS5220 @@ -1470,9 +1635,14 @@ void tms5220_device::device_start() set_variant(TMS5220_IS_5220); m_clock = clock(); - /* resolve irq and readyq line */ + /* resolve callbacks */ m_irq_handler.resolve(); m_readyq_handler.resolve(); + m_m0_cb.resolve(); + m_m1_cb.resolve(); + m_romclk_cb.resolve(); + m_addr_cb.resolve(); + m_data_cb.resolve(); /* initialize a stream */ m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80); @@ -1917,7 +2087,12 @@ tms5220_device::tms5220_device(const machine_config &mconfig, const char *tag, d device_sound_interface(mconfig, *this), m_irq_handler(*this), m_readyq_handler(*this), - m_speechrom_tag(nullptr) + m_speechrom_tag(nullptr), + m_m0_cb(*this), + m_m1_cb(*this), + m_addr_cb(*this), + m_data_cb(*this), + m_romclk_cb(*this) { } @@ -1926,7 +2101,12 @@ tms5220_device::tms5220_device(const machine_config &mconfig, device_type type, device_sound_interface(mconfig, *this), m_irq_handler(*this), m_readyq_handler(*this), - m_speechrom_tag(nullptr) + m_speechrom_tag(nullptr), + m_m0_cb(*this), + m_m1_cb(*this), + m_addr_cb(*this), + m_data_cb(*this), + m_romclk_cb(*this) { } diff --git a/src/devices/sound/tms5220.h b/src/devices/sound/tms5220.h index 2f764eecb80..38a0ea20dc7 100644 --- a/src/devices/sound/tms5220.h +++ b/src/devices/sound/tms5220.h @@ -25,9 +25,25 @@ #define MCFG_TMS52XX_READYQ_HANDLER(_devcb) \ devcb = &tms5220_device::set_readyq_handler(*device, DEVCB_##_devcb); +/* old VSM handler, remove me! */ #define MCFG_TMS52XX_SPEECHROM(_tag) \ tms5220_device::set_speechrom_tag(*device, _tag); +/* new VSM handler */ +#define MCFG_TMS52XX_M0_CB(_devcb) \ + devcb = &tms5220_device::set_m0_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS52XX_M1_CB(_devcb) \ + devcb = &tms5220_device::set_m1_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS52XX_ADDR_CB(_devcb) \ + devcb = &tms5220_device::set_addr_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS52XX_DATA_CB(_devcb) \ + devcb = &tms5220_device::set_data_callback(*device, DEVCB_##_devcb); + +#define MCFG_TMS52XX_ROMCLK_CB(_devcb) \ + devcb = &tms5220_device::set_romclk_callback(*device, DEVCB_##_devcb); class tms5220_device : public device_t, public device_sound_interface { @@ -38,7 +54,14 @@ public: // static configuration helpers template static devcb_base &set_irq_handler(device_t &device, _Object object) { return downcast(device).m_irq_handler.set_callback(object); } template static devcb_base &set_readyq_handler(device_t &device, _Object object) { return downcast(device).m_readyq_handler.set_callback(object); } + // old VSM support, remove me! static void set_speechrom_tag(device_t &device, const char *_tag) { downcast(device).m_speechrom_tag = _tag; } + // new VSM support + template static devcb_base &set_m0_callback(device_t &device, _Object object) { return downcast(device).m_m0_cb.set_callback(object); } + template static devcb_base &set_m1_callback(device_t &device, _Object object) { return downcast(device).m_m1_cb.set_callback(object); } + template static devcb_base &set_addr_callback(device_t &device, _Object object) { return downcast(device).m_addr_cb.set_callback(object); } + template static devcb_base &set_data_callback(device_t &device, _Object object) { return downcast(device).m_data_cb.set_callback(object); } + template static devcb_base &set_romclk_callback(device_t &device, _Object object) { return downcast(device).m_romclk_cb.set_callback(object); } /* Control lines - once written to will switch interface into * "true" timing behaviour. @@ -73,6 +96,12 @@ protected: void set_variant(int variant); private: + // 51xx and VSM related + void new_int_write(UINT8 rc, UINT8 m0, UINT8 m1, UINT8 addr); + void new_int_write_addr(UINT8 addr); + UINT8 new_int_read(); + void perform_dummy_read(); + // 52xx or common void register_for_save_states(); void data_write(int data); void update_fifo_status_and_ints(); @@ -96,6 +125,24 @@ private: /* coefficient tables */ const struct tms5100_coeffs *m_coeff; + /* these contain global status bits */ + UINT8 m_PDC; + UINT8 m_CTL_pins; + UINT8 m_state; + + /* New VSM interface */ + UINT32 m_address; + UINT8 m_next_is_address; + UINT8 m_schedule_dummy_read; + UINT8 m_addr_bit; + /* read byte */ + UINT8 m_CTL_buffer; + + /* Old VSM interface; 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 */ + /* these contain data that describes the 128-bit data FIFO */ UINT8 m_fifo[FIFO_SIZE]; UINT8 m_fifo_head; @@ -167,11 +214,6 @@ private: UINT16 m_RNG; /* the random noise generator configuration is: 1 + x + x^3 + x^4 + x^13 TODO: no it isn't */ 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 */ - /* 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 @@ -201,8 +243,18 @@ 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 + 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 + devcb_read_line m_data_cb; // Read one bit from ADD8/Data - voice data + // On a real chip rom_clk is running all the time + // Here, we only use it to properly emulate the protocol. + // Do not rely on it to be a timed signal. + devcb_write_line m_romclk_cb; // rom clock - Only used to drive the data lines }; extern const device_type TMS5220;