diff options
Diffstat (limited to 'src/devices/sound/tms5220.cpp')
-rw-r--r-- | src/devices/sound/tms5220.cpp | 503 |
1 files changed, 291 insertions, 212 deletions
diff --git a/src/devices/sound/tms5220.cpp b/src/devices/sound/tms5220.cpp index 4889cd85c60..77869045bea 100644 --- a/src/devices/sound/tms5220.cpp +++ b/src/devices/sound/tms5220.cpp @@ -312,7 +312,7 @@ Exidy's 'Victory' and 'Victor Banana' (need verify for both) Pinball: Several (don't know names offhand, have not checked schematics; likely Zaccaria's 'Farfalla') Home computer: Street Electronics Corp.'s Apple II 'Echo 2' Speech synthesizer (later cards only); Texas Instruments' 'Speak and Learn' -scanner wand unit. +scanner wand unit; HP 27201A Speech Output Module (serial port connection). TMS5220C AKA TSP5220C: (on stuff made from 1984 to 1992 or so) Arcade: Atari's 'Indiana Jones and the Temple of Doom', '720', @@ -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***** */ -// general, somewhat obsolete, catch all for debugs which don't fit elsewhere -#define LOG_GENERAL (1 << 0) -/* 5220 only; above dumps the data written to the tms52xx to stdout, useful +/* 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 (1 << 1) +#define LOG_DUMP_INPUT_DATA (1U << 1) + // 5220 only; above debugs FIFO stuff: writes, reads and flag updates -#define LOG_FIFO (1 << 2) +#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 (1 << 3) +#define LOG_PARSE_FRAME_DUMP_BIN (1U << 4) + // dumps each speech frame as hex -#define LOG_PARSE_FRAME_DUMP_HEX (1 << 4) +#define LOG_PARSE_FRAME_DUMP_HEX (1U << 5) + // dumps info if a frame ran out of data -#define LOG_FRAME_ERRORS (1 << 6) +#define LOG_FRAME_ERRORS (1U << 6) + // dumps all non-speech-data command writes -#define LOG_COMMAND_DUMP (1 << 7) -// dumps decoded info about command writes -#define LOG_COMMAND_VERBOSE (1 << 8) -// spams the errorlog with i/o ready messages whenever the ready or irq pin is read -#define LOG_PIN_READS (1 << 9) +#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 (1 << 10) +#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 (1 << 11) +#define LOG_GENERATION_VERBOSE (1U << 12) + // dumps the lattice filter state data each sample. -#define LOG_LATTICE (1 << 12) -// dumps info to stderr whenever the analog clip hardware is (or would be) clipping the signal. -#define LOG_CLIP (1 << 13) +#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 (1 << 14) +#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 (1 << 15) +#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) -//#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) +// Show state changes +#define LOG_STATE (1U << 20) + +//#define VERBOSE (LOG_FIFO | LOG_PARSE | LOG_FRAME_ERRORS | LOG_COMMAND | LOG_GENERATION | LOG_DATA_W | LOG_STATE) #include "logmacro.h" #define MAX_SAMPLE_CHUNK 512 @@ -440,6 +468,8 @@ emulating the tms5220 in MCU code). Look for a 16-pin chip at U6 labeled static const uint8_t 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. +#define NOCOMMAND 0xff + // Pull in the ROM tables #include "tms5110r.hxx" @@ -482,6 +512,9 @@ void tms5220_device::register_for_save_states() save_item(NAME(m_irq_pin)); save_item(NAME(m_ready_pin)); + save_item(NAME(m_command_register)); + save_item(NAME(m_data_latched)); + // current and previous frames save_item(NAME(m_OLDE)); save_item(NAME(m_OLDP)); @@ -565,18 +598,15 @@ 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) { - 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()) + m_m0_cb(m0); + m_m1_cb(m1); + m_addr_cb(offs_t(0), addr); + if (!m_romclk_cb.isunset()) { //printf("rc %d\n", rc); m_romclk_cb(rc); @@ -585,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 - if (!m_data_cb.isnull()) - return m_data_cb(); - LOGMASKED(LOG_GENERAL, "WARNING: CALLBACK MISSING, RETURNING 0!\n"); - return 0; + 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()) + 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 } /********************************************************************************************** @@ -632,7 +682,7 @@ void tms5220_device::data_write(int data) m_fifo[m_fifo_tail] = data; m_fifo_tail = (m_fifo_tail + 1) % FIFO_SIZE; m_fifo_count++; - LOGMASKED(LOG_FIFO, "data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count); + LOGMASKED(LOG_FIFO, "data_write: Added %02X byte to FIFO (current count=%2d)\n", data, m_fifo_count); update_fifo_status_and_ints(); // if we just unset buffer low with that last write, and SPEN *was* zero (see circuit 251, sheet 12) @@ -668,12 +718,14 @@ void tms5220_device::data_write(int data) LOGMASKED(LOG_FIFO, "data_write: Ran out of room in the tms52xx FIFO! this should never happen!\n"); // at this point, /READY should remain HIGH/inactive until the FIFO has at least one byte open in it. } - - + m_data_latched = false; } else //(! m_DDIS) // R Nabet : we parse commands at once. It is necessary for such commands as read. process_command(data); + + if (!m_data_latched) + m_io_ready = true; } /********************************************************************************************** @@ -741,21 +793,45 @@ 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()) { - LOGMASKED(LOG_GENERAL, "Talk status WAS 1, is now 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; + + m_previous_talk_status = false; + + // Is there a command stuck in the command register due to speech output? + // Then resume it. + if (m_command_register != NOCOMMAND) + { + 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_STATE, "Pending byte write: %02X\n", m_write_latch); + m_timer_io_ready->adjust(clocks_to_attotime(16), 1); + } + else + m_io_ready = true; + + update_ready_state(); + } } m_previous_talk_status = talk_status(); + // update continuously when RSQ is held active low + if (m_rs_ws == 0x01 && !m_RDB_flag) + m_read_latch = status_read(false); } /********************************************************************************************** - extract_bits -- extract a specific number of bits from the current input stream (FIFO or VSM) + read_bits -- read a specific number of bits from the current input stream (FIFO or VSM) ***********************************************************************************************/ -int tms5220_device::extract_bits(int count) +int tms5220_device::read_bits(int count) { int val = 0; @@ -778,32 +854,33 @@ 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); + if (!m_m0_cb.isunset()) + { + while (count--) + { + val = (val << 1) | vsm_read(); + LOGMASKED(LOG_VSM, "bit read: %d\n", val&1); + } + } 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--) { - val = (val << 1) | new_int_read(); - LOGMASKED(LOG_GENERAL, "bit read: %d\n", val&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 + 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(); - LOGMASKED(LOG_GENERAL, "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(); } } @@ -886,7 +963,7 @@ void tms5220_device::process(int16_t *buffer, unsigned int size) int i, bitout; int32_t this_sample; - LOGMASKED(LOG_GENERAL, "process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); + LOGMASKED(LOG_GENERATION, "process called with size of %d; IP=%d, PC=%d, subcycle=%d, m_SPEN=%d, m_TALK=%d, m_TALKD=%d\n", size, m_IP, m_PC, m_subcycle, m_SPEN, m_TALK, m_TALKD); /* loop until the buffer is full or we've stopped speaking */ while (size > 0) @@ -941,12 +1018,8 @@ void tms5220_device::process(int16_t *buffer, unsigned int size) m_inhibit = false; /* Debug info for current parsed frame */ - LOGMASKED(LOG_GENERATION, "OLDE: %d; NEWE: %d; OLDP: %d; NEWP: %d ", old_frame_silence_flag(), new_frame_silence_flag(), old_frame_unvoiced_flag(), new_frame_unvoiced_flag()); - LOGMASKED(LOG_GENERATION, "Processing new frame: "); - if (!m_inhibit) - LOGMASKED(LOG_GENERATION, "Normal Frame\n"); - else - LOGMASKED(LOG_GENERATION, "Interpolation Inhibited\n"); + LOGMASKED(LOG_GENERATION, "OLDE: %d; NEWE: %d; OLDP: %d; NEWP: %d\n", old_frame_silence_flag(), new_frame_silence_flag(), old_frame_unvoiced_flag(), new_frame_unvoiced_flag()); + LOGMASKED(LOG_GENERATION, "Processing new frame: %s\n", !m_inhibit ? "Normal Frame" : "Interpolation Inhibited"); LOGMASKED(LOG_GENERATION, "*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n",m_current_energy, m_current_pitch, m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], m_current_k[8], m_current_k[9]); LOGMASKED(LOG_GENERATION, "*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", (m_coeff->energytable[m_new_frame_energy_idx] * (1-m_zpar)), @@ -1219,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) LOGMASKED(LOG_GENERAL, "matrix multiplier overflowed! a: %x, b: %x, result: %x", a, b, result); - if (result<-16384) LOGMASKED(LOG_GENERAL, "matrix multiplier underflowed! a: %x, b: %x, result: %x", a, b, result); + 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; } @@ -1302,77 +1375,110 @@ int32_t tms5220_device::lattice_filter() /********************************************************************************************** - process_command -- extract a byte from the FIFO and interpret it as a command + process_command -- decode byte and run the command + + During SPEAK, the address counter is locked against modification by + LOAD_ADDRESS. In that time, a LOAD_ADDRESS command does not terminate but + remains in the command register. + When another command is fed into the speech processor, the READY line is + lowered until the command register is cleared, then the new command is + loaded into the command register. + + Note that the running SPEAK command does not block the command register; + it is a command that attempts to change the address during the SPEAK + process. [mz] ***********************************************************************************************/ -void tms5220_device::process_command(unsigned char cmd) +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; } else - LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received during TALK state, ignoring!\n"); + LOGMASKED(LOG_COMMAND_VERBOSE, "Read Byte command received during TALK state, suspended.\n"); break; - case 0x00: case 0x20: /* set rate (tms5220c and cd2501ecd only), otherwise NOP */ + case 0x00: + 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; 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; case 0x40 : /* load address */ - LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received\n"); if (!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. */ - 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; } else - LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received during TALK state, ignoring!\n"); + { + // The Load Address command is not ignored during speech output, + // as tests show. In fact, it is normally executed when the speech + // terminates. + LOGMASKED(LOG_COMMAND_VERBOSE, "Load Address command received during TALK state, suspended.\n"); + } 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; @@ -1395,10 +1501,12 @@ void tms5220_device::process_command(unsigned char cmd) m_new_frame_k_idx[i] = 0xF; for (int i = 7; i < m_coeff->num_k; i++) m_new_frame_k_idx[i] = 0x7; + + m_command_register = NOCOMMAND; 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); @@ -1423,17 +1531,20 @@ void tms5220_device::process_command(unsigned char cmd) for (int i = 7; i < m_coeff->num_k; i++) m_new_frame_k_idx[i] = 0x7; m_RDB_flag = false; + + m_command_register = NOCOMMAND; 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; } @@ -1474,7 +1585,7 @@ void tms5220_device::parse_frame() has a 2 bit rate preceding it, grab two bits here and store them as the rate; */ if ((TMS5220_HAS_RATE_CONTROL) && (m_c_variant_rate & 0x04)) { - i = extract_bits(2); + i = read_bits(2); printbits(i, 2); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); m_IP = reload_table[i]; @@ -1486,7 +1597,7 @@ void tms5220_device::parse_frame() if (m_DDIS && m_buffer_empty) goto ranout; // attempt to extract the energy index - m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits); + m_new_frame_energy_idx = read_bits(m_coeff->energy_bits); printbits(m_new_frame_energy_idx, m_coeff->energy_bits); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); update_fifo_status_and_ints(); @@ -1497,12 +1608,12 @@ void tms5220_device::parse_frame() // attempt to extract the repeat flag - rep_flag = extract_bits(1); + rep_flag = read_bits(1); printbits(rep_flag, 1); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); // attempt to extract the pitch - m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits); + m_new_frame_pitch_idx = read_bits(m_coeff->pitch_bits); printbits(m_new_frame_pitch_idx, m_coeff->pitch_bits); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); // if the new frame is unvoiced, be sure to zero out the k5-k10 parameters @@ -1516,7 +1627,7 @@ void tms5220_device::parse_frame() // extract first 4 K coefficients for (i = 0; i < 4; i++) { - m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); + m_new_frame_k_idx[i] = read_bits(m_coeff->kbits[i]); printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); update_fifo_status_and_ints(); @@ -1533,7 +1644,7 @@ void tms5220_device::parse_frame() // 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]); + m_new_frame_k_idx[i] = read_bits(m_coeff->kbits[i]); printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]); LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, " "); update_fifo_status_and_ints(); @@ -1542,9 +1653,9 @@ void tms5220_device::parse_frame() LOGMASKED(LOG_PARSE_FRAME_DUMP_BIN | LOG_PARSE_FRAME_DUMP_HEX, "\n"); if (m_DDIS) - LOGMASKED(LOG_GENERAL, "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 - LOGMASKED(LOG_GENERAL, "Parsed a frame successfully in ROM\n"); + LOGMASKED(LOG_PARSE, "Parsed a frame successfully in ROM\n"); return; ranout: @@ -1564,9 +1675,11 @@ void tms5220_device::set_interrupt_state(int state) LOGMASKED(LOG_PIN_READS, "irq pin set to state %d\n", state); - if (!m_irq_handler.isnull() && state != m_irq_pin) + if (state != m_irq_pin) + { + m_irq_pin = state; m_irq_handler(!state); - m_irq_pin = state; + } } /********************************************************************************************** @@ -1581,8 +1694,7 @@ void tms5220_device::update_ready_state() if (m_ready_pin != state) { LOGMASKED(LOG_PIN_READS, "ready pin set to state %d\n", state); - if (!m_readyq_handler.isnull()) - m_readyq_handler(!state); + m_readyq_handler(!state); m_ready_pin = state; } } @@ -1594,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: @@ -1639,19 +1738,10 @@ void tms5220_device::device_start() fatalerror("Unknown variant in tms5220_set_variant\n"); } - /* 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); + m_stream = stream_alloc(0, 1, clock() / 80); - m_timer_io_ready = timer_alloc(0); + m_timer_io_ready = timer_alloc(FUNC(tms5220_device::set_io_ready), this); /* not during reset which is called from within a write! */ m_io_ready = true; @@ -1680,6 +1770,9 @@ void tms5220_device::device_reset() update_ready_state(); m_buffer_empty = m_buffer_low = true; + m_command_register = NOCOMMAND; + m_data_latched = false; + m_RDB_flag = false; /* initialize the energy/pitch/k states */ @@ -1703,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; @@ -1724,68 +1807,68 @@ void tms5220_device::device_reset() m_next_is_address = false; m_addr_bit = 0; m_CTL_buffer = 0; - } -/********************************************************************************************** - - True timing - -***********************************************************************************************/ - -void tms5220_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +TIMER_CALLBACK_MEMBER(tms5220_device::set_io_ready) { - switch(id) + /* bring up to date first */ + m_stream->update(); + + LOGMASKED(LOG_IO_READY, "m_timer_io_ready timer fired, param = %02x, m_rs_ws = %02x\n", param, m_rs_ws); + if (param) // low->high ready state { - case 0: // m_timer_io_ready - /* bring up to date first */ - m_stream->update(); - LOGMASKED(LOG_IO_READY, "m_timer_io_ready timer fired, param = %02x, m_rs_ws = %02x\n", param, m_rs_ws); - if (param) // low->high ready state + switch (m_rs_ws) { - switch (m_rs_ws) + case 0x02: + /* Write */ + LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Attempting to service write...\n"); + if ((m_fifo_count >= FIFO_SIZE) && m_DDIS) // if FIFO is full and we're in speak external mode { - case 0x02: - /* Write */ - LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Attempting to service write...\n"); - if ((m_fifo_count >= FIFO_SIZE) && m_DDIS) // if FIFO is full and we're in speak external mode + LOGMASKED(LOG_IO_READY, "m_timer_io_ready: in SPKEXT and FIFO was full! cannot service write now, delaying 16 cycles...\n"); + m_timer_io_ready->adjust(clocks_to_attotime(16), 1); + break; + } + else + { + if (m_command_register != NOCOMMAND) { - LOGMASKED(LOG_IO_READY, "m_timer_io_ready: in SPKEXT and FIFO was full! cannot service write now, delaying 16 cycles...\n"); - m_timer_io_ready->adjust(clocks_to_attotime(16), 1); - break; + // The command register is still busy; do not activate /READY + // and keep the data latch + LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Command register not ready\n"); } else { - LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced write: %02x\n", m_write_latch); + LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced write: %02X\n", m_write_latch); + m_data_latched = false; data_write(m_write_latch); - m_io_ready = param; - break; } - case 0x01: - /* Read */ - m_read_latch = status_read(true); - LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced read, returning %02x\n", m_read_latch); - m_io_ready = param; - break; - case 0x03: - /* High Impedance */ - m_io_ready = param; - case 0x00: - /* illegal */ - m_io_ready = param; + break; } + case 0x01: + /* Read */ + m_read_latch = status_read(true); + LOGMASKED(LOG_IO_READY, "m_timer_io_ready: Serviced read, returning %02X\n", m_read_latch); + m_io_ready = true; + break; + case 0x03: + /* High Impedance */ + m_io_ready = true; + break; + case 0x00: + /* illegal */ + m_io_ready = true; + break; } - - update_ready_state(); - break; } + + update_ready_state(); } /* * /RS line write handler */ -WRITE_LINE_MEMBER( tms5220_device::rsq_w ) +void tms5220_device::rsq_w(int state) { m_true_timing = true; state &= 0x01; @@ -1832,7 +1915,7 @@ WRITE_LINE_MEMBER( tms5220_device::rsq_w ) /* * /WS line write handler */ -WRITE_LINE_MEMBER( tms5220_device::wsq_w ) +void tms5220_device::wsq_w(int state) { m_true_timing = true; state &= 0x01; @@ -1851,7 +1934,7 @@ WRITE_LINE_MEMBER( tms5220_device::wsq_w ) LOGMASKED(LOG_RS_WS, "tms5220_wsq_w: illegal\n"); return; } - else if ( new_val == 3) + else if (new_val == 3) { /* high impedance */ m_read_latch = 0xff; @@ -1965,10 +2048,12 @@ void tms5220_device::combined_rsq_wsq_w(u8 data) void tms5220_device::data_w(uint8_t data) { - LOGMASKED(LOG_RS_WS, "tms5220_write_data: data %02x\n", data); + LOGMASKED(LOG_DATA_W, "tms5220_write_data: data %02X\n", data); /* bring up to date first */ m_stream->update(); m_write_latch = data; + m_data_latched = true; + if (!m_true_timing) // if we're in the default hacky mode where we don't bother with rsq_w and wsq_w... data_write(m_write_latch); // ...force the write through instantly. else @@ -2019,7 +2104,7 @@ uint8_t tms5220_device::status_r() ***********************************************************************************************/ -READ_LINE_MEMBER( tms5220_device::readyq_r ) +int tms5220_device::readyq_r() { // prevent debugger from changing the internal state if (!machine().side_effects_disabled()) @@ -2035,7 +2120,7 @@ READ_LINE_MEMBER( tms5220_device::readyq_r ) ***********************************************************************************************/ -READ_LINE_MEMBER( tms5220_device::intq_r ) +int tms5220_device::intq_r() { // prevent debugger from changing the internal state if (!machine().side_effects_disabled()) @@ -2055,24 +2140,19 @@ READ_LINE_MEMBER( tms5220_device::intq_r ) // 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) +void tms5220_device::sound_stream_update(sound_stream &stream) { int16_t sample_data[MAX_SAMPLE_CHUNK]; - stream_sample_t *buffer = outputs[0]; /* loop while we still have samples to generate */ - while (samples) + for (int sampindex = 0; sampindex < stream.samples(); ) { - int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; - int index; + int length = (stream.samples() > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : stream.samples(); /* 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; + for (int index = 0; index < length; index++) + stream.put_int(0, sampindex++, sample_data[index], 32768); } } @@ -2114,11 +2194,10 @@ 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) - , m_data_cb(*this) + , m_data_cb(*this, 0) , m_romclk_cb(*this) { } |