diff options
author | Michael Zapf <Michael.Zapf@mizapf.de> | 2017-06-25 18:11:48 +0200 |
---|---|---|
committer | Michael Zapf <Michael.Zapf@mizapf.de> | 2017-06-25 18:12:34 +0200 |
commit | c318e49ab277001120e667876f3b21da7539a047 (patch) | |
tree | f93767d761335006b8b9bb67a7870b280a2a37de | |
parent | d80ae34c064b9e2e592235eaaaab07fbf6568dec (diff) |
ti99: Changed Hexbus chaining
-rw-r--r-- | src/devices/bus/ti99/hexbus/hexbus.cpp | 236 | ||||
-rw-r--r-- | src/devices/bus/ti99/hexbus/hexbus.h | 119 | ||||
-rw-r--r-- | src/devices/bus/ti99/hexbus/hx5102.cpp | 8 | ||||
-rw-r--r-- | src/devices/bus/ti99/hexbus/hx5102.h | 5 | ||||
-rw-r--r-- | src/devices/bus/ti99/internal/998board.cpp | 17 | ||||
-rw-r--r-- | src/devices/bus/ti99/internal/998board.h | 6 |
6 files changed, 206 insertions, 185 deletions
diff --git a/src/devices/bus/ti99/hexbus/hexbus.cpp b/src/devices/bus/ti99/hexbus/hexbus.cpp index 92251f423b2..d8c315057c7 100644 --- a/src/devices/bus/ti99/hexbus/hexbus.cpp +++ b/src/devices/bus/ti99/hexbus/hexbus.cpp @@ -88,15 +88,42 @@ 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> + Usually the device offers an own hexbus socket, so we can chain devices: - 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. + mame <driver> -hexbus <device1> -hexbus:<device1>:hexbus <device2> ... + + The direction towards the console is named "inbound" in the implementation, + while the direction towards the end of the chain is named "outbound". + + Implementation + -------------- + + All lines (ADB0-3, HSK*, BAV*) are pull-down outputs with open collectors, + and at the same time also inputs. + + The challenge, compared to other daisy-chained buses, is that the Hexbus + is nondirectional. Writing on the bus is sensed by all devices in either + direction. Also, reading from the bus is the product of all active output + buffers. With no active device, the bus lines are pulled high. + + Every Hexbus device has an interface "device_ti_hexbus_interface" which + allows it to plug into a preceding Hexbus socket. + + Since the signal propagation is the same for all devices, there is a + parent class "hexbus_chained_device" that calculates the current levels + for all bus lines by fetching all values from the attached devices, ANDing + them, and propagating them again. This must be done in both directions. + + Reading is simpler, because we assume that changes can only be done by + writing to the bus. + + The "hexbus_chained_device" implements the "device_ti_hexbus_interface" + and holds references to up to two Hexbus instances, one for each direction. + The computer console will not offer an inbound Hexbus connection, only + an outbound one, and possibly there is some device that must be connected + at the end, without further outbound connections. References ---------- @@ -118,163 +145,162 @@ // 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) + m_next_dev(nullptr) { } void hexbus_device::device_start() { + m_next_dev = dynamic_cast<device_ti_hexbus_interface *>(get_card_device()); } -void hexbus_device::device_config_complete() +/* + Write to the hexbus. If the write operation comes from the plugged device, + this is an inbound write; otherwise, the write comes from the owner of the + hexbus connector, which means an outbound write. +*/ +void hexbus_device::write(int dir, uint8_t data) { - m_slave = dynamic_cast<device_ti_hexbus_interface*>(subdevices().first()); - if (m_slave != nullptr) - m_slave->set_hexbus(this); + if (dir == INBOUND) + m_chain_element->bus_write(INBOUND, data); + else + { + // Is there another Hexbus device? + if (m_next_dev != nullptr) + m_next_dev->bus_write(OUTBOUND, data); + } } -void hexbus_device::send() +/* + Read from the hexbus. If the read operation comes from the plugged device, + this is an inbound read; otherwise, the read comes from the owner of the + hexbus connector, which means an outbound read. +*/ +uint8_t hexbus_device::read(int dir) { - uint8_t sum = m_master->get_value(); - if (m_slave != nullptr) + // Default is: all lines pulled up + uint8_t value = 0xff; + + if (dir == INBOUND) + value = m_chain_element->bus_read(INBOUND); + else { - sum &= m_slave->get_value(); - m_slave->receive(sum); + // Is there another Hexbus device? + if (m_next_dev != nullptr) + value = m_next_dev->bus_read(OUTBOUND); } - m_master->receive(sum); + return value; } // ------------------------------------------------------------------------ -hexbus_chain_device::hexbus_chain_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, TI_HEXBUS_CHAIN, tag, owner, clock), +hexbus_chained_device::hexbus_chained_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_ti_hexbus_interface(mconfig, *this) { + m_hexbus_inbound = dynamic_cast<hexbus_device *>(owner); + m_myvalue = 0xff; } -uint8_t hexbus_chain_device::get_value() +void hexbus_chained_device::device_start() { - uint8_t sum = 0xff; + m_hexbus_outbound = static_cast<hexbus_device*>(subdevice("hexbus")); - // Do the wired AND - for (device_t &child : subdevices()) - { - hexbus_slot_device* slot = downcast<hexbus_slot_device *>(&child); - sum &= slot->get_value(); - } - - return sum; + // Establish callback for inbound propagations + m_hexbus_outbound->set_chain_element(this); } -void hexbus_chain_device::receive(uint8_t value) +/* + Called from the Hexbus user, that is, the device that subclasses + hexbus_chained_device, like the HX5102 +*/ +void hexbus_chained_device::hexbus_write(uint8_t data) { - // Propagate - for (device_t &child : subdevices()) - { - hexbus_slot_device* slot = downcast<hexbus_slot_device *>(&child); - slot->receive(value); - } -} + m_myvalue = data; -void hexbus_chain_device::device_start() -{ -} + uint8_t inbound_value = 0xff; + uint8_t outbound_value = 0xff; -SLOT_INTERFACE_START( ti_hexbus_chain_slot ) -// SLOT_INTERFACE("hx5102", TI_HX5102) // not an option yet -SLOT_INTERFACE_END + // Determine the current bus level from the values of the + // other devices left and right from us + if (m_hexbus_inbound != nullptr) + inbound_value = m_hexbus_inbound->read(INBOUND); -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 + if (m_hexbus_outbound != nullptr) + outbound_value = m_hexbus_outbound->read(OUTBOUND); -// ------------------------------------------------------------------------ + // What is the new bus level? + uint8_t newvalue = inbound_value & outbound_value & m_myvalue; -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; + // If it changed, propagate to both directions. + if (newvalue != m_current_bus_value) + { + hexbus_value_changed(newvalue); + m_current_bus_value = newvalue; - return atoi(mytag+i+1); -} + if (m_hexbus_inbound != nullptr) + m_hexbus_inbound->write(INBOUND, m_current_bus_value); -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) -{ + if (m_hexbus_outbound != nullptr) + m_hexbus_outbound->write(OUTBOUND, m_current_bus_value); + } } -/* Called from the Hexbus instance */ -int hexbus_slot_device::get_index() +/* + Called from the Hexbus user, that is, the device that subclasses + hexbus_chained_device, like the HX5102 +*/ +uint8_t hexbus_chained_device::hexbus_read() { - if (m_hexbdev == nullptr) return NOTCONN; - return get_index_from_tagname(); + return m_current_bus_value; } -uint8_t hexbus_slot_device::get_value() +/* + Called from another hexbus device on the bus +*/ +uint8_t hexbus_chained_device::bus_read(int dir) { - return (m_hexbdev != nullptr)? m_hexbdev->get_value() : 0xff; -} + uint8_t tmpvalue = 0xff; + hexbus_device* hexbuscont = (dir == INBOUND)? m_hexbus_inbound : m_hexbus_outbound; -void hexbus_slot_device::receive(uint8_t value) -{ - if (m_hexbdev != nullptr) - m_hexbdev->receive(value); -} + if (hexbuscont != nullptr) + tmpvalue = hexbuscont->read(dir); -void hexbus_slot_device::device_start() -{ + return m_myvalue & tmpvalue; } -void hexbus_slot_device::device_config_complete() +/* + Called from another hexbus device on the bus +*/ +void hexbus_chained_device::bus_write(int dir, uint8_t data) { - m_hexbus = dynamic_cast<hexbus_device*>(owner()); - m_hexbdev = dynamic_cast<device_ti_hexbus_interface *>(subdevices().first()); -} + hexbus_device* hexbuscont = (dir == INBOUND)? m_hexbus_inbound : m_hexbus_outbound; -// ------------------------------------------------------------------------ + // Notify device + if (data != m_current_bus_value) + hexbus_value_changed(data); -void device_ti_hexbus_interface::interface_config_complete() -{ - m_hexbus = dynamic_cast<hexbus_device*>(device().owner()); -} + m_current_bus_value = data; -void device_ti_hexbus_interface::hexbus_send(uint8_t value) -{ - m_value = value; - m_hexbus->send(); + // Propagate + if (hexbuscont != nullptr) + hexbuscont->write(dir, data); } +MACHINE_CONFIG_MEMBER( hexbus_chained_device::device_add_mconfig ) + MCFG_HEXBUS_ADD("hexbus") +MACHINE_CONFIG_END + // ------------------------------------------------------------------------ } } } // 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("hx5102", TI_HX5102) SLOT_INTERFACE_END diff --git a/src/devices/bus/ti99/hexbus/hexbus.h b/src/devices/bus/ti99/hexbus/hexbus.h index 6718a79768f..5c9f62274c2 100644 --- a/src/devices/bus/ti99/hexbus/hexbus.h +++ b/src/devices/bus/ti99/hexbus/hexbus.h @@ -21,119 +21,104 @@ namespace bus { namespace ti99 { namespace hexbus { enum { - MAX_DEVICES = 4 + INBOUND = 0, + OUTBOUND = 1 }; class hexbus_device; +class hexbus_chained_device; /******************************************************************** - Common parent class of all devices attached to the hexbus port + Interface for a device that connects to the Hexbus ********************************************************************/ + class device_ti_hexbus_interface : public device_slot_card_interface { - friend class hexbus_device; - friend class hexbus_slot_device; +public: + virtual uint8_t bus_read(int dir) =0; + virtual void bus_write(int dir, uint8_t data) =0; protected: - using device_slot_card_interface::device_slot_card_interface; - void hexbus_send(uint8_t value); - uint8_t hexbus_receive() { return m_busvalue; } - - virtual void receive(uint8_t value) { m_busvalue = value; } - virtual uint8_t get_value() { return m_value; } - - virtual void interface_config_complete() override; - hexbus_device *m_hexbus; // Link to the Hexbus - -private: - void set_hexbus(hexbus_device* hexbus) { m_hexbus = hexbus; } - uint8_t m_value; - uint8_t m_busvalue; + device_ti_hexbus_interface(const machine_config &mconfig, device_t &device) : + device_slot_card_interface(mconfig, device) { } }; -// ------------------------------------------------------------------------ - -class hexbus_device : public device_t, public device_slot_interface +/******************************************************************** + Common parent class of all devices attached to the hexbus port + This class implements the signal propagation in both directions +********************************************************************/ +class hexbus_chained_device : public device_t, public device_ti_hexbus_interface { - friend class device_ti_hexbus_interface; + friend class hexbus_device; public: - hexbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - void connect_master(device_ti_hexbus_interface *masterdev) { m_master = masterdev; } + hexbus_chained_device(const machine_config &mconfig, device_type type, const char *tag, device_t *owner, uint32_t clock); + virtual void device_start() override; protected: - void device_start() override; - void device_config_complete() override; + virtual void device_add_mconfig(machine_config &config) override; -private: - device_ti_hexbus_interface *m_master; - device_ti_hexbus_interface *m_slave; + // Link to the inbound Hexbus (if not null, see Oso chip) + hexbus_device *m_hexbus_inbound; - // Called from a slot, samples all values from the devices, and propagates - // the logical product to all connected devices - void send(); -}; + // Link to the outbound Hexbus (if not null) + hexbus_device *m_hexbus_outbound; + // Common AND of all private values + uint8_t m_current_bus_value; -// ------------------------------------------------------------------------ + // From device_ti_hexbus_interface + virtual uint8_t bus_read(int dir) override; + virtual void bus_write(int dir, uint8_t data) override; -class hexbus_chain_device : public device_t, public device_ti_hexbus_interface -{ -public: - hexbus_chain_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - void device_add_mconfig(machine_config &config) override; + // Methods to be used from subclasses + void hexbus_write(uint8_t data); + uint8_t hexbus_read(); + + // For interrupts + virtual void hexbus_value_changed(uint8_t data) { }; private: - void device_start() override; - void receive(uint8_t value) override; - uint8_t get_value() override; + uint8_t m_myvalue; }; // ------------------------------------------------------------------------ -class hexbus_slot_device : public device_t, public device_slot_interface -{ - friend class hexbus_attached_device; - friend class hexbus_chain_device; +/******************************************************************** + Connector to the Hexbus, offers a slot for Hexbus-chained devices +********************************************************************/ +class hexbus_device : public device_t, public device_slot_interface +{ public: - hexbus_slot_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); + hexbus_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - // Called from the hexbus (direction to attached device) - void receive(uint8_t value); + // Used to establish the reverse link (inbound) + void set_chain_element(hexbus_chained_device* chain) { m_chain_element = chain; } - // Called from the hexbus - uint8_t get_value(); + // Read and write operations on the bus + uint8_t read(int dir); + void write(int dir, uint8_t data); protected: void device_start() override; - void device_config_complete() override; - - // Called from the Hexbus instance - int get_index(); + device_ti_hexbus_interface *m_next_dev; private: - int get_index_from_tagname(); - - device_ti_hexbus_interface* m_hexbdev; - hexbus_device* m_hexbus; + // owner of this Hexbus socket; may be the owning component or another + // component in the device hierarchy (see TI-99/8 where it belongs to Oso, + // but the Hexbus is a subdevice of the driver itself) + hexbus_chained_device* m_chain_element; }; - #define MCFG_HEXBUS_ADD( _tag ) \ MCFG_DEVICE_ADD(_tag, TI_HEXBUS, 0) \ MCFG_DEVICE_SLOT_INTERFACE( ti_hexbus_conn, nullptr, false) -#define MCFG_HEXBUS_SLOT_ADD(_tag, _slot_intf) \ - MCFG_DEVICE_ADD(_tag, TI_HEXBUS_SLOT, 0) \ - MCFG_DEVICE_SLOT_INTERFACE(_slot_intf, nullptr, false) - } } } // end namespace bus::ti99::hexbus SLOT_INTERFACE_EXTERN( ti_hexbus_conn ); -DECLARE_DEVICE_TYPE_NS(TI_HEXBUS, bus::ti99::hexbus, hexbus_device) -DECLARE_DEVICE_TYPE_NS(TI_HEXBUS_CHAIN, bus::ti99::hexbus, hexbus_chain_device) -DECLARE_DEVICE_TYPE_NS(TI_HEXBUS_SLOT, bus::ti99::hexbus, hexbus_slot_device) +DECLARE_DEVICE_TYPE_NS(TI_HEXBUS, bus::ti99::hexbus, hexbus_device) #endif // MAME_BUS_TI99_HEXBUS_HEXBUS_H diff --git a/src/devices/bus/ti99/hexbus/hx5102.cpp b/src/devices/bus/ti99/hexbus/hx5102.cpp index e95c31c8d1e..e1bfb5fcbfa 100644 --- a/src/devices/bus/ti99/hexbus/hx5102.cpp +++ b/src/devices/bus/ti99/hexbus/hx5102.cpp @@ -15,18 +15,20 @@ #include "emu.h" #include "hx5102.h" +#define TRACE_HEXBUS 0 + DEFINE_DEVICE_TYPE_NS(TI_HX5102, bus::ti99::hexbus, hx5102_device, "ti_hx5102", "TI Hexbus Floppy") namespace bus { namespace ti99 { namespace hexbus { hx5102_device::hx5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock): - device_t(mconfig, TI_HX5102, tag, owner, clock), - device_ti_hexbus_interface(mconfig, *this) + hexbus_chained_device(mconfig, TI_HX5102, tag, owner, clock) { } -void hx5102_device::device_start() +void hx5102_device::hexbus_value_changed(uint8_t data) { + if (TRACE_HEXBUS) logerror("Hexbus value changed to %02x\n", data); } } } } // end namespace bus::ti99::hexbus diff --git a/src/devices/bus/ti99/hexbus/hx5102.h b/src/devices/bus/ti99/hexbus/hx5102.h index 6eb2837ad1b..c384305a9fd 100644 --- a/src/devices/bus/ti99/hexbus/hx5102.h +++ b/src/devices/bus/ti99/hexbus/hx5102.h @@ -21,12 +21,11 @@ namespace bus { namespace ti99 { namespace hexbus { -class hx5102_device : public device_t, public device_ti_hexbus_interface +class hx5102_device : public hexbus_chained_device { public: hx5102_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); - - void device_start() override; + void hexbus_value_changed(uint8_t data) override; }; } } } // end namespace bus::ti99::hexbus diff --git a/src/devices/bus/ti99/internal/998board.cpp b/src/devices/bus/ti99/internal/998board.cpp index 28e01049671..a89353051e9 100644 --- a/src/devices/bus/ti99/internal/998board.cpp +++ b/src/devices/bus/ti99/internal/998board.cpp @@ -2228,13 +2228,14 @@ enum }; oso_device::oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock) : - device_t(mconfig, TI99_OSO, tag, owner, clock), - bus::ti99::hexbus::device_ti_hexbus_interface(mconfig, *this), + bus::ti99::hexbus::hexbus_chained_device(mconfig, TI99_OSO, tag, owner, clock), m_data(0), m_status(0), m_control(0), m_xmit(0) { + m_hexbus_inbound = nullptr; + m_hexbus_outbound = nullptr; } READ8_MEMBER( oso_device::read ) @@ -2276,6 +2277,7 @@ WRITE8_MEMBER( oso_device::write ) // write 5FF8: write transmit register if (TRACE_OSO) logerror("Write transmit register %02x\n", data); m_xmit = data; + hexbus_write(data); // We set the status register directly in order to prevent lock-ups // until we have a complete Hexbus implementation m_status |= HSKWT; @@ -2292,13 +2294,20 @@ WRITE8_MEMBER( oso_device::write ) } } +void oso_device::hexbus_value_changed(uint8_t data) +{ + if (TRACE_OSO) logerror("Hexbus value changed to %02x\n", data); +} + void oso_device::device_start() { logerror("Starting\n"); m_status = m_xmit = m_control = m_data = 0; - m_hexbus = downcast<bus::ti99::hexbus::hexbus_device*>(machine().device(TI_HEXBUS_TAG)); - m_hexbus->connect_master(this); + m_hexbus_outbound = dynamic_cast<bus::ti99::hexbus::hexbus_device*>(machine().device(TI_HEXBUS_TAG)); + + // Establish callback + m_hexbus_outbound->set_chain_element(this); save_item(NAME(m_data)); save_item(NAME(m_status)); diff --git a/src/devices/bus/ti99/internal/998board.h b/src/devices/bus/ti99/internal/998board.h index 45b154a590b..a0d09062a54 100644 --- a/src/devices/bus/ti99/internal/998board.h +++ b/src/devices/bus/ti99/internal/998board.h @@ -422,7 +422,7 @@ private: /* Custom chip: OSO */ -class oso_device : public device_t, public bus::ti99::hexbus::device_ti_hexbus_interface +class oso_device : public bus::ti99::hexbus::hexbus_chained_device { public: oso_device(const machine_config &mconfig, const char *tag, device_t *owner, uint32_t clock); @@ -430,13 +430,13 @@ public: DECLARE_WRITE8_MEMBER( write ); void device_start() override; + void hexbus_value_changed(uint8_t data) override; + private: uint8_t m_data; uint8_t m_status; uint8_t m_control; uint8_t m_xmit; - - bus::ti99::hexbus::hexbus_device* m_hexbus; }; class mainboard8_device : public device_t |