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.
This commit is contained in:
Vas Crabb 2022-12-14 19:26:21 +11:00 committed by GitHub
parent 9a8cac8d1e
commit 01c5fe81f1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 552 additions and 775 deletions

View File

@ -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

View File

@ -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<gg_ext_port_device *>(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<device_gg_ext_port_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);
}

View File

@ -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<device_gg_ext_port_interface>
{
public:
// construction/destruction
template <typename T>
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 <typename T> void set_screen_tag(T &&tag) { m_screen.set_tag(std::forward<T>(tag)); }
// for peripherals that interact with the machine's screen
required_device<screen_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

View File

@ -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));
}

View File

@ -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<sms_control_port_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

View File

@ -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

View File

@ -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);
}

View File

@ -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 <utility>
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<u8 ()>;
using parallel_out_delegate = device_delegate<void (u8 data, u8 mem_mask)>;
megadrive_io_port_device(
machine_config const &mconfig,
char const *tag,
device_t *owner,
u32 clock);
// external signal handler configuration
template <typename... T>
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

View File

@ -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;

View File

@ -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<ym2413_device> m_ym;
optional_device<sms_control_port_device> m_port_ctrl1;
optional_device<sms_control_port_device> m_port_ctrl2;
optional_device<gg_ext_port_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 <typename X> 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<gamegear_io_port_device> m_gg_ioport;
required_device<sms_control_port_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<int []> m_line_buffer;
uint8_t m_gg_sio[5]{};
int m_gg_paused = 0;
};

View File

@ -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);
}
WRITE_LINE_MEMBER(gamegear_state::gg_nmi)
{
if (!(m_cartslot->exists() && m_cartslot->get_sms_mode()))
m_maincpu->set_input_line(INPUT_LINE_NMI, state);
}
void sms_state::sms_get_inputs()
{
uint8_t data2 = 0xff;
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_vdp->psg_stereo_w(data);
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;
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();
}