diff --git a/Machines/Apple/ADB/Bus.cpp b/Machines/Apple/ADB/Bus.cpp index fc424013a..82cfadc91 100644 --- a/Machines/Apple/ADB/Bus.cpp +++ b/Machines/Apple/ADB/Bus.cpp @@ -14,17 +14,12 @@ Bus::Bus(HalfCycles clock_speed) : half_cycles_to_microseconds_(1'000'000.0 / cl void Bus::run_for(HalfCycles duration) { time_in_state_ += duration; + time_since_get_state_ += duration; } -size_t Bus::add_device() { - const size_t id = next_device_id_; - ++next_device_id_; - return id; -} - -void Bus::set_device_output(size_t device, bool output) { +void Bus::set_device_output(size_t device_id, bool output) { // Modify the all-devices bus state. - bus_state_[device] = output; + bus_state_[device_id] = output; // React to signal edges only. const bool data_level = get_state(); @@ -45,12 +40,12 @@ void Bus::set_device_output(size_t device, bool output) { // 50–72 µs 0 // 300 µs service request if(low_microseconds > 1040.0) { - for(auto observer: observers_) { - observer->adb_bus_did_observe_event(this, Event::Reset); + for(auto device: devices_) { + device->adb_bus_did_observe_event(Event::Reset); } } else if(low_microseconds >= 560.0) { - for(auto observer: observers_) { - observer->adb_bus_did_observe_event(this, Event::Attention); + for(auto device: devices_) { + device->adb_bus_did_observe_event(Event::Attention); } shift_register_ = 1; } else if(low_microseconds < 50.0) { @@ -58,12 +53,12 @@ void Bus::set_device_output(size_t device, bool output) { } else if(low_microseconds < 72.0) { shift(0); } else if(low_microseconds >= 291.0 && low_microseconds <= 309.0) { - for(auto observer: observers_) { - observer->adb_bus_did_observe_event(this, Event::ServiceRequest); + for(auto device: devices_) { + device->adb_bus_did_observe_event(Event::ServiceRequest); } } else { - for(auto observer: observers_) { - observer->adb_bus_did_observe_event(this, Event::Unrecognised); + for(auto device: devices_) { + device->adb_bus_did_observe_event(Event::Unrecognised); } } } @@ -77,17 +72,30 @@ void Bus::shift(unsigned int value) { // Trigger a byte whenever a start bit hits bit 9. if(shift_register_ & 0x200) { - for(auto observer: observers_) { - observer->adb_bus_did_observe_event(this, Event::Byte, uint8_t(shift_register_ >> 1)); + for(auto device: devices_) { + device->adb_bus_did_observe_event(Event::Byte, uint8_t(shift_register_ >> 1)); } shift_register_ = 0; } } bool Bus::get_state() const { + const auto microseconds = time_since_get_state_.as() * half_cycles_to_microseconds_; + time_since_get_state_ = HalfCycles(0); + + for(auto device: devices_) { + device->advance_state(microseconds); + } return bus_state_.all(); } -void Bus::add_observer(Observer *observer) { - observers_.push_back(observer); +size_t Bus::add_device() { + const size_t id = next_device_id_; + ++next_device_id_; + return id; +} + +size_t Bus::add_device(Device *device) { + devices_.push_back(device); + return add_device(); } diff --git a/Machines/Apple/ADB/Bus.hpp b/Machines/Apple/ADB/Bus.hpp index 1b7e1b102..48d7c56cf 100644 --- a/Machines/Apple/ADB/Bus.hpp +++ b/Machines/Apple/ADB/Bus.hpp @@ -58,6 +58,15 @@ inline Command decode_command(uint8_t code) { The ADB bus models the data line of the ADB bus; it allows multiple devices to post their current data level, or read the current level, and also offers a tokenised version of all activity on the bus. + + In implementation terms, two types of device are envisaged: + + * proactive devices, which use @c add_device() and then merely @c set_device_output + and @c get_state() as required, according to their own tracking of time; and + + * reactive devices, which use @c add_device(Device*) and then merely react to + @c adb_bus_did_observe_event and @c advance_state in order to + update @c set_device_output. */ class Bus { public: @@ -77,7 +86,7 @@ class Bus { /*! Sets the current data line output for @c device. */ - void set_device_output(size_t device, bool output); + void set_device_output(size_t device_id, bool output); /*! @returns The current state of the ADB data line. @@ -93,20 +102,28 @@ class Bus { Unrecognised }; - struct Observer { + struct Device { /// Reports to an observer that @c event was observed in the activity /// observed on this bus. If this was a byte event, that byte's value is given as @c value. - virtual void adb_bus_did_observe_event(Bus *, Event event, uint8_t value = 0xff); + virtual void adb_bus_did_observe_event(Event event, uint8_t value = 0xff) = 0; + + /// Requests that the device update itself @c microseconds and, if necessary, post a + /// new value ot @c set_device_output. This will be called only when the bus needs + /// to reevaluate its current level. It cannot reliably be used to track the timing between + /// observed events. + virtual void advance_state(double microseconds) = 0; }; /*! - Adds an observer. + Adds a device. */ - void add_observer(Observer *); + size_t add_device(Device *); private: HalfCycles time_in_state_; + mutable HalfCycles time_since_get_state_; + double half_cycles_to_microseconds_ = 1.0; - std::vector observers_; + std::vector devices_; unsigned int shift_register_ = 0; bool data_level_ = true; diff --git a/Machines/Apple/ADB/ReactiveDevice.cpp b/Machines/Apple/ADB/ReactiveDevice.cpp new file mode 100644 index 000000000..67396abf2 --- /dev/null +++ b/Machines/Apple/ADB/ReactiveDevice.cpp @@ -0,0 +1,21 @@ +// +// ReactiveDevice.cpp +// Clock Signal +// +// Created by Thomas Harte on 12/02/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#include "ReactiveDevice.hpp" + +using namespace Apple::ADB; + +ReactiveDevice::ReactiveDevice(Apple::ADB::Bus &bus) : device_id_(bus.add_device(this)) {} + +void ReactiveDevice::post_response(const std::vector &&response) { + response_ = std::move(response); +} + +void ReactiveDevice::advance_state(double microseconds) { + (void)microseconds; +} diff --git a/Machines/Apple/ADB/ReactiveDevice.hpp b/Machines/Apple/ADB/ReactiveDevice.hpp new file mode 100644 index 000000000..e9c92494d --- /dev/null +++ b/Machines/Apple/ADB/ReactiveDevice.hpp @@ -0,0 +1,35 @@ +// +// ReactiveDevice.hpp +// Clock Signal +// +// Created by Thomas Harte on 12/02/2021. +// Copyright © 2021 Thomas Harte. All rights reserved. +// + +#ifndef ReactiveDevice_hpp +#define ReactiveDevice_hpp + +#include "Bus.hpp" + +#include +#include + +namespace Apple { +namespace ADB { + +class ReactiveDevice: public Bus::Device { + protected: + ReactiveDevice(Bus &bus); + + void post_response(const std::vector &&response); + void advance_state(double microseconds) override; + + private: + const size_t device_id_; + std::vector response_; +}; + +} +} + +#endif /* ReactiveDevice_hpp */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 428312bd6..1dafeca2a 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -172,6 +172,8 @@ 4B2BFDB21DAEF5FF001A68B8 /* Video.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2BFDB01DAEF5FF001A68B8 /* Video.cpp */; }; 4B2C45421E3C3896002A2389 /* cartridge.png in Resources */ = {isa = PBXBuildFile; fileRef = 4B2C45411E3C3896002A2389 /* cartridge.png */; }; 4B2E2D9D1C3A070400138695 /* Electron.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E2D9B1C3A070400138695 /* Electron.cpp */; }; + 4B2E86B725D7490E0024F1E9 /* ReactiveDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */; }; + 4B2E86B825D7490E0024F1E9 /* ReactiveDevice.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */; }; 4B302184208A550100773308 /* DiskII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B302183208A550100773308 /* DiskII.cpp */; }; 4B302185208A550100773308 /* DiskII.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B302183208A550100773308 /* DiskII.cpp */; }; 4B30512D1D989E2200B4FED8 /* Drive.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4B30512B1D989E2200B4FED8 /* Drive.cpp */; }; @@ -1116,6 +1118,8 @@ 4B2C455C1EC9442600FC74DD /* RegisterSizes.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = RegisterSizes.hpp; sourceTree = ""; }; 4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = ""; }; 4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = ""; }; + 4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReactiveDevice.cpp; sourceTree = ""; }; + 4B2E86B625D7490E0024F1E9 /* ReactiveDevice.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ReactiveDevice.hpp; sourceTree = ""; }; 4B302182208A550100773308 /* DiskII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskII.hpp; sourceTree = ""; }; 4B302183208A550100773308 /* DiskII.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskII.cpp; sourceTree = ""; }; 4B30512B1D989E2200B4FED8 /* Drive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drive.cpp; sourceTree = ""; }; @@ -4189,6 +4193,8 @@ children = ( 4BCE1DEF25D4C3FA00AE7A2B /* Bus.cpp */, 4BCE1DF025D4C3FA00AE7A2B /* Bus.hpp */, + 4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */, + 4B2E86B625D7490E0024F1E9 /* ReactiveDevice.hpp */, ); path = ADB; sourceTree = ""; @@ -5108,6 +5114,7 @@ 4B055A991FAE85CB0060FFFF /* DiskController.cpp in Sources */, 4B25B5F925BD083C00362C84 /* DiskIIDrive.cpp in Sources */, 4B055ACC1FAE9B030060FFFF /* Electron.cpp in Sources */, + 4B2E86B825D7490E0024F1E9 /* ReactiveDevice.cpp in Sources */, 4B74CF822312FA9C00500CE8 /* HFV.cpp in Sources */, 4B8318B022D3E531006DB630 /* AppleII.cpp in Sources */, 4B1B58F7246CC4E8009C171E /* State.cpp in Sources */, @@ -5284,6 +5291,7 @@ 4BE21219253FCE9C00435408 /* AppleIIgs.cpp in Sources */, 4BCE0060227D39AB000CA200 /* Video.cpp in Sources */, 4B0ACC2E23775819008902D0 /* TIA.cpp in Sources */, + 4B2E86B725D7490E0024F1E9 /* ReactiveDevice.cpp in Sources */, 4B74CF85231370BC00500CE8 /* MacintoshVolume.cpp in Sources */, 4B4518A51F75FD1C00926311 /* SSD.cpp in Sources */, 4B55CE5F1C3B7D960093A61B /* MachineDocument.swift in Sources */,