diff --git a/src/emu/sound/votrax.c b/src/emu/sound/votrax.c index 4f8e146c6ee..e308de26b87 100644 --- a/src/emu/sound/votrax.c +++ b/src/emu/sound/votrax.c @@ -2,8 +2,7 @@ votrax.c - Hacked up votrax simulator that maps to samples, until a real one - is written. + Simple VOTRAX SC-01 simulator based on sample fragments. **************************************************************************** @@ -43,23 +42,75 @@ +//************************************************************************** +// CONSTANTS +//************************************************************************** + +// note that according to the patent timing circuit, p1/p2 and phi1/phi2 +// run 4x faster than all references in the patent text +const UINT32 P_CLOCK_BIT = 5; // 5 according to timing diagram +const UINT32 PHI_CLOCK_BIT = 3; // 3 according to timing diagram + + + //************************************************************************** // GLOBAL VARIABLES //************************************************************************** // device type definition -const device_type VOTRAX = &device_creator; +const device_type VOTRAX_SC01 = &device_creator; -const char *const votrax_device::s_phoneme_table[64] = +// ROM definition for the Votrax phoneme ROM +ROM_START( votrax_sc01 ) + ROM_REGION( 0x200, "phoneme", 0 ) + ROM_LOAD( "sc01.bin", 0x0000, 0x200, CRC(0353dd6c) SHA1(00e8e497b96a10bd9f4d7e559433c3c209b0d3a8) ) +ROM_END + +// textual phoneme names for debugging +const char *const votrax_sc01_device::s_phoneme_table[64] = { - "EH3", "EH2", "EH1", " "/*PA0*/"DT", "A1", "A2", "ZH", + "EH3", "EH2", "EH1", "PA0", "DT", "A1", "A2", "ZH", "AH2", "I3", "I2", "I1", "M", "N", "B", "V", "CH", "SH", "Z", "AW1", "NG", "AH1", "OO1", "OO", "L", "K", "J", "H", "G", "F", "D", "S", "A", "AY", "Y1", "UH3", "AH", "P", "O", "I", "U", "Y", "T", "R", "E", "W", "AE", "AE1", "AW2", "UH2", "UH1", "UH", "O2", "O1", "IU", "U1", - "THV", "TH", "ER", "EH", "E1", "AW", " "/*PA1*/, "."/*STOP*/ + "THV", "TH", "ER", "EH", "E1", "AW", "PA1", "STOP" +}; + +const UINT16 votrax_sc01_device::s_phoneme_duration[64] = +{ + 59, 71, 121, 47, 47, 71, 103, 90, + 71, 55, 80, 121, 103, 80, 71, 71, + 71, 121, 71, 146, 121, 146, 103, 185, + 103, 80, 47, 71, 71, 103, 55, 90, + 185, 65, 80, 47, 250, 103, 185, 185, + 185, 103, 71, 90, 185, 80, 185, 103, + 90, 71, 103, 185, 80, 121, 59, 90, + 80, 71, 146, 185, 121, 253, 185, 47 +}; + +// this waveform is derived from measuring fig. 10 in the patent +// it is only an approximation +const double votrax_sc01_device::s_glottal_wave[16] = +{ + 0, + 16.0/22.0, + -22.0/22.0, + -17.0/22.0, + -15.0/22.0, + -10.0/22.0, + -7.0/22.0, + -4.0/22.0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 }; @@ -69,11 +120,14 @@ const char *const votrax_device::s_phoneme_table[64] = //************************************************************************** //------------------------------------------------- -// votrax_device - constructor +// votrax_sc01_device - constructor //------------------------------------------------- -votrax_device::votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) - : samples_device(mconfig, VOTRAX, "VOTRAX SC-01", tag, owner, clock) +votrax_sc01_device::votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, VOTRAX_SC01, "Votrax SC-01", "votrax", tag, owner, clock), + device_sound_interface(mconfig, *this), + m_stream(NULL), + m_phoneme_timer(NULL) { } @@ -83,10 +137,10 @@ votrax_device::votrax_device(const machine_config &mconfig, const char *tag, dev // to set the interface //------------------------------------------------- -void votrax_device::static_set_interface(device_t &device, const votrax_interface &interface) +void votrax_sc01_device::static_set_interface(device_t &device, const votrax_sc01_interface &interface) { - votrax_device &samples = downcast(device); - static_cast(samples) = interface; + votrax_sc01_device &votrax = downcast(device); + static_cast(votrax) = interface; } @@ -99,42 +153,598 @@ void votrax_device::static_set_interface(device_t &device, const votrax_interfac // write - handle a write to the control register //------------------------------------------------- -WRITE8_MEMBER( votrax_device::write ) +WRITE8_MEMBER( votrax_sc01_device::write ) { - // append to the current string - m_current.cat(s_phoneme_table[data & 0x3f]); + // flush out anything currently processing + m_stream->update(); - // look for a match in our sample table - for (int index = 0; m_votrax_map[index].phoneme != NULL; index++) - if (m_current.find(m_votrax_map[index].phoneme) != -1) - { - // if we found it, play the corresponding sample and flush the buffer - start(0, index); - m_current.replace(m_votrax_map[index].phoneme, ""); - m_current.trimspace(); - if (m_current.len() > 0) - mame_printf_warning("Votrax missed partial match: %s\n", m_current.cstr()); - m_current.reset(); - return; - } + // only 6 bits matter + m_phoneme = data & 0x3f; +mame_printf_debug("%s: STROBE %s\n", machine().time().as_string(3), s_phoneme_table[m_phoneme]); + + // the STROBE signal resets the phoneme counter + m_counter_84 = 0xf; + + // not in the schematics, but necessary to fully reset the request latch + m_latch_92 = 0; - // if we got a stop and didn't find a match, print it - if ((data & 0x3f) == 0x3f) - { - mame_printf_warning("Votrax missed match: %s\n", m_current.cstr()); - m_current.reset(); - } + // clear the request signal + m_request_func(m_request_state = m_internal_request = CLEAR_LINE); + m_phoneme_timer->adjust(attotime::zero); } //------------------------------------------------- -// status - read the status line +// inflection_w - handle a write to the +// inflection bits //------------------------------------------------- -READ_LINE_MEMBER( votrax_device::status ) +WRITE8_MEMBER( votrax_sc01_device::inflection_w ) { - // is this correct, or is it really a ready line and should be inverted? - return (m_current.len() > 0 || playing(0)) ? ASSERT_LINE : CLEAR_LINE; + // only 2 bits matter + data &= 3; + if (m_inflection == data) + return; + + // append an inflection marker + m_stream->update(); + m_inflection = data; +} + + + +//************************************************************************** +// CORE LOGIC +//************************************************************************** + +//------------------------------------------------- +// update_subphoneme_clock_period - re-compute the +// period of the sub-phoneme clock, as a multiple +// of the master clock +//------------------------------------------------- + +void votrax_sc01_device::update_subphoneme_clock_period() +{ + assert(m_latch_80 < 128); + +/* + The sub-phoneme timing circuit is based off the switching capacitor + technique described in the Votrax patent. Replacing the capacitor + ladder with [Rx] representing the effective resistance, the circuit + becomes essentially a pair of op-amps: + + VM + | i1 + [R1] + | Vc + +----------------------+ + | +---|C1|---+ | + [R2] | | | |\ + |Vb i2 | |\ | +--++\ + +--[Rx]--+----+-\ | | > + | | >--+-----+-/ + [R3] +----++/ Vc |/ + |i3 | |/ + +--------+ Va + | + [R4] + | + 0 + + We have two op-amps, the left used as a standard amplifier, the right + one as a comparator. The circuit triggers when the two inputs of the + right op-amp are equal. + + The left part of the circuit (before C1) is simply a current injector. + It's all made of resistors, there's no modulated input, so everything + is going to be constant. If you don't know about op-amps used as + amplifiers, you just need to know that it forces its two inputs to + have the same voltage while not sending or providing any current + through there (only though its output in fact). + + In the schema, the injected current is i2. Basic equations apply: + Va = R4.i3 + Vb = Va + R3.i3 + Vb = Va + Rx.i2 + Vc = Vb + R2.i1 + VM = Vc + R1.i1 + i1 = i2 + i3 + + And the tipping happens when the voltage on the right of C1 reaches + Vc, so: + Vc = Va + i2.T/C1 + + (i2 being a constant, the integration is kinda easy) + + Some maths later: + R3.i3 = Rx.i2 -> i3 = Rx/R3.i2 + i1 = (1+Rx/R3).i2 + Va + (Rx + R2 + R2.Rx/R3).i2 = Va + T/C1.i2 + T = C1*(Rx*(1+R2/R3) + R2) + + Which isn't, interestingly though not surprisingly, dependant on Vm, + R1 or R4. And you have to round it to the next multiple of + 0.2ms+0.1ms due to the clocking on p2 and its offset to p1 (charging + only happens on p1 active), and add one p1/p2 cycle (0.2ms) for the + discharge. + + So now you have your base clock, which you have to multiply by 16 to + get the phoneme length. + + r2 = 9e3 + r3 = 1e3 + c1 = 1000e-12 + rx = 1/(5KHz * cx) +*/ + + // determine total capacitance + double cx = 0; + if ((m_latch_80 & 0x01) != 0) cx += 5e-12; + if ((m_latch_80 & 0x02) != 0) cx += 11e-12; + if ((m_latch_80 & 0x04) != 0) cx += 21e-12; + if ((m_latch_80 & 0x08) != 0) cx += 43e-12; + if ((m_latch_80 & 0x10) != 0) cx += 86e-12; + if ((m_latch_80 & 0x20) != 0) cx += 173e-12; + if ((m_latch_80 & 0x40) != 0) cx += 345e-12; + + // apply the equation above to determine charging time + // note that the 5kHz listed above for P1 is for a nominal master + // clock frequency of 1.28MHz, meaning it is master clock / 128 + // which should be the P1 clock but appears to be a bit different + double p1_frequency = double(m_master_clock_freq) / double(1 << (P_CLOCK_BIT + 2)); + double rx = 1.0 / (p1_frequency * cx); + double period = 1000e-12 * (rx * (1.0 + 9e3 / 1e3) + 9e3); + + // convert to master clock cycles and round up + m_subphoneme_period = UINT32(ceil(period * double(m_master_clock_freq))); +} + + +//------------------------------------------------- +// sound_stream_update - handle update requests +// for our sound stream +//------------------------------------------------- + +void votrax_sc01_device::sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples) +{ + // determine how many master half-clocks per sample + int clocks_per_sample = m_master_clock_freq / stream.sample_rate(); + + // iterate over clocks (samples) + stream_sample_t *dest = outputs[0]; + while (samples--) + { + // run the digital logic at the master clock rate + double glottal_out = 0; + double noise_out = 0; + for (int curclock = 0; curclock < clocks_per_sample; curclock++) + { + //============================================== + // + // Timing circuit (patent figure 2a) + // + //============================================== + + // update master clock + m_master_clock ^= 1; + + // on the falling edge of the master clock, advance the 10-bit counter at 34 + UINT8 old_latch_72 = m_latch_72; + if (m_master_clock == 0) + m_counter_34 = (m_counter_34 + 1) & 0x3ff; + else + { + m_latch_70 = m_counter_34 & 0xf; + m_latch_72 = ((m_counter_34 >> 4) & 7) | ((m_counter_34 >> 6) & 8); + } + + // derive beta 1 clock: + // set if m_latch_70.0 == 1 + // reset if m_latch_70.0 == 0 +// UINT8 old_beta1 = m_beta1; + m_beta1 = BIT(m_latch_70, 0); + + // derive p2 clock: + // set if (m_counter_34.P_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.P_CLOCK_BIT == 0) + UINT8 old_p2 = m_p2; + if (BIT(m_counter_34, P_CLOCK_BIT) & m_master_clock) + m_p2 = 1; + else if (!BIT(m_counter_34, P_CLOCK_BIT)) + m_p2 = 0; + + // derive p1 clock: + // set if (!m_counter_34.P_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.P_CLOCK_BIT == 1) +// UINT8 old_p1 = m_p1; + if (BIT(~m_counter_34, P_CLOCK_BIT) & m_master_clock) + m_p1 = 1; + else if (BIT(m_counter_34, P_CLOCK_BIT)) + m_p1 = 0; + + // derive phi2 clock: + // set if (m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 0) + UINT8 old_phi2 = m_phi2; + if (BIT(m_counter_34, PHI_CLOCK_BIT) & m_master_clock) + m_phi2 = 1; + else if (!BIT(m_counter_34, PHI_CLOCK_BIT)) + m_phi2 = 0; + + // derive phi1 clock: + // set if (!m_counter_34.PHI_CLOCK_BIT & clock) == 1 + // reset if (m_counter_34.PHI_CLOCK_BIT == 1) + UINT8 old_phi1 = m_phi1; + if (BIT(~m_counter_34, PHI_CLOCK_BIT) & m_master_clock) + m_phi1 = 1; + else if (BIT(m_counter_34, PHI_CLOCK_BIT)) + m_phi1 = 0; + + // determine rising edges of each clock of interest +// UINT8 beta1_rising = (old_beta1 ^ m_beta1) & m_beta1; + UINT8 p2_rising = (old_p2 ^ m_p2) & m_p2; +// UINT8 p1_rising = (old_p1 ^ m_p1) & m_p1; + UINT8 phi2_rising = (old_phi2 ^ m_phi2) & m_phi2; + UINT8 phi1_rising = (old_phi1 ^ m_phi1) & m_phi1; + UINT8 a0_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 0); + UINT8 a2_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 2); + UINT8 _125k_rising = BIT((old_latch_72 ^ m_latch_72) & m_latch_72, 3); + + // track subphoneme counter state + if (!(m_latch_42 | m_phi1)) + m_subphoneme_count = 0; + else + m_subphoneme_count++; + if (p2_rising) + m_latch_42 = (m_subphoneme_count < m_subphoneme_period); + + // update the state of the subphoneme clock line + UINT8 old_clock_88 = m_clock_88; + m_clock_88 = !m_latch_42; //!(m_latch_42 | m_phi1); -- figure 7 seems to be wrong here + UINT8 clock_88_rising = (old_clock_88 ^ m_clock_88) & m_clock_88; + + // the A/R line holds the counter in reset except during phoneme processing, + // when it is clocked on the rising edge of the subphoneme timer clock + if (m_internal_request != CLEAR_LINE) + m_counter_84 = 0xf; + else if (clock_88_rising) + { + m_counter_84 = (m_counter_84 - 1) & 0x0f; +mame_printf_debug("counter=%d\n", m_counter_84); + } + + // clock the zero count latch + if (p2_rising) + m_latch_92 = ((m_counter_84 == 0) | (m_latch_92 << 1)) & 3; + + // once both bits are set, the request line goes high + if (m_latch_92 == 3) + { + // if the request line was previously low, reset the VD/CLD flip-flops + if (m_internal_request == CLEAR_LINE) + m_srff_112 = m_srff_114 = 0; + m_internal_request = ASSERT_LINE; + } + + //============================================== + // + // Low parameter clocking (patent figure 2b) + // + //============================================== + + // fetch ROM data; note that the address lines come directly from + // counter_34 and not from the latches, which are 1 cycle delayed + UINT8 romdata = m_rom[(m_phoneme << 3) | ((m_counter_34 >> 4) & 7)]; + + // update the ROM data; ROM format is (upper nibble/lower nibble) + // +00 = F1 parameter / 0 + // +01 = F2 parameter / 0 + // +02 = FC parameter / 0 + // +03 = F3 parameter / CL + // +04 = F2Q Parameter / CLD + // +05 = VA Parameter / VD + // +06 = FA Parameter / PAC + // +07 = Phoneme timing (full 7 bits) + + // latch a new value from ROM on phi2 + UINT8 a = m_latch_72 & 7; + UINT8 romdata_swapped; + if (phi2_rising) + { + switch (a) + { + // update CL + case 3: + m_srff_132 = m_srff_114 & BIT(~romdata, 3); + break; + + // update CLD + case 4: + romdata_swapped = (BIT(romdata, 0) << 3) | (BIT(romdata, 1) << 2) | (BIT(romdata, 2) << 1) | (BIT(romdata, 3) << 0); + if (m_counter_84 != 0 && romdata_swapped == (m_counter_84 ^ 0xf)) + m_srff_114 = 1; + break; + + // update VD + case 5: + romdata_swapped = (BIT(romdata, 0) << 3) | (BIT(romdata, 1) << 2) | (BIT(romdata, 2) << 1) | (BIT(romdata, 3) << 0); + if (m_counter_84 != 0 && romdata_swapped == (m_counter_84 ^ 0xf)) + m_srff_112 = 1; + break; + + // update FF == PAC & (VA | FA) + case 6: + m_srff_142 = BIT(romdata, 3); + break; + + // update PH + case 7: + if (m_latch_80 != (romdata & 0x7f)) + { + m_latch_80 = romdata & 0x7f; +mame_printf_debug("[PH=%02X]\n", m_latch_80); + UINT32 old_period = m_subphoneme_period; + update_subphoneme_clock_period(); + m_subphoneme_count = (m_subphoneme_count * m_subphoneme_period) / old_period; + m_phoneme_timer->adjust(attotime::zero); + } + break; + } + } + + //============================================== + // + // Glottal circuit (patent figure 6) + // + //============================================== + + // determine the TC output from the counters (note that TC requires ET) + UINT8 counter_222_tc = (m_counter_222 == 0xf); + UINT8 counter_220_tc = (m_counter_220 == 0xf && counter_222_tc); + UINT8 counter_224_tc = (m_counter_224 == 0xf && counter_222_tc); + + // clock glottal counter 224 on rising edge of a0 + if (a0_rising) + { + // counter 224 is only enabled if TC of counter 222 is 1 + if (counter_222_tc) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_224 = (m_inflection << 1) | ((~m_f1 & 0x8) >> 3); + else + m_counter_224 = (m_counter_224 + 1) & 0xf; + } + } + + // clock remaining glottal counters (220, 222, 236) on rising edge of phi2 + if (phi2_rising) + { + // counter 220 is only enabled if TC of counter 222 is 1 + if (counter_222_tc) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_220 = (m_inflection << 1) | ((~m_f1 & 0x8) >> 3); + else + m_counter_220 = (m_counter_220 + 1) & 0xf; + } + + // counter 222 is always enabled + if (1) + { + // if counter 220's TC is 1, do a load instead of a count + if (counter_220_tc) + m_counter_222 = (~m_f1 & 0x7) << 1; + else + m_counter_222 = (m_counter_222 + 1) & 0xf; + } + + // counter 236 is always enabled + if (1) + { + m_counter_236 = (m_counter_236 + 1) & 0xf; + + // rising edge of Q1 from counter 236 clocks counter 234 + if ((m_counter_236 & 0x3) == 0x2) + { + // counter 234 is only enabled if it has not reached terminal + if (m_counter_234 != 0xf) + m_counter_234 = (m_counter_234 + 1) & 0xf; + } + } + } + + // update FGATE state + if (counter_220_tc) + m_fgate = 0; + if (counter_224_tc) + m_fgate = 1; + + // apply asynchronous clear to counters 234/236 + if (counter_220_tc && m_phi1) + m_counter_236 = m_counter_234 = 0; + + // derive glottal circuit output signals + UINT8 old_glottal_sync = m_glottal_sync; + m_glottal_sync = (m_counter_234 == 0); + glottal_out = s_glottal_wave[m_counter_234]; + + //============================================== + // + // Transition circuit (patent figure 3a/3b) + // + //============================================== + + // divide 1.25k clock by 2 (lower-left of 46) + UINT8 old_0625_clock = m_0625_clock; + if (_125k_rising) + m_0625_clock = !m_0625_clock; + UINT8 _0625_rising = (old_0625_clock ^ m_0625_clock) & m_0625_clock; + + // update counter above + if (_0625_rising) + { + if (m_counter_46 == 0xf) + m_counter_46 = 0xd; + else + m_counter_46 = (m_counter_46 + 1) & 0xf; + } + + // and then the latch to the right + if (a2_rising) + m_latch_46 = (BIT(m_counter_46, 1) << 0) | + (BIT(m_latch_46, 0) << 1) | + (m_0625_clock << 2) | + (BIT(m_latch_46, 2) << 3); + + // determine the read/write signal + UINT8 ram_write = 0; + switch (a) + { + // write if not FF and low 2 bits of latch + // FF is the S/R flip-flop at 142 ANDed with !(/FA & /VA) + case 0: case 1: case 2: case 3: case 4: + if (!(m_srff_142 && ((m_fa | m_va) & 0xf0) != 0) && (m_latch_46 & 0x3) == 0x3) + ram_write = 1; + break; + + case 5: + if ((m_latch_46 & 0xc) == 0xc && m_srff_112) + ram_write = 1; + break; + + case 6: + if ((m_latch_46 & 0xc) == 0xc && m_srff_114) + ram_write = 1; + break; + } + + // gate on the phi2 clock (OR gate @ 172) + ram_write &= m_phi2; + + // write the transitioned values to RAM if requested + // (note we consolidate the serial addition and clocking steps here) + if (ram_write) + { + UINT8 old = (m_latch_168 << 4) | m_latch_170; + m_ram[a] = old - (old >> 3) + ((romdata & 0xf0) >> 3); + } + + // latch some parameter values on rising edge of phi2 + if (phi2_rising) + { + switch (a) + { + case 2: + m_fc = m_latch_168; + break; + + case 5: + m_va = m_latch_168; + break; + + case 6: + m_fa = m_latch_168; + break; + } + } + + // latch remaining parameter values on rising edge of (phi2 & glottal sync) + UINT8 old_phi2_glottal = (old_phi2 & old_glottal_sync); + UINT8 new_phi2_glottal = m_phi2 & m_glottal_sync; + if ((old_phi2_glottal ^ new_phi2_glottal) & new_phi2_glottal) + switch (a) + { + case 0: + m_f1 = m_latch_168; + break; + + case 1: + m_f2 = (m_latch_168 << 1) | (m_latch_170 >> 3); + break; + + case 3: + m_f3 = m_latch_168; + break; + + case 4: + m_f2q = m_latch_168; + break; + } + + // latch value from RAM on rising edge of phi1 + if (phi1_rising) + { + m_latch_168 = m_ram[a] >> 4; + m_latch_170 = m_ram[a] & 0xf; + } + + //============================================== + // + // Noise generator circuit (patent figure 8) + // + //============================================== + + // nose is clocked by the NOR of /FA and P1 + UINT8 old_noise_clock = m_noise_clock; + m_noise_clock = !((m_fa == 0) | m_p1); + UINT8 noise_clock_rising = (old_noise_clock ^ m_noise_clock) & m_noise_clock; + UINT8 noise_clock_falling = (old_noise_clock ^ m_noise_clock) & old_noise_clock; + + // falling edge clocks the shift register + if (noise_clock_falling) + { + // shift register 252 is actually 4 shift registers (2 4-bit, 2 5-bit) + // d1 and d3 are the 4-bit registers, d2 and d4 are the 5-bit registers + // XOR'ed input goes into d4, which shifts in to d2, then d3, then d1 + // thus the full 18-bit value is effectively + // + // d4 = (m_shift_252 >> 0) & 0x1f; + // d2 = (m_shift_252 >> 5) & 0x1f; + // d3 = (m_shift_252 >> 10) & 0xf; + // d1 = (m_shift_252 >> 14) & 0xf; + // + // input at the low end is ((d1+4 ^ d2+5) ^ (d4+4 ^ d4+5)) ^ !(counter2 | counter3) + // output is tapped at d3+4 + + UINT32 old_shift = m_shift_252; + m_shift_252 <<= 1; + m_shift_252 |= ((BIT(old_shift, 17) ^ BIT(old_shift, 9)) ^ (BIT(old_shift, 3) ^ BIT(old_shift, 4))) ^ + ((m_counter_250 & 0xc) == 0); + } + + // rising edge clocks the counter + if (noise_clock_rising) + { + // counter is reset to 1 if terminal, otherwise it increments + if (m_counter_250 == 0xf) + m_counter_250 = 0x1; + else + m_counter_250 = (m_counter_250 + 1) & 0xf; + } + + // compute final noise out signal + UINT8 noise_out_digital = !(BIT(m_shift_252, 13) & (m_fgate | (m_va == 0))); + noise_out = noise_out_digital ? (double(m_fa) / 15.0f) : 0; + } + + // amplify the glottal pulse by the VA and cheesily mix in the noise just to + // help see what's going on + double current = 0.5 * glottal_out * (double(m_va) / 15.0f) + 0.5 * noise_out; + + // TODO: apply high pass noise shaping to noise_out (see figure 8) + + // TODO: apply resonsant filters based on m_f1, m_f2, m_f2q and + // inject noise based on m_fc (see figure 9) + + // TODO: apply final filter f3 and inject inverse of noise based on ~m_fc (see figure 5) + + // TODO: apply closure circuit (undocumented) + + // output the current result + *dest++ = INT16(current * 32767.0); + } } @@ -143,21 +753,233 @@ READ_LINE_MEMBER( votrax_device::status ) // DEVICE INTERFACE //************************************************************************** +//------------------------------------------------- +// rom_region - return a pointer to the device's +// internal ROM region +//------------------------------------------------- + +const rom_entry *votrax_sc01_device::device_rom_region() const +{ + return ROM_NAME( votrax_sc01 ); +} + + //------------------------------------------------- // device_start - handle device startup //------------------------------------------------- -void votrax_device::device_start() +void votrax_sc01_device::device_start() { - // build up a samples list - for (const votrax_map *curmap = m_votrax_map; curmap->phoneme != NULL; curmap++) - m_sample_list.append((curmap->samplename != NULL) ? curmap->samplename : ""); + // initialize internal state + m_master_clock_freq = clock(); + m_stream = stream_alloc(0, 1, m_master_clock_freq / 16); + m_phoneme_timer = timer_alloc(); + m_rom = subregion("phoneme")->base(); + + // reset inputs + m_inflection = 0; + m_phoneme = 0x3f; + + // reset outputs + m_request_func.resolve(m_request_cb, *this); + m_request_state = ASSERT_LINE; + m_internal_request = ASSERT_LINE; + + // save inputs + save_item(NAME(m_inflection)); + save_item(NAME(m_phoneme)); + + // save outputs + save_item(NAME(m_request_state)); + save_item(NAME(m_internal_request)); + + // save timing circuit + save_item(NAME(m_master_clock_freq)); + save_item(NAME(m_master_clock)); + save_item(NAME(m_counter_34)); + save_item(NAME(m_latch_70)); + save_item(NAME(m_latch_72)); + save_item(NAME(m_beta1)); + save_item(NAME(m_p2)); + save_item(NAME(m_p1)); + save_item(NAME(m_phi2)); + save_item(NAME(m_phi1)); + save_item(NAME(m_subphoneme_period)); + save_item(NAME(m_subphoneme_count)); + save_item(NAME(m_clock_88)); + save_item(NAME(m_latch_42)); + save_item(NAME(m_counter_84)); + save_item(NAME(m_latch_92)); + + // save low parameter clocking + save_item(NAME(m_srff_132)); + save_item(NAME(m_srff_114)); + save_item(NAME(m_srff_112)); + save_item(NAME(m_srff_142)); + save_item(NAME(m_latch_80)); + + // save glottal circuit + save_item(NAME(m_counter_220)); + save_item(NAME(m_counter_222)); + save_item(NAME(m_counter_224)); + save_item(NAME(m_counter_234)); + save_item(NAME(m_counter_236)); + save_item(NAME(m_fgate)); + save_item(NAME(m_glottal_sync)); - // create the samples interface - m_channels = 1; - m_names = m_sample_list; - m_start = NULL; - - // let the samples device do the rest - samples_device::device_start(); + // save transition circuit + save_item(NAME(m_0625_clock)); + save_item(NAME(m_counter_46)); + save_item(NAME(m_latch_46)); + save_item(NAME(m_ram)); + save_item(NAME(m_latch_168)); + save_item(NAME(m_latch_170)); + save_item(NAME(m_f1)); + save_item(NAME(m_f2)); + save_item(NAME(m_fc)); + save_item(NAME(m_f3)); + save_item(NAME(m_f2q)); + save_item(NAME(m_va)); + save_item(NAME(m_fa)); + + // save noise generator circuit + save_item(NAME(m_noise_clock)); + save_item(NAME(m_shift_252)); + save_item(NAME(m_counter_250)); +} + + +//------------------------------------------------- +// device_reset - handle device reset +//------------------------------------------------- + +void votrax_sc01_device::device_reset() +{ + // set the initial state + m_stream->update(); + + // reset inputs + m_phoneme = 0x3f; + m_request_func(m_internal_request = m_request_state = ASSERT_LINE); + + // reset timing circuit + m_master_clock = 0; + m_counter_34 = 0; + m_latch_70 = 0; + m_latch_72 = 0; + m_beta1 = 0; + m_p2 = 0; + m_p1 = 0; + m_phi2 = 0; + m_phi1 = 0; + m_subphoneme_period = 1000; + m_subphoneme_count = 0; + m_clock_88 = 0; + m_latch_42 = 0; + m_counter_84 = 0; + m_latch_92 = 0; + + // reset low parameter clocking + m_srff_132 = 0; + m_srff_114 = 0; + m_srff_112 = 0; + m_srff_142 = 0; + m_latch_80 = 50; + update_subphoneme_clock_period(); + + // reset glottal circuit + m_counter_220 = 0; + m_counter_222 = 0; + m_counter_224 = 0; + m_counter_234 = 0; + m_counter_236 = 0; + m_fgate = 0; + m_glottal_sync = 0; + + // reset transition circuit + m_0625_clock = 0; + m_counter_46 = 0; + m_latch_46 = 0; + memset(m_ram, 0, sizeof(m_ram)); + m_latch_168 = 0; + m_latch_170 = 0; + m_f1 = 0; + m_f2 = 0; + m_fc = 0; + m_f3 = 0; + m_f2q = 0; + m_va = 0; + m_fa = 0; + + // reset noise circuit + m_noise_clock = 0; + m_shift_252 = 0; + m_counter_250 = 0; +} + + +//------------------------------------------------- +// device_clock_changed - handle dynamic clock +// changes by altering our output frequency +//------------------------------------------------- + +void votrax_sc01_device::device_clock_changed() +{ + // compute new frequency of the master clock, and update if changed + UINT32 newfreq = clock(); + if (newfreq != m_master_clock_freq) + { + // if we have a stream + if (m_stream != NULL) + { + m_stream->update(); + m_stream->set_sample_rate(newfreq / 16); + } + + // determine how many clock ticks remained on the phoneme timer + UINT64 remaining = m_phoneme_timer->remaining().as_ticks(m_master_clock_freq); + + // recompute the master clock + m_master_clock_freq = newfreq; + + // adjust the phoneme timer to the same number of ticks based on the new frequency + if (remaining > 0) + m_phoneme_timer->adjust(attotime::from_ticks(remaining, newfreq)); + } +} + + +//------------------------------------------------- +// device_timer - handle device timer +//------------------------------------------------- + +void votrax_sc01_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + // force a stream update + m_stream->update(); + + // if we're requesting more data, no need for timing + if (m_request_state == ASSERT_LINE) + return; + + // if we're supposed to have fired, do it now + if (m_internal_request == ASSERT_LINE) + { +mame_printf_debug("%s: REQUEST\n", timer.machine().time().as_string(3)); + m_request_func(m_request_state = ASSERT_LINE); + return; + } + + // account for the rest of this subphoneme clock + UINT32 clocks_until_request = 0; + if (m_counter_84 != 0) + { + if (m_subphoneme_count < m_subphoneme_period) + clocks_until_request += m_subphoneme_period - m_subphoneme_count; + clocks_until_request += m_subphoneme_period * (m_counter_84 - 1); + } + + // plus 1/2 + clocks_until_request = MAX(clocks_until_request, (1 << P_CLOCK_BIT) / 2); + timer.adjust(attotime::from_ticks(clocks_until_request, m_master_clock_freq)); } diff --git a/src/emu/sound/votrax.h b/src/emu/sound/votrax.h index ffde9eeabdd..2686946a3f9 100644 --- a/src/emu/sound/votrax.h +++ b/src/emu/sound/votrax.h @@ -2,8 +2,7 @@ votrax.h - Hacked up votrax simulator that maps to samples, until a real one - is written. + Simple VOTRAX SC-01 simulator based on sample fragments. **************************************************************************** @@ -50,56 +49,129 @@ // INTERFACE CONFIGURATION MACROS //************************************************************************** -#define MCFG_VOTRAX_ADD(_tag, _clock, _interface) \ - MCFG_DEVICE_ADD(_tag, VOTRAX, 0) \ - votrax_device::static_set_interface(*device, _interface); - +#define MCFG_VOTRAX_SC01_ADD(_tag, _clock, _interface) \ + MCFG_DEVICE_ADD(_tag, VOTRAX_SC01, _clock) \ + votrax_sc01_device::static_set_interface(*device, _interface); \ + //************************************************************************** // TYPE DEFINITIONS //************************************************************************** -// ======================> votrax_interface sample +// ======================> votrax_sc01_interface -struct votrax_map +struct votrax_sc01_interface { - const char *phoneme; - const char *samplename; -}; - -struct votrax_interface -{ - votrax_map const *m_votrax_map; // array of map entries + devcb_write_line m_request_cb; // callback for request }; -// ======================> votrax_device +// ======================> votrax_sc01_device -class votrax_device : public samples_device, - public votrax_interface +class votrax_sc01_device : public device_t, + public device_sound_interface, + public votrax_sc01_interface { public: // construction/destruction - votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + votrax_sc01_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); // static configuration helpers - static void static_set_interface(device_t &device, const votrax_interface &interface); + static void static_set_interface(device_t &device, const votrax_sc01_interface &interface); // writers DECLARE_WRITE8_MEMBER( write ); - DECLARE_READ_LINE_MEMBER( status ); + DECLARE_WRITE8_MEMBER( inflection_w ); + DECLARE_READ_LINE_MEMBER( request ) { return m_request_state; } protected: // device-level overrides + const rom_entry *device_rom_region() const; virtual void device_start(); + virtual void device_reset(); + virtual void device_clock_changed(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + + // device_sound_interface overrides + virtual void sound_stream_update(sound_stream &stream, stream_sample_t **inputs, stream_sample_t **outputs, int samples); private: - // internal state - astring m_current; - dynamic_array m_sample_list; + // internal helpers + void update_subphoneme_clock_period(); + // internal state + sound_stream * m_stream; // output stream + emu_timer * m_phoneme_timer; // phoneme timer + const UINT8 * m_rom; // pointer to our ROM + + // inputs + UINT8 m_inflection; // 2-bit inflection value + UINT8 m_phoneme; // 6-bit phoneme value + + // outputs + devcb_resolved_write_line m_request_func; // request callback + UINT8 m_request_state; // request as seen to the outside world + UINT8 m_internal_request; // request managed by stream timing + + // timing circuit + UINT32 m_master_clock_freq; // frequency of the master clock + UINT8 m_master_clock; // master clock + UINT16 m_counter_34; // ripple counter @ 34 + UINT8 m_latch_70; // 4-bit latch @ 70 + UINT8 m_latch_72; // 4-bit latch @ 72 + UINT8 m_beta1; // beta1 clock state + UINT8 m_p2; // P2 clock state + UINT8 m_p1; // P1 clock state + UINT8 m_phi2; // phi2 clock state + UINT8 m_phi1; // phi1 clock state + UINT32 m_subphoneme_period; // period of the subphoneme timer + UINT32 m_subphoneme_count; // number of ticks executed already + UINT8 m_clock_88; // subphoneme clock output @ 88 + UINT8 m_latch_42; // D flip-flop @ 42 + UINT8 m_counter_84; // 4-bit phoneme counter @ 84 + UINT8 m_latch_92; // 2-bit latch @ 92 + + // low parameter clocking + UINT8 m_srff_132; // S/R flip-flop @ 132 + UINT8 m_srff_114; // S/R flip-flop @ 114 + UINT8 m_srff_112; // S/R flip-flop @ 112 + UINT8 m_srff_142; // S/R flip-flop @ 142 + UINT8 m_latch_80; // phoneme timing latch @ 80 + + // glottal circuit + UINT8 m_counter_220; // 4-bit counter @ 220 + UINT8 m_counter_222; // 4-bit counter @ 222 + UINT8 m_counter_224; // 4-bit counter @ 224 + UINT8 m_counter_234; // 4-bit counter @ 234 + UINT8 m_counter_236; // 4-bit counter @ 236 + UINT8 m_fgate; // FGATE signal + UINT8 m_glottal_sync; // Glottal Sync signal + + // transition circuit + UINT8 m_0625_clock; // state of 0.625kHz clock + UINT8 m_counter_46; // 4-bit counter in block @ 46 + UINT8 m_latch_46; // 4-bit latch in block @ 46 + UINT8 m_ram[8]; // RAM to hold parameters + UINT8 m_latch_168; // 4-bit latch @ 168 + UINT8 m_latch_170; // 4-bit latch @ 170 + UINT8 m_f1; // latched 4-bit F1 value + UINT8 m_f2; // latched 5-bit F2 value + UINT8 m_fc; // latched 4-bit FC value + UINT8 m_f3; // latched 4-bit F3 value + UINT8 m_f2q; // latched 4-bit F2Q value + UINT8 m_va; // latched 4-bit VA value + UINT8 m_fa; // latched 4-bit FA value + + // noise generator circuit + UINT8 m_noise_clock; // clock input to noise generator + UINT32 m_shift_252; // shift register @ 252 + UINT8 m_counter_250; // 4-bit counter @ 250 + + // static tables static const char *const s_phoneme_table[64]; + static const UINT16 s_phoneme_duration[64]; + static const double s_glottal_wave[16]; }; @@ -109,7 +181,7 @@ private: //************************************************************************** // device type definition -extern const device_type VOTRAX; +extern const device_type VOTRAX_SC01; #endif /* __VOTRAX_H__ */ diff --git a/src/mame/audio/gottlieb.c b/src/mame/audio/gottlieb.c index 1eb16a71b0b..a4d24bd9b86 100644 --- a/src/mame/audio/gottlieb.c +++ b/src/mame/audio/gottlieb.c @@ -1,19 +1,46 @@ /*************************************************************************** - Gottlieb hardware - dedicated to Warren Davis, Jeff Lee, Tim Skelly & David Thiel + gottlieb.h + + Gottlieb 6502-based sound hardware implementations. + + Dedicated to Warren Davis, Jeff Lee, Tim Skelly & David Thiel + +**************************************************************************** + + Copyright Aaron Giles + All rights reserved. + + Redistribution and use in source and binary forms, with or without + modification, are permitted provided that the following conditions are + met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + * Neither the name 'MAME' nor the names of its contributors may be + used to endorse or promote products derived from this software + without specific prior written permission. + + THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND ANY EXPRESS OR + IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + DISCLAIMED. IN NO EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, + INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING + IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + POSSIBILITY OF SUCH DAMAGE. ***************************************************************************/ +#define ADDRESS_MAP_MODERN #include "emu.h" -#include "debugger.h" -#include "cpu/m6502/m6502.h" -#include "machine/6532riot.h" -#include "sound/samples.h" -#include "sound/dac.h" -#include "sound/ay8910.h" -//#include "sound/votrax.h" -#include "sound/sp0250.h" #include "includes/gottlieb.h" @@ -22,118 +49,26 @@ #define SOUND2_SPEECH_CLOCK XTAL_3_12MHz +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +extern const device_type GOTTLIEB_SOUND_REV1 = &device_creator; +extern const device_type GOTTLIEB_SOUND_REV1_WITH_VOTRAX = &device_creator; +extern const device_type GOTTLIEB_SOUND_REV2 = &device_creator; +//************************************************************************** +// OLD CRAPPY SAMPLE PLAYER +//************************************************************************** +#if USE_FAKE_VOTRAX - - -static void gottlieb1_sh_w(device_t *riot, UINT8 data); -static void gottlieb2_sh_w(address_space *space, UINT8 data); -static void trigger_sample(samples_device *samples, UINT8 data); - - - -/************************************* - * - * Generic interfaces - * - *************************************/ - -WRITE8_HANDLER( gottlieb_sh_w ) +void gottlieb_sound_r1_device::trigger_sample(UINT8 data) { - device_t *riot = space->machine().device("riot"); - - /* identify rev1 boards by the presence of a 6532 RIOT device */ - if (riot != NULL) - gottlieb1_sh_w(riot, data); - else - gottlieb2_sh_w(space, data); -} - - - -/************************************* - * - * Rev. 1 handlers - * - *************************************/ - -static void gottlieb1_sh_w(device_t *riot, UINT8 data) -{ - samples_device *samples = riot->machine().device("samples"); - int pa7 = (data & 0x0f) != 0xf; - int pa0_5 = ~data & 0x3f; - - /* snoop the data looking for commands that need samples */ - if (pa7 && samples != NULL) - trigger_sample(samples, pa0_5); - - /* write the command data to the low 6 bits, and the trigger to the upper bit */ - riot6532_porta_in_set(riot, pa0_5 | (pa7 << 7), 0xbf); -} - - - -/************************************* - * - * Rev. 1 RIOT interfaces - * - *************************************/ - -static WRITE_LINE_DEVICE_HANDLER( snd_interrupt ) -{ - cputag_set_input_line(device->machine(), "audiocpu", M6502_IRQ_LINE, state); -} - - -static WRITE8_DEVICE_HANDLER( r6532_portb_w ) -{ - /* unsure if this is ever used, but the NMI is connected to the RIOT's PB7 */ - cputag_set_input_line(device->machine(), "audiocpu", INPUT_LINE_NMI, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE); -} - - -static const riot6532_interface gottlieb_riot6532_intf = -{ - DEVCB_NULL, - DEVCB_INPUT_PORT("SB1"), - DEVCB_NULL, - DEVCB_HANDLER(r6532_portb_w), - DEVCB_LINE(snd_interrupt) -}; - - - -/************************************* - * - * Rev. 1 sample players - * - *************************************/ - -static void play_sample(samples_device *samples, const char *phonemes) -{ - if (strcmp(phonemes, "[0] HEH3LOOW AH1EH3I3YMTERI2NDAHN") == 0) /* Q-Bert - Hello, I am turned on */ - samples->start(0, 42); - else if (strcmp(phonemes, "[0]BAH1EH1Y") == 0) /* Q-Bert - Bye, bye */ - samples->start(0, 43); - else if (strcmp(phonemes, "[0]A2YHT LEH2FTTH") == 0) /* Reactor - Eight left */ - samples->start(0, 0); - else if (strcmp(phonemes, "[0]SI3KS DTYN LEH2FTTH") == 0) /* Reactor - Sixteen left */ - samples->start(0, 1); - else if (strcmp(phonemes, "[0]WO2RNYNG KO2R UH1NSDTABUH1L") == 0) /* Reactor - Warning core unstable */ - samples->start(0, 5); - else if (strcmp(phonemes, "[0]CHAMBERR AE1EH2KTI1VA1I3DTEH1DT ") == 0) /* Reactor - Chamber activated */ - samples->start(0, 7); -} - - -static void trigger_sample(samples_device *samples, UINT8 data) -{ - gottlieb_state *state = samples->machine().driver_data(); /* Reactor samples */ - if (strcmp(samples->machine().system().name, "reactor") == 0) + if (strcmp(machine().system().name, "reactor") == 0) { switch (data) { @@ -141,17 +76,17 @@ static void trigger_sample(samples_device *samples, UINT8 data) case 56: case 57: case 59: - samples->start(0, data - 53); + m_samples->start(0, data - 53); break; case 31: - state->m_score_sample = 7; + m_score_sample = 7; break; case 39: - state->m_score_sample++; - if (state->m_score_sample < 20) - samples->start(0, state->m_score_sample); + m_score_sample++; + if (m_score_sample < 20) + m_samples->start(0, m_score_sample); break; } } @@ -166,52 +101,28 @@ static void trigger_sample(samples_device *samples, UINT8 data) case 19: case 20: case 21: - samples->start(0, (data - 17) * 8 + state->m_random_offset); - state->m_random_offset = (state->m_random_offset + 1) & 7; + m_samples->start(0, (data - 17) * 8 + m_random_offset); + m_random_offset = (m_random_offset + 1) & 7; break; case 22: - samples->start(0,40); + m_samples->start(0,40); break; case 23: - samples->start(0,41); + m_samples->start(0,41); break; } } } - -#ifdef UNUSED_FUNCTION -void gottlieb_knocker(running_machine &machine) +void gottlieb_sound_r1_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) { - samples_device *samples = space->machine().device("samples"); - if (!strcmp(machine.system().name,"reactor")) /* reactor */ - { - } - else if (samples != NULL) /* qbert */ - samples->start(0,44); -} -#endif - - - -/************************************* - * - * Rev. 1 speech interface - * - *************************************/ - -/* callback for the timer */ -static TIMER_CALLBACK( gottlieb_nmi_generate ) -{ - cputag_set_input_line(machine, "audiocpu", INPUT_LINE_NMI, PULSE_LINE); + m_audiocpu->set_input_line(INPUT_LINE_NMI, PULSE_LINE); } - -static WRITE8_HANDLER( vortrax_data_w ) +void gottlieb_sound_r1_device::fake_votrax_data_w(UINT8 data) { - gottlieb_state *state = space->machine().driver_data(); static const char *const PhonemeTable[0x40] = { "EH3", "EH2", "EH1", "PA0", "DT" , "A1" , "A2" , "ZH", @@ -228,23 +139,22 @@ static WRITE8_HANDLER( vortrax_data_w ) logerror("Votrax: intonation %d, phoneme %02x %s\n",data >> 6,data & 0x3f,PhonemeTable[data & 0x3f]); - state->m_votrax_queue[state->m_votrax_queuepos++] = data; + m_votrax_queue[m_votrax_queuepos++] = data; if ((data & 0x3f) == 0x3f) { - if (state->m_votrax_queuepos > 1) + if (m_votrax_queuepos > 1) { - samples_device *samples = space->machine().device("samples"); int last = -1; int i; char phonemes[200]; phonemes[0] = 0; - for (i = 0;i < state->m_votrax_queuepos-1;i++) + for (i = 0;i < m_votrax_queuepos-1;i++) { static const char *const inf[4] = { "[0]", "[1]", "[2]", "[3]" }; - int phoneme = state->m_votrax_queue[i] & 0x3f; - int inflection = state->m_votrax_queue[i] >> 6; + int phoneme = m_votrax_queue[i] & 0x3f; + int inflection = m_votrax_queue[i] >> 6; if (inflection != last) strcat(phonemes, inf[inflection]); last = inflection; if (phoneme == 0x03 || phoneme == 0x3e) strcat(phonemes," "); @@ -252,93 +162,339 @@ logerror("Votrax: intonation %d, phoneme %02x %s\n",data >> 6,data & 0x3f,Phonem } mame_printf_debug("Votrax played '%s'\n", phonemes); - play_sample(samples, phonemes); -#if 0 - popmessage("%s", phonemes); -#endif + if (strcmp(phonemes, "[0] HEH3LOOW AH1EH3I3YMTERI2NDAHN") == 0) /* Q-Bert - Hello, I am turned on */ + m_samples->start(0, 42); + else if (strcmp(phonemes, "[0]BAH1EH1Y") == 0) /* Q-Bert - Bye, bye */ + m_samples->start(0, 43); + else if (strcmp(phonemes, "[0]A2YHT LEH2FTTH") == 0) /* Reactor - Eight left */ + m_samples->start(0, 0); + else if (strcmp(phonemes, "[0]SI3KS DTYN LEH2FTTH") == 0) /* Reactor - Sixteen left */ + m_samples->start(0, 1); + else if (strcmp(phonemes, "[0]WO2RNYNG KO2R UH1NSDTABUH1L") == 0) /* Reactor - Warning core unstable */ + m_samples->start(0, 5); + else if (strcmp(phonemes, "[0]CHAMBERR AE1EH2KTI1VA1I3DTEH1DT ") == 0) /* Reactor - Chamber activated */ + m_samples->start(0, 7); } - state->m_votrax_queuepos = 0; + m_votrax_queuepos = 0; } /* generate a NMI after a while to make the CPU continue to send data */ - space->machine().scheduler().timer_set(attotime::from_usec(50), FUNC(gottlieb_nmi_generate)); + timer_set(attotime::from_usec(50)); } -static WRITE8_HANDLER( speech_clock_dac_w ) +static const char *const reactor_sample_names[] = { - gottlieb_state *state = space->machine().driver_data(); -if (data != state->m_last) - mame_printf_debug("clock = %02X\n", data); -state->m_last = data; -} + "*reactor", + "fx_53", /* "8 left" */ + "fx_54", /* "16 left" */ + "fx_55", /* "24 left" */ + "fx_56", /* "32 left" */ + "fx_57", /* "40 left" */ + "fx_58", /* "warning, core unstable" */ + "fx_59", /* "bonus" */ + "fx_31", /* "chamber activated" */ + "fx_39a", /* "2000" */ + "fx_39b", /* "5000" */ + "fx_39c", /* "10000" */ + "fx_39d", /* "15000" */ + "fx_39e", /* "20000" */ + "fx_39f", /* "25000" */ + "fx_39g", /* "30000" */ + "fx_39h", /* "35000" */ + "fx_39i", /* "40000" */ + "fx_39j", /* "45000" */ + "fx_39k", /* "50000" */ + "fx_39l", /* "55000" */ + 0 /* end of array */ +}; - -/************************************* - * - * Rev 1. initialization - * - *************************************/ - -static SOUND_START( gottlieb1 ) +static const char *const qbert_sample_names[] = { - gottlieb_state *state = machine.driver_data(); - state->m_score_sample = 7; - state->m_random_offset = 0; + "*qbert", + "fx_17a", /* random speech, voice clock 255 */ + "fx_17b", /* random speech, voice clock 255 */ + "fx_17c", /* random speech, voice clock 255 */ + "fx_17d", /* random speech, voice clock 255 */ + "fx_17e", /* random speech, voice clock 255 */ + "fx_17f", /* random speech, voice clock 255 */ + "fx_17g", /* random speech, voice clock 255 */ + "fx_17h", /* random speech, voice clock 255 */ + "fx_18a", /* random speech, voice clock 176 */ + "fx_18b", /* random speech, voice clock 176 */ + "fx_18c", /* random speech, voice clock 176 */ + "fx_18d", /* random speech, voice clock 176 */ + "fx_18e", /* random speech, voice clock 176 */ + "fx_18f", /* random speech, voice clock 176 */ + "fx_18g", /* random speech, voice clock 176 */ + "fx_18h", /* random speech, voice clock 176 */ + "fx_19a", /* random speech, voice clock 128 */ + "fx_19b", /* random speech, voice clock 128 */ + "fx_19c", /* random speech, voice clock 128 */ + "fx_19d", /* random speech, voice clock 128 */ + "fx_19e", /* random speech, voice clock 128 */ + "fx_19f", /* random speech, voice clock 128 */ + "fx_19g", /* random speech, voice clock 128 */ + "fx_19h", /* random speech, voice clock 128 */ + "fx_20a", /* random speech, voice clock 96 */ + "fx_20b", /* random speech, voice clock 96 */ + "fx_20c", /* random speech, voice clock 96 */ + "fx_20d", /* random speech, voice clock 96 */ + "fx_20e", /* random speech, voice clock 96 */ + "fx_20f", /* random speech, voice clock 96 */ + "fx_20g", /* random speech, voice clock 96 */ + "fx_20h", /* random speech, voice clock 96 */ + "fx_21a", /* random speech, voice clock 62 */ + "fx_21b", /* random speech, voice clock 62 */ + "fx_21c", /* random speech, voice clock 62 */ + "fx_21d", /* random speech, voice clock 62 */ + "fx_21e", /* random speech, voice clock 62 */ + "fx_21f", /* random speech, voice clock 62 */ + "fx_21g", /* random speech, voice clock 62 */ + "fx_21h", /* random speech, voice clock 62 */ + "fx_22", /* EH2 with decreasing voice clock */ + "fx_23", /* O1 with varying voice clock */ + "fx_28", + "fx_36", + "knocker", + 0 /* end of array */ +}; - state_save_register_global_array(machine, state->m_votrax_queue); - state_save_register_global(machine, state->m_votrax_queuepos); +static const samples_interface reactor_samples_interface = +{ + 1, /* one channel */ + reactor_sample_names +}; + +static const samples_interface qbert_samples_interface = +{ + 1, /* one channel */ + qbert_sample_names +}; + +MACHINE_CONFIG_FRAGMENT( reactor_samples ) + MCFG_SAMPLES_ADD("samples", reactor_samples_interface) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( qbert_samples ) + MCFG_SAMPLES_ADD("samples", qbert_samples_interface) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + +#endif + + + +//************************************************************************** +// REV 1 SOUND BOARD: 6502 + DAC +//************************************************************************** + +//------------------------------------------------- +// gottlieb_sound_r1_device - constructors +//------------------------------------------------- + +gottlieb_sound_r1_device::gottlieb_sound_r1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GOTTLIEB_SOUND_REV1, "Gottlieb Sound rev. 1", "gotsndr1", tag, owner, clock), + device_mixer_interface(mconfig, *this), + m_audiocpu(*this, "audiocpu"), + m_riot(*this, "riot"), + m_dac(*this, "dac"), + m_votrax(*this, "votrax"), + m_populate_votrax(false), + m_last_speech_clock(0) +#if USE_FAKE_VOTRAX + , m_samples(*this, ":samples"), + m_score_sample(0), + m_random_offset(0), + m_votrax_queuepos(0) +#endif +{ +} + +gottlieb_sound_r1_device::gottlieb_sound_r1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, bool populate_votrax) + : device_t(mconfig, GOTTLIEB_SOUND_REV1, "Gottlieb Sound rev. 1", "gotsndr1", tag, owner, clock), + device_mixer_interface(mconfig, *this), + m_audiocpu(*this, "audiocpu"), + m_riot(*this, "riot"), + m_dac(*this, "dac"), + m_votrax(*this, "votrax"), + m_populate_votrax(populate_votrax), + m_last_speech_clock(0) +#if USE_FAKE_VOTRAX + , m_samples(*this, ":samples"), + m_score_sample(0), + m_random_offset(0), + m_votrax_queuepos(0) +#endif +{ } +//------------------------------------------------- +// write - handle an external command write +//------------------------------------------------- -/************************************* - * - * Rev 1. address map - * - *************************************/ +WRITE8_MEMBER( gottlieb_sound_r1_device::write ) +{ + // write the command data to the low 6 bits, and the trigger to the upper bit + UINT8 pa7 = (data & 0x0f) != 0xf; + UINT8 pa0_5 = ~data & 0x3f; + m_riot->porta_in_set(pa0_5 | (pa7 << 7), 0xbf); -static ADDRESS_MAP_START( gottlieb_sound1_map, AS_PROGRAM, 8 ) - /* A15 not decoded except in expansion socket */ +#if USE_FAKE_VOTRAX + if (pa7 && m_samples != NULL) + trigger_sample(pa0_5); +#endif +} + + +//------------------------------------------------- +// snd_interrupt - signal a sound interrupt +//------------------------------------------------- + +WRITE_LINE_MEMBER( gottlieb_sound_r1_device::snd_interrupt ) +{ + m_audiocpu->set_input_line(M6502_IRQ_LINE, state); +} + + +//------------------------------------------------- +// r6532_portb_w - handle writes to the RIOT's +// port B +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r1_device::r6532_portb_w ) +{ + // unsure if this is ever used, but the NMI is connected to the RIOT's PB7 + m_audiocpu->set_input_line(INPUT_LINE_NMI, (data & 0x80) ? CLEAR_LINE : ASSERT_LINE); +} + + +//------------------------------------------------- +// votrax_data_w - write data to the Votrax SC-01 +// speech chip +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r1_device::votrax_data_w ) +{ + if (m_votrax != NULL) + { + m_votrax->inflection_w(space, offset, data >> 6); + m_votrax->write(space, offset, ~data & 0x3f); + } + +#if USE_FAKE_VOTRAX + fake_votrax_data_w(data); +#endif +} + + +//------------------------------------------------- +// speech_clock_dac_w - modify the clock driving +// the Votrax SC-01 speech chip +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r1_device::speech_clock_dac_w ) +{ + if (m_votrax != NULL) + { + // nominal clock is 0xa0 + if (data != m_last_speech_clock) + { + mame_printf_debug("clock = %02X\n", data); + + // totally random guesswork; would like to get real measurements on a board + if (m_votrax != NULL) + m_votrax->set_unscaled_clock(600000 + (data - 0xa0) * 10000); + m_last_speech_clock = data; + } + } +} + + +//------------------------------------------------- +// votrax_request - map the VOTRAX SC-01 request +// line to the NMI pin on the sound chip +//------------------------------------------------- + +WRITE_LINE_MEMBER( gottlieb_sound_r1_device::votrax_request ) +{ + m_audiocpu->set_input_line(INPUT_LINE_NMI, state); +} + + +//------------------------------------------------- +// RIOT interface +//------------------------------------------------- + +static const riot6532_interface gottlieb_riot6532_intf = +{ + DEVCB_NULL, + DEVCB_INPUT_PORT("SB1"), + DEVCB_NULL, + DEVCB_DEVICE_MEMBER(DEVICE_SELF_OWNER, gottlieb_sound_r1_device, r6532_portb_w), + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, gottlieb_sound_r1_device, snd_interrupt) +}; + + +//------------------------------------------------- +// VOTRAX interface +//------------------------------------------------- + +static const votrax_sc01_interface gottlieb_votrax_interface = +{ + DEVCB_DEVICE_LINE_MEMBER(DEVICE_SELF_OWNER, gottlieb_sound_r1_device, votrax_request) +}; + + +//------------------------------------------------- +// audio CPU map +//------------------------------------------------- + +static ADDRESS_MAP_START( gottlieb_sound_r1_map, AS_PROGRAM, 8, gottlieb_sound_r1_device ) + // A15 not decoded except in expansion socket ADDRESS_MAP_GLOBAL_MASK(0x7fff) AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x0d80) AM_RAM - AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0de0) AM_DEVREADWRITE("riot", riot6532_r, riot6532_w) - AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x0fff) AM_DEVWRITE("dac", dac_w) - AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x0fff) AM_WRITE(vortrax_data_w) + AM_RANGE(0x0200, 0x021f) AM_MIRROR(0x0de0) AM_DEVREADWRITE("riot", riot6532_device, read, write) + AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x0fff) AM_DEVWRITE_LEGACY("dac", dac_w) + AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x0fff) AM_WRITE(votrax_data_w) AM_RANGE(0x3000, 0x3000) AM_MIRROR(0x0fff) AM_WRITE(speech_clock_dac_w) AM_RANGE(0x6000, 0x7fff) AM_ROM ADDRESS_MAP_END +//------------------------------------------------- +// machine configuration +//------------------------------------------------- -/************************************* - * - * Rev. 1 machine driver - * - *************************************/ - -MACHINE_CONFIG_FRAGMENT( gottlieb_soundrev1 ) - MCFG_SOUND_START(gottlieb1) +MACHINE_CONFIG_FRAGMENT( gottlieb_sound_r1 ) + // audio CPU + MCFG_CPU_ADD("audiocpu", M6502, SOUND1_CLOCK/4) // the board can be set to /2 as well + MCFG_CPU_PROGRAM_MAP(gottlieb_sound_r1_map) + // I/O configuration MCFG_RIOT6532_ADD("riot", SOUND1_CLOCK/4, gottlieb_riot6532_intf) - MCFG_CPU_ADD("audiocpu", M6502, SOUND1_CLOCK/4) /* the board can be set to /2 as well */ - MCFG_CPU_PROGRAM_MAP(gottlieb_sound1_map) - - /* sound hardware */ + // sound devices MCFG_SOUND_ADD("dac", DAC, 0) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 0.50) +MACHINE_CONFIG_END + +MACHINE_CONFIG_FRAGMENT( gottlieb_sound_r1_with_votrax ) + MCFG_FRAGMENT_ADD(gottlieb_sound_r1) + + // add the VOTRAX + MCFG_VOTRAX_SC01_ADD("votrax", 720000, gottlieb_votrax_interface) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 0.50) MACHINE_CONFIG_END +//------------------------------------------------- +// input ports +//------------------------------------------------- -/************************************* - * - * Rev. 1 input ports - * - *************************************/ - -INPUT_PORTS_START( gottlieb1_sound ) +INPUT_PORTS_START( gottlieb_sound_r1 ) PORT_START("SB1") PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SB1:7" ) PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SB1:6" ) @@ -349,341 +505,387 @@ INPUT_PORTS_START( gottlieb1_sound ) PORT_DIPNAME( 0x40, 0x40, "Sound Test" ) PORT_DIPLOCATION("SB1:2") PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_BIT( 0x80, 0x80, IPT_UNKNOWN ) /* To U3-6 on QBert */ + PORT_BIT( 0x80, 0x80, IPT_SPECIAL ) +INPUT_PORTS_END + +INPUT_PORTS_START( gottlieb_sound_r1_with_votrax ) + PORT_INCLUDE(gottlieb_sound_r1) + PORT_MODIFY("SB1") + PORT_BIT( 0x80, 0x80, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER("votrax", votrax_sc01_device, request) INPUT_PORTS_END +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- -/************************************* - * - * Rev. 2 communication handlers - * - *************************************/ - -static void gottlieb2_sh_w(address_space *space, UINT8 data) +machine_config_constructor gottlieb_sound_r1_device::device_mconfig_additions() const { - gottlieb_state *state = space->machine().driver_data(); - /* when data is not 0xff, the transparent latch at A3 allows it to pass through unmolested */ + return MACHINE_CONFIG_NAME( gottlieb_sound_r1 ); +} + + +//------------------------------------------------- +// device_input_ports - return a pointer to +// the device's I/O ports +//------------------------------------------------- + +ioport_constructor gottlieb_sound_r1_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( gottlieb_sound_r1 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gottlieb_sound_r1_device::device_start() +{ +} + + + +//************************************************************************** +// REV 1 SOUND BOARD WITH VOTRAX +//************************************************************************** + +//------------------------------------------------- +// gottlieb_sound_r1_with_votrax_device - +// constructor +//------------------------------------------------- + +gottlieb_sound_r1_with_votrax_device::gottlieb_sound_r1_with_votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : gottlieb_sound_r1_device(mconfig, tag, owner, clock, true) +{ +} + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor gottlieb_sound_r1_with_votrax_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( gottlieb_sound_r1_with_votrax ); +} + + +//------------------------------------------------- +// device_input_ports - return a pointer to +// the device's I/O ports +//------------------------------------------------- + +ioport_constructor gottlieb_sound_r1_with_votrax_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( gottlieb_sound_r1_with_votrax ); +} + + + +//************************************************************************** +// REV 2 SOUND BOARD: 6502 + 2 x DAC + 2 x AY-8913 +//************************************************************************** + +//------------------------------------------------- +// gottlieb_sound_r2_device - constructor +//------------------------------------------------- + +gottlieb_sound_r2_device::gottlieb_sound_r2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) + : device_t(mconfig, GOTTLIEB_SOUND_REV2, "Gottlieb Sound rev. 2", "gotsndr2", tag, owner, clock), + device_mixer_interface(mconfig, *this), + m_audiocpu(*this, "audiocpu"), + m_speechcpu(*this, "speechcpu"), + m_dac(*this, "dac"), + m_ay1(*this, "ay1"), + m_ay2(*this, "ay2"), + m_sp0250(*this, "spsnd"), + m_cobram3_mod(false), + m_nmi_timer(NULL), + m_nmi_state(0), + m_audiocpu_latch(0), + m_speechcpu_latch(0), + m_speech_control(0), + m_last_command(0), + m_psg_latch(0), + m_psg_data_latch(0), + m_sp0250_latch(0) +{ +} + + +//------------------------------------------------- +// static_enable_cobram3_mods - enable changes +// for cobram3 +//------------------------------------------------- + +void gottlieb_sound_r2_device::static_enable_cobram3_mods(device_t &device) +{ + downcast(device).m_cobram3_mod = true; +} + + +//------------------------------------------------- +// write - handle an external command write +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r2_device::write ) +{ + // when data is not 0xff, the transparent latch at A3 allows it to pass through unmolested if (data != 0xff) { - /* each CPU has its own latch */ - soundlatch_w(space, 0, data); - soundlatch2_w(space, 0, data); + // latch data on a timer + synchronize(TID_SOUND_LATCH_WRITE, data); - /* if the previous data was 0xff, clock an IRQ on each */ - if (state->m_last_command == 0xff) + // if the previous data was 0xff, clock an IRQ on each + if (m_last_command == 0xff) { - cputag_set_input_line(space->machine(), "audiocpu", M6502_IRQ_LINE, ASSERT_LINE); - cputag_set_input_line(space->machine(), "speech", M6502_IRQ_LINE, ASSERT_LINE); + m_audiocpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); + m_speechcpu->set_input_line(M6502_IRQ_LINE, ASSERT_LINE); } } - state->m_last_command = data; + m_last_command = data; } -static READ8_HANDLER( speech_data_r ) +//------------------------------------------------- +// nmi_timer_adjust - adjust the NMI timer to +// fire based on its configured rate +//------------------------------------------------- + +inline void gottlieb_sound_r2_device::nmi_timer_adjust() { - cputag_set_input_line(space->machine(), "speech", M6502_IRQ_LINE, CLEAR_LINE); - return soundlatch_r(space, offset); + // adjust timer to go off in the future based on the current rate + m_nmi_timer->adjust(attotime::from_hz(SOUND2_CLOCK/16) * (256 * (256 - m_nmi_rate))); } -static READ8_HANDLER( audio_data_r ) +//------------------------------------------------- +// nmi_state_update - update the NMI state based +// on the timer firing and the enable control +//------------------------------------------------- + +inline void gottlieb_sound_r2_device::nmi_state_update() { - cputag_set_input_line(space->machine(), "audiocpu", M6502_IRQ_LINE, CLEAR_LINE); - return soundlatch2_r(space, offset); + // update the NMI line state based on the enable and state + m_speechcpu->set_input_line(INPUT_LINE_NMI, (m_nmi_state && (m_speech_control & 1)) ? ASSERT_LINE : CLEAR_LINE); } -static WRITE8_HANDLER( signal_audio_nmi_w ) +//------------------------------------------------- +// speech_data_r - read the input command latch +// from the audio CPU +//------------------------------------------------- + +READ8_MEMBER( gottlieb_sound_r2_device::audio_data_r ) { - cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_NMI, ASSERT_LINE); - cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_NMI, CLEAR_LINE); + m_audiocpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + return m_audiocpu_latch; } +//------------------------------------------------- +// speech_data_r - read the input command latch +// from the speech CPU +//------------------------------------------------- -/************************************* - * - * Rev. 2 NMI timer - * - *************************************/ - -INLINE void nmi_timer_adjust(running_machine &machine) +READ8_MEMBER( gottlieb_sound_r2_device::speech_data_r ) { - gottlieb_state *state = machine.driver_data(); - /* adjust timer to go off in the future based on the current rate */ - state->m_nmi_timer->adjust(attotime::from_hz(SOUND2_CLOCK/16) * (256 * (256 - state->m_nmi_rate))); + m_speechcpu->set_input_line(M6502_IRQ_LINE, CLEAR_LINE); + return m_speechcpu_latch; } -INLINE void nmi_state_update(running_machine &machine) +//------------------------------------------------- +// signal_audio_nmi_w - signal an NMI from the +// speech CPU to the audio CPU +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r2_device::signal_audio_nmi_w ) { - gottlieb_state *state = machine.driver_data(); - /* update the NMI line state based on the enable and state */ - cputag_set_input_line(machine, "speech", INPUT_LINE_NMI, (state->m_nmi_state && (state->m_speech_control & 1)) ? ASSERT_LINE : CLEAR_LINE); + m_audiocpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE); + m_audiocpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE); } -static TIMER_CALLBACK( nmi_clear ) +//------------------------------------------------- +// nmi_rate_w - adjust the NMI rate on the speech +// CPU +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r2_device::nmi_rate_w ) { - gottlieb_state *state = machine.driver_data(); - /* clear the NMI state and update it */ - state->m_nmi_state = 0; - nmi_state_update(machine); + // the new rate is picked up when the previous timer expires + m_nmi_rate = data; } -static TIMER_CALLBACK( nmi_callback ) +//------------------------------------------------- +// speech_drq_custom_r - return the SP0250 +// request line as an input port bit +//------------------------------------------------- + +CUSTOM_INPUT_MEMBER( gottlieb_sound_r2_device::speech_drq_custom_r ) { - gottlieb_state *state = machine.driver_data(); - /* assert the NMI if it is not disabled */ - state->m_nmi_state = 1; - nmi_state_update(machine); - - /* set a timer to turn it off again on hte next SOUND_CLOCK/16 */ - machine.scheduler().timer_set(attotime::from_hz(SOUND2_CLOCK/16), FUNC(nmi_clear)); - - /* adjust the NMI timer for the next time */ - nmi_timer_adjust(machine); + return sp0250_drq_r(m_sp0250); } -static WRITE8_HANDLER( nmi_rate_w ) +//------------------------------------------------- +// dac_w - write to one of the two DACs on the +// board +//------------------------------------------------- + +WRITE8_MEMBER( gottlieb_sound_r2_device::dac_w ) { - gottlieb_state *state = space->machine().driver_data(); - /* the new rate is picked up when the previous timer expires */ - state->m_nmi_rate = data; + // dual DAC; the first DAC serves as the reference voltage for the + // second, effectively scaling the output + m_dac_data[offset] = data; + dac_data_16_w(m_dac, m_dac_data[0] * m_dac_data[1]); } +//------------------------------------------------- +// speech_control_w - primary audio control +// register on the speech board +//------------------------------------------------- -/************************************* - * - * Rev. 2 sound chip access - * - *************************************/ - -static CUSTOM_INPUT( speech_drq_custom_r ) +WRITE8_MEMBER( gottlieb_sound_r2_device::speech_control_w ) { - return sp0250_drq_r(field.machine().device("spsnd")); -} + UINT8 previous = m_speech_control; + m_speech_control = data; + // bit 0 enables/disables the NMI line + nmi_state_update(); -static WRITE8_DEVICE_HANDLER( gottlieb_dac_w ) -{ - gottlieb_state *state = device->machine().driver_data(); - /* dual DAC; the first DAC serves as the reference voltage for the - second, effectively scaling the output */ - state->m_dac_data[offset] = data; - dac_data_16_w(device, state->m_dac_data[0] * state->m_dac_data[1]); -} - - -static WRITE8_HANDLER( speech_control_w ) -{ - gottlieb_state *state = space->machine().driver_data(); - UINT8 previous = state->m_speech_control; - state->m_speech_control = data; - - /* bit 0 enables/disables the NMI line */ - nmi_state_update(space->machine()); - - /* bit 1 controls a LED on the sound board */ - - /* bit 2 goes to 8913 BDIR pin */ - if ((previous & 0x04) != 0 && (data & 0x04) == 0) + // bit 1 controls a LED on the sound board + + // bits 2-4 control the AY-8913, but act differently between the + // standard sound board and the modified Cobra Command board + if (!m_cobram3_mod) { - /* bit 3 selects which of the two 8913 to enable */ - /* bit 4 goes to the 8913 BC1 pin */ - device_t *ay = space->machine().device((data & 0x08) ? "ay1" : "ay2"); - ay8910_data_address_w(ay, data >> 4, *state->m_psg_latch); - } - - /* bit 5 goes to the speech chip DIRECT DATA TEST pin */ - - /* bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data */ - if ((previous & 0x40) == 0 && (data & 0x40) != 0) - { - device_t *sp = space->machine().device("spsnd"); - sp0250_w(sp, 0, *state->m_sp0250_latch); - } - - /* bit 7 goes to the speech chip RESET pin */ - if ((previous ^ data) & 0x80) - space->machine().device("spsnd")->reset(); -} - -static WRITE8_HANDLER( cobram3_speech_control_w ) -{ - gottlieb_state *state = space->machine().driver_data(); - UINT8 previous = state->m_speech_control; - state->m_speech_control = data; - - /* bit 0 enables/disables the NMI line */ - nmi_state_update(space->machine()); - - /* bit 1 controls a LED on the sound board */ - - if ( data & 0x10 ) - { - state->m_psg_data_latch = *state->m_psg_latch; + // bit 2 goes to 8913 BDIR pin + if ((previous & 0x04) != 0 && (data & 0x04) == 0) + { + // bit 3 selects which of the two 8913 to enable + // bit 4 goes to the 8913 BC1 pin + if ((data & 0x08) != 0) + ay8910_data_address_w(m_ay1, data >> 4, m_psg_latch); + else + ay8910_data_address_w(m_ay2, data >> 4, m_psg_latch); + } } else { - device_t *ay = space->machine().device((data & 0x08) ? "ay1" : "ay2"); - ay8910_address_w(ay, 0, *state->m_psg_latch); - ay8910_data_w(ay, 0, state->m_psg_data_latch); + if ( data & 0x10 ) + { + m_psg_data_latch = m_psg_latch; + } + else + { + device_t *ay = machine().device((data & 0x08) ? "ay1" : "ay2"); + ay8910_address_w(ay, 0, m_psg_latch); + ay8910_data_w(ay, 0, m_psg_data_latch); + } } - /* bit 5 goes to the speech chip DIRECT DATA TEST pin */ - /* bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data */ + // bit 5 goes to the speech chip DIRECT DATA TEST pin + + // bit 6 = speech chip DATA PRESENT pin; high then low to make the chip read data if ((previous & 0x40) == 0 && (data & 0x40) != 0) - { - device_t *sp = space->machine().device("spsnd"); - sp0250_w(sp, 0, *state->m_sp0250_latch); - } + sp0250_w(m_sp0250, 0, m_sp0250_latch); - /* bit 7 goes to the speech chip RESET pin */ + // bit 7 goes to the speech chip RESET pin if ((previous ^ data) & 0x80) - space->machine().device("spsnd")->reset(); + m_sp0250->reset(); } -/************************************* - * - * Rev. 2 initialization - * - *************************************/ +//------------------------------------------------- +// psg_latch_w - store an 8-bit value in the PSG +// latch register +//------------------------------------------------- -static SOUND_START( gottlieb2 ) +WRITE8_MEMBER( gottlieb_sound_r2_device::psg_latch_w ) { - gottlieb_state *state = machine.driver_data(); - /* set up the NMI timer */ - state->m_nmi_timer = machine.scheduler().timer_alloc(FUNC(nmi_callback)); - state->m_nmi_rate = 0; - nmi_timer_adjust(machine); - - state->m_dac_data[0] = state->m_dac_data[1] = 0xff; - - /* register for save states */ - state_save_register_global(machine, state->m_nmi_rate); - state_save_register_global(machine, state->m_nmi_state); - state_save_register_global(machine, state->m_speech_control); - state_save_register_global(machine, state->m_last_command); + m_psg_latch = data; } +//------------------------------------------------- +// psg_latch_w - store an 8-bit value in the +// SP0250 latch register +//------------------------------------------------- -/************************************* - * - * Rev. 2 address map - * - *************************************/ - -static ADDRESS_MAP_START( gottlieb_speech2_map, AS_PROGRAM, 8 ) - AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x1c00) AM_RAM - AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x1fff) AM_WRITEONLY AM_BASE_MEMBER(gottlieb_state, m_sp0250_latch) - AM_RANGE(0x4000, 0x4000) AM_MIRROR(0x1fff) AM_WRITE(speech_control_w) - AM_RANGE(0x6000, 0x6000) AM_MIRROR(0x1fff) AM_READ_PORT("SB2") - AM_RANGE(0x8000, 0x8000) AM_MIRROR(0x1fff) AM_WRITEONLY AM_BASE_MEMBER(gottlieb_state, m_psg_latch) - AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x07ff) AM_WRITE(nmi_rate_w) - AM_RANGE(0xa800, 0xa800) AM_MIRROR(0x07ff) AM_READ(speech_data_r) - AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x07ff) AM_WRITE(signal_audio_nmi_w) - AM_RANGE(0xc000, 0xffff) AM_ROM -ADDRESS_MAP_END +WRITE8_MEMBER( gottlieb_sound_r2_device::sp0250_latch_w ) +{ + m_sp0250_latch = data; +} -static ADDRESS_MAP_START( gottlieb_cobram3_speech2_map, AS_PROGRAM, 8 ) - AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x1c00) AM_RAM - AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x1fff) AM_WRITEONLY AM_BASE_MEMBER(gottlieb_state, m_sp0250_latch) - AM_RANGE(0x4000, 0x4000) AM_MIRROR(0x1fff) AM_WRITE(cobram3_speech_control_w) - AM_RANGE(0x6000, 0x6000) AM_MIRROR(0x1fff) AM_READ_PORT("SB2") - AM_RANGE(0x8000, 0x8000) AM_MIRROR(0x1fff) AM_WRITEONLY AM_BASE_MEMBER(gottlieb_state, m_psg_latch) - AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x07ff) AM_WRITE(nmi_rate_w) - AM_RANGE(0xa800, 0xa800) AM_MIRROR(0x07ff) AM_READ(speech_data_r) - AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x07ff) AM_WRITE(signal_audio_nmi_w) - AM_RANGE(0xc000, 0xffff) AM_ROM -ADDRESS_MAP_END +//------------------------------------------------- +// sound CPU address map +//------------------------------------------------- -static ADDRESS_MAP_START( gottlieb_audio2_map, AS_PROGRAM, 8 ) +static ADDRESS_MAP_START( gottlieb_sound_r2_map, AS_PROGRAM, 8, gottlieb_sound_r2_device ) AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x3c00) AM_RAM - AM_RANGE(0x4000, 0x4001) AM_MIRROR(0x3ffe) AM_DEVWRITE("dac1", gottlieb_dac_w) AM_BASE_MEMBER(gottlieb_state, m_dac_data) + AM_RANGE(0x4000, 0x4001) AM_MIRROR(0x3ffe) AM_WRITE(dac_w) AM_RANGE(0x8000, 0x8000) AM_MIRROR(0x3fff) AM_READ(audio_data_r) AM_RANGE(0xe000, 0xffff) AM_MIRROR(0x2000) AM_ROM ADDRESS_MAP_END +//------------------------------------------------- +// sppech CPU address map +//------------------------------------------------- -/************************************* - * - * Rev. 2 machine driver - * - *************************************/ +static ADDRESS_MAP_START( gottlieb_speech_r2_map, AS_PROGRAM, 8, gottlieb_sound_r2_device ) + AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x1c00) AM_RAM + AM_RANGE(0x2000, 0x2000) AM_MIRROR(0x1fff) AM_WRITE(sp0250_latch_w) + AM_RANGE(0x4000, 0x4000) AM_MIRROR(0x1fff) AM_WRITE(speech_control_w) + AM_RANGE(0x6000, 0x6000) AM_MIRROR(0x1fff) AM_READ_PORT("SB2") + AM_RANGE(0x8000, 0x8000) AM_MIRROR(0x1fff) AM_WRITE(psg_latch_w) + AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x07ff) AM_WRITE(nmi_rate_w) + AM_RANGE(0xa800, 0xa800) AM_MIRROR(0x07ff) AM_READ(speech_data_r) + AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x07ff) AM_WRITE(signal_audio_nmi_w) + AM_RANGE(0xc000, 0xffff) AM_ROM +ADDRESS_MAP_END -MACHINE_CONFIG_FRAGMENT( gottlieb_soundrev2 ) - /* audio CPUs */ + +//------------------------------------------------- +// machine configuration +//------------------------------------------------- + +MACHINE_CONFIG_FRAGMENT( gottlieb_sound_r2 ) + // audio CPUs MCFG_CPU_ADD("audiocpu", M6502, SOUND2_CLOCK/4) - MCFG_CPU_PROGRAM_MAP(gottlieb_audio2_map) + MCFG_CPU_PROGRAM_MAP(gottlieb_sound_r2_map) - MCFG_CPU_ADD("speech", M6502, SOUND2_CLOCK/4) - MCFG_CPU_PROGRAM_MAP(gottlieb_speech2_map) + MCFG_CPU_ADD("speechcpu", M6502, SOUND2_CLOCK/4) + MCFG_CPU_PROGRAM_MAP(gottlieb_speech_r2_map) - /* sound hardware */ - MCFG_SOUND_START( gottlieb2 ) - - MCFG_SOUND_ADD("dac1", DAC, 0) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) - - MCFG_SOUND_ADD("dac2", DAC, 0) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + // sound hardware + MCFG_SOUND_ADD("dac", DAC, 0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 0.15) MCFG_SOUND_ADD("ay1", AY8913, SOUND2_CLOCK/2) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 0.15) MCFG_SOUND_ADD("ay2", AY8913, SOUND2_CLOCK/2) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 0.15) MCFG_SOUND_ADD("spsnd", SP0250, SOUND2_SPEECH_CLOCK) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) -MACHINE_CONFIG_END - -MACHINE_CONFIG_FRAGMENT( gottlieb_cobram3_soundrev2 ) - /* audio CPUs */ - MCFG_CPU_ADD("audiocpu", M6502, SOUND2_CLOCK/4) - MCFG_DEVICE_DISABLE() - MCFG_CPU_PROGRAM_MAP(gottlieb_audio2_map) - - MCFG_CPU_ADD("speech", M6502, SOUND2_CLOCK/4) - MCFG_CPU_PROGRAM_MAP(gottlieb_cobram3_speech2_map) - - /* sound hardware */ - MCFG_SOUND_START( gottlieb2 ) - - MCFG_SOUND_ADD("dac1", DAC, 0) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) - - MCFG_SOUND_ADD("dac2", DAC, 0) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.15) - - MCFG_SOUND_ADD("ay1", AY8913, SOUND2_CLOCK/2) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) - - MCFG_SOUND_ADD("ay2", AY8913, SOUND2_CLOCK/2) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) - - MCFG_SOUND_ADD("spsnd", SP0250, SOUND2_SPEECH_CLOCK) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 1.0) MACHINE_CONFIG_END -/************************************* - * - * Rev. 2 input ports - * - *************************************/ +//------------------------------------------------- +// input ports +//------------------------------------------------- -INPUT_PORTS_START( gottlieb2_sound ) +INPUT_PORTS_START( gottlieb_sound_r2 ) PORT_START("SB2") PORT_DIPUNKNOWN_DIPLOC( 0x01, 0x01, "SB2:1") PORT_DIPUNKNOWN_DIPLOC( 0x02, 0x02, "SB2:2") @@ -694,5 +896,88 @@ INPUT_PORTS_START( gottlieb2_sound ) PORT_DIPNAME( 0x40, 0x40, "Sound Test" ) PORT_DIPLOCATION("SB2:7") PORT_DIPSETTING( 0x40, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(speech_drq_custom_r, NULL) + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, gottlieb_sound_r2_device, speech_drq_custom_r, NULL) INPUT_PORTS_END + + +//------------------------------------------------- +// device_mconfig_additions - return a pointer to +// the device's machine fragment +//------------------------------------------------- + +machine_config_constructor gottlieb_sound_r2_device::device_mconfig_additions() const +{ + return MACHINE_CONFIG_NAME( gottlieb_sound_r2 ); +} + + +//------------------------------------------------- +// device_input_ports - return a pointer to +// the device's I/O ports +//------------------------------------------------- + +ioport_constructor gottlieb_sound_r2_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( gottlieb_sound_r2 ); +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void gottlieb_sound_r2_device::device_start() +{ + // set up the NMI timer + m_nmi_timer = timer_alloc(TID_NMI_GENERATE); + m_nmi_rate = 0; + nmi_timer_adjust(); + + // reset the DACs + m_dac_data[0] = m_dac_data[1] = 0xff; + + // disable the non-speech CPU for cobram3 + if (m_cobram3_mod) + m_audiocpu->set_input_line(INPUT_LINE_HALT, ASSERT_LINE); + + // register for save states + save_item(NAME(m_nmi_rate)); + save_item(NAME(m_nmi_state)); + save_item(NAME(m_speech_control)); + save_item(NAME(m_last_command)); +} + + +//------------------------------------------------- +// device_timer - handle timer-based behaviors +//------------------------------------------------- + +void gottlieb_sound_r2_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) +{ + switch (id) + { + case TID_NMI_GENERATE: + // update state + m_nmi_state = 1; + nmi_state_update(); + + // set a timer to turn it off again on hte next SOUND_CLOCK/16 + timer_set(attotime::from_hz(SOUND2_CLOCK/16), TID_NMI_CLEAR); + + // adjust the NMI timer for the next time + nmi_timer_adjust(); + break; + + case TID_NMI_CLEAR: + // update state + m_nmi_state = 0; + nmi_state_update(); + break; + + case TID_SOUND_LATCH_WRITE: + // each CPU has its own latch + m_audiocpu_latch = param; + m_speechcpu_latch = param; + break; + } +} diff --git a/src/mame/drivers/gottlieb.c b/src/mame/drivers/gottlieb.c index 864237e7fe0..c6b727d31a5 100644 --- a/src/mame/drivers/gottlieb.c +++ b/src/mame/drivers/gottlieb.c @@ -194,7 +194,6 @@ VBlank duration: 1/VSYNC * (16/256) = 1017.6 us ***************************************************************************/ #include "emu.h" -#include "cpu/i86/i86.h" #include "machine/6532riot.h" #include "sound/ay8910.h" #include "sound/dac.h" @@ -693,6 +692,15 @@ static INTERRUPT_GEN( gottlieb_interrupt ) * Main CPU memory handlers * *************************************/ + +static WRITE8_HANDLER( gottlieb_sh_w ) +{ + gottlieb_state *state = space->machine().driver_data(); + if (state->m_r1_sound != NULL) + state->m_r1_sound->write(*space, offset, data); + if (state->m_r2_sound != NULL) + state->m_r2_sound->write(*space, offset, data); +} static ADDRESS_MAP_START( reactor_map, AS_PROGRAM, 8 ) ADDRESS_MAP_GLOBAL_MASK(0xffff) @@ -791,8 +799,6 @@ static INPUT_PORTS_START( reactor ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_COIN2 ) PORT_BIT( 0xc0, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - PORT_INCLUDE(gottlieb1_sound) - PORT_START("TRACKX") /* trackball H */ PORT_BIT( 0xff, 0, IPT_TRACKBALL_X ) PORT_SENSITIVITY(15) PORT_KEYDELTA(20) @@ -848,8 +854,6 @@ static INPUT_PORTS_START( qbert ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -904,8 +908,6 @@ static INPUT_PORTS_START( insector ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -957,8 +959,6 @@ static INPUT_PORTS_START( tylz ) PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) ) PORT_DIPSETTING( 0x80, DEF_STR( Off ) ) PORT_DIPSETTING( 0x00, DEF_STR( On ) ) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1014,8 +1014,6 @@ static INPUT_PORTS_START( argusg ) PORT_START("TRACKY") PORT_BIT( 0xff, 0, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(15) PORT_KEYDELTA(20) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1069,8 +1067,6 @@ static INPUT_PORTS_START( mplanets ) PORT_START("TRACKY") PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(5) PORT_KEYDELTA(10) PORT_CODE_DEC(KEYCODE_Z) PORT_CODE_INC(KEYCODE_X) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1124,8 +1120,6 @@ static INPUT_PORTS_START( krull ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_RIGHT ) PORT_8WAY PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_DOWN ) PORT_8WAY PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICKLEFT_LEFT ) PORT_8WAY - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1170,8 +1164,6 @@ static INPUT_PORTS_START( kngtmare ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_START1 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_START2 ) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1232,8 +1224,6 @@ static INPUT_PORTS_START( qbertqub ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1293,8 +1283,6 @@ static INPUT_PORTS_START( curvebal ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT(0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Bunt") PORT_PLAYER(1) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb1_sound) INPUT_PORTS_END @@ -1349,8 +1337,6 @@ static INPUT_PORTS_START( screwloo ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Start 1P") PORT_PLAYER(1) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNKNOWN ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1405,8 +1391,6 @@ static INPUT_PORTS_START( mach3 ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END static INPUT_PORTS_START( cobram3 ) @@ -1460,8 +1444,6 @@ static INPUT_PORTS_START( cobram3 ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1507,8 +1489,6 @@ static INPUT_PORTS_START( usvsthem ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1575,8 +1555,6 @@ static INPUT_PORTS_START( 3stooges ) PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(3) PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(3) PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(3) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1628,8 +1606,6 @@ static INPUT_PORTS_START( vidvince ) PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNKNOWN ) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1682,8 +1658,6 @@ static INPUT_PORTS_START( wizwarz ) PORT_START("TRACKY") PORT_BIT( 0xff, 0x00, IPT_DIAL ) PORT_SENSITIVITY(15) PORT_KEYDELTA(15) PORT_CODE_DEC(KEYCODE_Z) PORT_CODE_INC(KEYCODE_X) - - PORT_INCLUDE(gottlieb2_sound) INPUT_PORTS_END @@ -1737,103 +1711,6 @@ GFXDECODE_END -/************************************* - * - * Sound interfaces - * - *************************************/ - -static const char *const reactor_sample_names[] = -{ - "*reactor", - "fx_53", /* "8 left" */ - "fx_54", /* "16 left" */ - "fx_55", /* "24 left" */ - "fx_56", /* "32 left" */ - "fx_57", /* "40 left" */ - "fx_58", /* "warning, core unstable" */ - "fx_59", /* "bonus" */ - "fx_31", /* "chamber activated" */ - "fx_39a", /* "2000" */ - "fx_39b", /* "5000" */ - "fx_39c", /* "10000" */ - "fx_39d", /* "15000" */ - "fx_39e", /* "20000" */ - "fx_39f", /* "25000" */ - "fx_39g", /* "30000" */ - "fx_39h", /* "35000" */ - "fx_39i", /* "40000" */ - "fx_39j", /* "45000" */ - "fx_39k", /* "50000" */ - "fx_39l", /* "55000" */ - 0 /* end of array */ -}; - -static const char *const qbert_sample_names[] = -{ - "*qbert", - "fx_17a", /* random speech, voice clock 255 */ - "fx_17b", /* random speech, voice clock 255 */ - "fx_17c", /* random speech, voice clock 255 */ - "fx_17d", /* random speech, voice clock 255 */ - "fx_17e", /* random speech, voice clock 255 */ - "fx_17f", /* random speech, voice clock 255 */ - "fx_17g", /* random speech, voice clock 255 */ - "fx_17h", /* random speech, voice clock 255 */ - "fx_18a", /* random speech, voice clock 176 */ - "fx_18b", /* random speech, voice clock 176 */ - "fx_18c", /* random speech, voice clock 176 */ - "fx_18d", /* random speech, voice clock 176 */ - "fx_18e", /* random speech, voice clock 176 */ - "fx_18f", /* random speech, voice clock 176 */ - "fx_18g", /* random speech, voice clock 176 */ - "fx_18h", /* random speech, voice clock 176 */ - "fx_19a", /* random speech, voice clock 128 */ - "fx_19b", /* random speech, voice clock 128 */ - "fx_19c", /* random speech, voice clock 128 */ - "fx_19d", /* random speech, voice clock 128 */ - "fx_19e", /* random speech, voice clock 128 */ - "fx_19f", /* random speech, voice clock 128 */ - "fx_19g", /* random speech, voice clock 128 */ - "fx_19h", /* random speech, voice clock 128 */ - "fx_20a", /* random speech, voice clock 96 */ - "fx_20b", /* random speech, voice clock 96 */ - "fx_20c", /* random speech, voice clock 96 */ - "fx_20d", /* random speech, voice clock 96 */ - "fx_20e", /* random speech, voice clock 96 */ - "fx_20f", /* random speech, voice clock 96 */ - "fx_20g", /* random speech, voice clock 96 */ - "fx_20h", /* random speech, voice clock 96 */ - "fx_21a", /* random speech, voice clock 62 */ - "fx_21b", /* random speech, voice clock 62 */ - "fx_21c", /* random speech, voice clock 62 */ - "fx_21d", /* random speech, voice clock 62 */ - "fx_21e", /* random speech, voice clock 62 */ - "fx_21f", /* random speech, voice clock 62 */ - "fx_21g", /* random speech, voice clock 62 */ - "fx_21h", /* random speech, voice clock 62 */ - "fx_22", /* EH2 with decreasing voice clock */ - "fx_23", /* O1 with varying voice clock */ - "fx_28", - "fx_36", - "knocker", - 0 /* end of array */ -}; - -static const samples_interface qbert_samples_interface = -{ - 1, /* one channel */ - qbert_sample_names -}; - -static const samples_interface reactor_samples_interface = -{ - 1, /* one channel */ - reactor_sample_names -}; - - - /************************************* * * Core machine drivers @@ -1862,23 +1739,32 @@ static MACHINE_CONFIG_START( gottlieb_core, gottlieb_state ) MCFG_VIDEO_START(gottlieb) - /* sound hardware */ + // basic speaker configuration MCFG_SPEAKER_STANDARD_MONO("mono") MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( gottlieb1, gottlieb_core ) - MCFG_FRAGMENT_ADD(gottlieb_soundrev1) + MCFG_GOTTLIEB_SOUND_R1_ADD("r1sound") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) +MACHINE_CONFIG_END + + +static MACHINE_CONFIG_DERIVED( gottlieb1_votrax, gottlieb_core ) + MCFG_GOTTLIEB_SOUND_R1_ADD_VOTRAX("r1sound") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( gottlieb2, gottlieb_core ) - MCFG_FRAGMENT_ADD(gottlieb_soundrev2) + MCFG_GOTTLIEB_SOUND_R2_ADD("r2sound") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( g2laser, gottlieb_core ) - MCFG_FRAGMENT_ADD(gottlieb_soundrev2) + MCFG_GOTTLIEB_SOUND_R2_ADD("r2sound") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MCFG_LASERDISC_PR8210_ADD("laserdisc") MCFG_LASERDISC_AUDIO(laserdisc_audio_delegate(FUNC(laserdisc_audio_process), device)) @@ -1892,12 +1778,15 @@ static MACHINE_CONFIG_DERIVED( g2laser, gottlieb_core ) MACHINE_CONFIG_END + /************************************* * * Specific machine drivers * *************************************/ +#if USE_FAKE_VOTRAX + static MACHINE_CONFIG_DERIVED( reactor, gottlieb1 ) /* basic machine hardware */ @@ -1905,20 +1794,31 @@ static MACHINE_CONFIG_DERIVED( reactor, gottlieb1 ) MCFG_CPU_PROGRAM_MAP(reactor_map) MCFG_DEVICE_REMOVE("nvram") - - /* sound hardware */ - MCFG_SAMPLES_ADD("samples", reactor_samples_interface) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + MCFG_FRAGMENT_ADD(reactor_samples) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( qbert, gottlieb1 ) - - /* video hardware */ - MCFG_SAMPLES_ADD("samples", qbert_samples_interface) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) + MCFG_FRAGMENT_ADD(qbert_samples) MACHINE_CONFIG_END +#else + +static MACHINE_CONFIG_DERIVED( reactor, gottlieb1_votrax ) + + /* basic machine hardware */ + MCFG_CPU_MODIFY("maincpu") + MCFG_CPU_PROGRAM_MAP(reactor_map) + + MCFG_DEVICE_REMOVE("nvram") +MACHINE_CONFIG_END + + +static MACHINE_CONFIG_DERIVED( qbert, gottlieb1_votrax ) +MACHINE_CONFIG_END + +#endif + static MACHINE_CONFIG_DERIVED( screwloo, gottlieb2 ) @@ -1926,7 +1826,8 @@ static MACHINE_CONFIG_DERIVED( screwloo, gottlieb2 ) MACHINE_CONFIG_END static MACHINE_CONFIG_DERIVED( cobram3, gottlieb_core ) - MCFG_FRAGMENT_ADD(gottlieb_cobram3_soundrev2) + MCFG_GOTTLIEB_SOUND_R2_ADD_COBRAM3("r2sound") + MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0) MCFG_LASERDISC_PR8210_ADD("laserdisc") MCFG_LASERDISC_AUDIO(laserdisc_audio_delegate(FUNC(laserdisc_audio_process), device)) @@ -1939,9 +1840,9 @@ static MACHINE_CONFIG_DERIVED( cobram3, gottlieb_core ) MCFG_LASERDISC_SCREEN_ADD_NTSC("screen", "laserdisc") /* sound hardware */ - MCFG_SOUND_MODIFY("dac1") + MCFG_SOUND_MODIFY("r2sound:dac") MCFG_SOUND_ROUTES_RESET() - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + MCFG_SOUND_ROUTE(ALL_OUTPUTS, DEVICE_SELF_OWNER, 1.00) MACHINE_CONFIG_END @@ -1962,7 +1863,7 @@ ROM_START( reactor ) ROM_LOAD( "rom1", 0xe000, 0x1000, CRC(944e1ddf) SHA1(6b487f1cb405e2ba9345190e8ab6022c790882c1) ) ROM_LOAD( "rom0", 0xf000, 0x1000, CRC(55930aed) SHA1(37ed60386935741e8cc0b8750bfcdf6f54c1bf9e) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "snd1", 0x7000, 0x800, CRC(d958a0fd) SHA1(3c383076c68a929f96d844e89b09f3075f331906) ) ROM_LOAD( "snd2", 0x7800, 0x800, CRC(5dc86942) SHA1(a449fcfb25521a0e7523184518b5204dac56e5f8) ) @@ -1983,7 +1884,7 @@ ROM_START( qbert ) ROM_LOAD( "qb-rom1.bin", 0xc000, 0x2000, CRC(55635447) SHA1(ca6acdef1c9e06b33efe1f0a2df2dfb03723cfbe) ) ROM_LOAD( "qb-rom0.bin", 0xe000, 0x2000, CRC(8e318641) SHA1(7f8f66d1e6a7905e93cce07fc92e8801370b7194) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2004,7 +1905,7 @@ ROM_START( qberta ) ROM_LOAD( "qrom_1.bin", 0xc000, 0x2000, CRC(19d924e3) SHA1(af55ecb5b650e7b069d8be67eb9a9d0f3e69e3f1) ) ROM_LOAD( "qrom_0.bin", 0xe000, 0x2000, CRC(2e7fad1b) SHA1(5c1feafe00c21ddddde67ab0093e847a5fc9ec2d) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2025,7 +1926,7 @@ ROM_START( qbertj ) ROM_LOAD( "qbj-rom1.bin", 0xc000, 0x2000, CRC(c61216e7) SHA1(e727b85dddc2963e33af6c02b675243f6fbe2710) ) ROM_LOAD( "qbj-rom0.bin", 0xe000, 0x2000, CRC(69679d5c) SHA1(996d45517d0c01a1952fead05dbe201dbb7dca35) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2046,7 +1947,7 @@ ROM_START( myqbert ) ROM_LOAD( "mqb-rom1.bin", 0xc000, 0x2000, CRC(11f0a4e4) SHA1(a805e51c40042fae209ace277abd9b35a990905b) ) ROM_LOAD( "mqb-rom0.bin", 0xe000, 0x2000, CRC(12a90cb2) SHA1(a33203aea79fe43d1233a16e3fdddaceac6e4a20) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "mqb-snd1.bin", 0x7000, 0x800, CRC(495ffcd2) SHA1(b2c16fffbd6af1c17fdb1a99844819e6ee0550ee) ) ROM_LOAD( "mqb-snd2.bin", 0x7800, 0x800, CRC(9bbaa945) SHA1(13791b69cd6f426ad77a7d0537b10012feb0bc87) ) @@ -2067,7 +1968,7 @@ ROM_START( qberttst ) ROM_LOAD( "qbtst1.bin", 0xc000, 0x2000, CRC(e97fdd78) SHA1(98dd07043a72273240c593650aa9947199347870) ) ROM_LOAD( "qbtst0.bin", 0xe000, 0x2000, CRC(94c9f588) SHA1(f586bcd8e6762614bed634a007508abea071754c) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2089,7 +1990,7 @@ ROM_START( qbtrktst ) ROM_LOAD( "qb-rom1.bin", 0xc000, 0x2000, CRC(55635447) SHA1(ca6acdef1c9e06b33efe1f0a2df2dfb03723cfbe) ) ROM_LOAD( "gv103_t-ball-test_rom0_2764.c11c12", 0xe000, 0x2000, CRC(5d390cd2) SHA1(9031926a6f6179e340b67c3a7949062b4a75e3cf) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2112,7 +2013,7 @@ ROM_START( insector ) ROM_LOAD( "rom1", 0xc000, 0x2000, CRC(706962af) SHA1(e40b567fdf6a3f7c6485808b4db45cea322c7724) ) ROM_LOAD( "rom0", 0xe000, 0x2000, CRC(31cee24b) SHA1(3d21f5d530cc022f9633ad487e13a664848dd3e6) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "gv106s.bin", 0x7000, 0x1000, CRC(25bcc8bc) SHA1(adf401901f1479a5bffaed85135669b1133334b4) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2134,7 +2035,7 @@ ROM_START( tylz ) ROM_LOAD( "tylz.r4", 0xc000, 0x2000, CRC(657c3d2e) SHA1(9908a2dd5109e632dff38b8b4b56160615355200) ) ROM_LOAD( "tylz.n4", 0xe000, 0x2000, CRC(b2a15510) SHA1(15db4d1a2fb70d8111940246cd7a8ae06403cac5) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "tylz.f2", 0x7000, 0x1000, CRC(ebcedba9) SHA1(94aee8e32bdc80bbc5dc1423ca97597bdb9d808c) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2159,7 +2060,7 @@ ROM_START( argusg ) ROM_LOAD( "arg_rom1_2764.c12c13", 0xc000, 0x2000, CRC(733d3d44) SHA1(03c11e89ed6906c0383dc19c0db2d21ebe69b128) ) ROM_LOAD( "arg_rom0_2764.c11c12", 0xe000, 0x2000, CRC(e1906355) SHA1(4735370ff0dfe381358dfa41d82fab455ec3c016) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "arg_snd1_2716.u5", 0x7000, 0x800, CRC(3a6cf455) SHA1(0c701aa4d956947a101212b494b030cd2df5a2d6) ) ROM_LOAD( "arg_snd2_2716.u6", 0x7800, 0x800, CRC(ddf32040) SHA1(61ae22faa013b29a5fbd9520073f172a98ca38ec) ) @@ -2184,7 +2085,7 @@ ROM_START( mplanets ) /* note from f205v: my original Gottlieb PCB only sports one 2732 sound EPROM labeled "snd.3h" It contains the two joint roms you can find herefollowing, therefore the sound is identical */ - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "snd1", 0x7000, 0x0800, CRC(453193a1) SHA1(317ec81f71661eaa92624c0304a52b635dcd5613) ) ROM_LOAD( "snd2", 0x7800, 0x0800, CRC(f5ffc98f) SHA1(516e895df94942fc51f1b51eb9316d4296df82e7) ) @@ -2207,7 +2108,7 @@ ROM_START( mplanetsuk ) ROM_LOAD( "mpt_rom1.bin", 0xc000, 0x2000, CRC(94d67b87) SHA1(2cbf09f0ba3b6769de90d8f61913fec3010553e2) ) ROM_LOAD( "mpt_rom0.bin", 0xe000, 0x2000, CRC(a9e30ad2) SHA1(39d830dda92ab5a6dbb44943be92bca0464e64e0) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "mpt_snd1.bin", 0x7000, 0x800, CRC(453193a1) SHA1(317ec81f71661eaa92624c0304a52b635dcd5613) ) ROM_LOAD( "mpt_snd2.bin", 0x7800, 0x800, CRC(f5ffc98f) SHA1(516e895df94942fc51f1b51eb9316d4296df82e7) ) @@ -2233,7 +2134,7 @@ ROM_START( krull ) ROM_LOAD( "rom1.bin", 0xc000, 0x2000, CRC(1ad956a3) SHA1(f5b74b196fe1bd9ab48336e0051cbf29c650cfc1) ) ROM_LOAD( "rom0.bin", 0xe000, 0x2000, CRC(a466afae) SHA1(d691cbb46e8c3b71f9b1688d7fcef36df82aa854) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "snd1.bin", 0x6000, 0x1000, CRC(dd2b30b4) SHA1(f01cb64932493bf69d4fc75a7fa809ff6f6e4263) ) ROM_LOAD( "snd2.bin", 0x7000, 0x1000, CRC(8cab901b) SHA1(b886532828efc8cf442e2ee4ebbfe37acd489f62) ) @@ -2255,7 +2156,7 @@ ROM_START( kngtmare ) ROM_LOAD( "gv112_rom1_2764.c12c13", 0xc000, 0x2000, CRC(5b340640) SHA1(8ccad017d5b9b748327baf22ff51d30ee96cb25e) ) ROM_LOAD( "gv112_rom0_2764.c11c12", 0xe000, 0x2000, CRC(620dc629) SHA1(0d94b7c50ef499eb9bb3f4986a8d29547181f7ea) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "gv112_snd", 0x7000, 0x1000, NO_DUMP ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2276,7 +2177,7 @@ ROM_START( sqbert ) ROM_LOAD( "qb-rom1.bin", 0xc000, 0x2000, CRC(eaf3076c) SHA1(749a87b3c40ba0a2ecd2ca962786e066daf63e30) ) ROM_LOAD( "qb-rom0.bin", 0xe000, 0x2000, CRC(61260a7e) SHA1(e2028a453aa34aaffa2c465f64a963504315df3c) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qb-snd1.bin", 0x7000, 0x800, CRC(15787c07) SHA1(8b7d03fbf2ebaa71b3a7e2f636a0d1bb9b796e43) ) ROM_LOAD( "qb-snd2.bin", 0x7800, 0x800, CRC(58437508) SHA1(09d8053e7e99679b602dcda230d64db7fe6cb7f5) ) @@ -2299,7 +2200,7 @@ ROM_START( qbertqub ) ROM_LOAD( "qq-rom1.bin", 0xc000, 0x2000, CRC(63e6c43d) SHA1(9435eb06dc069e5bf1c439f0c772fef3183745b0) ) ROM_LOAD( "qq-rom0.bin", 0xe000, 0x2000, CRC(8ddbe438) SHA1(31112d711af5d4039491e99a0be0c088b3272482) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "qq-snd1.bin", 0x7000, 0x800, CRC(e704b450) SHA1(d509f54658e9f0264b9ab865a6f36e5423a28904) ) ROM_LOAD( "qq-snd2.bin", 0x7800, 0x800, CRC(c6a98bf8) SHA1(cc5b5bb5966f5d79226f1f665a3f9fc934f4ef7f) ) @@ -2322,7 +2223,7 @@ ROM_START( curvebal ) ROM_LOAD( "cb-rom-1.chp", 0xc000, 0x2000, CRC(eb1e08bd) SHA1(f558664df12e4e15ef2779a0bdf99538f8c43ca3) ) ROM_LOAD( "cb-rom-0.chp", 0xe000, 0x2000, CRC(401fc7e3) SHA1(86ca53cb6f1d88d5a95baa9524c6b42a1f7fc9c2) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r1sound:audiocpu", 0 ) ROM_LOAD( "yrom.sbd", 0x6000, 0x1000, CRC(4c313d9b) SHA1(c61a8c827f4b199fdfb6ffc0bc6cca396c73625e) ) ROM_LOAD( "drom.sbd", 0x7000, 0x1000, CRC(cecece88) SHA1(4c6639f6f89f80b04b6ffbb5004ea2121e71f504) ) @@ -2346,10 +2247,10 @@ ROM_START( screwloo ) ROM_LOAD( "rom1", 0xc000, 0x2000, CRC(571b65ca) SHA1(75077f4fab296b3802271fa77af588003570cde6) ) ROM_LOAD( "rom0", 0xe000, 0x2000, CRC(6447fe54) SHA1(6391c841cafd35dd315d9fac99ed5d8304018747) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "drom1", 0xc000, 0x2000, CRC(ae965ade) SHA1(84a690cba8990fe6406b7cfbd6ea643a48446567) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "yrom1", 0xe000, 0x2000, CRC(3719b0b5) SHA1(4f215ca2f15956374c4cd9484b6798f1c4d60fc7) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2372,10 +2273,10 @@ ROM_START( mach3 ) ROM_LOAD( "m3rom1.bin", 0xc000, 0x2000, CRC(3b0ba80b) SHA1(bc7e961311b40f05f2998f10f0a68f2e515c8e66) ) ROM_LOAD( "m3rom0.bin", 0xe000, 0x2000, CRC(70c12bf4) SHA1(c26127b6e2a16791b3be8abac93be6af4f30fb3b) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "m3drom1.bin", 0xd000, 0x1000, CRC(a6e29212) SHA1(a73aafc2efa99e9ae0aecbb6075a10f7178ac938) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "m3yrom1.bin", 0xf000, 0x1000, CRC(eddf8872) SHA1(29ed0d1828639849bab826b3e2ab4eefac45fd85) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2400,10 +2301,10 @@ ROM_START( cobram3 ) ROM_LOAD( "bh01", 0xc000, 0x2000, CRC(7d86ab08) SHA1(26b7eb089ca3fe3f8b1531316ce8f95e33b380e5) ) ROM_LOAD( "bh00", 0xe000, 0x2000, CRC(c19ad038) SHA1(4d20ae70d8ad1eaa61cb91d7a0cff6932fce30d2) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "m3drom1.bin", 0xd000, 0x1000, CRC(a6e29212) SHA1(a73aafc2efa99e9ae0aecbb6075a10f7178ac938) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "bh04", 0xe000, 0x2000, CRC(c3f61bc9) SHA1(d02374e6e29238def0cfb01c96c78b206f24d77e) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2429,10 +2330,10 @@ ROM_START( usvsthem ) ROM_LOAD( "usvs.rm1", 0xc000, 0x2000, CRC(697bc989) SHA1(ebfc0868f949e5aba1efb8fbce06f795888d8e00) ) ROM_LOAD( "usvs.rm0", 0xe000, 0x2000, CRC(30cf6bd9) SHA1(527ad3b96ea4a77f6d6f8a89a9215da490292297) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "usvsdrom.1", 0xc000, 0x2000, CRC(c0b5cab0) SHA1(b18e8fd9837bb52d6b3d86f2b652f6573c7cd3b3) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "usvsyrom.1", 0xe000, 0x2000, CRC(c3d245ca) SHA1(d281b139ae6c58e855b2914a24ca4bc5f8800681) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2459,10 +2360,10 @@ ROM_START( 3stooges ) ROM_LOAD( "gv113rom.1", 0xc000, 0x2000, CRC(34ab051e) SHA1(df416aaf34d6bbbdd79ae633842355a292ed935d) ) ROM_LOAD( "gv113rom.0", 0xe000, 0x2000, CRC(ab124329) SHA1(de1bc721eea74426035eec10a389f77b435aa9b9) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "drom1", 0xc000, 0x2000, CRC(87a9fa10) SHA1(9c07837dce1384d6b51b716aa8ceeb5bc247a911) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "yrom2", 0xc000, 0x2000, CRC(90f9c940) SHA1(646dacc902cf235948ac9c064c92390e2764370b) ) ROM_LOAD( "yrom1", 0xe000, 0x2000, CRC(55f8ab30) SHA1(a6b6318f12fd4a1fab61b82cde33759da615d5b2) ) @@ -2486,10 +2387,10 @@ ROM_START( vidvince ) ROM_LOAD( "gv132_rom1_2764.c12c13", 0xc000, 0x2000, CRC(a5bf40b7) SHA1(a5a193173fa7b764706bf8d3eaaaf18c6812e436) ) ROM_LOAD( "gv132_rom0_2764.c11c12", 0xe000, 0x2000, CRC(2c02b598) SHA1(0c214f6625d6ef88bf89d96776683e15cf4a85c4) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "gv132_drom_snd_2764.k2", 0xc000, 0x2000, CRC(18d9d72f) SHA1(985007f49885621eb96e86dc51812983bd113550) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "gv132_yrom2_snd_2764.k3", 0xc000, 0x2000, CRC(ff59f618) SHA1(c8b2cb1ab3b69f94dd6be87da8bdfc85c6ed8707) ) ROM_LOAD( "gv132_yrom1_snd_2764.n3", 0xe000, 0x2000, CRC(befa4b97) SHA1(424b40844629631a3f31cc12c61ac7000b5f3eb9) ) @@ -2513,10 +2414,10 @@ ROM_START( wizwarz ) ROM_LOAD( "gv110_rom1_2764.c12c13", 0xc000, 0x2000, CRC(358895b5) SHA1(38a4a27849ab491a6e3dd3415fe684d1c71c392d) ) ROM_LOAD( "gv110_rom0_2764.c11c12", 0xe000, 0x2000, CRC(f7157e17) SHA1(1b155602557ad173d74d4d5cf953b206b262987b) ) - ROM_REGION( 0x10000, "audiocpu", 0 ) + ROM_REGION( 0x10000, "r2sound:audiocpu", 0 ) ROM_LOAD( "gv110_drom1_snd_2732.k2",0xd000, 0x1000, CRC(05ca79da) SHA1(f9e9b0de02d618aeb73f7218a49b41d7b94c24a4) ) - ROM_REGION( 0x10000, "speech", 0 ) + ROM_REGION( 0x10000, "r2sound:speechcpu", 0 ) ROM_LOAD( "gv110_yrom1_snd_2732.n3",0xf000, 0x1000, CRC(1e3de643) SHA1(7717547c6c5b1ff178595c67f19265dc59130d90) ) ROM_REGION( 0x2000, "bgtiles", 0 ) @@ -2583,23 +2484,23 @@ static DRIVER_INIT( vidvince ) *************************************/ /* games using rev 1 sound board */ -GAME( 1982, reactor, 0, reactor, reactor, ramtiles, ROT0, "Gottlieb", "Reactor", GAME_IMPERFECT_SOUND ) -GAME( 1982, qbert, 0, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (US set 1)", GAME_IMPERFECT_SOUND ) -GAME( 1982, qberta, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (US set 2)", GAME_IMPERFECT_SOUND ) -GAME( 1982, qbertj, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb (Konami license)", "Q*bert (Japan)", GAME_IMPERFECT_SOUND ) -GAME( 1982, myqbert, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Mello Yello Q*bert", GAME_IMPERFECT_SOUND ) -GAME( 1982, qberttst, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (early test version)", GAME_IMPERFECT_SOUND ) -GAME( 1982, qbtrktst, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert Board Input Test Rom", GAME_IMPERFECT_SOUND ) -GAME( 1982, insector, 0, gottlieb1, insector, romtiles, ROT0, "Gottlieb", "Insector (prototype)", 0 ) -GAME( 1982, tylz, 0, qbert, tylz, romtiles, ROT0, "Mylstar", "Tylz (prototype)", GAME_IMPERFECT_SOUND ) // modified sound hw? -GAME( 1984, argusg, 0, gottlieb1, argusg, ramtiles, ROT0, "Gottlieb", "Argus (Gottlieb, prototype)" , 0) // aka Guardian / Protector? -GAME( 1983, mplanets, 0, gottlieb1, mplanets, romtiles, ROT270, "Gottlieb", "Mad Planets", 0 ) -GAME( 1983, mplanetsuk,mplanets, gottlieb1, mplanets, romtiles, ROT270, "Gottlieb (Taitel license)", "Mad Planets (UK)", 0 ) -GAME( 1983, krull, 0, gottlieb1, krull, ramtiles, ROT270, "Gottlieb", "Krull", 0 ) -GAME( 1983, kngtmare, 0, gottlieb1, kngtmare, romtiles, ROT0, "Gottlieb", "Knightmare (prototype)", GAME_NO_SOUND ) -GAME( 1983, sqbert, 0, qbert, qbert, romtiles, ROT270, "Mylstar", "Faster, Harder, More Challenging Q*bert (prototype)", GAME_IMPERFECT_SOUND ) -GAME( 1983, qbertqub, 0, qbert, qbertqub, romtiles, ROT270, "Mylstar", "Q*bert's Qubes", GAME_IMPERFECT_SOUND ) -GAME( 1984, curvebal, 0, gottlieb1, curvebal, romtiles, ROT270, "Mylstar", "Curve Ball", 0 ) +GAME( 1982, reactor, 0, reactor, reactor, ramtiles, ROT0, "Gottlieb", "Reactor", GAME_IMPERFECT_SOUND ) +GAME( 1982, qbert, 0, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (US set 1)", GAME_IMPERFECT_SOUND ) +GAME( 1982, qberta, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (US set 2)", GAME_IMPERFECT_SOUND ) +GAME( 1982, qbertj, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb (Konami license)", "Q*bert (Japan)", GAME_IMPERFECT_SOUND ) +GAME( 1982, myqbert, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Mello Yello Q*bert", GAME_IMPERFECT_SOUND ) +GAME( 1982, qberttst, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert (early test version)", GAME_IMPERFECT_SOUND ) +GAME( 1982, qbtrktst, qbert, qbert, qbert, romtiles, ROT270, "Gottlieb", "Q*bert Board Input Test Rom", GAME_IMPERFECT_SOUND ) +GAME( 1982, insector, 0, gottlieb1, insector, romtiles, ROT0, "Gottlieb", "Insector (prototype)", 0 ) +GAME( 1982, tylz, 0, gottlieb1_votrax, tylz, romtiles, ROT0, "Mylstar", "Tylz (prototype)", GAME_IMPERFECT_SOUND ) // modified sound hw? +GAME( 1984, argusg, 0, gottlieb1, argusg, ramtiles, ROT0, "Gottlieb", "Argus (Gottlieb, prototype)" , 0) // aka Guardian / Protector? +GAME( 1983, mplanets, 0, gottlieb1, mplanets, romtiles, ROT270, "Gottlieb", "Mad Planets", 0 ) +GAME( 1983, mplanetsuk,mplanets, gottlieb1, mplanets, romtiles, ROT270, "Gottlieb (Taitel license)", "Mad Planets (UK)", 0 ) +GAME( 1983, krull, 0, gottlieb1, krull, ramtiles, ROT270, "Gottlieb", "Krull", 0 ) +GAME( 1983, kngtmare, 0, gottlieb1, kngtmare, romtiles, ROT0, "Gottlieb", "Knightmare (prototype)", GAME_NO_SOUND ) +GAME( 1983, sqbert, 0, qbert, qbert, romtiles, ROT270, "Mylstar", "Faster, Harder, More Challenging Q*bert (prototype)", GAME_IMPERFECT_SOUND ) +GAME( 1983, qbertqub, 0, qbert, qbertqub, romtiles, ROT270, "Mylstar", "Q*bert's Qubes", GAME_IMPERFECT_SOUND ) +GAME( 1984, curvebal, 0, gottlieb1, curvebal, romtiles, ROT270, "Mylstar", "Curve Ball", 0 ) /* games using rev 2 sound board */ GAME( 1983, screwloo, 0, screwloo, screwloo, screwloo, ROT0, "Mylstar", "Screw Loose (prototype)", 0 ) diff --git a/src/mame/includes/gottlieb.h b/src/mame/includes/gottlieb.h index 615a5b49571..414382fb0c2 100644 --- a/src/mame/includes/gottlieb.h +++ b/src/mame/includes/gottlieb.h @@ -4,41 +4,220 @@ ***************************************************************************/ +#include "cpu/i86/i86.h" +#include "cpu/m6502/m6502.h" #include "machine/6532riot.h" +#include "sound/dac.h" +#include "sound/ay8910.h" +#include "sound/sp0250.h" +#include "sound/samples.h" +#include "sound/votrax.h" #include "machine/ldpr8210.h" +// set to 0 to enable Votrax device and disable samples +#define USE_FAKE_VOTRAX (1) + + #define GOTTLIEB_VIDEO_HCOUNT 318 #define GOTTLIEB_VIDEO_HBLANK 256 #define GOTTLIEB_VIDEO_VCOUNT 256 #define GOTTLIEB_VIDEO_VBLANK 240 +//************************************************************************** +// GLOBAL VARIABLES +//************************************************************************** + +extern const device_type GOTTLIEB_SOUND_REV1; +extern const device_type GOTTLIEB_SOUND_REV1_WITH_VOTRAX; +extern const device_type GOTTLIEB_SOUND_REV2; + + + +//************************************************************************** +// DEVICE CONFIGURATION MACROS +//************************************************************************** + +#define MCFG_GOTTLIEB_SOUND_R1_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, GOTTLIEB_SOUND_REV1, 0) \ + +#define MCFG_GOTTLIEB_SOUND_R1_ADD_VOTRAX(_tag) \ + MCFG_DEVICE_ADD(_tag, GOTTLIEB_SOUND_REV1_WITH_VOTRAX, 0) \ + + +#define MCFG_GOTTLIEB_SOUND_R2_ADD(_tag) \ + MCFG_DEVICE_ADD(_tag, GOTTLIEB_SOUND_REV2, 0) \ + +#define MCFG_GOTTLIEB_SOUND_R2_ADD_COBRAM3(_tag) \ + MCFG_DEVICE_ADD(_tag, GOTTLIEB_SOUND_REV2, 0) \ + gottlieb_sound_r2_device::static_enable_cobram3_mods(*device); \ + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> gottlieb_sound_r1_device + +// rev 1 sound board, with unpopulated VOTRAX +class gottlieb_sound_r1_device : public device_t, + public device_mixer_interface +{ +public: + // construction/destruction + gottlieb_sound_r1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + gottlieb_sound_r1_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock, bool populate_votrax); + + // read/write + DECLARE_WRITE8_MEMBER( write ); + + // internal communications + DECLARE_WRITE_LINE_MEMBER( snd_interrupt ); + DECLARE_WRITE8_MEMBER( r6532_portb_w ); + DECLARE_WRITE8_MEMBER( votrax_data_w ); + DECLARE_WRITE8_MEMBER( speech_clock_dac_w ); + DECLARE_WRITE_LINE_MEMBER( votrax_request ); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + +private: + // devices + required_device m_audiocpu; + required_device m_riot; + required_device m_dac; + optional_device m_votrax; + + // internal state + bool m_populate_votrax; + UINT8 m_last_speech_clock; + +#if USE_FAKE_VOTRAX +protected: + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); +private: + void fake_votrax_data_w(UINT8 data); + void trigger_sample(UINT8 data); + optional_device m_samples; + UINT8 m_score_sample; + UINT8 m_random_offset; + UINT8 m_votrax_queue[100]; + UINT8 m_votrax_queuepos; +#endif +}; + +// fully populated rev 1 sound board +class gottlieb_sound_r1_with_votrax_device : public gottlieb_sound_r1_device +{ +public: + // construction/destruction + gottlieb_sound_r1_with_votrax_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; +}; + + +// ======================> gottlieb_sound_r2_device + +// fully populated rev 2 sound board +class gottlieb_sound_r2_device : public device_t, + public device_mixer_interface +{ +public: + // construction/destruction + gottlieb_sound_r2_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // static configuration helpers + static void static_enable_cobram3_mods(device_t &device); + + // read/write + DECLARE_WRITE8_MEMBER( write ); + + // internal communications + DECLARE_READ8_MEMBER( speech_data_r ); + DECLARE_READ8_MEMBER( audio_data_r ); + DECLARE_WRITE8_MEMBER( signal_audio_nmi_w ); + DECLARE_WRITE8_MEMBER( nmi_rate_w ); + CUSTOM_INPUT_MEMBER( speech_drq_custom_r ); + DECLARE_WRITE8_MEMBER( dac_w ); + DECLARE_WRITE8_MEMBER( speech_control_w ); + DECLARE_WRITE8_MEMBER( sp0250_latch_w ); + DECLARE_WRITE8_MEMBER( psg_latch_w ); + +protected: + // device-level overrides + virtual machine_config_constructor device_mconfig_additions() const; + virtual ioport_constructor device_input_ports() const; + virtual void device_start(); + virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr); + +private: + // internal helpers + void nmi_timer_adjust(); + void nmi_state_update(); + + // timer IDs + enum + { + TID_NMI_GENERATE, + TID_NMI_CLEAR, + TID_SOUND_LATCH_WRITE + }; + + // devices + required_device m_audiocpu; + required_device m_speechcpu; + required_device m_dac; + required_device m_ay1; + required_device m_ay2; + optional_device m_sp0250; + + // internal state + bool m_cobram3_mod; + emu_timer * m_nmi_timer; + UINT8 m_nmi_rate; + UINT8 m_nmi_state; + UINT8 m_audiocpu_latch; + UINT8 m_speechcpu_latch; + UINT8 m_speech_control; + UINT8 m_last_command; + UINT8 m_dac_data[2]; + UINT8 m_psg_latch; + UINT8 m_psg_data_latch; + UINT8 m_sp0250_latch; +}; + + +// ======================> gottlieb_state + +// shared driver state class gottlieb_state : public driver_device { public: gottlieb_state(const machine_config &mconfig, device_type type, const char *tag) : driver_device(mconfig, type, tag), - m_laserdisc(*this, "laserdisc") { } + m_maincpu(*this, "maincpu"), + m_laserdisc(*this, "laserdisc"), + m_r1_sound(*this, "r1sound"), + m_r2_sound(*this, "r2sound") { } + + // devices + required_device m_maincpu; + optional_device m_laserdisc; + optional_device m_r1_sound; + optional_device m_r2_sound; UINT8 *m_videoram; - UINT8 m_votrax_queue[100]; - UINT8 m_votrax_queuepos; - emu_timer *m_nmi_timer; - UINT8 m_nmi_rate; - UINT8 m_nmi_state; - UINT8 m_speech_control; - UINT8 m_last_command; - UINT8 *m_dac_data; - UINT8 *m_psg_latch; - UINT8 m_psg_data_latch; - UINT8 *m_sp0250_latch; - int m_score_sample; - int m_random_offset; - int m_last; UINT8 m_joystick_select; UINT8 m_track[2]; - optional_device m_laserdisc; emu_timer *m_laserdisc_bit_timer; emu_timer *m_laserdisc_philips_timer; UINT8 m_laserdisc_select; @@ -64,18 +243,6 @@ public: }; -/*----------- defined in audio/gottlieb.c -----------*/ - -WRITE8_HANDLER( gottlieb_sh_w ); - -MACHINE_CONFIG_EXTERN( gottlieb_soundrev1 ); -MACHINE_CONFIG_EXTERN( gottlieb_soundrev2 ); -MACHINE_CONFIG_EXTERN( gottlieb_cobram3_soundrev2 ); - -INPUT_PORTS_EXTERN( gottlieb1_sound ); -INPUT_PORTS_EXTERN( gottlieb2_sound ); - - /*----------- defined in video/gottlieb.c -----------*/ extern WRITE8_HANDLER( gottlieb_videoram_w ); @@ -87,3 +254,8 @@ extern WRITE8_HANDLER( gottlieb_paletteram_w ); VIDEO_START( gottlieb ); VIDEO_START( screwloo ); SCREEN_UPDATE_RGB32( gottlieb ); + +#if USE_FAKE_VOTRAX +MACHINE_CONFIG_EXTERN( reactor_samples ); +MACHINE_CONFIG_EXTERN( qbert_samples ); +#endif