1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-02 05:29:32 +00:00

Starts to establish the means by which I'll implement ADB devices.

This commit is contained in:
Thomas Harte 2021-02-12 18:42:12 -05:00
parent e83b2120ce
commit adfdfa205f
5 changed files with 115 additions and 26 deletions

View File

@ -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) {
// 5072 µ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<double>() * 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();
}

View File

@ -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<Observer *> observers_;
std::vector<Device *> devices_;
unsigned int shift_register_ = 0;
bool data_level_ = true;

View File

@ -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<uint8_t> &&response) {
response_ = std::move(response);
}
void ReactiveDevice::advance_state(double microseconds) {
(void)microseconds;
}

View File

@ -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 <cstddef>
#include <vector>
namespace Apple {
namespace ADB {
class ReactiveDevice: public Bus::Device {
protected:
ReactiveDevice(Bus &bus);
void post_response(const std::vector<uint8_t> &&response);
void advance_state(double microseconds) override;
private:
const size_t device_id_;
std::vector<uint8_t> response_;
};
}
}
#endif /* ReactiveDevice_hpp */

View File

@ -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 = "<group>"; };
4B2E2D9B1C3A070400138695 /* Electron.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = Electron.cpp; path = Electron/Electron.cpp; sourceTree = "<group>"; };
4B2E2D9C1C3A070400138695 /* Electron.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = Electron.hpp; path = Electron/Electron.hpp; sourceTree = "<group>"; };
4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ReactiveDevice.cpp; sourceTree = "<group>"; };
4B2E86B625D7490E0024F1E9 /* ReactiveDevice.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ReactiveDevice.hpp; sourceTree = "<group>"; };
4B302182208A550100773308 /* DiskII.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = DiskII.hpp; sourceTree = "<group>"; };
4B302183208A550100773308 /* DiskII.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DiskII.cpp; sourceTree = "<group>"; };
4B30512B1D989E2200B4FED8 /* Drive.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Drive.cpp; sourceTree = "<group>"; };
@ -4189,6 +4193,8 @@
children = (
4BCE1DEF25D4C3FA00AE7A2B /* Bus.cpp */,
4BCE1DF025D4C3FA00AE7A2B /* Bus.hpp */,
4B2E86B525D7490E0024F1E9 /* ReactiveDevice.cpp */,
4B2E86B625D7490E0024F1E9 /* ReactiveDevice.hpp */,
);
path = ADB;
sourceTree = "<group>";
@ -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 */,