From faed87bd573dbe646a1ae06385f8741af56d41e6 Mon Sep 17 00:00:00 2001 From: Wilbert Pol Date: Tue, 14 Jan 2014 19:44:56 +0000 Subject: [PATCH] (MESS) sms.c: Various changes: [Enik Land] - adjust/add some comments - restore complete controller port functions to the japanese SMS version - isolate some code to their proper consoles - remove FM support of the sms2kr driver - remove Reset button of the smsj driver - add emulation of the japanese Sports Pad model, required by Sports Pad Soccer - adjust some code of other controller devices. --- .gitattributes | 2 + src/mess/drivers/sms.c | 117 +++++++++++++----- src/mess/includes/sms.h | 5 +- src/mess/machine/sms.c | 211 +++++++++++++++++++++----------- src/mess/machine/sms_paddle.c | 20 ++- src/mess/machine/sms_paddle.h | 6 +- src/mess/machine/sms_rfu.c | 23 ++-- src/mess/machine/sms_rfu.h | 6 +- src/mess/machine/sms_sports.c | 38 +++--- src/mess/machine/sms_sports.h | 9 +- src/mess/machine/sms_sportsjp.c | 157 ++++++++++++++++++++++++ src/mess/machine/sms_sportsjp.h | 66 ++++++++++ src/mess/machine/smsctrl.c | 1 + src/mess/machine/smsctrl.h | 1 + src/mess/mess.mak | 1 + 15 files changed, 499 insertions(+), 164 deletions(-) create mode 100644 src/mess/machine/sms_sportsjp.c create mode 100644 src/mess/machine/sms_sportsjp.h diff --git a/.gitattributes b/.gitattributes index 35f6095cbb6..376c593477d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -8287,6 +8287,8 @@ src/mess/machine/sms_rfu.c svneol=native#text/plain src/mess/machine/sms_rfu.h svneol=native#text/plain src/mess/machine/sms_sports.c svneol=native#text/plain src/mess/machine/sms_sports.h svneol=native#text/plain +src/mess/machine/sms_sportsjp.c svneol=native#text/plain +src/mess/machine/sms_sportsjp.h svneol=native#text/plain src/mess/machine/smsctrl.c svneol=native#text/plain src/mess/machine/smsctrl.h svneol=native#text/plain src/mess/machine/smsexp.c svneol=native#text/plain diff --git a/src/mess/drivers/sms.c b/src/mess/drivers/sms.c index 801d790d848..7d0554de93a 100644 --- a/src/mess/drivers/sms.c +++ b/src/mess/drivers/sms.c @@ -10,11 +10,14 @@ To do: - SIO interface for Game Gear (needs netplay, I guess) - - SMS Store Display Unit - - Keyboard support for Sega Mark-III (sg1000m3 driver) - - 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) + - Gear to Gear Port SMS Controller Adaptor + - SMS Store Display Unit (Kiosk) + - Sega Game Box 9 + - SMS Disk System (floppy disk drive) - unreleased + - Sega Graphic Board (black version) - unreleased + - Rapid button of japanese Master System & korean Gam*Boy I + - Keyboard support for Sega Mark III (sg1000m3 driver) + - Mark III expansion slot, used by keyboard and FM module - 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 @@ -297,7 +300,7 @@ static ADDRESS_MAP_START( sms_io, AS_IO, 8, sms_state ) ADDRESS_MAP_END -// I/O ports $3E and $3F do not exist on Mark-III +// I/O ports $3E and $3F do not exist on Mark III static ADDRESS_MAP_START( sg1000m3_io, AS_IO, 8, sms_state ) ADDRESS_MAP_GLOBAL_MASK(0xff) ADDRESS_MAP_UNMAP_HIGH @@ -320,16 +323,17 @@ static ADDRESS_MAP_START( sg1000m3_io, AS_IO, 8, sms_state ) ADDRESS_MAP_END -// It seems the Korean version does some more strict decoding on the I/O +// It seems the Korean versions do some more strict decoding on the I/O // addresses. // At least the mirrors for I/O ports $3E/$3F don't seem to exist there. // Leaving the mirrors breaks the Korean cartridge bublboky. -// 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 ) +// Assume the same for the japanese SMS, which derived the first korean +// version. +static ADDRESS_MAP_START( smsj_io, AS_IO, 8, sms_state ) ADDRESS_MAP_GLOBAL_MASK(0xff) ADDRESS_MAP_UNMAP_HIGH 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_DEVWRITE("segapsg", segapsg_device, write) AM_RANGE(0x80, 0x80) AM_MIRROR(0x3e) AM_DEVREADWRITE("sms_vdp", sega315_5124_device, vram_read, vram_write) @@ -402,6 +406,13 @@ static INPUT_PORTS_START( sms1 ) PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Reset Button") INPUT_PORTS_END +static INPUT_PORTS_START( smsj ) + PORT_INCLUDE( sg1000m3 ) + + //PORT_START("RAPID") + //PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_SERVICE1 ) PORT_NAME("Rapid Button") /* Not implemented */ +INPUT_PORTS_END + static INPUT_PORTS_START( gg ) PORT_START("GG_PORT_DC") PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_PLAYER(1) PORT_8WAY @@ -529,6 +540,30 @@ static MACHINE_CONFIG_START( sms_ntsc_base, sms_state ) MCFG_SMS_CONTROL_PORT_PIXEL_HANDLER(READ32(sms_state, sms_pixel_color)) MACHINE_CONFIG_END +/* + For SMS drivers, the ratio between CPU and pixel clocks, set through dividers, is 2/3. The + division that sets the pixel clock, in MCFG_SCREEN_RAW_PARAMS(), results in a remainder + that is discarded internally. Due to this rounding, the cycle time and the screen pixel + time, derived from their clocks, do not longer match (inversely) the exact original ratio + of these clocks. The SMS VDP emulation controls some properties (counters/flags) through + screen timing, that the core calculates based on the emulation time. The VDP properties + are read in the CPU timeslice. When a CPU operation that access the VDP is executed, the + elapsed emulation time is also based on how many CPU cycles have elapsed since start of + the current timeslice. Depending on this amount of CPU cycles, when the core divides the + elapsed time by the pixel time, the obtained pixel count may be less than expected. Flubba's + VDPTest ROM relies on exact results. A workaround is to use an additional macro, for each + driver, that resets the refresh rate, and by consequence the pixel time, without discard + the remainder of the division. Considered a hack, it's not applied. The line that would be + added, after MCFG_SCREEN_RAW_PARAMS(), is one of the following, according to the TV system + of the driver. + + - For NTSC drivers: + MCFG_SCREEN_REFRESH_RATE((double) XTAL_53_693175MHz/10 / (SEGA315_5124_WIDTH * SEGA315_5124_HEIGHT_NTSC)) + + - For PAL drivers: + MCFG_SCREEN_REFRESH_RATE((double) MASTER_CLOCK_PAL/10 / (SEGA315_5124_WIDTH * SEGA315_5124_HEIGHT_PAL)) +*/ + static MACHINE_CONFIG_DERIVED( sms2_ntsc, sms_ntsc_base ) /* video hardware */ MCFG_SCREEN_ADD("screen", RASTER) @@ -753,13 +788,7 @@ MACHINE_CONFIG_END 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_CPU_IO_MAP(smsj_io) MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15) MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) @@ -769,16 +798,19 @@ static MACHINE_CONFIG_DERIVED( sg1000m3, sms_fm ) MCFG_CPU_MODIFY("maincpu") MCFG_CPU_IO_MAP(sg1000m3_io) + // Mark III does 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_DEVICE_REMOVE("slot") MCFG_SG1000MK3_CARTRIDGE_ADD("slot", sg1000mk3_cart, NULL) MACHINE_CONFIG_END -static MACHINE_CONFIG_DERIVED( sms2_fm, sms2_ntsc ) +static MACHINE_CONFIG_DERIVED( sms2_kr, sms2_ntsc ) MCFG_CPU_MODIFY("maincpu") - MCFG_CPU_IO_MAP(sms_fm_io) - - MCFG_SOUND_ADD("ym2413", YM2413, XTAL_53_693175MHz/15) - MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 1.00) + MCFG_CPU_IO_MAP(smsj_io) MACHINE_CONFIG_END static MACHINE_CONFIG_START( gamegear, sms_state ) @@ -926,7 +958,7 @@ ROM_END Game driver(s) US - - Sega Master System I (sms1) + - Sega Master System (I) (sms1) - prototype (M404) bios - 1986 - without built-in game v1.3 - 1986 - built-in Hang On/Safari Hunt v2.4 - 1988 @@ -943,11 +975,15 @@ ROM_END - without built-in game v2.1 - 1987 KR - - Sega Master System II (sms2kr) - - built-in Alex Kidd in Miracle World (Korean) + - Samsung Gam*Boy (same as smsj) + - without built-in game v2.1 - 1989 + (same smsj driver used, despite units with plug-in AC adaptor + have FM and the ones with built-in AC adaptor do not) + - Samsung Gam*Boy II / Aladdin Boy (sms2kr) + - built-in Alex Kidd in Miracle World (Korean) - 1992 for A.Boy EU - - Sega Master System I (sms1pal) + - Sega Master System (I) (sms1pal) - without built-in game v1.3 - 1986 - built-in Hang On/Safari Hunt v2.4 - 1988 - built-in Hang On v3.4 - 1988 @@ -958,11 +994,26 @@ ROM_END - built-in Sonic the Hedgehog - 1991 BR - - Sega Master System I - 1987 - - Sega Master System II??? - - Sega Master System III - Tec Toy, 1987 - - Sega Master System Compact - Tec Toy, 1992 - - Sega Master System Girl - Tec Toy, 1992 + - Tec Toy Master System (I) (same as sms1) + - built-in Hang On/Safari Hunt v2.4 - 1989 + - Tec Toy Master System II (same as sms1) + - built-in Alex Kidd in Miracle World - 1991 + - Tec Toy Master System III Compact (same as sms) + - built-in Alex Kidd in Miracle World - 1992 + - built-in Sonic the Hedgehog - 1993 + - built-in World Cup Italia '90 (Super Futebol II) - 1994 + - built-in Hang On/Safari Hunt v2.4 (blue L.Phaser pack) + - Tec Toy Master System Super Compact (no driver) + - built-in Alex Kidd in Miracle World - 1993 (or 1994?) + - built-in Sonic the Hedgehog - 1993 + - built-in World Cup Italia '90 (Super Futebol II) - 1994 + - Tec Toy Master System Girl (no driver) + - built-in Monica no Castelo do Dragao + - built-in Sonic the Hedgehog (T. Monica em O Resgate pack) + Notes about BR: + - PAL-M has same frequency and line count of NTSC + - Tec Toy later changed its logo twice and its name to Tectoy + - 20XX models (Handy, Collection, Evolution...) likely have SoC hardware ***************************************************************************/ @@ -971,10 +1022,10 @@ CONS( 1984, sg1000m3, sms, 0, sg1000m3, sg1000m3, sms_state, 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, smssdisp, sms, 0, sms_sdisp, sms, smssdisp_state, smssdisp, "Sega", "Master System Store Display Unit", GAME_NOT_WORKING | GAME_SUPPORTS_SAVE ) -CONS( 1987, smsj, sms, 0, sms_fm, sms1, sms_state, smsj, "Sega", "Master System (Japan)", GAME_SUPPORTS_SAVE ) +CONS( 1987, smsj, sms, 0, sms_fm, smsj, sms_state, smsj, "Sega", "Master System (Japan)", GAME_SUPPORTS_SAVE ) CONS( 1990, sms, 0, 0, sms2_ntsc, sms, sms_state, sms1, "Sega", "Master System II", GAME_SUPPORTS_SAVE ) CONS( 1990, smspal, sms, 0, sms2_pal, sms, sms_state, sms1, "Sega", "Master System II (PAL)", GAME_SUPPORTS_SAVE ) -CONS( 1990, sms2kr, sms, 0, sms2_fm, sms, sms_state, sms2kr, "Samsung", "Gam*Boy II (Korea)", GAME_SUPPORTS_SAVE ) +CONS( 1990, sms2kr, sms, 0, sms2_kr, sms, sms_state, sms2kr, "Samsung", "Gam*Boy II (Korea)", GAME_SUPPORTS_SAVE ) CONS( 1990, gamegear, 0, sms, gamegear, gg, sms_state, gamegear, "Sega", "Game Gear (Europe/America)", GAME_SUPPORTS_SAVE ) CONS( 1990, gamegeaj, gamegear, 0, gamegear, gg, sms_state, gamegeaj, "Sega", "Game Gear (Japan)", GAME_SUPPORTS_SAVE ) diff --git a/src/mess/includes/sms.h b/src/mess/includes/sms.h index 0318b6cdedc..0ea38733720 100644 --- a/src/mess/includes/sms.h +++ b/src/mess/includes/sms.h @@ -48,7 +48,7 @@ public: m_port_persist(*this, "PERSISTENCE"), m_is_gamegear(0), m_is_region_japan(0), - m_is_korean(0), + m_is_mark_iii(0), m_is_sdisp(0), m_has_bios_0400(0), m_has_bios_2000(0), @@ -103,7 +103,7 @@ public: // model identifiers UINT8 m_is_gamegear; UINT8 m_is_region_japan; - UINT8 m_is_korean; + UINT8 m_is_mark_iii; UINT8 m_is_sdisp; UINT8 m_has_bios_0400; UINT8 m_has_bios_2000; @@ -174,7 +174,6 @@ public: protected: void setup_bios(); void setup_rom(); - void setup_sms_cart(); void lphaser_hcount_latch(); void sms_get_inputs(address_space &space); }; diff --git a/src/mess/machine/sms.c b/src/mess/machine/sms.c index c715e43b762..a2a8a7b8b57 100644 --- a/src/mess/machine/sms.c +++ b/src/mess/machine/sms.c @@ -25,7 +25,7 @@ void sms_state::lphaser_hcount_latch() WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input) { // Check if TH of controller port 1 is set to input (1) - if (m_is_korean || (m_io_ctrl_reg & 0x02)) + if (m_io_ctrl_reg & 0x02) { if (state == 0) { @@ -33,7 +33,7 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input) } else { - // If previous state was 0 and now is 1, latch hcount. + // State is 1. If changed from 0, hcount is latched. if (m_ctrl1_th_state == 0) lphaser_hcount_latch(); } @@ -45,7 +45,7 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input) WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input) { // Check if TH of controller port 2 is set to input (1) - if (m_is_korean || (m_io_ctrl_reg & 0x08)) + if (m_io_ctrl_reg & 0x08) { if (state == 0) { @@ -53,7 +53,7 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input) } else { - // If previous state was 0 and now is 1, latch hcount. + // State is 1. If changed from 0, hcount is latched. if (m_ctrl2_th_state == 0) lphaser_hcount_latch(); } @@ -69,6 +69,10 @@ void sms_state::sms_get_inputs( address_space &space ) m_port_dc_reg = 0xff; m_port_dd_reg = 0xff; + // The bit order of the emulated controller port tries to follow its + // physical pins numbering. For register bits whose order differs, + // it's necessary move the equivalent controller bits to match. + data1 = m_port_ctrl1->port_r(); m_port_dc_reg &= ~0x0f | data1; // Up, Down, Left, Right m_port_dc_reg &= ~0x10 | (data1 >> 1); // TL (Button 1) @@ -80,8 +84,8 @@ void sms_state::sms_get_inputs( address_space &space ) m_port_dd_reg &= ~0x04 | (data2 >> 3); // TL (Button 1) m_port_dd_reg &= ~0x08 | (data2 >> 4); // TR (Button 2) - // Japanese consoles do not have TH line connected. - if (!m_is_region_japan || m_is_korean) + // Sega Mark III does not have TH line connected. + if (!m_is_mark_iii) { m_port_dd_reg &= ~0x40 | data1; // TH ctrl1 m_port_dd_reg &= ~0x80 | (data2 << 1); // TH ctrl2 @@ -104,7 +108,7 @@ READ8_MEMBER(sms_state::sms_fm_detect_r) } else { - if (m_bios_port & IO_CHIP) + if (!m_is_mark_iii && (m_bios_port & IO_CHIP)) { return 0xff; } @@ -213,14 +217,23 @@ WRITE_LINE_MEMBER(sms_state::sms_pause_callback) else m_paused = 0; - // clear TH latch of the controller ports - m_ctrl1_th_latch = 0; - m_ctrl2_th_latch = 0; + if (!m_is_mark_iii) + { + // clear TH latch of the controller ports + m_ctrl1_th_latch = 0; + m_ctrl2_th_latch = 0; + } } READ8_MEMBER(sms_state::sms_input_port_dc_r) { + if (m_is_mark_iii) + { + sms_get_inputs(space); + return m_port_dc_reg; + } + if (m_bios_port & IO_CHIP) { return 0xff; @@ -230,7 +243,7 @@ READ8_MEMBER(sms_state::sms_input_port_dc_r) sms_get_inputs(space); // Check if TR of controller port 1 is set to output (0) - if (!m_is_region_japan && !(m_io_ctrl_reg & 0x01)) + if (!(m_io_ctrl_reg & 0x01)) { // Read TR state set through IO control port m_port_dc_reg &= ~0x20 | ((m_io_ctrl_reg & 0x10) << 1); @@ -243,6 +256,12 @@ READ8_MEMBER(sms_state::sms_input_port_dc_r) READ8_MEMBER(sms_state::sms_input_port_dd_r) { + if (m_is_mark_iii) + { + sms_get_inputs(space); + return m_port_dd_reg; + } + if (m_bios_port & IO_CHIP) return 0xff; @@ -255,14 +274,14 @@ READ8_MEMBER(sms_state::sms_input_port_dd_r) } // Check if TR of controller port 2 is set to output (0) - if (!m_is_region_japan && !(m_io_ctrl_reg & 0x04)) + if (!(m_io_ctrl_reg & 0x04)) { // Read TR state set through IO control port m_port_dd_reg &= ~0x08 | ((m_io_ctrl_reg & 0x40) >> 3); } // Check if TH of controller port 1 is set to output (0) - if (!m_is_region_japan && !(m_io_ctrl_reg & 0x02)) + if (!(m_io_ctrl_reg & 0x02)) { // Read TH state set through IO control port m_port_dd_reg &= ~0x40 | ((m_io_ctrl_reg & 0x20) << 1); @@ -277,7 +296,7 @@ READ8_MEMBER(sms_state::sms_input_port_dd_r) } // Check if TH of controller port 2 is set to output (0) - if (!m_is_region_japan && !(m_io_ctrl_reg & 0x08)) + if (!(m_io_ctrl_reg & 0x08)) { // Read TH state set through IO control port m_port_dd_reg &= ~0x80 | (m_io_ctrl_reg & 0x80); @@ -373,7 +392,16 @@ WRITE8_MEMBER(sms_state::sms_mapper_w) m_mapper[offset] = data; m_mainram[0x1ffc + offset] = data; - if (m_bios_port & IO_BIOS_ROM || (m_is_gamegear && m_BIOS == NULL)) + if (m_is_mark_iii) + { + if (m_cartslot && m_cartslot->m_cart) + cartridge_selected = true; + else if (m_cardslot && m_cardslot->m_cart) + card_selected = true; + else + return; // nothing to page in + } + else if (m_bios_port & IO_BIOS_ROM || (m_is_gamegear && m_BIOS == NULL)) { if (!(m_bios_port & IO_CARTRIDGE) || (m_is_gamegear && m_BIOS == NULL)) cartridge_selected = true; @@ -394,7 +422,7 @@ WRITE8_MEMBER(sms_state::sms_mapper_w) switch (offset) { case 0: // Control RAM/ROM - if (!(data & 0x08) && !(m_bios_port & IO_BIOS_ROM) && bios_selected) // BIOS ROM + if (!(data & 0x08) && bios_selected && !(m_bios_port & IO_BIOS_ROM)) // BIOS ROM { if (!m_has_bios_0400 && !m_has_bios_2000) { @@ -677,6 +705,29 @@ void sms_state::setup_rom() m_bank_enabled[1] = ENABLE_NONE; m_bank_enabled[2] = ENABLE_NONE; + if (m_is_mark_iii) + { + // Mark III uses the card slot by default, but has hardware method + // that prioritizes the cartridge slot if it has a cartridge inserted. + if (m_cartslot && m_cartslot->m_cart) + { + m_bank_enabled[3] = ENABLE_CART; + m_bank_enabled[0] = ENABLE_CART; + m_bank_enabled[1] = ENABLE_CART; + m_bank_enabled[2] = ENABLE_CART; + logerror("Switched in cartridge rom.\n"); + } + else + { + m_bank_enabled[3] = ENABLE_CARD; + m_bank_enabled[0] = ENABLE_CARD; + m_bank_enabled[1] = ENABLE_CARD; + m_bank_enabled[2] = ENABLE_CARD; + logerror("Switching to card rom port.\n"); + } + return; + } + /* 2. check and set up expansion port */ if (!(m_bios_port & IO_EXPANSION) && (m_bios_port & IO_CARTRIDGE) && (m_bios_port & IO_CARD)) { @@ -746,7 +797,6 @@ void sms_state::setup_bios() if (m_BIOS == NULL || m_BIOS[0] == 0x00) { m_BIOS = NULL; - m_bios_port |= IO_BIOS_ROM; m_has_bios_0400 = 0; m_has_bios_2000 = 0; m_has_bios_full = 0; @@ -759,14 +809,22 @@ void sms_state::setup_bios() m_bios_page[1] = (1 < m_bios_page_count) ? 1 : 0; m_bios_page[2] = (2 < m_bios_page_count) ? 2 : 0; } + + if (!m_is_mark_iii) + { + m_bios_port = (IO_EXPANSION | IO_CARTRIDGE | IO_CARD); + if (!m_BIOS) + { + m_bios_port &= ~(IO_CARTRIDGE); + m_bios_port |= IO_BIOS_ROM; + } + } } MACHINE_START_MEMBER(sms_state,sms) { char str[7]; - m_left_lcd = machine().device("left_lcd"); - m_right_lcd = machine().device("right_lcd"); m_space = &m_maincpu->space(AS_PROGRAM); // alibaba and blockhol are ports of games for the MSX system. The @@ -775,30 +833,44 @@ MACHINE_START_MEMBER(sms_state,sms) // the "call $4010" without a following RET statement. That is basically // a bug in the program code. The only way this cartridge could have run // successfully on a real unit is if the RAM would be initialized with - // a F0 pattern on power up; F0 = RET P. Do that only for consoles in - // Japan region (including KR), until confirmed on other consoles. + // a F0 pattern on power up; F0 = RET P. Do that only for consoles of + // Japan region (including Korea), until confirmed on other consoles. if (m_is_region_japan) { memset((UINT8*)m_space->get_write_ptr(0xc000), 0xf0, 0x1fff); } - save_item(NAME(m_fm_detect)); - save_item(NAME(m_io_ctrl_reg)); save_item(NAME(m_paused)); - save_item(NAME(m_bios_port)); save_item(NAME(m_mapper)); save_item(NAME(m_port_dc_reg)); save_item(NAME(m_port_dd_reg)); - save_item(NAME(m_gg_sio)); save_item(NAME(m_bank_enabled)); - save_item(NAME(m_bios_page)); - save_item(NAME(m_ctrl1_th_state)); - save_item(NAME(m_ctrl2_th_state)); - save_item(NAME(m_ctrl1_th_latch)); - save_item(NAME(m_ctrl2_th_latch)); - save_item(NAME(m_sscope_state)); - save_item(NAME(m_frame_sscope_state)); + if (m_has_fm) + { + save_item(NAME(m_fm_detect)); + } + + if (!m_is_mark_iii) + { + save_item(NAME(m_bios_port)); + save_item(NAME(m_bios_page)); + save_item(NAME(m_io_ctrl_reg)); + save_item(NAME(m_ctrl1_th_latch)); + save_item(NAME(m_ctrl2_th_latch)); + } + + if (m_is_gamegear) + { + save_item(NAME(m_gg_sio)); + } + else + { + save_item(NAME(m_ctrl1_th_state)); + save_item(NAME(m_ctrl2_th_state)); + save_item(NAME(m_sscope_state)); + save_item(NAME(m_frame_sscope_state)); + } if (m_is_sdisp) { @@ -830,40 +902,47 @@ MACHINE_START_MEMBER(sms_state,sms) MACHINE_RESET_MEMBER(sms_state,sms) { - m_io_ctrl_reg = 0xff; if (m_has_fm) m_fm_detect = 0x01; + if (!m_is_mark_iii) + { + m_io_ctrl_reg = 0xff; + m_bios_port = 0; + m_ctrl1_th_latch = 0; + m_ctrl2_th_latch = 0; + } + + if (m_is_gamegear) + { + if (m_cartslot->m_cart && m_cartslot->m_cart->get_sms_mode()) + m_vdp->set_sega315_5124_compatibility_mode(true); + + /* Initialize SIO stuff for GG */ + m_gg_sio[0] = 0x7f; + m_gg_sio[1] = 0xff; + m_gg_sio[2] = 0x00; + m_gg_sio[3] = 0xff; + m_gg_sio[4] = 0x00; + } + else + { + m_ctrl1_th_state = 1; + m_ctrl2_th_state = 1; + m_lphaser_x_offs = (m_cartslot->m_cart) ? m_cartslot->m_cart->get_lphaser_xoffs() : 44; + + m_sscope_state = 0; + m_frame_sscope_state = 0; + } + if (m_is_sdisp) { m_store_control = 0; m_current_cartridge = 0; } - m_bios_port = 0; - setup_bios(); - setup_sms_cart(); setup_rom(); - - if (m_cartslot->m_cart && m_cartslot->m_cart->get_sms_mode()) - m_vdp->set_sega315_5124_compatibility_mode(true); - - /* Initialize SIO stuff for GG */ - m_gg_sio[0] = 0x7f; - m_gg_sio[1] = 0xff; - m_gg_sio[2] = 0x00; - m_gg_sio[3] = 0xff; - m_gg_sio[4] = 0x00; - - m_ctrl1_th_state = 1; - m_ctrl2_th_state = 1; - m_ctrl1_th_latch = 0; - m_ctrl2_th_latch = 0; - m_lphaser_x_offs = (m_cartslot->m_cart) ? m_cartslot->m_cart->get_lphaser_xoffs() : 44; - - m_sscope_state = 0; - m_frame_sscope_state = 0; } READ8_MEMBER(smssdisp_state::sms_store_cart_select_r) @@ -932,25 +1011,10 @@ WRITE_LINE_MEMBER(smssdisp_state::sms_store_int_callback) } } -void sms_state::setup_sms_cart() -{ - m_bios_port = (IO_EXPANSION | IO_CARTRIDGE | IO_CARD); - if (!m_is_gamegear && !m_BIOS) - { - m_bios_port |= IO_BIOS_ROM; - - // Mark-III has hardware method that prioritizes cartridge slot. - if (m_cartslot && m_cartslot->m_cart) - m_bios_port &= ~(IO_CARTRIDGE); - else - m_bios_port &= ~(IO_CARD); - } -} - - DRIVER_INIT_MEMBER(sms_state,sg1000m3) { m_is_region_japan = 1; + m_is_mark_iii = 1; m_has_fm = 1; } @@ -973,8 +1037,6 @@ DRIVER_INIT_MEMBER(sms_state,sms2kr) { m_is_region_japan = 1; m_has_bios_full = 1; - m_has_fm = 1; - m_is_korean = 1; } @@ -1001,6 +1063,9 @@ DRIVER_INIT_MEMBER(sms_state,gamegeaj) VIDEO_START_MEMBER(sms_state,sms1) { + m_left_lcd = machine().device("left_lcd"); + m_right_lcd = machine().device("right_lcd"); + m_main_scr->register_screen_bitmap(m_prevleft_bitmap); m_main_scr->register_screen_bitmap(m_prevright_bitmap); save_item(NAME(m_prevleft_bitmap)); diff --git a/src/mess/machine/sms_paddle.c b/src/mess/machine/sms_paddle.c index ce3f1c7cde6..90aa121d77f 100644 --- a/src/mess/machine/sms_paddle.c +++ b/src/mess/machine/sms_paddle.c @@ -25,7 +25,7 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r ) { UINT8 data = m_paddle_x->read(); - if (m_paddle_read_state) + if (m_read_state) data >>= 4; // The returned value is inverted due to IP_ACTIVE_LOW mapping. @@ -36,7 +36,7 @@ CUSTOM_INPUT_MEMBER( sms_paddle_device::dir_pins_r ) CUSTOM_INPUT_MEMBER( sms_paddle_device::tr_pin_r ) { // The returned value is inverted due to IP_ACTIVE_LOW mapping. - return ~m_paddle_read_state; + return ~m_read_state; } @@ -77,7 +77,7 @@ sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char * device_sms_control_port_interface(mconfig, *this), m_paddle_pins(*this, "CTRL_PORT"), m_paddle_x(*this, "PADDLE_X"), - m_paddle_interval(PADDLE_INTERVAL) + m_interval(PADDLE_INTERVAL) { } @@ -88,13 +88,11 @@ sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char * void sms_paddle_device::device_start() { - save_item(NAME(m_paddle_read_state)); -} + m_start_time = machine().time(); + m_read_state = 0; - -void sms_paddle_device::device_reset() -{ - m_paddle_read_state = 0; + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); } @@ -104,8 +102,8 @@ void sms_paddle_device::device_reset() UINT8 sms_paddle_device::peripheral_r() { - int n_intervals = machine().time().as_double() / m_paddle_interval.as_double(); - m_paddle_read_state = n_intervals & 1; + 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(); } diff --git a/src/mess/machine/sms_paddle.h b/src/mess/machine/sms_paddle.h index a0d1facfa71..c267800e851 100644 --- a/src/mess/machine/sms_paddle.h +++ b/src/mess/machine/sms_paddle.h @@ -40,7 +40,6 @@ public: protected: // device-level overrides virtual void device_start(); - virtual void device_reset(); // device_sms_control_port_interface overrides virtual UINT8 peripheral_r(); @@ -49,8 +48,9 @@ private: required_ioport m_paddle_pins; required_ioport m_paddle_x; - UINT8 m_paddle_read_state; - const attotime m_paddle_interval; + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; }; diff --git a/src/mess/machine/sms_rfu.c b/src/mess/machine/sms_rfu.c index f4721d15975..7d1ec8472b5 100644 --- a/src/mess/machine/sms_rfu.c +++ b/src/mess/machine/sms_rfu.c @@ -55,7 +55,7 @@ sms_rapid_fire_device::sms_rapid_fire_device(const machine_config &mconfig, cons device_sms_control_port_interface(mconfig, *this), m_rfire_sw(*this, "rfu_sw"), m_subctrl_port(*this, "ctrl"), - m_rapid_fire_interval(RAPID_FIRE_INTERVAL) + m_interval(RAPID_FIRE_INTERVAL) { } @@ -66,17 +66,16 @@ sms_rapid_fire_device::sms_rapid_fire_device(const machine_config &mconfig, cons void sms_rapid_fire_device::device_start() { - save_item(NAME(m_rapid_fire_state)); + m_start_time = machine().time(); + m_read_state = 0; + + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); + m_subctrl_port->device_start(); } -void sms_rapid_fire_device::device_reset() -{ - m_rapid_fire_state = 0; -} - - //------------------------------------------------- // sms_peripheral_r - rapid fire read //------------------------------------------------- @@ -85,18 +84,18 @@ UINT8 sms_rapid_fire_device::peripheral_r() { UINT8 data = 0xff; - int n_intervals = machine().time().as_double() / m_rapid_fire_interval.as_double(); - m_rapid_fire_state = n_intervals & 1; + int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double(); + m_read_state = num_intervals & 1; data = m_subctrl_port->port_r(); /* Check Rapid Fire switch for Button 1 (TL) */ if (!(data & 0x20) && (m_rfire_sw->read() & 0x01)) - data |= m_rapid_fire_state << 5; + data |= m_read_state << 5; /* Check Rapid Fire switch for Button 2 (TR) */ if (!(data & 0x80) && (m_rfire_sw->read() & 0x02)) - data |= m_rapid_fire_state << 7; + data |= m_read_state << 7; return data; } diff --git a/src/mess/machine/sms_rfu.h b/src/mess/machine/sms_rfu.h index 78c9bf573c1..e266e5d028f 100644 --- a/src/mess/machine/sms_rfu.h +++ b/src/mess/machine/sms_rfu.h @@ -40,7 +40,6 @@ public: protected: // device-level overrides virtual void device_start(); - virtual void device_reset(); virtual machine_config_constructor device_mconfig_additions() const; // device_sms_control_port_interface overrides @@ -51,8 +50,9 @@ private: required_ioport m_rfire_sw; required_device m_subctrl_port; - UINT8 m_rapid_fire_state; - const attotime m_rapid_fire_interval; + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; }; diff --git a/src/mess/machine/sms_sports.c b/src/mess/machine/sms_sports.c index 412809da8d3..05090342740 100644 --- a/src/mess/machine/sms_sports.c +++ b/src/mess/machine/sms_sports.c @@ -23,18 +23,18 @@ const device_type SMS_SPORTS_PAD = &device_creator; CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r ) { - UINT8 data = 0xff; + UINT8 data = 0; - switch (m_sports_pad_state) + switch (m_read_state) { case 0: - data = (m_sports_x->read() >> 4); + data = m_sports_x->read() >> 4; break; case 1: data = m_sports_x->read(); break; case 2: - data = (m_sports_y->read() >> 4); + data = m_sports_y->read() >> 4; break; case 3: data = m_sports_y->read(); @@ -48,7 +48,7 @@ CUSTOM_INPUT_MEMBER( sms_sports_pad_device::dir_pins_r ) CUSTOM_INPUT_MEMBER( sms_sports_pad_device::th_pin_r ) { - return m_sports_pad_last_data; + return m_last_data; } @@ -56,16 +56,16 @@ INPUT_CHANGED_MEMBER( sms_sports_pad_device::th_pin_w ) { attotime cur_time = machine().time(); - if (cur_time - m_sports_pad_last_time > m_sports_pad_interval) + if (cur_time - m_last_time > m_interval) { - m_sports_pad_state = 0; + m_read_state = 0; } else { - m_sports_pad_state = (m_sports_pad_state + 1) & 3; + m_read_state = (m_read_state + 1) & 3; } - m_sports_pad_last_time = cur_time; - m_sports_pad_last_data = newval; + m_last_time = cur_time; + m_last_data = newval; } @@ -118,7 +118,7 @@ sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, cons m_sports_out(*this, "SPORTS_OUT"), m_sports_x(*this, "SPORTS_X"), m_sports_y(*this, "SPORTS_Y"), - m_sports_pad_interval(SPORTS_PAD_INTERVAL) + m_interval(SPORTS_PAD_INTERVAL) { } @@ -129,17 +129,13 @@ sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, cons void sms_sports_pad_device::device_start() { - save_item(NAME(m_sports_pad_state)); - save_item(NAME(m_sports_pad_last_data)); - save_item(NAME(m_sports_pad_last_time)); -} + m_read_state = 0; + m_last_data = 0; + m_last_time = machine().time(); - -void sms_sports_pad_device::device_reset() -{ - m_sports_pad_state = 0; - m_sports_pad_last_data = 0; - m_sports_pad_last_time = machine().time(); + save_item(NAME(m_read_state)); + save_item(NAME(m_last_data)); + save_item(NAME(m_last_time)); } diff --git a/src/mess/machine/sms_sports.h b/src/mess/machine/sms_sports.h index 13e31fe3fd4..7f0d33838cc 100644 --- a/src/mess/machine/sms_sports.h +++ b/src/mess/machine/sms_sports.h @@ -41,7 +41,6 @@ public: protected: // device-level overrides virtual void device_start(); - virtual void device_reset(); // device_sms_control_port_interface overrides virtual UINT8 peripheral_r(); @@ -53,10 +52,10 @@ private: required_ioport m_sports_x; required_ioport m_sports_y; - UINT8 m_sports_pad_state; - UINT8 m_sports_pad_last_data; - const attotime m_sports_pad_interval; - attotime m_sports_pad_last_time; + UINT8 m_read_state; + UINT8 m_last_data; + const attotime m_interval; + attotime m_last_time; }; diff --git a/src/mess/machine/sms_sportsjp.c b/src/mess/machine/sms_sportsjp.c new file mode 100644 index 00000000000..352e199efa1 --- /dev/null +++ b/src/mess/machine/sms_sportsjp.c @@ -0,0 +1,157 @@ +/********************************************************************** + + Sega Master System "Sports Pad" (japanese model) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +// The japanese Sports Pad controller is only required to play the cartridge +// Sports Pad Soccer, released in Japan. It uses a different mode than the +// used by the US model, due to missing output lines on Sega Mark III +// controller ports. + +#include "sms_sportsjp.h" + + + +//************************************************************************** +// DEVICE DEFINITIONS +//************************************************************************** + +const device_type SMS_SPORTS_PAD_JP = &device_creator; + + +#define SPORTS_PAD_JP_INTERVAL attotime::from_hz(30000) // 30Hz (not measured) + + +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); +} + + +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, NULL) // Directional pins + 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_UNUSED ) // TH + PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2) + + PORT_START("SPORTS_JP_X") /* Sports Pad X axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) + + PORT_START("SPORTS_JP_Y") /* Sports Pad Y axis */ + PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) +INPUT_PORTS_END + + +//------------------------------------------------- +// input_ports - device-specific input ports +//------------------------------------------------- + +ioport_constructor sms_sports_pad_jp_device::device_input_ports() const +{ + return INPUT_PORTS_NAME( sms_sports_pad_jp ); +} + + + +//************************************************************************** +// LIVE DEVICE +//************************************************************************** + +//------------------------------------------------- +// 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 clock) : + device_t(mconfig, SMS_SPORTS_PAD_JP, "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_x(*this, "SPORTS_JP_X"), + m_sports_jp_y(*this, "SPORTS_JP_Y"), + m_interval(SPORTS_PAD_JP_INTERVAL) +{ +} + + +//------------------------------------------------- +// device_start - device-specific startup +//------------------------------------------------- + +void sms_sports_pad_jp_device::device_start() +{ + m_start_time = machine().time(); + m_read_state = 0; + + save_item(NAME(m_start_time)); + save_item(NAME(m_read_state)); +} + + +//------------------------------------------------- +// sms_peripheral_r - sports pad read +//------------------------------------------------- + +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) + { + case 0: + // X high nibble + data &= ~0x20; // TL 0 + data &= ~0x80; // TR 0 + break; + case 1: + // X low nibble + data |= 0x20; // TL 1 + data &= ~0x80; // TR 0 + break; + case 2: + // Y high nibble + data &= ~0x20; // TL 0 + data &= ~0x80; // TR 0 + break; + case 3: + // Y low nibble + data |= 0x20; // TL 1 + data &= ~0x80; // TR 0 + break; + case 4: + // buttons 1 and 2 + data = (data & 0x20) >> 5 | (data & 0x80) >> 6 | 0xfc; + data |= 0x20; // TL 1 + data |= 0x80; // TR 1 + break; + } + + return data; +} diff --git a/src/mess/machine/sms_sportsjp.h b/src/mess/machine/sms_sportsjp.h new file mode 100644 index 00000000000..57906c68f43 --- /dev/null +++ b/src/mess/machine/sms_sportsjp.h @@ -0,0 +1,66 @@ +/********************************************************************** + + Sega Master System "Sports Pad" (japanese model) emulation + + Copyright MESS Team. + Visit http://mamedev.org for licensing and usage restrictions. + +**********************************************************************/ + +// The japanese Sports Pad controller is only required to play the cartridge +// Sports Pad Soccer, released in Japan. It uses a different mode than the +// used by the US model, due to missing output lines on Sega Mark III +// controller ports. + +#pragma once + +#ifndef __SMS_SPORTS_PAD_JP__ +#define __SMS_SPORTS_PAD_JP__ + + +#include "emu.h" +#include "machine/smsctrl.h" + + + +//************************************************************************** +// TYPE DEFINITIONS +//************************************************************************** + +// ======================> sms_sports_pad_jp_device + +class sms_sports_pad_jp_device : public device_t, + public device_sms_control_port_interface +{ +public: + // construction/destruction + sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, UINT32 clock); + + // optional information overrides + virtual ioport_constructor device_input_ports() const; + + CUSTOM_INPUT_MEMBER( dir_pins_r ); + +protected: + // device-level overrides + virtual void device_start(); + + // device_sms_control_port_interface overrides + virtual UINT8 peripheral_r(); + +private: + required_ioport m_sports_jp_in; + required_ioport m_sports_jp_x; + required_ioport m_sports_jp_y; + + UINT8 m_read_state; + attotime m_start_time; + const attotime m_interval; +}; + + +// device type definition +extern const device_type SMS_SPORTS_PAD_JP; + + +#endif diff --git a/src/mess/machine/smsctrl.c b/src/mess/machine/smsctrl.c index 9c907b46744..e379f318703 100644 --- a/src/mess/machine/smsctrl.c +++ b/src/mess/machine/smsctrl.c @@ -118,5 +118,6 @@ SLOT_INTERFACE_START( sms_control_port_devices ) SLOT_INTERFACE("lphaser", SMS_LIGHT_PHASER) SLOT_INTERFACE("paddle", SMS_PADDLE) SLOT_INTERFACE("sportspad", SMS_SPORTS_PAD) + SLOT_INTERFACE("sportspadjp", SMS_SPORTS_PAD_JP) SLOT_INTERFACE("rapidfire", SMS_RAPID_FIRE) SLOT_INTERFACE_END diff --git a/src/mess/machine/smsctrl.h b/src/mess/machine/smsctrl.h index bcb0b683683..27edf7b6056 100644 --- a/src/mess/machine/smsctrl.h +++ b/src/mess/machine/smsctrl.h @@ -118,6 +118,7 @@ extern const device_type SMS_CONTROL_PORT; #include "machine/sms_lphaser.h" #include "machine/sms_paddle.h" #include "machine/sms_sports.h" +#include "machine/sms_sportsjp.h" #include "machine/sms_rfu.h" SLOT_INTERFACE_EXTERN( sms_control_port_devices ); diff --git a/src/mess/mess.mak b/src/mess/mess.mak index 7fff7c4c0dc..89c3981f235 100644 --- a/src/mess/mess.mak +++ b/src/mess/mess.mak @@ -1793,6 +1793,7 @@ $(MESSOBJ)/sega.a: \ $(MESS_MACHINE)/sms_lphaser.o \ $(MESS_MACHINE)/sms_paddle.o \ $(MESS_MACHINE)/sms_sports.o \ + $(MESS_MACHINE)/sms_sportsjp.o \ $(MESS_MACHINE)/sms_rfu.o \ $(MESS_MACHINE)/sega8_slot.o \ $(MESS_MACHINE)/sega8_rom.o \