summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2019-11-02 02:07:50 +1100
committer Vas Crabb <vas@vastheman.com>2019-11-02 02:07:50 +1100
commit74bd9899a7d5854f60eecfdacd643b2aea8c2ada (patch)
tree8e86315844618480e68c583c23e2494575ef3871
parentb1246642eb6e3f48f1fe19b7ae6584c1e544e88b (diff)
New working machines
-------------------- RS-232 DCE-DCE Bridge (nw) This is a simple machine for wiring together two things that want to plug into an RS-232 port. This means that for DCE-like things (e.g. serial printers) there's no need to create an extra machine to allow them to talk to the outside world with the null_modem device. (Also added some asserts, removed a FIXME, and put the swtpc8212 terminal in the default RS-232 devices.)
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/devices/bus/acorn/bus.h2
-rw-r--r--src/devices/bus/bml3/bml3bus.cpp1
-rw-r--r--src/devices/bus/c64/fcc.cpp2
-rw-r--r--src/devices/bus/nasbus/nasbus.cpp1
-rw-r--r--src/devices/bus/rs232/null_modem.cpp4
-rw-r--r--src/devices/bus/rs232/rs232.cpp2
-rw-r--r--src/devices/bus/ss50/mps.cpp2
-rw-r--r--src/devices/bus/ss50/mps2.cpp3
-rw-r--r--src/devices/bus/svi3x8/slot/slot.cpp1
-rw-r--r--src/mame/drivers/dcebridge.cpp312
-rw-r--r--src/mame/layout/dcebridge.lay86
-rw-r--r--src/mame/mame.lst3
13 files changed, 410 insertions, 10 deletions
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index 031c563ad4c..a999bff7ddc 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -2371,6 +2371,7 @@ files {
MAME_DIR .. "src/mame/drivers/4004clk.cpp",
MAME_DIR .. "src/mame/drivers/68ksbc.cpp",
MAME_DIR .. "src/mame/drivers/craft.cpp",
+ MAME_DIR .. "src/mame/drivers/dcebridge.cpp",
MAME_DIR .. "src/mame/drivers/homez80.cpp",
MAME_DIR .. "src/mame/drivers/p112.cpp",
MAME_DIR .. "src/mame/drivers/phunsy.cpp",
diff --git a/src/devices/bus/acorn/bus.h b/src/devices/bus/acorn/bus.h
index 02adc30a8a9..bfd9a980304 100644
--- a/src/devices/bus/acorn/bus.h
+++ b/src/devices/bus/acorn/bus.h
@@ -104,7 +104,7 @@ public:
virtual ~device_acorn_bus_interface();
// inline configuration
- void set_acorn_bus(acorn_bus_device &bus) { m_bus = &bus; }
+ void set_acorn_bus(acorn_bus_device &bus) { assert(!device().started()); m_bus = &bus; }
protected:
device_acorn_bus_interface(const machine_config &mconfig, device_t &device);
diff --git a/src/devices/bus/bml3/bml3bus.cpp b/src/devices/bus/bml3/bml3bus.cpp
index fb2dee6a65f..54e63ea70ec 100644
--- a/src/devices/bus/bml3/bml3bus.cpp
+++ b/src/devices/bus/bml3/bml3bus.cpp
@@ -210,6 +210,7 @@ void device_bml3bus_card_interface::interface_pre_start()
void device_bml3bus_card_interface::set_bml3bus(bml3bus_device &bus, const char *slottag)
{
assert(!m_bml3bus);
+ assert(!device().started());
// extract the slot number from the last digit of the slot tag
int tlen = strlen(slottag);
diff --git a/src/devices/bus/c64/fcc.cpp b/src/devices/bus/c64/fcc.cpp
index 7960074d663..405c1761a2e 100644
--- a/src/devices/bus/c64/fcc.cpp
+++ b/src/devices/bus/c64/fcc.cpp
@@ -45,8 +45,6 @@ void c64_final_chesscard_device::device_add_mconfig(machine_config &config)
M65SC02(config, m_maincpu, 5_MHz_XTAL);
m_maincpu->set_addrmap(AS_PROGRAM, &c64_final_chesscard_device::c64_fcc_map);
- //config.set_perfect_quantum(m_maincpu); FIXME: not safe in a slot device - add barriers
-
GENERIC_LATCH_8(config, m_mainlatch).data_pending_callback().set(FUNC(c64_final_chesscard_device::mainlatch_int));
GENERIC_LATCH_8(config, m_sublatch).data_pending_callback().set_inputline(m_maincpu, INPUT_LINE_NMI);
}
diff --git a/src/devices/bus/nasbus/nasbus.cpp b/src/devices/bus/nasbus/nasbus.cpp
index 2d19290161c..29fff032d39 100644
--- a/src/devices/bus/nasbus/nasbus.cpp
+++ b/src/devices/bus/nasbus/nasbus.cpp
@@ -130,6 +130,7 @@ device_nasbus_card_interface::~device_nasbus_card_interface()
void device_nasbus_card_interface::set_nasbus_device(nasbus_device &nasbus)
{
+ assert(!device().started());
m_nasbus = &nasbus;
}
diff --git a/src/devices/bus/rs232/null_modem.cpp b/src/devices/bus/rs232/null_modem.cpp
index 59f08142302..976a55f23c5 100644
--- a/src/devices/bus/rs232/null_modem.cpp
+++ b/src/devices/bus/rs232/null_modem.cpp
@@ -3,8 +3,8 @@
#include "emu.h"
#include "null_modem.h"
-null_modem_device::null_modem_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
- : device_t(mconfig, NULL_MODEM, tag, owner, clock),
+null_modem_device::null_modem_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, NULL_MODEM, tag, owner, clock),
device_serial_interface(mconfig, *this),
device_rs232_port_interface(mconfig, *this),
m_stream(*this, "stream"),
diff --git a/src/devices/bus/rs232/rs232.cpp b/src/devices/bus/rs232/rs232.cpp
index bb1f69c35cd..77b79132de0 100644
--- a/src/devices/bus/rs232/rs232.cpp
+++ b/src/devices/bus/rs232/rs232.cpp
@@ -168,6 +168,7 @@ device_rs232_port_interface::~device_rs232_port_interface()
#include "printer.h"
#include "pty.h"
#include "sun_kbd.h"
+#include "swtpc8212.h"
#include "terminal.h"
#include "ie15.h"
@@ -182,4 +183,5 @@ void default_rs232_devices(device_slot_interface &device)
device.option_add("pty", PSEUDO_TERMINAL);
device.option_add("sunkbd", SUN_KBD_ADAPTOR);
device.option_add("ie15", SERIAL_TERMINAL_IE15);
+ device.option_add("swtpc8212", SERIAL_TERMINAL_SWTPC8212);
}
diff --git a/src/devices/bus/ss50/mps.cpp b/src/devices/bus/ss50/mps.cpp
index 30e2a534615..a7ff13a7555 100644
--- a/src/devices/bus/ss50/mps.cpp
+++ b/src/devices/bus/ss50/mps.cpp
@@ -10,7 +10,6 @@
#include "mps.h"
#include "bus/rs232/rs232.h"
-#include "bus/rs232/swtpc8212.h"
#include "machine/6850acia.h"
//**************************************************************************
@@ -116,7 +115,6 @@ void ss50_mps_device::device_add_mconfig(machine_config &config)
rs232_port_device &rs232(RS232_PORT(config, "rs232", default_rs232_devices, "terminal"));
rs232.rxd_handler().set(m_acia, FUNC(acia6850_device::write_rxd));
rs232.cts_handler().set(FUNC(ss50_mps_device::route_cts_r));
- rs232.option_add("swtpc8212", SERIAL_TERMINAL_SWTPC8212);
rs232.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal));
}
diff --git a/src/devices/bus/ss50/mps2.cpp b/src/devices/bus/ss50/mps2.cpp
index f2c6c8c1f77..30bdd9e5a64 100644
--- a/src/devices/bus/ss50/mps2.cpp
+++ b/src/devices/bus/ss50/mps2.cpp
@@ -11,7 +11,6 @@
#include "mps2.h"
#include "bus/rs232/rs232.h"
-#include "bus/rs232/swtpc8212.h"
#include "machine/6850acia.h"
#include "machine/input_merger.h"
@@ -142,7 +141,6 @@ void ss50_mps2_device::device_add_mconfig(machine_config &config)
rs232_upper.rxd_handler().set(m_acia_upper, FUNC(acia6850_device::write_rxd));
rs232_upper.cts_handler().set(m_acia_upper, FUNC(acia6850_device::write_cts));
rs232_upper.dcd_handler().set(m_acia_upper, FUNC(acia6850_device::write_dcd));
- rs232_upper.option_add("swtpc8212", SERIAL_TERMINAL_SWTPC8212);
rs232_upper.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal_upper));
ACIA6850(config, m_acia_lower, 0);
@@ -154,7 +152,6 @@ void ss50_mps2_device::device_add_mconfig(machine_config &config)
rs232_lower.rxd_handler().set(m_acia_lower, FUNC(acia6850_device::write_rxd));
rs232_lower.cts_handler().set(m_acia_lower, FUNC(acia6850_device::write_cts));
rs232_lower.dcd_handler().set(m_acia_lower, FUNC(acia6850_device::write_dcd));
- rs232_lower.option_add("swtpc8212", SERIAL_TERMINAL_SWTPC8212);
rs232_lower.set_option_device_input_defaults("terminal", DEVICE_INPUT_DEFAULTS_NAME(terminal_lower));
INPUT_MERGER_ANY_HIGH(config, "irq").output_handler().set(FUNC(ss50_mps2_device::write_irq));
diff --git a/src/devices/bus/svi3x8/slot/slot.cpp b/src/devices/bus/svi3x8/slot/slot.cpp
index 7397414a0d6..705734dea4c 100644
--- a/src/devices/bus/svi3x8/slot/slot.cpp
+++ b/src/devices/bus/svi3x8/slot/slot.cpp
@@ -244,5 +244,6 @@ device_svi_slot_interface::~device_svi_slot_interface()
void device_svi_slot_interface::set_bus_device(svi_slot_bus_device &bus)
{
+ assert(!device().started());
m_bus = &bus;
}
diff --git a/src/mame/drivers/dcebridge.cpp b/src/mame/drivers/dcebridge.cpp
new file mode 100644
index 00000000000..317fe5462ca
--- /dev/null
+++ b/src/mame/drivers/dcebridge.cpp
@@ -0,0 +1,312 @@
+// 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 <unsigned N> DECLARE_INPUT_CHANGED_MEMBER(dtr_source);
+ template <unsigned N> DECLARE_INPUT_CHANGED_MEMBER(rts_source);
+
+ void dcebridge(machine_config &config);
+
+protected:
+ virtual void driver_start() override;
+ virtual void driver_reset() override;
+
+private:
+ template <unsigned N> void dcd(int state);
+ template <unsigned N> void dsr(int state);
+ template <unsigned N> void cts(int state);
+
+ template <unsigned N> void update_dtr();
+ template <unsigned N> void update_rts();
+
+ required_device_array<rs232_port_device, 2> 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 <unsigned N> INPUT_CHANGED_MEMBER(dcebridge_state::dtr_source)
+{
+ update_dtr<N>();
+}
+
+
+template <unsigned N> INPUT_CHANGED_MEMBER(dcebridge_state::rts_source)
+{
+ update_rts<N>();
+}
+
+
+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 <unsigned N> 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) == DTR_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) == DTR_SOURCE_DCD_REMOTE)
+ m_ports[N ^ 1U]->write_rts(state);
+ }
+ }
+}
+
+
+template <unsigned N> 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) == DTR_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) == DTR_SOURCE_DSR_REMOTE)
+ m_ports[N ^ 1U]->write_rts(state);
+ }
+ }
+}
+
+
+template <unsigned N> 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 <unsigned N> 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 <unsigned N> 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 )
diff --git a/src/mame/layout/dcebridge.lay b/src/mame/layout/dcebridge.lay
new file mode 100644
index 00000000000..04792f90476
--- /dev/null
+++ b/src/mame/layout/dcebridge.lay
@@ -0,0 +1,86 @@
+<?xml version="1.0"?>
+<!--
+license:CC0
+copyright-holders:Vas Crabb
+RS-232 DCE-DCE bridge layout
+-->
+<mamelayout version="2">
+ <element name="led">
+ <disk state="0">
+ <color red="1.0" green="0.0" blue="0.0" />
+ </disk>
+ <disk state="1">
+ <color red="0.15" green="0.0" blue="0.0" />
+ </disk>
+ </element>
+
+ <element name="label_a">
+ <text string="A" />
+ </element>
+ <element name="label_b">
+ <text string="B" />
+ </element>
+
+ <element name="label_dcd">
+ <text string="DCD" />
+ </element>
+ <element name="label_dsr">
+ <text string="DSR" />
+ </element>
+ <element name="label_ri">
+ <text string="RI" />
+ </element>
+ <element name="label_cts">
+ <text string="CTS" />
+ </element>
+
+ <view name="Control Lines">
+ <bounds x="0" y="0" width="95" height="45" />
+
+ <element ref="label_a">
+ <bounds x="5" y="16" width="10" height="8" />
+ </element>
+ <element ref="label_b">
+ <bounds x="5" y="31" width="10" height="8" />
+ </element>
+
+ <element ref="label_dcd">
+ <bounds x="18" y="5" width="14" height="8" />
+ </element>
+ <element ref="label_dsr">
+ <bounds x="38" y="5" width="14" height="8" />
+ </element>
+ <element ref="label_ri">
+ <bounds x="58" y="5" width="14" height="8" />
+ </element>
+ <element ref="label_cts">
+ <bounds x="78" y="5" width="14" height="8" />
+ </element>
+
+ <element ref="led" name="dcd_a">
+ <bounds x="20" y="15" width="10" height="10" />
+ </element>
+ <element ref="led" name="dsr_a">
+ <bounds x="40" y="15" width="10" height="10" />
+ </element>
+ <element ref="led" name="ri_a">
+ <bounds x="60" y="15" width="10" height="10" />
+ </element>
+ <element ref="led" name="cts_a">
+ <bounds x="80" y="15" width="10" height="10" />
+ </element>
+
+ <element ref="led" name="dcd_b">
+ <bounds x="20" y="30" width="10" height="10" />
+ </element>
+ <element ref="led" name="dsr_b">
+ <bounds x="40" y="30" width="10" height="10" />
+ </element>
+ <element ref="led" name="ri_b">
+ <bounds x="60" y="30" width="10" height="10" />
+ </element>
+ <element ref="led" name="cts_b">
+ <bounds x="80" y="30" width="10" height="10" />
+ </element>
+ </view>
+</mamelayout>
diff --git a/src/mame/mame.lst b/src/mame/mame.lst
index fa75b317e6c..b3b6bf18c28 100644
--- a/src/mame/mame.lst
+++ b/src/mame/mame.lst
@@ -11319,6 +11319,9 @@ dceu // 1999 Sega Dreamcast (Europe)
dcjp // 1998 Sega Dreamcast (Japan)
dctream // 200? Treamcast
+@source:dcebridge.cpp
+dcebridge // generic
+
@source:dcheese.cpp
cecmatch // (c) 1993 Coastal Amusements
dcheese // (c) 1993 HAR