// license:BSD-3-Clause // copyright-holders:Vas Crabb // Simple RS-232 DCE-DCE bridge #include "emu.h" #include "bus/rs232/rs232.h" #include "dcebridge.lh" namespace { enum : ioport_value { DTR_SOURCE_MASK = 0x07, DTR_SOURCE_DCD_REMOTE = 0x00, DTR_SOURCE_DSR_REMOTE = 0x01, DTR_SOURCE_CTS_REMOTE = 0x02, DTR_SOURCE_DCD_LOCAL = 0x03, DTR_SOURCE_DSR_LOCAL = 0x04, DTR_SOURCE_CTS_LOCAL = 0x05, DTR_SOURCE_ASSERT = 0x06, DTR_SOURCE_DEASSERT = 0x07, RTS_SOURCE_MASK = 0x38, RTS_SOURCE_DCD_REMOTE = 0x00, RTS_SOURCE_DSR_REMOTE = 0x08, RTS_SOURCE_CTS_REMOTE = 0x10, RTS_SOURCE_DCD_LOCAL = 0x18, RTS_SOURCE_DSR_LOCAL = 0x20, RTS_SOURCE_CTS_LOCAL = 0x28, RTS_SOURCE_ASSERT = 0x30, RTS_SOURCE_DEASSERT = 0x38, }; class dcebridge_state : public driver_device { public: dcebridge_state(machine_config const &mconfig, device_type &type, char const *tag) : driver_device(mconfig, type, tag) , m_ports(*this, "%c", 'a') , m_conf(*this, "CONF_%c", 'A') { } template DECLARE_INPUT_CHANGED_MEMBER(dtr_source); template DECLARE_INPUT_CHANGED_MEMBER(rts_source); void dcebridge(machine_config &config); protected: virtual void driver_start() override; virtual void driver_reset() override; private: template void dcd(int state); template void dsr(int state); template void cts(int state); template void update_dtr(); template void update_rts(); required_device_array m_ports; required_ioport_array<2> m_conf; u8 m_dcd[2] = { 0U, 0U }; u8 m_dsr[2] = { 0U, 0U }; u8 m_cts[2] = { 0U, 0U }; }; template INPUT_CHANGED_MEMBER(dcebridge_state::dtr_source) { update_dtr(); } template INPUT_CHANGED_MEMBER(dcebridge_state::rts_source) { update_rts(); } void dcebridge_state::dcebridge(machine_config &config) { RS232_PORT(config, m_ports[0], default_rs232_devices, nullptr); m_ports[0]->rxd_handler().set(m_ports[1], FUNC(rs232_port_device::write_txd)); m_ports[0]->dcd_handler().set(FUNC(dcebridge_state::dcd<0>)); m_ports[0]->dcd_handler().append_output("dcd_a"); m_ports[0]->dsr_handler().set(FUNC(dcebridge_state::dsr<0>)); m_ports[0]->dsr_handler().append_output("dsr_a"); m_ports[0]->ri_handler().set_output("ri_a"); m_ports[0]->cts_handler().set(FUNC(dcebridge_state::cts<0>)); m_ports[0]->cts_handler().append_output("cts_a"); RS232_PORT(config, m_ports[1], default_rs232_devices, "null_modem"); m_ports[1]->rxd_handler().set(m_ports[0], FUNC(rs232_port_device::write_txd)); m_ports[1]->dcd_handler().set(FUNC(dcebridge_state::dcd<1>)); m_ports[1]->dcd_handler().append_output("dcd_b"); m_ports[1]->dsr_handler().set(FUNC(dcebridge_state::dsr<1>)); m_ports[1]->dsr_handler().append_output("dsr_b"); m_ports[1]->ri_handler().set_output("ri_b"); m_ports[1]->cts_handler().set(FUNC(dcebridge_state::cts<1>)); m_ports[1]->cts_handler().append_output("cts_b"); config.set_default_layout(layout_dcebridge); } void dcebridge_state::driver_start() { save_item(NAME(m_dcd)); save_item(NAME(m_dsr)); save_item(NAME(m_cts)); } void dcebridge_state::driver_reset() { update_dtr<0>(); update_rts<0>(); update_dtr<1>(); update_rts<1>(); } template void dcebridge_state::dcd(int state) { if (m_dcd[N] != state) { m_dcd[N] = state; if (started()) { ioport_value const conf_local(m_conf[N]->read()); if ((conf_local & DTR_SOURCE_MASK) == DTR_SOURCE_DCD_LOCAL) m_ports[N]->write_dtr(state); if ((conf_local & RTS_SOURCE_MASK) == RTS_SOURCE_DCD_LOCAL) m_ports[N]->write_rts(state); ioport_value const conf_remote(m_conf[N ^ 1U]->read()); if ((conf_remote & DTR_SOURCE_MASK) == DTR_SOURCE_DCD_REMOTE) m_ports[N ^ 1U]->write_dtr(state); if ((conf_remote & RTS_SOURCE_MASK) == RTS_SOURCE_DCD_REMOTE) m_ports[N ^ 1U]->write_rts(state); } } } template void dcebridge_state::dsr(int state) { if (m_dsr[N] != state) { m_dsr[N] = state; if (started()) { ioport_value const conf_local(m_conf[N]->read()); if ((conf_local & DTR_SOURCE_MASK) == DTR_SOURCE_DSR_LOCAL) m_ports[N]->write_dtr(state); if ((conf_local & RTS_SOURCE_MASK) == RTS_SOURCE_DSR_LOCAL) m_ports[N]->write_rts(state); ioport_value const conf_remote(m_conf[N ^ 1U]->read()); if ((conf_remote & DTR_SOURCE_MASK) == DTR_SOURCE_DSR_REMOTE) m_ports[N ^ 1U]->write_dtr(state); if ((conf_remote & RTS_SOURCE_MASK) == RTS_SOURCE_DSR_REMOTE) m_ports[N ^ 1U]->write_rts(state); } } } template void dcebridge_state::cts(int state) { if (m_cts[N] != state) { m_cts[N] = state; if (started()) { ioport_value const conf_local(m_conf[N]->read()); if ((conf_local & DTR_SOURCE_MASK) == DTR_SOURCE_CTS_LOCAL) m_ports[N]->write_dtr(state); if ((conf_local & RTS_SOURCE_MASK) == DTR_SOURCE_CTS_LOCAL) m_ports[N]->write_rts(state); ioport_value const conf_remote(m_conf[N ^ 1U]->read()); if ((conf_remote & DTR_SOURCE_MASK) == DTR_SOURCE_CTS_REMOTE) m_ports[N ^ 1U]->write_dtr(state); if ((conf_remote & RTS_SOURCE_MASK) == DTR_SOURCE_CTS_REMOTE) m_ports[N ^ 1U]->write_rts(state); } } } template void dcebridge_state::update_dtr() { ioport_value const conf(m_conf[N]->read()); switch (conf & DTR_SOURCE_MASK) { case DTR_SOURCE_DCD_REMOTE: m_ports[N]->write_dtr(m_dcd[N ^ 1U]); break; case DTR_SOURCE_DSR_REMOTE: m_ports[N]->write_dtr(m_dsr[N ^ 1U]); break; case DTR_SOURCE_CTS_REMOTE: m_ports[N]->write_dtr(m_cts[N ^ 1U]); break; case DTR_SOURCE_DCD_LOCAL: m_ports[N]->write_dtr(m_dcd[N]); break; case DTR_SOURCE_DSR_LOCAL: m_ports[N]->write_dtr(m_dsr[N]); break; case DTR_SOURCE_CTS_LOCAL: m_ports[N]->write_dtr(m_cts[N]); break; case DTR_SOURCE_ASSERT: m_ports[N]->write_dtr(0); break; case DTR_SOURCE_DEASSERT: m_ports[N]->write_dtr(1); break; } } template void dcebridge_state::update_rts() { ioport_value const conf(m_conf[N]->read()); switch (conf & RTS_SOURCE_MASK) { case RTS_SOURCE_DCD_REMOTE: m_ports[N]->write_rts(m_dcd[N ^ 1U]); break; case RTS_SOURCE_DSR_REMOTE: m_ports[N]->write_rts(m_dsr[N ^ 1U]); break; case RTS_SOURCE_CTS_REMOTE: m_ports[N]->write_rts(m_cts[N ^ 1U]); break; case RTS_SOURCE_DCD_LOCAL: m_ports[N]->write_rts(m_dcd[N]); break; case RTS_SOURCE_DSR_LOCAL: m_ports[N]->write_rts(m_dsr[N]); break; case RTS_SOURCE_CTS_LOCAL: m_ports[N]->write_rts(m_cts[N]); break; case RTS_SOURCE_ASSERT: m_ports[N]->write_rts(0); break; case RTS_SOURCE_DEASSERT: m_ports[N]->write_rts(1); break; } } INPUT_PORTS_START(dcebridge) PORT_START("CONF_A") PORT_CONFNAME(DTR_SOURCE_MASK, DTR_SOURCE_DSR_REMOTE, "DTR A Source") PORT_CHANGED_MEMBER(DEVICE_SELF, dcebridge_state, dtr_source<0>, 0) PORT_CONFSETTING(DTR_SOURCE_DCD_REMOTE, "DCD B") PORT_CONFSETTING(DTR_SOURCE_DSR_REMOTE, "DSR B") PORT_CONFSETTING(DTR_SOURCE_CTS_REMOTE, "CTS B") PORT_CONFSETTING(DTR_SOURCE_DCD_LOCAL, "DCD A Loopback") PORT_CONFSETTING(DTR_SOURCE_DSR_LOCAL, "DSR A Loopback") PORT_CONFSETTING(DTR_SOURCE_CTS_LOCAL, "CTS A Loopback") PORT_CONFSETTING(DTR_SOURCE_ASSERT, "Asserted") PORT_CONFSETTING(DTR_SOURCE_DEASSERT, "Deasserted") PORT_CONFNAME(RTS_SOURCE_MASK, RTS_SOURCE_CTS_REMOTE, "RTS A Source") PORT_CHANGED_MEMBER(DEVICE_SELF, dcebridge_state, rts_source<0>, 0) PORT_CONFSETTING(RTS_SOURCE_DCD_REMOTE, "DCD B") PORT_CONFSETTING(RTS_SOURCE_DSR_REMOTE, "DSR B") PORT_CONFSETTING(RTS_SOURCE_CTS_REMOTE, "CTS B") PORT_CONFSETTING(RTS_SOURCE_DCD_LOCAL, "DCD A Loopback") PORT_CONFSETTING(RTS_SOURCE_DSR_LOCAL, "DSR A Loopback") PORT_CONFSETTING(RTS_SOURCE_CTS_LOCAL, "CTS A Loopback") PORT_CONFSETTING(RTS_SOURCE_ASSERT, "Asserted") PORT_CONFSETTING(RTS_SOURCE_DEASSERT, "Deasserted") PORT_START("CONF_B") PORT_CONFNAME(DTR_SOURCE_MASK, DTR_SOURCE_DSR_REMOTE, "DTR B Source") PORT_CHANGED_MEMBER(DEVICE_SELF, dcebridge_state, dtr_source<1>, 0) PORT_CONFSETTING(DTR_SOURCE_DCD_REMOTE, "DCD A") PORT_CONFSETTING(DTR_SOURCE_DSR_REMOTE, "DSR A") PORT_CONFSETTING(DTR_SOURCE_CTS_REMOTE, "CTS A") PORT_CONFSETTING(DTR_SOURCE_DCD_LOCAL, "DCD B Loopback") PORT_CONFSETTING(DTR_SOURCE_DSR_LOCAL, "DSR B Loopback") PORT_CONFSETTING(DTR_SOURCE_CTS_LOCAL, "CTS B Loopback") PORT_CONFSETTING(DTR_SOURCE_ASSERT, "Asserted") PORT_CONFSETTING(DTR_SOURCE_DEASSERT, "Deasserted") PORT_CONFNAME(RTS_SOURCE_MASK, RTS_SOURCE_CTS_REMOTE, "RTS B Source") PORT_CHANGED_MEMBER(DEVICE_SELF, dcebridge_state, rts_source<1>, 0) PORT_CONFSETTING(RTS_SOURCE_DCD_REMOTE, "DCD A") PORT_CONFSETTING(RTS_SOURCE_DSR_REMOTE, "DSR A") PORT_CONFSETTING(RTS_SOURCE_CTS_REMOTE, "CTS A") PORT_CONFSETTING(RTS_SOURCE_DCD_LOCAL, "DCD B Loopback") PORT_CONFSETTING(RTS_SOURCE_DSR_LOCAL, "DSR B Loopback") PORT_CONFSETTING(RTS_SOURCE_CTS_LOCAL, "CTS B Loopback") PORT_CONFSETTING(RTS_SOURCE_ASSERT, "Asserted") PORT_CONFSETTING(RTS_SOURCE_DEASSERT, "Deasserted") INPUT_PORTS_END ROM_START(dcebridge) ROM_END } // anonymous namespace // YEAR NAME PARENT COMPAT MACHINE INPUT CLASS INIT COMPANY FULLNAME FLAGS SYST( 197?, dcebridge, 0, 0, dcebridge, dcebridge, dcebridge_state, empty_init, "generic", "RS-232 DCE-DCE Bridge", MACHINE_NO_SOUND_HW )