bus/sms_ctrl: Reworked Sega Master System controller bus.

Rationalised interface, got rid of TH from the "pulled" lines, and
extended to support output on all data lines.  Renamed to be less
specific as the same interface is shared by multiple consoles.

Removed a lot of unnecessary indirection through I/O ports and multiple
levels of inversion in peripheral emulation that was obfuscating the
code.

Made Rapid Fire Unit switches toggles so they can be assigned to
controller buttons and switched on/off easily during gameplay.  You can
still see/change the current state in the Toggle Inputs menu if you
don't want to assign buttons.

Implemented idle timeout in Furrtek 4-player Master System adapter.

Improved crosshair tracking in Graphic Board, added ability to
raise/lower pen, and greatly cleaned up code.

Fixed paddle controller when used with export consoles.

Added 3-button and 6-button Mega Drive control devices.

sega/sms.cpp: SG-1000 Mark III has pin 7 of controller ports tied low -
indicate this to attached controllers (this pin became TH on the Master
System).

sega/mdconsole.cpp: Replaced controller emulation in the driver with
Sega controller ports.  Also removed some vestigial code from the driver
base class.

sharp/x68k.cpp: Replaced controller emulation in the driver with MSX
controller ports.

bus/msx/ctrl: Added a Sega controller adapter device, supported by
X68000 software including chelnov and ssf2.
This commit is contained in:
Vas Crabb 2022-12-08 05:09:34 +11:00
parent c7ca12561a
commit dc360abb02
45 changed files with 1754 additions and 2065 deletions

View File

@ -2842,7 +2842,7 @@ license:CC0
</part>
</software>
<!-- Notes: FM support; game uses input code for some unreleased international version of the paddle that must have been in development, glitches heavily on machines that fail Japan region check -->
<!-- Notes: FM support; glitches heavily on machines that fail Japan region check -->
<software name="galactpr">
<description>Galactic Protector (Japan)</description>
<year>1988</year>
@ -3371,8 +3371,8 @@ license:CC0
<year>1987</year>
<publisher>Sega</publisher>
<info name="serial" value="5062 (USA)"/>
<sharedfeat name="ctrl1_default" value="sportspad" />
<sharedfeat name="ctrl2_default" value="sportspad" />
<sharedfeat name="ctrl1_default" value="sports" />
<sharedfeat name="ctrl2_default" value="sports" />
<part name="cart" interface="sms_cart">
<!-- PCB info based on SMS Power (Jpn cart) -->
<feature name="pcb" value="171-5552" />
@ -6615,8 +6615,8 @@ license:CC0
<year>1987</year>
<publisher>Sega</publisher>
<info name="serial" value="5060"/>
<sharedfeat name="ctrl1_default" value="sportspad" />
<sharedfeat name="ctrl2_default" value="sportspad" />
<sharedfeat name="ctrl1_default" value="sports" />
<sharedfeat name="ctrl2_default" value="sports" />
<part name="cart" interface="sms_cart">
<dataarea name="rom" size="131072">
<rom name="sports pad football (usa).bin" size="131072" crc="e42e4998" sha1="556d9ab4ba3c3a34440b36c6fc8e972f70f16d72" offset="000000" />
@ -6643,8 +6643,8 @@ license:CC0
<info name="serial" value="G-1365"/>
<info name="release" value="19881029"/>
<info name="alt_title" value="スポーツパッドサッカー" />
<sharedfeat name="ctrl1_default" value="sportspad" />
<sharedfeat name="ctrl2_default" value="sportspad" />
<sharedfeat name="ctrl1_default" value="sports" />
<sharedfeat name="ctrl2_default" value="sports" />
<part name="cart" interface="sms_cart">
<dataarea name="rom" size="131072">
<rom name="sports pad soccer (japan).bin" size="131072" crc="41c948bf" sha1="7634ce39e87049dad1ee4f32a80d728e4bd1f81f" offset="000000" />

View File

@ -1809,6 +1809,8 @@ if (BUSES["MSX_CTRL"]~=null) then
MAME_DIR .. "src/devices/bus/msx/ctrl/libbler.h",
MAME_DIR .. "src/devices/bus/msx/ctrl/mouse.cpp",
MAME_DIR .. "src/devices/bus/msx/ctrl/mouse.h",
MAME_DIR .. "src/devices/bus/msx/ctrl/sgadapt.cpp",
MAME_DIR .. "src/devices/bus/msx/ctrl/sgadapt.h",
MAME_DIR .. "src/devices/bus/msx/ctrl/towns6b.cpp",
MAME_DIR .. "src/devices/bus/msx/ctrl/towns6b.h",
MAME_DIR .. "src/devices/bus/msx/ctrl/townspad.cpp",
@ -3519,24 +3521,30 @@ end
if (BUSES["SMS_CTRL"]~=null) then
files {
MAME_DIR .. "src/devices/bus/sms_ctrl/smsctrl.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/smsctrl.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/controllers.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/controllers.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/joypad.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/joypad.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/lphaser.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/lphaser.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/md6bt.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/md6bt.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/mdpad.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/mdpad.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/multitap.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/multitap.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/paddle.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/paddle.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/rfu.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/rfu.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/smsctrl.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/smsctrl.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/sports.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/sports.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/sportsjp.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/sportsjp.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/multitap.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/multitap.h",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.cpp",
MAME_DIR .. "src/devices/bus/sms_ctrl/graphic.h",
}
end

View File

@ -61,7 +61,7 @@ public:
// pin 10 - Not connected
//
uint8_t port_r();
void port_w( uint8_t data );
void port_w(uint8_t data);
void th_pin_w(int state);

View File

@ -10,6 +10,8 @@
#include "emu.h"
#include "smsctrladp.h"
#include "bus/sms_ctrl/controllers.h"
//**************************************************************************
@ -30,7 +32,8 @@ DEFINE_DEVICE_TYPE(SMS_CTRL_ADAPTOR, sms_ctrl_adaptor_device, "sms_ctrl_adaptor"
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_subctrl_port(*this, "ctrl"),
m_th_state(0x40)
{
}
@ -41,6 +44,7 @@ sms_ctrl_adaptor_device::sms_ctrl_adaptor_device(const machine_config &mconfig,
void sms_ctrl_adaptor_device::device_start()
{
save_item(NAME(m_th_state));
}
@ -50,7 +54,8 @@ void sms_ctrl_adaptor_device::device_start()
uint8_t sms_ctrl_adaptor_device::peripheral_r()
{
return m_subctrl_port->port_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);
}
@ -60,12 +65,16 @@ uint8_t sms_ctrl_adaptor_device::peripheral_r()
void sms_ctrl_adaptor_device::peripheral_w(uint8_t data)
{
m_subctrl_port->port_w(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);
}
@ -76,9 +85,8 @@ WRITE_LINE_MEMBER( sms_ctrl_adaptor_device::th_pin_w )
void sms_ctrl_adaptor_device::device_add_mconfig(machine_config &config)
{
SMS_CONTROL_PORT(config, m_subctrl_port, sms_control_port_devices, "joypad");
if (m_port != nullptr)
m_subctrl_port->set_screen_tag(m_port->m_screen);
m_subctrl_port->th_input_handler().set(FUNC(sms_ctrl_adaptor_device::th_pin_w));
// Game Gear screen is an LCD - it won't work with lightguns anyway
SMS_CONTROL_PORT(config, m_subctrl_port, sms_control_port_devices, SMS_CTRL_OPTION_JOYPAD);
m_subctrl_port->th_handler().set(FUNC(sms_ctrl_adaptor_device::th_pin_w));
}

View File

@ -44,6 +44,8 @@ private:
DECLARE_WRITE_LINE_MEMBER(th_pin_w);
required_device<sms_control_port_device> m_subctrl_port;
uint8_t m_th_state;
};

View File

@ -12,6 +12,7 @@
#include "joystick.h"
#include "libbler.h"
#include "mouse.h"
#include "sgadapt.h"
#include "towns6b.h"
#include "townspad.h"
@ -46,6 +47,7 @@ void msx_general_purpose_port_devices(device_slot_interface &device)
device.option_add("libbler", MSX_LIBBLERPAD);
device.option_add("martypad", MSX_MARTYPAD);
device.option_add("mouse", MSX_MOUSE);
device.option_add("sega", MSX_SEGACTRL);
device.option_add("towns6b", MSX_TOWNS6B);
device.option_add("townspad", MSX_TOWNSPAD);
}

View File

@ -0,0 +1,112 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega controller adapter emulation
**********************************************************************/
#include "emu.h"
#include "sgadapt.h"
#include "bus/sms_ctrl/controllers.h"
#include "bus/sms_ctrl/smsctrl.h"
//#define VERBOSE 1
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
namespace {
class sega_adapter_device : public device_t, public device_msx_general_purpose_port_interface
{
public:
sega_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
virtual u8 read() override;
virtual void pin_6_w(int state) override;
virtual void pin_7_w(int state) override;
virtual void pin_8_w(int state) override;
protected:
virtual void device_start() override;
virtual void device_add_mconfig(machine_config &config) override;
private:
required_device<sms_control_port_device> m_port;
u8 m_out;
u8 m_th_in;
};
sega_adapter_device::sega_adapter_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock)
: device_t(mconfig, MSX_SEGACTRL, tag, owner, clock)
, device_msx_general_purpose_port_interface(mconfig, *this)
, m_port(*this, "ctrl")
, m_out(0x7f)
, m_th_in(0x40)
{
}
u8 sega_adapter_device::read()
{
return (m_port->in_r() & 0x3f) | m_th_in;
}
void sega_adapter_device::pin_6_w(int state)
{
if (u8(state ? 1 : 0) != BIT(m_out, 4))
{
if (state)
m_out |= 0x10;
else
m_out &= ~0x10;
LOG("TL %u -> %u (out 0x%02X)\n", BIT(~m_out, 4), BIT(m_out, 4), m_out);
m_port->out_w(m_out, m_out ^ 0x7f);
}
}
void sega_adapter_device::pin_7_w(int state)
{
if (u8(state ? 1 : 0) != BIT(m_out, 5))
{
if (state)
m_out |= 0x20;
else
m_out &= ~0x20;
LOG("TR %u -> %u (out 0x%02X)\n", BIT(~m_out, 5), BIT(m_out, 5), m_out);
m_port->out_w(m_out, m_out ^ 0x7f);
}
}
void sega_adapter_device::pin_8_w(int state)
{
if (u8(state ? 1 : 0) != BIT(m_out, 6))
{
if (state)
m_out |= 0x40;
else
m_out &= ~0x40;
LOG("TH %u -> %u (out 0x%02X)\n", BIT(~m_out, 6), BIT(m_out, 6), m_out);
m_port->out_w(m_out, m_out ^ 0x7f);
}
}
void sega_adapter_device::device_start()
{
save_item(NAME(m_out));
save_item(NAME(m_th_in));
}
void sega_adapter_device::device_add_mconfig(machine_config &config)
{
SMS_CONTROL_PORT(config, m_port, sms_control_port_devices, SMS_CTRL_OPTION_MD_6BUTTON);
m_port->th_handler().set([this] (int state) { m_th_in = state ? 0x40 : 0x00; });
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(MSX_SEGACTRL, device_msx_general_purpose_port_interface, sega_adapter_device, "msx_segactrl", "X68000 Sega Controller Adapter")

View File

@ -0,0 +1,20 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega controller adapter emulation
**********************************************************************/
#ifndef MAME_BUS_MSX_CTRL_SGADAPT_H
#define MAME_BUS_MSX_CTRL_SGADAPT_H
#pragma once
#include "ctrl.h"
DECLARE_DEVICE_TYPE(MSX_SEGACTRL, device_msx_general_purpose_port_interface)
DECLARE_DEVICE_TYPE(MSX_SEGACTRL, device_msx_general_purpose_port_interface)
#endif // MAME_BUS_MSX_CTRL_SGADAPT_H

View File

@ -0,0 +1,55 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega DE-9 controllers
**********************************************************************/
#include "emu.h"
#include "controllers.h"
#include "graphic.h"
#include "joypad.h"
#include "lphaser.h"
#include "md6bt.h"
#include "mdpad.h"
#include "multitap.h"
#include "paddle.h"
#include "rfu.h"
#include "sports.h"
#include "sportsjp.h"
char const *const SMS_CTRL_OPTION_GRAPHIC = "graphic";
char const *const SMS_CTRL_OPTION_LPHASER = "lphaser";
char const *const SMS_CTRL_OPTION_MD_6BUTTON = "md6button";
char const *const SMS_CTRL_OPTION_MD_PAD = "mdpad";
char const *const SMS_CTRL_OPTION_MULTITAP = "multitap";
char const *const SMS_CTRL_OPTION_JOYPAD = "mspad";
char const *const SMS_CTRL_OPTION_PADDLE = "paddle";
char const *const SMS_CTRL_OPTION_RAPID_FIRE = "rapidfire";
char const *const SMS_CTRL_OPTION_SPORTS = "sports";
char const *const SMS_CTRL_OPTION_SPORTS_JP = "sportsjp";
void sms_control_port_devices(device_slot_interface &device)
{
device.option_add(SMS_CTRL_OPTION_GRAPHIC, SMS_GRAPHIC);
device.option_add(SMS_CTRL_OPTION_LPHASER, SMS_LIGHT_PHASER);
device.option_add(SMS_CTRL_OPTION_MD_6BUTTON, SMS_MD6BUTTON);
device.option_add(SMS_CTRL_OPTION_MD_PAD, SMS_MDPAD);
device.option_add(SMS_CTRL_OPTION_MULTITAP, SMS_MULTITAP);
device.option_add(SMS_CTRL_OPTION_JOYPAD, SMS_JOYPAD);
device.option_add(SMS_CTRL_OPTION_PADDLE, SMS_PADDLE);
device.option_add(SMS_CTRL_OPTION_RAPID_FIRE, SMS_RAPID_FIRE);
device.option_add(SMS_CTRL_OPTION_SPORTS, SMS_SPORTS_PAD);
device.option_add(SMS_CTRL_OPTION_SPORTS_JP, SMS_SPORTS_PAD_JP);
}
void sms_control_port_passive_devices(device_slot_interface &device)
{
device.option_add(SMS_CTRL_OPTION_JOYPAD, SMS_JOYPAD);
}

View File

@ -0,0 +1,28 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega DE-9 controllers
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_CONTROLLERS_H
#define MAME_BUS_SMS_CTRL_CONTROLLERS_H
#pragma once
extern char const *const SMS_CTRL_OPTION_GRAPHIC;
extern char const *const SMS_CTRL_OPTION_LPHASER;
extern char const *const SMS_CTRL_OPTION_MD_6BUTTON;
extern char const *const SMS_CTRL_OPTION_MD_PAD;
extern char const *const SMS_CTRL_OPTION_MULTITAP;
extern char const *const SMS_CTRL_OPTION_JOYPAD;
extern char const *const SMS_CTRL_OPTION_PADDLE;
extern char const *const SMS_CTRL_OPTION_RAPID_FIRE;
extern char const *const SMS_CTRL_OPTION_SPORTS;
extern char const *const SMS_CTRL_OPTION_SPORTS_JP;
void sms_control_port_devices(device_slot_interface &device);
void sms_control_port_passive_devices(device_slot_interface &device);
#endif // MAME_BUS_SMS_CTRL_CONTROLLERS_H

View File

@ -36,55 +36,69 @@ Then 2 nibbles are read to form a byte containing the absolute Y coordiante.
#include "graphic.h"
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_GRAPHIC, sms_graphic_device, "sms_graphic", "Sega SMS Graphic Board")
namespace {
static INPUT_PORTS_START( sms_graphic )
PORT_START("BUTTONS")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) // MENU
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) // DO
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_BUTTON3 ) // PEN
PORT_BIT( 0xf8, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_UNKNOWN ) // some kind of ready signal?
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_TOGGLE PORT_NAME("%p Pen") // pretend pen pressure is all-or-nothing
PORT_START("X")
PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15)
PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 254 / 268.0, 6 / 268.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(1)
PORT_START("Y")
PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15)
PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_Y) PORT_CROSSHAIR(Y, 255 / 224.0, -19 / 224.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(1)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_graphic_device::device_input_ports() const
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class sms_graphic_device : public device_t, public device_sms_control_interface
{
return INPUT_PORTS_NAME( sms_graphic );
}
public:
// construction/destruction
sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_sms_control_interface implementation
virtual uint8_t in_r() override;
virtual void out_w(uint8_t data, uint8_t mem_mask) override;
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_graphic); }
virtual void device_start() override;
private:
required_ioport m_buttons;
required_ioport m_x_axis;
required_ioport m_y_axis;
uint8_t m_phase;
uint8_t m_select;
uint8_t m_data;
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_graphic_device - constructor
//-------------------------------------------------
sms_graphic_device::sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
: device_t(mconfig, SMS_GRAPHIC, tag, owner, clock)
, device_sms_control_port_interface(mconfig, *this)
, m_buttons(*this, "BUTTONS")
, m_x(*this, "X")
, m_y(*this, "Y")
, m_index(0)
, m_previous_write(0xff)
, m_pressure(0xfd)
sms_graphic_device::sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_GRAPHIC, tag, owner, clock),
device_sms_control_interface(mconfig, *this),
m_buttons(*this, "BUTTONS"),
m_x_axis(*this, "X"),
m_y_axis(*this, "Y"),
m_phase(0),
m_select(0x7f),
m_data(0xff)
{
}
@ -95,8 +109,12 @@ sms_graphic_device::sms_graphic_device(const machine_config &mconfig, const char
void sms_graphic_device::device_start()
{
save_item(NAME(m_index));
save_item(NAME(m_previous_write));
m_phase = 0;
m_data = 0xff;
save_item(NAME(m_phase));
save_item(NAME(m_select));
save_item(NAME(m_data));
}
@ -104,54 +122,55 @@ void sms_graphic_device::device_start()
// sms_peripheral_r - joypad read
//-------------------------------------------------
uint8_t sms_graphic_device::peripheral_r()
uint8_t sms_graphic_device::in_r()
{
switch (m_index)
{
case 0: // Initial state / "I am a board"
// If any regular button is pressed raise/lower TL ?
// if ((m_buttons->read() & 0x07) != 0x07)
// return 0xf0;
return 0xd0;
case 1: // Read buttons (active low)
return m_buttons->read();
case 2: // Some thing only FD, FE, and FF cause the other values to be read
return m_pressure >> 4;
case 3:
return m_pressure & 0x0f;
case 4: // High nibble X?
return m_x->read() >> 4;
case 5: // Low nibble X?
return m_x->read() & 0x0f;
case 6: // High nibble Y?
return m_y->read() >> 4;
case 7: // Low Nibble Y?
return m_y->read() & 0x0f;
}
return 0xff;
if (BIT(m_select, 5))
return 0x20; // low four bits must be low to recognise Graphic Board, TL is a kind of active-low ready flag
else if (m_phase)
return BIT(m_data, BIT(m_select, 6) ? 0 : 4, 4) | 0x30;
else
return (m_buttons->read() & 0x1f) | 0x20;
}
void sms_graphic_device::peripheral_w(uint8_t data)
void sms_graphic_device::out_w(uint8_t data, uint8_t mem_mask)
{
// Check for toggle on TH/TL
if ((data ^ m_previous_write) & 0xc0)
if (BIT(data, 5))
{
m_index++;
// TR high - deselected
m_phase = 0;
}
else if (!BIT(m_select, 5) && BIT(m_select, 6) && !BIT(data, 6))
{
// negative edge on TH seems to trigger acquisition
switch (m_phase)
{
case 0:
m_data = BIT(m_buttons->read(), 5) ? 0xfe : 0x00; // values made up to satisfy software
m_phase = 1;
break;
case 1:
m_data = m_x_axis->read();
m_phase = 2;
break;
case 2:
m_data = m_y_axis->read();
m_phase = 3;
break;
default:
break; // TODO: what actually happens if you keep clocking TH?
}
}
// If TR is high, restart
if (data & 0x80)
{
m_index = 0;
}
m_previous_write = data;
m_select = data;
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_GRAPHIC, device_sms_control_interface, sms_graphic_device, "sms_graphic", "Sega Master System Graphic Board")

View File

@ -5,54 +5,14 @@
Sega Master System "Graphic Board" emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_GRAPHIC_H
#define MAME_BUS_SMS_CTRL_GRAPHIC_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_graphic_device
class sms_graphic_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_graphic_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
protected:
// device-level overrides
virtual void device_start() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
virtual void peripheral_w(uint8_t data) override;
private:
required_ioport m_buttons;
required_ioport m_x;
required_ioport m_y;
int m_index;
uint8_t m_previous_write;
uint8_t m_pressure;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_GRAPHIC, sms_graphic_device)
DECLARE_DEVICE_TYPE(SMS_GRAPHIC, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_GRAPHIC_H

View File

@ -25,41 +25,42 @@ Release data from the Sega Retro project:
#include "joypad.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_JOYPAD, sms_joypad_device, "sms_joypad", "Sega SMS Control Pad")
static INPUT_PORTS_START( sms_joypad )
INPUT_PORTS_START( sms_joypad )
PORT_START("JOYPAD")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_joypad_device::device_input_ports() const
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class sms_joypad_device : public device_t, public device_sms_control_interface
{
return INPUT_PORTS_NAME( sms_joypad );
}
public:
// construction/destruction
sms_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_sms_control_interface implementation
virtual uint8_t in_r() override { return m_joypad->read(); }
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_joypad); }
virtual void device_start() override { }
private:
required_ioport m_joypad;
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_joypad_device - constructor
@ -67,26 +68,17 @@ ioport_constructor sms_joypad_device::device_input_ports() const
sms_joypad_device::sms_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_JOYPAD, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
device_sms_control_interface(mconfig, *this),
m_joypad(*this, "JOYPAD")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_joypad_device::device_start()
{
}
} // anonymous namespace
//-------------------------------------------------
// sms_peripheral_r - joypad read
//-------------------------------------------------
uint8_t sms_joypad_device::peripheral_r()
{
return m_joypad->read();
}
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_JOYPAD, device_sms_control_interface, sms_joypad_device, "sms_joypad", "Sega Master System Control Pad")

View File

@ -5,47 +5,14 @@
Sega Mark III "Joypad" / Master System "Control Pad" emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_JOYPAD_H
#define MAME_BUS_SMS_CTRL_JOYPAD_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_joypad_device
class sms_joypad_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_joypad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
protected:
// device-level overrides
virtual void device_start() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
private:
required_ioport m_joypad;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_JOYPAD, sms_joypad_device)
DECLARE_DEVICE_TYPE(SMS_JOYPAD, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_JOYPAD_H

View File

@ -19,43 +19,57 @@ Notes:
**********************************************************************/
#include "emu.h"
#include "screen.h"
#include "lphaser.h"
#include "screen.h"
//#define VERBOSE 1
#include "logmacro.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
// TYPE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_LIGHT_PHASER, sms_light_phaser_device, "sms_light_phaser", "Sega SMS Light Phaser")
#define LGUN_RADIUS 6
#define LGUN_X_INTERVAL 4
READ_LINE_MEMBER( sms_light_phaser_device::th_pin_r )
class sms_light_phaser_device : public device_t, public device_sms_control_interface
{
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
return ~m_sensor_last_state;
}
public:
// construction/destruction
sms_light_phaser_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
DECLARE_INPUT_CHANGED_MEMBER(position_changed) { sensor_check(0); }
// device_sms_control_interface implementation
virtual uint8_t in_r() override { return m_trigger->read(); }
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override;
virtual void device_start() override;
virtual void device_reset() override;
private:
required_ioport m_trigger;
required_ioport m_x_axis;
required_ioport m_y_axis;
emu_timer *m_update_timer;
int m_sensor_last_state;
TIMER_CALLBACK_MEMBER(sensor_check);
int bright_aim_area(int lgun_x, int lgun_y );
uint16_t screen_hpos_nonscaled(int scaled_hpos);
uint16_t screen_vpos_nonscaled(int scaled_vpos);
};
INPUT_CHANGED_MEMBER( sms_light_phaser_device::position_changed )
{
if (newval != oldval)
{
sensor_check(0);
}
}
static INPUT_PORTS_START( sms_light_phaser )
PORT_START("CTRL_PORT")
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (trigger)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_DEVICE_MEMBER(DEVICE_SELF, sms_light_phaser_device, th_pin_r)
PORT_BIT( 0x9f, IP_ACTIVE_LOW, IPT_UNUSED )
INPUT_PORTS_START(sms_light_phaser)
PORT_START("LPHASER_T")
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (trigger)
PORT_BIT( 0x2f, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("LPHASER_X")
PORT_BIT( 0xff, 0x00, IPT_LIGHTGUN_X) PORT_CROSSHAIR(X, 1.0, 0.0, 0) PORT_SENSITIVITY(50) PORT_KEYDELTA(15) PORT_CHANGED_MEMBER(DEVICE_SELF, sms_light_phaser_device, position_changed, 0)
@ -71,27 +85,22 @@ INPUT_PORTS_END
ioport_constructor sms_light_phaser_device::device_input_ports() const
{
return INPUT_PORTS_NAME( sms_light_phaser );
return INPUT_PORTS_NAME(sms_light_phaser);
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_light_phaser_device - constructor
//-------------------------------------------------
sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_LIGHT_PHASER, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_lphaser_pins(*this, "CTRL_PORT"),
m_lphaser_x(*this, "LPHASER_X"),
m_lphaser_y(*this, "LPHASER_Y"),
m_sensor_last_state(0),
m_lphaser_timer(nullptr)
device_sms_control_interface(mconfig, *this),
m_trigger(*this, "LPHASER_T"),
m_x_axis(*this, "LPHASER_X"),
m_y_axis(*this, "LPHASER_Y"),
m_update_timer(nullptr),
m_sensor_last_state(0)
{
}
@ -102,24 +111,17 @@ sms_light_phaser_device::sms_light_phaser_device(const machine_config &mconfig,
void sms_light_phaser_device::device_start()
{
m_update_timer = timer_alloc(FUNC(sms_light_phaser_device::sensor_check), this);
m_sensor_last_state = 1;
save_item(NAME(m_sensor_last_state));
m_lphaser_timer = timer_alloc(FUNC(sms_light_phaser_device::sensor_check), this);
}
void sms_light_phaser_device::device_reset()
{
m_sensor_last_state = 1; // off (1)
}
//-------------------------------------------------
// sms_peripheral_r - light phaser read
//-------------------------------------------------
uint8_t sms_light_phaser_device::peripheral_r()
{
return m_lphaser_pins->read();
// TODO: sensor check now? The device itself doesn't respond to system reset
}
@ -148,13 +150,21 @@ uint8_t sms_light_phaser_device::peripheral_r()
*/
int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
{
constexpr int LGUN_RADIUS = 6;
constexpr int LGUN_X_INTERVAL = 4;
// brightness of the lightgray color in the frame drawn by Light Phaser games
constexpr uint8_t SENSOR_MIN_BRIGHTNESS = 0x7f;
screen_device &scr(*screen());
const int r_x_r = LGUN_RADIUS * LGUN_RADIUS;
const rectangle &visarea = m_port->m_screen->visible_area();
const rectangle &visarea = scr.visible_area();
rectangle aim_area;
int beam_x = m_port->m_screen->hpos();
int beam_y = m_port->m_screen->vpos();
int beam_x_orig = beam_x;
int beam_y_orig = beam_y;
int beam_x = scr.hpos();
int beam_y = scr.vpos();
const int beam_x_orig = beam_x;
const int beam_y_orig = beam_y;
int result = 1;
bool new_check_point = false;
@ -163,16 +173,14 @@ int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
while (!new_check_point)
{
/* If beam's y doesn't point to a line where the aim area is,
change it to the first line where the beam enters that area. */
// If beam's y doesn't point to a line where the aim area is, change it to the first line where the beam enters that area.
if (beam_y < aim_area.min_y || beam_y > aim_area.max_y)
{
beam_y = aim_area.min_y;
}
int dy = abs(beam_y - lgun_y);
/* Caculate distance in x of the radius, relative to beam's y distance.
First try some shortcuts. */
// Calculate distance in x of the radius, relative to beam's y distance. First try some shortcuts.
double dx_radius = 0;
if (dy == 0)
{
@ -180,9 +188,9 @@ int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
}
else if (dy != LGUN_RADIUS)
{
/* step 1: r^2 = dx^2 + dy^2 */
/* step 2: dx^2 = r^2 - dy^2 */
/* step 3: dx = sqrt(r^2 - dy^2) */
// step 1: r^2 = dx^2 + dy^2
// step 2: dx^2 = r^2 - dy^2
// step 3: dx = sqrt(r^2 - dy^2)
dx_radius = ceil(sqrt(double(r_x_r - (dy * dy))));
}
@ -191,8 +199,7 @@ int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
while (!new_check_point)
{
/* If beam's x has passed the aim area, change it to the
next line and go back to recheck y/x coordinates. */
// If beam's x has passed the aim area, change it to the next line and go back to recheck y/x coordinates.
if (beam_x > aim_area.max_x)
{
beam_x = visarea.min_x;
@ -200,8 +207,7 @@ int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
break;
}
/* If beam's x isn't in the aim area, change it to the
next point where the beam enters that area. */
// If beam's x isn't in the aim area, change it to the next point where the beam enters that area.
if (beam_x < aim_area.min_x)
{
beam_x = aim_area.min_x;
@ -209,58 +215,52 @@ int sms_light_phaser_device::bright_aim_area(int lgun_x, int lgun_y)
if (beam_x_orig != beam_x || beam_y_orig != beam_y)
{
/* adopt the new coordinates to adjust the timer */
// adopt the new coordinates to adjust the timer
new_check_point = true;
break;
}
if (m_sensor_last_state == 0)
{
/* sensor is already on */
/* keep sensor on until out of the aim area */
// sensor is already on - keep sensor on until out of the aim area
result = 0;
}
else
{
rgb_t color;
uint8_t brightness;
/* brightness of the lightgray color in the frame drawn by Light Phaser games */
const uint8_t sensor_min_brightness = 0x7f;
scr.update_now();
const rgb_t color = scr.pixel(beam_x, beam_y);
m_port->m_screen->update_now();
color = m_port->m_screen->pixel(beam_x, beam_y);
// reference: http://www.w3.org/TR/AERT#color-contrast
const uint8_t brightness = (color.r() * 0.299) + (color.g() * 0.587) + (color.b() * 0.114);
LOG("color brightness: %2X for x %d y %d\n", brightness, beam_x, beam_y);
/* reference: http://www.w3.org/TR/AERT#color-contrast */
brightness = (color.r() * 0.299) + (color.g() * 0.587) + (color.b() * 0.114);
//printf ("color brightness: %2X for x %d y %d\n", brightness, beam_x, beam_y);
result = (brightness >= sensor_min_brightness) ? 0 : 1;
result = (brightness >= SENSOR_MIN_BRIGHTNESS) ? 0 : 1;
}
if (result == 0) /* sensor on */
if (result == 0) // sensor on
{
/* Set next check for when sensor will be off */
// Set next check for when sensor will be off
beam_x = aim_area.max_x + 1;
/* adopt the new coordinates to adjust the timer */
// adopt the new coordinates to adjust the timer
new_check_point = true;
}
else
{
/* Next check will happen after the minimum interval */
// Next check will happen after the minimum interval
beam_x += LGUN_X_INTERVAL;
}
}
}
m_lphaser_timer->adjust(m_port->m_screen->time_until_pos(beam_y, beam_x));
m_update_timer->adjust(scr.time_until_pos(beam_y, beam_x));
return result;
}
uint16_t sms_light_phaser_device::screen_hpos_nonscaled(int scaled_hpos)
{
const rectangle &visarea = m_port->m_screen->visible_area();
const rectangle &visarea = screen()->visible_area();
int offset_x = (scaled_hpos * (visarea.max_x - visarea.min_x)) / 255;
return visarea.min_x + offset_x;
}
@ -268,7 +268,7 @@ uint16_t sms_light_phaser_device::screen_hpos_nonscaled(int scaled_hpos)
uint16_t sms_light_phaser_device::screen_vpos_nonscaled(int scaled_vpos)
{
const rectangle &visarea = m_port->m_screen->visible_area();
const rectangle &visarea = screen()->visible_area();
int offset_y = (scaled_vpos * (visarea.max_y - visarea.min_y)) / 255;
return visarea.min_y + offset_y;
}
@ -276,13 +276,26 @@ uint16_t sms_light_phaser_device::screen_vpos_nonscaled(int scaled_vpos)
TIMER_CALLBACK_MEMBER(sms_light_phaser_device::sensor_check)
{
const int x = screen_hpos_nonscaled(m_lphaser_x->read());
const int y = screen_vpos_nonscaled(m_lphaser_y->read());
int sensor_new_state = bright_aim_area(x, y);
if (sensor_new_state != m_sensor_last_state)
if (screen())
{
m_port->th_pin_w(sensor_new_state);
m_sensor_last_state = sensor_new_state;
const int x = screen_hpos_nonscaled(m_x_axis->read());
const int y = screen_vpos_nonscaled(m_y_axis->read());
int sensor_new_state = bright_aim_area(x, y);
if (sensor_new_state != m_sensor_last_state)
{
th_w(sensor_new_state);
m_sensor_last_state = sensor_new_state;
}
}
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_LIGHT_PHASER, device_sms_control_interface, sms_light_phaser_device, "sms_light_phaser", "Sega Master System Light Phaser")

View File

@ -5,61 +5,14 @@
Sega Master System "Light Phaser" (light gun) emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_LPHASER_H
#define MAME_BUS_SMS_CTRL_LPHASER_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_light_phaser_device
class sms_light_phaser_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_light_phaser_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
DECLARE_READ_LINE_MEMBER( th_pin_r );
DECLARE_INPUT_CHANGED_MEMBER( position_changed );
protected:
// device-level overrides
virtual void device_start() override;
virtual void device_reset() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
private:
required_ioport m_lphaser_pins;
required_ioport m_lphaser_x;
required_ioport m_lphaser_y;
int m_sensor_last_state;
emu_timer *m_lphaser_timer;
TIMER_CALLBACK_MEMBER(sensor_check);
int bright_aim_area(int lgun_x, int lgun_y );
uint16_t screen_hpos_nonscaled(int scaled_hpos);
uint16_t screen_vpos_nonscaled(int scaled_vpos);
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_LIGHT_PHASER, sms_light_phaser_device)
DECLARE_DEVICE_TYPE(SMS_LIGHT_PHASER, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_LPHASER_H

View File

@ -0,0 +1,170 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mega Drive Six Button Control Pad emulation
Called "Fighting Pad 6B" (6B) in Japan
Called "6 Button Arcade Pad" in North America
Called "Bloc darcade à 6 boutons" in Canada
Called "Joystick 6 Botões" in Brazil
**********************************************************************/
#include "emu.h"
#include "md6bt.h"
//#define VERBOSE 1
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
namespace {
INPUT_PORTS_START( sms_md6button )
PORT_START("PAD")
PORT_BIT( 0x001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("%p B")
PORT_BIT( 0x020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("%p C")
PORT_BIT( 0x040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("%p A")
PORT_BIT( 0x080, IP_ACTIVE_LOW, IPT_START )
PORT_BIT( 0x100, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_NAME("%p Z")
PORT_BIT( 0x200, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_NAME("%p Y")
PORT_BIT( 0x400, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_NAME("%p X")
PORT_BIT( 0x800, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("%p Mode")
INPUT_PORTS_END
class sms_md6button_device : public device_t, public device_sms_control_interface
{
public:
sms_md6button_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual u8 in_r() override;
virtual void out_w(u8 data, u8 mem_mask) override;
protected:
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_md6button); }
virtual void device_start() override;
virtual void device_reset() override;
private:
TIMER_CALLBACK_MEMBER(timeout);
required_ioport m_pad;
emu_timer *m_idle_timer;
u8 m_th;
u8 m_phase;
u8 m_mode;
};
sms_md6button_device::sms_md6button_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_MD6BUTTON, tag, owner, clock),
device_sms_control_interface(mconfig, *this),
m_pad(*this, "PAD"),
m_idle_timer(nullptr),
m_th(1),
m_phase(0),
m_mode(0)
{
}
u8 sms_md6button_device::in_r()
{
ioport_value const lines = m_pad->read();
u8 result;
switch (m_phase)
{
default:
case 0:
case 1:
if (m_th)
result = BIT(lines, 0, 6); // CBRLDU
else
result = (BIT(lines, 6, 2) << 4) | BIT(lines, 0, 2); // SA00DU
break;
case 2:
if (m_th)
result = BIT(lines, 0, 6); // CBRLDU
else
result = (BIT(lines, 6, 2) << 4); // SA0000
break;
case 3:
if (m_th)
result = (BIT(lines, 4, 2) << 4) | BIT(lines, 8, 4); // CBMXYZ
else
result = (BIT(lines, 6, 2) << 4) | 0x0f; // SA----
break;
}
LOG("%s: TH = %u read 0x%02X\n", machine().describe_context(), m_th, result);
return result;
}
void sms_md6button_device::out_w(u8 data, u8 mem_mask)
{
u8 const th = BIT(data, 6);
if (!th)
{
m_idle_timer->reset();
}
else if (m_th)
{
// not an edge
}
else if (BIT(m_mode, 0))
{
m_idle_timer->adjust(attotime::from_usec(1500));
m_phase = (m_phase + 1) & 0x03;
LOG("%s: 6-button mode, TH rising, phase = %u\n", machine().describe_context(), m_phase);
}
else
{
LOG("%s: 3-button mode, TH rising, phase = %u\n", machine().describe_context(), m_phase);
}
m_th = th;
}
void sms_md6button_device::device_start()
{
m_idle_timer = timer_alloc(FUNC(sms_md6button_device::timeout), this);
m_phase = 0;
m_mode = 0;
save_item(NAME(m_th));
save_item(NAME(m_phase));
save_item(NAME(m_mode));
}
void sms_md6button_device::device_reset()
{
// TODO: doesn't work reset happens before inputs are read
if (!m_mode)
m_mode = BIT(m_pad->read(), 11) | 0x02;
}
TIMER_CALLBACK_MEMBER(sms_md6button_device::timeout)
{
m_phase = 0;
LOG("timeout, phase = %u\n", m_phase);
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(SMS_MD6BUTTON, device_sms_control_interface, sms_md6button_device, "sms_md6button", "Sega Mega Drive Six Button Control Pad")

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mega Drive Six Button Control Pad emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_MD6BT_H
#define MAME_BUS_SMS_CTRL_MD6BT_H
#pragma once
#include "smsctrl.h"
DECLARE_DEVICE_TYPE(SMS_MD6BUTTON, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_MD6BT_H

View File

@ -0,0 +1,82 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mega Drive Control Pad emulation
**********************************************************************/
#include "emu.h"
#include "mdpad.h"
namespace {
INPUT_PORTS_START( sms_mdpad )
PORT_START("PAD")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("%p B")
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_NAME("%p C")
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("%p A")
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_START )
INPUT_PORTS_END
class sms_mdpad_device : public device_t, public device_sms_control_interface
{
public:
sms_mdpad_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual u8 in_r() override;
virtual void out_w(u8 data, u8 mem_mask) override;
protected:
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_mdpad); }
virtual void device_start() override;
private:
required_ioport m_pad;
u8 m_th;
};
sms_mdpad_device::sms_mdpad_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_MDPAD, tag, owner, clock),
device_sms_control_interface(mconfig, *this),
m_pad(*this, "PAD"),
m_th(1)
{
}
u8 sms_mdpad_device::in_r()
{
ioport_value const lines = m_pad->read();
if (m_th)
return BIT(lines, 0, 6);
else
return (BIT(lines, 6, 2) << 4) | BIT(lines, 0, 2);
}
void sms_mdpad_device::out_w(u8 data, u8 mem_mask)
{
m_th = BIT(data, 6);
}
void sms_mdpad_device::device_start()
{
save_item(NAME(m_th));
}
} // anonymous namespace
DEFINE_DEVICE_TYPE_PRIVATE(SMS_MDPAD, device_sms_control_interface, sms_mdpad_device, "sms_mdpad", "Sega Mega Drive Control Pad")

View File

@ -0,0 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mega Drive Control Pad emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_MDPAD_H
#define MAME_BUS_SMS_CTRL_MDPAD_H
#pragma once
#include "smsctrl.h"
DECLARE_DEVICE_TYPE(SMS_MDPAD, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_MDPAD_H

View File

@ -4,25 +4,56 @@
Furrtek's homemade multitap emulation
Schematic: http://www.smspower.org/uploads/Homebrew/BOoM-SMS-sms4p_2.png
Works by pulling ground low on one of the four ports at a time.
Doesn't pass through power, only works with passive devices.
**********************************************************************/
#include "emu.h"
#include "multitap.h"
#include "controllers.h"
// Scheme: http://www.smspower.org/uploads/Homebrew/BOoM-SMS-sms4p_2.png
//#define VERBOSE 1
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
// TYPE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_MULTITAP, sms_multitap_device, "sms_multitap", "Furrtek SMS Multitap")
class sms_multitap_device : public device_t, public device_sms_control_interface
{
public:
// construction/destruction
sms_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_sms_control_interface implementation
virtual uint8_t in_r() override;
virtual void out_w(uint8_t data, uint8_t mem_mask) override;
protected:
// device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
virtual void device_resolve_objects() override;
virtual void device_start() override;
private:
TIMER_CALLBACK_MEMBER(reset_timeout);
required_device_array<sms_control_port_device, 4> m_subctrl_ports;
emu_timer *m_reset_timer;
uint8_t m_read_state;
uint8_t m_th_state;
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_multitap_device - constructor
@ -30,25 +61,32 @@ DEFINE_DEVICE_TYPE(SMS_MULTITAP, sms_multitap_device, "sms_multitap", "Furrtek S
sms_multitap_device::sms_multitap_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_MULTITAP, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_subctrl1_port(*this, "ctrl1"),
m_subctrl2_port(*this, "ctrl2"),
m_subctrl3_port(*this, "ctrl3"),
m_subctrl4_port(*this, "ctrl4"),
device_sms_control_interface(mconfig, *this),
m_subctrl_ports(*this, "ctrl%u", 1U),
m_reset_timer(nullptr),
m_read_state(0),
m_last_data(0)
m_th_state(1)
{
}
void sms_multitap_device::device_resolve_objects()
{
m_read_state = 0;
m_th_state = 1;
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_multitap_device::device_start()
{
m_reset_timer = timer_alloc(FUNC(sms_multitap_device::reset_timeout), this);
save_item(NAME(m_read_state));
save_item(NAME(m_last_data));
save_item(NAME(m_th_state));
}
@ -56,30 +94,13 @@ void sms_multitap_device::device_start()
// sms_peripheral_r - multitap read
//-------------------------------------------------
uint8_t sms_multitap_device::peripheral_r()
uint8_t sms_multitap_device::in_r()
{
uint8_t data = 0xff;
switch(m_read_state)
{
case 0:
data = m_subctrl1_port->port_r();
break;
case 1:
data = m_subctrl2_port->port_r();
break;
case 2:
data = m_subctrl3_port->port_r();
break;
case 3:
data = m_subctrl4_port->port_r();
break;
}
// force TH level high (1), as the line is not connected to subports.
data |= 0x40;
return data;
// only low two bits of count value are decoded
uint8_t const port = m_read_state & 0x03;
uint8_t const result = m_subctrl_ports[port]->in_r();
LOG("%s: read player %u = 0x%02X\n", machine().describe_context(), port + 1, result);
return result;
}
@ -87,35 +108,27 @@ uint8_t sms_multitap_device::peripheral_r()
// sms_peripheral_w - multitap write
//-------------------------------------------------
void sms_multitap_device::peripheral_w(uint8_t data)
void sms_multitap_device::out_w(uint8_t data, uint8_t mem_mask)
{
uint8_t output_data;
// check if TH level is low (0) and was high (1)
if (!(data & 0x40) && (m_last_data & 0x40))
uint8_t const th_state = BIT(data, 6);
if (!th_state)
{
m_read_state = (m_read_state + 1) & 3;
m_reset_timer->reset(); // capacitor discharged through diode
if (m_th_state)
{
m_read_state = (m_read_state + 1) & 0x0f; // 74LS393 4-bit counter
LOG("%s: TH falling, count = 0x%X (player %u)\n", machine().describe_context(), m_read_state, (m_read_state & 0x03) + 1);
}
}
m_last_data = data;
// output default TH level (1), as the line is not connected to subports.
output_data = data | 0x40;
switch(m_read_state)
else if (!m_th_state)
{
case 0:
m_subctrl1_port->port_w(output_data);
break;
case 1:
m_subctrl2_port->port_w(output_data);
break;
case 2:
m_subctrl3_port->port_w(output_data);
break;
case 3:
m_subctrl4_port->port_w(output_data);
break;
// start charging 0.1u capacitor via 100k resistor - timeout approximated
m_reset_timer->adjust(attotime::from_msec(10));
}
m_th_state = th_state;
for (auto &port : m_subctrl_ports)
port->out_w(data | 0x40, mem_mask & ~0x40); // TH not connected to controllers
}
@ -125,17 +138,24 @@ void sms_multitap_device::peripheral_w(uint8_t data)
void sms_multitap_device::device_add_mconfig(machine_config &config)
{
// Controller subports setup, without the TH callback declaration,
// because the circuit scheme shows TH of subports without connection.
SMS_CONTROL_PORT(config, m_subctrl1_port, sms_control_port_devices, "joypad");
SMS_CONTROL_PORT(config, m_subctrl2_port, sms_control_port_devices, "joypad");
SMS_CONTROL_PORT(config, m_subctrl3_port, sms_control_port_devices, "joypad");
SMS_CONTROL_PORT(config, m_subctrl4_port, sms_control_port_devices, "joypad");
if (m_port != nullptr)
{
m_subctrl1_port->set_screen_tag(m_port->m_screen);
m_subctrl2_port->set_screen_tag(m_port->m_screen);
m_subctrl3_port->set_screen_tag(m_port->m_screen);
m_subctrl4_port->set_screen_tag(m_port->m_screen);
}
// TH not connected, no point configuring screen when power isn't passed through
for (auto port : m_subctrl_ports)
SMS_CONTROL_PORT(config, port, sms_control_port_passive_devices, SMS_CTRL_OPTION_JOYPAD);
}
TIMER_CALLBACK_MEMBER(sms_multitap_device::reset_timeout)
{
m_read_state = 0;
LOG("Timeout, count = 0x%X (player %u)\n", m_read_state, (m_read_state & 0x03) + 1);
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_MULTITAP, device_sms_control_interface, sms_multitap_device, "sms_multitap", "Furrtek Sega Master System Multitap")

View File

@ -5,52 +5,14 @@
Furrtek's homemade multitap emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_MULTITAP_H
#define MAME_BUS_SMS_CTRL_MULTITAP_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_multitap_device
class sms_multitap_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_multitap_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_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
virtual void peripheral_w(uint8_t data) override;
private:
required_device<sms_control_port_device> m_subctrl1_port;
required_device<sms_control_port_device> m_subctrl2_port;
required_device<sms_control_port_device> m_subctrl3_port;
required_device<sms_control_port_device> m_subctrl4_port;
uint8_t m_read_state;
uint8_t m_last_data;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_MULTITAP, sms_multitap_device)
DECLARE_DEVICE_TYPE(SMS_MULTITAP, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_MULTITAP_H

View File

@ -1,127 +1,184 @@
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mark III "Paddle Control" emulation
Release data from the Sega Retro project:
Release data from the Sega Retro project:
Year: 1987 Country/region: JP Model code: HPD-200
Year: 1987 Country/region: JP Model code: HPD-200
Notes:
Notes:
The main chip contained in the device is labeled 315-5243.
The main chip contained in the device is labeled 315-5243.
The Paddle Control was only released in Japan. To work with the device,
paddle games need to detect the system region as Japanese, else they switch
to a different mode that uses the TH line as output to select which nibble
of the X axis will be read. This other mode is similar to how the US Sports
Pad works, so on an Export system, paddle games are somewhat playable with
that device, though it needs to be used inverted and the trackball needs to
be moved slowly, else the software for the paddle think it's moving backward.
On Japanese systems (Mark III and Master System), the games
read the port and expect the value on the low four bits
(usually used joystick switches) to alternate between the low
and high nybbles of the paddle position, with TR indicating
the current state.
On export consoles, the games toggle the TH output before
reading a nybble, expecting to be able to select the high or
low nybble of the paddle position. It spins for longer between
pulling TH low and reading the low nybble than it does between
pulling TH high and reading the high nybble, suggesting that
pulling TH low triggers acquisition.
Only a single paddle controller was released that works with
both Japanese and export consoles, and the Mark III has the pin
that became TH tied low while it's left high when reading the
paddle on Japanese Master Systems. This suggests that if the
TH line doesn't change state for some amount of time, the
paddle will periodically switch between high and low nybbles.
**********************************************************************/
#include "emu.h"
#include "paddle.h"
//#define VERBOSE 1
//#define LOG_OUTPUT_FUNC osd_printf_info
#include "logmacro.h"
namespace {
INPUT_PORTS_START( sms_paddle )
PORT_START("BUTTON")
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_START("PADDLE")
PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_MINMAX(0, 255) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0)
INPUT_PORTS_END
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class sms_paddle_device : public device_t, public device_sms_control_interface
{
public:
// construction/destruction
sms_paddle_device(const machine_config &mconfig, char const *tag, device_t *owner, u32 clock);
// device_sms_control_interface implementation
virtual u8 in_r() override;
virtual void out_w(u8 data, u8 mem_mask) override;
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_paddle); }
virtual void device_start() override;
private:
TIMER_CALLBACK_MEMBER(timeout);
// time interval guessed
// Player 2 of Galactic Protector is the most sensitive to this timing
static attotime interval() { return attotime::from_hz(XTAL(10'738'635) / 3 / 100); }
// delay guessed
static attotime delay() { return attotime::from_msec(5); }
required_ioport m_button;
required_ioport m_axis;
emu_timer *m_idle_timer;
u8 m_th;
u8 m_nybble;
u8 m_data;
};
sms_paddle_device::sms_paddle_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_PADDLE, tag, owner, clock),
device_sms_control_interface(mconfig, *this),
m_button(*this, "BUTTON"),
m_axis(*this, "PADDLE"),
m_idle_timer(nullptr),
m_th(1),
m_nybble(1),
m_data(0)
{
}
u8 sms_paddle_device::in_r()
{
LOG("%s: read %s nybble = 0x%x\n", machine().describe_context(), m_nybble ? "high" : "low", m_data & 0x0f);
return (m_nybble << 5) | (m_button->read() << 4) | (m_data & 0x0f);
}
void sms_paddle_device::out_w(u8 data, u8 mem_mask)
{
u8 const th = BIT(data, 6);
if (th != m_th)
{
m_idle_timer->reset(delay());
if (!th)
{
m_nybble = 0;
m_data = m_axis->read();
LOG("%s: TH %u -> %u\n, acquire data 0x%02X", machine().describe_context(), m_th, th, m_data);
}
else if (!m_nybble)
{
m_nybble = 1;
m_data >>= 4;
LOG("%s: TH %u -> %u\n, shift data", machine().describe_context(), m_th, th);
}
else
{
LOG("%s: TH %u -> %u\n", machine().describe_context(), m_th, th);
}
m_th = th;
}
}
void sms_paddle_device::device_start()
{
m_idle_timer = timer_alloc(FUNC(sms_paddle_device::timeout), this);
m_nybble = 1;
m_data = 0;
save_item(NAME(m_th));
save_item(NAME(m_nybble));
save_item(NAME(m_data));
m_idle_timer->adjust(delay(), 0, interval());
}
TIMER_CALLBACK_MEMBER(sms_paddle_device::timeout)
{
if (m_nybble)
{
m_nybble = 0;
m_data = m_axis->read();
LOG("timeout: acquire data 0x%02X\n", m_data);
}
else
{
m_nybble = 1;
m_data >>= 4;
LOG("timeout: shift data\n");
}
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_PADDLE, sms_paddle_device, "sms_paddle", "Sega SMS Paddle")
// time interval not verified
// Player 2 of Galactic Protector is the most sensible to this timming.
#define PADDLE_INTERVAL attotime::from_hz(XTAL(10'738'635)/3/100)
CUSTOM_INPUT_MEMBER( sms_paddle_device::rldu_pins_r )
{
uint8_t data = m_paddle_x->read();
if (m_read_state)
data >>= 4;
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
return ~data;
}
READ_LINE_MEMBER( sms_paddle_device::tr_pin_r )
{
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
return ~m_read_state;
}
static INPUT_PORTS_START( sms_paddle )
PORT_START("CTRL_PORT")
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(sms_paddle_device, rldu_pins_r) // R,L,D,U
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(sms_paddle_device, tr_pin_r) // TR
PORT_START("PADDLE_X") // Paddle knob
PORT_BIT( 0xff, 0x80, IPT_PADDLE) PORT_SENSITIVITY(40) PORT_KEYDELTA(20) PORT_CENTERDELTA(0) PORT_MINMAX(0,255)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_paddle_device::device_input_ports() const
{
return INPUT_PORTS_NAME( sms_paddle );
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_paddle_device - constructor
//-------------------------------------------------
sms_paddle_device::sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_PADDLE, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_paddle_pins(*this, "CTRL_PORT"),
m_paddle_x(*this, "PADDLE_X"),
m_read_state(0),
m_interval(PADDLE_INTERVAL)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_paddle_device::device_start()
{
m_start_time = machine().time();
save_item(NAME(m_start_time));
save_item(NAME(m_read_state));
}
//-------------------------------------------------
// sms_peripheral_r - paddle read
//-------------------------------------------------
uint8_t sms_paddle_device::peripheral_r()
{
int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double();
m_read_state = num_intervals & 1;
return m_paddle_pins->read();
}
DEFINE_DEVICE_TYPE_PRIVATE(SMS_PADDLE, device_sms_control_interface, sms_paddle_device, "sms_paddle", "Sega Mark III Paddle (Japan)")

View File

@ -1,58 +1,18 @@
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Mark III "Paddle Control" emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_PADDLE_H
#define MAME_BUS_SMS_CTRL_PADDLE_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_paddle_device
class sms_paddle_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_paddle_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
DECLARE_READ_LINE_MEMBER( tr_pin_r );
protected:
// device-level overrides
virtual void device_start() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
private:
required_ioport m_paddle_pins;
required_ioport m_paddle_x;
uint8_t m_read_state;
attotime m_start_time;
const attotime m_interval;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_PADDLE, sms_paddle_device)
DECLARE_DEVICE_TYPE(SMS_PADDLE, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_PADDLE_H

View File

@ -14,76 +14,98 @@ Release data from the Sega Retro project:
Notes:
This emulated device is the version released by Sega. In Brazil, Tec Toy
released a version that does not have any switch to turn on/off auto-repeat.
This emulated device is the version released by Sega. In Brazil,
Tec Toy released a version that does not have any switch to turn
on/off auto-repeat.
Uses a separate oscillator consisting of a 27k resistor, a 1u
capacitor, and two NOR gates from a 74HCTLS02 for each button. In
reality, the two oscillators will run at slightly different speeds
and drift away from each other, so the buttons won't be
synchronised.
The rapid fire oscillators should start when the button is pressed,
but this would require pushing TL and TR state from the controller
to the port.
**********************************************************************/
#include "emu.h"
#include "rfu.h"
#include "controllers.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
// TYPE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_RAPID_FIRE, sms_rapid_fire_device, "sms_rapid_fire", "Sega SMS Rapid Fire Unit")
class sms_rapid_fire_device : public device_t, public device_sms_control_interface
{
public:
// construction/destruction
sms_rapid_fire_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// time interval not verified
#define RAPID_FIRE_INTERVAL attotime::from_hz(10)
// device_sms_control_interface implementation
virtual uint8_t in_r() override;
virtual void out_w(uint8_t data, uint8_t mem_mask) override;
DECLARE_WRITE_LINE_MEMBER(rapid_changed);
protected:
// device_t implementation
virtual void device_add_mconfig(machine_config &config) override;
virtual ioport_constructor device_input_ports() const override;
virtual void device_config_complete() override;
virtual void device_start() override;
virtual void device_reset() override;
private:
required_device<sms_control_port_device> m_subctrl_port;
required_ioport m_rfire_sw;
uint8_t m_in;
uint8_t m_drive;
uint8_t m_rapid;
};
static INPUT_PORTS_START( sms_rapid_fire )
PORT_START("rfu_sw") // Rapid Fire Unit switches
PORT_CONFNAME( 0x03, 0x00, "Rapid Fire Unit" )
PORT_CONFSETTING( 0x00, DEF_STR( Off ) )
PORT_CONFSETTING( 0x01, "Button 1" )
PORT_CONFSETTING( 0x02, "Button 2" )
PORT_CONFSETTING( 0x03, "Button 1 + 2" )
INPUT_PORTS_START( sms_rapid_fire )
PORT_START("rfu_sw")
PORT_BIT( 0x00, IP_ACTIVE_HIGH, IPT_UNUSED )
PORT_BIT( 0x10, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_TOGGLE PORT_NAME("Rapid Fire 1") PORT_WRITE_LINE_MEMBER(sms_rapid_fire_device, rapid_changed)
PORT_BIT( 0x20, IP_ACTIVE_HIGH, IPT_OTHER ) PORT_TOGGLE PORT_NAME("Rapid Fire 2") PORT_WRITE_LINE_MEMBER(sms_rapid_fire_device, rapid_changed)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_rapid_fire_device::device_input_ports() const
{
return INPUT_PORTS_NAME( sms_rapid_fire );
return INPUT_PORTS_NAME(sms_rapid_fire);
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_rapid_fire_device - constructor
//-------------------------------------------------
sms_rapid_fire_device::sms_rapid_fire_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_RAPID_FIRE, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_rfire_sw(*this, "rfu_sw"),
device_sms_control_interface(mconfig, *this),
m_subctrl_port(*this, "ctrl"),
m_read_state(0),
m_interval(RAPID_FIRE_INTERVAL)
m_rfire_sw(*this, "rfu_sw"),
m_in(0x03),
m_drive(0x00),
m_rapid(0x00)
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_rapid_fire_device::device_start()
WRITE_LINE_MEMBER(sms_rapid_fire_device::rapid_changed)
{
m_start_time = machine().time();
save_item(NAME(m_start_time));
save_item(NAME(m_read_state));
m_rapid = m_rfire_sw->read();
m_subctrl_port->out_w(m_in | m_rapid, m_drive & ~m_rapid);
}
@ -91,51 +113,57 @@ void sms_rapid_fire_device::device_start()
// sms_peripheral_r - rapid fire read
//-------------------------------------------------
uint8_t sms_rapid_fire_device::peripheral_r()
uint8_t sms_rapid_fire_device::in_r()
{
uint8_t data;
uint8_t const read_state = machine().time().as_ticks(10) & 1; // time interval not verified
int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double();
m_read_state = num_intervals & 1;
data = m_subctrl_port->port_r();
/* Check Rapid Fire switch for Button 1 (TL) */
if (!(data & 0x20) && (m_rfire_sw->read() & 0x01))
data |= m_read_state << 5;
/* Check Rapid Fire switch for Button 2 (TR) */
if (!(data & 0x80) && (m_rfire_sw->read() & 0x02))
data |= m_read_state << 7;
return data;
return m_subctrl_port->in_r() | (read_state ? m_rfire_sw->read() : 0U);
}
//-------------------------------------------------
// sms_peripheral_w - rapid fire write
//-------------------------------------------------
void sms_rapid_fire_device::peripheral_w(uint8_t data)
void sms_rapid_fire_device::out_w(uint8_t data, uint8_t mem_mask)
{
m_subctrl_port->port_w(data);
}
//-------------------------------------------------
// device_add_mconfig - add device configuration
//-------------------------------------------------
WRITE_LINE_MEMBER( sms_rapid_fire_device::th_pin_w )
{
m_port->th_pin_w(state);
// TR pulled up via a 4k7 resistor, connected directly to console pin when rapid fire disabled
m_subctrl_port->out_w(data | m_rapid, mem_mask & ~m_rapid);
m_in = data;
m_drive = mem_mask;
}
void sms_rapid_fire_device::device_add_mconfig(machine_config &config)
{
SMS_CONTROL_PORT(config, m_subctrl_port, sms_control_port_devices, "joypad");
if (m_port != nullptr)
m_subctrl_port->set_screen_tag(m_port->m_screen);
m_subctrl_port->th_input_handler().set(FUNC(sms_rapid_fire_device::th_pin_w));
SMS_CONTROL_PORT(config, m_subctrl_port, sms_control_port_devices, SMS_CTRL_OPTION_JOYPAD);
m_subctrl_port->th_handler().set(FUNC(sms_rapid_fire_device::th_w));
}
void sms_rapid_fire_device::device_config_complete()
{
configure_screen(
[this] (auto const &s)
{ subdevice<sms_control_port_device>("ctrl")->set_screen(s); });
}
void sms_rapid_fire_device::device_start()
{
save_item(NAME(m_in));
save_item(NAME(m_drive));
save_item(NAME(m_rapid));
}
void sms_rapid_fire_device::device_reset()
{
m_rapid = m_rfire_sw->read();
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_RAPID_FIRE, device_sms_control_interface, sms_rapid_fire_device, "sms_rapid_fire", "Sega Master System Rapid Fire Unit")

View File

@ -5,56 +5,14 @@
Sega SG-1000/Mark-III/SMS "Rapid Fire Unit" emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_RFU_H
#define MAME_BUS_SMS_CTRL_RFU_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_rapid_fire_device
class sms_rapid_fire_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_rapid_fire_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
protected:
// device-level overrides
virtual void device_start() override;
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
virtual void device_add_mconfig(machine_config &config) override;
// device_sms_control_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_ioport m_rfire_sw;
required_device<sms_control_port_device> m_subctrl_port;
uint8_t m_read_state;
attotime m_start_time;
const attotime m_interval;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_RAPID_FIRE, sms_rapid_fire_device)
DECLARE_DEVICE_TYPE(SMS_RAPID_FIRE, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_RFU_H

View File

@ -1,132 +1,78 @@
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Master System controller port emulation
Sega DE-9 controller port emulation
**********************************************************************/
#include "emu.h"
#include "screen.h"
#include "smsctrl.h"
// slot devices
#include "joypad.h"
#include "lphaser.h"
#include "paddle.h"
#include "sports.h"
#include "sportsjp.h"
#include "rfu.h"
#include "multitap.h"
#include "graphic.h"
//**************************************************************************
// GLOBAL VARIABLES
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_CONTROL_PORT, sms_control_port_device, "sms_control_port", "Sega SMS controller port")
DEFINE_DEVICE_TYPE(SMS_CONTROL_PORT, sms_control_port_device, "sms_control_port", "Sega DE-9 controller port")
//**************************************************************************
// CARD INTERFACE
// CONTROLLER INTERFACE
//**************************************************************************
//-------------------------------------------------
// device_sms_control_port_interface - constructor
//-------------------------------------------------
device_sms_control_port_interface::device_sms_control_port_interface(const machine_config &mconfig, device_t &device)
: device_interface(device, "smsctrl")
device_sms_control_interface::device_sms_control_interface(machine_config const &mconfig, device_t &device) :
device_interface(device, "smsctrl"),
m_port(dynamic_cast<sms_control_port_device *>(device.owner()))
{
m_port = dynamic_cast<sms_control_port_device *>(device.owner());
}
//-------------------------------------------------
// ~device_sms_control_port_interface - destructor
//-------------------------------------------------
device_sms_control_interface::~device_sms_control_interface()
{
}
device_sms_control_port_interface::~device_sms_control_port_interface()
u8 device_sms_control_interface::in_r()
{
return 0xff;
}
void device_sms_control_interface::out_w(u8 data, u8 mem_mask)
{
}
//**************************************************************************
// LIVE DEVICE
// SLOT DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_control_port_device - constructor
//-------------------------------------------------
sms_control_port_device::sms_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
sms_control_port_device::sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
device_t(mconfig, SMS_CONTROL_PORT, tag, owner, clock),
device_slot_interface(mconfig, *this),
device_single_card_slot_interface<device_sms_control_interface>(mconfig, *this),
m_screen(*this, finder_base::DUMMY_TAG),
m_device(nullptr),
m_th_pin_handler(*this)
m_th_handler(*this),
m_controller(nullptr)
{
}
//-------------------------------------------------
// sms_control_port_device - destructor
//-------------------------------------------------
sms_control_port_device::~sms_control_port_device()
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_control_port_device::device_resolve_objects()
{
m_th_handler.resolve_safe();
}
void sms_control_port_device::device_start()
{
m_device = dynamic_cast<device_sms_control_port_interface *>(get_card_device());
m_th_pin_handler.resolve_safe();
}
uint8_t sms_control_port_device::port_r()
{
uint8_t data = 0xff;
if (m_device)
data = m_device->peripheral_r();
return data;
}
void sms_control_port_device::port_w( uint8_t data )
{
if (m_device)
m_device->peripheral_w(data);
}
void sms_control_port_device::th_pin_w(int state)
{
m_th_pin_handler(state);
}
//-------------------------------------------------
// SLOT_INTERFACE( sms_control_port_devices )
//-------------------------------------------------
void sms_control_port_devices(device_slot_interface &device)
{
device.option_add("joypad", SMS_JOYPAD);
device.option_add("lphaser", SMS_LIGHT_PHASER);
device.option_add("paddle", SMS_PADDLE);
device.option_add("sportspad", SMS_SPORTS_PAD);
device.option_add("sportspadjp", SMS_SPORTS_PAD_JP);
device.option_add("rapidfire", SMS_RAPID_FIRE);
device.option_add("multitap", SMS_MULTITAP);
device.option_add("graphic", SMS_GRAPHIC);
m_controller = get_card_device();
}

View File

@ -1,38 +1,55 @@
// license:BSD-3-Clause
// copyright-holders:Fabio Priuli
// copyright-holders:Vas Crabb
/**********************************************************************
Sega Master System controller port emulation
Sega DE-9 controller port emulation
**********************************************************************
1 Up in
2 Down in
3 Left in
4 Right in
5 +5V
6 TL TxD in
7 TH in/out edge-sensitive
8 GND
9 TR RxD in/out
SG-1000 Mark III:
* Pin 7 (TH) tied to ground
* Pin 9 (TR) is input only
Mega Drive:
* All pins besides +5V and GND are in/out
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_SMSCTRL_H
#define MAME_BUS_SMS_CTRL_SMSCTRL_H
#include "screen.h"
#pragma once
#include "screen.h"
#include <utility>
//**************************************************************************
// TYPE DEFINITIONS
// FORWARD DECLARATIONS
//**************************************************************************
// ======================> sms_control_port_device
class device_sms_control_interface;
class device_sms_control_port_interface;
class sms_control_port_device : public device_t,
public device_slot_interface
//**************************************************************************
// CLASS DECLARATIONS
//**************************************************************************
class sms_control_port_device : public device_t, public device_single_card_slot_interface<device_sms_control_interface>
{
public:
// construction/destruction
template <typename T>
sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt)
: sms_control_port_device(mconfig, tag, owner, 0)
sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, T &&opts, char const *dflt) :
sms_control_port_device(mconfig, tag, owner, 0)
{
option_reset();
opts(*this);
@ -40,70 +57,95 @@ public:
set_fixed(false);
}
sms_control_port_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
sms_control_port_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
virtual ~sms_control_port_device();
// static configuration helpers
auto th_input_handler() { return m_th_pin_handler.bind(); }
auto th_handler() { return m_th_handler.bind(); } // 0 for pulled low, 1 for pulled high or high impedance
template <typename T> void set_screen(T &&tag) { m_screen.set_tag(std::forward<T>(tag)); }
// Physical DE-9 connector interface
// 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)
// Bit Pin Signal
// 0 1 Up
// 1 2 Down
// 2 3 Left
// 3 4 Right
// 4 6 TL
// 5 9 TR
//
uint8_t port_r();
void port_w( uint8_t data );
// return bits set for pulled high or high impedance
// return bits clear for pulled low
u8 in_r();
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;
// Bit Pin Signal
// 0 1 Up
// 1 2 Down
// 2 3 Left
// 3 4 Right
// 4 6 TL
// 5 9 TR
// 6 7 TH
//
// mem_mask bits set for lines driven by low impedance output
// mem_mask bits clear for lines with high-impedance pull-up/pull-down
void out_w(u8 data, u8 mem_mask);
protected:
// device-level overrides
virtual void device_resolve_objects() override;
virtual void device_start() override;
device_sms_control_port_interface *m_device;
private:
devcb_write_line m_th_pin_handler;
optional_device<screen_device> m_screen;
devcb_write_line m_th_handler;
device_sms_control_interface *m_controller;
friend class device_sms_control_interface;
};
// ======================> device_sms_control_port_interface
// class representing interface-specific live sms_expansion card
class device_sms_control_port_interface : public device_interface
class device_sms_control_interface : public device_interface
{
public:
// construction/destruction
virtual ~device_sms_control_port_interface();
virtual ~device_sms_control_interface();
virtual uint8_t peripheral_r() { return 0xff; }
virtual void peripheral_w(uint8_t data) { }
virtual u8 in_r();
virtual void out_w(u8 data, u8 mem_mask);
protected:
device_sms_control_port_interface(const machine_config &mconfig, device_t &device);
device_sms_control_interface(machine_config const &mconfig, device_t &device);
sms_control_port_device *m_port;
template <typename T> void configure_screen(T &&act) { if (m_port) act(std::as_const(m_port->m_screen)); }
screen_device *screen() const { return m_port ? m_port->m_screen.target() : nullptr; }
DECLARE_WRITE_LINE_MEMBER(th_w) { if (m_port) m_port->m_th_handler(state); }
private:
sms_control_port_device *const m_port;
};
// device type definition
//**************************************************************************
// INLINE MEMBER FUNCTIONS
//**************************************************************************
inline u8 sms_control_port_device::in_r()
{
return m_controller ? m_controller->in_r() : 0xff;
}
inline void sms_control_port_device::out_w(u8 data, u8 mem_mask)
{
if (m_controller)
m_controller->out_w(data, mem_mask);
}
//**************************************************************************
// DEVICE TYPE DECLARATIONS
//**************************************************************************
DECLARE_DEVICE_TYPE(SMS_CONTROL_PORT, sms_control_port_device)
void sms_control_port_devices(device_slot_interface &device);
#endif // MAME_BUS_SMS_CTRL_SMSCTRL_H

View File

@ -23,7 +23,7 @@ Notes:
when it does not detect use by a Japanese SMS console, because the Sega
Mark III lacks the TH line. There was a different Sports Pad model released
in Japan and no information was found about it supporting both modes, so
that model is currently emulated as a different device (see sportsjp.c).
that model is currently emulated as a different device (see sportsjp.cpp).
It was discovered that games designed for the Paddle Controller, released
in Japan, will switch to a mode incompatible with the original Paddle when
@ -41,129 +41,91 @@ Notes:
#include "sports.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
INPUT_PORTS_START( sms_sports_pad )
PORT_START("SPORTS_BT")
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR
DEFINE_DEVICE_TYPE(SMS_SPORTS_PAD, sms_sports_pad_device, "sms_sports_pad", "Sega SMS Sports Pad (US)")
// time interval not verified
#define SPORTS_PAD_INTERVAL attotime::from_hz(XTAL(10'738'635)/3/512)
TIMER_CALLBACK_MEMBER(sms_sports_pad_device::read_tick)
{
// values for x and y axis need to be reset for Sports Pad games, but
// are not reset for paddle games, so it was assumed the reset occurs
// only when this timer fires after the read state reaches its maximum value.
if (m_read_state == 3)
{
m_x_axis_reset_value = m_sports_x->read();
m_y_axis_reset_value = m_sports_y->read();
}
else
{
// set to maximum value, so it wraps to 0 at next increment
m_read_state = 3;
}
}
READ_LINE_MEMBER( sms_sports_pad_device::th_pin_r )
{
return m_th_pin_state;
}
WRITE_LINE_MEMBER( sms_sports_pad_device::th_pin_w )
{
m_read_state = (m_read_state + 1) & 3;
m_sportspad_timer->adjust(m_interval);
m_th_pin_state = state;
}
CUSTOM_INPUT_MEMBER( sms_sports_pad_device::rldu_pins_r )
{
uint8_t data = 0;
switch (m_read_state)
{
case 0:
data = (m_sports_x->read() - m_x_axis_reset_value) >> 4;
break;
case 1:
data = (m_sports_x->read() - m_x_axis_reset_value);
break;
case 2:
data = (m_sports_y->read() - m_y_axis_reset_value) >> 4;
break;
case 3:
data = (m_sports_y->read() - m_y_axis_reset_value);
break;
}
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
return ~(data & 0x0f);
}
static INPUT_PORTS_START( sms_sports_pad )
PORT_START("SPORTS_IN")
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(sms_sports_pad_device, rldu_pins_r) // R,L,D,U
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL (Button 1)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(sms_sports_pad_device, th_pin_r) // TH
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR (Button 2)
PORT_START("SPORTS_OUT")
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_UNUSED ) // Directional pins
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_UNUSED ) // TL (Button 1)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_OUTPUT ) PORT_WRITE_LINE_MEMBER(sms_sports_pad_device, th_pin_w) // TH
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) // TR (Button 2)
PORT_START("SPORTS_X") /* Sports Pad X axis */
PORT_START("SPORTS_X") // X axis
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_REVERSE
PORT_START("SPORTS_Y") /* Sports Pad Y axis */
PORT_START("SPORTS_Y") // Y axis
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40) PORT_REVERSE
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_sports_pad_device::device_input_ports() const
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class sms_sports_pad_device : public device_t, public device_sms_control_interface
{
return INPUT_PORTS_NAME( sms_sports_pad );
public:
// construction/destruction
sms_sports_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_sms_control_interface implementation
virtual uint8_t in_r() override;
virtual void out_w(uint8_t data, uint8_t mem_mask) override;
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_sports_pad); }
virtual void device_start() override;
private:
TIMER_CALLBACK_MEMBER(timeout);
required_ioport m_buttons;
required_ioport m_x_axis;
required_ioport m_y_axis;
emu_timer *m_timeout_timer;
uint8_t m_phase;
uint8_t m_th_state;
uint8_t m_x_base;
uint8_t m_y_base;
uint8_t m_data;
};
TIMER_CALLBACK_MEMBER(sms_sports_pad_device::timeout)
{
// values for x and y axis need to be reset for Sports Pad games, but
// are not reset for paddle games, so it was assumed the reset occurs
// only when this timer fires after the read state reaches its maximum value.
if (3U == m_phase)
{
m_x_base = m_x_axis->read();
m_y_base = m_y_axis->read();
}
else
{
// set to maximum value, so it wraps to 0 at next increment
m_phase = 3;
}
}
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_sports_pad_device - constructor
//-------------------------------------------------
sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_SPORTS_PAD, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_sports_in(*this, "SPORTS_IN"),
m_sports_out(*this, "SPORTS_OUT"),
m_sports_x(*this, "SPORTS_X"),
m_sports_y(*this, "SPORTS_Y"),
m_read_state(0),
m_th_pin_state(0),
m_x_axis_reset_value(0x80), // value 0x80 helps when starting paddle games.
m_y_axis_reset_value(0x80),
m_interval(SPORTS_PAD_INTERVAL),
m_sportspad_timer(nullptr)
device_sms_control_interface(mconfig, *this),
m_buttons(*this, "SPORTS_BT"),
m_x_axis(*this, "SPORTS_X"),
m_y_axis(*this, "SPORTS_Y"),
m_timeout_timer(nullptr),
m_phase(0),
m_th_state(1),
m_x_base(0),
m_y_base(0)
{
}
@ -174,20 +136,63 @@ sms_sports_pad_device::sms_sports_pad_device(const machine_config &mconfig, cons
void sms_sports_pad_device::device_start()
{
m_sportspad_timer = timer_alloc(FUNC(sms_sports_pad_device::read_tick), this);
m_timeout_timer = timer_alloc(FUNC(sms_sports_pad_device::timeout), this);
save_item(NAME(m_read_state));
save_item(NAME(m_th_pin_state));
save_item(NAME(m_x_axis_reset_value));
save_item(NAME(m_y_axis_reset_value));
m_phase = 0;
m_x_base = 0x80; // value 0x80 helps when starting paddle games.
m_y_base = 0x80;
save_item(NAME(m_phase));
save_item(NAME(m_th_state));
save_item(NAME(m_x_base));
save_item(NAME(m_y_base));
}
uint8_t sms_sports_pad_device::peripheral_r()
uint8_t sms_sports_pad_device::in_r()
{
return m_sports_in->read();
uint8_t result = m_buttons->read();
switch (m_phase)
{
case 0:
result |= BIT(m_x_axis->read() - m_x_base, 4, 4);
break;
case 1:
result |= BIT(m_x_axis->read() - m_x_base, 0, 4);
break;
case 2:
result |= BIT(m_y_axis->read() - m_y_base, 4, 4);
break;
case 3:
result |= BIT(m_y_axis->read() - m_y_base, 0, 4);
break;
}
return result;
}
void sms_sports_pad_device::peripheral_w(uint8_t data)
void sms_sports_pad_device::out_w(uint8_t data, uint8_t mem_mask)
{
m_sports_out->write(data);
uint8_t const th_state = BIT(data, 6);
// FIXME: this is definitely wrong - work out how it actually responds to edges
if (th_state != m_th_state)
{
m_phase = (m_phase + 1) & 3;
m_timeout_timer->adjust(attotime::from_hz(XTAL(10'738'635) / 3 / 512)); // timeout not verified
}
m_th_state = th_state;
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_SPORTS_PAD, device_sms_control_interface, sms_sports_pad_device, "sms_sports_pad", "Sega SMS Sports Pad (US)")

View File

@ -5,64 +5,14 @@
Sega Master System "Sports Pad" (US model) emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTRL_SPORTS_H
#define MAME_BUS_SMS_CTRL_SPORTS_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_sports_pad_device
class sms_sports_pad_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_sports_pad_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
DECLARE_READ_LINE_MEMBER( th_pin_r );
DECLARE_WRITE_LINE_MEMBER( th_pin_w );
protected:
// device-level overrides
virtual void device_start() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
virtual void peripheral_w(uint8_t data) override;
private:
required_ioport m_sports_in;
required_ioport m_sports_out;
required_ioport m_sports_x;
required_ioport m_sports_y;
uint8_t m_read_state;
uint8_t m_th_pin_state;
uint8_t m_x_axis_reset_value;
uint8_t m_y_axis_reset_value;
const attotime m_interval;
emu_timer *m_sportspad_timer;
TIMER_CALLBACK_MEMBER(read_tick);
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_SPORTS_PAD, sms_sports_pad_device)
DECLARE_DEVICE_TYPE(SMS_SPORTS_PAD, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTRL_SPORTS_H

View File

@ -45,59 +45,47 @@ Notes:
#include "sportsjp.h"
namespace {
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE(SMS_SPORTS_PAD_JP, sms_sports_pad_jp_device, "sms_sports_pad_jp", "Sega SMS Sports Pad (JP)")
// time interval not verified
#define SPORTS_PAD_JP_INTERVAL attotime::from_hz(20000)
// The returned value is inverted due to IP_ACTIVE_LOW mapping.
READ_LINE_MEMBER( sms_sports_pad_jp_device::tl_pin_r ) { return ~m_tl_pin_state; }
READ_LINE_MEMBER( sms_sports_pad_jp_device::tr_pin_r ) { return ~m_tr_pin_state; }
CUSTOM_INPUT_MEMBER( sms_sports_pad_jp_device::rldu_pins_r ) { return ~(m_rldu_pins_state & 0x0f); }
static INPUT_PORTS_START( sms_sports_pad_jp )
PORT_START("SPORTS_JP_IN")
PORT_BIT( 0x0f, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_CUSTOM_MEMBER(sms_sports_pad_jp_device, rldu_pins_r) // R,L,D,U
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) // Vcc
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(sms_sports_pad_jp_device, tl_pin_r) // TL
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_UNUSED ) // TH
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_CUSTOM ) PORT_READ_LINE_MEMBER(sms_sports_pad_jp_device, tr_pin_r) // TR
PORT_START("SPORTS_JP_BT") /* Sports Pad buttons nibble */
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 )
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 )
INPUT_PORTS_START( sms_sports_pad_jp )
PORT_START("SPORTS_JP_BT") // buttons
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON1 ) // TL
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON2 ) // TR
PORT_BIT( 0x0c, IP_ACTIVE_LOW, IPT_UNUSED )
PORT_START("SPORTS_JP_X") /* Sports Pad X axis */
PORT_START("SPORTS_JP_X") // X axis
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_X ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40)
PORT_START("SPORTS_JP_Y") /* Sports Pad Y axis */
PORT_START("SPORTS_JP_Y") // Y axis
PORT_BIT( 0xff, 0x00, IPT_TRACKBALL_Y ) PORT_SENSITIVITY(50) PORT_KEYDELTA(40)
INPUT_PORTS_END
//-------------------------------------------------
// input_ports - device-specific input ports
//-------------------------------------------------
ioport_constructor sms_sports_pad_jp_device::device_input_ports() const
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
class sms_sports_pad_jp_device : public device_t, public device_sms_control_interface
{
return INPUT_PORTS_NAME( sms_sports_pad_jp );
}
public:
// construction/destruction
sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// device_sms_control_interface implementation
virtual uint8_t in_r() override;
protected:
// device_t implementation
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(sms_sports_pad_jp); }
virtual void device_start() override { }
private:
required_ioport m_buttons;
required_ioport m_x_axis;
required_ioport m_y_axis;
};
//**************************************************************************
// LIVE DEVICE
//**************************************************************************
//-------------------------------------------------
// sms_sports_pad_jp_device - constructor
@ -105,75 +93,44 @@ ioport_constructor sms_sports_pad_jp_device::device_input_ports() const
sms_sports_pad_jp_device::sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
device_t(mconfig, SMS_SPORTS_PAD_JP, tag, owner, clock),
device_sms_control_port_interface(mconfig, *this),
m_sports_jp_in(*this, "SPORTS_JP_IN"),
m_sports_jp_bt(*this, "SPORTS_JP_BT"),
m_sports_jp_x(*this, "SPORTS_JP_X"),
m_sports_jp_y(*this, "SPORTS_JP_Y"),
m_rldu_pins_state(0x0f),
m_tl_pin_state(1),
m_tr_pin_state(1),
m_interval(SPORTS_PAD_JP_INTERVAL)
device_sms_control_interface(mconfig, *this),
m_buttons(*this, "SPORTS_JP_BT"),
m_x_axis(*this, "SPORTS_JP_X"),
m_y_axis(*this, "SPORTS_JP_Y")
{
}
//-------------------------------------------------
// device_start - device-specific startup
//-------------------------------------------------
void sms_sports_pad_jp_device::device_start()
{
m_start_time = machine().time();
save_item(NAME(m_start_time));
save_item(NAME(m_rldu_pins_state));
save_item(NAME(m_tl_pin_state));
save_item(NAME(m_tr_pin_state));
}
//-------------------------------------------------
// sms_peripheral_r - sports pad read
//-------------------------------------------------
uint8_t sms_sports_pad_jp_device::peripheral_r()
uint8_t sms_sports_pad_jp_device::in_r()
{
int num_intervals = (machine().time() - m_start_time).as_double() / m_interval.as_double();
int const num_intervals = machine().time().as_ticks(20000); // time interval not verified
switch (num_intervals % 5)
{
case 0:
// X high nibble
m_rldu_pins_state = m_sports_jp_x->read() >> 4;
m_tl_pin_state = 0;
m_tr_pin_state = 0;
break;
case 1:
// X low nibble
m_rldu_pins_state = m_sports_jp_x->read();
m_tl_pin_state = 1;
m_tr_pin_state = 0;
break;
case 2:
// Y high nibble
m_rldu_pins_state = m_sports_jp_y->read() >> 4;
m_tl_pin_state = 0;
m_tr_pin_state = 0;
break;
case 3:
// Y low nibble
m_rldu_pins_state = m_sports_jp_y->read();
m_tl_pin_state = 1;
m_tr_pin_state = 0;
break;
case 4:
// buttons 1 and 2
m_rldu_pins_state = m_sports_jp_bt->read();
m_tl_pin_state = 1;
m_tr_pin_state = 1;
break;
default: // shut up dumb compilers
case 0: // X high nibble
return 0x00 | ((m_x_axis->read() >> 4) & 0x0f);
case 1: // X low nibble
return 0x10 | (m_x_axis->read() & 0x0f);
case 2: // Y high nibble
return 0x00 | ((m_y_axis->read() >> 4) & 0x0f);
case 3: // Y low nibble
return 0x10 | (m_y_axis->read() & 0x0f);
case 4: // buttons 1 and 2
return 0x30 | m_buttons->read();
}
return m_sports_jp_in->read();
}
} // anonymous namespace
//**************************************************************************
// DEVICE DEFINITIONS
//**************************************************************************
DEFINE_DEVICE_TYPE_PRIVATE(SMS_SPORTS_PAD_JP, device_sms_control_interface, sms_sports_pad_jp_device, "sms_sports_pad_jp", "Sega Mark III Sports Pad (Japan)")

View File

@ -5,60 +5,14 @@
Sega Master System "Sports Pad" (Japanese model) emulation
**********************************************************************/
#ifndef MAME_BUS_SMS_CTROL_SPORTSJP_H
#define MAME_BUS_SMS_CTROL_SPORTSJP_H
#pragma once
#include "smsctrl.h"
//**************************************************************************
// TYPE DEFINITIONS
//**************************************************************************
// ======================> sms_sports_pad_jp_device
class sms_sports_pad_jp_device : public device_t,
public device_sms_control_port_interface
{
public:
// construction/destruction
sms_sports_pad_jp_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock);
// optional information overrides
virtual ioport_constructor device_input_ports() const override;
DECLARE_CUSTOM_INPUT_MEMBER( rldu_pins_r ); // Right, Left, Down and Up lines.
DECLARE_READ_LINE_MEMBER( tl_pin_r );
DECLARE_READ_LINE_MEMBER( tr_pin_r );
protected:
// device-level overrides
virtual void device_start() override;
// device_sms_control_port_interface overrides
virtual uint8_t peripheral_r() override;
private:
required_ioport m_sports_jp_in;
required_ioport m_sports_jp_bt;
required_ioport m_sports_jp_x;
required_ioport m_sports_jp_y;
uint8_t m_rldu_pins_state;
uint8_t m_tl_pin_state;
uint8_t m_tr_pin_state;
attotime m_start_time;
const attotime m_interval;
};
// device type definition
DECLARE_DEVICE_TYPE(SMS_SPORTS_PAD_JP, sms_sports_pad_jp_device)
DECLARE_DEVICE_TYPE(SMS_SPORTS_PAD_JP, device_sms_control_interface)
#endif // MAME_BUS_SMS_CTROL_SPORTSJP_H

View File

@ -6,6 +6,7 @@
#include "bus/generic/carts.h"
#include "bus/generic/slot.h"
#include "bus/sms_ctrl/controllers.h"
#include "imagedev/chd_cd.h"
#include "sound/sn76496.h"
@ -24,139 +25,57 @@
/* They're needed to give the users the choice between different controllers */
uint8_t md_cons_state::mess_md_io_read_data_port(offs_t offset)
{
int portnum = offset;
// get bits set to output first - bit 7 always reads the latch
uint8_t const mask = m_io_ctrl_regs[offset] | 0x80;
uint8_t result = mask & m_io_data_regs[offset];
uint8_t retdata;
int controller;
uint8_t helper_6b = (m_megadrive_io_ctrl_regs[portnum] & 0x3f) | 0xc0; // bits 6 & 7 always come from megadrive_io_data_regs
uint8_t helper_3b = (m_megadrive_io_ctrl_regs[portnum] & 0x7f) | 0x80; // bit 7 always comes from megadrive_io_data_regs
switch (portnum)
switch (offset)
{
case 0:
controller = (m_io_ctrlr->read() & 0x0f);
break;
case 0:
case 1:
result |= ~mask & (m_io_ctrl_th_in[offset] | (m_ctrl_ports[offset]->in_r() & 0x3f));
break;
case 1:
controller = (m_io_ctrlr->read() & 0xf0);
break;
default:
controller = 0;
break;
default: // TODO: where does this come from on a console?
result |= 0x7f;
}
/* Are we using a 6 buttons Joypad? */
if (controller)
{
if (m_megadrive_io_data_regs[portnum] & 0x40)
{
if (m_io_stage[portnum] == 2)
{
/* here we read B, C & the additional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper_6b) |
((((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0x30) |
((m_io_pad6b[1][portnum] ? m_io_pad6b[1][portnum]->read() : 0) & 0x0f)) & ~helper_6b);
}
else
{
/* here we read B, C & the directional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper_6b) |
(((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0x3f) & ~helper_6b);
}
}
else
{
if (m_io_stage[portnum] == 1)
{
/* here we read ((Start & A) >> 2) | 0x00 */
retdata = (m_megadrive_io_data_regs[portnum] & helper_6b) |
((((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0xc0) >> 2) & ~helper_6b);
}
else if (m_io_stage[portnum]==2)
{
/* here we read ((Start & A) >> 2) | 0x0f */
retdata = (m_megadrive_io_data_regs[portnum] & helper_6b) |
(((((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0xc0) >> 2) | 0x0f) & ~helper_6b);
}
else
{
/* here we read ((Start & A) >> 2) | Up and Down */
retdata = (m_megadrive_io_data_regs[portnum] & helper_6b) |
(((((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0xc0) >> 2) |
((m_io_pad6b[0][portnum] ? m_io_pad6b[0][portnum]->read() : 0) & 0x03)) & ~helper_6b);
}
}
// handle test input for SVP test
if (!offset && m_cart && m_cart->read_test())
result = m_io_data_regs[0] & 0xc0;
// osd_printf_debug("read io data port stage %d port %d %02x\n",mess_io_stage[portnum],portnum,retdata);
retdata |= (retdata << 8);
}
/* Otherwise it's a 3 buttons Joypad */
else
{
uint8_t svp_test = 0;
if (m_cart)
svp_test = m_cart->read_test();
// handle test input for SVP test
if (portnum == 0 && svp_test)
{
retdata = (m_megadrive_io_data_regs[0] & 0xc0);
}
else if (m_megadrive_io_data_regs[portnum] & 0x40)
{
/* here we read B, C & the directional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper_3b) |
((((m_io_pad3b[portnum] ? m_io_pad3b[portnum]->read() : 0) & 0x3f) | 0x40) & ~helper_3b);
}
else
{
/* here we read ((Start & A) >> 2) | Up and Down */
retdata = (m_megadrive_io_data_regs[portnum] & helper_3b) |
(((((m_io_pad3b[portnum] ? m_io_pad3b[portnum]->read() : 0) & 0xc0) >> 2) |
((m_io_pad3b[portnum] ? m_io_pad3b[portnum]->read() : 0) & 0x03) | 0x40) & ~helper_3b);
}
}
return retdata;
return result;
}
void md_cons_state::mess_md_io_write_data_port(offs_t offset, uint16_t data)
{
int portnum = offset;
int controller;
// FIXME: need to update the port when I/O direction changes, too
switch (portnum)
switch (offset)
{
case 0:
controller = (m_io_ctrlr->read() & 0x0f);
break;
case 0:
case 1:
m_ctrl_ports[offset]->out_w((data | ~m_io_ctrl_regs[offset]) & 0x7f, m_io_ctrl_regs[offset] & 0x7f);
break;
case 1:
controller = (m_io_ctrlr->read() & 0xf0);
break;
default:
controller = 0;
break;
default: // TODO: where does this go on a console?
break;
}
if (controller)
{
if (m_megadrive_io_ctrl_regs[portnum] & 0x40)
{
if (((m_megadrive_io_data_regs[portnum] & 0x40) == 0x00) && ((data & 0x40) == 0x40))
{
m_io_stage[portnum]++;
m_io_timeout[portnum]->adjust(m_maincpu->cycles_to_attotime(8192));
}
m_io_data_regs[offset] = data;
}
}
}
m_megadrive_io_data_regs[portnum] = data;
//osd_printf_debug("Writing IO Data Register #%d data %04x\n",portnum,data);
void md_cons_state::md_ctrl_ports(machine_config &config)
{
SMS_CONTROL_PORT(config, m_ctrl_ports[0], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD);
m_ctrl_ports[0]->th_handler().set([this] (int state) { m_io_ctrl_th_in[0] = state ? 0x40 : 0x00; });
m_ctrl_ports[0]->set_screen(m_screen);
SMS_CONTROL_PORT(config, m_ctrl_ports[1], sms_control_port_devices, SMS_CTRL_OPTION_MD_PAD);
m_ctrl_ports[1]->th_handler().set([this] (int state) { m_io_ctrl_th_in[1] = state ? 0x40 : 0x00; });
m_ctrl_ports[1]->set_screen(m_screen);
}
@ -167,96 +86,22 @@ void md_cons_state::mess_md_io_write_data_port(offs_t offset, uint16_t data)
*************************************/
static INPUT_PORTS_START( md_base )
PORT_START("PAD1_3B") /* Joypad 1 (3 button + start) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 B") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 C") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 A") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x00)
static INPUT_PORTS_START( md )
// Unemulated controllers:
// Sega Mouse
// Sega Menacer
// Konami Justifier
// Sega Team Player
// EA 4-Play
/* there exists both a 2 buttons version of the Mouse (Jpn ver, to be used with RPGs, it
can aslo be used as trackball) and a 3 buttons version (US ver, no trackball feats.) */
PORT_START("PAD2_3B") /* Joypad 2 (3 button + start) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 B") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 C") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 A") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x00)
PORT_START("PAD1_6B") /* Joypad 1 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("P1 B") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("P1 C") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("P1 A") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_START("EXTRA1") /* Extra buttons for Joypad 1 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Z") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 Y") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("P1 X") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("P1 Mode") PORT_CONDITION("CTRLSEL", 0x0f, EQUALS, 0x01)
PORT_START("PAD2_6B") /* Joypad 2 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("P2 B") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("P2 C") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("P2 A") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_START("EXTRA2") /* Extra buttons for Joypad 2 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("P2 Z") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("P2 Y") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("P2 X") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("P2 Mode") PORT_CONDITION("CTRLSEL", 0xf0, EQUALS, 0x10)
PORT_START("RESET") /* Buttons on Genesis Console */
PORT_START("RESET") // Buttons on Mega Drive console
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_SERVICE1 ) PORT_NAME("Reset Button") PORT_IMPULSE(1) // reset, resets 68k (and..?)
INPUT_PORTS_END
static INPUT_PORTS_START( md )
PORT_INCLUDE( md_base )
PORT_START("CTRLSEL") /* Controller selection */
PORT_CONFNAME( 0x0f, 0x00, "Player 1 Controller" )
PORT_CONFSETTING( 0x00, "Joystick 3 Buttons" )
PORT_CONFSETTING( 0x01, "Joystick 6 Buttons" )
// PORT_CONFSETTING( 0x02, "Sega Mouse" )
/* there exists both a 2 buttons version of the Mouse (Jpn ver, to be used with RPGs, it
can aslo be used as trackball) and a 3 buttons version (US ver, no trackball feats.) */
// PORT_CONFSETTING( 0x03, "Sega Menacer" )
// PORT_CONFSETTING( 0x04, "Konami Justifier" )
// PORT_CONFSETTING( 0x05, "Team Player (Sega Multitap)" )
// PORT_CONFSETTING( 0x06, "4-Play (EA Multitap)" )
// PORT_CONFSETTING( 0x07, "J-Cart" )
PORT_CONFNAME( 0xf0, 0x00, "Player 2 Controller" )
PORT_CONFSETTING( 0x00, "Joystick 3 Buttons" )
PORT_CONFSETTING( 0x10, "Joystick 6 Buttons" )
INPUT_PORTS_END
static INPUT_PORTS_START( megajet )
PORT_INCLUDE( md_base )
PORT_START("CTRLSEL") /* Fixed controller setting for Player 1 */
PORT_CONFNAME( 0x0f, 0x01, "Player 1 Controller" ) // Fixed
PORT_CONFSETTING( 0x01, "Joystick 6 Buttons" )
PORT_CONFNAME( 0xf0, 0x00, "Player 2 Controller" )
PORT_CONFSETTING( 0x00, "Joystick 3 Buttons" )
PORT_CONFSETTING( 0x10, "Joystick 6 Buttons" )
INPUT_PORTS_END
static INPUT_PORTS_START( gen_nomd )
PORT_INCLUDE( megajet )
PORT_INCLUDE( md )
PORT_MODIFY("RESET") /* No reset button */
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_UNUSED )
@ -271,24 +116,10 @@ INPUT_PORTS_END
void md_cons_state::machine_start()
{
static const char *const pad6names[2][4] = {
{ "PAD1_6B", "PAD2_6B", "UNUSED", "UNUSED" },
{ "EXTRA1", "EXTRA2", "UNUSED", "UNUSED" }
};
static const char *const pad3names[4] = { "PAD1_3B", "PAD2_3B", "UNUSED", "UNUSED" };
m_io_ctrl_th_in[0] = 0x40;
m_io_ctrl_th_in[1] = 0x40;
m_io_ctrlr = ioport("CTRLSEL");
for (int i = 0; i < 4; i++)
{
m_io_pad3b[i] = ioport(pad3names[i]);
m_io_pad6b[0][i] = ioport(pad6names[0][i]);
m_io_pad6b[1][i] = ioport(pad6names[1][i]);
}
// setup timers for 6 button pads
for (int i = 0; i < 3; i++)
m_io_timeout[i] = timer_alloc(FUNC(md_base_state::io_timeout_timer_callback), this);
save_item(NAME(m_io_ctrl_th_in));
m_vdp->stop_timers();
@ -415,7 +246,9 @@ void md_cons_slot_state::ms_megadriv(machine_config &config)
{
md_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_slot_state::screen_vblank_console));
md_ctrl_ports(config);
MD_CART_SLOT(config, m_cart, md_cart, nullptr).set_must_be_loaded(true);
SOFTWARE_LIST(config, "cart_list").set_original("megadriv");
@ -425,7 +258,9 @@ void md_cons_slot_state::ms_megadpal(machine_config &config)
{
md_pal(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_slot_state::screen_vblank_console));
md_ctrl_ports(config);
MD_CART_SLOT(config, m_cart, md_cart, nullptr).set_must_be_loaded(true);
SOFTWARE_LIST(config, "cart_list").set_original("megadriv");
@ -435,12 +270,23 @@ void md_cons_slot_state::ms_megadriv2(machine_config &config)
{
md2_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_slot_state::screen_vblank_console));
md_ctrl_ports(config);
MD_CART_SLOT(config, m_cart, md_cart, nullptr).set_must_be_loaded(true);
SOFTWARE_LIST(config, "cart_list").set_original("megadriv");
}
void md_cons_slot_state::ms_megajet(machine_config &config)
{
ms_megadriv2(config);
// P1 controller is integrated
m_ctrl_ports[0]->set_default_option(SMS_CTRL_OPTION_MD_6BUTTON);
m_ctrl_ports[0]->set_fixed(true);
}
void md_cons_slot_state::genesis_tmss(machine_config &config)
{
ms_megadriv(config);
@ -451,7 +297,9 @@ void md_cons_state::dcat16_megadriv(machine_config &config)
{
dcat16_megadriv_base(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
md_ctrl_ports(config);
// has SD card slot instead?
// MD_CART_SLOT(config, m_cart, md_cart, nullptr).set_must_be_loaded(true);
@ -465,7 +313,7 @@ void md_cons_state::dcat16_megadriv(machine_config &config)
*************************************/
/* we don't use the bios rom (it's not needed and only provides security on early models) */
/* we don't use the BIOS ROM (it's not needed and only provides security on early models) */
ROM_START(genesis)
ROM_REGION(MD_CPU_REGION_SIZE, "maincpu", ROMREGION_ERASEFF)
@ -515,8 +363,8 @@ ROM_END
void md_cons_state::init_mess_md_common()
{
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_cons_state::mess_md_io_read_data_port));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_cons_state::mess_md_io_write_data_port));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_cons_state::mess_md_io_read_data_port));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_cons_state::mess_md_io_write_data_port));
}
void md_cons_state::init_genesis()
@ -660,7 +508,7 @@ void md_cons_state::genesis_32x(machine_config &config)
m_32x->add_route(0, "lspeaker", 1.00);
m_32x->add_route(1, "rspeaker", 1.00);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
// we need to remove and re-add the YM because the balance is different
// due to MAME having severe issues if the dac output is > 0.40? (sound is corrupted even if DAC is silent?!)
@ -668,6 +516,8 @@ void md_cons_state::genesis_32x(machine_config &config)
m_ymsnd->add_route(0, "lspeaker", (0.50)/2);
m_ymsnd->add_route(1, "rspeaker", (0.50)/2);
md_ctrl_ports(config);
generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin"));
cartslot.set_must_be_loaded(true);
cartslot.set_device_load(FUNC(md_cons_state::_32x_cart));
@ -692,7 +542,7 @@ void md_cons_state::mdj_32x(machine_config &config)
m_32x->add_route(0, "lspeaker", 1.00);
m_32x->add_route(1, "rspeaker", 1.00);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
// we need to remove and re-add the sound system because the balance is different
// due to MAME having severe issues if the dac output is > 0.40? (sound is corrupted even if DAC is silent?!)
@ -700,6 +550,8 @@ void md_cons_state::mdj_32x(machine_config &config)
m_ymsnd->add_route(0, "lspeaker", (0.50)/2);
m_ymsnd->add_route(1, "rspeaker", (0.50)/2);
md_ctrl_ports(config);
generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin"));
cartslot.set_must_be_loaded(true);
cartslot.set_device_load(FUNC(md_cons_state::_32x_cart));
@ -724,7 +576,7 @@ void md_cons_state::md_32x(machine_config &config)
m_32x->add_route(0, "lspeaker", 1.00);
m_32x->add_route(1, "rspeaker", 1.00);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
// we need to remove and re-add the sound system because the balance is different
// due to MAME having severe issues if the dac output is > 0.40? (sound is corrupted even if DAC is silent?!)
@ -732,6 +584,8 @@ void md_cons_state::md_32x(machine_config &config)
m_ymsnd->add_route(0, "lspeaker", (0.50)/2);
m_ymsnd->add_route(1, "rspeaker", (0.50)/2);
md_ctrl_ports(config);
generic_cartslot_device &cartslot(GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin"));
cartslot.set_must_be_loaded(true);
cartslot.set_device_load(FUNC(md_cons_state::_32x_cart));
@ -776,7 +630,7 @@ void md_cons_cd_state::genesis_scd(machine_config &config)
{
md_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_US(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -785,6 +639,8 @@ void md_cons_cd_state::genesis_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("segacd");
@ -794,7 +650,7 @@ void md_cons_cd_state::genesis2_scd(machine_config &config)
{
md2_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_US(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -803,6 +659,8 @@ void md_cons_cd_state::genesis2_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("segacd");
@ -812,7 +670,7 @@ void md_cons_cd_state::md_scd(machine_config &config)
{
md_pal(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_EUROPE(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -821,6 +679,8 @@ void md_cons_cd_state::md_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("megacd");
@ -830,7 +690,7 @@ void md_cons_cd_state::md2_scd(machine_config &config)
{
md2_pal(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_EUROPE(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -839,6 +699,8 @@ void md_cons_cd_state::md2_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("megacd");
@ -848,7 +710,7 @@ void md_cons_cd_state::mdj_scd(machine_config &config)
{
md_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_JAPAN(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -857,6 +719,8 @@ void md_cons_cd_state::mdj_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("megacdj");
@ -866,7 +730,7 @@ void md_cons_cd_state::md2j_scd(machine_config &config)
{
md2_ntsc(config);
subdevice<screen_device>("megadriv")->screen_vblank().set(FUNC(md_cons_state::screen_vblank_console));
m_screen->screen_vblank().set(FUNC(md_cons_cd_state::screen_vblank_console));
SEGA_SEGACD_JAPAN(config, m_segacd, 0);
m_segacd->set_palette("gen_vdp:gfx_palette");
@ -875,6 +739,8 @@ void md_cons_cd_state::md2j_scd(machine_config &config)
config.set_perfect_quantum("segacd:segacd_68k"); // perfect sync to the fastest cpu
md_ctrl_ports(config);
CDROM(config, "cdrom").set_interface("scd_cdrom");
SOFTWARE_LIST(config, "cd_list").set_original("megacdj");
@ -896,7 +762,7 @@ void md_cons_cd_state::genesis_32x_scd(machine_config &config)
CDROM(config, "cdrom").set_interface("scd_cdrom");
config.device_remove("cartslot");
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_state::_32x_cart));
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_cd_state::_32x_cart));
//config.m_perfect_cpu_quantum = subtag("32x_master_sh2");
SOFTWARE_LIST(config, "cd_list").set_original("segacd");
@ -916,7 +782,7 @@ void md_cons_cd_state::md_32x_scd(machine_config &config)
CDROM(config, "cdrom").set_interface("scd_cdrom");
config.device_remove("cartslot");
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_state::_32x_cart));
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_cd_state::_32x_cart));
//config.m_perfect_cpu_quantum = subtag("32x_master_sh2");
SOFTWARE_LIST(config, "cd_list").set_original("megacd");
@ -936,7 +802,7 @@ void md_cons_cd_state::mdj_32x_scd(machine_config &config)
CDROM(config, "cdrom").set_interface("scd_cdrom");
config.device_remove("cartslot");
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_state::_32x_cart));
GENERIC_CARTSLOT(config, "cartslot", generic_plain_slot, "_32x_cart", "32x,bin").set_device_load(FUNC(md_cons_cd_state::_32x_cart));
//config.m_perfect_cpu_quantum = subtag("32x_master_sh2");
SOFTWARE_LIST(config, "cd_list").set_original("megacdj");
@ -1193,7 +1059,7 @@ CONS( 1994, 32x_mcdj, 32x_scd, 0, mdj_32x_scd, md, md_cons_c
CONS( 1995, gen_nomd, 0, 0, ms_megadriv2, gen_nomd, md_cons_slot_state, init_genesis, "Sega", "Genesis Nomad (USA Genesis handheld)", MACHINE_SUPPORTS_SAVE )
// handheld without LCD
CONS( 1993, megajet, gen_nomd, 0, ms_megadriv2, megajet, md_cons_slot_state, init_md_jpn, "Sega", "Mega Jet (Japan Mega Drive handheld)", MACHINE_SUPPORTS_SAVE )
CONS( 1993, megajet, gen_nomd, 0, ms_megajet, md, md_cons_slot_state, init_md_jpn, "Sega", "Mega Jet (Japan Mega Drive handheld)", MACHINE_SUPPORTS_SAVE )
// LaserActive (Laserdisc Player(ex: CLD-A100) with 'Control Pack' Addon slot)
// Mega Drive Pack(PAC-S1)/Genesis Pack(PAC-S10) plugged into the Control Pack slot, for plays Mega Drive/Genesis Cartridge, Mega-CD/Sega CD, Mega-LD stuffs

View File

@ -12,6 +12,7 @@
#include "bus/megadrive/md_slot.h"
#include "bus/megadrive/md_carts.h"
#include "bus/sms_ctrl/smsctrl.h"
class md_cons_state : public md_base_state
@ -22,50 +23,55 @@ public:
m_32x(*this,"sega32x"),
m_segacd(*this,"segacd"),
m_cart(*this, "mdslot"),
m_tmss(*this, "tmss")
m_tmss(*this, "tmss"),
m_ctrl_ports(*this, "ctrl%u", 1U)
{ }
ioport_port *m_io_ctrlr = nullptr;
ioport_port *m_io_pad3b[4]{};
ioport_port *m_io_pad6b[2][4]{};
optional_device<sega_32x_device> m_32x;
optional_device<sega_segacd_device> m_segacd;
optional_device<md_cart_slot_device> m_cart;
optional_region_ptr<uint16_t> m_tmss;
void init_mess_md_common();
void init_genesis();
void init_md_eur();
void init_md_jpn();
uint8_t mess_md_io_read_data_port(offs_t offset);
void mess_md_io_write_data_port(offs_t offset, uint16_t data);
void md_32x(machine_config &config);
void genesis_32x(machine_config &config);
void mdj_32x(machine_config &config);
void dcat16_megadriv(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
DECLARE_WRITE_LINE_MEMBER(screen_vblank_console);
DECLARE_DEVICE_IMAGE_LOAD_MEMBER( _32x_cart );
void install_cartslot();
void install_tmss();
optional_device<sega_32x_device> m_32x;
optional_device<sega_segacd_device> m_segacd;
optional_device<md_cart_slot_device> m_cart;
optional_region_ptr<uint16_t> m_tmss;
optional_device_array<sms_control_port_device, 2> m_ctrl_ports;
void md_ctrl_ports(machine_config &config);
private:
uint8_t mess_md_io_read_data_port(offs_t offset);
void mess_md_io_write_data_port(offs_t offset, uint16_t data);
void _32x_scanline_callback(int x, uint32_t priority, uint32_t &lineptr);
void _32x_interrupt_callback(int scanline, int irq6);
void _32x_scanline_helper_callback(int scanline);
void install_cartslot();
void install_tmss();
uint16_t tmss_r(offs_t offset);
void tmss_swap_w(uint16_t data);
void dcat16_megadriv_base(machine_config &config);
void dcat16_megadriv(machine_config &config);
void md_32x(machine_config &config);
void genesis_32x(machine_config &config);
void mdj_32x(machine_config &config);
protected:
virtual void machine_start() override;
virtual void machine_reset() override;
uint8_t m_io_ctrl_th_in[2];
};
class md_cons_slot_state : public md_cons_state
{
public:
@ -76,6 +82,7 @@ public:
void ms_megadpal(machine_config &config);
void ms_megadriv(machine_config &config);
void ms_megadriv2(machine_config &config);
void ms_megajet(machine_config &config);
void genesis_tmss(machine_config &config);
@ -84,6 +91,7 @@ protected:
virtual void machine_start() override;
};
class md_cons_cd_state : public md_cons_state
{
public:

View File

@ -170,61 +170,41 @@ INPUT_PORTS_START( megadriv )
PORT_BIT( 0x0001, IP_ACTIVE_HIGH, IPT_SERVICE1 ) PORT_NAME("Reset Button") PORT_IMPULSE(1) // reset, resets 68k (and..?)
INPUT_PORTS_END
INPUT_PORTS_START( megadri6 )
PORT_INCLUDE( megadriv )
PORT_START("EXTRA1") /* Extra buttons for Joypad 1 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("P1 Z") // z
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("P1 Y") // y
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("P1 X") // x
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_PLAYER(1) PORT_NAME("P1 MODE") // mode
PORT_START("EXTRA2") /* Extra buttons for Joypad 2 (6 button + start + mode) NOT READ DIRECTLY */
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("P2 Z") // z
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("P2 Y") // y
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("P2 X") // x
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON8 ) PORT_PLAYER(2) PORT_NAME("P2 MODE") // mode
INPUT_PORTS_END
void md_base_state::megadrive_reset_io()
{
int i;
m_io_data_regs[0] = 0x7f;
m_io_data_regs[1] = 0x7f;
m_io_data_regs[2] = 0x7f;
m_io_ctrl_regs[0] = 0x00;
m_io_ctrl_regs[1] = 0x00;
m_io_ctrl_regs[2] = 0x00;
m_io_tx_regs[0] = 0xff;
m_io_tx_regs[1] = 0xff;
m_io_tx_regs[2] = 0xff;
m_megadrive_io_data_regs[0] = 0x7f;
m_megadrive_io_data_regs[1] = 0x7f;
m_megadrive_io_data_regs[2] = 0x7f;
m_megadrive_io_ctrl_regs[0] = 0x00;
m_megadrive_io_ctrl_regs[1] = 0x00;
m_megadrive_io_ctrl_regs[2] = 0x00;
m_megadrive_io_tx_regs[0] = 0xff;
m_megadrive_io_tx_regs[1] = 0xff;
m_megadrive_io_tx_regs[2] = 0xff;
for (i=0; i<3; i++)
{
for (int i = 0; i < 3; i++)
m_io_stage[i] = -1;
}
}
/************* 6 buttons version **************************/
uint8_t md_base_state::megadrive_io_read_data_port_6button(offs_t offset)
{
int portnum = offset;
uint8_t retdata, helper = (m_megadrive_io_ctrl_regs[portnum] & 0x3f) | 0xc0; // bits 6 & 7 always come from m_megadrive_io_data_regs
uint8_t retdata, helper = (m_io_ctrl_regs[portnum] & 0x3f) | 0xc0; // bits 6 & 7 always come from m_io_data_regs
if (m_megadrive_io_data_regs[portnum] & 0x40)
if (m_io_data_regs[portnum] & 0x40)
{
if (m_io_stage[portnum] == 2)
{
/* here we read B, C & the additional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0x30) |
((m_io_pad_6b[portnum] ? m_io_pad_6b[portnum]->read() : 0) & 0x0f)) & ~helper);
}
else
{
/* here we read B, C & the directional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
(((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0x3f) & ~helper);
}
}
@ -233,19 +213,19 @@ uint8_t md_base_state::megadrive_io_read_data_port_6button(offs_t offset)
if (m_io_stage[portnum] == 1)
{
/* here we read ((Start & A) >> 2) | 0x00 */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0xc0) >> 2) & ~helper);
}
else if (m_io_stage[portnum]==2)
{
/* here we read ((Start & A) >> 2) | 0x0f */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
(((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0xc0) >> 2) | 0x0f) & ~helper);
}
else
{
/* here we read ((Start & A) >> 2) | Up and Down */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
(((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0xc0) >> 2) |
((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0x03)) & ~helper);
}
@ -261,18 +241,18 @@ uint8_t md_base_state::megadrive_io_read_data_port_6button(offs_t offset)
uint8_t md_base_state::megadrive_io_read_data_port_3button(offs_t offset)
{
int portnum = offset;
uint8_t retdata, helper = (m_megadrive_io_ctrl_regs[portnum] & 0x7f) | 0x80; // bit 7 always comes from m_megadrive_io_data_regs
uint8_t retdata, helper = (m_io_ctrl_regs[portnum] & 0x7f) | 0x80; // bit 7 always comes from m_io_data_regs
if (m_megadrive_io_data_regs[portnum] & 0x40)
if (m_io_data_regs[portnum] & 0x40)
{
/* here we read B, C & the directional buttons */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0x3f) | 0x40) & ~helper);
}
else
{
/* here we read ((Start & A) >> 2) | Up and Down */
retdata = (m_megadrive_io_data_regs[portnum] & helper) |
retdata = (m_io_data_regs[portnum] & helper) |
(((((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0xc0) >> 2) |
((m_io_pad_3b[portnum] ? m_io_pad_3b[portnum]->read() : 0) & 0x03) | 0x40) & ~helper);
}
@ -283,7 +263,7 @@ uint8_t md_base_state::megadrive_io_read_data_port_3button(offs_t offset)
uint8_t md_base_state::megadrive_io_read_ctrl_port(int portnum)
{
uint8_t retdata;
retdata = m_megadrive_io_ctrl_regs[portnum];
retdata = m_io_ctrl_regs[portnum];
//osd_printf_debug("read io ctrl port %d %02x\n",portnum,retdata);
return retdata | (retdata << 8);
@ -292,7 +272,7 @@ uint8_t md_base_state::megadrive_io_read_ctrl_port(int portnum)
uint8_t md_base_state::megadrive_io_read_tx_port(int portnum)
{
uint8_t retdata;
retdata = m_megadrive_io_tx_regs[portnum];
retdata = m_io_tx_regs[portnum];
return retdata | (retdata << 8);
}
@ -338,7 +318,7 @@ uint16_t md_base_state::megadriv_68k_io_read(offs_t offset)
case 0x1:
case 0x2:
case 0x3:
retdata = m_megadrive_io_read_data_port_ptr(offset-1);
retdata = m_io_read_data_port_ptr(offset-1);
break;
case 0x4:
@ -370,7 +350,7 @@ uint16_t md_base_state::megadriv_68k_io_read(offs_t offset)
void md_base_state::megadrive_io_write_data_port_3button(offs_t offset, uint16_t data)
{
int portnum = offset;
m_megadrive_io_data_regs[portnum] = data;
m_io_data_regs[portnum] = data;
//osd_printf_debug("Writing IO Data Register #%d data %04x\n",portnum,data);
}
@ -381,9 +361,9 @@ void md_base_state::megadrive_io_write_data_port_3button(offs_t offset, uint16_t
void md_base_state::megadrive_io_write_data_port_6button(offs_t offset, uint16_t data)
{
int portnum = offset;
if (m_megadrive_io_ctrl_regs[portnum]&0x40)
if (m_io_ctrl_regs[portnum]&0x40)
{
if (((m_megadrive_io_data_regs[portnum]&0x40)==0x00) && ((data&0x40) == 0x40))
if (((m_io_data_regs[portnum]&0x40)==0x00) && ((data&0x40) == 0x40))
{
m_io_stage[portnum]++;
m_io_timeout[portnum]->adjust(m_maincpu->cycles_to_attotime(8192), portnum);
@ -391,7 +371,7 @@ void md_base_state::megadrive_io_write_data_port_6button(offs_t offset, uint16_t
}
m_megadrive_io_data_regs[portnum] = data;
m_io_data_regs[portnum] = data;
//osd_printf_debug("Writing IO Data Register #%d data %04x\n",portnum,data);
}
@ -401,13 +381,13 @@ void md_base_state::megadrive_io_write_data_port_6button(offs_t offset, uint16_t
void md_base_state::megadrive_io_write_ctrl_port(int portnum, uint16_t data)
{
m_megadrive_io_ctrl_regs[portnum] = data;
m_io_ctrl_regs[portnum] = data;
// osd_printf_debug("Setting IO Control Register #%d data %04x\n",portnum,data);
}
void md_base_state::megadrive_io_write_tx_port(int portnum, uint16_t data)
{
m_megadrive_io_tx_regs[portnum] = data;
m_io_tx_regs[portnum] = data;
}
void md_base_state::megadrive_io_write_rx_port(int portnum, uint16_t data)
@ -435,7 +415,7 @@ void md_base_state::megadriv_68k_io_write(offs_t offset, uint16_t data, uint16_t
case 0x1:
case 0x2:
case 0x3:
m_megadrive_io_write_data_port_ptr(offset-1,data);
m_io_write_data_port_ptr(offset-1,data);
break;
case 0x4:
@ -821,9 +801,9 @@ void md_base_state::machine_start()
m_io_pad_3b[3] = ioport("UNK");
save_item(NAME(m_io_stage));
save_item(NAME(m_megadrive_io_data_regs));
save_item(NAME(m_megadrive_io_ctrl_regs));
save_item(NAME(m_megadrive_io_tx_regs));
save_item(NAME(m_io_data_regs));
save_item(NAME(m_io_ctrl_regs));
save_item(NAME(m_io_tx_regs));
if (m_z80snd)
m_genz80.z80_run_timer = timer_alloc(FUNC(md_base_state::megadriv_z80_run_state), this);
@ -1048,8 +1028,8 @@ void md_base_state::megadriv_init_common()
m_maincpu->set_tas_write_callback(*this, FUNC(md_base_state::megadriv_tas_callback));
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_3button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_3button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_3button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_3button));
}
void md_base_state::init_megadriv()

View File

@ -21,9 +21,6 @@
INPUT_PORTS_EXTERN( md_common );
INPUT_PORTS_EXTERN( megadriv );
INPUT_PORTS_EXTERN( megadri6 );
INPUT_PORTS_EXTERN( ssf2mdb );
INPUT_PORTS_EXTERN( mk3mdb );
class md_base_state : public driver_device
@ -39,8 +36,8 @@ public:
m_megadrive_ram(*this,"megadrive_ram"),
m_screen(*this,"megadriv"),
m_io_reset(*this, "RESET"),
m_megadrive_io_read_data_port_ptr(*this),
m_megadrive_io_write_data_port_ptr(*this)
m_io_read_data_port_ptr(*this),
m_io_write_data_port_ptr(*this)
{ }
required_device<m68000_base_device> m_maincpu;
@ -96,11 +93,11 @@ public:
/* Megadrive / Genesis has 3 I/O ports */
emu_timer *m_io_timeout[3];
int m_io_stage[3];
uint8_t m_megadrive_io_data_regs[3];
uint8_t m_megadrive_io_ctrl_regs[3];
uint8_t m_megadrive_io_tx_regs[3];
read8sm_delegate m_megadrive_io_read_data_port_ptr;
write16sm_delegate m_megadrive_io_write_data_port_ptr;
uint8_t m_io_data_regs[3];
uint8_t m_io_ctrl_regs[3];
uint8_t m_io_tx_regs[3];
read8sm_delegate m_io_read_data_port_ptr;
write16sm_delegate m_io_write_data_port_ptr;
WRITE_LINE_MEMBER(vdp_sndirqline_callback_genesis_z80);
WRITE_LINE_MEMBER(vdp_lv6irqline_callback_genesis_68k);

View File

@ -1209,8 +1209,8 @@ void md_boot_state::init_mk3mdb()
init_megadriv();
// 6 button game, so overwrite 3 button io handlers
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
}
void md_boot_state::init_ssf2mdb()
@ -1222,8 +1222,8 @@ void md_boot_state::init_ssf2mdb()
init_megadrij();
// 6 button game, so overwrite 3 button io handlers
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
}
void md_boot_state::init_srmdb()

View File

@ -552,16 +552,16 @@ void megadriv_radica_6button_state::init_megadriv_radica_6button_pal()
{
init_megadrie();
// 6 button game, so overwrite 3 button io handlers
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
}
void megadriv_radica_6button_state::init_megadriv_radica_6button_ntsc()
{
init_megadriv();
// 6 button game, so overwrite 3 button io handlers
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
}
void megadriv_dgunl_state::init_dgunl3227()
@ -647,8 +647,8 @@ void megadriv_ra145_state::init_ra145()
m_romsize = 0x8000000;
init_megadriv();
// 6 button game, so overwrite 3 button io handlers
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_6button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_6button));
}
// US versions show 'Genesis' on the menu, show a www.radicagames.com splash screen, and use NTSC versions of the ROMs, sometimes region locked

View File

@ -428,7 +428,7 @@ void mplay_state::bios_gamesel_w(uint8_t data)
void mplay_state::mp_io_write(offs_t offset, uint16_t data)
{
if (offset == 0x03)
m_megadrive_io_data_regs[2] = (data & m_megadrive_io_ctrl_regs[2]) | (m_megadrive_io_data_regs[2] & ~m_megadrive_io_ctrl_regs[2]);
m_io_data_regs[2] = (data & m_io_ctrl_regs[2]) | (m_io_data_regs[2] & ~m_io_ctrl_regs[2]);
else
megadriv_68k_io_write(offset & 0x1f, data);
}
@ -436,7 +436,7 @@ void mplay_state::mp_io_write(offs_t offset, uint16_t data)
uint16_t mplay_state::mp_io_read(offs_t offset)
{
if (offset == 0x03)
return m_megadrive_io_data_regs[2];
return m_io_data_regs[2];
else
return megadriv_68k_io_read(offset & 0x1f);
}
@ -504,25 +504,25 @@ void mplay_state::bank_w(offs_t offset, uint8_t data)
uint8_t mplay_state::bios_6402_r()
{
return m_megadrive_io_data_regs[2];// & 0xfe;
return m_io_data_regs[2];// & 0xfe;
}
void mplay_state::bios_6402_w(uint8_t data)
{
m_megadrive_io_data_regs[2] = (m_megadrive_io_data_regs[2] & 0x07) | ((data & 0x70) >> 1);
m_io_data_regs[2] = (m_io_data_regs[2] & 0x07) | ((data & 0x70) >> 1);
// logerror("BIOS: 0x6402 write: 0x%02x\n", data);
}
uint8_t mplay_state::bios_6204_r()
{
return m_megadrive_io_data_regs[2];
return m_io_data_regs[2];
// return (m_bios_width & 0xf8) + (m_bios_6204 & 0x07);
}
void mplay_state::bios_width_w(uint8_t data)
{
m_bios_width = data;
m_megadrive_io_data_regs[2] = (m_megadrive_io_data_regs[2] & 0x07) | ((data & 0xf8));
m_io_data_regs[2] = (m_io_data_regs[2] & 0x07) | ((data & 0xf8));
// logerror("BIOS: 0x6204 - Width write: %02x\n", data);
}
@ -963,8 +963,8 @@ void mplay_state::init_megaplay()
m_ic37_ram = std::make_unique<uint8_t[]>(0x10000);
init_megadrij();
m_megadrive_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_3button));
m_megadrive_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_3button));
m_io_read_data_port_ptr = read8sm_delegate(*this, FUNC(md_base_state::megadrive_io_read_data_port_3button));
m_io_write_data_port_ptr = write16sm_delegate(*this, FUNC(md_base_state::megadrive_io_write_data_port_3button));
// for now ...
m_maincpu->space(AS_PROGRAM).install_readwrite_handler(0xa10000, 0xa1001f, read16sm_delegate(*this, FUNC(mplay_state::mp_io_read)), write16sm_delegate(*this, FUNC(mplay_state::mp_io_write)));

View File

@ -59,9 +59,11 @@ TODO:
#include "emu.h"
#include "sms.h"
#include "cpu/z80/z80.h"
#include "machine/nvram.h"
#include "sound/beep.h"
#include "emupal.h"
#include "screen.h"
#include "speaker.h"
@ -72,13 +74,13 @@ namespace {
class shtzone_state : public sms_state
{
public:
shtzone_state(const machine_config &mconfig, device_type type, const char *tag)
: sms_state(mconfig, type, tag),
shtzone_state(const machine_config &mconfig, device_type type, const char *tag) :
sms_state(mconfig, type, tag),
m_timercpu(*this, "timercpu"),
m_buzzer(*this, "buzzer"),
m_slots(*this, {"slot", "slot2", "slot3", "slot4", "slot5"}),
m_led(*this, "led")
{ }
{ }
void shtzone(machine_config &config);
@ -354,7 +356,7 @@ ROM_START( shtzone )
ROM_FILL(0x0000, 0x4000, 0xff)
ROM_END
} // Anonymous namespace
} // anonymous namespace
GAME( 1987, shtzone, 0, shtzone, shtzone, shtzone_state, empty_init, ROT0, "Sega", "Shooting Zone System BIOS", MACHINE_NOT_WORKING | MACHINE_IS_BIOS_ROOT )

View File

@ -245,6 +245,7 @@ DC00 - Selection buttons #2, 9-16 (R)
#include "emu.h"
#include "sms.h"
#include "bus/sms_ctrl/controllers.h"
#include "cpu/z80/z80.h"
#include "softlist_dev.h"
#include "speaker.h"
@ -494,25 +495,25 @@ INPUT_PORTS_END
void sms_state::sms_base(machine_config &config)
{
/* basic machine hardware */
SPEAKER(config, "mono").front_center();
SMS_CART_SLOT(config, "slot", sms_cart, nullptr);
SOFTWARE_LIST(config, "cart_list").set_original("sms");
SMS_CONTROL_PORT(config, m_port_ctrl1, sms_control_port_devices, "joypad");
m_port_ctrl1->set_screen_tag(m_main_scr);
m_port_ctrl1->th_input_handler().set(FUNC(sms_state::sms_ctrl1_th_input));
SMS_CONTROL_PORT(config, m_port_ctrl1, sms_control_port_devices, SMS_CTRL_OPTION_JOYPAD);
m_port_ctrl1->set_screen(m_main_scr);
m_port_ctrl1->th_handler().set(FUNC(sms_state::sms_ctrl1_th_input));
SMS_CONTROL_PORT(config, m_port_ctrl2, sms_control_port_devices, "joypad");
m_port_ctrl2->set_screen_tag(m_main_scr);
m_port_ctrl2->th_input_handler().set(FUNC(sms_state::sms_ctrl2_th_input));
SMS_CONTROL_PORT(config, m_port_ctrl2, sms_control_port_devices, SMS_CTRL_OPTION_JOYPAD);
m_port_ctrl2->set_screen(m_main_scr);
m_port_ctrl2->th_handler().set(FUNC(sms_state::sms_ctrl2_th_input));
}
void sms_state::sms_ntsc_base(machine_config &config)
{
sms_base(config);
Z80(config, m_maincpu, XTAL(10'738'635)/3);
m_maincpu->set_addrmap(AS_PROGRAM, &sms_state::sms_mem);
m_maincpu->set_addrmap(AS_IO, &sms_state::sms_io);
@ -937,8 +938,8 @@ void sms1_state::sg1000m3(machine_config &config)
SOFTWARE_LIST(config, "cart_list2").set_original("sg1000");
// Mark III does not have TH connected.
m_port_ctrl1->th_input_handler().set_nop();
m_port_ctrl2->th_input_handler().set_nop();
m_port_ctrl1->th_handler().set_nop();
m_port_ctrl2->th_handler().set_nop();
m_has_bios_full = false;
m_is_mark_iii = true;

View File

@ -2,35 +2,28 @@
// copyright-holders:Wilbert Pol, Charles MacDonald,Mathis Rosenhauer,Brad Oliver,Michael Luong,Fabio Priuli,Enik Land
/*****************************************************************************
*
* includes/sms.h
* sega/sms.h
*
****************************************************************************/
#ifndef MAME_INCLUDES_SMS_H
#define MAME_INCLUDES_SMS_H
#define LOG_REG
#define LOG_PAGING
#define LOG_COLOR
#define NVRAM_SIZE (0x08000)
#define CPU_ADDRESSABLE_SIZE (0x10000)
#define MAX_CARTRIDGES 16
#define CONTROL1_TAG "ctrl1"
#define CONTROL2_TAG "ctrl2"
#pragma once
#include "bus/gamegear/ggext.h"
#include "bus/sega8/sega8_slot.h"
#include "bus/sg1000_exp/sg1000exp.h"
#include "bus/sms_ctrl/smsctrl.h"
#include "bus/sms_exp/smsexp.h"
#include "machine/timer.h"
#include "sound/ymopl.h"
#include "video/315_5124.h"
#include "screen.h"
#include "machine/timer.h"
#define LOG_REG
#define LOG_PAGING
#define LOG_COLOR
class sms_state : public driver_device
@ -42,8 +35,8 @@ public:
m_vdp(*this, "sms_vdp"),
m_main_scr(*this, "screen"),
m_ym(*this, "ym2413"),
m_port_ctrl1(*this, CONTROL1_TAG),
m_port_ctrl2(*this, CONTROL2_TAG),
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"),

View File

@ -1,14 +1,11 @@
// license:BSD-3-Clause
// copyright-holders:Wilbert Pol, Charles MacDonald,Mathis Rosenhauer,Brad Oliver,Michael Luong,Fabio Priuli,Enik Land
#include "emu.h"
#include "crsshair.h"
#include "cpu/z80/z80.h"
#include "video/315_5124.h"
#include "sound/ymopl.h"
#include "sms.h"
#define VERBOSE 0
#define LOG(x) do { if (VERBOSE) logerror x; } while (0)
#include "cpu/z80/z80.h"
#include "crsshair.h"
#define ENABLE_NONE 0x00
#define ENABLE_EXPANSION 0x01
@ -26,8 +23,7 @@ TIMER_CALLBACK_MEMBER(sms_state::lphaser_th_generate)
void sms_state::lphaser_hcount_latch()
{
/* A delay seems to occur when the Light Phaser latches the
VDP hcount, then an offset is added here to the hpos. */
// A delay seems to occur when the Light Phaser latches the VDP hcount, then an offset is added here to the hpos.
m_lphaser_th_timer->adjust(m_main_scr->time_until_pos(m_main_scr->vpos(), m_main_scr->hpos() + m_lphaser_x_offs));
}
@ -37,18 +33,18 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl1_th_input)
// Check if TH of controller port 1 is set to input (1)
if (m_io_ctrl_reg & 0x02)
{
if (state == 0)
if (!state)
{
m_ctrl1_th_latch = 1;
}
else
{
// State is 1. If changed from 0, hcount is latched.
if (m_ctrl1_th_state == 0)
if (!m_ctrl1_th_state)
lphaser_hcount_latch();
}
m_ctrl1_th_state = state;
}
m_ctrl1_th_state = state;
}
@ -57,18 +53,18 @@ WRITE_LINE_MEMBER(sms_state::sms_ctrl2_th_input)
// Check if TH of controller port 2 is set to input (1)
if (m_io_ctrl_reg & 0x08)
{
if (state == 0)
if (!state)
{
m_ctrl2_th_latch = 1;
}
else
{
// State is 1. If changed from 0, hcount is latched.
if (m_ctrl2_th_state == 0)
if (!m_ctrl2_th_state)
lphaser_hcount_latch();
}
m_ctrl2_th_state = state;
}
m_ctrl2_th_state = state;
}
@ -84,7 +80,6 @@ WRITE_LINE_MEMBER(gamegear_state::gg_ext_th_input)
void sms_state::sms_get_inputs()
{
uint8_t data1 = 0xff;
uint8_t data2 = 0xff;
m_port_dc_reg = 0xff;
@ -96,43 +91,36 @@ void sms_state::sms_get_inputs()
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.
data1 = m_port_gg_dc->read();
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
{
data1 = m_port_ctrl1->port_r();
m_port_dc_reg &= ~0x0f | data1; // Up, Down, Left, Right
m_port_dc_reg &= ~0x10 | (data1 >> 1); // TL (Button 1)
m_port_dc_reg &= ~0x20 | (data1 >> 2); // TR (Button 2)
m_port_dc_reg &= ~0x3f | m_port_ctrl1->in_r(); // Up, Down, Left, Right, TL, TR
data2 = m_port_ctrl2->port_r();
data2 = m_port_ctrl2->in_r();
}
m_port_dc_reg &= ~0xc0 | (data2 << 6); // Up, Down
m_port_dd_reg &= ~0x03 | (data2 >> 2); // Left, Right
m_port_dd_reg &= ~0x04 | (data2 >> 3); // TL (Button 1)
m_port_dd_reg &= ~0x08 | (data2 >> 4); // TR (Button 2)
if (!m_is_mark_iii)
{
m_port_dd_reg &= ~0x40 | data1; // TH ctrl1
m_port_dd_reg &= ~0x80 | (data2 << 1); // TH ctrl2
}
m_port_dd_reg &= ~0x0f | (data2 >> 2); // Left, Right, TL, TR
m_port_dd_reg &= ~0x40 | (m_ctrl1_th_state << 6); // TH ctrl1
m_port_dd_reg &= ~0x80 | (m_ctrl2_th_state << 7); // TH ctrl2
}
void sms_state::sms_io_control_w(uint8_t data)
{
bool latch_hcount = false;
uint8_t ctrl1_port_data = 0xff;
uint8_t ctrl2_port_data = 0xff;
if (m_is_gamegear && !(m_cartslot->exists() && m_cartslot->get_sms_mode()))
{
@ -143,58 +131,46 @@ void sms_state::sms_io_control_w(uint8_t data)
// Controller Port 1:
// check if TR or TH are set to output (0).
if ((data & 0x03) != 0x03)
if (!m_is_gamegear && ((data & 0x33) != (m_io_ctrl_reg & 0x33)))
{
if (!(data & 0x01)) // TR set to output
{
ctrl1_port_data &= ~0x80 | (data << 3);
}
if (!(data & 0x02)) // TH set to output
{
ctrl1_port_data &= ~0x40 | (data << 1);
}
if (!m_is_gamegear)
m_port_ctrl1->port_w(ctrl1_port_data);
m_port_ctrl1->out_w(((BIT(data, 4, 2) | BIT(data, 0, 2)) << 5) | 0x1f, BIT(~data, 0, 2) << 5);
}
// check if TH is set to input (1).
if (data & 0x02)
{
if (!m_is_gamegear)
ctrl1_port_data &= ~0x40 | m_port_ctrl1->port_r();
// check if TH input level is high (1) and was output/low (0)
if ((ctrl1_port_data & 0x40) && !(m_io_ctrl_reg & 0x22))
// 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;
}
// Controller Port 2:
// check if TR or TH are set to output (0).
if ((data & 0x0c) != 0x0c)
if (m_is_gamegear)
{
if (!(data & 0x04)) // TR set to output
if ((data & 0x0c) != 0x0c)
{
ctrl2_port_data &= ~0x80 | (data << 1);
}
if (!(data & 0x08)) // TH set to output
{
ctrl2_port_data &= ~0x40 | (data >> 1);
}
if (!m_is_gamegear)
m_port_ctrl2->port_w(ctrl2_port_data);
else
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);
}
}
// check if TH is set to input (1).
if (data & 0x08)
else if ((data & 0xcc) != (m_io_ctrl_reg & 0xcc))
{
if (!m_is_gamegear)
ctrl2_port_data &= ~0x40 | m_port_ctrl2->port_r();
else
ctrl2_port_data &= ~0x40 | m_port_gg_ext->port_r();
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 ((ctrl2_port_data & 0x40) && !(m_io_ctrl_reg & 0x88))
// 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;
}
@ -398,14 +374,11 @@ uint8_t sms_state::sms_input_port_dd_r()
// Check if TH of controller port 1 is set to output (0)
if (!(m_io_ctrl_reg & 0x02))
{
if (m_ioctrl_region_is_japan)
{
m_port_dd_reg &= ~0x40;
}
else
m_port_dd_reg &= ~0x40;
if (!m_ioctrl_region_is_japan)
{
// Read TH state set through IO control port
m_port_dd_reg &= ~0x40 | ((m_io_ctrl_reg & 0x20) << 1);
m_port_dd_reg |= (m_io_ctrl_reg & 0x20) << 1;
}
}
else // TH set to input (1)
@ -422,14 +395,11 @@ uint8_t sms_state::sms_input_port_dd_r()
// Check if TH of controller port 2 is set to output (0)
if (!(m_io_ctrl_reg & 0x08))
{
if (m_ioctrl_region_is_japan)
{
m_port_dd_reg &= ~0x80;
}
else
m_port_dd_reg &= ~0x80;
if (!m_ioctrl_region_is_japan)
{
// Read TH state set through IO control port
m_port_dd_reg &= ~0x80 | (m_io_ctrl_reg & 0x80);
m_port_dd_reg |= m_io_ctrl_reg & 0x80;
}
}
else // TH set to input (1)
@ -1009,6 +979,9 @@ void sms_state::setup_bios()
void sms_state::machine_start()
{
m_ctrl1_th_state = 1;
m_ctrl2_th_state = 1;
// turn on the Power LED
if (m_has_pwr_led)
{
@ -1119,13 +1092,17 @@ void sms_state::machine_reset()
m_led_pwr = 1;
}
if (!m_is_mark_iii)
if (m_is_mark_iii)
{
// pin 7 is tied to ground on the Mark III
m_port_ctrl1->out_w(0x3f, 0x40);
m_port_ctrl2->out_w(0x3f, 0x40);
}
else
{
m_io_ctrl_reg = 0xff;
m_ctrl1_th_latch = 0;
m_ctrl2_th_latch = 0;
m_ctrl1_th_state = 1;
m_ctrl2_th_state = 1;
}
setup_bios();

View File

@ -303,242 +303,42 @@ void x68k_state::set_adpcm()
m_adpcm_timer->adjust(attotime::from_ticks(rate, res_clock), 0, attotime::from_ticks(rate, res_clock));
}
// Megadrive 3 button gamepad
// According to XM6, bits 4 and 7 are always 1 (is this correct?)
// Bits 4 and 5 of PPI port C control each controller's multiplexer
// Button inputs (Start, A, B and C) are read in bits 5 and 6 (rather than 4
// and 5 like on a Megadrive)
uint8_t x68k_state::md_3button_r(int port)
{
if(port == 1)
{
uint8_t porta = m_md3b->read() & 0xff;
uint8_t portb = (m_md3b->read() >> 8) & 0xff;
if(m_mdctrl.mux1 & 0x10)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | (porta & 0x03) | 0x90;
}
}
if(port == 2)
{
uint8_t porta = (m_md3b->read() >> 16) & 0xff;
uint8_t portb = (m_md3b->read() >> 24) & 0xff;
if(m_mdctrl.mux2 & 0x20)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | (porta & 0x03) | 0x90;
}
}
return 0xff;
}
// Megadrive 6 button gamepad
TIMER_CALLBACK_MEMBER(x68k_state::md_6button_port1_timeout)
{
m_mdctrl.seq1 = 0;
}
TIMER_CALLBACK_MEMBER(x68k_state::md_6button_port2_timeout)
{
m_mdctrl.seq2 = 0;
}
void x68k_state::md_6button_init()
{
m_mdctrl.io_timeout1 = timer_alloc(FUNC(x68k_state::md_6button_port1_timeout), this);
m_mdctrl.io_timeout2 = timer_alloc(FUNC(x68k_state::md_6button_port2_timeout), this);
}
uint8_t x68k_state::md_6button_r(int port)
{
if(port == 1)
{
uint8_t porta = m_md6b->read() & 0xff;
uint8_t portb = (m_md6b->read() >> 8) & 0xff;
uint8_t extra = m_md6b_extra->read() & 0x0f;
switch(m_mdctrl.seq1)
{
case 1:
default:
if(m_mdctrl.mux1 & 0x10)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | (porta & 0x03) | 0x90;
}
case 2:
if(m_mdctrl.mux1 & 0x10)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | 0x90;
}
case 3:
if(m_mdctrl.mux1 & 0x10)
{
return (porta & 0x60) | (extra & 0x0f) | 0x90;
}
else
{
return (portb & 0x60) | 0x9f;
}
}
}
if(port == 2)
{
uint8_t porta = (m_md6b->read() >> 16) & 0xff;
uint8_t portb = (m_md6b->read() >> 24) & 0xff;
uint8_t extra = (m_md6b_extra->read() >> 4) & 0x0f;
switch(m_mdctrl.seq2)
{
case 1:
default:
if(m_mdctrl.mux2 & 0x20)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | (porta & 0x03) | 0x90;
}
case 2:
if(m_mdctrl.mux2 & 0x20)
{
return porta | 0x90;
}
else
{
return (portb & 0x60) | 0x90;
}
case 3:
if(m_mdctrl.mux2 & 0x20)
{
return (porta & 0x60) | (extra & 0x0f) | 0x90;
}
else
{
return (portb & 0x60) | 0x9f;
}
}
}
return 0xff;
}
// XPD-1LR dual D-pad controller.
// Sold with Video Game Anthology Vol 4: Libble Rabble.
// Also compatible with Video Game Anthology Vol 5: Crazy Climber 1 & 2
// Uses the same input multiplexer hardware as Megadrive controllers
// Output is the same as for standard controllers, but when ctl is high,
// the directions refer to the right D-pad, and when low, the left D-pad
// The buttons are read the same as normal, regardless of ctl.
uint8_t x68k_state::xpd1lr_r(int port)
{
if(port == 1)
{
uint8_t porta = m_xpd1lr->read() & 0xff;
uint8_t portb = (m_xpd1lr->read() >> 8) & 0xff;
if(m_mdctrl.mux1 & 0x10)
{
return porta;
}
else
{
return portb | (porta & 0x60);
}
}
if(port == 2)
{
uint8_t porta = (m_xpd1lr->read() >> 16) & 0xff;
uint8_t portb = (m_xpd1lr->read() >> 24) & 0xff;
if(m_mdctrl.mux2 & 0x20)
{
return porta;
}
else
{
return portb | (porta & 0x60);
}
}
return 0xff;
}
// Judging from the XM6 source code, PPI ports A and B are joystick inputs
// PPI ports A and B are joystick inputs
uint8_t x68k_state::ppi_port_a_r()
{
int ctrl = m_ctrltype->read() & 0x0f;
// first read the joystick inputs
uint8_t const input = m_joy[0]->read();
uint8_t result = 0x90 | (BIT(input, 4, 2) << 5) | BIT(input, 0, 4);
switch(ctrl)
{
case 0x00: // standard MSX/FM-Towns joystick
if(m_joy.joy1_enable == 0)
return m_joy1->read();
else
return 0xff;
case 0x01: // 3-button Megadrive gamepad
return md_3button_r(1);
case 0x02: // 6-button Megadrive gamepad
return md_6button_r(1);
case 0x03: // XPD-1LR
return xpd1lr_r(1);
}
// trigger lines can be pulled down by port C outputs
result &= ~(BIT(m_ppi_portc, 6, 2) << 5);
return 0xff;
return result;
}
uint8_t x68k_state::ppi_port_b_r()
{
int ctrl = m_ctrltype->read() & 0xf0;
switch(ctrl)
{
case 0x00: // standard MSX/FM-Towns joystick
if(m_joy.joy2_enable == 0)
return m_joy2->read();
else
return 0xff;
case 0x10: // 3-button Megadrive gamepad
return md_3button_r(2);
case 0x20: // 6-button Megadrive gamepad
return md_6button_r(2);
case 0x30: // XPD-1LR
return xpd1lr_r(2);
}
return 0xff;
uint8_t const input = m_joy[1]->read();
return 0x90 | (BIT(input, 4, 2) << 5) | BIT(input, 0, 4);
}
uint8_t x68k_state::ppi_port_c_r()
{
return m_ppi_port[2];
return m_ppi_portc;
}
/* PPI port C (Joystick control, R/W)
bit 7 - IOC7 - Function B operation of joystick 1 (?)
bit 6 - IOC6 - Function A operation of joystick 1 (?)
bit 5 - IOC5 - Enable Joystick 2
bit 4 - IOC4 - Enable Joystick 1
bit 7 - IOC7 - Pull down joystick 1 trigger B (JS pin 7)
bit 6 - IOC6 - Pull down joystick 1 trigger A (JS pin 6)
bit 5 - IOC5 - Joystick 2 strobe (JT pin 8)
bit 4 - IOC4 - Joystick 1 strobe (JS pin 8)
bits 3,2 - ADPCM Sample rate
bits 1,0 - ADPCM Pan (00 = Both, 01 = Right only, 10 = Left only, 11 = Off)
*/
void x68k_state::ppi_port_c_w(uint8_t data)
{
// ADPCM / Joystick control
m_ppi_port[2] = data;
if((data & 0x0f) != (m_ppi_prev & 0x0f))
if((data & 0x0f) != (m_ppi_portc & 0x0f))
{
m_adpcm.pan = data & 0x03;
m_adpcm.rate = (data & 0x0c) >> 2;
@ -551,26 +351,18 @@ void x68k_state::ppi_port_c_w(uint8_t data)
m_adpcm_out[1]->flt_volume_set_volume((m_adpcm.pan & 2) ? 0.0f : 1.0f);
}
// The joystick enable bits also handle the multiplexer for various controllers
m_joy.joy1_enable = data & 0x10;
m_mdctrl.mux1 = data & 0x10;
if((m_ppi_prev & 0x10) == 0x00 && (data & 0x10) == 0x10)
{
m_mdctrl.seq1++;
m_mdctrl.io_timeout1->adjust(m_maincpu->cycles_to_attotime(8192));
}
// Set joystick outputs
if(BIT(data, 6) != BIT(m_ppi_portc, 6))
m_joy[0]->pin_6_w(BIT(~data, 6));
if(BIT(data, 7) != BIT(m_ppi_portc, 7))
m_joy[0]->pin_7_w(BIT(~data, 7));
if(BIT(data, 4) != BIT(m_ppi_portc, 4))
m_joy[0]->pin_8_w(BIT(data, 4));
if(BIT(data, 5) != BIT(m_ppi_portc, 5))
m_joy[1]->pin_8_w(BIT(data, 5));
m_joy.joy2_enable = data & 0x20;
m_mdctrl.mux2 = data & 0x20;
if((m_ppi_prev & 0x20) == 0x00 && (data & 0x20) == 0x20)
{
m_mdctrl.seq2++;
m_mdctrl.io_timeout2->adjust(m_maincpu->cycles_to_attotime(8192));
}
m_ppi_prev = data;
m_joy.ioc6 = data & 0x40;
m_joy.ioc7 = data & 0x80;
// update saved value
m_ppi_portc = data;
}
@ -1261,39 +1053,8 @@ void x68030_state::x68030_map(address_map &map)
}
static INPUT_PORTS_START( x68000 )
PORT_START("ctrltype")
PORT_CONFNAME(0x0f, 0x00, "Joystick Port 1")
PORT_CONFSETTING(0x00, "Standard 2-button MSX/FM-Towns joystick")
PORT_CONFSETTING(0x01, "3-button Megadrive gamepad")
PORT_CONFSETTING(0x02, "6-button Megadrive gamepad")
PORT_CONFSETTING(0x03, "XPD-1LR dual D-pad gamepad")
PORT_CONFNAME(0xf0, 0x00, "Joystick Port 2")
PORT_CONFSETTING(0x00, "Standard 2-button MSX/FM-Towns joystick")
PORT_CONFSETTING(0x10, "3-button Megadrive gamepad")
PORT_CONFSETTING(0x20, "6-button Megadrive gamepad")
PORT_CONFSETTING(0x30, "XPD-1LR dual D-pad gamepad")
// TODO: Sharp Cyber Stick (CZ-8NJ2) support
PORT_START( "joy1" )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x00)
PORT_START( "joy2" )
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_CODE(JOYCODE_Y_UP_SWITCH) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_CODE(JOYCODE_Y_DOWN_SWITCH) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_CODE(JOYCODE_X_LEFT_SWITCH) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_CODE(JOYCODE_X_RIGHT_SWITCH) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x10, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x20, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_CODE(JOYCODE_BUTTON1) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x40, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_CODE(JOYCODE_BUTTON2) PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_BIT( 0x80, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x00)
PORT_START("options")
PORT_CONFNAME( 0x02, 0x02, "Enable fake bus errors")
PORT_CONFSETTING( 0x00, DEF_STR( Off ))
@ -1308,133 +1069,6 @@ static INPUT_PORTS_START( x68000 )
PORT_START("mouse3") // Y-axis
PORT_BIT( 0xff, 0x00, IPT_MOUSE_Y) PORT_SENSITIVITY(100) PORT_KEYDELTA(0) PORT_PLAYER(1)
// 3-button Megadrive gamepad
PORT_START("md3b")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("MD Pad 1 Up") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("MD Pad 1 Down") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_NAME("MD Pad 1 Left") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_NAME("MD Pad 1 Right") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 B Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 C Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00002000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 A Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 Start Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00008000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x01)
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("MD Pad 2 Up") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("MD Pad 2 Down") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_NAME("MD Pad 2 Left") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_NAME("MD Pad 2 Right") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 B Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 C Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x01000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x02000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x04000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x08000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x10000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x20000000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 A Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x40000000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 Start Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
PORT_BIT( 0x80000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x10)
// 6-button Megadrive gamepad
PORT_START("md6b")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("MD Pad 1 Up") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("MD Pad 1 Down") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_NAME("MD Pad 1 Left") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_NAME("MD Pad 1 Right") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 B Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 C Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00002000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 A Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 Start Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00008000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_JOYSTICK_UP ) PORT_NAME("MD Pad 2 Up") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_JOYSTICK_DOWN ) PORT_NAME("MD Pad 2 Down") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_JOYSTICK_LEFT ) PORT_NAME("MD Pad 2 Left") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_JOYSTICK_RIGHT ) PORT_NAME("MD Pad 2 Right") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 B Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_BUTTON3 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 C Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x01000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x02000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x04000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x08000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x10000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x20000000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 A Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x40000000, IP_ACTIVE_LOW, IPT_START ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 Start Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x80000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
// extra inputs
PORT_START("md6b_extra")
PORT_BIT( 0x0001, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 Z Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x0002, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 Y Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x0004, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 X Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x0008, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(1) PORT_NAME("MD Pad 1 Mode Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x02)
PORT_BIT( 0x0010, IP_ACTIVE_LOW, IPT_BUTTON6 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 Z Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x0020, IP_ACTIVE_LOW, IPT_BUTTON5 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 Y Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x0040, IP_ACTIVE_LOW, IPT_BUTTON4 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 X Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
PORT_BIT( 0x0080, IP_ACTIVE_LOW, IPT_BUTTON7 ) PORT_PLAYER(2) PORT_NAME("MD Pad 2 Mode Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x20)
// Dempa/Micomsoft XPD-1LR (dual D-pad gamepad sold with Libble Rabble)
PORT_START("xpd1lr")
PORT_BIT( 0x00000001, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_UP ) PORT_NAME("XPD Pad 1 Left/Up") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000002, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_DOWN ) PORT_NAME("XPD Pad 1 Left/Down") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000004, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_LEFT ) PORT_NAME("XPD Pad 1 Left/Left") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000008, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_RIGHT ) PORT_NAME("XPD Pad 1 Left/Right") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000010, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000020, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(1) PORT_NAME("XPD Pad 1 B Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000040, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(1) PORT_NAME("XPD Pad 1 A Button") PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000080, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000100, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_UP ) PORT_NAME("XPD Pad 1 Right/Up") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000200, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_DOWN ) PORT_NAME("XPD Pad 1 Right/Down") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000400, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_LEFT ) PORT_NAME("XPD Pad 1 Right/Left") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00000800, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_RIGHT ) PORT_NAME("XPD Pad 1 Right/Right") PORT_8WAY PORT_PLAYER(1) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00001000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00002000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00004000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00008000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0x0f, EQUALS, 0x03)
PORT_BIT( 0x00010000, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_UP ) PORT_NAME("XPD Pad 2 Left/Up") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00020000, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_DOWN ) PORT_NAME("XPD Pad 2 Left/Down") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00040000, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_LEFT ) PORT_NAME("XPD Pad 2 Left/Left") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00080000, IP_ACTIVE_LOW, IPT_JOYSTICKLEFT_RIGHT ) PORT_NAME("XPD Pad 2 Left/Right") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00100000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00200000, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_PLAYER(2) PORT_NAME("XPD Pad 2 B Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00400000, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_PLAYER(2) PORT_NAME("XPD Pad 2 A Button") PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x00800000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x01000000, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_UP ) PORT_NAME("XPD Pad 2 Right/Up") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x02000000, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_DOWN ) PORT_NAME("XPD Pad 2 Right/Down") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x04000000, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_LEFT ) PORT_NAME("XPD Pad 2 Right/Left") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x08000000, IP_ACTIVE_LOW, IPT_JOYSTICKRIGHT_RIGHT ) PORT_NAME("XPD Pad 2 Right/Right") PORT_8WAY PORT_PLAYER(2) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x10000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x20000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x40000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
PORT_BIT( 0x80000000, IP_ACTIVE_LOW, IPT_UNUSED ) PORT_CONDITION("ctrltype", 0xf0, EQUALS, 0x30)
INPUT_PORTS_END
void x68k_state::floppy_load_unload(bool load, floppy_image_device *dev)
@ -1568,9 +1202,6 @@ void x68k_state::driver_start()
m_adpcm_timer = timer_alloc(FUNC(x68ksupr_state::adpcm_drq_tick), this);
m_bus_error_timer = timer_alloc(FUNC(x68ksupr_state::bus_error), this);
// Initialise timers for 6-button MD controllers
md_6button_init();
m_sysport.cputype = 0xff; // 68000, 10MHz
m_is_32bit = false;
@ -1625,6 +1256,9 @@ void x68k_state::x68000_base(machine_config &config)
rs232_port_device &keyboard(RS232_PORT(config, "keyboard", keyboard_devices, "x68k"));
keyboard.rxd_handler().set(m_mfpdev, FUNC(mc68901_device::si_w));
MSX_GENERAL_PURPOSE_PORT(config, m_joy[0], msx_general_purpose_port_devices, "townspad");
MSX_GENERAL_PURPOSE_PORT(config, m_joy[1], msx_general_purpose_port_devices, "townspad");
I8255A(config, m_ppi, 0);
m_ppi->in_pa_callback().set(FUNC(x68k_state::ppi_port_a_r));
m_ppi->in_pb_callback().set(FUNC(x68k_state::ppi_port_b_r));

View File

@ -13,6 +13,10 @@
#pragma once
#include "x68k_crtc.h"
#include "bus/msx/ctrl/ctrl.h"
#include "bus/x68k/x68kexp.h"
#include "cpu/m68000/m68000.h"
#include "cpu/m68000/m68030.h"
#include "imagedev/floppy.h"
@ -27,8 +31,6 @@
#include "sound/flt_vol.h"
#include "sound/okim6258.h"
#include "sound/ymopm.h"
#include "x68k_crtc.h"
#include "bus/x68k/x68kexp.h"
#include "emupal.h"
#include "screen.h"
@ -58,19 +60,13 @@ public:
, m_ppi(*this, "ppi8255")
, m_screen(*this, "screen")
, m_upd72065(*this, "upd72065")
, m_joy(*this, "joy%u", 1U)
, m_expansion(*this, "exp%u", 1U)
, m_adpcm_out(*this, {"adpcm_outl", "adpcm_outr"})
, m_options(*this, "options")
, m_mouse1(*this, "mouse1")
, m_mouse2(*this, "mouse2")
, m_mouse3(*this, "mouse3")
, m_xpd1lr(*this, "xpd1lr")
, m_ctrltype(*this, "ctrltype")
, m_joy1(*this, "joy1")
, m_joy2(*this, "joy2")
, m_md3b(*this, "md3b")
, m_md6b(*this, "md6b")
, m_md6b_extra(*this, "md6b_extra")
, m_eject_drv_out(*this, "eject_drv%u", 0U)
, m_ctrl_drv_out(*this, "ctrl_drv%u", 0U)
, m_access_drv_out(*this, "access_drv%u", 0U)
@ -109,6 +105,7 @@ protected:
required_device<i8255_device> m_ppi;
required_device<screen_device> m_screen;
required_device<upd72065_device> m_upd72065;
required_device_array<msx_general_purpose_port_device, 2> m_joy;
required_device_array<x68k_expansion_slot_device, 2> m_expansion;
required_device_array<filter_volume_device, 2> m_adpcm_out;
@ -117,13 +114,6 @@ protected:
required_ioport m_mouse1;
required_ioport m_mouse2;
required_ioport m_mouse3;
required_ioport m_xpd1lr;
required_ioport m_ctrltype;
required_ioport m_joy1;
required_ioport m_joy2;
required_ioport m_md3b;
required_ioport m_md6b;
required_ioport m_md6b_extra;
output_finder<4> m_eject_drv_out;
output_finder<4> m_ctrl_drv_out;
@ -162,13 +152,6 @@ protected:
int select_drive = 0;
} m_fdc;
struct
{
int ioc7 = 0; // "Function B operation of joystick # one option"
int ioc6 = 0; // "Function A operation of joystick # one option"
int joy1_enable = 0; // IOC4
int joy2_enable = 0; // IOC5
} m_joy;
struct
{
int rate = 0; // ADPCM sample rate
int pan = 0; // ADPCM output switch
@ -206,18 +189,7 @@ protected:
char last_mouse_y = 0; // previous mouse y-axis value
int bufferempty = 0; // non-zero if buffer is empty
} m_mouse;
struct
{
// port A
int mux1 = 0; // multiplexer value
int seq1 = 0; // part of 6-button input sequence.
emu_timer* io_timeout1 = nullptr;
// port B
int mux2 = 0; // multiplexer value
int seq2 = 0; // part of 6-button input sequence.
emu_timer* io_timeout2 = nullptr;
} m_mdctrl;
uint8_t m_ppi_port[3]{};
uint8_t m_ppi_portc = 0;
bool m_dmac_int = false;
bool m_mfp_int = false;
bool m_exp_irq2[2]{};
@ -228,7 +200,6 @@ protected:
emu_timer* m_mouse_timer = nullptr;
emu_timer* m_led_timer = nullptr;
unsigned char m_scc_prev = 0;
uint16_t m_ppi_prev = 0;
emu_timer* m_fdc_tc = nullptr;
emu_timer* m_adpcm_timer = nullptr;
emu_timer* m_bus_error_timer = nullptr;
@ -250,8 +221,6 @@ protected:
TIMER_CALLBACK_MEMBER(adpcm_drq_tick);
TIMER_CALLBACK_MEMBER(led_callback);
TIMER_CALLBACK_MEMBER(scc_ack);
TIMER_CALLBACK_MEMBER(md_6button_port1_timeout);
TIMER_CALLBACK_MEMBER(md_6button_port2_timeout);
TIMER_CALLBACK_MEMBER(bus_error);
uint8_t ppi_port_a_r();
uint8_t ppi_port_b_r();
@ -268,10 +237,6 @@ protected:
int read_mouse();
void set_adpcm();
uint8_t md_3button_r(int port);
void md_6button_init();
uint8_t md_6button_r(int port);
uint8_t xpd1lr_r(int port);
DECLARE_WRITE_LINE_MEMBER(fm_irq);
template <int N> DECLARE_WRITE_LINE_MEMBER(irq2_line);