summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ti8x/ti8x.h
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 /src/devices/bus/ti8x/ti8x.h
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
Diffstat (limited to 'src/devices/bus/ti8x/ti8x.h')
-rw-r--r--src/devices/bus/ti8x/ti8x.h213
1 files changed, 213 insertions, 0 deletions
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