From ecfe68d70f0538de7b60539a5e8717944639cb47 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sat, 6 Nov 2021 16:54:20 -0700 Subject: [PATCH] =?UTF-8?q?Introduce=20the=20principle=20that=20a=20Serial?= =?UTF-8?q?::Line=20can=20be=20two-wire=20=E2=80=94=20clock=20+=20data.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Components/6526/6526.hpp | 8 +-- Components/6850/6850.cpp | 2 +- Components/6850/6850.hpp | 14 ++--- Components/Serial/Line.cpp | 72 ++++++++++++++++------- Components/Serial/Line.hpp | 2 +- Machines/Amiga/Keyboard.cpp | 2 +- Machines/Amiga/Keyboard.hpp | 4 +- Machines/Atari/ST/IntelligentKeyboard.cpp | 4 +- Machines/Atari/ST/IntelligentKeyboard.hpp | 8 +-- 9 files changed, 71 insertions(+), 45 deletions(-) diff --git a/Components/6526/6526.hpp b/Components/6526/6526.hpp index 5dc8299d6..1a48ced32 100644 --- a/Components/6526/6526.hpp +++ b/Components/6526/6526.hpp @@ -64,12 +64,8 @@ template class MOS6526: /// Sets the current state of the CNT input. void set_cnt_input(bool active); - /// Provides the serial input bit. - Serial::Line serial_input; - - /// Optionally sets CNT to automatically toggle based on the events - /// generated by @c serial_input. - void set_cnt_tied_to_input(bool); + /// Provides both the serial input bit and an additional source of CNT. + Serial::Line serial_input; /// Sets the current state of the FLG input. void set_flag_input(bool low); diff --git a/Components/6850/6850.cpp b/Components/6850/6850.cpp index 561a1caac..032b02887 100644 --- a/Components/6850/6850.cpp +++ b/Components/6850/6850.cpp @@ -148,7 +148,7 @@ uint8_t ACIA::parity(uint8_t value) { return value ^ (parity_ == Parity::Even); } -bool ACIA::serial_line_did_produce_bit(Serial::Line *, int bit) { +bool ACIA::serial_line_did_produce_bit(Serial::Line *, int bit) { // Shift this bit into the 11-bit input register; this is big enough to hold // the largest transmission symbol. ++bits_received_; diff --git a/Components/6850/6850.hpp b/Components/6850/6850.hpp index 8e2dbf19d..69e192e90 100644 --- a/Components/6850/6850.hpp +++ b/Components/6850/6850.hpp @@ -18,7 +18,7 @@ namespace Motorola { namespace ACIA { -class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { +class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { public: static constexpr const HalfCycles SameAsTransmit = HalfCycles(0); @@ -77,13 +77,13 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { void reset(); // Input lines. - Serial::Line receive; - Serial::Line clear_to_send; - Serial::Line data_carrier_detect; + Serial::Line receive; + Serial::Line clear_to_send; + Serial::Line data_carrier_detect; // Output lines. - Serial::Line transmit; - Serial::Line request_to_send; + Serial::Line transmit; + Serial::Line request_to_send; // ClockingHint::Source. ClockingHint::Preference preferred_clocking() const final; @@ -118,7 +118,7 @@ class ACIA: public ClockingHint::Source, private Serial::Line::ReadDelegate { HalfCycles transmit_clock_rate_; HalfCycles receive_clock_rate_; - bool serial_line_did_produce_bit(Serial::Line *line, int bit) final; + bool serial_line_did_produce_bit(Serial::Line *line, int bit) final; bool interrupt_line_ = false; void update_interrupt_line(); diff --git a/Components/Serial/Line.cpp b/Components/Serial/Line.cpp index 16623cd97..c0f756b35 100644 --- a/Components/Serial/Line.cpp +++ b/Components/Serial/Line.cpp @@ -12,11 +12,13 @@ using namespace Serial; -void Line::set_writer_clock_rate(HalfCycles clock_rate) { +template +void Line::set_writer_clock_rate(HalfCycles clock_rate) { clock_rate_ = clock_rate; } -void Line::advance_writer(HalfCycles cycles) { +template +void Line::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 +void Line::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 void Line::write_internal(HalfCycles cycles, int count, IntT levels) { +template +template void Line::write_internal(HalfCycles cycles, int count, IntT levels) { remaining_delays_ += count * cycles.as_integral(); auto event = events_.size(); @@ -95,40 +99,37 @@ template void Line::write_internal(HalfCycles cy } } -void Line::write(HalfCycles cycles, int count, int levels) { +template +void Line::write(HalfCycles cycles, int count, int levels) { write_internal(cycles, count, levels); } -template void Line::write(HalfCycles cycles, IntT value) { +template +template void Line::write(HalfCycles cycles, IntT value) { write_internal(cycles, 8 * sizeof(IntT), value); } -template void Line::write(HalfCycles, uint8_t); -template void Line::write(HalfCycles, uint8_t); -template void Line::write(HalfCycles, uint16_t); -template void Line::write(HalfCycles, uint16_t); -template void Line::write(HalfCycles, uint32_t); -template void Line::write(HalfCycles, uint32_t); -template void Line::write(HalfCycles, uint64_t); -template void Line::write(HalfCycles, uint64_t); - -void Line::reset_writing() { +template +void Line::reset_writing() { remaining_delays_ = 0; events_.clear(); } -bool Line::read() const { +template +bool Line::read() const { return level_; } -void Line::set_read_delegate(ReadDelegate *delegate, Storage::Time bit_length) { +template +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) { +template +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; @@ -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 +Cycles::IntType Line::minimum_write_cycles_for_read_delegate_bit() { if(!read_delegate_) return 0; - return 1 + (read_delegate_bit_length_ * unsigned(clock_rate_.as_integral())).get(); + return 1 + (read_delegate_bit_length_ * unsigned(clock_rate_.as_integral())).template get(); } + +// +// 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; +template class Serial::Line; + +template void Line::write(HalfCycles, uint8_t); +template void Line::write(HalfCycles, uint8_t); +template void Line::write(HalfCycles, uint16_t); +template void Line::write(HalfCycles, uint16_t); +template void Line::write(HalfCycles, uint32_t); +template void Line::write(HalfCycles, uint32_t); +template void Line::write(HalfCycles, uint64_t); +template void Line::write(HalfCycles, uint64_t); + +template void Line::write(HalfCycles, uint8_t); +template void Line::write(HalfCycles, uint8_t); +template void Line::write(HalfCycles, uint16_t); +template void Line::write(HalfCycles, uint16_t); +template void Line::write(HalfCycles, uint32_t); +template void Line::write(HalfCycles, uint32_t); +template void Line::write(HalfCycles, uint64_t); +template void Line::write(HalfCycles, uint64_t); diff --git a/Components/Serial/Line.hpp b/Components/Serial/Line.hpp index 2c2952f51..a23c8e9c4 100644 --- a/Components/Serial/Line.hpp +++ b/Components/Serial/Line.hpp @@ -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 class Line { public: void set_writer_clock_rate(HalfCycles clock_rate); diff --git a/Machines/Amiga/Keyboard.cpp b/Machines/Amiga/Keyboard.cpp index e443d5709..b3e0054ff 100644 --- a/Machines/Amiga/Keyboard.cpp +++ b/Machines/Amiga/Keyboard.cpp @@ -42,7 +42,7 @@ using namespace Amiga; -Keyboard::Keyboard(Serial::Line &output) : output_(output) { +Keyboard::Keyboard(Serial::Line &output) : output_(output) { output_.set_writer_clock_rate(HalfCycles(1'000'000)); // Use µs. } diff --git a/Machines/Amiga/Keyboard.hpp b/Machines/Amiga/Keyboard.hpp index 973140f6e..dbdc80b0d 100644 --- a/Machines/Amiga/Keyboard.hpp +++ b/Machines/Amiga/Keyboard.hpp @@ -77,7 +77,7 @@ struct KeyboardMapper: public MachineTypes::MappedKeyboardMachine::KeyboardMappe class Keyboard { public: - Keyboard(Serial::Line &output); + Keyboard(Serial::Line &output); // enum Lines: uint8_t { // Data = (1 << 0), @@ -106,7 +106,7 @@ class Keyboard { uint8_t lines_ = 0; - Serial::Line &output_; + Serial::Line &output_; }; } diff --git a/Machines/Atari/ST/IntelligentKeyboard.cpp b/Machines/Atari/ST/IntelligentKeyboard.cpp index e2b84ca6d..7e9ba4940 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.cpp +++ b/Machines/Atari/ST/IntelligentKeyboard.cpp @@ -15,7 +15,7 @@ using namespace Atari::ST; -IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) { +IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &output) : output_line_(output) { input.set_read_delegate(this, Storage::Time(2, 15625)); output_line_.set_writer_clock_rate(15625); @@ -24,7 +24,7 @@ IntelligentKeyboard::IntelligentKeyboard(Serial::Line &input, Serial::Line &outp joysticks_.emplace_back(new Joystick); } -bool IntelligentKeyboard::serial_line_did_produce_bit(Serial::Line *, int bit) { +bool IntelligentKeyboard::serial_line_did_produce_bit(Serial::Line *, int bit) { // Shift. command_ = (command_ >> 1) | (bit << 9); diff --git a/Machines/Atari/ST/IntelligentKeyboard.hpp b/Machines/Atari/ST/IntelligentKeyboard.hpp index fb96045e6..e876e0d88 100644 --- a/Machines/Atari/ST/IntelligentKeyboard.hpp +++ b/Machines/Atari/ST/IntelligentKeyboard.hpp @@ -53,11 +53,11 @@ static_assert(uint16_t(Key::KeypadEnter) == 0x72, "KeypadEnter should have key c keyboard input and output and mouse handling. */ class IntelligentKeyboard: - public Serial::Line::ReadDelegate, + public Serial::Line::ReadDelegate, public ClockingHint::Source, public Inputs::Mouse { public: - IntelligentKeyboard(Serial::Line &input, Serial::Line &output); + IntelligentKeyboard(Serial::Line &input, Serial::Line &output); ClockingHint::Preference preferred_clocking() const final; void run_for(HalfCycles duration); @@ -78,10 +78,10 @@ class IntelligentKeyboard: // MARK: - Serial line state. int bit_count_ = 0; int command_ = 0; - Serial::Line &output_line_; + Serial::Line &output_line_; void output_bytes(std::initializer_list value); - bool serial_line_did_produce_bit(Serial::Line *, int bit) final; + bool serial_line_did_produce_bit(Serial::Line *, int bit) final; // MARK: - Command dispatch. std::vector command_sequence_;