New working game - Gradius (Bubble Memory) - [ArcadeHacker, Bryan McPhail]

The bubble memory interface MCU is currently simulated, it will be decapped at a future date.
This commit is contained in:
bmcphail 2019-04-25 10:32:10 -04:00
parent d88ae76121
commit 716e5fe21a
3 changed files with 223 additions and 26 deletions

View File

@ -20,7 +20,7 @@
Hyper Crash (Version C) GX790
Kitten Kaboodle GX712
Nyan Nyan Panic (Japan) GX712
Bubble System
driver by Bryan McPhail
@ -36,6 +36,8 @@ modified by hap
06/09/2012
Special thx 2 Neusneus, Audrey Tautou, my water bottle, chair, sleepiness
Bubble System added 2019 ArcadeHacker/Bryan McPhail
Notes:
- blkpnthr:
There are sprite priority problems in upper part of the screen ,
@ -78,6 +80,12 @@ WRITE_LINE_MEMBER(nemesis_state::blkpnthr_vblank_irq)
m_maincpu->set_input_line(2, HOLD_LINE);
}
WRITE_LINE_MEMBER(nemesis_state::bubsys_vblank_irq)
{
if (state && m_irq_on)
m_maincpu->set_input_line(4, HOLD_LINE);
}
TIMER_DEVICE_CALLBACK_MEMBER(nemesis_state::konamigt_interrupt)
{
int scanline = param;
@ -140,6 +148,52 @@ WRITE_LINE_MEMBER(nemesis_state::sound_irq_w)
m_audiocpu->set_input_line_and_vector(0, HOLD_LINE, 0xff); // Z80
}
WRITE_LINE_MEMBER(nemesis_state::sound_nmi_w)
{
if (state) // On Bubble System this goes to an LS02 NOR before the Z80, so there may be a disable somewhere
m_audiocpu->pulse_input_line(INPUT_LINE_NMI, attotime::zero);
}
WRITE16_MEMBER(nemesis_state::bubsys_mcu_w)
{
COMBINE_DATA(&m_bubsys_control_ram[offset]);
//logerror("bubsys_mcu_w (%08x) %d (%02x %02x %02x %02x)\n", m_maincpu->pc(), state, m_bubsys_control_ram[0], m_bubsys_control_ram[1], m_bubsys_control_ram[2], m_bubsys_control_ram[3]);
if (offset==1)
{
// NOP?
if (m_bubsys_control_ram[1]==0)
{
}
// Read
else if (m_bubsys_control_ram[1]==1)
{
// The MCU copies the requested page of bubble memory to 0xf00 of shared RAM
int page = m_bubsys_control_ram[0] & 0x7ff;
//int unknownBit = m_bubsys_control_ram[0] & 0x800;
logerror("\tCopy page %02x to shared ram\n", page);
const uint8_t *src = memregion("bubblememory")->base();
memcpy(m_bubsys_shared_ram + 0xf00/2, src + page * 0x90, 0x80);
// The last 2 bytes of the block are loaded into the control register
m_bubsys_control_ram[0] = src[page * 0x90 + 0x80] | (src[page * 0x90 + 0x81]<<8);
m_maincpu->set_input_line(5, HOLD_LINE);
}
// Write?
else if (m_bubsys_control_ram[1]==2)
{
logerror("Request to write to bubble memory? %04x\n", m_bubsys_control_ram[0]);
}
}
else
{
//logerror("bubsys_mcu_trigger_w (%08x) %d (%02x %02x %02x %02x)\n", m_maincpu->pc(), state, m_bubsys_control_ram[0], m_bubsys_control_ram[1], m_bubsys_control_ram[2], m_bubsys_control_ram[3]);
m_maincpu->set_input_line(5, CLEAR_LINE); // Not confirmed the clear happens here
}
}
READ16_MEMBER(nemesis_state::gx400_sharedram_word_r)
{
@ -311,6 +365,38 @@ void nemesis_state::gx400_map(address_map &map)
map(0x080000, 0x0bffff).rom();
}
void nemesis_state::bubsys_map(address_map &map)
{
map(0x000000, 0x000fff).ram().share("bubsys_shared"); /* Shared with MCU */
map(0x010000, 0x01ffff).ram(); /* PROGRAM RAM */
map(0x020000, 0x027fff).rw(FUNC(nemesis_state::gx400_sharedram_word_r), FUNC(nemesis_state::gx400_sharedram_word_w));
map(0x030000, 0x03ffff).ram().w(FUNC(nemesis_state::nemesis_charram_word_w)).share("charram");
map(0x040000, 0x040007).ram().w(FUNC(nemesis_state::bubsys_mcu_w)).share("bubsys_control"); // Shared with MCU
map(0x050000, 0x051fff).ram();
map(0x050000, 0x0503ff).share("xscroll1");
map(0x050400, 0x0507ff).share("xscroll2");
map(0x050f00, 0x050f7f).share("yscroll2");
map(0x050f80, 0x050fff).share("yscroll1");
map(0x052000, 0x052fff).ram().w(FUNC(nemesis_state::nemesis_videoram1_word_w)).share("videoram1"); /* VRAM */
map(0x053000, 0x053fff).ram().w(FUNC(nemesis_state::nemesis_videoram2_word_w)).share("videoram2");
map(0x054000, 0x054fff).ram().w(FUNC(nemesis_state::nemesis_colorram1_word_w)).share("colorram1");
map(0x055000, 0x055fff).ram().w(FUNC(nemesis_state::nemesis_colorram2_word_w)).share("colorram2");
map(0x056000, 0x056fff).ram().share("spriteram");
map(0x05a000, 0x05afff).ram().w(FUNC(nemesis_state::nemesis_palette_word_w)).share("paletteram");
map(0x05c001, 0x05c001).w("soundlatch", FUNC(generic_latch_8_device::write));
map(0x05c402, 0x05c403).portr("DSW0");
map(0x05c404, 0x05c405).portr("DSW1");
map(0x05c406, 0x05c407).portr("TEST");
map(0x05c800, 0x05c801).w("watchdog", FUNC(watchdog_timer_device::reset16_w)); /* probably */
map(0x05cc00, 0x05cc01).portr("IN0");
map(0x05cc02, 0x05cc03).portr("IN1");
map(0x05cc04, 0x05cc05).portr("IN2");
map(0x05e000, 0x05e00f).w("outlatch", FUNC(ls259_device::write_d0)).umask16(0xff00);
map(0x05e000, 0x05e00f).w("intlatch", FUNC(ls259_device::write_d0)).umask16(0x00ff);
map(0x070000, 0x073fff).ram(); /* WORK RAM */
map(0x078000, 0x07ffff).rom(); /* Empty diagnostic ROM slot */
}
void nemesis_state::konamigt_map(address_map &map)
{
map(0x000000, 0x03ffff).rom();
@ -1314,6 +1400,75 @@ static INPUT_PORTS_START( hcrash )
PORT_BIT( 0xff, 0x80, IPT_PADDLE ) PORT_SENSITIVITY(50) PORT_KEYDELTA(5) PORT_CONDITION("DSW1", 0x03, EQUALS, 0x02)
INPUT_PORTS_END
static INPUT_PORTS_START( bubsys )
PORT_START("IN0")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SERVICE1 )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START1 )
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_START2 )
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("IN1")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) // power-up
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) // shoot
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) // missile
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("IN2")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_START("DSW0")
KONAMI_COINAGE_LOC(DEF_STR( Free_Play ), DEF_STR( None ), SW1)
/* "None" = coin slot B disabled */
PORT_START("DSW1")
PORT_DIPNAME( 0x03, 0x03, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1,2")
PORT_DIPSETTING( 0x03, "3" )
PORT_DIPSETTING( 0x02, "4" )
PORT_DIPSETTING( 0x01, "5" )
PORT_DIPSETTING( 0x00, "7" )
PORT_DIPNAME( 0x04, 0x00, DEF_STR( Cabinet ) ) PORT_DIPLOCATION("SW2:3")
PORT_DIPSETTING( 0x00, DEF_STR( Upright ) )
PORT_DIPSETTING( 0x04, DEF_STR( Cocktail ) )
PORT_DIPNAME( 0x18, 0x18, DEF_STR( Bonus_Life ) ) PORT_DIPLOCATION("SW2:4,5")
PORT_DIPSETTING( 0x18, "50k and every 100k" )
PORT_DIPSETTING( 0x10, "30k" )
PORT_DIPSETTING( 0x08, "50k" )
PORT_DIPSETTING( 0x00, "100k" )
PORT_DIPNAME( 0x60, 0x40, DEF_STR( Difficulty ) ) PORT_DIPLOCATION("SW2:6,7")
PORT_DIPSETTING( 0x60, DEF_STR( Easy ) )
PORT_DIPSETTING( 0x40, DEF_STR( Normal ) )
PORT_DIPSETTING( 0x20, DEF_STR( Hard ) )
PORT_DIPSETTING( 0x00, DEF_STR( Hardest ) )
PORT_DIPNAME( 0x80, 0x00, DEF_STR( Demo_Sounds ) ) PORT_DIPLOCATION("SW2:8")
PORT_DIPSETTING( 0x80, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_START("TEST")
PORT_DIPNAME( 0x01, 0x01, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW3:1")
PORT_DIPSETTING( 0x01, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPNAME( 0x02, 0x02, "Upright Controls" ) PORT_DIPLOCATION("SW3:2")
PORT_DIPSETTING( 0x02, DEF_STR( Single ) )
PORT_DIPSETTING( 0x00, DEF_STR( Dual ) )
PORT_SERVICE_DIPLOC( 0x04, IP_ACTIVE_LOW, "SW3:3" )
PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_END
/******************************************************************************/
static const gfx_layout charlayout =
@ -1440,7 +1595,6 @@ void nemesis_state::machine_start()
save_item(NAME(m_frame_counter));
save_item(NAME(m_gx400_irq1_cnt));
save_item(NAME(m_selected_ip));
save_item(NAME(m_tilemap_flip));
save_item(NAME(m_flipscreen));
save_item(NAME(m_irq_port_last));
@ -2431,18 +2585,6 @@ a black background and numbers that count down from 99 to 0, and below that text
'PRESENTED BY KONAMI". A tune also plays while the numbers count down.
When the counter reaches 0 the game boots.
I suspect that the 'GETTING READY' stuff is actually warming up the bubble memory
(which operates at 30-40 degrees C) and the 'WARMING UP NOW' part is actually copying
data from the bubble memory to the 2x 6264 SRAMs on the small plug-in PCB or some other
on-board RAM then the game runs entirely from RAM thereafter. This is assuming the
bubble memory is not fast enough to be directly accessed in real time.
This is speculation at this early stage.... it's entirely possible that the game does
run from the bubble memory.
Only two games were released on the 'Bubble Memory' version of the
GX400 hardware ....
1985/02 TwinBee
1985/05 Gradius (Japan release) / Nemesis (International release)
The harness pinout matches Scramble with 3 additional wires....
-12V = A15 (pin 15 solder side)
@ -2680,17 +2822,17 @@ void nemesis_state::bubsys(machine_config &config)
{
/* basic machine hardware */
M68000(config, m_maincpu, 18432000/2); /* 9.216MHz */
m_maincpu->set_addrmap(AS_PROGRAM, &nemesis_state::gx400_map);
//TIMER(config, "scantimer").configure_scanline(FUNC(nemesis_state::gx400_interrupt), "screen", 0, 1);
m_maincpu->set_disable();
m_maincpu->set_addrmap(AS_PROGRAM, &nemesis_state::bubsys_map);
TIMER(config, "scantimer").configure_scanline(FUNC(nemesis_state::gx400_interrupt), "screen", 0, 1);
Z80(config, m_audiocpu, 14318180/4); /* 3.579545 MHz */
m_audiocpu->set_addrmap(AS_PROGRAM, &nemesis_state::gx400_sound_map);
ls259_device &outlatch(LS259(config, "outlatch"));
outlatch.q_out_cb<0>().set(FUNC(nemesis_state::coin1_lockout_w));;
outlatch.q_out_cb<0>().set(FUNC(nemesis_state::coin1_lockout_w));
outlatch.q_out_cb<1>().set(FUNC(nemesis_state::coin2_lockout_w));
outlatch.q_out_cb<2>().set(FUNC(nemesis_state::sound_irq_w));
outlatch.q_out_cb<4>().set(FUNC(nemesis_state::sound_nmi_w));
outlatch.q_out_cb<7>().set(FUNC(nemesis_state::irq4_enable_w)); // ??
ls259_device &intlatch(LS259(config, "intlatch"));
@ -2751,10 +2893,12 @@ void nemesis_state::bubsys(machine_config &config)
ROM_START( bubsys )
ROM_REGION( 0x140000, "maincpu", ROMREGION_ERASE00 )
// no dump, MCU provides code there
ROM_REGION( 0x80000, "maincpu", ROMREGION_ERASE00 )
ROM_LOAD16_WORD( "boot.bin", 0x0000, 0x1e0, CRC(f0774fc2) SHA1(84fade54e025f170d983200a86c1ed96ef1a9ed3) )
ROM_REGION( 0x1000, "mcu", ROMREGION_ERASE00 ) // Fujitsu MCU, unknown type
ROM_REGION( 0x49000, "bubblememory", ROMREGION_ERASE00 )
ROM_REGION( 0x1000, "mcu", ROMREGION_ERASE00 ) /* Fujitsu MCU, unknown type */
ROM_LOAD( "mcu", 0x0000, 0x1000, NO_DUMP )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for sound */
@ -2763,10 +2907,51 @@ ROM_START( bubsys )
ROM_REGION( 0x0200, "k005289", 0 ) /* 2x 256 byte for 0005289 wavetable data */
ROM_LOAD( "400a1.2b", 0x000, 0x100, CRC(5827b1e8) SHA1(fa8cf5f868cfb08bce203baaebb6c4055ee2a000) )
ROM_LOAD( "400a2.1b", 0x100, 0x100, CRC(2f44f970) SHA1(7ab46f9d5d587665782cefc623b8de0124a6d38a) )
ROM_REGION( 0x4000, "sram", 0 ) // raw RAM dumps, just for emulation aid, to be removed ...
ROM_LOAD( "sram1.ic1", 0x0000, 0x2000, CRC(45fc9453) SHA1(eeb4ff2c2c9d3b6ea9d0f0e8fd4873f2cce2cff9) )
ROM_LOAD( "sram2.ic3", 0x2000, 0x2000, CRC(dda768be) SHA1(e98bae3ccf63eb67193346e9c40257a3ddb88e59) )
ROM_END
GAME( 1985, bubsys, 0, bubsys, nemesis, nemesis_state, empty_init, ROT0, "Konami", "Bubble System BIOS", MACHINE_IS_BIOS_ROOT | MACHINE_NOT_WORKING )
ROM_START( gradiusb )
ROM_REGION( 0x80000, "maincpu", ROMREGION_ERASE00 )
ROM_LOAD16_WORD( "boot.bin", 0x0000, 0x1e0, CRC(f0774fc2) SHA1(84fade54e025f170d983200a86c1ed96ef1a9ed3) )
ROM_REGION( 0x48360, "bubblememory", 0 )
/* The Gradius cartridge contains 0x807 pages of 130 bytes each */
ROM_LOAD16_WORD_SWAP( "gradius.bin", 0x000, 0x48360, CRC(f83b9607) SHA1(53493c2d5b0e66dd6b75865abf0982ee50c01a6f) )
ROM_REGION( 0x1000, "mcu", ROMREGION_ERASE00 ) /* Fujitsu MCU, unknown type */
ROM_LOAD( "mcu", 0x0000, 0x1000, NO_DUMP )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for sound */
ROM_LOAD( "400b03.8g", 0x00000, 0x2000, CRC(85c2afc5) SHA1(387842d02d50d0d78a27270e7267af19555b9e63) )
ROM_REGION( 0x0200, "k005289", 0 ) /* 2x 256 byte for 0005289 wavetable data */
ROM_LOAD( "400a1.2b", 0x000, 0x100, CRC(5827b1e8) SHA1(fa8cf5f868cfb08bce203baaebb6c4055ee2a000) )
ROM_LOAD( "400a2.1b", 0x100, 0x100, CRC(2f44f970) SHA1(7ab46f9d5d587665782cefc623b8de0124a6d38a) )
ROM_END
void nemesis_state::bubsys_init()
{
/*
The MCU is the master of the system and controls the /RESET and /HALT lines of the 68000.
At boot the MCU halts the 68000 and copies the 68000 boot program to shared RAM which
takes 30.65 milliseconds then the 68000 starts execution.
As the MCU is not dumped we effectively start the simulation at the point the 68000
is released, and manually copy the boot program to 68000 address space.
*/
const uint8_t *src = memregion("maincpu")->base();
memcpy(m_bubsys_shared_ram, src, 0x2000);
/*
The MCU sets this flag once the boot program is copied. The 68000 will reset
if the value is not correct.
*/
m_bubsys_control_ram[3]=0x240;
}
GAME( 1985, bubsys, 0, bubsys, bubsys, nemesis_state, bubsys_init, ROT0, "Konami", "Bubble System BIOS", MACHINE_IS_BIOS_ROOT )
GAME( 1985, gradiusb, bubsys, bubsys, bubsys, nemesis_state, bubsys_init, ROT0, "Konami", "Gradius (Bubble System)", 0 )
// Bubble System Twinbee
// Bubble System RF2
// Bubble System Galactic Warriors
// Bubble System Attack Rush

View File

@ -32,6 +32,8 @@ public:
m_spriteram(*this, "spriteram"),
m_paletteram(*this, "paletteram"),
m_gx400_shared_ram(*this, "gx400_shared"),
m_bubsys_shared_ram(*this, "bubsys_shared"),
m_bubsys_control_ram(*this, "bubsys_control"),
m_maincpu(*this, "maincpu"),
m_audiocpu(*this, "audiocpu"),
m_filter1(*this, "filter1"),
@ -57,6 +59,8 @@ public:
void nemesis(machine_config &config);
void blkpnthr(machine_config &config);
void bubsys_init();
private:
/* memory pointers */
required_shared_ptr<uint16_t> m_charram;
@ -71,6 +75,8 @@ private:
required_shared_ptr<uint16_t> m_spriteram;
optional_shared_ptr<uint16_t> m_paletteram;
optional_shared_ptr<uint8_t> m_gx400_shared_ram;
optional_shared_ptr<uint16_t> m_bubsys_shared_ram;
optional_shared_ptr<uint16_t> m_bubsys_control_ram;
/* video-related */
tilemap_t *m_background;
@ -112,11 +118,13 @@ private:
DECLARE_WRITE_LINE_MEMBER(coin1_lockout_w);
DECLARE_WRITE_LINE_MEMBER(coin2_lockout_w);
DECLARE_WRITE_LINE_MEMBER(sound_irq_w);
DECLARE_WRITE_LINE_MEMBER(sound_nmi_w);
DECLARE_READ16_MEMBER(gx400_sharedram_word_r);
DECLARE_WRITE16_MEMBER(gx400_sharedram_word_w);
DECLARE_READ16_MEMBER(konamigt_input_word_r);
DECLARE_WRITE16_MEMBER(selected_ip_word_w);
DECLARE_READ16_MEMBER(selected_ip_word_r);
DECLARE_WRITE16_MEMBER(bubsys_mcu_w);
DECLARE_READ8_MEMBER(wd_r);
DECLARE_WRITE_LINE_MEMBER(gfx_flipx_w);
DECLARE_WRITE_LINE_MEMBER(gfx_flipy_w);
@ -139,6 +147,8 @@ private:
virtual void video_start() override;
uint32_t screen_update_nemesis(screen_device &screen, bitmap_ind16 &bitmap, const rectangle &cliprect);
DECLARE_WRITE_LINE_MEMBER(nemesis_vblank_irq);
DECLARE_WRITE_LINE_MEMBER(bubsys_vblank_irq);
DECLARE_WRITE_LINE_MEMBER(blkpnthr_vblank_irq);
TIMER_DEVICE_CALLBACK_MEMBER(konamigt_interrupt);
TIMER_DEVICE_CALLBACK_MEMBER(gx400_interrupt);
@ -163,6 +173,7 @@ private:
void salamand_map(address_map &map);
void salamand_vlm_map(address_map &map);
void sound_map(address_map &map);
void bubsys_map(address_map &map);
};
#endif // MAME_INCLUDES_NEMESIS_H

View File

@ -30121,6 +30121,7 @@ bubsys //
citybomb // GX787 (c) 1987 (World)
citybombj // GX787 (c) 1987 (Japan)
gradius // GX456 (c) 1985
gradiusb // Bubble System
gwarrior // GX578 (c) 1985
hcrash // GX790 (c) 1987
hcrashc // GX790 (c) 1987