src/emu/sound/tms5220.c
| r15499 | r15500 | |
| 332 | 332 | // above debugs the tms5220_data_r and data_w access methods which actually respect rs and ws |
| 333 | 333 | |
| 334 | 334 | #define MAX_SAMPLE_CHUNK 512 |
| 335 | | #define FIFO_SIZE 16 |
| 336 | 335 | |
| 337 | 336 | /* Variants */ |
| 338 | 337 | |
| r15499 | r15500 | |
| 2039 | 2038 | DEFINE_LEGACY_SOUND_DEVICE(TMS5220, tms5220); |
| 2040 | 2039 | DEFINE_LEGACY_SOUND_DEVICE(TMC0285, tmc0285); |
| 2041 | 2040 | DEFINE_LEGACY_SOUND_DEVICE(TMS5200, tms5200); |
| 2041 | |
| 2042 | |
| 2043 | /****************************************************************************** |
| 2044 | New class implementation |
| 2045 | ******************************************************************************/ |
| 2046 | |
| 2047 | #define M_INTERP_SHIFT >> m_coeff->interp_coeff[m_interp_period] |
| 2048 | |
| 2049 | tms52xx_device::tms52xx_device(const machine_config &mconfig, device_type type, const char *name, const char *tag, const struct tms5100_coeffs* coeffs, const int var, device_t *owner, UINT32 clock) |
| 2050 | : device_t(mconfig, type, name, tag, owner, clock), |
| 2051 | device_sound_interface(mconfig, *this), |
| 2052 | m_variant(var), |
| 2053 | m_coeff(coeffs) |
| 2054 | { |
| 2055 | } |
| 2056 | |
| 2057 | |
| 2058 | tms5220n_device::tms5220n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 2059 | : tms52xx_device(mconfig, TMS5220N, "TMS5220N", tag, &tms5220_coeff, TMS5220_IS_5220, owner, clock) |
| 2060 | { |
| 2061 | } |
| 2062 | |
| 2063 | tms5220cn_device::tms5220cn_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 2064 | : tms52xx_device(mconfig, TMS5220CN, "TMS5220CN", tag, &tms5220c_coeff, TMS5220_IS_5220C, owner, clock) |
| 2065 | { |
| 2066 | } |
| 2067 | |
| 2068 | tmc0285n_device::tmc0285n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 2069 | : tms52xx_device(mconfig, TMC0285N, "TMC0285N", tag, &tms5200_coeff, TMS5220_IS_TMC0285, owner, clock) |
| 2070 | { |
| 2071 | } |
| 2072 | |
| 2073 | tms5200n_device::tms5200n_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) |
| 2074 | : tms52xx_device(mconfig, TMS5200N, "TMS5200N", tag, &tms5200_coeff, TMS5220_IS_5200, owner, clock) |
| 2075 | { |
| 2076 | } |
| 2077 | |
| 2078 | void tms52xx_device::device_start() |
| 2079 | { |
| 2080 | const tms52xx_config *conf = reinterpret_cast<const tms52xx_config *>(static_config()); |
| 2081 | //m_table = region(); |
| 2082 | |
| 2083 | /* resolve irq and readyq line */ |
| 2084 | m_irq_func.resolve(conf->irq_func, *this); |
| 2085 | m_readyq_func.resolve(conf->readyq_func, *this); |
| 2086 | m_read_mem.resolve(conf->read_mem, *this); |
| 2087 | m_load_address.resolve(conf->load_address, *this); |
| 2088 | m_read_and_branch.resolve(conf->read_and_branch, *this); |
| 2089 | |
| 2090 | /* initialize a stream */ |
| 2091 | m_stream = machine().sound().stream_alloc(*this, 0, 1, clock() / 80, this); |
| 2092 | |
| 2093 | /*if (m_table == NULL) |
| 2094 | { |
| 2095 | assert_always(m_conf->M0_callback != NULL, "Missing _mandatory_ 'M0_callback' function pointer in the TMS5110 interface\n This function is used by TMS5220 to call for a new single bit\n needed to generate the speech when in VSM mode\n Aborting startup...\n"); |
| 2096 | m_M0_callback = conf->M0_callback; |
| 2097 | m_set_load_address = conf->load_address; |
| 2098 | } |
| 2099 | else |
| 2100 | { |
| 2101 | m_M0_callback = speech_rom_read_bit; |
| 2102 | m_set_load_address = speech_rom_set_addr; |
| 2103 | }*/ |
| 2104 | |
| 2105 | /* not during reset which is called frm within a write! */ |
| 2106 | m_io_ready = true; |
| 2107 | m_true_timing = false; |
| 2108 | m_rs_ws = 0x03; // rs and ws are assumed to be inactive on device startup |
| 2109 | |
| 2110 | m_ready_timer = timer_alloc(0); |
| 2111 | |
| 2112 | register_for_save_states(); |
| 2113 | } |
| 2114 | |
| 2115 | void tms52xx_device::device_reset() |
| 2116 | { |
| 2117 | m_digital_select = FORCE_DIGITAL; // assume analog output |
| 2118 | // initialize the FIFO */ |
| 2119 | // memset(tms->fifo, 0, sizeof(tms->fifo)); |
| 2120 | m_fifo_head = 0; |
| 2121 | m_fifo_tail = 0; |
| 2122 | m_fifo_count = 0; |
| 2123 | m_fifo_bits_taken = 0; |
| 2124 | |
| 2125 | // initialize the chip state |
| 2126 | // Note that we do not actually clear IRQ on start-up: IRQ is even raised |
| 2127 | // if m_buffer_empty or m_buffer_low are 0 |
| 2128 | m_speaking_now = false; |
| 2129 | m_speak_external = false; |
| 2130 | m_talk_status = false; |
| 2131 | m_irq_pin = 0; // CLEAR_LINE |
| 2132 | m_ready_pin = 0; // CLEAR_LINE |
| 2133 | |
| 2134 | set_interrupt_state(0); // CLEAR_LINE |
| 2135 | update_ready_state(); |
| 2136 | m_buffer_empty = true; |
| 2137 | m_buffer_low = true; |
| 2138 | |
| 2139 | m_RDB_flag = false; |
| 2140 | |
| 2141 | /* initialize the energy/pitch/k states */ |
| 2142 | #ifdef PERFECT_INTERPOLATION_HACK |
| 2143 | m_old_frame_energy_idx = 0; |
| 2144 | m_old_frame_pitch_idx = 0; |
| 2145 | memset(m_old_frame_k_idx, 0, sizeof(m_old_frame_k_idx)); |
| 2146 | #endif |
| 2147 | |
| 2148 | m_new_frame_energy_idx = 0; |
| 2149 | m_current_energy = 0; |
| 2150 | m_target_energy = 0; |
| 2151 | m_new_frame_pitch_idx = 0; |
| 2152 | m_current_pitch = 0; |
| 2153 | m_target_pitch = 0; |
| 2154 | |
| 2155 | memset(m_new_frame_k_idx, 0, sizeof(m_new_frame_k_idx)); |
| 2156 | memset(m_current_k, 0, sizeof(m_current_k)); |
| 2157 | memset(m_target_k, 0, sizeof(m_target_k)); |
| 2158 | |
| 2159 | /* initialize the sample generators */ |
| 2160 | m_inhibit = true; |
| 2161 | m_subcycle = 0; |
| 2162 | m_tms5220c_rate = 0; |
| 2163 | m_pitch_count = 0; |
| 2164 | m_PC = 0; |
| 2165 | |
| 2166 | m_subc_reload = FORCE_SUBC_RELOAD; |
| 2167 | m_OLDE = 1; |
| 2168 | m_OLDP = 1; |
| 2169 | |
| 2170 | m_interp_period = reload_table[m_tms5220c_rate&0x3]; |
| 2171 | m_RNG = 0x1FFF; |
| 2172 | memset(m_u, 0, sizeof(m_u)); |
| 2173 | memset(m_x, 0, sizeof(m_x)); |
| 2174 | |
| 2175 | m_load_address(0, 0); |
| 2176 | m_schedule_dummy_read = true; |
| 2177 | } |
| 2178 | |
| 2179 | /****************************************************************************** |
| 2180 | set_interrupt_state -- generate an interrupt |
| 2181 | *******************************************************************************/ |
| 2182 | |
| 2183 | void tms52xx_device::set_interrupt_state(int state) |
| 2184 | { |
| 2185 | #ifdef DEBUG_PIN_READS |
| 2186 | logerror("tms52xx: irq pin set to state %d\n", state); |
| 2187 | #endif |
| 2188 | if (state != m_irq_pin) m_irq_func(!state); |
| 2189 | m_irq_pin = state; |
| 2190 | } |
| 2191 | |
| 2192 | /****************************************************************************** |
| 2193 | update_ready_state -- update the ready line |
| 2194 | *******************************************************************************/ |
| 2195 | |
| 2196 | void tms52xx_device::update_ready_state() |
| 2197 | { |
| 2198 | int state = ready_read(); |
| 2199 | #ifdef DEBUG_PIN_READS |
| 2200 | logerror("tms52xx: ready pin set to state %d\n", state); |
| 2201 | #endif |
| 2202 | if (state != m_ready_pin) m_readyq_func(!state); |
| 2203 | m_ready_pin = state; |
| 2204 | } |
| 2205 | |
| 2206 | /****************************************************************************** |
| 2207 | tms5220_set_frequency -- adjusts the playback frequency |
| 2208 | *******************************************************************************/ |
| 2209 | |
| 2210 | void tms52xx_device::set_frequency(int frequency) |
| 2211 | { |
| 2212 | m_stream->set_sample_rate(frequency / 80); |
| 2213 | m_clock = frequency; |
| 2214 | } |
| 2215 | |
| 2216 | /****************************************************************************** |
| 2217 | tms5220_update -- update the sound chip so that it is in sync with CPU execution |
| 2218 | *******************************************************************************/ |
| 2219 | |
| 2220 | void tms52xx_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) |
| 2221 | { |
| 2222 | INT16 sample_data[MAX_SAMPLE_CHUNK]; |
| 2223 | stream_sample_t *buffer = outputs[0]; |
| 2224 | |
| 2225 | /* loop while we still have samples to generate */ |
| 2226 | while (samples>0) |
| 2227 | { |
| 2228 | int length = (samples > MAX_SAMPLE_CHUNK) ? MAX_SAMPLE_CHUNK : samples; |
| 2229 | int index; |
| 2230 | |
| 2231 | /* generate the samples and copy to the target buffer */ |
| 2232 | process(sample_data, length); |
| 2233 | for (index = 0; index < length; index++) |
| 2234 | *buffer++ = sample_data[index]; |
| 2235 | |
| 2236 | /* account for the samples */ |
| 2237 | samples -= length; |
| 2238 | } |
| 2239 | } |
| 2240 | |
| 2241 | /****************************************************************************** |
| 2242 | process -- fill the buffer with a specific number of samples |
| 2243 | *******************************************************************************/ |
| 2244 | |
| 2245 | void tms52xx_device::process(INT16 *buffer, unsigned int size) |
| 2246 | { |
| 2247 | int buf_count=0; |
| 2248 | int i, bitout; |
| 2249 | bool zpar; |
| 2250 | INT32 this_sample; |
| 2251 | |
| 2252 | // The following gotos are probably safe to remove |
| 2253 | // if we're empty and still not speaking, fill with nothingness |
| 2254 | if (!m_speaking_now) goto empty; |
| 2255 | |
| 2256 | // if speak external is set, but talk status is not (yet) set, |
| 2257 | // wait for buffer low to clear |
| 2258 | if (!m_talk_status && m_speak_external && m_buffer_low) goto empty; |
| 2259 | |
| 2260 | // loop until the buffer is full or we've stopped speaking |
| 2261 | while ((size > 0) && m_speaking_now) |
| 2262 | { |
| 2263 | // if it is the appropriate time to update the old energy/pitch idxes, |
| 2264 | // i.e. when IP=7, PC=12, T=17, subcycle=2, do so. Since IP=7 PC=12 T=17 |
| 2265 | // is JUST BEFORE the transition to IP=0 PC=0 T=0 sybcycle=(0 or 1), |
| 2266 | // which happens 4 T-cycles later), we change on the latter. |
| 2267 | if ((m_interp_period == 0) && (m_PC == 0) && (m_subcycle < 2)) |
| 2268 | { |
| 2269 | m_OLDE = (m_new_frame_energy_idx == 0); |
| 2270 | m_OLDP = (m_new_frame_pitch_idx == 0); |
| 2271 | } |
| 2272 | |
| 2273 | //if we're ready for a new frame to be applied, i.e. when IP=0, PC=12, Sub=1 |
| 2274 | // (In reality, the frame was really loaded incrementally during the |
| 2275 | // entire IP=0 PC=x time period, but it doesn't affect anything until IP=0 PC=12 happens) |
| 2276 | if ((m_interp_period == 0) && (m_PC == 12) && (m_subcycle == 1)) |
| 2277 | { |
| 2278 | // HACK for regression testing, be sure to comment out before release! |
| 2279 | // m_RNG = 0x1234; |
| 2280 | // end HACK |
| 2281 | |
| 2282 | // appropriately override the interp count if needed; this will be incremented after the frame parse! |
| 2283 | m_interp_period = reload_table[m_tms5220c_rate & 0x3]; |
| 2284 | |
| 2285 | #ifdef PERFECT_INTERPOLATION_HACK |
| 2286 | // remember previous frame energy, pitch, and coefficients |
| 2287 | m_old_frame_energy_idx = m_new_frame_energy_idx; |
| 2288 | m_old_frame_pitch_idx = m_new_frame_pitch_idx; |
| 2289 | for (i = 0; i < m_coeff->num_k; i++) |
| 2290 | m_old_frame_k_idx[i] = m_new_frame_k_idx[i]; |
| 2291 | #endif |
| 2292 | |
| 2293 | // if the talk status was clear last frame, halt speech now. |
| 2294 | if (m_talk_status == false) |
| 2295 | { |
| 2296 | #ifdef DEBUG_GENERATION |
| 2297 | fprintf(stderr,"tms5220_process: processing frame: talk status = 0 caused by stop frame or buffer empty, halting speech.\n"); |
| 2298 | #endif |
| 2299 | m_speaking_now = false; // finally halt speech |
| 2300 | goto empty; |
| 2301 | } |
| 2302 | |
| 2303 | // Parse a new frame into the new_target_energy, new_target_pitch and new_target_k[] |
| 2304 | parse_frame(); |
| 2305 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2306 | fprintf(stderr,"\n"); |
| 2307 | #endif |
| 2308 | // if the new frame is a stop frame, set an interrupt and set talk status to 0 |
| 2309 | if (M_NEW_FRAME_STOP_FLAG == 1) |
| 2310 | { |
| 2311 | m_talk_status = false; |
| 2312 | m_speak_external = false; |
| 2313 | set_interrupt_state(1); |
| 2314 | update_status_and_ints(); |
| 2315 | } |
| 2316 | |
| 2317 | // in all cases where interpolation would be inhibited, set the inhibit flag; otherwise clear it. |
| 2318 | // Interpolation inhibit cases: |
| 2319 | // * Old frame was voiced, new is unvoiced |
| 2320 | // * Old frame was silence/zero energy, new has nonzero energy |
| 2321 | // * Old frame was unvoiced, new is voiced |
| 2322 | |
| 2323 | if ( ((M_OLD_FRAME_UNVOICED_FLAG == false) && (M_NEW_FRAME_UNVOICED_FLAG == true)) |
| 2324 | || ((M_OLD_FRAME_UNVOICED_FLAG == true) && (M_NEW_FRAME_UNVOICED_FLAG == false)) |
| 2325 | || ((M_OLD_FRAME_SILENCE_FLAG == true) && (M_NEW_FRAME_SILENCE_FLAG == false)) ) |
| 2326 | m_inhibit = true; |
| 2327 | else // normal frame, normal interpolation |
| 2328 | m_inhibit = false; |
| 2329 | |
| 2330 | // load new frame targets from tables, using parsed indices |
| 2331 | m_target_energy = m_coeff->energytable[m_new_frame_energy_idx]; |
| 2332 | m_target_pitch = m_coeff->pitchtable[m_new_frame_pitch_idx]; |
| 2333 | zpar = M_NEW_FRAME_UNVOICED_FLAG; // find out if parameters k5-k10 should be zeroed |
| 2334 | for (i = 0; i < 4; i++) |
| 2335 | m_target_k[i] = m_coeff->ktable[i][m_new_frame_k_idx[i]]; |
| 2336 | for (i = 4; i < m_coeff->num_k; i++) |
| 2337 | m_target_k[i] = (m_coeff->ktable[i][m_new_frame_k_idx[i]] * (1-zpar)); |
| 2338 | |
| 2339 | #ifdef DEBUG_GENERATION |
| 2340 | /* Debug info for current parsed frame */ |
| 2341 | fprintf(stderr, "OLDE: %d; OLDP: %d; ", m_OLDE, m_OLDP); |
| 2342 | fprintf(stderr,"Processing frame: "); |
| 2343 | if (m_inhibit == 0) |
| 2344 | fprintf(stderr, "Normal Frame\n"); |
| 2345 | else |
| 2346 | fprintf(stderr,"Interpolation Inhibited\n"); |
| 2347 | fprintf(stderr,"*** current Energy, Pitch and Ks = %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", |
| 2348 | m_current_energy, m_current_pitch, |
| 2349 | m_current_k[0], m_current_k[1], m_current_k[2], m_current_k[3], |
| 2350 | m_current_k[4], m_current_k[5], m_current_k[6], m_current_k[7], |
| 2351 | m_current_k[8], m_current_k[9]); |
| 2352 | fprintf(stderr,"*** target Energy(idx), Pitch, and Ks = %04d(%x),%04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d, %04d\n", |
| 2353 | m_target_energy, m_new_frame_energy_idx, m_target_pitch, |
| 2354 | m_target_k[0], m_target_k[1], m_target_k[2], m_target_k[3], |
| 2355 | m_target_k[4], m_target_k[5], m_target_k[6], m_target_k[7], |
| 2356 | m_target_k[8], m_target_k[9]); |
| 2357 | #endif |
| 2358 | |
| 2359 | /* if TS is now 0, ramp the energy down to 0. Is this really correct to hardware? */ |
| 2360 | if (!m_talk_status) |
| 2361 | { |
| 2362 | #ifdef DEBUG_GENERATION |
| 2363 | fprintf(stderr,"Talk status is 0, forcing target energy to 0\n"); |
| 2364 | #endif |
| 2365 | m_target_energy = 0; |
| 2366 | } |
| 2367 | } |
| 2368 | else // Not a new frame, just interpolate the existing frame. |
| 2369 | { |
| 2370 | bool inhibit_state = (m_inhibit && (m_interp_period != 0)); // disable inhibit when reaching the last interp period, but don't overwrite the tms->inhibit value |
| 2371 | #ifdef PERFECT_INTERPOLATION_HACK |
| 2372 | int samples_per_frame = (m_subc_reload!=0)? 175:266; // either (13 A cycles + 12 B cycles) * 7 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 7 interps for SPKSLOW |
| 2373 | //int samples_per_frame = (m_subc_reload!=0)?200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW |
| 2374 | int current_sample = (tms->subcycle - tms->subc_reload)+(tms->PC*(3-tms->subc_reload))+((tms->subc_reload?25:38)*((tms->interp_period-1)&7)); |
| 2375 | |
| 2376 | zpar = M_OLD_FRAME_UNVOICED_FLAG; |
| 2377 | //fprintf(stderr, "CS: %03d", current_sample); |
| 2378 | // reset the current energy, pitch, etc to what it was at frame start |
| 2379 | m_current_energy = m_coeff->energytable[m_old_frame_energy_idx]; |
| 2380 | m_current_pitch = m_coeff->pitchtable[m_old_frame_pitch_idx]; |
| 2381 | for (i = 0; i < 4; i++) |
| 2382 | m_current_k[i] = m_coeff->ktable[i][m_old_frame_k_idx[i]]; |
| 2383 | for (i = 4; i < m_coeff->num_k; i++) |
| 2384 | m_current_k[i] = (m_coeff->ktable[i][m_old_frame_k_idx[i]] * (1-zpar)); |
| 2385 | // now adjust each value to be exactly correct for each of the samples per frame |
| 2386 | if (m_interp_period != 0) // if we're still interpolating... |
| 2387 | { |
| 2388 | if (!inhibit_state) |
| 2389 | { |
| 2390 | m_current_energy += ((m_target_energy - m_current_energy)*current_sample)/samples_per_frame; |
| 2391 | m_current_pitch += ((m_target_pitch - m_current_pitch)*current_sample)/samples_per_frame; |
| 2392 | for (i = 0; i < m_coeff->num_k; i++) |
| 2393 | { |
| 2394 | m_current_k[i] += ((m_target_k[i] - m_current_k[i])*current_sample)/samples_per_frame; |
| 2395 | } |
| 2396 | } |
| 2397 | } |
| 2398 | else // we're done, play this frame for 1/8 frame. |
| 2399 | { |
| 2400 | m_current_energy = m_target_energy; |
| 2401 | m_current_pitch = m_target_pitch; |
| 2402 | for (i = 0; i < m_coeff->num_k; i++) |
| 2403 | m_current_k[i] = m_target_k[i]; |
| 2404 | } |
| 2405 | #else |
| 2406 | // Updates to parameters only happen on subcycle '2' (B cycle) of PCs. |
| 2407 | if (m_subcycle == 2) |
| 2408 | { |
| 2409 | if (!inhibit_state) |
| 2410 | { |
| 2411 | switch(m_PC) |
| 2412 | { |
| 2413 | case 0: // PC = 0, B cycle, write updated energy |
| 2414 | m_current_energy += ((m_target_energy - m_current_energy) M_INTERP_SHIFT); |
| 2415 | break; |
| 2416 | case 1: /* PC = 1, B cycle, write updated pitch */ |
| 2417 | m_current_pitch += ((m_target_pitch - m_current_pitch) M_INTERP_SHIFT); |
| 2418 | break; |
| 2419 | case 2: case 3: case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: |
| 2420 | /* PC = 2 through 11, B cycle, write updated K1 through K10 */ |
| 2421 | m_current_k[m_PC-2] += ((m_target_k[m_PC-2] - m_current_k[m_PC-2]) M_INTERP_SHIFT); |
| 2422 | break; |
| 2423 | case 12: /* PC = 12, do nothing */ |
| 2424 | break; |
| 2425 | } |
| 2426 | } |
| 2427 | } |
| 2428 | #endif |
| 2429 | } |
| 2430 | |
| 2431 | // calculate the output |
| 2432 | if (M_OLD_FRAME_UNVOICED_FLAG == true) |
| 2433 | { |
| 2434 | // generate unvoiced samples here |
| 2435 | #ifndef UNVOICED_HACK |
| 2436 | if (m_RNG & 1) |
| 2437 | m_excitation_data = ~0x3F; // according to the patent it is (either + or -) half of the maximum value in the chirp table, so either 01000000(0x40) or 11000000(0xC0) |
| 2438 | else |
| 2439 | m_excitation_data = 0x40; |
| 2440 | #else // hack to double unvoiced strength, doesn't match patent |
| 2441 | if (m_RNG & 1) |
| 2442 | m_excitation_data = ~0x7F; |
| 2443 | else |
| 2444 | m_excitation_data = 0x80; |
| 2445 | #endif |
| 2446 | } |
| 2447 | else // (M_OLD_FRAME_UNVOICED_FLAG == false) |
| 2448 | { |
| 2449 | // generate voiced samples here |
| 2450 | // US patent 4331836 Figure 14B shows, and logic would hold, that a pitch based chirp |
| 2451 | // function has a chirp/peak and then a long chain of zeroes. |
| 2452 | // The last entry of the chirp rom is at address 0b110011 (51d), the 52nd sample, |
| 2453 | // and if the address reaches that point the ADDRESS incrementer is |
| 2454 | // disabled, forcing all samples beyond 51d to be == 51d |
| 2455 | // (address 51d holds zeroes, which may or may not be inverted to -1) |
| 2456 | |
| 2457 | if (m_pitch_count >= 51) |
| 2458 | m_excitation_data = m_coeff->chirptable[51]; |
| 2459 | else // tms->pitch_count < 51 |
| 2460 | m_excitation_data = m_coeff->chirptable[m_pitch_count]; |
| 2461 | #ifdef VOICED_INV_HACK |
| 2462 | // invert waveform |
| 2463 | if (m_pitch_count >= 51) |
| 2464 | m_excitation_data = ~m_coeff->chirptable[51]; |
| 2465 | else // tms->pitch_count < 51 |
| 2466 | m_excitation_data = ~m_coeff->chirptable[m_pitch_count]; |
| 2467 | #endif |
| 2468 | #ifdef VOICED_ZERO_HACK |
| 2469 | // 0 and >=51 are -128, as implied by qboxpro tables |
| 2470 | if ((m_pitch_count == 0) | (m_pitch_count >= 51)) |
| 2471 | m_excitation_data = -128; |
| 2472 | else /*tms->pitch_count < 51 && > 0*/ |
| 2473 | m_excitation_data = m_coeff->chirptable[m_pitch_count]; |
| 2474 | #endif |
| 2475 | #ifdef VOICED_PULSE_HACK |
| 2476 | // if pitch is between 1 and PWIDTH+1, out = PAMP, if between PWIDTH+1 and (2*PWIDTH)+1, out ~PAMP, else out = 0 |
| 2477 | if (m_pitch_count == 0) |
| 2478 | m_excitation_data = 0; |
| 2479 | else if (m_pitch_count < PWIDTH+1) |
| 2480 | m_excitation_data = PAMP; |
| 2481 | else if (m_pitch_count < (PWIDTH*2)+1) |
| 2482 | m_excitation_data = ~PAMP; |
| 2483 | else |
| 2484 | m_excitation_data = 0; |
| 2485 | #endif |
| 2486 | #ifdef VOICED_PULSE_MONOPOLAR_HACK |
| 2487 | // if pitch is between 1 and PWIDTH+1, out = PAMP, else out = 0 |
| 2488 | if (m_pitch_count == 0) |
| 2489 | m_excitation_data = 0; |
| 2490 | else if (m_pitch_count < PWIDTH+1) |
| 2491 | m_excitation_data = PAMP; |
| 2492 | else |
| 2493 | m_excitation_data = 0; |
| 2494 | #endif |
| 2495 | } |
| 2496 | |
| 2497 | // Update LFSR *20* times every sample (once per T cycle), like patent shows |
| 2498 | for (i=0; i<20; i++) |
| 2499 | { |
| 2500 | bitout = ((m_RNG >> 12) & 1) ^ |
| 2501 | ((m_RNG >> 3) & 1) ^ |
| 2502 | ((m_RNG >> 2) & 1) ^ |
| 2503 | ((m_RNG >> 0) & 1); |
| 2504 | m_RNG <<= 1; |
| 2505 | m_RNG |= bitout; |
| 2506 | } |
| 2507 | |
| 2508 | this_sample = lattice_filter(); // execute lattice filter |
| 2509 | #ifdef DEBUG_GENERATION_VERBOSE |
| 2510 | //fprintf(stderr,"C:%01d; ",tms->subcycle); |
| 2511 | fprintf(stderr,"IP:%01d PC:%02d X:%04d E:%03d P:%03d Pc:%03d ",m_interp_period, m_PC, |
| 2512 | m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 2513 | //fprintf(stderr,"X:%04d E:%03d P:%03d Pc:%03d ", m_excitation_data, m_current_energy, m_current_pitch, m_pitch_count); |
| 2514 | for (i=0; i<10; i++) |
| 2515 | fprintf(stderr,"K%d:%04d ", i+1, m_current_k[i]); |
| 2516 | fprintf(stderr,"Out:%06d", this_sample); |
| 2517 | fprintf(stderr,"\n"); |
| 2518 | #endif |
| 2519 | // next, force result to 14 bits (since its possible that the addition at the final (k1) stage of the lattice overflowed) |
| 2520 | while (this_sample > 16383) this_sample -= 32768; |
| 2521 | while (this_sample < -16384) this_sample += 32768; |
| 2522 | if (!m_digital_select) // analog SPK pin output is only 8 bits, with clipping |
| 2523 | buffer[buf_count] = clip_analog(this_sample); |
| 2524 | else // digital I/O pin output is 12 bits |
| 2525 | { |
| 2526 | #ifdef ALLOW_4_LSB |
| 2527 | // input: ssss ssss ssss ssss ssnn nnnn nnnn nnnn |
| 2528 | // N taps: ^ = 0x2000; |
| 2529 | // output: ssss ssss ssss ssss snnn nnnn nnnn nnnN |
| 2530 | buffer[buf_count] = (this_sample<<1)|((this_sample&0x2000)>>13); |
| 2531 | #else |
| 2532 | this_sample &= ~0xF; |
| 2533 | // input: ssss ssss ssss ssss ssnn nnnn nnnn 0000 |
| 2534 | // N taps: ^^ ^^^ = 0x3E00; |
| 2535 | // output: ssss ssss ssss ssss snnn nnnn nnnN NNNN |
| 2536 | buffer[buf_count] = (this_sample<<1)|((this_sample&0x3E00)>>9); |
| 2537 | #endif |
| 2538 | } |
| 2539 | |
| 2540 | // Update all counts |
| 2541 | m_subcycle++; |
| 2542 | if ((m_subcycle == 2) && (m_PC == 12)) |
| 2543 | { |
| 2544 | m_subcycle = m_subc_reload; |
| 2545 | m_PC = 0; |
| 2546 | m_interp_period++; |
| 2547 | m_interp_period &= 0x7; |
| 2548 | } |
| 2549 | else if (m_subcycle == 3) |
| 2550 | { |
| 2551 | m_subcycle = m_subc_reload; |
| 2552 | m_PC++; |
| 2553 | } |
| 2554 | // Circuit 412 in the patent ensures that when INHIBIT is true, |
| 2555 | // during the period from IP=7 PC=12 T12, to IP=0 PC=12 T12, the pitch |
| 2556 | // count is forced to 0; since the initial stop happens right before |
| 2557 | // the switch to IP=0 PC=0 and this code is located after the switch would |
| 2558 | // happen, we check for ip=0 inhibit=1, which covers that whole range. |
| 2559 | // The purpose of Circuit 412 is to prevent a spurious click caused by |
| 2560 | // the voiced source being fed to the filter before all the values have |
| 2561 | // been updated during ip=0 when interpolation was inhibited. |
| 2562 | |
| 2563 | m_pitch_count++; |
| 2564 | if (m_pitch_count >= m_current_pitch) m_pitch_count = 0; |
| 2565 | if ((m_interp_period == 0) && m_inhibit) m_pitch_count = 0; |
| 2566 | m_pitch_count &= 0x1FF; |
| 2567 | buf_count++; |
| 2568 | size--; |
| 2569 | } |
| 2570 | |
| 2571 | empty: |
| 2572 | |
| 2573 | while (size > 0) |
| 2574 | { |
| 2575 | m_subcycle++; |
| 2576 | if ((m_subcycle == 2) && (m_PC == 12)) |
| 2577 | { |
| 2578 | m_subcycle = m_subc_reload; |
| 2579 | m_PC = 0; |
| 2580 | m_interp_period++; |
| 2581 | m_interp_period &= 0x7; |
| 2582 | } |
| 2583 | else if (m_subcycle == 3) |
| 2584 | { |
| 2585 | m_subcycle = m_subc_reload; |
| 2586 | m_PC++; |
| 2587 | } |
| 2588 | buffer[buf_count] = -1; // should be just -1; actual chip outputs -1 every idle sample; (cf note in data sheet, p 10, table 4) |
| 2589 | buf_count++; |
| 2590 | size--; |
| 2591 | } |
| 2592 | } |
| 2593 | |
| 2594 | /****************************************************************************** |
| 2595 | lattice_filter -- executes one 'full run' of the lattice filter on a |
| 2596 | specific byte of excitation data, and specific values of all the current k |
| 2597 | constants, and returns the resulting sample. |
| 2598 | ******************************************************************************/ |
| 2599 | |
| 2600 | INT32 tms52xx_device::lattice_filter() |
| 2601 | { |
| 2602 | // Lattice filter here */ |
| 2603 | // Aug/05/07: redone as unrolled loop, for clarity - LN |
| 2604 | // Originally Copied verbatim from table I in US patent 4,209,804, now updated |
| 2605 | // to be in same order as the actual chip does it, not that it matters. |
| 2606 | // notation equivalencies from table: |
| 2607 | // Yn(i) == m_u[n-1] |
| 2608 | // Kn = m_current_k[n-1] |
| 2609 | // bn = m_x[n-1] |
| 2610 | |
| 2611 | m_u[10] = matrix_multiply(m_previous_energy, (m_excitation_data<<6)); //Y(11) |
| 2612 | m_u[9] = m_u[10] - matrix_multiply(m_current_k[9], m_x[9]); |
| 2613 | m_u[8] = m_u[9] - matrix_multiply(m_current_k[8], m_x[8]); |
| 2614 | m_u[7] = m_u[8] - matrix_multiply(m_current_k[7], m_x[7]); |
| 2615 | m_u[6] = m_u[7] - matrix_multiply(m_current_k[6], m_x[6]); |
| 2616 | m_u[5] = m_u[6] - matrix_multiply(m_current_k[5], m_x[5]); |
| 2617 | m_u[4] = m_u[5] - matrix_multiply(m_current_k[4], m_x[4]); |
| 2618 | m_u[3] = m_u[4] - matrix_multiply(m_current_k[3], m_x[3]); |
| 2619 | m_u[2] = m_u[3] - matrix_multiply(m_current_k[2], m_x[2]); |
| 2620 | m_u[1] = m_u[2] - matrix_multiply(m_current_k[1], m_x[1]); |
| 2621 | m_u[0] = m_u[1] - matrix_multiply(m_current_k[0], m_x[0]); |
| 2622 | m_x[9] = m_x[8] + matrix_multiply(m_current_k[8], m_u[8]); |
| 2623 | m_x[8] = m_x[7] + matrix_multiply(m_current_k[7], m_u[7]); |
| 2624 | m_x[7] = m_x[6] + matrix_multiply(m_current_k[6], m_u[6]); |
| 2625 | m_x[6] = m_x[5] + matrix_multiply(m_current_k[5], m_u[5]); |
| 2626 | m_x[5] = m_x[4] + matrix_multiply(m_current_k[4], m_u[4]); |
| 2627 | m_x[4] = m_x[3] + matrix_multiply(m_current_k[3], m_u[3]); |
| 2628 | m_x[3] = m_x[2] + matrix_multiply(m_current_k[2], m_u[2]); |
| 2629 | m_x[2] = m_x[1] + matrix_multiply(m_current_k[1], m_u[1]); |
| 2630 | m_x[1] = m_x[0] + matrix_multiply(m_current_k[0], m_u[0]); |
| 2631 | m_x[0] = m_u[0]; |
| 2632 | m_previous_energy = m_current_energy; |
| 2633 | #ifdef DEBUG_LATTICE |
| 2634 | |
| 2635 | int i; |
| 2636 | fprintf(stderr,"V:%04d ", m_u[10]); |
| 2637 | for (i = 9; i >= 0; i--) |
| 2638 | { |
| 2639 | fprintf(stderr,"Y%d:%04d ", i+1, m_u[i]); |
| 2640 | fprintf(stderr,"b%d:%04d ", i+1, m_x[i]); |
| 2641 | if ((i % 5) == 0) fprintf(stderr,"\n"); |
| 2642 | } |
| 2643 | #endif |
| 2644 | return m_u[0]; |
| 2645 | } |
| 2646 | |
| 2647 | /********************************************************************************************** |
| 2648 | data_write -- handle a write to the TMS5220 |
| 2649 | ***********************************************************************************************/ |
| 2650 | |
| 2651 | void tms52xx_device::data_write(int data) |
| 2652 | { |
| 2653 | #ifdef DEBUG_DUMP_INPUT_DATA |
| 2654 | fprintf(stdout, "%c",data); |
| 2655 | #endif |
| 2656 | if (m_speak_external) // If we're in speak external mode |
| 2657 | { |
| 2658 | /* add this byte to the FIFO */ |
| 2659 | if (m_fifo_count < FIFO_SIZE) |
| 2660 | { |
| 2661 | m_fifo[m_fifo_tail] = data; |
| 2662 | m_fifo_tail = (m_fifo_tail + 1) % FIFO_SIZE; |
| 2663 | m_fifo_count++; |
| 2664 | #ifdef DEBUG_FIFO |
| 2665 | logerror("tms52xx: data_write: Added byte to FIFO (current count=%2d)\n", m_fifo_count); |
| 2666 | #endif |
| 2667 | update_status_and_ints(); |
| 2668 | if ((!m_talk_status) && (!m_buffer_low)) // we just unset buffer low with that last write, and talk status *was* zero... |
| 2669 | { |
| 2670 | int i; |
| 2671 | #ifdef DEBUG_FIFO |
| 2672 | logerror("tms52xx: data_write triggered talk status to go active!\n"); |
| 2673 | #endif |
| 2674 | // ...then we now have enough bytes to start talking; clear out |
| 2675 | // the new frame parameters (it will become old frame just before the first call to parse_frame()) |
| 2676 | // TODO: the 3 lines below (and others) are needed for victory |
| 2677 | // to not fail its selftest due to a sample ending too late, may require additional investigation |
| 2678 | m_subcycle = m_subc_reload; |
| 2679 | m_PC = 0; |
| 2680 | m_interp_period = reload_table[m_tms5220c_rate & 0x3]; // is this correct? should this be always 7 instead, so that the new frame is loaded quickly? |
| 2681 | m_new_frame_energy_idx = 0; |
| 2682 | m_new_frame_pitch_idx = 0; |
| 2683 | |
| 2684 | for (i = 0; i < 4; i++) |
| 2685 | m_new_frame_k_idx[i] = 0; |
| 2686 | for (i = 4; i < 7; i++) |
| 2687 | m_new_frame_k_idx[i] = 0xF; |
| 2688 | for (i = 7; i < m_coeff->num_k; i++) |
| 2689 | m_new_frame_k_idx[i] = 0x7; |
| 2690 | m_talk_status = m_speaking_now = true; |
| 2691 | } |
| 2692 | } |
| 2693 | else |
| 2694 | { |
| 2695 | #ifdef DEBUG_FIFO |
| 2696 | logerror("tms52xx: data_write: Ran out of room in the tms52xx FIFO! this should never happen!\n"); |
| 2697 | // at this point, /READY should remain HIGH/inactive until the fifo has at least one byte open in it. |
| 2698 | #endif |
| 2699 | } |
| 2700 | |
| 2701 | |
| 2702 | } |
| 2703 | else //(! m_speak_external) |
| 2704 | /* R Nabet : we parse commands at once. It is necessary for such commands as read. */ |
| 2705 | process_command(data); |
| 2706 | } |
| 2707 | |
| 2708 | /****************************************************************************** |
| 2709 | process_command -- extract a byte from the FIFO and interpret it as a command |
| 2710 | *******************************************************************************/ |
| 2711 | |
| 2712 | void tms52xx_device::process_command(unsigned char cmd) |
| 2713 | { |
| 2714 | #ifdef DEBUG_COMMAND_DUMP |
| 2715 | fprintf(stderr,"process_command called with parameter %02X\n",cmd); |
| 2716 | #endif |
| 2717 | // parse the command |
| 2718 | switch (cmd & 0x70) |
| 2719 | { |
| 2720 | case 0x10 : // read byte |
| 2721 | if (!m_talk_status) // TALKST must be clear for RDBY |
| 2722 | { |
| 2723 | if (m_schedule_dummy_read) |
| 2724 | { |
| 2725 | m_schedule_dummy_read = false; |
| 2726 | (void)m_read_mem(1); |
| 2727 | } |
| 2728 | m_data_register = m_read_mem(8); // read one byte from speech ROM... |
| 2729 | m_RDB_flag = true; |
| 2730 | } |
| 2731 | break; |
| 2732 | |
| 2733 | case 0x00: |
| 2734 | case 0x20: // set rate (tms5220c only), otherwise NOP |
| 2735 | if (m_variant == SUBTYPE_TMS5220C) |
| 2736 | { |
| 2737 | m_tms5220c_rate = cmd & 0x0F; |
| 2738 | } |
| 2739 | break; |
| 2740 | |
| 2741 | case 0x30: // read and branch |
| 2742 | if (!m_talk_status) // TALKST must be clear for RB |
| 2743 | { |
| 2744 | #ifdef VERBOSE |
| 2745 | logerror("tms5520: read and branch command received\n"); |
| 2746 | #endif |
| 2747 | m_RDB_flag = false; |
| 2748 | m_read_and_branch(0, 0); |
| 2749 | } |
| 2750 | break; |
| 2751 | |
| 2752 | case 0x40 : // load address |
| 2753 | if (!m_talk_status) // TALKST must be clear for LA |
| 2754 | { |
| 2755 | // tms5220 data sheet says that if we load only one 4-bit nibble, it won't work. |
| 2756 | // This code does not care about this. |
| 2757 | m_load_address(0, cmd & 0x0f); |
| 2758 | m_schedule_dummy_read = true; |
| 2759 | } |
| 2760 | break; |
| 2761 | |
| 2762 | case 0x50: // speak |
| 2763 | if (m_schedule_dummy_read) |
| 2764 | { |
| 2765 | m_schedule_dummy_read = false; |
| 2766 | (void)m_read_mem(1); |
| 2767 | } |
| 2768 | m_speaking_now = true; |
| 2769 | m_speak_external = false; |
| 2770 | m_talk_status = true; // start immediately |
| 2771 | // clear out variables before speaking |
| 2772 | // TODO: similar to the victory case described above, but for VSM speech |
| 2773 | m_subcycle = m_subc_reload; |
| 2774 | m_PC = 0; |
| 2775 | m_interp_period = reload_table[m_tms5220c_rate & 0x3]; |
| 2776 | m_new_frame_energy_idx = 0; |
| 2777 | m_new_frame_pitch_idx = 0; |
| 2778 | |
| 2779 | int i; |
| 2780 | for (i = 0; i < 4; i++) |
| 2781 | m_new_frame_k_idx[i] = 0; |
| 2782 | for (i = 4; i < 7; i++) |
| 2783 | m_new_frame_k_idx[i] = 0xF; |
| 2784 | for (i = 7; i < m_coeff->num_k; i++) |
| 2785 | m_new_frame_k_idx[i] = 0x7; |
| 2786 | break; |
| 2787 | |
| 2788 | case 0x60: // speak external |
| 2789 | if (!m_talk_status) // TALKST must be clear for SPKEXT |
| 2790 | { |
| 2791 | //SPKEXT going active activates SPKEE which clears the fifo |
| 2792 | m_fifo_head = m_fifo_tail = 0; |
| 2793 | m_fifo_count = m_fifo_bits_taken = 0; |
| 2794 | m_speak_external = true; |
| 2795 | m_RDB_flag = false; |
| 2796 | } |
| 2797 | break; |
| 2798 | |
| 2799 | case 0x70: // reset |
| 2800 | if (m_schedule_dummy_read) |
| 2801 | { |
| 2802 | m_schedule_dummy_read = false; |
| 2803 | (void)m_read_mem(1); |
| 2804 | } |
| 2805 | device_reset(); |
| 2806 | break; |
| 2807 | } |
| 2808 | |
| 2809 | // update the buffer low state |
| 2810 | update_status_and_ints(); |
| 2811 | } |
| 2812 | |
| 2813 | /****************************************************************************** |
| 2814 | parse_frame -- parse a new frame's worth of data; returns 0 if not |
| 2815 | enough bits in buffer |
| 2816 | *******************************************************************************/ |
| 2817 | |
| 2818 | void tms52xx_device::parse_frame() |
| 2819 | { |
| 2820 | int indx, i, rep_flag; |
| 2821 | |
| 2822 | // We actually don't care how many bits are left in the fifo here; the |
| 2823 | // frame subpart will be processed normally, and any bits extracted 'past |
| 2824 | // the end' of the fifo will be read as zeroes; the fifo being emptied will |
| 2825 | // set the /BE latch which will halt speech exactly as if a stop frame had |
| 2826 | // been encountered (instead of whatever partial frame was read); the same |
| 2827 | // exact circuitry is used for both on the real chip, see us patent 4335277 |
| 2828 | // sheet 16, gates 232a (decode stop frame) and 232b (decode /BE plus DDIS |
| 2829 | // (decode disable) which is active during speak external). |
| 2830 | |
| 2831 | // if the chip is a tms5220C, and the rate mode is set to that each frame (0x04 bit set) |
| 2832 | // has a 2 bit rate preceding it, grab two bits here and store them as the rate; |
| 2833 | if ((m_variant == SUBTYPE_TMS5220C) && (m_tms5220c_rate & 0x04)) |
| 2834 | { |
| 2835 | indx = extract_bits(2); |
| 2836 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2837 | printbits(indx,2); |
| 2838 | fprintf(stderr," "); |
| 2839 | #endif |
| 2840 | m_interp_period = reload_table[indx]; |
| 2841 | } |
| 2842 | else // non-5220C and 5220C in fixed rate mode |
| 2843 | m_interp_period = reload_table[m_tms5220c_rate & 0x3]; |
| 2844 | |
| 2845 | update_status_and_ints(); |
| 2846 | if (!m_talk_status) goto ranout; |
| 2847 | |
| 2848 | // attempt to extract the energy index |
| 2849 | m_new_frame_energy_idx = extract_bits(m_coeff->energy_bits); |
| 2850 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2851 | printbits(m_new_frame_energy_idx,m_coeff->energy_bits); |
| 2852 | fprintf(stderr," "); |
| 2853 | #endif |
| 2854 | update_status_and_ints(); |
| 2855 | if (!m_talk_status) goto ranout; |
| 2856 | // if the energy index is 0 or 15, we're done |
| 2857 | if ((m_new_frame_energy_idx == 0) || (m_new_frame_energy_idx == 15)) |
| 2858 | return; |
| 2859 | |
| 2860 | // attempt to extract the repeat flag |
| 2861 | rep_flag = extract_bits(1); |
| 2862 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2863 | printbits(rep_flag, 1); |
| 2864 | fprintf(stderr," "); |
| 2865 | #endif |
| 2866 | |
| 2867 | // attempt to extract the pitch |
| 2868 | m_new_frame_pitch_idx = extract_bits(m_coeff->pitch_bits); |
| 2869 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2870 | printbits(m_new_frame_pitch_idx, m_coeff->pitch_bits); |
| 2871 | fprintf(stderr," "); |
| 2872 | #endif |
| 2873 | update_status_and_ints(); |
| 2874 | if (!m_talk_status) goto ranout; |
| 2875 | // if this is a repeat frame, just do nothing, it will reuse the |
| 2876 | // old coefficients's |
| 2877 | if (rep_flag) return; |
| 2878 | |
| 2879 | // extract first 4 K coefficients |
| 2880 | for (i = 0; i < 4; i++) |
| 2881 | { |
| 2882 | m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); |
| 2883 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2884 | printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]); |
| 2885 | fprintf(stderr," "); |
| 2886 | #endif |
| 2887 | update_status_and_ints(); |
| 2888 | if (!m_talk_status) goto ranout; |
| 2889 | } |
| 2890 | |
| 2891 | // if the pitch index was zero, we only need 4 K's... |
| 2892 | if (m_new_frame_pitch_idx == 0) |
| 2893 | { |
| 2894 | // and the rest of the coefficients are zeroed, but that's done in the generator code |
| 2895 | return; |
| 2896 | } |
| 2897 | |
| 2898 | // If we got here, we need the remaining 6 K's |
| 2899 | for (i = 4; i < m_coeff->num_k; i++) |
| 2900 | { |
| 2901 | m_new_frame_k_idx[i] = extract_bits(m_coeff->kbits[i]); |
| 2902 | #ifdef DEBUG_PARSE_FRAME_DUMP |
| 2903 | printbits(m_new_frame_k_idx[i], m_coeff->kbits[i]); |
| 2904 | fprintf(stderr," "); |
| 2905 | #endif |
| 2906 | update_status_and_ints(); |
| 2907 | if (!m_talk_status) goto ranout; |
| 2908 | } |
| 2909 | #ifdef VERBOSE |
| 2910 | if (m_speak_external) |
| 2911 | logerror("tms52xx: Parsed a frame successfully in FIFO - %d bits remaining\n", (m_fifo_count*8)-(m_fifo_bits_taken)); |
| 2912 | else |
| 2913 | logerror("tms52xx: Parsed a frame successfully in ROM\n"); |
| 2914 | #endif |
| 2915 | return; |
| 2916 | |
| 2917 | ranout: |
| 2918 | #ifdef DEBUG_FRAME_ERRORS |
| 2919 | logerror("tms52xx: Ran out of bits on a parse!\n"); |
| 2920 | #endif |
| 2921 | return; |
| 2922 | } |
| 2923 | |
| 2924 | /********************************************************************************************** |
| 2925 | |
| 2926 | update_status_and_ints -- check to see if the various flags should be on or off |
| 2927 | Description of flags, and their position in the status register: |
| 2928 | From the data sheet: |
| 2929 | bit D0(bit 7) = TS - Talk Status is active (high) when the VSP is processing speech data. |
| 2930 | Talk Status goes active at the initiation of a Speak command or after nine |
| 2931 | bytes of data are loaded into the FIFO following a Speak External command. It |
| 2932 | goes inactive (low) when the stop code (Energy=1111) is processed, or |
| 2933 | immediately by a buffer empty condition or a reset command. |
| 2934 | bit D1(bit 6) = BL - Buffer Low is active (high) when the FIFO buffer is more than half empty. |
| 2935 | Buffer Low is set when the "Last-In" byte is shifted down past the half-full |
| 2936 | boundary of the stack. Buffer Low is cleared when data is loaded to the stack |
| 2937 | so that the "Last-In" byte lies above the half-full boundary and becomes the |
| 2938 | eighth data byte of the stack. |
| 2939 | bit D2(bit 5) = BE - Buffer Empty is active (high) when the FIFO buffer has run out of data |
| 2940 | while executing a Speak External command. Buffer Empty is set when the last bit |
| 2941 | of the "Last-In" byte is shifted out to the Synthesis Section. This causes |
| 2942 | Talk Status to be cleared. Speed is terminated at some abnormal point and the |
| 2943 | Speak External command execution is terminated. |
| 2944 | |
| 2945 | ***********************************************************************************************/ |
| 2946 | |
| 2947 | void tms52xx_device::update_status_and_ints() |
| 2948 | { |
| 2949 | // update flags and set ints if needed |
| 2950 | update_ready_state(); |
| 2951 | |
| 2952 | // BL is set if neither byte 9 nor 8 of the fifo are in use; this |
| 2953 | // translates to having fifo_count (which ranges from 0 bytes in use to 16 |
| 2954 | // bytes used) being less than or equal to 8. Victory/Victorba depends on this. |
| 2955 | if (m_fifo_count <= 8) |
| 2956 | { |
| 2957 | // generate an interrupt if necessary; if /BL was inactive and is now active, set int. |
| 2958 | if (!m_buffer_low) set_interrupt_state(1); |
| 2959 | m_buffer_low = true; |
| 2960 | } |
| 2961 | else |
| 2962 | m_buffer_low = false; |
| 2963 | |
| 2964 | // BE is set if neither byte 15 nor 14 of the fifo are in use; this |
| 2965 | // translates to having fifo_count equal to exactly 0 */ |
| 2966 | if (m_fifo_count == 0) |
| 2967 | { |
| 2968 | // generate an interrupt if necessary; if /BE was inactive and is now active, set int. |
| 2969 | if (!m_buffer_empty) set_interrupt_state(1); |
| 2970 | m_buffer_empty = true; |
| 2971 | } |
| 2972 | else |
| 2973 | m_buffer_empty = false; |
| 2974 | |
| 2975 | // TS is talk status and is set elsewhere in the fifo parser and in |
| 2976 | // the SPEAK command handler; however, if /BE is true during speak external |
| 2977 | // mode, it is immediately unset here. |
| 2978 | if (m_speak_external && m_buffer_empty) |
| 2979 | { |
| 2980 | // generate an interrupt: /TS was active, and is now inactive. |
| 2981 | if (m_talk_status) |
| 2982 | { |
| 2983 | m_talk_status = m_speak_external = false; |
| 2984 | set_interrupt_state(1); |
| 2985 | } |
| 2986 | } |
| 2987 | // Note that TS being unset will also generate an interrupt when a STOP |
| 2988 | // frame is encountered; this is handled in the sample generator code and not here */ |
| 2989 | } |
| 2990 | |
| 2991 | /****************************************************************************** |
| 2992 | extract_bits -- extract a specific number of bits from the current input stream (FIFO or VSM) |
| 2993 | *******************************************************************************/ |
| 2994 | |
| 2995 | int tms52xx_device::extract_bits(int count) |
| 2996 | { |
| 2997 | int val = 0; |
| 2998 | |
| 2999 | if (m_speak_external) |
| 3000 | { |
| 3001 | // extract from FIFO |
| 3002 | while (count--) |
| 3003 | { |
| 3004 | val = (val << 1) | ((m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 1); |
| 3005 | m_fifo_bits_taken++; |
| 3006 | if (m_fifo_bits_taken >= 8) |
| 3007 | { |
| 3008 | m_fifo_count--; |
| 3009 | m_fifo[m_fifo_head] = 0; // zero the newly depleted fifo head byte |
| 3010 | m_fifo_head = (m_fifo_head + 1) % FIFO_SIZE; |
| 3011 | m_fifo_bits_taken = 0; |
| 3012 | update_status_and_ints(); |
| 3013 | } |
| 3014 | } |
| 3015 | } |
| 3016 | else |
| 3017 | { |
| 3018 | // extract from VSM (speech ROM) |
| 3019 | val = m_read_mem(count); |
| 3020 | } |
| 3021 | return val; |
| 3022 | } |
| 3023 | |
| 3024 | /****************************************************************************** |
| 3025 | status_read -- read status or data from the TMS5220 |
| 3026 | *******************************************************************************/ |
| 3027 | |
| 3028 | int tms52xx_device::status_read() |
| 3029 | { |
| 3030 | if (m_RDB_flag) |
| 3031 | { // if last command was read, return data register |
| 3032 | m_RDB_flag = false; |
| 3033 | return m_data_register; |
| 3034 | } |
| 3035 | else |
| 3036 | { // read status |
| 3037 | // clear the interrupt pin on status read |
| 3038 | set_interrupt_state(0); |
| 3039 | #ifdef DEBUG_PIN_READS |
| 3040 | logerror("tms52xx: Status read: TS=%d BL=%d BE=%d\n", m_talk_status, m_buffer_low, m_buffer_empty); |
| 3041 | #endif |
| 3042 | |
| 3043 | int retvalue = 0; |
| 3044 | if (m_talk_status) retvalue |= 0x80; |
| 3045 | if (m_buffer_low) retvalue |= 0x40; |
| 3046 | if (m_buffer_empty) retvalue |= 0x20; |
| 3047 | return retvalue; |
| 3048 | } |
| 3049 | } |
| 3050 | |
| 3051 | /****************************************************************************** |
| 3052 | ready_read -- returns the ready state of the TMS5220 |
| 3053 | *******************************************************************************/ |
| 3054 | |
| 3055 | inline bool tms52xx_device::ready_read() |
| 3056 | { |
| 3057 | #ifdef DEBUG_PIN_READS |
| 3058 | logerror("tms52xx: ready_read: ready pin read, io_ready is %d, fifo count is %d\n", m_io_ready, m_fifo_count); |
| 3059 | #endif |
| 3060 | return ((m_fifo_count < FIFO_SIZE)||(!m_speak_external)) && m_io_ready; |
| 3061 | } |
| 3062 | |
| 3063 | /****************************************************************************** |
| 3064 | int_read -- returns the interrupt state of the TMS5220 |
| 3065 | *******************************************************************************/ |
| 3066 | |
| 3067 | inline int tms52xx_device::int_read() |
| 3068 | { |
| 3069 | #ifdef DEBUG_PIN_READS |
| 3070 | logerror("tms52xx: int_read: irq pin read, state is %d\n", m_irq_pin); |
| 3071 | #endif |
| 3072 | return m_irq_pin; |
| 3073 | } |
| 3074 | |
| 3075 | /****************************************************************************** |
| 3076 | cycles_to_ready -- returns the number of cycles until ready is asserted |
| 3077 | NOTE: this function is deprecated and is known to be VERY inaccurate. |
| 3078 | Use at your own peril! |
| 3079 | *******************************************************************************/ |
| 3080 | |
| 3081 | int tms52xx_device::cycles_to_ready() |
| 3082 | { |
| 3083 | int answer; |
| 3084 | |
| 3085 | if (ready_read()) answer = 0; |
| 3086 | else |
| 3087 | { |
| 3088 | int val; |
| 3089 | int samples_per_frame = (m_subc_reload!=0)? 200:304; // either (13 A cycles + 12 B cycles) * 8 interps for normal SPEAK/SPKEXT, or (13*2 A cycles + 12 B cycles) * 8 interps for SPKSLOW |
| 3090 | int current_sample = ((m_PC * (3-m_subc_reload)) + (((m_subc_reload!=0)? 38:25) * m_interp_period)); |
| 3091 | answer = samples_per_frame - current_sample + 8; |
| 3092 | |
| 3093 | // total number of bits available in current byte is (8 - tms->fifo_bits_taken) |
| 3094 | // if more than 4 are available, we need to check the energy |
| 3095 | if (m_fifo_bits_taken < 4) |
| 3096 | { |
| 3097 | // read energy |
| 3098 | val = (m_fifo[m_fifo_head] >> m_fifo_bits_taken) & 0xf; |
| 3099 | if (val == 0) |
| 3100 | // 0 -> silence frame: we will only read 4 bits, and we will |
| 3101 | // therefore need to read another frame before the FIFO is not |
| 3102 | // full any more |
| 3103 | answer += 200; |
| 3104 | // 15 -> stop frame, we will only read 4 bits, but the FIFO will |
| 3105 | // we cleared |
| 3106 | //otherwise, we need to parse the repeat flag (1 bit) and the |
| 3107 | // pitch (6 bits), so everything will be OK. |
| 3108 | } |
| 3109 | } |
| 3110 | return answer; |
| 3111 | } |
| 3112 | |
| 3113 | /****************************************************************************** |
| 3114 | True timing |
| 3115 | *******************************************************************************/ |
| 3116 | |
| 3117 | void tms52xx_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) |
| 3118 | { |
| 3119 | if (param) |
| 3120 | { |
| 3121 | switch (m_rs_ws) |
| 3122 | { |
| 3123 | case 0x02: |
| 3124 | // Write |
| 3125 | // bring up to date first |
| 3126 | #ifdef DEBUG_IO_READY |
| 3127 | logerror("tms52xx: Serviced write: %02x\n", tms->write_latch); |
| 3128 | //fprintf(stderr, "Processed write data: %02X\n", tms->write_latch); |
| 3129 | #endif |
| 3130 | m_stream->update(); |
| 3131 | data_write(m_write_latch); |
| 3132 | break; |
| 3133 | case 0x01: |
| 3134 | // Read |
| 3135 | // bring up to date first |
| 3136 | m_stream->update(); |
| 3137 | m_read_latch = status_read(); |
| 3138 | break; |
| 3139 | case 0x03: |
| 3140 | // High Impedance |
| 3141 | case 0x00: |
| 3142 | // illegal |
| 3143 | break; |
| 3144 | } |
| 3145 | } |
| 3146 | m_io_ready = param; |
| 3147 | update_ready_state(); |
| 3148 | } |
| 3149 | |
| 3150 | /***************************************************** |
| 3151 | /RS line write handler |
| 3152 | *****************************************************/ |
| 3153 | |
| 3154 | WRITE_LINE_MEMBER( tms52xx_device::rsq_w ) |
| 3155 | { |
| 3156 | UINT8 new_val; |
| 3157 | |
| 3158 | m_true_timing = true; |
| 3159 | state &= 0x01; |
| 3160 | #ifdef DEBUG_RS_WS |
| 3161 | logerror("tms52xx: /RS written with data: %d\n", state); |
| 3162 | #endif |
| 3163 | new_val = (m_rs_ws & 0x01) | (state<<1); |
| 3164 | if (new_val != m_rs_ws) |
| 3165 | { |
| 3166 | m_rs_ws = new_val; |
| 3167 | if (new_val == 0) |
| 3168 | { |
| 3169 | if (m_variant == SUBTYPE_TMS5220C) |
| 3170 | reset(); |
| 3171 | #ifdef DEBUG_RS_WS |
| 3172 | else |
| 3173 | // illegal |
| 3174 | logerror("tms52xx: illegal line setting /RS=0 and /WS=0\n"); |
| 3175 | #endif |
| 3176 | return; |
| 3177 | } |
| 3178 | else if (new_val == 3) |
| 3179 | { |
| 3180 | // high impedance |
| 3181 | m_read_latch = 0xff; |
| 3182 | return; |
| 3183 | } |
| 3184 | if (state) |
| 3185 | { |
| 3186 | // low to high |
| 3187 | } |
| 3188 | else |
| 3189 | { |
| 3190 | // high to low - schedule ready cycle |
| 3191 | #ifdef DEBUG_RS_WS |
| 3192 | logerror("tms52xx: Scheduling ready cycle for /RS...\n"); |
| 3193 | #endif |
| 3194 | // upon /RS being activated, /READY goes inactive after 100 nsec from |
| 3195 | // data sheet, through 3 asynchronous gates on patent. This is effectively |
| 3196 | // within one clock, so we immediately set io_ready to 0 and activate the callback. */ |
| 3197 | m_io_ready = 0; |
| 3198 | update_ready_state(); |
| 3199 | // How long does /READY stay inactive, when /RS is pulled low? |
| 3200 | // I believe its almost always ~16 clocks (25 usec at 800khz as shown on the datasheet) |
| 3201 | m_ready_timer->adjust(attotime::from_hz(clock()/16)); |
| 3202 | } |
| 3203 | } |
| 3204 | } |
| 3205 | |
| 3206 | /***************************************************** |
| 3207 | /WS line write handler |
| 3208 | *****************************************************/ |
| 3209 | |
| 3210 | WRITE_LINE_MEMBER( tms52xx_device::wsq_w ) |
| 3211 | { |
| 3212 | UINT8 new_val; |
| 3213 | |
| 3214 | m_true_timing = true; |
| 3215 | state &= 0x01; |
| 3216 | #ifdef DEBUG_RS_WS |
| 3217 | logerror("tms52xx: /WS written with data: %d\n", state); |
| 3218 | #endif |
| 3219 | new_val = (m_rs_ws & 0x02) | (state<<0); |
| 3220 | if (new_val != m_rs_ws) |
| 3221 | { |
| 3222 | m_rs_ws = new_val; |
| 3223 | if (new_val == 0) |
| 3224 | { |
| 3225 | if (m_variant == SUBTYPE_TMS5220C) |
| 3226 | reset(); |
| 3227 | #ifdef DEBUG_RS_WS |
| 3228 | else |
| 3229 | // illegal |
| 3230 | logerror("tms52xx: illegal line setting /RS=0 and /WS=0\n"); |
| 3231 | #endif |
| 3232 | return; |
| 3233 | } |
| 3234 | else if ( new_val == 3) |
| 3235 | { |
| 3236 | // high impedance |
| 3237 | m_read_latch = 0xff; |
| 3238 | return; |
| 3239 | } |
| 3240 | if (state) |
| 3241 | { |
| 3242 | // low to high |
| 3243 | } |
| 3244 | else |
| 3245 | { |
| 3246 | // high to low - schedule ready cycle |
| 3247 | #ifdef DEBUG_RS_WS |
| 3248 | logerror("tms52xx: Scheduling ready cycle for /WS...\n"); |
| 3249 | #endif |
| 3250 | // upon /WS being activated, /READY goes inactive after 100 nsec |
| 3251 | // from data sheet, through 3 asynchronous gates on patent. |
| 3252 | // This is effectively within one clock, so we immediately set io_ready to 0 and activate the callback. |
| 3253 | m_io_ready = 0; |
| 3254 | update_ready_state(); |
| 3255 | // Now comes the complicated part: long does /READY stay inactive |
| 3256 | // when /WS is pulled low? This depends ENTIRELY on the command written, |
| 3257 | // or whether the chip is in speak external mode or not... |
| 3258 | // Speak external mode: ~16 cycles |
| 3259 | // Command Mode: |
| 3260 | // SPK: ? cycles |
| 3261 | // SPKEXT: ? cycles |
| 3262 | // RDBY: between 60 and 140 cycles |
| 3263 | // RB: ? cycles (80?) |
| 3264 | // RST: between 60 and 140 cycles |
| 3265 | // SET RATE (5220C only): ? cycles (probably ~16) |
| 3266 | |
| 3267 | // TODO: actually HANDLE the timing differences! currently just assuming always 16 cycles |
| 3268 | m_ready_timer->adjust(attotime::from_hz(clock()/16)); |
| 3269 | } |
| 3270 | } |
| 3271 | } |
| 3272 | |
| 3273 | /***************************************************************************** |
| 3274 | write -- write data to the sound chip |
| 3275 | *******************************************************************************/ |
| 3276 | |
| 3277 | WRITE8_MEMBER( tms52xx_device::write ) |
| 3278 | { |
| 3279 | #ifdef DEBUG_RS_WS |
| 3280 | logerror("tms52xx: write data %02x\n", data); |
| 3281 | #endif |
| 3282 | if (!m_true_timing) |
| 3283 | { |
| 3284 | // bring up to date first |
| 3285 | m_stream->update(); |
| 3286 | data_write(data); |
| 3287 | } |
| 3288 | else |
| 3289 | { |
| 3290 | // actually in a write? |
| 3291 | #ifdef DEBUG_RS_WS |
| 3292 | if (!(m_rs_ws == 0x02)) |
| 3293 | logerror("tms52xx: write data written outside ws, status: %02x!\n", m_rs_ws); |
| 3294 | #endif |
| 3295 | m_write_latch = data; |
| 3296 | } |
| 3297 | } |
| 3298 | |
| 3299 | /****************************************************************************** |
| 3300 | read -- read status or data from the sound chip |
| 3301 | *******************************************************************************/ |
| 3302 | |
| 3303 | READ8_MEMBER( tms52xx_device::read ) |
| 3304 | { |
| 3305 | if (!m_true_timing) |
| 3306 | { |
| 3307 | // bring up-to-date first |
| 3308 | m_stream->update(); |
| 3309 | return status_read(); |
| 3310 | } |
| 3311 | else |
| 3312 | { |
| 3313 | // actually in a read? |
| 3314 | if (m_rs_ws == 0x01) |
| 3315 | return m_read_latch; |
| 3316 | #ifdef DEBUG_RS_WS |
| 3317 | else |
| 3318 | logerror("tms52xx: data read outside rs!\n"); |
| 3319 | #endif |
| 3320 | return 0xff; |
| 3321 | } |
| 3322 | } |
| 3323 | |
| 3324 | /******************************************************************************* |
| 3325 | ready -- return the not ready status from the sound chip |
| 3326 | *******************************************************************************/ |
| 3327 | |
| 3328 | READ_LINE_MEMBER( tms52xx_device::readyq ) |
| 3329 | { |
| 3330 | // bring up-to-date first |
| 3331 | m_stream->update(); |
| 3332 | return !ready_read(); |
| 3333 | } |
| 3334 | |
| 3335 | |
| 3336 | /****************************************************************************** |
| 3337 | time_to_ready -- return the time in seconds until the |
| 3338 | ready line is asserted |
| 3339 | *******************************************************************************/ |
| 3340 | |
| 3341 | double tms52xx_device::time_to_ready() |
| 3342 | { |
| 3343 | double cycles; |
| 3344 | |
| 3345 | // bring up-to-date |
| 3346 | m_stream->update(); |
| 3347 | cycles = cycles_to_ready(); |
| 3348 | return cycles * 80.0 / m_clock; |
| 3349 | } |
| 3350 | |
| 3351 | /****************************************************************************** |
| 3352 | intq -- return the interrupt status from the sound chip |
| 3353 | ******************************************************************************/ |
| 3354 | |
| 3355 | READ_LINE_MEMBER( tms52xx_device::intq ) |
| 3356 | { |
| 3357 | // bring up-to-date first |
| 3358 | m_stream->update(); |
| 3359 | return !int_read(); |
| 3360 | } |
| 3361 | |
| 3362 | void tms52xx_device::register_for_save_states() |
| 3363 | { |
| 3364 | save_item(NAME(m_fifo)); |
| 3365 | save_item(NAME(m_fifo_head)); |
| 3366 | save_item(NAME(m_fifo_tail)); |
| 3367 | save_item(NAME(m_fifo_count)); |
| 3368 | save_item(NAME(m_fifo_bits_taken)); |
| 3369 | |
| 3370 | save_item(NAME(m_speaking_now)); |
| 3371 | save_item(NAME(m_speak_external)); |
| 3372 | save_item(NAME(m_talk_status)); |
| 3373 | save_item(NAME(m_buffer_low)); |
| 3374 | save_item(NAME(m_buffer_empty)); |
| 3375 | save_item(NAME(m_irq_pin)); |
| 3376 | save_item(NAME(m_ready_pin)); |
| 3377 | |
| 3378 | save_item(NAME(m_OLDE)); |
| 3379 | save_item(NAME(m_OLDP)); |
| 3380 | |
| 3381 | save_item(NAME(m_new_frame_energy_idx)); |
| 3382 | save_item(NAME(m_new_frame_pitch_idx)); |
| 3383 | save_item(NAME(m_new_frame_k_idx)); |
| 3384 | #ifdef PERFECT_INTERPOLATION_HACK |
| 3385 | save_item(NAME(m_old_frame_energy_idx)); |
| 3386 | save_item(NAME(m_old_frame_pitch_idx)); |
| 3387 | save_item(NAME(m_old_frame_k_idx)); |
| 3388 | #endif |
| 3389 | save_item(NAME(m_current_energy)); |
| 3390 | save_item(NAME(m_current_pitch)); |
| 3391 | save_item(NAME(m_current_k)); |
| 3392 | |
| 3393 | save_item(NAME(m_target_energy)); |
| 3394 | save_item(NAME(m_target_pitch)); |
| 3395 | save_item(NAME(m_target_k)); |
| 3396 | |
| 3397 | save_item(NAME(m_previous_energy)); |
| 3398 | |
| 3399 | save_item(NAME(m_subcycle)); |
| 3400 | save_item(NAME(m_subc_reload)); |
| 3401 | save_item(NAME(m_PC)); |
| 3402 | save_item(NAME(m_interp_period)); |
| 3403 | save_item(NAME(m_inhibit)); |
| 3404 | save_item(NAME(m_tms5220c_rate)); |
| 3405 | save_item(NAME(m_pitch_count)); |
| 3406 | |
| 3407 | save_item(NAME(m_u)); |
| 3408 | save_item(NAME(m_x)); |
| 3409 | |
| 3410 | save_item(NAME(m_RNG)); |
| 3411 | save_item(NAME(m_excitation_data)); |
| 3412 | |
| 3413 | save_item(NAME(m_schedule_dummy_read)); |
| 3414 | save_item(NAME(m_data_register)); |
| 3415 | save_item(NAME(m_RDB_flag)); |
| 3416 | save_item(NAME(m_digital_select)); |
| 3417 | |
| 3418 | save_item(NAME(m_io_ready)); |
| 3419 | } |
| 3420 | |
| 3421 | |
| 3422 | const device_type TMS5220N = &device_creator<tms5220n_device>; |
| 3423 | const device_type TMS5220CN = &device_creator<tms5220cn_device>; |
| 3424 | const device_type TMC0285N = &device_creator<tmc0285n_device>; |
| 3425 | const device_type TMS5200N = &device_creator<tms5200n_device>; |
| 3426 | |