summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/sms_ctrl/multitap.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/sms_ctrl/multitap.cpp')
-rw-r--r--src/devices/bus/sms_ctrl/multitap.cpp166
1 files changed, 93 insertions, 73 deletions
diff --git a/src/devices/bus/sms_ctrl/multitap.cpp b/src/devices/bus/sms_ctrl/multitap.cpp
index 74d6c749cb5..5634f0c989d 100644
--- a/src/devices/bus/sms_ctrl/multitap.cpp
+++ b/src/devices/bus/sms_ctrl/multitap.cpp
@@ -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"
+
+//#define VERBOSE 1
+//#define LOG_OUTPUT_FUNC osd_printf_info
+#include "logmacro.h"
-// Scheme: http://www.smspower.org/uploads/Homebrew/BOoM-SMS-sms4p_2.png
+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 ATTR_COLD;
+ virtual void device_resolve_objects() override ATTR_COLD;
+ virtual void device_start() override ATTR_COLD;
+
+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,14 +61,19 @@ 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;
}
@@ -47,8 +83,10 @@ sms_multitap_device::sms_multitap_device(const machine_config &mconfig, const ch
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")