From 33c5196a429d0afa801caac3ad24a76bf0ac273d Mon Sep 17 00:00:00 2001 From: Miodrag Milanovic Date: Wed, 6 Apr 2016 07:49:49 +0200 Subject: [PATCH] This one documents what I think is a real bug of the Japanese game Sports Pad Soccer: part of the player 2 input is read from player 1 input instead. The patch also reorganizes code of the Japanese Sports Pad controller device and replace some PORT_CUSTOM/PORT_CHANGED callbacks with PORT_READ_LINE/PORT_WRITE_LINE. [Enik] --- hash/sms.xml | 1 + src/devices/bus/sms_ctrl/lphaser.cpp | 11 +++- src/devices/bus/sms_ctrl/lphaser.h | 2 +- src/devices/bus/sms_ctrl/paddle.cpp | 8 +-- src/devices/bus/sms_ctrl/paddle.h | 4 +- src/devices/bus/sms_ctrl/sports.cpp | 20 +++--- src/devices/bus/sms_ctrl/sports.h | 8 +-- src/devices/bus/sms_ctrl/sportsjp.cpp | 88 +++++++++++++-------------- src/devices/bus/sms_ctrl/sportsjp.h | 9 ++- src/mame/drivers/sms.cpp | 8 +-- 10 files changed, 85 insertions(+), 74 deletions(-) diff --git a/hash/sms.xml b/hash/sms.xml index 03d0930f9f7..a5e70ea41e8 100644 --- a/hash/sms.xml +++ b/hash/sms.xml @@ -6128,6 +6128,7 @@ + Sports Pad Soccer (Jpn) 1988 diff --git a/src/devices/bus/sms_ctrl/lphaser.cpp b/src/devices/bus/sms_ctrl/lphaser.cpp index 8a49c9a1554..ccf240d9eec 100644 --- a/src/devices/bus/sms_ctrl/lphaser.cpp +++ b/src/devices/bus/sms_ctrl/lphaser.cpp @@ -12,6 +12,13 @@ Release data from the Sega Retro project: Year: 1989 Country/region: BR Model code: 010470 Year: 198? Country/region: KR Model code: ? +Notes: + + The Light Phaser gun doesn't work with the Japanese SMS and Sega Mark III. + There are reports about Light Phaser working on the second Korean SMS + version, and a Korean advert shows support on the first version (Gam*Boy I, + although based on Japanese SMS). + **********************************************************************/ #include "lphaser.h" @@ -29,7 +36,7 @@ const device_type SMS_LIGHT_PHASER = &device_creator; #define LGUN_X_INTERVAL 4 -CUSTOM_INPUT_MEMBER( sms_light_phaser_device::th_pin_r ) +READ_LINE_MEMBER( sms_light_phaser_device::th_pin_r ) { // The returned value is inverted due to IP_ACTIVE_LOW mapping. return ~m_sensor_last_state; @@ -46,7 +53,7 @@ INPUT_CHANGED_MEMBER( sms_light_phaser_device::position_changed ) static INPUT_PORTS_START( sms_light_phaser ) PORT_START("CTRL_PORT") PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (trigger) - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r, nullptr) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r) PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("LPHASER_X") diff --git a/src/devices/bus/sms_ctrl/lphaser.h b/src/devices/bus/sms_ctrl/lphaser.h index 7d2f9ca1ed6..860b8d4007f 100644 --- a/src/devices/bus/sms_ctrl/lphaser.h +++ b/src/devices/bus/sms_ctrl/lphaser.h @@ -34,7 +34,7 @@ public: // optional information overrides virtual ioport_constructor device_input_ports() const override; - DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r ); + DECLARE_READ_LINE_MEMBER( th_pin_r ); DECLARE_INPUT_CHANGED_MEMBER( position_changed ); protected: diff --git a/src/devices/bus/sms_ctrl/paddle.cpp b/src/devices/bus/sms_ctrl/paddle.cpp index f502b9ad196..964a00f5133 100644 --- a/src/devices/bus/sms_ctrl/paddle.cpp +++ b/src/devices/bus/sms_ctrl/paddle.cpp @@ -38,7 +38,7 @@ const device_type SMS_PADDLE = &device_creator; #define PADDLE_INTERVAL attotime::from_hz(XTAL_53_693175MHz/15/100) -CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r ) +CUSTOM_INPUT_MEMBER( sms_paddle_device::rldu_pins_r ) { UINT8 data = m_paddle_x->read(); @@ -50,7 +50,7 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r ) } -CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r ) +READ_LINE_MEMBER( sms_paddle_device::tr_pin_r ) { // The returned value is inverted due to IP_ACTIVE_LOW mapping. return ~m_read_state; @@ -59,11 +59,11 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r ) 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, dir_pins_r, nullptr) // Directional pins + 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_CUSTOM_MEMBER(DEVICE_SELF, sms_paddle_device, tr_pin_r, nullptr) + 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) diff --git a/src/devices/bus/sms_ctrl/paddle.h b/src/devices/bus/sms_ctrl/paddle.h index fae7a93fb19..968abe1b345 100644 --- a/src/devices/bus/sms_ctrl/paddle.h +++ b/src/devices/bus/sms_ctrl/paddle.h @@ -33,8 +33,8 @@ public: // optional information overrides virtual ioport_constructor device_input_ports() const override; - DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r ); - DECLARE_CUSTOM_INPUT_MEMBER( tr_pin_r ); + DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines. + DECLARE_READ_LINE_MEMBER( tr_pin_r ); protected: // device-level overrides diff --git a/src/devices/bus/sms_ctrl/sports.cpp b/src/devices/bus/sms_ctrl/sports.cpp index b4bd54d81a1..54fa867a8c1 100644 --- a/src/devices/bus/sms_ctrl/sports.cpp +++ b/src/devices/bus/sms_ctrl/sports.cpp @@ -82,21 +82,21 @@ void sms_sports_pad_device::device_timer(emu_timer &timer, device_timer_id id, i } -CUSTOM_INPUT_MEMBER( sms_sports_pad_device::th_pin_r ) +READ_LINE_MEMBER( sms_sports_pad_device::th_pin_r ) { - return m_last_data; + return m_th_pin_state; } -INPUT_CHANGED_MEMBER( sms_sports_pad_device::th_pin_w ) +WRITE_LINE_MEMBER( sms_sports_pad_device::th_pin_w ) { m_read_state = (m_read_state + 1) & 3; m_sportspad_timer->adjust(m_interval); - m_last_data = newval; + m_th_pin_state = state; } -CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r ) +CUSTOM_INPUT_MEMBER( sms_sports_pad_device::rldu_pins_r ) { UINT8 data = 0; @@ -123,17 +123,17 @@ CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r ) static INPUT_PORTS_START( sms_sports_pad ) PORT_START("SPORTS_IN") - PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, dir_pins_r, nullptr) // Directional pins + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_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 (Button 1) - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_r, nullptr) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_r) // TH PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2) PORT_START("SPORTS_OUT") PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // Directional pins PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // TL (Button 1) - PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_w, nullptr) + PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_sports_pad_device, th_pin_w) // TH PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // TR (Button 2) PORT_START("SPORTS_X") /* Sports Pad X axis */ @@ -171,7 +171,7 @@ sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, cons m_sports_x(*this, "SPORTS_X"), m_sports_y(*this, "SPORTS_Y"), m_read_state(0), - m_last_data(0), + m_th_pin_state(0), m_x_axis_reset_value(0x80), // value 0x80 helps when start playing paddle games. m_y_axis_reset_value(0x80), m_interval(SPORTS_PAD_INTERVAL), m_sportspad_timer(nullptr) @@ -188,7 +188,7 @@ void sms_sports_pad_device::device_start() m_sportspad_timer = timer_alloc(TIMER_SPORTSPAD); save_item(NAME(m_read_state)); - save_item(NAME(m_last_data)); + save_item(NAME(m_th_pin_state)); save_item(NAME(m_x_axis_reset_value)); save_item(NAME(m_y_axis_reset_value)); } diff --git a/src/devices/bus/sms_ctrl/sports.h b/src/devices/bus/sms_ctrl/sports.h index fe98c9e5e70..5ca209e748d 100644 --- a/src/devices/bus/sms_ctrl/sports.h +++ b/src/devices/bus/sms_ctrl/sports.h @@ -33,9 +33,9 @@ public: // optional information overrides virtual ioport_constructor device_input_ports() const override; - DECLARE_CUSTOM_INPUT_MEMBER( dir_pins_r ); - DECLARE_CUSTOM_INPUT_MEMBER( th_pin_r ); - DECLARE_INPUT_CHANGED_MEMBER( th_pin_w ); + DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines. + DECLARE_READ_LINE_MEMBER( th_pin_r ); + DECLARE_WRITE_LINE_MEMBER( th_pin_w ); protected: // device-level overrides @@ -52,7 +52,7 @@ private: required_ioport m_sports_y; UINT8 m_read_state; - UINT8 m_last_data; + UINT8 m_th_pin_state; UINT8 m_x_axis_reset_value; UINT8 m_y_axis_reset_value; const attotime m_interval; diff --git a/src/devices/bus/sms_ctrl/sportsjp.cpp b/src/devices/bus/sms_ctrl/sportsjp.cpp index fef04df69e8..e9b148c19e9 100644 --- a/src/devices/bus/sms_ctrl/sportsjp.cpp +++ b/src/devices/bus/sms_ctrl/sportsjp.cpp @@ -22,6 +22,13 @@ Notes: used by the US model, due to the missing TH line on Sega Mark III controller ports. + A bug was discovered in the player 2 input handling code 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 "sportsjp.h" @@ -39,38 +46,24 @@ const device_type SMS_SPORTS_PAD_JP = &device_creator; -DECLARE_CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::dir_pins_r ) -{ - UINT8 data = 0; - - switch (m_read_state) - { - case 0: - data = m_sports_jp_x->read() >> 4; - break; - case 1: - data = m_sports_jp_x->read(); - break; - case 2: - data = m_sports_jp_y->read() >> 4; - break; - case 3: - data = m_sports_jp_y->read(); - break; - } - - // The returned value is inverted due to IP_ACTIVE_LOW mapping. - return ~(data & 0x0f); -} +// The returned value is inverted due to IP_ACTIVE_LOW mapping. +READ_LINE_MEMBER( sms_sports_pad_jp_device::tl_pin_r ) { return ~m_tl_pin_state; } +READ_LINE_MEMBER( sms_sports_pad_jp_device::tr_pin_r ) { return ~m_tr_pin_state; } +CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::rldu_pins_r ) { return ~(m_rldu_pins_state & 0x0f); } static INPUT_PORTS_START( sms_sports_pad_jp ) PORT_START("SPORTS_JP_IN") - PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_jp_device, dir_pins_r, nullptr) // Directional pins + PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_CUSTOM_MEMBER(DEVICE_SELF, sms_sports_pad_jp_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 (Button 1) + PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_sports_pad_jp_device, tl_pin_r ) // TL PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH - PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2) + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_SPECIAL ) PORT_READ_LINE_DEVICE_MEMBER( DEVICE_SELF, sms_sports_pad_jp_device, tr_pin_r ) // TR + + PORT_START("SPORTS_JP_BT") /* Sports Pad buttons nibble */ + PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) + PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) + PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_START("SPORTS_JP_X") /* Sports Pad X axis */ PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) @@ -103,9 +96,12 @@ sms_sports_pad_jp_device::sms_sports_pad_jp_device(const machine_config &mconfig device_t(mconfig, SMS_SPORTS_PAD_JP, "Sega SMS Sports Pad JP", tag, owner, clock, "sms_sports_pad_jp", __FILE__), device_sms_control_port_interface(mconfig, *this), m_sports_jp_in(*this, "SPORTS_JP_IN"), + m_sports_jp_bt(*this, "SPORTS_JP_BT"), m_sports_jp_x(*this, "SPORTS_JP_X"), m_sports_jp_y(*this, "SPORTS_JP_Y"), - m_read_state(0), + m_rldu_pins_state(0x0f), + m_tl_pin_state(1), + m_tr_pin_state(1), m_interval(SPORTS_PAD_JP_INTERVAL) { } @@ -120,7 +116,9 @@ void sms_sports_pad_jp_device::device_start() m_start_time = machine().time(); save_item(NAME(m_start_time)); - save_item(NAME(m_read_state)); + save_item(NAME(m_rldu_pins_state)); + save_item(NAME(m_tl_pin_state)); + save_item(NAME(m_tr_pin_state)); } @@ -130,41 +128,41 @@ void sms_sports_pad_jp_device::device_start() UINT8 sms_sports_pad_jp_device::peripheral_r() { - UINT8 data; int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double(); - m_read_state = num_intervals % 5; - data = m_sports_jp_in->read(); - - switch (m_read_state) + switch (num_intervals % 5) { case 0: // X high nibble - data &= ~0x20; // TL 0 - data &= ~0x80; // TR 0 + m_rldu_pins_state = m_sports_jp_x->read() >> 4; + m_tl_pin_state = 0; + m_tr_pin_state = 0; break; case 1: // X low nibble - data |= 0x20; // TL 1 - data &= ~0x80; // TR 0 + m_rldu_pins_state = m_sports_jp_x->read(); + m_tl_pin_state = 1; + m_tr_pin_state = 0; break; case 2: // Y high nibble - data &= ~0x20; // TL 0 - data &= ~0x80; // TR 0 + m_rldu_pins_state = m_sports_jp_y->read() >> 4; + m_tl_pin_state = 0; + m_tr_pin_state = 0; break; case 3: // Y low nibble - data |= 0x20; // TL 1 - data &= ~0x80; // TR 0 + m_rldu_pins_state = m_sports_jp_y->read(); + m_tl_pin_state = 1; + m_tr_pin_state = 0; break; case 4: // buttons 1 and 2 - data = (data & 0x20) >> 5 | (data & 0x80) >> 6 | 0xfc; - data |= 0x20; // TL 1 - data |= 0x80; // TR 1 + m_rldu_pins_state = m_sports_jp_bt->read(); + m_tl_pin_state = 1; + m_tr_pin_state = 1; break; } - return data; + return m_sports_jp_in->read(); } diff --git a/src/devices/bus/sms_ctrl/sportsjp.h b/src/devices/bus/sms_ctrl/sportsjp.h index ad438d12bb1..3e82c18dd85 100644 --- a/src/devices/bus/sms_ctrl/sportsjp.h +++ b/src/devices/bus/sms_ctrl/sportsjp.h @@ -33,7 +33,9 @@ public: // optional information overrides virtual ioport_constructor device_input_ports() const override; - CUSTOM_INPUT_MEMBER( dir_pins_r ); + DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines. + DECLARE_READ_LINE_MEMBER( tl_pin_r ); + DECLARE_READ_LINE_MEMBER( tr_pin_r ); protected: // device-level overrides @@ -44,10 +46,13 @@ protected: private: required_ioport m_sports_jp_in; + required_ioport m_sports_jp_bt; required_ioport m_sports_jp_x; required_ioport m_sports_jp_y; - UINT8 m_read_state; + UINT8 m_rldu_pins_state; + UINT8 m_tl_pin_state; + UINT8 m_tr_pin_state; attotime m_start_time; const attotime m_interval; }; diff --git a/src/mame/drivers/sms.cpp b/src/mame/drivers/sms.cpp index a3839649aac..1f2ddde1437 100644 --- a/src/mame/drivers/sms.cpp +++ b/src/mame/drivers/sms.cpp @@ -60,7 +60,7 @@ General compatibility issues on real hardware (not emulation bugs): Paddle controller; - Few games of the ones with FM support need to detect the system region as Japanese to play FM sound; -- The Light Phaser gun doesn't work with the Japanese SMS; +- The Light Phaser gun doesn't work with the Japanese SMS and Sega Mark III; - There are reports about Light Phaser working on the second Korean SMS version, and a Korean advert shows support on the first version (Gam*Boy I, although based on Japanese SMS); @@ -337,10 +337,10 @@ ADDRESS_MAP_END // The first Korean SMS version also seems to lack I/O port $3F. Games execute // a region detection procedure that, through that port, sets the mode used by -// the TH bits of port $DD and tests their behavior. The region of the first SMS +// the TH bits of port $DD and tests their behaviour. The region of the first SMS // version is detected as Japanese (opposite to the second version). However, -// as it supports Light Phaser games, it doesn't have the same behavior of the -// Japanese SMS. If it had the behavior of other SMS versions, the system +// as it supports Light Phaser games, it doesn't have the same behaviour of the +// Japanese SMS. If it had the behaviour of other SMS versions, the system // region would be detected as Export, so it probably lacks the port. static ADDRESS_MAP_START( sms1kr_io, AS_IO, 8, sms_state ) AM_IMPORT_FROM(sg1000m3_io)