diff options
Diffstat (limited to 'src/mame/drivers/snes.cpp')
-rw-r--r-- | src/mame/drivers/snes.cpp | 1397 |
1 files changed, 1397 insertions, 0 deletions
diff --git a/src/mame/drivers/snes.cpp b/src/mame/drivers/snes.cpp new file mode 100644 index 00000000000..f92d7a5098e --- /dev/null +++ b/src/mame/drivers/snes.cpp @@ -0,0 +1,1397 @@ +// license:BSD-3-Clause +// copyright-holders:Angelo Salese, R. Belmont, Anthony Kruize, Fabio Priuli +/*************************************************************************** + + snes.c + + Driver file to handle emulation of the Nintendo Super NES. + + Based on original MESS driver by Lee Hammerton (aka Savoury Snax), + later contributions by + R. Belmont + Anthony Kruize + Angelo Salese + Fabio Priuli + byuu (extensive RE of both SNES and add-on chips) + + + Todo (in no particular order): + - Fix sync between 5A22, SPC700 and PPU + - Fix remaining sound and video bugs + - Fix vertical mosaic effects + - Add support for real CX4 and ST018 CPUs + - Add support for SA-1 and SuperGB add-ons + - Fix superscope support + - Add support for other controllers + +***************************************************************************/ + +#include "emu.h" +#include "audio/snes_snd.h" +#include "cpu/spc700/spc700.h" +#include "includes/snes.h" +#include "machine/snescx4.h" + +#include "bus/snes/snes_slot.h" +#include "bus/snes/snes_carts.h" +#include "bus/snes_ctrl/ctrl.h" +#include "softlist.h" + +class snes_console_state : public snes_state +{ +public: + snes_console_state(const machine_config &mconfig, device_type type, const char *tag) + : snes_state(mconfig, type, tag) + , m_ctrl1(*this, "ctrl1") + , m_ctrl2(*this, "ctrl2") + , m_cartslot(*this, "snsslot") + { } + + DECLARE_READ8_MEMBER( snes20_hi_r ); + DECLARE_WRITE8_MEMBER( snes20_hi_w ); + DECLARE_READ8_MEMBER( snes20_lo_r ); + DECLARE_WRITE8_MEMBER( snes20_lo_w ); + DECLARE_READ8_MEMBER( snes21_lo_r ); + DECLARE_WRITE8_MEMBER( snes21_lo_w ); + DECLARE_READ8_MEMBER( snes21_hi_r ); + DECLARE_WRITE8_MEMBER( snes21_hi_w ); + DECLARE_READ8_MEMBER( snessfx_hi_r ); + DECLARE_READ8_MEMBER( snessfx_lo_r ); + DECLARE_WRITE8_MEMBER( snessfx_hi_w ); + DECLARE_WRITE8_MEMBER( snessfx_lo_w ); + DECLARE_READ8_MEMBER( snessa1_hi_r ); + DECLARE_READ8_MEMBER( snessa1_lo_r ); + DECLARE_WRITE8_MEMBER( snessa1_hi_w ); + DECLARE_WRITE8_MEMBER( snessa1_lo_w ); + DECLARE_READ8_MEMBER( snes7110_hi_r ); + DECLARE_READ8_MEMBER( snes7110_lo_r ); + DECLARE_WRITE8_MEMBER( snes7110_hi_w ); + DECLARE_WRITE8_MEMBER( snes7110_lo_w ); + DECLARE_READ8_MEMBER( snessdd1_lo_r ); + DECLARE_WRITE8_MEMBER( snessdd1_lo_w ); + DECLARE_READ8_MEMBER( snessdd1_hi_r ); + DECLARE_WRITE8_MEMBER( snessdd1_hi_w ); + DECLARE_READ8_MEMBER( snesbsx_hi_r ); + DECLARE_WRITE8_MEMBER( snesbsx_hi_w ); + DECLARE_READ8_MEMBER( snesbsx_lo_r ); + DECLARE_WRITE8_MEMBER( snesbsx_lo_w ); + DECLARE_READ8_MEMBER( snessgb_hi_r ); + DECLARE_READ8_MEMBER( snessgb_lo_r ); + DECLARE_WRITE8_MEMBER( snessgb_hi_w ); + DECLARE_WRITE8_MEMBER( snessgb_lo_w ); + DECLARE_READ8_MEMBER( pfest94_hi_r ); + DECLARE_WRITE8_MEMBER( pfest94_hi_w ); + DECLARE_READ8_MEMBER( pfest94_lo_r ); + DECLARE_WRITE8_MEMBER( pfest94_lo_w ); + + DECLARE_READ8_MEMBER( spc_ram_100_r ); + DECLARE_WRITE8_MEMBER( spc_ram_100_w ); + TIMER_CALLBACK_MEMBER( lightgun_tick ); + + // input related + SNESCTRL_ONSCREEN_CB(onscreen_cb); + SNESCTRL_GUNLATCH_CB(gun_latch_cb); + virtual DECLARE_WRITE8_MEMBER(io_read); + virtual UINT8 oldjoy1_read(int latched); + virtual UINT8 oldjoy2_read(int latched); + virtual void write_joy_latch(UINT8 data); + virtual void wrio_write(UINT8 data); + + virtual void machine_start(); + virtual void machine_reset(); + int m_type; + required_device<snes_control_port_device> m_ctrl1; + required_device<snes_control_port_device> m_ctrl2; + optional_device<sns_cart_slot_device> m_cartslot; +}; + + +/************************************* + * + * Memory handlers + * + *************************************/ + +// SPC access + +READ8_MEMBER(snes_console_state::spc_ram_100_r ) +{ + return m_spc700->spc_ram_r(space, offset + 0x100); +} + +WRITE8_MEMBER(snes_console_state::spc_ram_100_w ) +{ + m_spc700->spc_ram_w(space, offset + 0x100, data); +} + +// Memory access for the various types of carts + +//--------------------------------------------------------------------------------- +// LoROM & LoROM + BSX slot & LoROM + some add-on chips +//--------------------------------------------------------------------------------- + +// In general LoROM games have perfect mirror between 0x00-0x7d and 0x80-0xff +// But BSX+LoROM games use different read handlers (to access ROM beyond 2MB) +// so we use two different set of handlers... + +// Also we have here LoROM + CX4, until the Hitachi CPU is emulated, +// and the LoROM + Seta DSP, because their chip_read/chip_write need global offset + +READ8_MEMBER( snes_console_state::snes20_hi_r ) +{ + UINT16 address = offset & 0xffff; + + // take care of add-on IO + if ((m_cartslot->get_type() == SNES_ST010 || m_cartslot->get_type() == SNES_ST011) + && (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000)) + return m_cartslot->chip_read(space, offset); + else if ((m_cartslot->get_type() == SNES_ST010 || m_cartslot->get_type() == SNES_ST011) + && (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000)) + return m_cartslot->chip_read(space, offset); + else if (m_cartslot->get_type() == SNES_CX4 + && (offset < 0x400000 && (offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)) // hack until we emulate the real CPU + return CX4_read((offset & 0xffff) - 0x6000); + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else if (address < 0x8000) + return snes_open_bus_r(space, 0); + else + return m_cartslot->read_h(space, offset); + } + else if (offset < 0x700000) + { + if (address < 0x8000) + return snes_open_bus_r(space, 0); + else + return m_cartslot->read_h(space, offset); + } + else + { + if (m_type == SNES_SUFAMITURBO && address >= 0x8000 && offset < 0x740000) + return m_cartslot->read_h(space, offset); + + // here usually there is SRAM mirrored in the whole range, but if ROM is very large then arrives here too (see tokimeki and wizardg4) + if (m_cartslot->m_cart->get_rom_size() > 0x200000 && address >= 0x8000) + return m_cartslot->read_h(space, offset); + else + { + if (m_cartslot->m_cart->get_nvram_size() > 0x8000) + { + // In this case, SRAM is mapped in 0x8000 chunks at diff offsets: 0x700000-0x707fff, 0x710000-0x717fff, etc. + offset = ((offset - 0x700000) / 0x10000) * 0x8000 + (offset & 0x7fff); + return m_cartslot->read_ram(space, offset); + } + else if (m_cartslot->m_cart->get_nvram_size() > 0) + return m_cartslot->read_ram(space, offset); + else + return snes_open_bus_r(space, 0); + } + } +} + +WRITE8_MEMBER( snes_console_state::snes20_hi_w ) +{ + UINT16 address = offset & 0xffff; + + // take care of add-on IO + if ((m_cartslot->get_type() == SNES_ST010 || m_cartslot->get_type() == SNES_ST011) + && (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000)) + { m_cartslot->chip_write(space, offset, data); return; } + else if ((m_cartslot->get_type() == SNES_ST010 || m_cartslot->get_type() == SNES_ST011) + && (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000)) + { m_cartslot->chip_write(space, offset, data); return; } + else if (m_cartslot->get_type() == SNES_CX4 + && (offset < 0x400000 && (offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)) // hack until we emulate the real CPU + { CX4_write(space.machine(), (offset & 0xffff) - 0x6000, data); return; } + else if (m_type == SNES_SUFAMITURBO + && address >= 0x8000 && ((offset >= 0x600000 && offset < 0x640000) || (offset >= 0x700000 && offset < 0x740000))) + { m_cartslot->write_h(space, offset, data); return; } + + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + snes_w_io(space, address, data); + } + else if (offset >= 0x700000 && (m_cartslot->m_cart->get_rom_size() <= 0x200000 || address < 0x8000)) // NVRAM access + { + if (m_cartslot->m_cart->get_nvram_size() > 0x8000) + { + // In this case, SRAM is mapped in 0x8000 chunks at diff offsets: 0x700000-0x707fff, 0x710000-0x717fff, etc. + offset = ((offset - 0x700000) / 0x10000) * 0x8000 + (offset & 0x7fff); + m_cartslot->write_ram(space, offset, data); + } + else if (m_cartslot->m_cart->get_nvram_size() > 0) + m_cartslot->write_ram(space, offset, data); + } +} + +READ8_MEMBER( snes_console_state::snes20_lo_r ) +{ + UINT16 address = offset & 0xffff; + + // take care of add-on IO + if ((m_cartslot->get_type() == SNES_ST010 /*|| m_cartslot->get_type() == SNES_ST011*/) // why does this break moritash? + && (offset >= 0x600000 && offset < 0x680000 && (offset & 0xffff) < 0x4000)) + return m_cartslot->chip_read(space, offset); + else if ((m_cartslot->get_type() == SNES_ST010 || m_cartslot->get_type() == SNES_ST011) + && (offset >= 0x680000 && offset < 0x700000 && (offset & 0xffff) < 0x8000)) + return m_cartslot->chip_read(space, offset); + else if (m_cartslot->get_type() == SNES_CX4 + && (offset < 0x400000 && (offset & 0xffff) >= 0x6000 && (offset & 0xffff) < 0x8000)) // hack until we emulate the real CPU + return CX4_read((offset & 0xffff) - 0x6000); + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else if (address < 0x8000) + return snes_open_bus_r(space, 0); + else + return m_cartslot->read_l(space, offset); + } + else if (offset < 0x700000) + { + if (address < 0x8000) + return snes_open_bus_r(space, 0); + else + return m_cartslot->read_l(space, offset); + } + else + { + if (m_type == SNES_SUFAMITURBO && address >= 0x8000 && offset < 0x740000) + return m_cartslot->read_l(space, offset); + + // here usually there is SRAM mirrored in the whole range, but if ROM is very large then arrives here too (see tokimeki and wizardg4) + if (m_cartslot->m_cart->get_rom_size() > 0x200000 && address >= 0x8000) + return m_cartslot->read_l(space, offset); + else + { + if (m_cartslot->m_cart->get_nvram_size() > 0x8000) + { + // In this case, SRAM is mapped in 0x8000 chunks at diff offsets: 0x700000-0x707fff, 0x710000-0x717fff, etc. + offset = ((offset - 0x700000) / 0x10000) * 0x8000 + (offset & 0x7fff); + return m_cartslot->read_ram(space, offset); + } + else if (m_cartslot->m_cart->get_nvram_size() > 0) + return m_cartslot->read_ram(space, offset); + else + return snes_open_bus_r(space, 0); + } + } +} + +WRITE8_MEMBER( snes_console_state::snes20_lo_w ) +{ + if (m_type == SNES_SUFAMITURBO + && (offset & 0xffff) >= 0x8000 && ((offset >= 0x600000 && offset < 0x640000) || (offset >= 0x700000 && offset < 0x740000))) + { m_cartslot->write_l(space, offset, data); return; } + + // other add-on writes matches the hi handler + snes20_hi_w(space, offset, data, 0xff); +} + + +//--------------------------------------------------------------------------------- +// HiROM & HiROM + BSX slot +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snes21_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000 && address < 0x8000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else + { + if (m_type == SNES_BSXHI && m_cartslot->m_cart->get_nvram_size() && offset >= 0x200000) + { + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; + return m_cartslot->read_ram(space, (offset - 0x6000) & mask); + } + + if (m_cartslot->m_cart->get_nvram_size() && offset >= 0x300000) + { + /* Donkey Kong Country checks this and detects a copier if 0x800 is not masked out due to sram size */ + /* OTOH Secret of Mana does not work properly if sram is not mirrored on later banks */ + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; /* Limit SRAM size to what's actually present */ + return m_cartslot->read_ram(space, (offset - 0x6000) & mask); + } + else + return snes_open_bus_r(space, 0); + } + } + + // ROM access + return m_cartslot->read_l(space, offset); +} + +WRITE8_MEMBER( snes_console_state::snes21_lo_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000 && address < 0x8000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + snes_w_io(space, address, data); + else + { + if (m_type == SNES_BSXHI && m_cartslot->m_cart->get_nvram_size() && offset >= 0x200000) + { + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; + m_cartslot->write_ram(space, (offset - 0x6000) & mask, data); + return; + } + if (m_cartslot->m_cart->get_nvram_size() && offset >= 0x300000) + { + /* Donkey Kong Country checks this and detects a copier if 0x800 is not masked out due to sram size */ + /* OTOH Secret of Mana does not work properly if sram is not mirrored on later banks */ + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; /* Limit SRAM size to what's actually present */ + m_cartslot->write_ram(space, (offset - 0x6000) & mask, data); + } + } + } +} + +READ8_MEMBER( snes_console_state::snes21_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000 && address < 0x8000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else + { + if (m_type == SNES_BSXHI && m_cartslot->m_cart->get_nvram_size() && offset >= 0x200000) + { + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; + return m_cartslot->read_ram(space, (offset - 0x6000) & mask); + } + + if (m_cartslot->m_cart->get_nvram_size() && offset >= 0x300000) + { + /* Donkey Kong Country checks this and detects a copier if 0x800 is not masked out due to sram size */ + /* OTOH Secret of Mana does not work properly if sram is not mirrored on later banks */ + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; /* Limit SRAM size to what's actually present */ + return m_cartslot->read_ram(space, (offset - 0x6000) & mask); + } + else + return snes_open_bus_r(space, 0); + } + } + + // ROM access + return m_cartslot->read_h(space, offset); +} + +WRITE8_MEMBER( snes_console_state::snes21_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000 && address < 0x8000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + snes_w_io(space, address, data); + else + { + if (m_type == SNES_BSXHI && m_cartslot->m_cart->get_nvram_size() && offset >= 0x200000) + { + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; + m_cartslot->write_ram(space, (offset - 0x6000) & mask, data); + return; + } + if (m_cartslot->m_cart->get_nvram_size() && offset >= 0x300000) + { + /* Donkey Kong Country checks this and detects a copier if 0x800 is not masked out due to sram size */ + /* OTOH Secret of Mana does not work properly if sram is not mirrored on later banks */ + int mask = (m_cartslot->m_cart->get_nvram_size() - 1) & 0x7fff; /* Limit SRAM size to what's actually present */ + m_cartslot->write_ram(space, (offset - 0x6000) & mask, data); + } + } + } +} + +//--------------------------------------------------------------------------------- +// LoROM + SuperFX / GSU +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snessfx_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x3000 && address < 0x3300) + return m_cartslot->chip_read(space, offset); + else + return snes_r_io(space, address); + } + else if (address < 0x8000) + return m_cartslot->read_ram(space, offset & 0x1fff); + else + return m_cartslot->read_h(space, offset); + } + else if (offset < 0x600000) + return m_cartslot->read_h(space, offset); + else + return m_cartslot->read_ram(space, offset); +} + +READ8_MEMBER( snes_console_state::snessfx_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x3000 && address < 0x3300) + return m_cartslot->chip_read(space, offset); + else + return snes_r_io(space, address); + } + else if (address < 0x8000) + return m_cartslot->read_ram(space, offset & 0x1fff); + else + return m_cartslot->read_l(space, offset); + } + else if (offset < 0x600000) + return m_cartslot->read_l(space, offset); + else + return m_cartslot->read_ram(space, offset); +} + +WRITE8_MEMBER( snes_console_state::snessfx_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + { + if (address >= 0x3000 && address < 0x3300) + m_cartslot->chip_write(space, offset, data); + else + snes_w_io(space, address, data); + } + else if (address < 0x8000) + m_cartslot->write_ram(space, offset & 0x1fff, data); + } + else if (offset >= 0x600000) + m_cartslot->write_ram(space, offset, data); +} + +WRITE8_MEMBER( snes_console_state::snessfx_lo_w ) +{ + snessfx_hi_w(space, offset, data, 0xff); +} + +//--------------------------------------------------------------------------------- +// LoROM + SA-1 +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snessa1_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x2200 && address < 0x2400) + return m_cartslot->chip_read(space, offset); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + return m_cartslot->chip_read(space, offset); // Internal SA-1 RAM (2K) + else + return snes_r_io(space, address); + } + else if (address < 0x8000) + return m_cartslot->chip_read(space, offset); // SA-1 BWRAM + else + return m_cartslot->read_h(space, offset); + } + else + return m_cartslot->read_h(space, offset); +} + +READ8_MEMBER( snes_console_state::snessa1_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x2200 && address < 0x2400) + return m_cartslot->chip_read(space, offset); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + return m_cartslot->chip_read(space, offset); // Internal SA-1 RAM (2K) + else + return snes_r_io(space, address); + } + else if (address < 0x8000) + return m_cartslot->chip_read(space, offset); // SA-1 BWRAM + else + return m_cartslot->read_l(space, offset); + } + else if (offset < 0x500000) + return m_cartslot->chip_read(space, offset); // SA-1 BWRAM (not mirrored above!) + else + return snes_r_io(space, address); // nothing mapped here! +} + +WRITE8_MEMBER( snes_console_state::snessa1_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + { + if (address >= 0x2200 && address < 0x2400) + m_cartslot->chip_write(space, offset, data); // SA-1 Regs + else if (address >= 0x3000 && address < 0x3800) + m_cartslot->chip_write(space, offset, data); // Internal SA-1 RAM (2K) + else + snes_w_io(space, address, data); + } + else if (address < 0x8000) + m_cartslot->chip_write(space, offset, data); // SA-1 BWRAM + } +} + +WRITE8_MEMBER( snes_console_state::snessa1_lo_w ) +{ + if (offset >= 0x400000 && offset < 0x500000) + m_cartslot->chip_write(space, offset, data); // SA-1 BWRAM (not mirrored above!) + else + snessa1_hi_w(space, offset, data, 0xff); +} + +//--------------------------------------------------------------------------------- +// HiROM + SPC-7110 +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snes7110_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + UINT16 limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; + if (address >= 0x4800 && address < limit) + return m_cartslot->chip_read(space, address); + + return snes_r_io(space, address); + } + else if (address < 0x8000) + { + if (offset < 0x10000) + return m_cartslot->read_ram(space, offset); + if (offset >= 0x300000 && offset < 0x310000) + return m_cartslot->read_ram(space, offset); + } + else + return m_cartslot->read_h(space, offset); + } + return m_cartslot->read_h(space, offset); +} + +READ8_MEMBER( snes_console_state::snes7110_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + UINT16 limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; + if (address >= 0x4800 && address < limit) + return m_cartslot->chip_read(space, address); + + return snes_r_io(space, address); + } + else if (address < 0x8000) + { + if (offset < 0x10000) + return m_cartslot->read_ram(space, offset); + if (offset >= 0x300000 && offset < 0x310000) + return m_cartslot->read_ram(space, offset); + } + else + return m_cartslot->read_l(space, offset); + } + if (offset >= 0x500000 && offset < 0x510000) + return m_cartslot->chip_read(space, 0x4800); + + return snes_open_bus_r(space, 0); +} + +WRITE8_MEMBER( snes_console_state::snes7110_hi_w ) +{ + snes7110_lo_w(space, offset, data, 0xff); +} + +WRITE8_MEMBER( snes_console_state::snes7110_lo_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + { + UINT16 limit = (m_cartslot->get_type() == SNES_SPC7110_RTC) ? 0x4843 : 0x4840; + if (address >= 0x4800 && address < limit) + { + m_cartslot->chip_write(space, address, data); + return; + } + snes_w_io(space, address, data); + } + else if (address < 0x8000) + { + if (offset < 0x10000) + m_cartslot->write_ram(space, offset, data); + if (offset >= 0x300000 && offset < 0x310000) + m_cartslot->write_ram(space, offset, data); + } + } +} + + +//--------------------------------------------------------------------------------- +// LoROM + S-DD1 +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snessdd1_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x4800 && address < 0x4808) + return m_cartslot->chip_read(space, address); + + return snes_r_io(space, address); + } + else if (address < 0x8000) + return snes_open_bus_r(space, 0); + else + return m_cartslot->read_l(space, offset); + } + else if (offset >= 0x700000 && address < 0x8000 && m_cartslot->m_cart->get_nvram_size()) // NVRAM access + return m_cartslot->read_ram(space, offset); + else // ROM access + return m_cartslot->read_l(space, offset); +} + +READ8_MEMBER( snes_console_state::snessdd1_hi_r ) +{ + if (offset >= 0x400000) + return m_cartslot->read_h(space, offset); + else + return snessdd1_lo_r(space, offset, 0xff); +} + +WRITE8_MEMBER( snes_console_state::snessdd1_lo_w ) +{ + snessdd1_hi_w(space, offset, data, 0xff); +} + +WRITE8_MEMBER( snes_console_state::snessdd1_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + { + if (address >= 0x4300 && address < 0x4380) + { + m_cartslot->chip_write(space, address, data); + // here we don't return, but we let the w_io happen... + } + if (address >= 0x4800 && address < 0x4808) + { + m_cartslot->chip_write(space, address, data); + return; + } + snes_w_io(space, address, data); + } + } + if (offset >= 0x700000 && address < 0x8000 && m_cartslot->m_cart->get_nvram_size()) + return m_cartslot->write_ram(space, offset, data); +} + + +//--------------------------------------------------------------------------------- +// LoROM + BS-X (Base unit) +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snesbsx_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x2188 && address < 0x21a0) + return m_cartslot->chip_read(space, offset); + if (address >= 0x5000) + return m_cartslot->chip_read(space, offset); + return snes_r_io(space, address); + } + else if (address < 0x8000) + { + if (offset >= 0x200000) + return m_cartslot->read_h(space, offset); + else + return snes_open_bus_r(space, 0); + } + else + return m_cartslot->read_h(space, offset); + } + return m_cartslot->read_h(space, offset); +} + +WRITE8_MEMBER( snes_console_state::snesbsx_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + { + if (address >= 0x2188 && address < 0x21a0) + { + m_cartslot->chip_write(space, offset, data); + return; + } + if (address >= 0x5000) + { + m_cartslot->chip_write(space, offset, data); + return; + } + snes_w_io(space, address, data); + } + else if (address < 0x8000) + { + if (offset >= 0x200000) + return m_cartslot->write_l(space, offset, data); + } + else + return m_cartslot->write_l(space, offset, data); + } + return m_cartslot->write_l(space, offset, data); +} + +READ8_MEMBER( snes_console_state::snesbsx_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + { + if (address >= 0x2188 && address < 0x21a0) + return m_cartslot->chip_read(space, offset); + if (address >= 0x5000) + return m_cartslot->chip_read(space, offset); + return snes_r_io(space, address); + } + else if (address < 0x8000) + { + if (offset >= 0x200000) + return m_cartslot->read_l(space, offset); + else + return snes_open_bus_r(space, 0); + } + else + return m_cartslot->read_l(space, offset); + } + return m_cartslot->read_l(space, offset); +} + +WRITE8_MEMBER( snes_console_state::snesbsx_lo_w ) +{ + snesbsx_hi_w(space, offset, data, 0xff); +} + + +//--------------------------------------------------------------------------------- +// LoROM + SuperGB +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::snessgb_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else if (address < 0x8000) + return m_cartslot->chip_read(space, offset); + else + return m_cartslot->read_h(space, offset); + } + else if (address >= 0x8000) + return m_cartslot->read_h(space, offset); + + return snes_open_bus_r(space, 0); +} + +READ8_MEMBER( snes_console_state::snessgb_lo_r ) +{ + return snessgb_hi_r(space, offset, 0xff); +} + +WRITE8_MEMBER( snes_console_state::snessgb_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + snes_w_io(space, address, data); + else if (address < 0x8000) + m_cartslot->chip_write(space, offset, data); + } +} + +WRITE8_MEMBER( snes_console_state::snessgb_lo_w ) +{ + snessgb_hi_w(space, offset, data, 0xff); +} + +//--------------------------------------------------------------------------------- +// Powerfest '94 event cart +//--------------------------------------------------------------------------------- + +READ8_MEMBER( snes_console_state::pfest94_hi_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else if (address < 0x8000) + { + if (offset < 0x100000) // DSP access + return m_cartslot->chip_read(space, offset); + else if (offset == 0x106000) // menu access + return m_cartslot->chip_read(space, offset + 0x8000); + else if (offset >= 0x300000 && m_cartslot->m_cart->get_nvram_size()) // NVRAM access + return m_cartslot->read_ram(space, offset); + else + return snes_open_bus_r(space, 0); + } + else + return m_cartslot->read_h(space, offset); + } + return m_cartslot->read_h(space, offset); +} + +WRITE8_MEMBER( snes_console_state::pfest94_hi_w ) +{ + UINT16 address = offset & 0xffff; + if (offset < 0x400000) + { + if (address < 0x2000) + space.write_byte(0x7e0000 + address, data); + else if (address < 0x6000) + snes_w_io(space, address, data); + else if (address < 0x8000) + { + if (offset < 0x100000) // DSP access + m_cartslot->chip_write(space, offset, data); + else if (offset == 0x206000) // menu access + m_cartslot->chip_write(space, offset + 0x8000, data); + else if (offset >= 0x300000 && m_cartslot->m_cart->get_nvram_size()) // NVRAM access + m_cartslot->write_ram(space, offset, data); + } + } +} + +READ8_MEMBER( snes_console_state::pfest94_lo_r ) +{ + UINT16 address = offset & 0xffff; + + if (offset < 0x400000) + { + if (address < 0x2000) + return space.read_byte(0x7e0000 + address); + else if (address < 0x6000) + return snes_r_io(space, address); + else if (address < 0x8000) + { + if (offset < 0x100000) // DSP access + return m_cartslot->chip_read(space, offset); + else if (offset == 0x106000) // menu access + return m_cartslot->chip_read(space, offset + 0x8000); + else if (offset >= 0x300000 && m_cartslot->m_cart->get_nvram_size()) // NVRAM access + return m_cartslot->read_ram(space, offset); + else + return snes_open_bus_r(space, 0); + } + else + return m_cartslot->read_l(space, offset); + } + return 0xff; // or open_bus? +} + +WRITE8_MEMBER( snes_console_state::pfest94_lo_w ) +{ + pfest94_hi_w(space, offset, data, 0xff); +} + + +/************************************* + * + * Address maps + * + *************************************/ + +static ADDRESS_MAP_START( snes_map, AS_PROGRAM, 8, snes_console_state ) +// AM_RANGE(0x000000, 0x7dffff) AM_READWRITE(snes20_lo_r, snes20_lo_w) + AM_RANGE(0x7e0000, 0x7fffff) AM_RAM /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */ +// AM_RANGE(0x800000, 0xffffff) AM_READWRITE(snes20_hi_r, snes20_hi_w) +ADDRESS_MAP_END + +static ADDRESS_MAP_START( spc_map, AS_PROGRAM, 8, snes_console_state ) + AM_RANGE(0x0000, 0x00ef) AM_DEVREADWRITE("spc700", snes_sound_device, spc_ram_r, spc_ram_w) /* lower 32k ram */ + AM_RANGE(0x00f0, 0x00ff) AM_DEVREADWRITE("spc700", snes_sound_device, spc_io_r, spc_io_w) /* spc io */ + AM_RANGE(0x0100, 0xffff) AM_READWRITE(spc_ram_100_r, spc_ram_100_w) +ADDRESS_MAP_END + + +/************************************* + * + * Input ports + * + *************************************/ + +static INPUT_PORTS_START( snes ) + // input devices go through slot options + PORT_START("OPTIONS") + PORT_CONFNAME( 0x01, 0x00, "Hi-Res pixels blurring (TV effect)") + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x01, DEF_STR( On ) ) + +#if SNES_LAYER_DEBUG + PORT_START("DEBUG1") + PORT_CONFNAME( 0x03, 0x00, "Select BG1 priority" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x01, "BG1B (lower) only" ) + PORT_CONFSETTING( 0x02, "BG1A (higher) only" ) + PORT_CONFNAME( 0x0c, 0x00, "Select BG2 priority" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x04, "BG2B (lower) only" ) + PORT_CONFSETTING( 0x08, "BG2A (higher) only" ) + PORT_CONFNAME( 0x30, 0x00, "Select BG3 priority" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x10, "BG3B (lower) only" ) + PORT_CONFSETTING( 0x20, "BG3A (higher) only" ) + PORT_CONFNAME( 0xc0, 0x00, "Select BG4 priority" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x40, "BG4B (lower) only" ) + PORT_CONFSETTING( 0x80, "BG4A (higher) only" ) + + PORT_START("DEBUG2") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 1") PORT_CODE(KEYCODE_1_PAD) PORT_TOGGLE + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 2") PORT_CODE(KEYCODE_2_PAD) PORT_TOGGLE + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 3") PORT_CODE(KEYCODE_3_PAD) PORT_TOGGLE + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle BG 4") PORT_CODE(KEYCODE_4_PAD) PORT_TOGGLE + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Objects") PORT_CODE(KEYCODE_5_PAD) PORT_TOGGLE + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Main/Sub") PORT_CODE(KEYCODE_6_PAD) PORT_TOGGLE + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Color Math") PORT_CODE(KEYCODE_7_PAD) PORT_TOGGLE + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Windows") PORT_CODE(KEYCODE_8_PAD) PORT_TOGGLE + + PORT_START("DEBUG3") + PORT_BIT( 0x4, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mosaic") PORT_CODE(KEYCODE_9_PAD) PORT_TOGGLE + PORT_CONFNAME( 0x70, 0x00, "Select OAM priority" ) + PORT_CONFSETTING( 0x00, "All" ) + PORT_CONFSETTING( 0x10, "OAM0 only" ) + PORT_CONFSETTING( 0x20, "OAM1 only" ) + PORT_CONFSETTING( 0x30, "OAM2 only" ) + PORT_CONFSETTING( 0x40, "OAM3 only" ) + PORT_CONFNAME( 0x80, 0x00, "Draw sprite in reverse order" ) + PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) + PORT_CONFSETTING( 0x80, DEF_STR( On ) ) + + PORT_START("DEBUG4") + PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 0 draw") PORT_TOGGLE + PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 1 draw") PORT_TOGGLE + PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 2 draw") PORT_TOGGLE + PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 3 draw") PORT_TOGGLE + PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 4 draw") PORT_TOGGLE + PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 5 draw") PORT_TOGGLE + PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 6 draw") PORT_TOGGLE + PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Toggle Mode 7 draw") PORT_TOGGLE +#endif +INPUT_PORTS_END + + +/************************************* + * + * Input callbacks + * + *************************************/ + +WRITE8_MEMBER(snes_console_state::io_read) +{ + // is automatic reading on? if so, read 16bits from oldjoy1/2 + if (SNES_CPU_REG(NMITIMEN) & 1) + { + UINT16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0; + m_ctrl1->port_poll(); + m_ctrl2->port_poll(); + + for (int i = 0; i < 16; i++) + { + joy1 |= ((m_ctrl1->read_pin4() & 1) << (15 - i)); + joy2 |= ((m_ctrl2->read_pin4() & 1) << (15 - i)); + joy3 |= ((m_ctrl1->read_pin5() & 1) << (15 - i)); + joy4 |= ((m_ctrl2->read_pin5() & 1) << (15 - i)); + } + + SNES_CPU_REG(JOY1L) = (joy1 & 0x00ff) >> 0; + SNES_CPU_REG(JOY1H) = (joy1 & 0xff00) >> 8; + SNES_CPU_REG(JOY2L) = (joy2 & 0x00ff) >> 0; + SNES_CPU_REG(JOY2H) = (joy2 & 0xff00) >> 8; + SNES_CPU_REG(JOY3L) = (joy3 & 0x00ff) >> 0; + SNES_CPU_REG(JOY3H) = (joy3 & 0xff00) >> 8; + SNES_CPU_REG(JOY4L) = (joy4 & 0x00ff) >> 0; + SNES_CPU_REG(JOY4H) = (joy4 & 0xff00) >> 8; + } +} + +UINT8 snes_console_state::oldjoy1_read(int latched) +{ + UINT8 ret = 0; + ret |= m_ctrl1->read_pin4(); + ret |= (m_ctrl1->read_pin5() << 1); + return ret; +} + +UINT8 snes_console_state::oldjoy2_read(int latched) +{ + UINT8 ret = 0; + ret |= m_ctrl2->read_pin4(); + ret |= (m_ctrl2->read_pin5() << 1); + return ret; +} + +void snes_console_state::write_joy_latch(UINT8 data) +{ + m_ctrl1->write_strobe(data); + m_ctrl2->write_strobe(data); +} + +void snes_console_state::wrio_write(UINT8 data) +{ + if (!(SNES_CPU_REG(WRIO) & 0x80) && (data & 0x80)) + { + // external latch + m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y()); + } + + m_ctrl1->write_pin6(BIT(data, 6)); + m_ctrl2->write_pin6(BIT(data, 7)); + +} + +SNESCTRL_GUNLATCH_CB(snes_console_state::gun_latch_cb) +{ + // these are the theoretical boundaries + if (x < 0) + x = 0; + if (x > (SNES_SCR_WIDTH - 1)) + x = SNES_SCR_WIDTH - 1; + + if (y < 0) + y = 0; + if (y > (m_ppu->m_beam.last_visible_line - 1)) + y = m_ppu->m_beam.last_visible_line - 1; + +// m_ppu->set_latch_hv(x, y); // it would be more accurate to write twice to WRIO register, first with bit7 = 0 and then with bit7 = 1 + m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y()); +} + +SNESCTRL_ONSCREEN_CB(snes_console_state::onscreen_cb) +{ + // these are the theoretical boundaries, but we currently are always onscreen due to the + // way IPT_LIGHTGUNs work... investigate more on this! + if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= m_ppu->m_beam.last_visible_line) + return false; + else + return true; +} + + +/************************************* + * + * Machine driver + * + *************************************/ + +void snes_console_state::machine_start() +{ + snes_state::machine_start(); + + if (m_cartslot && m_cartslot->exists()) + { + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snes20_lo_r),this), write8_delegate(FUNC(snes_console_state::snes20_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes20_hi_r),this), write8_delegate(FUNC(snes_console_state::snes20_hi_w),this)); + m_maincpu->set_5a22_map(); + + m_type = m_cartslot->get_type(); + + switch (m_type) + { + // LoROM & LoROM + addons + case SNES_MODE20: + case SNES_BSXLO: + case SNES_SUFAMITURBO: + case SNES_CX4: // this still uses the old simulation instead of emulating the CPU + case SNES_ST010: // this requires two diff kinds of chip access, so we handle it in snes20_lo/hi_r/w + case SNES_ST011: // this requires two diff kinds of chip access, so we handle it in snes20_lo/hi_r/w + case SNES_ST018: // still unemulated + break; + case SNES_Z80GB: // skeleton support + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snessgb_lo_r),this), write8_delegate(FUNC(snes_console_state::snessgb_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snessgb_hi_r),this), write8_delegate(FUNC(snes_console_state::snessgb_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_SA1: // skeleton support + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snessa1_lo_r),this), write8_delegate(FUNC(snes_console_state::snessa1_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snessa1_hi_r),this), write8_delegate(FUNC(snes_console_state::snessa1_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_DSP: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x208000, 0x20ffff, 0, 0x9f0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x208000, 0x20ffff, 0, 0x9f0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_DSP_2MB: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x600000, 0x607fff, 0, 0x8f0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x600000, 0x607fff, 0, 0x8f0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_DSP4: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x308000, 0x30ffff, 0, 0x8f0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x308000, 0x30ffff, 0, 0x8f0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_OBC1: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x006000, 0x007fff, 0, 0xbf0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x006000, 0x007fff, 0, 0xbf0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_SFX: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snessfx_lo_r),this), write8_delegate(FUNC(snes_console_state::snessfx_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snessfx_hi_r),this), write8_delegate(FUNC(snes_console_state::snessfx_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_SDD1: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snessdd1_lo_r),this), write8_delegate(FUNC(snes_console_state::snessdd1_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snessdd1_hi_r),this), write8_delegate(FUNC(snes_console_state::snessdd1_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_BSX: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snesbsx_lo_r),this), write8_delegate(FUNC(snes_console_state::snesbsx_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snesbsx_hi_r),this), write8_delegate(FUNC(snes_console_state::snesbsx_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + // HiROM & HiROM + addons + case SNES_MODE21: + case SNES_BSXHI: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snes21_lo_r),this), write8_delegate(FUNC(snes_console_state::snes21_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes21_hi_r),this), write8_delegate(FUNC(snes_console_state::snes21_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_DSP_MODE21: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snes21_lo_r),this), write8_delegate(FUNC(snes_console_state::snes21_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes21_hi_r),this), write8_delegate(FUNC(snes_console_state::snes21_hi_w),this)); + m_maincpu->space(AS_PROGRAM).install_read_handler(0x006000, 0x007fff, 0, 0x9f0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x006000, 0x007fff, 0, 0x9f0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->set_5a22_map(); + break; + case SNES_SRTC: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snes21_lo_r),this), write8_delegate(FUNC(snes_console_state::snes21_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes21_hi_r),this), write8_delegate(FUNC(snes_console_state::snes21_hi_w),this)); + m_maincpu->space(AS_PROGRAM).install_read_handler(0x002800, 0x002800, 0, 0xbf0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x002801, 0x002801, 0, 0xbf0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->set_5a22_map(); + break; + case SNES_SPC7110: + case SNES_SPC7110_RTC: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::snes7110_lo_r),this), write8_delegate(FUNC(snes_console_state::snes7110_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes7110_hi_r),this), write8_delegate(FUNC(snes_console_state::snes7110_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + case SNES_PFEST94: + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x000000, 0x7dffff, read8_delegate(FUNC(snes_console_state::pfest94_lo_r),this), write8_delegate(FUNC(snes_console_state::pfest94_lo_w),this)); + m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0x800000, 0xffffff, read8_delegate(FUNC(snes_console_state::pfest94_hi_r),this), write8_delegate(FUNC(snes_console_state::pfest94_hi_w),this)); + m_maincpu->set_5a22_map(); + break; + // pirate 'mappers' + case SNES_POKEMON: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x800000, 0x80ffff, 0, 0x780000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x800000, 0x80ffff, 0, 0x780000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_TEKKEN2: + m_maincpu->space(AS_PROGRAM).install_read_handler(0x808000, 0x8087ff, 0, 0x3f0000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_write_handler(0x808000, 0x8087ff, 0, 0x3f0000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_MCPIR1: + case SNES_MCPIR2: + m_maincpu->space(AS_PROGRAM).install_write_handler(0xffff00, 0xffffff, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_20COL: + m_maincpu->space(AS_PROGRAM).install_write_handler(0x008000, 0x008fff, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); + break; + case SNES_SOULBLAD: + // reads from xxx0-xxx3in range [80-bf] return a fixed sequence of 4bits; reads in range [c0-ff] return open bus + m_maincpu->space(AS_PROGRAM).install_read_handler(0x808000, 0x808003, 0, 0x3f7ff0, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); + m_maincpu->space(AS_PROGRAM).install_read_handler(0xc00000, 0xffffff, read8_delegate(FUNC(snes_console_state::snes_open_bus_r),this)); + break; + case SNES_BUGS: + case SNES_BANANA: +// m_maincpu->space(AS_PROGRAM).install_read_handler(0x808000, 0x80ffff, 0, 0x780000, read8_delegate(FUNC(base_sns_cart_slot_device::chip_read),(base_sns_cart_slot_device*)m_cartslot)); +// m_maincpu->space(AS_PROGRAM).install_write_handler(0x808000, 0x80ffff, 0, 0x780000, write8_delegate(FUNC(base_sns_cart_slot_device::chip_write),(base_sns_cart_slot_device*)m_cartslot)); +// m_maincpu->set_5a22_map(); + break; + } + m_cartslot->save_ram(); + } +} + +void snes_console_state::machine_reset() +{ + snes_state::machine_reset(); +} + + +static MACHINE_CONFIG_START( snes, snes_console_state ) + + /* basic machine hardware */ + MCFG_CPU_ADD("maincpu", _5A22, MCLK_NTSC) /* 2.68 MHz, also 3.58 MHz */ + MCFG_CPU_PROGRAM_MAP(snes_map) + + MCFG_CPU_ADD("soundcpu", SPC700, 1024000) /* 1.024 MHz */ + MCFG_CPU_PROGRAM_MAP(spc_map) + + //MCFG_QUANTUM_TIME(attotime::from_hz(48000)) + MCFG_QUANTUM_PERFECT_CPU("maincpu") + + /* video hardware */ + MCFG_SCREEN_ADD("screen", RASTER) + MCFG_SCREEN_RAW_PARAMS(DOTCLK_NTSC * 2, SNES_HTOTAL * 2, 0, SNES_SCR_WIDTH * 2, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC) + MCFG_SCREEN_UPDATE_DRIVER( snes_state, screen_update ) + + MCFG_DEVICE_ADD("ppu", SNES_PPU, 0) + MCFG_SNES_PPU_OPENBUS_CB(READ8(snes_state, snes_open_bus_r)) + MCFG_VIDEO_SET_SCREEN("screen") + + MCFG_SNES_CONTROL_PORT_ADD("ctrl1", snes_control_port_devices, "joypad") + MCFG_SNESCTRL_ONSCREEN_CB(snes_console_state, onscreen_cb) + MCFG_SNES_CONTROL_PORT_ADD("ctrl2", snes_control_port_devices, "joypad") + MCFG_SNESCTRL_ONSCREEN_CB(snes_console_state, onscreen_cb) + MCFG_SNESCTRL_GUNLATCH_CB(snes_console_state, gun_latch_cb) + + /* sound hardware */ + MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") + MCFG_SOUND_ADD("spc700", SNES, 0) + MCFG_SOUND_ROUTE(0, "lspeaker", 1.00) + MCFG_SOUND_ROUTE(1, "rspeaker", 1.00) + + MCFG_SNS_CARTRIDGE_ADD("snsslot", snes_cart, NULL) + MCFG_SOFTWARE_LIST_ADD("cart_list","snes") + MCFG_SOFTWARE_LIST_ADD("bsx_list","snes_bspack") + MCFG_SOFTWARE_LIST_ADD("st_list","snes_strom") +MACHINE_CONFIG_END + +static MACHINE_CONFIG_DERIVED( snespal, snes ) + MCFG_CPU_MODIFY( "maincpu" ) + MCFG_CPU_CLOCK( MCLK_PAL ) + + MCFG_SCREEN_MODIFY("screen") + MCFG_SCREEN_RAW_PARAMS(DOTCLK_PAL, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_PAL, 0, SNES_SCR_HEIGHT_PAL) +MACHINE_CONFIG_END + + + +/************************************* + * + * ROM definition(s) + * + *************************************/ + +ROM_START( snes ) + ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 ) + + ROM_REGION( 0x100, "sound_ipl", 0 ) /* IPL ROM */ + ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */ +ROM_END + +#define rom_snespal rom_snes + +/************************************* + * + * Game driver(s) + * + *************************************/ + +/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ +CONS( 1989, snes, 0, 0, snes, snes, driver_device, 0, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) +CONS( 1991, snespal, snes, 0, snespal, snes, driver_device, 0, "Nintendo", "Super Nintendo Entertainment System (PAL)", MACHINE_IMPERFECT_GRAPHICS | MACHINE_IMPERFECT_SOUND | MACHINE_SUPPORTS_SAVE ) |