summaryrefslogtreecommitdiffstatshomepage
path: root/trunk/src/mame/drivers/multigam.c
diff options
context:
space:
mode:
Diffstat (limited to 'trunk/src/mame/drivers/multigam.c')
-rw-r--r--trunk/src/mame/drivers/multigam.c1421
1 files changed, 1421 insertions, 0 deletions
diff --git a/trunk/src/mame/drivers/multigam.c b/trunk/src/mame/drivers/multigam.c
new file mode 100644
index 00000000000..1995b3ff4b5
--- /dev/null
+++ b/trunk/src/mame/drivers/multigam.c
@@ -0,0 +1,1421 @@
+/*
+ Multi Game
+
+ driver by Mariusz Wojcieszek
+ uses NES emulation by Brad Olivier
+
+ Hardware is based around Nintendo NES. After coin up, it allows to play one of
+ 35 NES games (choosen from text menu). Manufacturer is unknown, code for title
+ screen and game selection contains string:
+ "Programed by SANG HO ENG. K. B. KIM 1986/1/ 1"
+
+ Notes:
+ - rom at 0x6000-0x7fff contains control program, which handles coins and timer
+ - each game rom has NMI (VBLANK) vector changed to 0x6100 (control program). Then,
+ game NMI is called through IRQ vector
+ - there is additional RAM (0x800-0xfff) used by control program
+ - ROM banked at 0x5000-0x5ffe seems to contain patches for games. At least
+ Ninja code jumps into this area
+ - game roms are banked in 16KB units. Bank switching of game rom is handled by
+ writing to 0x6fff. If bank select has 7th bit turned on, then 32KB rom is
+ switched into $8000 - $ffff. Otherwise, 16KB rom is switched on.
+ - PPU VROMS are banked in 8KB units. Write to 0x7fff controls PPU VROM banking.
+ - some games use additional banking on PPU VROMS. This is enabled by writing
+ value with bit 7 on to 0x7fff and then selecting a vrom by writing into
+ 0x8000 - 0xffff range.
+ - there is a register at 0x5002. 0xff is written there when game is played,
+ 0x00 otherwise. Its purpose is unknown.
+
+
+ Notes by Roberto Fresca:
+
+ - Added multigame (set2).
+ - Main differences are:
+ - Control program: Offset 0x79b4 = JMP $c4c4 was changed to JMP $c4c6.
+ - ROM at 0x80000: Several things patched and/or relocated.
+ Most original NOPs were replaced by proper code.
+
+ Multi Game 2 & III: 21 games included, hardware features MMC3 NES mapper and additional
+ RAM used by Super Mario Bros 3.
+
+ Multi Game (Tung Sheng Electronics): 10 games included, selectable by dip switches.
+
+ Super Game III:
+
+PCB Layout
+----------
+
+|------------------------------------|
+|UPC1242H 3.579545MHz 6264 |
+| 4066 UPC1352 6116 ROM14|
+| ROM15|
+|J ROM16|
+|A UA6527 UA6528 ROM17|
+|M |
+|M PAL DIP40* IC36 |
+|A DIP24* ROM18|
+| 21.47727MHz ROM10|
+| ROM11|
+| PLSI1016 ROM12|
+|DIPSW(8) 6264 6264 ROM13|
+|------------------------------------|
+* - chip surface scratched
+
+ Super Game III features 15 games, updated hardware with several NES mappers allowing newer NES
+ games to run.
+*/
+
+#include "emu.h"
+#include "cpu/m6502/m6502.h"
+#include "sound/dac.h"
+#include "sound/nes_apu.h"
+#include "video/ppu2c0x.h"
+
+
+class multigam_state : public driver_device
+{
+public:
+ multigam_state(const machine_config &mconfig, device_type type, const char *tag)
+ : driver_device(mconfig, type, tag) { }
+
+ UINT8* m_nt_ram;
+ UINT8* m_vram;
+ UINT8* m_nt_page[4];
+ UINT32 m_in_0;
+ UINT32 m_in_1;
+ UINT32 m_in_0_shift;
+ UINT32 m_in_1_shift;
+ UINT32 m_in_dsw;
+ UINT32 m_in_dsw_shift;
+ int m_game_gfx_bank;
+ int m_multigam3_mmc3_scanline_counter;
+ int m_multigam3_mmc3_scanline_latch;
+ int m_multigam3_mmc3_banks[2];
+ int m_multigam3_mmc3_4screen;
+ int m_multigam3_mmc3_last_bank;
+ UINT8* m_multigmc_mmc3_6000_ram;
+ UINT8* m_multigam3_mmc3_prg_base;
+ int m_multigam3_mmc3_prg_size;
+ int m_multigam3_mmc3_chr_bank_base;
+ int m_multigam3_mmc3_command;
+ UINT8* m_mapper02_prg_base;
+ int m_mapper02_prg_size;
+ int m_mmc1_shiftreg;
+ int m_mmc1_shiftcount;
+ int m_mmc1_rom_mask;
+ UINT8* m_mmc1_prg_base;
+ int m_mmc1_prg_size;
+ int m_mmc1_chr_bank_base;
+ int m_mmc1_reg_write_enable;
+ int m_size16k;
+ int m_switchlow;
+ int m_vrom4k;
+ UINT8 m_supergm3_prg_bank;
+ UINT8 m_supergm3_chr_bank;
+};
+
+
+/******************************************************
+
+ PPU external bus interface
+
+*******************************************************/
+
+
+static void set_mirroring(multigam_state *state, int mirroring)
+{
+ switch(mirroring)
+ {
+ case PPU_MIRROR_LOW:
+ state->m_nt_page[0] = state->m_nt_page[1] = state->m_nt_page[2] = state->m_nt_page[3] = state->m_nt_ram;
+ break;
+ case PPU_MIRROR_HIGH:
+ state->m_nt_page[0] = state->m_nt_page[1] = state->m_nt_page[2] = state->m_nt_page[3] = state->m_nt_ram + 0x400;
+ break;
+ case PPU_MIRROR_HORZ:
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram;
+ state->m_nt_page[2] = state->m_nt_ram + 0x400;
+ state->m_nt_page[3] = state->m_nt_ram + 0x400;
+ break;
+ case PPU_MIRROR_VERT:
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram + 0x400;
+ state->m_nt_page[2] = state->m_nt_ram;
+ state->m_nt_page[3] = state->m_nt_ram + 0x400;
+ break;
+ case PPU_MIRROR_NONE:
+ default:
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram + 0x400;
+ state->m_nt_page[2] = state->m_nt_ram + 0x800;
+ state->m_nt_page[3] = state->m_nt_ram + 0xc00;
+ break;
+ }
+}
+
+static WRITE8_HANDLER (multigam_nt_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ int page = ((offset & 0xc00) >> 10);
+ state->m_nt_page[page][offset & 0x3ff] = data;
+}
+
+
+static READ8_HANDLER (multigam_nt_r)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ int page = ((offset & 0xc00) >> 10);
+ return state->m_nt_page[page][offset & 0x3ff];
+}
+
+static const char * const banknames[] = { "bank2", "bank3", "bank4", "bank5", "bank6", "bank7", "bank8", "bank9" };
+
+static void set_videorom_bank(running_machine& machine, int start, int count, int bank, int bank_size_in_kb)
+{
+ int i;
+ int offset = bank * (bank_size_in_kb * 0x400);
+ /* bank_size_in_kb is used to determine how large the "bank" parameter is */
+ /* count determines the size of the area mapped in KB */
+ for (i = 0; i < count; i++, offset += 0x400)
+ {
+ memory_set_bankptr(machine, banknames[i + start], machine.region("gfx1")->base() + offset);
+ }
+}
+
+static void set_videoram_bank(running_machine& machine, int start, int count, int bank, int bank_size_in_kb)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ int i;
+ int offset = bank * (bank_size_in_kb * 0x400);
+ /* bank_size_in_kb is used to determine how large the "bank" parameter is */
+ /* count determines the size of the area mapped in KB */
+ for (i = 0; i < count; i++, offset += 0x400)
+ {
+ memory_set_bankptr(machine, banknames[i + start], state->m_vram + offset);
+ }
+}
+
+/******************************************************
+
+ NES interface
+
+*******************************************************/
+
+static WRITE8_HANDLER( sprite_dma_w )
+{
+ int source = (data & 7);
+ ppu2c0x_spriteram_dma(space, space->machine().device("ppu"), source);
+}
+
+static READ8_DEVICE_HANDLER( psg_4015_r )
+{
+ return nes_psg_r(device, 0x15);
+}
+
+static WRITE8_DEVICE_HANDLER( psg_4015_w )
+{
+ nes_psg_w(device, 0x15, data);
+}
+
+static WRITE8_DEVICE_HANDLER( psg_4017_w )
+{
+ nes_psg_w(device, 0x17, data);
+}
+
+/******************************************************
+
+ Inputs
+
+*******************************************************/
+
+
+static READ8_HANDLER( multigam_IN0_r )
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ return ((state->m_in_0 >> state->m_in_0_shift++) & 0x01) | 0x40;
+}
+
+static WRITE8_HANDLER( multigam_IN0_w )
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ if (data & 0x01)
+ {
+ return;
+ }
+
+ state->m_in_0_shift = 0;
+ state->m_in_1_shift = 0;
+
+ state->m_in_0 = input_port_read(space->machine(), "P1");
+ state->m_in_1 = input_port_read(space->machine(), "P2");
+
+ state->m_in_dsw_shift = 0;
+ state->m_in_dsw = input_port_read_safe(space->machine(), "DSW", 0);
+}
+
+static READ8_HANDLER( multigam_IN1_r )
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ return ((state->m_in_1 >> state->m_in_1_shift++) & 0x01) | 0x40;
+}
+
+static CUSTOM_INPUT( multigam_inputs_r )
+{
+ multigam_state *state = field.machine().driver_data<multigam_state>();
+ /* bit 0: serial input (dsw)
+ bit 1: coin */
+ return (state->m_in_dsw >> state->m_in_dsw_shift++) & 0x01;
+}
+
+
+/******************************************************
+
+ ROM/VROM banking (Multi Game)
+
+*******************************************************/
+
+
+static WRITE8_HANDLER(multigam_switch_prg_rom)
+{
+ /* switch PRG rom */
+ UINT8* dst = space->machine().region("maincpu")->base();
+ UINT8* src = space->machine().region("user1")->base();
+
+ if (data & 0x80)
+ {
+ if (data & 0x01)
+ {
+ data &= ~0x01;
+ }
+ memcpy(&dst[0x8000], &src[(data & 0x7f) * 0x4000], 0x8000);
+ }
+ else
+ {
+ memcpy(&dst[0x8000], &src[data*0x4000], 0x4000);
+ memcpy(&dst[0xc000], &src[data*0x4000], 0x4000);
+ }
+};
+
+static WRITE8_HANDLER(multigam_switch_gfx_rom)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ memory_set_bankptr(space->machine(), "bank1", space->machine().region("gfx1")->base() + (0x2000 * (data & 0x3f)));
+ set_mirroring(state, data & 0x40 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ state->m_game_gfx_bank = data;
+};
+
+
+static WRITE8_HANDLER(multigam_mapper2_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ if (state->m_game_gfx_bank & 0x80)
+ {
+ memory_set_bankptr(space->machine(), "bank1", space->machine().region("gfx1")->base() + (0x2000 * ((data & 0x3) + (state->m_game_gfx_bank & 0x3c))));
+ }
+ else
+ {
+ logerror("Unmapped multigam_mapper2_w: offset = %04X, data = %02X\n", offset, data);
+ }
+}
+
+/******************************************************
+
+ Memory map (Multi Game)
+
+*******************************************************/
+
+static ADDRESS_MAP_START( multigam_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM /* NES RAM */
+ AM_RANGE(0x0800, 0x0fff) AM_RAM /* additional RAM */
+ AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w)
+ AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nes", nes_psg_r, nes_psg_w) /* PSG primary registers */
+ AM_RANGE(0x4014, 0x4014) AM_WRITE(sprite_dma_w)
+ AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nes", psg_4015_r, psg_4015_w) /* PSG status / first control register */
+ AM_RANGE(0x4016, 0x4016) AM_READWRITE(multigam_IN0_r, multigam_IN0_w) /* IN0 - input port 1 */
+ AM_RANGE(0x4017, 0x4017) AM_READ(multigam_IN1_r) AM_DEVWRITE("nes", psg_4017_w) /* IN1 - input port 2 / PSG second control register */
+ AM_RANGE(0x5002, 0x5002) AM_WRITENOP
+ AM_RANGE(0x5000, 0x5ffe) AM_ROM
+ AM_RANGE(0x5fff, 0x5fff) AM_READ_PORT("IN0")
+ AM_RANGE(0x6000, 0x7fff) AM_ROM
+ AM_RANGE(0x6fff, 0x6fff) AM_WRITE(multigam_switch_prg_rom)
+ AM_RANGE(0x7fff, 0x7fff) AM_WRITE(multigam_switch_gfx_rom)
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_WRITE(multigam_mapper2_w)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( multigmt_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM /* NES RAM */
+ AM_RANGE(0x0800, 0x0fff) AM_RAM /* additional RAM */
+ AM_RANGE(0x3000, 0x3000) AM_WRITE(multigam_switch_prg_rom)
+ AM_RANGE(0x3fff, 0x3fff) AM_WRITE(multigam_switch_gfx_rom)
+ AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w)
+ AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nes", nes_psg_r, nes_psg_w) /* PSG primary registers */
+ AM_RANGE(0x4014, 0x4014) AM_WRITE(sprite_dma_w)
+ AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nes", psg_4015_r, psg_4015_w) /* PSG status / first control register */
+ AM_RANGE(0x4016, 0x4016) AM_READWRITE(multigam_IN0_r, multigam_IN0_w) /* IN0 - input port 1 */
+ AM_RANGE(0x4017, 0x4017) AM_READ(multigam_IN1_r) AM_DEVWRITE("nes", psg_4017_w) /* IN1 - input port 2 / PSG second control register */
+ AM_RANGE(0x5002, 0x5002) AM_WRITENOP
+ AM_RANGE(0x5000, 0x5ffe) AM_ROM
+ AM_RANGE(0x5fff, 0x5fff) AM_READ_PORT("IN0")
+ AM_RANGE(0x6000, 0x7fff) AM_ROM
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_WRITE(multigam_mapper2_w)
+ADDRESS_MAP_END
+
+/******************************************************
+
+ MMC3 (Multi Game III)
+
+*******************************************************/
+
+
+static void multigam3_mmc3_scanline_cb( device_t *device, int scanline, int vblank, int blanked )
+{
+ multigam_state *state = device->machine().driver_data<multigam_state>();
+ if (!vblank && !blanked)
+ {
+ if (--state->m_multigam3_mmc3_scanline_counter == -1)
+ {
+ state->m_multigam3_mmc3_scanline_counter = state->m_multigam3_mmc3_scanline_latch;
+ generic_pulse_irq_line(device->machine().device("maincpu"), 0);
+ }
+ }
+}
+
+static WRITE8_HANDLER( multigam3_mmc3_rom_switch_w )
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ device_t *ppu = space->machine().device("ppu");
+
+ /* basically, a MMC3 mapper from the nes */
+ int bankmask = state->m_multigam3_mmc3_prg_size == 0x40000 ? 0x1f : 0x0f;
+
+ switch(offset & 0x7001)
+ {
+ case 0x0000:
+ state->m_multigam3_mmc3_command = data;
+
+ if (state->m_multigam3_mmc3_last_bank != (data & 0xc0))
+ {
+ int bank;
+ UINT8 *prg = space->machine().region("maincpu")->base();
+
+ /* reset the banks */
+ if (state->m_multigam3_mmc3_command & 0x40)
+ {
+ /* high bank */
+ bank = (state->m_multigam3_mmc3_banks[0] & bankmask) * 0x2000;
+
+ memcpy(&prg[0x0c000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+ memcpy(&prg[0x08000], &state->m_multigam3_mmc3_prg_base[state->m_multigam3_mmc3_prg_size - 0x4000], 0x2000);
+ }
+ else
+ {
+ /* low bank */
+ bank = (state->m_multigam3_mmc3_banks[0] & bankmask) * 0x2000;
+
+ memcpy(&prg[0x08000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+ memcpy(&prg[0x0c000], &state->m_multigam3_mmc3_prg_base[state->m_multigam3_mmc3_prg_size - 0x4000], 0x2000);
+ }
+
+ /* mid bank */
+ bank = (state->m_multigam3_mmc3_banks[1] & bankmask) * 0x2000;
+ memcpy(&prg[0x0a000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+
+ state->m_multigam3_mmc3_last_bank = data & 0xc0;
+ }
+ break;
+
+ case 0x0001:
+ {
+ UINT8 cmd = state->m_multigam3_mmc3_command & 0x07;
+ int page = (state->m_multigam3_mmc3_command & 0x80) >> 5;
+ int bank;
+
+ switch (cmd)
+ {
+ case 0: /* char banking */
+ case 1: /* char banking */
+ data &= 0xfe;
+ page ^= (cmd << 1);
+ set_videorom_bank(space->machine(), page, 2, state->m_multigam3_mmc3_chr_bank_base + data, 1);
+ break;
+
+ case 2: /* char banking */
+ case 3: /* char banking */
+ case 4: /* char banking */
+ case 5: /* char banking */
+ page ^= cmd + 2;
+ set_videorom_bank(space->machine(), page, 1, state->m_multigam3_mmc3_chr_bank_base + data, 1);
+ break;
+
+ case 6: /* program banking */
+ {
+ UINT8 *prg = space->machine().region("maincpu")->base();
+ if (state->m_multigam3_mmc3_command & 0x40)
+ {
+ /* high bank */
+ state->m_multigam3_mmc3_banks[0] = data & bankmask;
+ bank = (state->m_multigam3_mmc3_banks[0]) * 0x2000;
+
+ memcpy(&prg[0x0c000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+ memcpy(&prg[0x08000], &state->m_multigam3_mmc3_prg_base[state->m_multigam3_mmc3_prg_size - 0x4000], 0x2000);
+ }
+ else
+ {
+ /* low bank */
+ state->m_multigam3_mmc3_banks[0] = data & bankmask;
+ bank = (state->m_multigam3_mmc3_banks[0]) * 0x2000;
+
+ memcpy(&prg[0x08000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+ memcpy(&prg[0x0c000], &state->m_multigam3_mmc3_prg_base[state->m_multigam3_mmc3_prg_size - 0x4000], 0x2000);
+ }
+ }
+ break;
+
+ case 7: /* program banking */
+ {
+ /* mid bank */
+ UINT8 *prg = space->machine().region("maincpu")->base();
+
+ state->m_multigam3_mmc3_banks[1] = data & bankmask;
+ bank = state->m_multigam3_mmc3_banks[1] * 0x2000;
+
+ memcpy(&prg[0x0a000], &state->m_multigam3_mmc3_prg_base[bank], 0x2000);
+ }
+ break;
+ }
+ }
+ break;
+
+ case 0x2000: /* mirroring */
+ if (!state->m_multigam3_mmc3_4screen)
+ {
+ if (data & 0x40)
+ set_mirroring(state, PPU_MIRROR_HIGH);
+ else
+ set_mirroring(state, (data & 1) ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ }
+ break;
+
+ case 0x2001: /* enable ram at $6000 */
+ if (data & 0x80)
+ {
+ memory_set_bankptr(space->machine(), "bank10", state->m_multigmc_mmc3_6000_ram);
+ }
+ else
+ {
+ memory_set_bankptr(space->machine(), "bank10", space->machine().region("maincpu")->base() + 0x6000);
+ }
+ if (data & 0x40)
+ {
+ logerror("Write protect for 6000 enabled\n");
+ }
+ break;
+
+ case 0x4000: /* scanline counter */
+ state->m_multigam3_mmc3_scanline_counter = data;
+ break;
+
+ case 0x4001: /* scanline latch */
+ state->m_multigam3_mmc3_scanline_latch = data;
+ break;
+
+ case 0x6000: /* disable irqs */
+ ppu2c0x_set_scanline_callback(ppu, 0);
+ break;
+
+ case 0x6001: /* enable irqs */
+ ppu2c0x_set_scanline_callback(ppu, multigam3_mmc3_scanline_cb);
+ break;
+ }
+}
+
+static void multigam_init_mmc3(running_machine &machine, UINT8 *prg_base, int prg_size, int chr_bank_base)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ UINT8* dst = machine.region("maincpu")->base();
+
+ // Tom & Jerry in Super Game III enables 6000 ram, but does not read/write it
+ // however, it expects ROM from 6000 there (code jumps to $6xxx)
+ memcpy(state->m_multigmc_mmc3_6000_ram, dst + 0x6000, 0x2000);
+
+ memcpy(&dst[0x8000], prg_base + (prg_size - 0x4000), 0x4000);
+ memcpy(&dst[0xc000], prg_base + (prg_size - 0x4000), 0x4000);
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0xffff, FUNC(multigam3_mmc3_rom_switch_w) );
+
+ state->m_multigam3_mmc3_banks[0] = 0x1e;
+ state->m_multigam3_mmc3_banks[1] = 0x1f;
+ state->m_multigam3_mmc3_scanline_counter = 0;
+ state->m_multigam3_mmc3_scanline_latch = 0;
+ state->m_multigam3_mmc3_4screen = 0;
+ state->m_multigam3_mmc3_last_bank = 0xff;
+ state->m_multigam3_mmc3_prg_base = prg_base;
+ state->m_multigam3_mmc3_chr_bank_base = chr_bank_base;
+ state->m_multigam3_mmc3_prg_size = prg_size;
+};
+
+static WRITE8_HANDLER(multigm3_mapper2_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ if (state->m_game_gfx_bank & 0x80)
+ {
+ set_videorom_bank(space->machine(), 0, 8, (state->m_game_gfx_bank & 0x3c) + (data & 0x3), 8);
+ }
+ else
+ {
+ logerror("Unmapped multigam_mapper2_w: offset = %04X, data = %02X\n", offset, data);
+ }
+};
+
+static WRITE8_HANDLER(multigm3_switch_gfx_rom)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ set_videorom_bank(space->machine(), 0, 8, data & 0x3f, 8);
+ set_mirroring(state, data & 0x40 ? PPU_MIRROR_HORZ : PPU_MIRROR_VERT);
+ state->m_game_gfx_bank = data;
+};
+
+static WRITE8_HANDLER(multigm3_switch_prg_rom)
+{
+ /* switch PRG rom */
+ UINT8* dst = space->machine().region("maincpu")->base();
+ UINT8* src = space->machine().region("user1")->base();
+
+ if (data == 0xa8)
+ {
+ multigam_init_mmc3(space->machine(), src + 0xa0000, 0x40000, 0x180);
+ return;
+ }
+ else
+ {
+ space->install_legacy_write_handler(0x8000, 0xffff, FUNC(multigm3_mapper2_w) );
+ memory_set_bankptr(space->machine(), "bank10", space->machine().region("maincpu")->base() + 0x6000);
+ }
+
+ if (data & 0x80)
+ {
+ if (data & 0x01)
+ {
+ data &= ~0x01;
+ }
+ memcpy(&dst[0x8000], &src[(data & 0x7f) * 0x4000], 0x8000);
+ }
+ else
+ {
+ memcpy(&dst[0x8000], &src[data*0x4000], 0x4000);
+ memcpy(&dst[0xc000], &src[data*0x4000], 0x4000);
+ }
+};
+
+/******************************************************
+
+ Memory map (Multi Game III)
+
+*******************************************************/
+
+static ADDRESS_MAP_START( multigm3_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM /* NES RAM */
+ AM_RANGE(0x0800, 0x0fff) AM_RAM /* additional RAM */
+ AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w)
+ AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nes", nes_psg_r, nes_psg_w) /* PSG primary registers */
+ AM_RANGE(0x4014, 0x4014) AM_WRITE(sprite_dma_w)
+ AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nes", psg_4015_r, psg_4015_w) /* PSG status / first control register */
+ AM_RANGE(0x4016, 0x4016) AM_READWRITE(multigam_IN0_r, multigam_IN0_w) /* IN0 - input port 1 */
+ AM_RANGE(0x4017, 0x4017) AM_READ(multigam_IN1_r) AM_DEVWRITE("nes", psg_4017_w) /* IN1 - input port 2 / PSG second control register */
+ AM_RANGE(0x5001, 0x5001) AM_WRITE(multigm3_switch_prg_rom)
+ AM_RANGE(0x5002, 0x5002) AM_WRITENOP
+ AM_RANGE(0x5003, 0x5003) AM_WRITE(multigm3_switch_gfx_rom)
+ AM_RANGE(0x5000, 0x5ffe) AM_ROM
+ AM_RANGE(0x5fff, 0x5fff) AM_READ_PORT("IN0")
+ AM_RANGE(0x6000, 0x7fff) AM_RAMBANK("bank10")
+ AM_RANGE(0x6fff, 0x6fff) AM_WRITENOP /* 0x00 in attract mode, 0xff during play */
+ AM_RANGE(0x8000, 0xffff) AM_ROM AM_WRITE(multigm3_mapper2_w)
+ADDRESS_MAP_END
+
+/******************************************************
+
+ Mapper 02
+
+*******************************************************/
+
+
+static WRITE8_HANDLER(multigam3_mapper02_rom_switch_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ UINT8* mem = space->machine().region("maincpu")->base();
+ int bankmask = (state->m_mapper02_prg_size/0x4000) - 1;
+ memcpy(mem + 0x8000, state->m_mapper02_prg_base + 0x4000*(data & bankmask), 0x4000);
+}
+
+static void multigam_init_mapper02(running_machine &machine, UINT8* prg_base, int prg_size)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ UINT8* mem = machine.region("maincpu")->base();
+ memcpy(mem + 0x8000, prg_base + prg_size - 0x8000, 0x8000);
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0xffff, FUNC(multigam3_mapper02_rom_switch_w) );
+
+ state->m_mapper02_prg_base = prg_base;
+ state->m_mapper02_prg_size = prg_size;
+
+ ppu2c0x_set_scanline_callback(machine.device("ppu"), 0);
+}
+
+/******************************************************
+
+ MMC1 mapper
+
+*******************************************************/
+
+
+static TIMER_CALLBACK( mmc1_resync_callback )
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ state->m_mmc1_reg_write_enable = 1;
+}
+
+static WRITE8_HANDLER( mmc1_rom_switch_w )
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ /* basically, a MMC1 mapper from the nes */
+
+ if ( state->m_mmc1_reg_write_enable == 0 )
+ {
+ return;
+ }
+ else
+ {
+ state->m_mmc1_reg_write_enable = 0;
+ space->machine().scheduler().synchronize(FUNC(mmc1_resync_callback));
+ }
+
+ int reg = (offset >> 13);
+
+ /* reset mapper */
+ if (data & 0x80)
+ {
+ state->m_mmc1_shiftreg = state->m_mmc1_shiftcount = 0;
+
+ state->m_size16k = 1;
+ state->m_switchlow = 1;
+ state->m_vrom4k = 0;
+
+ return;
+ }
+
+ /* see if we need to clock in data */
+ if (state->m_mmc1_shiftcount < 5)
+ {
+ state->m_mmc1_shiftreg >>= 1;
+ state->m_mmc1_shiftreg |= (data & 1) << 4;
+ state->m_mmc1_shiftcount++;
+ }
+
+ /* are we done shifting? */
+ if (state->m_mmc1_shiftcount == 5)
+ {
+ /* reset count */
+ state->m_mmc1_shiftcount = 0;
+
+ /* apply data to registers */
+ switch (reg)
+ {
+ case 0: /* mirroring and options */
+ {
+ int _mirroring;
+
+ state->m_vrom4k = state->m_mmc1_shiftreg & 0x10;
+ state->m_size16k = state->m_mmc1_shiftreg & 0x08;
+ state->m_switchlow = state->m_mmc1_shiftreg & 0x04;
+
+ switch (state->m_mmc1_shiftreg & 3)
+ {
+ case 0:
+ _mirroring = PPU_MIRROR_LOW;
+ break;
+
+ case 1:
+ _mirroring = PPU_MIRROR_HIGH;
+ break;
+
+ case 2:
+ _mirroring = PPU_MIRROR_VERT;
+ break;
+
+ default:
+ case 3:
+ _mirroring = PPU_MIRROR_HORZ;
+ break;
+ }
+
+ /* apply mirroring */
+ set_mirroring(state, _mirroring);
+ }
+ break;
+
+ case 1: /* video rom banking - bank 0 - 4k or 8k */
+ if (state->m_mmc1_chr_bank_base == 0)
+ set_videoram_bank(space->machine(), 0, (state->m_vrom4k) ? 4 : 8, (state->m_mmc1_shiftreg & 0x1f), 4);
+ else
+ set_videorom_bank(space->machine(), 0, (state->m_vrom4k) ? 4 : 8, state->m_mmc1_chr_bank_base + (state->m_mmc1_shiftreg & 0x1f), 4);
+ break;
+
+ case 2: /* video rom banking - bank 1 - 4k only */
+ if (state->m_vrom4k)
+ {
+ if (state->m_mmc1_chr_bank_base == 0)
+ set_videoram_bank(space->machine(), 0, (state->m_vrom4k) ? 4 : 8, (state->m_mmc1_shiftreg & 0x1f), 4);
+ else
+ set_videorom_bank(space->machine(), 4, 4, state->m_mmc1_chr_bank_base + (state->m_mmc1_shiftreg & 0x1f), 4);
+ }
+ break;
+
+ case 3: /* program banking */
+ {
+ int bank = (state->m_mmc1_shiftreg & state->m_mmc1_rom_mask) * 0x4000;
+ UINT8 *prg = space->machine().region("maincpu")->base();
+
+ if (!state->m_size16k)
+ {
+ bank = ((state->m_mmc1_shiftreg >> 1) & state->m_mmc1_rom_mask) * 0x4000;
+ /* switch 32k */
+ memcpy(&prg[0x08000], state->m_mmc1_prg_base + bank, 0x8000);
+ }
+ else
+ {
+ /* switch 16k */
+ if (state->m_switchlow)
+ {
+ /* low */
+ memcpy(&prg[0x08000], state->m_mmc1_prg_base + bank, 0x4000);
+ memcpy(&prg[0x0c000], state->m_mmc1_prg_base + (0x0f & state->m_mmc1_rom_mask) * 0x4000, 0x4000);
+ }
+ else
+ {
+ /* high */
+ memcpy(&prg[0x08000], state->m_mmc1_prg_base + (0x00 & state->m_mmc1_rom_mask) * 0x4000, 0x4000);
+ memcpy(&prg[0x0c000], state->m_mmc1_prg_base + bank, 0x4000);
+ }
+ }
+ }
+ break;
+ }
+ }
+}
+
+static void multigam_init_mmc1(running_machine &machine, UINT8 *prg_base, int prg_size, int chr_bank_base)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ UINT8* dst = machine.region("maincpu")->base();
+
+ memcpy(&dst[0x8000], prg_base + (prg_size - 0x8000), 0x8000);
+
+ machine.device("maincpu")->memory().space(AS_PROGRAM)->install_legacy_write_handler(0x8000, 0xffff, FUNC(mmc1_rom_switch_w) );
+
+ state->m_mmc1_reg_write_enable = 1;
+ state->m_mmc1_rom_mask = (prg_size / 0x4000) - 1;
+ state->m_mmc1_prg_base = prg_base;
+ state->m_mmc1_prg_size = prg_size;
+ state->m_mmc1_chr_bank_base = chr_bank_base;
+
+ ppu2c0x_set_scanline_callback(machine.device("ppu"), 0);
+
+};
+
+
+/******************************************************
+
+ ROM/VROM banking (Super Game III)
+
+*******************************************************/
+
+/*
+ 76543210
+5001: x select rom at 0x8000: 0 - control program, 1 - game
+ x mapper for game: 0 - mapper 02, 1 - MMC1/MMC3
+ x game rom size: 0 - 256KB, 1 - 128KB
+ xxxxx rom bank, each bank has 0x20000 bytes (128KB)
+
+ 76543210
+5002: x unknown, always 0
+ x CHR rom size: 0 - 256KB, 1 - 128KB
+ x CHR rom flag: 0 - no CHR rom, 1 - CHR rom present
+ x mapper for game: 0 - MMC1, 1 - MMC3
+ xxxx CHR rom bank, each bank has 0x8000 bytes (32KB)
+*/
+
+
+static void supergm3_set_bank(running_machine &machine)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ device_t *ppu = machine.device("ppu");
+ UINT8* mem = machine.region("maincpu")->base();
+
+ // video bank
+ if (state->m_supergm3_chr_bank == 0x10 ||
+ state->m_supergm3_chr_bank == 0x40 )
+ {
+ // VRAM
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x0000, 0x1fff, "bank1");
+ ppu->memory().space(AS_PROGRAM)->install_write_bank(0x0000, 0x1fff, "bank1");
+ memory_set_bankptr(machine, "bank1", state->m_vram);
+
+ if (state->m_supergm3_chr_bank == 0x40)
+ set_mirroring(state, PPU_MIRROR_VERT);
+ }
+ else
+ {
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x0000, 0x03ff, "bank2");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x0400, 0x07ff, "bank3");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x0800, 0x0bff, "bank4");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x0c00, 0x0fff, "bank5");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x1000, 0x13ff, "bank6");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x1400, 0x17ff, "bank7");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x1800, 0x1bff, "bank8");
+ ppu->memory().space(AS_PROGRAM)->install_read_bank(0x1c00, 0x1fff, "bank9");
+ ppu->memory().space(AS_PROGRAM)->unmap_write(0x0000, 0x1fff);
+
+ set_videorom_bank(machine, 0, 8, 0, 8);
+ }
+
+ // prg bank
+ if ((state->m_supergm3_prg_bank & 0x80) == 0)
+ {
+ // title screen
+ memcpy(mem + 0x8000, mem + 0x18000, 0x8000);
+ memory_set_bankptr(machine, "bank10", mem + 0x6000);
+ ppu2c0x_set_scanline_callback(ppu, 0);
+ }
+ else if ((state->m_supergm3_prg_bank & 0x40) == 0)
+ {
+ // mapper 02
+ multigam_init_mapper02(machine,
+ machine.region("user1")->base() + (state->m_supergm3_prg_bank & 0x1f)*0x20000,
+ 0x20000);
+ }
+ else if (state->m_supergm3_chr_bank & 0x10)
+ {
+ // MMC3
+ multigam_init_mmc3(machine,
+ machine.region("user1")->base() + (state->m_supergm3_prg_bank & 0x1f)*0x20000,
+ (state->m_supergm3_prg_bank & 0x20) ? 0x20000 : 0x40000,
+ (state->m_supergm3_chr_bank & 0x0f)*0x80);
+ }
+ else
+ {
+ //MMC1
+ multigam_init_mmc1(machine,
+ machine.region("user1")->base() + (state->m_supergm3_prg_bank & 0x1f)*0x20000,
+ 0x20000,
+ (state->m_supergm3_chr_bank & 0x0f)*0x80/4 );
+ }
+}
+
+static WRITE8_HANDLER(supergm3_prg_bank_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ state->m_supergm3_prg_bank = data;
+}
+
+static WRITE8_HANDLER(supergm3_chr_bank_w)
+{
+ multigam_state *state = space->machine().driver_data<multigam_state>();
+ state->m_supergm3_chr_bank = data;
+ supergm3_set_bank(space->machine());
+}
+
+/******************************************************
+
+ Memory map (Super Game III)
+
+*******************************************************/
+
+static ADDRESS_MAP_START( supergm3_map, AS_PROGRAM, 8 )
+ AM_RANGE(0x0000, 0x07ff) AM_RAM /* NES RAM */
+ AM_RANGE(0x0800, 0x0fff) AM_RAM /* additional RAM */
+ AM_RANGE(0x2000, 0x3fff) AM_DEVREADWRITE("ppu", ppu2c0x_r, ppu2c0x_w)
+ AM_RANGE(0x4000, 0x4013) AM_DEVREADWRITE("nes", nes_psg_r, nes_psg_w) /* PSG primary registers */
+ AM_RANGE(0x4014, 0x4014) AM_WRITE(sprite_dma_w)
+ AM_RANGE(0x4015, 0x4015) AM_DEVREADWRITE("nes", psg_4015_r, psg_4015_w) /* PSG status / first control register */
+ AM_RANGE(0x4016, 0x4016) AM_READWRITE(multigam_IN0_r, multigam_IN0_w) /* IN0 - input port 1 */
+ AM_RANGE(0x4017, 0x4017) AM_READ(multigam_IN1_r) AM_DEVWRITE("nes", psg_4017_w) /* IN1 - input port 2 / PSG second control register */
+ AM_RANGE(0x4fff, 0x4fff) AM_READ_PORT("IN0")
+ AM_RANGE(0x5000, 0x5fff) AM_ROM
+ AM_RANGE(0x5000, 0x5000) AM_WRITENOP
+ AM_RANGE(0x5001, 0x5001) AM_WRITE(supergm3_prg_bank_w)
+ AM_RANGE(0x5002, 0x5002) AM_WRITE(supergm3_chr_bank_w)
+ AM_RANGE(0x5fff, 0x5fff) AM_WRITENOP
+ AM_RANGE(0x6000, 0x7fff) AM_RAMBANK("bank10")
+ AM_RANGE(0x8000, 0xffff) AM_ROM
+ADDRESS_MAP_END
+
+/******************************************************
+
+ Input ports
+
+*******************************************************/
+
+static INPUT_PORTS_START( multigam_common )
+ PORT_START("P1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(1)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(1)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(1) /* Select */
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START1 )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1)
+
+ PORT_START("P2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_PLAYER(2)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_PLAYER(2)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_PLAYER(2) /* Select */
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_START2 )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2)
+
+ PORT_START("IN0")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(multigam_inputs_r, NULL)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_COIN1 )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( multigam )
+ PORT_INCLUDE( multigam_common )
+
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x06, 0x00, "Coin/Time" )
+ PORT_DIPSETTING( 0x00, "3 min" )
+ PORT_DIPSETTING( 0x04, "5 min" )
+ PORT_DIPSETTING( 0x02, "7 min" )
+ PORT_DIPSETTING( 0x06, "10 min" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( multigm2 )
+ PORT_INCLUDE( multigam_common )
+
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x06, 0x00, "Coin/Time" )
+ PORT_DIPSETTING( 0x00, "5 min" )
+ PORT_DIPSETTING( 0x04, "8 min" )
+ PORT_DIPSETTING( 0x02, "11 min" )
+ PORT_DIPSETTING( 0x06, "15 min" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( multigm3 )
+ PORT_INCLUDE( multigam_common )
+
+ PORT_START("DSW")
+ PORT_DIPNAME( 0x06, 0x00, "Coin/Time" )
+ PORT_DIPSETTING( 0x00, "15 min" )
+ PORT_DIPSETTING( 0x04, "8 min" )
+ PORT_DIPSETTING( 0x02, "11 min" )
+ PORT_DIPSETTING( 0x06, "5 min" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( multigmt )
+ PORT_INCLUDE( multigam_common )
+
+ PORT_START("DSW")
+ PORT_DIPNAME( 0xf0, 0x00, "Game" )
+ PORT_DIPSETTING( 0x00, "Pacman" )
+ PORT_DIPSETTING( 0x10, "Super Mario Bros" )
+ PORT_DIPSETTING( 0x20, "Tetris" )
+ PORT_DIPSETTING( 0x30, "Road Fighter" )
+ PORT_DIPSETTING( 0x40, "Gorilla 3" )
+ PORT_DIPSETTING( 0x50, "Zippy Race" )
+ PORT_DIPSETTING( 0x80, "Tennis" )
+ PORT_DIPSETTING( 0x90, "Galaga" )
+ PORT_DIPSETTING( 0xa0, "Track & Field" )
+ PORT_DIPSETTING( 0xb0, "Bomb Jack" )
+
+ PORT_DIPNAME( 0x06, 0x00, "Coin/Time" )
+ PORT_DIPSETTING( 0x00, "3 min" )
+ PORT_DIPSETTING( 0x04, "5 min" )
+ PORT_DIPSETTING( 0x02, "7 min" )
+ PORT_DIPSETTING( 0x06, "10 min" )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( supergm3 )
+ PORT_INCLUDE( multigam_common )
+
+ PORT_MODIFY("IN0")
+ PORT_DIPNAME( 0x03, 0x00, "Play Time per Credit" )
+ PORT_DIPSETTING( 0x00, "3 min" )
+ PORT_DIPSETTING( 0x02, "5 min" )
+ PORT_DIPSETTING( 0x01, "8 min" )
+ PORT_DIPSETTING( 0x03, "10 min" )
+ PORT_DIPNAME( 0x0c, 0x00, DEF_STR( Coinage ) )
+ PORT_DIPSETTING( 0x0c, DEF_STR( 3C_1C ) )
+ PORT_DIPSETTING( 0x08, DEF_STR( 2C_1C ) )
+ PORT_DIPSETTING( 0x00, DEF_STR( 1C_1C ) )
+ PORT_DIPSETTING( 0x04, DEF_STR( 1C_2C ) )
+ PORT_DIPNAME( 0x10, 0x00, "Enable 2 players" )
+ PORT_DIPSETTING( 0x00, DEF_STR( Off ) )
+ PORT_DIPSETTING( 0x10, DEF_STR( On ) )
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_COIN1 )
+INPUT_PORTS_END
+/******************************************************
+
+ PPU/Video interface
+
+*******************************************************/
+
+static const nes_interface multigam_interface_1 =
+{
+ "maincpu"
+};
+
+static PALETTE_INIT( multigam )
+{
+ ppu2c0x_init_palette(machine, 0);
+}
+
+static void ppu_irq( device_t *device, int *ppu_regs )
+{
+ cputag_set_input_line(device->machine(), "maincpu", INPUT_LINE_NMI, PULSE_LINE);
+}
+
+/* our ppu interface */
+static const ppu2c0x_interface ppu_interface =
+{
+ 0, /* gfxlayout num */
+ 0, /* color base */
+ PPU_MIRROR_NONE, /* mirroring */
+ ppu_irq /* irq */
+};
+
+static VIDEO_START( multigam )
+{
+}
+
+static SCREEN_UPDATE( multigam )
+{
+ /* render the ppu */
+ ppu2c0x_render(screen->machine().device("ppu"), bitmap, 0, 0, 0, 0);
+ return 0;
+}
+
+static GFXDECODE_START( multigam )
+ /* none, the ppu generates one */
+GFXDECODE_END
+
+/******************************************************
+
+ Machine
+
+*******************************************************/
+
+static MACHINE_RESET( multigam )
+{
+}
+
+static MACHINE_RESET( multigm3 )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ /* reset the ppu */
+ multigm3_switch_prg_rom(space, 0, 0x01 );
+};
+
+static MACHINE_START( multigam )
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ state->m_nt_ram = auto_alloc_array(machine, UINT8, 0x1000);
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram + 0x400;
+ state->m_nt_page[2] = state->m_nt_ram + 0x800;
+ state->m_nt_page[3] = state->m_nt_ram + 0xc00;
+
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(multigam_nt_r), FUNC(multigam_nt_w));
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x0000, 0x1fff, "bank1");
+ memory_set_bankptr(machine, "bank1", machine.region("gfx1")->base());
+}
+
+static MACHINE_START( multigm3 )
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ state->m_nt_ram = auto_alloc_array(machine, UINT8, 0x1000);
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram + 0x400;
+ state->m_nt_page[2] = state->m_nt_ram + 0x800;
+ state->m_nt_page[3] = state->m_nt_ram + 0xc00;
+
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(multigam_nt_r), FUNC(multigam_nt_w));
+
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x0000, 0x03ff, "bank2");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x0400, 0x07ff, "bank3");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x0800, 0x0bff, "bank4");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x0c00, 0x0fff, "bank5");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x1000, 0x13ff, "bank6");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x1400, 0x17ff, "bank7");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x1800, 0x1bff, "bank8");
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_read_bank(0x1c00, 0x1fff, "bank9");
+
+ set_videorom_bank(machine, 0, 8, 0, 8);
+};
+
+static MACHINE_START( supergm3 )
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ state->m_nt_ram = auto_alloc_array(machine, UINT8, 0x1000);
+ state->m_nt_page[0] = state->m_nt_ram;
+ state->m_nt_page[1] = state->m_nt_ram + 0x400;
+ state->m_nt_page[2] = state->m_nt_ram + 0x800;
+ state->m_nt_page[3] = state->m_nt_ram + 0xc00;
+
+ machine.device("ppu")->memory().space(AS_PROGRAM)->install_legacy_readwrite_handler(0x2000, 0x3eff, FUNC(multigam_nt_r), FUNC(multigam_nt_w));
+
+ state->m_vram = auto_alloc_array(machine, UINT8, 0x2000);
+ state->m_multigmc_mmc3_6000_ram = auto_alloc_array(machine, UINT8, 0x2000);
+}
+
+static MACHINE_CONFIG_START( multigam, multigam_state )
+ /* basic machine hardware */
+ MCFG_CPU_ADD("maincpu", N2A03, N2A03_DEFAULTCLOCK)
+ MCFG_CPU_PROGRAM_MAP(multigam_map)
+
+ MCFG_MACHINE_START( multigam )
+ MCFG_MACHINE_RESET( multigam )
+
+ /* video hardware */
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_REFRESH_RATE(60)
+ MCFG_SCREEN_FORMAT(BITMAP_FORMAT_INDEXED16)
+ MCFG_SCREEN_SIZE(32*8, 262)
+ MCFG_SCREEN_VISIBLE_AREA(0*8, 32*8-1, 0*8, 30*8-1)
+ MCFG_SCREEN_UPDATE(multigam)
+
+ MCFG_GFXDECODE(multigam)
+ MCFG_PALETTE_LENGTH(8*4*16)
+
+ MCFG_PALETTE_INIT(multigam)
+ MCFG_VIDEO_START(multigam)
+
+ MCFG_PPU2C04_ADD("ppu", ppu_interface)
+
+ /* sound hardware */
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("nes", NES, N2A03_DEFAULTCLOCK)
+ MCFG_SOUND_CONFIG(multigam_interface_1)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+
+ MCFG_SOUND_ADD("dac", DAC, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( multigm3, multigam )
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(multigm3_map)
+
+ MCFG_MACHINE_START( multigm3 )
+ MCFG_MACHINE_RESET( multigm3 )
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( multigmt, multigam )
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(multigmt_map)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( supergm3, multigam )
+ MCFG_CPU_MODIFY("maincpu")
+ MCFG_CPU_PROGRAM_MAP(supergm3_map)
+
+ MCFG_MACHINE_START(supergm3)
+MACHINE_CONFIG_END
+
+ROM_START( multigam )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "7.bin", 0x0000, 0x8000, CRC(f0fa7cf2) SHA1(7f3b3dca796b964893197aef7f0f31dfd7a2c1a4) )
+
+ ROM_REGION( 0xC0000, "user1", 0 )
+ ROM_LOAD( "1.bin", 0x00000, 0x20000, CRC(e0bb14a5) SHA1(74026f59dfb08456183adaaf381bb28830212a1c) )
+ ROM_LOAD( "2.bin", 0x20000, 0x20000, CRC(f52c07ad) SHA1(51be288bcf5aeab5bdd95ee93a6d807867e30e97) )
+ ROM_LOAD( "3.bin", 0x40000, 0x20000, CRC(92e8303e) SHA1(4a735fce22cdea65801aa7e4e00fa8c15a022ea4) )
+ ROM_LOAD( "4.bin", 0x60000, 0x20000, CRC(f5c50f29) SHA1(6f3bd969d9d82a0d92aa6119375a607ccdb5d8b9) )
+ ROM_LOAD( "5.bin", 0x80000, 0x20000, CRC(e1232243) SHA1(fa864b255b7f3cb195d3789f8a2a7b3848b255a2) )
+ ROM_LOAD( "6.bin", 0xa0000, 0x20000, CRC(fb129b09) SHA1(b677937d6cf7800359dc6d35dd2de3ec27919d71) )
+
+ ROM_REGION( 0x80000, "gfx1", 0 )
+ ROM_LOAD( "8.bin", 0x00000, 0x20000, CRC(509c0e94) SHA1(9e87c74e76afe6c3a7ba194439434f54e2c879eb) )
+ ROM_LOAD( "9.bin", 0x20000, 0x20000, CRC(48416f20) SHA1(f461fcbff6d2fa4774d64c26475089d1aeea7fb5) )
+ ROM_LOAD( "10.bin", 0x40000, 0x20000, CRC(869d1661) SHA1(ac155bd24ebfea8e064859e1a05317001286f9ae) )
+ ROM_FILL( 0x60000, 0x20000, 0x00 )
+ROM_END
+
+ROM_START( multigmb )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "mg_4.bin", 0x0000, 0x8000, CRC(079226c1) SHA1(f4ceedd9b6cc3454550be7421dc75904ad664545) )
+
+ ROM_REGION( 0xC0000, "user1", 0 )
+ ROM_LOAD( "1.bin", 0x00000, 0x20000, CRC(e0bb14a5) SHA1(74026f59dfb08456183adaaf381bb28830212a1c) )
+ ROM_LOAD( "2.bin", 0x20000, 0x20000, CRC(f52c07ad) SHA1(51be288bcf5aeab5bdd95ee93a6d807867e30e97) )
+ ROM_LOAD( "3.bin", 0x40000, 0x20000, CRC(92e8303e) SHA1(4a735fce22cdea65801aa7e4e00fa8c15a022ea4) )
+ ROM_LOAD( "4.bin", 0x60000, 0x20000, CRC(f5c50f29) SHA1(6f3bd969d9d82a0d92aa6119375a607ccdb5d8b9) )
+ ROM_LOAD( "mg_9.bin", 0x80000, 0x20000, CRC(47f968af) SHA1(ed60bda060984e5acc2c6b6cac5b36eafbb2b631) )
+ ROM_LOAD( "6.bin", 0xa0000, 0x20000, CRC(fb129b09) SHA1(b677937d6cf7800359dc6d35dd2de3ec27919d71) )
+
+ ROM_REGION( 0x80000, "gfx1", 0 )
+ ROM_LOAD( "8.bin", 0x00000, 0x20000, CRC(509c0e94) SHA1(9e87c74e76afe6c3a7ba194439434f54e2c879eb) )
+ ROM_LOAD( "9.bin", 0x20000, 0x20000, CRC(48416f20) SHA1(f461fcbff6d2fa4774d64c26475089d1aeea7fb5) )
+ ROM_LOAD( "10.bin", 0x40000, 0x20000, CRC(869d1661) SHA1(ac155bd24ebfea8e064859e1a05317001286f9ae) )
+ ROM_FILL( 0x60000, 0x20000, 0x00 )
+ROM_END
+
+ROM_START( multigm2 )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "mg2-8u21.bin", 0x0000, 0x8000, CRC(e0588e11) SHA1(43b5f6bad7828b372c6b4251e9e24c748793bb2d) )
+
+ ROM_REGION( 0x100000, "user1", 0 )
+ ROM_LOAD( "mg2-4u10.bin", 0x00000, 0x20000, CRC(fc7b2461) SHA1(60cf296ba531495d577eac73220a7ae1dc897237) )
+ ROM_LOAD( "mg2-6-u4.bin", 0x20000, 0x20000, CRC(f1ced4a6) SHA1(d94d7c9fc9270d0e5eaecf819e4048c20866ba2d) )
+ ROM_LOAD( "mg2-3u15.bin", 0x40000, 0x20000, CRC(a1f84c4f) SHA1(c191677170c7d8907bbaee599a988c9adcc17449) )
+ ROM_LOAD( "mg2-2u20.bin", 0x60000, 0x10000, CRC(8413c2bd) SHA1(54e9a8c2ccfcb1a70ea7aa6125116829e4c72855) )
+ ROM_LOAD( "mg2-1u24.bin", 0x70000, 0x10000, CRC(53fd3238) SHA1(01095e6b853fa55783e9ac635fbf7c1450dc3eb1) )
+ ROM_LOAD( "mg2-5-u6.bin", 0x80000, 0x20000, CRC(0b95a92d) SHA1(df2e30d537a6703cc614ecc4b93b828f1339807b) )
+ ROM_LOAD( "mg2-7-u1.bin", 0xa0000, 0x40000, CRC(240ebac1) SHA1(83a8264d5efa261580c45112d718f6cd55957aa0) )
+
+
+ ROM_REGION( 0x80000, "gfx1", 0 )
+ ROM_LOAD( "mg2-9u27.bin", 0x00000, 0x20000, CRC(01ec6b04) SHA1(2e0e8b0ae8403070cae198555f66c044f48d19f4) )
+ ROM_LOAD( "mg210u23.bin", 0x20000, 0x20000, CRC(a85f1104) SHA1(a447f265a683d471dba2f0ef88ca9260089274bf) )
+ ROM_LOAD( "mg211u19.bin", 0x40000, 0x20000, CRC(44f21e4d) SHA1(e002004da5dd74ef30dc7ce95f426dd9a47fede5) )
+ ROM_LOAD( "mg212u14.bin", 0x60000, 0x20000, CRC(a0ae2b4b) SHA1(5e026ad8a6b2a8120e386471d5178625bda04525) )
+ROM_END
+
+ROM_START( multigm3 )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "mg3-6.bin", 0x0000, 0x8000, CRC(3c1e53f1) SHA1(2eaf84e592db58cd268738da2642c716895e4eaa) )
+
+ ROM_REGION( 0x100000, "user1", 0 )
+ ROM_LOAD( "mg3-2.bin", 0x00000, 0x20000, CRC(de6d2232) SHA1(30a5e6cd44cfbce2c5186dbc45c0c14c8b1510c4) )
+ ROM_LOAD( "mg3-1.bin", 0x40000, 0x20000, CRC(b0dc8136) SHA1(6d7334aae9047ec2028790bd3b326458b5cdc737) )
+ ROM_LOAD( "mg3-3.bin", 0x60000, 0x20000, CRC(6e96d642) SHA1(45eb954a0a905ad48ebc04ee3ed8858a1077817a) )
+ ROM_LOAD( "mg3-5.bin", 0xa0000, 0x40000, CRC(44609e6f) SHA1(c12a63e34b379427a3c146f1f85688fedf55ed0f) )
+ ROM_LOAD( "mg3-4.bin", 0xe0000, 0x20000, CRC(9b022e13) SHA1(96ad9c49cf72fe19a3e9944f8102d2d905266e92) )
+
+
+ ROM_REGION( 0x80000, "gfx1", 0 )
+ ROM_LOAD( "mg3-7.bin", 0x00000, 0x20000, CRC(d8308cdb) SHA1(7bfb864611c32cf3740cfd650bfe275513d511d7) )
+ ROM_LOAD( "mg3-8.bin", 0x20000, 0x20000, CRC(b4a53b9d) SHA1(63d8901149d0d9b69f28bfc096f7932448542032) )
+ ROM_FILL( 0x40000, 0x20000, 0x00 )
+ ROM_LOAD( "mg3-9.bin", 0x60000, 0x20000, CRC(a0ae2b4b) SHA1(5e026ad8a6b2a8120e386471d5178625bda04525) )
+ROM_END
+
+ROM_START( multigmt )
+ ROM_REGION( 0x10000, "maincpu", 0 )
+ ROM_LOAD( "3.24", 0x0000, 0x8000, CRC(fdc40548) SHA1(323dcfe04bff4afd7ea290c93ef466690214f2b0) )
+
+ ROM_REGION( 0x80000, "user1", 0 )
+ ROM_LOAD( "1.22", 0x00000, 0x40000, CRC(14d0509e) SHA1(9922b2bae7592f4942f5c1bb32746705d7298eb6) )
+ ROM_RELOAD( 0x40000, 0x40000)
+
+ ROM_REGION( 0x80000, "gfx1", 0 )
+ ROM_LOAD( "5.34", 0x00000, 0x40000, CRC(cdf70463) SHA1(79b7c399ebea245a0b06f461e5d8c3291b215878) )
+ ROM_RELOAD( 0x40000, 0x40000)
+
+ ROM_REGION( 0x40000, "unknown", 0 )
+ ROM_LOAD( "r11.7", 0x00000, 0x20000, CRC(e6fdcabb) SHA1(9ff3adb61b81d5cac4e88520fe4281414d7e5311) )
+ ROM_LOAD( "4.27", 0x20000, 0x10000, CRC(e6ed25fe) SHA1(e5723efab5652da3b276b13cd72ca5dc14f37a8b) )
+ ROM_LOAD( "10.72", 0x30000, 0x10000, CRC(43f393ee) SHA1(4a307264bedfe77286a6dde47a7f1009a2698ab5) )
+
+ROM_END
+
+ROM_START( supergm3 )
+ ROM_REGION( 0x20000, "maincpu", 0 )
+ ROM_LOAD( "sg3.ic36", 0x0000, 0x10000, CRC(f79dd9ef) SHA1(31b84097f4f14bdb6e87a7a624e9974abe680c80) )
+ ROM_COPY("maincpu", 0x0000, 0x10000, 0x10000)
+
+ ROM_REGION( 0x400000, "user1", 0 )
+ ROM_LOAD( "sg3.rom18", 0x000000, 0x80000, CRC(aa7b8631) SHA1(4d6695da2baef7cc5b0d3f9f620f6b49d8f89e23) )
+ ROM_LOAD( "sg3.rom10", 0x080000, 0x80000, CRC(4581454f) SHA1(ce3b43e80e4893a7c9ad3adf7c1edb02e14b351a) )
+ ROM_LOAD( "sg3.rom11", 0x100000, 0x80000, CRC(14490668) SHA1(d5076d2466ea974bf6867c3cf3052242b0242ffb) )
+ ROM_LOAD( "sg3.rom12", 0x180000, 0x80000, CRC(6ce8781f) SHA1(cf75fccb3d22bbbcfbc7e8b8104eb79353a24c97) )
+ ROM_LOAD( "sg3.rom13", 0x300000, 0x40000, CRC(bbc9ab4f) SHA1(4a833b4cc73330461ee519715b56ba0ba2e7ce50) )
+
+ ROM_REGION( 0x200000, "gfx1", 0 )
+ ROM_LOAD( "sg3.rom14", 0x000000, 0x80000, CRC(197cd696) SHA1(a5a9ee2c5f63b730b9e93d46a1745fabfdc02db2) )
+ ROM_LOAD( "sg3.rom15", 0x080000, 0x20000, CRC(e18eff5f) SHA1(d865b5a23a248b7d582fe3ccb3ff46fbbff9a2a9) )
+ ROM_LOAD( "sg3.rom16", 0x100000, 0x80000, CRC(151f4ffa) SHA1(8055b9c275f539707aca45f3e57fd4b1fc2c3fc5) )
+ ROM_LOAD( "sg3.rom17", 0x180000, 0x80000, CRC(7be7fbb8) SHA1(03cda9c098eaf21326b001d5c227ad85502b6378) )
+ROM_END
+
+static DRIVER_INIT( multigam )
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+ multigam_switch_prg_rom(space, 0x0, 0x01);
+}
+
+static void multigm3_decrypt(UINT8* mem, int memsize, const UINT8* decode_nibble)
+{
+ int i;
+ for (i = 0; i < memsize; i++)
+ {
+ mem[i] = decode_nibble[mem[i] & 0x0f] | (decode_nibble[mem[i] >> 4] << 4);
+ }
+};
+
+static DRIVER_INIT(multigm3)
+{
+ multigam_state *state = machine.driver_data<multigam_state>();
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ const UINT8 decode[16] = { 0x09, 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01, 0x00, 0x0f, 0x0e, 0x0d, 0x0c, 0x0b, 0x0a };
+
+ multigm3_decrypt(machine.region("maincpu")->base(), machine.region("maincpu")->bytes(), decode );
+ multigm3_decrypt(machine.region("user1")->base(), machine.region("user1")->bytes(), decode );
+
+ state->m_multigmc_mmc3_6000_ram = auto_alloc_array(machine, UINT8, 0x2000);
+
+ multigam_switch_prg_rom(space, 0x0, 0x01);
+}
+
+static DRIVER_INIT(multigmt)
+{
+ address_space *space = machine.device("maincpu")->memory().space(AS_PROGRAM);
+
+ UINT8* buf = auto_alloc_array(machine, UINT8, 0x80000);
+ UINT8 *rom;
+ int size;
+ int i;
+ int addr;
+
+ rom = machine.region("maincpu")->base();
+ size = 0x8000;
+ memcpy(buf, rom, size);
+ for (i = 0; i < size; i++)
+ {
+
+ addr = BITSWAP24(i,23,22,21,20,19,18,17,16,15,14,13,8,11,12,10,9,7,6,5,4,3,2,1,0);
+ rom[i] = buf[addr];
+ }
+
+ rom = machine.region("user1")->base();
+ size = 0x80000;
+ memcpy(buf, rom, size);
+ for (i = 0; i < size; i++)
+ {
+ addr = BITSWAP24(i,23,22,21,20,19,18,17,16,15,14,13,8,11,12,10,9,7,6,5,4,3,2,1,0);
+ rom[i] = buf[addr];
+ }
+ rom = machine.region("gfx1")->base();
+ size = 0x80000;
+ memcpy(buf, rom, size);
+ for (i = 0; i < size; i++)
+ {
+ addr = BITSWAP24(i,23,22,21,20,19,18,17,15,16,11,10,12,13,14,8,9,1,3,5,7,6,4,2,0);
+ rom[i] = BITSWAP8(buf[addr], 4, 7, 3, 2, 5, 1, 6, 0);
+ }
+
+ auto_free(machine, buf);
+
+ multigam_switch_prg_rom(space, 0x0, 0x01);
+};
+
+GAME( 1992, multigam, 0, multigam, multigam, multigam, ROT0, "<unknown>", "Multi Game (set 1)", 0 )
+GAME( 1992, multigmb, multigam, multigam, multigam, multigam, ROT0, "<unknown>", "Multi Game (set 2)", 0 )
+GAME( 1992, multigm2, 0, multigm3, multigm2, multigm3, ROT0, "Seo Jin", "Multi Game 2", 0 )
+GAME( 1992, multigm3, 0, multigm3, multigm3, multigm3, ROT0, "Seo Jin", "Multi Game III", 0 )
+GAME( 1992, multigmt, 0, multigmt, multigmt, multigmt, ROT0, "Tung Sheng Electronics", "Multi Game (Tung Sheng Electronics)", 0 )
+GAME( 1996, supergm3, 0, supergm3, supergm3, 0, ROT0, "<unknown>", "Super Game III", 0 )