/*******************************************************************************
Block Hole (GX973) (c) 1989 Konami
driver by Nicola Salmoria
Notes:
Quarth works, but Block Hole crashes when it reaches the title screen. An
interrupt happens, and after rti the ROM bank is not the same as before so
it jumps to garbage code.
If you want to see this happen, place a breakpoint at 0x8612, and trace
after that.
The code is almost identical in the two versions, it looks like Quarth is
working just because luckily the interrupt doesn't happen at that point.
It seems that the interrupt handler trashes the selected ROM bank and forces
it to 0. To prevent crashes, I only generate interrupts when the ROM bank is
already 0. There might be another interrupt enable register, but I haven't
found it.
*******************************************************************************/
#include "emu.h"
#include "cpu/z80/z80.h"
#include "cpu/konami/konami.h" /* for the callback and the firq irq definition */
#include "video/konicdev.h"
#include "sound/2151intf.h"
#include "includes/konamipt.h"
#include "includes/blockhl.h"
/* prototypes */
static KONAMI_SETLINES_CALLBACK( blockhl_banking );
static INTERRUPT_GEN( blockhl_interrupt )
{
blockhl_state *state = device->machine().driver_data<blockhl_state>();
if (k052109_is_irq_enabled(state->m_k052109) && state->m_rombank == 0) /* kludge to prevent crashes */
device_set_input_line(device, KONAMI_IRQ_LINE, HOLD_LINE);
}
static READ8_HANDLER( bankedram_r )
{
blockhl_state *state = space->machine().driver_data<blockhl_state>();
if (state->m_palette_selected)
return space->machine().generic.paletteram.u8[offset];
else
return state->m_ram[offset];
}
static WRITE8_HANDLER( bankedram_w )
{
blockhl_state *state = space->machine().driver_data<blockhl_state>();
if (state->m_palette_selected)
paletteram_xBBBBBGGGGGRRRRR_be_w(space, offset, data);
else
state->m_ram[offset] = data;
}
static WRITE8_HANDLER( blockhl_sh_irqtrigger_w )
{
blockhl_state *state = space->machine().driver_data<blockhl_state>();
device_set_input_line_and_vector(state->m_audiocpu, 0, HOLD_LINE, 0xff);
}
/* special handlers to combine 052109 & 051960 */
static READ8_HANDLER( k052109_051960_r )
{
blockhl_state *state = space->machine().driver_data<blockhl_state>();
if (k052109_get_rmrd_line(state->m_k052109) == CLEAR_LINE)
{
if (offset >= 0x3800 && offset < 0x3808)
return k051937_r(state->m_k051960, offset - 0x3800);
else if (offset < 0x3c00)
return k052109_r(state->m_k052109, offset);
else
return k051960_r(state->m_k051960, offset - 0x3c00);
}
else
return k052109_r(state->m_k052109, offset);
}
static WRITE8_HANDLER( k052109_051960_w )
{
blockhl_state *state = space->machine().driver_data<blockhl_state>();
if (offset >= 0x3800 && offset < 0x3808)
k051937_w(state->m_k051960, offset - 0x3800, data);
else if (offset < 0x3c00)
k052109_w(state->m_k052109, offset, data);
else
k051960_w(state->m_k051960, offset - 0x3c00, data);
}
static ADDRESS_MAP_START( main_map, AS_PROGRAM, 8 )
AM_RANGE(0x1f84, 0x1f84) AM_WRITE(soundlatch_w)
AM_RANGE(0x1f88, 0x1f88) AM_WRITE(blockhl_sh_irqtrigger_w)
AM_RANGE(0x1f8c, 0x1f8c) AM_WRITE(watchdog_reset_w)
AM_RANGE(0x1f94, 0x1f94) AM_READ_PORT("DSW3")
AM_RANGE(0x1f95, 0x1f95) AM_READ_PORT("P1")
AM_RANGE(0x1f96, 0x1f96) AM_READ_PORT("P2")
AM_RANGE(0x1f97, 0x1f97) AM_READ_PORT("DSW1")
AM_RANGE(0x1f98, 0x1f98) AM_READ_PORT("DSW2")
AM_RANGE(0x0000, 0x3fff) AM_READWRITE(k052109_051960_r, k052109_051960_w)
AM_RANGE(0x4000, 0x57ff) AM_RAM
AM_RANGE(0x5800, 0x5fff) AM_READWRITE(bankedram_r, bankedram_w) AM_BASE_MEMBER(blockhl_state, m_ram)
AM_RANGE(0x6000, 0x7fff) AM_ROMBANK("bank1")
AM_RANGE(0x8000, 0xffff) AM_ROM
ADDRESS_MAP_END
static ADDRESS_MAP_START( audio_map, AS_PROGRAM, 8 )
AM_RANGE(0x0000, 0x7fff) AM_ROM
AM_RANGE(0x8000, 0x87ff) AM_RAM
AM_RANGE(0xa000, 0xa000) AM_READ(soundlatch_r)
AM_RANGE(0xc000, 0xc001) AM_DEVREADWRITE("ymsnd", ym2151_r, ym2151_w)
AM_RANGE(0xe00c, 0xe00d) AM_WRITENOP /* leftover from missing 007232? */
ADDRESS_MAP_END
/***************************************************************************
Input Ports
***************************************************************************/
static INPUT_PORTS_START( blockhl )
PORT_START("P1")
KONAMI8_B123_START(1)
PORT_START("P2")
KONAMI8_B123_START(2)
PORT_START("DSW1")
KONAMI_COINAGE_LOC(DEF_STR( Free_Play ), "No Coin B", SW1)
/* "No Coin B" = coins produce sound, but no effect on coin counter */
PORT_START("DSW2")
PORT_DIPNAME( 0x01, 0x01, DEF_STR( Lives ) ) PORT_DIPLOCATION("SW2:1")
PORT_DIPSETTING( 0x01, "1" )
PORT_DIPSETTING( 0x00, "2" )
PORT_DIPUNUSED_DIPLOC( 0x02, 0x02, "SW2:2" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x04, 0x04, "SW2:3" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x08, 0x08, "SW2:4" ) /* Listed as "Unused" */
PORT_DIPUNUSED_DIPLOC( 0x10, 0x10, "SW2:5" ) /* Listed as "Unused" */
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( Difficult ) )
PORT_DIPSETTING( 0x00, DEF_STR( Very_Difficult ) )
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("DSW3")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_COIN2 )
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_COIN3 )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNKNOWN )
PORT_DIPNAME( 0x10, 0x10, DEF_STR( Flip_Screen ) ) PORT_DIPLOCATION("SW3:1")
PORT_DIPSETTING( 0x10, DEF_STR( Off ) )
PORT_DIPSETTING( 0x00, DEF_STR( On ) )
PORT_DIPUNUSED_DIPLOC( 0x20, 0x20, "SW3:2" ) /* Listed as "Unused" */
PORT_SERVICE_DIPLOC(0x40, IP_ACTIVE_LOW, "SW3:3" )
PORT_DIPUNUSED_DIPLOC( 0x80, 0x80, "SW3:4" ) /* Listed as "Unused" */
INPUT_PORTS_END
/***************************************************************************
Machine Driver
***************************************************************************/
static const k052109_interface blockhl_k052109_intf =
{
"gfx1", 0,
NORMAL_PLANE_ORDER,
KONAMI_ROM_DEINTERLEAVE_2,
blockhl_tile_callback
};
static const k051960_interface blockhl_k051960_intf =
{
"gfx2", 1,
NORMAL_PLANE_ORDER,
KONAMI_ROM_DEINTERLEAVE_2,
blockhl_sprite_callback
};
static MACHINE_START( blockhl )
{
blockhl_state *state = machine.driver_data<blockhl_state>();
UINT8 *ROM = machine.region("maincpu")->base();
memory_configure_bank(machine, "bank1", 0, 4, &ROM[0x10000], 0x2000);
state->m_maincpu = machine.device("maincpu");
state->m_audiocpu = machine.device("audiocpu");
state->m_k052109 = machine.device("k052109");
state->m_k051960 = machine.device("k051960");
state->save_item(NAME(state->m_palette_selected));
state->save_item(NAME(state->m_rombank));
}
static MACHINE_RESET( blockhl )
{
blockhl_state *state = machine.driver_data<blockhl_state>();
konami_configure_set_lines(machine.device("maincpu"), blockhl_banking);
state->m_palette_selected = 0;
state->m_rombank = 0;
}
static MACHINE_CONFIG_START( blockhl, blockhl_state )
/* basic machine hardware */
MCFG_CPU_ADD("maincpu", KONAMI,3000000) /* Konami custom 052526 */
MCFG_CPU_PROGRAM_MAP(main_map)
MCFG_CPU_VBLANK_INT("screen", blockhl_interrupt)
MCFG_CPU_ADD("audiocpu", Z80, 3579545)
MCFG_CPU_PROGRAM_MAP(audio_map)
MCFG_MACHINE_START(blockhl)
MCFG_MACHINE_RESET(blockhl)
/* video hardware */
MCFG_VIDEO_ATTRIBUTES(VIDEO_HAS_SHADOWS)
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(64*8, 32*8)
MCFG_SCREEN_VISIBLE_AREA(14*8, (64-14)*8-1, 2*8, 30*8-1 )
MCFG_SCREEN_UPDATE(blockhl)
MCFG_PALETTE_LENGTH(1024)
MCFG_VIDEO_START(blockhl)
MCFG_K052109_ADD("k052109", blockhl_k052109_intf)
MCFG_K051960_ADD("k051960", blockhl_k051960_intf)
/* sound hardware */
MCFG_SPEAKER_STANDARD_MONO("mono")
MCFG_SOUND_ADD("ymsnd", YM2151, 3579545)
MCFG_SOUND_ROUTE(0, "mono", 0.60)
MCFG_SOUND_ROUTE(1, "mono", 0.60)
MACHINE_CONFIG_END
/***************************************************************************
Game ROMs
***************************************************************************/
ROM_START( blockhl )
ROM_REGION( 0x18000, "maincpu", 0 ) /* code + banked roms + space for banked RAM */
ROM_LOAD( "973l02.e21", 0x10000, 0x08000, CRC(e14f849a) SHA1(d44cf178cc98998b72ed32c6e20b6ebdf1f97579) )
ROM_CONTINUE( 0x08000, 0x08000 )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */
ROM_LOAD( "973d01.g6", 0x0000, 0x8000, CRC(eeee9d92) SHA1(6c6c324b1f6f4fba0aa12e0d1fc5dbab133ef669) )
ROM_REGION( 0x20000, "gfx1", 0 ) /* graphics (addressable by the main CPU) */
ROM_LOAD16_BYTE( "973f07.k15", 0x00000, 0x08000, CRC(1a8cd9b4) SHA1(7cb7944d24ac51fa6b610542d9dec68697cacf0f) ) /* tiles */
ROM_LOAD16_BYTE( "973f08.k18", 0x00001, 0x08000, CRC(952b51a6) SHA1(017575738d444b688b137cad5611638d53be84f2) )
ROM_LOAD16_BYTE( "973f09.k20", 0x10000, 0x08000, CRC(77841594) SHA1(e1bfdc5bb598d865868d578ef7faba8078becd7a) )
ROM_LOAD16_BYTE( "973f10.k23", 0x10001, 0x08000, CRC(09039fab) SHA1(a9dea17aacf4484d21ef3b16470263447b51b6b5) )
ROM_REGION( 0x20000, "gfx2", 0 ) /* graphics (addressable by the main CPU) */
ROM_LOAD16_BYTE( "973f06.k12", 0x00000, 0x08000, CRC(51acfdb6) SHA1(94d243f341b490684f5297d95d4835bd522ece35) ) /* sprites */
ROM_LOAD16_BYTE( "973f05.k9", 0x00001, 0x08000, CRC(4cfea298) SHA1(4772b5b99f5fd8174d8884bd84173512e1edabf4) )
ROM_LOAD16_BYTE( "973f04.k7", 0x10000, 0x08000, CRC(69ca41bd) SHA1(9b0b1c888efd2f2d5525f14778e18fb4a7353eb6) )
ROM_LOAD16_BYTE( "973f03.k4", 0x10001, 0x08000, CRC(21e98472) SHA1(8c697d369a1f57be0825c33b4e9107ce1b02a130) )
ROM_REGION( 0x0100, "proms", 0 ) /* PROMs */
ROM_LOAD( "973a11.h10", 0x0000, 0x0100, CRC(46d28fe9) SHA1(9d0811a928c8907785ef483bfbee5445506b3ec8) ) /* priority encoder (not used) */
ROM_END
ROM_START( quarth )
ROM_REGION( 0x18000, "maincpu", 0 ) /* code + banked roms + space for banked RAM */
ROM_LOAD( "973j02.e21", 0x10000, 0x08000, CRC(27a90118) SHA1(51309385b93db29b9277d14252166c4ea1746303) )
ROM_CONTINUE( 0x08000, 0x08000 )
ROM_REGION( 0x10000, "audiocpu", 0 ) /* 64k for the sound CPU */
ROM_LOAD( "973d01.g6", 0x0000, 0x8000, CRC(eeee9d92) SHA1(6c6c324b1f6f4fba0aa12e0d1fc5dbab133ef669) )
ROM_REGION( 0x20000, "gfx1", 0 ) /* graphics (addressable by the main CPU) */
ROM_LOAD16_BYTE( "973e07.k15", 0x00000, 0x08000, CRC(0bd6b0f8) SHA1(6c59cf637354fe2df424eaa89feb9c1bc1f66a92) ) /* tiles */
ROM_LOAD16_BYTE( "973e08.k18", 0x00001, 0x08000, CRC(104d0d5f) SHA1(595698911513113d01e5b565f5b073d1bd033d3f) )
ROM_LOAD16_BYTE( "973e09.k20", 0x10000, 0x08000, CRC(bd3a6f24) SHA1(eb45db3a6a52bb2b25df8c2dace877e59b4130a6) )
ROM_LOAD16_BYTE( "973e10.k23", 0x10001, 0x08000, CRC(cf5e4b86) SHA1(43348753894c1763b26dbfc70245dac92048db8f) )
ROM_REGION( 0x20000, "gfx2", 0 ) /* graphics (addressable by the main CPU) */
ROM_LOAD16_BYTE( "973e06.k12", 0x00000, 0x08000, CRC(0d58af85) SHA1(2efd661d614fb305a14cfe1aa4fb17714f215d4f) ) /* sprites */
ROM_LOAD16_BYTE( "973e05.k9", 0x00001, 0x08000, CRC(15d822cb) SHA1(70ecad5e0a461df0da6e6eb23f43a7b643297f0d) )
ROM_LOAD16_BYTE( "973e04.k7", 0x10000, 0x08000, CRC(d70f4a2c) SHA1(25f835a17bacf2b8debb2eb8a3cff90cab3f402a) )
ROM_LOAD16_BYTE( "973e03.k4", 0x10001, 0x08000, CRC(2c5a4b4b) SHA1(e2991dd78b9cd96cf93ebd6de0d4e060d346ab9c) )
ROM_REGION( 0x0100, "proms", 0 ) /* PROMs */
ROM_LOAD( "973a11.h10", 0x0000, 0x0100, CRC(46d28fe9) SHA1(9d0811a928c8907785ef483bfbee5445506b3ec8) ) /* priority encoder (not used) */
ROM_END
/***************************************************************************
Game driver(s)
***************************************************************************/
static KONAMI_SETLINES_CALLBACK( blockhl_banking )
{
blockhl_state *state = device->machine().driver_data<blockhl_state>();
/* bits 0-1 = ROM bank */
state->m_rombank = lines & 0x03;
memory_set_bank(device->machine(), "bank1", state->m_rombank);
/* bits 3/4 = coin counters */
coin_counter_w(device->machine(), 0, lines & 0x08);
coin_counter_w(device->machine(), 1, lines & 0x10);
/* bit 5 = select palette RAM or work RAM at 5800-5fff */
state->m_palette_selected = ~lines & 0x20;
/* bit 6 = enable char ROM reading through the video RAM */
k052109_set_rmrd_line(state->m_k052109, (lines & 0x40) ? ASSERT_LINE : CLEAR_LINE);
/* bit 7 used but unknown */
/* other bits unknown */
if ((lines & 0x84) != 0x80)
logerror("%04x: setlines %02x\n", cpu_get_pc(device), lines);
}
GAME( 1989, blockhl, 0, blockhl, blockhl, 0, ROT0, "Konami", "Block Hole", GAME_SUPPORTS_SAVE )
GAME( 1989, quarth, blockhl, blockhl, blockhl, 0, ROT0, "Konami", "Quarth (Japan)", GAME_SUPPORTS_SAVE )