summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/drivers/galaxian.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/drivers/galaxian.c')
-rw-r--r--trunk/src/mame/drivers/galaxian.c3387
1 files changed, 3387 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/galaxian.c b/trunk/src/mame/drivers/galaxian.c
new file mode 100644
index 00000000000..c56de9ac4d0
--- /dev/null
+++ b/trunk/src/mame/drivers/galaxian.c
@@ -0,0 +1,3387 @@
+/***************************************************************************
+
+ Galaxian-derived hardware
+
+ Galaxian is the root hardware for many, many systems developed in the
+ 1980-1982 timeframe. The basic design, which originated with Namco(?),
+ was replicated, tweaked, bootlegged, and used numerous times.
+
+ The basic hardware design comprises three sections on a single PCB:
+ a CPU section, a sound section, and a video section.
+
+ The CPU section is based around a Z80 (though there are modified
+ designed that changed this to an S2650). The base galaxian hardware
+ is designed to allow access to up to 16k of program ROM and 2k of
+ working RAM.
+
+ The sound section consists of three parts. The first part is
+ a programmable 8-bit down counter that clocks a 4-bit counter which
+ generates a primitive waveform whose shape is hardcoded but can be
+ controlled by a pair of variable resistors. The second part is
+ a set of three 555 timers which can be individually enabled and
+ combined to produce square waves at fixed separated pitches. A
+ fourth 555 timer is configured via a 4-bit frequency parameter to
+ control the overall pitch of the other three. Finally, two single
+ bit-triggered noise circuits are available. A 17-bit noise LFSR
+ (which also generates stars for the video circuit) feeds into both
+ circuits. A "HIT" line enables a simple on/off control of one
+ filtered output, while a "FIRE" line triggers a fixed short duration
+ pulse (controlled by another 555 timer) of modulated noise.
+
+ See video/galaxian.c for a description of the video section.
+
+****************************************************************************
+
+ Schematics are known to exist for these games:
+ * Galaxian
+ * Moon Alien Part 2
+ * King and Balloon
+
+ * Moon Cresta
+ * Moon Shuttle
+
+ * Frogger
+ * Amidar
+ * Turtles
+
+ * Scramble
+ * The End
+
+ * Super Cobra
+ * Dark Planet
+ * Lost Tomb
+
+ * Dambusters
+
+****************************************************************************
+
+Main clock: XTAL = 18.432 MHz
+Z80 Clock: XTAL/6 = 3.072 MHz
+Horizontal video frequency: HSYNC = XTAL/3/192/2 = 16 kHz
+Video frequency: VSYNC = HSYNC/132/2 = 60.606060 Hz
+VBlank duration: 1/VSYNC * (20/132) = 2500 us
+
+
+Notes:
+-----
+
+- The only code difference between 'galaxian' and 'galmidw' is that the
+ 'BONUS SHIP' text is printed on a different line.
+
+
+TODO:
+----
+
+- Problems with Galaxian based on the observation of a real machine:
+
+ - Background humming is incorrect. It's faster on a real machine
+ - Explosion sound is much softer. Filter involved?
+
+- $4800-4bff in Streaking/Ghost Muncher
+
+
+
+Moon Cresta versions supported:
+------------------------------
+
+mooncrst Nichibutsu - later revision with better demo mode and
+ text for docking. Encrypted. No ROM/RAM check
+mooncrsu Nichibutsu USA - later revision with better demo mode and
+ text for docking. Unencrypted. No ROM/RAM check
+mooncrsa Nichibutsu - older revision with better demo mode and
+ text for docking. Encrypted. No ROM/RAM check
+mooncrs2 Nichibutsu - probably first revision (no patches) and ROM/RAM check code.
+ This came from a bootleg board, with the logos erased
+ from the graphics
+mooncrsg Gremlin - same docking text as mooncrst
+mooncrsb bootleg of mooncrs2. ROM/RAM check erased.
+
+
+Notes about 'azurian' :
+-----------------------
+
+ bit 6 of IN1 is linked with bit 2 of IN2 (check code at 0x05b3) to set difficulty :
+
+ bit 6 bit 2 contents of
+ IN1 IN2 0x40f4 consequences difficulty
+
+ OFF OFF 2 aliens move 2 frames out of 3 easy
+ ON OFF 4 aliens move 4 frames out of 5 hard
+ OFF ON 3 aliens move 3 frames out of 4 normal
+ ON ON 5 aliens move 5 frames out of 6 very hard
+
+ aliens movements is handled by routine at 0x1d59 :
+
+ - alien 1 moves when 0x4044 != 0 else contents of 0x40f4 is stored at 0x4044
+ - alien 2 moves when 0x4054 != 0 else contents of 0x40f4 is stored at 0x4054
+ - alien 3 moves when 0x4064 != 0 else contents of 0x40f4 is stored at 0x4064
+
+
+Notes about 'smooncrs' :
+------------------------
+
+ Due to code at 0x2b1c and 0x3306, the game ALWAYS checks the inputs for player 1
+ (even for player 2 when "Cabinet" Dip Switch is set to "Cocktail")
+
+
+Notes about 'scorpnmc' :
+-----------------------
+
+ As the START buttons are also the buttons for player 1, how should I map them ?
+ I've coded this the same way as in 'checkman', but I'm not sure this is correct.
+
+ I can't tell if it's a bug, but if you reset the game when the screen is flipped,
+ the screens remains flipped (the "flip screen" routine doesn't seem to be called) !
+
+
+Notes about 'frogg' :
+---------------------
+
+ If bit 5 of IN0 or bit 5 of IN1 is HIGH, something strange occurs (check code
+ at 0x3580) : each time you press START2 a counter at 0x47da is incremented.
+ When this counter reaches 0x2f, each next time you press START2, it acts as if
+ you had pressed COIN2, so credits are added !
+ Bit 5 of IN0 is tested if "Cabinet" Dip Switch is set to "Upright" and
+ bit 5 of IN1 is tested if "Cabinet" Dip Switch is set to "Cocktail".
+
+
+Galaxian Bootleg Single Board Layout:
+-------------------------------------
+
+ |----------------------------------------------------------------------------------------------|
+ | |
+ A | AM27LS00 7486 7486 74163 74163 74LS393 LM324 NE555 ECG740A |
+ | |
+ B | AM27LS00 74LS00 74LS32 74LS161 74LS161 74LS74 NE555 NE555 |
+ | |
+ C | AM27LS00 7408 74LS02 74LS161 74LS161 74175 4066 NE555 NE555 |
+ | |
+ D | AM27LS00 74LS00 74LS20 74LS10 74LS74 74LS377 2114 74LS138 |
+ | |
+ E | AM27LS00 7408 74LS20 74LS283 74LS283 74LS02 2114 74LS138 DM8334 |
+ | |
+ F | 7486 74LS273 74LS?? 74LS367 74LS367 74LS273 74LS138 DM8334 |
+ | G |
+ G | F 74LS194 74LS157 74LS273 74LS367 6331-1J PRG1 74LS00 DM8334 |--|
+ | X |
+ H | 1 74LS194 74LS157 UPB8216 74161 74161 |
+ | |
+ I | G 74LS194 74LS157 UPB8216 74LS157 74LS273 |
+ | F |
+ J | X 74LS194 2114 2 2 7408 UPB8216 |
+ | 2 1 1 PRG2 |
+ K | 18.432MHZ 74LS157 2114 0 0 74LS74 UPB8216 74LS368 |
+ | 1 1 |
+ L | 74LS368 74LS157 74LS157 74LS157 74LS157 74LS04 74LS139 74LS368 |--|
+ | |
+ M | 74LS107 7474 74LS74 74LS139 74LS10 74LS02 74LS367 74LS367 74LS368 2 |
+ | | |
+ N | 7474 74LS20 74LS139 74LS74 74LS74 74LS367 74LS368 U |
+ | P |
+ O | 74LS164 74LS366 7486 7486 7486 7486 Z80 C |
+ | G |
+ P | 74LS164 74LS30 74LS161 74LS161 74LS161 74LS161 |
+ |----------------------------------------------------------------------------------------------|
+ 1 2 3 4 5 6 7 8 9 1
+ 0
+
+
+Stephh's notes (based on the games Z80 code and some tests) for games based on 'scobra' MACHINE_DRIVER :
+
+1) 'scobra' and clones
+
+1a) 'scobra'
+
+ - Player 2 controls are used for player 2 regardless of the "Cabinet" Dip Switch.
+ - COIN1 and SERVICE1 share the same coinage while COIN2 always awards 3 credits per coin;
+ when "Coinage" is set to "99 Credits", credits are always set to 99 when pressing COIN1 (code at 0x037d).
+ - There is an unused coinage routine at 0x0159 with the following settings :
+
+ PORT_DIPNAME( 0x06, 0x00, DEF_STR( Coinage ) )
+ PORT_DIPSETTING( 0x00, "A 2/1 B 99" )
+ PORT_DIPSETTING( 0x06, "A 1/2 B 1/1" )
+ PORT_DIPSETTING( 0x04, "A 1/5 B 1/1" )
+ PORT_DIPSETTING( 0x02, "A 1/7 B 1/1" )
+
+ I can't tell at the moment if it's a leftover from another Konami game on similar hardware.
+ - You can have 3 or 4 lives at start, and you can only continue 4 times (code at 0x0ebf).
+
+1b) 'scobrase'
+
+ - The only difference in main CPU with 'scobra' is not in code but in data :
+ * data at 0x1323+ and 0x1575+ displays " (c) SEGA 1981 " instead of "(c) KONAMI 1981".
+ * data from 0x3d0c to 0x3fff has an unknown effect (this area is filled with 0xff in 'scobra').
+ * data from 0x5b62 to 0x5b6f displays "SEGA" instead of "OSAKA" on the first building in the "BASE"
+ (last) level ("KONAMI" is always still displayed on other buildings).
+ As the code is the same, comments from 'scobra' also apply to this set.
+ - Audio CPU is different than the one in 'scobra'. More investigation is needed !
+
+1c) 'scobras'
+
+ - Main CPU is different than the one in 'scobra', but audio CPU is the same as 'scobrase' !
+ - Player 2 controls are used for player 2 regardless of the "Cabinet" Dip Switch.
+ - COIN1 and SERVICE1 share the same coinage while COIN2 always awards 3 credits per coin;
+ when "Coinage" is set to "99 Credits", credits are always set to 99 when pressing COIN1 (code at 0x0bec).
+ - There is NO unused coinage routine.
+ - You can have 3 or 5 lives at start, and you can only continue 255 times (code at 0x00e3).
+ - On the first building in the "BASE" (last) level is written "STERN" instead of "OSAKA".
+
+1d) 'scobrab'
+
+ - The only difference in main CPU with 'scobras' is not in code but in data :
+ * data from 0x0434 to 0x043e affects the addresses in ROM area of the strings to display.
+ * data from 0x0456 to 0x07a0 affects the strings which are displayed (almost all of them).
+ - Audio CPU is the same as the one in 'scobra' (with different ROM names though).
+
+1e) 'suprheli'
+
+ - The only difference in main CPU with 'scobras' is not in code but in data :
+ * data at 0x0522+ displays "- SUPER HELI - " instead of "- SUPER COBRA -".
+ * data at 0x0547+ and 0x0799+ displays " " instead of "(c) STERN 1981 ".
+ * data from 0x5b26 to 0x5b32 displays "APPLE" instead of "STERN" on the first building in the "BASE"
+ (last) level.
+ * data from 0x5bbb to 0x5bc9 displays "ORANGE" instead of "KONAMI" on the other buildings in the "BASE"
+ (last) level.
+ As the code is the same, comments from 'scobras' also apply to this set.
+ - There is only ONE byte of difference with audio CPU in 'scobrase' :
+
+ Z:\MAME\data>fc /B epr1277.5e 9.9d
+ Comparaison des fichiers epr1277.5e et 9.9D
+ 00001332: FD FF
+
+ Could it be a rotten bit ? As I have no evidence of this, I don't flag the ROM as BAD_DUMP.
+
+2) 'moonwar' and clones
+
+ - "8255 Port C bit 4 was originally designed so when bit4=0, 1P spinner is selected, and when bit4=1,
+ 2P spinner gets selected. But they forgot to change the 8255 initialization value and Port C was set
+ to input, setting the spinner select bit to HI regardless what was written to it. This bug has been
+ corrected in the newer set, but, to maintain hardware compatibility with older PCB's, they had to reverse
+ to active status of the select bit. So in the newer set, Bit4=1 selects the 1P spinner and Bit4=0 selects
+ the 2P spinner".
+
+2a) 'moonwar'
+
+ - Press START1 when reseting the game to enter sort of inputs "test mode".
+ - "Hyperflip" button is ignored when "Cabinet" is set to "Cocktail" (code at 0x108d).
+ - When in "Free Play" mode, you only 3 lives at start.
+
+2b) 'moonwara'
+
+ - Press START1 when reseting the game to enter sort of inputs "test mode".
+ - "Hyperflip" button is ignored when "Cabinet" is set to "Cocktail" (code at 0x107f).
+ - Besides the spinner bug, coinage is very weird in this set (no correlation between COIN1 and COIN2).
+
+3) 'armorcar' and clones
+
+3a) 'armorcar'
+
+ - Press P2 BUTTON2 when reseting the game to enter sort of inputs "test mode".
+ You'll notice that there is some leftover code from 'moonwar' as you can see 2 (muxed) PORT A
+ (and there are still writes to PORT C bit 4). This has no effect in the game though.
+ - After the 3 ports are read, when "Cabinet" is set to "Cocktail" and its player 2 turn, player 2 inputs
+ are "copied" into player 1 ones (code at 0x0fd2 : start reading inputs).
+
+3b) 'armorcar2'
+
+ - When IN1 bit 2 is ON when reseting the game, you enter sort of inputs "test mode".
+ You'll notice that there is some leftover code from 'moonwar' as you can see 2 (muxed) PORT A
+ (and there are still writes to IN2 bit 4). This has no effect in the game though.
+ As this bit is marked as "unused" (see below why), you can never access to this "test mode".
+ - IN2 bit 3 has no real effect in this set : even if contents of 0x8627 is updated each time player changes,
+ screen flipping (0xa806 and 0xa807) is always set to "normal" (0x00 * 2) due to code at 0x0598, there is a
+ missing call to 0x0abf at 0x0a8c (there is even a 'ret' for call from 0x15aa), and there is no code to "copy"
+ player 2 inputs into player 1 ones (code at 0x0fb2 : start reading inputs).
+ There is still a leftover from 'armorcar' code, so this bit affects display (how ?) when IN2 bit 3 is ON
+ and it is player 2 turn (code at 0x0b66 is the same as the one at 0x0b87 in 'armorcar').
+
+4) 'tazmania'
+
+ - Press P1 BUTTON2 when reseting the game to enter sort of inputs "test mode".
+ - After the 3 ports are read, when "Cabinet" is set to "Cocktail" and its player 2 turn, player 2 inputs
+ are "copied" into player 1 ones (code at 0x124e : start reading inputs).
+ - When "Cabinet" is set to "Upright", press any player 2 joystick direction to end current level
+ (code at 0x38dd). This trick does NOT work in bonus rooms though.
+
+5) 'anteater'
+
+ - Press P1 BUTTON1 when reseting the game to enter sort of inputs "test mode".
+ - IN2 bit 3 has no effect in this set : even if contents of 0x86c4 is updated each time player changes,
+ screen flipping (0xa806 and 0xa807) is always reset to "normal" (0x00 * 2) after possible screen inversion
+ due to code at 0x05c7, and there is no code to "copy" player 2 inputs into player 1 ones (code at 0x0f7a :
+ start reading inputs).
+
+6) 'calipso'
+
+ - Press P1 BUTTON1 when reseting the game to enter sort of inputs "test mode".
+ - Press P1 BUTTON1 to start a 1 player game or press P2 BUTTON1 to start a 2 players game ("Team-Play").
+ - IN2 bit 3 has no effect in this set : even if there is code to "copy" player 2 inputs into player 1 ones
+ (code at 0x1448 : start reading inputs), contents of 0x8669 is always set to 0x01 regardless of number players
+ and is NEVER updated (there is even no code for this). Furthermore, the screen flipping routine forces the
+ screen to be "normal" ([0xa806] = [0xa807] = 0x00) because of the 'jr' instruction at 0x2988.
+ It's possible that there is a cocktail version of the game, but I'm not really convinced about it.
+
+7) 'losttomb' and clones
+
+7a) 'losttomb'
+
+ - Press P1 right joystick UP when reseting the game to enter sort of inputs "test mode".
+ - There is no "Cabinet" Dip Switch for this game and no possible muxed input for a 2nd player.
+ Furthermore, the routine at 0x254b is NEVER called, so the screen NEVER flips !
+ - The routine that reads inputs (code at 0x0ef4) behaves differently if you are in "attract mode" or not :
+ * when playing ([0x865f] = 0x00), it reads the 3 inputs ports
+ * when in "attract mode" ([0x865f] = 0xff), it only reads IN0 (to get status of COINn and STARTn)
+ and IN1 (to get the status of the "Lives" Dip Switch), and IN2 is completely ignored
+ The side effect of such thing is that the status of the "Demo Sounds" Dip Switch will be taken into
+ consideration only after a game has been played (for example, the game will always be silenced in
+ "attract mode" after resetting the machine because 0x00 is stored at 0x8613 during initialisation).
+ - When in "Free Play" mode, you only 3 lives at start.
+
+7b) 'losttombh'
+
+ - The only difference with 'losttomb' is not in code but in data :
+
+ Z:\MAME\data>fc /B 2h-easy lthard
+ Comparaison des fichiers 2h-easy et LTHARD
+ 00000399: 0A 0B
+ 0000039E: 0D 11
+ 000003A3: 0F 14
+ 000003A8: 13 19
+ 000003AD: 15 1A
+ 000003B2: 18 1B
+ 000003B7: 1A 1C
+ 000003BC: 1B 1D
+ 000003C1: 1C 1E
+ 000003C6: 1D 1F
+ 000003CB: 1E 20
+ 000003D0: 1F 21
+ 000003D5: 20 22
+ 000003D9: 03 05
+ 000003E6: 0E 10
+ 000003F0: 12 15
+ 000003FD: 14 17
+ 00000409: 0E 10
+ 00000415: 0E 10
+ 0000099B: AA 76 altered value to please the checksum routine
+
+ So the game is harder, but it has the same ingame bugs as 'losttomb'.
+
+8) 'spdcoin'
+
+ - Press START1 or START2 when reseting the game to enter sort of inputs "test mode" (in fact, only IN0 is tested).
+ Press BOTH START1 and START2 to exit from it.
+ - Press START1 + START2 + P1 joystick LEFT when reseting the game to display some statistics (code at 0x0226).
+ Release BOTH START1 and START2 to exit this screen.
+
+9) 'superbon'
+
+ - This game is heavily based on 'losttomb', so not surprisingly is the code similar.
+ - The main difference in terms of gameplay is that you only have 1 joystick to control your character
+ and that you shoot in the direction you are running unless you press the "HOLD" button.
+ - There are no tests at startup and it's not possible to enter sort of inputs "test mode" (even if code exists)
+ by pressing P1 joystick UP because of 'jump' instruction at 0x007d. If you try to check the ROMS, you'll
+ notice that they have the same name as in 'losttomb' and that they fail the checksum routines.
+ - There is no "Cabinet" Dip Switch for this game and no possible muxed input for a 2nd player.
+ Furthermore, the routine at 0x2a48 is NEVER called, so the screen NEVER flips !
+ - The routine that reads inputs (code at 0x0eb7) behaves differently if you are in "attract mode" or not :
+ * when playing ([0x8667] = 0x00), it reads the 3 inputs ports
+ * when in "attract mode" ([0x8667] = 0xff), it only reads IN0 (to get status of COINn and STARTn)
+ and IN1 (to get the status of the "Lives" Dip Switch), and IN2 is completely ignored
+ The side effect of such thing is that the status of the "Demo Sounds" Dip Switch will be taken into
+ consideration only after a game has been played (for example, the game will always be silenced in
+ "attract mode" after resetting the machine because 0x00 is stored at 0x8613 during initialisation).
+ - When in "Free Play" mode, you only 3 lives at start.
+
+
+
+
+TO DO :
+-------
+
+ - smooncrs : fix read/writes at/to unmapped memory (when player 2, "cocktail" mode)
+ fix the ?#! bug with "bullets" (when player 2, "cocktail" mode)
+ - zigzag : full Dip Switches and Inputs
+ - zigzag2 : full Dip Switches and Inputs
+ - jumpbug : full Dip Switches and Inputs
+ - jumpbugb : full Dip Switches and Inputs
+ - levers : full Dip Switches and Inputs
+ - kingball : full Dip Switches and Inputs
+ - kingbalj : full Dip Switches and Inputs
+ - frogg : fix read/writes at/to unmapped/wrong memory
+ - scprpng : fix read/writes at/to unmapped/wrong memory
+ - scorpion : check whether konami filters are used
+ - explorer : check whether konami filters are used
+
+***************************************************************************/
+
+#include "emu.h"
+#include "cpu/z80/z80.h"
+#include "cpu/s2650/s2650.h"
+#include "machine/8255ppi.h"
+#include "sound/ay8910.h"
+#include "sound/sn76496.h"
+#include "sound/dac.h"
+#include "sound/digitalk.h"
+#include "sound/discrete.h"
+#include "audio/cclimber.h"
+#include "audio/galaxian.h"
+#include "includes/galaxian.h"
+
+
+#define KONAMI_SOUND_CLOCK 14318000
+
+
+
+/*************************************
+ *
+ * Interrupts
+ *
+ *************************************/
+
+static INTERRUPT_GEN( interrupt_gen )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ /* interrupt line is clocked at VBLANK */
+ /* a flip-flop at 6F is held in the preset state based on the NMI ON signal */
+ if (state->m_irq_enabled)
+ device_set_input_line(device, state->m_irq_line, ASSERT_LINE);
+}
+
+static INTERRUPT_GEN( fakechange_interrupt_gen )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ interrupt_gen(device);
+
+ if (input_port_read_safe(device->machine(), "FAKE_SELECT", 0x00))
+ {
+ state->m_tenspot_current_game++;
+ state->m_tenspot_current_game%=10;
+ tenspot_set_game_bank(device->machine(), state->m_tenspot_current_game, 1);
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_RESET, PULSE_LINE);
+ }
+}
+
+static WRITE8_HANDLER( irq_enable_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ /* the latched D0 bit here goes to the CLEAR line on the interrupt flip-flop */
+ state->m_irq_enabled = data & 1;
+
+ /* if CLEAR is held low, we must make sure the interrupt signal is clear */
+ if (!state->m_irq_enabled)
+ device_set_input_line(&space->device(), state->m_irq_line, CLEAR_LINE);
+}
+
+/*************************************
+ *
+ * DRIVER latch control
+ *
+ *************************************/
+
+static WRITE8_HANDLER( start_lamp_w )
+{
+ /* offset 0 = 1P START LAMP */
+ /* offset 1 = 2P START LAMP */
+ set_led_status(space->machine(), offset, data & 1);
+}
+
+
+static WRITE8_HANDLER( coin_lock_w )
+{
+ /* many variants and bootlegs don't have this */
+ coin_lockout_global_w(space->machine(), ~data & 1);
+}
+
+
+static WRITE8_HANDLER( coin_count_0_w )
+{
+ coin_counter_w(space->machine(), 0, data & 1);
+}
+
+
+static WRITE8_HANDLER( coin_count_1_w )
+{
+ coin_counter_w(space->machine(), 1, data & 1);
+}
+
+
+
+/*************************************
+ *
+ * General Konami sound I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( konami_ay8910_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x20) result &= ay8910_r(space->machine().device("8910.1"), 0);
+ if (offset & 0x80) result &= ay8910_r(space->machine().device("8910.0"), 0);
+ return result;
+}
+
+
+static WRITE8_HANDLER( konami_ay8910_w )
+{
+ /* AV 4,5 ==> AY8910 #2 */
+ /* the decoding here is very simplistic, and you can address two simultaneously */
+ if (offset & 0x10)
+ ay8910_address_w(space->machine().device("8910.1"), 0, data);
+ else if (offset & 0x20)
+ ay8910_data_w(space->machine().device("8910.1"), 0, data);
+ /* AV6,7 ==> AY8910 #1 */
+ if (offset & 0x40)
+ ay8910_address_w(space->machine().device("8910.0"), 0, data);
+ else if (offset & 0x80)
+ ay8910_data_w(space->machine().device("8910.0"), 0, data);
+}
+
+
+static WRITE8_DEVICE_HANDLER( konami_sound_control_w )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ UINT8 old = state->m_konami_sound_control;
+ state->m_konami_sound_control = data;
+
+ /* the inverse of bit 3 clocks the flip flop to signal an INT */
+ /* it is automatically cleared on the acknowledge */
+ if ((old & 0x08) && !(data & 0x08))
+ cputag_set_input_line(device->machine(), "audiocpu", 0, HOLD_LINE);
+
+ /* bit 4 is sound disable */
+ device->machine().sound().system_mute(data & 0x10);
+}
+
+
+static READ8_DEVICE_HANDLER( konami_sound_timer_r )
+{
+ /*
+ The timer is clocked at KONAMI_SOUND_CLOCK and cascades through a
+ series of counters. It first encounters a chained pair of 4-bit
+ counters in an LS393, which produce an effective divide-by-256. Next
+ it enters the divide-by-2 counter in an LS93, followed by the
+ divide-by-8 counter. Finally, it clocks a divide-by-5 counter in an
+ LS90, followed by the divide-by-2 counter. This produces an effective
+ period of 16*16*2*8*5*2 = 40960 clocks.
+
+ The clock for the sound CPU comes from output C of the first
+ divide-by-16 counter, or KONAMI_SOUND_CLOCK/8. To recover the
+ current counter index, we use the sound cpu clock times 8 mod
+ 16*16*2*8*5*2.
+ */
+ UINT32 cycles = (device->machine().device<cpu_device>("audiocpu")->total_cycles() * 8) % (UINT64)(16*16*2*8*5*2);
+ UINT8 hibit = 0;
+
+ /* separate the high bit from the others */
+ if (cycles >= 16*16*2*8*5)
+ {
+ hibit = 1;
+ cycles -= 16*16*2*8*5;
+ }
+
+ /* the top bits of the counter index map to various bits here */
+ return (hibit << 7) | /* B7 is the output of the final divide-by-2 counter */
+ (BIT(cycles,14) << 6) | /* B6 is the high bit of the divide-by-5 counter */
+ (BIT(cycles,13) << 5) | /* B5 is the 2nd highest bit of the divide-by-5 counter */
+ (BIT(cycles,11) << 4) | /* B4 is the high bit of the divide-by-8 counter */
+ 0x0e; /* assume remaining bits are high, except B0 which is grounded */
+}
+
+
+static WRITE8_HANDLER( konami_sound_filter_w )
+{
+ device_t *discrete = space->machine().device("konami");
+ static const char *const ayname[2] = { "8910.0", "8910.1" };
+ int which, chan;
+
+ /* the offset is used as data, 6 channels * 2 bits each */
+ /* AV0 .. AV5 ==> AY8910 #2 */
+ /* AV6 .. AV11 ==> AY8910 #1 */
+ for (which = 0; which < 2; which++)
+ if (space->machine().device(ayname[which]) != NULL)
+ for (chan = 0; chan < 3; chan++)
+ {
+ UINT8 bits = (offset >> (2 * chan + 6 * (1 - which))) & 3;
+
+ /* low bit goes to 0.22uF capacitor = 220000pF */
+ /* high bit goes to 0.047uF capacitor = 47000pF */
+ discrete_sound_w(discrete, NODE(3 * which + chan + 11), bits);
+ }
+}
+
+
+static WRITE8_DEVICE_HANDLER( konami_portc_0_w )
+{
+ logerror("%s:ppi0_portc_w = %02X\n", device->machine().describe_context(), data);
+}
+
+
+static WRITE8_DEVICE_HANDLER( konami_portc_1_w )
+{
+ logerror("%s:ppi1_portc_w = %02X\n", device->machine().describe_context(), data);
+}
+
+
+static const ppi8255_interface konami_ppi8255_0_intf =
+{
+ DEVCB_INPUT_PORT("IN0"), /* Port A read */
+ DEVCB_INPUT_PORT("IN1"), /* Port B read */
+ DEVCB_INPUT_PORT("IN2"), /* Port C read */
+ DEVCB_NULL, /* Port A write */
+ DEVCB_NULL, /* Port B write */
+ DEVCB_HANDLER(konami_portc_0_w) /* Port C write */
+};
+
+
+static const ppi8255_interface konami_ppi8255_1_intf =
+{
+ DEVCB_NULL, /* Port A read */
+ DEVCB_NULL, /* Port B read */
+ DEVCB_INPUT_PORT("IN3"), /* Port C read */
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, soundlatch_w), /* Port A write */
+ DEVCB_HANDLER(konami_sound_control_w), /* Port B write */
+ DEVCB_HANDLER(konami_portc_1_w) /* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * The End I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( theend_ppi8255_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x0100) result &= ppi8255_r(space->machine().device("ppi8255_0"), offset & 3);
+ if (offset & 0x0200) result &= ppi8255_r(space->machine().device("ppi8255_1"), offset & 3);
+ return result;
+}
+
+
+static WRITE8_HANDLER( theend_ppi8255_w )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ if (offset & 0x0100) ppi8255_w(space->machine().device("ppi8255_0"), offset & 3, data);
+ if (offset & 0x0200) ppi8255_w(space->machine().device("ppi8255_1"), offset & 3, data);
+}
+
+
+static WRITE8_DEVICE_HANDLER( theend_coin_counter_w )
+{
+ coin_counter_w(device->machine(), 0, data & 0x80);
+}
+
+
+static const ppi8255_interface theend_ppi8255_0_intf =
+{
+ DEVCB_INPUT_PORT("IN0"), /* Port A read */
+ DEVCB_INPUT_PORT("IN1"), /* Port B read */
+ DEVCB_INPUT_PORT("IN2"), /* Port C read */
+ DEVCB_NULL, /* Port A write */
+ DEVCB_NULL, /* Port B write */
+ DEVCB_HANDLER(theend_coin_counter_w)/* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * Scramble I/O
+ *
+ *************************************/
+
+static WRITE8_DEVICE_HANDLER( scramble_protection_w )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ /*
+ This is not fully understood; the low 4 bits of port C are
+ inputs; the upper 4 bits are outputs. Scramble main set always
+ writes sequences of 3 or more nibbles to the low port and
+ expects certain results in the upper nibble afterwards.
+ */
+ state->m_protection_state = (state->m_protection_state << 4) | (data & 0x0f);
+ switch (state->m_protection_state & 0xfff)
+ {
+ /* scramble */
+ case 0xf09: state->m_protection_result = 0xff; break;
+ case 0xa49: state->m_protection_result = 0xbf; break;
+ case 0x319: state->m_protection_result = 0x4f; break;
+ case 0x5c9: state->m_protection_result = 0x6f; break;
+
+ /* scrambls */
+ case 0x246: state->m_protection_result ^= 0x80; break;
+ case 0xb5f: state->m_protection_result = 0x6f; break;
+ }
+}
+
+
+static READ8_DEVICE_HANDLER( scramble_protection_r )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ return state->m_protection_result;
+}
+
+
+static CUSTOM_INPUT( scramble_protection_alt_r )
+{
+ galaxian_state *state = field.machine().driver_data<galaxian_state>();
+ /*
+ There are two additional bits that are derived from bit 7 of
+ the protection result. This is just a guess but works well enough
+ to boot scrambls.
+ */
+ return (state->m_protection_result >> 7) & 1;
+}
+
+
+static const ppi8255_interface scramble_ppi8255_1_intf =
+{
+ DEVCB_NULL, /* Port A read */
+ DEVCB_NULL, /* Port B read */
+ DEVCB_HANDLER(scramble_protection_r), /* Port C read */
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, soundlatch_w), /* Port A write */
+ DEVCB_HANDLER(konami_sound_control_w), /* Port B write */
+ DEVCB_HANDLER(scramble_protection_w) /* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * Explorer I/O
+ *
+ *************************************/
+
+static WRITE8_HANDLER( explorer_sound_control_w )
+{
+ cputag_set_input_line(space->machine(), "audiocpu", 0, ASSERT_LINE);
+}
+
+
+static READ8_DEVICE_HANDLER( explorer_sound_latch_r )
+{
+ cputag_set_input_line(device->machine(), "audiocpu", 0, CLEAR_LINE);
+ return soundlatch_r(device->machine().device("audiocpu")->memory().space(AS_PROGRAM), 0);
+}
+
+
+
+/*************************************
+ *
+ * SF-X I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( sfx_sample_io_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x04) result &= ppi8255_r(space->machine().device("ppi8255_2"), offset & 3);
+ return result;
+}
+
+
+static WRITE8_HANDLER( sfx_sample_io_w )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ if (offset & 0x04) ppi8255_w(space->machine().device("ppi8255_2"), offset & 3, data);
+ if (offset & 0x10) dac_signed_data_w(space->machine().device("dac"), data);
+}
+
+
+static WRITE8_DEVICE_HANDLER( sfx_sample_control_w )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ UINT8 old = state->m_sfx_sample_control;
+ state->m_sfx_sample_control = data;
+
+ /* the inverse of bit 0 clocks the flip flop to signal an INT */
+ /* it is automatically cleared on the acknowledge */
+ if ((old & 0x01) && !(data & 0x01))
+ cputag_set_input_line(device->machine(), "audio2", 0, HOLD_LINE);
+}
+
+
+static const ppi8255_interface sfx_ppi8255_2_intf =
+{
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, soundlatch2_r),/* Port A read */
+ DEVCB_NULL, /* Port B read */
+ DEVCB_NULL, /* Port C read */
+ DEVCB_NULL, /* Port A write */
+ DEVCB_NULL, /* Port B write */
+ DEVCB_NULL /* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * Frogger I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( frogger_ppi8255_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x1000) result &= ppi8255_r(space->machine().device("ppi8255_1"), (offset >> 1) & 3);
+ if (offset & 0x2000) result &= ppi8255_r(space->machine().device("ppi8255_0"), (offset >> 1) & 3);
+ return result;
+}
+
+
+static WRITE8_HANDLER( frogger_ppi8255_w )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ if (offset & 0x1000) ppi8255_w(space->machine().device("ppi8255_1"), (offset >> 1) & 3, data);
+ if (offset & 0x2000) ppi8255_w(space->machine().device("ppi8255_0"), (offset >> 1) & 3, data);
+}
+
+
+static READ8_HANDLER( frogger_ay8910_r )
+{
+ /* the decoding here is very simplistic */
+ UINT8 result = 0xff;
+ if (offset & 0x40) result &= ay8910_r(space->machine().device("8910.0"), 0);
+ return result;
+}
+
+
+static WRITE8_HANDLER( frogger_ay8910_w )
+{
+ /* the decoding here is very simplistic */
+ /* AV6,7 ==> AY8910 #1 */
+ if (offset & 0x40)
+ ay8910_data_w(space->machine().device("8910.0"), 0, data);
+ else if (offset & 0x80)
+ ay8910_address_w(space->machine().device("8910.0"), 0, data);
+}
+
+
+static READ8_DEVICE_HANDLER( frogger_sound_timer_r )
+{
+ /* same as regular Konami sound but with bits 3,5 swapped */
+ UINT8 konami_value = konami_sound_timer_r(device, 0);
+ return BITSWAP8(konami_value, 7,6,3,4,5,2,1,0);
+}
+
+
+static WRITE8_HANDLER( froggrmc_sound_control_w )
+{
+ cputag_set_input_line(space->machine(), "audiocpu", 0, (data & 1) ? CLEAR_LINE : ASSERT_LINE);
+}
+
+
+
+/*************************************
+ *
+ * Frog (Falcon) I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( frogf_ppi8255_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x1000) result &= ppi8255_r(space->machine().device("ppi8255_0"), (offset >> 3) & 3);
+ if (offset & 0x2000) result &= ppi8255_r(space->machine().device("ppi8255_1"), (offset >> 3) & 3);
+ return result;
+}
+
+
+static WRITE8_HANDLER( frogf_ppi8255_w )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ if (offset & 0x1000) ppi8255_w(space->machine().device("ppi8255_0"), (offset >> 3) & 3, data);
+ if (offset & 0x2000) ppi8255_w(space->machine().device("ppi8255_1"), (offset >> 3) & 3, data);
+}
+
+
+
+/*************************************
+ *
+ * Turtles I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( turtles_ppi8255_0_r ) { return ppi8255_r(space->machine().device("ppi8255_0"), (offset >> 4) & 3); }
+static READ8_HANDLER( turtles_ppi8255_1_r ) { return ppi8255_r(space->machine().device("ppi8255_1"), (offset >> 4) & 3); }
+static WRITE8_HANDLER( turtles_ppi8255_0_w ) { ppi8255_w(space->machine().device("ppi8255_0"), (offset >> 4) & 3, data); }
+static WRITE8_HANDLER( turtles_ppi8255_1_w ) { ppi8255_w(space->machine().device("ppi8255_1"), (offset >> 4) & 3, data); }
+
+
+
+/*************************************
+ *
+ * Scorpion sound I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( scorpion_ay8910_r )
+{
+ /* the decoding here is very simplistic, and you can address both simultaneously */
+ UINT8 result = 0xff;
+ if (offset & 0x08) result &= ay8910_r(space->machine().device("8910.2"), 0);
+ if (offset & 0x20) result &= ay8910_r(space->machine().device("8910.1"), 0);
+ if (offset & 0x80) result &= ay8910_r(space->machine().device("8910.0"), 0);
+ return result;
+}
+
+
+static WRITE8_HANDLER( scorpion_ay8910_w )
+{
+ /* the decoding here is very simplistic, and you can address all six simultaneously */
+ if (offset & 0x04) ay8910_address_w(space->machine().device("8910.2"), 0, data);
+ if (offset & 0x08) ay8910_data_w(space->machine().device("8910.2"), 0, data);
+ if (offset & 0x10) ay8910_address_w(space->machine().device("8910.1"), 0, data);
+ if (offset & 0x20) ay8910_data_w(space->machine().device("8910.1"), 0, data);
+ if (offset & 0x40) ay8910_address_w(space->machine().device("8910.0"), 0, data);
+ if (offset & 0x80) ay8910_data_w(space->machine().device("8910.0"), 0, data);
+}
+
+
+static READ8_DEVICE_HANDLER( scorpion_protection_r )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ UINT16 paritybits;
+ UINT8 parity = 0;
+
+ /* compute parity of the current (bitmask & $CE29) */
+ for (paritybits = state->m_protection_state & 0xce29; paritybits != 0; paritybits >>= 1)
+ if (paritybits & 1)
+ parity++;
+
+ /* only the low bit matters for protection, but bit 2 is also checked */
+ return parity;
+}
+
+
+static WRITE8_DEVICE_HANDLER( scorpion_protection_w )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ /* bit 5 low is a reset */
+ if (!(data & 0x20))
+ state->m_protection_state = 0x0000;
+
+ /* bit 4 low is a clock */
+ if (!(data & 0x10))
+ {
+ /* each clock shifts left one bit and ORs in the inverse of the parity */
+ state->m_protection_state = (state->m_protection_state << 1) | (~scorpion_protection_r(device, 0) & 1);
+ }
+}
+
+static READ8_HANDLER( scorpion_digitalker_intr_r )
+{
+ device_t *digitalker = space->machine().device("digitalker");
+ return digitalker_0_intr_r(digitalker);
+}
+
+static WRITE8_DEVICE_HANDLER( scorpion_digitalker_control_w )
+{
+ digitalker_0_cs_w(device, data & 1 ? ASSERT_LINE : CLEAR_LINE);
+ digitalker_0_cms_w(device, data & 2 ? ASSERT_LINE : CLEAR_LINE);
+ digitalker_0_wr_w(device, data & 4 ? ASSERT_LINE : CLEAR_LINE);
+}
+
+static const ppi8255_interface scorpion_ppi8255_1_intf =
+{
+ DEVCB_NULL, /* Port A read */
+ DEVCB_NULL, /* Port B read */
+ DEVCB_HANDLER(scorpion_protection_r), /* Port C read */
+ DEVCB_MEMORY_HANDLER("maincpu", PROGRAM, soundlatch_w), /* Port A write */
+ DEVCB_HANDLER(konami_sound_control_w), /* Port B write */
+ DEVCB_HANDLER(scorpion_protection_w) /* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * Ghostmuncher Galaxian I/O
+ *
+ *************************************/
+
+static INPUT_CHANGED( gmgalax_game_changed )
+{
+ galaxian_state *state = field.machine().driver_data<galaxian_state>();
+ address_space *space = field.machine().device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* new value is the selected game */
+ state->m_gmgalax_selected_game = newval;
+
+ /* select the bank and graphics bank based on it */
+ memory_set_bank(field.machine(), "bank1", state->m_gmgalax_selected_game);
+ galaxian_gfxbank_w(space, 0, state->m_gmgalax_selected_game);
+
+ /* reset the stars */
+ galaxian_stars_enable_w(space, 0, 0);
+
+ /* reset the CPU */
+ cputag_set_input_line(field.machine(), "maincpu", INPUT_LINE_RESET, PULSE_LINE);
+}
+
+
+static CUSTOM_INPUT( gmgalax_port_r )
+{
+ galaxian_state *state = field.machine().driver_data<galaxian_state>();
+ const char *portname = (const char *)param;
+ if (state->m_gmgalax_selected_game != 0)
+ portname += strlen(portname) + 1;
+ return input_port_read(field.machine(), portname);
+}
+
+
+
+/*************************************
+ *
+ * Zig Zag I/O
+ *
+ *************************************/
+
+static WRITE8_HANDLER( zigzag_bankswap_w )
+{
+ memory_set_bank(space->machine(), "bank1", data & 1);
+ memory_set_bank(space->machine(), "bank2", ~data & 1);
+}
+
+
+static WRITE8_HANDLER( zigzag_ay8910_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ switch (offset & 0x300)
+ {
+ case 0x000:
+ /* control lines */
+ /* bit 0 = WRITE */
+ /* bit 1 = C/D */
+ if ((offset & 1) != 0)
+ ay8910_data_address_w(space->machine().device("aysnd"), offset >> 1, state->m_zigzag_ay8910_latch);
+ break;
+
+ case 0x100:
+ /* data latch */
+ state->m_zigzag_ay8910_latch = offset & 0xff;
+ break;
+
+ case 0x200:
+ /* unknown */
+ break;
+ }
+}
+
+
+
+/*************************************
+ *
+ * Azurian I/O
+ *
+ *************************************/
+
+static CUSTOM_INPUT( azurian_port_r )
+{
+ return (input_port_read(field.machine(), "FAKE") >> (FPTR)param) & 1;
+}
+
+
+
+/*************************************
+ *
+ * King & Balloon I/O
+ *
+ *************************************/
+
+static CUSTOM_INPUT( kingball_muxbit_r )
+{
+ galaxian_state *state = field.machine().driver_data<galaxian_state>();
+ /* multiplex the service mode switch with a speech DIP switch */
+ return (input_port_read(field.machine(), "FAKE") >> state->m_kingball_speech_dip) & 1;
+}
+
+
+static CUSTOM_INPUT( kingball_noise_r )
+{
+ /* bit 5 is the NOISE line from the sound circuit. The code just verifies
+ that it's working, doesn't actually use return value, so we can just use
+ rand() */
+ return field.machine().rand() & 1;
+}
+
+
+static WRITE8_HANDLER( kingball_speech_dip_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ state->m_kingball_speech_dip = data;
+}
+
+
+static WRITE8_HANDLER( kingball_sound1_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ state->m_kingball_sound = (state->m_kingball_sound & ~0x01) | data;
+}
+
+
+static WRITE8_HANDLER( kingball_sound2_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ state->m_kingball_sound = (state->m_kingball_sound & ~0x02) | (data << 1);
+ soundlatch_w(space, 0, state->m_kingball_sound | 0xf0);
+}
+
+
+static WRITE8_DEVICE_HANDLER( kingball_dac_w )
+{
+ dac_w(device, offset, data ^ 0xff);
+}
+
+
+
+/*************************************
+ *
+ * Moon Shuttle I/O
+ *
+ *************************************/
+
+static WRITE8_HANDLER( mshuttle_ay8910_cs_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ state->m_mshuttle_ay8910_cs = data & 1;
+}
+
+
+static WRITE8_HANDLER( mshuttle_ay8910_control_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ if (!state->m_mshuttle_ay8910_cs)
+ ay8910_address_w(space->machine().device("aysnd"), offset, data);
+}
+
+
+static WRITE8_HANDLER( mshuttle_ay8910_data_w )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ if (!state->m_mshuttle_ay8910_cs)
+ ay8910_data_w(space->machine().device("aysnd"), offset, data);
+}
+
+
+static READ8_HANDLER( mshuttle_ay8910_data_r )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ if (!state->m_mshuttle_ay8910_cs)
+ return ay8910_r(space->machine().device("aysnd"), offset);
+ return 0xff;
+}
+
+
+
+/*************************************
+ *
+ * Jump Bug I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( jumpbug_protection_r )
+{
+ switch (offset)
+ {
+ case 0x0114: return 0x4f;
+ case 0x0118: return 0xd3;
+ case 0x0214: return 0xcf;
+ case 0x0235: return 0x02;
+ case 0x0311: return 0xff; /* not checked */
+ }
+ logerror("Unknown protection read. Offset: %04X PC=%04X\n",0xb000+offset,cpu_get_pc(&space->device()));
+ return 0xff;
+}
+
+
+
+/*************************************
+ *
+ * Checkman I/O
+ *
+ *************************************/
+
+static WRITE8_HANDLER( checkman_sound_command_w )
+{
+ soundlatch_w(space, 0, data);
+ cputag_set_input_line(space->machine(), "audiocpu", INPUT_LINE_NMI, PULSE_LINE);
+}
+
+
+static TIMER_DEVICE_CALLBACK( checkmaj_irq0_gen )
+{
+ cputag_set_input_line(timer.machine(), "audiocpu", 0, HOLD_LINE);
+}
+
+
+static READ8_HANDLER( checkmaj_protection_r )
+{
+ switch (cpu_get_pc(&space->device()))
+ {
+ case 0x0f15: return 0xf5;
+ case 0x0f8f: return 0x7c;
+ case 0x10b3: return 0x7c;
+ case 0x10e0: return 0x00;
+ case 0x10f1: return 0xaa;
+ case 0x1402: return 0xaa;
+ default:
+ logerror("Unknown protection read. PC=%04X\n",cpu_get_pc(&space->device()));
+ }
+
+ return 0;
+}
+
+
+
+/*************************************
+ *
+ * Dingo I/O
+ *
+ *************************************/
+
+static READ8_HANDLER( dingo_3000_r )
+{
+ return 0xaa;
+}
+
+
+static READ8_HANDLER( dingo_3035_r )
+{
+ return 0x8c;
+}
+
+
+static READ8_HANDLER( dingoe_3001_r )
+{
+ return 0xaa;
+}
+
+
+/*************************************
+ *
+ * Moon War I/O
+ *
+ *************************************/
+
+static WRITE8_DEVICE_HANDLER( moonwar_port_select_w )
+{
+ galaxian_state *state = device->machine().driver_data<galaxian_state>();
+ state->m_moonwar_port_select = data & 0x10;
+}
+
+
+static const ppi8255_interface moonwar_ppi8255_0_intf =
+{
+ DEVCB_INPUT_PORT("IN0"), /* Port A read */
+ DEVCB_INPUT_PORT("IN1"), /* Port B read */
+ DEVCB_INPUT_PORT("IN2"), /* Port C read */
+ DEVCB_NULL, /* Port A write */
+ DEVCB_NULL, /* Port B write */
+ DEVCB_HANDLER(moonwar_port_select_w) /* Port C write */
+};
+
+
+
+/*************************************
+ *
+ * Memory maps
+ *
+ *************************************/
+
+/*
+0000-3fff
+
+
+4000-7fff
+ 4000-47ff -> RAM read/write (10 bits = 0x400)
+ 4800-4fff -> n/c
+ 5000-57ff -> /VRAM RD or /VRAM WR (10 bits = 0x400)
+ 5800-5fff -> /OBJRAM RD or /OBJRAM WR (8 bits = 0x100)
+ 6000-67ff -> /SW0 or /DRIVER
+ 6800-6fff -> /SW1 or /SOUND
+ 7000-77ff -> /DIPSW or LATCH
+ 7800-7fff -> /WDR or /PITCH
+
+/DRIVER: (write 6000-67ff)
+ D0 = data bit
+ A0-A2 = decoder
+ 6000 -> 1P START
+ 6001 -> 2P START
+ 6002 -> COIN LOCKOUT
+ 6003 -> COIN COUNTER
+ 6004 -> 1M resistor (controls 555 timer @ 9R)
+ 6005 -> 470k resistor (controls 555 timer @ 9R)
+ 6006 -> 220k resistor (controls 555 timer @ 9R)
+ 6007 -> 100k resistor (controls 555 timer @ 9R)
+
+/SOUND: (write 6800-6fff)
+ D0 = data bit
+ A0-A2 = decoder
+ 6800 -> FS1 (enables 555 timer at 8R)
+ 6801 -> FS2 (enables 555 timer at 8S)
+ 6802 -> FS3 (enables 555 timer at 8T)
+ 6803 -> HIT
+ 6804 -> n/c
+ 6805 -> FIRE
+ 6806 -> VOL1
+ 6807 -> VOL2
+
+LATCH: (write 7000-77ff)
+ D0 = data bit
+ A0-A2 = decoder
+ 7000 -> n/c
+ 7001 -> NMI ON
+ 7002 -> n/c
+ 7003 -> n/c
+ 7004 -> STARS ON
+ 7005 -> n/c
+ 7006 -> HFLIP
+ 7007 -> VFLIP
+
+/PITCH: (write 7800-7fff)
+ loads latch at 9J
+*/
+
+/* map derived from schematics */
+
+static ADDRESS_MAP_START( galaxian_map_discrete, AS_PROGRAM, 8 )
+ AM_RANGE(0x6004, 0x6007) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_lfo_freq_w)
+ AM_RANGE(0x6800, 0x6807) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_sound_w)
+ AM_RANGE(0x7800, 0x7800) AM_MIRROR(0x07ff) AM_DEVWRITE(GAL_AUDIO, galaxian_pitch_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( galaxian_map_base, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0x0400) AM_RAM
+ AM_RANGE(0x5000, 0x53ff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x5800, 0x58ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x6000, 0x6000) AM_MIRROR(0x07ff) AM_READ_PORT("IN0")
+ AM_RANGE(0x6000, 0x6001) AM_MIRROR(0x07f8) AM_WRITE(start_lamp_w)
+ AM_RANGE(0x6002, 0x6002) AM_MIRROR(0x07f8) AM_WRITE(coin_lock_w)
+ AM_RANGE(0x6003, 0x6003) AM_MIRROR(0x07f8) AM_WRITE(coin_count_0_w)
+ //AM_RANGE(0x6004, 0x6007) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_lfo_freq_w)
+ AM_RANGE(0x6800, 0x6800) AM_MIRROR(0x07ff) AM_READ_PORT("IN1")
+ //AM_RANGE(0x6800, 0x6807) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_sound_w)
+ AM_RANGE(0x7000, 0x7000) AM_MIRROR(0x07ff) AM_READ_PORT("IN2")
+ AM_RANGE(0x7001, 0x7001) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x7004, 0x7004) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x7006, 0x7006) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x7007, 0x7007) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+ //AM_RANGE(0x7800, 0x7800) AM_MIRROR(0x07ff) AM_DEVWRITE(GAL_AUDIO, galaxian_pitch_w)
+ AM_RANGE(0x7800, 0x7800) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( galaxian_map, AS_PROGRAM, 8 )
+ AM_IMPORT_FROM(galaxian_map_base)
+ AM_IMPORT_FROM(galaxian_map_discrete)
+ADDRESS_MAP_END
+
+/* map derived from schematics */
+
+static ADDRESS_MAP_START( mooncrst_map_discrete, AS_PROGRAM, 8 )
+ AM_RANGE(0xa004, 0xa007) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_lfo_freq_w)
+ AM_RANGE(0xa800, 0xa807) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_sound_w)
+ AM_RANGE(0xb800, 0xb800) AM_MIRROR(0x07ff) AM_DEVWRITE(GAL_AUDIO, galaxian_pitch_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( mooncrst_map_base, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_MIRROR(0x0400) AM_RAM
+ AM_RANGE(0x9000, 0x93ff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x9800, 0x98ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x07ff) AM_READ_PORT("IN0")
+ AM_RANGE(0xa000, 0xa002) AM_MIRROR(0x07f8) AM_WRITE(galaxian_gfxbank_w)
+ AM_RANGE(0xa003, 0xa003) AM_MIRROR(0x07f8) AM_WRITE(coin_count_0_w)
+// AM_RANGE(0xa004, 0xa007) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_lfo_freq_w)
+ AM_RANGE(0xa800, 0xa800) AM_MIRROR(0x07ff) AM_READ_PORT("IN1")
+// AM_RANGE(0xa800, 0xa807) AM_MIRROR(0x07f8) AM_DEVWRITE(GAL_AUDIO, galaxian_sound_w)
+ AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x07ff) AM_READ_PORT("IN2")
+ AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xb004, 0xb004) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0xb006, 0xb006) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xb007, 0xb007) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+// AM_RANGE(0xb800, 0xb800) AM_MIRROR(0x07ff) AM_DEVWRITE(GAL_AUDIO, galaxian_pitch_w)
+ AM_RANGE(0xb800, 0xb800) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( mooncrst_map, AS_PROGRAM, 8 )
+ AM_IMPORT_FROM(mooncrst_map_base)
+ AM_IMPORT_FROM(mooncrst_map_discrete)
+ADDRESS_MAP_END
+
+
+
+/* map derived from schematics */
+#if 0
+static ADDRESS_MAP_START( dambustr_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+// AM_RANGE(0x8000, 0x8000) AM_WRITE(dambustr_bg_color_w)
+// AM_RANGE(0x8001, 0x8001) AM_WRITE(dambustr_bg_split_line_w)
+ AM_RANGE(0xc000, 0xc3ff) AM_MIRROR(0x0400) AM_RAM
+ AM_RANGE(0xd000, 0xd3ff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0xd800, 0xd8ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xe000, 0xe000) AM_MIRROR(0x07ff) AM_READ_PORT("IN0")
+ AM_RANGE(0xe004, 0xe007) AM_MIRROR(0x07f8) AM_WRITE(galaxian_lfo_freq_w)
+ AM_RANGE(0xe800, 0xe800) AM_MIRROR(0x07ff) AM_READ_PORT("IN1")
+ AM_RANGE(0xe800, 0xe807) AM_MIRROR(0x07f8) AM_WRITE(galaxian_sound_w)
+ AM_RANGE(0xf000, 0xf000) AM_MIRROR(0x07ff) AM_READ_PORT("IN2")
+ AM_RANGE(0xf001, 0xf001) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xf004, 0xf004) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0xf006, 0xf006) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xf007, 0xf007) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0xf800, 0xf800) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0xf800, 0xf800) AM_MIRROR(0x07ff) AM_WRITE(galaxian_pitch_w)
+ADDRESS_MAP_END
+#endif
+
+
+/* map derived from schematics */
+static ADDRESS_MAP_START( theend_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x4000, 0x47ff) AM_RAM
+ AM_RANGE(0x4800, 0x4bff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x5000, 0x50ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x6801, 0x6801) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x6802, 0x6802) AM_MIRROR(0x07f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0x6803, 0x6803) AM_MIRROR(0x07f8) AM_WRITE(scramble_background_enable_w)
+ AM_RANGE(0x6804, 0x6804) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x6805, 0x6805) AM_MIRROR(0x07f8) //POUT2
+ AM_RANGE(0x6806, 0x6806) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x6807, 0x6807) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0x7000, 0x7000) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0x8000, 0xffff) AM_READWRITE(theend_ppi8255_r, theend_ppi8255_w)
+ADDRESS_MAP_END
+
+
+/* map derived from schematics */
+static ADDRESS_MAP_START( scobra_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0x87ff) AM_MIRROR(0x4000) AM_RAM
+ AM_RANGE(0x8800, 0x8bff) AM_MIRROR(0x4400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x9000, 0x90ff) AM_MIRROR(0x4700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x9800, 0x9803) AM_MIRROR(0x47fc) AM_DEVREADWRITE("ppi8255_0", ppi8255_r, ppi8255_w)
+ AM_RANGE(0xa000, 0xa003) AM_MIRROR(0x47fc) AM_DEVREADWRITE("ppi8255_1", ppi8255_r, ppi8255_w)
+ AM_RANGE(0xa801, 0xa801) AM_MIRROR(0x47f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xa802, 0xa802) AM_MIRROR(0x47f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0xa803, 0xa803) AM_MIRROR(0x47f8) AM_WRITE(scramble_background_enable_w)
+ AM_RANGE(0xa804, 0xa804) AM_MIRROR(0x47f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0xa805, 0xa805) AM_MIRROR(0x47f8) /* POUT2 */
+ AM_RANGE(0xa806, 0xa806) AM_MIRROR(0x47f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xa807, 0xa807) AM_MIRROR(0x47f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0xb000, 0xb000) AM_MIRROR(0x47ff) AM_READ(watchdog_reset_r)
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( anteateruk_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x03ff) AM_ROM
+ AM_RANGE(0x0400, 0x0bff) AM_RAM
+ AM_RANGE(0x0c00, 0x0fff) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x1001, 0x1001) AM_MIRROR(0x01f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x1002, 0x1002) AM_MIRROR(0x01f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0x1003, 0x1003) AM_MIRROR(0x01f8) AM_WRITE(scramble_background_enable_w)
+ AM_RANGE(0x1004, 0x1004) AM_MIRROR(0x01f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x1005, 0x1005) AM_MIRROR(0x01f8) //POUT2
+ AM_RANGE(0x1006, 0x1006) AM_MIRROR(0x01f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x1007, 0x1007) AM_MIRROR(0x01f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0x1200, 0x12ff) AM_MIRROR(0x0100) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x1400, 0x1400) AM_MIRROR(0x03ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0x4000, 0xbfff) AM_ROM
+ AM_RANGE(0xc000, 0xc003) AM_MIRROR(0x3efc) AM_DEVREADWRITE("ppi8255_1", ppi8255_r, ppi8255_w)
+ AM_RANGE(0xc100, 0xc103) AM_MIRROR(0x3efc) AM_DEVREADWRITE("ppi8255_0", ppi8255_r, ppi8255_w)
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( anteaterg_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x03ff) AM_ROM
+ AM_RANGE(0x0400, 0x0bff) AM_RAM
+ AM_RANGE(0x0c00, 0x0fff) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x2000, 0x20ff) AM_MIRROR(0x0300) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x2400, 0x2403) AM_MIRROR(0x01fc) AM_DEVREADWRITE("ppi8255_1", ppi8255_r, ppi8255_w)
+ AM_RANGE(0x2601, 0x2601) AM_MIRROR(0x01f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x2602, 0x2602) AM_MIRROR(0x01f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0x2603, 0x2603) AM_MIRROR(0x01f8) AM_WRITE(scramble_background_enable_w)
+ AM_RANGE(0x2604, 0x2604) AM_MIRROR(0x01f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x2605, 0x2605) AM_MIRROR(0x01f8) //POUT2
+ AM_RANGE(0x2606, 0x2606) AM_MIRROR(0x01f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x2607, 0x2607) AM_MIRROR(0x01f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0x4000, 0xbfff) AM_ROM
+ AM_RANGE(0x7c00, 0x7fff) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram) /* mirror! */
+ AM_RANGE(0xf400, 0xf400) AM_MIRROR(0x01ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0xf600, 0xf603) AM_MIRROR(0x01fc) AM_DEVREADWRITE("ppi8255_0", ppi8255_r, ppi8255_w)
+ADDRESS_MAP_END
+
+
+/* map derived from schematics */
+static ADDRESS_MAP_START( frogger_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x8000, 0x87ff) AM_RAM
+ AM_RANGE(0x8800, 0x8800) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0xa800, 0xabff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0xb000, 0xb0ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xb808, 0xb808) AM_MIRROR(0x07e3) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xb80c, 0xb80c) AM_MIRROR(0x07e3) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0xb810, 0xb810) AM_MIRROR(0x07e3) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xb818, 0xb818) AM_MIRROR(0x07e3) AM_WRITE(coin_count_0_w) /* IOPC7 */
+ AM_RANGE(0xb81c, 0xb81c) AM_MIRROR(0x07e3) AM_WRITE(coin_count_1_w) /* POUT1 */
+ AM_RANGE(0xc000, 0xffff) AM_READWRITE(frogger_ppi8255_r, frogger_ppi8255_w)
+ADDRESS_MAP_END
+
+
+/* map derived from schematics */
+static ADDRESS_MAP_START( turtles_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0x87ff) AM_MIRROR(0x4000) AM_RAM
+ AM_RANGE(0x9000, 0x93ff) AM_MIRROR(0x4400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x9800, 0x98ff) AM_MIRROR(0x4700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xa000, 0xa000) AM_MIRROR(0x47c7) AM_WRITE(scramble_background_red_w)
+ AM_RANGE(0xa008, 0xa008) AM_MIRROR(0x47c7) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xa010, 0xa010) AM_MIRROR(0x47c7) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0xa018, 0xa018) AM_MIRROR(0x47c7) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xa020, 0xa020) AM_MIRROR(0x47c7) AM_WRITE(scramble_background_green_w)
+ AM_RANGE(0xa028, 0xa028) AM_MIRROR(0x47c7) AM_WRITE(scramble_background_blue_w)
+ AM_RANGE(0xa030, 0xa030) AM_MIRROR(0x47c7) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0xa038, 0xa038) AM_MIRROR(0x47c7) AM_WRITE(coin_count_1_w)
+ AM_RANGE(0xa800, 0xa800) AM_MIRROR(0x47ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0xb000, 0xb03f) AM_MIRROR(0x47cf) AM_READWRITE(turtles_ppi8255_0_r, turtles_ppi8255_0_w)
+ AM_RANGE(0xb800, 0xb83f) AM_MIRROR(0x47cf) AM_READWRITE(turtles_ppi8255_1_r, turtles_ppi8255_1_w)
+ADDRESS_MAP_END
+
+
+/* this is the same as theend, except for separate RGB background controls
+ and some extra ROM space at $7000 and $C000 */
+static ADDRESS_MAP_START( sfx_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x4000, 0x47ff) AM_RAM
+ AM_RANGE(0x4800, 0x4bff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x5000, 0x50ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x6800, 0x6800) AM_MIRROR(0x07f8) AM_WRITE(scramble_background_red_w)
+ AM_RANGE(0x6801, 0x6801) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x6802, 0x6802) AM_MIRROR(0x07f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0x6803, 0x6803) AM_MIRROR(0x07f8) AM_WRITE(scramble_background_blue_w)
+ AM_RANGE(0x6804, 0x6804) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x6805, 0x6805) AM_MIRROR(0x07f8) AM_WRITE(scramble_background_green_w)
+ AM_RANGE(0x6806, 0x6806) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x6807, 0x6807) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0x7000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0xbfff) AM_READWRITE(theend_ppi8255_r, theend_ppi8255_w)
+ AM_RANGE(0xc000, 0xefff) AM_ROM
+ADDRESS_MAP_END
+
+
+/* changes from galaxian map:
+ galaxian sound removed
+ $4800-$57ff: cointains video and object RAM (normally at $5000-$5fff)
+ $5800-$5fff: AY-8910 access added
+ $6002-$6006: graphics banking controls replace coin lockout, coin counter, and lfo
+ $7002: coin counter (moved from $6003)
+ $8000-$afff: additional ROM area
+ $b000-$bfff: protection
+*/
+static ADDRESS_MAP_START( jumpbug_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x4000, 0x47ff) AM_RAM
+ AM_RANGE(0x4800, 0x4bff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x5000, 0x50ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0x5800, 0x5800) AM_MIRROR(0x00ff) AM_DEVWRITE("aysnd", ay8910_data_w)
+ AM_RANGE(0x5900, 0x5900) AM_MIRROR(0x00ff) AM_DEVWRITE("aysnd", ay8910_address_w)
+ AM_RANGE(0x6000, 0x6000) AM_MIRROR(0x07ff) AM_READ_PORT("IN0")
+ AM_RANGE(0x6002, 0x6006) AM_MIRROR(0x07f8) AM_WRITE(galaxian_gfxbank_w)
+ AM_RANGE(0x6800, 0x6800) AM_MIRROR(0x07ff) AM_READ_PORT("IN1")
+ AM_RANGE(0x7000, 0x7000) AM_MIRROR(0x07ff) AM_READ_PORT("IN2")
+ AM_RANGE(0x7001, 0x7001) AM_MIRROR(0x07f8) AM_WRITE(irq_enable_w)
+ AM_RANGE(0x7002, 0x7002) AM_MIRROR(0x07f8) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0x7004, 0x7004) AM_MIRROR(0x07f8) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0x7006, 0x7006) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0x7007, 0x7007) AM_MIRROR(0x07f8) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0x8000, 0xafff) AM_ROM
+ AM_RANGE(0xb000, 0xbfff) AM_READ(jumpbug_protection_r)
+ADDRESS_MAP_END
+
+
+static ADDRESS_MAP_START( frogf_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x3fff) AM_ROM
+ AM_RANGE(0x8000, 0x87ff) AM_RAM
+ AM_RANGE(0x8800, 0x8bff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x9000, 0x90ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xa802, 0xa802) AM_MIRROR(0x07f1) AM_WRITE(galaxian_flip_screen_x_w)
+ AM_RANGE(0xa804, 0xa804) AM_MIRROR(0x07f1) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xa806, 0xa806) AM_MIRROR(0x07f1) AM_WRITE(galaxian_flip_screen_y_w)
+ AM_RANGE(0xa808, 0xa808) AM_MIRROR(0x07f1) AM_WRITE(coin_count_1_w)
+ AM_RANGE(0xa80e, 0xa80e) AM_MIRROR(0x07f1) AM_WRITE(coin_count_0_w)
+ AM_RANGE(0xb800, 0xb800) AM_MIRROR(0x07ff) AM_READ(watchdog_reset_r)
+ AM_RANGE(0xc000, 0xffff) AM_READWRITE(frogf_ppi8255_r, frogf_ppi8255_w)
+ADDRESS_MAP_END
+
+
+/* mooncrst */
+static ADDRESS_MAP_START( mshuttle_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_RAM
+ AM_RANGE(0x9000, 0x93ff) AM_MIRROR(0x0400) AM_RAM_WRITE(galaxian_videoram_w) AM_BASE_MEMBER(galaxian_state, m_videoram)
+ AM_RANGE(0x9800, 0x98ff) AM_MIRROR(0x0700) AM_RAM_WRITE(galaxian_objram_w) AM_BASE_GENERIC(spriteram)
+ AM_RANGE(0xa000, 0xa000) AM_READ_PORT("IN0")
+ AM_RANGE(0xa000, 0xa000) AM_WRITE(irq_enable_w)
+ AM_RANGE(0xa001, 0xa001) AM_WRITE(galaxian_stars_enable_w)
+ AM_RANGE(0xa002, 0xa002) AM_WRITE(galaxian_flip_screen_xy_w)
+ AM_RANGE(0xa004, 0xa004) AM_WRITE(cclimber_sample_trigger_w)
+ AM_RANGE(0xa007, 0xa007) AM_WRITE(mshuttle_ay8910_cs_w)
+ AM_RANGE(0xa800, 0xa800) AM_READ_PORT("IN1")
+ AM_RANGE(0xa800, 0xa800) AM_WRITE(cclimber_sample_rate_w)
+ AM_RANGE(0xb000, 0xb000) AM_READ_PORT("IN2")
+ AM_RANGE(0xb000, 0xb000) AM_WRITE(cclimber_sample_volume_w)
+ AM_RANGE(0xb800, 0xb800) AM_READ(watchdog_reset_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( mshuttle_portmap, AS_IO, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0x0f)
+ AM_RANGE(0x08, 0x08) AM_WRITE(mshuttle_ay8910_control_w)
+ AM_RANGE(0x09, 0x09) AM_WRITE(mshuttle_ay8910_data_w)
+ AM_RANGE(0x0c, 0x0c) AM_READ(mshuttle_ay8910_data_r)
+ADDRESS_MAP_END
+
+
+static WRITE8_HANDLER( tenspot_unk_6000_w )
+{
+ logerror("tenspot_unk_6000_w %02x\n",data);
+}
+
+static WRITE8_HANDLER( tenspot_unk_8000_w )
+{
+ logerror("tenspot_unk_8000_w %02x\n",data);
+}
+
+static WRITE8_HANDLER( tenspot_unk_e000_w )
+{
+ logerror("tenspot_unk_e000_w %02x\n",data);
+}
+
+static ADDRESS_MAP_START( tenspot_select_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x07ff) AM_ROM
+ AM_RANGE(0x2000, 0x23ff) AM_RAM
+ AM_RANGE(0x4000, 0x4000) AM_READ_PORT("SELECT2")
+ AM_RANGE(0x6000, 0x6000) AM_WRITE(tenspot_unk_6000_w)
+ AM_RANGE(0xc000, 0xc000) AM_READ_PORT("SELECT")
+ AM_RANGE(0x8000, 0x8000) AM_WRITE(tenspot_unk_8000_w)
+ AM_RANGE(0xa000, 0xa03f) AM_RAM
+ AM_RANGE(0xe000, 0xe000) AM_WRITE(tenspot_unk_e000_w)
+ADDRESS_MAP_END
+
+/*************************************
+ *
+ * Sound CPU memory maps
+ *
+ *************************************/
+
+/* Konami Frogger with 1 x AY-8910A */
+static ADDRESS_MAP_START( frogger_sound_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_GLOBAL_MASK(0x7fff)
+ AM_RANGE(0x0000, 0x1fff) AM_ROM
+ AM_RANGE(0x4000, 0x43ff) AM_MIRROR(0x1c00) AM_RAM
+ AM_RANGE(0x6000, 0x6fff) AM_MIRROR(0x1000) AM_WRITE(konami_sound_filter_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( frogger_sound_portmap, AS_IO, 8 )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0xff) AM_READWRITE(frogger_ay8910_r, frogger_ay8910_w)
+ADDRESS_MAP_END
+
+
+/* Konami generic with 2 x AY-8910A */
+static ADDRESS_MAP_START( konami_sound_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x2fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_MIRROR(0x6c00) AM_RAM
+ AM_RANGE(0x9000, 0x9fff) AM_MIRROR(0x6000) AM_WRITE(konami_sound_filter_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( konami_sound_portmap, AS_IO, 8 )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0xff) AM_READWRITE(konami_ay8910_r, konami_ay8910_w)
+ADDRESS_MAP_END
+
+
+/* Checkman with 1 x AY-8910A */
+static ADDRESS_MAP_START( checkman_sound_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x0fff) AM_ROM
+ AM_RANGE(0x2000, 0x23ff) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( checkman_sound_portmap, AS_IO, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x03, 0x03) AM_READ(soundlatch_r)
+ AM_RANGE(0x04, 0x05) AM_DEVWRITE("aysnd", ay8910_address_data_w)
+ AM_RANGE(0x06, 0x06) AM_DEVREAD("aysnd", ay8910_r)
+ADDRESS_MAP_END
+
+
+/* Checkman alternate with 1 x AY-8910A */
+static ADDRESS_MAP_START( checkmaj_sound_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ AM_RANGE(0x0000, 0x0fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_RAM
+ AM_RANGE(0xa000, 0xa001) AM_DEVWRITE("aysnd", ay8910_address_data_w)
+ AM_RANGE(0xa002, 0xa002) AM_DEVREAD("aysnd", ay8910_r)
+ADDRESS_MAP_END
+
+
+/* King and Balloon with DAC */
+static ADDRESS_MAP_START( kingball_sound_map, AS_PROGRAM, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0x3fff)
+ AM_RANGE(0x0000, 0x1fff) AM_ROM
+ AM_RANGE(0x0000, 0x03ff) AM_MIRROR(0x1c00) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( kingball_sound_portmap, AS_IO, 8 )
+ ADDRESS_MAP_UNMAP_HIGH
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0x00) AM_MIRROR(0xff) AM_READ(soundlatch_r) AM_DEVWRITE("dac", kingball_dac_w)
+ADDRESS_MAP_END
+
+
+/* SF-X sample player */
+static ADDRESS_MAP_START( sfx_sample_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x5fff) AM_ROM
+ AM_RANGE(0x8000, 0x83ff) AM_MIRROR(0x6c00) AM_RAM
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( sfx_sample_portmap, AS_IO, 8 )
+ ADDRESS_MAP_GLOBAL_MASK(0xff)
+ AM_RANGE(0x00, 0xff) AM_READWRITE(sfx_sample_io_r, sfx_sample_io_w)
+ADDRESS_MAP_END
+
+
+
+/*************************************
+ *
+ * Graphics layouts
+ *
+ *************************************/
+
+static const gfx_layout galaxian_charlayout =
+{
+ 8,8,
+ RGN_FRAC(1,2),
+ 2,
+ { RGN_FRAC(0,2), RGN_FRAC(1,2) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+static const gfx_layout galaxian_spritelayout =
+{
+ 16,16,
+ RGN_FRAC(1,2),
+ 2,
+ { RGN_FRAC(0,2), RGN_FRAC(1,2) },
+ { STEP8(0,1), STEP8(8*8,1) },
+ { STEP8(0,8), STEP8(16*8,8) },
+ 16*16
+};
+
+static const gfx_layout galaxian_charlayout_0x200 =
+{
+ 8,8,
+ 0x200,
+ 2,
+ { RGN_FRAC(0,2), RGN_FRAC(1,2) },
+ { STEP8(0,1) },
+ { STEP8(0,8) },
+ 8*8
+};
+
+static const gfx_layout galaxian_spritelayout_0x80 =
+{
+ 16,16,
+ 0x80,
+ 2,
+ { RGN_FRAC(0,2), RGN_FRAC(1,2) },
+ { STEP8(0,1), STEP8(8*8,1) },
+ { STEP8(0,8), STEP8(16*8,8) },
+ 16*16
+};
+
+/*************************************
+ *
+ * Graphics decoding
+ *
+ *************************************/
+
+static GFXDECODE_START(galaxian)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_charlayout, 0, 8, GALAXIAN_XSCALE,1)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_spritelayout, 0, 8, GALAXIAN_XSCALE,1)
+GFXDECODE_END
+
+static GFXDECODE_START(gmgalax)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_charlayout, 0, 16, GALAXIAN_XSCALE,1)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_spritelayout, 0, 16, GALAXIAN_XSCALE,1)
+GFXDECODE_END
+
+/* separate character and sprite ROMs */
+static GFXDECODE_START(pacmanbl)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_charlayout, 0, 8, GALAXIAN_XSCALE,1)
+ GFXDECODE_SCALE("gfx2", 0x0000, galaxian_spritelayout, 0, 8, GALAXIAN_XSCALE,1)
+GFXDECODE_END
+
+static GFXDECODE_START(tenspot)
+ GFXDECODE_SCALE("gfx1", 0x0000, galaxian_charlayout_0x200, 0, 8, GALAXIAN_XSCALE,1)
+ GFXDECODE_SCALE("gfx2", 0x0000, galaxian_spritelayout_0x80, 0, 8, GALAXIAN_XSCALE,1)
+GFXDECODE_END
+
+
+/*************************************
+ *
+ * Sound configuration
+ *
+ *************************************/
+
+static const ay8910_interface frogger_ay8910_interface =
+{
+ AY8910_DISCRETE_OUTPUT,
+ {RES_K(5.1), RES_K(5.1), RES_K(5.1)},
+ DEVCB_MEMORY_HANDLER("audiocpu", PROGRAM, soundlatch_r),
+ DEVCB_HANDLER(frogger_sound_timer_r),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const ay8910_interface konami_ay8910_interface_1 =
+{
+ AY8910_DISCRETE_OUTPUT,
+ {RES_K(5.1), RES_K(5.1), RES_K(5.1)},
+ DEVCB_MEMORY_HANDLER("audiocpu", PROGRAM, soundlatch_r),
+ DEVCB_HANDLER(konami_sound_timer_r),
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const ay8910_interface konami_ay8910_interface_2 =
+{
+ AY8910_DISCRETE_OUTPUT,
+ {RES_K(5.1), RES_K(5.1), RES_K(5.1)},
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const ay8910_interface explorer_ay8910_interface_1 =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_HANDLER(explorer_sound_latch_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const ay8910_interface explorer_ay8910_interface_2 =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_HANDLER(konami_sound_timer_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const ay8910_interface sfx_ay8910_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_MEMORY_HANDLER("audiocpu", PROGRAM, soundlatch2_w),
+ DEVCB_HANDLER(sfx_sample_control_w)
+};
+
+static const ay8910_interface scorpion_ay8910_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_DEVICE_HANDLER("digitalker", digitalker_data_w),
+ DEVCB_DEVICE_HANDLER("digitalker", scorpion_digitalker_control_w)
+};
+
+static const ay8910_interface checkmaj_ay8910_interface =
+{
+ AY8910_LEGACY_OUTPUT,
+ AY8910_DEFAULT_LOADS,
+ DEVCB_MEMORY_HANDLER("audiocpu", PROGRAM, soundlatch_r),
+ DEVCB_NULL,
+ DEVCB_NULL,
+ DEVCB_NULL
+};
+
+static const discrete_mixer_desc konami_sound_mixer_desc =
+ {DISC_MIXER_IS_OP_AMP,
+ {RES_K(5.1), RES_K(5.1), RES_K(5.1), RES_K(5.1), RES_K(5.1), RES_K(5.1)},
+ {0,0,0,0,0,0}, /* no variable resistors */
+ {0,0,0,0,0,0}, /* no node capacitors */
+ 0, RES_K(2.2),
+ 0,
+ 0, /* modelled separately */
+ 0, 1};
+
+static DISCRETE_SOUND_START( konami_sound )
+
+ DISCRETE_INPUTX_STREAM(NODE_01, 0, 1.0, 0)
+ DISCRETE_INPUTX_STREAM(NODE_02, 1, 1.0, 0)
+ DISCRETE_INPUTX_STREAM(NODE_03, 2, 1.0, 0)
+
+ DISCRETE_INPUTX_STREAM(NODE_04, 3, 1.0, 0)
+ DISCRETE_INPUTX_STREAM(NODE_05, 4, 1.0, 0)
+ DISCRETE_INPUTX_STREAM(NODE_06, 5, 1.0, 0)
+
+ DISCRETE_INPUT_DATA(NODE_11)
+ DISCRETE_INPUT_DATA(NODE_12)
+ DISCRETE_INPUT_DATA(NODE_13)
+
+ DISCRETE_INPUT_DATA(NODE_14)
+ DISCRETE_INPUT_DATA(NODE_15)
+ DISCRETE_INPUT_DATA(NODE_16)
+
+ DISCRETE_RCFILTER_SW(NODE_21, 1, NODE_01, NODE_11, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+ DISCRETE_RCFILTER_SW(NODE_22, 1, NODE_02, NODE_12, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+ DISCRETE_RCFILTER_SW(NODE_23, 1, NODE_03, NODE_13, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+
+ DISCRETE_RCFILTER_SW(NODE_24, 1, NODE_04, NODE_14, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+ DISCRETE_RCFILTER_SW(NODE_25, 1, NODE_05, NODE_15, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+ DISCRETE_RCFILTER_SW(NODE_26, 1, NODE_06, NODE_16, AY8910_INTERNAL_RESISTANCE+1000, CAP_U(0.22), CAP_U(0.047), 0, 0)
+
+ DISCRETE_MIXER6(NODE_30, 1, NODE_21, NODE_22, NODE_23, NODE_24, NODE_25, NODE_26, &konami_sound_mixer_desc)
+
+ /* FIXME the amplifier M51516L has a decay circuit */
+ /* This is handled with sound_global_enable but */
+ /* belongs here. */
+
+ /* Input impedance of a M51516L is typically 30k (datasheet) */
+ DISCRETE_CRFILTER(NODE_40,NODE_30,RES_K(30),CAP_U(0.15))
+
+ DISCRETE_OUTPUT(NODE_40, 10.0 )
+
+DISCRETE_SOUND_END
+
+
+
+/*************************************
+ *
+ * Core machine driver pieces
+ *
+ *************************************/
+
+static MACHINE_CONFIG_START( galaxian_base, galaxian_state )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", Z80, GALAXIAN_PIXEL_CLOCK/3/2)
+ MCFG_CPU_PROGRAM_MAP(galaxian_map)
+ MCFG_CPU_VBLANK_INT("screen", interrupt_gen)
+
+ MCFG_WATCHDOG_VBLANK_INIT(8)
+
+ /* video hardware */
+ MCFG_GFXDECODE(galaxian)
+ MCFG_PALETTE_LENGTH(32)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_RGB32)
+ MCFG_SCREEN_RAW_PARAMS(GALAXIAN_PIXEL_CLOCK, GALAXIAN_HTOTAL, GALAXIAN_HBEND, GALAXIAN_HBSTART, GALAXIAN_VTOTAL, GALAXIAN_VBEND, GALAXIAN_VBSTART)
+ MCFG_SCREEN_UPDATE(galaxian)
+
+ MCFG_PALETTE_INIT(galaxian)
+ MCFG_VIDEO_START(galaxian)
+
+ /* blinking frequency is determined by 555 counter with Ra=100k, Rb=10k, C=10uF */
+ MCFG_TIMER_ADD_PERIODIC("stars", galaxian_stars_blink_timer, PERIOD_OF_555_ASTABLE(100000, 10000, 0.00001))
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+MACHINE_CONFIG_END
+
+
+
+static MACHINE_CONFIG_DERIVED( konami_base, galaxian_base )
+
+ MCFG_PPI8255_ADD( "ppi8255_0", konami_ppi8255_0_intf )
+ MCFG_PPI8255_ADD( "ppi8255_1", konami_ppi8255_1_intf )
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_FRAGMENT( konami_sound_1x_ay8910 )
+
+ /* 2nd CPU to drive sound */
+ MCFG_CPU_ADD("audiocpu", Z80, KONAMI_SOUND_CLOCK/8)
+ MCFG_CPU_PROGRAM_MAP(frogger_sound_map)
+ MCFG_CPU_IO_MAP(frogger_sound_portmap)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("8910.0", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(frogger_ay8910_interface)
+ MCFG_SOUND_ROUTE_EX(0, "konami", 1.0, 0)
+ MCFG_SOUND_ROUTE_EX(1, "konami", 1.0, 1)
+ MCFG_SOUND_ROUTE_EX(2, "konami", 1.0, 2)
+
+ MCFG_SOUND_ADD("konami", DISCRETE, 0)
+ MCFG_SOUND_CONFIG_DISCRETE(konami_sound)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.75)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_FRAGMENT( konami_sound_2x_ay8910 )
+
+ /* 2nd CPU to drive sound */
+ MCFG_CPU_ADD("audiocpu", Z80, KONAMI_SOUND_CLOCK/8)
+ MCFG_CPU_PROGRAM_MAP(konami_sound_map)
+ MCFG_CPU_IO_MAP(konami_sound_portmap)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("8910.0", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(konami_ay8910_interface_1)
+ MCFG_SOUND_ROUTE_EX(0, "konami", 1.0, 0)
+ MCFG_SOUND_ROUTE_EX(1, "konami", 1.0, 1)
+ MCFG_SOUND_ROUTE_EX(2, "konami", 1.0, 2)
+
+ MCFG_SOUND_ADD("8910.1", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(konami_ay8910_interface_2)
+ MCFG_SOUND_ROUTE_EX(0, "konami", 1.0, 3)
+ MCFG_SOUND_ROUTE_EX(1, "konami", 1.0, 4)
+ MCFG_SOUND_ROUTE_EX(2, "konami", 1.0, 5)
+
+ MCFG_SOUND_ADD("konami", DISCRETE, 0)
+ MCFG_SOUND_CONFIG_DISCRETE(konami_sound)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
+MACHINE_CONFIG_END
+
+
+
+/*************************************
+ *
+ * Machine drivers
+ *
+ *************************************/
+
+static MACHINE_CONFIG_DERIVED( galaxian, galaxian_base )
+ MCFG_FRAGMENT_ADD(galaxian_audio)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( pacmanbl, galaxian )
+
+ /* separate tile/sprite ROMs */
+ MCFG_GFXDECODE(pacmanbl)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( tenspot, galaxian )
+
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_VBLANK_INT("screen", fakechange_interrupt_gen)
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("selectcpu", Z80, GALAXIAN_PIXEL_CLOCK/3/2) // ?? mhz
+ MCFG_CPU_PROGRAM_MAP(tenspot_select_map)
+ //MCFG_CPU_VBLANK_INT("screen", nmi_line_pulse)
+
+ /* separate tile/sprite ROMs */
+ MCFG_GFXDECODE(tenspot)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( zigzag, galaxian_base )
+
+ /* separate tile/sprite ROMs */
+ MCFG_GFXDECODE(pacmanbl)
+
+ /* basic machine hardware */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(galaxian_map_base) /* no discrete sound */
+
+ /* video hardware */
+ MCFG_SCREEN_MODIFY("screen")
+ MCFG_SCREEN_UPDATE(zigzag)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("aysnd", AY8910, 1789750)
+
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( gmgalax, galaxian )
+
+ /* banked video hardware */
+ MCFG_GFXDECODE(gmgalax)
+ MCFG_PALETTE_LENGTH(64)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( mooncrst, galaxian_base )
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(mooncrst_map)
+
+ MCFG_FRAGMENT_ADD(mooncrst_audio)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( jumpbug, galaxian_base )
+
+ MCFG_WATCHDOG_VBLANK_INIT(0)
+
+ /* basic machine hardware */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(jumpbug_map)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("aysnd", AY8910, 1789750)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( checkman, mooncrst )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("audiocpu", Z80, 1620000) /* 1.62 MHz */
+ MCFG_CPU_PROGRAM_MAP(checkman_sound_map)
+ MCFG_CPU_IO_MAP(checkman_sound_portmap)
+ MCFG_CPU_VBLANK_INT("screen", irq0_line_hold) /* NMIs are triggered by the main CPU */
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("aysnd", AY8910, 1789750)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( checkmaj, galaxian_base )
+
+ /* basic machine hardware */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(galaxian_map_base) /* no discrete sound */
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("audiocpu", Z80, 1620000)
+ MCFG_CPU_PROGRAM_MAP(checkmaj_sound_map)
+
+ MCFG_TIMER_ADD_SCANLINE("irq0", checkmaj_irq0_gen, "screen", 0, 8)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("aysnd", AY8910, 1620000)
+ MCFG_SOUND_CONFIG(checkmaj_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 2)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( mshuttle, galaxian_base )
+
+ /* basic machine hardware */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(mshuttle_map)
+ MCFG_CPU_IO_MAP(mshuttle_portmap)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("aysnd", AY8910, GALAXIAN_PIXEL_CLOCK/3/4)
+ MCFG_SOUND_CONFIG(cclimber_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ MCFG_SOUND_ADD("samples", SAMPLES, 0)
+ MCFG_SOUND_CONFIG(cclimber_samples_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.5)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( kingball, mooncrst )
+
+ /* basic machine hardware */
+ MCFG_CPU_ADD("audiocpu", Z80,5000000/2)
+ MCFG_CPU_PROGRAM_MAP(kingball_sound_map)
+ MCFG_CPU_IO_MAP(kingball_sound_portmap)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( frogger, konami_base )
+ MCFG_FRAGMENT_ADD(konami_sound_1x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(frogger_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( froggrmc, galaxian_base )
+ MCFG_FRAGMENT_ADD(konami_sound_1x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(mooncrst_map_base) /* no discrete sound ! */
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( froggers, konami_base )
+ MCFG_FRAGMENT_ADD(konami_sound_1x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(theend_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( frogf, konami_base )
+ MCFG_FRAGMENT_ADD(konami_sound_1x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(frogf_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( turtles, konami_base )
+ MCFG_FRAGMENT_ADD(konami_sound_2x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(turtles_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( theend, galaxian_base )
+ MCFG_FRAGMENT_ADD(konami_sound_2x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(theend_map)
+
+ MCFG_PPI8255_ADD( "ppi8255_0", theend_ppi8255_0_intf )
+ MCFG_PPI8255_ADD( "ppi8255_1", konami_ppi8255_1_intf )
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( scramble, galaxian_base )
+ MCFG_FRAGMENT_ADD(konami_sound_2x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(theend_map)
+
+ MCFG_PPI8255_ADD( "ppi8255_0", konami_ppi8255_0_intf )
+ MCFG_PPI8255_ADD( "ppi8255_1", scramble_ppi8255_1_intf )
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( explorer, konami_base )
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(theend_map)
+
+ /* 2nd CPU to drive sound */
+ MCFG_CPU_ADD("audiocpu", Z80,KONAMI_SOUND_CLOCK/8)
+ MCFG_CPU_PROGRAM_MAP(konami_sound_map)
+ MCFG_CPU_IO_MAP(konami_sound_portmap)
+
+ /* sound hardware */
+ MCFG_SOUND_ADD("8910.0", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(explorer_ay8910_interface_1)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("8910.1", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(explorer_ay8910_interface_2)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( scorpion, theend )
+
+ MCFG_PPI8255_RECONFIG( "ppi8255_0", konami_ppi8255_0_intf )
+ MCFG_PPI8255_RECONFIG( "ppi8255_1", scorpion_ppi8255_1_intf )
+
+ /* extra AY8910 with I/O ports */
+ MCFG_SOUND_ADD("8910.2", AY8910, KONAMI_SOUND_CLOCK/8)
+ MCFG_SOUND_CONFIG(scorpion_ay8910_interface)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.25)
+
+ MCFG_SOUND_ADD("digitalker", DIGITALKER, 4000000)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.16)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( sfx, galaxian_base )
+ MCFG_FRAGMENT_ADD(konami_sound_2x_ay8910)
+
+ MCFG_WATCHDOG_VBLANK_INIT(0)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(sfx_map)
+
+ /* 3rd CPU for the sample player */
+ MCFG_CPU_ADD("audio2", Z80, KONAMI_SOUND_CLOCK/8)
+ MCFG_CPU_PROGRAM_MAP(sfx_sample_map)
+ MCFG_CPU_IO_MAP(sfx_sample_portmap)
+
+ MCFG_PPI8255_ADD( "ppi8255_0", konami_ppi8255_0_intf )
+ MCFG_PPI8255_ADD( "ppi8255_1", konami_ppi8255_1_intf )
+ MCFG_PPI8255_ADD( "ppi8255_2", sfx_ppi8255_2_intf )
+
+ /* port on 2nd 8910 is used for communication */
+ MCFG_SOUND_MODIFY("8910.1")
+ MCFG_SOUND_CONFIG(sfx_ay8910_interface)
+
+ /* DAC for the sample player */
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.0)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( scobra, konami_base )
+ MCFG_FRAGMENT_ADD(konami_sound_2x_ay8910)
+
+ /* alternate memory map */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(scobra_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( anteater, scobra )
+
+ /* quiet down the sounds */
+ MCFG_SOUND_MODIFY("konami")
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.1)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( anteateruk, anteater )
+
+ /* strange memory map, maybe a kind of protection */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(anteateruk_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( anteaterg, anteater )
+
+ /* strange memory map, maybe a kind of protection */
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(anteaterg_map)
+MACHINE_CONFIG_END
+
+
+static MACHINE_CONFIG_DERIVED( moonwar, scobra )
+
+ /* device config overrides */
+ MCFG_PPI8255_RECONFIG( "ppi8255_0", moonwar_ppi8255_0_intf )
+ MCFG_PPI8255_RECONFIG( "ppi8255_1", konami_ppi8255_1_intf )
+
+ MCFG_PALETTE_INIT(moonwar) // bullets are less yellow
+MACHINE_CONFIG_END
+
+
+/*************************************
+ *
+ * Decryption helpers
+ *
+ *************************************/
+
+static void decode_mooncrst(running_machine &machine, int length, UINT8 *dest)
+{
+ UINT8 *rom = machine.region("maincpu")->base();
+ int offs;
+
+ for (offs = 0; offs < length; offs++)
+ {
+ UINT8 data = rom[offs];
+ UINT8 res = data;
+ if (BIT(data,1)) res ^= 0x40;
+ if (BIT(data,5)) res ^= 0x04;
+ if ((offs & 1) == 0) res = BITSWAP8(res,7,2,5,4,3,6,1,0);
+ dest[offs] = res;
+ }
+}
+
+
+static void decode_checkman(running_machine &machine)
+{
+ /*
+ Encryption Table
+ ----------------
+ +---+---+---+------+------+------+------+------+------+------+------+
+ |A2 |A1 |A0 |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0 |
+ +---+---+---+------+------+------+------+------+------+------+------+
+ | 0 | 0 | 0 |D7 |D6 |D5 |D4 |D3 |D2 |D1 |D0^^D6|
+ | 0 | 0 | 1 |D7 |D6 |D5 |D4 |D3 |D2 |D1^^D5|D0 |
+ | 0 | 1 | 0 |D7 |D6 |D5 |D4 |D3 |D2^^D4|D1^^D6|D0 |
+ | 0 | 1 | 1 |D7 |D6 |D5 |D4^^D2|D3 |D2 |D1 |D0^^D5|
+ | 1 | 0 | 0 |D7 |D6^^D4|D5^^D1|D4 |D3 |D2 |D1 |D0 |
+ | 1 | 0 | 1 |D7 |D6^^D0|D5^^D2|D4 |D3 |D2 |D1 |D0 |
+ | 1 | 1 | 0 |D7 |D6 |D5 |D4 |D3 |D2^^D0|D1 |D0 |
+ | 1 | 1 | 1 |D7 |D6 |D5 |D4^^D1|D3 |D2 |D1 |D0 |
+ +---+---+---+------+------+------+------+------+------+------+------+
+
+ For example if A2=1, A1=1 and A0=0 then D2 to the CPU would be an XOR of
+ D2 and D0 from the ROM's. Note that D7 and D3 are not encrypted.
+
+ Encryption PAL 16L8 on cardridge
+ +--- ---+
+ OE --| U |-- VCC
+ ROMD0 --| |-- D0
+ ROMD1 --| |-- D1
+ ROMD2 --|VER 5.2|-- D2
+ A0 --| |-- NOT USED
+ A1 --| |-- A2
+ ROMD4 --| |-- D4
+ ROMD5 --| |-- D5
+ ROMD6 --| |-- D6
+ GND --| |-- M1 (NOT USED)
+ +-------+
+ Pin layout is such that links can replace the PAL if encryption is not used.
+ */
+ static const UINT8 xortable[8][4] =
+ {
+ { 6,0,6,0 },
+ { 5,1,5,1 },
+ { 4,2,6,1 },
+ { 2,4,5,0 },
+ { 4,6,1,5 },
+ { 0,6,2,5 },
+ { 0,2,0,2 },
+ { 1,4,1,4 }
+ };
+ UINT8 *rombase = machine.region("maincpu")->base();
+ UINT32 romlength = machine.region("maincpu")->bytes();
+ UINT32 offs;
+
+ for (offs = 0; offs < romlength; offs++)
+ {
+ UINT8 data = rombase[offs];
+ UINT32 line = offs & 0x07;
+
+ data ^= (BIT(data,xortable[line][0]) << xortable[line][1]) | (BIT(data,xortable[line][2]) << xortable[line][3]);
+ rombase[offs] = data;
+ }
+}
+
+
+static void decode_dingoe(running_machine &machine)
+{
+ UINT8 *rombase = machine.region("maincpu")->base();
+ UINT32 romlength = machine.region("maincpu")->bytes();
+ UINT32 offs;
+
+ for (offs = 0; offs < romlength; offs++)
+ {
+ UINT8 data = rombase[offs];
+
+ /* XOR bit 4 with bit 2, and bit 0 with bit 5, and invert bit 1 */
+ data ^= BIT(data, 2) << 4;
+ data ^= BIT(data, 5) << 0;
+ data ^= 0x02;
+
+ /* Swap bit0 with bit4 */
+ if (offs & 0x02)
+ data = BITSWAP8(data, 7,6,5,0,3,2,1,4);
+ rombase[offs] = data;
+ }
+}
+
+
+static void decode_frogger_sound(running_machine &machine)
+{
+ UINT8 *rombase = machine.region("audiocpu")->base();
+ UINT32 offs;
+
+ /* the first ROM of the sound CPU has data lines D0 and D1 swapped */
+ for (offs = 0; offs < 0x0800; offs++)
+ rombase[offs] = BITSWAP8(rombase[offs], 7,6,5,4,3,2,0,1);
+}
+
+
+static void decode_frogger_gfx(running_machine &machine)
+{
+ UINT8 *rombase = machine.region("gfx1")->base();
+ UINT32 offs;
+
+ /* the 2nd gfx ROM has data lines D0 and D1 swapped */
+ for (offs = 0x0800; offs < 0x1000; offs++)
+ rombase[offs] = BITSWAP8(rombase[offs], 7,6,5,4,3,2,0,1);
+}
+
+
+static void decode_anteater_gfx(running_machine &machine)
+{
+ UINT32 romlength = machine.region("gfx1")->bytes();
+ UINT8 *rombase = machine.region("gfx1")->base();
+ UINT8 *scratch = auto_alloc_array(machine, UINT8, romlength);
+ UINT32 offs;
+
+ memcpy(scratch, rombase, romlength);
+ for (offs = 0; offs < romlength; offs++)
+ {
+ UINT32 srcoffs = offs & 0x9bf;
+ srcoffs |= (BIT(offs,4) ^ BIT(offs,9) ^ (BIT(offs,2) & BIT(offs,10))) << 6;
+ srcoffs |= (BIT(offs,2) ^ BIT(offs,10)) << 9;
+ srcoffs |= (BIT(offs,0) ^ BIT(offs,6) ^ 1) << 10;
+ rombase[offs] = scratch[srcoffs];
+ }
+ auto_free(machine, scratch);
+}
+
+
+static void decode_losttomb_gfx(running_machine &machine)
+{
+ UINT32 romlength = machine.region("gfx1")->bytes();
+ UINT8 *rombase = machine.region("gfx1")->base();
+ UINT8 *scratch = auto_alloc_array(machine, UINT8, romlength);
+ UINT32 offs;
+
+ memcpy(scratch, rombase, romlength);
+ for (offs = 0; offs < romlength; offs++)
+ {
+ UINT32 srcoffs = offs & 0xa7f;
+ srcoffs |= ((BIT(offs,1) & BIT(offs,8)) | ((1 ^ BIT(offs,1)) & (BIT(offs,10)))) << 7;
+ srcoffs |= (BIT(offs,7) ^ (BIT(offs,1) & (BIT(offs,7) ^ BIT(offs,10)))) << 8;
+ srcoffs |= ((BIT(offs,1) & BIT(offs,7)) | ((1 ^ BIT(offs,1)) & (BIT(offs,8)))) << 10;
+ rombase[offs] = scratch[srcoffs];
+ }
+ auto_free(machine, scratch);
+}
+
+
+static void decode_superbon(running_machine &machine)
+{
+ offs_t i;
+ UINT8 *RAM;
+
+ /* Deryption worked out by hand by Chris Hardy. */
+
+ RAM = machine.region("maincpu")->base();
+
+ for (i = 0;i < 0x1000;i++)
+ {
+ /* Code is encrypted depending on bit 7 and 9 of the address */
+ switch (i & 0x0280)
+ {
+ case 0x0000:
+ RAM[i] ^= 0x92;
+ break;
+ case 0x0080:
+ RAM[i] ^= 0x82;
+ break;
+ case 0x0200:
+ RAM[i] ^= 0x12;
+ break;
+ case 0x0280:
+ RAM[i] ^= 0x10;
+ break;
+ }
+ }
+}
+
+
+/*************************************
+ *
+ * Driver configuration
+ *
+ *************************************/
+
+static void common_init(
+ running_machine &machine,
+ galaxian_draw_bullet_func draw_bullet,
+ galaxian_draw_background_func draw_background,
+ galaxian_extend_tile_info_func extend_tile_info,
+ galaxian_extend_sprite_info_func extend_sprite_info)
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ state->m_irq_enabled = 0;
+ state->m_irq_line = INPUT_LINE_NMI;
+ state->m_frogger_adjust = FALSE;
+ state->m_sfx_tilemap = FALSE;
+ state->m_draw_bullet_ptr = (draw_bullet != NULL) ? draw_bullet : galaxian_draw_bullet;
+ state->m_draw_background_ptr = (draw_background != NULL) ? draw_background : galaxian_draw_background;
+ state->m_extend_tile_info_ptr = extend_tile_info;
+ state->m_extend_sprite_info_ptr = extend_sprite_info;
+}
+
+
+static void unmap_galaxian_sound(running_machine &machine, offs_t base)
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ space->unmap_write(base + 0x0004, base + 0x0007, 0, 0x07f8);
+ space->unmap_write(base + 0x0800, base + 0x0807, 0, 0x07f8);
+ space->unmap_write(base + 0x1800, base + 0x1800, 0, 0x07ff);
+}
+
+
+
+/*************************************
+ *
+ * Galaxian-derived games
+ *
+ *************************************/
+
+static DRIVER_INIT( galaxian )
+{
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, NULL, NULL);
+}
+
+
+static DRIVER_INIT( nolock )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* same as galaxian... */
+ DRIVER_INIT_CALL(galaxian);
+
+ /* ...but coin lockout disabled/disconnected */
+ space->unmap_write(0x6002, 0x6002, 0, 0x7f8);
+}
+
+
+static DRIVER_INIT( azurian )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* yellow bullets instead of white ones */
+ common_init(machine, scramble_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ /* coin lockout disabled */
+ space->unmap_write(0x6002, 0x6002, 0, 0x7f8);
+}
+
+
+static DRIVER_INIT( gmgalax )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, gmgalax_extend_tile_info, gmgalax_extend_sprite_info);
+
+ /* ROM is banked */
+ space->install_read_bank(0x0000, 0x3fff, "bank1");
+ memory_configure_bank(machine, "bank1", 0, 2, machine.region("maincpu")->base() + 0x10000, 0x4000);
+
+ /* callback when the game select is toggled */
+ gmgalax_game_changed(*state, *machine.m_portlist.first()->fieldlist().first(), NULL, 0, 0);
+ state_save_register_global(machine, state->m_gmgalax_selected_game);
+}
+
+
+static DRIVER_INIT( pisces )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, pisces_extend_tile_info, pisces_extend_sprite_info);
+
+ /* coin lockout replaced by graphics bank */
+ space->install_legacy_write_handler(0x6002, 0x6002, 0, 0x7f8, FUNC(galaxian_gfxbank_w));
+}
+
+
+static DRIVER_INIT( batman2 )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, batman2_extend_tile_info, upper_extend_sprite_info);
+
+ /* coin lockout replaced by graphics bank */
+ space->install_legacy_write_handler(0x6002, 0x6002, 0, 0x7f8, FUNC(galaxian_gfxbank_w));
+}
+
+
+static DRIVER_INIT( frogg )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* same as galaxian... */
+ common_init(machine, galaxian_draw_bullet, frogger_draw_background, frogger_extend_tile_info, frogger_extend_sprite_info);
+
+ /* ...but needs a full 2k of RAM */
+ space->install_ram(0x4000, 0x47ff);
+}
+
+
+
+/*************************************
+ *
+ * Moon Cresta-derived games
+ *
+ *************************************/
+
+static DRIVER_INIT( mooncrst )
+{
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+
+ /* decrypt program code */
+ decode_mooncrst(machine, 0x8000, machine.region("maincpu")->base());
+}
+
+
+static DRIVER_INIT( mooncrsu )
+{
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+}
+
+
+static DRIVER_INIT( mooncrgx )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+
+ /* LEDs and coin lockout replaced by graphics banking */
+ space->install_legacy_write_handler(0x6000, 0x6002, 0, 0x7f8, FUNC(galaxian_gfxbank_w));
+}
+
+
+static DRIVER_INIT( moonqsr )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *decrypt = auto_alloc_array(machine, UINT8, 0x8000);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, moonqsr_extend_tile_info, moonqsr_extend_sprite_info);
+
+ /* decrypt program code */
+ decode_mooncrst(machine, 0x8000, decrypt);
+ space->set_decrypted_region(0x0000, 0x7fff, decrypt);
+}
+
+static WRITE8_HANDLER( artic_gfxbank_w )
+{
+// printf("artic_gfxbank_w %02x\n",data);
+}
+
+static DRIVER_INIT( pacmanbl )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* same as galaxian... */
+ DRIVER_INIT_CALL(galaxian);
+
+ /* ...but coin lockout disabled/disconnected */
+ space->install_legacy_write_handler(0x6002, 0x6002, 0, 0x7f8, FUNC(artic_gfxbank_w));
+}
+
+static READ8_HANDLER( tenspot_dsw_read )
+{
+ galaxian_state *state = space->machine().driver_data<galaxian_state>();
+ char tmp[64];
+ sprintf(tmp,"IN2_GAME%d", state->m_tenspot_current_game);
+ return input_port_read_safe(space->machine(), tmp, 0x00);
+}
+
+
+void tenspot_set_game_bank(running_machine& machine, int bank, int from_game)
+{
+ char tmp[64];
+ UINT8* srcregion;
+ UINT8* dstregion;
+ UINT8* color_prom;
+ int x;
+
+ sprintf(tmp,"game_%d_cpu", bank);
+ srcregion = machine.region(tmp)->base();
+ dstregion = machine.region("maincpu")->base();
+ memcpy(dstregion, srcregion, 0x4000);
+
+ sprintf(tmp,"game_%d_temp", bank);
+ srcregion = machine.region(tmp)->base();
+ dstregion = machine.region("gfx1")->base();
+ memcpy(dstregion, srcregion, 0x2000);
+ dstregion = machine.region("gfx2")->base();
+ memcpy(dstregion, srcregion, 0x2000);
+
+ if (from_game)
+ {
+
+ for (x=0;x<0x200;x++)
+ {
+ gfx_element_mark_dirty(machine.gfx[0], x);
+ }
+
+ for (x=0;x<0x80;x++)
+ {
+ gfx_element_mark_dirty(machine.gfx[1], x);
+ }
+ }
+
+ sprintf(tmp,"game_%d_prom", bank);
+ srcregion = machine.region(tmp)->base();
+ dstregion = machine.region("proms")->base();
+ memcpy(dstregion, srcregion, 0x20);
+
+ color_prom = dstregion;
+ PALETTE_INIT_CALL(galaxian);
+}
+
+static DRIVER_INIT( tenspot )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* these are needed for batman part 2 to work properly, this banking is probably a property of the artic board,
+ which tenspot appears to have copied */
+
+ /* video extensions */
+ //common_init(machine, galaxian_draw_bullet, galaxian_draw_background, batman2_extend_tile_info, upper_extend_sprite_info);
+
+ /* coin lockout replaced by graphics bank */
+ //space->install_legacy_write_handler(0x6002, 0x6002, 0, 0x7f8, FUNC(galaxian_gfxbank_w));
+
+
+ DRIVER_INIT_CALL(galaxian);
+
+ space->install_legacy_write_handler(0x6002, 0x6002, 0, 0x7f8, FUNC(artic_gfxbank_w));
+
+ state->m_tenspot_current_game = 0;
+
+ tenspot_set_game_bank(machine, state->m_tenspot_current_game, 0);
+
+ space->install_legacy_read_handler(0x7000, 0x7000, FUNC(tenspot_dsw_read));
+}
+
+
+
+static DRIVER_INIT( devilfsg )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ /* IRQ line is INT, not NMI */
+ state->m_irq_line = 0;
+}
+
+
+static DRIVER_INIT( zigzag )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, NULL, galaxian_draw_background, NULL, NULL);
+ state->m_draw_bullet_ptr = NULL;
+
+ /* make ROMs 2 & 3 swappable */
+ space->install_read_bank(0x2000, 0x2fff, "bank1");
+ space->install_read_bank(0x3000, 0x3fff, "bank2");
+ memory_configure_bank(machine, "bank1", 0, 2, machine.region("maincpu")->base() + 0x2000, 0x1000);
+ memory_configure_bank(machine, "bank2", 0, 2, machine.region("maincpu")->base() + 0x2000, 0x1000);
+
+ /* also re-install the fixed ROM area as a bank in order to inform the memory system that
+ the fixed area only extends to 0x1fff */
+ space->install_read_bank(0x0000, 0x1fff, "bank3");
+ memory_set_bankptr(machine, "bank3", machine.region("maincpu")->base() + 0x0000);
+
+ /* handler for doing the swaps */
+ space->install_legacy_write_handler(0x7002, 0x7002, 0, 0x07f8, FUNC(zigzag_bankswap_w));
+ zigzag_bankswap_w(space, 0, 0);
+
+ /* coin lockout disabled */
+ space->unmap_write(0x6002, 0x6002, 0, 0x7f8);
+
+ /* remove the galaxian sound hardware */
+ unmap_galaxian_sound(machine, 0x6000);
+
+ /* install our AY-8910 handler */
+ space->install_legacy_write_handler(0x4800, 0x4fff, FUNC(zigzag_ay8910_w));
+}
+
+
+static DRIVER_INIT( jumpbug )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, jumpbug_draw_background, jumpbug_extend_tile_info, jumpbug_extend_sprite_info);
+}
+
+
+static DRIVER_INIT( checkman )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ address_space *iospace = machine.device("maincpu")->memory().space(AS_IO);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+
+ /* move the interrupt enable from $b000 to $b001 */
+ space->unmap_write(0xb000, 0xb000, 0, 0x7f8);
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(irq_enable_w));
+
+ /* attach the sound command handler */
+ iospace->install_legacy_write_handler(0x00, 0x00, 0, 0xffff, FUNC(checkman_sound_command_w));
+
+ /* decrypt program code */
+ decode_checkman(machine);
+}
+
+
+static DRIVER_INIT( checkmaj )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ /* attach the sound command handler */
+ space->install_legacy_write_handler(0x7800, 0x7800, 0, 0x7ff, FUNC(checkman_sound_command_w));
+
+ /* for the title screen */
+ space->install_legacy_read_handler(0x3800, 0x3800, FUNC(checkmaj_protection_r));
+}
+
+
+static DRIVER_INIT( dingo )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ /* attach the sound command handler */
+ space->install_legacy_write_handler(0x7800, 0x7800, 0, 0x7ff, FUNC(checkman_sound_command_w));
+
+ space->install_legacy_read_handler(0x3000, 0x3000, FUNC(dingo_3000_r));
+ space->install_legacy_read_handler(0x3035, 0x3035, FUNC(dingo_3035_r));
+}
+
+
+static DRIVER_INIT( dingoe )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ address_space *iospace = machine.device("maincpu")->memory().space(AS_IO);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+
+ /* move the interrupt enable from $b000 to $b001 */
+ space->unmap_write(0xb000, 0xb000, 0, 0x7f8);
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(irq_enable_w));
+
+ /* attach the sound command handler */
+ iospace->install_legacy_write_handler(0x00, 0x00, 0, 0xffff, FUNC(checkman_sound_command_w));
+
+ space->install_legacy_read_handler(0x3001, 0x3001, FUNC(dingoe_3001_r)); /* Protection check */
+
+ /* decrypt program code */
+ decode_dingoe(machine);
+}
+
+
+static DRIVER_INIT( skybase )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, pisces_extend_tile_info, pisces_extend_sprite_info);
+
+ /* coin lockout replaced by graphics bank */
+ space->install_legacy_write_handler(0xa002, 0xa002, 0, 0x7f8, FUNC(galaxian_gfxbank_w));
+
+ /* needs a full 2k of RAM */
+ space->install_ram(0x8000, 0x87ff);
+
+ /* extend ROM */
+ space->install_rom(0x0000, 0x5fff, machine.region("maincpu")->base());
+}
+
+
+static void mshuttle_decode(running_machine &machine, const UINT8 convtable[8][16])
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ UINT8 *rom = machine.region("maincpu")->base();
+ UINT8 *decrypt = auto_alloc_array(machine, UINT8, 0x10000);
+ int A;
+
+ space->set_decrypted_region(0x0000, 0xffff, decrypt);
+
+ for (A = 0x0000;A < 0x10000;A++)
+ {
+ int i,j;
+ UINT8 src = rom[A];
+
+ /* pick the translation table from bit 0 of the address */
+ /* and from bits 1 7 of the source data */
+ i = (A & 1) | (src & 0x02) | ((src & 0x80) >> 5);
+
+ /* pick the offset in the table from bits 0 2 4 6 of the source data */
+ j = (src & 0x01) | ((src & 0x04) >> 1) | ((src & 0x10) >> 2) | ((src & 0x40) >> 3);
+
+ /* decode the opcodes */
+ decrypt[A] = (src & 0xaa) | convtable[i][j];
+ }
+}
+
+
+static DRIVER_INIT( mshuttle )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ static const UINT8 convtable[8][16] =
+ {
+ /* -1 marks spots which are unused and therefore unknown */
+ { 0x40,0x41,0x44,0x15,0x05,0x51,0x54,0x55,0x50,0x00,0x01,0x04, -1,0x10,0x11,0x14 },
+ { 0x45,0x51,0x55,0x44,0x40,0x11,0x05,0x41,0x10,0x14,0x54,0x50,0x15,0x04,0x00,0x01 },
+ { 0x11,0x14,0x10,0x00,0x44,0x05, -1,0x04,0x45,0x15,0x55,0x50, -1,0x01,0x54,0x51 },
+ { 0x14,0x01,0x11,0x10,0x50,0x15,0x00,0x40,0x04,0x51,0x45,0x05,0x55,0x54, -1,0x44 },
+ { 0x04,0x10, -1,0x40,0x15,0x41,0x50,0x50,0x11, -1,0x14,0x00,0x51,0x45,0x55,0x01 },
+ { 0x44,0x45,0x00,0x51, -1, -1,0x15,0x11,0x01,0x10,0x04,0x55,0x05,0x40,0x50,0x41 },
+ { 0x51,0x00,0x01,0x05,0x04,0x55,0x54,0x50,0x41, -1,0x11,0x15,0x14,0x10,0x44,0x40 },
+ { 0x05,0x04,0x51,0x01, -1, -1,0x55, -1,0x00,0x50,0x15,0x14,0x44,0x41,0x40,0x54 },
+ };
+
+ /* video extensions */
+ common_init(machine, mshuttle_draw_bullet, galaxian_draw_background, mshuttle_extend_tile_info, mshuttle_extend_sprite_info);
+
+ /* IRQ line is INT, not NMI */
+ state->m_irq_line = 0;
+
+ /* decrypt the code */
+ mshuttle_decode(machine, convtable);
+}
+
+
+static DRIVER_INIT( mshuttlj )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ static const UINT8 convtable[8][16] =
+ {
+ { 0x41,0x54,0x51,0x14,0x05,0x10,0x01,0x55,0x44,0x11,0x00,0x50,0x15,0x40,0x04,0x45 },
+ { 0x50,0x11,0x40,0x55,0x51,0x14,0x45,0x04,0x54,0x15,0x10,0x05,0x44,0x01,0x00,0x41 },
+ { 0x44,0x11,0x00,0x50,0x41,0x54,0x04,0x14,0x15,0x40,0x51,0x55,0x05,0x10,0x01,0x45 },
+ { 0x10,0x50,0x54,0x55,0x01,0x44,0x40,0x04,0x14,0x11,0x00,0x41,0x45,0x15,0x51,0x05 },
+ { 0x14,0x41,0x01,0x44,0x04,0x50,0x51,0x45,0x11,0x40,0x54,0x15,0x10,0x00,0x55,0x05 },
+ { 0x01,0x05,0x41,0x45,0x54,0x50,0x55,0x10,0x11,0x15,0x51,0x14,0x44,0x40,0x04,0x00 },
+ { 0x05,0x55,0x00,0x50,0x11,0x40,0x54,0x14,0x45,0x51,0x10,0x04,0x44,0x01,0x41,0x15 },
+ { 0x55,0x50,0x15,0x10,0x01,0x04,0x41,0x44,0x45,0x40,0x05,0x00,0x11,0x14,0x51,0x54 },
+ };
+
+ /* video extensions */
+ common_init(machine, mshuttle_draw_bullet, galaxian_draw_background, mshuttle_extend_tile_info, mshuttle_extend_sprite_info);
+
+ /* IRQ line is INT, not NMI */
+ state->m_irq_line = 0;
+
+ /* decrypt the code */
+ mshuttle_decode(machine, convtable);
+}
+
+
+static DRIVER_INIT( kingball )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ space->install_legacy_write_handler(0xb000, 0xb000, 0, 0x7f8, FUNC(kingball_sound1_w));
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(irq_enable_w));
+ space->install_legacy_write_handler(0xb002, 0xb002, 0, 0x7f8, FUNC(kingball_sound2_w));
+ space->install_legacy_write_handler(0xb003, 0xb003, 0, 0x7f8, FUNC(kingball_speech_dip_w));
+
+ state_save_register_global(machine, state->m_kingball_speech_dip);
+ state_save_register_global(machine, state->m_kingball_sound);
+}
+
+
+static DRIVER_INIT( scorpnmc )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, batman2_extend_tile_info, upper_extend_sprite_info);
+
+ /* move the interrupt enable from $b000 to $b001 */
+ space->unmap_write(0xb000, 0xb000, 0, 0x7f8);
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(irq_enable_w));
+
+ /* extra ROM */
+ space->install_rom(0x5000, 0x67ff, machine.region("maincpu")->base() + 0x5000);
+
+ /* install RAM at $4000-$4800 */
+ space->install_ram(0x4000, 0x47ff);
+
+ /* doesn't appear to use original RAM */
+ space->unmap_readwrite(0x8000, 0x87ff);
+}
+
+static DRIVER_INIT( thepitm )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, galaxian_draw_bullet, galaxian_draw_background, mooncrst_extend_tile_info, mooncrst_extend_sprite_info);
+
+ /* move the interrupt enable from $b000 to $b001 */
+ space->unmap_write(0xb000, 0xb000, 0, 0x7f8);
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(irq_enable_w));
+
+ /* disable the stars */
+ space->unmap_write(0xb004, 0xb004, 0, 0x07f8);
+
+ /* extend ROM */
+ space->install_rom(0x0000, 0x47ff, machine.region("maincpu")->base());
+}
+
+/*************************************
+ *
+ * Konami games
+ *
+ *************************************/
+
+static DRIVER_INIT( theend )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, theend_draw_bullet, galaxian_draw_background, NULL, NULL);
+
+ /* coin counter on the upper bit of port C */
+ space->unmap_write(0x6802, 0x6802, 0, 0x7f8);
+}
+
+
+static DRIVER_INIT( scramble )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+}
+
+
+static DRIVER_INIT( explorer )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+
+ /* watchdog works for writes as well? (or is it just disabled?) */
+ space->install_legacy_write_handler(0x7000, 0x7000, 0, 0x7ff, FUNC(watchdog_reset_w));
+
+ /* I/O appears to be direct, not via PPIs */
+ space->unmap_readwrite(0x8000, 0xffff);
+ space->install_read_port(0x8000, 0x8000, 0, 0xffc, "IN0");
+ space->install_read_port(0x8001, 0x8001, 0, 0xffc, "IN1");
+ space->install_read_port(0x8002, 0x8002, 0, 0xffc, "IN2");
+ space->install_read_port(0x8003, 0x8003, 0, 0xffc, "IN3");
+ space->install_legacy_write_handler(0x8000, 0x8000, 0, 0xfff, FUNC(soundlatch_w));
+ space->install_legacy_write_handler(0x9000, 0x9000, 0, 0xfff, FUNC(explorer_sound_control_w));
+}
+
+
+static DRIVER_INIT( sfx )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ /* basic configuration */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, upper_extend_tile_info, NULL);
+ state->m_sfx_tilemap = TRUE;
+
+ /* sound board has space for extra ROM */
+ machine.device("audiocpu")->memory().space(AS_PROGRAM)->install_read_bank(0x0000, 0x3fff, "bank1");
+ memory_set_bankptr(machine, "bank1", machine.region("audiocpu")->base());
+}
+
+
+static DRIVER_INIT( atlantis )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+
+ /* watchdog is at $7800? (or is it just disabled?) */
+ space->unmap_read(0x7000, 0x7000, 0, 0x7ff);
+ space->install_legacy_read_handler(0x7800, 0x7800, 0, 0x7ff, FUNC(watchdog_reset_r));
+}
+
+
+static DRIVER_INIT( scobra )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+}
+
+
+static DRIVER_INIT( losttomb )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+
+ /* decrypt */
+ decode_losttomb_gfx(machine);
+}
+
+
+static DRIVER_INIT( frogger )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ /* video extensions */
+ common_init(machine, NULL, frogger_draw_background, frogger_extend_tile_info, frogger_extend_sprite_info);
+ state->m_frogger_adjust = TRUE;
+
+ /* decrypt */
+ decode_frogger_sound(machine);
+ decode_frogger_gfx(machine);
+}
+
+
+static DRIVER_INIT( froggrmc )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ /* video extensions */
+ common_init(machine, NULL, frogger_draw_background, frogger_extend_tile_info, frogger_extend_sprite_info);
+
+ space->install_legacy_write_handler(0xa800, 0xa800, 0, 0x7ff, FUNC(soundlatch_w));
+ space->install_legacy_write_handler(0xb001, 0xb001, 0, 0x7f8, FUNC(froggrmc_sound_control_w));
+
+ /* actually needs 2k of RAM */
+ space->install_ram(0x8000, 0x87ff);
+
+ /* decrypt */
+ decode_frogger_sound(machine);
+}
+
+
+static DRIVER_INIT( froggers )
+{
+ /* video extensions */
+ common_init(machine, NULL, frogger_draw_background, frogger_extend_tile_info, frogger_extend_sprite_info);
+
+ /* decrypt */
+ decode_frogger_sound(machine);
+}
+
+
+static DRIVER_INIT( turtles )
+{
+ /* video extensions */
+ common_init(machine, NULL, turtles_draw_background, NULL, NULL);
+}
+
+
+#ifdef UNUSED_FUNCTION
+static DRIVER_INIT( amidar )
+{
+ /* no existing amidar sets run on Amidar hardware as described by Amidar schematics! */
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, amidar_draw_background, NULL, NULL);
+}
+#endif
+
+
+static DRIVER_INIT( scorpion )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, batman2_extend_tile_info, upper_extend_sprite_info);
+
+ /* hook up AY8910 */
+ machine.device("audiocpu")->memory().space(AS_IO)->install_legacy_readwrite_handler(0x00, 0xff, FUNC(scorpion_ay8910_r), FUNC(scorpion_ay8910_w));
+
+ /* extra ROM */
+ space->install_read_bank(0x5800, 0x67ff, "bank1");
+ memory_set_bankptr(machine, "bank1", machine.region("maincpu")->base() + 0x5800);
+
+ /* no background related */
+// space->nop_write(0x6803, 0x6803);
+
+ machine.device("audiocpu")->memory().space(AS_PROGRAM)->install_legacy_read_handler(0x3000, 0x3000, FUNC(scorpion_digitalker_intr_r));
+/*
+{
+ const UINT8 *rom = machine.region("speech")->base();
+ int i;
+
+ for (i = 0; i < 0x2c; i++)
+ {
+ UINT16 addr = (rom[2*i] << 8) | rom[2*i+1];
+ UINT16 endaddr = (rom[2*i+2] << 8) | rom[2*i+3];
+ int j;
+ printf("Cmd %02X -> %04X-%04X:", i, addr, endaddr - 1);
+ for (j = 0; j < 32 && addr < endaddr; j++)
+ printf(" %02X", rom[addr++]);
+ printf("\n");
+ }
+}
+*/
+}
+
+
+static DRIVER_INIT( anteater )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, anteater_draw_background, NULL, NULL);
+
+ /* decode graphics */
+ decode_anteater_gfx(machine);
+}
+
+
+static DRIVER_INIT( anteateruk )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, anteater_draw_background, NULL, NULL);
+}
+
+
+static DRIVER_INIT( superbon )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+
+ /* decode code */
+ decode_superbon(machine);
+}
+
+
+static DRIVER_INIT( calipso )
+{
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, calipso_extend_sprite_info);
+}
+
+
+static DRIVER_INIT( moonwar )
+{
+ galaxian_state *state = machine.driver_data<galaxian_state>();
+ /* video extensions */
+ common_init(machine, scramble_draw_bullet, scramble_draw_background, NULL, NULL);
+
+ state_save_register_global(machine, state->m_moonwar_port_select);
+}
+
+
+
+#include "galdrvr.c"