trunk/src/emu/sound/tms5220.c
| r24564 | r24565 | |
| 23 | 23 | US patent 4,335,277 describes the complete 52xx chip |
| 24 | 24 | Special Thanks to Larry Brantingham for answering questions regarding the chip details |
| 25 | 25 | |
| 26 | | TMS5200/TMS5220/TMS5220C: |
| 26 | TMS5200/TMS5220/TMS5220C/CD2501E/CD2501ECD: |
| 27 | 27 | |
| 28 | 28 | +-----------------+ |
| 29 | 29 | D7(d0) | 1 28 | /RS |
| r24564 | r24565 | |
| 120 | 120 | 01 7 0#3 4 5 6 7 0#3 4 5 6 7 0#3 4 5 |
| 121 | 121 | 10 7 0#5 6 7 0#5 6 7 0#5 6 7 0#5 6 7 |
| 122 | 122 | 11 7 0#7 0#7 0#7 0#7 0#7 0#7 0#7 0#7 |
| 123 | Based on the behavior tested on the CD2501ECD this is assumed to be the same for that chip as well. |
| 123 | 124 | |
| 124 | 125 | Most of the following is based on figure 8c of 4,331,836, which is the |
| 125 | 126 | TMS5100/TMC0280 patent, but the same information applies to the TMS52xx |
| r24564 | r24565 | |
| 155 | 156 | |
| 156 | 157 | |
| 157 | 158 | ****Documentation of chip commands:*** |
| 158 | | x0x0xbcc : on 5200/5220: NOP (does nothing); on 5220C: Select frame length by cc, and b selects whether every frame is preceded by 2 bits to select the frame length (instead of using the value set by cc); the default (and after a reset command) is as if '0x00' was written, i.e. for frame length (200 samples) and 0 for whether the preceding 2 bits are enabled (off) |
| 159 | x0x0xbcc : on 5200/5220: NOP (does nothing); on 5220C and CD2501ECD: Select frame length by cc, and b selects whether every frame is preceded by 2 bits to select the frame length (instead of using the value set by cc); the default (and after a reset command) is as if '0x00' was written, i.e. for frame length (200 samples) and 0 for whether the preceding 2 bits are enabled (off) |
| 159 | 160 | |
| 160 | 161 | x001xxxx: READ BYTE (RDBY) Sends eight read bit commands (M0 high M1 low) to VSM and reads the resulting bits serially into a temporary register, which becomes readable as the next byte read from the tms52xx once ready goes active. Note the bit order of the byte read from the TMS52xx is BACKWARDS as compared to the actual data order as in the rom on the VSM chips; the read byte command of the tms5100 reads the bits in the 'correct' order. This was IMHO a rather silly design decision of TI. (I (LN) asked Larry Brantingham about this but he wasn't involved with the TMS52xx chips, just the 5100); There's ASCII data in the TI 99/4 speech module VSMs which has the bit order reversed on purpose because of this! |
| 161 | 162 | TALK STATUS must be CLEAR for this command to work; otherwise it is treated as a NOP. |
| r24564 | r24565 | |
| 175 | 176 | |
| 176 | 177 | |
| 177 | 178 | Other chip differences: |
| 178 | | The 5220 is 'noisier' when playing unvoiced frames than the 5220C is; I (LN) think the 5220C may use a different energy table (or use one value lower in the normal energy table) than the 5220 does, possibly only when playing unvoiced frames, but I can't prove this without a decap; the 5220C's PROMOUT pin (for dumping the lpc tables as played) is non-functional due to a changed design or a die bug (or may need special timing to know exactly when to read it, different than the 5200 and 5220 which are both easily readable). |
| 179 | | In addition, the NOP commands on the FIFO interface have been changed on the 5220C and data passed in the low bits has a meaning regarding frame length, see above. |
| 179 | The 5220C (and CD2501ECD maybe?) are quieter due to a better dac arrangement on die which allows less crossover between bits, based on the decap differences. |
| 180 | 180 | |
| 181 | | It is also possible but inconclusive that the chirp table was changed; The LPC tables between the 5220 and 5220C are MOSTLY the same of not completely so, but as mentioned above the energy table has some sort of difference. |
| 182 | 181 | |
| 183 | | |
| 184 | 182 | ***MAME Driver specific notes:*** |
| 185 | 183 | |
| 186 | 184 | Victory's initial audio selftest is pretty brutal to the FIFO: it sends a |
| r24564 | r24565 | |
| 220 | 218 | serial chips); Street Electronics Corp.'s Apple II 'Echo 2' Speech |
| 221 | 219 | synthesizer (early cards only) |
| 222 | 220 | |
| 221 | CD2501ECD: (1983) |
| 222 | Home computer: TI 99/8 (prototypes only) |
| 223 | |
| 223 | 224 | TMS5220: (mostly on things made between 1981 and 1984-1985) |
| 224 | 225 | Arcade: Bally/Midway's 'NFL Football'; Atari's 'Star Wars', |
| 225 | 226 | 'Firefox', 'Return of the Jedi', 'Road Runner', 'The Empire Strikes |
| r24564 | r24565 | |
| 265 | 266 | |
| 266 | 267 | /* Other hacks */ |
| 267 | 268 | /* HACK?: if defined, outputs the low 4 bits of the lattice filter to the i/o |
| 268 | | * or clip logic, even though the real hardware doesn't do this... |
| 269 | | * ...actually the tms5220c might legitamately do this! */ |
| 269 | * or clip logic, even though the real hardware doesn't do this, partially verified by decap */ |
| 270 | 270 | #undef ALLOW_4_LSB |
| 271 | 271 | |
| 272 | 272 | |
| r24564 | r24565 | |
| 317 | 317 | #define TMS5220_IS_5220C (4) |
| 318 | 318 | #define TMS5220_IS_5200 (5) |
| 319 | 319 | #define TMS5220_IS_5220 (6) |
| 320 | #define TMS5220_IS_CD2501ECD (7) |
| 320 | 321 | |
| 321 | | #define TMS5220_IS_TMC0285 TMS5220_IS_5200 |
| 322 | #define TMS5220_IS_CD2501E TMS5220_IS_5200 |
| 322 | 323 | |
| 323 | | 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. |
| 324 | #define TMS5220_HAS_RATE_CONTROL ((m_variant == TMS5220_IS_5220C) || (m_variant == TMS5220_IS_CD2501ECD)) |
| 324 | 325 | |
| 326 | 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. |
| 327 | |
| 325 | 328 | // Pull in the ROM tables |
| 326 | 329 | #include "tms5110r.c" |
| 327 | 330 | |
| r24564 | r24565 | |
| 331 | 334 | switch (variant) |
| 332 | 335 | { |
| 333 | 336 | case TMS5220_IS_5200: |
| 337 | case TMS5220_IS_CD2501ECD: |
| 334 | 338 | m_coeff = &tms5200_coeff; |
| 335 | 339 | break; |
| 336 | 340 | case TMS5220_IS_5220C: |
| r24564 | r24565 | |
| 386 | 390 | save_item(NAME(m_PC)); |
| 387 | 391 | save_item(NAME(m_IP)); |
| 388 | 392 | save_item(NAME(m_inhibit)); |
| 389 | | save_item(NAME(m_tms5220c_rate)); |
| 393 | save_item(NAME(m_c_variant_rate)); |
| 390 | 394 | save_item(NAME(m_pitch_count)); |
| 391 | 395 | |
| 392 | 396 | save_item(NAME(m_u)); |
| r24564 | r24565 | |
| 475 | 479 | // 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 |
| 476 | 480 | m_subcycle = m_subc_reload; |
| 477 | 481 | m_PC = 0; |
| 478 | | 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? |
| 482 | m_IP = reload_table[m_c_variant_rate&0x3]; // is this correct? should this be always 7 instead, so that the new frame is loaded quickly? |
| 479 | 483 | m_new_frame_energy_idx = 0; |
| 480 | 484 | m_new_frame_pitch_idx = 0; |
| 481 | 485 | for (i = 0; i < 4; i++) |
| r24564 | r24565 | |
| 755 | 759 | // end HACK |
| 756 | 760 | |
| 757 | 761 | /* appropriately override the interp count if needed; this will be incremented after the frame parse! */ |
| 758 | | m_IP = reload_table[m_tms5220c_rate&0x3]; |
| 762 | m_IP = reload_table[m_c_variant_rate&0x3]; |
| 759 | 763 | |
| 760 | 764 | #ifdef PERFECT_INTERPOLATION_HACK |
| 761 | 765 | /* remember previous frame energy, pitch, and coefficients */ |
| r24564 | r24565 | |
| 1165 | 1169 | } |
| 1166 | 1170 | break; |
| 1167 | 1171 | |
| 1168 | | case 0x00: case 0x20: /* set rate (tms5220c only), otherwise NOP */ |
| 1169 | | if (m_variant == TMS5220_IS_5220C) |
| 1172 | case 0x00: case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */ |
| 1173 | if (TMS5220_HAS_RATE_CONTROL) |
| 1170 | 1174 | { |
| 1171 | | m_tms5220c_rate = cmd&0x0F; |
| 1175 | m_c_variant_rate = cmd&0x0F; |
| 1172 | 1176 | } |
| 1173 | 1177 | break; |
| 1174 | 1178 | |
| r24564 | r24565 | |
| 1209 | 1213 | // TODO: similar to the victory case described above, but for VSM speech |
| 1210 | 1214 | m_subcycle = m_subc_reload; |
| 1211 | 1215 | m_PC = 0; |
| 1212 | | m_IP = reload_table[m_tms5220c_rate&0x3]; |
| 1216 | m_IP = reload_table[m_c_variant_rate&0x3]; |
| 1213 | 1217 | m_new_frame_energy_idx = 0; |
| 1214 | 1218 | m_new_frame_pitch_idx = 0; |
| 1215 | 1219 | int i; |
| r24564 | r24565 | |
| 1257 | 1261 | |
| 1258 | 1262 | /* if the chip is a tms5220C, and the rate mode is set to that each frame (0x04 bit set) |
| 1259 | 1263 | has a 2 bit rate preceding it, grab two bits here and store them as the rate; */ |
| 1260 | | if ((m_variant == TMS5220_IS_5220C) && (m_tms5220c_rate & 0x04)) |
| 1264 | if ((TMS5220_HAS_RATE_CONTROL) && (m_c_variant_rate & 0x04)) |
| 1261 | 1265 | { |
| 1262 | 1266 | indx = extract_bits(2); |
| 1263 | 1267 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| r24564 | r24565 | |
| 1267 | 1271 | m_IP = reload_table[indx]; |
| 1268 | 1272 | } |
| 1269 | 1273 | else // non-5220C and 5220C in fixed rate mode |
| 1270 | | m_IP = reload_table[m_tms5220c_rate&0x3]; |
| 1274 | m_IP = reload_table[m_c_variant_rate&0x3]; |
| 1271 | 1275 | |
| 1272 | 1276 | update_status_and_ints(); |
| 1273 | 1277 | if (!m_talk_status) goto ranout; |
| r24564 | r24565 | |
| 1442 | 1446 | // device_start - device-specific startup |
| 1443 | 1447 | //------------------------------------------------- |
| 1444 | 1448 | |
| 1445 | | void tmc0285_device::device_start() |
| 1449 | void cd2501e_device::device_start() |
| 1446 | 1450 | { |
| 1447 | 1451 | tms5220_device::device_start(); |
| 1448 | | set_variant(TMS5220_IS_TMC0285); |
| 1452 | set_variant(TMS5220_IS_CD2501E); |
| 1449 | 1453 | } |
| 1450 | 1454 | |
| 1451 | 1455 | //------------------------------------------------- |
| r24564 | r24565 | |
| 1458 | 1462 | set_variant(TMS5220_IS_5200); |
| 1459 | 1463 | } |
| 1460 | 1464 | |
| 1465 | //------------------------------------------------- |
| 1466 | // device_start - device-specific startup |
| 1467 | //------------------------------------------------- |
| 1461 | 1468 | |
| 1469 | void cd2501ecd_device::device_start() |
| 1470 | { |
| 1471 | tms5220_device::device_start(); |
| 1472 | set_variant(TMS5220_IS_CD2501ECD); |
| 1473 | } |
| 1474 | |
| 1462 | 1475 | //------------------------------------------------- |
| 1463 | 1476 | // device_reset - device-specific reset |
| 1464 | 1477 | //------------------------------------------------- |
| r24564 | r24565 | |
| 1492 | 1505 | |
| 1493 | 1506 | /* initialize the sample generators */ |
| 1494 | 1507 | m_inhibit = 1; |
| 1495 | | m_subcycle = m_tms5220c_rate = m_pitch_count = m_PC = 0; |
| 1508 | m_subcycle = m_c_variant_rate = m_pitch_count = m_PC = 0; |
| 1496 | 1509 | m_subc_reload = FORCE_SUBC_RELOAD; |
| 1497 | 1510 | m_OLDE = m_OLDP = 1; |
| 1498 | | m_IP = reload_table[m_tms5220c_rate&0x3]; |
| 1511 | m_IP = reload_table[m_c_variant_rate&0x3]; |
| 1499 | 1512 | m_RNG = 0x1FFF; |
| 1500 | 1513 | memset(m_u, 0, sizeof(m_u)); |
| 1501 | 1514 | memset(m_x, 0, sizeof(m_x)); |
| r24564 | r24565 | |
| 1575 | 1588 | m_rs_ws = new_val; |
| 1576 | 1589 | if (new_val == 0) |
| 1577 | 1590 | { |
| 1578 | | if (m_variant == TMS5220_IS_5220C) |
| 1591 | if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd |
| 1579 | 1592 | reset(); |
| 1580 | 1593 | #ifdef DEBUG_RS_WS |
| 1581 | 1594 | else |
| r24564 | r24565 | |
| 1627 | 1640 | m_rs_ws = new_val; |
| 1628 | 1641 | if (new_val == 0) |
| 1629 | 1642 | { |
| 1630 | | if (m_variant == TMS5220_IS_5220C) |
| 1643 | if (TMS5220_HAS_RATE_CONTROL) // correct for 5220c, ? for cd2501ecd |
| 1631 | 1644 | reset(); |
| 1632 | 1645 | #ifdef DEBUG_RS_WS |
| 1633 | 1646 | else |
| r24564 | r24565 | |
| 1663 | 1676 | RDBY: between 60 and 140 cycles |
| 1664 | 1677 | RB: ? cycles (80?) |
| 1665 | 1678 | RST: between 60 and 140 cycles |
| 1666 | | SET RATE (5220C only): ? cycles (probably ~16) |
| 1679 | SET RATE (5220C and CD2501ECD only): ? cycles (probably ~16) |
| 1667 | 1680 | */ |
| 1668 | 1681 | // TODO: actually HANDLE the timing differences! currently just assuming always 16 cycles |
| 1669 | 1682 | 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 |
| r24564 | r24565 | |
| 1868 | 1881 | } |
| 1869 | 1882 | |
| 1870 | 1883 | |
| 1871 | | const device_type TMC0285 = &device_creator<tmc0285_device>; |
| 1884 | const device_type CD2501E = &device_creator<cd2501e_device>; |
| 1872 | 1885 | |
| 1873 | | tmc0285_device::tmc0285_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 1874 | | : tms5220_device(mconfig, TMC0285, "TMC0285", tag, owner, clock, "tmc0285", __FILE__) |
| 1886 | cd2501e_device::cd2501e_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 1887 | : tms5220_device(mconfig, CD2501E, "CD2501E", tag, owner, clock, "cd2501e", __FILE__) |
| 1875 | 1888 | { |
| 1876 | 1889 | } |
| 1877 | 1890 | |
| r24564 | r24565 | |
| 1882 | 1895 | : tms5220_device(mconfig, TMS5200, "TMS5200", tag, owner, clock, "tms5200", __FILE__) |
| 1883 | 1896 | { |
| 1884 | 1897 | } |
| 1898 | |
| 1899 | |
| 1900 | const device_type CD2501ECD = &device_creator<cd2501ecd_device>; |
| 1901 | |
| 1902 | cd2501ecd_device::cd2501ecd_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 1903 | : tms5220_device(mconfig, CD2501ECD, "CD2501ECD", tag, owner, clock, "cd2501ecd", __FILE__) |
| 1904 | { |
| 1905 | } |
trunk/src/mess/machine/ti99/spchsyn.c
| r24564 | r24565 | |
| 7 | 7 | right side of the console. In order to be used with Geneve and SGCPU, the |
| 8 | 8 | speech synthesizer must be moved into the Peripheral Box. |
| 9 | 9 | |
| 10 | | The Speech Synthesizer used for the TI was the TMS5200, aka TMC0285, a |
| 11 | | predecessor of the TMS5220 which was used in other commercial products. |
| 10 | The Speech Synthesizer used for the TI was the CD2501E, AKA TMS5200, |
| 11 | (internal name TMC0285), a predecessor of the TMS5220 which was used in |
| 12 | other commercial products. |
| 12 | 13 | |
| 13 | 14 | Note that this adapter also contains the speech roms. |
| 14 | 15 | |
| r24564 | r24565 | |
| 166 | 167 | |
| 167 | 168 | void ti_speech_synthesizer_device::device_config_complete() |
| 168 | 169 | { |
| 169 | | m_vsp = subdevice<tmc0285_device>("speechsyn"); |
| 170 | m_vsp = subdevice<cd2501e_device>("speechsyn"); |
| 170 | 171 | } |
| 171 | 172 | |
| 172 | 173 | void ti_speech_synthesizer_device::device_reset() |
| r24564 | r24565 | |
| 187 | 188 | MCFG_DEVICE_ADD("vsm", SPEECHROM, 0) |
| 188 | 189 | |
| 189 | 190 | MCFG_SPEAKER_STANDARD_MONO("mono") |
| 190 | | MCFG_SOUND_ADD("speechsyn", TMC0285, 640000L) |
| 191 | MCFG_SOUND_ADD("speechsyn", CD2501E, 640000L) |
| 191 | 192 | MCFG_TMS52XX_READYQ_HANDLER(WRITELINE(ti_speech_synthesizer_device, speech_ready)) |
| 192 | 193 | MCFG_TMS52XX_SPEECHROM("vsm") |
| 193 | 194 | MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) |
| r24564 | r24565 | |
| 195 | 196 | |
| 196 | 197 | ROM_START( ti99_speech ) |
| 197 | 198 | ROM_REGION(0x8000, "vsm", 0) |
| 199 | // Note: the following line is actually wrong; the speech roms in the ti 99/4a and 99/8 are two VSM roms labeled CD2325A and CD2326A, and contain the same data as the following line rom does, but with the byte bit order reversed. This bit ordering issue needs to be fixed elsewhere in the code here before the original/real roms can be used. |
| 198 | 200 | ROM_LOAD_OPTIONAL("spchrom.bin", 0x0000, 0x8000, CRC(58b155f7) SHA1(382292295c00dff348d7e17c5ce4da12a1d87763)) /* system speech ROM */ |
| 201 | // correct lines are: |
| 202 | // ROM_LOAD_OPTIONAL("cd2325a.u2a", 0x0000, 0x4000, CRC(1f58b571) SHA1(0ef4f178716b575a1c0c970c56af8a8d97561ffe)) // at location u2, bottom of stack |
| 203 | // ROM_LOAD_OPTIONAL("cd2326a.u2b", 0x4000, 0x4000, CRC(65d00401) SHA1(a367242c2c96cebf0e2bf21862f3f6734b2b3020)) // at location u2, top of stack |
| 199 | 204 | ROM_END |
| 200 | 205 | |
| 201 | 206 | machine_config_constructor ti_speech_synthesizer_device::device_mconfig_additions() const |