summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/audio/midway.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/audio/midway.cpp')
-rw-r--r--src/mame/audio/midway.cpp831
1 files changed, 0 insertions, 831 deletions
diff --git a/src/mame/audio/midway.cpp b/src/mame/audio/midway.cpp
deleted file mode 100644
index e7b4a5007c9..00000000000
--- a/src/mame/audio/midway.cpp
+++ /dev/null
@@ -1,831 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Aaron Giles
-/***************************************************************************
-
- midway.cpp
-
- Functions to emulate general the various Midway sound cards.
-
- TODO: the "Turbo Cheap Squeak" and "Sounds Good" boards are nearly identical
- in function, but use different CPUs and Memory maps (The PIA hookup, DAC
- and Filter are all exactly the same), so these should probably be combined
- into one base class with two subclass device implementations to reduce
- duplicated code.
- The "Cheap Squeak Deluxe" board in /audio/csd.cpp is also almost identical
- to the "Sounds Good" board, and should also be a member of any future
- combined class/device implementation.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "includes/mcr.h"
-#include "audio/midway.h"
-#include "audio/williams.h"
-
-#include <algorithm>
-
-
-//**************************************************************************
-// GLOBAL VARIABLES
-//**************************************************************************
-
-DEFINE_DEVICE_TYPE(MIDWAY_SSIO, midway_ssio_device, "midssio", "Midway SSIO Sound Board")
-DEFINE_DEVICE_TYPE(MIDWAY_SOUNDS_GOOD, midway_sounds_good_device, "midsg", "Midway Sounds Good Sound Board")
-DEFINE_DEVICE_TYPE(MIDWAY_TURBO_CHEAP_SQUEAK, midway_turbo_cheap_squeak_device, "midtcs", "Midway Turbo Cheap Squeak Sound Board")
-
-
-//**************************************************************************
-// SUPER SOUND I/O BOARD (SSIO)
-//**************************************************************************
-
-//-------------------------------------------------
-// midway_ssio_device - constructor
-//-------------------------------------------------
-
-midway_ssio_device::midway_ssio_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MIDWAY_SSIO, tag, owner, clock)
- , device_mixer_interface(mconfig, *this, 2)
- , m_cpu(*this, "cpu")
- , m_ay0(*this, "ay0")
- , m_ay1(*this, "ay1")
- , m_ports(*this, "IP%u", 0U)
- , m_status(0)
- , m_14024_count(0)
- , m_mute(0)
- , m_custom_input_mask{ 0U, 0U, 0U, 0U, 0U }
- , m_custom_input(*this)
- , m_custom_output_mask{ 0U, 0U }
- , m_custom_output(*this)
-{
- std::fill(std::begin(m_data), std::end(m_data), 0);
- std::fill(std::begin(m_overall), std::end(m_overall), 0);
- for (auto &duty_cycle : m_duty_cycle)
- std::fill(std::begin(duty_cycle), std::end(duty_cycle), 0);
- std::fill(std::begin(m_ayvolume_lookup), std::end(m_ayvolume_lookup), 0);
-}
-
-
-//-------------------------------------------------
-// suspend_cpu
-//-------------------------------------------------
-
-void midway_ssio_device::suspend_cpu()
-{
- m_cpu->suspend(SUSPEND_REASON_DISABLE, 1);
-}
-
-//-------------------------------------------------
-// read - return the status value
-//-------------------------------------------------
-
-uint8_t midway_ssio_device::read()
-{
- return m_status;
-}
-
-
-//-------------------------------------------------
-// write - handle an external write to one of the
-// input latches
-//-------------------------------------------------
-
-void midway_ssio_device::write(offs_t offset, uint8_t data)
-{
- synchronize(0, (offset << 8) | (data & 0xff));
-}
-
-
-//-------------------------------------------------
-// reset_write - write to the reset line
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(midway_ssio_device::reset_write)
-{
- if (state)
- {
- // going high halts the CPU
- device_reset();
- m_cpu->set_input_line(INPUT_LINE_RESET, ASSERT_LINE);
- }
- else
- {
- // going low resets and reactivates the CPU
- m_cpu->set_input_line(INPUT_LINE_RESET, CLEAR_LINE);
- }
-}
-
-
-//-------------------------------------------------
-// ioport_read - read from one of the I/O ports
-// on the device
-//-------------------------------------------------
-
-uint8_t midway_ssio_device::ioport_read(offs_t offset)
-{
- uint8_t result = m_ports[offset].read_safe(0xff);
- if (!m_custom_input[offset].isnull())
- result = (result & ~m_custom_input_mask[offset]) |
- (m_custom_input[offset]() & m_custom_input_mask[offset]);
- return result;
-}
-
-
-//-------------------------------------------------
-// ioport_write - write to one of the I/O ports
-// on the device
-//-------------------------------------------------
-
-void midway_ssio_device::ioport_write(offs_t offset, uint8_t data)
-{
- int which = offset >> 2;
- if (!m_custom_output[which].isnull())
- m_custom_output[which](data & m_custom_output_mask[which]);
-}
-
-
-//-------------------------------------------------
-// compute_ay8910_modulation - precompute
-// volume modulation tables based on the duty
-// cycle described by the PROMs
-//-------------------------------------------------
-
-void midway_ssio_device::compute_ay8910_modulation()
-{
- //
- // AY-8910 modulation:
- //
- // Starts with a 16MHz oscillator
- // /2 via 7474 flip-flip @ F11
- //
- // This signal clocks the binary counter @ E11 which
- // cascades into the decade counter @ D11. This combo
- // effectively counts from 0-159 and then wraps. The
- // value from these counters is input to an 82S123 PROM,
- // which appears to be standard on all games.
- //
- // One bit at a time from this PROM is clocked at a time
- // and the resulting inverted signal becomes a clock for
- // the down counters at F3, F4, F5, F8, F9, and F10. The
- // value in these down counters are reloaded after the 160
- // counts from the binary/decade counter combination.
- //
- // When these down counters are loaded, the TC signal is
- // clear, which mutes the voice. When the down counters
- // cross through 0, the TC signal goes high and the 4016
- // multiplexers allow the AY-8910 voice to go through.
- // Thus, writing a 0 to the counters will enable the
- // voice for the longest period of time, while writing
- // a 15 enables it for the shortest period of time.
- // This creates an effective duty cycle for the voice.
- //
- // Given that the down counters are reset 50000 times per
- // second (SSIO_CLOCK/2/160), which is above the typical
- // frequency of sound output. So we simply apply a volume
- // adjustment to each voice according to the duty cycle.
- //
-
- // loop over all possible values of the duty cycle
- uint8_t *prom = memregion("proms")->base();
- for (int volval = 0; volval < 16; volval++)
- {
- // loop over all the clocks until we run out; look up in the PROM
- // to find out when the next clock should fire
- int remaining_clocks = volval;
- int cur = 0, prev = 1;
- int curclock;
- for (curclock = 0; curclock < 160 && remaining_clocks; curclock++)
- {
- cur = prom[curclock / 8] & (0x80 >> (curclock % 8));
-
- // check for a high -> low transition
- if (cur == 0 && prev != 0)
- remaining_clocks--;
-
- prev = cur;
- }
-
- // treat the duty cycle as a volume
- m_ayvolume_lookup[15 - volval] = curclock * 100 / 160;
- }
-}
-
-
-//-------------------------------------------------
-// clock_14024 - periodic timer to clock the
-// 7-bit async counter at C12
-//-------------------------------------------------
-
-INTERRUPT_GEN_MEMBER(midway_ssio_device::clock_14024)
-{
- //
- // /SINT is generated as follows:
- //
- // Starts with a 16MHz oscillator
- // /2 via 7474 flip-flop @ F11
- // /16 via 74161 binary counter @ E11
- // /10 via 74190 decade counter @ D11
- //
- // Bit 3 of the decade counter clocks a 14024 7-bit async counter @ C12.
- // This routine is called to clock this 7-bit counter.
- // Bit 6 of the output is inverted and connected to /SINT.
- //
- m_14024_count = (m_14024_count + 1) & 0x7f;
-
- // if the low 5 bits clocked to 0, bit 6 has changed state
- if ((m_14024_count & 0x3f) == 0)
- m_cpu->set_input_line(0, (m_14024_count & 0x40) ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// irq_clear - reset the IRQ state and 14024 count
-//-------------------------------------------------
-
-uint8_t midway_ssio_device::irq_clear()
-{
- // a read here asynchronously resets the 14024 count, clearing /SINT
- if (!machine().side_effects_disabled())
- {
- m_14024_count = 0;
- m_cpu->set_input_line(0, CLEAR_LINE);
- }
- return 0xff;
-}
-
-
-//-------------------------------------------------
-// status_w - set the outgoing status value
-//-------------------------------------------------
-
-void midway_ssio_device::status_w(uint8_t data)
-{
- m_status = data;
-}
-
-
-//-------------------------------------------------
-// data_r - read incoming data latches
-//-------------------------------------------------
-
-uint8_t midway_ssio_device::data_r(offs_t offset)
-{
- return m_data[offset];
-}
-
-
-//-------------------------------------------------
-// porta0_w - handle writes to AY-8910 #0 port A
-//-------------------------------------------------
-
-void midway_ssio_device::porta0_w(uint8_t data)
-{
- m_duty_cycle[0][0] = data & 15;
- m_duty_cycle[0][1] = data >> 4;
- update_volumes();
-}
-
-
-//-------------------------------------------------
-// portb0_w - handle writes to AY-8910 #0 port B
-//-------------------------------------------------
-
-void midway_ssio_device::portb0_w(uint8_t data)
-{
- m_duty_cycle[0][2] = data & 15;
- m_overall[0] = (data >> 4) & 7;
- update_volumes();
-}
-
-
-//-------------------------------------------------
-// porta1_w - handle writes to AY-8910 #1 port A
-//-------------------------------------------------
-
-void midway_ssio_device::porta1_w(uint8_t data)
-{
- m_duty_cycle[1][0] = data & 15;
- m_duty_cycle[1][1] = data >> 4;
- update_volumes();
-}
-
-
-//-------------------------------------------------
-// portb1_w - handle writes to AY-8910 #1 port B
-//-------------------------------------------------
-
-void midway_ssio_device::portb1_w(uint8_t data)
-{
- m_duty_cycle[1][2] = data & 15;
- m_overall[1] = (data >> 4) & 7;
- m_mute = data & 0x80;
- update_volumes();
-}
-
-
-//-------------------------------------------------
-// update_volumes - update the volumes of each
-// AY-8910 channel based on modulation and mute
-//-------------------------------------------------
-
-void midway_ssio_device::update_volumes()
-{
- m_ay0->set_volume(0, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][0]]);
- m_ay0->set_volume(1, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][1]]);
- m_ay0->set_volume(2, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[0][2]]);
- m_ay1->set_volume(0, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][0]]);
- m_ay1->set_volume(1, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][1]]);
- m_ay1->set_volume(2, m_mute ? 0 : m_ayvolume_lookup[m_duty_cycle[1][2]]);
-}
-
-//-------------------------------------------------
-// audio CPU map
-//-------------------------------------------------
-
-// address map verified from schematics
-void midway_ssio_device::ssio_map(address_map &map)
-{
- map.unmap_value_high();
- map(0x0000, 0x3fff).rom();
- map(0x8000, 0x83ff).mirror(0x0c00).ram();
- map(0x9000, 0x9003).mirror(0x0ffc).r(FUNC(midway_ssio_device::data_r));
- map(0xa000, 0xa000).mirror(0x0ffc).w("ay0", FUNC(ay8910_device::address_w));
- map(0xa001, 0xa001).mirror(0x0ffc).r("ay0", FUNC(ay8910_device::data_r));
- map(0xa002, 0xa002).mirror(0x0ffc).w("ay0", FUNC(ay8910_device::data_w));
- map(0xb000, 0xb000).mirror(0x0ffc).w("ay1", FUNC(ay8910_device::address_w));
- map(0xb001, 0xb001).mirror(0x0ffc).r("ay1", FUNC(ay8910_device::data_r));
- map(0xb002, 0xb002).mirror(0x0ffc).w("ay1", FUNC(ay8910_device::data_w));
- map(0xc000, 0xcfff).nopr().w(FUNC(midway_ssio_device::status_w));
- map(0xd000, 0xdfff).nopw(); // low bit controls yellow LED
- map(0xe000, 0xefff).r(FUNC(midway_ssio_device::irq_clear));
- map(0xf000, 0xffff).portr("DIP"); // 6 DIP switches
-}
-
-
-//-------------------------------------------------
-// default ports map
-//-------------------------------------------------
-
-void midway_ssio_device::ssio_input_ports(address_map &map, const char *ssio)
-{
- map(0x00, 0x04).mirror(0x18).r(ssio, FUNC(midway_ssio_device::ioport_read));
- map(0x07, 0x07).mirror(0x18).r(ssio, FUNC(midway_ssio_device::read));
- map(0x00, 0x07).w(ssio, FUNC(midway_ssio_device::ioport_write));
- map(0x1c, 0x1f).w(ssio, FUNC(midway_ssio_device::write));
-}
-
-
-//-------------------------------------------------
-// ROM definitions
-//-------------------------------------------------
-
-ROM_START( midway_ssio )
- ROM_REGION( 0x0020, "proms", 0 )
- ROM_LOAD( "82s123.12d", 0x0000, 0x0020, CRC(e1281ee9) SHA1(9ac9b01d24affc0ee9227a4364c4fd8f8290343a) ) /* from shollow, assuming it's the same */
-ROM_END
-
-
-//-------------------------------------------------
-// device_rom_region - return a pointer to the
-// the device's ROM definitions
-//-------------------------------------------------
-
-const tiny_rom_entry *midway_ssio_device::device_rom_region() const
-{
- return ROM_NAME(midway_ssio);
-}
-
-
-//-------------------------------------------------
-// device_add_mconfig - add device configuration
-//-------------------------------------------------
-
-void midway_ssio_device::device_add_mconfig(machine_config &config)
-{
- Z80(config, m_cpu, DERIVED_CLOCK(1, 2*4));
- m_cpu->set_addrmap(AS_PROGRAM, &midway_ssio_device::ssio_map);
- if (clock())
- m_cpu->set_periodic_int(DEVICE_SELF, FUNC(midway_ssio_device::clock_14024), attotime::from_hz(clock() / (2*16*10)));
-
- AY8910(config, m_ay0, DERIVED_CLOCK(1, 2*4));
- m_ay0->port_a_write_callback().set(FUNC(midway_ssio_device::porta0_w));
- m_ay0->port_b_write_callback().set(FUNC(midway_ssio_device::portb0_w));
- m_ay0->add_route(ALL_OUTPUTS, *this, 0.33, AUTO_ALLOC_INPUT, 0);
-
- AY8910(config, m_ay1, DERIVED_CLOCK(1, 2*4));
- m_ay1->port_a_write_callback().set(FUNC(midway_ssio_device::porta1_w));
- m_ay1->port_b_write_callback().set(FUNC(midway_ssio_device::portb1_w));
- m_ay1->add_route(ALL_OUTPUTS, *this, 0.33, AUTO_ALLOC_INPUT, 1);
-}
-
-
-//-------------------------------------------------
-// device_input_ports - return a pointer to
-// the device's I/O ports
-//-------------------------------------------------
-
-ioport_constructor midway_ssio_device::device_input_ports() const
-{
- return nullptr;
-// return INPUT_PORTS_NAME( midway_ssio );
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void midway_ssio_device::device_start()
-{
- compute_ay8910_modulation();
- save_item(NAME(m_data));
- save_item(NAME(m_status));
- save_item(NAME(m_14024_count));
- save_item(NAME(m_mute));
- save_item(NAME(m_overall));
- save_item(NAME(m_duty_cycle));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void midway_ssio_device::device_reset()
-{
- // latches also get reset
- memset(m_data, 0, sizeof(m_data));
- m_status = 0;
- m_14024_count = 0;
-}
-
-
-//-------------------------------------------------
-// device_timer - timer callbacks
-//-------------------------------------------------
-
-void midway_ssio_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- m_data[param >> 8] = param & 0xff;
-}
-
-
-
-//**************************************************************************
-// SOUNDS GOOD BOARD
-//**************************************************************************
-
-//-------------------------------------------------
-// midway_sounds_good_device - constructor
-//-------------------------------------------------
-
-midway_sounds_good_device::midway_sounds_good_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MIDWAY_SOUNDS_GOOD, tag, owner, clock)
- , device_mixer_interface(mconfig, *this)
- , m_cpu(*this, "cpu")
- , m_pia(*this, "pia")
- , m_dac(*this, "dac")
- , m_dac_filter(*this, "dac_filter%u", 0U)
- , m_status(0)
- , m_dacval(0)
-{
-}
-
-
-//-------------------------------------------------
-// read - return the status value
-//-------------------------------------------------
-
-uint8_t midway_sounds_good_device::read()
-{
- return m_status;
-}
-
-
-//-------------------------------------------------
-// write - handle an external write to the input
-// latch
-//-------------------------------------------------
-
-void midway_sounds_good_device::write(uint8_t data)
-{
- synchronize(0, data);
-}
-
-
-//-------------------------------------------------
-// reset_write - write to the reset line
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(midway_sounds_good_device::reset_write)
-{
-//if (state) osd_printf_debug("SG Reset\n");
- m_cpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// porta_w - PIA port A writes
-//-------------------------------------------------
-
-void midway_sounds_good_device::porta_w(uint8_t data)
-{
- m_dacval = (data << 2) | (m_dacval & 3);
- m_dac->write(m_dacval);
-}
-
-
-//-------------------------------------------------
-// portb_w - PIA port B writes
-//-------------------------------------------------
-
-void midway_sounds_good_device::portb_w(uint8_t data)
-{
- uint8_t z_mask = m_pia->port_b_z_mask();
-
- m_dacval = (m_dacval & ~3) | (data >> 6);
- m_dac->write(m_dacval);
-
- if (~z_mask & 0x10) m_status = (m_status & ~1) | ((data >> 4) & 1);
- if (~z_mask & 0x20) m_status = (m_status & ~2) | ((data >> 4) & 2);
-}
-
-
-//-------------------------------------------------
-// irq_w - IRQ line state changes
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(midway_sounds_good_device::irq_w)
-{
- int combined_state = m_pia->irq_a_state() | m_pia->irq_b_state();
- m_cpu->set_input_line(4, combined_state ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// audio CPU map
-//-------------------------------------------------
-
-// address map determined by PAL20L10 @U15; not dumped/verified yet
-//Address map (x = ignored; * = selects address within this range)
-//68k address map known for certain:
-//a23 a22 a21 a20 a19 a18 a17 a16 a15 a14 a13 a12 a11 a10 a9 a8 a7 a6 a5 a4 a3 a2 a1 (a0 via UDS/LDS)
-//x x x x x * * * ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? RW PAL@
-//BEGIN 68k map guesses (until we have a pal dump):
-//x x x x x 0 [a] [b] * * * * * * * * * * * * * * * -> R ROM U7, U17
-//x x x x x 0 [c] [d] * * * * * * * * * * * * * * * -> R ROM U8, U18
-//x x x x x 1 1 0 x x x x x x x x x x x x 0 *e* *f* 1 RW PIA U9 (e goes to PIA RS0, f goes to PIA RS1, D8-D15 go to PIA D0-D7)
-//x x x x x 1 1 1 x x x x * * * * * * * * * * * ? RW RAM U6, U16
-//The ROMTYPE PAL line, is pulled low if JW1 is present, and this presumably controls [a] [b] [c] [d] as such:
-//When ROMTYPE is HIGH/JW1 absent, 27256 roms: (JW3 should be present, JW2 absent)
-//x x x x x 0 0? 0 * * * * * * * * * * * * * * * -> R ROM U7, U17
-//x x x x x 0 0? 1 * * * * * * * * * * * * * * * -> R ROM U8, U18
-//When ROMTYPE is LOW/JW1 present, 27512 roms: (JW3 should be absent, JW2 present)
-//x x x x x 0 0 * * * * * * * * * * * * * * * * -> R ROM U7, U17
-//x x x x x 0 1 * * * * * * * * * * * * * * * * -> R ROM U8, U18
-//JW2 and JW3 are mutually exclusive, and control whether 68k a16 connects to the EPROM pin 1 line (JW2 present), or whether it is tied high (JW3 present).
-//EPROM pin 1 is A15 on 27512, and VPP(usually an active high enable) on 27256
-//END guesses
-
-
-
-void midway_sounds_good_device::soundsgood_map(address_map &map)
-{
- map.unmap_value_high();
- map.global_mask(0x7ffff);
- map(0x000000, 0x03ffff).rom();
- map(0x060000, 0x060007).mirror(0x00fff0).rw(m_pia, FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt)).umask16(0xff00); // RS0 connects to A2, RS1 connects to A1, hence the "alt" functions are used.
- map(0x070000, 0x070fff).mirror(0x00f000).ram();
-}
-
-
-//-------------------------------------------------
-// device_add_mconfig - add device configuration
-//-------------------------------------------------
-
-void midway_sounds_good_device::device_add_mconfig(machine_config &config)
-{
- M68000(config, m_cpu, DERIVED_CLOCK(1, 2));
- m_cpu->set_addrmap(AS_PROGRAM, &midway_sounds_good_device::soundsgood_map);
-
- PIA6821(config, m_pia, 0);
- m_pia->writepa_handler().set(FUNC(midway_sounds_good_device::porta_w));
- m_pia->writepb_handler().set(FUNC(midway_sounds_good_device::portb_w));
- m_pia->irqa_handler().set(FUNC(midway_sounds_good_device::irq_w));
- m_pia->irqb_handler().set(FUNC(midway_sounds_good_device::irq_w));
-
- AD7533(config, m_dac, 0); /// ad7533jn.u10
-
- // The DAC filters here are identical to those on the "Turbo Cheap Squeak" and "Cheap Squeak Deluxe" boards.
- //LM359 @U2.2, 2nd order MFB low-pass (fc = 5404.717733, Q = 0.625210, gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[2]).opamp_mfb_lowpass_setup(RES_K(150), RES_K(82), RES_K(150), CAP_P(470), CAP_P(150)); // R115, R109, R108, C112, C111
- m_dac_filter[2]->add_route(ALL_OUTPUTS, *this, 1.0);
- //LM359 @U3.2, 2nd order MFB low-pass (fc = 5310.690763, Q = 1.608630, gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[1]).opamp_mfb_lowpass_setup(RES_K(33), RES_K(18), RES_K(33), CAP_P(5600), CAP_P(270)); // R113, R117, R116, C115, C118
- m_dac_filter[1]->add_route(ALL_OUTPUTS, m_dac_filter[2], 1.0);
- //LM359 @U3.1, 1st order MFB low-pass (fc = 4912.189602, Q = 0.707107(ignored), gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[0]).opamp_mfb_lowpass_setup(RES_K(120), RES_K(0), RES_K(120), CAP_P(0), CAP_P(270)); // R112, <short>, R111, <nonexistent>, C113
- m_dac_filter[0]->add_route(ALL_OUTPUTS, m_dac_filter[1], 1.0);
- m_dac->add_route(ALL_OUTPUTS, m_dac_filter[0], 1.0);
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void midway_sounds_good_device::device_start()
-{
- save_item(NAME(m_status));
- save_item(NAME(m_dacval));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void midway_sounds_good_device::device_reset()
-{
-}
-
-
-//-------------------------------------------------
-// device_timer - timer callbacks
-//-------------------------------------------------
-
-void midway_sounds_good_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- m_pia->portb_w((param >> 1) & 0x0f);
- m_pia->ca1_w(~param & 0x01);
-
- // oftentimes games will write one nibble at a time; the sync on this is very
- // important, so we boost the interleave briefly while this happens
- machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(250));
-}
-
-
-
-//**************************************************************************
-// TURBO CHEAP SQUEAK BOARD
-//**************************************************************************
-
-//-------------------------------------------------
-// midway_turbo_cheap_squeak_device - constructor
-//-------------------------------------------------
-
-midway_turbo_cheap_squeak_device::midway_turbo_cheap_squeak_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, MIDWAY_TURBO_CHEAP_SQUEAK, tag, owner, clock),
- device_mixer_interface(mconfig, *this)
- , m_cpu(*this, "cpu")
- , m_pia(*this, "pia")
- , m_dac(*this, "dac")
- , m_dac_filter(*this, "dac_filter%u", 0U)
- , m_status(0)
- , m_dacval(0)
-{
-}
-
-
-//-------------------------------------------------
-// read - return the status value
-//-------------------------------------------------
-
-uint8_t midway_turbo_cheap_squeak_device::read()
-{
- return m_status;
-}
-
-
-//-------------------------------------------------
-// write - handle an external write to the input
-// latch
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::write(uint8_t data)
-{
- synchronize(0, data);
-}
-
-
-//-------------------------------------------------
-// reset_write - write to the reset line
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::reset_write)
-{
- m_cpu->set_input_line(INPUT_LINE_RESET, state ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// porta_w - PIA port A writes
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::porta_w(uint8_t data)
-{
- m_dacval = (data << 2) | (m_dacval & 3);
- m_dac->write(m_dacval);
-}
-
-
-//-------------------------------------------------
-// portb_w - PIA port B writes
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::portb_w(uint8_t data)
-{
- m_dacval = (m_dacval & ~3) | (data >> 6);
- m_dac->write(m_dacval);
- m_status = (data >> 4) & 3;
-}
-
-
-//-------------------------------------------------
-// irq_w - IRQ line state changes
-//-------------------------------------------------
-
-WRITE_LINE_MEMBER(midway_turbo_cheap_squeak_device::irq_w)
-{
- int combined_state = m_pia->irq_a_state() | m_pia->irq_b_state();
- m_cpu->set_input_line(M6809_IRQ_LINE, combined_state ? ASSERT_LINE : CLEAR_LINE);
-}
-
-
-//-------------------------------------------------
-// audio CPU map
-//-------------------------------------------------
-
-// address map verified from schematics
-void midway_turbo_cheap_squeak_device::turbocs_map(address_map &map)
-{
- map.unmap_value_high();
- map(0x0000, 0x07ff).mirror(0x3800).ram();
- map(0x4000, 0x4003).mirror(0x3ffc).rw("pia", FUNC(pia6821_device::read_alt), FUNC(pia6821_device::write_alt));
- map(0x8000, 0xffff).rom();
-}
-
-
-//-------------------------------------------------
-// device_add_mconfig - add device configuration
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::device_add_mconfig(machine_config &config)
-{
- MC6809E(config, m_cpu, DERIVED_CLOCK(1, 4));
- m_cpu->set_addrmap(AS_PROGRAM, &midway_turbo_cheap_squeak_device::turbocs_map);
-
- PIA6821(config, m_pia, 0);
- m_pia->writepa_handler().set(FUNC(midway_turbo_cheap_squeak_device::porta_w));
- m_pia->writepb_handler().set(FUNC(midway_turbo_cheap_squeak_device::portb_w));
- m_pia->irqa_handler().set(FUNC(midway_turbo_cheap_squeak_device::irq_w));
- m_pia->irqb_handler().set(FUNC(midway_turbo_cheap_squeak_device::irq_w));
-
- AD7533(config, m_dac, 0); /// ad7533jn.u11
-
- // The DAC filters here are identical to those on the "Sounds Good" and "Cheap Squeak Deluxe" boards.
- //LM359 @U14.2, 2nd order MFB low-pass (fc = 5404.717733, Q = 0.625210, gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[2]).opamp_mfb_lowpass_setup(RES_K(150), RES_K(82), RES_K(150), CAP_P(470), CAP_P(150)); // R36, R37, R39, C19, C20
- m_dac_filter[2]->add_route(ALL_OUTPUTS, *this, 1.0);
- //LM359 @U13.2, 2nd order MFB low-pass (fc = 5310.690763, Q = 1.608630, gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[1]).opamp_mfb_lowpass_setup(RES_K(33), RES_K(18), RES_K(33), CAP_P(5600), CAP_P(270)); // R32, R33, R35, C16, C17
- m_dac_filter[1]->add_route(ALL_OUTPUTS, m_dac_filter[2], 1.0);
- //LM359 @U13.1, 1st order MFB low-pass (fc = 4912.189602, Q = 0.707107(ignored), gain = -1.000000)
- FILTER_BIQUAD(config, m_dac_filter[0]).opamp_mfb_lowpass_setup(RES_K(120), RES_K(0), RES_K(120), CAP_P(0), CAP_P(270)); // R27, <short>, R31, <nonexistent>, C14
- m_dac_filter[0]->add_route(ALL_OUTPUTS, m_dac_filter[1], 1.0);
- m_dac->add_route(ALL_OUTPUTS, m_dac_filter[0], 1.0);
-}
-
-
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::device_start()
-{
- save_item(NAME(m_status));
- save_item(NAME(m_dacval));
-}
-
-
-//-------------------------------------------------
-// device_reset - device-specific reset
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::device_reset()
-{
-}
-
-
-//-------------------------------------------------
-// device_timer - timer callbacks
-//-------------------------------------------------
-
-void midway_turbo_cheap_squeak_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- m_pia->portb_w((param >> 1) & 0x0f);
- m_pia->ca1_w(~param & 0x01);
-
- // oftentimes games will write one nibble at a time; the sync on this is very
- // important, so we boost the interleave briefly while this happens
- machine().scheduler().boost_interleave(attotime::zero, attotime::from_usec(100));
-}