diff options
Diffstat (limited to 'src/mame/machine/vsnes.cpp')
-rw-r--r-- | src/mame/machine/vsnes.cpp | 1109 |
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))); -} |