summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/taito/sspeedr.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/taito/sspeedr.cpp')
-rw-r--r--src/mame/taito/sspeedr.cpp648
1 files changed, 648 insertions, 0 deletions
diff --git a/src/mame/taito/sspeedr.cpp b/src/mame/taito/sspeedr.cpp
new file mode 100644
index 00000000000..d07ad12f9ce
--- /dev/null
+++ b/src/mame/taito/sspeedr.cpp
@@ -0,0 +1,648 @@
+// license:BSD-3-Clause
+// copyright-holders: Stefan Jokisch
+
+/***************************************************************************
+
+Taito / Midway Super Speed Race driver
+
+TODO:
+- add Japan version(s), it has different graphics
+
+***************************************************************************/
+
+#include "emu.h"
+
+#include "nl_sspeedr.h"
+
+#include "cpu/z80/z80.h"
+#include "machine/netlist.h"
+#include "machine/watchdog.h"
+
+#include "emupal.h"
+#include "screen.h"
+#include "speaker.h"
+
+#include "sspeedr.lh"
+
+
+namespace {
+
+class sspeedr_state : public driver_device
+{
+public:
+ sspeedr_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_gfxdecode(*this, "gfxdecode")
+ , m_palette(*this, "palette")
+ , m_pedal_bit(*this, "sound_nl:pedal_bit_%u", 0U)
+ , m_hi_shift(*this, "sound_nl:hi_shift")
+ , m_lo_shift(*this, "sound_nl:lo_shift")
+ , m_boom(*this, "sound_nl:boom")
+ , m_engine_sound_off(*this, "sound_nl:engine_sound_off")
+ , m_noise_cr(*this, "sound_nl:noise_cr%u", 1U)
+ , m_silence(*this, "sound_nl:silence")
+ , m_track(*this, "track")
+ , m_digits(*this, "digit%u", 0U)
+ , m_lampgo(*this, "lampGO")
+ , m_lampep(*this, "lampEP")
+ { }
+
+ void sspeedr(machine_config &config) ATTR_COLD;
+
+protected:
+ virtual void video_start() override ATTR_COLD;
+ virtual void machine_start() override ATTR_COLD;
+
+private:
+ required_device<cpu_device> m_maincpu;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_device<palette_device> m_palette;
+ required_device_array<netlist_mame_logic_input_device, 4> m_pedal_bit;
+ required_device<netlist_mame_logic_input_device> m_hi_shift;
+ required_device<netlist_mame_logic_input_device> m_lo_shift;
+ required_device<netlist_mame_logic_input_device> m_boom;
+ required_device<netlist_mame_logic_input_device> m_engine_sound_off;
+ required_device_array<netlist_mame_logic_input_device, 2> m_noise_cr;
+ required_device<netlist_mame_logic_input_device> m_silence;
+ required_region_ptr<uint8_t> m_track;
+ output_finder<26> m_digits;
+ output_finder<> m_lampgo;
+ output_finder<> m_lampep;
+
+
+ uint8_t m_toggle = 0;
+ uint16_t m_driver_horz = 0;
+ uint8_t m_driver_vert = 0;
+ uint8_t m_driver_pic = 0;
+ uint16_t m_drones_horz = 0;
+ uint8_t m_drones_vert[3]{};
+ uint8_t m_drones_mask = 0;
+ uint16_t m_track_horz = 0;
+ uint8_t m_track_vert[2]{};
+ uint8_t m_track_ice = 0;
+
+ void int_ack_w(uint8_t data);
+ void lamp_w(uint8_t data);
+ void time_w(offs_t offset, uint8_t data);
+ void score_w(offs_t offset, uint8_t data);
+ void sound1_w(uint8_t data);
+ void sound2_w(uint8_t data);
+ void driver_horz_w(uint8_t data);
+ void driver_horz_2_w(uint8_t data);
+ void driver_vert_w(uint8_t data);
+ void driver_pic_w(uint8_t data);
+ void drones_horz_w(uint8_t data);
+ void drones_horz_2_w(uint8_t data);
+ void drones_mask_w(uint8_t data);
+ void drones_vert_w(offs_t offset, uint8_t data);
+ void track_horz_w(uint8_t data);
+ void track_horz_2_w(uint8_t data);
+ void track_vert_w(offs_t offset, uint8_t data);
+ void track_ice_w(uint8_t data);
+ void palette(palette_device &palette) const ATTR_COLD;
+ uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void screen_vblank(int state);
+ void draw_track(bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void draw_drones(bitmap_ind16 &bitmap, const rectangle &cliprect);
+ void draw_driver(bitmap_ind16 &bitmap, const rectangle &cliprect);
+
+ void io_map(address_map &map) ATTR_COLD;
+ void prg_map(address_map &map) ATTR_COLD;
+};
+
+
+void sspeedr_state::driver_horz_w(uint8_t data)
+{
+ m_driver_horz = (m_driver_horz & 0x100) | data;
+}
+
+
+void sspeedr_state::driver_horz_2_w(uint8_t data)
+{
+ m_driver_horz = (m_driver_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+void sspeedr_state::driver_vert_w(uint8_t data)
+{
+ m_driver_vert = data;
+}
+
+
+void sspeedr_state::driver_pic_w(uint8_t data)
+{
+ m_driver_pic = data & 0x1f;
+}
+
+
+void sspeedr_state::drones_horz_w(uint8_t data)
+{
+ m_drones_horz = (m_drones_horz & 0x100) | data;
+}
+
+
+void sspeedr_state::drones_horz_2_w(uint8_t data)
+{
+ m_drones_horz = (m_drones_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+void sspeedr_state::drones_mask_w(uint8_t data)
+{
+ m_drones_mask = data & 0x3f;
+}
+
+
+void sspeedr_state::drones_vert_w(offs_t offset, uint8_t data)
+{
+ m_drones_vert[offset] = data;
+}
+
+
+void sspeedr_state::track_horz_w(uint8_t data)
+{
+ m_track_horz = (m_track_horz & 0x100) | data;
+}
+
+
+void sspeedr_state::track_horz_2_w(uint8_t data)
+{
+ m_track_horz = (m_track_horz & 0xff) | ((data & 1) << 8);
+}
+
+
+void sspeedr_state::track_vert_w(offs_t offset, uint8_t data)
+{
+ m_track_vert[offset] = data & 0x7f;
+}
+
+
+void sspeedr_state::track_ice_w(uint8_t data)
+{
+ m_track_ice = data & 0x07;
+}
+
+
+void sspeedr_state::draw_track(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ for (int x = cliprect.min_x; x <= cliprect.max_x; x++)
+ {
+ unsigned counter_x = x + m_track_horz + 0x50;
+
+ int flag = 0;
+
+ if (m_track_ice & 2)
+ {
+ flag = 1;
+ }
+ else if (m_track_ice & 4)
+ {
+ if (m_track_ice & 1)
+ {
+ flag = (counter_x <= 0x1ff);
+ }
+ else
+ {
+ flag = (counter_x >= 0x200);
+ }
+ }
+
+ if (counter_x >= 0x200)
+ {
+ counter_x -= 0x1c8;
+ }
+
+ int y = cliprect.min_y;
+
+ // upper landscape
+ for (; y < m_track_vert[0] && y <= cliprect.max_y; y++)
+ {
+ unsigned const counter_y = y - m_track_vert[0];
+
+ int const offset =
+ ((counter_y & 0x1f) << 3) |
+ ((counter_x & 0x1c) >> 2) |
+ ((counter_x & 0xe0) << 3);
+
+ if (counter_x & 2)
+ {
+ bitmap.pix(y, x) = m_track[offset] >> 4;
+ }
+ else
+ {
+ bitmap.pix(y, x) = m_track[offset] & 0xf;
+ }
+ }
+
+ // street
+ for (; y < 128 + m_track_vert[1] && y <= cliprect.max_y; y++)
+ {
+ bitmap.pix(y, x) = flag ? 15 : 0;
+ }
+
+ // lower landscape
+ for (; y <= cliprect.max_y; y++)
+ {
+ unsigned const counter_y = y - m_track_vert[1];
+
+ int const offset =
+ ((counter_y & 0x1f) << 3) |
+ ((counter_x & 0x1c) >> 2) |
+ ((counter_x & 0xe0) << 3);
+
+ if (counter_x & 2)
+ {
+ bitmap.pix(y, x) = m_track[offset] >> 4;
+ }
+ else
+ {
+ bitmap.pix(y, x) = m_track[offset] & 0xf;
+ }
+ }
+ }
+}
+
+
+void sspeedr_state::draw_drones(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ static const uint8_t code[6] =
+ {
+ 0xf, 0x4, 0x3, 0x9, 0x7, 0xc
+ };
+
+ for (int i = 0; i < 6; i++)
+ {
+ if ((m_drones_mask >> i) & 1)
+ {
+ continue;
+ }
+
+ int x = (code[i] << 5) - m_drones_horz - 0x50;
+
+ if (x <= -32)
+ {
+ x += 0x1c8;
+ }
+
+ int const y = 0xf0 - m_drones_vert[i >> 1];
+
+ m_gfxdecode->gfx(1)->transpen(bitmap, cliprect,
+ code[i] ^ m_toggle,
+ 0,
+ 0, 0,
+ x,
+ y, 0);
+ }
+}
+
+
+void sspeedr_state::draw_driver(bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ if (!(m_driver_pic & 0x10))
+ {
+ return;
+ }
+
+ int x = 0x1e0 - m_driver_horz - 0x50;
+
+ if (x <= -32)
+ {
+ x += 0x1c8;
+ }
+
+ int const y = 0xf0 - m_driver_vert;
+
+ m_gfxdecode->gfx(0)->transpen(bitmap, cliprect,
+ m_driver_pic,
+ 0,
+ 0, 0,
+ x,
+ y, 0);
+}
+
+
+void sspeedr_state::video_start()
+{
+ m_toggle = 0;
+
+ save_item(NAME(m_toggle));
+ save_item(NAME(m_driver_horz));
+ save_item(NAME(m_driver_vert));
+ save_item(NAME(m_driver_pic));
+ save_item(NAME(m_drones_horz));
+ save_item(NAME(m_drones_vert));
+ save_item(NAME(m_drones_mask));
+ save_item(NAME(m_track_horz));
+ save_item(NAME(m_track_vert));
+ save_item(NAME(m_track_ice));
+}
+
+
+uint32_t sspeedr_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ draw_track(bitmap, cliprect);
+ draw_drones(bitmap, cliprect);
+ draw_driver(bitmap, cliprect);
+ return 0;
+}
+
+
+void sspeedr_state::screen_vblank(int state)
+{
+ // rising edge
+ if (state)
+ {
+ m_toggle ^= 1;
+ }
+}
+
+
+void sspeedr_state::machine_start()
+{
+ m_digits.resolve();
+ m_lampgo.resolve();
+ m_lampep.resolve();
+}
+
+void sspeedr_state::palette(palette_device &palette) const
+{
+ for (int i = 0; i < 16; i++)
+ {
+ int r = BIT(i, 0) ? 0xb0 : 0x20;
+ int g = BIT(i, 1) ? 0xb0 : 0x20;
+ int b = BIT(i, 2) ? 0xb0 : 0x20;
+
+ if (BIT(i, 3))
+ {
+ r += 0x4f;
+ g += 0x4f;
+ b += 0x4f;
+ }
+
+ palette.set_pen_color(i, rgb_t(r, g, b));
+ }
+}
+
+
+void sspeedr_state::int_ack_w(uint8_t data)
+{
+ m_maincpu->set_input_line(0, CLEAR_LINE);
+}
+
+
+void sspeedr_state::lamp_w(uint8_t data)
+{
+ m_lampgo = BIT(data, 0);
+ m_lampep = BIT(data, 1);
+ machine().bookkeeping().coin_counter_w(0, BIT(data, 3));
+}
+
+
+// uses a 7447A, which is equivalent to an LS47/48
+constexpr uint8_t ls48_map[16] =
+ { 0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7c,0x07,0x7f,0x67,0x58,0x4c,0x62,0x69,0x78,0x00 };
+
+void sspeedr_state::time_w(offs_t offset, uint8_t data)
+{
+ m_digits[24 + offset] = ls48_map[data & 0xf];
+}
+
+void sspeedr_state::score_w(offs_t offset, uint8_t data)
+{
+ m_digits[offset] = ls48_map[~data & 0xf];
+}
+
+
+void sspeedr_state::sound1_w(uint8_t data)
+{
+ // **** Output pins from 74174 latch at C2 ****
+
+ // Bits 0-3 (PEDAL_BIT0 to PEDAL_BIT3): accelerator pedal position
+ // Sets the frequency and volume of the engine sound oscillators.
+ for (int i = 0; i < 4; i++)
+ m_pedal_bit[i]->write_line(BIT(data, i));
+
+ // Bit 4 (HI SHIFT): set when gearshift is in high gear
+ // Modifies the engine sound to be lower pitched at a given speed and
+ // to change more slowly.
+ m_hi_shift->write_line(BIT(data, 4));
+
+ // Bit 5 (LO SHIFT): set when gearshift is in low gear
+ // Modifies the engine sound to be higher pitched at a given speed and
+ // to change faster.
+ m_lo_shift->write_line(BIT(data, 5));
+
+ // Bits 6-7 (D6, D7): not connected.
+}
+
+
+void sspeedr_state::sound2_w(uint8_t data)
+{
+ // **** Output pins from 74174 latch at D2 ****
+
+ // Bit 0 (BOOM): Set to activate boom sound for a crash. Cleared to
+ // terminate boom.
+ m_boom->write_line(BIT(data, 0));
+
+ // Bit 1 (ENGINE SOUND OFF): Set to turn *off* engine sound.
+ // Used in a crash.
+ m_engine_sound_off->write_line(BIT(data, 1));
+
+ // Bit 2 (NOISE CR 1): tire squealing sound
+ // Set to activate "tire squeal" noise from noise generator.
+ m_noise_cr[0]->write_line(BIT(data, 2));
+
+ // Bit 3 (NOISE CR 2): secondary crash noise
+ // Set to activate high-pitched screeching hiss that accompanies BOOM
+ // when the the car crashes. In Super Speed Race, the BOOM and NOISE
+ // CR 2 effects play simultaneously.
+ m_noise_cr[1]->write_line(BIT(data, 3));
+
+ // Bit 4 (SILENCE): mute all sound when game is not running.
+ m_silence->write_line(BIT(data, 4));
+
+ // Bits 5-7 (D5, D6, D7): not connected.
+}
+
+
+void sspeedr_state::prg_map(address_map &map)
+{
+ map(0x0000, 0x0fff).rom();
+ map(0x2000, 0x21ff).ram();
+ map(0x7f00, 0x7f17).w(FUNC(sspeedr_state::score_w));
+}
+
+
+void sspeedr_state::io_map(address_map &map)
+{
+ map.global_mask(0xff);
+ map(0x00, 0x00).portr("IN0").w(FUNC(sspeedr_state::sound1_w));
+ map(0x01, 0x01).portr("IN1").w(FUNC(sspeedr_state::sound2_w));
+ map(0x02, 0x02).w(FUNC(sspeedr_state::lamp_w));
+ map(0x03, 0x03).portr("DSW");
+ map(0x04, 0x04).portr("IN2");
+ map(0x04, 0x05).w(FUNC(sspeedr_state::time_w));
+ map(0x06, 0x06).w("watchdog", FUNC(watchdog_timer_device::reset_w));
+ map(0x10, 0x10).w(FUNC(sspeedr_state::driver_horz_w));
+ map(0x11, 0x11).w(FUNC(sspeedr_state::driver_pic_w));
+ map(0x12, 0x12).w(FUNC(sspeedr_state::driver_horz_2_w));
+ map(0x13, 0x13).w(FUNC(sspeedr_state::drones_horz_w));
+ map(0x14, 0x14).w(FUNC(sspeedr_state::drones_horz_2_w));
+ map(0x15, 0x15).w(FUNC(sspeedr_state::drones_mask_w));
+ map(0x16, 0x16).w(FUNC(sspeedr_state::driver_vert_w));
+ map(0x17, 0x18).w(FUNC(sspeedr_state::track_vert_w));
+ map(0x19, 0x19).w(FUNC(sspeedr_state::track_horz_w));
+ map(0x1a, 0x1a).w(FUNC(sspeedr_state::track_horz_2_w));
+ map(0x1b, 0x1b).w(FUNC(sspeedr_state::track_ice_w));
+ map(0x1c, 0x1e).w(FUNC(sspeedr_state::drones_vert_w));
+ map(0x1f, 0x1f).w(FUNC(sspeedr_state::int_ack_w));
+}
+
+
+static const ioport_value sspeedr_controller_table[] =
+{
+ 0x3f, 0x3e, 0x3c, 0x3d, 0x39, 0x38, 0x3a, 0x3b,
+ 0x33, 0x32, 0x30, 0x31, 0x35, 0x34, 0x36, 0x37,
+ 0x27, 0x26, 0x24, 0x25, 0x21, 0x20, 0x22, 0x23,
+ 0x2b, 0x2a, 0x28, 0x29, 0x2d, 0x2c, 0x2e, 0x2f,
+ 0x0f, 0x0e, 0x0c, 0x0d, 0x09, 0x08, 0x0a, 0x0b,
+ 0x03, 0x02, 0x00, 0x01, 0x05, 0x04, 0x06, 0x07,
+ 0x17, 0x16, 0x14, 0x15, 0x11, 0x10, 0x12, 0x13,
+ 0x1b, 0x1a, 0x18, 0x19, 0x1d, 0x1c, 0x1e, 0x1f
+};
+
+
+static INPUT_PORTS_START( sspeedr )
+
+ PORT_START("IN0")
+ PORT_BIT( 0x3f, 0x00, IPT_POSITIONAL ) PORT_POSITIONS(64) PORT_REMAP_TABLE(sspeedr_controller_table) PORT_WRAPS PORT_SENSITIVITY(25) PORT_KEYDELTA(10)
+
+ PORT_START("IN1")
+ // The gas pedal is adjusted physically so the encoder is at position 2 when the pedal is not pressed.
+ // It also only uses half of the encoder.
+ PORT_BIT( 0x1f, 0x00, IPT_POSITIONAL_V ) PORT_POSITIONS(30) PORT_REMAP_TABLE(sspeedr_controller_table + 2) PORT_SENSITIVITY(25) PORT_KEYDELTA(20)
+
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x03, 0x00, DEF_STR( Coinage ) ) PORT_DIPLOCATION("SW1:1,2")
+ PORT_DIPSETTING( 0x01, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x03, DEF_STR( 2C_3C ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( 1C_2C ) )
+ PORT_DIPNAME( 0x0c, 0x08, "Play Time" ) PORT_DIPLOCATION("SW1:3,4")
+ PORT_DIPSETTING( 0x00, "60 seconds")
+ PORT_DIPSETTING( 0x04, "70 seconds")
+ PORT_DIPSETTING( 0x08, "80 seconds")
+ PORT_DIPSETTING( 0x0c, "90 seconds")
+ PORT_DIPNAME( 0x10, 0x00, "Extended Play" ) PORT_DIPLOCATION("SW1:5")
+ PORT_DIPSETTING( 0x00, "20 seconds" )
+ PORT_DIPSETTING( 0x10, "30 seconds" )
+ PORT_DIPNAME( 0xe0, 0x20, DEF_STR( Service_Mode ) ) PORT_DIPLOCATION("SW1:6,7,8")
+ PORT_DIPSETTING( 0x20, "Play Mode" )
+ PORT_DIPSETTING( 0xa0, "RAM/ROM Test" )
+ PORT_DIPSETTING( 0xe0, "Accelerator Adjustment" )
+
+ PORT_START("IN2")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("Shifter") PORT_TOGGLE
+ PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_COIN1 )
+
+ PORT_START("POT_MASTER_VOL")
+ PORT_ADJUSTER( 50, "Pot: Master Volume" ) NETLIST_ANALOG_PORT_CHANGED("sound_nl", "pot_master_vol")
+INPUT_PORTS_END
+
+
+static const gfx_layout car_layout =
+{
+ 32, 16,
+ 16,
+ 4,
+ { 0, 1, 2, 3 },
+ {
+ 0x04, 0x04, 0x00, 0x00, 0x0c, 0x0c, 0x08, 0x08,
+ 0x14, 0x14, 0x10, 0x10, 0x1c, 0x1c, 0x18, 0x18,
+ 0x24, 0x24, 0x20, 0x20, 0x2c, 0x2c, 0x28, 0x28,
+ 0x34, 0x34, 0x30, 0x30, 0x3c, 0x3c, 0x38, 0x38
+ },
+ {
+ 0x000, 0x040, 0x080, 0x0c0, 0x100, 0x140, 0x180, 0x1c0,
+ 0x200, 0x240, 0x280, 0x2c0, 0x300, 0x340, 0x380, 0x3c0
+ },
+ 0x400
+};
+
+
+static GFXDECODE_START( gfx_sspeedr )
+ GFXDECODE_ENTRY( "driver", 0, car_layout, 0, 1 )
+ GFXDECODE_ENTRY( "drone", 0, car_layout, 0, 1 )
+GFXDECODE_END
+
+
+void sspeedr_state::sspeedr(machine_config &config)
+{
+ // basic machine hardware
+ Z80(config, m_maincpu, 19.968_MHz_XTAL / 8);
+ m_maincpu->set_addrmap(AS_PROGRAM, &sspeedr_state::prg_map);
+ m_maincpu->set_addrmap(AS_IO, &sspeedr_state::io_map);
+ m_maincpu->set_vblank_int("screen", FUNC(sspeedr_state::irq0_line_assert));
+
+ WATCHDOG_TIMER(config, "watchdog");
+
+ // video hardware
+ screen_device &screen(SCREEN(config, "screen", SCREEN_TYPE_RASTER));
+ screen.set_raw(14.318181_MHz_XTAL / 2, 456, 0, 376, 264, 0, 248);
+ screen.set_screen_update(FUNC(sspeedr_state::screen_update));
+ screen.screen_vblank().set(FUNC(sspeedr_state::screen_vblank));
+ screen.set_palette(m_palette);
+
+ GFXDECODE(config, m_gfxdecode, m_palette, gfx_sspeedr);
+ PALETTE(config, m_palette, FUNC(sspeedr_state::palette), 16);
+
+ // sound hardware
+ SPEAKER(config, "mono").front_center();
+
+ NETLIST_SOUND(config, "sound_nl", 48000)
+ .set_source(NETLIST_NAME(sspeedr))
+ .add_route(ALL_OUTPUTS, "mono", 1.0);
+
+ NETLIST_LOGIC_INPUT(config, m_pedal_bit[0], "I_PEDAL_BIT0", 0);
+ NETLIST_LOGIC_INPUT(config, m_pedal_bit[1], "I_PEDAL_BIT1", 0);
+ NETLIST_LOGIC_INPUT(config, m_pedal_bit[2], "I_PEDAL_BIT2", 0);
+ NETLIST_LOGIC_INPUT(config, m_pedal_bit[3], "I_PEDAL_BIT3", 0);
+ NETLIST_LOGIC_INPUT(config, m_hi_shift, "I_HI_SHIFT", 0);
+ NETLIST_LOGIC_INPUT(config, m_lo_shift, "I_LO_SHIFT", 0);
+ NETLIST_LOGIC_INPUT(config, m_boom, "I_BOOM", 0);
+ NETLIST_LOGIC_INPUT(config, m_engine_sound_off, "I_ENGINE_SOUND_OFF", 0);
+ NETLIST_LOGIC_INPUT(config, m_noise_cr[0], "I_NOISE_CR_1", 0);
+ NETLIST_LOGIC_INPUT(config, m_noise_cr[1], "I_NOISE_CR_2", 0);
+ NETLIST_LOGIC_INPUT(config, m_silence, "I_SILENCE", 0);
+
+ // Audio output is from an LM3900 op-amp whose output has a
+ // peak-to-peak range of about 12 volts, centered on 6 volts.
+ NETLIST_STREAM_OUTPUT(config, "sound_nl:cout0", 0, "OUTPUT").set_mult_offset(1.0 / 6.0, -1.0);
+
+ // Netlist volume-potentiometer interface
+ NETLIST_ANALOG_INPUT(config, "sound_nl:pot_master_vol", "R70.DIAL");
+}
+
+
+ROM_START( sspeedr )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "ssr0000.pgm", 0x0000, 0x0800, CRC(bfc7069a) SHA1(2f7aa3d3c7cfd804ba4b625c6a8338534a204855) )
+ ROM_LOAD( "ssr0800.pgm", 0x0800, 0x0800, CRC(ec46b59a) SHA1(d5727efecb32ad3d034b885e4a57d7373368ca9e) )
+
+ ROM_REGION( 0x0800, "driver", 0 )
+ ROM_LOAD( "ssrm762a.f3", 0x0000, 0x0800, CRC(de4653a9) SHA1(a6bbffb7eb60581eee43c74d20ca00b50c9a6e07) )
+
+ ROM_REGION( 0x0800, "drone", 0 )
+ ROM_LOAD( "ssrm762b.j3", 0x0000, 0x0800, CRC(ef6a1cd6) SHA1(77c31f14783e5ba90849bdc930b099c8360aeba7) )
+
+ ROM_REGION( 0x0800, "track", 0 )
+ ROM_LOAD( "ssrm762c.l3", 0x0000, 0x0800, CRC(ebaad3ee) SHA1(54ac994b505d20c75cf07a4f68da12360ee00153) )
+ROM_END
+
+} // anonymous namespace
+
+
+GAMEL( 1979, sspeedr, 0, sspeedr, sspeedr, sspeedr_state, empty_init, ROT270, "Taito (Midway license)", "Super Speed Race", MACHINE_SUPPORTS_SAVE, layout_sspeedr )