summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/sms_ctrl/paddle.cpp
blob: 4d3ade12477b0845d7f59d1866780c8600ecba8b (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
/**********************************************************************

    Sega Mark III "Paddle Control" emulation


Release data from the Sega Retro project:

  Year: 1987    Country/region: JP    Model code: HPD-200

Notes:

  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.

**********************************************************************/

#include "emu.h"
#include "paddle.h"



//**************************************************************************
//  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)


CUSTOM_INPUT_MEMBER( sms_paddle_device::rldu_pins_r )
{
	uint8_t data = m_paddle_x->read();

	if (m_read_state)
		data >>= 4;

	// The returned value is inverted due to IP_ACTIVE_LOW mapping.
	return ~data;
}


READ_LINE_MEMBER( sms_paddle_device::tr_pin_r )
{
	// 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_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, rldu_pins_r, nullptr) // 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_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_paddle_device, tr_pin_r ) // TR

	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 );
}



//**************************************************************************
//  LIVE DEVICE
//**************************************************************************

//-------------------------------------------------
//  sms_paddle_device - constructor
//-------------------------------------------------

sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t 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_start - device-specific startup
//-------------------------------------------------

void sms_paddle_device::device_start()
{
	m_start_time = machine().time();

	save_item(NAME(m_start_time));
	save_item(NAME(m_read_state));
}


//-------------------------------------------------
//  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();
}