summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/drivers/malzak.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/drivers/malzak.cpp')
-rw-r--r--src/mame/drivers/malzak.cpp417
1 files changed, 417 insertions, 0 deletions
diff --git a/src/mame/drivers/malzak.cpp b/src/mame/drivers/malzak.cpp
new file mode 100644
index 00000000000..ae3997d1f4f
--- /dev/null
+++ b/src/mame/drivers/malzak.cpp
@@ -0,0 +1,417 @@
+// license:BSD-3-Clause
+// copyright-holders:Pierpaolo Prazzoli, Barry Rodewald
+/*
+
+ Malzak
+
+ Produced by Kitronix, cabinet artwork suggests it was
+ released in 1980.
+
+ Was sold around New Zealand in the early '80s.
+ Sold about 500 sets, fairly decent for the time.
+
+ There are more games on this hardware, as far as I am aware.
+
+ Driver by Reip, Barry Rodewald
+ SAA 5050 display code "borrowed" from the Philips 2000T/2000M driver in MESS
+
+ Basic memory map
+
+ 0x0000 - 0x0fff | S2650 code [malzak.5, malzak.4, malzak.2 (data only)]
+ 0x1000 - 0x13ff | Work RAM
+ 0x1400 - 0x14ff | S2636 #1 video
+ 0x1500 - 0x15ff | S2636 #2 video
+ 0x1600 - 0x16ff | Playfield gfx
+ 0x1700 - 0x17ff | Work RAM - contains hiscore table, coin count
+ 0x1800 - 0x1fff | SAA 5050 video RAM
+
+ TODO - I/O ports (0x00 for sprite->background collisions)
+ sound (2x SN76477)
+ playfield graphics may be banked, tiles above 0x1f are incorrect
+ sprite->sprite collisions aren't quite perfect
+ (you can often fly through flying missiles)
+
+ Notes:
+ - Test mode in Malzak II should be enabled by setting a POT to position
+ '4' and pressing button 1 three times. Then the POT is set to position
+ '1' to go back to the game.
+
+ Guru Notes:
+ This board looks like an early proto, it's hand etched, with
+ a ton of wire mods. I'm told the game is kind of like Scramble.
+ It's probably _ultra_ rare too.
+
+ The board looks like pure crap actually, with lot's of resistors
+ jumpering tracks and a partial harness that is wired directly to
+ the logic chips which has been *ruthlessly* chopped off!
+
+ Here's what I can see.....
+
+ EPROMs (x5, dumped, MALZAK.1 by itself, the other 4 grouped together)
+ S 8039 2650AI (DIP 40)
+ S 8051 2636N (DIP 40)
+ S 8112 2636N (DIP 40)
+ 5101 (SRAM, x3)
+ 6MHz Xtal
+ 2114 (SRAM, x4)
+ SAA 5020 (DIP 24)
+ SAA 5050 (DIP 28)
+ SN76477 (x2, DIP28)
+ INS/DP8212N P8212 (x2, DIP 24)
+ plenty of logic chips, resistors, caps etc
+
+ Note: There's no PALs or PROMs
+
+*/
+
+#include "emu.h"
+#include "cpu/s2650/s2650.h"
+#include "sound/sn76477.h"
+#include "video/saa5050.h"
+#include "machine/nvram.h"
+#include "includes/malzak.h"
+
+
+READ8_MEMBER(malzak_state::fake_VRLE_r)
+{
+ return (m_s2636_0->work_ram_r(space, 0xcb) & 0x3f) + (m_screen->vblank() * 0x40);
+}
+
+READ8_MEMBER(malzak_state::s2636_portA_r)
+{
+ // POT switch position, read from port A of the first S2636
+ // Not sure of the correct values to return, but these should
+ // do based on the game code.
+ switch (ioport("POT")->read())
+ {
+ case 0: // Normal play
+ return 0xf0;
+ case 1:
+ return 0x90;
+ case 2:
+ return 0x70;
+ case 3: // Change settings
+ return 0x00;
+ default:
+ return 0xf0;
+ }
+}
+
+static ADDRESS_MAP_START( malzak_map, AS_PROGRAM, 8, malzak_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x7fff)
+ AM_RANGE(0x0000, 0x0bff) AM_ROM
+ AM_RANGE(0x0c00, 0x0fff) AM_ROMBANK("bank1")
+ AM_RANGE(0x1000, 0x10ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1100, 0x11ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1200, 0x12ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1300, 0x13ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x14cb, 0x14cb) AM_MIRROR(0x6000) AM_READ(fake_VRLE_r)
+ AM_RANGE(0x1400, 0x14ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("s2636_0", s2636_device, work_ram_r, work_ram_w)
+ AM_RANGE(0x1500, 0x15ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("s2636_1", s2636_device, work_ram_r, work_ram_w)
+ AM_RANGE(0x1600, 0x16ff) AM_MIRROR(0x6000) AM_RAM_WRITE(malzak_playfield_w)
+ AM_RANGE(0x1700, 0x17ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1800, 0x1fff) AM_MIRROR(0x6000) AM_RAM AM_SHARE("videoram")
+ AM_RANGE(0x2000, 0x2fff) AM_ROM
+ AM_RANGE(0x4000, 0x4fff) AM_ROM
+ AM_RANGE(0x6000, 0x6fff) AM_ROM
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( malzak2_map, AS_PROGRAM, 8, malzak_state )
+ ADDRESS_MAP_GLOBAL_MASK(0x7fff)
+ AM_RANGE(0x0000, 0x0bff) AM_ROM
+ AM_RANGE(0x0c00, 0x0fff) AM_ROMBANK("bank1")
+ AM_RANGE(0x1000, 0x10ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1100, 0x11ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1200, 0x12ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x1300, 0x13ff) AM_MIRROR(0x6000) AM_RAM
+ AM_RANGE(0x14cb, 0x14cb) AM_MIRROR(0x6000) AM_READ(fake_VRLE_r)
+ AM_RANGE(0x14cc, 0x14cc) AM_MIRROR(0x6000) AM_READ(s2636_portA_r)
+ AM_RANGE(0x1400, 0x14ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("s2636_0", s2636_device, work_ram_r, work_ram_w)
+ AM_RANGE(0x1500, 0x15ff) AM_MIRROR(0x6000) AM_DEVREADWRITE("s2636_1", s2636_device, work_ram_r, work_ram_w)
+ AM_RANGE(0x1600, 0x16ff) AM_MIRROR(0x6000) AM_RAM_WRITE(malzak_playfield_w)
+ AM_RANGE(0x1700, 0x17ff) AM_MIRROR(0x6000) AM_RAM AM_SHARE("nvram")
+ AM_RANGE(0x1800, 0x1fff) AM_MIRROR(0x6000) AM_RAM AM_SHARE("videoram")
+ AM_RANGE(0x2000, 0x2fff) AM_ROM
+ AM_RANGE(0x4000, 0x4fff) AM_ROM
+ AM_RANGE(0x6000, 0x6fff) AM_ROM
+ADDRESS_MAP_END
+
+
+READ8_MEMBER(malzak_state::s2650_data_r)
+{
+ popmessage("S2650 data port read");
+ return 0xff;
+}
+
+WRITE8_MEMBER(malzak_state::port40_w)
+{
+// Bit 0 is constantly set high during gameplay
+// Bit 4 is set high, then low, upon death
+// Bit 1 is set high on boot, and on the title screens.
+// Bits 1-3 are all set high upon death, until the game continues
+// Bit 6 is used only in Malzak II, and is set high after checking
+// the selected version
+// logerror("S2650 [0x%04x]: port 0x40 write: 0x%02x\n", m_maincpu->safe_pc(), data);
+ membank("bank1")->set_entry((data & 0x40) >> 6);
+}
+
+WRITE8_MEMBER(malzak_state::port60_w)
+{
+ m_malzak_x = data;
+ // logerror("I/O: port 0x60 write 0x%02x\n", data);
+}
+
+WRITE8_MEMBER(malzak_state::portc0_w)
+{
+ m_malzak_y = data;
+ // logerror("I/O: port 0xc0 write 0x%02x\n", data);
+}
+
+READ8_MEMBER(malzak_state::collision_r)
+{
+ // High 4 bits seem to refer to the row affected.
+ if(++m_collision_counter > 15)
+ m_collision_counter = 0;
+
+ // logerror("I/O port 0x00 read\n");
+ return 0xd0 + m_collision_counter;
+}
+
+static ADDRESS_MAP_START( malzak_io_map, AS_IO, 8, malzak_state )
+ AM_RANGE(0x00, 0x00) AM_READ(collision_r) // returns where a collision can occur.
+ AM_RANGE(0x40, 0x40) AM_WRITE(port40_w) // possibly sound codes for dual SN76477s
+ AM_RANGE(0x60, 0x60) AM_WRITE(port60_w) // possibly playfield scroll X offset
+ AM_RANGE(0x80, 0x80) AM_READ_PORT("IN0") //controls
+ AM_RANGE(0xa0, 0xa0) AM_WRITENOP // echoes I/O port read from port 0x80
+ AM_RANGE(0xc0, 0xc0) AM_WRITE(portc0_w) // possibly playfield row selection for writing and/or collisions
+ AM_RANGE(S2650_DATA_PORT, S2650_DATA_PORT) AM_READ(s2650_data_r) // read upon death
+ AM_RANGE(S2650_SENSE_PORT, S2650_SENSE_PORT) AM_READ_PORT("SENSE")
+ADDRESS_MAP_END
+
+
+static INPUT_PORTS_START( malzak )
+
+ /* Malzak has an 8-way stick
+ and only one button (firing and bomb dropping on the same button) */
+
+ PORT_START("IN0") /* I/O port 0x80 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_START1 )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START2 )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
+
+ PORT_START("POT")
+ /* No POT switch on Malzak as far as I know */
+
+ PORT_START("SENSE")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
+
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( malzak2 )
+
+ /* Same as Malzak, but with additional POT switch, and
+ possibly a reset button too. */
+
+ PORT_START("IN0") /* I/O port 0x80 */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_COIN1 )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_START1 )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START2 )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON1 )
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
+
+ PORT_START("POT") /* Fake DIP switch to handle the POT switch */
+ PORT_DIPNAME( 0x03, 0x00, "POT switch position" )
+ PORT_DIPSETTING( 0x00, "1" ) // Normal play
+ PORT_DIPSETTING( 0x01, "2" )
+ PORT_DIPSETTING( 0x02, "3" )
+ PORT_DIPSETTING( 0x03, "4" ) // Change settings
+
+ PORT_START("SENSE")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_CUSTOM ) PORT_VBLANK("screen")
+
+INPUT_PORTS_END
+
+
+static const gfx_layout charlayout =
+{
+ 16,16,
+ RGN_FRAC(1,1),
+ 1,
+ { 0 },
+ { 7, 6, 5, 4, 3, 2, 1, 0, 15, 14, 13, 12, 11, 10, 9, 8 },
+ { 0*16, 1*16, 2*16, 3*16, 4*16, 5*16, 6*16, 7*16,
+ 8*16, 9*16, 10*16, 11*16, 12*16, 13*16, 14*16, 15*16 },
+// { 0*8, 1*8, 2*8, 3*8, 4*8, 5*8, 6*8, 7*8 },
+ 16*16
+// 8*8
+};
+
+
+static GFXDECODE_START( malzak )
+ GFXDECODE_ENTRY( "gfx1", 0x0000, charlayout, 0, 16 )
+GFXDECODE_END
+
+
+PALETTE_INIT_MEMBER(malzak_state, malzak)
+{
+ int i;
+
+ for (i = 0; i < 8 * 8; i++)
+ {
+ palette.set_pen_color(i * 2 + 0, pal1bit(i >> 3), pal1bit(i >> 4), pal1bit(i >> 5));
+ palette.set_pen_color(i * 2 + 1, pal1bit(i >> 0), pal1bit(i >> 1), pal1bit(i >> 2));
+ }
+}
+
+
+READ8_MEMBER(malzak_state::videoram_r)
+{
+ return m_videoram[offset];
+}
+
+void malzak_state::machine_start()
+{
+ membank("bank1")->configure_entries(0, 2, memregion("user2")->base(), 0x400);
+
+ m_saa5050 = machine().device("saa5050");
+
+ save_item(NAME(m_playfield_code));
+ save_item(NAME(m_malzak_x));
+ save_item(NAME(m_malzak_y));
+}
+
+void malzak_state::machine_reset()
+{
+ memset(m_playfield_code, 0, 256 * sizeof(int));
+
+ m_malzak_x = 0;
+ m_malzak_y = 0;
+}
+
+static MACHINE_CONFIG_START( malzak, malzak_state )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", S2650, 3800000/4)
+ MCFG_CPU_PROGRAM_MAP(malzak_map)
+ MCFG_CPU_IO_MAP(malzak_io_map)
+
+ /* video hardware */
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_REFRESH_RATE(50)
+ MCFG_SCREEN_VBLANK_TIME(ATTOSECONDS_IN_USEC(2500))
+ MCFG_SCREEN_SIZE(480, 512) /* vert size is a guess */
+ MCFG_SCREEN_VISIBLE_AREA(0, 479, 0, 479)
+ MCFG_SCREEN_UPDATE_DRIVER(malzak_state, screen_update_malzak)
+
+ MCFG_GFXDECODE_ADD("gfxdecode", "palette", malzak)
+ MCFG_PALETTE_ADD("palette", 128)
+ MCFG_PALETTE_INIT_OWNER(malzak_state, malzak)
+
+ MCFG_DEVICE_ADD("s2636_0", S2636, 0)
+ MCFG_S2636_WORKRAM_SIZE(0x100)
+ MCFG_S2636_OFFSETS(0, -16) // -8, -16
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_DEVICE_ADD("s2636_1", S2636, 0)
+ MCFG_S2636_WORKRAM_SIZE(0x100)
+ MCFG_S2636_OFFSETS(0, -16) // -9, -16
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_DEVICE_ADD("saa5050", SAA5050, 6000000)
+ MCFG_SAA5050_D_CALLBACK(READ8(malzak_state, videoram_r))
+ MCFG_SAA5050_SCREEN_SIZE(42, 24, 64)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("sn1", SN76477, 0)
+ MCFG_SN76477_NOISE_PARAMS(0, 0, 0) // noise + filter: N/C
+ MCFG_SN76477_DECAY_RES(0) // decay_res: N/C
+ MCFG_SN76477_ATTACK_PARAMS(0, RES_K(100)) // attack_decay_cap + attack_res
+ MCFG_SN76477_AMP_RES(RES_K(56)) // amplitude_res
+ MCFG_SN76477_FEEDBACK_RES(RES_K(10)) // feedback_res
+ MCFG_SN76477_VCO_PARAMS(0, CAP_U(0.1), RES_K(8.2)) // VCO volt + cap + res
+ MCFG_SN76477_PITCH_VOLTAGE(5.0) // pitch_voltage
+ MCFG_SN76477_SLF_PARAMS(CAP_U(1.0), RES_K(120)) // slf caps + res
+ MCFG_SN76477_ONESHOT_PARAMS(0, 0) // oneshot caps + res: N/C
+ MCFG_SN76477_VCO_MODE(0) // VCO mode
+ MCFG_SN76477_MIXER_PARAMS(1, 1, 1) // mixer A, B, C
+ MCFG_SN76477_ENVELOPE_PARAMS(1, 1) // envelope 1, 2
+ MCFG_SN76477_ENABLE(1) // enable
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("sn2", SN76477, 0)
+ MCFG_SN76477_NOISE_PARAMS(0, 0, 0) // noise + filter: N/C
+ MCFG_SN76477_DECAY_RES(0) // decay_res: N/C
+ MCFG_SN76477_ATTACK_PARAMS(0, RES_K(100)) // attack_decay_cap + attack_res
+ MCFG_SN76477_AMP_RES(RES_K(56)) // amplitude_res
+ MCFG_SN76477_FEEDBACK_RES(RES_K(10)) // feedback_res
+ MCFG_SN76477_VCO_PARAMS(0, CAP_U(0.1), RES_K(8.2)) // VCO volt + cap + res
+ MCFG_SN76477_PITCH_VOLTAGE(5.0) // pitch_voltage
+ MCFG_SN76477_SLF_PARAMS(CAP_U(1.0), RES_K(120)) // slf caps + res
+ MCFG_SN76477_ONESHOT_PARAMS(0, 0) // oneshot caps + res: N/C
+ MCFG_SN76477_VCO_MODE(0) // VCO mode
+ MCFG_SN76477_MIXER_PARAMS(1, 1, 1) // mixer A, B, C
+ MCFG_SN76477_ENVELOPE_PARAMS(1, 1) // envelope 1, 2
+ MCFG_SN76477_ENABLE(1) // enable
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( malzak2, malzak )
+
+ MCFG_CPU_MODIFY( "maincpu" )
+ MCFG_CPU_PROGRAM_MAP(malzak2_map)
+
+ MCFG_NVRAM_ADD_0FILL("nvram")
+MACHINE_CONFIG_END
+
+ROM_START( malzak )
+ ROM_REGION( 0x8000, "maincpu", 0 )
+ ROM_LOAD( "malzak.5", 0x0000, 0x0800, CRC(75355c98) SHA1(7036ed5d9ee38585b1a6bc204d410d5fb5ddd81f) )
+ ROM_CONTINUE( 0x2000, 0x0800 )
+ ROM_LOAD( "malzak.4", 0x0800, 0x0400, CRC(744c81e3) SHA1(c08d6df3cf2808a5f99d8247fc19a59be88121a9) )
+ ROM_CONTINUE( 0x4000, 0x0c00 )
+ // Terrain data
+ ROM_LOAD( "malzak.3", 0x4400, 0x0800, CRC(b947229e) SHA1(37b88b5aa91a483fcfe60a9bdd67a66f6378c487) )
+
+ // Screen data
+ ROM_REGION(0x0800, "user2", 0)
+ ROM_LOAD( "malzak.2", 0x0000, 0x0800, CRC(2a12ad67) SHA1(f89a50b62311a170004c061abd8dedc3ebd84748) )
+
+ ROM_REGION( 0x0800, "gfx1", 0 )
+ ROM_LOAD( "malzak.1", 0x0000, 0x0800, CRC(74d5ff7b) SHA1(cae326370dc83b86542f9d070e2dc91b1b833356) )
+ROM_END
+
+ROM_START( malzak2 )
+ ROM_REGION( 0x8000, "maincpu", 0 )
+ ROM_LOAD( "malz1a.bin", 0x000000, 0x000800, CRC(5c3cb14c) SHA1(2d3b5703cb9a47e34aa593f0e8d42d4e67c167d9) )
+ ROM_CONTINUE( 0x2000, 0x0800 )
+
+ ROM_LOAD( "malz2b.bin", 0x0800, 0x0400, CRC(2af8aace) SHA1(7aaf03d4848c2cce72b2b3729661e7826834ad44) )
+ ROM_CONTINUE( 0x4000, 0x0400 )
+ ROM_CONTINUE( 0x2800, 0x0400 )
+ ROM_CONTINUE( 0x6000, 0x0400 )
+ // Terrain data
+ ROM_LOAD( "malz3c.bin", 0x4400, 0x0800, CRC(54d6a02e) SHA1(80c550d74da770689fe451cb0ee8e550a63b1b96) )
+
+ // Screen data
+ ROM_REGION(0x0800, "user2", 0)
+ ROM_LOAD( "malz4d.bin", 0x0000, 0x0800, CRC(5c6ca415) SHA1(e7571519ac7911507d2c1cf975a7663f41321cb9) )
+
+ ROM_REGION( 0x0800, "gfx1", 0 )
+ ROM_LOAD( "malzak.1", 0x0000, 0x0800, CRC(74d5ff7b) SHA1(cae326370dc83b86542f9d070e2dc91b1b833356) )
+ROM_END
+
+
+GAME( 19??, malzak, 0, malzak, malzak, driver_device, 0, ROT0, "Kitronix", "Malzak", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )
+GAME( 19??, malzak2, malzak, malzak2, malzak2, driver_device, 0, ROT0, "Kitronix", "Malzak II", MACHINE_NOT_WORKING | MACHINE_IMPERFECT_SOUND | MACHINE_IMPERFECT_GRAPHICS | MACHINE_SUPPORTS_SAVE )