From 01c5fe81f19ceda4d0cde3e77cc89264b08d2f87 Mon Sep 17 00:00:00 2001 From: Vas Crabb Date: Wed, 14 Dec 2022 19:26:21 +1100 Subject: sega/sms.cpp: Refactored Game Gear handling. (#10682) Use a memory view to switching between Game Gear and Master System compatibility I/O space mapping. Got rid of most of the conditional code checking whether it's a Game Gear driver. Got rid of the special Game Gear EXT port slot. It's the same thing as a Mega Drive controller/expansion I/O port with a different connector. sega/mdioport.cpp: Added a variant for the Game Gear with the TH/PC6 interrupt latch, and added it to the Game Gear. --- scripts/src/bus.lua | 14 - src/devices/bus/gamegear/ggext.cpp | 118 -------- src/devices/bus/gamegear/ggext.h | 109 -------- src/devices/bus/gamegear/smsctrladp.cpp | 92 ------ src/devices/bus/gamegear/smsctrladp.h | 56 ---- src/devices/bus/sms_ctrl/smsctrl.h | 3 +- src/mame/sega/mdioport.cpp | 479 +++++++++++++++++++++----------- src/mame/sega/mdioport.h | 119 ++++++-- src/mame/sega/sms.cpp | 43 ++- src/mame/sega/sms.h | 28 +- src/mame/sega/sms_m.cpp | 266 +++++++----------- 11 files changed, 552 insertions(+), 775 deletions(-) delete mode 100644 src/devices/bus/gamegear/ggext.cpp delete mode 100644 src/devices/bus/gamegear/ggext.h delete mode 100644 src/devices/bus/gamegear/smsctrladp.cpp delete mode 100644 src/devices/bus/gamegear/smsctrladp.h diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua index 749d453b783..347b1edd6f3 100644 --- a/scripts/src/bus.lua +++ b/scripts/src/bus.lua @@ -3828,20 +3828,6 @@ if (BUSES["GAMEBOY"]~=null) then } end ---------------------------------------------------- --- ---@src/devices/bus/gamegear/ggext.h,BUSES["GAMEGEAR"] = true ---------------------------------------------------- - -if (BUSES["GAMEGEAR"]~=null) then - files { - MAME_DIR .. "src/devices/bus/gamegear/ggext.cpp", - MAME_DIR .. "src/devices/bus/gamegear/ggext.h", - MAME_DIR .. "src/devices/bus/gamegear/smsctrladp.cpp", - MAME_DIR .. "src/devices/bus/gamegear/smsctrladp.h", - } -end - --------------------------------------------------- -- --@src/devices/bus/gba/gba_slot.h,BUSES["GBA"] = true diff --git a/src/devices/bus/gamegear/ggext.cpp b/src/devices/bus/gamegear/ggext.cpp deleted file mode 100644 index dad471f1f9b..00000000000 --- a/src/devices/bus/gamegear/ggext.cpp +++ /dev/null @@ -1,118 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/********************************************************************** - - Sega Game Gear EXT port emulation - Also known as Gear-to-Gear (or VS, in Japan) cable connector - -**********************************************************************/ - -#include "emu.h" -#include "screen.h" -#include "ggext.h" -// slot devices -#include "smsctrladp.h" - - - -//************************************************************************** -// GLOBAL VARIABLES -//************************************************************************** - -DEFINE_DEVICE_TYPE(GG_EXT_PORT, gg_ext_port_device, "gg_ext_port", "Game Gear EXT Port") - - - -//************************************************************************** -// CARD INTERFACE -//************************************************************************** - -//------------------------------------------------- -// device_gg_ext_port_interface - constructor -//------------------------------------------------- - -device_gg_ext_port_interface::device_gg_ext_port_interface(const machine_config &mconfig, device_t &device) : - device_interface(device, "gamegearext") -{ - m_port = dynamic_cast(device.owner()); -} - - -//------------------------------------------------- -// ~device_gg_ext_port_interface - destructor -//------------------------------------------------- - -device_gg_ext_port_interface::~device_gg_ext_port_interface() -{ -} - - - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// gg_ext_port_device - constructor -//------------------------------------------------- - -gg_ext_port_device::gg_ext_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, GG_EXT_PORT, tag, owner, clock), - device_single_card_slot_interface(mconfig, *this), - m_screen(*this, finder_base::DUMMY_TAG), - m_device(nullptr), - m_th_pin_handler(*this) -{ -} - - -//------------------------------------------------- -// gg_ext_port_device - destructor -//------------------------------------------------- - -gg_ext_port_device::~gg_ext_port_device() -{ -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void gg_ext_port_device::device_start() -{ - m_device = get_card_device(); - - m_th_pin_handler.resolve_safe(); -} - - -uint8_t gg_ext_port_device::port_r() -{ - uint8_t data = 0xff; - if (m_device) - data = m_device->peripheral_r(); - return data; -} - -void gg_ext_port_device::port_w( uint8_t data ) -{ - if (m_device) - m_device->peripheral_w(data); -} - - -void gg_ext_port_device::th_pin_w(int state) -{ - m_th_pin_handler(state); -} - - -//------------------------------------------------- -// SLOT_INTERFACE( gg_ext_port_devices ) -//------------------------------------------------- - -void gg_ext_port_devices(device_slot_interface &device) -{ - device.option_add("smsctrladp", SMS_CTRL_ADAPTOR); -} diff --git a/src/devices/bus/gamegear/ggext.h b/src/devices/bus/gamegear/ggext.h deleted file mode 100644 index 250e7ff6500..00000000000 --- a/src/devices/bus/gamegear/ggext.h +++ /dev/null @@ -1,109 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/********************************************************************** - - Sega Game Gear EXT port emulation - Also known as Gear-to-Gear (or VS, in Japan) cable connector - -********************************************************************** - - -**********************************************************************/ - -#ifndef MAME_BUS_GAMEGEAR_GGEXT_H -#define MAME_BUS_GAMEGEAR_GGEXT_H - -#pragma once - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> gg_ext_port_device - -class device_gg_ext_port_interface; - -class gg_ext_port_device : public device_t, public device_single_card_slot_interface -{ -public: - // construction/destruction - template - gg_ext_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) - : gg_ext_port_device(mconfig, tag, owner, 0) - { - option_reset(); - opts(*this); - set_default_option(dflt); - set_fixed(false); - } - - gg_ext_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock = 0); - virtual ~gg_ext_port_device(); - - // static configuration helpers - auto th_input_handler() { return m_th_pin_handler.bind(); } - - // Currently, only the support for SMS Controller Adaptor is emulated, - // for when SMS Compatibility mode is enabled. In that mode, the 10 pins - // of the EXT port follows the same numbering of a SMS Control port. - - // Data returned by the port_r methods: - // bit 0 - pin 1 - Up - // bit 1 - pin 2 - Down - // bit 2 - pin 3 - Left - // bit 3 - pin 4 - Right - // bit 4 - pin 5 - Vcc (no data) - // bit 5 - pin 6 - TL (Button 1/Light Phaser Trigger) - // bit 6 - pin 7 - TH (Light Phaser sensor) - // pin 8 - GND - // bit 7 - pin 9 - TR (Button 2) - // pin 10 - Not connected - // - uint8_t port_r(); - void port_w(uint8_t data); - - void th_pin_w(int state); - - template void set_screen_tag(T &&tag) { m_screen.set_tag(std::forward(tag)); } - - // for peripherals that interact with the machine's screen - required_device m_screen; - -//protected: - // device-level overrides - virtual void device_start() override; - - device_gg_ext_port_interface *m_device; - -private: - devcb_write_line m_th_pin_handler; -}; - - -// ======================> device_gg_ext_port_interface - -// class representing interface-specific live sms_expansion card -class device_gg_ext_port_interface : public device_interface -{ -public: - // construction/destruction - virtual ~device_gg_ext_port_interface(); - - virtual uint8_t peripheral_r() { return 0xff; } - virtual void peripheral_w(uint8_t data) { } - -protected: - device_gg_ext_port_interface(const machine_config &mconfig, device_t &device); - - gg_ext_port_device *m_port; -}; - - -// device type definition -DECLARE_DEVICE_TYPE(GG_EXT_PORT, gg_ext_port_device) - - -void gg_ext_port_devices(device_slot_interface &device); - -#endif // MAME_BUS_GAMEGEAR_GGEXT_H diff --git a/src/devices/bus/gamegear/smsctrladp.cpp b/src/devices/bus/gamegear/smsctrladp.cpp deleted file mode 100644 index e5c40b333e9..00000000000 --- a/src/devices/bus/gamegear/smsctrladp.cpp +++ /dev/null @@ -1,92 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/********************************************************************** - - Sega Game Gear "SMS Controller Adaptor" emulation - Also known as "Master Link" cable. - -**********************************************************************/ - -#include "emu.h" -#include "smsctrladp.h" - -#include "bus/sms_ctrl/controllers.h" - - - -//************************************************************************** -// DEVICE DEFINITIONS -//************************************************************************** - -DEFINE_DEVICE_TYPE(SMS_CTRL_ADAPTOR, sms_ctrl_adaptor_device, "sms_ctrl_adaptor", "SMS Controller Adaptor") - - -//************************************************************************** -// LIVE DEVICE -//************************************************************************** - -//------------------------------------------------- -// sms_ctrl_adaptor_device - constructor -//------------------------------------------------- - -sms_ctrl_adaptor_device::sms_ctrl_adaptor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, SMS_CTRL_ADAPTOR, tag, owner, clock), - device_gg_ext_port_interface(mconfig, *this), - m_subctrl_port(*this, "ctrl"), - m_th_state(0x40) -{ -} - - -//------------------------------------------------- -// device_start - device-specific startup -//------------------------------------------------- - -void sms_ctrl_adaptor_device::device_start() -{ - save_item(NAME(m_th_state)); -} - - -//------------------------------------------------- -// sms_peripheral_r - sms_ctrl_adaptor read -//------------------------------------------------- - -uint8_t sms_ctrl_adaptor_device::peripheral_r() -{ - uint8_t const in = m_subctrl_port->in_r(); - return BIT(in, 0, 4) | 0x10 | (BIT(in, 4) << 5) | m_th_state | (BIT(in, 5) << 7); -} - - -//------------------------------------------------- -// sms_peripheral_w - sms_ctrl_adaptor write -//------------------------------------------------- - -void sms_ctrl_adaptor_device::peripheral_w(uint8_t data) -{ - // FIXME: need driver state to be passed through - uint8_t const out = (bitswap<2>(data, 6, 7) << 5) | 0x1f; - uint8_t const mask = bitswap<2>(~data, 6, 7) << 5; // assume only driven low until this is fixed - m_subctrl_port->out_w(out, mask); -} - - -WRITE_LINE_MEMBER( sms_ctrl_adaptor_device::th_pin_w ) -{ - m_th_state = state ? 0x40 : 0x00; - m_port->th_pin_w(state); -} - - -//------------------------------------------------- -// device_add_mconfig - add device configuration -//------------------------------------------------- - -void sms_ctrl_adaptor_device::device_add_mconfig(machine_config &config) -{ - // Game Gear screen is an LCD - it won't work with lightguns anyway - SMS_CONTROL_PORT(config, m_subctrl_port, sms_control_port_devices, SMS_CTRL_OPTION_JOYPAD); - m_subctrl_port->th_handler().set(FUNC(sms_ctrl_adaptor_device::th_pin_w)); -} - diff --git a/src/devices/bus/gamegear/smsctrladp.h b/src/devices/bus/gamegear/smsctrladp.h deleted file mode 100644 index 613fab1e5a8..00000000000 --- a/src/devices/bus/gamegear/smsctrladp.h +++ /dev/null @@ -1,56 +0,0 @@ -// license:BSD-3-Clause -// copyright-holders:Fabio Priuli -/********************************************************************** - - Sega Game Gear "SMS Controller Adaptor" emulation - Also known as "Master Link" cable. - -**********************************************************************/ - -#ifndef MAME_BUS_GAMEGEAR_SMSCRTLADP_H -#define MAME_BUS_GAMEGEAR_SMSCRTLADP_H - -#pragma once - - -#include "ggext.h" -#include "bus/sms_ctrl/smsctrl.h" - - - -//************************************************************************** -// TYPE DEFINITIONS -//************************************************************************** - -// ======================> sms_ctrl_adaptor_device - -class sms_ctrl_adaptor_device : public device_t, - public device_gg_ext_port_interface -{ -public: - // construction/destruction - sms_ctrl_adaptor_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - -protected: - // device-level overrides - virtual void device_start() override; - virtual void device_add_mconfig(machine_config &config) override; - - // device_gg_ext_port_interface overrides - virtual uint8_t peripheral_r() override; - virtual void peripheral_w(uint8_t data) override; - -private: - DECLARE_WRITE_LINE_MEMBER(th_pin_w); - - required_device m_subctrl_port; - - uint8_t m_th_state; -}; - - -// device type definition -DECLARE_DEVICE_TYPE(SMS_CTRL_ADAPTOR, sms_ctrl_adaptor_device) - - -#endif // MAME_BUS_GAMEGEAR_SMSCRTLADP_H diff --git a/src/devices/bus/sms_ctrl/smsctrl.h b/src/devices/bus/sms_ctrl/smsctrl.h index 27231749fa6..b45c2e10f51 100644 --- a/src/devices/bus/sms_ctrl/smsctrl.h +++ b/src/devices/bus/sms_ctrl/smsctrl.h @@ -16,7 +16,8 @@ 10 NC - DE-9 connector on most systems, or 10-pin tongue connector on - Game Gear. Pin 10 is not connected if present. + Game Gear (Hoshiden HDC-0492). Pin 10 is not connected if + present. SG-1000 Mark III: * Pin 7 (TH) tied to ground diff --git a/src/mame/sega/mdioport.cpp b/src/mame/sega/mdioport.cpp index ef4006639a3..d281cb1dad9 100644 --- a/src/mame/sega/mdioport.cpp +++ b/src/mame/sega/mdioport.cpp @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Vas Crabb -/**********************************************************************8 +/*********************************************************************** Sega Mega Drive I/O Port @@ -10,10 +10,7 @@ * Serial reception - requires peripherals to be reworked. * Is the transmit data register separate from the transmit shift register? - * What sets the serial receive error? Framing error, overrun, - or both? - * Can receive errors cause interrupts when the receive buffer - isn't ready? + * Does receive overrun set the receive error bit? ***********************************************************************/ @@ -27,15 +24,27 @@ #include "logmacro.h" + +/*********************************** + Device type definitions +***********************************/ + DEFINE_DEVICE_TYPE(MEGADRIVE_IO_PORT, megadrive_io_port_device, "megadrive_io_port", "Sega Mega Drive I/O Port Controller") +DEFINE_DEVICE_TYPE(GAMEGEAR_IO_PORT, gamegear_io_port_device, "gamegear_io_port", "Sega Game Gear I/O Port Controller") -megadrive_io_port_device::megadrive_io_port_device( + +/*********************************** + Common behaviour +***********************************/ + +megadrive_io_port_device_base::megadrive_io_port_device_base( machine_config const &mconfig, + device_type type, char const *tag, device_t *owner, u32 clock) : - device_t(mconfig, MEGADRIVE_IO_PORT, tag, owner, clock), + device_t(mconfig, type, tag, owner, clock), device_serial_interface(mconfig, *this), m_in_callback(*this), m_out_callback(*this), @@ -51,24 +60,7 @@ megadrive_io_port_device::megadrive_io_port_device( } -WRITE_LINE_MEMBER(megadrive_io_port_device::th_w) -{ - u8 const th = state ? DATA_TH_MASK : 0x00; - if (th != m_th_in) - { - LOG(state ? "TH rising\n" : "TH falling\n"); - bool const hlupdate = - ctrl_int() && - !BIT(m_ctrl, DATA_TH_BIT) && - !rrdy_int(); - m_th_in = th; - if (hlupdate) - m_hl_callback(state ? 0 : 1); - } -} - - -u8 megadrive_io_port_device::data_r() +u8 megadrive_io_port_device_base::data_r() { // TODO: confirm what's read from pins set to input and configured for serial I/O u8 const serialmask = @@ -85,117 +77,7 @@ u8 megadrive_io_port_device::data_r() } -u8 megadrive_io_port_device::s_ctrl_r() -{ - // TODO: confirm this has no side effects - return m_s_ctrl; -} - - -u8 megadrive_io_port_device::rxdata_r() -{ - if (!machine().side_effects_disabled()) - { - // TODO: confirm this resets both RERR and RRDY - LOG( - "%s: read RxDATA 0x%02X\n%s%s", - machine().describe_context(), - m_rxdata, - s_ctrl_rerr() ? ", clear RERR" : "", - s_ctrl_rrdy() ? ", clear RRDY" : ""); - bool const hlupdate = rrdy_int() && !th_int(); - m_s_ctrl &= ~(S_CTRL_RERR_MASK | S_CTRL_RRDY_MASK); - if (hlupdate) - m_hl_callback(0); - } - - return m_rxdata; -} - - -void megadrive_io_port_device::data_w(u8 data) -{ - // TODO: confirm whether TH-INT follows TH as output - u8 const outmask = - (m_ctrl & 0x7f) & - (s_ctrl_sin() ? ~DATA_RXD_MASK : 0xff) & - (s_ctrl_sout() ? ~DATA_TXD_MASK : 0xff); - bool const outupdate = - !m_out_callback.isnull() && - ((data & outmask) != (m_data & outmask)); - bool const hlupdate = - ctrl_int() && - !rrdy_int() && - BIT(m_ctrl & (data ^ m_data), DATA_TH_BIT); - - m_data = data; - if (outupdate) - update_out(); - if (hlupdate) - m_hl_callback(BIT(~data, DATA_TH_BIT)); -} - - -void megadrive_io_port_device::ctrl_w(u8 data) -{ - // TODO: confirm whether TH-INT follows TH as output - u8 const changed = data ^ m_ctrl; - u8 const parallelmask = - 0x4f | - (s_ctrl_sin() ? 0x00 : DATA_RXD_MASK) | - (s_ctrl_sout() ? 0x00 : DATA_TXD_MASK); - bool const outupdate = !m_out_callback.isnull() && (changed & parallelmask); - bool const hlupdate = - (BIT(changed, 7) || (BIT(data, 7) && BIT(changed & (m_data ^ m_th_in), DATA_TH_BIT))) && - !rrdy_int(); - - m_ctrl = data; - if (outupdate) - update_out(); - if (hlupdate) - m_hl_callback(th_int() ? 1 : 0); -} - - -void megadrive_io_port_device::s_ctrl_w(u8 data) -{ - u8 const changed = data ^ m_s_ctrl; - - if (changed & 0xc0) - { - int rate; - switch (data & 0xc0) - { - default: // shut up stupid compilers - case 0x00: rate = 4800; break; - case 0x40: rate = 2400; break; - case 0x80: rate = 1200; break; - case 0xc0: rate = 300; break; - } - LOG( - "%s: serial data rate = %u bits/second\n", - machine().describe_context(), - rate); - set_rate(rate); - } - - bool const outchanged = - ((changed & S_CTRL_SIN_MASK) && BIT(m_ctrl, 5)) || - ((changed & S_CTRL_SOUT_MASK) && BIT(~m_ctrl | (m_data ^ m_txd), 4)); - bool const hlupdate = - (changed & S_CTRL_RINT_MASK) && - (s_ctrl_rerr() || s_ctrl_rrdy()) && - !th_int(); - - m_s_ctrl = (data & 0xf8) | (m_s_ctrl & 0x07); - if (!m_out_callback.isnull() && outchanged) - update_out(); - if (hlupdate) - m_hl_callback(s_ctrl_rint() ? 1 : 0); -} - - -void megadrive_io_port_device::txdata_w(u8 data) +void megadrive_io_port_device_base::txdata_w(u8 data) { if (s_ctrl_tful()) { @@ -223,7 +105,7 @@ void megadrive_io_port_device::txdata_w(u8 data) } -void megadrive_io_port_device::device_resolve_objects() +void megadrive_io_port_device_base::device_resolve_objects() { m_th_in = DATA_TH_MASK; @@ -233,7 +115,7 @@ void megadrive_io_port_device::device_resolve_objects() } -void megadrive_io_port_device::device_start() +void megadrive_io_port_device_base::device_start() { save_item(NAME(m_txd)); save_item(NAME(m_th_in)); @@ -247,7 +129,7 @@ void megadrive_io_port_device::device_start() } -void megadrive_io_port_device::device_reset() +void megadrive_io_port_device_base::device_reset() { // TODO: proper reset state for DATA, TxDATA and RxDATA m_txd = DATA_TXD_MASK; @@ -267,7 +149,7 @@ void megadrive_io_port_device::device_reset() } -void megadrive_io_port_device::tra_callback() +void megadrive_io_port_device_base::tra_callback() { u8 const txd = transmit_register_get_data_bit() ? DATA_TXD_MASK : 0x00; if (txd != m_txd) @@ -279,7 +161,7 @@ void megadrive_io_port_device::tra_callback() } -void megadrive_io_port_device::tra_complete() +void megadrive_io_port_device_base::tra_complete() { if (s_ctrl_tful()) { @@ -294,15 +176,103 @@ void megadrive_io_port_device::tra_complete() } -void megadrive_io_port_device::rcv_complete() +inline bool megadrive_io_port_device_base::rrdy_int() const +{ + return s_ctrl_rint() && s_ctrl_rrdy(); +} + + +inline u8 megadrive_io_port_device_base::out_drive() const +{ + return + (m_ctrl & (s_ctrl_sin() ? 0x5f : 0x7f)) | + (s_ctrl_sout() ? DATA_TXD_MASK : 0x00); +} + + +inline void megadrive_io_port_device_base::update_out() +{ + assert(!m_out_callback.isnull()); + + u8 const drive = out_drive(); + u8 const data = (m_data | ~drive) & (s_ctrl_sout() ? 0x6f : 0x7f); + m_out_callback(data | (s_ctrl_sout() ? m_txd : 0x00), drive); +} + + +inline void megadrive_io_port_device_base::set_data(u8 data) +{ + u8 const outmask = + (m_ctrl & 0x7f) & + (s_ctrl_sin() ? ~DATA_RXD_MASK : 0xff) & + (s_ctrl_sout() ? ~DATA_TXD_MASK : 0xff); + bool const outupdate = + !m_out_callback.isnull() && + ((data & outmask) != (m_data & outmask)); + + m_data = data; + if (outupdate) + update_out(); +} + + +inline void megadrive_io_port_device_base::set_ctrl(u8 data) +{ + u8 const changed = data ^ m_ctrl; + u8 const parallelmask = + 0x4f | + (s_ctrl_sin() ? 0x00 : DATA_RXD_MASK) | + (s_ctrl_sout() ? 0x00 : DATA_TXD_MASK); + bool const outupdate = !m_out_callback.isnull() && (changed & parallelmask); + + m_ctrl = data; + if (outupdate) + update_out(); +} + + +inline bool megadrive_io_port_device_base::set_s_ctrl(u8 data) +{ + u8 const changed = data ^ m_s_ctrl; + + if (changed & 0xc0) + { + int rate; + switch (data & 0xc0) + { + default: // shut up stupid compilers + case 0x00: rate = 4800; break; + case 0x40: rate = 2400; break; + case 0x80: rate = 1200; break; + case 0xc0: rate = 300; break; + } + LOG( + "%s: serial data rate = %u bits/second\n", + machine().describe_context(), + rate); + set_rate(rate); + } + + bool const rintchanged = + ((data ^ m_s_ctrl) & S_CTRL_RINT_MASK) && + s_ctrl_rrdy(); + bool const outchanged = + ((changed & S_CTRL_SIN_MASK) && BIT(m_ctrl, DATA_RXD_BIT)) || + ((changed & S_CTRL_SOUT_MASK) && BIT(~m_ctrl | (m_data ^ m_txd), DATA_TXD_BIT)); + + m_s_ctrl = (data & 0xf8) | (m_s_ctrl & 0x07); + if (!m_out_callback.isnull() && outchanged) + update_out(); + + return rintchanged; +} + + +inline bool megadrive_io_port_device_base::data_received() { receive_register_extract(); u8 const data = get_received_char(); - bool const hlupdate = - s_ctrl_rint() && - !s_ctrl_rerr() && - !s_ctrl_rrdy() && - !th_int(); + bool const rintchanged = s_ctrl_rint() && !s_ctrl_rrdy(); if (s_ctrl_rrdy()) { @@ -316,7 +286,6 @@ void megadrive_io_port_device::rcv_complete() } else if (is_receive_framing_error()) { - // TODO: confirm whether framing error sets RRDY and/or updates RxDATA LOG("received byte 0x%02X, framing error\n", data); m_s_ctrl |= S_CTRL_RERR_MASK | S_CTRL_RRDY_MASK; } @@ -327,7 +296,101 @@ void megadrive_io_port_device::rcv_complete() } m_rxdata = data; + + return rintchanged; +} + + + +/*********************************** + Mega Drive variant +***********************************/ + +megadrive_io_port_device::megadrive_io_port_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) : + megadrive_io_port_device_base(mconfig, MEGADRIVE_IO_PORT, tag, owner, clock) +{ +} + + +WRITE_LINE_MEMBER(megadrive_io_port_device::th_w) +{ + u8 const th = state ? DATA_TH_MASK : 0x00; + if (th != m_th_in) + { + LOG(state ? "TH rising\n" : "TH falling\n"); + bool const hlupdate = + ctrl_int() && + !BIT(m_ctrl, DATA_TH_BIT) && + !rrdy_int(); + m_th_in = th; + if (hlupdate) + m_hl_callback(state ? 0 : 1); + } +} + + +u8 megadrive_io_port_device::rxdata_r() +{ + if (!machine().side_effects_disabled()) + { + LOG( + "%s: read RxDATA 0x%02X\n%s%s", + machine().describe_context(), + m_rxdata, + s_ctrl_rerr() ? ", clear RERR" : "", + s_ctrl_rrdy() ? ", clear RRDY" : ""); + bool const hlupdate = rrdy_int() && !th_int(); + m_s_ctrl &= ~(S_CTRL_RERR_MASK | S_CTRL_RRDY_MASK); + if (hlupdate) + m_hl_callback(0); + } + + return m_rxdata; +} + + +void megadrive_io_port_device::data_w(u8 data) +{ + // TODO: confirm whether TH-INT follows TH as output + bool const hlupdate = + ctrl_int() && + !rrdy_int() && + BIT(m_ctrl & (data ^ m_data), DATA_TH_BIT); + set_data(data); if (hlupdate) + m_hl_callback(BIT(~data, DATA_TH_BIT)); +} + + +void megadrive_io_port_device::ctrl_w(u8 data) +{ + // TODO: confirm whether TH-INT follows TH as output + u8 const changed = data ^ m_ctrl; + bool const hlupdate = + (BIT(changed, 7) || (BIT(data, 7) && BIT(changed & (m_data ^ m_th_in), DATA_TH_BIT))) && + !rrdy_int(); + set_ctrl(data); + if (hlupdate) + m_hl_callback(th_int() ? 1 : 0); +} + + +void megadrive_io_port_device::s_ctrl_w(u8 data) +{ + bool const rintchanged = set_s_ctrl(data); + if (rintchanged && !th_int()) + m_hl_callback(s_ctrl_rint() ? 1 : 0); +} + + +void megadrive_io_port_device::rcv_complete() +{ + bool const rintchanged = data_received(); + if (rintchanged && !th_int()) m_hl_callback(1); } @@ -341,26 +404,122 @@ inline bool megadrive_io_port_device::th_int() const } -inline bool megadrive_io_port_device::rrdy_int() const + +/*********************************** + Game Gear variant +***********************************/ + +gamegear_io_port_device::gamegear_io_port_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) : + megadrive_io_port_device_base(mconfig, GAMEGEAR_IO_PORT, tag, owner, clock), + m_pc6int(0) { - // TODO: confirm whether RERR can cause an interrupt - return s_ctrl_rint() && (s_ctrl_rerr() || s_ctrl_rrdy()); } -inline u8 megadrive_io_port_device::out_drive() const +WRITE_LINE_MEMBER(gamegear_io_port_device::th_w) { - return - (m_ctrl & (s_ctrl_sin() ? 0x5f : 0x7f)) | - (s_ctrl_sout() ? DATA_TXD_MASK : 0x00); + u8 const th = state ? DATA_TH_MASK : 0x00; + if (th != m_th_in) + { + LOG(state ? "PC6 rising\n" : "PC6 falling\n"); + m_th_in = th; + if (!state && ctrl_int() && !BIT(m_ctrl, DATA_TH_BIT) && !m_pc6int) + { + LOG("PC6 interrupt triggered\n"); + m_pc6int = 1; + if (!rrdy_int()) + m_hl_callback(1); + } + } } -inline void megadrive_io_port_device::update_out() +u8 gamegear_io_port_device::rxdata_r() { - assert(!m_out_callback.isnull()); + if (!machine().side_effects_disabled()) + { + LOG( + "%s: read RxDATA 0x%02X\n%s%s", + machine().describe_context(), + m_rxdata, + s_ctrl_rerr() ? ", clear RERR" : "", + s_ctrl_rrdy() ? ", clear RRDY" : ""); + bool const hlupdate = rrdy_int() && !m_pc6int; + m_s_ctrl &= ~(S_CTRL_RERR_MASK | S_CTRL_RRDY_MASK); + if (hlupdate) + m_hl_callback(0); + } - u8 const drive = out_drive(); - u8 const data = (m_data | ~drive) & (s_ctrl_sout() ? 0x6f : 0x7f); - m_out_callback(data | (s_ctrl_sout() ? m_txd : 0x00), drive); + return m_rxdata; +} + + +void gamegear_io_port_device::data_w(u8 data) +{ + // TODO: can changing PC6 as an output set the interrupt latch? + set_data(data); +} + + +void gamegear_io_port_device::ctrl_w(u8 data) +{ + // TODO: can changing the direction of the TH pin set the interrupt latch? + bool const intchanged = BIT(~data ^ m_ctrl, 7); + set_ctrl(~data); + if (intchanged) + { + if (m_pc6int) + { + if (!ctrl_int()) + { + LOG("%s: PC6 interrupt cleared\n", machine().describe_context()); + m_pc6int = 0; + if (!rrdy_int()) + m_hl_callback(0); + } + } + else if (ctrl_int() && !BIT(m_data & m_ctrl, DATA_TH_BIT)) + { + LOG("%s: PC6 interrupt triggered\n", machine().describe_context()); + m_pc6int = 1; + if (!rrdy_int()) + m_hl_callback(1); + } + } +} + + +void gamegear_io_port_device::s_ctrl_w(u8 data) +{ + bool const rintchanged = set_s_ctrl(data); + if (rintchanged && !m_pc6int) + m_hl_callback(s_ctrl_rint() ? 1 : 0); +} + + +void gamegear_io_port_device::device_start() +{ + megadrive_io_port_device_base::device_start(); + + save_item(NAME(m_pc6int)); +} + + +void gamegear_io_port_device::device_reset() +{ + megadrive_io_port_device_base::device_reset(); + + m_pc6int = 0; +} + + +void gamegear_io_port_device::rcv_complete() +{ + bool const rintchanged = data_received(); + if (rintchanged && !m_pc6int) + m_hl_callback(1); } diff --git a/src/mame/sega/mdioport.h b/src/mame/sega/mdioport.h index b54a843a57f..e63b91fd1bc 100644 --- a/src/mame/sega/mdioport.h +++ b/src/mame/sega/mdioport.h @@ -1,6 +1,6 @@ // license:BSD-3-Clause // copyright-holders:Vas Crabb -/********************************************************************** +/*********************************************************************** Sega Mega Drive I/O Port @@ -13,7 +13,7 @@ Game Gear has one instance of this block connected to the EXT connector. -**********************************************************************/ +***********************************************************************/ #ifndef MAME_SEGA_MDIOPORT_H #define MAME_SEGA_MDIOPORT_H @@ -24,18 +24,12 @@ #include -class megadrive_io_port_device : public device_t, public device_serial_interface +class megadrive_io_port_device_base : public device_t, public device_serial_interface { public: using parallel_in_delegate = device_delegate; using parallel_out_delegate = device_delegate; - megadrive_io_port_device( - machine_config const &mconfig, - char const *tag, - device_t *owner, - u32 clock); - // external signal handler configuration template void set_in_handler(T &&... args) @@ -51,34 +45,15 @@ public: // host output configuration auto hl_handler() { return m_hl_callback.bind(); } - // external signal inputs - DECLARE_WRITE_LINE_MEMBER(th_w); - // host read registers u8 data_r(); - u8 ctrl_r() { return m_ctrl; } - u8 s_ctrl_r(); + u8 s_ctrl_r() { return m_s_ctrl; } u8 txdata_r() { return m_txdata; } - u8 rxdata_r(); // host write registers - void data_w(u8 data); - void ctrl_w(u8 data); - void s_ctrl_w(u8 data); void txdata_w(u8 data); protected: - // device_t implementation - virtual void device_resolve_objects() override ATTR_COLD; - virtual void device_start() override ATTR_COLD; - virtual void device_reset() override ATTR_COLD; - - // device_serial_interface implementation - virtual void tra_callback() override; - virtual void tra_complete() override; - virtual void rcv_complete() override; - -private: enum : unsigned { DATA_UP_BIT = 0, @@ -117,6 +92,22 @@ private: S_CTRL_TFUL_MASK = 0x01 }; + megadrive_io_port_device_base( + machine_config const &mconfig, + device_type type, + char const *tag, + device_t *owner, + u32 clock) ATTR_COLD; + + // device_t implementation + virtual void device_resolve_objects() override ATTR_COLD; + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_serial_interface implementation + virtual void tra_callback() override; + virtual void tra_complete() override; + bool ctrl_int() const { return BIT(m_ctrl, 7); } bool s_ctrl_sin() const { return m_s_ctrl & S_CTRL_SIN_MASK; } @@ -126,10 +117,13 @@ private: bool s_ctrl_rrdy() const { return m_s_ctrl & S_CTRL_RRDY_MASK; } bool s_ctrl_tful() const { return m_s_ctrl & S_CTRL_TFUL_MASK; } - bool th_int() const; bool rrdy_int() const; u8 out_drive() const; void update_out(); + void set_data(u8 data); + void set_ctrl(u8 data); + bool set_s_ctrl(u8 data); + bool data_received(); parallel_in_delegate m_in_callback; parallel_out_delegate m_out_callback; @@ -145,6 +139,71 @@ private: }; +class megadrive_io_port_device : public megadrive_io_port_device_base +{ +public: + megadrive_io_port_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) ATTR_COLD; + + // external signal inputs + DECLARE_WRITE_LINE_MEMBER(th_w); + + // host read registers + u8 ctrl_r() { return m_ctrl; } + u8 rxdata_r(); + + // host write registers + void data_w(u8 data); + void ctrl_w(u8 data); + void s_ctrl_w(u8 data); + +protected: + // device_serial_interface implementation + virtual void rcv_complete() override; + +private: + bool th_int() const; +}; + + +class gamegear_io_port_device : public megadrive_io_port_device_base +{ +public: + gamegear_io_port_device( + machine_config const &mconfig, + char const *tag, + device_t *owner, + u32 clock) ATTR_COLD; + + // external signal inputs + DECLARE_WRITE_LINE_MEMBER(th_w); + + // host read registers + u8 ctrl_r() { return ~m_ctrl; } + u8 rxdata_r(); + + // host write registers + void data_w(u8 data); + void ctrl_w(u8 data); + void s_ctrl_w(u8 data); + +protected: + // device_t implementation + virtual void device_start() override ATTR_COLD; + virtual void device_reset() override ATTR_COLD; + + // device_serial_interface implementation + virtual void rcv_complete() override; + +private: + u8 m_pc6int; +}; + + DECLARE_DEVICE_TYPE(MEGADRIVE_IO_PORT, megadrive_io_port_device) +DECLARE_DEVICE_TYPE(GAMEGEAR_IO_PORT, gamegear_io_port_device) #endif // MAME_SEGA_MDIOPORT_H diff --git a/src/mame/sega/sms.cpp b/src/mame/sega/sms.cpp index 1584e2797c6..01879e0c62f 100644 --- a/src/mame/sega/sms.cpp +++ b/src/mame/sega/sms.cpp @@ -323,14 +323,14 @@ void sms_state::sms_io(address_map &map) } -// It seems the Korean versions do some more strict decoding on the I/O -// addresses. +// 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. void sms_state::smskr_io(address_map &map) { map.global_mask(0xff); map.unmap_value_high(); + map(0x3e, 0x3e).w(FUNC(sms_state::sms_mem_control_w)); map(0x3f, 0x3f).w(FUNC(sms_state::sms_io_control_w)); map(0x40, 0x7f).r(FUNC(sms_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w)); @@ -370,18 +370,28 @@ void gamegear_state::gg_io(address_map &map) map.global_mask(0xff); map.unmap_value_high(); - map(0x00, 0x00).r(FUNC(gamegear_state::gg_input_port_00_r)); - map(0x01, 0x05).rw(FUNC(gamegear_state::gg_sio_r), FUNC(gamegear_state::gg_sio_w)); - map(0x06, 0x06).w(FUNC(gamegear_state::gg_psg_stereo_w)); - map(0x3e, 0x3e).w(FUNC(gamegear_state::sms_mem_control_w)); - map(0x3f, 0x3f).w(FUNC(gamegear_state::sms_io_control_w)); + map(0x3e, 0x3e).w(FUNC(gamegear_state::sms_mem_control_w)); // TODO: only really exists in Master System mode map(0x40, 0x7f).r(FUNC(gamegear_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w)); map(0x80, 0x80).mirror(0x3e).rw(m_vdp, FUNC(sega315_5124_device::data_read), FUNC(sega315_5124_device::data_write)); map(0x81, 0x81).mirror(0x3e).rw(m_vdp, FUNC(sega315_5124_device::control_read), FUNC(sega315_5124_device::control_write)); - map(0xc0, 0xc0).r(FUNC(gamegear_state::sms_input_port_dc_r)); - map(0xc1, 0xc1).r(FUNC(gamegear_state::sms_input_port_dd_r)); - map(0xdc, 0xdc).r(FUNC(gamegear_state::sms_input_port_dc_r)); - map(0xdd, 0xdd).r(FUNC(gamegear_state::sms_input_port_dd_r)); + map(0xc0, 0xc0).r(FUNC(gamegear_state::gg_input_port_dc_r)); + map(0xc1, 0xc1).r(FUNC(gamegear_state::gg_input_port_dd_r)); + map(0xdc, 0xdc).r(FUNC(gamegear_state::gg_input_port_dc_r)); + map(0xdd, 0xdd).r(FUNC(gamegear_state::gg_input_port_dd_r)); + + map(0x00, 0x3f).view(m_io_view); + + // Game Gear mode + m_io_view[0](0x00, 0x00).r(FUNC(gamegear_state::gg_input_port_00_r)); + m_io_view[0](0x01, 0x01).rw(m_gg_ioport, FUNC(gamegear_io_port_device::data_r), FUNC(gamegear_io_port_device::data_w)); + m_io_view[0](0x02, 0x02).rw(m_gg_ioport, FUNC(gamegear_io_port_device::ctrl_r), FUNC(gamegear_io_port_device::ctrl_w)); + m_io_view[0](0x03, 0x03).rw(m_gg_ioport, FUNC(gamegear_io_port_device::txdata_r), FUNC(gamegear_io_port_device::txdata_w)); + m_io_view[0](0x04, 0x04).r(m_gg_ioport, FUNC(gamegear_io_port_device::rxdata_r)); + m_io_view[0](0x05, 0x05).rw(m_gg_ioport, FUNC(gamegear_io_port_device::s_ctrl_r), FUNC(gamegear_io_port_device::s_ctrl_w)); + m_io_view[0](0x06, 0x06).w(m_vdp, FUNC(sega315_5124_device::psg_stereo_w)); + + // Master System mode + m_io_view[1](0x3f, 0x3f).w(FUNC(gamegear_state::gg_io_control_w)); } @@ -982,9 +992,14 @@ void gamegear_state::gamegear(machine_config &config) SOFTWARE_LIST(config, "cart_list").set_original("gamegear"); - GG_EXT_PORT(config, m_port_gg_ext, gg_ext_port_devices, nullptr); - m_port_gg_ext->set_screen_tag(m_main_scr); - m_port_gg_ext->th_input_handler().set(FUNC(gamegear_state::gg_ext_th_input)); + GAMEGEAR_IO_PORT(config, m_gg_ioport, 0); + m_gg_ioport->set_in_handler(m_port_gg_ext, FUNC(sms_control_port_device::in_r)); + m_gg_ioport->set_out_handler(m_port_gg_ext, FUNC(sms_control_port_device::out_w)); + m_gg_ioport->hl_handler().set(FUNC(gamegear_state::gg_nmi)); + + SMS_CONTROL_PORT(config, m_port_gg_ext, sms_control_port_devices, nullptr); + m_port_gg_ext->set_screen(m_main_scr); + m_port_gg_ext->th_handler().set(FUNC(gamegear_state::gg_ext_th_input)); m_is_gamegear = true; m_has_bios_0400 = true; diff --git a/src/mame/sega/sms.h b/src/mame/sega/sms.h index 59834cfab00..7e4875ffe02 100644 --- a/src/mame/sega/sms.h +++ b/src/mame/sega/sms.h @@ -10,7 +10,8 @@ #pragma once -#include "bus/gamegear/ggext.h" +#include "mdioport.h" + #include "bus/sega8/sega8_slot.h" #include "bus/sg1000_exp/sg1000exp.h" #include "bus/sms_ctrl/smsctrl.h" @@ -37,8 +38,6 @@ public: m_ym(*this, "ym2413"), m_port_ctrl1(*this, "ctrl1"), m_port_ctrl2(*this, "ctrl2"), - m_port_gg_ext(*this, "ext"), - m_port_gg_dc(*this, "GG_PORT_DC"), m_port_pause(*this, "PAUSE"), m_port_reset(*this, "RESET"), m_port_rapid(*this, "RAPID"), @@ -124,9 +123,7 @@ protected: optional_device m_ym; optional_device m_port_ctrl1; optional_device m_port_ctrl2; - optional_device m_port_gg_ext; - optional_ioport m_port_gg_dc; optional_ioport m_port_pause; optional_ioport m_port_reset; optional_ioport m_port_rapid; @@ -302,7 +299,11 @@ class gamegear_state : public sms_state { public: gamegear_state(const machine_config &mconfig, device_type type, const char *tag) : - sms_state(mconfig, type, tag) + sms_state(mconfig, type, tag), + m_io_view(*this, "io"), + m_gg_ioport(*this, "ioport"), + m_port_gg_ext(*this, "ext"), + m_port_gg_dc(*this, "GG_PORT_DC") { } void gamegear(machine_config &config); @@ -318,18 +319,26 @@ private: template static void screen_gg_raw_params(screen_device &screen, X &&pixelclock); uint8_t gg_input_port_00_r(); - uint8_t gg_sio_r(offs_t offset); - void gg_sio_w(offs_t offset, uint8_t data); - void gg_psg_stereo_w(uint8_t data); + uint8_t gg_input_port_dc_r(); + uint8_t gg_input_port_dd_r(); + void gg_io_control_w(uint8_t data); DECLARE_WRITE_LINE_MEMBER(gg_pause_callback); DECLARE_WRITE_LINE_MEMBER(gg_ext_th_input); + DECLARE_WRITE_LINE_MEMBER(gg_nmi); uint32_t screen_update_gamegear(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void screen_gg_sms_mode_scaling(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect); void gg_io(address_map &map); + memory_view m_io_view; + + required_device m_gg_ioport; + required_device m_port_gg_ext; + + required_ioport m_port_gg_dc; + // for gamegear SMS mode scaling bitmap_rgb32 m_gg_sms_mode_bitmap; @@ -337,7 +346,6 @@ private: // vertical scaling in the Game Gear SMS compatibility mode. std::unique_ptr m_line_buffer; - uint8_t m_gg_sio[5]{}; int m_gg_paused = 0; }; diff --git a/src/mame/sega/sms_m.cpp b/src/mame/sega/sms_m.cpp index 254a79af9d9..293c4a66ed2 100644 --- a/src/mame/sega/sms_m.cpp +++ b/src/mame/sega/sms_m.cpp @@ -70,46 +70,29 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input) WRITE_LINE_MEMBER(gamegear_state::gg_ext_th_input) { - if (!(m_cartslot->exists() && m_cartslot->get_sms_mode())) - return; + m_gg_ioport->th_w(state); - // The EXT port act as the controller port 2 on SMS compatibility mode. - sms_ctrl2_th_input(state); + // TODO: verify behaviour in SMS mode + if (m_cartslot->exists() && m_cartslot->get_sms_mode()) + sms_ctrl2_th_input(state); } -void sms_state::sms_get_inputs() +WRITE_LINE_MEMBER(gamegear_state::gg_nmi) { - uint8_t data2 = 0xff; + if (!(m_cartslot->exists() && m_cartslot->get_sms_mode())) + m_maincpu->set_input_line(INPUT_LINE_NMI, state); +} + +void sms_state::sms_get_inputs() +{ 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. + m_port_dc_reg &= ~0x3f | m_port_ctrl1->in_r(); // Up, Down, Left, Right, TL, TR - if (m_is_gamegear) - { - // FIXME: make the Game Gear EXT port sane - it's more like a Mega Drive port - - // For Game Gear, this function is used only if SMS mode is - // enabled, else only register $dc receives input data, through - // direct read of the m_port_gg_dc I/O port. - - uint8_t data1 = m_port_gg_dc->read(); - m_port_dc_reg &= ~0x03f | data1; - - data2 = m_port_gg_ext->port_r(); - m_ctrl2_th_state = BIT(data2, 6); - data2 = bitswap<6>(data2, 7, 5, 3, 2, 1, 0); - } - else - { - m_port_dc_reg &= ~0x3f | m_port_ctrl1->in_r(); // Up, Down, Left, Right, TL, TR - - data2 = m_port_ctrl2->in_r(); - } + uint8_t const data2 = m_port_ctrl2->in_r(); m_port_dc_reg &= ~0xc0 | (data2 << 6); // Up, Down m_port_dd_reg &= ~0x0f | (data2 >> 2); // Left, Right, TL, TR @@ -122,62 +105,33 @@ void sms_state::sms_io_control_w(uint8_t data) { bool latch_hcount = false; - if (m_is_gamegear && !(m_cartslot->exists() && m_cartslot->get_sms_mode())) - { - m_io_ctrl_reg = data; - return; - } - // Controller Port 1: // check if TR or TH are set to output (0). - if (!m_is_gamegear && ((data & 0x33) != (m_io_ctrl_reg & 0x33))) + if ((data & 0x33) != (m_io_ctrl_reg & 0x33)) { m_port_ctrl1->out_w(((BIT(data, 4, 2) | BIT(data, 0, 2)) << 5) | 0x1f, BIT(~data, 0, 2) << 5); } // check if TH input level is high (1) and was output/low (0) - if ((data & 0x02) && !(m_io_ctrl_reg & 0x22)) - { - if (m_is_gamegear || m_ctrl1_th_state) - latch_hcount = true; - } + if ((data & 0x02) && !(m_io_ctrl_reg & 0x22) && m_ctrl1_th_state) + latch_hcount = true; // Controller Port 2: // check if TR or TH are set to output (0). - if (m_is_gamegear) - { - if ((data & 0x0c) != 0x0c) - { - uint8_t ctrl2_port_data = 0xff; - if (!(data & 0x04)) // TR set to output - { - ctrl2_port_data &= ~0x80 | (data << 1); - } - if (!(data & 0x08)) // TH set to output - { - ctrl2_port_data &= ~0x40 | (data >> 1); - } - m_port_gg_ext->port_w(ctrl2_port_data); - } - } - else if ((data & 0xcc) != (m_io_ctrl_reg & 0xcc)) + if ((data & 0xcc) != (m_io_ctrl_reg & 0xcc)) { m_port_ctrl2->out_w(((BIT(data, 6, 2) | BIT(data, 2, 2)) << 5) | 0x1f, BIT(~data, 2, 2) << 5); } // check if TH input level is high (1) and was output/low (0) - if ((data & 0x08) && !(m_io_ctrl_reg & 0x88)) - { - if (m_is_gamegear ? BIT(m_port_gg_ext->port_r(), 6) : m_ctrl2_th_state) - latch_hcount = true; - } + if ((data & 0x08) && !(m_io_ctrl_reg & 0x88) && m_ctrl2_th_state) + latch_hcount = true; if (latch_hcount) - { m_vdp->hcount_latch(); - } + m_io_ctrl_reg = data; } @@ -290,20 +244,10 @@ WRITE_LINE_MEMBER(sms_state::rapid_n_csync_callback) uint8_t sms_state::sms_input_port_dc_r() { - if (m_is_gamegear) - { - // If SMS mode is disabled, just return the data read from the - // input port. Its mapped port bits match the bits of register $dc. - if (!(m_cartslot->exists() && m_cartslot->get_sms_mode())) - return m_port_gg_dc->read(); - } - else - { - // Return if the I/O chip is disabled (1). This check isn't performed - // for the Game Gear because has no effect on it, even in SMS mode. - if (m_mem_ctrl_reg & IO_CHIP) - return 0xff; - } + // Return if the I/O chip is disabled (1). This check isn't performed + // for the Game Gear because has no effect on it, even in SMS mode. + if (m_mem_ctrl_reg & IO_CHIP) + return 0xff; sms_get_inputs(); @@ -331,18 +275,10 @@ uint8_t sms_state::sms_input_port_dc_r() uint8_t sms_state::sms_input_port_dd_r() { - if (m_is_gamegear) - { - if (!(m_cartslot->exists() && m_cartslot->get_sms_mode())) - return 0xff; - } - else - { - // Return if the I/O chip is disabled (1). This check isn't performed - // for the Game Gear because has no effect on it, even in SMS mode. - if (m_mem_ctrl_reg & IO_CHIP) - return 0xff; - } + // Return if the I/O chip is disabled (1). This check isn't performed + // for the Game Gear because has no effect on it, even in SMS mode. + if (m_mem_ctrl_reg & IO_CHIP) + return 0xff; sms_get_inputs(); @@ -486,32 +422,77 @@ void sms_state::smsj_ym2413_data_port_w(uint8_t data) } -void gamegear_state::gg_psg_stereo_w(uint8_t data) +void gamegear_state::gg_io_control_w(uint8_t data) { - if (m_cartslot->exists() && m_cartslot->get_sms_mode()) - return; + // Only used in SMS mode + // TODO: confirm behaviour + + m_gg_ioport->data_w(0x9f | (BIT(data, 6, 2) << 5)); + m_gg_ioport->ctrl_w(0x9f | (BIT(data, 2, 2) << 5)); + + bool const latch_hcount1 = (data & 0x02) && !(m_io_ctrl_reg & 0x22); + bool const latch_hcount2 = (data & 0x08) && !(m_io_ctrl_reg & 0x88) && m_ctrl2_th_state; - m_vdp->psg_stereo_w(data); + if (latch_hcount1 || latch_hcount2) + m_vdp->hcount_latch(); + + m_io_ctrl_reg = data; } uint8_t gamegear_state::gg_input_port_00_r() { + // bit 6 is NJAP (0=domestic/1=overseas); bit 7 is STT (START button) + uint8_t data = (m_ioctrl_region_is_japan ? 0x00 : 0x40) | (m_port_start->read() & 0x80); + + // According to GG official docs, bits 0-4 are meaningless and bit 5 + // is NNTS (0=NTSC, 1=PAL). All games run in NTSC and no original GG + // allows the user to change that mode, but there are NTSC and PAL + // versions of the TV Tuner. + + //logerror("port $00 read, val: %02x, pc: %04x\n", data, activecpu_get_pc()); + return data; +} + + +uint8_t gamegear_state::gg_input_port_dc_r() +{ + // TODO: does setting TL/TR to output in SMS mode affect this? + return (m_port_gg_dc->read() & 0x3f) | (m_gg_ioport->data_r() << 6); +} + + +uint8_t gamegear_state::gg_input_port_dd_r() +{ + uint8_t const ext = m_gg_ioport->data_r(); + uint8_t result = 0x70 | ((ext >> 2) & 0x0f) | (BIT(ext, 6) << 7); + if (m_cartslot->exists() && m_cartslot->get_sms_mode()) - return 0xff; - else { - // bit 6 is NJAP (0=domestic/1=overseas); bit 7 is STT (START button) - uint8_t data = (m_ioctrl_region_is_japan ? 0x00 : 0x40) | (m_port_start->read() & 0x80); + // TODO: confirm behaviour in SMS mode - // According to GG official docs, bits 0-4 are meaningless and bit 5 - // is NNTS (0=NTSC, 1=PAL). All games run in NTSC and no original GG - // allows the user to change that mode, but there are NTSC and PAL - // versions of the TV Tuner. + if (!(m_io_ctrl_reg & 0x02)) + { + result &= ~0x40; + if (!m_ioctrl_region_is_japan) + result |= BIT(m_io_ctrl_reg, 5) << 6; + } - //logerror("port $00 read, val: %02x, pc: %04x\n", data, activecpu_get_pc()); - return data; + if (!(m_io_ctrl_reg & 0x08)) + { + if (m_ioctrl_region_is_japan) + result &= ~0x80; + } + else if (m_ctrl2_th_latch) + { + if (m_vdp->hcount_latched()) + result &= ~0x80; + + m_ctrl2_th_latch = 0; + } } + + return result; } @@ -779,63 +760,6 @@ void sg1000m3_state::sg1000m3_peripheral_w(offs_t offset, uint8_t data) } -void gamegear_state::gg_sio_w(offs_t offset, uint8_t data) -{ - if (m_cartslot->exists() && m_cartslot->get_sms_mode()) - return; - - logerror("*** write %02X to SIO register #%d\n", data, offset); - - m_gg_sio[offset & 0x07] = data; - switch (offset & 7) - { - case 0x00: /* Parallel Data */ - break; - - case 0x01: /* Data Direction / NMI Enable */ - break; - - case 0x02: /* Serial Output */ - break; - - case 0x03: /* Serial Input */ - break; - - case 0x04: /* Serial Control / Status */ - break; - } -} - - -uint8_t gamegear_state::gg_sio_r(offs_t offset) -{ - if (m_cartslot->exists() && m_cartslot->get_sms_mode()) - return 0xff; - - logerror("*** read SIO register #%d\n", offset); - - switch (offset & 7) - { - case 0x00: /* Parallel Data */ - break; - - case 0x01: /* Data Direction / NMI Enable */ - break; - - case 0x02: /* Serial Output */ - break; - - case 0x03: /* Serial Input */ - break; - - case 0x04: /* Serial Control / Status */ - break; - } - - return m_gg_sio[offset]; -} - - void sms_state::setup_enabled_slots() { m_mem_device_enabled = ENABLE_NONE; @@ -1051,7 +975,6 @@ void gamegear_state::machine_start() sms_state::machine_start(); save_item(NAME(m_gg_paused)); - save_item(NAME(m_gg_sio)); // The game Ecco requires SP to be initialized, so, to run on a BIOS-less Game // Gear, probably a custom chip like the 315-5378 does the initialization, as @@ -1110,15 +1033,16 @@ void sg1000m3_state::machine_reset() void gamegear_state::machine_reset() { + // TODO: default with SMS mode pin floating is SMS compatibility mode if (m_cartslot->exists() && m_cartslot->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_io_view.select(1); + } + else + { + m_io_view.select(0); + } sms_state::machine_reset(); } -- cgit v1.2.3