(MESS) snes: converted input code to use slot devices. This means that you

now change the emulated controllers (Joypad, Mouse, Multitap, Super Scope)
via the Slot Device menu of the UI interface and not anymore from the System
Configurations menu. Also, changing controller now requires to reset the
system, so please take some timeto choose the desired controller *before*
starting the game, if you want to play a game that uses special controllers.
[Fabio Priuli]

(MESS) snes: fixed Mouse emulation so that it does not jump back erratically
if you keep moving beyond the window border. [Fabio Priuli]

(MESS) snes: fixed Multitap Adapter emulation so games properly recognize
the device and inputs from all 5 controllers are accepted by the games.
[Fabio Priuli]

(MESS) snes: added emulation of the Pachinko controller used by a few
pachinko games for Super Famicom. [Fabio Priuli]

(MESS) snes: added emulation of the Yonezawa Twin Tap controllers,
which allow to play with up to 8 players a quiz games for Super Famicom.
[Fabio Priuli]

(MESS) snes: added emulation of the Epoch Barcode Battler unit (even if
only as Super Famicom controller, and not as a standalone unit) which is
necessary to play Conveni Wars Barcode Battler Senki for Super Famicom.
[Fabio Priuli]
This commit is contained in:
etabeta78 2015-01-31 10:59:42 +01:00
parent bf5af9fcd6
commit c0c92d60b5
25 changed files with 1924 additions and 733 deletions

View File

@ -1132,6 +1132,23 @@ BUSOBJS += $(BUSOBJ)/snes/sufami.o
BUSOBJS += $(BUSOBJ)/snes/upd.o BUSOBJS += $(BUSOBJ)/snes/upd.o
endif 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 #@src/emu/bus/vboy/slot.h,BUSES += VBOY

View File

@ -20,18 +20,6 @@
const device_type NES_BARCODE_BATTLER = &device_creator<nes_bcbattle_device>; const device_type NES_BARCODE_BATTLER = &device_creator<nes_bcbattle_device>;
static INPUT_PORTS_START( nes_battler )
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor nes_bcbattle_device::device_input_ports() const
{
return INPUT_PORTS_NAME( nes_battler );
}
MACHINE_CONFIG_FRAGMENT( nes_battler ) MACHINE_CONFIG_FRAGMENT( nes_battler )
MCFG_BARCODE_READER_ADD("battler") MCFG_BARCODE_READER_ADD("battler")
MACHINE_CONFIG_END MACHINE_CONFIG_END
@ -46,6 +34,9 @@ machine_config_constructor nes_bcbattle_device::device_mconfig_additions() const
// device_timer - handler timer events // 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) void nes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{ {
if (id == TIMER_BATTLER) 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) : 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), device_nes_control_port_interface(mconfig, *this),
m_reader(*this, "battler") m_reader(*this, "battler")
{ {

View File

@ -30,7 +30,6 @@ public:
// construction/destruction // construction/destruction
nes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); 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 void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual machine_config_constructor device_mconfig_additions() const; virtual machine_config_constructor device_mconfig_additions() const;

View File

@ -0,0 +1,213 @@
/**********************************************************************
Nintendo Super Famicom - Epoch Barcode Battler
TODO: this should be actually emulated as a standalone system with
a few 7segments LEDs, once we get a dump of its BIOS
At the moment we only emulated the connection with a Super Famicom
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "bcbattle.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_BARCODE_BATTLER = &device_creator<snes_bcbattle_device>;
MACHINE_CONFIG_FRAGMENT( snes_battler )
MCFG_BARCODE_READER_ADD("battler")
MACHINE_CONFIG_END
machine_config_constructor snes_bcbattle_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( snes_battler );
}
//-------------------------------------------------
// device_timer - handler timer events
//-------------------------------------------------
// This part is the hacky replacement for the real Barcode unit [shared with NES implementation]:
// code periodically checks whether a new code has been scanned and it moves it to the
// m_current_barcode array
void snes_bcbattle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
if (id == TIMER_BATTLER)
{
int old = m_new_code;
m_new_code = m_reader->get_pending_code();
// has something new been scanned?
if (old < m_new_code)
{
if (m_reader->get_byte_length() == 13)
{
for (int i = 0; i < 13; i++)
m_current_barcode[i] = m_reader->read_code() + '0';
}
else if (m_reader->get_byte_length() == 8)
{
for (int i = 0; i < 5; i++)
m_current_barcode[i] = 0x20;
for (int i = 5; i < 13; i++)
m_current_barcode[i] = m_reader->read_code() + '0';
}
// read one more, to reset the internal byte counter
m_reader->read_code();
// the string "SUNSOFT" is accepted as well by Barcode World
m_current_barcode[13] = 'E';
m_current_barcode[14] = 'P';
m_current_barcode[15] = 'O';
m_current_barcode[16] = 'C';
m_current_barcode[17] = 'H';
m_current_barcode[18] = 0x0d;
m_current_barcode[19] = 0x0a;
m_pending_code = 1;
}
}
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_bcbattle_device - constructor
//-------------------------------------------------
snes_bcbattle_device::snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_BARCODE_BATTLER, "Epoch Barcode Battler (SFC)", tag, owner, clock, "snes_bcbattle", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_reader(*this, "battler")
{
}
//-------------------------------------------------
// device_start
//-------------------------------------------------
void snes_bcbattle_device::device_start()
{
// lacking emulation of the standalone Barcode Battler, we refresh periodically the input from the reader
// proper emulation would have the standalone unit acknowledging that a new barcode has been scanned
// and sending the proper serial bits, instead of our read_current_bit() function!
battler_timer = timer_alloc(TIMER_BATTLER);
battler_timer->adjust(attotime::zero, 0, machine().device<cpu_device>("maincpu")->cycles_to_attotime(1000));
save_item(NAME(m_current_barcode));
save_item(NAME(m_new_code));
save_item(NAME(m_pending_code));
save_item(NAME(m_transmitting));
save_item(NAME(m_cur_bit));
save_item(NAME(m_cur_byte));
}
//-------------------------------------------------
// device_reset
//-------------------------------------------------
void snes_bcbattle_device::device_reset()
{
m_pending_code = 0;
m_new_code = 0;
m_transmitting = 0;
m_cur_bit = 0;
m_cur_byte = 0;
memset(m_current_barcode, 0, ARRAY_LENGTH(m_current_barcode));
}
//-------------------------------------------------
// read
//-------------------------------------------------
int snes_bcbattle_device::read_current_bit()
{
if (m_pending_code)
{
if (m_cur_bit < 4)
{
int bit = BIT(m_current_barcode[m_cur_byte], m_cur_bit - 1);
m_cur_bit++;
return bit;
}
if (m_cur_bit == 4) // only the low nibble is transmitted (this is the main action of the BBII interface for SNES)
{
m_cur_bit = 0;
//printf("%X ", m_current_barcode[m_cur_byte]);
m_cur_byte++;
if (m_cur_byte == 13)
{
m_cur_byte = 0;
m_pending_code = 0;
}
return 0;
}
}
return 0;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_bcbattle_device::port_poll()
{
m_idx = 0;
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_bcbattle_device::read_pin4()
{
UINT8 ret = 0;
if (m_idx >= 80)
ret |= 0x00;
else if (m_idx >= 28) // scan actual barcode
{
ret |= read_current_bit(); // if no code is pending transmission, the function returns 0
m_idx++;
}
else if (m_idx >= 25) // unknown flags?
m_idx++;
else if (m_idx == 24) // barcode present
{
ret |= m_pending_code;
m_idx++;
}
else if (m_idx >= 12) // controller ID
ret |= BIT(0x7000, m_idx++);
else // first 12 bytes are unknown and probably always 0
m_idx++;
return ret;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_bcbattle_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -0,0 +1,61 @@
/**********************************************************************
Nintendo Super Famicom - Epoch Barcode Battler
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#pragma once
#ifndef __SNES_BCBATTLE__
#define __SNES_BCBATTLE__
#include "emu.h"
#include "ctrl.h"
#include "machine/bcreader.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> snes_bcbattle_device
class snes_bcbattle_device : public device_t,
public device_snes_control_port_interface
{
public:
// construction/destruction
snes_bcbattle_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
virtual machine_config_constructor device_mconfig_additions() const;
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
virtual UINT8 read_pin4();
virtual void write_strobe(UINT8 data);
virtual void port_poll();
int read_current_bit();
private:
static const device_timer_id TIMER_BATTLER = 1;
required_device<barcode_reader_device> m_reader;
UINT8 m_current_barcode[20];
int m_pending_code, m_new_code, m_transmitting, m_cur_bit, m_cur_byte;
emu_timer *battler_timer;
int m_strobe, m_on, m_idx;
};
// device type definition
extern const device_type SNES_BARCODE_BATTLER;
#endif

View File

@ -0,0 +1,135 @@
/**********************************************************************
Nintendo Super Famicom & SNES controller port emulation
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "ctrl.h"
// slot devices
#include "bcbattle.h"
#include "joypad.h"
#include "mouse.h"
#include "multitap.h"
#include "pachinko.h"
#include "sscope.h"
#include "twintap.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
const device_type SNES_CONTROL_PORT = &device_creator<snes_control_port_device>;
//**************************************************************************
// CARD INTERFACE
//**************************************************************************
//-------------------------------------------------
// device_snes_control_port_interface - constructor
//-------------------------------------------------
device_snes_control_port_interface::device_snes_control_port_interface(const machine_config &mconfig, device_t &device)
: device_slot_card_interface(mconfig,device)
{
m_port = dynamic_cast<snes_control_port_device *>(device.owner());
}
//-------------------------------------------------
// ~device_snes_control_port_interface - destructor
//-------------------------------------------------
device_snes_control_port_interface::~device_snes_control_port_interface()
{
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_control_port_device - constructor
//-------------------------------------------------
snes_control_port_device::snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_CONTROL_PORT, "Nintendo SNES / SFC control port", tag, owner, clock, "snes_control_port", __FILE__),
device_slot_interface(mconfig, *this)
{
}
//-------------------------------------------------
// snes_control_port_device - destructor
//-------------------------------------------------
snes_control_port_device::~snes_control_port_device()
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_control_port_device::device_start()
{
m_device = dynamic_cast<device_snes_control_port_interface *>(get_card_device());
m_onscreen_cb.bind_relative_to(*owner());
m_gunlatch_cb.bind_relative_to(*owner());
}
UINT8 snes_control_port_device::read_pin4()
{
UINT8 data = 0;
if (m_device)
data |= m_device->read_pin4();
return data;
}
UINT8 snes_control_port_device::read_pin5()
{
UINT8 data = 0;
if (m_device)
data |= m_device->read_pin5();
return data;
}
void snes_control_port_device::write_strobe(UINT8 data)
{
if (m_device)
m_device->write_strobe(data);
}
void snes_control_port_device::write_pin6(UINT8 data)
{
if (m_device)
m_device->write_pin6(data);
}
void snes_control_port_device::port_poll()
{
if (m_device)
m_device->port_poll();
}
//-------------------------------------------------
// SLOT_INTERFACE( snes_control_port_devices )
//-------------------------------------------------
SLOT_INTERFACE_START( snes_control_port_devices )
SLOT_INTERFACE("joypad", SNES_JOYPAD)
SLOT_INTERFACE("mouse", SNES_MOUSE)
SLOT_INTERFACE("multitap", SNES_MULTITAP)
SLOT_INTERFACE("pachinko", SNES_PACHINKO)
SLOT_INTERFACE("sscope", SNES_SUPERSCOPE)
SLOT_INTERFACE("twintap", SNES_TWINTAP)
SLOT_INTERFACE("barcode_battler", SNES_BARCODE_BATTLER)
SLOT_INTERFACE_END

View File

@ -0,0 +1,101 @@
/**********************************************************************
Nintendo Super Famicom & SNES controller port emulation
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#pragma once
#ifndef __SNES_CONTROL_PORT__
#define __SNES_CONTROL_PORT__
#include "emu.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class snes_control_port_device;
// ======================> device_snes_control_port_interface
class device_snes_control_port_interface : public device_slot_card_interface
{
public:
// construction/destruction
device_snes_control_port_interface(const machine_config &mconfig, device_t &device);
virtual ~device_snes_control_port_interface();
virtual UINT8 read_pin4() { return 0; };
virtual UINT8 read_pin5() { return 0; };
virtual void write_pin6(UINT8 data) { };
virtual void write_strobe(UINT8 data) { };
virtual void port_poll() { };
protected:
snes_control_port_device *m_port;
};
typedef device_delegate<bool (INT16 x, INT16 y)> snesctrl_onscreen_delegate;
#define SNESCTRL_ONSCREEN_CB(name) bool name(INT16 x, INT16 y)
typedef device_delegate<void (INT16 x, INT16 y)> snesctrl_gunlatch_delegate;
#define SNESCTRL_GUNLATCH_CB(name) void name(INT16 x, INT16 y)
// ======================> snes_control_port_device
class snes_control_port_device : public device_t,
public device_slot_interface
{
public:
// construction/destruction
snes_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
virtual ~snes_control_port_device();
static void set_onscreen_callback(device_t &device, snesctrl_onscreen_delegate callback) { downcast<snes_control_port_device &>(device).m_onscreen_cb = callback; }
static void set_gunlatch_callback(device_t &device, snesctrl_gunlatch_delegate callback) { downcast<snes_control_port_device &>(device).m_gunlatch_cb = callback; }
UINT8 read_pin4();
UINT8 read_pin5();
void write_pin6(UINT8 data);
void write_strobe(UINT8 data);
void port_poll();
snesctrl_onscreen_delegate m_onscreen_cb;
snesctrl_gunlatch_delegate m_gunlatch_cb;
protected:
// device-level overrides
virtual void device_start();
device_snes_control_port_interface *m_device;
};
// device type definition
extern const device_type SNES_CONTROL_PORT;
//**************************************************************************
// INTERFACE CONFIGURATION MACROS
//**************************************************************************
#define MCFG_SNES_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \
MCFG_DEVICE_ADD(_tag, SNES_CONTROL_PORT, 0) \
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
#define MCFG_SNESCTRL_ONSCREEN_CB(_class, _method) \
snes_control_port_device::set_onscreen_callback(*device, snesctrl_onscreen_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
#define MCFG_SNESCTRL_GUNLATCH_CB(_class, _method) \
snes_control_port_device::set_gunlatch_callback(*device, snesctrl_gunlatch_delegate(&_class::_method, #_class "::" #_method, downcast<_class *>(owner)));
SLOT_INTERFACE_EXTERN( snes_control_port_devices );
#endif

View File

@ -0,0 +1,127 @@
/**********************************************************************
Nintendo Super Famicom & SNES Joypad
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "joypad.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_JOYPAD = &device_creator<snes_joypad_device>;
static INPUT_PORTS_START( snes_joypad )
PORT_START("JOYPAD")
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("B")
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Y")
PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("Select")
PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("Start")
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP )
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN )
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT )
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT )
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("A")
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("X")
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("L")
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("R")
PORT_BIT( 0xf000, IP_ACTIVE_HIGH, IPT_UNUSED )
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_joypad_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_joypad );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_joypad_device - constructor
//-------------------------------------------------
snes_joypad_device::snes_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_JOYPAD, "Nintendo SNES / SFC Control Pad", tag, owner, clock, "snes_joypad", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_joypad(*this, "JOYPAD")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_joypad_device::device_start()
{
save_item(NAME(m_latch));
save_item(NAME(m_strobe));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void snes_joypad_device::device_reset()
{
m_latch = 0;
m_strobe = 0;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_joypad_device::port_poll()
{
UINT16 temp = m_joypad->read();
// avoid sending signals that could crash games
// if left, no right
if (temp & 0x40)
temp &= ~0x80;
// if up, no down
if (temp & 0x10)
temp &= ~0x20;
m_latch = temp | 0xffff0000;
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_joypad_device::read_pin4()
{
UINT8 ret = m_latch & 1;
m_latch >>= 1;
return ret;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_joypad_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -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

View File

@ -0,0 +1,241 @@
/**********************************************************************
Nintendo Super Famicom & SNES Mouse
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "mouse.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_MOUSE = &device_creator<snes_mouse_device>;
static INPUT_PORTS_START( snes_mouse )
PORT_START("BUTTONS")
PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_SPECIAL ) // these must be 0!
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Button Right")
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Button Left")
PORT_BIT( 0x0c00, IP_ACTIVE_HIGH, IPT_UNUSED ) // mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x8000, IP_ACTIVE_LOW, IPT_UNUSED )
// we use IPT_LIGHTGUN instead of IPT_MOUSE to avoid input to wrap when you reach the screen border
// due to the relative nature of movement detection in SNES mouse, when we wrap the system would
// detect a sudden jump in the wrong direction, making the usage unfriendly...
PORT_START("MOUSE_X")
PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
// PORT_BIT( 0xff, 0x00, IPT_MOUSE_X) PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
PORT_START("MOUSE_Y")
PORT_BIT( 0x1ff, 0x100, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
// PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(30) PORT_KEYDELTA(5)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_mouse_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_mouse );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_mouse_device - constructor
//-------------------------------------------------
snes_mouse_device::snes_mouse_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_MOUSE, "Nintendo SNES / SFC Mouse Controller", tag, owner, clock, "snes_mouse", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_buttons(*this, "BUTTONS"),
m_xaxis(*this, "MOUSE_X"),
m_yaxis(*this, "MOUSE_Y")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_mouse_device::device_start()
{
save_item(NAME(m_strobe));
save_item(NAME(m_idx));
save_item(NAME(m_latch));
save_item(NAME(m_x));
save_item(NAME(m_y));
save_item(NAME(m_oldx));
save_item(NAME(m_oldy));
save_item(NAME(m_deltax));
save_item(NAME(m_deltay));
save_item(NAME(m_speed));
save_item(NAME(m_dirx));
save_item(NAME(m_diry));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void snes_mouse_device::device_reset()
{
m_strobe = 0;
m_idx = 0;
m_latch = 0;
m_x = 0;
m_y = 0;
m_oldx = 0;
m_oldy = 0;
m_deltax = 0;
m_deltay = 0;
m_speed = 0;
m_dirx = -1;
m_diry = -1;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_mouse_device::port_poll()
{
INT16 var;
int new_dir;
m_idx = 0;
m_latch = m_buttons->read();
m_oldx = m_x;
m_oldy = m_y;
m_x = m_xaxis->read();
m_y = m_yaxis->read();
var = m_x - m_oldx;
if (var)
{
new_dir = (var < 0) ? 1 : 0;
if (m_dirx != new_dir)
m_dirx = new_dir;
}
if (var < -127)
{
m_deltax = 0x7f;
m_oldx -= 127;
}
else if (var < 0)
{
m_deltax = -var;
m_oldx = m_x;
}
else if (var > 127)
{
m_deltax = 0x7f;
m_oldx += 127;
}
else
{
m_deltax = var;
m_oldx = m_x;
}
var = m_y - m_oldy;
if (var)
{
new_dir = (var < 0) ? 1 : 0;
if (m_diry != new_dir)
m_diry = new_dir;
}
if (var < -127)
{
m_deltay = 0x7f;
m_oldy -= 127;
}
else if (var < 0)
{
m_deltay = -var;
m_oldy = m_y;
}
else if (var > 127)
{
m_deltay = 0x7f;
m_oldy += 127;
}
else
{
m_deltay = var;
m_oldy = m_y;
}
m_deltax |= (m_dirx << 7);
m_deltay |= (m_diry << 7);
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_mouse_device::read_pin4()
{
UINT8 res = 0;
if (m_strobe == 1)
{
// reading with strobe 1, changes mouse speed
m_speed = (m_speed + 1) % 3;
return res;
}
if (m_idx >= 32)
res |= 0x01;
else if (m_idx >= 24)
res |= BIT(m_deltax, (31 - m_idx++));
else if (m_idx >= 16)
res |= BIT(m_deltay, (23 - m_idx++));
else if (m_idx == 11)
{
res |= BIT(m_speed, 0);
m_idx++;
}
else if (m_idx == 10)
{
res |= BIT(m_speed, 1);
m_idx++;
}
else
res |= BIT(m_latch, m_idx++);
return res;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_mouse_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -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

View File

@ -0,0 +1,155 @@
/**********************************************************************
Nintendo Super Famicom & SNES Multitap Adapter
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "multitap.h"
#include "joypad.h"
#include "twintap.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_MULTITAP = &device_creator<snes_multitap_device>;
static INPUT_PORTS_START( snes_multitap )
PORT_START("CONFIG")
PORT_CONFNAME( 0x01, 0x00, "Number of players")
PORT_CONFSETTING( 0x00, "3-5P" )
PORT_CONFSETTING( 0x01, "2P" )
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_multitap_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_multitap );
}
static SLOT_INTERFACE_START( snes_multitap )
SLOT_INTERFACE("joypad", SNES_JOYPAD)
SLOT_INTERFACE("twintap", SNES_TWINTAP)
SLOT_INTERFACE_END
static MACHINE_CONFIG_FRAGMENT( multi5p )
MCFG_SNES_CONTROL_PORT_ADD("port1", snes_multitap, "joypad")
MCFG_SNES_CONTROL_PORT_ADD("port2", snes_multitap, "joypad")
MCFG_SNES_CONTROL_PORT_ADD("port3", snes_multitap, "joypad")
MCFG_SNES_CONTROL_PORT_ADD("port4", snes_multitap, "joypad")
MACHINE_CONFIG_END
//-------------------------------------------------
// machine_config_additions - device-specific
// machine configurations
//-------------------------------------------------
machine_config_constructor snes_multitap_device::device_mconfig_additions() const
{
return MACHINE_CONFIG_NAME( multi5p );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_multitap_device - constructor
//-------------------------------------------------
snes_multitap_device::snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_MULTITAP, "Nintendo SNES / SFC Multitap Adapter", tag, owner, clock, "snes_joypad", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_port1(*this, "port1"),
m_port2(*this, "port2"),
m_port3(*this, "port3"),
m_port4(*this, "port4"),
m_cfg(*this, "CONFIG")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_multitap_device::device_start()
{
save_item(NAME(m_select));
}
void snes_multitap_device::device_reset()
{
m_select = 1;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_multitap_device::port_poll()
{
m_port1->port_poll();
if (m_cfg->read() == 0) // 4P
{
m_port2->port_poll();
m_port3->port_poll();
m_port4->port_poll();
}
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_multitap_device::read_pin4()
{
UINT8 ret = 0;
if (m_cfg->read() == 0) // 4P
ret |= m_select ? m_port1->read_pin4() : m_port3->read_pin4();
else // 1P
ret |= m_select ? m_port1->read_pin4() : 0;
return ret;
}
UINT8 snes_multitap_device::read_pin5()
{
UINT8 ret = 0;
if (m_cfg->read() == 0) // 4P
ret |= m_select ? m_port2->read_pin4() : m_port4->read_pin4();
return ret;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_multitap_device::write_strobe(UINT8 data)
{
m_port1->write_strobe(data);
if (m_cfg->read() == 0) // 4P
{
m_port2->write_strobe(data);
m_port3->write_strobe(data);
m_port4->write_strobe(data);
}
}
void snes_multitap_device::write_pin6(UINT8 data)
{
m_select = data & 1;
}

View File

@ -0,0 +1,62 @@
/**********************************************************************
Nintendo Super Famicom & SNES Multitap Adapter
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#pragma once
#ifndef __SNES_MULTITAP__
#define __SNES_MULTITAP__
#include "emu.h"
#include "ctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> snes_multitap_device
class snes_multitap_device : public device_t,
public device_snes_control_port_interface
{
public:
// construction/destruction
snes_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const;
virtual machine_config_constructor device_mconfig_additions() const;
protected:
// device-level overrides
virtual void device_start();
virtual void device_reset();
// device_sms_control_port_interface overrides
virtual UINT8 read_pin4();
virtual UINT8 read_pin5();
virtual void write_strobe(UINT8 data);
virtual void write_pin6(UINT8 data);
virtual void port_poll();
private:
required_device<snes_control_port_device> m_port1;
required_device<snes_control_port_device> m_port2;
required_device<snes_control_port_device> m_port3;
required_device<snes_control_port_device> m_port4;
required_ioport m_cfg;
int m_select;
};
// device type definition
extern const device_type SNES_MULTITAP;
#endif

View File

@ -0,0 +1,111 @@
/**********************************************************************
Nintendo Super Famicom - Sunsoft Pachinko Controller
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "pachinko.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_PACHINKO = &device_creator<snes_pachinko_device>;
static INPUT_PORTS_START( snes_pachinko )
PORT_START("DIAL")
PORT_BIT( 0x7f, 0x3f, IPT_PADDLE) PORT_SENSITIVITY(25) PORT_KEYDELTA(25) PORT_CENTERDELTA(0) PORT_MINMAX(0x18,0x7f)
PORT_START("BUTTON")
PORT_BIT( 0x00ff, IP_ACTIVE_HIGH, IPT_UNUSED)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_BUTTON1) PORT_NAME("Button")
PORT_BIT( 0xfe00, IP_ACTIVE_HIGH, IPT_UNUSED)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_pachinko_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_pachinko );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_pachinko_device - constructor
//-------------------------------------------------
snes_pachinko_device::snes_pachinko_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_PACHINKO, "Sunsoft Pachinko Controller", tag, owner, clock, "snes_pachinko", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_dial(*this, "DIAL"),
m_button(*this, "BUTTON")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_pachinko_device::device_start()
{
save_item(NAME(m_latch));
save_item(NAME(m_strobe));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void snes_pachinko_device::device_reset()
{
m_latch = 0;
m_strobe = 0;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_pachinko_device::port_poll()
{
UINT8 dial = BITSWAP8(m_dial->read() ^ 0xff,7,6,5,4,3,2,1,0);
m_latch = m_button->read() | (dial << 25) | 0xee7000; // add ID
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_pachinko_device::read_pin4()
{
UINT8 ret = m_latch & 1;
m_latch >>= 1;
return ret;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_pachinko_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -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

View File

@ -0,0 +1,187 @@
/**********************************************************************
Nintendo Super Famicom & SNES SuperScope
TODO: x,y positions are not correctly latched
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "sscope.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_SUPERSCOPE = &device_creator<snes_sscope_device>;
static INPUT_PORTS_START( snes_sscope )
PORT_START("BUTTONS")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Superscope Fire")
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Superscope Cursor")
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Superscope Turbo")
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Superscope Pause")
PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_UNUSED ) // On-screen (handled below in port_poll)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
PORT_START("SSX")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15)
PORT_START("SSY")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_sscope_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_sscope );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_sscope_device - constructor
//-------------------------------------------------
snes_sscope_device::snes_sscope_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_SUPERSCOPE, "Nintendo SNES / SFC SuperScope", tag, owner, clock, "snes_sscope", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_buttons(*this, "BUTTONS"),
m_xaxis(*this, "SSX"),
m_yaxis(*this, "SSY")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_sscope_device::device_start()
{
save_item(NAME(m_strobe));
save_item(NAME(m_idx));
save_item(NAME(m_latch));
save_item(NAME(m_x));
save_item(NAME(m_y));
save_item(NAME(m_turbo_lock));
save_item(NAME(m_pause_lock));
save_item(NAME(m_fire_lock));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void snes_sscope_device::device_reset()
{
m_strobe = 0;
m_idx = 0;
m_latch = 0;
m_x = 0;
m_y = 0;
m_turbo_lock = 0;
m_pause_lock = 0;
m_fire_lock = 0;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_sscope_device::port_poll()
{
// first read input bits
UINT8 input = m_buttons->read();
m_x = m_xaxis->read();
m_y = m_yaxis->read();
m_idx = 0;
// then start elaborating input bits
// 1. only keep old turbo value
m_latch &= 0x04;
// 2. set onscreen/offscreen
if (!m_port->m_onscreen_cb.isnull())
m_latch |= (m_port->m_onscreen_cb(m_x, m_y) ? 0x00 : 0x40);
// 3. pause is a button that is always edge sensitive
if (BIT(input, 3) && !m_pause_lock)
{
m_latch |= 0x08;
m_pause_lock = 1;
}
else if (!BIT(input, 3))
m_pause_lock = 0;
// 4. turbo is a switch; toggle is edge sensitive
if (BIT(input, 2) && !m_turbo_lock)
{
m_latch ^= 0x04;
m_turbo_lock = 1;
}
else if (!BIT(input, 2))
m_turbo_lock = 0;
// 5. cursor is a button that is always level sensitive
m_latch |= BIT(input, 1);
// 6. fire is a button with two behaviors: if turbo is active, trigger is level sensitive;
// otherwise it is edge sensitive
if (BIT(input, 0) && (BIT(m_latch, 2) || !m_fire_lock))
{
m_latch |= 0x01;
m_fire_lock = 1;
}
else if (!BIT(input, 0))
m_fire_lock = 0;
// If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal.
// Notice that this only works in Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1
// has IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other
// words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position
if ((m_latch & 0x03) && !(m_latch & 0x40) && !m_port->m_gunlatch_cb.isnull())
m_port->m_gunlatch_cb(m_x, m_y);
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_sscope_device::read_pin4()
{
UINT8 res = 0;
if (m_idx >= 8) // bits 8-15 = ID = all 1s; bits >= 16 all 1s
res |= 0x01;
else
res |= BIT(m_latch, m_idx++);
return res;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_sscope_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -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

View File

@ -0,0 +1,114 @@
/**********************************************************************
Nintendo Super Famicom - Yonezawa / PartyRoom 21 Twin Tap Controller
This controller consists of two 1-button small units attached to a
single 7pin connector. You plug the connector to Port2 and two
players can compete on the quiz game (Port1 should have a joypad
plugged in, to start the game and browse the menus). By plugging
a multitap adapter to Port2, up to 4 Twin Tap controllers can be
attached at the same time, allowing for 8 players quiz sessions.
Copyright MESS Team.
Visit http://mamedev.org for licensing and usage restrictions.
**********************************************************************/
#include "twintap.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
const device_type SNES_TWINTAP = &device_creator<snes_twintap_device>;
static INPUT_PORTS_START( snes_twintap )
PORT_START("INPUTS")
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 2")
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_NAME("Button 1")
PORT_BIT( 0x8ffc, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x7000, IP_ACTIVE_LOW, IPT_UNUSED ) // controller ID unknown
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor snes_twintap_device::device_input_ports() const
{
return INPUT_PORTS_NAME( snes_twintap );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// snes_twintap_device - constructor
//-------------------------------------------------
snes_twintap_device::snes_twintap_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock) :
device_t(mconfig, SNES_TWINTAP, "Yonezawa Twin Tap Controller", tag, owner, clock, "snes_twintap", __FILE__),
device_snes_control_port_interface(mconfig, *this),
m_inputs(*this, "INPUTS")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void snes_twintap_device::device_start()
{
save_item(NAME(m_latch));
save_item(NAME(m_strobe));
}
//-------------------------------------------------
// device_reset - device-specific reset
//-------------------------------------------------
void snes_twintap_device::device_reset()
{
m_latch = 0;
m_strobe = 0;
}
//-------------------------------------------------
// poll
//-------------------------------------------------
void snes_twintap_device::port_poll()
{
m_latch = m_inputs->read();
}
//-------------------------------------------------
// read
//-------------------------------------------------
UINT8 snes_twintap_device::read_pin4()
{
UINT8 ret = m_latch & 1;
m_latch >>= 1;
return ret;
}
//-------------------------------------------------
// write
//-------------------------------------------------
void snes_twintap_device::write_strobe(UINT8 data)
{
int old = m_strobe;
m_strobe = data & 0x01;
if (m_strobe < old) // 1 -> 0 transition
port_poll();
}

View File

@ -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

View File

@ -268,7 +268,6 @@ void snes_ppu_device::device_start()
save_item(NAME(m_beam.latch_horz)); save_item(NAME(m_beam.latch_horz));
save_item(NAME(m_beam.latch_vert)); 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.current_vert));
save_item(NAME(m_beam.last_visible_line)); save_item(NAME(m_beam.last_visible_line));
save_item(NAME(m_beam.interlace_count)); 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_vert = 0;
m_beam.latch_horz = 0; m_beam.latch_horz = 0;
m_beam.current_vert = 0; m_beam.current_vert = 0;
m_beam.current_horz = 0;
m_beam.last_visible_line = 225; /* TODO: PAL setting */ m_beam.last_visible_line = 225; /* TODO: PAL setting */
m_mode = 0; m_mode = 0;
m_ppu1_version = 1; // 5C77 chip version number, read by STAT77, only '1' is known 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 }; 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. // 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 = y;
m_beam.latch_vert = m_screen->vpos(); m_beam.latch_horz = x;
m_beam.latch_horz = m_beam.current_horz;
m_stat78 |= 0x40; // indicate we latched 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); // 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; return m_ppu1_open_bus;
} }
case SLHV: /* Software latch for H/V counter */ 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 */ return m_openbus_cb(space, 0); /* Return value is meaningless */
case ROAMDATA: /* Read data from OAM (DR) */ case ROAMDATA: /* Read data from OAM (DR) */

View File

@ -124,7 +124,6 @@ public:
{ {
UINT16 latch_horz; UINT16 latch_horz;
UINT16 latch_vert; UINT16 latch_vert;
UINT16 current_horz;
UINT16 current_vert; UINT16 current_vert;
UINT8 last_visible_line; UINT8 last_visible_line;
UINT8 interlace_count; 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); 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 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(); void dynamic_res_change();
inline UINT32 get_vram_address(); inline UINT32 get_vram_address();
UINT8 dbg_video(UINT16 curline); UINT8 dbg_video(UINT16 curline);

View File

@ -397,7 +397,8 @@ public:
void hdma_init(address_space &space); void hdma_init(address_space &space);
void hdma_update(address_space &space, int dma); void hdma_update(address_space &space, int dma);
void hirq_tick(); 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); inline UINT8 snes_rom_access(UINT32 offset);
void snes_init_ram(); void snes_init_ram();

View File

@ -87,7 +87,7 @@ void snes_state::hirq_tick()
{ {
// latch the counters and pull IRQ // latch the counters and pull IRQ
// (don't need to switch to the 65816 context, we don't do anything dependant on it) // (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 */ SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */
m_maincpu->set_input_line(G65816_LINE_IRQ, ASSERT_LINE); 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 */ SNES_CPU_REG(TIMEUP) = 0x80; /* Indicate that irq occurred */
// IRQ latches the counters, do it now // 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 ); 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; SNES_CPU_REG(NMITIMEN) = data;
return; return;
case WRIO: /* Programmable I/O port - latches H/V counters on a 0->1 transition */ case WRIO: /* Programmable I/O port - latches H/V counters on a 0->1 transition */
if (!(SNES_CPU_REG(WRIO) & 0x80) && (data & 0x80)) wrio_write(data);
{
// external latch
m_ppu->latch_counters();
}
SNES_CPU_REG(WRIO) = data; SNES_CPU_REG(WRIO) = data;
return; return;
case HTIMEL: /* H-Count timer settings (low) */ 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) WRITE_LINE_MEMBER(snes_state::snes_extern_irq_w)
{ {
m_maincpu->set_input_line(G65816_LINE_IRQ, state); m_maincpu->set_input_line(G65816_LINE_IRQ, state);

View File

@ -21,8 +21,7 @@
- Fix vertical mosaic effects - Fix vertical mosaic effects
- Add support for real CX4 and ST018 CPUs - Add support for real CX4 and ST018 CPUs
- Add support for SA-1 and SuperGB add-ons - Add support for SA-1 and SuperGB add-ons
- Fix mouse & superscope support - Fix superscope support
- Add multitap support
- Add support for other controllers - Add support for other controllers
***************************************************************************/ ***************************************************************************/
@ -33,38 +32,17 @@
#include "includes/snes.h" #include "includes/snes.h"
#include "machine/snescx4.h" #include "machine/snescx4.h"
#include "crsshair.h"
#include "bus/snes/snes_slot.h" #include "bus/snes/snes_slot.h"
#include "bus/snes/snes_carts.h" #include "bus/snes/snes_carts.h"
#include "bus/snes_ctrl/ctrl.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;
};
class snes_console_state : public snes_state class snes_console_state : public snes_state
{ {
public: public:
enum
{
TIMER_LIGHTGUN_TICK = TIMER_SNES_LAST
};
snes_console_state(const machine_config &mconfig, device_type type, const char *tag) snes_console_state(const machine_config &mconfig, device_type type, const char *tag)
: snes_state(mconfig, type, tag) : snes_state(mconfig, type, tag)
, m_ctrl1(*this, "ctrl1")
, m_ctrl2(*this, "ctrl2")
, m_cartslot(*this, "snsslot") , m_cartslot(*this, "snsslot")
{ } { }
@ -110,35 +88,20 @@ public:
TIMER_CALLBACK_MEMBER( lightgun_tick ); TIMER_CALLBACK_MEMBER( lightgun_tick );
// input related // input related
SNESCTRL_ONSCREEN_CB(onscreen_cb);
SNESCTRL_GUNLATCH_CB(gun_latch_cb);
virtual DECLARE_WRITE8_MEMBER(io_read); virtual DECLARE_WRITE8_MEMBER(io_read);
virtual UINT8 oldjoy1_read(int latched); virtual UINT8 oldjoy1_read(int latched);
virtual UINT8 oldjoy2_read(int latched); virtual UINT8 oldjoy2_read(int latched);
virtual void write_joy_latch(UINT8 data);
// pad inputs virtual void wrio_write(UINT8 data);
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 machine_start(); virtual void machine_start();
virtual void machine_reset(); virtual void machine_reset();
int m_type; int m_type;
required_device<snes_control_port_device> m_ctrl1;
required_device<snes_control_port_device> m_ctrl2;
optional_device<sns_cart_slot_device> m_cartslot; optional_device<sns_cart_slot_device> m_cartslot;
protected:
snes_mouse m_mouse[2];
snes_superscope m_scope[2];
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
}; };
@ -1060,230 +1023,8 @@ ADDRESS_MAP_END
* *
*************************************/ *************************************/
void snes_console_state::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
{
switch (id)
{
case TIMER_LIGHTGUN_TICK:
lightgun_tick(ptr, param);
break;
default:
snes_state::device_timer(timer, id, param, ptr);
break;
}
}
TIMER_CALLBACK_MEMBER( snes_console_state::lightgun_tick )
{
if ((ioport("CTRLSEL")->read() & 0x0f) == 0x03 || (ioport("CTRLSEL")->read() & 0x0f) == 0x04) {
/* enable lightpen crosshair */
crosshair_set_screen(machine(), 0, CROSSHAIR_SCREEN_ALL);
}
else
{
/* disable lightpen crosshair */
crosshair_set_screen(machine(), 0, CROSSHAIR_SCREEN_NONE);
}
if ((ioport("CTRLSEL")->read() & 0xf0) == 0x30 || (ioport("CTRLSEL")->read() & 0xf0) == 0x40)
{
/* enable lightpen crosshair */
crosshair_set_screen(machine(), 1, CROSSHAIR_SCREEN_ALL);
}
else
{
/* disable lightpen crosshair */
crosshair_set_screen(machine(), 1, CROSSHAIR_SCREEN_NONE);
}
}
static INPUT_PORTS_START( snes_joypads )
PORT_START("JOY1")
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Button B") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P1 Button Y") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P1 Select") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START1 ) PORT_NAME("P1 Start") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Button A") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P1 Button X") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P1 Button L") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P1 Button R") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_START("JOY2")
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("P2 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
// temp hack to share the same port both for P2 alone and P2 through MP5 adapter
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Button B") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P2 Button Y") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P2 Select") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START2 ) PORT_NAME("P2 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Button A") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P2 Button X") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P2 Button L") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P2 Button R") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_START("JOY3")
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P3 Button B") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P3 Button Y") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P3 Select") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START3 ) PORT_NAME("P3 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P3 Button A") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P3 Button X") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P3 Button L") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P3 Button R") PORT_PLAYER(3) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_START("JOY4")
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P4 Button B") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P4 Button Y") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P4 Select") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START4 ) PORT_NAME("P4 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P4 Button A") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P4 Button X") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P4 Button L") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P4 Button R") PORT_PLAYER(4) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_START("JOY5")
PORT_BIT( 0x8000, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P5 Button B") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x4000, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("P5 Button Y") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x2000, IP_ACTIVE_HIGH, IPT_SELECT ) PORT_NAME("P5 Select") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x1000, IP_ACTIVE_HIGH, IPT_START5 ) PORT_NAME("P5 Start") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0800, IP_ACTIVE_HIGH, IPT_JOYSTICK_UP ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0400, IP_ACTIVE_HIGH, IPT_JOYSTICK_DOWN ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0200, IP_ACTIVE_HIGH, IPT_JOYSTICK_LEFT ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0100, IP_ACTIVE_HIGH, IPT_JOYSTICK_RIGHT ) PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P5 Button A") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON5 ) PORT_NAME("P5 Button X") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0020, IP_ACTIVE_HIGH, IPT_BUTTON6 ) PORT_NAME("P5 Button L") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x0010, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("P5 Button R") PORT_PLAYER(5) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
PORT_BIT( 0x000f, IP_ACTIVE_HIGH, IPT_UNUSED ) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x50)
INPUT_PORTS_END
static INPUT_PORTS_START( snes_mouse )
PORT_START("MOUSE1")
/* bits 0,3 = mouse signature (must be 1) */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x0002, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x0004, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x0008, IP_ACTIVE_HIGH, IPT_UNUSED )
/* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */
PORT_BIT( 0x0030, IP_ACTIVE_HIGH, IPT_UNUSED )
/* bits 6,7 = mouse buttons */
PORT_BIT( 0x0040, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P1 Mouse Button Left") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x0080, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P1 Mouse Button Right") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
PORT_BIT( 0xff00, IP_ACTIVE_HIGH, IPT_SPECIAL ) // these must be 0!
PORT_START("MOUSE1_X")
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
PORT_START("MOUSE1_Y")
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x02)
PORT_START("MOUSE2")
/* bits 0,3 = mouse signature (must be 1) */
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
/* bits 4,5 = mouse speed: 0 = slow, 1 = normal, 2 = fast, 3 = unused */
PORT_BIT( 0x30, IP_ACTIVE_HIGH, IPT_UNUSED )
/* bits 6,7 = mouse buttons */
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("P2 Mouse Button Left") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("P2 Mouse Button Right") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
PORT_START("MOUSE2_X")
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
PORT_START("MOUSE2_Y")
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x20)
INPUT_PORTS_END
static INPUT_PORTS_START( snes_superscope )
PORT_START("SUPERSCOPE1")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, snes_console_state, sscope_offscreen_input, (void *)0)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port1 Superscope Pause") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port1 Superscope Turbo") PORT_TOGGLE PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port1 Superscope Cursor") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port1 Superscope Fire") PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_START("SUPERSCOPE1_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port1 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_START("SUPERSCOPE1_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port1 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x03)
PORT_START("SUPERSCOPE2")
PORT_BIT( 0x01, IP_ACTIVE_HIGH, IPT_UNUSED ) // Noise
PORT_BIT( 0x02, IP_ACTIVE_HIGH, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, snes_console_state, sscope_offscreen_input, (void *)1)
PORT_BIT( 0x04, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_BUTTON4 ) PORT_NAME("Port2 Superscope Pause") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_BUTTON3 ) PORT_NAME("Port2 Superscope Turbo") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x40, IP_ACTIVE_HIGH, IPT_BUTTON2 ) PORT_NAME("Port2 Superscope Cursor") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x80, IP_ACTIVE_HIGH, IPT_BUTTON1 ) PORT_NAME("Port2 Superscope Fire") PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
PORT_START("SUPERSCOPE2_X")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_X ) PORT_NAME("Port2 Superscope X Axis") PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
PORT_START("SUPERSCOPE2_Y")
PORT_BIT( 0xff, 0x80, IPT_LIGHTGUN_Y) PORT_NAME("Port2 Superscope Y Axis") PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(25) PORT_KEYDELTA(15) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x30)
INPUT_PORTS_END
static INPUT_PORTS_START( snes ) static INPUT_PORTS_START( snes )
PORT_START("CTRLSEL") /* Select Controller Type */ // input devices go through slot options
PORT_CONFNAME( 0x0f, 0x01, "P1 Controller")
PORT_CONFSETTING( 0x00, "Unconnected" )
PORT_CONFSETTING( 0x01, "Gamepad" )
PORT_CONFSETTING( 0x02, "Mouse" )
PORT_CONFSETTING( 0x03, "Superscope" )
// PORT_CONFSETTING( 0x04, "Justfier" )
// PORT_CONFSETTING( 0x05, "Multitap" )
PORT_CONFNAME( 0xf0, 0x10, "P2 Controller")
PORT_CONFSETTING( 0x00, "Unconnected" )
PORT_CONFSETTING( 0x10, "Gamepad" )
PORT_CONFSETTING( 0x20, "Mouse" )
PORT_CONFSETTING( 0x30, "Superscope" )
// PORT_CONFSETTING( 0x40, "Justfier" )
PORT_CONFSETTING( 0x50, "Multitap" )
PORT_INCLUDE(snes_joypads)
PORT_INCLUDE(snes_mouse)
PORT_INCLUDE(snes_superscope)
PORT_START("OPTIONS") PORT_START("OPTIONS")
PORT_CONFNAME( 0x01, 0x00, "Hi-Res pixels blurring (TV effect)") PORT_CONFNAME( 0x01, 0x00, "Hi-Res pixels blurring (TV effect)")
PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
@ -1349,130 +1090,72 @@ INPUT_PORTS_END
* *
*************************************/ *************************************/
// Mouse handling WRITE8_MEMBER(snes_console_state::io_read)
void snes_console_state::input_read_mouse(int port)
{ {
INT16 var; // is automatic reading on? if so, read 16bits from oldjoy1/2
static const char *const portnames[2][3] = if (SNES_CPU_REG(NMITIMEN) & 1)
{ {
{ "MOUSE1", "MOUSE1_X", "MOUSE1_Y" }, UINT16 joy1 = 0, joy2 = 0, joy3 = 0, joy4 = 0;
{ "MOUSE2", "MOUSE2_X", "MOUSE2_Y" }, m_ctrl1->port_poll();
}; m_ctrl2->port_poll();
m_mouse[port].buttons = ioport(portnames[port][0])->read(); for (int i = 0; i < 16; i++)
m_mouse[port].x = ioport(portnames[port][1])->read(); {
m_mouse[port].y = ioport(portnames[port][2])->read(); 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));
}
var = m_mouse[port].x - m_mouse[port].oldx; SNES_CPU_REG(JOY1L) = (joy1 & 0x00ff) >> 0;
SNES_CPU_REG(JOY1H) = (joy1 & 0xff00) >> 8;
if (var < -127) SNES_CPU_REG(JOY2L) = (joy2 & 0x00ff) >> 0;
{ SNES_CPU_REG(JOY2H) = (joy2 & 0xff00) >> 8;
m_mouse[port].deltax = 0xff; SNES_CPU_REG(JOY3L) = (joy3 & 0x00ff) >> 0;
m_mouse[port].oldx -= 127; SNES_CPU_REG(JOY3H) = (joy3 & 0xff00) >> 8;
SNES_CPU_REG(JOY4L) = (joy4 & 0x00ff) >> 0;
SNES_CPU_REG(JOY4H) = (joy4 & 0xff00) >> 8;
} }
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;
} }
UINT8 snes_console_state::input_serial_mouse(int port, int latched) UINT8 snes_console_state::oldjoy1_read(int latched)
{ {
UINT8 res = 0; UINT8 ret = 0;
ret |= m_ctrl1->read_pin4();
if (latched) ret |= (m_ctrl1->read_pin5() << 1);
{ return ret;
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;
} }
// Superscope handling UINT8 snes_console_state::oldjoy2_read(int latched)
CUSTOM_INPUT_MEMBER( snes_console_state::sscope_offscreen_input )
{ {
int port = (FPTR)param; UINT8 ret = 0;
static const char *const portnames[2][3] = ret |= m_ctrl2->read_pin4();
{ ret |= (m_ctrl2->read_pin5() << 1);
{ "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, return ret;
{ "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;
} }
void snes_console_state::write_joy_latch(UINT8 data)
void snes_console_state::gun_latch(INT16 x, INT16 y)
{ {
/* 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) if (x < 0)
x = 0; x = 0;
if (x > (SNES_SCR_WIDTH - 1)) if (x > (SNES_SCR_WIDTH - 1))
@ -1483,311 +1166,20 @@ void snes_console_state::gun_latch(INT16 x, INT16 y)
if (y > (m_ppu->m_beam.last_visible_line - 1)) if (y > (m_ppu->m_beam.last_visible_line - 1))
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->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->m_beam.latch_vert = y; m_ppu->set_latch_hv(m_ppu->current_x(), m_ppu->current_y());
m_ppu->m_stat78 |= 0x40;
} }
void snes_console_state::input_read_sscope(int port) SNESCTRL_ONSCREEN_CB(snes_console_state::onscreen_cb)
{ {
static const char *const portnames[2][3] = // these are the theoretical boundaries, but we currently are always onscreen due to the
{ // way IPT_LIGHTGUNs work... investigate more on this!
{ "SUPERSCOPE1", "SUPERSCOPE1_X", "SUPERSCOPE1_Y" }, if (x < 0 || x >= SNES_SCR_WIDTH || y < 0 || y >= m_ppu->m_beam.last_visible_line)
{ "SUPERSCOPE2", "SUPERSCOPE2_X", "SUPERSCOPE2_Y" }, return false;
};
UINT8 input;
/* first read input bits */
m_scope[port].x = ioport(portnames[port][1])->read();
m_scope[port].y = ioport(portnames[port][2])->read();
input = ioport(portnames[port][0])->read();
/* then start elaborating input bits: only keep old turbo value */
m_scope[port].buttons &= 0x20;
/* set onscreen/offscreen */
m_scope[port].buttons |= BIT(input, 1);
/* turbo is a switch; toggle is edge sensitive */
if (BIT(input, 5) && !m_scope[port].turbo_lock)
{
m_scope[port].buttons ^= 0x20;
m_scope[port].turbo_lock = 1;
}
else if (!BIT(input, 5))
m_scope[port].turbo_lock = 0;
/* fire is a button; if turbo is active, trigger is level sensitive; otherwise it is edge sensitive */
if (BIT(input, 7) && (BIT(m_scope[port].buttons, 5) || !m_scope[port].fire_lock))
{
m_scope[port].buttons |= 0x80;
m_scope[port].fire_lock = 1;
}
else if (!BIT(input, 7))
m_scope[port].fire_lock = 0;
/* cursor is a button; it is always level sensitive */
m_scope[port].buttons |= BIT(input, 6);
/* pause is a button; it is always edge sensitive */
if (BIT(input, 4) && !m_scope[port].pause_lock)
{
m_scope[port].buttons |= 0x10;
m_scope[port].pause_lock = 1;
}
else if (!BIT(input, 4))
m_scope[port].pause_lock = 0;
/* If we have pressed fire or cursor and we are on-screen and SuperScope is in Port2, then latch video signal.
Notice that we only latch Port2 because its IOBit pin is connected to bit7 of the IO Port, while Port1 has
IOBit pin connected to bit6 of the IO Port, and the latter is not detected by the H/V Counters. In other
words, you can connect SuperScope to Port1, but there is no way SNES could detect its on-screen position */
if ((m_scope[port].buttons & 0xc0) && !(m_scope[port].buttons & 0x02) && port == 1)
gun_latch(m_scope[port].x, m_scope[port].y);
m_data1[port] = 0xff | (m_scope[port].buttons << 8);
m_data2[port] = 0;
}
UINT8 snes_console_state::input_serial_sscope(int port, int latched)
{
UINT8 res = 0;
if (m_read_idx[port] >= 8)
res |= 0x01;
else else
res |= (m_scope[port].buttons >> (7 - m_read_idx[port]++)) & 0x01; return true;
return res;
} }
// Joypad + Multitap handling
// input_read_joy is used both for standard joys and for the MP5 multitap
void snes_console_state::input_read_joy( int port, bool multitap )
{
static const char *const portnames[4][2] =
{
{ "JOY1", "JOY3" },
{ "JOY2", "JOY3" },
{ "JOY4", "JOY5" },
{ "JOY4", "JOY5" }
};
if (!multitap)
{
m_data1[port] = ioport(portnames[port][0])->read();
m_data2[port] = 0;
// avoid sending signals that could crash games
// if left, no right
if (m_data1[port] & 0x200)
m_data1[port] &= ~0x100;
// if up, no down
if (m_data1[port] & 0x800)
m_data1[port] &= ~0x400;
// if left, no right
if (m_data2[port] & 0x200)
m_data2[port] &= ~0x100;
// if up, no down
if (m_data2[port] & 0x800)
m_data2[port] &= ~0x400;
}
else
{
m_data1[port] = ioport(portnames[port][0])->read();
m_data2[port] = ioport(portnames[port][1])->read();
m_data1[port + 2] = ioport(portnames[port + 2][0])->read();
m_data2[port + 2] = ioport(portnames[port + 2][1])->read();
// avoid sending signals that could crash games
// if left, no right
if (m_data1[port] & 0x200)
m_data1[port] &= ~0x100;
// if up, no down
if (m_data1[port] & 0x800)
m_data1[port] &= ~0x400;
// if left, no right
if (m_data2[port] & 0x200)
m_data2[port] &= ~0x100;
// if up, no down
if (m_data2[port] & 0x800)
m_data2[port] &= ~0x400;
// if left, no right
if (m_data1[port + 2] & 0x200)
m_data1[port + 2] &= ~0x100;
// if up, no down
if (m_data1[port + 2] & 0x800)
m_data1[port + 2] &= ~0x400;
// if left, no right
if (m_data2[port + 2] & 0x200)
m_data2[port + 2] &= ~0x100;
// if up, no down
if (m_data2[port + 2] & 0x800)
m_data2[port + 2] &= ~0x400;
}
}
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; 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) if (m_cartslot)
m_cartslot->save_ram(); 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_SNES_PPU_OPENBUS_CB(READ8(snes_state, snes_open_bus_r))
MCFG_VIDEO_SET_SCREEN("screen") 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 */ /* sound hardware */
MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker") MCFG_SPEAKER_STANDARD_STEREO("lspeaker", "rspeaker")
MCFG_SOUND_ADD("spc700", SNES, 0) MCFG_SOUND_ADD("spc700", SNES, 0)

View File

@ -635,6 +635,7 @@ BUSES += SEGA8
BUSES += SMS_CTRL BUSES += SMS_CTRL
BUSES += SMS_EXP BUSES += SMS_EXP
BUSES += SNES BUSES += SNES
BUSES += SNES_CTRL
BUSES += SPC1000 BUSES += SPC1000
BUSES += TI99PEB BUSES += TI99PEB
BUSES += TVC BUSES += TVC