summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/sms_ctrl/sportsjp.cpp
blob: ecdbc1a7967b9ac3625b35cfaad6d95c0a0754a3 (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
128
129
130
131
132
133
134
135
136
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
/**********************************************************************

    Sega Master System "Sports Pad" (Japanese model) emulation


Release data from the Sega Retro project:

  Year: 1988    Country/region: JP    Model code: SP-500

TODO:

- For low-level emulation, a device for the TMP42C66P, a Toshiba 4bit
  microcontroller, needs to be created, but a dump of its internal ROM
  seems to be required.

Notes:

  This Japanese Sports Pad controller device is only required to play the
  cartridge Sports Pad Soccer, released in Japan, on non-SMSJ consoles without
  ROM header validation, like the Sega Mark III and the Korean SMS2 version.

  The Japanese version of Sports Pad Soccer has code to operate the Sports
  Pad controller in two diffent modes. When it detects a Japanese SMS (testing
  if port $F2 has two bits for mute control), the operation is the same used
  by US Sports Pad games. Otherwise, it uses a mode that polls bits TR and TL
  of the controller ports, compatible with the Sega Mark III, that lacks the
  TH line used by the US Sports Pad mode. This Mark III mode is also used on
  other non-SMSJ consoles, like the Korean SMS2 version. The two controller
  modes are significantly different from each other and no information was
  found about support for both modes on the Japanese Sports Pad model, so that
  model is currently emulated as a different device.

  A bug was discovered in the player 2 input handling code of the Mark III
  compatible mode of the only known good ROM dump of Sports Pad Soccer (JP):
  size="131072" crc="41c948bf" sha1="7634ce39e87049dad1ee4f32a80d728e4bd1f81f"
  At address $12D1, instead read the upper 2 bits of port $DC and lower 2 bits
  of port $DD (to obtain the lower nibble of the current axis for player 2),
  the code wrongly reads the lower nibble of port $DC, that is player 1 data.

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

#include "emu.h"
#include "sportsjp.h"


namespace {

INPUT_PORTS_START( sms_sports_pad_jp )
	PORT_START("SPORTS_JP_BT")    // buttons
	PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
	PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR
	PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_UNUSED )

	PORT_START("SPORTS_JP_X")    // X axis
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40)

	PORT_START("SPORTS_JP_Y")    // Y axis
	PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40)
INPUT_PORTS_END



//**************************************************************************
//  TYPE DEFINITIONS
//**************************************************************************

class sms_sports_pad_jp_device : public device_t, public device_sms_control_interface
{
public:
	// construction/destruction
	sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);

	// device_sms_control_interface implementation
	virtual uint8_t in_r() override;

protected:
	// device_t implementation
	virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_sports_pad_jp); }
	virtual void device_start() override { }

private:
	required_ioport m_buttons;
	required_ioport m_x_axis;
	required_ioport m_y_axis;
};


//-------------------------------------------------
//  sms_sports_pad_jp_device - constructor
//-------------------------------------------------

sms_sports_pad_jp_device::sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
	device_t(mconfig, SMS_SPORTS_PAD_JP, tag, owner, clock),
	device_sms_control_interface(mconfig, *this),
	m_buttons(*this, "SPORTS_JP_BT"),
	m_x_axis(*this, "SPORTS_JP_X"),
	m_y_axis(*this, "SPORTS_JP_Y")
{
}


//-------------------------------------------------
//  sms_peripheral_r - sports pad read
//-------------------------------------------------

uint8_t sms_sports_pad_jp_device::in_r()
{
	int const num_intervals = machine().time().as_ticks(20000); // time interval not verified

	switch (num_intervals % 5)
	{
	default: // shut up dumb compilers
	case 0: // X high nibble
		return 0x00 | ((m_x_axis->read() >> 4) & 0x0f);
	case 1: // X low nibble
		return 0x10 | (m_x_axis->read() & 0x0f);
	case 2: // Y high nibble
		return 0x00 | ((m_y_axis->read() >> 4) & 0x0f);
	case 3: // Y low nibble
		return 0x10 | (m_y_axis->read() & 0x0f);
	case 4: // buttons 1 and 2
		return 0x30 | m_buttons->read();
	}
}

} // anonymous namespace



//**************************************************************************
//  DEVICE DEFINITIONS
//**************************************************************************

DEFINE_DEVICE_TYPE_PRIVATE(SMS_SPORTS_PAD_JP, device_sms_control_interface, sms_sports_pad_jp_device, "sms_sports_pad_jp", "Sega Mark III Sports Pad (Japan)")