summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/sbrkout.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/sbrkout.cpp')
-rw-r--r--src/mame/drivers/sbrkout.cpp708
1 files changed, 708 insertions, 0 deletions
diff --git a/src/mame/drivers/sbrkout.cpp b/src/mame/drivers/sbrkout.cpp
new file mode 100644
index 00000000000..33b8e1d5a10
--- /dev/null
+++ b/src/mame/drivers/sbrkout.cpp
@@ -0,0 +1,708 @@
+// license:BSD-3-Clause
+// copyright-holders:Mike Balfour
+/***************************************************************************
+
+ Atari Super Breakout hardware
+
+ driver by Mike Balfour
+
+ Games supported:
+ * Super Breakout
+ * Super Breakout (Canyon and Vertical Breakout, prototype)
+ * Super Breakout (Cocktail, prototype)
+
+ Known issues:
+ * none at this time
+
+****************************************************************************
+
+ To do:
+
+ * Merge with Sprint 1
+
+****************************************************************************
+
+ Stephh's notes (based on the games M6502 code and some tests) :
+
+ - Each time the game is reset, it is set to "Cavity".
+ I can't remember if it's the correct behaviour or not,
+ but the VBLANK interruption is not called in "demo mode".
+ - You can only select the game after 1st coin is inserted
+ and before you press BUTTON1 to launch the first ball,
+ then the VBLANK interruption is no more called.
+ This means that player 2 plays the same game as player 1.
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/dac.h"
+
+#include "sbrkout.lh"
+
+
+class sbrkout_state : public driver_device
+{
+public:
+ sbrkout_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag),
+ m_videoram(*this, "videoram"),
+ m_maincpu(*this, "maincpu"),
+ m_dac(*this, "dac"),
+ m_gfxdecode(*this, "gfxdecode"),
+ m_screen(*this, "screen"),
+ m_palette(*this, "palette") { }
+
+ required_shared_ptr<UINT8> m_videoram;
+ emu_timer *m_scanline_timer;
+ emu_timer *m_pot_timer;
+ tilemap_t *m_bg_tilemap;
+ UINT8 m_sync2_value;
+ UINT8 m_pot_mask[2];
+ UINT8 m_pot_trigger[2];
+ DECLARE_WRITE8_MEMBER(irq_ack_w);
+ DECLARE_READ8_MEMBER(switches_r);
+ DECLARE_READ8_MEMBER(sbrkoutct_switches_r);
+ DECLARE_WRITE8_MEMBER(pot_mask1_w);
+ DECLARE_WRITE8_MEMBER(pot_mask2_w);
+ DECLARE_WRITE8_MEMBER(start_1_led_w);
+ DECLARE_WRITE8_MEMBER(start_2_led_w);
+ DECLARE_WRITE8_MEMBER(serve_led_w);
+ DECLARE_WRITE8_MEMBER(serve_2_led_w);
+ DECLARE_WRITE8_MEMBER(coincount_w);
+ DECLARE_READ8_MEMBER(sync_r);
+ DECLARE_READ8_MEMBER(sync2_r);
+ DECLARE_WRITE8_MEMBER(sbrkout_videoram_w);
+ TILE_GET_INFO_MEMBER(get_bg_tile_info);
+ virtual void machine_start();
+ virtual void machine_reset();
+ virtual void video_start();
+ UINT32 screen_update_sbrkout(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
+ TIMER_CALLBACK_MEMBER(scanline_callback);
+ TIMER_CALLBACK_MEMBER(pot_trigger_callback);
+ void update_nmi_state();
+ required_device<cpu_device> m_maincpu;
+ required_device<dac_device> m_dac;
+ required_device<gfxdecode_device> m_gfxdecode;
+ required_device<screen_device> m_screen;
+ required_device<palette_device> m_palette;
+};
+
+
+
+
+/*************************************
+ *
+ * Constants
+ *
+ *************************************/
+
+#define MAIN_CLOCK XTAL_12_096MHz
+#define TIME_4V attotime::from_hz(MAIN_CLOCK/2/256/2/4)
+
+
+
+/*************************************
+ *
+ * Prototypes
+ *
+ *************************************/
+
+
+
+
+
+
+/*************************************
+ *
+ * Machine setup
+ *
+ *************************************/
+
+void sbrkout_state::machine_start()
+{
+ UINT8 *videoram = m_videoram;
+ membank("bank1")->set_base(&videoram[0x380]);
+ m_scanline_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sbrkout_state::scanline_callback),this));
+ m_pot_timer = machine().scheduler().timer_alloc(timer_expired_delegate(FUNC(sbrkout_state::pot_trigger_callback),this));
+
+ save_item(NAME(m_sync2_value));
+ save_item(NAME(m_pot_mask));
+ save_item(NAME(m_pot_trigger));
+}
+
+
+void sbrkout_state::machine_reset()
+{
+ m_scanline_timer->adjust(m_screen->time_until_pos(0));
+}
+
+
+
+/*************************************
+ *
+ * Interrupts
+ *
+ *************************************/
+
+TIMER_CALLBACK_MEMBER(sbrkout_state::scanline_callback)
+{
+ UINT8 *videoram = m_videoram;
+ int scanline = param;
+
+ /* force a partial update before anything happens */
+ m_screen->update_partial(scanline);
+
+ /* if this is a rising edge of 16V, assert the CPU interrupt */
+ if (scanline % 32 == 16)
+ m_maincpu->set_input_line(0, ASSERT_LINE);
+
+ /* update the DAC state */
+ m_dac->write_unsigned8((videoram[0x380 + 0x11] & (scanline >> 2)) ? 255 : 0);
+
+ /* on the VBLANK, read the pot and schedule an interrupt time for it */
+ if (scanline == m_screen->visible_area().max_y + 1)
+ {
+ UINT8 potvalue = ioport("PADDLE")->read();
+ m_pot_timer->adjust(m_screen->time_until_pos(56 + (potvalue / 2), (potvalue % 2) * 128));
+ }
+
+ /* call us back in 4 scanlines */
+ scanline += 4;
+ if (scanline >= m_screen->height())
+ scanline = 0;
+ m_scanline_timer->adjust(m_screen->time_until_pos(scanline), scanline);
+}
+
+
+WRITE8_MEMBER(sbrkout_state::irq_ack_w)
+{
+ m_maincpu->set_input_line(0, CLEAR_LINE);
+}
+
+
+
+/*************************************
+ *
+ * Inputs
+ *
+ *************************************/
+
+READ8_MEMBER(sbrkout_state::switches_r)
+{
+ UINT8 result = 0xff;
+
+ /* DIP switches are selected by ADR0+ADR1 if ADR3 == 0 */
+ if ((offset & 0x0b) == 0x00)
+ result &= (ioport("DIPS")->read() << 6) | 0x3f;
+ if ((offset & 0x0b) == 0x01)
+ result &= (ioport("DIPS")->read() << 4) | 0x3f;
+ if ((offset & 0x0b) == 0x02)
+ result &= (ioport("DIPS")->read() << 0) | 0x3f;
+ if ((offset & 0x0b) == 0x03)
+ result &= (ioport("DIPS")->read() << 2) | 0x3f;
+
+ /* other switches are selected by ADR0+ADR1+ADR2 if ADR4 == 0 */
+ if ((offset & 0x17) == 0x00)
+ result &= (ioport("SELECT")->read() << 7) | 0x7f;
+ if ((offset & 0x17) == 0x04)
+ result &= ((m_pot_trigger[0] & ~m_pot_mask[0]) << 7) | 0x7f;
+ if ((offset & 0x17) == 0x05)
+ result &= ((m_pot_trigger[1] & ~m_pot_mask[1]) << 7) | 0x7f;
+ if ((offset & 0x17) == 0x06)
+ result &= ioport("SERVE")->read();
+ if ((offset & 0x17) == 0x07)
+ result &= (ioport("SELECT")->read() << 6) | 0x7f;
+
+ return result;
+}
+
+READ8_MEMBER(sbrkout_state::sbrkoutct_switches_r)
+{
+ UINT8 result = 0xff;
+
+ switch( offset )
+ {
+ case 0x28: result = ioport("SELECT")->read(); break;
+ case 0x2e: result = ioport("SERVE")->read(); break;
+ case 0x2f: result = ioport("SERVE2")->read(); break;
+ case 0x30: result = (ioport("DIPS")->read() & 0x03) << 6; break;
+ case 0x31: result = (ioport("DIPS")->read() & 0x0c) << 4; break;
+ case 0x32: result = ioport("DIPS")->read() & 0xc0; break;
+ case 0x33: result = (ioport("DIPS")->read() & 0x30) << 2; break;
+ default: logerror("Unknown port read %x\n", offset); break;
+ }
+ return result;
+}
+
+void sbrkout_state::update_nmi_state()
+{
+ if ((m_pot_trigger[0] & ~m_pot_mask[0]) | (m_pot_trigger[1] & ~m_pot_mask[1]))
+ m_maincpu->set_input_line(INPUT_LINE_NMI, ASSERT_LINE);
+ else
+ m_maincpu->set_input_line(INPUT_LINE_NMI, CLEAR_LINE);
+}
+
+
+TIMER_CALLBACK_MEMBER(sbrkout_state::pot_trigger_callback)
+{
+ m_pot_trigger[param] = 1;
+ update_nmi_state();
+}
+
+
+WRITE8_MEMBER(sbrkout_state::pot_mask1_w)
+{
+ m_pot_mask[0] = ~offset & 1;
+ m_pot_trigger[0] = 0;
+ update_nmi_state();
+}
+
+
+WRITE8_MEMBER(sbrkout_state::pot_mask2_w)
+{
+ m_pot_mask[1] = ~offset & 1;
+ m_pot_trigger[1] = 0;
+ update_nmi_state();
+}
+
+
+
+/*************************************
+ *
+ * Lamps and other outputs
+ *
+ *************************************/
+
+/*
+ The LEDs are turned on and off by two consecutive memory addresses. The
+ first address turns them off, the second address turns them on. This is
+ reversed for the Serve LED, which has a NOT on the signal.
+*/
+
+WRITE8_MEMBER(sbrkout_state::start_1_led_w)
+{
+ output_set_led_value(0, offset & 1);
+}
+
+
+WRITE8_MEMBER(sbrkout_state::start_2_led_w)
+{
+ output_set_led_value(1, offset & 1);
+}
+
+
+WRITE8_MEMBER(sbrkout_state::serve_led_w)
+{
+ output_set_led_value(0, ~offset & 1);
+}
+
+WRITE8_MEMBER(sbrkout_state::serve_2_led_w)
+{
+ output_set_led_value(1, ~offset & 1);
+}
+
+WRITE8_MEMBER(sbrkout_state::coincount_w)
+{
+ coin_counter_w(machine(), 0, offset & 1);
+}
+
+
+
+/*************************************
+ *
+ * Video timing
+ *
+ *************************************/
+
+READ8_MEMBER(sbrkout_state::sync_r)
+{
+ int hpos = m_screen->hpos();
+ m_sync2_value = (hpos >= 128 && hpos <= m_screen->visible_area().max_x);
+ return m_screen->vpos();
+}
+
+
+READ8_MEMBER(sbrkout_state::sync2_r)
+{
+ return (m_sync2_value << 7) | 0x7f;
+}
+
+
+
+/*************************************
+ *
+ * Background tilemap
+ *
+ *************************************/
+
+TILE_GET_INFO_MEMBER(sbrkout_state::get_bg_tile_info)
+{
+ UINT8 *videoram = m_videoram;
+ int code = (videoram[tile_index] & 0x80) ? videoram[tile_index] : 0;
+ SET_TILE_INFO_MEMBER(0, code, 0, 0);
+}
+
+
+void sbrkout_state::video_start()
+{
+ m_bg_tilemap = &machine().tilemap().create(m_gfxdecode, tilemap_get_info_delegate(FUNC(sbrkout_state::get_bg_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 32, 32);
+}
+
+
+WRITE8_MEMBER(sbrkout_state::sbrkout_videoram_w)
+{
+ UINT8 *videoram = m_videoram;
+ videoram[offset] = data;
+ m_bg_tilemap->mark_tile_dirty(offset);
+}
+
+
+
+/*************************************
+ *
+ * Video update
+ *
+ *************************************/
+
+UINT32 sbrkout_state::screen_update_sbrkout(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
+{
+ UINT8 *videoram = m_videoram;
+ int ball;
+
+ m_bg_tilemap->draw(screen, bitmap, cliprect, 0, 0);
+
+ for (ball = 2; ball >= 0; ball--)
+ {
+ int code = ((videoram[0x380 + 0x18 + ball * 2 + 1] & 0x80) >> 7);
+ int sx = 31 * 8 - videoram[0x380 + 0x10 + ball * 2];
+ int sy = 30 * 8 - videoram[0x380 + 0x18 + ball * 2];
+
+ m_gfxdecode->gfx(1)->transpen(bitmap,cliprect, code, 0, 0, 0, sx, sy, 0);
+ }
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Main CPU memory handlers
+ *
+ *************************************/
+
+/* full memory map derived from schematics */
+static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8, sbrkout_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x3fff)
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x380) AM_RAMBANK("bank1")
+ AM_RANGE(0x0400, 0x07ff) AM_RAM_WRITE(sbrkout_videoram_w) AM_SHARE("videoram")
+ AM_RANGE(0x0800, 0x083f) AM_READ(switches_r)
+ AM_RANGE(0x0840, 0x0840) AM_MIRROR(0x003f) AM_READ_PORT("COIN")
+ AM_RANGE(0x0880, 0x0880) AM_MIRROR(0x003f) AM_READ_PORT("START")
+ AM_RANGE(0x08c0, 0x08c0) AM_MIRROR(0x003f) AM_READ_PORT("SERVICE")
+ AM_RANGE(0x0c00, 0x0c00) AM_MIRROR(0x03ff) AM_READ(sync_r)
+ AM_RANGE(0x0c10, 0x0c11) AM_MIRROR(0x000e) AM_WRITE(serve_led_w)
+ AM_RANGE(0x0c30, 0x0c31) AM_MIRROR(0x000e) AM_WRITE(start_1_led_w)
+ AM_RANGE(0x0c40, 0x0c41) AM_MIRROR(0x000e) AM_WRITE(start_2_led_w)
+ AM_RANGE(0x0c50, 0x0c51) AM_MIRROR(0x000e) AM_WRITE(pot_mask1_w)
+ AM_RANGE(0x0c60, 0x0c61) AM_MIRROR(0x000e) AM_WRITE(pot_mask2_w)
+ AM_RANGE(0x0c70, 0x0c71) AM_MIRROR(0x000e) AM_WRITE(coincount_w)
+ AM_RANGE(0x0c80, 0x0c80) AM_MIRROR(0x007f) AM_WRITE(watchdog_reset_w)
+ AM_RANGE(0x0e00, 0x0e00) AM_MIRROR(0x007f) AM_WRITE(irq_ack_w)
+ AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x03ff) AM_READ(sync2_r)
+ AM_RANGE(0x2800, 0x3fff) AM_ROM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( sbrkoutct_main_map, AS_PROGRAM, 8, sbrkout_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x3fff)
+ AM_RANGE(0x0000, 0x007f) AM_MIRROR(0x380) AM_RAMBANK("bank1")
+ AM_RANGE(0x0400, 0x07ff) AM_RAM_WRITE(sbrkout_videoram_w) AM_SHARE("videoram")
+ AM_RANGE(0x0800, 0x083f) AM_READ(sbrkoutct_switches_r)
+ AM_RANGE(0x0840, 0x0840) AM_MIRROR(0x003f) AM_READ_PORT("COIN")
+ AM_RANGE(0x0880, 0x0880) AM_MIRROR(0x003f) AM_READ_PORT("START")
+ AM_RANGE(0x08c0, 0x08c0) AM_MIRROR(0x003f) AM_READ_PORT("SERVICE")
+ AM_RANGE(0x0c00, 0x0c00) AM_MIRROR(0x03ff) AM_READ(sync_r)
+ AM_RANGE(0x0c10, 0x0c11) AM_MIRROR(0x000e) AM_WRITE(serve_led_w)
+ AM_RANGE(0x0c20, 0x0c21) AM_MIRROR(0x000e) AM_WRITE(serve_2_led_w)
+ AM_RANGE(0x0c30, 0x0c31) AM_MIRROR(0x000e) AM_WRITE(start_1_led_w)
+ AM_RANGE(0x0c40, 0x0c41) AM_MIRROR(0x000e) AM_WRITE(start_2_led_w)
+ AM_RANGE(0x0c50, 0x0c51) AM_MIRROR(0x000e) AM_WRITE(pot_mask1_w)
+ AM_RANGE(0x0c60, 0x0c61) AM_MIRROR(0x000e) AM_WRITE(pot_mask2_w)
+ AM_RANGE(0x0c70, 0x0c71) AM_MIRROR(0x000e) AM_WRITE(coincount_w)
+ AM_RANGE(0x0c80, 0x0c80) AM_MIRROR(0x007f) AM_WRITE(watchdog_reset_w)
+ AM_RANGE(0x0e00, 0x0e00) AM_MIRROR(0x007f) AM_WRITE(irq_ack_w)
+ AM_RANGE(0x1000, 0x1000) AM_MIRROR(0x03ff) AM_READ(sync2_r)
+ AM_RANGE(0x2800, 0x3fff) AM_ROM
+ADDRESS_MAP_END
+
+
+/*************************************
+ *
+ * Port definitions
+ *
+ *************************************/
+
+static INPUT_PORTS_START( sbrkout )
+ PORT_START("DIPS")
+ PORT_DIPNAME( 0x03, 0x00, DEF_STR( Language ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( English ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( German ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( French ) )
+ PORT_DIPSETTING( 0x03, DEF_STR( Spanish ) )
+ PORT_DIPNAME( 0x0c, 0x08, DEF_STR( Coinage ) )
+ PORT_DIPSETTING( 0x0c, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( Free_Play ) )
+ PORT_DIPNAME( 0x70, 0x00, "Extended Play" )
+ /* Progressive */
+ PORT_DIPSETTING( 0x10, "200" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x20, "400" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x30, "600" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x40, "900" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x50, "1200" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x60, "1600" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ PORT_DIPSETTING( 0x70, "2000" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x00)
+ /* Double */
+ PORT_DIPSETTING( 0x10, "200" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x20, "400" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x30, "600" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x40, "800" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x50, "1000" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x60, "1200" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ PORT_DIPSETTING( 0x70, "1500" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x02)
+ /* Cavity */
+ PORT_DIPSETTING( 0x10, "200" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x20, "300" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x30, "400" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x40, "700" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x50, "900" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x60, "1100" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x70, "1400" ) PORT_CONDITION("SELECT",0x03,EQUALS,0x01)
+ PORT_DIPSETTING( 0x00, DEF_STR( None ) )
+ PORT_DIPNAME( 0x80, 0x80, DEF_STR( Lives ) )
+ PORT_DIPSETTING( 0x80, "3" )
+ PORT_DIPSETTING( 0x00, "5" )
+
+ PORT_START("COIN")
+ PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_COIN1 )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN2 )
+
+ PORT_START("START")
+ PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_START1 )
+ PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START2 )
+
+ PORT_START("SERVICE")
+ PORT_BIT( 0x3f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_TILT )
+ PORT_SERVICE( 0x80, IP_ACTIVE_LOW )
+
+ PORT_START("SERVE")
+ PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 )
+
+ PORT_START("PADDLE")
+ PORT_BIT( 0xff, 0x00, IPT_PADDLE ) PORT_SENSITIVITY(50) PORT_KEYDELTA(10) PORT_CENTERDELTA(0)
+
+ PORT_START("SELECT") /* IN6 - fake port, used to set the game select dial */
+ PORT_CONFNAME( 0x03, 0x00, "Game Select" )
+ PORT_CONFSETTING( 0x00, "Progressive" )
+ PORT_CONFSETTING( 0x02, "Double" )
+ PORT_CONFSETTING( 0x01, "Cavity" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( sbrkoutc )
+ PORT_INCLUDE(sbrkout)
+
+ PORT_MODIFY("SELECT") /* IN6 - fake port, used to set the game select dial */
+ PORT_CONFNAME( 0x03, 0x00, "Game Select" )
+ PORT_CONFSETTING( 0x00, "Canyon" )
+ PORT_CONFSETTING( 0x02, "Vertical" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( sbrkoutct )
+ PORT_INCLUDE(sbrkout)
+
+ PORT_START("SERVE2")
+ PORT_BIT( 0x7f, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2)
+
+ PORT_MODIFY("SELECT")
+ PORT_CONFNAME(0x80, 0x00, "Game Select" )
+ PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
+ PORT_CONFSETTING( 0x80, DEF_STR( On ) )
+INPUT_PORTS_END
+
+/*************************************
+ *
+ * Graphics definitions
+ *
+ *************************************/
+
+static const gfx_layout charlayout =
+{
+ 8,8,
+ 64,
+ 1,
+ { 0 },
+ { 4, 5, 6, 7, 0x200*8 + 4, 0x200*8 + 5, 0x200*8 + 6, 0x200*8 + 7 },
+ { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 8*8
+};
+
+
+static const gfx_layout balllayout =
+{
+ 3,3,
+ 2,
+ 1,
+ { 0 },
+ { 0, 1, 2 },
+ { 0*8, 1*8, 2*8 },
+ 3*8
+};
+
+
+static GFXDECODE_START( sbrkout )
+ GFXDECODE_ENTRY( "gfx1", 0, charlayout, 0, 1 )
+ GFXDECODE_ENTRY( "gfx2", 0, balllayout, 0, 1 )
+GFXDECODE_END
+
+
+
+/*************************************
+ *
+ * Machine driver
+ *
+ *************************************/
+
+static MACHINE_CONFIG_START( sbrkout, sbrkout_state )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", M6502,MAIN_CLOCK/16) /* 375 KHz? Should be 750KHz? */
+ MCFG_CPU_PROGRAM_MAP(main_map)
+
+ MCFG_WATCHDOG_VBLANK_INIT(8)
+
+ /* video hardware */
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", sbrkout)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(MAIN_CLOCK/2, 384, 0, 256, 262, 0, 224)
+ MCFG_SCREEN_UPDATE_DRIVER(sbrkout_state, screen_update_sbrkout)
+ MCFG_SCREEN_PALETTE("palette")
+
+ MCFG_PALETTE_ADD_BLACK_AND_WHITE("palette")
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+ MCFG_DAC_ADD("dac")
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED(sbrkoutct, sbrkout)
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(sbrkoutct_main_map)
+MACHINE_CONFIG_END
+
+/*************************************
+ *
+ * ROM definitions
+ *
+ *************************************/
+
+// see page 3-21 of schematics which explain the 2 versions.
+// the rev 01 and rev 02 are not mentioned in the tm-118 manual despite it being a first printing
+// hence they are probably prototypes. neither is dumped.
+
+ROM_START( sbrkout ) // rev 04
+ ROM_REGION( 0x4000, "maincpu", 0 )
+ ROM_LOAD( "033453.c1", 0x2800, 0x0800, CRC(a35d00e3) SHA1(53617ed1d362e82d6f45abd66056bffe23300e3b) )
+ ROM_LOAD( "033454.d1", 0x3000, 0x0800, CRC(d42ea79a) SHA1(66c9b29226cde36d1ac6d1e81f34ebb5c79eded4) )
+ ROM_LOAD( "033455.e1", 0x3800, 0x0800, CRC(e0a6871c) SHA1(1bdfa73d7b8d91e1c68b7847fc310cac314ee02d) )
+
+ ROM_REGION( 0x0400, "gfx1", 0 )
+ ROM_LOAD( "033280.p4", 0x0000, 0x0200, CRC(5a69ce85) SHA1(ad9078d12495c350738bdb0b1e1b6120d9e01f60) )
+ ROM_LOAD( "033281.r4", 0x0200, 0x0200, CRC(066bd624) SHA1(cfb86c7013a70b8375126b23a4e66df5f3b9186b) )
+
+ ROM_REGION( 0x0020, "gfx2", 0 )
+ ROM_LOAD( "033282.k6", 0x0000, 0x0020, CRC(6228736b) SHA1(bc176261dba11521df19d545ce604f8cc294287a) )
+
+ ROM_REGION( 0x0120, "proms", 0 )
+ ROM_LOAD( "006400.m2", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync (not used) */
+ ROM_LOAD( "006401.e2", 0x0100, 0x0020, CRC(857df8db) SHA1(06313d5bde03220b2bc313d18e50e4bb1d0cfbbb) ) /* memory mapper */
+ROM_END
+
+
+ROM_START( sbrkout3 ) // rev 03; main cpu roms are on 1024x4bit (82s137 or equiv) proms, otherwise seems identical to rev 04
+ ROM_REGION( 0x4000, "maincpu", 0 )
+ ROM_LOAD_NIB_HIGH( "33442-01.kl0", 0x2C00, 0x0400, CRC(fb5cb68a) SHA1(301e8e47f6a82d6c2290a890bcd5c53d61d58ff7) )
+ ROM_LOAD_NIB_LOW( "33448-01.kl1", 0x2C00, 0x0400, CRC(b1d2b269) SHA1(46de71f1f9695f03465fd9b2289b5c5ffe19b3a2) )
+ ROM_LOAD_NIB_HIGH( "33443-01.l0", 0x3000, 0x0400, CRC(1e7d059f) SHA1(e1831febfd26cf2560351d45f37763a7498c029e) )
+ ROM_LOAD_NIB_LOW( "33449-01.l1", 0x3000, 0x0400, CRC(f936918d) SHA1(9d62fe75d39f95085a4380059c4980f3affe1bbf) )
+ ROM_LOAD_NIB_HIGH( "33444-01.m0", 0x3400, 0x0400, CRC(5b7e0e3b) SHA1(4dbd62b23249fbb05e1fffe50b89a5e280a2dde9) )
+ ROM_LOAD_NIB_LOW( "33450-01.m1", 0x3400, 0x0400, CRC(430cf9e8) SHA1(8e6075f12dbe0b973500d4e38e0090e40ee47260) )
+ ROM_LOAD_NIB_HIGH( "33445-01.n0", 0x3800, 0x0400, CRC(cdf19919) SHA1(13623bde69e7f352beaef33524f69d74c540e1cc) )
+ ROM_LOAD_NIB_LOW( "33451-01.n1", 0x3800, 0x0400, CRC(19f7c50d) SHA1(91ba9ef7ab4b200a55ae7b7979f4a01e617dd9ad) )
+ ROM_LOAD_NIB_HIGH( "33446-01.p0", 0x3C00, 0x0400, CRC(9553663c) SHA1(6c28b3a11b7ff0aa224bf262c664a62166dc9cdf) )
+ ROM_LOAD_NIB_LOW( "33452-01.p1", 0x3C00, 0x0400, CRC(6dc0439a) SHA1(9cc0b735935a610519eb1b53ed303223e69af0b7) )
+
+ ROM_REGION( 0x0400, "gfx1", 0 )
+ ROM_LOAD( "033280.p4", 0x0000, 0x0200, CRC(5a69ce85) SHA1(ad9078d12495c350738bdb0b1e1b6120d9e01f60) )
+ ROM_LOAD( "033281.r4", 0x0200, 0x0200, CRC(066bd624) SHA1(cfb86c7013a70b8375126b23a4e66df5f3b9186b) )
+
+ ROM_REGION( 0x0020, "gfx2", 0 )
+ ROM_LOAD( "033282.k6", 0x0000, 0x0020, CRC(6228736b) SHA1(bc176261dba11521df19d545ce604f8cc294287a) )
+
+ ROM_REGION( 0x0120, "proms", 0 )
+ ROM_LOAD( "006400.m2", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync (not used) */
+ ROM_LOAD( "006401.e2", 0x0100, 0x0020, CRC(857df8db) SHA1(06313d5bde03220b2bc313d18e50e4bb1d0cfbbb) ) /* memory mapper */
+ROM_END
+
+ROM_START( sbrkoutc ) // built from original Atari source code
+ ROM_REGION( 0x4000, "maincpu", 0 )
+ ROM_LOAD( "a33443.bin", 0x2800, 0x1800, CRC(bf418976) SHA1(d766e220a284a7b9caf876207e8191aff0497a03) )
+
+ ROM_REGION( 0x0400, "gfx1", 0 )
+ ROM_LOAD( "033280.p4", 0x0000, 0x0200, CRC(5a69ce85) SHA1(ad9078d12495c350738bdb0b1e1b6120d9e01f60) )
+ ROM_LOAD( "033281.r4", 0x0200, 0x0200, CRC(066bd624) SHA1(cfb86c7013a70b8375126b23a4e66df5f3b9186b) )
+
+ ROM_REGION( 0x0020, "gfx2", 0 )
+ ROM_LOAD( "033282.k6", 0x0000, 0x0020, CRC(6228736b) SHA1(bc176261dba11521df19d545ce604f8cc294287a) )
+
+ ROM_REGION( 0x0120, "proms", 0 )
+ ROM_LOAD( "006400.m2", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync (not used) */
+ ROM_LOAD( "006401.e2", 0x0100, 0x0020, CRC(857df8db) SHA1(06313d5bde03220b2bc313d18e50e4bb1d0cfbbb) ) /* memory mapper */
+ROM_END
+
+ROM_START( sbrkoutct ) // built from original Atari source code
+ ROM_REGION( 0x4000, "maincpu", 0 )
+ ROM_LOAD( "034555-01.c1", 0x2800, 0x0800, CRC(2da82521) SHA1(1f53e549676052647486cea6738c5c7a45133538) )
+ ROM_LOAD( "034556-01.d11", 0x3000, 0x0800, CRC(5a6497ae) SHA1(96c2a136fb1e649e2db17bcb12bdc2a8d250a63e) )
+ ROM_LOAD( "034557-01.ef1", 0x3800, 0x0800, CRC(b6b3b07b) SHA1(c4d2cdcca89c2944afd4a4ed0bb5003b3eca4c7e) )
+
+ ROM_REGION( 0x0400, "gfx1", 0 )
+ ROM_LOAD( "034559-01.r4", 0x0000, 0x0200, CRC(84368539) SHA1(50b2c3f443346e3a355492ed1f7ec0a8cc6364d4) )
+ ROM_LOAD( "034558-01.p4", 0x0200, 0x0200, CRC(cc0f81f2) SHA1(a2180280991c9cf43f4e941d9ba4fe5654d1af65) )
+
+ ROM_REGION( 0x0020, "gfx2", 0 )
+ ROM_LOAD( "033282.k6", 0x0000, 0x0020, CRC(6228736b) SHA1(bc176261dba11521df19d545ce604f8cc294287a) )
+
+ ROM_REGION( 0x0120, "proms", 0 )
+ ROM_LOAD( "006400.m2", 0x0000, 0x0100, CRC(b8094b4c) SHA1(82dc6799a19984f3b204ee3aeeb007e55afc8be3) ) /* sync (not used) */
+ ROM_LOAD( "006401.e2", 0x0100, 0x0020, CRC(857df8db) SHA1(06313d5bde03220b2bc313d18e50e4bb1d0cfbbb) ) /* memory mapper */
+ROM_END
+
+/*************************************
+ *
+ * Game drivers
+ *
+ *************************************/
+
+GAMEL( 1978, sbrkout, 0, sbrkout, sbrkout, driver_device, 0, ROT270, "Atari", "Super Breakout (rev 04)", MACHINE_SUPPORTS_SAVE, layout_sbrkout )
+GAMEL( 1978, sbrkout3, sbrkout, sbrkout, sbrkout, driver_device, 0, ROT270, "Atari", "Super Breakout (rev 03)", MACHINE_SUPPORTS_SAVE, layout_sbrkout )
+GAMEL( 1978, sbrkoutc, sbrkout, sbrkout, sbrkoutc, driver_device, 0, ROT270, "Atari", "Super Breakout (Canyon and Vertical Breakout, prototype)", MACHINE_SUPPORTS_SAVE, layout_sbrkout )
+GAMEL( 1978, sbrkoutct, sbrkout, sbrkoutct, sbrkoutct, driver_device, 0, ROT270, "Atari", "Super Breakout (Cocktail, prototype)", MACHINE_SUPPORTS_SAVE, layout_sbrkout )