// license:BSD-3-Clause
// copyright-holders:Angelo Salese, David Haywood
/*******************************************************************************************
Popo Bear (c) 2000 BMC
driver by Angelo Salese, David Haywood
TODO:
- auto-animation speed is erratic (way too fast);
- BGM seems quite off, YM2413 core bug?
- IRQ generation;
- all possible related to some timers?
- I/Os;
- Port 0x620000 is quite a mystery, some silly protection?
============================================================================================
Popo Bear - BMC-A00211
(c) 2000 - Bao Ma Technology Co., LTD
|-----------------------------------------|
| DIP2 DIP4 UM3567(YM2413) |J
| DIP1 DIP3 |A
| TA-A-901 |M
| EN-A-701 EN-A-801 U6295(OKI) |M
| EN-A-501 EN-A-601 |A
| EN-A-301 EN-A-401 |
| |C
| AIA90610 |O
| BMC-68pin AIA90423 |N
| plcc (68k) BMC-160pin |N
| |E
| OSC |C
| 42.000 |T
|-----------------------------------------|
1 - BMC AIA90423 - 160-Pin ASIC, FGPA, Video?
1 - BMC AIA90610 - 68 Pin CPU (Likely 16 MHz, 68-lead plastic LCC 68000)
1 - UM3567 (YM2413) Sound
1 - U6295 (OKI6295) Sound
1 - 42.000MHz XTAL
4 - 8 Position DIP switches
JAMMA CONNECTOR
Component Side A B Solder Side
GND 1 1 GND
GND 2 2 GND
+5v 3 3 +5v
+5v 4 4 +5v
5 5
+12v 6 6 +12v
7 7
Coin Meter 8 8
9 9
Speaker 10 10 GND
11 11
Red 12 12 Green
Blue 13 13 Syn
GND 14 14
Test 15 15
Coin1 16 16 Coin2
1P Start 17 17 2P Start
1P Up 18 18 2P Up
1P Down 19 19 2P Down
1P Left 20 20 2P Left
1P Right 21 21 2P Right
1P A 22 22 2P A
1P B 23 23 2P B
1P C 24 24 2P C
25 25
26 26
GND 27 27 GND
GND 28 28 GND
*******************************************************************************************/
#include "emu.h"
#include "cpu/m68000/m68000.h"
#include "machine/timer.h"
#include "sound/okim6295.h"
#include "sound/ym2413.h"
#include "screen.h"
#include "speaker.h"
class popobear_state : public driver_device
{
public:
popobear_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_spr(*this, "spr"),
m_vram(*this, "vram"),
m_vregs(*this, "vregs")
{
m_tilemap_base[0] = 0xf0000;
m_tilemap_base[1] = 0xf4000;
m_tilemap_base[2] = 0xf8000;
m_tilemap_base[3] = 0xfc000;
}
required_device<cpu_device> m_maincpu;
required_device<gfxdecode_device> m_gfxdecode;
required_device<palette_device> m_palette;
required_shared_ptr<uint16_t> m_spr;
required_shared_ptr<uint16_t> m_vram;
required_shared_ptr<uint16_t> m_vregs;
std::vector<uint16_t> m_vram_rearranged;
int m_tilemap_base[4];
tilemap_t *m_bg_tilemap[4];
TILE_GET_INFO_MEMBER(get_bg0_tile_info);
TILE_GET_INFO_MEMBER(get_bg1_tile_info);
TILE_GET_INFO_MEMBER(get_bg2_tile_info);
TILE_GET_INFO_MEMBER(get_bg3_tile_info);
DECLARE_READ8_MEMBER(_620000_r);
DECLARE_WRITE8_MEMBER(irq_ack_w);
DECLARE_WRITE16_MEMBER(vram_w);
virtual void video_start() override;
uint32_t screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
void draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect);
TIMER_DEVICE_CALLBACK_MEMBER(irq);
void postload();
void popobear(machine_config &config);
void popobear_mem(address_map &map);
};
WRITE16_MEMBER(popobear_state::vram_w)
{
COMBINE_DATA(&m_vram[offset]);
// the graphic data for the tiles is in a strange order, rearrange it so that we can use it as tiles..
int swapped_offset = bitswap<32>(offset, /* unused bits */ 31,30,29,28,27,26,25,24,23,22,21,20,19, /* end unused bits */
18,17,16,15,14,13,12,
8,7,6,5,4,3,2,
11,10,9, /* y tile address bits */
1,0 /* x tile address bits */);
COMBINE_DATA(&m_vram_rearranged[swapped_offset]);
m_gfxdecode->gfx(0)->mark_dirty((swapped_offset)/32);
// unfortunately tilemaps and tilegfx share the same ram so we're always dirty if we write to RAM
m_bg_tilemap[0]->mark_all_dirty();
m_bg_tilemap[1]->mark_all_dirty();
m_bg_tilemap[2]->mark_all_dirty();
m_bg_tilemap[3]->mark_all_dirty();
}
static const gfx_layout char_layout =
{
8,8,
RGN_FRAC(1,1),
8,
{ 0,1,2,3,4,5,6,7 },
{ STEP8(0, 8) },
{ STEP8(0, 64) },
8*64
};
GFXDECODE_START(gfx_popobear)
GFXDECODE_RAM( "vram", 0, char_layout, 0, 1 )
GFXDECODE_END
TILE_GET_INFO_MEMBER(popobear_state::get_bg0_tile_info)
{
int base = m_tilemap_base[0];
int tileno = m_vram[base/2 + tile_index];
int flipyx = (tileno>>14);
SET_TILE_INFO_MEMBER(0, tileno&0x3fff, 0, TILE_FLIPYX(flipyx));
}
TILE_GET_INFO_MEMBER(popobear_state::get_bg1_tile_info)
{
int base = m_tilemap_base[1];
int tileno = m_vram[base/2 + tile_index];
int flipyx = (tileno>>14);
SET_TILE_INFO_MEMBER(0, tileno&0x3fff, 0, TILE_FLIPYX(flipyx));
}
TILE_GET_INFO_MEMBER(popobear_state::get_bg2_tile_info)
{
int base = m_tilemap_base[2];
int tileno = m_vram[base/2 + tile_index];
int flipyx = (tileno>>14);
SET_TILE_INFO_MEMBER(0, tileno&0x3fff, 0, TILE_FLIPYX(flipyx));
}
TILE_GET_INFO_MEMBER(popobear_state::get_bg3_tile_info)
{
int base = m_tilemap_base[3];
int tileno = m_vram[base/2 + tile_index];
int flipyx = (tileno>>14);
SET_TILE_INFO_MEMBER(0, tileno&0x3fff, 0, TILE_FLIPYX(flipyx));
}
void popobear_state::postload()
{
m_gfxdecode->gfx(0)->mark_all_dirty();
}
void popobear_state::video_start()
{
m_vram_rearranged.resize(0x100000 / 2);
m_gfxdecode->gfx(0)->set_source(reinterpret_cast<uint8_t *>(&m_vram_rearranged[0]));
m_bg_tilemap[0] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(popobear_state::get_bg0_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
m_bg_tilemap[1] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(popobear_state::get_bg1_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
m_bg_tilemap[2] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(popobear_state::get_bg2_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
m_bg_tilemap[3] = &machine().tilemap().create(*m_gfxdecode, tilemap_get_info_delegate(FUNC(popobear_state::get_bg3_tile_info),this), TILEMAP_SCAN_ROWS, 8, 8, 128, 64);
m_bg_tilemap[0]->set_transparent_pen(0);
m_bg_tilemap[1]->set_transparent_pen(0);
m_bg_tilemap[2]->set_transparent_pen(0);
m_bg_tilemap[3]->set_transparent_pen(0);
save_item(NAME(m_vram_rearranged));
machine().save().register_postload(save_prepost_delegate(FUNC(popobear_state::postload), this));
}
void popobear_state::draw_sprites(bitmap_ind16 &bitmap,const rectangle &cliprect)
{
uint8_t* vram = reinterpret_cast<uint8_t *>(m_spr.target());
int i;
/*
???? ---- ---- ---- unused?
---- xxxx ---- ---- priority (against other sprites! used to keep the line of characters following you in order)
---- ---- x--- ---- Y direction
---- ---- -x-- ---- X direction
---- ---- --xx ---- size (height & width)
---- ---- ---- xx-- color bank
---- ---- ---- --x- NOT set on the enemy character / characters in your line
---- ---- ---- ---x set on opposite to above?
*/
for (int drawpri = 0xf;drawpri>=0x0;drawpri--)
{
/* 0x106 = 8 x 8 */
/* 0x*29 = 32 x 32 */
for(i = 0x800-8;i >= 0; i-=8)
{
uint16_t *sprdata = &m_spr[(0x7f800 + i) / 2];
int param = sprdata[0];
int pri = (param & 0x0f00)>>8;
// we do this because it's sprite<->sprite priority,
if (pri!=drawpri)
continue;
int y = sprdata[1];
int x = sprdata[2];
int spr_num = sprdata[3];
int width = 8 << ((param & 0x30)>>4);
int height = width; // sprites are always square?
int color_bank = ((param & 0xc)>>2);
int x_dir = param & 0x40;
int y_dir = param & 0x80;
if (x&0x8000) x-= 0x10000;
if (y&0x8000) y-= 0x10000;
if (param&0xf000) color_bank = (machine().rand() & 0x3);
int add_it = 0;
// this isn't understood, not enough evidence.
switch (param & 3)
{
case 0x0: // not used?
color_bank = (machine().rand() & 0x3);
add_it = color_bank*0x40;
break;
case 0x1: // butterflies in intro, enemy characters, line of characters, stage start text
//color_bank = (machine().rand() & 0x3);
add_it = color_bank*0x40;
break;
case 0x2: // characters in intro, main player, powerups, timer, large dancing chars between levels (0x3f?)
//color_bank = (machine().rand() & 0x3);
add_it = color_bank*0x40;
break;
case 0x3: // letters on GAME OVER need this..
add_it = color_bank*0x40;
add_it += 0x20;
break;
}
if(param == 0)
continue;
spr_num <<= 3;
for(int yi=0;yi<height;yi++)
{
int y_draw = (y_dir) ? y+((height-1) - yi) : y+yi;
for(int xi=0;xi<width;xi++)
{
uint8_t pix = vram[BYTE_XOR_BE(spr_num)];
int x_draw = (x_dir) ? x+((width-1) - xi) : x+xi;
if(cliprect.contains(x_draw, y_draw))
{
// this is a bit strange, pix data is basically 8-bit
// but we have to treat 0x00, 0x40, 0x80, 0xc0 */
// see scores when you colect an item, must be at least steps of 0x40 or one of the female panda gfx between levels breaks.. might depend on lower bits?
// granularity also means colour bank is applied *0x40
// and we have 2 more possible colour bank bits
// colours on game over screen are still wrong without the weird param kludge above
if (pix&0x3f)
{
bitmap.pix16(y_draw, x_draw) = m_palette->pen(((pix+(add_it))&0xff)+0x100);
}
}
spr_num++;
}
}
}
}
}
uint32_t popobear_state::screen_update(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect)
{
bitmap.fill(0, cliprect);
int line;
rectangle clip;
int scrollbase;
int scrollbase2;
const rectangle &visarea = screen.visible_area();
clip = visarea;
//popmessage("%04x",m_vregs[0/2]);
uint16_t* vreg = m_vregs;
// popmessage("%04x %04x %04x %04x %04x %04x %04x - %04x - %04x %04x",vreg[0x00],vreg[0x01],vreg[0x02],vreg[0x03],vreg[0x04],vreg[0x05],vreg[0x06], vreg[0x0b],vreg[0x0e],vreg[0x0f]);
// vreg[0x00] also looks like it could be some enable registers
// 0x82ff - BMC logo
// 0x8aff - some attract scenes (no sprites)
// 0x8bff - game attract scense etc. (sprites)
// vreg[0x01] is always
// 0xfefb
// these are more than just enable, they get written with 0x0d and 0x1f (and 0x00 when a layer is off)
// seems to be related to the linescroll mode at least? maybe sizes?
int enable0 = (m_vregs[0x0c] & 0xff00)>>8;
int enable1 = (m_vregs[0x0c] & 0x00ff)>>0;
int enable2 = (m_vregs[0x0d] & 0xff00)>>8;
int enable3 = (m_vregs[0x0d] & 0x00ff)>>0;
if ((enable0 != 0x00) && (enable0 != 0x0d) && (enable0 != 0x1f)) printf("unknown enable0 value %02x\n", enable0);
if ((enable1 != 0x00) && (enable1 != 0x0d) && (enable1 != 0x1f)) printf("unknown enable1 value %02x\n", enable1);
if ((enable2 != 0x00) && (enable2 != 0x0d)) printf("unknown enable2 value %02x\n", enable2);
if ((enable3 != 0x00) && (enable3 != 0x0d)) printf("unknown enable3 value %02x\n", enable3);
// the lower 2 tilemaps use regular scrolling
m_bg_tilemap[2]->set_scrollx(0, vreg[0x07]);
m_bg_tilemap[2]->set_scrolly(0, vreg[0x08]);
m_bg_tilemap[3]->set_scrollx(0, vreg[0x09]);
m_bg_tilemap[3]->set_scrolly(0, vreg[0x0a]);
if (enable3) m_bg_tilemap[3]->draw(screen, bitmap, cliprect, 0, 0);
if (enable2) m_bg_tilemap[2]->draw(screen, bitmap, cliprect, 0, 0);
// the upper 2 tilemaps have a lineselect / linescroll logic
if (enable1 == 0x1f)
{
scrollbase = 0xdf600;
scrollbase2 = 0xdf800;
for (line = 0; line < 240;line++)
{
uint16_t val = m_vram[scrollbase/2 + line];
uint16_t upper = (m_vram[scrollbase2/2 + line]&0xff00)>>8;
clip.min_y = clip.max_y = line;
m_bg_tilemap[1]->set_scrollx(0,(val&0x00ff) | (upper << 8));
m_bg_tilemap[1]->set_scrolly(0,((val&0xff00)>>8)-line);
m_bg_tilemap[1]->draw(screen, bitmap, clip, 0, 0);
}
}
else if (enable1 != 0x00)
{
m_bg_tilemap[1]->set_scrollx(0, 0);
m_bg_tilemap[1]->set_scrolly(0, 0);
m_bg_tilemap[1]->draw(screen, bitmap, cliprect, 0, 0);
}
if (enable0 == 0x1f)
{
scrollbase = 0xdf400;
scrollbase2 = 0xdf800;
for (line = 0; line < 240;line++)
{
uint16_t val = m_vram[scrollbase/2 + line];
uint16_t upper = (m_vram[scrollbase2/2 + line]&0x00ff)>>0;
clip.min_y = clip.max_y = line;
m_bg_tilemap[0]->set_scrollx(0,(val&0x00ff) | (upper << 8));
m_bg_tilemap[0]->set_scrolly(0,((val&0xff00)>>8)-line);
m_bg_tilemap[0]->draw(screen, bitmap, clip, 0, 0);
}
}
else if (enable0 != 0x00)
{
m_bg_tilemap[0]->set_scrollx(0, 0);
m_bg_tilemap[0]->set_scrolly(0, 0);
m_bg_tilemap[0]->draw(screen, bitmap, cliprect, 0, 0);
}
draw_sprites(bitmap,cliprect);
return 0;
}
/* ??? */
READ8_MEMBER(popobear_state::_620000_r)
{
return 9;
}
WRITE8_MEMBER(popobear_state::irq_ack_w)
{
int i;
for(i=0;i<8;i++)
{
if(data & 1 << i)
m_maincpu->set_input_line(i, CLEAR_LINE);
}
}
void popobear_state::popobear_mem(address_map &map)
{
map.unmap_value_high();
map(0x000000, 0x03ffff).rom();
map(0x210000, 0x21ffff).ram();
map(0x280000, 0x2fffff).ram().share("spr"); // unknown boundaries, 0x2ff800 contains a sprite list, lower area = sprite gfx
map(0x300000, 0x3fffff).ram().w(this, FUNC(popobear_state::vram_w)).share("vram"); // tile definitions + tilemaps
/* Most if not all of these are vregs */
map(0x480000, 0x48001f).ram().share("vregs");
map(0x480020, 0x480023).ram();
map(0x480028, 0x48002d).ram();
// AM_RANGE(0x480020, 0x480021) AM_NOP //AM_READ(480020_r) AM_WRITE(480020_w)
// AM_RANGE(0x480028, 0x480029) AM_NOP //AM_WRITE(480028_w)
// AM_RANGE(0x48002c, 0x48002d) AM_NOP //AM_WRITE(48002c_w)
map(0x480031, 0x480031).w(this, FUNC(popobear_state::irq_ack_w));
map(0x480034, 0x480035).ram(); // coin counter or coin lockout
map(0x48003a, 0x48003b).ram(); //AM_READ(48003a_r) AM_WRITE(48003a_w)
map(0x480400, 0x4807ff).ram().w(m_palette, FUNC(palette_device::write16)).share("palette");
map(0x500000, 0x500001).portr("IN0");
map(0x520000, 0x520001).portr("IN1");
map(0x540001, 0x540001).rw("oki", FUNC(okim6295_device::read), FUNC(okim6295_device::write));
map(0x550000, 0x550003).w("ymsnd", FUNC(ym2413_device::write)).umask16(0x00ff);
map(0x600000, 0x600001).nopw();
map(0x620000, 0x620000).r(this, FUNC(popobear_state::_620000_r));
map(0x620000, 0x620001).nopw();
map(0x800000, 0xbfffff).rom();
}
static INPUT_PORTS_START( popobear )
PORT_START("DSW1")
PORT_DIPNAME( 0x01, 0x01, DEF_STR( Demo_Sounds ) )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x01, DEF_STR( On ) )
PORT_DIPNAME( 0x0e, 0x00, "Coin_A" )
PORT_DIPSETTING( 0x0c, DEF_STR( 3C_1C ) )
PORT_DIPSETTING( 0x0a, DEF_STR( 2C_1C ) )
PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
PORT_DIPSETTING( 0x02, DEF_STR( 1C_2C ) )
PORT_DIPSETTING( 0x04, DEF_STR( 1C_3C ) )
PORT_DIPSETTING( 0x06, DEF_STR( 1C_4C ) )
PORT_DIPSETTING( 0x08, DEF_STR( 1C_5C ) )
PORT_DIPSETTING( 0x0e, "Freeplay" )
PORT_DIPNAME( 0x30, 0x00, DEF_STR( Lives ) )
PORT_DIPSETTING( 0x10, "2" )
PORT_DIPSETTING( 0x00, "3" )
PORT_DIPSETTING( 0x20, "4" )
PORT_DIPSETTING( 0x30, "5" )
PORT_DIPNAME( 0xc0, 0x00, DEF_STR( Difficulty ) )
PORT_DIPSETTING( 0x80, DEF_STR( Very_Easy ) )
PORT_DIPSETTING( 0x40, DEF_STR( Easy ) )
PORT_DIPSETTING( 0x00, DEF_STR( Normal ) )
PORT_DIPSETTING( 0xc0, DEF_STR( Hard ) )
PORT_START("DSW2")
PORT_DIPNAME( 0x01, 0x00, "Arrow" )
PORT_DIPSETTING( 0x01, DEF_STR( No ) )
PORT_DIPSETTING( 0x00, DEF_STR( Yes ) )
PORT_DIPNAME( 0x02, 0x00, "DSW2:2" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x02, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x00, "DSW2:3" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x04, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x00, "DSW2:4" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x08, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x00, "DSW2:5" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x10, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x00, "DSW2:6" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x20, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x00, "DSW2:7" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x40, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x00, "DSW2:8" )
PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
PORT_DIPSETTING( 0x80, DEF_STR( On ) )
PORT_START("IN0")
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x0200, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x0400, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x0800, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x1000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1)
PORT_BIT( 0x2000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1)
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1)
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("IN1")
PORT_DIPNAME( 0x01, 0x01, "DSWA" )
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x02, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x02, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x04, 0x04, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x04, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x08, 0x08, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x08, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x20, 0x20, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x20, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x40, 0x40, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x40, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x80, 0x80, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_BIT( 0x0100, IP_ACTIVE_LOW, IPT_COIN1 ) PORT_IMPULSE(2)
PORT_DIPNAME( 0x0200, 0x0200, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x0200, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x0400, 0x0400, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x0400, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x0800, 0x0800, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x0800, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x1000, 0x1000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x1000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_DIPNAME( 0x2000, 0x2000, DEF_STR( Unknown ) )
PORT_DIPSETTING( 0x2000, DEF_STR( Off ) )
PORT_DIPSETTING( 0x0000, DEF_STR( On ) )
PORT_BIT( 0x4000, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_START1 )
INPUT_PORTS_END
TIMER_DEVICE_CALLBACK_MEMBER(popobear_state::irq)
{
int scanline = param;
/* Order is trusted (5 as vblank-out makes the title screen logo spinning to behave wrongly) */
if(scanline == 240)
m_maincpu->set_input_line(3, ASSERT_LINE);
if(scanline == 0)
m_maincpu->set_input_line(5, ASSERT_LINE);
/* TODO: actually a timer irq, tied with YM2413 sound chip (controls BGM tempo) */
/* the YM2413 doesn't have interrupts? */
if(scanline == 64 || scanline == 192)
m_maincpu->set_input_line(2, ASSERT_LINE);
}
MACHINE_CONFIG_START(popobear_state::popobear)
MCFG_DEVICE_ADD("maincpu", M68000, XTAL(42'000'000)/4) // XTAL CORRECT, DIVISOR GUESSED
MCFG_DEVICE_PROGRAM_MAP(popobear_mem)
// levels 2,3,5 look interesting
//MCFG_DEVICE_VBLANK_INT_DRIVER("screen", popobear_state, irq5_line_assert)
//MCFG_DEVICE_PERIODIC_INT_DRIVER(popobear_state, irq2_line_assert, 120)
MCFG_TIMER_DRIVER_ADD_SCANLINE("scantimer", popobear_state, irq, "screen", 0, 1)
MCFG_SCREEN_ADD("screen", RASTER)
MCFG_SCREEN_REFRESH_RATE(60)
MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500)) /* not accurate */
MCFG_SCREEN_UPDATE_DRIVER(popobear_state, screen_update)
MCFG_SCREEN_PALETTE("palette")
MCFG_SCREEN_SIZE(128*8, 32*8)
MCFG_SCREEN_VISIBLE_AREA(0, 479, 0, 239)
MCFG_PALETTE_ADD("palette", 256*2)
MCFG_PALETTE_FORMAT(xBBBBBGGGGGRRRRR)
SPEAKER(config, "mono").front_center();
MCFG_DEVICE_ADD("gfxdecode", GFXDECODE, "palette", gfx_popobear)
MCFG_DEVICE_ADD("ymsnd", YM2413, XTAL(42'000'000)/16) // XTAL CORRECT, DIVISOR GUESSED
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MCFG_DEVICE_ADD("oki", OKIM6295, XTAL(42'000'000)/32, okim6295_device::PIN7_LOW) // XTAL CORRECT, DIVISOR GUESSED
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
MACHINE_CONFIG_END
ROM_START( popobear )
ROM_REGION( 0x1000000, "maincpu", 0 ) /* 68000 Code + gfx data */
ROM_LOAD16_BYTE( "popobear_en-a-301_1.6.u3", 0x000001, 0x020000, CRC(b934adf6) SHA1(93431c7a19af812b549aad35cc1176a81805ffab) )
ROM_LOAD16_BYTE( "popobear_en-a-401_1.6.u4", 0x000000, 0x020000, CRC(0568af9c) SHA1(920531dbc4bbde2d1db062bd5c48b97dd50b7185) )
ROM_LOAD16_BYTE( "popobear_en-a-501.u5", 0x800001, 0x100000, CRC(185901a9) SHA1(7ff82b5751645df53435eaa66edce589684cc5c7) )
ROM_LOAD16_BYTE( "popobear_en-a-601.u6", 0x800000, 0x100000, CRC(84fa9f3f) SHA1(34dd7873f88b0dae5fb81fe84e82d2b6b49f7332) )
ROM_LOAD16_BYTE( "popobear_en-a-701.u7", 0xa00001, 0x100000, CRC(45eba6d0) SHA1(0278602ed57ac45040619d590e6cc85e2cfeed31) )
ROM_LOAD16_BYTE( "popobear_en-a-801.u8", 0xa00000, 0x100000, CRC(2760f2e6) SHA1(58af59f486c9df930f7c124f89154f8f389a5bd7) )
ROM_REGION( 0x040000, "oki", 0 ) /* Samples */
ROM_LOAD( "popobear_ta-a-901.u9", 0x00000, 0x40000, CRC(f1e94926) SHA1(f4d6f5b5811d90d0069f6efbb44d725ff0d07e1c) )
ROM_END
GAME( 2000, popobear, 0, popobear, popobear, popobear_state, empty_init, ROT0, "BMC", "PoPo Bear", MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )