summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author etabeta78 <etabeta78@users.noreply.github.com>2015-01-31 10:59:42 +0100
committer etabeta78 <etabeta78@users.noreply.github.com>2015-01-31 10:59:42 +0100
commitc0c92d60b5170dd51c631185ad05d22eb37283ad (patch)
tree93ce73ef8d2ef4c65d0445410cfbd23d0e58d387
parentbf5af9fcd64fa149fb044e9065f00f2754ae5ce4 (diff)
(MESS) snes: converted input code to use slot devices. This means that you
now change the emulated controllers (Joypad, Mouse, Multitap, Super Scope) via the Slot Device menu of the UI interface and not anymore from the System Configurations menu. Also, changing controller now requires to reset the system, so please take some timeto choose the desired controller *before* starting the game, if you want to play a game that uses special controllers. [Fabio Priuli] (MESS) snes: fixed Mouse emulation so that it does not jump back erratically if you keep moving beyond the window border. [Fabio Priuli] (MESS) snes: fixed Multitap Adapter emulation so games properly recognize the device and inputs from all 5 controllers are accepted by the games. [Fabio Priuli] (MESS) snes: added emulation of the Pachinko controller used by a few pachinko games for Super Famicom. [Fabio Priuli] (MESS) snes: added emulation of the Yonezawa Twin Tap controllers, which allow to play with up to 8 players a quiz games for Super Famicom. [Fabio Priuli] (MESS) snes: added emulation of the Epoch Barcode Battler unit (even if only as Super Famicom controller, and not as a standalone unit) which is necessary to play Conveni Wars Barcode Battler Senki for Super Famicom. [Fabio Priuli]
-rw-r--r--src/emu/bus/bus.mak17
-rw-r--r--src/emu/bus/nes_ctrl/bcbattle.c17
-rw-r--r--src/emu/bus/nes_ctrl/bcbattle.h1
-rw-r--r--src/emu/bus/snes_ctrl/bcbattle.c213
-rw-r--r--src/emu/bus/snes_ctrl/bcbattle.h61
-rw-r--r--src/emu/bus/snes_ctrl/ctrl.c135
-rw-r--r--src/emu/bus/snes_ctrl/ctrl.h101
-rw-r--r--src/emu/bus/snes_ctrl/joypad.c127
-rw-r--r--src/emu/bus/snes_ctrl/joypad.h56
-rw-r--r--src/emu/bus/snes_ctrl/mouse.c241
-rw-r--r--src/emu/bus/snes_ctrl/mouse.h64
-rw-r--r--src/emu/bus/snes_ctrl/multitap.c155
-rw-r--r--src/emu/bus/snes_ctrl/multitap.h62
-rw-r--r--src/emu/bus/snes_ctrl/pachinko.c111
-rw-r--r--src/emu/bus/snes_ctrl/pachinko.h57
-rw-r--r--src/emu/bus/snes_ctrl/sscope.c187
-rw-r--r--src/emu/bus/snes_ctrl/sscope.h61
-rw-r--r--src/emu/bus/snes_ctrl/twintap.c114
-rw-r--r--src/emu/bus/snes_ctrl/twintap.h56
-rw-r--r--src/emu/video/snes_ppu.c12
-rw-r--r--src/emu/video/snes_ppu.h5
-rw-r--r--src/mame/includes/snes.h3
-rw-r--r--src/mame/machine/snes.c19
-rw-r--r--src/mess/drivers/snes.c771
-rw-r--r--src/mess/mess.mak1
25 files changed, 1919 insertions, 728 deletions
diff --git a/src/emu/bus/bus.mak b/src/emu/bus/bus.mak
index 24e0adc9b30..c47965275ea 100644
--- a/src/emu/bus/bus.mak
+++ b/src/emu/bus/bus.mak
@@ -1134,6 +1134,23 @@ endif
#-------------------------------------------------
#
+#@src/emu/bus/snes_ctrl/ctrl.h,BUSES += SNES_CTRL
+#-------------------------------------------------
+
+ifneq ($(filter SNES_CTRL,$(BUSES)),)
+OBJDIRS += $(BUSOBJ)/snes_ctrl
+BUSOBJS += $(BUSOBJ)/snes_ctrl/ctrl.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/bcbattle.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/joypad.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/mouse.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/multitap.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/pachinko.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/sscope.o
+BUSOBJS += $(BUSOBJ)/snes_ctrl/twintap.o
+endif
+
+#-------------------------------------------------
+#
#@src/emu/bus/vboy/slot.h,BUSES += VBOY
#-------------------------------------------------
ifneq ($(filter VBOY,$(BUSES)),)
diff --git a/src/emu/bus/nes_ctrl/bcbattle.c b/src/emu/bus/nes_ctrl/bcbattle.c
index c845627487e..81331440767 100644
--- a/src/emu/bus/nes_ctrl/bcbattle.c
+++ b/src/emu/bus/nes_ctrl/bcbattle.c
@@ -20,18 +20,6 @@
const device_type NES_BARCODE_BATTLER = &device_creator<nes_bcbattle_device>;
-static INPUT_PORTS_START( nes_battler )
-INPUT_PORTS_END
-
-//-------------------------------------------------
-// input_ports - device-specific input ports
-//-------------------------------------------------
-
-ioport_constructor nes_bcbattle_device::device_input_ports() const
-{
- return INPUT_PORTS_NAME( nes_battler );
-}
-
MACHINE_CONFIG_FRAGMENT( nes_battler )
MCFG_BARCODE_READER_ADD("battler")
MACHINE_CONFIG_END
@@ -46,6 +34,9 @@ machine_config_constructor nes_bcbattle_device::device_mconfig_additions() const
// device_timer - handler timer events
//-------------------------------------------------
+// This part is the hacky replacement for the real Barcode unit [shared with SNES implementation]:
+// code periodically checks whether a new code has been scanned and it moves it to the
+// m_current_barcode array
void nes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (id == TIMER_BATTLER)
@@ -92,7 +83,7 @@ void nes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int
//-------------------------------------------------
nes_bcbattle_device::nes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
- device_t(mconfig, NES_BARCODE_BATTLER, "Epoch Barcode Battler", tag, owner, clock, "nes_bcbattle", __FILE__),
+ device_t(mconfig, NES_BARCODE_BATTLER, "Epoch Barcode Battler (FC)", tag, owner, clock, "nes_bcbattle", __FILE__),
device_nes_control_port_interface(mconfig, *this),
m_reader(*this, "battler")
{
diff --git a/src/emu/bus/nes_ctrl/bcbattle.h b/src/emu/bus/nes_ctrl/bcbattle.h
index c38c8d54c1b..f844b7ac28b 100644
--- a/src/emu/bus/nes_ctrl/bcbattle.h
+++ b/src/emu/bus/nes_ctrl/bcbattle.h
@@ -30,7 +30,6 @@ public:
// construction/destruction
nes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
- virtual ioport_constructor device_input_ports() const;
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual machine_config_constructor device_mconfig_additions() const;
diff --git a/src/emu/bus/snes_ctrl/bcbattle.c b/src/emu/bus/snes_ctrl/bcbattle.c
new file mode 100644
index 00000000000..83682589c71
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/bcbattle.c
@@ -0,0 +1,213 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Epoch Barcode Battler
+
+ TODO: this should be actually emulated as a standalone system with
+ a few 7segments LEDs, once we get a dump of its BIOS
+ At the moment we only emulated the connection with a Super Famicom
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "bcbattle.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_BARCODE_BATTLER = &device_creator<snes_bcbattle_device>;
+
+
+MACHINE_CONFIG_FRAGMENT( snes_battler )
+ MCFG_BARCODE_READER_ADD("battler")
+MACHINE_CONFIG_END
+
+machine_config_constructor snes_bcbattle_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( snes_battler );
+}
+
+
+//-------------------------------------------------
+// device_timer - handler timer events
+//-------------------------------------------------
+
+// This part is the hacky replacement for the real Barcode unit [shared with NES implementation]:
+// code periodically checks whether a new code has been scanned and it moves it to the
+// m_current_barcode array
+void snes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ if (id == TIMER_BATTLER)
+ {
+ int old = m_new_code;
+ m_new_code = m_reader->get_pending_code();
+ // has something new been scanned?
+ if (old < m_new_code)
+ {
+ if (m_reader->get_byte_length() == 13)
+ {
+ for (int i = 0; i < 13; i++)
+ m_current_barcode[i] = m_reader->read_code() + '0';
+ }
+ else if (m_reader->get_byte_length() == 8)
+ {
+ for (int i = 0; i < 5; i++)
+ m_current_barcode[i] = 0x20;
+ for (int i = 5; i < 13; i++)
+ m_current_barcode[i] = m_reader->read_code() + '0';
+ }
+ // read one more, to reset the internal byte counter
+ m_reader->read_code();
+
+ // the string "SUNSOFT" is accepted as well by Barcode World
+ m_current_barcode[13] = 'E';
+ m_current_barcode[14] = 'P';
+ m_current_barcode[15] = 'O';
+ m_current_barcode[16] = 'C';
+ m_current_barcode[17] = 'H';
+ m_current_barcode[18] = 0x0d;
+ m_current_barcode[19] = 0x0a;
+ m_pending_code = 1;
+ }
+ }
+}
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_bcbattle_device - constructor
+//-------------------------------------------------
+
+snes_bcbattle_device::snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_BARCODE_BATTLER, "Epoch Barcode Battler (SFC)", tag, owner, clock, "snes_bcbattle", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_reader(*this, "battler")
+{
+}
+
+
+//-------------------------------------------------
+// device_start
+//-------------------------------------------------
+
+void snes_bcbattle_device::device_start()
+{
+ // lacking emulation of the standalone Barcode Battler, we refresh periodically the input from the reader
+ // proper emulation would have the standalone unit acknowledging that a new barcode has been scanned
+ // and sending the proper serial bits, instead of our read_current_bit() function!
+ battler_timer = timer_alloc(TIMER_BATTLER);
+ battler_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(1000));
+
+ save_item(NAME(m_current_barcode));
+ save_item(NAME(m_new_code));
+ save_item(NAME(m_pending_code));
+ save_item(NAME(m_transmitting));
+ save_item(NAME(m_cur_bit));
+ save_item(NAME(m_cur_byte));
+}
+
+
+//-------------------------------------------------
+// device_reset
+//-------------------------------------------------
+
+void snes_bcbattle_device::device_reset()
+{
+ m_pending_code = 0;
+ m_new_code = 0;
+ m_transmitting = 0;
+ m_cur_bit = 0;
+ m_cur_byte = 0;
+ memset(m_current_barcode, 0, ARRAY_LENGTH(m_current_barcode));
+}
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+int snes_bcbattle_device::read_current_bit()
+{
+ if (m_pending_code)
+ {
+ if (m_cur_bit < 4)
+ {
+ int bit = BIT(m_current_barcode[m_cur_byte], m_cur_bit - 1);
+ m_cur_bit++;
+ return bit;
+ }
+ if (m_cur_bit == 4) // only the low nibble is transmitted (this is the main action of the BBII interface for SNES)
+ {
+ m_cur_bit = 0;
+ //printf("%X ", m_current_barcode[m_cur_byte]);
+ m_cur_byte++;
+ if (m_cur_byte == 13)
+ {
+ m_cur_byte = 0;
+ m_pending_code = 0;
+ }
+ return 0;
+ }
+ }
+
+ return 0;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_bcbattle_device::port_poll()
+{
+ m_idx = 0;
+}
+
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_bcbattle_device::read_pin4()
+{
+ UINT8 ret = 0;
+
+ if (m_idx >= 80)
+ ret |= 0x00;
+ else if (m_idx >= 28) // scan actual barcode
+ {
+ ret |= read_current_bit(); // if no code is pending transmission, the function returns 0
+ m_idx++;
+ }
+ else if (m_idx >= 25) // unknown flags?
+ m_idx++;
+ else if (m_idx == 24) // barcode present
+ {
+ ret |= m_pending_code;
+ m_idx++;
+ }
+ else if (m_idx >= 12) // controller ID
+ ret |= BIT(0x7000, m_idx++);
+ else // first 12 bytes are unknown and probably always 0
+ m_idx++;
+
+ return ret;
+}
+
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_bcbattle_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
diff --git a/src/emu/bus/snes_ctrl/bcbattle.h b/src/emu/bus/snes_ctrl/bcbattle.h
new file mode 100644
index 00000000000..cf72146ede9
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/bcbattle.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Epoch Barcode Battler
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_BCBATTLE__
+#define __SNES_BCBATTLE__
+
+
+#include "emu.h"
+#include "ctrl.h"
+#include "machine/bcreader.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_bcbattle_device
+
+class snes_bcbattle_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+ int read_current_bit();
+
+private:
+
+ static const device_timer_id TIMER_BATTLER = 1;
+ required_device<barcode_reader_device> m_reader;
+ UINT8 m_current_barcode[20];
+ int m_pending_code, m_new_code, m_transmitting, m_cur_bit, m_cur_byte;
+ emu_timer *battler_timer;
+
+ int m_strobe, m_on, m_idx;
+};
+
+// device type definition
+extern const device_type SNES_BARCODE_BATTLER;
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/ctrl.c b/src/emu/bus/snes_ctrl/ctrl.c
new file mode 100644
index 00000000000..a09365dab27
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/ctrl.c
@@ -0,0 +1,135 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES controller port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "ctrl.h"
+// slot devices
+#include "bcbattle.h"
+#include "joypad.h"
+#include "mouse.h"
+#include "multitap.h"
+#include "pachinko.h"
+#include "sscope.h"
+#include "twintap.h"
+
+
+//**************************************************************************
+// GLOBAL VARIABLES
+//**************************************************************************
+
+const device_type SNES_CONTROL_PORT = &device_creator<snes_control_port_device>;
+
+
+//**************************************************************************
+// CARD INTERFACE
+//**************************************************************************
+
+//-------------------------------------------------
+// device_snes_control_port_interface - constructor
+//-------------------------------------------------
+
+device_snes_control_port_interface::device_snes_control_port_interface(const machine_config &mconfig, device_t &device)
+ : device_slot_card_interface(mconfig,device)
+{
+ m_port = dynamic_cast<snes_control_port_device *>(device.owner());
+}
+
+
+//-------------------------------------------------
+// ~device_snes_control_port_interface - destructor
+//-------------------------------------------------
+
+device_snes_control_port_interface::~device_snes_control_port_interface()
+{
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_control_port_device - constructor
+//-------------------------------------------------
+
+snes_control_port_device::snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_CONTROL_PORT, "Nintendo SNES / SFC control port", tag, owner, clock, "snes_control_port", __FILE__),
+ device_slot_interface(mconfig, *this)
+{
+}
+
+
+//-------------------------------------------------
+// snes_control_port_device - destructor
+//-------------------------------------------------
+
+snes_control_port_device::~snes_control_port_device()
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_control_port_device::device_start()
+{
+ m_device = dynamic_cast<device_snes_control_port_interface *>(get_card_device());
+ m_onscreen_cb.bind_relative_to(*owner());
+ m_gunlatch_cb.bind_relative_to(*owner());
+}
+
+
+UINT8 snes_control_port_device::read_pin4()
+{
+ UINT8 data = 0;
+ if (m_device)
+ data |= m_device->read_pin4();
+ return data;
+}
+
+UINT8 snes_control_port_device::read_pin5()
+{
+ UINT8 data = 0;
+ if (m_device)
+ data |= m_device->read_pin5();
+ return data;
+}
+
+void snes_control_port_device::write_strobe(UINT8 data)
+{
+ if (m_device)
+ m_device->write_strobe(data);
+}
+
+void snes_control_port_device::write_pin6(UINT8 data)
+{
+ if (m_device)
+ m_device->write_pin6(data);
+}
+
+void snes_control_port_device::port_poll()
+{
+ if (m_device)
+ m_device->port_poll();
+}
+
+
+//-------------------------------------------------
+// SLOT_INTERFACE( snes_control_port_devices )
+//-------------------------------------------------
+
+SLOT_INTERFACE_START( snes_control_port_devices )
+ SLOT_INTERFACE("joypad", SNES_JOYPAD)
+ SLOT_INTERFACE("mouse", SNES_MOUSE)
+ SLOT_INTERFACE("multitap", SNES_MULTITAP)
+ SLOT_INTERFACE("pachinko", SNES_PACHINKO)
+ SLOT_INTERFACE("sscope", SNES_SUPERSCOPE)
+ SLOT_INTERFACE("twintap", SNES_TWINTAP)
+ SLOT_INTERFACE("barcode_battler", SNES_BARCODE_BATTLER)
+SLOT_INTERFACE_END
diff --git a/src/emu/bus/snes_ctrl/ctrl.h b/src/emu/bus/snes_ctrl/ctrl.h
new file mode 100644
index 00000000000..d7f87ef5c42
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/ctrl.h
@@ -0,0 +1,101 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES controller port emulation
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+
+#pragma once
+
+#ifndef __SNES_CONTROL_PORT__
+#define __SNES_CONTROL_PORT__
+
+#include "emu.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+class snes_control_port_device;
+
+// ======================> device_snes_control_port_interface
+
+class device_snes_control_port_interface : public device_slot_card_interface
+{
+public:
+ // construction/destruction
+ device_snes_control_port_interface(const machine_config &mconfig, device_t &device);
+ virtual ~device_snes_control_port_interface();
+
+ virtual UINT8 read_pin4() { return 0; };
+ virtual UINT8 read_pin5() { return 0; };
+ virtual void write_pin6(UINT8 data) { };
+ virtual void write_strobe(UINT8 data) { };
+ virtual void port_poll() { };
+
+protected:
+ snes_control_port_device *m_port;
+};
+
+typedef device_delegate<bool (INT16 x, INT16 y)> snesctrl_onscreen_delegate;
+#define SNESCTRL_ONSCREEN_CB(name) bool name(INT16 x, INT16 y)
+
+typedef device_delegate<void (INT16 x, INT16 y)> snesctrl_gunlatch_delegate;
+#define SNESCTRL_GUNLATCH_CB(name) void name(INT16 x, INT16 y)
+
+// ======================> snes_control_port_device
+
+class snes_control_port_device : public device_t,
+ public device_slot_interface
+{
+public:
+ // construction/destruction
+ snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+ virtual ~snes_control_port_device();
+
+ static void set_onscreen_callback(device_t &device, snesctrl_onscreen_delegate callback) { downcast<snes_control_port_device &>(device).m_onscreen_cb = callback; }
+ static void set_gunlatch_callback(device_t &device, snesctrl_gunlatch_delegate callback) { downcast<snes_control_port_device &>(device).m_gunlatch_cb = callback; }
+
+ UINT8 read_pin4();
+ UINT8 read_pin5();
+ void write_pin6(UINT8 data);
+ void write_strobe(UINT8 data);
+ void port_poll();
+
+ snesctrl_onscreen_delegate m_onscreen_cb;
+ snesctrl_gunlatch_delegate m_gunlatch_cb;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+
+ device_snes_control_port_interface *m_device;
+};
+
+
+// device type definition
+extern const device_type SNES_CONTROL_PORT;
+
+
+//**************************************************************************
+// INTERFACE CONFIGURATION MACROS
+//**************************************************************************
+
+#define MCFG_SNES_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \
+ MCFG_DEVICE_ADD(_tag, SNES_CONTROL_PORT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
+
+#define MCFG_SNESCTRL_ONSCREEN_CB(_class, _method) \
+ snes_control_port_device::set_onscreen_callback(*device, snesctrl_onscreen_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
+
+#define MCFG_SNESCTRL_GUNLATCH_CB(_class, _method) \
+ snes_control_port_device::set_gunlatch_callback(*device, snesctrl_gunlatch_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
+
+
+SLOT_INTERFACE_EXTERN( snes_control_port_devices );
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/joypad.c b/src/emu/bus/snes_ctrl/joypad.c
new file mode 100644
index 00000000000..a8291c2dfdb
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/joypad.c
@@ -0,0 +1,127 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Joypad
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "joypad.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_JOYPAD = &device_creator<snes_joypad_device>;
+
+
+static INPUT_PORTS_START( snes_joypad )
+ PORT_START("JOYPAD")
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B")
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Y")
+ PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Select")
+ PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start")
+ PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
+ PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
+ PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
+ PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A")
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("X")
+ PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("L")
+ PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("R")
+ PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_joypad_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_joypad );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_joypad_device - constructor
+//-------------------------------------------------
+
+snes_joypad_device::snes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_JOYPAD, "Nintendo SNES / SFC Control Pad", tag, owner, clock, "snes_joypad", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_joypad(*this, "JOYPAD")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_joypad_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_strobe));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void snes_joypad_device::device_reset()
+{
+ m_latch = 0;
+ m_strobe = 0;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_joypad_device::port_poll()
+{
+ UINT16 temp = m_joypad->read();
+ // avoid sending signals that could crash games
+ // if left, no right
+ if (temp & 0x40)
+ temp &= ~0x80;
+ // if up, no down
+ if (temp & 0x10)
+ temp &= ~0x20;
+
+ m_latch = temp | 0xffff0000;
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_joypad_device::read_pin4()
+{
+ UINT8 ret = m_latch & 1;
+ m_latch >>= 1;
+ return ret;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_joypad_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
+
diff --git a/src/emu/bus/snes_ctrl/joypad.h b/src/emu/bus/snes_ctrl/joypad.h
new file mode 100644
index 00000000000..9c6920e7a18
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/joypad.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Joypad
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_JOYPAD__
+#define __SNES_JOYPAD__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_joypad_device
+
+class snes_joypad_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_ioport m_joypad;
+ int m_strobe;
+ UINT32 m_latch;
+};
+
+
+// device type definition
+extern const device_type SNES_JOYPAD;
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/mouse.c b/src/emu/bus/snes_ctrl/mouse.c
new file mode 100644
index 00000000000..1d6cb5b52f6
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/mouse.c
@@ -0,0 +1,241 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Mouse
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "mouse.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_MOUSE = &device_creator<snes_mouse_device>;
+
+
+static INPUT_PORTS_START( snes_mouse )
+ PORT_START("BUTTONS")
+ PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_SPECIAL ) // these must be 0!
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Button Right")
+ PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button Left")
+ PORT_BIT( 0x0c00, IP_ACTIVE_HIGH, IPT_UNUSED ) // mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused
+ PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )
+
+ // we use IPT_LIGHTGUN instead of IPT_MOUSE to avoid input to wrap when you reach the screen border
+ // due to the relative nature of movement detection in SNES mouse, when we wrap the system would
+ // detect a sudden jump in the wrong direction, making the usage unfriendly...
+ PORT_START("MOUSE_X")
+ PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
+// PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
+
+ PORT_START("MOUSE_Y")
+ PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
+// PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_mouse_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_mouse );
+}
+
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_mouse_device - constructor
+//-------------------------------------------------
+
+snes_mouse_device::snes_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_MOUSE, "Nintendo SNES / SFC Mouse Controller", tag, owner, clock, "snes_mouse", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_buttons(*this, "BUTTONS"),
+ m_xaxis(*this, "MOUSE_X"),
+ m_yaxis(*this, "MOUSE_Y")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_mouse_device::device_start()
+{
+ save_item(NAME(m_strobe));
+ save_item(NAME(m_idx));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_x));
+ save_item(NAME(m_y));
+ save_item(NAME(m_oldx));
+ save_item(NAME(m_oldy));
+ save_item(NAME(m_deltax));
+ save_item(NAME(m_deltay));
+ save_item(NAME(m_speed));
+ save_item(NAME(m_dirx));
+ save_item(NAME(m_diry));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void snes_mouse_device::device_reset()
+{
+ m_strobe = 0;
+ m_idx = 0;
+ m_latch = 0;
+ m_x = 0;
+ m_y = 0;
+ m_oldx = 0;
+ m_oldy = 0;
+ m_deltax = 0;
+ m_deltay = 0;
+ m_speed = 0;
+ m_dirx = -1;
+ m_diry = -1;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_mouse_device::port_poll()
+{
+ INT16 var;
+ int new_dir;
+ m_idx = 0;
+ m_latch = m_buttons->read();
+
+ m_oldx = m_x;
+ m_oldy = m_y;
+ m_x = m_xaxis->read();
+ m_y = m_yaxis->read();
+
+ var = m_x - m_oldx;
+ if (var)
+ {
+ new_dir = (var < 0) ? 1 : 0;
+ if (m_dirx != new_dir)
+ m_dirx = new_dir;
+ }
+
+ if (var < -127)
+ {
+ m_deltax = 0x7f;
+ m_oldx -= 127;
+ }
+ else if (var < 0)
+ {
+ m_deltax = -var;
+ m_oldx = m_x;
+ }
+ else if (var > 127)
+ {
+ m_deltax = 0x7f;
+ m_oldx += 127;
+ }
+ else
+ {
+ m_deltax = var;
+ m_oldx = m_x;
+ }
+
+ var = m_y - m_oldy;
+ if (var)
+ {
+ new_dir = (var < 0) ? 1 : 0;
+ if (m_diry != new_dir)
+ m_diry = new_dir;
+ }
+
+ if (var < -127)
+ {
+ m_deltay = 0x7f;
+ m_oldy -= 127;
+ }
+ else if (var < 0)
+ {
+ m_deltay = -var;
+ m_oldy = m_y;
+ }
+ else if (var > 127)
+ {
+ m_deltay = 0x7f;
+ m_oldy += 127;
+ }
+ else
+ {
+ m_deltay = var;
+ m_oldy = m_y;
+ }
+
+ m_deltax |= (m_dirx << 7);
+ m_deltay |= (m_diry << 7);
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_mouse_device::read_pin4()
+{
+ UINT8 res = 0;
+
+ if (m_strobe == 1)
+ {
+ // reading with strobe 1, changes mouse speed
+ m_speed = (m_speed + 1) % 3;
+ return res;
+ }
+
+ if (m_idx >= 32)
+ res |= 0x01;
+ else if (m_idx >= 24)
+ res |= BIT(m_deltax, (31 - m_idx++));
+ else if (m_idx >= 16)
+ res |= BIT(m_deltay, (23 - m_idx++));
+ else if (m_idx == 11)
+ {
+ res |= BIT(m_speed, 0);
+ m_idx++;
+ }
+ else if (m_idx == 10)
+ {
+ res |= BIT(m_speed, 1);
+ m_idx++;
+ }
+ else
+ res |= BIT(m_latch, m_idx++);
+
+ return res;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_mouse_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
+
diff --git a/src/emu/bus/snes_ctrl/mouse.h b/src/emu/bus/snes_ctrl/mouse.h
new file mode 100644
index 00000000000..fbce1ba6c41
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/mouse.h
@@ -0,0 +1,64 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Mouse
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_MOUSE__
+#define __SNES_MOUSE__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_mouse_device
+
+class snes_mouse_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_ioport m_buttons;
+ required_ioport m_xaxis;
+ required_ioport m_yaxis;
+ int m_strobe;
+ int m_idx;
+ UINT32 m_latch;
+
+ INT16 m_x, m_y, m_oldx, m_oldy;
+ UINT8 m_deltax, m_deltay;
+ int m_speed;
+ int m_dirx, m_diry;
+};
+
+
+// device type definition
+extern const device_type SNES_MOUSE;
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/multitap.c b/src/emu/bus/snes_ctrl/multitap.c
new file mode 100644
index 00000000000..bf1d04cada9
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/multitap.c
@@ -0,0 +1,155 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Multitap Adapter
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "multitap.h"
+#include "joypad.h"
+#include "twintap.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_MULTITAP = &device_creator<snes_multitap_device>;
+
+
+static INPUT_PORTS_START( snes_multitap )
+ PORT_START("CONFIG")
+ PORT_CONFNAME( 0x01, 0x00, "Number of players")
+ PORT_CONFSETTING( 0x00, "3-5P" )
+ PORT_CONFSETTING( 0x01, "2P" )
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_multitap_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_multitap );
+}
+
+
+static SLOT_INTERFACE_START( snes_multitap )
+ SLOT_INTERFACE("joypad", SNES_JOYPAD)
+ SLOT_INTERFACE("twintap", SNES_TWINTAP)
+SLOT_INTERFACE_END
+
+static MACHINE_CONFIG_FRAGMENT( multi5p )
+ MCFG_SNES_CONTROL_PORT_ADD("port1", snes_multitap, "joypad")
+ MCFG_SNES_CONTROL_PORT_ADD("port2", snes_multitap, "joypad")
+ MCFG_SNES_CONTROL_PORT_ADD("port3", snes_multitap, "joypad")
+ MCFG_SNES_CONTROL_PORT_ADD("port4", snes_multitap, "joypad")
+MACHINE_CONFIG_END
+
+
+//-------------------------------------------------
+// machine_config_additions - device-specific
+// machine configurations
+//-------------------------------------------------
+
+machine_config_constructor snes_multitap_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME( multi5p );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_multitap_device - constructor
+//-------------------------------------------------
+
+snes_multitap_device::snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_MULTITAP, "Nintendo SNES / SFC Multitap Adapter", tag, owner, clock, "snes_joypad", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_port1(*this, "port1"),
+ m_port2(*this, "port2"),
+ m_port3(*this, "port3"),
+ m_port4(*this, "port4"),
+ m_cfg(*this, "CONFIG")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_multitap_device::device_start()
+{
+ save_item(NAME(m_select));
+}
+
+void snes_multitap_device::device_reset()
+{
+ m_select = 1;
+}
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_multitap_device::port_poll()
+{
+ m_port1->port_poll();
+ if (m_cfg->read() == 0) // 4P
+ {
+ m_port2->port_poll();
+ m_port3->port_poll();
+ m_port4->port_poll();
+ }
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_multitap_device::read_pin4()
+{
+ UINT8 ret = 0;
+
+ if (m_cfg->read() == 0) // 4P
+ ret |= m_select ? m_port1->read_pin4() : m_port3->read_pin4();
+ else // 1P
+ ret |= m_select ? m_port1->read_pin4() : 0;
+
+ return ret;
+}
+
+UINT8 snes_multitap_device::read_pin5()
+{
+ UINT8 ret = 0;
+
+ if (m_cfg->read() == 0) // 4P
+ ret |= m_select ? m_port2->read_pin4() : m_port4->read_pin4();
+ return ret;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_multitap_device::write_strobe(UINT8 data)
+{
+ m_port1->write_strobe(data);
+ if (m_cfg->read() == 0) // 4P
+ {
+ m_port2->write_strobe(data);
+ m_port3->write_strobe(data);
+ m_port4->write_strobe(data);
+ }
+}
+
+void snes_multitap_device::write_pin6(UINT8 data)
+{
+ m_select = data & 1;
+}
diff --git a/src/emu/bus/snes_ctrl/multitap.h b/src/emu/bus/snes_ctrl/multitap.h
new file mode 100644
index 00000000000..b43f3116f18
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/multitap.h
@@ -0,0 +1,62 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES Multitap Adapter
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_MULTITAP__
+#define __SNES_MULTITAP__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_multitap_device
+
+class snes_multitap_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+ virtual machine_config_constructor device_mconfig_additions() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual UINT8 read_pin5();
+ virtual void write_strobe(UINT8 data);
+ virtual void write_pin6(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_device<snes_control_port_device> m_port1;
+ required_device<snes_control_port_device> m_port2;
+ required_device<snes_control_port_device> m_port3;
+ required_device<snes_control_port_device> m_port4;
+ required_ioport m_cfg;
+ int m_select;
+};
+
+
+// device type definition
+extern const device_type SNES_MULTITAP;
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/pachinko.c b/src/emu/bus/snes_ctrl/pachinko.c
new file mode 100644
index 00000000000..099e4e00f57
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/pachinko.c
@@ -0,0 +1,111 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Sunsoft Pachinko Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "pachinko.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_PACHINKO = &device_creator<snes_pachinko_device>;
+
+
+static INPUT_PORTS_START( snes_pachinko )
+ PORT_START("DIAL")
+ PORT_BIT( 0x7f, 0x3f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x18,0x7f)
+
+ PORT_START("BUTTON")
+ PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED)
+ PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Button")
+ PORT_BIT( 0xfe00, IP_ACTIVE_HIGH, IPT_UNUSED)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_pachinko_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_pachinko );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_pachinko_device - constructor
+//-------------------------------------------------
+
+snes_pachinko_device::snes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_PACHINKO, "Sunsoft Pachinko Controller", tag, owner, clock, "snes_pachinko", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_dial(*this, "DIAL"),
+ m_button(*this, "BUTTON")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_pachinko_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_strobe));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void snes_pachinko_device::device_reset()
+{
+ m_latch = 0;
+ m_strobe = 0;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_pachinko_device::port_poll()
+{
+ UINT8 dial = BITSWAP8(m_dial->read() ^ 0xff,7,6,5,4,3,2,1,0);
+ m_latch = m_button->read() | (dial << 25) | 0xee7000; // add ID
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_pachinko_device::read_pin4()
+{
+ UINT8 ret = m_latch & 1;
+ m_latch >>= 1;
+ return ret;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_pachinko_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
diff --git a/src/emu/bus/snes_ctrl/pachinko.h b/src/emu/bus/snes_ctrl/pachinko.h
new file mode 100644
index 00000000000..0dc2fe25480
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/pachinko.h
@@ -0,0 +1,57 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Sunsoft Pachinko Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_PACHINKO__
+#define __SNES_PACHINKO__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_pachinko_device
+
+class snes_pachinko_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_ioport m_dial;
+ required_ioport m_button;
+ int m_strobe;
+ UINT32 m_latch;
+};
+
+
+// device type definition
+extern const device_type SNES_PACHINKO;
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/sscope.c b/src/emu/bus/snes_ctrl/sscope.c
new file mode 100644
index 00000000000..93e46879a16
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/sscope.c
@@ -0,0 +1,187 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES SuperScope
+
+ TODO: x,y positions are not correctly latched
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "sscope.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_SUPERSCOPE = &device_creator<snes_sscope_device>;
+
+
+static INPUT_PORTS_START( snes_sscope )
+ PORT_START("BUTTONS")
+ PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Superscope Fire")
+ PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Superscope Cursor")
+ PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Superscope Turbo")
+ PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Superscope Pause")
+ PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // On-screen (handled below in port_poll)
+ PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
+
+ PORT_START("SSX")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15)
+
+ PORT_START("SSY")
+ PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15)
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_sscope_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_sscope );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_sscope_device - constructor
+//-------------------------------------------------
+
+snes_sscope_device::snes_sscope_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_SUPERSCOPE, "Nintendo SNES / SFC SuperScope", tag, owner, clock, "snes_sscope", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_buttons(*this, "BUTTONS"),
+ m_xaxis(*this, "SSX"),
+ m_yaxis(*this, "SSY")
+{
+}
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_sscope_device::device_start()
+{
+ save_item(NAME(m_strobe));
+ save_item(NAME(m_idx));
+ save_item(NAME(m_latch));
+ save_item(NAME(m_x));
+ save_item(NAME(m_y));
+ save_item(NAME(m_turbo_lock));
+ save_item(NAME(m_pause_lock));
+ save_item(NAME(m_fire_lock));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void snes_sscope_device::device_reset()
+{
+ m_strobe = 0;
+ m_idx = 0;
+ m_latch = 0;
+ m_x = 0;
+ m_y = 0;
+ m_turbo_lock = 0;
+ m_pause_lock = 0;
+ m_fire_lock = 0;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_sscope_device::port_poll()
+{
+ // first read input bits
+ UINT8 input = m_buttons->read();
+ m_x = m_xaxis->read();
+ m_y = m_yaxis->read();
+ m_idx = 0;
+
+ // then start elaborating input bits
+ // 1. only keep old turbo value
+ m_latch &= 0x04;
+
+ // 2. set onscreen/offscreen
+ if (!m_port->m_onscreen_cb.isnull())
+ m_latch |= (m_port->m_onscreen_cb(m_x, m_y) ? 0x00 : 0x40);
+
+ // 3. pause is a button that is always edge sensitive
+ if (BIT(input, 3) && !m_pause_lock)
+ {
+ m_latch |= 0x08;
+ m_pause_lock = 1;
+ }
+ else if (!BIT(input, 3))
+ m_pause_lock = 0;
+
+ // 4. turbo is a switch; toggle is edge sensitive
+ if (BIT(input, 2) && !m_turbo_lock)
+ {
+ m_latch ^= 0x04;
+ m_turbo_lock = 1;
+ }
+ else if (!BIT(input, 2))
+ m_turbo_lock = 0;
+
+ // 5. cursor is a button that is always level sensitive
+ m_latch |= BIT(input, 1);
+
+ // 6. fire is a button with two behaviors: if turbo is active, trigger is level sensitive;
+ // otherwise it is edge sensitive
+ if (BIT(input, 0) && (BIT(m_latch, 2) || !m_fire_lock))
+ {
+ m_latch |= 0x01;
+ m_fire_lock = 1;
+ }
+ else if (!BIT(input, 0))
+ m_fire_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 this only works in 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 ((m_latch & 0x03) && !(m_latch & 0x40) && !m_port->m_gunlatch_cb.isnull())
+ m_port->m_gunlatch_cb(m_x, m_y);
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_sscope_device::read_pin4()
+{
+ UINT8 res = 0;
+
+ if (m_idx >= 8) // bits 8-15 = ID = all 1s; bits >= 16 all 1s
+ res |= 0x01;
+ else
+ res |= BIT(m_latch, m_idx++);
+
+ return res;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_sscope_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
+
diff --git a/src/emu/bus/snes_ctrl/sscope.h b/src/emu/bus/snes_ctrl/sscope.h
new file mode 100644
index 00000000000..e6a806038fc
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/sscope.h
@@ -0,0 +1,61 @@
+/**********************************************************************
+
+ Nintendo Super Famicom & SNES SuperScope
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_SUPERSCOPE__
+#define __SNES_SUPERSCOPE__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_sscope_device
+
+class snes_sscope_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_sscope_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_ioport m_buttons;
+ required_ioport m_xaxis;
+ required_ioport m_yaxis;
+ int m_strobe, m_idx;
+ UINT32 m_latch;
+
+ INT16 m_x, m_y;
+ int m_turbo_lock, m_pause_lock, m_fire_lock;
+};
+
+
+// device type definition
+extern const device_type SNES_SUPERSCOPE;
+
+
+#endif
diff --git a/src/emu/bus/snes_ctrl/twintap.c b/src/emu/bus/snes_ctrl/twintap.c
new file mode 100644
index 00000000000..6ddcb32b158
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/twintap.c
@@ -0,0 +1,114 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Yonezawa / PartyRoom 21 Twin Tap Controller
+
+ This controller consists of two 1-button small units attached to a
+ single 7pin connector. You plug the connector to Port2 and two
+ players can compete on the quiz game (Port1 should have a joypad
+ plugged in, to start the game and browse the menus). By plugging
+ a multitap adapter to Port2, up to 4 Twin Tap controllers can be
+ attached at the same time, allowing for 8 players quiz sessions.
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#include "twintap.h"
+
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+const device_type SNES_TWINTAP = &device_creator<snes_twintap_device>;
+
+
+static INPUT_PORTS_START( snes_twintap )
+ PORT_START("INPUTS")
+ PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 2")
+ PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 1")
+ PORT_BIT( 0x8ffc, IP_ACTIVE_HIGH, IPT_UNUSED )
+ PORT_BIT( 0x7000, IP_ACTIVE_LOW, IPT_UNUSED ) // controller ID unknown
+INPUT_PORTS_END
+
+
+//-------------------------------------------------
+// input_ports - device-specific input ports
+//-------------------------------------------------
+
+ioport_constructor snes_twintap_device::device_input_ports() const
+{
+ return INPUT_PORTS_NAME( snes_twintap );
+}
+
+
+//**************************************************************************
+// LIVE DEVICE
+//**************************************************************************
+
+//-------------------------------------------------
+// snes_twintap_device - constructor
+//-------------------------------------------------
+
+snes_twintap_device::snes_twintap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
+ device_t(mconfig, SNES_TWINTAP, "Yonezawa Twin Tap Controller", tag, owner, clock, "snes_twintap", __FILE__),
+ device_snes_control_port_interface(mconfig, *this),
+ m_inputs(*this, "INPUTS")
+{
+}
+
+
+//-------------------------------------------------
+// device_start - device-specific startup
+//-------------------------------------------------
+
+void snes_twintap_device::device_start()
+{
+ save_item(NAME(m_latch));
+ save_item(NAME(m_strobe));
+}
+
+
+//-------------------------------------------------
+// device_reset - device-specific reset
+//-------------------------------------------------
+
+void snes_twintap_device::device_reset()
+{
+ m_latch = 0;
+ m_strobe = 0;
+}
+
+
+//-------------------------------------------------
+// poll
+//-------------------------------------------------
+
+void snes_twintap_device::port_poll()
+{
+ m_latch = m_inputs->read();
+}
+
+//-------------------------------------------------
+// read
+//-------------------------------------------------
+
+UINT8 snes_twintap_device::read_pin4()
+{
+ UINT8 ret = m_latch & 1;
+ m_latch >>= 1;
+ return ret;
+}
+
+//-------------------------------------------------
+// write
+//-------------------------------------------------
+
+void snes_twintap_device::write_strobe(UINT8 data)
+{
+ int old = m_strobe;
+ m_strobe = data & 0x01;
+
+ if (m_strobe < old) // 1 -> 0 transition
+ port_poll();
+}
diff --git a/src/emu/bus/snes_ctrl/twintap.h b/src/emu/bus/snes_ctrl/twintap.h
new file mode 100644
index 00000000000..482a20e1bc6
--- /dev/null
+++ b/src/emu/bus/snes_ctrl/twintap.h
@@ -0,0 +1,56 @@
+/**********************************************************************
+
+ Nintendo Super Famicom - Yonezawa / PartyRoom 21 Twin Tap Controller
+
+ Copyright MESS Team.
+ Visit http://mamedev.org for licensing and usage restrictions.
+
+**********************************************************************/
+
+#pragma once
+
+#ifndef __SNES_TWINTAP__
+#define __SNES_TWINTAP__
+
+
+#include "emu.h"
+#include "ctrl.h"
+
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
+
+// ======================> snes_twintap_device
+
+class snes_twintap_device : public device_t,
+ public device_snes_control_port_interface
+{
+public:
+ // construction/destruction
+ snes_twintap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
+
+ // optional information overrides
+ virtual ioport_constructor device_input_ports() const;
+
+protected:
+ // device-level overrides
+ virtual void device_start();
+ virtual void device_reset();
+
+ // device_sms_control_port_interface overrides
+ virtual UINT8 read_pin4();
+ virtual void write_strobe(UINT8 data);
+ virtual void port_poll();
+
+private:
+ required_ioport m_inputs;
+ int m_strobe;
+ UINT32 m_latch;
+};
+
+
+// device type definition
+extern const device_type SNES_TWINTAP;
+
+
+#endif
diff --git a/src/emu/video/snes_ppu.c b/src/emu/video/snes_ppu.c
index 6defa1b22b7..459adb0bb8a 100644
--- a/src/emu/video/snes_ppu.c
+++ b/src/emu/video/snes_ppu.c
@@ -268,7 +268,6 @@ void snes_ppu_device::device_start()
save_item(NAME(m_beam.latch_horz));
save_item(NAME(m_beam.latch_vert));
- save_item(NAME(m_beam.current_horz));
save_item(NAME(m_beam.current_vert));
save_item(NAME(m_beam.last_visible_line));
save_item(NAME(m_beam.interlace_count));
@@ -370,7 +369,6 @@ void snes_ppu_device::device_reset()
m_beam.latch_vert = 0;
m_beam.latch_horz = 0;
m_beam.current_vert = 0;
- m_beam.current_horz = 0;
m_beam.last_visible_line = 225; /* TODO: PAL setting */
m_mode = 0;
m_ppu1_version = 1; // 5C77 chip version number, read by STAT77, only '1' is known
@@ -1978,13 +1976,11 @@ static const UINT16 vram_fgr_inccnts[4] = { 0, 32, 64, 128 };
static const UINT16 vram_fgr_shiftab[4] = { 0, 5, 6, 7 };
// utility function - latches the H/V counters. Used by IRQ, writes to WRIO, etc.
-void snes_ppu_device::latch_counters()
+void snes_ppu_device::set_latch_hv(INT16 x, INT16 y)
{
- m_beam.current_horz = m_screen->hpos() / m_htmult;
- m_beam.latch_vert = m_screen->vpos();
- m_beam.latch_horz = m_beam.current_horz;
+ m_beam.latch_vert = y;
+ m_beam.latch_horz = x;
m_stat78 |= 0x40; // indicate we latched
-// m_read_ophct = m_read_opvct = 0; // clear read flags - 2009-08: I think we must clear these when STAT78 is read...
// printf("latched @ H %d V %d\n", m_beam.latch_horz, m_beam.latch_vert);
}
@@ -2308,7 +2304,7 @@ UINT8 snes_ppu_device::read(address_space &space, UINT32 offset, UINT8 wrio_bit7
return m_ppu1_open_bus;
}
case SLHV: /* Software latch for H/V counter */
- latch_counters();
+ set_latch_hv(m_screen->hpos() / m_htmult, m_screen->vpos());
return m_openbus_cb(space, 0); /* Return value is meaningless */
case ROAMDATA: /* Read data from OAM (DR) */
diff --git a/src/emu/video/snes_ppu.h b/src/emu/video/snes_ppu.h
index 7b25c1a4417..fa141e84e92 100644
--- a/src/emu/video/snes_ppu.h
+++ b/src/emu/video/snes_ppu.h
@@ -124,7 +124,6 @@ public:
{
UINT16 latch_horz;
UINT16 latch_vert;
- UINT16 current_horz;
UINT16 current_vert;
UINT8 last_visible_line;
UINT8 interlace_count;
@@ -250,7 +249,9 @@ public:
inline void draw_blend(UINT16 offset, UINT16 *colour, UINT8 prevent_color_math, UINT8 black_pen_clip, int switch_screens);
void refresh_scanline(bitmap_rgb32 &bitmap, UINT16 curline);
- void latch_counters();
+ inline INT16 current_x() { return m_screen->hpos() / m_htmult; }
+ inline INT16 current_y() { return m_screen->vpos(); }
+ void set_latch_hv(INT16 x, INT16 y);
void dynamic_res_change();
inline UINT32 get_vram_address();
UINT8 dbg_video(UINT16 curline);
diff --git a/src/mame/includes/snes.h b/src/mame/includes/snes.h
index 04f697e439d..e18670c6ace 100644
--- a/src/mame/includes/snes.h
+++ b/src/mame/includes/snes.h
@@ -397,7 +397,8 @@ public:
void hdma_init(address_space &space);
void hdma_update(address_space &space, int dma);
void hirq_tick();
- void write_joy_latch(UINT8 data);
+ virtual void write_joy_latch(UINT8 data);
+ virtual void wrio_write(UINT8 data);
inline UINT8 snes_rom_access(UINT32 offset);
void snes_init_ram();
diff --git a/src/mame/machine/snes.c b/src/mame/machine/snes.c
index 7b9981efaaa..2741e451cf5 100644
--- a/src/mame/machine/snes.c
+++ b/src/mame/machine/snes.c
@@ -87,7 +87,7 @@ void snes_state::hirq_tick()
{
// latch the counters and pull IRQ
// (don't need to switch to the 65816 context, we don't do anything dependant on it)
- m_ppu->latch_counters();
+ m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y());
SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */
m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE);
@@ -142,7 +142,7 @@ TIMER_CALLBACK_MEMBER(snes_state::snes_scanline_tick)
{
SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */
// IRQ latches the counters, do it now
- m_ppu->latch_counters();
+ m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y());
m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE );
}
}
@@ -536,11 +536,7 @@ WRITE8_MEMBER( snes_state::snes_w_io )
SNES_CPU_REG(NMITIMEN) = data;
return;
case WRIO: /* Programmable I/O port - latches H/V counters on a 0->1 transition */
- if (!(SNES_CPU_REG(WRIO) & 0x80) && (data & 0x80))
- {
- // external latch
- m_ppu->latch_counters();
- }
+ wrio_write(data);
SNES_CPU_REG(WRIO) = data;
return;
case HTIMEL: /* H-Count timer settings (low) */
@@ -611,6 +607,15 @@ void snes_state::write_joy_latch(UINT8 data)
}
+void snes_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());
+ }
+}
+
WRITE_LINE_MEMBER(snes_state::snes_extern_irq_w)
{
m_maincpu->set_input_line(G65816_LINE_IRQ, state);
diff --git a/src/mess/drivers/snes.c b/src/mess/drivers/snes.c
index 94573efb94c..24f9ab055f5 100644
--- a/src/mess/drivers/snes.c
+++ b/src/mess/drivers/snes.c
@@ -21,8 +21,7 @@
- Fix vertical mosaic effects
- Add support for real CX4 and ST018 CPUs
- Add support for SA-1 and SuperGB add-ons
- - Fix mouse & superscope support
- - Add multitap support
+ - Fix superscope support
- Add support for other controllers
***************************************************************************/
@@ -33,38 +32,17 @@
#include "includes/snes.h"
#include "machine/snescx4.h"
-#include "crsshair.h"
-
#include "bus/snes/snes_slot.h"
#include "bus/snes/snes_carts.h"
-
-struct snes_mouse
-{
- INT16 x, y, oldx, oldy;
- UINT16 buttons;
- UINT8 deltax, deltay;
- int speed;
-};
-
-struct snes_superscope
-{
- INT16 x, y;
- UINT8 buttons;
- int turbo_lock, pause_lock, fire_lock;
- int offscreen;
-};
-
+#include "bus/snes_ctrl/ctrl.h"
class snes_console_state : public snes_state
{
public:
- enum
- {
- TIMER_LIGHTGUN_TICK = TIMER_SNES_LAST
- };
-
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")
{ }
@@ -110,35 +88,20 @@ public:
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);
-
- // pad inputs
- void input_read_joy(int port, bool multitap);
- UINT8 input_serial_pad(int port, int latched, bool multitap);
-
- // mouse inputs
- void input_read_mouse(int port);
- UINT8 input_serial_mouse(int port, int latched);
-
- // superscope inputs
- DECLARE_CUSTOM_INPUT_MEMBER( sscope_offscreen_input );
- void input_read_sscope(int port);
- UINT8 input_serial_sscope(int port, int latched);
- void gun_latch(INT16 x, INT16 y);
+ 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;
-
-protected:
-
- snes_mouse m_mouse[2];
- snes_superscope m_scope[2];
-
- virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
};
@@ -1060,230 +1023,8 @@ ADDRESS_MAP_END
*
*************************************/
-void snes_console_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
-{
- switch (id)
- {
- case TIMER_LIGHTGUN_TICK:
- lightgun_tick(ptr, param);
- break;
- default:
- snes_state::device_timer(timer, id, param, ptr);
- break;
- }
-}
-
-TIMER_CALLBACK_MEMBER( snes_console_state::lightgun_tick )
-{
- if ((ioport("CTRLSEL")->read() & 0x0f) == 0x03 || (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 ((ioport("CTRLSEL")->read() & 0xf0) == 0x30 || (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("JOY1")
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("P1 Start") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
-
- PORT_START("JOY2")
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("P2 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
-// temp hack to share the same port both for P2 alone and P2 through MP5 adapter
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("P2 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
-
- PORT_START("JOY3")
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 Button B") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P3 Button Y") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START3 ) PORT_NAME("P3 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 Button A") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P3 Button X") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P3 Button L") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P3 Button R") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
-
- PORT_START("JOY4")
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 Button B") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P4 Button Y") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START4 ) PORT_NAME("P4 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 Button A") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P4 Button X") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P4 Button L") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P4 Button R") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
-
- PORT_START("JOY5")
- PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P5 Button B") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P5 Button Y") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START5 ) PORT_NAME("P5 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P5 Button A") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P5 Button X") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P5 Button L") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P5 Button R") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
- PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
-
-INPUT_PORTS_END
-
-static INPUT_PORTS_START( snes_mouse )
- PORT_START("MOUSE1")
- /* bits 0,3 = mouse signature (must be 1) */
- PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED )
- PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNUSED )
- PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNUSED )
- PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED )
- /* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */
- PORT_BIT( 0x0030, IP_ACTIVE_HIGH, IPT_UNUSED )
- /* bits 6,7 = mouse buttons */
- PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Button Left") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
- PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Button Right") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
- PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) // these must be 0!
-
- PORT_START("MOUSE1_X")
- PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) 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(15) 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_UNUSED )
- /* 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(15) 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(15) 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_MEMBER(DEVICE_SELF, snes_console_state, sscope_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_MEMBER(DEVICE_SELF, snes_console_state, sscope_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)
-
+ // 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 ) )
@@ -1349,446 +1090,97 @@ INPUT_PORTS_END
*
*************************************/
-// Mouse handling
-
-void snes_console_state::input_read_mouse(int port)
+WRITE8_MEMBER(snes_console_state::io_read)
{
- INT16 var;
- static const char *const portnames[2][3] =
- {
- { "MOUSE1", "MOUSE1_X", "MOUSE1_Y" },
- { "MOUSE2", "MOUSE2_X", "MOUSE2_Y" },
- };
-
- m_mouse[port].buttons = ioport(portnames[port][0])->read();
- m_mouse[port].x = ioport(portnames[port][1])->read();
- m_mouse[port].y = ioport(portnames[port][2])->read();
-
- var = m_mouse[port].x - m_mouse[port].oldx;
-
- if (var < -127)
- {
- m_mouse[port].deltax = 0xff;
- m_mouse[port].oldx -= 127;
- }
- else if (var < 0)
- {
- m_mouse[port].deltax = 0x80 | (-var);
- m_mouse[port].oldx = m_mouse[port].x;
- }
- else if (var > 127)
- {
- m_mouse[port].deltax = 0x7f;
- m_mouse[port].oldx += 127;
- }
- else
- {
- m_mouse[port].deltax = var & 0xff;
- m_mouse[port].oldx = m_mouse[port].x;
- }
-
- var = m_mouse[port].y - m_mouse[port].oldy;
-
- if (var < -127)
- {
- m_mouse[port].deltay = 0xff;
- m_mouse[port].oldy -= 127;
- }
- else if (var < 0)
- {
- m_mouse[port].deltay = 0x80 | (-var);
- m_mouse[port].oldy = m_mouse[port].y;
- }
- else if (var > 127)
- {
- m_mouse[port].deltay = 0x7f;
- m_mouse[port].oldy += 127;
- }
- else
+ // is automatic reading on? if so, read 16bits from oldjoy1/2
+ if (SNES_CPU_REG(NMITIMEN) & 1)
{
- m_mouse[port].deltay = var & 0xff;
- m_mouse[port].oldy = m_mouse[port].y;
- }
+ 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));
+ }
- m_data1[port] = m_mouse[port].buttons;
- m_data2[port] = 0;
+ 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::input_serial_mouse(int port, int latched)
+UINT8 snes_console_state::oldjoy1_read(int latched)
{
- UINT8 res = 0;
-
- if (latched)
- {
- m_mouse[port].speed = (m_mouse[port].speed + 1) % 3;
- return res;
- }
-
- if (m_read_idx[port] >= 32)
- res |= 0x01;
- else if (m_read_idx[port] >= 24)
- res |= (m_mouse[port].deltax >> (31 - m_read_idx[port]++)) & 0x01;
- else if (m_read_idx[port] >= 16)
- res |= (m_mouse[port].deltay >> (23 - m_read_idx[port]++)) & 0x01;
- else if (m_read_idx[port] == 11)
- {
- res |= (m_mouse[port].speed >> 0) & 0x01;
- m_read_idx[port]++;
- }
- else if (m_read_idx[port] == 10)
- {
- res |= (m_mouse[port].speed >> 1) & 0x01;
- m_read_idx[port]++;
- }
- else
- res |= (m_mouse[port].buttons >> (15 - m_read_idx[port]++)) & 0x01;
+ UINT8 ret = 0;
+ ret |= m_ctrl1->read_pin4();
+ ret |= (m_ctrl1->read_pin5() << 1);
+ return ret;
+}
- return res;
+UINT8 snes_console_state::oldjoy2_read(int latched)
+{
+ UINT8 ret = 0;
+ ret |= m_ctrl2->read_pin4();
+ ret |= (m_ctrl2->read_pin5() << 1);
+ return ret;
}
-// Superscope handling
+void snes_console_state::write_joy_latch(UINT8 data)
+{
+ m_ctrl1->write_strobe(data);
+ m_ctrl2->write_strobe(data);
+}
-CUSTOM_INPUT_MEMBER( snes_console_state::sscope_offscreen_input )
+void snes_console_state::wrio_write(UINT8 data)
{
- int port = (FPTR)param;
- static const char *const portnames[2][3] =
+ if (!(SNES_CPU_REG(WRIO) & 0x80) && (data & 0x80))
{
- { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" },
- { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" },
- };
-
- INT16 x = ioport(portnames[port][1])->read();
- INT16 y = ioport(portnames[port][2])->read();
+ // external latch
+ m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y());
+ }
- /* these are the theoretical boundaries, but we currently are always onscreen... */
- if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= m_ppu->m_beam.last_visible_line)
- m_scope[port].offscreen = 1;
- else
- m_scope[port].offscreen = 0;
+ m_ctrl1->write_pin6(BIT(data, 6));
+ m_ctrl2->write_pin6(BIT(data, 7));
- return m_scope[port].offscreen;
}
-
-void snes_console_state::gun_latch(INT16 x, INT16 y)
+SNESCTRL_GUNLATCH_CB(snes_console_state::gun_latch_cb)
{
- /* these are the theoretical boundaries */
+ // 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->m_beam.latch_horz = x;
- m_ppu->m_beam.latch_vert = y;
- m_ppu->m_stat78 |= 0x40;
-}
-
-void snes_console_state::input_read_sscope(int port)
-{
- static const char *const portnames[2][3] =
- {
- { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" },
- { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" },
- };
- UINT8 input;
-
- /* first read input bits */
- m_scope[port].x = ioport(portnames[port][1])->read();
- m_scope[port].y = ioport(portnames[port][2])->read();
- input = ioport(portnames[port][0])->read();
-
- /* then start elaborating input bits: only keep old turbo value */
- m_scope[port].buttons &= 0x20;
-
- /* set onscreen/offscreen */
- m_scope[port].buttons |= BIT(input, 1);
-
- /* turbo is a switch; toggle is edge sensitive */
- if (BIT(input, 5) && !m_scope[port].turbo_lock)
- {
- m_scope[port].buttons ^= 0x20;
- m_scope[port].turbo_lock = 1;
- }
- else if (!BIT(input, 5))
- 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(m_scope[port].buttons, 5) || !m_scope[port].fire_lock))
- {
- m_scope[port].buttons |= 0x80;
- m_scope[port].fire_lock = 1;
- }
- else if (!BIT(input, 7))
- m_scope[port].fire_lock = 0;
-
- /* cursor is a button; it is always level sensitive */
- m_scope[port].buttons |= BIT(input, 6);
-
- /* pause is a button; it is always edge sensitive */
- if (BIT(input, 4) && !m_scope[port].pause_lock)
- {
- m_scope[port].buttons |= 0x10;
- m_scope[port].pause_lock = 1;
- }
- else if (!BIT(input, 4))
- 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 ((m_scope[port].buttons & 0xc0) && !(m_scope[port].buttons & 0x02) && port == 1)
- gun_latch(m_scope[port].x, m_scope[port].y);
-
- m_data1[port] = 0xff | (m_scope[port].buttons << 8);
- m_data2[port] = 0;
-}
-
-UINT8 snes_console_state::input_serial_sscope(int port, int latched)
-{
- UINT8 res = 0;
-
- if (m_read_idx[port] >= 8)
- res |= 0x01;
- else
- res |= (m_scope[port].buttons >> (7 - m_read_idx[port]++)) & 0x01;
-
- return res;
-}
-
-// Joypad + Multitap handling
-// input_read_joy is used both for standard joys and for the MP5 multitap
-
-void snes_console_state::input_read_joy( int port, bool multitap )
-{
- static const char *const portnames[4][2] =
- {
- { "JOY1", "JOY3" },
- { "JOY2", "JOY3" },
- { "JOY4", "JOY5" },
- { "JOY4", "JOY5" }
- };
-
- if (!multitap)
- {
- m_data1[port] = ioport(portnames[port][0])->read();
- m_data2[port] = 0;
- // avoid sending signals that could crash games
- // if left, no right
- if (m_data1[port] & 0x200)
- m_data1[port] &= ~0x100;
- // if up, no down
- if (m_data1[port] & 0x800)
- m_data1[port] &= ~0x400;
- // if left, no right
- if (m_data2[port] & 0x200)
- m_data2[port] &= ~0x100;
- // if up, no down
- if (m_data2[port] & 0x800)
- m_data2[port] &= ~0x400;
- }
- else
- {
- m_data1[port] = ioport(portnames[port][0])->read();
- m_data2[port] = ioport(portnames[port][1])->read();
- m_data1[port + 2] = ioport(portnames[port + 2][0])->read();
- m_data2[port + 2] = ioport(portnames[port + 2][1])->read();
- // avoid sending signals that could crash games
- // if left, no right
- if (m_data1[port] & 0x200)
- m_data1[port] &= ~0x100;
- // if up, no down
- if (m_data1[port] & 0x800)
- m_data1[port] &= ~0x400;
- // if left, no right
- if (m_data2[port] & 0x200)
- m_data2[port] &= ~0x100;
- // if up, no down
- if (m_data2[port] & 0x800)
- m_data2[port] &= ~0x400;
- // if left, no right
- if (m_data1[port + 2] & 0x200)
- m_data1[port + 2] &= ~0x100;
- // if up, no down
- if (m_data1[port + 2] & 0x800)
- m_data1[port + 2] &= ~0x400;
- // if left, no right
- if (m_data2[port + 2] & 0x200)
- m_data2[port + 2] &= ~0x100;
- // if up, no down
- if (m_data2[port + 2] & 0x800)
- m_data2[port + 2] &= ~0x400;
- }
+// 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());
}
-UINT8 snes_console_state::input_serial_pad(int port, int latched, bool multitap)
+SNESCTRL_ONSCREEN_CB(snes_console_state::onscreen_cb)
{
- UINT8 res = 0;
-
- // multitap signature? Super Bomberman 3-5 do not like this at all...
- if (multitap)
- res |= 2;
- if (latched)
- return res;
-
- if (!multitap)
- {
- if (m_read_idx[port] >= 16)
- res |= 0x01;
- else
- {
- res |= (BIT(m_data1[port], (15 - m_read_idx[port])));
- res |= (BIT(m_data2[port], (15 - m_read_idx[port])) << 1);
- m_read_idx[port]++;
- }
- }
+ // 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
- {
- int shift = !(SNES_CPU_REG(WRIO) & 0x80) ? 2 : 0;
- if (m_read_idx[port + shift] >= 16)
- res |= 0x03;
- else
- {
- res |= (BIT(m_data1[port + shift], (15 - m_read_idx[port + shift])));
- res |= (BIT(m_data2[port + shift], (15 - m_read_idx[port + shift])) << 1);
- m_read_idx[port + shift]++;
- }
- }
- return res;
+ return true;
}
-// input handling from the system side
-
-WRITE8_MEMBER(snes_console_state::io_read)
-{
- UINT8 ctrl1 = ioport("CTRLSEL")->read() & 0x0f;
- UINT8 ctrl2 = (ioport("CTRLSEL")->read() & 0xf0) >> 4;
- bool multitap0 = FALSE;
- bool multitap1 = FALSE;
-
- // Check if lightgun has been chosen as input: if so, enable crosshair
- timer_set(attotime::zero, TIMER_LIGHTGUN_TICK);
-
- switch (ctrl1)
- {
- case 1: // SNES joypad
- input_read_joy(0, FALSE);
- break;
- case 2: // SNES Mouse
- input_read_mouse(0);
- break;
- case 3: // SNES Superscope
- input_read_sscope(0);
- break;
- case 5: // SNES joypad(s) through MP5 multitap
- input_read_joy(0, TRUE);
- multitap0 = TRUE;
- break;
- case 0: // empty port1
- default:
- m_data1[0] = 0;
- m_data2[0] = 0;
- break;
- }
-
- switch (ctrl2)
- {
- case 1: // SNES joypad
- input_read_joy(1, FALSE);
- break;
- case 2: // SNES Mouse
- input_read_mouse(1);
- break;
- case 3: // SNES Superscope
- input_read_sscope(1);
- break;
- case 5: // SNES joypad(s) through MP5 multitap
- input_read_joy(1, TRUE);
- multitap1 = TRUE;
- break;
- case 0: // empty port2
- default:
- m_data1[1] = 0;
- 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_CPU_REG(NMITIMEN) & 1)
- {
- int shift0 = (multitap0 && !(SNES_CPU_REG(WRIO) & 0x80)) ? 2 : 0;
- int shift1 = (multitap1 && !(SNES_CPU_REG(WRIO) & 0x80)) ? 2 : 0;
-
- SNES_CPU_REG(JOY1L) = (m_data1[0 + shift0] & 0x00ff) >> 0;
- SNES_CPU_REG(JOY1H) = (m_data1[0 + shift0] & 0xff00) >> 8;
- SNES_CPU_REG(JOY2L) = (m_data1[1 + shift1] & 0x00ff) >> 0;
- SNES_CPU_REG(JOY2H) = (m_data1[1 + shift1] & 0xff00) >> 8;
- SNES_CPU_REG(JOY3L) = (m_data2[0 + shift0] & 0x00ff) >> 0;
- SNES_CPU_REG(JOY3H) = (m_data2[0 + shift0] & 0xff00) >> 8;
- SNES_CPU_REG(JOY4L) = (m_data2[1 + shift1] & 0x00ff) >> 0;
- SNES_CPU_REG(JOY4H) = (m_data2[1 + shift1] & 0xff00) >> 8;
-
- // make sure read_idx starts returning all 1s because the auto-read reads it :-)
- m_read_idx[0 + shift0] = 16;
- m_read_idx[1 + shift1] = 16;
- }
-}
-
-UINT8 snes_console_state::oldjoy1_read(int latched)
-{
- UINT8 ctrl1 = ioport("CTRLSEL")->read() & 0x0f;
-
- switch (ctrl1)
- {
- case 1: // SNES joypad
- return input_serial_pad(0, latched, FALSE);
-
- case 2: // SNES Mouse
- return input_serial_mouse(0, latched);
-
- case 3: // SNES Superscope
- return input_serial_sscope(0, latched);
-
- case 5: // SNES multipad
- return input_serial_pad(0, latched, TRUE);
-
- case 0: // empty port1
- default:
- return 0;
- }
-}
-
-UINT8 snes_console_state::oldjoy2_read(int latched)
-{
- UINT8 ctrl2 = (ioport("CTRLSEL")->read() & 0xf0) >> 4;
-
- switch (ctrl2)
- {
- case 1: // SNES joypad
- return input_serial_pad(1, latched, FALSE);
-
- case 2: // SNES Mouse
- return input_serial_mouse(1, latched);
-
- case 3: // SNES Superscope
- return input_serial_sscope(1, latched);
-
- case 5: // SNES multipad
- return input_serial_pad(1, latched, TRUE);
-
- case 0: // empty port1
- default:
- return 0;
- }
-}
-
/*************************************
*
* Machine driver
@@ -1914,25 +1306,6 @@ void snes_console_state::machine_start()
break;
}
- for (int i = 0; i < 2; i++)
- {
- save_item(NAME(m_mouse[i].x), i);
- save_item(NAME(m_mouse[i].oldx), i);
- save_item(NAME(m_mouse[i].y), i);
- save_item(NAME(m_mouse[i].oldy), i);
- save_item(NAME(m_mouse[i].buttons), i);
- save_item(NAME(m_mouse[i].deltax), i);
- save_item(NAME(m_mouse[i].deltay), i);
- save_item(NAME(m_mouse[i].speed), i);
- save_item(NAME(m_scope[i].x), i);
- save_item(NAME(m_scope[i].y), i);
- save_item(NAME(m_scope[i].buttons), i);
- save_item(NAME(m_scope[i].turbo_lock), i);
- save_item(NAME(m_scope[i].pause_lock), i);
- save_item(NAME(m_scope[i].fire_lock), i);
- save_item(NAME(m_scope[i].offscreen), i);
- }
-
if (m_cartslot)
m_cartslot->save_ram();
}
@@ -1964,6 +1337,12 @@ static MACHINE_CONFIG_START( snes, snes_console_state )
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)
diff --git a/src/mess/mess.mak b/src/mess/mess.mak
index 3ee815adbd7..fdc4ca29768 100644
--- a/src/mess/mess.mak
+++ b/src/mess/mess.mak
@@ -635,6 +635,7 @@ BUSES += SEGA8
BUSES += SMS_CTRL
BUSES += SMS_EXP
BUSES += SNES
+BUSES += SNES_CTRL
BUSES += SPC1000
BUSES += TI99PEB
BUSES += TVC