summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/sms_ctrl/paddle.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/sms_ctrl/paddle.cpp')
-rw-r--r--src/devices/bus/sms_ctrl/paddle.cpp149
1 files changed, 63 insertions, 86 deletions
diff --git a/src/devices/bus/sms_ctrl/paddle.cpp b/src/devices/bus/sms_ctrl/paddle.cpp
index 06f1c9bfa16..04ce2d749ca 100644
--- a/src/devices/bus/sms_ctrl/paddle.cpp
+++ b/src/devices/bus/sms_ctrl/paddle.cpp
@@ -1,25 +1,36 @@
// license:BSD-3-Clause
-// copyright-holders:Fabio Priuli
+// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mark III "Paddle Control" emulation
-Release data from the Sega Retro project:
+ Release data from the Sega Retro project:
- Year: 1987 Country/region: JP Model code: HPD-200
+ Year: 1987 Country/region: JP Model code: HPD-200
-Notes:
+ Notes:
- The main chip contained in the device is labeled 315-5243.
+ The main chip contained in the device is labeled 315-5243.
- The Paddle Control was only released in Japan. To work with the device,
- paddle games need to detect the system region as Japanese, else they switch
- to a different mode that uses the TH line as output to select which nibble
- of the X axis will be read. This other mode is similar to how the US Sports
- Pad works, so on an Export system, paddle games are somewhat playable with
- that device, though it needs to be used inverted and the trackball needs to
- be moved slowly, else the software for the paddle think it's moving backward.
+ On Japanese systems (Mark III and Master System), the games
+ read the port and expect the value on the low four bits
+ (usually used joystick switches) to alternate between the low
+ and high nybbles of the paddle position, with TR indicating
+ the current state.
+
+ On export consoles, the games toggle the TH output before
+ reading a nybble, expecting to be able to select the high or
+ low nybble of the paddle position. It spins for longer between
+ pulling TH low and reading the low nybble than it does between
+ pulling TH high and reading the high nybble, suggesting that
+ pulling TH low triggers acquisition.
+
+ Only a single model of paddle controller was released for the
+ Japanese market. Photos show no connection to pin 7. There
+ are a few reports of paddle controllers working on export
+ consoles, but this is not possible unless another hardware
+ revision exists.
**********************************************************************/
@@ -27,101 +38,67 @@ Notes:
#include "paddle.h"
+namespace {
-//**************************************************************************
-// DEVICE DEFINITIONS
-//**************************************************************************
-
-DEFINE_DEVICE_TYPE(SMS_PADDLE, sms_paddle_device, "sms_paddle", "Sega SMS Paddle")
-
-// time interval not verified
-// Player 2 of Galactic Protector is the most sensible to this timming.
-#define PADDLE_INTERVAL attotime::from_hz(XTAL(10'738'635)/3/100)
-
+INPUT_PORTS_START( sms_paddle )
+ PORT_START("BUTTON")
+ PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
-CUSTOM_INPUT_MEMBER( sms_paddle_device::rldu_pins_r )
-{
- uint8_t data = m_paddle_x->read();
+ PORT_START("PADDLE")
+ PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_MINMAX(0, 255) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0)
+INPUT_PORTS_END
- if (m_read_state)
- data >>= 4;
- // The returned value is inverted due to IP_ACTIVE_LOW mapping.
- return ~data;
-}
+//**************************************************************************
+// TYPE DEFINITIONS
+//**************************************************************************
-READ_LINE_MEMBER( sms_paddle_device::tr_pin_r )
+class sms_paddle_device : public device_t, public device_sms_control_interface
{
- // The returned value is inverted due to IP_ACTIVE_LOW mapping.
- return ~m_read_state;
-}
-
-
-static INPUT_PORTS_START( sms_paddle )
- PORT_START("CTRL_PORT")
- PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(sms_paddle_device, rldu_pins_r) // R,L,D,U
- PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
- PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
- PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
- PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(sms_paddle_device, tr_pin_r) // TR
+public:
+ // construction/destruction
+ sms_paddle_device(const machine_config &mconfig, char const *tag, device_t *owner, u32 clock);
- PORT_START("PADDLE_X") // Paddle knob
- PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255)
-INPUT_PORTS_END
-
-
-//-------------------------------------------------
-// input_ports - device-specific input ports
-//-------------------------------------------------
-
-ioport_constructor sms_paddle_device::device_input_ports() const
-{
- return INPUT_PORTS_NAME( sms_paddle );
-}
+ // device_sms_control_interface implementation
+ virtual u8 in_r() override;
+protected:
+ // device_t implementation
+ virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_paddle); }
+ virtual void device_start() override { }
+private:
+ TIMER_CALLBACK_MEMBER(timeout);
-//**************************************************************************
-// LIVE DEVICE
-//**************************************************************************
+ required_ioport m_button;
+ required_ioport m_axis;
+};
-//-------------------------------------------------
-// sms_paddle_device - constructor
-//-------------------------------------------------
-sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+sms_paddle_device::sms_paddle_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_PADDLE, tag, owner, clock),
- device_sms_control_port_interface(mconfig, *this),
- m_paddle_pins(*this, "CTRL_PORT"),
- m_paddle_x(*this, "PADDLE_X"),
- m_read_state(0),
- m_interval(PADDLE_INTERVAL)
+ device_sms_control_interface(mconfig, *this),
+ m_button(*this, "BUTTON"),
+ m_axis(*this, "PADDLE")
{
}
-//-------------------------------------------------
-// device_start - device-specific startup
-//-------------------------------------------------
-
-void sms_paddle_device::device_start()
+u8 sms_paddle_device::in_r()
{
- m_start_time = machine().time();
-
- save_item(NAME(m_start_time));
- save_item(NAME(m_read_state));
+ // time interval guessed
+ // Player 2 of Galactic Protector is the most sensitive to this timing
+ uint8_t const nybble = machine().time().as_ticks(XTAL(10'738'635) / 3 / 100) & 1;
+ return (nybble << 5) | (m_button->read() << 4) | BIT(m_axis->read(), nybble ? 4 : 0, 4);
}
+} // anonymous namespace
-//-------------------------------------------------
-// sms_peripheral_r - paddle read
-//-------------------------------------------------
-uint8_t sms_paddle_device::peripheral_r()
-{
- int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double();
- m_read_state = num_intervals & 1;
- return m_paddle_pins->read();
-}
+//**************************************************************************
+// DEVICE DEFINITIONS
+//**************************************************************************
+
+DEFINE_DEVICE_TYPE_PRIVATE(SMS_PADDLE, device_sms_control_interface, sms_paddle_device, "sms_paddle", "Sega Mark III Paddle (Japan)")