diff options
Diffstat (limited to 'trunk/src/mame/drivers/popper.c')
-rw-r--r-- | trunk/src/mame/drivers/popper.c | 403 |
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 ) |