summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/drivers/popper.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/drivers/popper.c')
-rw-r--r--trunk/src/mame/drivers/popper.c403
1 files changed, 403 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/popper.c b/trunk/src/mame/drivers/popper.c
new file mode 100644
index 00000000000..dc08f3dc5a0
--- /dev/null
+++ b/trunk/src/mame/drivers/popper.c
@@ -0,0 +1,403 @@
+/***************************************************************************
+
+ Popper
+
+ Omori Electric CAD (OEC) 1983
+
+
+ PPR-12
+
+
+ 18.432MHz 6148 6148
+ 6148 4148
+ 2128
+ 2128
+ 2128
+ 2128
+ p3 p6
+ z80A p2 p5
+ p0 p1 p4
+ z80A
+ 8910
+ 8910 SW2 SW1 p.m4 p.m3
+
+
+Notes:
+
+- a lower interleave causes some sounds to miss, different interleave values
+ change random elements eg position of falling logs, it may be enough to
+ synchronise the cpus on read/writes to the 0xdd00/0f range
+
+- it's possible that the two score rows shouldn't be overlaid or shouldn't be
+ drawn at all times, the only time there is anything underneath is the colour
+ bars on the startup screen
+
+- on odd/bonus levels the chars are not aligned with the sprites when the pylons
+ are initially drawn (too low) resulting in the top 3 pylons being black, as
+ the pylons move up the screen the chars go out of alignment again (this time
+ too high) for a single frame to show another glitch
+
+- front to back ordering of object/enemy sprites appears wrong
+
+- on even levels the front most balloon carrying new enemies swaps between the
+ left and middle one, clipping to 16 pixel strips solves this but causes other
+ obvious sprite drawing errors
+
+- balloon sprites not displayed on high score entry due to the way videoram is
+ being drawn, possibly trying to create a stencil effect
+
+- bursting a balloon on bonus levels just before dying from a log causes a
+ sprite glitch for a few frames and then a 9999 point bonus
+
+- reads from 0xffff appear to be a harmless bug in the code that initialises
+ memory blocks for enemies on odd levels, it goes on to read from 0x001f,
+ 0x003f, 0x005f, 0x007f in the rom before giving up
+
+- a reset while a game is in progress or with credits inserted shows a
+ "sorry!! over run" message instead of the test screen during startup,
+ looks like the game assumes the reset was caused by the watchdog after a
+ hang/crash and is apologising to the player for the loss of their game
+
+- title screen sprite colour glitch in lower right corner of the large pylon
+ when an even level was shown before, caused by the game trying to colour
+ the top of the pylon in the same way as for odd levels
+
+- enemies stop moving on even levels on rare occasions
+
+- enemy sprites entering from the bridges on odd levels are clipped by a
+ few pixels at the top, this would happen even without the overlay as the
+ first few rows of videoram are high priority solid chars most of the time
+
+- unknown 0xe002 writes, on for title and level 2 off for all else, looks
+ to be graphic related
+
+- bottom of screen is scrappy on odd levels, amongst other things the sprites
+ leave early, screen size could be clipped tighter or there could be some
+ special handling needed, possibly tied to the 0xe002 writes
+
+- the game freezes in much the same way as the stop dip switch when the coin
+ inputs are high (a short PORT_IMPULSE duration will still cause a hitch),
+ so potentially there's a coin lockout mechanism
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "sound/ay8910.h"
+#include "includes/popper.h"
+
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+//e000 e001 e002 e003
+//76543210 76543210 76543210 76543210
+//x------- unused x------- unused x------- unused x------- unused
+//-x------ dsw1:1 -x------ dsw1:2 -x------ dsw1:3 -x------ dsw1:4
+//--x----- unused --x----- unused --x----- unused --x----- unused
+//---x---- dsw2:1 ---x---- dsw2:2 ---x---- dsw2:3 ---x---- dsw2:4
+//----x--- service ----xxxx p1 udlr ----x--- unused ----xxxx p2 udlr
+//-----x-- coin a -----x-- coin b
+//------x- start 1 ------x- start 2
+//-------x p1 b1 -------x p2 b1
+//
+//e004 e005 e006 e007
+//x------- dsw1:5 x------- dsw1:6 x------- dsw1:7 x------- dsw1:8
+//-x------ unused -x------ unused -x------ unused -x------ unused
+//--x----- dsw2:5 --x----- dsw2:6 --x----- dsw2:7 --x----- dsw2:8
+//---xxxxx unused ---xxxxx unused ---xxxxx unused ---xxxxx unused
+//
+//dsw1 dsw2
+//87654321 87654321
+//xx------ extra x------- stop
+//--xx---- poppers -x------ clear (current level)
+//----xx-- coin b --x----- upright (cabinet)
+//------xx coin a ---x---- crt dir. (flip screen)
+// ----x--- pass (unlimited lives)
+// -----x-- free play
+// ------x- continue
+// -------x sound
+static READ8_HANDLER( popper_input_ports_r )
+{
+ UINT8 data = 0;
+ switch (offset)
+ {
+ // player inputs dsw1 dsw2
+ case 0: data = input_port_read(space->machine(), "IN0") | ((input_port_read(space->machine(), "DSW1") & 0x02) << 5) | ((input_port_read(space->machine(), "DSW2") & 0x01) << 4); break;
+ case 1: data = input_port_read(space->machine(), "IN1") | ((input_port_read(space->machine(), "DSW1") & 0x01) << 6) | ((input_port_read(space->machine(), "DSW2") & 0x02) << 3); break;
+ case 2: data = input_port_read(space->machine(), "IN2") | ((input_port_read(space->machine(), "DSW1") & 0x08) << 3) | ((input_port_read(space->machine(), "DSW2") & 0x04) << 2); break;
+ case 3: data = input_port_read(space->machine(), "IN3") | ((input_port_read(space->machine(), "DSW1") & 0x04) << 4) | ((input_port_read(space->machine(), "DSW2") & 0x08) << 1); break;
+ case 4: data = ((input_port_read(space->machine(), "DSW1") & 0x20) << 2) | ((input_port_read(space->machine(), "DSW2") & 0x10) << 1); break;
+ case 5: data = ((input_port_read(space->machine(), "DSW1") & 0x10) << 3) | ((input_port_read(space->machine(), "DSW2") & 0x20) << 0); break;
+ case 6: data = ((input_port_read(space->machine(), "DSW1") & 0x80) << 0) | ((input_port_read(space->machine(), "DSW2") & 0x40) >> 1); break;
+ case 7: data = ((input_port_read(space->machine(), "DSW1") & 0x40) << 1) | ((input_port_read(space->machine(), "DSW2") & 0x80) >> 2); break;
+ }
+ return data;
+}
+
+static READ8_HANDLER( popper_soundcpu_nmi_r )
+{
+ popper_state *state = space->machine().driver_data<popper_state>();
+ device_set_input_line(state->m_audiocpu, INPUT_LINE_NMI, PULSE_LINE);
+ return 0;
+}
+
+/*************************************
+ *
+ * Memory maps
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( popper_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x5fff) AM_ROM
+ AM_RANGE(0xc000, 0xc1bf) AM_RAM
+ AM_RANGE(0xc1c0, 0xc1ff) AM_RAM_WRITE(popper_ol_videoram_w) AM_BASE_MEMBER(popper_state, m_ol_videoram)
+ AM_RANGE(0xc200, 0xc61f) AM_RAM_WRITE(popper_videoram_w) AM_BASE_MEMBER(popper_state, m_videoram)
+ AM_RANGE(0xc620, 0xc9bf) AM_RAM
+ AM_RANGE(0xc9c0, 0xc9ff) AM_RAM_WRITE(popper_ol_attribram_w) AM_BASE_MEMBER(popper_state, m_ol_attribram)
+ AM_RANGE(0xca00, 0xce1f) AM_RAM_WRITE(popper_attribram_w) AM_BASE_MEMBER(popper_state, m_attribram)
+ AM_RANGE(0xce20, 0xcfff) AM_RAM
+ AM_RANGE(0xd000, 0xd7ff) AM_RAM AM_BASE_SIZE_MEMBER(popper_state, m_spriteram, m_spriteram_size)
+ AM_RANGE(0xd800, 0xdfff) AM_RAM AM_SHARE("share1")
+ AM_RANGE(0xe000, 0xe007) AM_READ(popper_input_ports_r)
+ AM_RANGE(0xe000, 0xe000) AM_WRITE(interrupt_enable_w)
+ AM_RANGE(0xe001, 0xe001) AM_WRITE(popper_flipscreen_w)
+ AM_RANGE(0xe002, 0xe002) AM_WRITE(popper_e002_w) //?? seems to be graphic related
+ AM_RANGE(0xe003, 0xe003) AM_WRITE(popper_gfx_bank_w)
+ AM_RANGE(0xe004, 0xe007) AM_WRITENOP //?? range cleared once when the SP is set
+ AM_RANGE(0xe400, 0xe400) AM_READ(popper_soundcpu_nmi_r)
+ AM_RANGE(0xf800, 0xf800) AM_READNOP //?? read once at startup
+ AM_RANGE(0xfc00, 0xfc00) AM_READNOP //?? possibly watchdog
+ AM_RANGE(0xffff, 0xffff) AM_READNOP
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( popper_sound_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x0fff) AM_ROM
+ AM_RANGE(0x8000, 0x8001) AM_DEVWRITE("ay1", ay8910_address_data_w)
+ AM_RANGE(0x8002, 0x8002) AM_READNOP //?? all read once at startup and the
+ AM_RANGE(0x8002, 0x8002) AM_WRITENOP //?? same writes as 0x8000 (mostly)
+ AM_RANGE(0x8003, 0x8003) AM_READNOP //?? result ignored, looks like part
+ AM_RANGE(0xa000, 0xa001) AM_DEVWRITE("ay2", ay8910_address_data_w)
+ AM_RANGE(0xa002, 0xa002) AM_READNOP //?? of AY8910 initialisation
+ AM_RANGE(0xa002, 0xa002) AM_WRITENOP //?? same writes as 0xa000
+ AM_RANGE(0xd800, 0xdfff) AM_RAM AM_SHARE("share1")
+ADDRESS_MAP_END
+
+/*************************************
+ *
+ * Input ports
+ *
+ *************************************/
+
+static INPUT_PORTS_START( popper )
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_START1 )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_COIN1 ) //ignored if held for 12 or more frames
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_SERVICE1 )
+
+ PORT_START("IN1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY
+
+ PORT_START("IN2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_COCKTAIL
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_START2 )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_COIN2 ) //ignored if held for 12 or more frames
+
+ PORT_START("IN3")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_COCKTAIL
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_COCKTAIL
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_COCKTAIL
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_8WAY PORT_COCKTAIL
+
+ PORT_START("DSW1") /* FAKE DSW1 */
+ PORT_DIPNAME( 0x03, 0x00, DEF_STR( Coin_A ) ) //SW1:1-2
+ PORT_DIPSETTING( 0x02, DEF_STR( 3C_1C ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x03, DEF_STR( 1C_2C ) )
+ PORT_DIPNAME( 0x0c, 0x08, DEF_STR( Coin_B ) ) //SW1:3-4
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_3C ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_4C ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( 1C_5C ) )
+ PORT_DIPSETTING( 0x0c, DEF_STR( 1C_6C ) )
+ PORT_DIPNAME( 0x30, 0x10, DEF_STR( Lives ) ) //SW1:5-6
+ PORT_DIPSETTING( 0x00, "2" )
+ PORT_DIPSETTING( 0x10, "3" )
+ PORT_DIPSETTING( 0x20, "4" )
+ PORT_DIPSETTING( 0x30, "5" )
+ PORT_DIPNAME( 0xc0, 0x00, DEF_STR( Bonus_Life ) ) //SW1:7-8
+ PORT_DIPSETTING( 0x00, "20k, then every 70k" )
+ PORT_DIPSETTING( 0x40, "30k, then every 70k" )
+ PORT_DIPSETTING( 0x80, "40k, then every 70k" )
+ PORT_DIPSETTING( 0xc0, "50k, then every 70k" )
+
+ PORT_START("DSW2") /* FAKE DSW2 */
+ PORT_DIPNAME( 0x01, 0x01, DEF_STR( Demo_Sounds ) ) //SW2:1
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x01, DEF_STR( On ) )
+ PORT_DIPNAME( 0x02, 0x00, DEF_STR( Allow_Continue ) ) //SW2:2 (stored in 0xd987, never read)
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x02, DEF_STR( On ) )
+ PORT_DIPNAME( 0x04, 0x00, DEF_STR( Free_Play ) ) //SW2:3
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( On ) )
+ PORT_DIPNAME( 0x08, 0x00, "Pass (Unlimited Lives) (Cheat)") //SW2:4
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( On ) )
+ PORT_DIPNAME( 0x10, 0x00, DEF_STR( Flip_Screen ) ) //SW2:5
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_DIPNAME( 0x20, 0x20, DEF_STR( Cabinet ) ) //SW2:6
+ PORT_DIPSETTING( 0x20, DEF_STR( Upright ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( Cocktail ) )
+ PORT_DIPNAME( 0x40, 0x00, "Clear (Current Level) (Cheat)") //SW2:7
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x40, DEF_STR( On ) )
+ PORT_DIPNAME( 0x80, 0x00, "Stop" ) //SW2:8
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x80, DEF_STR( On ) )
+INPUT_PORTS_END
+
+/*************************************
+ *
+ * Graphics definitions
+ *
+ *************************************/
+
+static const gfx_layout popper_charlayout =
+{
+ 8,8,
+ RGN_FRAC(2,2),
+ 2,
+ { 0, 4 },
+ { STEP4(8,1), STEP4(0,1) },
+ { STEP8(0,16) },
+ 16*8
+};
+
+static const gfx_layout popper_spritelayout =
+{
+ 16,16,
+ RGN_FRAC(1,2),
+ 2,
+ { 0, RGN_FRAC(1,2) },
+ { STEP8(8,1), STEP8(0,1) },
+ { STEP16(0, 16) },
+ 16*2*8
+};
+
+static GFXDECODE_START( popper )
+ GFXDECODE_ENTRY( "gfx1", 0, popper_charlayout, 0, 16 )
+ GFXDECODE_ENTRY( "gfx2", 0, popper_spritelayout, 0, 16 )
+GFXDECODE_END
+
+/*************************************
+ *
+ * Machine driver
+ *
+ *************************************/
+
+static MACHINE_START( popper )
+{
+ popper_state *state = machine.driver_data<popper_state>();
+
+ state->m_audiocpu = machine.device("audiocpu");
+
+ state->save_item(NAME(state->m_flipscreen));
+ state->save_item(NAME(state->m_e002));
+ state->save_item(NAME(state->m_gfx_bank));
+}
+
+static MACHINE_RESET( popper )
+{
+ popper_state *state = machine.driver_data<popper_state>();
+
+ state->m_flipscreen = 0;
+ state->m_e002 = 0;
+ state->m_gfx_bank = 0;
+}
+
+static MACHINE_CONFIG_START( popper, popper_state )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", Z80,18432000/6)
+ MCFG_CPU_PROGRAM_MAP(popper_map)
+ MCFG_CPU_VBLANK_INT("screen", nmi_line_pulse)
+
+ MCFG_CPU_ADD("audiocpu", Z80,18432000/12)
+ MCFG_CPU_PROGRAM_MAP(popper_sound_map)
+ MCFG_CPU_PERIODIC_INT(irq0_line_hold,4*60) //NMIs caused by the main CPU
+
+ MCFG_QUANTUM_TIME(attotime::from_hz(1800))
+
+ MCFG_MACHINE_START(popper)
+ MCFG_MACHINE_RESET(popper)
+
+ /* video hardware */
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(0))
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MCFG_SCREEN_SIZE(33*8, 32*8)
+ MCFG_SCREEN_VISIBLE_AREA(0*8, 33*8-1, 2*8, 30*8-1)
+ MCFG_SCREEN_UPDATE(popper)
+
+ MCFG_GFXDECODE(popper)
+ MCFG_PALETTE_LENGTH(64)
+
+ MCFG_PALETTE_INIT(popper)
+ MCFG_VIDEO_START(popper)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("ay1", AY8910, 18432000/12)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("ay2", AY8910, 18432000/12)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
+
+
+/*************************************
+ *
+ * ROM definition
+ *
+ *************************************/
+
+ROM_START( popper )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "p1", 0x0000, 0x2000, CRC(56881b70) SHA1(d3ade7a54a6cb8a0babf0d667a6b27f492a739dc) )
+ ROM_LOAD( "p2", 0x2000, 0x2000, CRC(a054d9d2) SHA1(fcd86e7247b40cf07ea595a64c104b99b0e93ced) )
+ ROM_LOAD( "p3", 0x4000, 0x2000, CRC(6201928a) SHA1(53b571b9f2c0568f10cd974641863c2e00777b46) )
+
+ ROM_REGION( 0x10000, "audiocpu", 0 )
+ ROM_LOAD( "p0", 0x0000, 0x1000, CRC(ef5f7c5b) SHA1(c63a3d9ef2868ad7eaacddec810d62d2e124dc15) )
+
+ ROM_REGION( 0x2000, "gfx1", 0 )
+ ROM_LOAD( "p4", 0x0000, 0x2000, CRC(86203349) SHA1(cce2dd3fa786c2fb3ca80e7b93adf94db3b46b01) )
+
+ ROM_REGION( 0x4000, "gfx2", 0 )
+ ROM_LOAD( "p5", 0x0000, 0x2000, CRC(a21ac194) SHA1(2c0e3df8981a12d383b1c4619a0b95a7c2d176a7) )
+ ROM_LOAD( "p6", 0x2000, 0x2000, CRC(d99fa790) SHA1(201271ee4fb812236a38cb5f9070ac29e8186097) )
+
+ ROM_REGION( 0x0040, "proms", 0 )
+ ROM_LOAD( "p.m3", 0x0000, 0x0020, CRC(713217aa) SHA1(6083c3432bf94c9e983fcc79171529f519c86105) )
+ ROM_LOAD( "p.m4", 0x0020, 0x0020, CRC(384de5c1) SHA1(892c89a01c11671c5708113b4e4c27b84be37ea6) )
+ROM_END
+
+
+/*************************************
+ *
+ * Game driver
+ *
+ *************************************/
+
+GAME( 1983, popper, 0, popper, popper, 0, ROT90, "Omori Electric Co., Ltd.", "Popper", GAME_IMPERFECT_COLORS | GAME_SUPPORTS_SAVE )