mirror of
https://github.com/holub/mame
synced 2025-06-05 20:33:45 +03:00
More Micom Soft controller wrangling:
* bus/msx/ctrl: Added XE-1AP pad with defaults for personal computers. * bus/pce_ctrl: Added XHE-3 PC joystick adapter.
This commit is contained in:
parent
696b16ccb9
commit
a32b70c034
@ -1839,6 +1839,8 @@ if (BUSES["MSX_CTRL"]~=null) then
|
||||
MAME_DIR .. "src/devices/bus/msx/ctrl/towns6b.h",
|
||||
MAME_DIR .. "src/devices/bus/msx/ctrl/townspad.cpp",
|
||||
MAME_DIR .. "src/devices/bus/msx/ctrl/townspad.h",
|
||||
MAME_DIR .. "src/devices/bus/msx/ctrl/xe1ap.cpp",
|
||||
MAME_DIR .. "src/devices/bus/msx/ctrl/xe1ap.h",
|
||||
}
|
||||
end
|
||||
|
||||
@ -4053,6 +4055,28 @@ if (BUSES["PCE"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/pce_ctrl/pcectrl.h,BUSES["PCE_CTRL"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (BUSES["PCE_CTRL"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pcectrl.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pcectrl.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad2.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad2.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad6.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad6.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/multitap.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/multitap.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pachinko.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pachinko.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/xhe3.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/xhe3.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/scv/slot.h,BUSES["SCV"] = true
|
||||
@ -5078,26 +5102,6 @@ if (BUSES["THOMSON"]~=null) then
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/pce_ctrl/pcectrl.h,BUSES["PCE_CTRL"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (BUSES["PCE_CTRL"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pcectrl.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pcectrl.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad2.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad2.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad6.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/joypad6.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/multitap.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/multitap.h",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pachinko.cpp",
|
||||
MAME_DIR .. "src/devices/bus/pce_ctrl/pachinko.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/bus/pc8801/pc8801_31.h,BUSES["PC8801"] = true
|
||||
|
@ -5101,3 +5101,15 @@ if (MACHINES["AM9516"]~=null) then
|
||||
MAME_DIR .. "src/devices/machine/am9516.h",
|
||||
}
|
||||
end
|
||||
|
||||
---------------------------------------------------
|
||||
--
|
||||
--@src/devices/machine/micomxe1a.h,MACHINES["MICOMXE1A"] = true
|
||||
---------------------------------------------------
|
||||
|
||||
if (MACHINES["MICOMXE1A"]~=null) then
|
||||
files {
|
||||
MAME_DIR .. "src/devices/machine/micomxe1a.cpp",
|
||||
MAME_DIR .. "src/devices/machine/micomxe1a.h",
|
||||
}
|
||||
end
|
||||
|
@ -16,6 +16,7 @@
|
||||
#include "sgadapt.h"
|
||||
#include "towns6b.h"
|
||||
#include "townspad.h"
|
||||
#include "xe1ap.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(MSX_GENERAL_PURPOSE_PORT, msx_general_purpose_port_device, "msx_general_purpose_port", "MSX General Purpose port")
|
||||
@ -52,4 +53,5 @@ void msx_general_purpose_port_devices(device_slot_interface &device)
|
||||
device.option_add("sega", MSX_SEGACTRL);
|
||||
device.option_add("towns6b", MSX_TOWNS6B);
|
||||
device.option_add("townspad", MSX_TOWNSPAD);
|
||||
device.option_add("xe1ap", MSX_XE1AP);
|
||||
}
|
||||
|
101
src/devices/bus/msx/ctrl/xe1ap.cpp
Normal file
101
src/devices/bus/msx/ctrl/xe1ap.cpp
Normal file
@ -0,0 +1,101 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/**********************************************************************
|
||||
|
||||
Dempa Micom Soft Analog/Digital Controller XE-1AP emulation
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "xe1ap.h"
|
||||
|
||||
#include "machine/micomxe1a.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
INPUT_PORTS_START(xe1ap)
|
||||
PORT_START("BUTTONS")
|
||||
PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("%p D") // left shoulder lower
|
||||
PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("%p C") // left shoulder upper
|
||||
PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("%p B") // right shoulder lower
|
||||
PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("%p A") // right shoulder upper
|
||||
PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_SELECT) // left face bottom
|
||||
PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_START) // right face bottom
|
||||
PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("%p E2") // left face top inner
|
||||
PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("%p E1") // left face top outer
|
||||
PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_BUTTON8) PORT_NAME("%p B'") // right face top inner
|
||||
PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_BUTTON7) PORT_NAME("%p A'") // right face top outer
|
||||
PORT_BIT(0xfc00, IP_ACTIVE_LOW, IPT_UNUSED)
|
||||
|
||||
PORT_START("CH0")
|
||||
PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_SENSITIVITY(50) PORT_KEYDELTA(50)
|
||||
|
||||
PORT_START("CH1")
|
||||
PORT_BIT(0xff, 0x80, IPT_AD_STICK_X) PORT_SENSITIVITY(50) PORT_KEYDELTA(50)
|
||||
|
||||
PORT_START("CH2")
|
||||
PORT_BIT(0xff, 0x80, IPT_PADDLE_V) PORT_REVERSE PORT_SENSITIVITY(50) PORT_KEYDELTA(50)
|
||||
|
||||
PORT_START("CH3")
|
||||
PORT_BIT(0xff, 0x00, IPT_UNUSED)
|
||||
|
||||
PORT_START("MODE")
|
||||
PORT_CONFNAME(0x01, 0x01, "Mode") PORT_WRITE_LINE_DEVICE_MEMBER("xe1", micom_xe_1a_device, mode_w)
|
||||
PORT_CONFSETTING( 0x00, "Digital")
|
||||
PORT_CONFSETTING( 0x01, "Analog")
|
||||
PORT_CONFNAME(0x02, 0x00, "Interface") PORT_WRITE_LINE_DEVICE_MEMBER("xe1", micom_xe_1a_device, interface_w)
|
||||
PORT_CONFSETTING( 0x00, "Personal Computer")
|
||||
PORT_CONFSETTING( 0x02, "MD")
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
class xe1ap_device : public device_t, public device_msx_general_purpose_port_interface
|
||||
{
|
||||
public:
|
||||
xe1ap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) ATTR_COLD;
|
||||
|
||||
virtual u8 read() override { return m_xe1->out_r() | 0xc0; }
|
||||
virtual void pin_8_w(int state) override { m_xe1->req_w(state); }
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD { return INPUT_PORTS_NAME(xe1ap); }
|
||||
virtual void device_start() override ATTR_COLD { }
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
u8 read_channel(offs_t offset) { return m_axes[offset]->read(); }
|
||||
|
||||
required_device<micom_xe_1a_device> m_xe1;
|
||||
required_ioport_array<4> m_axes;
|
||||
required_ioport m_mode;
|
||||
};
|
||||
|
||||
xe1ap_device::xe1ap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, MSX_XE1AP, tag, owner, clock),
|
||||
device_msx_general_purpose_port_interface(mconfig, *this),
|
||||
m_xe1(*this, "xe1"),
|
||||
m_axes(*this, "CH%u", 0U),
|
||||
m_mode(*this, "MODE")
|
||||
{
|
||||
}
|
||||
|
||||
void xe1ap_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
MICOM_XE_1A(config, m_xe1);
|
||||
m_xe1->buttons_handler().set_ioport("BUTTONS");
|
||||
m_xe1->analog_handler().set(FUNC(xe1ap_device::read_channel));
|
||||
}
|
||||
|
||||
void xe1ap_device::device_reset()
|
||||
{
|
||||
auto const mode = m_mode->read();
|
||||
m_xe1->mode_w(BIT(mode, 0));
|
||||
m_xe1->interface_w(BIT(mode, 1));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(MSX_XE1AP, device_msx_general_purpose_port_interface, xe1ap_device, "msx_xe1ap", "Dempa Micom Soft Analog Controller (XE-1AP, PC)")
|
19
src/devices/bus/msx/ctrl/xe1ap.h
Normal file
19
src/devices/bus/msx/ctrl/xe1ap.h
Normal file
@ -0,0 +1,19 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/**********************************************************************
|
||||
|
||||
Dempa Micom Soft Analog/Digital Controller XE-1AP emulation
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_MSX_CTRL_XE1AP_H
|
||||
#define MAME_BUS_MSX_CTRL_XE1AP_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "ctrl.h"
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(MSX_XE1AP, device_msx_general_purpose_port_interface)
|
||||
|
||||
#endif // MAME_BUS_MSX_CTRL_XE1AP_H
|
@ -33,22 +33,17 @@
|
||||
#include "emu.h"
|
||||
#include "joypad2.h"
|
||||
|
||||
#include "machine/74157.h"
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE DEFINITIONS
|
||||
//**************************************************************************
|
||||
namespace {
|
||||
|
||||
DEFINE_DEVICE_TYPE(PCE_JOYPAD2, pce_joypad2_device, "pce_joypad2", "NEC PC Engine Pad")
|
||||
DEFINE_DEVICE_TYPE(PCE_JOYPAD2_TURBO, pce_joypad2_turbo_device, "pce_joypad2_turbo", "NEC PC Engine/TurboGrafx-16 2 Button Joypad")
|
||||
|
||||
|
||||
static INPUT_PORTS_START( pce_joypad2 )
|
||||
INPUT_PORTS_START( pce_joypad2 )
|
||||
// II is left of I on the original pad so we map them in reverse order
|
||||
PORT_START("BUTTONS")
|
||||
PORT_BIT( 0x01, IP_ACTIVE_LOW, IPT_BUTTON2 ) PORT_NAME("%p Button I")
|
||||
PORT_BIT( 0x02, IP_ACTIVE_LOW, IPT_BUTTON1 ) PORT_NAME("%p Button II")
|
||||
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT ) PORT_NAME("%p Select")
|
||||
PORT_BIT( 0x04, IP_ACTIVE_LOW, IPT_SELECT )
|
||||
PORT_BIT( 0x08, IP_ACTIVE_LOW, IPT_START ) PORT_NAME("%p Run")
|
||||
|
||||
PORT_START("DIRECTION")
|
||||
@ -59,7 +54,7 @@ static INPUT_PORTS_START( pce_joypad2 )
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
static INPUT_PORTS_START( pce_joypad2_turbo )
|
||||
INPUT_PORTS_START( pce_joypad2_turbo )
|
||||
PORT_INCLUDE( pce_joypad2 )
|
||||
|
||||
PORT_START("TURBO")
|
||||
@ -74,6 +69,73 @@ static INPUT_PORTS_START( pce_joypad2_turbo )
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> pce_joypad2_device
|
||||
|
||||
class pce_joypad2_device : public device_t, public device_pce_control_port_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
pce_joypad2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
pce_joypad2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
|
||||
// device_pce_control_port_interface overrides
|
||||
virtual u8 peripheral_r() override;
|
||||
virtual void sel_w(int state) override;
|
||||
virtual void clr_w(int state) override;
|
||||
|
||||
// devices
|
||||
required_device<ls157_device> m_muxer;
|
||||
};
|
||||
|
||||
|
||||
// ======================> pce_joypad2_turbo_device
|
||||
|
||||
class pce_joypad2_turbo_device : public pce_joypad2_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
pce_joypad2_turbo_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device_pce_control_port_interface overrides
|
||||
virtual void clr_w(int state) override;
|
||||
|
||||
private:
|
||||
u8 buttons_r();
|
||||
|
||||
// IO ports
|
||||
required_ioport m_buttons_io;
|
||||
required_ioport m_turbo_io;
|
||||
|
||||
// internal states
|
||||
u8 m_counter; // Turbo rate counter, connected on 74xx163 QB and QC.
|
||||
bool m_prev_clr; // previous CLR pin state
|
||||
};
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------
|
||||
// input_ports - device-specific input ports
|
||||
//-------------------------------------------------
|
||||
@ -242,3 +304,14 @@ u8 pce_joypad2_turbo_device::buttons_r()
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// DEVICE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(PCE_JOYPAD2, device_pce_control_port_interface, pce_joypad2_device, "pce_joypad2", "NEC PC Engine Pad")
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(PCE_JOYPAD2_TURBO, device_pce_control_port_interface, pce_joypad2_turbo_device, "pce_joypad2_turbo", "NEC PC Engine/TurboGrafx-16 2 Button Joypad")
|
||||
|
@ -5,87 +5,16 @@
|
||||
NEC PC Engine/TurboGrafx-16 2 Button Joypad emulation
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#ifndef MAME_BUS_PCE_CTRL_JOYPAD2_H
|
||||
#define MAME_BUS_PCE_CTRL_JOYPAD2_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
#include "machine/74157.h"
|
||||
#include "pcectrl.h"
|
||||
|
||||
|
||||
|
||||
//**************************************************************************
|
||||
// TYPE DEFINITIONS
|
||||
//**************************************************************************
|
||||
|
||||
// ======================> pce_joypad2_device
|
||||
|
||||
class pce_joypad2_device : public device_t,
|
||||
public device_pce_control_port_interface
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
pce_joypad2_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// construction/destruction
|
||||
pce_joypad2_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
|
||||
// device_pce_control_port_interface overrides
|
||||
virtual u8 peripheral_r() override;
|
||||
virtual void sel_w(int state) override;
|
||||
virtual void clr_w(int state) override;
|
||||
|
||||
// devices
|
||||
required_device<ls157_device> m_muxer;
|
||||
};
|
||||
|
||||
// ======================> pce_joypad2_turbo_device
|
||||
|
||||
class pce_joypad2_turbo_device : public pce_joypad2_device
|
||||
{
|
||||
public:
|
||||
// construction/destruction
|
||||
pce_joypad2_turbo_device(const machine_config &mconfig, const char *tag, device_t *owner, u32 clock);
|
||||
|
||||
protected:
|
||||
// optional information overrides
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
|
||||
// device-level overrides
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual void device_start() override;
|
||||
virtual void device_reset() override;
|
||||
|
||||
// device_pce_control_port_interface overrides
|
||||
virtual void clr_w(int state) override;
|
||||
|
||||
private:
|
||||
u8 buttons_r();
|
||||
|
||||
// IO ports
|
||||
required_ioport m_buttons_io;
|
||||
required_ioport m_turbo_io;
|
||||
|
||||
// internal states
|
||||
u8 m_counter; // Turbo rate counter, connected on 74xx163 QB and QC.
|
||||
bool m_prev_clr; // previous CLR pin state
|
||||
};
|
||||
|
||||
|
||||
// device type definition
|
||||
DECLARE_DEVICE_TYPE(PCE_JOYPAD2, pce_joypad2_device)
|
||||
DECLARE_DEVICE_TYPE(PCE_JOYPAD2_TURBO, pce_joypad2_turbo_device)
|
||||
|
||||
DECLARE_DEVICE_TYPE(PCE_JOYPAD2, device_pce_control_port_interface)
|
||||
DECLARE_DEVICE_TYPE(PCE_JOYPAD2_TURBO, device_pce_control_port_interface)
|
||||
|
||||
#endif // MAME_BUS_PCE_CTRL_JOYPAD2_H
|
||||
|
@ -51,14 +51,16 @@
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "screen.h"
|
||||
#include "pcectrl.h"
|
||||
|
||||
#include "screen.h"
|
||||
|
||||
// slot devices
|
||||
#include "joypad2.h"
|
||||
#include "joypad6.h"
|
||||
#include "multitap.h"
|
||||
#include "pachinko.h"
|
||||
#include "xhe3.h"
|
||||
|
||||
|
||||
|
||||
@ -176,6 +178,8 @@ void pce_control_port_devices(device_slot_interface &device)
|
||||
|
||||
device.option_add("multitap", PCE_MULTITAP);
|
||||
device.option_add("pachinko", PCE_PACHINKO);
|
||||
|
||||
device.option_add("pcjoy", PCE_XHE3);
|
||||
// 3 Button Joypad/Joysticks (ex: Avenue Pad 3)
|
||||
// PC Engine Mouse (PI-PD10)
|
||||
// Memory Base 128 (PI-AD19)
|
||||
|
92
src/devices/bus/pce_ctrl/xhe3.cpp
Normal file
92
src/devices/bus/pce_ctrl/xhe3.cpp
Normal file
@ -0,0 +1,92 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/***********************************************************************
|
||||
|
||||
Micom Soft XHE-3 PC Joystick Adapter for PC Engine emuation
|
||||
|
||||
***********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "xhe3.h"
|
||||
|
||||
#include "bus/msx/ctrl/ctrl.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
INPUT_PORTS_START( pce_xhe3 )
|
||||
PORT_START("BUTTONS") // using IPT_START/IPT_SELECT would steal a player index
|
||||
PORT_BIT(0x01, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Select")
|
||||
PORT_BIT(0x02, IP_ACTIVE_LOW, IPT_OTHER) PORT_NAME("Run")
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
|
||||
class pce_xhe3_device : public device_t, public device_pce_control_port_interface
|
||||
{
|
||||
public:
|
||||
pce_xhe3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
|
||||
|
||||
virtual u8 peripheral_r() override;
|
||||
virtual void sel_w(int state) override;
|
||||
virtual void clr_w(int state) override;
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override;
|
||||
virtual ioport_constructor device_input_ports() const override { return INPUT_PORTS_NAME(pce_xhe3); }
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
required_device<msx_general_purpose_port_device> m_port;
|
||||
required_ioport m_buttons;
|
||||
|
||||
u8 m_sel_in;
|
||||
};
|
||||
|
||||
|
||||
pce_xhe3_device::pce_xhe3_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, PCE_XHE3, tag, owner, clock),
|
||||
device_pce_control_port_interface(mconfig, *this),
|
||||
m_port(*this, "joy"),
|
||||
m_buttons(*this, "BUTTONS"),
|
||||
m_sel_in(1)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
u8 pce_xhe3_device::peripheral_r()
|
||||
{
|
||||
if (m_sel_in)
|
||||
return bitswap<4>(m_port->read(), 2, 1, 3, 0);
|
||||
else
|
||||
return bitswap<2>(m_port->read(), 5, 4) | (m_buttons->read() << 2);
|
||||
}
|
||||
|
||||
|
||||
void pce_xhe3_device::sel_w(int state)
|
||||
{
|
||||
m_sel_in = state ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void pce_xhe3_device::clr_w(int state)
|
||||
{
|
||||
m_port->pin_8_w(state);
|
||||
}
|
||||
|
||||
|
||||
void pce_xhe3_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
MSX_GENERAL_PURPOSE_PORT(config, m_port, msx_general_purpose_port_devices, "xe1ap");
|
||||
}
|
||||
|
||||
|
||||
void pce_xhe3_device::device_start()
|
||||
{
|
||||
save_item(NAME(m_sel_in));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(PCE_XHE3, device_pce_control_port_interface, pce_xhe3_device, "pce_xhe3", "Micom Soft XHE-3 PC Joystick Adapter for PC Engine")
|
18
src/devices/bus/pce_ctrl/xhe3.h
Normal file
18
src/devices/bus/pce_ctrl/xhe3.h
Normal file
@ -0,0 +1,18 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/***********************************************************************
|
||||
|
||||
Micom Soft XHE-3 PC Joystick Adapter for PC Engine emuation
|
||||
|
||||
***********************************************************************/
|
||||
#ifndef MAME_BUS_PCE_CTRL_XHE3_H
|
||||
#define MAME_BUS_PCE_CTRL_XHE3_H
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "pcectrl.h"
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(PCE_XHE3, device_pce_control_port_interface)
|
||||
|
||||
#endif // MAME_BUS_PCE_CTRL_XHE3_H
|
@ -4,129 +4,29 @@
|
||||
|
||||
Dempa Micom Soft Analog/Digital Controller XE-1AP emulation
|
||||
|
||||
PC pin Name MD pin Name Dir Signal
|
||||
1 Up 1 Up In D0
|
||||
2 Down 2 Down In D1
|
||||
3 Left 3 Left In D2
|
||||
4 Right 4 Right In D3
|
||||
6 TRIG1 6 TL In L/H
|
||||
7 TRIG2 9 TR In Ack
|
||||
8 STROBE 7 TH Out Req
|
||||
|
||||
In analog mode, data is shifted out as eleven nybbles:
|
||||
|
||||
_ ____________________________________________
|
||||
Req \_________/
|
||||
____ __ __ __ __ __ __ __ __
|
||||
Ack \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
|
||||
_____ _____ _____ _____
|
||||
L/H XX\____/ \_____/ \_____/ \_____/ \_____/
|
||||
____ _____ _____ _____ _____ _____ _____ _____ _____
|
||||
D XXX____X_____X_____X_____X_____X_____X_____X_____X_____X
|
||||
|
||||
The falling edge on Req causes data output to start. The host
|
||||
can't control the speed, it just polls the L/H and Ack lines to
|
||||
know when the data is ready to read.
|
||||
|
||||
Step D0 D1 D2 D3
|
||||
1 Select Start B' A'
|
||||
2 D C B A
|
||||
2 X4 X5 X6 X7
|
||||
3 Y4 Y5 Y6 Y7
|
||||
5 RZ4 RZ5 RZ6 RZ7
|
||||
6 Z4 Z5 Z6 Z7
|
||||
7 X0 X1 X2 X3
|
||||
8 Y0 Y1 Y2 Y3
|
||||
9 RZ0 RZ1 RZ2 RZ3
|
||||
10 Z0 Z1 Z2 Z3
|
||||
11 E2 E1 - -
|
||||
|
||||
In digital mode, Req is a simple multiplexer input:
|
||||
|
||||
Req 0 1
|
||||
D0 Up Throttle Up
|
||||
D1 Down Throttle Down
|
||||
D2 Left C
|
||||
D3 Right D
|
||||
L/H A E1
|
||||
Ack B E2
|
||||
|
||||
Start appears as simultaneous Left/Right
|
||||
Select appears as simultaneous Up/Down
|
||||
|
||||
This mode is almost compatible with a 6-button Towns Pad (on a
|
||||
real 6-button Towns Pad, buttons A and B can be read in either
|
||||
state, they bypass the multiplexer).
|
||||
|
||||
TODO:
|
||||
* Measure timings.
|
||||
* Confirm reported value for unused analog channel 4.
|
||||
* Confirm A', B', E1 and E2 bit mappings in analog mode.
|
||||
* Confirm buttons mapping in digital mode.
|
||||
- Is the mapping different in PC vs MD mode?
|
||||
* Implement trigger A/B rapid fire switches.
|
||||
* Implement channel shift switch (Y->X, X->Z, Z->X).
|
||||
* Implement special modes (holding buttons on power-on):
|
||||
- Double displacement modes:
|
||||
+ X/Y (hold SELECT + A')
|
||||
+ Z (hold SELECT + B')
|
||||
+ X/Y/Z (hold SELECT + A' + B')
|
||||
- Up/down reverse mode (hold C)
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "xe1ap.h"
|
||||
|
||||
//#define VERBOSE 1
|
||||
//#define LOG_OUTPUT_FUNC osd_printf_info
|
||||
#include "logmacro.h"
|
||||
#include "machine/micomxe1a.h"
|
||||
|
||||
|
||||
namespace {
|
||||
|
||||
class sms_xe1ap_device : public device_t, public device_sms_control_interface
|
||||
{
|
||||
public:
|
||||
sms_xe1ap_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;
|
||||
|
||||
DECLARE_INPUT_CHANGED_MEMBER(mode_changed);
|
||||
|
||||
protected:
|
||||
virtual ioport_constructor device_input_ports() const override;
|
||||
virtual void device_start() override;
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(step_output);
|
||||
|
||||
required_ioport m_buttons;
|
||||
required_ioport_array<4> m_axes;
|
||||
required_ioport m_mode;
|
||||
|
||||
emu_timer *m_output_timer;
|
||||
|
||||
u8 m_req;
|
||||
u8 m_out;
|
||||
};
|
||||
|
||||
|
||||
|
||||
INPUT_PORTS_START( sms_xe1ap )
|
||||
PORT_START("BUTTONS")
|
||||
PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_SELECT) // left face bottom
|
||||
PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_START) // right face bottom
|
||||
PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("%p B'") // right face top inner
|
||||
PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("%p A'") // right face top outer
|
||||
PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("%p D") // left shoulder lower
|
||||
PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("%p C") // left shoulder upper
|
||||
PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("%p B") // right shoulder lower
|
||||
PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("%p A") // right shoulder upper
|
||||
PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_BUTTON8) PORT_NAME("%p E2") // left face top inner
|
||||
PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_BUTTON7) PORT_NAME("%p E1") // left face top outer
|
||||
PORT_BIT(0x0c00, IP_ACTIVE_LOW, IPT_UNUSED)
|
||||
PORT_BIT(0x0001, IP_ACTIVE_LOW, IPT_BUTTON4) PORT_NAME("%p D") // left shoulder lower
|
||||
PORT_BIT(0x0002, IP_ACTIVE_LOW, IPT_BUTTON3) PORT_NAME("%p C") // left shoulder upper
|
||||
PORT_BIT(0x0004, IP_ACTIVE_LOW, IPT_BUTTON2) PORT_NAME("%p B") // right shoulder lower
|
||||
PORT_BIT(0x0008, IP_ACTIVE_LOW, IPT_BUTTON1) PORT_NAME("%p A") // right shoulder upper
|
||||
PORT_BIT(0x0010, IP_ACTIVE_LOW, IPT_SELECT) // left face bottom
|
||||
PORT_BIT(0x0020, IP_ACTIVE_LOW, IPT_START) // right face bottom
|
||||
PORT_BIT(0x0040, IP_ACTIVE_LOW, IPT_BUTTON6) PORT_NAME("%p E2") // left face top inner
|
||||
PORT_BIT(0x0080, IP_ACTIVE_LOW, IPT_BUTTON5) PORT_NAME("%p E1") // left face top outer
|
||||
PORT_BIT(0x0100, IP_ACTIVE_LOW, IPT_BUTTON8) PORT_NAME("%p B'") // right face top inner
|
||||
PORT_BIT(0x0200, IP_ACTIVE_LOW, IPT_BUTTON7) PORT_NAME("%p A'") // right face top outer
|
||||
PORT_BIT(0xfc00, IP_ACTIVE_LOW, IPT_UNUSED)
|
||||
|
||||
PORT_START("CH0")
|
||||
PORT_BIT(0xff, 0x80, IPT_AD_STICK_Y) PORT_SENSITIVITY(50) PORT_KEYDELTA(50)
|
||||
@ -138,181 +38,70 @@ INPUT_PORTS_START( sms_xe1ap )
|
||||
PORT_BIT(0xff, 0x80, IPT_PADDLE_V) PORT_REVERSE PORT_SENSITIVITY(50) PORT_KEYDELTA(50)
|
||||
|
||||
PORT_START("CH3")
|
||||
PORT_BIT(0xff, 0x80, IPT_UNUSED)
|
||||
PORT_BIT(0xff, 0x00, IPT_UNUSED)
|
||||
|
||||
PORT_START("MODE")
|
||||
PORT_CONFNAME(0x01, 0x01, "Mode") PORT_CHANGED_MEMBER(DEVICE_SELF, sms_xe1ap_device, mode_changed, 0)
|
||||
PORT_CONFNAME(0x01, 0x01, "Mode") PORT_WRITE_LINE_DEVICE_MEMBER("xe1", micom_xe_1a_device, mode_w)
|
||||
PORT_CONFSETTING( 0x00, "Digital")
|
||||
PORT_CONFSETTING( 0x01, "Analog")
|
||||
PORT_CONFNAME(0x02, 0x02, "Interface") PORT_WRITE_LINE_DEVICE_MEMBER("xe1", micom_xe_1a_device, interface_w)
|
||||
PORT_CONFSETTING( 0x00, "Personal Computer")
|
||||
PORT_CONFSETTING( 0x02, "MD")
|
||||
INPUT_PORTS_END
|
||||
|
||||
|
||||
|
||||
class sms_xe1ap_device : public device_t, public device_sms_control_interface
|
||||
{
|
||||
public:
|
||||
sms_xe1ap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) ATTR_COLD;
|
||||
|
||||
virtual u8 in_r() override { return m_xe1->out_r(); }
|
||||
virtual void out_w(u8 data, u8 mem_mask) override { m_xe1->req_w(BIT(data, 6)); }
|
||||
|
||||
protected:
|
||||
virtual void device_add_mconfig(machine_config &config) override ATTR_COLD;
|
||||
virtual ioport_constructor device_input_ports() const override ATTR_COLD { return INPUT_PORTS_NAME(sms_xe1ap); }
|
||||
virtual void device_start() override ATTR_COLD { }
|
||||
virtual void device_reset() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
u8 read_channel(offs_t offset) { return m_axes[offset]->read(); }
|
||||
|
||||
required_device<micom_xe_1a_device> m_xe1;
|
||||
required_ioport_array<4> m_axes;
|
||||
required_ioport m_mode;
|
||||
};
|
||||
|
||||
|
||||
|
||||
sms_xe1ap_device::sms_xe1ap_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock) :
|
||||
device_t(mconfig, SMS_XE1AP, tag, owner, clock),
|
||||
device_sms_control_interface(mconfig, *this),
|
||||
m_buttons(*this, "BUTTONS"),
|
||||
m_xe1(*this, "xe1"),
|
||||
m_axes(*this, "CH%u", 0U),
|
||||
m_mode(*this, "MODE"),
|
||||
m_output_timer(nullptr),
|
||||
m_req(1),
|
||||
m_out(0x3f)
|
||||
m_mode(*this, "MODE")
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
u8 sms_xe1ap_device::in_r()
|
||||
void sms_xe1ap_device::device_add_mconfig(machine_config &config)
|
||||
{
|
||||
if (BIT(m_mode->read(), 0))
|
||||
{
|
||||
LOG(
|
||||
"%s: analog mode read data = %02X\n",
|
||||
machine().describe_context(),
|
||||
m_out);
|
||||
return m_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 const buttons = m_buttons->read();
|
||||
if (m_req)
|
||||
{
|
||||
u8 const x = m_axes[0]->read();
|
||||
u8 const y = m_axes[1]->read();
|
||||
u8 const result =
|
||||
((BIT(buttons, 0) && (0x40 <= y)) ? 0x01 : 0x00) | // Select/Up
|
||||
((BIT(buttons, 0) && (0xc0 > y)) ? 0x02 : 0x00) | // Select/Down
|
||||
((BIT(buttons, 1) && (0x40 <= x)) ? 0x04 : 0x00) | // Start/Left
|
||||
((BIT(buttons, 1) && (0xc0 > x)) ? 0x08 : 0x00) | // Start/Right
|
||||
(BIT(buttons, 7) << 4) | // A
|
||||
(BIT(buttons, 6) << 5); // B
|
||||
LOG(
|
||||
"%s: digital mode basic read = 0x%02X\n",
|
||||
machine().describe_context(),
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 const z = m_axes[3]->read();
|
||||
u8 const result =
|
||||
((0xc0 > z) ? 0x01 : 0x00) | // Throttle Up
|
||||
((0x40 <= z) ? 0x02 : 0x00) | // Throttle Down
|
||||
(BIT(buttons, 5) << 2) | // C
|
||||
(BIT(buttons, 4) << 3) | // D
|
||||
(BIT(buttons, 9) << 4) | // E1
|
||||
(BIT(buttons, 8) << 5); // E2
|
||||
LOG(
|
||||
"%s: digital mode extended read = 0x%02X\n",
|
||||
machine().describe_context(),
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
MICOM_XE_1A(config, m_xe1);
|
||||
m_xe1->buttons_handler().set_ioport("BUTTONS");
|
||||
m_xe1->analog_handler().set(FUNC(sms_xe1ap_device::read_channel));
|
||||
}
|
||||
|
||||
|
||||
void sms_xe1ap_device::out_w(u8 data, u8 mem_mask)
|
||||
void sms_xe1ap_device::device_reset()
|
||||
{
|
||||
u8 const req = BIT(data, 6);
|
||||
if (req != m_req)
|
||||
{
|
||||
if (BIT(m_mode->read(), 0))
|
||||
{
|
||||
LOG("%s: /Req = %u\n", machine().describe_context(), req);
|
||||
if (!req)
|
||||
m_output_timer->adjust(attotime::from_usec(4), 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("%s: /Req = %u ignored in digital mode\n", machine().describe_context(), req);
|
||||
}
|
||||
m_req = req;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
INPUT_CHANGED_MEMBER(sms_xe1ap_device::mode_changed)
|
||||
{
|
||||
if (newval)
|
||||
{
|
||||
LOG("Analog mode selected\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Digital mode selected\n");
|
||||
m_output_timer->enable(false);
|
||||
m_out = 0x3f;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
ioport_constructor sms_xe1ap_device::device_input_ports() const
|
||||
{
|
||||
return INPUT_PORTS_NAME(sms_xe1ap);
|
||||
}
|
||||
|
||||
|
||||
void sms_xe1ap_device::device_start()
|
||||
{
|
||||
m_output_timer = timer_alloc(FUNC(sms_xe1ap_device::step_output), this);
|
||||
|
||||
save_item(NAME(m_req));
|
||||
save_item(NAME(m_out));
|
||||
}
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(sms_xe1ap_device::step_output)
|
||||
{
|
||||
if (!BIT(param, 0))
|
||||
{
|
||||
auto const step = param >> 1;
|
||||
if (12 > step)
|
||||
{
|
||||
switch (step)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
m_out = BIT(m_buttons->read(), step ? 4 : 0, 4);
|
||||
break;
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
case 8:
|
||||
case 9:
|
||||
m_out = BIT(m_axes[((step - 2) & 0x03) ^ 0x01]->read(), (step < 6) ? 4 : 0, 4);
|
||||
break;
|
||||
case 10:
|
||||
m_out = BIT(m_buttons->read(), 8, 4);
|
||||
break;
|
||||
default:
|
||||
m_out = 0x0f;
|
||||
}
|
||||
m_out |= BIT(param, 1) ? 0x30 : 0x20;
|
||||
LOG(
|
||||
"Set nybble %u data = 0x%X, L/H = %d, /Ack = 1\n",
|
||||
step,
|
||||
BIT(m_out, 0, 4),
|
||||
BIT(m_out, 4));
|
||||
m_output_timer->adjust(attotime::from_usec(4), param + 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
m_out = 0x3f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_out &= 0x1f;
|
||||
LOG("Set nybble %u /Ack = 0\n", param >> 1);
|
||||
m_output_timer->adjust(attotime::from_usec(20), param + 1);
|
||||
}
|
||||
auto const mode = m_mode->read();
|
||||
m_xe1->mode_w(BIT(mode, 0));
|
||||
m_xe1->interface_w(BIT(mode, 1));
|
||||
}
|
||||
|
||||
} // anonymous namespace
|
||||
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(SMS_XE1AP, device_sms_control_interface, sms_xe1ap_device, "sms_xe1ap", "Dempa Micom Soft Analog Controller (XE-1AP)")
|
||||
DEFINE_DEVICE_TYPE_PRIVATE(SMS_XE1AP, device_sms_control_interface, sms_xe1ap_device, "sms_xe1ap", "Dempa Micom Soft Analog Controller (XE-1AP, Sega)")
|
||||
|
278
src/devices/machine/micomxe1a.cpp
Normal file
278
src/devices/machine/micomxe1a.cpp
Normal file
@ -0,0 +1,278 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/**********************************************************************
|
||||
|
||||
Dempa Micom Soft Analog/Digital Controller emulation
|
||||
|
||||
PC pin Name MD pin Name Dir Signal
|
||||
1 Up 1 Up In D0
|
||||
2 Down 2 Down In D1
|
||||
3 Left 3 Left In D2
|
||||
4 Right 4 Right In D3
|
||||
6 TRIG1 6 TL In L/H
|
||||
7 TRIG2 9 TR In Ack
|
||||
8 STROBE 7 TH Out Req
|
||||
|
||||
In analog mode, data is shifted out as eleven nybbles:
|
||||
|
||||
_ ____________________________________________
|
||||
Req \_________/
|
||||
____ __ __ __ __ __ __ __ __
|
||||
Ack \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/ \__/
|
||||
_____ _____ _____ _____
|
||||
L/H XX\____/ \_____/ \_____/ \_____/ \_____/
|
||||
____ _____ _____ _____ _____ _____ _____ _____ _____
|
||||
D XXX____X_____X_____X_____X_____X_____X_____X_____X_____X
|
||||
|
||||
The falling edge on Req causes data output to start. The host
|
||||
can't control the speed, it just polls the L/H and Ack lines to
|
||||
know when the data is ready to read.
|
||||
|
||||
Step D0 D1 D2 D3
|
||||
1 D C B/B' A/A'
|
||||
2 Select Start E2 E1
|
||||
3 Y4 Y5 Y6 Y7
|
||||
4 X4 X5 X6 X7
|
||||
5 Z4 Z5 Z6 Z7
|
||||
6 RZ4 RZ5 RZ6 RZ7
|
||||
7 Y0 Y1 Y2 Y3
|
||||
8 X0 X1 X2 X3
|
||||
9 Z0 Z1 Z2 Z3
|
||||
10 RZ0 RZ1 RZ2 RZ3
|
||||
11 B' A' B A
|
||||
12 - - - -
|
||||
|
||||
In MD mode, each pair of nybbles is transmitted in reverse
|
||||
order.
|
||||
|
||||
In digital mode, Req is a simple multiplexer input:
|
||||
|
||||
Req 0 1
|
||||
D0 Up Throttle Up
|
||||
D1 Down Throttle Down
|
||||
D2 Left C
|
||||
D3 Right D
|
||||
L/H A/A' E1
|
||||
Ack B/B' E2
|
||||
|
||||
Start appears as simultaneous Left/Right
|
||||
Select appears as simultaneous Up/Down
|
||||
|
||||
This mode is almost compatible with a 6-button Towns Pad (on a
|
||||
real 6-button Towns Pad, buttons A and B can be read in either
|
||||
state, they bypass the multiplexer).
|
||||
|
||||
TODO:
|
||||
* Dump MB88513 microcontroller from original controller.
|
||||
* Measure timings.
|
||||
* Latch data at beginning of packet.
|
||||
* Confirm A', B', E1 and E2 bit mappings in analog mode.
|
||||
* Confirm buttons mapping in digital mode.
|
||||
- Is the mapping different in PC vs MD mode?
|
||||
* Implement trigger A/B rapid fire switches.
|
||||
* Implement channel shift switch (Y->X, X->Z, Z->X).
|
||||
* Implement special modes (holding buttons on power-on):
|
||||
- Double displacement modes:
|
||||
+ X/Y (hold SELECT + A')
|
||||
+ Z (hold SELECT + B')
|
||||
+ X/Y/Z (hold SELECT + A' + B')
|
||||
- Up/down reverse mode (hold C)
|
||||
* Implement desktop (XE-1AJ/CZ-8NJ2) version:
|
||||
- Four analog channels
|
||||
- E1/E2 on a rocker switch (can't press simultaneously)
|
||||
- Hold mode for A and B triggers
|
||||
- Variable rapid fire rate for A and B triggers
|
||||
- Reset button
|
||||
- Different special modes
|
||||
- No Mega Drive mode
|
||||
- Start and Select not reported in digital mode
|
||||
|
||||
**********************************************************************/
|
||||
|
||||
#include "emu.h"
|
||||
#include "micomxe1a.h"
|
||||
|
||||
//#define VERBOSE 1
|
||||
//#define LOG_OUTPUT_FUNC osd_printf_info
|
||||
#include "logmacro.h"
|
||||
|
||||
|
||||
DEFINE_DEVICE_TYPE(MICOM_XE_1A, micom_xe_1a_device, "micom_xe_1a", "Dempa Micom Soft Analog/Digital Intelligent Controller")
|
||||
|
||||
|
||||
|
||||
micom_xe_1a_device::micom_xe_1a_device(
|
||||
machine_config const &mconfig,
|
||||
char const *tag,
|
||||
device_t *owner,
|
||||
u32 clock):
|
||||
device_t(mconfig, MICOM_XE_1A, tag, owner, clock),
|
||||
m_buttons_callback(*this),
|
||||
m_analog_callback(*this),
|
||||
m_output_timer(nullptr),
|
||||
m_req(1),
|
||||
m_mode(1),
|
||||
m_interface(0),
|
||||
m_out(0x2e)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
u8 micom_xe_1a_device::out_r()
|
||||
{
|
||||
if (m_mode)
|
||||
{
|
||||
LOG("%s: analog mode read data = %02X\n", machine().describe_context(), m_out);
|
||||
return m_out;
|
||||
}
|
||||
else
|
||||
{
|
||||
u16 const buttons = m_buttons_callback();
|
||||
if (m_req)
|
||||
{
|
||||
u8 const z = m_analog_callback(2);
|
||||
u8 const result =
|
||||
((0xc0 > z) ? 0x01 : 0x00) | // Throttle Up
|
||||
((0x40 <= z) ? 0x02 : 0x00) | // Throttle Down
|
||||
(BIT(buttons, 1) << 2) | // C
|
||||
(BIT(buttons, 0) << 3) | // D
|
||||
(BIT(buttons, 7) << 4) | // E1
|
||||
(BIT(buttons, 6) << 5); // E2
|
||||
LOG(
|
||||
"%s: digital mode extended read = 0x%02X\n",
|
||||
machine().describe_context(),
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
else
|
||||
{
|
||||
u8 const y = m_analog_callback(0);
|
||||
u8 const x = m_analog_callback(1);
|
||||
u8 const result =
|
||||
((BIT(buttons, 4) && (0x40 <= y)) ? 0x01 : 0x00) | // Select/Up
|
||||
((BIT(buttons, 4) && (0xc0 > y)) ? 0x02 : 0x00) | // Select/Down
|
||||
((BIT(buttons, 5) && (0x40 <= x)) ? 0x04 : 0x00) | // Start/Left
|
||||
((BIT(buttons, 5) && (0xc0 > x)) ? 0x08 : 0x00) | // Start/Right
|
||||
((BIT(buttons, 3) & BIT(buttons, 9)) << 4) | // A/A'
|
||||
((BIT(buttons, 2) & BIT(buttons, 8)) << 5); // B/B'
|
||||
LOG(
|
||||
"%s: digital mode basic read = 0x%02X\n",
|
||||
machine().describe_context(),
|
||||
result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(micom_xe_1a_device::req_w)
|
||||
{
|
||||
u8 const req = state ? 1 : 0;
|
||||
if (req != m_req)
|
||||
{
|
||||
if (m_mode)
|
||||
{
|
||||
LOG("%s: /Req = %u\n", machine().describe_context(), req);
|
||||
if (!req)
|
||||
{
|
||||
// acquire data
|
||||
u16 const buttons = m_buttons_callback();
|
||||
u8 analog[4];
|
||||
for (unsigned i = 0; std::size(analog) > i; ++i)
|
||||
analog[i] = m_analog_callback(i);
|
||||
|
||||
// pack data
|
||||
m_data[0] = BIT(buttons, 0, 8) & ((BIT(buttons, 8, 2) << 2) | 0xf3);
|
||||
m_data[1] = BIT(analog[0], 4, 4) | (BIT(analog[1], 4, 4) << 4);
|
||||
m_data[2] = BIT(analog[2], 4, 4) | (BIT(analog[3], 4, 4) << 4);
|
||||
m_data[3] = BIT(analog[0], 0, 4) | (BIT(analog[1], 0, 4) << 4);
|
||||
m_data[4] = BIT(analog[2], 0, 4) | (BIT(analog[3], 0, 4) << 4);
|
||||
m_data[5] = BIT(buttons, 8, 8) & ((BIT(buttons, 6, 2) << 2) | 0xf3);
|
||||
|
||||
// takes a while to respond
|
||||
m_output_timer->adjust(attotime::from_nsec(46'600), 0);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("%s: /Req = %u ignored in digital mode\n", machine().describe_context(), req);
|
||||
}
|
||||
m_req = req;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(micom_xe_1a_device::mode_w)
|
||||
{
|
||||
u8 const mode = state ? 1 : 0;
|
||||
if (mode != m_mode)
|
||||
{
|
||||
if (mode)
|
||||
{
|
||||
LOG("Analog mode selected\n");
|
||||
}
|
||||
else
|
||||
{
|
||||
LOG("Digital mode selected\n");
|
||||
m_output_timer->enable(false);
|
||||
m_out = 0x2e;
|
||||
}
|
||||
m_mode = mode;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
WRITE_LINE_MEMBER(micom_xe_1a_device::interface_w)
|
||||
{
|
||||
m_interface = state ? 1 : 0;
|
||||
}
|
||||
|
||||
|
||||
void micom_xe_1a_device::device_start()
|
||||
{
|
||||
m_buttons_callback.resolve_safe(0xffff);
|
||||
m_analog_callback.resolve_safe(0x00);
|
||||
|
||||
m_output_timer = timer_alloc(FUNC(micom_xe_1a_device::step_output), this);
|
||||
|
||||
std::fill(std::begin(m_data), std::end(m_data), 0x00);
|
||||
m_out = 0x2e;
|
||||
|
||||
save_item(NAME(m_req));
|
||||
save_item(NAME(m_mode));
|
||||
save_item(NAME(m_interface));
|
||||
save_item(NAME(m_data));
|
||||
save_item(NAME(m_out));
|
||||
}
|
||||
|
||||
|
||||
TIMER_CALLBACK_MEMBER(micom_xe_1a_device::step_output)
|
||||
{
|
||||
auto const step = param >> 1;
|
||||
if (!BIT(param, 0))
|
||||
{
|
||||
auto const nybble = step ^ m_interface;
|
||||
if ((std::size(m_data) * 2) > step)
|
||||
m_out = BIT(m_data[nybble >> 1], BIT(nybble, 0) ? 4 : 0, 4);
|
||||
else
|
||||
m_out = 0xe;
|
||||
m_out |= BIT(step, 0) ? 0x30 : 0x20;
|
||||
LOG(
|
||||
"Set nybble %u data = 0x%X, L/H = %d, /Ack = 1\n",
|
||||
step,
|
||||
BIT(m_out, 0, 4),
|
||||
BIT(m_out, 4));
|
||||
if ((std::size(m_data) * 2) > step)
|
||||
{
|
||||
m_output_timer->adjust(
|
||||
attotime::from_nsec(BIT(step, 0) ? 3'800 : 21'800),
|
||||
param + 1);
|
||||
}
|
||||
}
|
||||
else if ((std::size(m_data) * 2) > step)
|
||||
{
|
||||
m_out &= 0x1f;
|
||||
LOG("Set nybble %u /Ack = 0\n", step);
|
||||
m_output_timer->adjust(attotime::from_nsec(12'100), param + 1);
|
||||
}
|
||||
}
|
49
src/devices/machine/micomxe1a.h
Normal file
49
src/devices/machine/micomxe1a.h
Normal file
@ -0,0 +1,49 @@
|
||||
// license:BSD-3-Clause
|
||||
// copyright-holders:Vas Crabb
|
||||
/**********************************************************************
|
||||
|
||||
Dempa Micom Soft Analog/Digital Controller emulation
|
||||
|
||||
**********************************************************************/
|
||||
#ifndef MAME_MACHINE_MICOMXE1A_H
|
||||
#define MAME_MACHINE_MICOMXE1A_H
|
||||
|
||||
#pragma once
|
||||
|
||||
|
||||
class micom_xe_1a_device : public device_t
|
||||
{
|
||||
public:
|
||||
micom_xe_1a_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock = 0) ATTR_COLD;
|
||||
|
||||
auto buttons_handler() { return m_buttons_callback.bind(); }
|
||||
auto analog_handler() { return m_analog_callback.bind(); }
|
||||
|
||||
u8 out_r();
|
||||
|
||||
DECLARE_WRITE_LINE_MEMBER(req_w);
|
||||
DECLARE_WRITE_LINE_MEMBER(mode_w); // 0 = digital, 1 = analog
|
||||
DECLARE_WRITE_LINE_MEMBER(interface_w); // 0 = PC, 1 = MD
|
||||
|
||||
protected:
|
||||
virtual void device_start() override ATTR_COLD;
|
||||
|
||||
private:
|
||||
TIMER_CALLBACK_MEMBER(step_output);
|
||||
|
||||
devcb_read16 m_buttons_callback;
|
||||
devcb_read8 m_analog_callback;
|
||||
|
||||
emu_timer *m_output_timer;
|
||||
|
||||
u8 m_req;
|
||||
u8 m_mode;
|
||||
u8 m_interface;
|
||||
u8 m_data[6];
|
||||
u8 m_out;
|
||||
};
|
||||
|
||||
|
||||
DECLARE_DEVICE_TYPE(MICOM_XE_1A, micom_xe_1a_device)
|
||||
|
||||
#endif // MAME_MACHINE_MICOMXE1A_H
|
Loading…
Reference in New Issue
Block a user