(MESS) sms.c: Improved I/O handling for Japanese and Korean drivers (Pause button for sg1000m3, TH input for sg1000m3 and smsj, and output via controller ports for Japanese and Korean drivers) [Enik Land]

This commit is contained in:
Wilbert Pol 2013-09-12 18:48:15 +00:00
parent c6a6b78f95
commit 52bfccb35c
5 changed files with 84 additions and 59 deletions

View File

@ -10,9 +10,15 @@
To do: To do:
- SIO interface for Game Gear (needs netplay, I guess) - SIO interface for Game Gear (needs netplay, I guess)
- SMS lightgun support - SMS Store Display Unit
- LCD persistence emulation for GG - Keyboard support for Sega Mark-III (sg1000m3 driver)
- SMS 3D glass support - Mark-III expansion slot, used by keyboard and FM module
- Japanese Sports Pad model used by the game Sports Pad Soccer
(info: http://www.smspower.org/forums/viewtopic.php?t=11876)
- Software compatibility flags, by region and/or BIOS
- Emulate SRAM cartridges? (for use with Bock's dump tool)
- Support for other DE-9 compatible controllers, like the Mega Drive 6-Button
that has software support (at least a test tool made by Charles MacDonald)
The Game Gear SIO hardware is not emulated but has some The Game Gear SIO hardware is not emulated but has some
placeholders in 'machine/sms.c' placeholders in 'machine/sms.c'
@ -291,8 +297,8 @@ static ADDRESS_MAP_START( sms_io, AS_IO, 8, sms_state )
ADDRESS_MAP_END ADDRESS_MAP_END
// I/O ports $3E and $3F do not exist o Mark-III // I/O ports $3E and $3F do not exist on Mark-III
static ADDRESS_MAP_START( sms_no3e3f_io, AS_IO, 8, sms_state ) static ADDRESS_MAP_START( sg1000m3_io, AS_IO, 8, sms_state )
ADDRESS_MAP_GLOBAL_MASK(0xff) ADDRESS_MAP_GLOBAL_MASK(0xff)
ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r) AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r)
@ -318,11 +324,12 @@ ADDRESS_MAP_END
// addresses. // addresses.
// At least the mirrors for I/O ports $3E/$3F don't seem to exist there. // At least the mirrors for I/O ports $3E/$3F don't seem to exist there.
// Leaving the mirrors breaks the Korean cartridge bublboky. // Leaving the mirrors breaks the Korean cartridge bublboky.
static ADDRESS_MAP_START( sms_kor_io, AS_IO, 8, sms_state ) // The version is derived from japanene SMS, that has no output on its
// controller ports, so port $3F probably does not exist, like on Mark-III.
static ADDRESS_MAP_START( sms_fm_io, AS_IO, 8, sms_state )
ADDRESS_MAP_GLOBAL_MASK(0xff) ADDRESS_MAP_GLOBAL_MASK(0xff)
ADDRESS_MAP_UNMAP_HIGH ADDRESS_MAP_UNMAP_HIGH
AM_RANGE(0x3e, 0x3e) AM_WRITE(sms_bios_w) AM_RANGE(0x3e, 0x3e) AM_WRITE(sms_bios_w)
AM_RANGE(0x3f, 0x3f) AM_WRITE(sms_io_control_w)
AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r) AM_RANGE(0x40, 0x7f) AM_READ(sms_count_r)
AM_RANGE(0x40, 0x7f) AM_DEVWRITE("segapsg", segapsg_device, write) AM_RANGE(0x40, 0x7f) AM_DEVWRITE("segapsg", segapsg_device, write)
AM_RANGE(0x80, 0x80) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sega315_5124_device, vram_read, vram_write) AM_RANGE(0x80, 0x80) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sega315_5124_device, vram_read, vram_write)
@ -371,12 +378,9 @@ static INPUT_PORTS_START( sms )
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_1) PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_OTHER ) PORT_NAME(DEF_STR(Pause)) PORT_CODE(KEYCODE_1)
INPUT_PORTS_END INPUT_PORTS_END
static INPUT_PORTS_START( sms1 ) static INPUT_PORTS_START( sg1000m3 )
PORT_INCLUDE( sms ) PORT_INCLUDE( sms )
PORT_START("RESET")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Reset Button")
PORT_START("SEGASCOPE") PORT_START("SEGASCOPE")
PORT_CONFNAME( 0x01, 0x00, "SegaScope (3-D Glasses)" ) PORT_CONFNAME( 0x01, 0x00, "SegaScope (3-D Glasses)" )
PORT_CONFSETTING( 0x00, DEF_STR( Off ) ) PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
@ -391,6 +395,13 @@ static INPUT_PORTS_START( sms1 )
PORT_BIT( 0x03, 0x00, IPT_UNUSED ) PORT_CONDITION("SEGASCOPE", 0x01, EQUALS, 0x00) PORT_BIT( 0x03, 0x00, IPT_UNUSED ) PORT_CONDITION("SEGASCOPE", 0x01, EQUALS, 0x00)
INPUT_PORTS_END INPUT_PORTS_END
static INPUT_PORTS_START( sms1 )
PORT_INCLUDE( sg1000m3 )
PORT_START("RESET")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Reset Button")
INPUT_PORTS_END
static INPUT_PORTS_START( gg ) static INPUT_PORTS_START( gg )
PORT_START("GG_PORT_DC") PORT_START("GG_PORT_DC")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY
@ -561,11 +572,11 @@ static MACHINE_CONFIG_DERIVED( sms1_ntsc, sms_ntsc_base )
MCFG_DEFAULT_LAYOUT(layout_sms1) MCFG_DEFAULT_LAYOUT(layout_sms1)
MCFG_PALETTE_LENGTH(SEGA315_5124_PALETTE_SIZE)
MCFG_VIDEO_START_OVERRIDE(sms_state,sms1) MCFG_VIDEO_START_OVERRIDE(sms_state,sms1)
MCFG_VIDEO_RESET_OVERRIDE(sms_state,sms1) MCFG_VIDEO_RESET_OVERRIDE(sms_state,sms1)
MCFG_PALETTE_LENGTH(SEGA315_5124_PALETTE_SIZE)
MCFG_SEGA315_5124_ADD("sms_vdp", _315_5124_ntsc_intf) MCFG_SEGA315_5124_ADD("sms_vdp", _315_5124_ntsc_intf)
MCFG_SEGA315_5124_SET_SCREEN("screen") MCFG_SEGA315_5124_SET_SCREEN("screen")
@ -727,11 +738,11 @@ static MACHINE_CONFIG_DERIVED( sms1_pal, sms_pal_base )
MCFG_DEFAULT_LAYOUT(layout_sms1) MCFG_DEFAULT_LAYOUT(layout_sms1)
MCFG_PALETTE_LENGTH(SEGA315_5124_PALETTE_SIZE)
MCFG_VIDEO_START_OVERRIDE(sms_state,sms1) MCFG_VIDEO_START_OVERRIDE(sms_state,sms1)
MCFG_VIDEO_RESET_OVERRIDE(sms_state,sms1) MCFG_VIDEO_RESET_OVERRIDE(sms_state,sms1)
MCFG_PALETTE_LENGTH(SEGA315_5124_PALETTE_SIZE)
MCFG_SEGA315_5124_ADD("sms_vdp", _315_5124_pal_intf) MCFG_SEGA315_5124_ADD("sms_vdp", _315_5124_pal_intf)
MCFG_SEGA315_5124_SET_SCREEN("screen") MCFG_SEGA315_5124_SET_SCREEN("screen")
@ -741,6 +752,14 @@ static MACHINE_CONFIG_DERIVED( sms1_pal, sms_pal_base )
MACHINE_CONFIG_END MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( sms_fm, sms1_ntsc ) static MACHINE_CONFIG_DERIVED( sms_fm, sms1_ntsc )
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_IO_MAP(sms_fm_io)
// Japanese sms and sg1000m3 consoles do not have TH input
MCFG_SMS_CONTROL_PORT_MODIFY(CONTROL1_TAG)
MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(NULL)
MCFG_SMS_CONTROL_PORT_MODIFY(CONTROL2_TAG)
MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(NULL)
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15) MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
@ -748,7 +767,7 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( sg1000m3, sms_fm ) static MACHINE_CONFIG_DERIVED( sg1000m3, sms_fm )
MCFG_CPU_MODIFY("maincpu") MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_IO_MAP(sms_no3e3f_io) MCFG_CPU_IO_MAP(sg1000m3_io)
MCFG_DEVICE_REMOVE("slot") MCFG_DEVICE_REMOVE("slot")
MCFG_SG1000MK3_CARTRIDGE_ADD("slot", sg1000mk3_cart, NULL) MCFG_SG1000MK3_CARTRIDGE_ADD("slot", sg1000mk3_cart, NULL)
@ -756,7 +775,7 @@ MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( sms2_fm, sms2_ntsc ) static MACHINE_CONFIG_DERIVED( sms2_fm, sms2_ntsc )
MCFG_CPU_MODIFY("maincpu") MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_IO_MAP(sms_kor_io) MCFG_CPU_IO_MAP(sms_fm_io)
MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15) MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15)
MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00)
@ -780,10 +799,10 @@ static MACHINE_CONFIG_START( gamegear, sms_state )
SEGA315_5124_HEIGHT_NTSC, SEGA315_5124_TBORDER_START + SEGA315_5124_NTSC_192_TBORDER_HEIGHT + 3*8, SEGA315_5124_TBORDER_START + SEGA315_5124_NTSC_192_TBORDER_HEIGHT + 21*8 ) SEGA315_5124_HEIGHT_NTSC, SEGA315_5124_TBORDER_START + SEGA315_5124_NTSC_192_TBORDER_HEIGHT + 3*8, SEGA315_5124_TBORDER_START + SEGA315_5124_NTSC_192_TBORDER_HEIGHT + 21*8 )
MCFG_SCREEN_UPDATE_DRIVER(sms_state, screen_update_gamegear) MCFG_SCREEN_UPDATE_DRIVER(sms_state, screen_update_gamegear)
MCFG_PALETTE_LENGTH(SEGA315_5378_PALETTE_SIZE)
MCFG_VIDEO_START_OVERRIDE(sms_state,gamegear) MCFG_VIDEO_START_OVERRIDE(sms_state,gamegear)
MCFG_PALETTE_LENGTH(SEGA315_5378_PALETTE_SIZE)
MCFG_SEGA315_5378_ADD("sms_vdp", _315_5124_ntsc_intf) MCFG_SEGA315_5378_ADD("sms_vdp", _315_5124_ntsc_intf)
MCFG_SEGA315_5378_SET_SCREEN("screen") MCFG_SEGA315_5378_SET_SCREEN("screen")
@ -947,8 +966,8 @@ ROM_END
***************************************************************************/ ***************************************************************************/
/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */ /* YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS */
CONS( 1984, sg1000m3, sms, 0, sg1000m3, sms1, sms_state, sg1000m3, "Sega", "SG-1000 Mark III", GAME_SUPPORTS_SAVE ) CONS( 1984, sg1000m3, sms, 0, sg1000m3, sg1000m3, sms_state, sg1000m3, "Sega", "SG-1000 Mark III", GAME_SUPPORTS_SAVE )
CONS( 1986, sms1, sms, 0, sms1_ntsc, sms1, sms_state, sms1, "Sega", "Master System I", GAME_SUPPORTS_SAVE ) CONS( 1986, sms1, sms, 0, sms1_ntsc, sms1, sms_state, sms1, "Sega", "Master System I", GAME_SUPPORTS_SAVE )
CONS( 1986, sms1pal, sms, 0, sms1_pal, sms1, sms_state, sms1, "Sega", "Master System I (PAL)" , GAME_SUPPORTS_SAVE ) CONS( 1986, sms1pal, sms, 0, sms1_pal, sms1, sms_state, sms1, "Sega", "Master System I (PAL)" , GAME_SUPPORTS_SAVE )
CONS( 1986, smssdisp, sms, 0, sms_sdisp, sms, smssdisp_state, smssdisp, "Sega", "Master System Store Display Unit", GAME_NOT_WORKING | GAME_SUPPORTS_SAVE ) CONS( 1986, smssdisp, sms, 0, sms_sdisp, sms, smssdisp_state, smssdisp, "Sega", "Master System Store Display Unit", GAME_NOT_WORKING | GAME_SUPPORTS_SAVE )

View File

@ -48,6 +48,7 @@ public:
m_port_persist(*this, "PERSISTENCE"), m_port_persist(*this, "PERSISTENCE"),
m_is_gamegear(0), m_is_gamegear(0),
m_is_region_japan(0), m_is_region_japan(0),
m_is_korean(0),
m_is_sdisp(0), m_is_sdisp(0),
m_has_bios_0400(0), m_has_bios_0400(0),
m_has_bios_2000(0), m_has_bios_2000(0),
@ -102,6 +103,7 @@ public:
// model identifiers // model identifiers
UINT8 m_is_gamegear; UINT8 m_is_gamegear;
UINT8 m_is_region_japan; UINT8 m_is_region_japan;
UINT8 m_is_korean;
UINT8 m_is_sdisp; UINT8 m_is_sdisp;
UINT8 m_has_bios_0400; UINT8 m_has_bios_0400;
UINT8 m_has_bios_2000; UINT8 m_has_bios_2000;

View File

@ -25,7 +25,7 @@ void sms_state::lphaser_hcount_latch()
WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input) WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input)
{ {
// Check if TH of controller port 1 is set to input (1) // Check if TH of controller port 1 is set to input (1)
if (m_io_ctrl_reg & 0x02) if (m_is_korean || (m_io_ctrl_reg & 0x02))
{ {
if (state == 0) if (state == 0)
{ {
@ -45,7 +45,7 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input)
WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input) WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input)
{ {
// Check if TH of controller port 2 is set to input (1) // Check if TH of controller port 2 is set to input (1)
if (m_io_ctrl_reg & 0x08) if (m_is_korean || (m_io_ctrl_reg & 0x08))
{ {
if (state == 0) if (state == 0)
{ {
@ -64,23 +64,28 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input)
void sms_state::sms_get_inputs( address_space &space ) void sms_state::sms_get_inputs( address_space &space )
{ {
UINT8 data; UINT8 data1, data2;
m_port_dc_reg = 0xff; m_port_dc_reg = 0xff;
m_port_dd_reg = 0xff; m_port_dd_reg = 0xff;
data = m_port_ctrl1->port_r(); data1 = m_port_ctrl1->port_r();
m_port_dc_reg &= ~0x0F | data; // Up, Down, Left, Right m_port_dc_reg &= ~0x0f | data1; // Up, Down, Left, Right
m_port_dc_reg &= ~0x10 | (data >> 1); // TL (Button 1) m_port_dc_reg &= ~0x10 | (data1 >> 1); // TL (Button 1)
m_port_dc_reg &= ~0x20 | (data >> 2); // TR (Button 2) m_port_dc_reg &= ~0x20 | (data1 >> 2); // TR (Button 2)
m_port_dd_reg &= ~0x40 | data; // TH
data = m_port_ctrl2->port_r(); data2 = m_port_ctrl2->port_r();
m_port_dc_reg &= ~0xc0 | (data << 6); // Up, Down m_port_dc_reg &= ~0xc0 | (data2 << 6); // Up, Down
m_port_dd_reg &= ~0x03 | (data >> 2); // Left, Right m_port_dd_reg &= ~0x03 | (data2 >> 2); // Left, Right
m_port_dd_reg &= ~0x04 | (data >> 3); // TL (Button 1) m_port_dd_reg &= ~0x04 | (data2 >> 3); // TL (Button 1)
m_port_dd_reg &= ~0x08 | (data >> 4); // TR (Button 2) m_port_dd_reg &= ~0x08 | (data2 >> 4); // TR (Button 2)
m_port_dd_reg &= ~0x80 | (data << 1); // TH
// Japanese consoles do not have TH line connected.
if (!m_is_region_japan || m_is_korean)
{
m_port_dd_reg &= ~0x40 | data1; // TH ctrl1
m_port_dd_reg &= ~0x80 | (data2 << 1); // TH ctrl2
}
} }
@ -225,10 +230,10 @@ READ8_MEMBER(sms_state::sms_input_port_dc_r)
sms_get_inputs(space); sms_get_inputs(space);
// Check if TR of controller port 1 is set to output (0) // Check if TR of controller port 1 is set to output (0)
if (!(m_io_ctrl_reg & 0x01)) if (!m_is_region_japan && !(m_io_ctrl_reg & 0x01))
{ {
// Read TR state set through IO control port // Read TR state set through IO control port
m_port_dc_reg &= ~0x20 | (m_is_region_japan ? 0x00 : (m_io_ctrl_reg & 0x10) << 1); m_port_dc_reg &= ~0x20 | ((m_io_ctrl_reg & 0x10) << 1);
} }
return m_port_dc_reg; return m_port_dc_reg;
@ -248,23 +253,19 @@ READ8_MEMBER(sms_state::sms_input_port_dd_r)
{ {
m_port_dd_reg &= ~0x10 | (m_port_reset->read() & 0x01) << 4; m_port_dd_reg &= ~0x10 | (m_port_reset->read() & 0x01) << 4;
} }
else
{
m_port_dd_reg |= 0x10;
}
// Check if TR of controller port 2 is set to output (0) // Check if TR of controller port 2 is set to output (0)
if (!(m_io_ctrl_reg & 0x04)) if (!m_is_region_japan && !(m_io_ctrl_reg & 0x04))
{ {
// Read TR state set through IO control port // Read TR state set through IO control port
m_port_dd_reg &= ~0x08 | (m_is_region_japan ? 0x00 : (m_io_ctrl_reg & 0x40) >> 3); m_port_dd_reg &= ~0x08 | ((m_io_ctrl_reg & 0x40) >> 3);
} }
// Check if TH of controller port 1 is set to output (0) // Check if TH of controller port 1 is set to output (0)
if (!(m_io_ctrl_reg & 0x02)) if (!m_is_region_japan && !(m_io_ctrl_reg & 0x02))
{ {
// Read TH state set through IO control port // Read TH state set through IO control port
m_port_dd_reg &= ~0x40 | (m_is_region_japan ? 0x00 : (m_io_ctrl_reg & 0x20) << 1); m_port_dd_reg &= ~0x40 | ((m_io_ctrl_reg & 0x20) << 1);
} }
else // TH set to input (1) else // TH set to input (1)
{ {
@ -276,10 +277,10 @@ READ8_MEMBER(sms_state::sms_input_port_dd_r)
} }
// Check if TH of controller port 2 is set to output (0) // Check if TH of controller port 2 is set to output (0)
if (!(m_io_ctrl_reg & 0x08)) if (!m_is_region_japan && !(m_io_ctrl_reg & 0x08))
{ {
// Read TH state set through IO control port // Read TH state set through IO control port
m_port_dd_reg &= ~0x80 | (m_is_region_japan ? 0x00 : (m_io_ctrl_reg & 0x80)); m_port_dd_reg &= ~0x80 | (m_io_ctrl_reg & 0x80);
} }
else // TH set to input (1) else // TH set to input (1)
{ {
@ -628,7 +629,7 @@ WRITE8_MEMBER(sms_state::gg_sio_w)
case 0x00: /* Parallel Data */ case 0x00: /* Parallel Data */
break; break;
case 0x01: /* Data Direction/ NMI Enable */ case 0x01: /* Data Direction / NMI Enable */
break; break;
case 0x02: /* Serial Output */ case 0x02: /* Serial Output */
@ -652,7 +653,7 @@ READ8_MEMBER(sms_state::gg_sio_r)
case 0x00: /* Parallel Data */ case 0x00: /* Parallel Data */
break; break;
case 0x01: /* Data Direction/ NMI Enable */ case 0x01: /* Data Direction / NMI Enable */
break; break;
case 0x02: /* Serial Output */ case 0x02: /* Serial Output */
@ -973,6 +974,7 @@ DRIVER_INIT_MEMBER(sms_state,sms2kr)
m_is_region_japan = 1; m_is_region_japan = 1;
m_has_bios_full = 1; m_has_bios_full = 1;
m_has_fm = 1; m_has_fm = 1;
m_is_korean = 1;
} }

View File

@ -78,7 +78,7 @@ sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig,
m_lphaser_y(*this, "LPHASER_Y") m_lphaser_y(*this, "LPHASER_Y")
{ {
// Workaround for failed validation that occurs when running on a driver // Workaround for failed validation that occurs when running on a driver
// with Sega Scope emulation, which adds 2 screens for left/right lens. // with Sega Scope emulation, which adds 2 screens (left/right lenses).
m_screen_tag = ":screen"; m_screen_tag = ":screen";
} }

View File

@ -26,6 +26,8 @@
#define MCFG_SMS_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \ #define MCFG_SMS_CONTROL_PORT_ADD(_tag, _slot_intf, _def_slot) \
MCFG_DEVICE_ADD(_tag, SMS_CONTROL_PORT, 0) \ MCFG_DEVICE_ADD(_tag, SMS_CONTROL_PORT, 0) \
MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false) MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, _def_slot, false)
#define MCFG_SMS_CONTROL_PORT_MODIFY(_tag) \
MCFG_DEVICE_MODIFY(_tag)
#define MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(_devcb) \ #define MCFG_SMS_CONTROL_PORT_TH_INPUT_HANDLER(_devcb) \