summaryrefslogtreecommitdiffstatshomepage
path: root/src/devices/bus/ti99/hexbus/hexbus.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/devices/bus/ti99/hexbus/hexbus.cpp')
-rw-r--r--src/devices/bus/ti99/hexbus/hexbus.cpp282
1 files changed, 282 insertions, 0 deletions
diff --git a/src/devices/bus/ti99/hexbus/hexbus.cpp b/src/devices/bus/ti99/hexbus/hexbus.cpp
new file mode 100644
index 00000000000..794d1d344d3
--- /dev/null
+++ b/src/devices/bus/ti99/hexbus/hexbus.cpp
@@ -0,0 +1,282 @@
+// license:LGPL-2.1+
+// copyright-holders:Michael Zapf
+/****************************************************************************
+
+ =========== Hexbus peripheral bus ===========
+
+ The Hexbus is a 4-bit peripheral bus with master/slave coordination. Bytes
+ are written over the bus in two passes. Hexbus was the designated standard
+ peripheral bus for TI computers before TI left the home computer market.
+
+ The Hexbus was also named IPB = Intelligent Peripheral Bus [1]
+
+ Existing devices are floppy drive, RS232 serial adapter, and
+ a "Wafertape" drive (kind of tape streamer)
+
+ Hexbus connector (console)
+ +---+---+---+---+
+ | 4 | 3 | 2 | 1 | 4 = L; 3 = BAV*; 2 = ADB1; 1 = ADB0
+ +---+---+---+---+
+ | 8 | 7 | 6 | 5 | 8 = ADB3; 7 = ADB2; 6 = nc; 5 = HSK*
+ +---+---+---+---+
+
+ ADBx = Hexbus data bit X (x=0..3)
+ HSK* = Handshake
+ BAV* = Bus available (0=yes)
+
+ Theory of operation
+ -------------------
+ The bus connects all devices in a daisy chain. The lines are inactive high
+ and pulled down by any device that sets them to 0.
+
+ HSK* is a synchronization line for transmitting single bytes.
+ BAV* is a synchronization line for complete request-response pairs
+
+ Before a byte can be sent, the sender must check the BAV* line. When it is
+ inactive (1), it pulls it down, and then starts transmitting. The line
+ is raised again when the response has been fully received.
+
+ For transmitting a byte, the HSK* line must first be pulled down by the
+ sender. Then, the lower nibble is transmitted first, and the sender
+ releases the HSK* line. Every receiver that has completely received the
+ nibble and is ready for the next one releases the HSK* line. The sender
+ must check the HSK* line until it goes high again (which means that the
+ slowest receiver has got the nibble). This is repeated for the high nibble.
+
+ When the BAV* signal is asserted (0), the HSK* line must not be high for
+ more than 20 ms, or a bus timeout occurs.
+
+ The device address is transmitted as part of the request header. All
+ devices with a non-matching device code must ignore the rest of the
+ message until BAV* goes inactive (1) again.
+
+ If there is no matching device, HSK* will remain 1 after the end of the
+ master's request, and after 20ms, a timeout will occur. Declaring a timeout
+ is a matter of the devices, not of the bus.
+
+ Message format
+ --------------
+
+ +-------------+-------------+-------------+-------------+
+ | Device Code | Command code| LogUnitNum | RecNum LSB |
+ +-------------+-------------+-------------+-------------+
+ | RecNum MSB | Buflen LSB | Buflen MSB | DataLen LSB |
+ +-------------+-------------+-------------+-------------+
+ | DataLen MSB | |
+ +-------------+ |
+ | Data ... (not padded) |
+ | |
+ | |
+ +-------------+-------------+-------------+-------------+
+
+ Device codes
+ ------------
+
+ 0 - all devices (but none will respond, forcing a timeout)
+ 1-8 - Tape mass storage
+ 10-17 - Printer / plotter
+ 20-27 - RS-232 interface
+ 30-37 - TV interface (color)
+ 40-47 - TV interface (B/W)
+ 50-57 - Centronics interface
+ 60-67 - Calculator in slave mode
+ 70-77 - Modem
+ 80-87 - GPIB interface (?)
+ 90-97 - Bar code reader
+ 100-107 - Floppy disk drive
+
+ Usage in MAME
+ -------------
+
+ Single device usage:
+ mame <driver> -hexbus <device>
+
+ Multiple device usage:
+ mame <driver> -hexbus chain -hexbus:chain:1 <device> ... -hexbus:chain:4 <device>
+
+ We currently assume a maximum length of 4 devices which can be increased
+ if desired. The chain positions should be used starting from 1 with no
+ gaps, but this is not enforced.
+
+ References
+ ----------
+
+ [1] Intelligent Peripheral Bus: Structure, Timing, and Protocol Specification
+ Texas Instruments Inc., Consumer Products Group, Calculator Division,
+ 7/3/82, Revision 2.8
+
+ Michael Zapf
+ June 2017
+
+*****************************************************************************/
+#include "emu.h"
+#include "hexbus.h"
+
+// Devices
+#include "hx5102.h"
+
+// Hexbus instance
+DEFINE_DEVICE_TYPE_NS(TI_HEXBUS, bus::ti99::hexbus, hexbus_device, "ti_hexbus", "Hexbus")
+
+// Hexbus daisy chain
+DEFINE_DEVICE_TYPE_NS(TI_HEXBUS_CHAIN, bus::ti99::hexbus, hexbus_chain_device, "ti_hexbus_chain", "Hexbus chain")
+
+// Single slot of the Hexbus
+DEFINE_DEVICE_TYPE_NS(TI_HEXBUS_SLOT, bus::ti99::hexbus, hexbus_slot_device, "ti_hexbus_slot", "Hexbus position")
+
+namespace bus { namespace ti99 { namespace hexbus {
+
+enum
+{
+ NOTCONN = -1
+};
+
+hexbus_device::hexbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, TI_HEXBUS, tag, owner, clock),
+ device_slot_interface(mconfig, *this),
+ m_master(nullptr),
+ m_slave(nullptr)
+{
+}
+
+void hexbus_device::device_start()
+{
+}
+
+void hexbus_device::device_config_complete()
+{
+ m_slave = static_cast<hexbus_attached_device*>(subdevices().first());
+ if (m_slave != nullptr)
+ m_slave->set_hexbus(this);
+}
+
+void hexbus_device::send()
+{
+ uint8_t sum = m_master->get_value();
+ if (m_slave != nullptr)
+ {
+ sum &= m_slave->get_value();
+ m_slave->receive(sum);
+ }
+ m_master->receive(sum);
+}
+
+// ------------------------------------------------------------------------
+
+hexbus_chain_device::hexbus_chain_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) :
+ hexbus_attached_device(mconfig, TI_HEXBUS_CHAIN, tag, owner, clock)
+{
+}
+
+uint8_t hexbus_chain_device::get_value()
+{
+ uint8_t sum = 0xff;
+
+ // Do the wired AND
+ for (device_t &child : subdevices())
+ {
+ hexbus_slot_device* slot = downcast<hexbus_slot_device *>(&child);
+ sum &= slot->get_value();
+ }
+
+ return sum;
+}
+
+void hexbus_chain_device::receive(uint8_t value)
+{
+ // Propagate
+ for (device_t &child : subdevices())
+ {
+ hexbus_slot_device* slot = downcast<hexbus_slot_device *>(&child);
+ slot->receive(value);
+ }
+}
+
+void hexbus_chain_device::device_start()
+{
+}
+
+SLOT_INTERFACE_START( ti_hexbus_chain_slot )
+// SLOT_INTERFACE("hx5102", TI_HX5102) // not an option yet
+SLOT_INTERFACE_END
+
+MACHINE_CONFIG_MEMBER( hexbus_chain_device::device_add_mconfig )
+ MCFG_HEXBUS_SLOT_ADD( "1", ti_hexbus_chain_slot )
+ MCFG_HEXBUS_SLOT_ADD( "2", ti_hexbus_chain_slot )
+ MCFG_HEXBUS_SLOT_ADD( "3", ti_hexbus_chain_slot )
+ MCFG_HEXBUS_SLOT_ADD( "4", ti_hexbus_chain_slot )
+MACHINE_CONFIG_END
+
+// ------------------------------------------------------------------------
+
+int hexbus_slot_device::get_index_from_tagname()
+{
+ const char *mytag = tag();
+ int maxlen = strlen(mytag);
+ int i;
+ for (i=maxlen-1; i >=0; i--)
+ if (mytag[i] < 48 || mytag[i] > 57) break;
+
+ return atoi(mytag+i+1);
+}
+
+hexbus_slot_device::hexbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock)
+ : device_t(mconfig, TI_HEXBUS_SLOT, tag, owner, clock),
+ device_slot_interface(mconfig, *this),
+ m_hexbdev(nullptr)
+{
+}
+
+/* Called from the Hexbus instance */
+int hexbus_slot_device::get_index()
+{
+ if (m_hexbdev == nullptr) return NOTCONN;
+ return get_index_from_tagname();
+}
+
+uint8_t hexbus_slot_device::get_value()
+{
+ return (m_hexbdev != nullptr)? m_hexbdev->get_value() : 0xff;
+}
+
+void hexbus_slot_device::receive(uint8_t value)
+{
+ if (m_hexbdev != nullptr)
+ m_hexbdev->receive(value);
+}
+
+void hexbus_slot_device::device_start()
+{
+}
+
+void hexbus_slot_device::device_config_complete()
+{
+ m_hexbus = dynamic_cast<hexbus_device*>(owner());
+ m_hexbdev = downcast<hexbus_attached_device *>(subdevices().first());
+}
+
+// ------------------------------------------------------------------------
+
+hexbus_attached_device::hexbus_attached_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock) :
+ device_t(mconfig, type, tag, owner, clock),
+ device_slot_card_interface(mconfig, *this)
+{
+}
+
+void hexbus_attached_device::device_start()
+{
+}
+
+void hexbus_attached_device::hexbus_send(uint8_t value)
+{
+ m_value = value;
+ m_hexbus->send();
+}
+
+} } } // end namespace bus::ti99::hexbus
+
+SLOT_INTERFACE_START( ti_hexbus_conn )
+// SLOT_INTERFACE("hx5102", TI_HX5102) // not an option yet
+ SLOT_INTERFACE("chain", TI_HEXBUS_CHAIN)
+SLOT_INTERFACE_END
+