1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-11-25 16:31:42 +00:00
CLK/Machines/Apple/ADB/Bus.cpp

114 lines
3.3 KiB
C++
Raw Normal View History

2021-02-11 02:24:31 +00:00
//
// Bus.cpp
// Clock Signal
//
// Created by Thomas Harte on 10/02/2021.
// Copyright © 2021 Thomas Harte. All rights reserved.
//
#include "Bus.hpp"
using namespace Apple::ADB;
Bus::Bus(HalfCycles clock_speed) : half_cycles_to_microseconds_(1'000'000.0 / clock_speed.as<double>()) {}
void Bus::run_for(HalfCycles duration) {
time_in_state_ += duration;
time_since_get_state_ += duration;
2021-02-11 02:24:31 +00:00
}
void Bus::set_device_output(size_t device_id, bool output) {
2021-02-11 02:24:31 +00:00
// Modify the all-devices bus state.
bus_state_[device_id] = output;
2021-02-11 02:24:31 +00:00
2021-02-14 04:16:45 +00:00
// React to signal edges only; don't use get_state here to avoid
// endless recursion should any reactive devices set new output
// during the various calls made below.
const bool data_level = bus_state_.all();
2021-02-11 02:24:31 +00:00
if(data_level_ != data_level) {
data_level_ = data_level;
if(data_level) {
// This was a transition to high; classify what just happened according to
// the duration of the low period.
const double low_microseconds = time_in_state_.as<double>() * half_cycles_to_microseconds_;
// Low periods:
// (partly as adapted from the AN591 data sheet; otherwise from the IIgs reference manual)
//
// > 1040 µs reset
// 5601040 µs attention
// < 50 µs 1
// 5072 µs 0
// 300 µs service request
if(low_microseconds > 1040.0) {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Reset);
2021-02-11 02:24:31 +00:00
}
} else if(low_microseconds >= 560.0) {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Attention);
2021-02-11 02:24:31 +00:00
}
shift_register_ = 1;
start_target_ = 9; // Consume the stop bit before posting the next byte.
phase_ = Phase::AttentionCapture;
2021-02-11 02:24:31 +00:00
} else if(low_microseconds < 50.0) {
shift(1);
} else if(low_microseconds < 72.0) {
shift(0);
} else if(low_microseconds >= 291.0 && low_microseconds <= 309.0) {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::ServiceRequest);
2021-02-11 02:24:31 +00:00
}
} else {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Unrecognised);
2021-02-11 02:24:31 +00:00
}
}
}
time_in_state_ = HalfCycles(0);
}
}
void Bus::shift(unsigned int value) {
shift_register_ = (shift_register_ << 1) | value;
// Trigger a byte whenever either:
// * a 'start bit' hits bit 8; or
// * if this was a command byte, wait for the stop bit (i.e. the start bit hits 9).
if(shift_register_ & (1 << start_target_)) {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Byte, uint8_t(shift_register_ >> (start_target_ - 8)));
2021-02-11 02:24:31 +00:00
}
// Expect a real start bit only if moving from attention capture to packet
// capture. Otherwise adopt an implied start bit.
shift_register_ = phase_ == Phase::PacketCapture;
start_target_ = 8;
phase_ = Phase::PacketCapture;
2021-02-11 02:24:31 +00:00
}
}
bool Bus::get_state() const {
const auto microseconds = time_since_get_state_.as<double>() * half_cycles_to_microseconds_;
time_since_get_state_ = HalfCycles(0);
const bool current_level = bus_state_.all();
for(auto device: devices_) {
device->advance_state(microseconds, current_level);
}
2021-02-11 02:24:31 +00:00
return bus_state_.all();
}
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();
2021-02-11 02:24:31 +00:00
}