summaryrefslogtreecommitdiffstatshomepage
diff options
context:
space:
mode:
author Vas Crabb <vas@vastheman.com>2017-03-01 16:25:12 +1100
committer Vas Crabb <vas@vastheman.com>2017-03-01 16:36:42 +1100
commit73e2a3f542e868149f3b0be6c1bf395283711f33 (patch)
treef9b167d4550c6ba8d2840b0ee53ca6bdf43e1a1c
parentb28ede22ef274037c5ecba26d4e5d66198555b2a (diff)
ti85.cpp: Convert TI-8x link port to a bus with emulated peripherals, should work with TI-82 and TI-85.
* tee allows two peripherals to be connected in parallel * glinkhle is an RS232 (9600 8N1) adaptor * bitsock sends raw assert/release line signals to/from a bitbanger device * monospkr is a speaker connected between tip/ring in parallel and sleeve * stereospkr is two speakers: left across tip and sleeve, right across ring and sleeve Use glinkhle to make emulated calculators talk with cooked sockets, e.g. mame ti82 -linkport glinkhle -linkport:glinkhle:rs232 null_modem -bitb socket.127.0.0.1:2345 Use bitsock to make emulated calculators talk with cooked sockets, e.g. mame ti82 -linkport bitsock -bitb socket.127.0.0.1:2345 You can use tee to do stuff like listen to data activity for debugging purposes, e.g. mame ti82 -linkport tee -linkport:tee:a stereospkr -linkport:tee:b glinkhle -linkport:tee:b:glinkhle:rs232 null_modem -bitb socket.127.0.0.1:2345
-rw-r--r--scripts/src/bus.lua20
-rw-r--r--scripts/target/mame/mess.lua1
-rw-r--r--src/devices/bus/ti8x/bitsocket.cpp89
-rw-r--r--src/devices/bus/ti8x/bitsocket.h55
-rw-r--r--src/devices/bus/ti8x/graphlinkhle.cpp162
-rw-r--r--src/devices/bus/ti8x/graphlinkhle.h66
-rw-r--r--src/devices/bus/ti8x/teeconn.cpp113
-rw-r--r--src/devices/bus/ti8x/teeconn.h45
-rw-r--r--src/devices/bus/ti8x/ti8x.cpp622
-rw-r--r--src/devices/bus/ti8x/ti8x.h213
-rw-r--r--src/devices/bus/ti8x/tispeaker.cpp117
-rw-r--r--src/devices/bus/ti8x/tispeaker.h55
-rw-r--r--src/mame/drivers/ti85.cpp49
-rw-r--r--src/mame/includes/ti85.h123
-rw-r--r--src/mame/machine/ti85.cpp103
15 files changed, 1700 insertions, 133 deletions
diff --git a/scripts/src/bus.lua b/scripts/src/bus.lua
index a21315344d8..b05cc795e85 100644
--- a/scripts/src/bus.lua
+++ b/scripts/src/bus.lua
@@ -2290,6 +2290,26 @@ end
---------------------------------------------------
--
+--@src/devices/bus/ti8x/ti8x.h,BUSES["TI8X"] = true
+---------------------------------------------------
+
+if (BUSES["TI8X"]~=null) then
+ files {
+ MAME_DIR .. "src/devices/bus/ti8x/bitsocket.cpp",
+ MAME_DIR .. "src/devices/bus/ti8x/bitsocket.h",
+ MAME_DIR .. "src/devices/bus/ti8x/graphlinkhle.cpp",
+ MAME_DIR .. "src/devices/bus/ti8x/graphlinkhle.h",
+ MAME_DIR .. "src/devices/bus/ti8x/teeconn.cpp",
+ MAME_DIR .. "src/devices/bus/ti8x/teeconn.h",
+ MAME_DIR .. "src/devices/bus/ti8x/ti8x.cpp",
+ MAME_DIR .. "src/devices/bus/ti8x/ti8x.h",
+ MAME_DIR .. "src/devices/bus/ti8x/tispeaker.cpp",
+ MAME_DIR .. "src/devices/bus/ti8x/tispeaker.h",
+ }
+end
+
+---------------------------------------------------
+--
--@src/devices/bus/ti99x/990_dk.h,BUSES["TI99X"] = true
--@src/devices/bus/ti99x/990_tap.h,BUSES["TI99X"] = true
--@src/devices/bus/ti99x/990_hd.h,BUSES["TI99X"] = true
diff --git a/scripts/target/mame/mess.lua b/scripts/target/mame/mess.lua
index a3f6f9ea260..cbca0919f1a 100644
--- a/scripts/target/mame/mess.lua
+++ b/scripts/target/mame/mess.lua
@@ -700,6 +700,7 @@ BUSES["SPC1000"] = true
BUSES["SUNKBD"] = true
BUSES["SVI_EXPANDER"] = true
BUSES["SVI_SLOT"] = true
+BUSES["TI8X"] = true
BUSES["TI99PEB"] = true
BUSES["TI99X"] = true
BUSES["TIKI100"] = true
diff --git a/src/devices/bus/ti8x/bitsocket.cpp b/src/devices/bus/ti8x/bitsocket.cpp
new file mode 100644
index 00000000000..71a153b2562
--- /dev/null
+++ b/src/devices/bus/ti8x/bitsocket.cpp
@@ -0,0 +1,89 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "bitsocket.h"
+
+
+device_type const TI8X_BIT_SOCKET = device_creator<bus::ti8x::bit_socket_device>;
+
+
+namespace bus { namespace ti8x {
+
+namespace {
+
+MACHINE_CONFIG_FRAGMENT(bit_socket)
+ MCFG_DEVICE_ADD("stream", BITBANGER, 0)
+MACHINE_CONFIG_END
+
+} // anonymous namespace
+
+
+bit_socket_device::bit_socket_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, TI8X_BIT_SOCKET, "TI-8x Bit Socket", tag, owner, clock, "ti8xbitsock", __FILE__)
+ , device_ti8x_link_port_interface(mconfig, *this)
+ , m_stream(*this, "stream")
+ , m_poll_timer(nullptr)
+ , m_tip_in(true)
+ , m_ring_in(true)
+{
+}
+
+
+machine_config_constructor bit_socket_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(bit_socket);
+}
+
+
+void bit_socket_device::device_start()
+{
+ m_poll_timer = timer_alloc(TIMER_ID_POLL);
+
+ save_item(NAME(m_tip_in));
+ save_item(NAME(m_ring_in));
+
+ m_tip_in = m_ring_in = true;
+
+ m_poll_timer->adjust(attotime::from_hz(200000), 0, attotime::from_hz(200000));
+}
+
+
+void bit_socket_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_POLL:
+ {
+ u8 data;
+ while (m_stream->input(&data, 1))
+ {
+ if (BIT(data, 1)) output_tip(BIT(data, 0));
+ if (BIT(data, 2)) output_ring(BIT(data, 0));
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+WRITE_LINE_MEMBER(bit_socket_device::input_tip)
+{
+ m_tip_in = bool(state);
+ m_stream->output((m_tip_in ? 0x01 : 0x00) | 0x02);
+}
+
+
+WRITE_LINE_MEMBER(bit_socket_device::input_ring)
+{
+ m_ring_in = bool(state);
+ m_stream->output((m_ring_in ? 0x01 : 0x00) | 0x04);
+}
+
+} } // namespace bus::ti8x
diff --git a/src/devices/bus/ti8x/bitsocket.h b/src/devices/bus/ti8x/bitsocket.h
new file mode 100644
index 00000000000..f4c635c9dfc
--- /dev/null
+++ b/src/devices/bus/ti8x/bitsocket.h
@@ -0,0 +1,55 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*
+ Sends raw assert/release signals over a socket. Seriously limits
+ transfer rates and probably won't work if there's much latency, but it
+ allows communication between instances using non-standard protocols.
+
+ bit 0 = data
+ bit 1 = set tip
+ bit 2 = set ring
+ */
+#ifndef MAME_DEVICES_BUS_TI8X_BITSOCKET_H
+#define MAME_DEVICES_BUS_TI8X_BITSOCKET_H
+
+#pragma once
+
+#include "ti8x.h"
+
+#include "imagedev/bitbngr.h"
+
+
+extern device_type const TI8X_BIT_SOCKET;
+
+
+namespace bus { namespace ti8x {
+
+class bit_socket_device
+ : public device_t
+ , public device_ti8x_link_port_interface
+{
+public:
+ bit_socket_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ enum
+ {
+ TIMER_ID_POLL = 1
+ };
+
+ virtual machine_config_constructor device_mconfig_additions() const override;
+ virtual void device_start() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) override;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) override;
+
+private:
+ required_device<bitbanger_device> m_stream;
+ emu_timer * m_poll_timer;
+ bool m_tip_in, m_ring_in;
+};
+
+} } // namespace bus::ti8x
+
+#endif // MAME_DEVICES_BUS_TI8X_BITSOCKET_H \ No newline at end of file
diff --git a/src/devices/bus/ti8x/graphlinkhle.cpp b/src/devices/bus/ti8x/graphlinkhle.cpp
new file mode 100644
index 00000000000..bcfcbd9fcb4
--- /dev/null
+++ b/src/devices/bus/ti8x/graphlinkhle.cpp
@@ -0,0 +1,162 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "graphlinkhle.h"
+
+
+device_type const TI8X_GRAPH_LINK_HLE = device_creator<bus::ti8x::graph_link_hle_device>;
+
+
+namespace bus { namespace ti8x {
+
+namespace {
+
+MACHINE_CONFIG_FRAGMENT(graph_link_hle)
+ MCFG_RS232_PORT_ADD("rs232", default_rs232_devices, nullptr)
+ MCFG_RS232_RXD_HANDLER(WRITELINE(graph_link_hle_device, rx_w))
+MACHINE_CONFIG_END
+
+} // anonymous namespace
+
+
+graph_link_hle_device::graph_link_hle_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, TI8X_GRAPH_LINK_HLE, "TI-Graph Link (grey, HLE)", tag, owner, clock, "glinkhle", __FILE__)
+ , device_ti8x_link_port_byte_interface(mconfig, *this)
+ , device_serial_interface(mconfig, *this)
+ , m_serial_port(*this, "rs232")
+ , m_buffer()
+ , m_head(0)
+ , m_tail(0)
+ , m_empty(true)
+ , m_ready(true)
+{
+}
+
+
+void graph_link_hle_device::device_start()
+{
+ device_serial_interface::register_save_state(machine().save(), this);
+
+ m_buffer = std::make_unique<u8 []>(BUFLEN);
+
+ save_pointer(NAME(m_buffer.get()), BUFLEN);
+}
+
+
+void graph_link_hle_device::device_reset()
+{
+ set_data_frame(1, 8, PARITY_NONE, STOP_BITS_1);
+ set_rate(9600);
+ receive_register_reset();
+ transmit_register_reset();
+
+ m_head = m_tail = 0;
+ m_empty = true;
+ m_ready = true;
+}
+
+
+void graph_link_hle_device::device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr)
+{
+ device_ti8x_link_port_byte_interface::device_timer(timer, id, param, ptr);
+ device_serial_interface::device_timer(timer, id, param, ptr);
+}
+
+
+machine_config_constructor graph_link_hle_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(graph_link_hle);
+}
+
+
+void graph_link_hle_device::byte_collision()
+{
+ if (m_empty)
+ {
+ m_ready = true;
+ }
+ else
+ {
+ send_byte(m_buffer[m_tail]);
+ m_tail = (m_tail + 1) % BUFLEN;
+ m_empty = m_head == m_tail;
+ }
+}
+
+
+void graph_link_hle_device::byte_send_timeout()
+{
+ if (m_empty)
+ {
+ m_ready = true;
+ }
+ else
+ {
+ send_byte(m_buffer[m_tail]);
+ m_tail = (m_tail + 1) % BUFLEN;
+ m_empty = m_head == m_tail;
+ }
+}
+
+
+void graph_link_hle_device::byte_receive_timeout()
+{
+}
+
+
+void graph_link_hle_device::byte_sent()
+{
+ if (m_empty)
+ {
+ m_ready = true;
+ }
+ else
+ {
+ send_byte(m_buffer[m_tail]);
+ m_tail = (m_tail + 1) % BUFLEN;
+ m_empty = m_head == m_tail;
+ }
+}
+
+
+void graph_link_hle_device::byte_received(u8 data)
+{
+ transmit_register_setup(data);
+}
+
+
+void graph_link_hle_device::rcv_complete()
+{
+ receive_register_extract();
+ if (m_ready)
+ {
+ assert(m_empty);
+
+ send_byte(get_received_char());
+ m_ready = false;
+ }
+ else
+ {
+ m_buffer[m_head] = get_received_char();
+ m_head = (m_head + 1) % BUFLEN;
+ m_empty = false;
+ }
+}
+
+
+void graph_link_hle_device::tra_callback()
+{
+ m_serial_port->write_txd(transmit_register_get_data_bit());
+}
+
+
+void graph_link_hle_device::tra_complete()
+{
+ accept_byte();
+}
+
+} } // namespace bus::ti8x
diff --git a/src/devices/bus/ti8x/graphlinkhle.h b/src/devices/bus/ti8x/graphlinkhle.h
new file mode 100644
index 00000000000..8f2d0eaf242
--- /dev/null
+++ b/src/devices/bus/ti8x/graphlinkhle.h
@@ -0,0 +1,66 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*
+ High-level emulation of a somewhat idealised TI-Graph Link "grey"
+ model. Translates byte-oriented TI-8x link port protocol to/from
+ 9600 Baud RS232. A real TI-Graph Link requires some delay between
+ bytes.
+
+ The buffer is there so that if you connect two emulated calculators
+ together with these it has some chance of working. The receiving
+ calculator can't slow the sending calculator down like it would be able
+ to in real life, so you get inevitable overruns without the buffer.
+ */
+#ifndef MAME_DEVICES_BUS_TI8X_GRAPHLINKHLE_H
+#define MAME_DEVICES_BUS_TI8X_GRAPHLINKHLE_H
+
+#pragma once
+
+#include "ti8x.h"
+
+#include "bus/rs232/rs232.h"
+
+#include <memory>
+
+
+extern device_type const TI8X_GRAPH_LINK_HLE;
+
+
+namespace bus { namespace ti8x {
+
+class graph_link_hle_device
+ : public device_t
+ , public device_ti8x_link_port_byte_interface
+ , public device_serial_interface
+{
+public:
+ graph_link_hle_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const override;
+ virtual void device_start() override;
+ virtual void device_reset() override;
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
+
+ virtual void byte_collision() override;
+ virtual void byte_send_timeout() override;
+ virtual void byte_receive_timeout() override;
+ virtual void byte_sent() override;
+ virtual void byte_received(u8 data) override;
+
+ virtual void rcv_complete() override;
+ virtual void tra_callback() override;
+ virtual void tra_complete() override;
+
+private:
+ static constexpr unsigned BUFLEN = 1U << 16;
+
+ required_device<rs232_port_device> m_serial_port;
+ std::unique_ptr<u8 []> m_buffer;
+ unsigned m_head, m_tail;
+ bool m_empty, m_ready;
+};
+
+} } // namespace bus::ti8x
+
+#endif // MAME_DEVICES_BUS_TI8X_GRAPHLINKHLE_H \ No newline at end of file
diff --git a/src/devices/bus/ti8x/teeconn.cpp b/src/devices/bus/ti8x/teeconn.cpp
new file mode 100644
index 00000000000..d887f1fd85a
--- /dev/null
+++ b/src/devices/bus/ti8x/teeconn.cpp
@@ -0,0 +1,113 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "teeconn.h"
+
+
+device_type const TI8X_TEE_CONNECTOR = device_creator<bus::ti8x::tee_connector_device>;
+
+
+namespace bus { namespace ti8x {
+
+namespace {
+
+MACHINE_CONFIG_FRAGMENT(tee_connector)
+ MCFG_TI8X_LINK_PORT_ADD("a", default_ti8x_link_devices, nullptr)
+ MCFG_TI8X_LINK_TIP_HANDLER(WRITELINE(tee_connector_device, tip_a_w))
+ MCFG_TI8X_LINK_RING_HANDLER(WRITELINE(tee_connector_device, ring_a_w))
+
+ MCFG_TI8X_LINK_PORT_ADD("b", default_ti8x_link_devices, nullptr)
+ MCFG_TI8X_LINK_TIP_HANDLER(WRITELINE(tee_connector_device, tip_b_w))
+ MCFG_TI8X_LINK_RING_HANDLER(WRITELINE(tee_connector_device, ring_b_w))
+MACHINE_CONFIG_END
+
+} // anonymous namespace
+
+
+tee_connector_device::tee_connector_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, TI8X_TEE_CONNECTOR, "T-connector", tag, owner, clock, "ti8xtconn", __FILE__)
+ , device_ti8x_link_port_interface(mconfig, *this)
+ , m_port_a(*this, "a")
+ , m_port_b(*this, "b")
+ , m_tip_host(true)
+ , m_tip_a(true)
+ , m_tip_b(true)
+ , m_ring_host(true)
+ , m_ring_a(true)
+ , m_ring_b(true)
+{
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::tip_a_w)
+{
+ m_tip_a = bool(state);
+ output_tip((m_tip_a && m_tip_b) ? 1 : 0);
+ m_port_b->tip_w((m_tip_host && m_tip_a) ? 1 : 0);
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::ring_a_w)
+{
+ m_ring_a = bool(state);
+ output_ring((m_ring_a && m_ring_b) ? 1 : 0);
+ m_port_b->ring_w((m_ring_host && m_ring_a) ? 1 : 0);
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::tip_b_w)
+{
+ m_tip_b = bool(state);
+ output_tip((m_tip_a && m_tip_b) ? 1 : 0);
+ m_port_a->tip_w((m_tip_host && m_tip_b) ? 1 : 0);
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::ring_b_w)
+{
+ m_ring_b = bool(state);
+ output_ring((m_ring_a && m_ring_b) ? 1 : 0);
+ m_port_a->ring_w((m_ring_host && m_ring_b) ? 1 : 0);
+}
+
+
+machine_config_constructor tee_connector_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(tee_connector);
+}
+
+
+void tee_connector_device::device_start()
+{
+ save_item(NAME(m_tip_host));
+ save_item(NAME(m_tip_a));
+ save_item(NAME(m_tip_b));
+ save_item(NAME(m_ring_host));
+ save_item(NAME(m_ring_a));
+ save_item(NAME(m_ring_b));
+
+ m_tip_host = m_tip_a = m_tip_b = true;
+ m_ring_host = m_ring_a = m_ring_b = true;
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::input_tip)
+{
+ m_tip_host = bool(state);
+ m_port_a->tip_w((m_tip_host && m_tip_b) ? 1 : 0);
+ m_port_b->tip_w((m_tip_host && m_tip_a) ? 1 : 0);
+}
+
+
+WRITE_LINE_MEMBER(tee_connector_device::input_ring)
+{
+ m_ring_host = bool(state);
+ m_port_a->ring_w((m_ring_host && m_ring_b) ? 1 : 0);
+ m_port_b->ring_w((m_ring_host && m_ring_a) ? 1 : 0);
+}
+
+} } // namespace bus::ti8x
diff --git a/src/devices/bus/ti8x/teeconn.h b/src/devices/bus/ti8x/teeconn.h
new file mode 100644
index 00000000000..3c6beb31b46
--- /dev/null
+++ b/src/devices/bus/ti8x/teeconn.h
@@ -0,0 +1,45 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*
+ A T-connector, strangely enough.
+ */
+#ifndef MAME_DEVICES_BUS_TI8X_TEECONN_H
+#define MAME_DEVICES_BUS_TI8X_TEECONN_H
+
+#pragma once
+
+#include "ti8x.h"
+
+
+extern device_type const TI8X_TEE_CONNECTOR;
+
+
+namespace bus { namespace ti8x {
+
+class tee_connector_device : public device_t, public device_ti8x_link_port_interface
+{
+public:
+ tee_connector_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+ DECLARE_WRITE_LINE_MEMBER(tip_a_w);
+ DECLARE_WRITE_LINE_MEMBER(ring_a_w);
+ DECLARE_WRITE_LINE_MEMBER(tip_b_w);
+ DECLARE_WRITE_LINE_MEMBER(ring_b_w);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const override;
+ virtual void device_start() override;
+
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) override;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) override;
+
+ required_device<ti8x_link_port_device> m_port_a;
+ required_device<ti8x_link_port_device> m_port_b;
+
+ bool m_tip_host, m_tip_a, m_tip_b;
+ bool m_ring_host, m_ring_a, m_ring_b;
+};
+
+} } // namespace bus::ti8x
+
+#endif // MAME_DEVICES_BUS_TI8X_TEECONN_H
diff --git a/src/devices/bus/ti8x/ti8x.cpp b/src/devices/bus/ti8x/ti8x.cpp
new file mode 100644
index 00000000000..0fa99837288
--- /dev/null
+++ b/src/devices/bus/ti8x/ti8x.cpp
@@ -0,0 +1,622 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "emu.h"
+#include "ti8x.h"
+
+#define LOG_GENERAL (1U << 0)
+#define LOG_BITPROTO (1U << 1)
+#define LOG_BYTEPROTO (1U << 2)
+
+//#define VERBOSE (LOG_GENERAL | LOG_BITPROTO | LOG_BYTEPROTO)
+#define LOG_OUTPUT_FUNC device().logerror
+#include "logmacro.h"
+
+#define LOGBITPROTO(...) LOGMASKED(LOG_BITPROTO, __VA_ARGS__)
+#define LOGBYTEPROTO(...) LOGMASKED(LOG_BYTEPROTO, __VA_ARGS__)
+
+
+
+device_type const TI8X_LINK_PORT = device_creator<ti8x_link_port_device>;
+
+
+ti8x_link_port_device::ti8x_link_port_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : ti8x_link_port_device(mconfig, TI8X_LINK_PORT, "TI-8x Link Port", tag, owner, clock, "ti8xlink", __FILE__)
+{
+}
+
+
+ti8x_link_port_device::ti8x_link_port_device(
+ machine_config const &mconfig,
+ device_type type,
+ char const *name,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock,
+ char const *shortname,
+ char const *source)
+ : device_t(mconfig, type, name, tag, owner, clock, shortname, source)
+ , device_slot_interface(mconfig, *this)
+ , m_tip_handler(*this)
+ , m_ring_handler(*this)
+ , m_dev(nullptr)
+ , m_tip_in(true)
+ , m_tip_out(true)
+ , m_ring_in(true)
+ , m_ring_out(true)
+{
+}
+
+
+WRITE_LINE_MEMBER(ti8x_link_port_device::tip_w)
+{
+ if (bool(state) != m_tip_out)
+ {
+ m_tip_out = bool(state);
+ if (m_dev)
+ m_dev->input_tip(m_tip_out ? 1 : 0);
+ }
+}
+
+
+WRITE_LINE_MEMBER(ti8x_link_port_device::ring_w)
+{
+ if (bool(state) != m_ring_out)
+ {
+ m_ring_out = bool(state);
+ if (m_dev)
+ m_dev->input_ring(m_ring_out ? 1 : 0);
+ }
+}
+
+
+void ti8x_link_port_device::device_start()
+{
+ m_tip_handler.resolve_safe();
+ m_ring_handler.resolve_safe();
+
+ save_item(NAME(m_tip_in));
+ save_item(NAME(m_tip_out));
+ save_item(NAME(m_ring_in));
+ save_item(NAME(m_ring_out));
+
+ m_tip_in = m_tip_out = true;
+ m_ring_in = m_ring_out = true;
+}
+
+
+void ti8x_link_port_device::device_config_complete()
+{
+ m_dev = dynamic_cast<device_ti8x_link_port_interface *>(get_card_device());
+}
+
+
+
+device_ti8x_link_port_interface::device_ti8x_link_port_interface(
+ machine_config const &mconfig,
+ device_t &device)
+ : device_slot_card_interface(mconfig, device)
+ , m_port(dynamic_cast<ti8x_link_port_device *>(device.owner()))
+{
+}
+
+
+
+device_ti8x_link_port_bit_interface::device_ti8x_link_port_bit_interface(
+ machine_config const &mconfig,
+ device_t &device)
+ : device_ti8x_link_port_interface(mconfig, device)
+ , m_error_timer(nullptr)
+ , m_bit_phase(IDLE)
+ , m_tx_bit_buffer(EMPTY)
+ , m_tip_in(true)
+ , m_ring_in(true)
+{
+}
+
+
+void device_ti8x_link_port_bit_interface::interface_pre_start()
+{
+ device_ti8x_link_port_interface::interface_pre_start();
+
+ m_error_timer = device().timer_alloc(TIMER_ID_BIT_TIMEOUT);
+
+ device().save_item(NAME(m_bit_phase));
+ device().save_item(NAME(m_tx_bit_buffer));
+ device().save_item(NAME(m_tip_in));
+ device().save_item(NAME(m_ring_in));
+
+ m_bit_phase = IDLE;
+ m_tx_bit_buffer = EMPTY;
+ m_tip_in = m_ring_in = true;
+}
+
+
+void device_ti8x_link_port_bit_interface::interface_pre_reset()
+{
+ device_ti8x_link_port_interface::interface_pre_reset();
+
+ m_error_timer->reset();
+ m_bit_phase = (m_tip_in && m_ring_in) ? IDLE : WAIT_IDLE;
+ m_tx_bit_buffer = EMPTY;
+
+ output_tip(1);
+ output_ring(1);
+}
+
+
+void device_ti8x_link_port_bit_interface::device_timer(
+ emu_timer &timer,
+ device_timer_id id,
+ int param, void *ptr)
+{
+ switch (id)
+ {
+ case TIMER_ID_BIT_TIMEOUT:
+ switch (m_bit_phase)
+ {
+ // something very bad happened (heap smash?)
+ case IDLE:
+ case HOLD_0:
+ case HOLD_1:
+ default:
+ throw false;
+
+ // receive timeout
+ case ACK_0:
+ case ACK_1:
+ LOGBITPROTO("timeout acknowledging %d bit\n", (ACK_0 == m_bit_phase) ? 0 : 1);
+ output_tip(1);
+ output_ring(1);
+ if (m_tip_in && m_ring_in)
+ {
+ check_tx_bit_buffer();
+ }
+ else
+ {
+ LOGBITPROTO("waiting for bus idle\n");
+ m_error_timer->reset((EMPTY == m_tx_bit_buffer) ? attotime::never : attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_IDLE;
+ }
+ bit_receive_timeout();
+ break;
+
+ // send timeout:
+ case WAIT_IDLE:
+ assert(EMPTY != m_tx_bit_buffer);
+ case WAIT_ACK_0:
+ case WAIT_ACK_1:
+ case WAIT_REL_0:
+ case WAIT_REL_1:
+ LOGBITPROTO("timeout sending bit\n");
+ m_error_timer->reset();
+ m_bit_phase = (m_tip_in && m_ring_in) ? IDLE : WAIT_IDLE;
+ m_tx_bit_buffer = EMPTY;
+ output_tip(1);
+ output_ring(1);
+ bit_send_timeout();
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+
+void device_ti8x_link_port_bit_interface::send_bit(bool data)
+{
+ LOGBITPROTO("queue %d bit\n", data ? 1 : 0);
+
+ if (EMPTY != m_tx_bit_buffer)
+ device().logerror("device_ti8x_link_port_bit_interface: warning: transmit buffer overrun\n");
+
+ m_tx_bit_buffer = data ? PENDING_1 : PENDING_0;
+ if (IDLE == m_bit_phase)
+ check_tx_bit_buffer();
+ else if (WAIT_IDLE == m_bit_phase)
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+}
+
+
+void device_ti8x_link_port_bit_interface::accept_bit()
+{
+ switch (m_bit_phase)
+ {
+ // can't accept a bit that isn't being held
+ case IDLE:
+ case WAIT_ACK_0:
+ case WAIT_ACK_1:
+ case WAIT_REL_0:
+ case WAIT_REL_1:
+ case ACK_0:
+ case ACK_1:
+ case WAIT_IDLE:
+ fatalerror("device_ti8x_link_port_bit_interface: attempt to accept bit when not holding");
+ break;
+
+ // release the acknowledgement - if the ring doesn't rise we've lost sync
+ case HOLD_0:
+ assert(m_tip_in);
+
+ output_ring(1);
+ if (m_ring_in)
+ {
+ LOGBITPROTO("accepted 0 bit\n");
+ check_tx_bit_buffer();
+ }
+ else
+ {
+ LOGBITPROTO("accepted 0 bit, ring low (collision) - waiting for bus idle\n");
+ m_error_timer->reset((EMPTY == m_tx_bit_buffer) ? attotime::never : attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_IDLE;
+ bit_collision();
+ }
+ break;
+
+ // release the acknowledgement - if the tip doesn't rise we've lost sync
+ case HOLD_1:
+ assert(m_ring_in);
+
+ output_tip(1);
+ if (m_tip_in)
+ {
+ LOGBITPROTO("accepted 1 bit\n");
+ check_tx_bit_buffer();
+ }
+ else
+ {
+ LOGBITPROTO("accepted 1 bit, tip low (collision) - waiting for bus idle\n");
+ m_error_timer->reset((EMPTY == m_tx_bit_buffer) ? attotime::never : attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_IDLE;
+ bit_collision();
+ }
+ break;
+
+ // something very bad happened (heap smash?)
+ default:
+ throw false;
+ }
+}
+
+
+WRITE_LINE_MEMBER(device_ti8x_link_port_bit_interface::input_tip)
+{
+ m_tip_in = bool(state);
+ switch (m_bit_phase)
+ {
+ // if tip falls while idle, it's the beginning of an incoming 0
+ case IDLE:
+ if (!m_tip_in)
+ {
+ LOGBITPROTO("falling edge on tip, acknowledging 0 bit\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = ACK_0;
+ output_ring(0);
+ }
+ break;
+
+ // we're driving tip low in this state, ignore it
+ case WAIT_ACK_0:
+ case ACK_1:
+ case HOLD_1:
+ break;
+
+ // tip must fall to acknowledge outgoing 1
+ case WAIT_ACK_1:
+ if (!m_tip_in)
+ {
+ LOGBITPROTO("falling edge on tip, 1 bit acknowledged, confirming\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_REL_1;
+ output_ring(1);
+ }
+ break;
+
+ // if tip falls now, we've lost sync
+ case WAIT_REL_0:
+ case HOLD_0:
+ if (!m_tip_in)
+ {
+ LOGBITPROTO("falling edge on tip, lost sync, waiting for bus idle\n");
+ m_error_timer->reset((EMPTY == m_tx_bit_buffer) ? attotime::never : attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_IDLE;
+ output_ring(1);
+ bit_collision();
+ }
+ break;
+
+ // tip must rise to complete outgoing 1 sequence
+ case WAIT_REL_1:
+ if (m_tip_in)
+ {
+ assert(!m_ring_in);
+
+ LOGBITPROTO("rising edge on tip, 1 bit sent\n");
+ check_tx_bit_buffer();
+ bit_sent();
+ }
+ break;
+
+ // tip must rise to accept our acknowledgement
+ case ACK_0:
+ if (m_tip_in)
+ {
+ LOGBITPROTO("rising edge on tip, 0 bit acknowledge confirmed, holding\n");
+ m_error_timer->reset();
+ m_bit_phase = HOLD_0;
+ bit_received(false);
+ }
+ break;
+
+ // if the bus is available, check for bit to send
+ case WAIT_IDLE:
+ if (m_tip_in && m_ring_in)
+ {
+ LOGBITPROTO("rising edge on tip, bus idle detected\n");
+ check_tx_bit_buffer();
+ }
+ break;
+
+ // something very bad happened (heap smash?)
+ default:
+ throw false;
+ }
+}
+
+
+WRITE_LINE_MEMBER(device_ti8x_link_port_bit_interface::input_ring)
+{
+ m_ring_in = bool(state);
+ switch (m_bit_phase)
+ {
+ // if ring falls while idle, it's the beginning of an incoming 1
+ case IDLE:
+ if (!m_ring_in)
+ {
+ LOGBITPROTO("falling edge on ring, acknowledging 1 bit\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = ACK_1;
+ output_tip(0);
+ }
+ break;
+
+ // ring must fall to acknowledge outgoing 0
+ case WAIT_ACK_0:
+ if (!m_ring_in)
+ {
+ LOGBITPROTO("falling edge on ring, 0 bit acknowledged, confirming\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_REL_0;
+ output_tip(1);
+ }
+ break;
+
+ // we're driving ring low in this state, ignore it
+ case WAIT_ACK_1:
+ case ACK_0:
+ case HOLD_0:
+ break;
+
+ // ring must rise to complete outgoing 0 sequence
+ case WAIT_REL_0:
+ if (m_ring_in)
+ {
+ assert(!m_tip_in);
+
+ LOGBITPROTO("rising edge on ring, 0 bit sent\n");
+ check_tx_bit_buffer();
+ bit_sent();
+ }
+ break;
+
+ // if ring falls now, we've lost sync
+ case WAIT_REL_1:
+ case HOLD_1:
+ if (!m_ring_in)
+ {
+ LOGBITPROTO("falling edge on ring, lost sync, waiting for bus idle\n");
+ m_error_timer->reset((EMPTY == m_tx_bit_buffer) ? attotime::never : attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_IDLE;
+ output_tip(1);
+ bit_collision();
+ }
+ break;
+
+ // ring must rise to accept our acknowledgement
+ case ACK_1:
+ if (m_ring_in)
+ {
+ LOGBITPROTO("rising edge on ring, 1 bit acknowledge confirmed, holding\n");
+ m_error_timer->reset();
+ m_bit_phase = HOLD_1;
+ bit_received(true);
+ }
+ break;
+
+ // if the bus is available, check for bit to send
+ case WAIT_IDLE:
+ if (m_tip_in && m_ring_in)
+ {
+ LOGBITPROTO("rising edge on tip, bus idle detected\n");
+ check_tx_bit_buffer();
+ }
+ break;
+
+ // something very bad happened (heap smash?)
+ default:
+ throw false;
+ }
+}
+
+
+void device_ti8x_link_port_bit_interface::check_tx_bit_buffer()
+{
+ assert(m_tip_in);
+ assert(m_ring_in);
+
+ switch (m_tx_bit_buffer)
+ {
+ // nothing to do
+ case EMPTY:
+ LOGBITPROTO("no pending bit, entering idle state\n");
+ m_error_timer->reset();
+ m_bit_phase = IDLE;
+ break;
+
+ // pull tip low and wait for acknowledgement
+ case PENDING_0:
+ LOGBITPROTO("sending 0 bit, pulling tip low\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_ACK_0;
+ m_tx_bit_buffer = EMPTY;
+ output_tip(0);
+ break;
+
+ // pull ring low and wait for acknowledgement
+ case PENDING_1:
+ LOGBITPROTO("sending 1 bit, pulling ring low\n");
+ m_error_timer->reset(attotime(1, 0)); // TODO: configurable timeout
+ m_bit_phase = WAIT_ACK_1;
+ m_tx_bit_buffer = EMPTY;
+ output_ring(0);
+ break;
+
+ // something very bad happened (heap smash?)
+ default:
+ throw false;
+ }
+}
+
+
+
+device_ti8x_link_port_byte_interface::device_ti8x_link_port_byte_interface(
+ machine_config const &mconfig,
+ device_t &device)
+ : device_ti8x_link_port_bit_interface(mconfig, device)
+ , m_tx_byte_buffer(0U)
+ , m_rx_byte_buffer(0U)
+{
+}
+
+
+void device_ti8x_link_port_byte_interface::interface_pre_start()
+{
+ device_ti8x_link_port_bit_interface::interface_pre_start();
+
+ device().save_item(NAME(m_tx_byte_buffer));
+ device().save_item(NAME(m_rx_byte_buffer));
+
+ m_tx_byte_buffer = m_rx_byte_buffer = 0U;
+}
+
+
+void device_ti8x_link_port_byte_interface::interface_pre_reset()
+{
+ device_ti8x_link_port_bit_interface::interface_pre_reset();
+
+ m_tx_byte_buffer = m_rx_byte_buffer = 0U;
+}
+
+
+void device_ti8x_link_port_byte_interface::send_byte(u8 data)
+{
+ if (m_tx_byte_buffer)
+ device().logerror("device_ti8x_link_port_byte_interface: warning: transmit buffer overrun\n");
+
+ LOGBYTEPROTO("sending byte 0x%02X\n", data);
+ m_tx_byte_buffer = 0x0080 | u16(data >> 1);
+ send_bit(BIT(data, 0));
+}
+
+
+void device_ti8x_link_port_byte_interface::accept_byte()
+{
+ assert(BIT(m_rx_byte_buffer, 8));
+
+ LOGBYTEPROTO("accepting final bit of byte\n");
+ m_rx_byte_buffer = 0U;
+ accept_bit();
+}
+
+
+void device_ti8x_link_port_byte_interface::bit_collision()
+{
+ LOGBYTEPROTO("bit collection, clearing byte buffers\n");
+ m_tx_byte_buffer = m_rx_byte_buffer = 0U;
+ byte_collision();
+}
+
+
+void device_ti8x_link_port_byte_interface::bit_send_timeout()
+{
+ LOGBYTEPROTO("bit send timeout, clearing send byte buffer\n");
+ m_tx_byte_buffer = 0U;
+ byte_send_timeout();
+}
+
+
+void device_ti8x_link_port_byte_interface::bit_receive_timeout()
+{
+ LOGBYTEPROTO("bit receive timeout, clearing receive byte buffer\n");
+ m_rx_byte_buffer = 0U;
+ byte_receive_timeout();
+}
+
+
+void device_ti8x_link_port_byte_interface::bit_sent()
+{
+ assert(m_tx_byte_buffer);
+
+ bool const data(BIT(m_tx_byte_buffer, 0));
+ if (m_tx_byte_buffer >>= 1)
+ {
+ LOGBYTEPROTO("bit sent, sending next bit of byte\n");
+ send_bit(data);
+ }
+ else
+ {
+ assert(data);
+
+ LOGBYTEPROTO("final bit of byte sent\n");
+ byte_sent();
+ }
+}
+
+
+void device_ti8x_link_port_byte_interface::bit_received(bool data)
+{
+ assert(!BIT(m_rx_byte_buffer, 8));
+
+ m_rx_byte_buffer = (!m_rx_byte_buffer ? 0x8000 : (m_rx_byte_buffer >> 1)) | (data ? 0x0080U : 0x0000U);
+ if (BIT(m_rx_byte_buffer, 8))
+ {
+ LOGBYTEPROTO("received final bit of byte 0x%02X\n", u8(m_rx_byte_buffer));
+ byte_received(u8(m_rx_byte_buffer));
+ }
+ else
+ {
+ LOGBYTEPROTO("bit received, accepting\n");
+ accept_bit();
+ }
+}
+
+
+
+#include "bitsocket.h"
+#include "graphlinkhle.h"
+#include "teeconn.h"
+#include "tispeaker.h"
+
+SLOT_INTERFACE_START(default_ti8x_link_devices)
+ SLOT_INTERFACE("bitsock", TI8X_BIT_SOCKET)
+ SLOT_INTERFACE("glinkhle", TI8X_GRAPH_LINK_HLE)
+ SLOT_INTERFACE("tee", TI8X_TEE_CONNECTOR)
+ SLOT_INTERFACE("monospkr", TI8X_SPEAKER_MONO)
+ SLOT_INTERFACE("stereospkr", TI8X_SPEAKER_STEREO)
+SLOT_INTERFACE_END
diff --git a/src/devices/bus/ti8x/ti8x.h b/src/devices/bus/ti8x/ti8x.h
new file mode 100644
index 00000000000..fdb998cb66c
--- /dev/null
+++ b/src/devices/bus/ti8x/ti8x.h
@@ -0,0 +1,213 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+/*
+ TI-8x calculator link port.
+
+ 2.5mm TRS connector on each device, tip and ring both used as I/O
+ lines. Each device has passive pull-ups and software-controlled active
+ pull-downs. In TI products, the tip is connected to a red wire and the
+ ring is connected to a white wire.
+
+ The link ports are only intended to allow linking two devices together,
+ but there is open source software implementing multi-master protocols
+ including I2C. The number of devices that can be connected together is
+ limited in practice by the fact that every device provides pull-ups and
+ there's a limit to the amount of current any device can sink.
+
+ TI's link port protocol uses 8-bit bytes transmitted LSB first with no
+ markers for beginning/end of a byte or parity. To transfer a bit, the
+ transmitting device pulls down a line (tip for 0, ring for 1), waits
+ for the receiving device to pull down the other line, releases its
+ line, and waits for the receiver to release the other line. This
+ ensures software-based implementations don't drop bits. The 6 MHz
+ Z80-based calculators can manage up to about 50 kbps.
+
+ In a TI-82, each line is tied to the supply rail via a 10kΩ resistor
+ in series with a signal diode, and can be pulled low by an NPN
+ transistor in series with a 470Ω resistor.
+
+ This bus implementation works with logic levels (1 = pulled up,
+ 0 = driven down). The port device just gives you the drive level from
+ the opposite side of the port which you need to mix with your device's
+ output. This makes implementing things like the tee connector easier.
+ */
+
+#ifndef MAME_DEVICES_BUS_TI8X_TI8X_H
+#define MAME_DEVICES_BUS_TI8X_TI8X_H
+
+#pragma once
+
+
+
+extern device_type const TI8X_LINK_PORT;
+
+
+#define MCFG_TI8X_LINK_PORT_ADD(tag, slot_intf, def_slot) \
+ MCFG_DEVICE_ADD(tag, TI8X_LINK_PORT, 0) \
+ MCFG_DEVICE_SLOT_INTERFACE(slot_intf, def_slot, false)
+
+#define MCFG_TI8X_LINK_TIP_HANDLER(cb) \
+ devcb = &ti8x_link_port_device::set_tip_handler(*device, DEVCB_##cb);
+
+#define MCFG_TI8X_LINK_RING_HANDLER(cb) \
+ devcb = &ti8x_link_port_device::set_ring_handler(*device, DEVCB_##cb);
+
+
+class device_ti8x_link_port_interface;
+
+
+class ti8x_link_port_device : public device_t, public device_slot_interface
+{
+public:
+ ti8x_link_port_device(machine_config const &mconfig, char const *tag, device_t *owner, u32 clock);
+
+ // static configuration helpers
+ template <class Object> static devcb_base &set_tip_handler(device_t &device, Object &&cb)
+ { return downcast<ti8x_link_port_device &>(device).m_tip_handler.set_callback(std::forward<Object>(cb)); }
+ template <class Object> static devcb_base &set_ring_handler(device_t &device, Object &&cb)
+ { return downcast<ti8x_link_port_device &>(device).m_ring_handler.set_callback(std::forward<Object>(cb)); }
+
+ DECLARE_WRITE_LINE_MEMBER(tip_w);
+ DECLARE_WRITE_LINE_MEMBER(ring_w);
+
+ DECLARE_READ_LINE_MEMBER(tip_r) { return m_tip_in ? 1 : 0; }
+ DECLARE_READ_LINE_MEMBER(ring_r) { return m_ring_in ? 1 : 0; }
+
+protected:
+ ti8x_link_port_device(
+ machine_config const &mconfig,
+ device_type type,
+ char const *name,
+ char const *tag,
+ device_t *owner,
+ u32 clock,
+ char const *shortname,
+ char const *source);
+
+ virtual void device_start() override;
+ virtual void device_config_complete() override;
+
+ devcb_write_line m_tip_handler;
+ devcb_write_line m_ring_handler;
+
+private:
+ friend class device_ti8x_link_port_interface;
+
+ device_ti8x_link_port_interface *m_dev;
+
+ bool m_tip_in, m_tip_out, m_ring_in, m_ring_out;
+};
+
+
+class device_ti8x_link_port_interface : public device_slot_card_interface
+{
+public:
+ DECLARE_WRITE_LINE_MEMBER(output_tip)
+ { if (bool(state) != m_port->m_tip_in) m_port->m_tip_handler((m_port->m_tip_in = bool(state)) ? 1 : 0); }
+ DECLARE_WRITE_LINE_MEMBER(output_ring)
+ { if (bool(state) != m_port->m_ring_in) m_port->m_ring_handler((m_port->m_ring_in = bool(state)) ? 1 : 0); }
+
+protected:
+ device_ti8x_link_port_interface(machine_config const &mconfig, device_t &device);
+
+ ti8x_link_port_device &port() { return *m_port; }
+
+private:
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) = 0;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) = 0;
+
+ friend class ti8x_link_port_device;
+
+ ti8x_link_port_device *m_port;
+};
+
+
+class device_ti8x_link_port_bit_interface : public device_ti8x_link_port_interface
+{
+protected:
+ device_ti8x_link_port_bit_interface(machine_config const &mconfig, device_t &device);
+
+ virtual void interface_pre_start() override;
+ virtual void interface_pre_reset() override;
+
+ virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr);
+
+ void send_bit(bool data);
+ void accept_bit();
+
+private:
+ enum
+ {
+ TIMER_ID_BIT_TIMEOUT = 20000 // ensure this doesn't clash with device_serial_interface
+ };
+
+ enum bit_phase
+ {
+ IDLE,
+ WAIT_ACK_0,
+ WAIT_ACK_1,
+ WAIT_REL_0,
+ WAIT_REL_1,
+ ACK_0,
+ ACK_1,
+ HOLD_0,
+ HOLD_1,
+ WAIT_IDLE
+ };
+
+ enum bit_buffer
+ {
+ EMPTY,
+ PENDING_0,
+ PENDING_1
+ };
+
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) override;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) override;
+
+ virtual void bit_collision() = 0;
+ virtual void bit_send_timeout() = 0;
+ virtual void bit_receive_timeout() = 0;
+ virtual void bit_sent() = 0;
+ virtual void bit_received(bool data) = 0;
+
+ void check_tx_bit_buffer();
+
+ emu_timer * m_error_timer;
+ u8 m_bit_phase;
+ u8 m_tx_bit_buffer;
+ bool m_tip_in, m_ring_in;
+};
+
+
+class device_ti8x_link_port_byte_interface : public device_ti8x_link_port_bit_interface
+{
+protected:
+ device_ti8x_link_port_byte_interface(machine_config const &mconfig, device_t &device);
+
+ virtual void interface_pre_start() override;
+ virtual void interface_pre_reset() override;
+
+ void send_byte(u8 data);
+ void accept_byte();
+
+private:
+ virtual void bit_collision() override;
+ virtual void bit_send_timeout() override;
+ virtual void bit_receive_timeout() override;
+ virtual void bit_sent() override;
+ virtual void bit_received(bool data) override;
+
+ virtual void byte_collision() = 0;
+ virtual void byte_send_timeout() = 0;
+ virtual void byte_receive_timeout() = 0;
+ virtual void byte_sent() = 0;
+ virtual void byte_received(u8 data) = 0;
+
+ u16 m_tx_byte_buffer, m_rx_byte_buffer;
+};
+
+
+SLOT_INTERFACE_EXTERN( default_ti8x_link_devices );
+
+#endif // MAME_DEVICES_BUS_TI8X_TI8X_H
diff --git a/src/devices/bus/ti8x/tispeaker.cpp b/src/devices/bus/ti8x/tispeaker.cpp
new file mode 100644
index 00000000000..c62ae827573
--- /dev/null
+++ b/src/devices/bus/ti8x/tispeaker.cpp
@@ -0,0 +1,117 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+
+#include "tispeaker.h"
+
+#include "speaker.h"
+
+
+device_type const TI8X_SPEAKER_STEREO = device_creator<bus::ti8x::stereo_speaker_device>;
+device_type const TI8X_SPEAKER_MONO = device_creator<bus::ti8x::mono_speaker_device>;
+
+
+namespace bus { namespace ti8x {
+
+namespace {
+
+MACHINE_CONFIG_FRAGMENT(ti_speaker_stereo)
+ MCFG_SPEAKER_STANDARD_STEREO("outl", "outr")
+
+ MCFG_SOUND_ADD("lspkr", SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "outl", 0.50)
+
+ MCFG_SOUND_ADD("rspkr", SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "outr", 0.50)
+MACHINE_CONFIG_END
+
+
+MACHINE_CONFIG_FRAGMENT(ti_speaker_mono)
+ MCFG_SPEAKER_STANDARD_MONO("mono")
+
+ MCFG_SOUND_ADD("spkr", SPEAKER_SOUND, 0)
+ MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+MACHINE_CONFIG_END
+
+} // anonymous namespace
+
+
+stereo_speaker_device::stereo_speaker_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, TI8X_SPEAKER_STEREO, "TI-8x Speaker (Stereo)", tag, owner, clock, "ti8xstspkr", __FILE__)
+ , device_ti8x_link_port_interface(mconfig, *this)
+ , m_left_speaker(*this, "lspkr")
+ , m_right_speaker(*this, "rspkr")
+{
+}
+
+
+machine_config_constructor stereo_speaker_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(ti_speaker_stereo);
+}
+
+
+void stereo_speaker_device::device_start()
+{
+}
+
+
+WRITE_LINE_MEMBER(stereo_speaker_device::input_tip)
+{
+ m_left_speaker->level_w(state);
+}
+
+
+WRITE_LINE_MEMBER(stereo_speaker_device::input_ring)
+{
+ m_right_speaker->level_w(state);
+}
+
+
+
+mono_speaker_device::mono_speaker_device(
+ machine_config const &mconfig,
+ char const *tag,
+ device_t *owner,
+ uint32_t clock)
+ : device_t(mconfig, TI8X_SPEAKER_MONO, "TI-8x Speaker (Mono)", tag, owner, clock, "ti8xmspkr", __FILE__)
+ , device_ti8x_link_port_interface(mconfig, *this)
+ , m_speaker(*this, "spkr")
+ , m_tip_state(true)
+ , m_ring_state(true)
+{
+}
+
+
+machine_config_constructor mono_speaker_device::device_mconfig_additions() const
+{
+ return MACHINE_CONFIG_NAME(ti_speaker_mono);
+}
+
+
+void mono_speaker_device::device_start()
+{
+ save_item(NAME(m_tip_state));
+ save_item(NAME(m_ring_state));
+
+ m_tip_state = m_ring_state = true;
+}
+
+
+WRITE_LINE_MEMBER(mono_speaker_device::input_tip)
+{
+ m_tip_state = bool(state);
+ m_speaker->level_w((m_tip_state || m_ring_state) ? 1 : 0);
+}
+
+
+WRITE_LINE_MEMBER(mono_speaker_device::input_ring)
+{
+ m_ring_state = bool(state);
+ m_speaker->level_w((m_tip_state || m_ring_state) ? 1 : 0);
+}
+
+} } // namespace bus::ti8x
diff --git a/src/devices/bus/ti8x/tispeaker.h b/src/devices/bus/ti8x/tispeaker.h
new file mode 100644
index 00000000000..308b316b3bf
--- /dev/null
+++ b/src/devices/bus/ti8x/tispeaker.h
@@ -0,0 +1,55 @@
+// license:BSD-3-Clause
+// copyright-holders:Vas Crabb
+#ifndef MAME_DEVICES_BUS_TI8X_TISPEAKER_H
+#define MAME_DEVICES_BUS_TI8X_TISPEAKER_H
+
+#pragma once
+
+#include "ti8x.h"
+#include "sound/spkrdev.h"
+
+
+extern device_type const TI8X_SPEAKER_STEREO;
+extern device_type const TI8X_SPEAKER_MONO;
+
+
+namespace bus { namespace ti8x {
+
+class stereo_speaker_device : public device_t, public device_ti8x_link_port_interface
+{
+public:
+ stereo_speaker_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const override;
+ virtual void device_start() override;
+
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) override;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) override;
+
+ required_device<speaker_sound_device> m_left_speaker;
+ required_device<speaker_sound_device> m_right_speaker;
+};
+
+
+class mono_speaker_device : public device_t, public device_ti8x_link_port_interface
+{
+public:
+ mono_speaker_device(machine_config const &mconfig, char const *tag, device_t *owner, uint32_t clock);
+
+protected:
+ virtual machine_config_constructor device_mconfig_additions() const override;
+ virtual void device_start() override;
+
+ virtual DECLARE_WRITE_LINE_MEMBER(input_tip) override;
+ virtual DECLARE_WRITE_LINE_MEMBER(input_ring) override;
+
+ required_device<speaker_sound_device> m_speaker;
+
+private:
+ bool m_tip_state, m_ring_state;
+};
+
+} } // namespace bus::ti8x
+
+#endif // MAME_DEVICES_BUS_TI8X_TISPEAKER_H
diff --git a/src/mame/drivers/ti85.cpp b/src/mame/drivers/ti85.cpp
index fc8aab49ddf..1cadc0ca12c 100644
--- a/src/mame/drivers/ti85.cpp
+++ b/src/mame/drivers/ti85.cpp
@@ -208,7 +208,6 @@ TI-86 ports:
#include "imagedev/snapquik.h"
#include "machine/bankdev.h"
#include "screen.h"
-#include "speaker.h"
/* port i/o functions */
@@ -599,10 +598,7 @@ static MACHINE_CONFIG_DERIVED( ti85, ti81 )
MCFG_SCREEN_SIZE(128, 64)
MCFG_SCREEN_VISIBLE_AREA(0, 128-1, 0, 64-1)
- /* sound hardware */
- MCFG_SPEAKER_STANDARD_MONO("mono")
- MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ MCFG_TI8X_LINK_PORT_ADD("linkport", default_ti8x_link_devices, nullptr)
MACHINE_CONFIG_END
@@ -629,18 +625,14 @@ static MACHINE_CONFIG_DERIVED( ti82, ti81 )
MCFG_DEVICE_ADD("t6a04", T6A04, 0)
MCFG_T6A04_SIZE(96, 64)
- MCFG_SPEAKER_STANDARD_MONO("mono")
- MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
-
- //MCFG_TI82SERIAL_ADD( "tiserial" )
+ MCFG_TI8X_LINK_PORT_ADD("linkport", default_ti8x_link_devices, nullptr)
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti81v2, ti82 )
MCFG_CPU_MODIFY("maincpu")
MCFG_CPU_IO_MAP(ti81v2_io)
- //MCFG_DEVICE_REMOVE( "tiserial" )
+ MCFG_DEVICE_REMOVE("linkport")
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti83, ti81 )
@@ -670,7 +662,6 @@ static MACHINE_CONFIG_DERIVED( ti86, ti85 )
MCFG_MACHINE_RESET_OVERRIDE(ti85_state, ti85 )
MCFG_SNAPSHOT_ADD("snapshot", ti85_state, ti8x, "sav", 0)
- //MCFG_TI86SERIAL_ADD( "tiserial" )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti83p, ti81 )
@@ -716,13 +707,9 @@ static MACHINE_CONFIG_DERIVED( ti83p, ti81 )
MCFG_DEVICE_ADD("t6a04", T6A04, 0)
MCFG_T6A04_SIZE(96, 64)
- MCFG_SPEAKER_STANDARD_MONO("mono")
- MCFG_SOUND_ADD("speaker", SPEAKER_SOUND, 0)
- MCFG_SOUND_ROUTE(ALL_OUTPUTS, "mono", 0.50)
+ MCFG_TI8X_LINK_PORT_ADD("linkport", default_ti8x_link_devices, nullptr)
MCFG_AMD_29F400T_ADD("flash")
-
- //MCFG_TI83PSERIAL_ADD( "tiserial" )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti83pse, ti83p )
@@ -744,8 +731,6 @@ static MACHINE_CONFIG_DERIVED( ti83pse, ti83p )
MCFG_MACHINE_START_OVERRIDE(ti85_state, ti83pse )
MCFG_DEVICE_REPLACE("flash", FUJITSU_29F160T, 0)
-
- //MCFG_TI83PSERIAL_ADD( "tiserial" )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti84p, ti83pse )
@@ -770,7 +755,7 @@ static MACHINE_CONFIG_DERIVED( ti84pse, ti83pse )
MACHINE_CONFIG_END
static MACHINE_CONFIG_DERIVED( ti73, ti83p )
- //MCFG_DEVICE_REMOVE( "tiserial" )
+ MCFG_DEVICE_REMOVE("linkport")
//MCFG_TI73SERIAL_ADD( "tiserial" )
MACHINE_CONFIG_END
@@ -921,15 +906,15 @@ ROM_START (ti84p)
ROMX_LOAD( "ti84pb100v255mp.bin", 0x00000, 0x100000, CRC(4af31251) SHA1(8f67269346644b87e7cd0f353f5f4030e787cf57), ROM_BIOS(1) )
ROM_END
-/* YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS */
-COMP( 1990, ti81, 0, 0, ti81, ti81, driver_device, 0, "Texas Instruments", "TI-81", MACHINE_NO_SOUND )
-COMP( 1992, ti85, 0, 0, ti85d, ti85, driver_device, 0, "Texas Instruments", "TI-85", MACHINE_NO_SOUND )
-COMP( 1993, ti82, 0, 0, ti82, ti82, driver_device, 0, "Texas Instruments", "TI-82", MACHINE_NO_SOUND )
-COMP( 1994, ti81v2, ti81, 0, ti81v2, ti81, driver_device, 0, "Texas Instruments", "TI-81 v2.0", MACHINE_NO_SOUND )
-COMP( 1996, ti83, 0, 0, ti83, ti83, driver_device, 0, "Texas Instruments", "TI-83", MACHINE_NO_SOUND )
-COMP( 1997, ti86, 0, 0, ti86, ti85, driver_device, 0, "Texas Instruments", "TI-86", MACHINE_NO_SOUND )
-COMP( 1998, ti73, 0, 0, ti73, ti82, driver_device, 0, "Texas Instruments", "TI-73", MACHINE_NO_SOUND )
-COMP( 1999, ti83p, 0, 0, ti83p, ti82, driver_device, 0, "Texas Instruments", "TI-83 Plus", MACHINE_NO_SOUND )
-COMP( 2001, ti83pse, 0, 0, ti83pse, ti82, driver_device, 0, "Texas Instruments", "TI-83 Plus Silver Edition", MACHINE_NO_SOUND )
-COMP( 2004, ti84p, 0, 0, ti84p, ti82, driver_device, 0, "Texas Instruments", "TI-84 Plus", MACHINE_NO_SOUND )
-COMP( 2004, ti84pse, 0, 0, ti84pse, ti82, driver_device, 0, "Texas Instruments", "TI-84 Plus Silver Edition", MACHINE_NO_SOUND )
+// YEAR NAME PARENT COMPAT MACHINE INPUT INIT COMPANY FULLNAME FLAGS
+COMP( 1990, ti81, 0, 0, ti81, ti81, driver_device, 0, "Texas Instruments", "TI-81", MACHINE_NO_SOUND_HW )
+COMP( 1992, ti85, 0, 0, ti85d, ti85, driver_device, 0, "Texas Instruments", "TI-85", MACHINE_NO_SOUND_HW )
+COMP( 1993, ti82, 0, 0, ti82, ti82, driver_device, 0, "Texas Instruments", "TI-82", MACHINE_NO_SOUND_HW )
+COMP( 1994, ti81v2, ti81, 0, ti81v2, ti81, driver_device, 0, "Texas Instruments", "TI-81 v2.0", MACHINE_NO_SOUND_HW )
+COMP( 1996, ti83, 0, 0, ti83, ti83, driver_device, 0, "Texas Instruments", "TI-83", MACHINE_NO_SOUND_HW )
+COMP( 1997, ti86, 0, 0, ti86, ti85, driver_device, 0, "Texas Instruments", "TI-86", MACHINE_NO_SOUND_HW )
+COMP( 1998, ti73, 0, 0, ti73, ti82, driver_device, 0, "Texas Instruments", "TI-73", MACHINE_NO_SOUND_HW )
+COMP( 1999, ti83p, 0, 0, ti83p, ti82, driver_device, 0, "Texas Instruments", "TI-83 Plus", MACHINE_NO_SOUND_HW )
+COMP( 2001, ti83pse, 0, 0, ti83pse, ti82, driver_device, 0, "Texas Instruments", "TI-83 Plus Silver Edition", MACHINE_NO_SOUND_HW )
+COMP( 2004, ti84p, 0, 0, ti84p, ti82, driver_device, 0, "Texas Instruments", "TI-84 Plus", MACHINE_NO_SOUND_HW )
+COMP( 2004, ti84pse, 0, 0, ti84pse, ti82, driver_device, 0, "Texas Instruments", "TI-84 Plus Silver Edition", MACHINE_NO_SOUND_HW )
diff --git a/src/mame/includes/ti85.h b/src/mame/includes/ti85.h
index 0e8a62e9b80..7f07288b66c 100644
--- a/src/mame/includes/ti85.h
+++ b/src/mame/includes/ti85.h
@@ -11,11 +11,11 @@
#pragma once
+#include "bus/ti8x/ti8x.h"
#include "imagedev/snapquik.h"
#include "machine/bankdev.h"
#include "machine/intelfsh.h"
#include "machine/nvram.h"
-#include "sound/spkrdev.h"
#include "video/t6a04.h"
@@ -56,22 +56,21 @@ class ti85_state : public driver_device
{
public:
ti85_state(const machine_config &mconfig, device_type type, const char *tag)
- : driver_device(mconfig, type, tag),
- m_maincpu(*this, "maincpu"),
- m_speaker(*this, "speaker"),
-// m_serial(*this, "tiserial"),
- m_nvram(*this, "nvram"),
- m_flash(*this, "flash"),
- m_membank1(*this, "membank1"),
- m_membank2(*this, "membank2"),
- m_membank3(*this, "membank3"),
- m_membank4(*this, "membank4")
- { }
+ : driver_device(mconfig, type, tag)
+ , m_maincpu(*this, "maincpu")
+ , m_link_port(*this, "linkport")
+ , m_nvram(*this, "nvram")
+ , m_flash(*this, "flash")
+ , m_membank1(*this, "membank1")
+ , m_membank2(*this, "membank2")
+ , m_membank3(*this, "membank3")
+ , m_membank4(*this, "membank4")
+ {
+ }
required_device<cpu_device> m_maincpu;
- optional_device<speaker_sound_device> m_speaker;
- //optional_device<> m_serial;
- optional_shared_ptr<uint8_t> m_nvram;
+ optional_device<ti8x_link_port_device> m_link_port;
+ optional_shared_ptr<uint8_t> m_nvram;
optional_device<intelfsh_device> m_flash;
optional_device<address_map_bank_device> m_membank1;
optional_device<address_map_bank_device> m_membank2;
@@ -104,8 +103,6 @@ public:
uint8_t m_ti81_port_7_data;
std::unique_ptr<uint8_t[]> m_ti8x_ram;
uint8_t m_PCR;
- uint8_t m_red_out;
- uint8_t m_white_out;
uint8_t m_ti8x_port2;
uint8_t m_ti83p_port4;
uint8_t m_ti83pse_port21;
@@ -150,24 +147,24 @@ public:
DECLARE_WRITE8_MEMBER(ti83p_port_0014_w);
DECLARE_WRITE8_MEMBER(ti83pse_port_0020_w);
DECLARE_WRITE8_MEMBER(ti83pse_port_0021_w);
- DECLARE_READ8_MEMBER( ti85_port_0002_r );
- DECLARE_READ8_MEMBER( ti85_port_0003_r );
- DECLARE_READ8_MEMBER( ti85_port_0004_r );
- DECLARE_READ8_MEMBER( ti85_port_0005_r );
- DECLARE_READ8_MEMBER( ti86_port_0006_r );
- DECLARE_READ8_MEMBER( ti82_port_0002_r );
- DECLARE_READ8_MEMBER( ti83_port_0002_r );
- DECLARE_READ8_MEMBER( ti83_port_0003_r );
- DECLARE_READ8_MEMBER( ti83p_port_0002_r );
- DECLARE_READ8_MEMBER( ti83p_port_0004_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0002_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0005_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0009_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0015_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0020_r );
- DECLARE_READ8_MEMBER( ti83pse_port_0021_r );
- DECLARE_READ8_MEMBER( ti84pse_port_0055_r );
- DECLARE_READ8_MEMBER( ti84pse_port_0056_r );
+ DECLARE_READ8_MEMBER(ti85_port_0002_r);
+ DECLARE_READ8_MEMBER(ti85_port_0003_r);
+ DECLARE_READ8_MEMBER(ti85_port_0004_r);
+ DECLARE_READ8_MEMBER(ti85_port_0005_r);
+ DECLARE_READ8_MEMBER(ti86_port_0006_r);
+ DECLARE_READ8_MEMBER(ti82_port_0002_r);
+ DECLARE_READ8_MEMBER(ti83_port_0002_r);
+ DECLARE_READ8_MEMBER(ti83_port_0003_r);
+ DECLARE_READ8_MEMBER(ti83p_port_0002_r);
+ DECLARE_READ8_MEMBER(ti83p_port_0004_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0002_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0005_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0009_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0015_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0020_r);
+ DECLARE_READ8_MEMBER(ti83pse_port_0021_r);
+ DECLARE_READ8_MEMBER(ti84pse_port_0055_r);
+ DECLARE_READ8_MEMBER(ti84pse_port_0056_r);
virtual void machine_start() override;
virtual void video_start() override;
DECLARE_PALETTE_INIT(ti85);
@@ -188,41 +185,41 @@ public:
//crystal timers
virtual void device_timer(emu_timer &timer, device_timer_id id, int param, void *ptr) override;
- void ti83pse_count( uint8_t timer, uint8_t data);
+ void ti83pse_count(uint8_t timer, uint8_t data);
emu_timer *m_crystal_timer1;
emu_timer *m_crystal_timer2;
emu_timer *m_crystal_timer3;
- DECLARE_READ8_MEMBER( ti83pse_ctimer1_setup_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer1_setup_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer1_loop_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer1_loop_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer1_count_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer1_count_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer2_setup_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer2_setup_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer2_loop_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer2_loop_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer2_count_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer2_count_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer3_setup_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer3_setup_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer3_loop_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer3_loop_w );
- DECLARE_READ8_MEMBER( ti83pse_ctimer3_count_r );
- DECLARE_WRITE8_MEMBER( ti83pse_ctimer3_count_w );
+ DECLARE_READ8_MEMBER(ti83pse_ctimer1_setup_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer1_setup_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer1_loop_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer1_loop_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer1_count_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer1_count_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer2_setup_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer2_setup_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer2_loop_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer2_loop_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer2_count_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer2_count_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer3_setup_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer3_setup_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer3_loop_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer3_loop_w);
+ DECLARE_READ8_MEMBER(ti83pse_ctimer3_count_r);
+ DECLARE_WRITE8_MEMBER(ti83pse_ctimer3_count_w);
void ti8x_update_bank(address_space &space, uint8_t bank, uint8_t *base, uint8_t page, bool is_ram);
- void update_ti85_memory ();
- void update_ti83p_memory ();
- void update_ti83pse_memory ();
- void update_ti86_memory ();
- void ti8x_snapshot_setup_registers (uint8_t * data);
- void ti85_setup_snapshot (uint8_t * data);
- void ti86_setup_snapshot (uint8_t * data);
- DECLARE_SNAPSHOT_LOAD_MEMBER( ti8x );
- DECLARE_DIRECT_UPDATE_MEMBER( ti83p_direct_update_handler );
+ void update_ti85_memory();
+ void update_ti83p_memory();
+ void update_ti83pse_memory();
+ void update_ti86_memory();
+ void ti8x_snapshot_setup_registers(uint8_t *data);
+ void ti85_setup_snapshot(uint8_t *data);
+ void ti86_setup_snapshot(uint8_t *data);
+ DECLARE_SNAPSHOT_LOAD_MEMBER(ti8x);
+ DECLARE_DIRECT_UPDATE_MEMBER(ti83p_direct_update_handler);
ti83pse_timer m_ctimer[3];
diff --git a/src/mame/machine/ti85.cpp b/src/mame/machine/ti85.cpp
index 654244bc102..678b2783894 100644
--- a/src/mame/machine/ti85.cpp
+++ b/src/mame/machine/ti85.cpp
@@ -265,8 +265,6 @@ void ti85_state::machine_start()
MACHINE_RESET_MEMBER(ti85_state,ti85)
{
- m_red_out = 0x00;
- m_white_out = 0x00;
m_PCR = 0xc0;
}
@@ -286,9 +284,7 @@ DIRECT_UPDATE_MEMBER(ti85_state::ti83p_direct_update_handler)
MACHINE_RESET_MEMBER(ti85_state,ti83p)
{
- m_red_out = 0x00;
- m_white_out = 0x00;
- m_PCR = 0xc0;
+ m_PCR = 0x00;
m_ti8x_memory_page_1 = 0;
@@ -520,13 +516,19 @@ READ8_MEMBER(ti85_state::ti85_port_0006_r)
READ8_MEMBER(ti85_state::ti8x_serial_r)
{
- //ti85_update_serial(m_serial);
- return (m_white_out<<3)
- | (m_red_out<<2)
- //| ((ti85serial_white_in(m_serial,0)&(1-m_white_out))<<1)
- //| (ti85serial_red_in(m_serial,0)&(1-m_red_out))
- | 0x03 // no link cable
- | m_PCR;
+ // 7: unknown (ROM always sets to 1)
+ // 6: unknown (ROM always sets to 1)
+ // 5: enable ring output
+ // 4: enable tip output
+ // 3: ring output
+ // 2: tip output
+ // 1: ring input
+ // 0: tip input
+ // If the calculator is driving a line low it will always read low
+
+ uint8_t const tip_in((!m_link_port || m_link_port->tip_r()) ? 0x03 : 0x02);
+ uint8_t const ring_in((!m_link_port || m_link_port->ring_r()) ? 0x03 : 0x01);
+ return (~((m_PCR >> 2) & (m_PCR >> 4)) & tip_in & ring_in) | (m_PCR & 0xfc);
}
READ8_MEMBER(ti85_state::ti82_port_0002_r )
@@ -575,13 +577,19 @@ READ8_MEMBER(ti85_state::ti83_port_0003_r )
READ8_MEMBER(ti85_state::ti8x_plus_serial_r)
{
- //ti85_update_serial(m_serial);
- return (m_white_out<<3)
- | (m_red_out<<2)
- //| ((ti85serial_white_in(m_serial,0)&(1-m_white_out))<<1)
- //| (ti85serial_red_in(m_serial,0)&(1-m_red_out))
- | 0x03 // no link cable
- | m_PCR;
+ // 7: unknown
+ // 6: byte receive in progress (TI-83+ only)
+ // 5: ring output
+ // 4: tip output
+ // 3: received byte ready (cleared by reading port 0x05, TI-83+ only)
+ // 2: enable byte receive (TI-83+ only)
+ // 1: ring input
+ // 0: tip input
+ // Note that tip/ring outputs are inverted by an NPN transistor
+
+ uint8_t const tip_in((!m_link_port || m_link_port->tip_r()) ? 0x03 : 0x02);
+ uint8_t const ring_in((!m_link_port || m_link_port->ring_r()) ? 0x03 : 0x01);
+ return (~(m_PCR >> 4) & tip_in & ring_in) | (m_PCR & 0xfc);
}
READ8_MEMBER(ti85_state::ti83p_port_0002_r )
@@ -682,13 +690,23 @@ WRITE8_MEMBER(ti85_state::ti85_port_0006_w)
WRITE8_MEMBER(ti85_state::ti8x_serial_w)
{
- m_speaker->level_w(BIT(data, 2) | BIT(data, 3));
- m_red_out = BIT(data, 2);
- m_white_out = BIT(data, 3);
- //ti85serial_red_out( m_serial, 0, m_red_out );
- //ti85serial_white_out( m_serial, 0, m_white_out );
- //ti85_update_serial(m_serial);
- m_PCR = data & 0xf0;
+ // 7: unknown (ROM always sets to 1)
+ // 6: unknown (ROM always sets to 1)
+ // 5: enable ring output
+ // 4: enable tip output
+ // 3: ring output
+ // 2: tip output
+ // 1: unused
+ // 0: unused
+ // Note that tip/ring outputs are inverted by an NPN transistor
+ // In practice, the ROM only uses values 0xc0, 0xd4 and 0xe8
+
+ m_PCR = data & 0xfc;
+ if (m_link_port)
+ {
+ m_link_port->tip_w(BIT(~data, 2) | BIT(~data, 4));
+ m_link_port->ring_w(BIT(~data, 3) | BIT(~data, 5));
+ }
}
WRITE8_MEMBER(ti85_state::ti86_port_0005_w)
@@ -725,22 +743,31 @@ WRITE8_MEMBER(ti85_state::ti83_port_0002_w)
WRITE8_MEMBER(ti85_state::ti83_port_0003_w)
{
- if (m_LCD_status && !(data&0x08)) m_timer_interrupt_mask = 0;
- m_ON_interrupt_mask = data&0x01;
- //m_timer_interrupt_mask = data&0x04;
- m_LCD_mask = data&0x02;
- m_LCD_status = data&0x08;
+ if (m_LCD_status && !(data&0x08)) m_timer_interrupt_mask = 0;
+ m_ON_interrupt_mask = data&0x01;
+ //m_timer_interrupt_mask = data&0x04;
+ m_LCD_mask = data&0x02;
+ m_LCD_status = data&0x08;
}
WRITE8_MEMBER(ti85_state::ti8x_plus_serial_w)
{
- m_speaker->level_w(BIT(data, 0) | BIT(data, 1));
- m_red_out = BIT(data, 0);
- m_white_out = BIT(data, 1);
- //ti85serial_red_out( m_serial, 0, m_red_out );
- //ti85serial_white_out( m_serial, 0, m_white_out );
- //ti85_update_serial(m_serial);
- m_PCR = data & 0xf0;
+ // 7: unknown
+ // 6: unknown
+ // 5: unknown
+ // 4: unknown
+ // 3: unknown
+ // 2: enable byte receive (TI-83+ only)
+ // 1: ring output
+ // 0: tip output
+ // Note that tip/ring outputs are inverted by an NPN transistor
+
+ m_PCR = (m_PCR & 0xc8) | (data & 0x04) | ((data << 4) & 0x30);
+ if (m_link_port)
+ {
+ m_link_port->tip_w(BIT(~data, 2) | BIT(~data, 4));
+ m_link_port->ring_w(BIT(~data, 3) | BIT(~data, 5));
+ }
}
WRITE8_MEMBER(ti85_state::ti83pse_int_ack_w)