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 @@ -1132,6 +1132,23 @@ BUSOBJS += $(BUSOBJ)/snes/sufami.o BUSOBJS += $(BUSOBJ)/snes/upd.o 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 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; -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; + + +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("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 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; + + +//************************************************************************** +// 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(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(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 snesctrl_onscreen_delegate; +#define SNESCTRL_ONSCREEN_CB(name) bool name(INT16 x, INT16 y) + +typedef device_delegate 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(device).m_onscreen_cb = callback; } + static void set_gunlatch_callback(device_t &device, snesctrl_gunlatch_delegate callback) { downcast(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; + + +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; + + +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; + + +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 m_port1; + required_device m_port2; + required_device m_port3; + required_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; + + +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; + + +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; + + +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 m_ctrl1; + required_device m_ctrl2; optional_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,445 +1090,96 @@ 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] = + // is automatic reading on? if so, read 16bits from oldjoy1/2 + if (SNES_CPU_REG(NMITIMEN) & 1) { - { "MOUSE1", "MOUSE1_X", "MOUSE1_Y" }, - { "MOUSE2", "MOUSE2_X", "MOUSE2_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_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 - { - m_mouse[port].deltay = var & 0xff; - m_mouse[port].oldy = m_mouse[port].y; - } - - 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; - - return res; + UINT8 ret = 0; + ret |= m_ctrl1->read_pin4(); + ret |= (m_ctrl1->read_pin5() << 1); + return ret; } -// Superscope handling - -CUSTOM_INPUT_MEMBER( snes_console_state::sscope_offscreen_input ) +UINT8 snes_console_state::oldjoy2_read(int latched) { - int port = (FPTR)param; - static const char *const portnames[2][3] = - { - { "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, - { "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, - }; - - INT16 x = ioport(portnames[port][1])->read(); - INT16 y = ioport(portnames[port][2])->read(); - - /* these are the theoretical boundaries, but we currently are always onscreen... */ - if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= m_ppu->m_beam.last_visible_line) - m_scope[port].offscreen = 1; - else - m_scope[port].offscreen = 0; - - return m_scope[port].offscreen; + UINT8 ret = 0; + ret |= m_ctrl2->read_pin4(); + ret |= (m_ctrl2->read_pin5() << 1); + return ret; } - -void snes_console_state::gun_latch(INT16 x, INT16 y) +void snes_console_state::write_joy_latch(UINT8 data) { - /* these are the theoretical boundaries */ + m_ctrl1->write_strobe(data); + m_ctrl2->write_strobe(data); +} + +void snes_console_state::wrio_write(UINT8 data) +{ + if (!(SNES_CPU_REG(WRIO) & 0x80) && (data & 0x80)) + { + // external latch + m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y()); + } + + m_ctrl1->write_pin6(BIT(data, 6)); + m_ctrl2->write_pin6(BIT(data, 7)); + +} + +SNESCTRL_GUNLATCH_CB(snes_console_state::gun_latch_cb) +{ + // these are the theoretical boundaries if (x < 0) x = 0; if (x > (SNES_SCR_WIDTH - 1)) x = SNES_SCR_WIDTH - 1; - + if (y < 0) y = 0; if (y > (m_ppu->m_beam.last_visible_line - 1)) y = m_ppu->m_beam.last_visible_line - 1; - m_ppu->m_beam.latch_horz = x; - m_ppu->m_beam.latch_vert = y; - m_ppu->m_stat78 |= 0x40; +// 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()); } -void snes_console_state::input_read_sscope(int port) +SNESCTRL_ONSCREEN_CB(snes_console_state::onscreen_cb) { - 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; + // 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 - res |= (m_scope[port].buttons >> (7 - m_read_idx[port]++)) & 0x01; - - return res; + return true; } -// 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; - } -} - -UINT8 snes_console_state::input_serial_pad(int port, int latched, bool multitap) -{ - 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]++; - } - } - 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; -} - - -// 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; - } -} /************************************* * @@ -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