summaryrefslogtreecommitdiffstatshomepage
path: root/src/mess/drivers/snes.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mess/drivers/snes.c')
-rw-r--r--src/mess/drivers/snes.c990
1 files changed, 990 insertions, 0 deletions
diff --git a/src/mess/drivers/snes.c b/src/mess/drivers/snes.c
new file mode 100644
index 00000000000..78da32fe677
--- /dev/null
+++ b/src/mess/drivers/snes.c
@@ -0,0 +1,990 @@
+/***************************************************************************
+
+ snes.c
+
+ Driver file to handle emulation of the Nintendo Super NES.
+
+ R. Belmont
+ Anthony Kruize
+ Angelo Salese
+ Fabio Priuli
+ byuu
+ Based on the original MESS driver by Lee Hammerton (aka Savoury Snax)
+
+ Driver is preliminary right now.
+
+ The memory map included below is setup in a way to make it easier to handle
+ Mode 20 and Mode 21 ROMs.
+
+ Todo (in no particular order):
+ - Fix additional sound bugs
+ - Emulate extra chips - superfx, dsp2, sa-1 etc.
+ - Add horizontal mosaic, hi-res. interlaced etc to video emulation.
+ - Fix support for Mode 7. (In Progress)
+ - Handle interleaved roms (maybe even multi-part roms, but how?)
+ - Add support for running at 3.58 MHz at the appropriate time.
+ - I'm sure there's lots more ...
+
+***************************************************************************/
+
+#include "emu.h"
+#include "audio/snes_snd.h"
+#include "cpu/spc700/spc700.h"
+#include "cpu/superfx/superfx.h"
+#include "cpu/g65816/g65816.h"
+#include "cpu/upd7725/upd7725.h"
+#include "includes/snes.h"
+#include "machine/snescart.h"
+#include "crsshair.h"
+
+#define MAX_SNES_CART_SIZE 0x600000
+
+/*************************************
+ *
+ * Memory handlers
+ *
+ *************************************/
+
+static READ8_DEVICE_HANDLER( spc_ram_100_r )
+{
+ return spc_ram_r(device, offset + 0x100);
+}
+
+static WRITE8_DEVICE_HANDLER( spc_ram_100_w )
+{
+ spc_ram_w(device, offset + 0x100, data);
+}
+
+/*************************************
+ *
+ * Address maps
+ *
+ *************************************/
+
+static ADDRESS_MAP_START( snes_map, AS_PROGRAM, 8, snes_state )
+ AM_RANGE(0x000000, 0x2fffff) AM_READWRITE_LEGACY(snes_r_bank1, snes_w_bank1) /* I/O and ROM (repeats for each bank) */
+ AM_RANGE(0x300000, 0x3fffff) AM_READWRITE_LEGACY(snes_r_bank2, snes_w_bank2) /* I/O and ROM (repeats for each bank) */
+ AM_RANGE(0x400000, 0x5fffff) AM_READ_LEGACY(snes_r_bank3) /* ROM (and reserved in Mode 20) */
+ AM_RANGE(0x600000, 0x6fffff) AM_READWRITE_LEGACY(snes_r_bank4, snes_w_bank4) /* used by Mode 20 DSP-1 */
+ AM_RANGE(0x700000, 0x7dffff) AM_READWRITE_LEGACY(snes_r_bank5, snes_w_bank5)
+ AM_RANGE(0x7e0000, 0x7fffff) AM_RAM /* 8KB Low RAM, 24KB High RAM, 96KB Expanded RAM */
+ AM_RANGE(0x800000, 0xbfffff) AM_READWRITE_LEGACY(snes_r_bank6, snes_w_bank6) /* Mirror and ROM */
+ AM_RANGE(0xc00000, 0xffffff) AM_READWRITE_LEGACY(snes_r_bank7, snes_w_bank7) /* Mirror and ROM */
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( superfx_map, AS_PROGRAM, 8, snes_state )
+ AM_RANGE(0x000000, 0x3fffff) AM_READWRITE_LEGACY(superfx_r_bank1, superfx_w_bank1)
+ AM_RANGE(0x400000, 0x5fffff) AM_READWRITE_LEGACY(superfx_r_bank2, superfx_w_bank2)
+ AM_RANGE(0x600000, 0x7dffff) AM_READWRITE_LEGACY(superfx_r_bank3, superfx_w_bank3)
+ AM_RANGE(0x800000, 0xbfffff) AM_READWRITE_LEGACY(superfx_r_bank1, superfx_w_bank1)
+ AM_RANGE(0xc00000, 0xdfffff) AM_READWRITE_LEGACY(superfx_r_bank2, superfx_w_bank2)
+ AM_RANGE(0xe00000, 0xffffff) AM_READWRITE_LEGACY(superfx_r_bank3, superfx_w_bank3)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( spc_map, AS_PROGRAM, 8, snes_state )
+ AM_RANGE(0x0000, 0x00ef) AM_DEVREADWRITE_LEGACY("spc700", spc_ram_r, spc_ram_w) /* lower 32k ram */
+ AM_RANGE(0x00f0, 0x00ff) AM_DEVREADWRITE_LEGACY("spc700", spc_io_r, spc_io_w) /* spc io */
+ AM_RANGE(0x0100, 0xffff) AM_DEVWRITE_LEGACY("spc700", spc_ram_100_w)
+ AM_RANGE(0x0100, 0xffbf) AM_DEVREAD_LEGACY("spc700", spc_ram_100_r)
+ AM_RANGE(0xffc0, 0xffff) AM_DEVREAD_LEGACY("spc700", spc_ipl_r)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( dsp_prg_map, AS_PROGRAM, 32, snes_state )
+ AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspprg", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( dsp_data_map, AS_DATA, 16, snes_state )
+ AM_RANGE(0x0000, 0x03ff) AM_ROM AM_REGION("dspdata", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( setadsp_prg_map, AS_PROGRAM, 32, snes_state )
+ AM_RANGE(0x0000, 0x3fff) AM_ROM AM_REGION("dspprg", 0)
+ADDRESS_MAP_END
+
+static ADDRESS_MAP_START( setadsp_data_map, AS_DATA, 16, snes_state )
+ AM_RANGE(0x0000, 0x07ff) AM_ROM AM_REGION("dspdata", 0)
+ADDRESS_MAP_END
+
+/*************************************
+ *
+ * Input ports
+ *
+ *************************************/
+
+static CUSTOM_INPUT( snes_mouse_speed_input )
+{
+ snes_state *state = field.machine().driver_data<snes_state>();
+ int port = (FPTR)param;
+
+ if (snes_ram[OLDJOY1] & 0x1)
+ {
+ state->m_mouse[port].speed++;
+ if ((state->m_mouse[port].speed & 0x03) == 0x03)
+ state->m_mouse[port].speed = 0;
+ }
+
+ return state->m_mouse[port].speed;
+}
+
+static CUSTOM_INPUT( snes_superscope_offscreen_input )
+{
+ snes_state *state = field.machine().driver_data<snes_state>();
+ int port = (FPTR)param;
+ static const char *const portnames[2][3] =
+ {
+ { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" },
+ { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" },
+ };
+
+ INT16 x = field.machine().root_device().ioport(portnames[port][1])->read();
+ INT16 y = field.machine().root_device().ioport(portnames[port][2])->read();
+
+ /* these are the theoretical boundaries, but we currently are always onscreen... */
+ if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= snes_ppu.beam.last_visible_line)
+ state->m_scope[port].offscreen = 1;
+ else
+ state->m_scope[port].offscreen = 0;
+
+ return state->m_scope[port].offscreen;
+}
+
+static TIMER_CALLBACK( lightgun_tick )
+{
+ if ((machine.root_device().ioport("CTRLSEL")->read() & 0x0f) == 0x03 || (machine.root_device().ioport("CTRLSEL")->read() & 0x0f) == 0x04) {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 0, CROSSHAIR_SCREEN_NONE);
+ }
+
+ if ((machine.root_device().ioport("CTRLSEL")->read() & 0xf0) == 0x30 || (machine.root_device().ioport("CTRLSEL")->read() & 0xf0) == 0x40)
+ {
+ /* enable lightpen crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_ALL);
+ }
+ else
+ {
+ /* disable lightpen crosshair */
+ crosshair_set_screen(machine, 1, CROSSHAIR_SCREEN_NONE);
+ }
+}
+
+
+static INPUT_PORTS_START( snes_joypads )
+ PORT_START("SERIAL1_DATA1_L")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_START("SERIAL1_DATA1_H")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("P1 Start") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
+
+ PORT_START("SERIAL2_DATA1_L")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_START("SERIAL2_DATA1_H")
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("P2 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
+
+ PORT_START("SERIAL1_DATA2_L")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_START("SERIAL1_DATA2_H")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
+
+ PORT_START("SERIAL2_DATA2_L")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_START("SERIAL2_DATA2_H")
+ PORT_BIT( 0xff, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( snes_mouse )
+ PORT_START("MOUSE1")
+ /* bits 0,3 = mouse signature (must be 1) */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */
+ PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)0)
+ /* bits 6,7 = mouse buttons */
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Button Left") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Button Right") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+
+ PORT_START("MOUSE1_X")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+
+ PORT_START("MOUSE1_Y")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
+
+ PORT_START("MOUSE2")
+ /* bits 0,3 = mouse signature (must be 1) */
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */
+ PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_mouse_speed_input, (void *)1)
+ /* bits 6,7 = mouse buttons */
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Mouse Button Left") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Mouse Button Right") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
+
+ PORT_START("MOUSE2_X")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
+
+ PORT_START("MOUSE2_Y")
+ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( snes_superscope )
+ PORT_START("SUPERSCOPE1")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)0)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port1 Superscope Pause") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port1 Superscope Turbo") PORT_TOGGLE PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port1 Superscope Cursor") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port1 Superscope Fire") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+
+ PORT_START("SUPERSCOPE1_X")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port1 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+
+ PORT_START("SUPERSCOPE1_Y")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port1 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
+
+ PORT_START("SUPERSCOPE2")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM(snes_superscope_offscreen_input, (void *)1)
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port2 Superscope Pause") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port2 Superscope Turbo") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port2 Superscope Cursor") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port2 Superscope Fire") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+
+ PORT_START("SUPERSCOPE2_X")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port2 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+
+ PORT_START("SUPERSCOPE2_Y")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port2 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
+INPUT_PORTS_END
+
+static INPUT_PORTS_START( snes )
+ PORT_START("CTRLSEL") /* Select Controller Type */
+ PORT_CONFNAME( 0x0f, 0x01, "P1 Controller")
+ PORT_CONFSETTING( 0x00, "Unconnected" )
+ PORT_CONFSETTING( 0x01, "Gamepad" )
+ PORT_CONFSETTING( 0x02, "Mouse" )
+ PORT_CONFSETTING( 0x03, "Superscope" )
+// PORT_CONFSETTING( 0x04, "Justfier" )
+// PORT_CONFSETTING( 0x05, "Multitap" )
+ PORT_CONFNAME( 0xf0, 0x10, "P2 Controller")
+ PORT_CONFSETTING( 0x00, "Unconnected" )
+ PORT_CONFSETTING( 0x10, "Gamepad" )
+ PORT_CONFSETTING( 0x20, "Mouse" )
+ PORT_CONFSETTING( 0x30, "Superscope" )
+// PORT_CONFSETTING( 0x40, "Justfier" )
+// PORT_CONFSETTING( 0x50, "Multitap" )
+
+ PORT_INCLUDE(snes_joypads)
+ PORT_INCLUDE(snes_mouse)
+ PORT_INCLUDE(snes_superscope)
+
+ 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
+ *
+ *************************************/
+
+static void snes_gun_latch( running_machine &machine, INT16 x, INT16 y )
+{
+ /* 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 > (snes_ppu.beam.last_visible_line - 1))
+ y = snes_ppu.beam.last_visible_line - 1;
+
+ snes_ppu.beam.latch_horz = x;
+ snes_ppu.beam.latch_vert = y;
+ snes_ram[STAT78] |= 0x40;
+}
+
+static void snes_input_read_joy( running_machine &machine, int port )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ static const char *const portnames[2][4] =
+ {
+ { "SERIAL1_DATA1_L", "SERIAL1_DATA1_H", "SERIAL1_DATA2_L", "SERIAL1_DATA2_H" },
+ { "SERIAL2_DATA1_L", "SERIAL2_DATA1_H", "SERIAL2_DATA2_L", "SERIAL2_DATA2_H" },
+ };
+
+ state->m_data1[port] = machine.root_device().ioport(portnames[port][0])->read() | (machine.root_device().ioport(portnames[port][1])->read() << 8);
+ state->m_data2[port] = machine.root_device().ioport(portnames[port][2])->read() | (machine.root_device().ioport(portnames[port][3])->read() << 8);
+
+ // avoid sending signals that could crash games
+ // if left, no right
+ if (state->m_data1[port] & 0x200)
+ state->m_data1[port] &= ~0x100;
+ // if up, no down
+ if (state->m_data1[port] & 0x800)
+ state->m_data1[port] &= ~0x400;
+
+ state->m_joypad[port].buttons = state->m_data1[port];
+}
+
+static void snes_input_read_mouse( running_machine &machine, int port )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ INT16 var;
+ static const char *const portnames[2][3] =
+ {
+ { "MOUSE1", "MOUSE1_X", "MOUSE1_Y" },
+ { "MOUSE2", "MOUSE2_X", "MOUSE2_Y" },
+ };
+
+ state->m_mouse[port].buttons = machine.root_device().ioport(portnames[port][0])->read();
+ state->m_mouse[port].x = machine.root_device().ioport(portnames[port][1])->read();
+ state->m_mouse[port].y = machine.root_device().ioport(portnames[port][2])->read();
+ var = state->m_mouse[port].x - state->m_mouse[port].oldx;
+
+ if (var < -127)
+ {
+ state->m_mouse[port].deltax = 0xff;
+ state->m_mouse[port].oldx -= 127;
+ }
+ else if (var < 0)
+ {
+ state->m_mouse[port].deltax = 0x80 | (-var);
+ state->m_mouse[port].oldx = state->m_mouse[port].x;
+ }
+ else if (var > 127)
+ {
+ state->m_mouse[port].deltax = 0x7f;
+ state->m_mouse[port].oldx += 127;
+ }
+ else
+ {
+ state->m_mouse[port].deltax = var & 0xff;
+ state->m_mouse[port].oldx = state->m_mouse[port].x;
+ }
+
+ var = state->m_mouse[port].y - state->m_mouse[port].oldy;
+
+ if (var < -127)
+ {
+ state->m_mouse[port].deltay = 0xff;
+ state->m_mouse[port].oldy -= 127;
+ }
+ else if (var < 0)
+ {
+ state->m_mouse[port].deltay = 0x80 | (-var);
+ state->m_mouse[port].oldy = state->m_mouse[port].y;
+ }
+ else if (var > 127)
+ {
+ state->m_mouse[port].deltay = 0x7f;
+ state->m_mouse[port].oldy += 127;
+ }
+ else
+ {
+ state->m_mouse[port].deltay = var & 0xff;
+ state->m_mouse[port].oldy = state->m_mouse[port].y;
+ }
+
+ state->m_data1[port] = state->m_mouse[port].buttons | (0x00 << 8);
+ state->m_data2[port] = 0;
+}
+
+static void snes_input_read_superscope( running_machine &machine, int port )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ static const char *const portnames[2][3] =
+ {
+ { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" },
+ { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" },
+ };
+ UINT8 input;
+
+ /* first read input bits */
+ state->m_scope[port].x = machine.root_device().ioport(portnames[port][1])->read();
+ state->m_scope[port].y = machine.root_device().ioport(portnames[port][2])->read();
+ input = machine.root_device().ioport(portnames[port][0])->read();
+
+ /* then start elaborating input bits: only keep old turbo value */
+ state->m_scope[port].buttons &= 0x20;
+
+ /* set onscreen/offscreen */
+ state->m_scope[port].buttons |= BIT(input, 1);
+
+ /* turbo is a switch; toggle is edge sensitive */
+ if (BIT(input, 5) && !state->m_scope[port].turbo_lock)
+ {
+ state->m_scope[port].buttons ^= 0x20;
+ state->m_scope[port].turbo_lock = 1;
+ }
+ else if (!BIT(input, 5))
+ state->m_scope[port].turbo_lock = 0;
+
+ /* fire is a button; if turbo is active, trigger is level sensitive; otherwise it is edge sensitive */
+ if (BIT(input, 7) && (BIT(state->m_scope[port].buttons, 5) || !state->m_scope[port].fire_lock))
+ {
+ state->m_scope[port].buttons |= 0x80;
+ state->m_scope[port].fire_lock = 1;
+ }
+ else if (!BIT(input, 7))
+ state->m_scope[port].fire_lock = 0;
+
+ /* cursor is a button; it is always level sensitive */
+ state->m_scope[port].buttons |= BIT(input, 6);
+
+ /* pause is a button; it is always edge sensitive */
+ if (BIT(input, 4) && !state->m_scope[port].pause_lock)
+ {
+ state->m_scope[port].buttons |= 0x10;
+ state->m_scope[port].pause_lock = 1;
+ }
+ else if (!BIT(input, 4))
+ state->m_scope[port].pause_lock = 0;
+
+ /* If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal.
+ Notice that we only latch Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1 has
+ IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other
+ words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position */
+ if ((state->m_scope[port].buttons & 0xc0) && !(state->m_scope[port].buttons & 0x02) && port == 1)
+ snes_gun_latch(machine, state->m_scope[port].x, state->m_scope[port].y);
+
+ state->m_data1[port] = 0xff | (state->m_scope[port].buttons << 8);
+ state->m_data2[port] = 0;
+}
+
+static void snes_input_read( running_machine &machine )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ctrl1 = machine.root_device().ioport("CTRLSEL")->read() & 0x0f;
+ UINT8 ctrl2 = (machine.root_device().ioport("CTRLSEL")->read() & 0xf0) >> 4;
+
+ /* Check if lightgun has been chosen as input: if so, enable crosshair */
+ machine.scheduler().timer_set(attotime::zero, FUNC(lightgun_tick));
+
+ switch (ctrl1)
+ {
+ case 1: /* SNES joypad */
+ snes_input_read_joy(machine, 0);
+ break;
+ case 2: /* SNES Mouse */
+ snes_input_read_mouse(machine, 0);
+ break;
+ case 3: /* SNES Superscope */
+ snes_input_read_superscope(machine, 0);
+ break;
+ case 0: /* no controller in port1 */
+ default:
+ state->m_data1[0] = 0;
+ state->m_data2[0] = 0;
+ break;
+ }
+
+ switch (ctrl2)
+ {
+ case 1: /* SNES joypad */
+ snes_input_read_joy(machine, 1);
+ break;
+ case 2: /* SNES Mouse */
+ snes_input_read_mouse(machine, 1);
+ break;
+ case 3: /* SNES Superscope */
+ snes_input_read_superscope(machine, 1);
+ break;
+ case 0: /* no controller in port2 */
+ default:
+ state->m_data1[1] = 0;
+ state->m_data2[1] = 0;
+ break;
+ }
+
+ // is automatic reading on? if so, copy port data1/data2 to joy1l->joy4h
+ // this actually works like reading the first 16bits from oldjoy1/2 in reverse order
+ if (snes_ram[NMITIMEN] & 1)
+ {
+ state->m_joy1l = (state->m_data1[0] & 0x00ff) >> 0;
+ state->m_joy1h = (state->m_data1[0] & 0xff00) >> 8;
+ state->m_joy2l = (state->m_data1[1] & 0x00ff) >> 0;
+ state->m_joy2h = (state->m_data1[1] & 0xff00) >> 8;
+ state->m_joy3l = (state->m_data2[0] & 0x00ff) >> 0;
+ state->m_joy3h = (state->m_data2[0] & 0xff00) >> 8;
+ state->m_joy4l = (state->m_data2[1] & 0x00ff) >> 0;
+ state->m_joy4h = (state->m_data2[1] & 0xff00) >> 8;
+
+ // make sure read_idx starts returning all 1s because the auto-read reads it :-)
+ state->m_read_idx[0] = 16;
+ state->m_read_idx[1] = 16;
+ }
+
+}
+
+static UINT8 snes_oldjoy1_read( running_machine &machine )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ctrl1 = machine.root_device().ioport("CTRLSEL")->read() & 0x0f;
+ UINT8 res = 0;
+
+ switch (ctrl1)
+ {
+ case 1: /* SNES joypad */
+ if (state->m_read_idx[0] >= 16)
+ res = 0x01;
+ else
+ res = (state->m_joypad[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01;
+ break;
+ case 2: /* SNES Mouse */
+ if (state->m_read_idx[0] >= 32)
+ res = 0x01;
+ else if (state->m_read_idx[0] >= 24)
+ res = (state->m_mouse[0].deltax >> (31 - state->m_read_idx[0]++)) & 0x01;
+ else if (state->m_read_idx[0] >= 16)
+ res = (state->m_mouse[0].deltay >> (23 - state->m_read_idx[0]++)) & 0x01;
+ else if (state->m_read_idx[0] >= 8)
+ res = (state->m_mouse[0].buttons >> (15 - state->m_read_idx[0]++)) & 0x01;
+ else
+ res = 0;
+ break;
+ case 3: /* SNES Superscope */
+ if (state->m_read_idx[0] >= 8)
+ res = 0x01;
+ else
+ res = (state->m_scope[0].buttons >> (7 - state->m_read_idx[0]++)) & 0x01;
+ break;
+ case 0: /* no controller in port2 */
+ default:
+ break;
+ }
+
+ return res;
+}
+
+static UINT8 snes_oldjoy2_read( running_machine &machine )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+ UINT8 ctrl2 = (machine.root_device().ioport("CTRLSEL")->read() & 0xf0) >> 4;
+ UINT8 res = 0;
+
+ switch (ctrl2)
+ {
+ case 1: /* SNES joypad */
+ if (state->m_read_idx[1] >= 16)
+ res = 0x01;
+ else
+ res = (state->m_joypad[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01;
+ break;
+ case 2: /* SNES Mouse */
+ if (state->m_read_idx[1] >= 32)
+ res = 0x01;
+ else if (state->m_read_idx[1] >= 24)
+ res = (state->m_mouse[1].deltax >> (31 - state->m_read_idx[1]++)) & 0x01;
+ else if (state->m_read_idx[1] >= 16)
+ res = (state->m_mouse[1].deltay >> (23 - state->m_read_idx[1]++)) & 0x01;
+ else if (state->m_read_idx[1] >= 8)
+ res = (state->m_mouse[1].buttons >> (15 - state->m_read_idx[1]++)) & 0x01;
+ else
+ res = 0;
+ break;
+ case 3: /* SNES Superscope */
+ if (state->m_read_idx[1] >= 8)
+ res = 0x01;
+ else
+ res = (state->m_scope[1].buttons >> (7 - state->m_read_idx[1]++)) & 0x01;
+ break;
+ case 0: /* no controller in port2 */
+ default:
+ break;
+ }
+
+ return res;
+}
+
+/*************************************
+ *
+ * Machine driver
+ *
+ *************************************/
+
+static MACHINE_RESET( snes_mess )
+{
+ snes_state *state = machine.driver_data<snes_state>();
+
+ MACHINE_RESET_CALL(snes);
+
+ state->m_io_read = snes_input_read;
+ state->m_oldjoy1_read = snes_oldjoy1_read;
+ state->m_oldjoy2_read = snes_oldjoy2_read;
+}
+
+static MACHINE_CONFIG_START( snes_base, snes_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")
+
+ MCFG_MACHINE_START(snes_mess)
+ MCFG_MACHINE_RESET(snes_mess)
+
+ /* video hardware */
+ MCFG_VIDEO_START(snes)
+
+ MCFG_SCREEN_ADD("screen", RASTER)
+ MCFG_SCREEN_RAW_PARAMS(DOTCLK_NTSC, SNES_HTOTAL, 0, SNES_SCR_WIDTH, SNES_VTOTAL_NTSC, 0, SNES_SCR_HEIGHT_NTSC)
+ MCFG_SCREEN_UPDATE_STATIC(snes)
+
+ /* 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)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snes, snes_base )
+
+ MCFG_FRAGMENT_ADD(snes_cartslot)
+MACHINE_CONFIG_END
+
+static SUPERFX_CONFIG( snes_superfx_config )
+{
+ DEVCB_LINE(snes_extern_irq_w) /* IRQ line from cart */
+};
+
+static MACHINE_CONFIG_DERIVED( snessfx, snes )
+
+ MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */
+ MCFG_CPU_PROGRAM_MAP(superfx_map)
+ MCFG_CPU_CONFIG(snes_superfx_config)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snesdsp, snes )
+
+ MCFG_CPU_ADD("dsp", UPD7725, 8000000)
+ MCFG_CPU_PROGRAM_MAP(dsp_prg_map)
+ MCFG_CPU_DATA_MAP(dsp_data_map)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snesst10, snes )
+
+ MCFG_CPU_ADD("setadsp", UPD96050, 10000000)
+ MCFG_CPU_PROGRAM_MAP(setadsp_prg_map)
+ MCFG_CPU_DATA_MAP(setadsp_data_map)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snesst11, snes )
+
+ MCFG_CPU_ADD("setadsp", UPD96050, 15000000)
+ MCFG_CPU_PROGRAM_MAP(setadsp_prg_map)
+ MCFG_CPU_DATA_MAP(setadsp_data_map)
+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
+
+static MACHINE_CONFIG_DERIVED( snespsfx, snespal )
+
+ MCFG_CPU_ADD("superfx", SUPERFX, 21480000) /* 21.48MHz */
+ MCFG_CPU_PROGRAM_MAP(superfx_map)
+ MCFG_CPU_CONFIG(snes_superfx_config)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snespdsp, snespal )
+
+ MCFG_CPU_ADD("dsp", UPD7725, 8000000)
+ MCFG_CPU_PROGRAM_MAP(dsp_prg_map)
+ MCFG_CPU_DATA_MAP(dsp_data_map)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snesst, snes_base )
+
+ MCFG_MACHINE_START(snesst)
+
+ MCFG_FRAGMENT_ADD(sufami_cartslot)
+MACHINE_CONFIG_END
+
+static MACHINE_CONFIG_DERIVED( snesbsx, snes_base )
+
+ MCFG_FRAGMENT_ADD(bsx_cartslot)
+MACHINE_CONFIG_END
+
+
+/*************************************
+ *
+ * ROM definition(s)
+ *
+ *************************************/
+
+ROM_START( snes )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snesdsp )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) )
+ ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) )
+ ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) )
+ ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) )
+ ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snesst10 )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "st010.bin", 0x000000, 0x011000, CRC(aa11ee2d) SHA1(cc1984e989cb94e3dcbb5f99e085b5414e18a017) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snesst11 )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x11000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "st011.bin", 0x000000, 0x011000, CRC(34d2952c) SHA1(1375b8c1efc8cae4962b57dfe22f6b78e1ddacc8) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x10000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x1000, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snessfx )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snespal )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snespdsp )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) )
+ ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) )
+ ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) )
+ ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) )
+ ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snespsfx )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snesst )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", ROMREGION_ERASE00 ) /* add-on chip ROMs (DSP, SFX, etc) */
+
+ ROM_REGION( 0x40000, "sufami", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "shvc-qh-0.bin", 0, 0x40000, CRC(9b4ca911) SHA1(ef86ea192eed03d5c413fdbbfd46043be1d7a127) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "slot_a", ROMREGION_ERASE00 )
+ ROM_REGION( MAX_SNES_CART_SIZE, "slot_b", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+ROM_START( snesbsx )
+ ROM_REGION( 0x1000000, "maincpu", ROMREGION_ERASE00 )
+
+ ROM_REGION( 0x100, "user5", 0 ) /* IPL ROM */
+ ROM_LOAD( "spc700.rom", 0, 0x40, CRC(44bb3a40) SHA1(97e352553e94242ae823547cd853eecda55c20f0) ) /* boot rom */
+
+ ROM_REGION( 0x10000, "addons", 0 ) /* add-on chip ROMs (DSP, SFX, etc) */
+ ROM_LOAD( "dsp1b.bin", SNES_DSP1B_OFFSET, 0x002800, CRC(453557e0) SHA1(3a218b0e4572a8eba6d0121b17fdac9529609220) )
+ ROM_LOAD( "dsp1.bin", SNES_DSP1_OFFSET, 0x002800, CRC(2838f9f5) SHA1(0a03ccb1fd2bea91151c745a4d1f217ae784f889) )
+ ROM_LOAD( "dsp2.bin", SNES_DSP2_OFFSET, 0x002800, CRC(8e9fbd9b) SHA1(06dd9fcb118d18f6bbe234e013cb8780e06d6e63) )
+ ROM_LOAD( "dsp3.bin", SNES_DSP3_OFFSET, 0x002800, CRC(6b86728a) SHA1(1b133741fad810eb7320c21ecfdd427d25a46da1) )
+ ROM_LOAD( "dsp4.bin", SNES_DSP4_OFFSET, 0x002800, CRC(ce0c7783) SHA1(76fd25f7dc26c3b3f7868a3aa78c7684068713e5) )
+
+ ROM_REGION( MAX_SNES_CART_SIZE, "cart", ROMREGION_ERASE00 )
+ ROM_REGION( MAX_SNES_CART_SIZE, "flash", ROMREGION_ERASE00 )
+ ROM_REGION( 0x2000, "dspprg", ROMREGION_ERASEFF)
+ ROM_REGION( 0x800, "dspdata", ROMREGION_ERASEFF)
+ROM_END
+
+
+
+/*************************************
+ *
+ * Game driver(s)
+ *
+ *************************************/
+
+/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
+CONS( 1989, snes, 0, 0, snes, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1991, snespal, snes, 0, snespal, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+
+// FIXME: the "hacked" drivers below, currently needed due to limitations in the core device design, should eventually be removed
+
+// These would require CPU to be added/removed depending on the cart which is loaded
+CONS( 1989, snesdsp, snes, 0, snesdsp, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1991, snespdsp, snes, 0, snespdsp, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/DSP-x)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1989, snessfx, snes, 0, snessfx, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1991, snespsfx, snes, 0, snespsfx, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SuperFX)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1989, snesst10, snes, 0, snesst10, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-010)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+CONS( 1989, snesst11, snes, 0, snesst11, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/ST-011)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+//CONS( 1989, snessa1, snes, 0, snessa1, snes, XXX_CLASS, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+//CONS( 1991, snespsa1, snes, 0, snespsa1, snes, XXX_CLASS, snes_mess, "Nintendo", "Super Nintendo Entertainment System (PAL, w/SA-1)", GAME_IMPERFECT_GRAPHICS | GAME_IMPERFECT_SOUND )
+
+// These would require cartslot to be added/removed depending on the cart which is loaded
+CONS( 1989, snesst, snes, 0, snesst, snes, snes_state, snesst, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/Sufami Turbo)", GAME_NOT_WORKING )
+CONS( 1989, snesbsx, snes, 0, snesbsx, snes, snes_state, snes_mess, "Nintendo", "Super Nintendo Entertainment System / Super Famicom (NTSC, w/BS-X Satellaview slotted cart)", GAME_NOT_WORKING )