mirror of
https://github.com/TomHarte/CLK.git
synced 2026-04-21 17:16:44 +00:00
Renames what didn't end up being a whole SerialPort.
This commit is contained in:
@@ -0,0 +1,140 @@
|
||||
//
|
||||
// SerialPort.cpp
|
||||
// Clock Signal
|
||||
//
|
||||
// Created by Thomas Harte on 12/10/2019.
|
||||
// Copyright © 2019 Thomas Harte. All rights reserved.
|
||||
//
|
||||
|
||||
#include "Line.hpp"
|
||||
|
||||
using namespace Serial;
|
||||
|
||||
void Line::set_writer_clock_rate(HalfCycles clock_rate) {
|
||||
clock_rate_ = clock_rate;
|
||||
}
|
||||
|
||||
void Line::advance_writer(HalfCycles cycles) {
|
||||
if(cycles == HalfCycles(0)) return;
|
||||
|
||||
const auto integral_cycles = cycles.as_integral();
|
||||
remaining_delays_ = std::max(remaining_delays_ - integral_cycles, Cycles::IntType(0));
|
||||
if(events_.empty()) {
|
||||
write_cycles_since_delegate_call_ += integral_cycles;
|
||||
if(transmission_extra_) {
|
||||
transmission_extra_ -= integral_cycles;
|
||||
if(transmission_extra_ <= 0) {
|
||||
transmission_extra_ = 0;
|
||||
update_delegate(level_);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
while(!events_.empty()) {
|
||||
if(events_.front().delay <= integral_cycles) {
|
||||
cycles -= events_.front().delay;
|
||||
write_cycles_since_delegate_call_ += events_.front().delay;
|
||||
const auto old_level = level_;
|
||||
|
||||
auto iterator = events_.begin() + 1;
|
||||
while(iterator != events_.end() && iterator->type != Event::Delay) {
|
||||
level_ = iterator->type == Event::SetHigh;
|
||||
++iterator;
|
||||
}
|
||||
events_.erase(events_.begin(), iterator);
|
||||
|
||||
if(old_level != level_) {
|
||||
update_delegate(old_level);
|
||||
}
|
||||
|
||||
// Book enough extra time for the read delegate to be posted
|
||||
// the final bit if one is attached.
|
||||
if(events_.empty()) {
|
||||
transmission_extra_ = minimum_write_cycles_for_read_delegate_bit();
|
||||
}
|
||||
} else {
|
||||
events_.front().delay -= integral_cycles;
|
||||
write_cycles_since_delegate_call_ += integral_cycles;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Line::write(bool level) {
|
||||
if(!events_.empty()) {
|
||||
events_.emplace_back();
|
||||
events_.back().type = level ? Event::SetHigh : Event::SetLow;
|
||||
} else {
|
||||
level_ = level;
|
||||
transmission_extra_ = minimum_write_cycles_for_read_delegate_bit();
|
||||
}
|
||||
}
|
||||
|
||||
void Line::write(HalfCycles cycles, int count, int levels) {
|
||||
remaining_delays_ += count * cycles.as_integral();
|
||||
|
||||
auto event = events_.size();
|
||||
events_.resize(events_.size() + size_t(count)*2);
|
||||
while(count--) {
|
||||
events_[event].type = Event::Delay;
|
||||
events_[event].delay = int(cycles.as_integral());
|
||||
events_[event+1].type = (levels&1) ? Event::SetHigh : Event::SetLow;
|
||||
levels >>= 1;
|
||||
event += 2;
|
||||
}
|
||||
}
|
||||
|
||||
void Line::reset_writing() {
|
||||
remaining_delays_ = 0;
|
||||
events_.clear();
|
||||
}
|
||||
|
||||
bool Line::read() {
|
||||
return level_;
|
||||
}
|
||||
|
||||
void Line::set_read_delegate(ReadDelegate *delegate, Storage::Time bit_length) {
|
||||
read_delegate_ = delegate;
|
||||
read_delegate_bit_length_ = bit_length;
|
||||
read_delegate_bit_length_.simplify();
|
||||
write_cycles_since_delegate_call_ = 0;
|
||||
}
|
||||
|
||||
void Line::update_delegate(bool level) {
|
||||
// Exit early if there's no delegate, or if the delegate is waiting for
|
||||
// zero and this isn't zero.
|
||||
if(!read_delegate_) return;
|
||||
|
||||
const int cycles_to_forward = write_cycles_since_delegate_call_;
|
||||
write_cycles_since_delegate_call_ = 0;
|
||||
if(level && read_delegate_phase_ == ReadDelegatePhase::WaitingForZero) return;
|
||||
|
||||
// Deal with a transition out of waiting-for-zero mode by seeding time left
|
||||
// in bit at half a bit.
|
||||
if(read_delegate_phase_ == ReadDelegatePhase::WaitingForZero) {
|
||||
time_left_in_bit_ = read_delegate_bit_length_;
|
||||
time_left_in_bit_.clock_rate <<= 1;
|
||||
read_delegate_phase_ = ReadDelegatePhase::Serialising;
|
||||
}
|
||||
|
||||
// Forward as many bits as occur.
|
||||
Storage::Time time_left(cycles_to_forward, int(clock_rate_.as_integral()));
|
||||
const int bit = level ? 1 : 0;
|
||||
int bits = 0;
|
||||
while(time_left >= time_left_in_bit_) {
|
||||
++bits;
|
||||
if(!read_delegate_->serial_line_did_produce_bit(this, bit)) {
|
||||
read_delegate_phase_ = ReadDelegatePhase::WaitingForZero;
|
||||
if(bit) return;
|
||||
}
|
||||
|
||||
time_left -= time_left_in_bit_;
|
||||
time_left_in_bit_ = read_delegate_bit_length_;
|
||||
}
|
||||
time_left_in_bit_ -= time_left;
|
||||
}
|
||||
|
||||
Cycles::IntType Line::minimum_write_cycles_for_read_delegate_bit() {
|
||||
if(!read_delegate_) return 0;
|
||||
return 1 + (read_delegate_bit_length_ * static_cast<unsigned int>(clock_rate_.as_integral())).get<int>();
|
||||
}
|
||||
Reference in New Issue
Block a user