1
0
mirror of https://github.com/TomHarte/CLK.git synced 2025-08-05 08:26:28 +00:00

Introduce the principle that a Serial::Line can be two-wire — clock + data.

This commit is contained in:
Thomas Harte
2021-11-06 16:54:20 -07:00
parent c0c2b5e3a9
commit ecfe68d70f
9 changed files with 71 additions and 45 deletions

View File

@@ -12,11 +12,13 @@
using namespace Serial;
void Line::set_writer_clock_rate(HalfCycles clock_rate) {
template <bool include_clock>
void Line<include_clock>::set_writer_clock_rate(HalfCycles clock_rate) {
clock_rate_ = clock_rate;
}
void Line::advance_writer(HalfCycles cycles) {
template <bool include_clock>
void Line<include_clock>::advance_writer(HalfCycles cycles) {
if(cycles == HalfCycles(0)) return;
const auto integral_cycles = cycles.as_integral();
@@ -62,7 +64,8 @@ void Line::advance_writer(HalfCycles cycles) {
}
}
void Line::write(bool level) {
template <bool include_clock>
void Line<include_clock>::write(bool level) {
if(!events_.empty()) {
events_.emplace_back();
events_.back().type = level ? Event::SetHigh : Event::SetLow;
@@ -72,7 +75,8 @@ void Line::write(bool level) {
}
}
template <bool lsb_first, typename IntT> void Line::write_internal(HalfCycles cycles, int count, IntT levels) {
template <bool include_clock>
template <bool lsb_first, typename IntT> void Line<include_clock>::write_internal(HalfCycles cycles, int count, IntT levels) {
remaining_delays_ += count * cycles.as_integral();
auto event = events_.size();
@@ -95,40 +99,37 @@ template <bool lsb_first, typename IntT> void Line::write_internal(HalfCycles cy
}
}
void Line::write(HalfCycles cycles, int count, int levels) {
template <bool include_clock>
void Line<include_clock>::write(HalfCycles cycles, int count, int levels) {
write_internal<true, int>(cycles, count, levels);
}
template <bool lsb_first, typename IntT> void Line::write(HalfCycles cycles, IntT value) {
template <bool include_clock>
template <bool lsb_first, typename IntT> void Line<include_clock>::write(HalfCycles cycles, IntT value) {
write_internal<lsb_first, IntT>(cycles, 8 * sizeof(IntT), value);
}
template void Line::write<true, uint8_t>(HalfCycles, uint8_t);
template void Line::write<false, uint8_t>(HalfCycles, uint8_t);
template void Line::write<true, uint16_t>(HalfCycles, uint16_t);
template void Line::write<false, uint16_t>(HalfCycles, uint16_t);
template void Line::write<true, uint32_t>(HalfCycles, uint32_t);
template void Line::write<false, uint32_t>(HalfCycles, uint32_t);
template void Line::write<true, uint64_t>(HalfCycles, uint64_t);
template void Line::write<false, uint64_t>(HalfCycles, uint64_t);
void Line::reset_writing() {
template <bool include_clock>
void Line<include_clock>::reset_writing() {
remaining_delays_ = 0;
events_.clear();
}
bool Line::read() const {
template <bool include_clock>
bool Line<include_clock>::read() const {
return level_;
}
void Line::set_read_delegate(ReadDelegate *delegate, Storage::Time bit_length) {
template <bool include_clock>
void Line<include_clock>::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) {
template <bool include_clock>
void Line<include_clock>::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;
@@ -162,7 +163,36 @@ void Line::update_delegate(bool level) {
time_left_in_bit_ -= time_left;
}
Cycles::IntType Line::minimum_write_cycles_for_read_delegate_bit() {
template <bool include_clock>
Cycles::IntType Line<include_clock>::minimum_write_cycles_for_read_delegate_bit() {
if(!read_delegate_) return 0;
return 1 + (read_delegate_bit_length_ * unsigned(clock_rate_.as_integral())).get<int>();
return 1 + (read_delegate_bit_length_ * unsigned(clock_rate_.as_integral())).template get<int>();
}
//
// Explicitly instantiate the meaningful instances of templates above;
// this class uses templates primarily to keep the interface compact and
// to take advantage of constexpr functionality selection, not so as
// to be generic.
//
template class Serial::Line<true>;
template class Serial::Line<false>;
template void Line<true>::write<true, uint8_t>(HalfCycles, uint8_t);
template void Line<true>::write<false, uint8_t>(HalfCycles, uint8_t);
template void Line<true>::write<true, uint16_t>(HalfCycles, uint16_t);
template void Line<true>::write<false, uint16_t>(HalfCycles, uint16_t);
template void Line<true>::write<true, uint32_t>(HalfCycles, uint32_t);
template void Line<true>::write<false, uint32_t>(HalfCycles, uint32_t);
template void Line<true>::write<true, uint64_t>(HalfCycles, uint64_t);
template void Line<true>::write<false, uint64_t>(HalfCycles, uint64_t);
template void Line<false>::write<true, uint8_t>(HalfCycles, uint8_t);
template void Line<false>::write<false, uint8_t>(HalfCycles, uint8_t);
template void Line<false>::write<true, uint16_t>(HalfCycles, uint16_t);
template void Line<false>::write<false, uint16_t>(HalfCycles, uint16_t);
template void Line<false>::write<true, uint32_t>(HalfCycles, uint32_t);
template void Line<false>::write<false, uint32_t>(HalfCycles, uint32_t);
template void Line<false>::write<true, uint64_t>(HalfCycles, uint64_t);
template void Line<false>::write<false, uint64_t>(HalfCycles, uint64_t);

View File

@@ -25,7 +25,7 @@ namespace Serial {
get ahead of the writer. If the writer posts events behind the reader they will simply be
given instanteous effect.
*/
class Line {
template <bool include_clock> class Line {
public:
void set_writer_clock_rate(HalfCycles clock_rate);