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
|
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
|
--@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 -
|
10 NC -
|
||||||
|
|
||||||
DE-9 connector on most systems, or 10-pin tongue connector on
|
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:
|
SG-1000 Mark III:
|
||||||
* Pin 7 (TH) tied to ground
|
* Pin 7 (TH) tied to ground
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
// license:BSD-3-Clause
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Vas Crabb
|
// copyright-holders:Vas Crabb
|
||||||
/**********************************************************************8
|
/***********************************************************************
|
||||||
|
|
||||||
Sega Mega Drive I/O Port
|
Sega Mega Drive I/O Port
|
||||||
|
|
||||||
@ -10,10 +10,7 @@
|
|||||||
* Serial reception - requires peripherals to be reworked.
|
* Serial reception - requires peripherals to be reworked.
|
||||||
* Is the transmit data register separate from the transmit shift
|
* Is the transmit data register separate from the transmit shift
|
||||||
register?
|
register?
|
||||||
* What sets the serial receive error? Framing error, overrun,
|
* Does receive overrun set the receive error bit?
|
||||||
or both?
|
|
||||||
* Can receive errors cause interrupts when the receive buffer
|
|
||||||
isn't ready?
|
|
||||||
|
|
||||||
***********************************************************************/
|
***********************************************************************/
|
||||||
|
|
||||||
@ -27,15 +24,27 @@
|
|||||||
#include "logmacro.h"
|
#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(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,
|
machine_config const &mconfig,
|
||||||
|
device_type type,
|
||||||
char const *tag,
|
char const *tag,
|
||||||
device_t *owner,
|
device_t *owner,
|
||||||
u32 clock) :
|
u32 clock) :
|
||||||
device_t(mconfig, MEGADRIVE_IO_PORT, tag, owner, clock),
|
device_t(mconfig, type, tag, owner, clock),
|
||||||
device_serial_interface(mconfig, *this),
|
device_serial_interface(mconfig, *this),
|
||||||
m_in_callback(*this),
|
m_in_callback(*this),
|
||||||
m_out_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 megadrive_io_port_device_base::data_r()
|
||||||
{
|
|
||||||
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()
|
|
||||||
{
|
{
|
||||||
// TODO: confirm what's read from pins set to input and configured for serial I/O
|
// TODO: confirm what's read from pins set to input and configured for serial I/O
|
||||||
u8 const serialmask =
|
u8 const serialmask =
|
||||||
@ -85,117 +77,7 @@ u8 megadrive_io_port_device::data_r()
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
u8 megadrive_io_port_device::s_ctrl_r()
|
void megadrive_io_port_device_base::txdata_w(u8 data)
|
||||||
{
|
|
||||||
// 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)
|
|
||||||
{
|
{
|
||||||
if (s_ctrl_tful())
|
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;
|
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_txd));
|
||||||
save_item(NAME(m_th_in));
|
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
|
// TODO: proper reset state for DATA, TxDATA and RxDATA
|
||||||
m_txd = DATA_TXD_MASK;
|
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;
|
u8 const txd = transmit_register_get_data_bit() ? DATA_TXD_MASK : 0x00;
|
||||||
if (txd != m_txd)
|
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())
|
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();
|
receive_register_extract();
|
||||||
u8 const data = get_received_char();
|
u8 const data = get_received_char();
|
||||||
bool const hlupdate =
|
bool const rintchanged = s_ctrl_rint() && !s_ctrl_rrdy();
|
||||||
s_ctrl_rint() &&
|
|
||||||
!s_ctrl_rerr() &&
|
|
||||||
!s_ctrl_rrdy() &&
|
|
||||||
!th_int();
|
|
||||||
|
|
||||||
if (s_ctrl_rrdy())
|
if (s_ctrl_rrdy())
|
||||||
{
|
{
|
||||||
@ -316,7 +286,6 @@ void megadrive_io_port_device::rcv_complete()
|
|||||||
}
|
}
|
||||||
else if (is_receive_framing_error())
|
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);
|
LOG("received byte 0x%02X, framing error\n", data);
|
||||||
m_s_ctrl |= S_CTRL_RERR_MASK | S_CTRL_RRDY_MASK;
|
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;
|
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)
|
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);
|
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
|
u8 const th = state ? DATA_TH_MASK : 0x00;
|
||||||
(m_ctrl & (s_ctrl_sin() ? 0x5f : 0x7f)) |
|
if (th != m_th_in)
|
||||||
(s_ctrl_sout() ? DATA_TXD_MASK : 0x00);
|
{
|
||||||
|
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();
|
return m_rxdata;
|
||||||
u8 const data = (m_data | ~drive) & (s_ctrl_sout() ? 0x6f : 0x7f);
|
}
|
||||||
m_out_callback(data | (s_ctrl_sout() ? m_txd : 0x00), drive);
|
|
||||||
|
|
||||||
|
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
|
// license:BSD-3-Clause
|
||||||
// copyright-holders:Vas Crabb
|
// copyright-holders:Vas Crabb
|
||||||
/**********************************************************************
|
/***********************************************************************
|
||||||
|
|
||||||
Sega Mega Drive I/O Port
|
Sega Mega Drive I/O Port
|
||||||
|
|
||||||
@ -13,7 +13,7 @@
|
|||||||
Game Gear has one instance of this block connected to the EXT
|
Game Gear has one instance of this block connected to the EXT
|
||||||
connector.
|
connector.
|
||||||
|
|
||||||
**********************************************************************/
|
***********************************************************************/
|
||||||
#ifndef MAME_SEGA_MDIOPORT_H
|
#ifndef MAME_SEGA_MDIOPORT_H
|
||||||
#define MAME_SEGA_MDIOPORT_H
|
#define MAME_SEGA_MDIOPORT_H
|
||||||
|
|
||||||
@ -24,18 +24,12 @@
|
|||||||
#include <utility>
|
#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:
|
public:
|
||||||
using parallel_in_delegate = device_delegate<u8 ()>;
|
using parallel_in_delegate = device_delegate<u8 ()>;
|
||||||
using parallel_out_delegate = device_delegate<void (u8 data, u8 mem_mask)>;
|
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
|
// external signal handler configuration
|
||||||
template <typename... T>
|
template <typename... T>
|
||||||
void set_in_handler(T &&... args)
|
void set_in_handler(T &&... args)
|
||||||
@ -51,34 +45,15 @@ public:
|
|||||||
// host output configuration
|
// host output configuration
|
||||||
auto hl_handler() { return m_hl_callback.bind(); }
|
auto hl_handler() { return m_hl_callback.bind(); }
|
||||||
|
|
||||||
// external signal inputs
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(th_w);
|
|
||||||
|
|
||||||
// host read registers
|
// host read registers
|
||||||
u8 data_r();
|
u8 data_r();
|
||||||
u8 ctrl_r() { return m_ctrl; }
|
u8 s_ctrl_r() { return m_s_ctrl; }
|
||||||
u8 s_ctrl_r();
|
|
||||||
u8 txdata_r() { return m_txdata; }
|
u8 txdata_r() { return m_txdata; }
|
||||||
u8 rxdata_r();
|
|
||||||
|
|
||||||
// host write registers
|
// host write registers
|
||||||
void data_w(u8 data);
|
|
||||||
void ctrl_w(u8 data);
|
|
||||||
void s_ctrl_w(u8 data);
|
|
||||||
void txdata_w(u8 data);
|
void txdata_w(u8 data);
|
||||||
|
|
||||||
protected:
|
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
|
enum : unsigned
|
||||||
{
|
{
|
||||||
DATA_UP_BIT = 0,
|
DATA_UP_BIT = 0,
|
||||||
@ -117,6 +92,22 @@ private:
|
|||||||
S_CTRL_TFUL_MASK = 0x01
|
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 ctrl_int() const { return BIT(m_ctrl, 7); }
|
||||||
|
|
||||||
bool s_ctrl_sin() const { return m_s_ctrl & S_CTRL_SIN_MASK; }
|
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_rrdy() const { return m_s_ctrl & S_CTRL_RRDY_MASK; }
|
||||||
bool s_ctrl_tful() const { return m_s_ctrl & S_CTRL_TFUL_MASK; }
|
bool s_ctrl_tful() const { return m_s_ctrl & S_CTRL_TFUL_MASK; }
|
||||||
|
|
||||||
bool th_int() const;
|
|
||||||
bool rrdy_int() const;
|
bool rrdy_int() const;
|
||||||
u8 out_drive() const;
|
u8 out_drive() const;
|
||||||
void update_out();
|
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_in_delegate m_in_callback;
|
||||||
parallel_out_delegate m_out_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(MEGADRIVE_IO_PORT, megadrive_io_port_device)
|
||||||
|
DECLARE_DEVICE_TYPE(GAMEGEAR_IO_PORT, gamegear_io_port_device)
|
||||||
|
|
||||||
#endif // MAME_SEGA_MDIOPORT_H
|
#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
|
// It seems the Korean versions do some more strict decoding on the I/O addresses.
|
||||||
// addresses.
|
|
||||||
// At least the mirrors for I/O ports $3E/$3F don't seem to exist there.
|
// At least the mirrors for I/O ports $3E/$3F don't seem to exist there.
|
||||||
// Leaving the mirrors breaks the Korean cartridge bublboky.
|
// Leaving the mirrors breaks the Korean cartridge bublboky.
|
||||||
void sms_state::smskr_io(address_map &map)
|
void sms_state::smskr_io(address_map &map)
|
||||||
{
|
{
|
||||||
map.global_mask(0xff);
|
map.global_mask(0xff);
|
||||||
map.unmap_value_high();
|
map.unmap_value_high();
|
||||||
|
|
||||||
map(0x3e, 0x3e).w(FUNC(sms_state::sms_mem_control_w));
|
map(0x3e, 0x3e).w(FUNC(sms_state::sms_mem_control_w));
|
||||||
map(0x3f, 0x3f).w(FUNC(sms_state::sms_io_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));
|
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.global_mask(0xff);
|
||||||
map.unmap_value_high();
|
map.unmap_value_high();
|
||||||
|
|
||||||
map(0x00, 0x00).r(FUNC(gamegear_state::gg_input_port_00_r));
|
map(0x3e, 0x3e).w(FUNC(gamegear_state::sms_mem_control_w)); // TODO: only really exists in Master System mode
|
||||||
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(0x40, 0x7f).r(FUNC(gamegear_state::sms_count_r)).w(m_vdp, FUNC(sega315_5124_device::psg_w));
|
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(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(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(0xc0, 0xc0).r(FUNC(gamegear_state::gg_input_port_dc_r));
|
||||||
map(0xc1, 0xc1).r(FUNC(gamegear_state::sms_input_port_dd_r));
|
map(0xc1, 0xc1).r(FUNC(gamegear_state::gg_input_port_dd_r));
|
||||||
map(0xdc, 0xdc).r(FUNC(gamegear_state::sms_input_port_dc_r));
|
map(0xdc, 0xdc).r(FUNC(gamegear_state::gg_input_port_dc_r));
|
||||||
map(0xdd, 0xdd).r(FUNC(gamegear_state::sms_input_port_dd_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");
|
SOFTWARE_LIST(config, "cart_list").set_original("gamegear");
|
||||||
|
|
||||||
GG_EXT_PORT(config, m_port_gg_ext, gg_ext_port_devices, nullptr);
|
GAMEGEAR_IO_PORT(config, m_gg_ioport, 0);
|
||||||
m_port_gg_ext->set_screen_tag(m_main_scr);
|
m_gg_ioport->set_in_handler(m_port_gg_ext, FUNC(sms_control_port_device::in_r));
|
||||||
m_port_gg_ext->th_input_handler().set(FUNC(gamegear_state::gg_ext_th_input));
|
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_is_gamegear = true;
|
||||||
m_has_bios_0400 = true;
|
m_has_bios_0400 = true;
|
||||||
|
@ -10,7 +10,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "bus/gamegear/ggext.h"
|
#include "mdioport.h"
|
||||||
|
|
||||||
#include "bus/sega8/sega8_slot.h"
|
#include "bus/sega8/sega8_slot.h"
|
||||||
#include "bus/sg1000_exp/sg1000exp.h"
|
#include "bus/sg1000_exp/sg1000exp.h"
|
||||||
#include "bus/sms_ctrl/smsctrl.h"
|
#include "bus/sms_ctrl/smsctrl.h"
|
||||||
@ -37,8 +38,6 @@ public:
|
|||||||
m_ym(*this, "ym2413"),
|
m_ym(*this, "ym2413"),
|
||||||
m_port_ctrl1(*this, "ctrl1"),
|
m_port_ctrl1(*this, "ctrl1"),
|
||||||
m_port_ctrl2(*this, "ctrl2"),
|
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_pause(*this, "PAUSE"),
|
||||||
m_port_reset(*this, "RESET"),
|
m_port_reset(*this, "RESET"),
|
||||||
m_port_rapid(*this, "RAPID"),
|
m_port_rapid(*this, "RAPID"),
|
||||||
@ -124,9 +123,7 @@ protected:
|
|||||||
optional_device<ym2413_device> m_ym;
|
optional_device<ym2413_device> m_ym;
|
||||||
optional_device<sms_control_port_device> m_port_ctrl1;
|
optional_device<sms_control_port_device> m_port_ctrl1;
|
||||||
optional_device<sms_control_port_device> m_port_ctrl2;
|
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_pause;
|
||||||
optional_ioport m_port_reset;
|
optional_ioport m_port_reset;
|
||||||
optional_ioport m_port_rapid;
|
optional_ioport m_port_rapid;
|
||||||
@ -302,7 +299,11 @@ class gamegear_state : public sms_state
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
gamegear_state(const machine_config &mconfig, device_type type, const char *tag) :
|
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);
|
void gamegear(machine_config &config);
|
||||||
@ -318,18 +319,26 @@ private:
|
|||||||
template <typename X> static void screen_gg_raw_params(screen_device &screen, X &&pixelclock);
|
template <typename X> static void screen_gg_raw_params(screen_device &screen, X &&pixelclock);
|
||||||
|
|
||||||
uint8_t gg_input_port_00_r();
|
uint8_t gg_input_port_00_r();
|
||||||
uint8_t gg_sio_r(offs_t offset);
|
uint8_t gg_input_port_dc_r();
|
||||||
void gg_sio_w(offs_t offset, uint8_t data);
|
uint8_t gg_input_port_dd_r();
|
||||||
void gg_psg_stereo_w(uint8_t data);
|
void gg_io_control_w(uint8_t data);
|
||||||
|
|
||||||
DECLARE_WRITE_LINE_MEMBER(gg_pause_callback);
|
DECLARE_WRITE_LINE_MEMBER(gg_pause_callback);
|
||||||
DECLARE_WRITE_LINE_MEMBER(gg_ext_th_input);
|
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);
|
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 screen_gg_sms_mode_scaling(screen_device &screen, bitmap_rgb32 &bitmap, const rectangle &cliprect);
|
||||||
|
|
||||||
void gg_io(address_map &map);
|
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
|
// for gamegear SMS mode scaling
|
||||||
bitmap_rgb32 m_gg_sms_mode_bitmap;
|
bitmap_rgb32 m_gg_sms_mode_bitmap;
|
||||||
|
|
||||||
@ -337,7 +346,6 @@ private:
|
|||||||
// vertical scaling in the Game Gear SMS compatibility mode.
|
// vertical scaling in the Game Gear SMS compatibility mode.
|
||||||
std::unique_ptr<int []> m_line_buffer;
|
std::unique_ptr<int []> m_line_buffer;
|
||||||
|
|
||||||
uint8_t m_gg_sio[5]{};
|
|
||||||
int m_gg_paused = 0;
|
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)
|
WRITE_LINE_MEMBER(gamegear_state::gg_ext_th_input)
|
||||||
{
|
{
|
||||||
if (!(m_cartslot->exists() && m_cartslot->get_sms_mode()))
|
m_gg_ioport->th_w(state);
|
||||||
return;
|
|
||||||
|
|
||||||
// The EXT port act as the controller port 2 on SMS compatibility mode.
|
// TODO: verify behaviour in SMS mode
|
||||||
sms_ctrl2_th_input(state);
|
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()
|
void sms_state::sms_get_inputs()
|
||||||
{
|
{
|
||||||
uint8_t data2 = 0xff;
|
|
||||||
|
|
||||||
m_port_dc_reg = 0xff;
|
m_port_dc_reg = 0xff;
|
||||||
m_port_dd_reg = 0xff;
|
m_port_dd_reg = 0xff;
|
||||||
|
|
||||||
// The bit order of the emulated controller port tries to follow its
|
m_port_dc_reg &= ~0x3f | m_port_ctrl1->in_r(); // Up, Down, Left, Right, TL, TR
|
||||||
// physical pins numbering. For register bits whose order differs,
|
|
||||||
// it's necessary move the equivalent controller bits to match.
|
|
||||||
|
|
||||||
if (m_is_gamegear)
|
uint8_t const data2 = m_port_ctrl2->in_r();
|
||||||
{
|
|
||||||
// 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();
|
|
||||||
}
|
|
||||||
|
|
||||||
m_port_dc_reg &= ~0xc0 | (data2 << 6); // Up, Down
|
m_port_dc_reg &= ~0xc0 | (data2 << 6); // Up, Down
|
||||||
m_port_dd_reg &= ~0x0f | (data2 >> 2); // Left, Right, TL, TR
|
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;
|
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:
|
// Controller Port 1:
|
||||||
|
|
||||||
// check if TR or TH are set to output (0).
|
// 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);
|
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)
|
// check if TH input level is high (1) and was output/low (0)
|
||||||
if ((data & 0x02) && !(m_io_ctrl_reg & 0x22))
|
if ((data & 0x02) && !(m_io_ctrl_reg & 0x22) && m_ctrl1_th_state)
|
||||||
{
|
latch_hcount = true;
|
||||||
if (m_is_gamegear || m_ctrl1_th_state)
|
|
||||||
latch_hcount = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Controller Port 2:
|
// Controller Port 2:
|
||||||
|
|
||||||
// check if TR or TH are set to output (0).
|
// check if TR or TH are set to output (0).
|
||||||
if (m_is_gamegear)
|
if ((data & 0xcc) != (m_io_ctrl_reg & 0xcc))
|
||||||
{
|
|
||||||
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))
|
|
||||||
{
|
{
|
||||||
m_port_ctrl2->out_w(((BIT(data, 6, 2) | BIT(data, 2, 2)) << 5) | 0x1f, BIT(~data, 2, 2) << 5);
|
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)
|
// check if TH input level is high (1) and was output/low (0)
|
||||||
if ((data & 0x08) && !(m_io_ctrl_reg & 0x88))
|
if ((data & 0x08) && !(m_io_ctrl_reg & 0x88) && m_ctrl2_th_state)
|
||||||
{
|
latch_hcount = true;
|
||||||
if (m_is_gamegear ? BIT(m_port_gg_ext->port_r(), 6) : m_ctrl2_th_state)
|
|
||||||
latch_hcount = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (latch_hcount)
|
if (latch_hcount)
|
||||||
{
|
|
||||||
m_vdp->hcount_latch();
|
m_vdp->hcount_latch();
|
||||||
}
|
|
||||||
m_io_ctrl_reg = data;
|
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()
|
uint8_t sms_state::sms_input_port_dc_r()
|
||||||
{
|
{
|
||||||
if (m_is_gamegear)
|
// 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 SMS mode is disabled, just return the data read from the
|
if (m_mem_ctrl_reg & IO_CHIP)
|
||||||
// input port. Its mapped port bits match the bits of register $dc.
|
return 0xff;
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
sms_get_inputs();
|
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()
|
uint8_t sms_state::sms_input_port_dd_r()
|
||||||
{
|
{
|
||||||
if (m_is_gamegear)
|
// 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_cartslot->exists() && m_cartslot->get_sms_mode()))
|
if (m_mem_ctrl_reg & IO_CHIP)
|
||||||
return 0xff;
|
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
sms_get_inputs();
|
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())
|
// Only used in SMS mode
|
||||||
return;
|
// 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()
|
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())
|
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)
|
// TODO: confirm behaviour in SMS mode
|
||||||
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
|
if (!(m_io_ctrl_reg & 0x02))
|
||||||
// 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
|
result &= ~0x40;
|
||||||
// versions of the TV Tuner.
|
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());
|
if (!(m_io_ctrl_reg & 0x08))
|
||||||
return data;
|
{
|
||||||
|
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()
|
void sms_state::setup_enabled_slots()
|
||||||
{
|
{
|
||||||
m_mem_device_enabled = ENABLE_NONE;
|
m_mem_device_enabled = ENABLE_NONE;
|
||||||
@ -1051,7 +975,6 @@ void gamegear_state::machine_start()
|
|||||||
sms_state::machine_start();
|
sms_state::machine_start();
|
||||||
|
|
||||||
save_item(NAME(m_gg_paused));
|
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
|
// 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
|
// 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()
|
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())
|
if (m_cartslot->exists() && m_cartslot->get_sms_mode())
|
||||||
|
{
|
||||||
m_vdp->set_sega315_5124_compatibility_mode(true);
|
m_vdp->set_sega315_5124_compatibility_mode(true);
|
||||||
|
m_io_view.select(1);
|
||||||
/* Initialize SIO stuff for GG */
|
}
|
||||||
m_gg_sio[0] = 0x7f;
|
else
|
||||||
m_gg_sio[1] = 0xff;
|
{
|
||||||
m_gg_sio[2] = 0x00;
|
m_io_view.select(0);
|
||||||
m_gg_sio[3] = 0xff;
|
}
|
||||||
m_gg_sio[4] = 0x00;
|
|
||||||
|
|
||||||
sms_state::machine_reset();
|
sms_state::machine_reset();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user