1
0
mirror of https://github.com/TomHarte/CLK.git synced 2024-07-04 18:29:40 +00:00
CLK/Machines/Apple/ADB/Bus.cpp

102 lines
2.6 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// 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;
}
void Bus::set_device_output(size_t device_id, bool output) {
// Modify the all-devices bus state.
bus_state_[device_id] = output;
// React to signal edges only.
const bool data_level = get_state();
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);
}
} else if(low_microseconds >= 560.0) {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Attention);
}
shift_register_ = 1;
} 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);
}
} else {
for(auto device: devices_) {
device->adb_bus_did_observe_event(Event::Unrecognised);
}
}
}
time_in_state_ = HalfCycles(0);
}
}
void Bus::shift(unsigned int value) {
shift_register_ = (shift_register_ << 1) | value;
// Trigger a byte whenever a start bit hits bit 9.
if(shift_register_ & 0x200) {
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();
}
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();
}