summaryrefslogtreecommitdiffstatshomepage
path: root/src/mame/machine/vsnes.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/mame/machine/vsnes.cpp')
-rw-r--r--src/mame/machine/vsnes.cpp1109
1 files changed, 0 insertions, 1109 deletions
diff --git a/src/mame/machine/vsnes.cpp b/src/mame/machine/vsnes.cpp
deleted file mode 100644
index cc45f2517f2..00000000000
--- a/src/mame/machine/vsnes.cpp
+++ /dev/null
@@ -1,1109 +0,0 @@
-// license:BSD-3-Clause
-// copyright-holders:Brad Oliver, Fabio Priuli
-/***************************************************************************
-
-Nintendo VS UniSystem and DualSystem - (c) 1984 Nintendo of America
-
- Portions of this code are heavily based on
- Brad Oliver's MESS implementation of the NES.
-
-***************************************************************************/
-
-#include "emu.h"
-#include "screen.h"
-#include "video/ppu2c0x.h"
-#include "includes/vsnes.h"
-
-
-/* PPU notes */
-/* nametable is, per Lord Nightmare, always 4K per PPU */
-/* The vsnes system has relatively few banking options for CHR */
-/* Each driver will use ROM or RAM for CHR, never both, and RAM is never banked */
-/* This leads to the memory system being an optimal place to perform banking */
-
-/* Prototypes for mapping board components to PPU bus */
-
-
-/*************************************
- *
- * Input Ports
- *
- *************************************/
-
-void vsnes_state::vsnes_in0_w(uint8_t data)
-{
- /* Toggling bit 0 high then low resets both controllers */
- if (data & 1)
- {
- /* load up the latches */
- m_input_latch[0] = ioport("IN0")->read();
- m_input_latch[1] = ioport("IN1")->read();
- }
-}
-
-uint8_t vsnes_state::gun_in0_r()
-{
- int ret = (m_input_latch[0]) & 1;
-
- /* shift */
- m_input_latch[0] >>= 1;
-
- ret |= ioport("COINS")->read(); /* merge coins, etc */
- ret |= (ioport("DSW0")->read() & 3) << 3; /* merge 2 dipswitches */
-
-/* The gun games expect a 1 returned on every 5th read after sound_fix is reset*/
-/* Info Supplied by Ben Parnell <xodnizel@home.com> of FCE Ultra fame */
-
- if (m_sound_fix == 4)
- {
- ret = 1;
- }
-
- m_sound_fix++;
-
- return ret;
-
-}
-
-uint8_t vsnes_state::vsnes_in0_r()
-{
- int ret = (m_input_latch[0]) & 1;
-
- /* shift */
- m_input_latch[0] >>= 1;
-
- ret |= ioport("COINS")->read(); /* merge coins, etc */
- ret |= (ioport("DSW0")->read() & 3) << 3; /* merge 2 dipswitches */
-
- return ret;
-
-}
-
-uint8_t vsnes_state::vsnes_in1_r()
-{
- int ret = (m_input_latch[1]) & 1;
-
- ret |= ioport("DSW0")->read() & ~3; /* merge the rest of the dipswitches */
-
- /* shift */
- m_input_latch[1] >>= 1;
-
- return ret;
-}
-
-void vsnes_state::vsnes_in0_1_w(uint8_t data)
-{
- /* Toggling bit 0 high then low resets both controllers */
- if (data & 1)
- {
- /* load up the latches */
- m_input_latch[2] = ioport("IN2")->read();
- m_input_latch[3] = ioport("IN3")->read();
- }
-}
-
-uint8_t vsnes_state::vsnes_in0_1_r()
-{
- int ret = (m_input_latch[2]) & 1;
-
- /* shift */
- m_input_latch[2] >>= 1;
-
- ret |= ioport("COINS2")->read(); /* merge coins, etc */
- ret |= (ioport("DSW1")->read() & 3) << 3; /* merge 2 dipswitches */
- return ret;
-}
-
-uint8_t vsnes_state::vsnes_in1_1_r()
-{
- int ret = (m_input_latch[3]) & 1;
-
- ret |= ioport("DSW1")->read() & ~3; /* merge the rest of the dipswitches */
-
- /* shift */
- m_input_latch[3] >>= 1;
-
- return ret;
-
-}
-
-/*************************************
- *
- * Init machine
- *
- *************************************/
-
-MACHINE_RESET_MEMBER(vsnes_state,vsnes)
-{
- m_last_bank = 0xff;
- m_sound_fix = 0;
- m_input_latch[0] = m_input_latch[1] = 0;
- m_input_latch[2] = m_input_latch[3] = 0;
-
-}
-
-/*************************************
- *
- * Init machine
- *
- *************************************/
-
-MACHINE_RESET_MEMBER(vsnes_state,vsdual)
-{
- m_input_latch[0] = m_input_latch[1] = 0;
- m_input_latch[2] = m_input_latch[3] = 0;
-
-}
-
-/*************************************
- *
- * Machine start functions
- *
- *************************************/
-
-void vsnes_state::v_set_videorom_bank( int start, int count, int vrom_start_bank )
-{
- int i;
-
- assert(start + count <= 8);
-
- vrom_start_bank &= (m_vrom_banks - 1);
- assert(vrom_start_bank + count <= m_vrom_banks);
-
- /* bank_size_in_kb is used to determine how large the "bank" parameter is */
- /* count determines the size of the area mapped */
- for (i = 0; i < count; i++)
- {
- m_chr_banks[i + start]->set_entry(vrom_start_bank + i);
- }
-}
-
-MACHINE_START_MEMBER(vsnes_state,vsnes)
-{
- address_space &ppu1_space = m_ppu1->space(AS_PROGRAM);
- int i;
-
- /* establish nametable ram */
- m_nt_ram[0] = std::make_unique<uint8_t[]>(0x1000);
- /* set mirroring */
- m_nt_page[0][0] = m_nt_ram[0].get();
- m_nt_page[0][1] = m_nt_ram[0].get() + 0x400;
- m_nt_page[0][2] = m_nt_ram[0].get() + 0x800;
- m_nt_page[0][3] = m_nt_ram[0].get() + 0xc00;
-
- ppu1_space.install_readwrite_handler(0x2000, 0x3eff, read8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_r)), write8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_w)));
-
- if (m_gfx1_rom != nullptr)
- {
- m_vrom[0] = memregion("gfx1")->base();
- m_vrom_size[0] = memregion("gfx1")->bytes();
- m_vrom_banks = m_vrom_size[0] / 0x400;
- }
- else
- {
- m_vrom[0] = nullptr;
- m_vrom_size[0] = 0;
- m_vrom_banks = 0;
- }
-
- /* establish chr banks */
- /* bank 1 is used already! */
- /* DRIVER_INIT is called first - means we can handle this different for VRAM games! */
- if (m_vrom[0] != nullptr)
- {
- for (i = 0; i < 8; i++)
- {
- ppu1_space.install_read_bank(0x0400 * i, 0x0400 * i + 0x03ff, m_chr_banks[i]);
- m_chr_banks[i]->configure_entries(0, m_vrom_banks, m_vrom[0], 0x400);
- }
- v_set_videorom_bank(0, 8, 0);
- }
- else
- {
- ppu1_space.install_ram(0x0000, 0x1fff, m_vram.get());
- }
-}
-
-MACHINE_START_MEMBER(vsnes_state,vsdual)
-{
- m_vrom[0] = memregion("gfx1")->base();
- m_vrom[1] = memregion("gfx2")->base();
- m_vrom_size[0] = memregion("gfx1")->bytes();
- m_vrom_size[1] = memregion("gfx2")->bytes();
-
- /* establish nametable ram */
- m_nt_ram[0] = std::make_unique<uint8_t[]>(0x1000);
- m_nt_ram[1] = std::make_unique<uint8_t[]>(0x1000);
- /* set mirroring */
- m_nt_page[0][0] = m_nt_ram[0].get();
- m_nt_page[0][1] = m_nt_ram[0].get() + 0x400;
- m_nt_page[0][2] = m_nt_ram[0].get() + 0x800;
- m_nt_page[0][3] = m_nt_ram[0].get() + 0xc00;
- m_nt_page[1][0] = m_nt_ram[1].get();
- m_nt_page[1][1] = m_nt_ram[1].get() + 0x400;
- m_nt_page[1][2] = m_nt_ram[1].get() + 0x800;
- m_nt_page[1][3] = m_nt_ram[1].get() + 0xc00;
-
- m_ppu1->space(AS_PROGRAM).install_readwrite_handler(0x2000, 0x3eff, read8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_r)), write8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_w)));
- m_ppu2->space(AS_PROGRAM).install_readwrite_handler(0x2000, 0x3eff, read8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt1_r)), write8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt1_w)));
- // read only!
- m_ppu1->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, m_bank_vrom[0]);
- // read only!
- m_ppu2->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, m_bank_vrom[1]);
- m_bank_vrom[0]->configure_entries(0, m_vrom_size[0] / 0x2000, m_vrom[0], 0x2000);
- m_bank_vrom[1]->configure_entries(0, m_vrom_size[1] / 0x2000, m_vrom[1], 0x2000);
- m_bank_vrom[0]->set_entry(0);
- m_bank_vrom[1]->set_entry(0);
-}
-
-MACHINE_START_MEMBER(vsnes_state, bootleg)
-{
- address_space &ppu1_space = m_ppu1->space(AS_PROGRAM);
-
- /* establish nametable ram */
- m_nt_ram[0] = std::make_unique<uint8_t[]>(0x1000);
- /* set mirroring */
- v_set_mirroring(0, PPU_MIRROR_VERT);
-
- ppu1_space.install_readwrite_handler(0x2000, 0x3eff, read8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_r)), write8sm_delegate(*this, FUNC(vsnes_state::vsnes_nt0_w)));
-
- m_vrom[0] = m_gfx1_rom->base();
- m_vrom_size[0] = m_gfx1_rom->bytes();
- m_vrom_banks = m_vrom_size[0] / 0x2000;
-
- /* establish chr banks */
- m_ppu1->space(AS_PROGRAM).install_read_bank(0x0000, 0x1fff, m_bank_vrom[0]);
- m_bank_vrom[0]->configure_entries(0, m_vrom_banks, m_vrom[0], 0x2000);
- m_bank_vrom[0]->set_entry(0);
-}
-
-/*************************************
- *
- * External mappings for PPU bus
- *
- *************************************/
-
-void vsnes_state::vsnes_nt0_w(offs_t offset, uint8_t data)
-{
- int page = ((offset & 0xc00) >> 10);
- m_nt_page[0][page][offset & 0x3ff] = data;
-}
-
-void vsnes_state::vsnes_nt1_w(offs_t offset, uint8_t data)
-{
- int page = ((offset & 0xc00) >> 10);
- m_nt_page[1][page][offset & 0x3ff] = data;
-}
-
-uint8_t vsnes_state::vsnes_nt0_r(offs_t offset)
-{
- int page = ((offset&0xc00) >> 10);
- return m_nt_page[0][page][offset & 0x3ff];
-}
-
-uint8_t vsnes_state::vsnes_nt1_r(offs_t offset)
-{
- int page = ((offset & 0xc00) >> 10);
- return m_nt_page[1][page][offset & 0x3ff];
-}
-
-void vsnes_state::v_set_mirroring(int ppu, int mirroring)
-{
- switch (mirroring)
- {
- case PPU_MIRROR_LOW:
- m_nt_page[ppu][0] = m_nt_page[ppu][1] = m_nt_page[ppu][2] = m_nt_page[ppu][3] = m_nt_ram[ppu].get();
- break;
- case PPU_MIRROR_HIGH:
- m_nt_page[ppu][0] = m_nt_page[ppu][1] = m_nt_page[ppu][2] = m_nt_page[ppu][3] = m_nt_ram[ppu].get() + 0x400;
- break;
- case PPU_MIRROR_HORZ:
- m_nt_page[ppu][0] = m_nt_ram[ppu].get();
- m_nt_page[ppu][1] = m_nt_ram[ppu].get();
- m_nt_page[ppu][2] = m_nt_ram[ppu].get() + 0x400;
- m_nt_page[ppu][3] = m_nt_ram[ppu].get() + 0x400;
- break;
- case PPU_MIRROR_VERT:
- m_nt_page[ppu][0] = m_nt_ram[ppu].get();
- m_nt_page[ppu][1] = m_nt_ram[ppu].get() + 0x400;
- m_nt_page[ppu][2] = m_nt_ram[ppu].get();
- m_nt_page[ppu][3] = m_nt_ram[ppu].get() + 0x400;
- break;
- case PPU_MIRROR_NONE:
- default:
- m_nt_page[ppu][0] = m_nt_ram[ppu].get();
- m_nt_page[ppu][1] = m_nt_ram[ppu].get() + 0x400;
- m_nt_page[ppu][2] = m_nt_ram[ppu].get() + 0x800;
- m_nt_page[ppu][3] = m_nt_ram[ppu].get() + 0xc00;
- break;
- }
-
-}
-
-/**********************************************************************************
- *
- * Game and Board-specific initialization
- *
- **********************************************************************************/
-
-/**********************************************************************************/
-/* Most games: VROM Banking in controller 0 write */
-
-void vsnes_state::vsnormal_vrom_banking(uint8_t data)
-{
- /* switch vrom */
- v_set_videorom_bank(0, 8, (data & 4) ? 8 : 0);
-
- /* bit 1 ( data & 2 ) enables writes to extra ram, we ignore it */
-
- /* move along */
- vsnes_in0_w(data);
-}
-
-void vsnes_state::init_vsnormal()
-{
- /* vrom switching is enabled with bit 2 of $4016 */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x4016, 0x4016, write8smo_delegate(*this, FUNC(vsnes_state::vsnormal_vrom_banking)));
-}
-
-/**********************************************************************************/
-/* Gun games: VROM Banking in controller 0 write */
-
-void vsnes_state::gun_in0_w(uint8_t data)
-{
- if (m_do_vrom_bank)
- {
- /* switch vrom */
- v_set_videorom_bank(0, 8, (data & 4) ? 8 : 0);
- }
-
- /* here we do things a little different */
- if (data & 1)
- {
- /* load up the latches */
- m_input_latch[0] = ioport("IN0")->read();
-
- /* do the gun thing */
- int x = ioport("GUNX")->read();
- float y = ioport("GUNY")->read();
-
- y = y * 0.9375f; // scale 256 (our gun input range is 0 - 255) to 240 (screen visible area / bitmap we're using is 0 - 239)
-
- uint8_t realy = (int)y;
-
- // update the screen if necessary
- if (!m_ppu1->screen().vblank())
- {
- int vpos = m_ppu1->screen().vpos();
- int hpos = m_ppu1->screen().hpos();
-
- if (vpos > realy || (vpos == realy && hpos >= x))
- m_ppu1->screen().update_now();
- }
-
- /* get the pixel at the gun position */
- rgb_t col = m_ppu1->screen().pixel(x, realy);
- uint8_t bright = col.brightness();
- // todo, calculate how bright it is with pix.r * 0.3 + pix.g * 0.59 + pix.b * 0.11 ?
- // the mame calc above is uint8_t brightness() const { return (r() * 222 + g() * 707 + b() * 71) / 1000; } (from lib/util/palette.h)
-#if 0
- uint8_t r = col.r();
- uint8_t g = col.g();
- uint8_t b = col.b();
- printf("pix is %02x %02x %02x | %02x\n", r,g,b,bright);
-#endif
- if (bright == 0xff)
- {
- m_input_latch[0] |= 0x40;
- }
-
-
-
-#if 0 // this is junk code, only works for NES palette..
- /* get the color base from the ppu */
- uint32_t color_base = 0;
-
- /* look at the screen and see if the cursor is over a bright pixel */
- if ((pix == color_base + 0x20 ) || (pix == color_base + 0x30) ||
- (pix == color_base + 0x33 ) || (pix == color_base + 0x34))
- {
- m_input_latch[0] |= 0x40;
- }
-#endif
-
- m_input_latch[1] = ioport("IN1")->read();
- }
-
- if ((m_zapstore & 1) && (!(data & 1)))
- /* reset sound_fix to keep sound from hanging */
- {
- m_sound_fix = 0;
- }
-
- m_zapstore = data;
-}
-
-void vsnes_state::init_vsgun()
-{
- /* VROM switching is enabled with bit 2 of $4016 */
- m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x4016, 0x4016, read8smo_delegate(*this, FUNC(vsnes_state::gun_in0_r)), write8smo_delegate(*this, FUNC(vsnes_state::gun_in0_w)));
- m_do_vrom_bank = 1;
-}
-
-/**********************************************************************************/
-/* Konami games: ROMs bankings at $8000-$ffff */
-
-void vsnes_state::vskonami_rom_banking(offs_t offset, uint8_t data)
-{
- int reg = (offset >> 12) & 0x07;
- int bankoffset = (data & 7) * 0x2000 + 0x10000;
-
- switch (reg)
- {
- case 0: /* code bank 0 */
- case 2: /* code bank 1 */
- case 4: /* code bank 2 */
- {
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000 + reg * 0x1000], &prg[bankoffset], 0x2000);
- }
- break;
-
- case 6: /* vrom bank 0 */
- v_set_videorom_bank(0, 4, data * 4);
- break;
-
- case 7: /* vrom bank 1 */
- v_set_videorom_bank(4, 4, data * 4);
- break;
- }
-}
-
-void vsnes_state::init_vskonami()
-{
- /* We do manual banking, in case the code falls through */
- /* Copy the initial banks */
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000], &prg[0x18000], 0x8000);
-
- /* banking is done with writes to the $8000-$ffff area */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x8000, 0xffff, write8sm_delegate(*this, FUNC(vsnes_state::vskonami_rom_banking)));
-}
-
-/***********************************************************************/
-/* Vs. Gumshoe */
-
-void vsnes_state::vsgshoe_gun_in0_w(uint8_t data)
-{
- int addr;
- if((data & 0x04) != m_old_bank)
- {
- uint8_t *prg = memregion("maincpu")->base();
- m_old_bank = data & 0x04;
- addr = m_old_bank ? 0x12000: 0x10000;
- memcpy(&prg[0x08000], &prg[addr], 0x2000);
- }
-
- gun_in0_w(data);
-}
-
-void vsnes_state::init_vsgshoe()
-{
- /* set up the default bank */
- uint8_t *prg = memregion("maincpu")->base();
- memcpy (&prg[0x08000], &prg[0x12000], 0x2000);
-
- /* vrom switching is enabled with bit 2 of $4016 */
- m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x4016, 0x4016, read8smo_delegate(*this, FUNC(vsnes_state::gun_in0_r)), write8smo_delegate(*this, FUNC(vsnes_state::vsgshoe_gun_in0_w)));
-
- m_do_vrom_bank = 1;
-}
-
-/**********************************************************************************/
-/* Dr Mario: ROMs bankings at $8000-$ffff */
-
-
-void vsnes_state::drmario_rom_banking(offs_t offset, uint8_t data)
-{
- /* basically, a MMC1 mapper from the nes */
-
- int reg = (offset >> 13);
-
- /* reset mapper */
- if (data & 0x80)
- {
- m_drmario_shiftreg = m_drmario_shiftcount = 0;
-
- m_size16k = 1;
-
- m_switchlow = 1;
- m_vrom4k = 0;
-
- return;
- }
-
- /* see if we need to clock in data */
- if (m_drmario_shiftcount < 5)
- {
- m_drmario_shiftreg >>= 1;
- m_drmario_shiftreg |= (data & 1) << 4;
- m_drmario_shiftcount++;
- }
-
- /* are we done shifting? */
- if (m_drmario_shiftcount == 5)
- {
- /* reset count */
- m_drmario_shiftcount = 0;
-
- /* apply data to registers */
- switch (reg)
- {
- case 0: /* mirroring and options */
- {
- int mirroring;
-
- m_vrom4k = m_drmario_shiftreg & 0x10;
- m_size16k = m_drmario_shiftreg & 0x08;
- m_switchlow = m_drmario_shiftreg & 0x04;
-
- switch (m_drmario_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 */
- v_set_mirroring(1, mirroring);
- }
- break;
-
- case 1: /* video rom banking - bank 0 - 4k or 8k */
- if (!m_vram)
- v_set_videorom_bank(0, (m_vrom4k) ? 4 : 8, m_drmario_shiftreg * 4);
- break;
-
- case 2: /* video rom banking - bank 1 - 4k only */
- if (m_vrom4k && !m_vram)
- v_set_videorom_bank(4, 4, m_drmario_shiftreg * 4);
- break;
-
- case 3: /* program banking */
- {
- int bank = (m_drmario_shiftreg & 0x03) * 0x4000;
- uint8_t *prg = memregion("maincpu")->base();
-
- if (!m_size16k)
- {
- /* switch 32k */
- memcpy(&prg[0x08000], &prg[0x010000 + bank], 0x8000);
- }
- else
- {
- /* switch 16k */
- if (m_switchlow)
- {
- /* low */
- memcpy(&prg[0x08000], &prg[0x010000 + bank], 0x4000);
- }
- else
- {
- /* high */
- memcpy(&prg[0x0c000], &prg[0x010000 + bank], 0x4000);
- }
- }
- }
- break;
- }
-
- m_drmario_shiftreg = 0;
- }
-}
-
-void vsnes_state::init_drmario()
-{
- /* We do manual banking, in case the code falls through */
- /* Copy the initial banks */
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000], &prg[0x10000], 0x4000);
- memcpy(&prg[0x0c000], &prg[0x1c000], 0x4000);
-
- /* MMC1 mapper at writes to $8000-$ffff */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x8000, 0xffff, write8sm_delegate(*this, FUNC(vsnes_state::drmario_rom_banking)));
-
- m_drmario_shiftreg = 0;
- m_drmario_shiftcount = 0;
-}
-
-/**********************************************************************************/
-/* Games with VRAM instead of graphics ROMs: ROMs bankings at $8000-$ffff */
-
-void vsnes_state::vsvram_rom_banking(uint8_t data)
-{
- int rombank = 0x10000 + (data & 7) * 0x4000;
- uint8_t *prg = memregion("maincpu")->base();
-
- memcpy(&prg[0x08000], &prg[rombank], 0x4000);
-}
-
-void vsnes_state::init_vsvram()
-{
- /* when starting the game, the 1st 16k and the last 16k are loaded into the 2 banks */
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000], &prg[0x28000], 0x8000);
-
- /* banking is done with writes to the $8000-$ffff area */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x8000, 0xffff, write8smo_delegate(*this, FUNC(vsnes_state::vsvram_rom_banking)));
-
- /* allocate m_vram */
- m_vram = std::make_unique<uint8_t[]>(0x2000);
-}
-
-/**********************************************************************************/
-
-
-void vsnes_state::mapper4_set_prg( )
-{
- uint8_t *prg = memregion("maincpu")->base();
- uint8_t prg_flip = (m_MMC3_cmd & 0x40) ? 2 : 0;
-
- memcpy(&prg[0x8000], &prg[0x2000 * (m_MMC3_prg_bank[0 ^ prg_flip] & m_MMC3_prg_mask) + 0x10000], 0x2000);
- memcpy(&prg[0xa000], &prg[0x2000 * (m_MMC3_prg_bank[1] & m_MMC3_prg_mask) + 0x10000], 0x2000);
- memcpy(&prg[0xc000], &prg[0x2000 * (m_MMC3_prg_bank[2 ^ prg_flip] & m_MMC3_prg_mask) + 0x10000], 0x2000);
- memcpy(&prg[0xe000], &prg[0x2000 * (m_MMC3_prg_bank[3] & m_MMC3_prg_mask) + 0x10000], 0x2000);
-}
-
-void vsnes_state::mapper4_set_chr( )
-{
- uint8_t chr_page = (m_MMC3_cmd & 0x80) >> 5;
-
- v_set_videorom_bank(chr_page ^ 0, 1, m_MMC3_chr_bank[0] & ~0x01);
- v_set_videorom_bank(chr_page ^ 1, 1, m_MMC3_chr_bank[0] | 0x01);
- v_set_videorom_bank(chr_page ^ 2, 1, m_MMC3_chr_bank[1] & ~0x01);
- v_set_videorom_bank(chr_page ^ 3, 1, m_MMC3_chr_bank[1] | 0x01);
- v_set_videorom_bank(chr_page ^ 4, 1, m_MMC3_chr_bank[2]);
- v_set_videorom_bank(chr_page ^ 5, 1, m_MMC3_chr_bank[3]);
- v_set_videorom_bank(chr_page ^ 6, 1, m_MMC3_chr_bank[4]);
- v_set_videorom_bank(chr_page ^ 7, 1, m_MMC3_chr_bank[5]);
-}
-
-
-void vsnes_state::mapper4_irq( int scanline, int vblank, int blanked )
-{
- if (scanline < ppu2c0x_device::BOTTOM_VISIBLE_SCANLINE)
- {
- int priorCount = m_IRQ_count;
- if (m_IRQ_count == 0)
- {
- m_IRQ_count = m_IRQ_count_latch;
- }
- else
- m_IRQ_count--;
-
- if (m_IRQ_enable && !blanked && (m_IRQ_count == 0) && priorCount)
- {
- m_maincpu->set_input_line(0, HOLD_LINE);
- }
- }
-}
-
-void vsnes_state::mapper4_w(offs_t offset, uint8_t data)
-{
- uint8_t MMC3_helper, cmd;
-
- switch (offset & 0x6001)
- {
- case 0x0000: /* $8000 */
- MMC3_helper = m_MMC3_cmd ^ data;
- m_MMC3_cmd = data;
-
- /* Has PRG Mode changed? */
- if (MMC3_helper & 0x40)
- mapper4_set_prg();
-
- /* Has CHR Mode changed? */
- if (MMC3_helper & 0x80)
- mapper4_set_chr();
- break;
-
- case 0x0001: /* $8001 */
- cmd = m_MMC3_cmd & 0x07;
- switch (cmd)
- {
- case 0: case 1: // these do not need to be separated: we take care of them in set_chr!
- case 2: case 3: case 4: case 5:
- m_MMC3_chr_bank[cmd] = data;
- mapper4_set_chr();
- break;
- case 6:
- case 7:
- m_MMC3_prg_bank[cmd - 6] = data;
- mapper4_set_prg();
- break;
- }
- break;
-
- case 0x2000: /* $a000 */
- if (data & 0x40)
- v_set_mirroring(1, PPU_MIRROR_HIGH);
- else
- {
- if (data & 0x01)
- v_set_mirroring(1, PPU_MIRROR_HORZ);
- else
- v_set_mirroring(1, PPU_MIRROR_VERT);
- }
- break;
-
- case 0x2001: /* $a001 - extra RAM enable/disable */
- /* ignored - we always enable it */
- break;
-
- case 0x4000: /* $c000 - IRQ scanline counter */
- m_IRQ_count = data;
- break;
-
- case 0x4001: /* $c001 - IRQ scanline latch */
- m_IRQ_count_latch = data;
- break;
-
- case 0x6000: /* $e000 - Disable IRQs */
- m_IRQ_enable = 0;
- m_IRQ_count = m_IRQ_count_latch;
- m_ppu1->set_scanline_callback(nullptr);
- break;
-
- case 0x6001: /* $e001 - Enable IRQs */
- m_IRQ_enable = 1;
- m_ppu1->set_scanline_callback(*this, FUNC(vsnes_state::mapper4_irq));
- break;
-
- default:
- logerror("mapper4_w uncaught: %04x value: %02x\n", offset + 0x8000, data);
- break;
- }
-}
-
-/* Common init for MMC3 games */
-
-void vsnes_state::init_MMC3()
-{
- uint8_t *prg = memregion("maincpu")->base();
- m_IRQ_enable = m_IRQ_count = m_IRQ_count_latch = 0;
- int MMC3_prg_chunks = (memregion("maincpu")->bytes() - 0x10000) / 0x4000;
-
- m_MMC3_prg_bank[0] = m_MMC3_prg_bank[2] = 0xfe;
- m_MMC3_prg_bank[1] = m_MMC3_prg_bank[3] = 0xff;
- m_MMC3_cmd = 0;
-
- m_MMC3_prg_mask = ((MMC3_prg_chunks << 1) - 1);
-
- memcpy(&prg[0x8000], &prg[(MMC3_prg_chunks - 1) * 0x4000 + 0x10000], 0x2000);
- memcpy(&prg[0xa000], &prg[(MMC3_prg_chunks - 1) * 0x4000 + 0x12000], 0x2000);
- memcpy(&prg[0xc000], &prg[(MMC3_prg_chunks - 1) * 0x4000 + 0x10000], 0x2000);
- memcpy(&prg[0xe000], &prg[(MMC3_prg_chunks - 1) * 0x4000 + 0x12000], 0x2000);
-
- /* MMC3 mapper at writes to $8000-$ffff */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x8000, 0xffff, write8sm_delegate(*this, FUNC(vsnes_state::mapper4_w)));
-
- /* extra ram at $6000-$7fff */
- m_extraram = std::make_unique<uint8_t[]>(0x2000);
- save_pointer(NAME(m_extraram.get()), 0x2000);
- m_maincpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, m_extraram.get());
-}
-
-/* Vs. RBI Baseball */
-
-uint8_t vsnes_state::rbi_hack_r(offs_t offset)
-{
- /* Supplied by Ben Parnell <xodnizel@home.com> of FCE Ultra fame */
-
-
- if (offset == 0)
- {
- m_VSindex=0;
- return 0xFF;
-
- }
- else
- {
- switch(m_VSindex++)
- {
- case 9:
- return 0x6F;
-
- case 14:
- return 0x94;
-
- default:
- return 0xB4;
- }
- }
-}
-
-void vsnes_state::init_rbibb()
-{
- init_MMC3();
-
- /* RBI Base ball hack */
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x5e00, 0x5e01, read8sm_delegate(*this, FUNC(vsnes_state::rbi_hack_r)));
-}
-
-/* Vs. Super Xevious */
-
-
-uint8_t vsnes_state::supxevs_read_prot_1_r()
-{
- return 0x05;
-}
-
-uint8_t vsnes_state::supxevs_read_prot_2_r()
-{
- if (m_supxevs_prot_index)
- return 0;
- else
- return 0x01;
-}
-
-uint8_t vsnes_state::supxevs_read_prot_3_r()
-{
- if (m_supxevs_prot_index)
- return 0xd1;
- else
- return 0x89;
-}
-
-uint8_t vsnes_state::supxevs_read_prot_4_r()
-{
- if (m_supxevs_prot_index)
- {
- m_supxevs_prot_index = 0;
- return 0x3e;
- }
- else
- {
- m_supxevs_prot_index = 1;
- return 0x37;
- }
-}
-
-
-void vsnes_state::init_supxevs()
-{
- init_MMC3();
-
- /* Vs. Super Xevious Protection */
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x54ff, 0x54ff, read8smo_delegate(*this, FUNC(vsnes_state::supxevs_read_prot_1_r)));
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x5678, 0x5678, read8smo_delegate(*this, FUNC(vsnes_state::supxevs_read_prot_2_r)));
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x578f, 0x578f, read8smo_delegate(*this, FUNC(vsnes_state::supxevs_read_prot_3_r)));
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x5567, 0x5567, read8smo_delegate(*this, FUNC(vsnes_state::supxevs_read_prot_4_r)));
-
- m_supxevs_prot_index = 0;
-}
-
-/* Vs. TKO Boxing */
-
-uint8_t vsnes_state::tko_security_r(offs_t offset)
-{
- static const uint8_t security_data[] = {
- 0xff, 0xbf, 0xb7, 0x97, 0x97, 0x17, 0x57, 0x4f,
- 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90, 0x94, 0x14,
- 0x56, 0x4e, 0x6f, 0x6b, 0xeb, 0xa9, 0xb1, 0x90,
- 0xd4, 0x5c, 0x3e, 0x26, 0x87, 0x83, 0x13, 0x00
- };
-
- if (offset == 0)
- {
- m_security_counter = 0;
- return 0;
- }
-
- return security_data[(m_security_counter++)];
-
-}
-
-void vsnes_state::init_tkoboxng()
-{
- init_MMC3();
-
- /* security device at $5e00-$5e01 */
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x5e00, 0x5e01, read8sm_delegate(*this, FUNC(vsnes_state::tko_security_r)));
-}
-
-/* Vs. Freedom Force */
-
-void vsnes_state::init_vsfdf()
-{
- init_MMC3();
-
- m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x4016, 0x4016, read8smo_delegate(*this, FUNC(vsnes_state::gun_in0_r)), write8smo_delegate(*this, FUNC(vsnes_state::gun_in0_w)));
-
- m_do_vrom_bank = 0;
-}
-
-/**********************************************************************************/
-/* Platoon rom banking */
-
-void vsnes_state::mapper68_rom_banking(offs_t offset, uint8_t data)
-{
- switch (offset & 0x7000)
- {
- case 0x0000:
- v_set_videorom_bank(0, 2, data * 2);
-
- break;
- case 0x1000:
- v_set_videorom_bank(2, 2, data * 2);
-
- break;
- case 0x2000:
- v_set_videorom_bank(4, 2, data * 2);
-
- break;
- case 0x3000: /* ok? */
- v_set_videorom_bank(6, 2, data * 2);
-
- break;
-
- case 0x7000:
- {
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000], &prg[0x10000 + data * 0x4000], 0x4000);
- }
- break;
-
- }
-
-}
-
-void vsnes_state::init_platoon()
-{
- /* when starting a mapper 68 game the first 16K ROM bank in the cart is loaded into $8000
- the LAST 16K ROM bank is loaded into $C000. The last 16K of ROM cannot be swapped. */
-
- uint8_t *prg = memregion("maincpu")->base();
- memcpy(&prg[0x08000], &prg[0x10000], 0x4000);
- memcpy(&prg[0x0c000], &prg[0x2c000], 0x4000);
-
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x8000, 0xffff, write8sm_delegate(*this, FUNC(vsnes_state::mapper68_rom_banking)));
-}
-
-/**********************************************************************************/
-/* Vs. Raid on Bungeling Bay (Japan) */
-
-void vsnes_state::set_bnglngby_irq_w(uint8_t data)
-{
- m_ret = data;
- m_maincpu->set_input_line(0, (data & 2) ? ASSERT_LINE : CLEAR_LINE);
- /* other values ??? */
- /* 0, 4, 84 */
-}
-
-uint8_t vsnes_state::set_bnglngby_irq_r()
-{
- return m_ret;
-}
-
-void vsnes_state::init_bnglngby()
-{
- m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x0231, 0x0231, read8smo_delegate(*this, FUNC(vsnes_state::set_bnglngby_irq_r)), write8smo_delegate(*this, FUNC(vsnes_state::set_bnglngby_irq_w)));
-
- /* extra ram */
- m_extraram = std::make_unique<uint8_t[]>(0x2000);
- save_pointer(NAME(m_extraram.get()), 0x2000);
- m_maincpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, m_extraram.get());
-
- m_ret = 0;
-
- /* normal banking */
- init_vsnormal();
-}
-
-/**********************************************************************************/
-/* VS Dualsystem */
-
-void vsnes_state::vsdual_vrom_banking_main(uint8_t data)
-{
- /* switch vrom */
- m_bank_vrom[0]->set_entry(BIT(data, 2));
-
- /* bit 1 ( data & 2 ) triggers irq on the other cpu */
- m_subcpu->set_input_line(0, (data & 2) ? CLEAR_LINE : ASSERT_LINE);
-
- /* move along */
- vsnes_in0_w(data);
-}
-
-void vsnes_state::vsdual_vrom_banking_sub(uint8_t data)
-{
- /* switch vrom */
- m_bank_vrom[1]->set_entry(BIT(data, 2));
-
- /* bit 1 ( data & 2 ) triggers irq on the other cpu */
- m_maincpu->set_input_line(0, (data & 2) ? CLEAR_LINE : ASSERT_LINE);
-
- /* move along */
- vsnes_in0_1_w(data);
-}
-
-void vsnes_state::init_vsdual()
-{
- uint8_t *prg = memregion("maincpu")->base();
-
- /* vrom switching is enabled with bit 2 of $4016 */
- m_maincpu->space(AS_PROGRAM).install_write_handler(0x4016, 0x4016, write8smo_delegate(*this, FUNC(vsnes_state::vsdual_vrom_banking_main)));
- m_subcpu->space(AS_PROGRAM).install_write_handler(0x4016, 0x4016, write8smo_delegate(*this, FUNC(vsnes_state::vsdual_vrom_banking_sub)));
-
- /* shared ram at $6000 */
- m_maincpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, &prg[0x6000]);
- m_subcpu->space(AS_PROGRAM).install_ram(0x6000, 0x7fff, &prg[0x6000]);
-}
-
-/**********************************************************************************/
-/* Vs. Super Mario Bros (Bootleg) */
-
-void vsnes_state::vsnes_bootleg_scanline(int scanline, int vblank, int blanked)
-{
- // Z80 IRQ is controlled by two factors:
- // - bit 6 of current (next) scanline number
- // - bit 6 of latched scanline number from Z80 reading $4000
- if (!(m_bootleg_latched_scanline & 0x40))
- {
- m_subcpu->set_input_line(INPUT_LINE_IRQ0, ((scanline + 1) & 0x40) ? ASSERT_LINE : CLEAR_LINE);
- }
-}
-
-uint8_t vsnes_state::vsnes_bootleg_ppudata()
-{
- // CPU always reads higher CHR ROM banks from $2007, PPU always reads lower ones
- m_bank_vrom[0]->set_entry(1);
- uint8_t data = m_ppu1->read(0x2007);
- m_bank_vrom[0]->set_entry(0);
-
- return data;
-}
-
-void vsnes_state::init_bootleg()
-{
- m_bootleg_sound_offset = 0;
- m_bootleg_sound_data = 0;
- m_bootleg_latched_scanline = 0;
-
- m_ppu1->set_scanline_callback(*this, FUNC(vsnes_state::vsnes_bootleg_scanline));
-
- m_maincpu->space(AS_PROGRAM).install_read_handler(0x2007, 0x2007, read8smo_delegate(*this, FUNC(vsnes_state::vsnes_bootleg_ppudata)));
-}