mirror of
https://github.com/holub/mame
synced 2025-06-29 23:48:56 +03:00
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:
parent
9a8cac8d1e
commit
01c5fe81f1
@ -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
|
||||
|
@ -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);
|
||||
}
|
@ -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
|
@ -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));
|
||||
}
|
||||
|
@ -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
|
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
};
|
||||
|
||||
|
@ -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();
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user