diff options
Diffstat (limited to 'src/devices/bus/sms_ctrl/multitap.cpp')
-rw-r--r-- | src/devices/bus/sms_ctrl/multitap.cpp | 166 |
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") |