diff --git a/Machines/Electron/Tape.cpp b/Machines/Electron/Tape.cpp index a95d94995..a137738ee 100644 --- a/Machines/Electron/Tape.cpp +++ b/Machines/Electron/Tape.cpp @@ -17,7 +17,9 @@ Tape::Tape() : delegate_(nullptr), output_({.bits_remaining_until_empty = 0, .cycles_into_pulse = 0}), last_posted_interrupt_status_(0), - interrupt_status_(0) {} + interrupt_status_(0) { + shifter_.set_delegate(this); +} void Tape::push_tape_bit(uint16_t bit) { data_register_ = (uint16_t)((data_register_ >> 1) | (bit << 10)); @@ -71,30 +73,11 @@ uint8_t Tape::get_data_register() { } void Tape::process_input_pulse(Storage::Tape::Tape::Pulse pulse) { - crossings_[0] = crossings_[1]; - crossings_[1] = crossings_[2]; - crossings_[2] = crossings_[3]; + shifter_.process_pulse(pulse); +} - crossings_[3] = Tape::Unrecognised; - if(pulse.type != Storage::Tape::Tape::Pulse::Zero) { - float pulse_length = (float)pulse.length.length / (float)pulse.length.clock_rate; - if(pulse_length >= 0.35 / 2400.0 && pulse_length < 0.7 / 1200.0) { - crossings_[3] = pulse_length > 1.0 / 3000.0 ? Tape::Long : Tape::Short; - } -// if(pulse_length >= 0.35 / 2400.0 && pulse_length < 0.7 / 2400.0) crossings_[3] = Tape::Short; -// if(pulse_length >= 0.35 / 1200.0 && pulse_length < 0.7 / 1200.0) crossings_[3] = Tape::Long; - } - - if(crossings_[0] == Tape::Long && crossings_[1] == Tape::Long) { - push_tape_bit(0); - crossings_[0] = crossings_[1] = Tape::Recognised; - } else { - if(crossings_[0] == Tape::Short && crossings_[1] == Tape::Short && crossings_[2] == Tape::Short && crossings_[3] == Tape::Short) { - push_tape_bit(1); - crossings_[0] = crossings_[1] = - crossings_[2] = crossings_[3] = Tape::Recognised; - } - } +void Tape::acorn_shifter_output_bit(int value) { + push_tape_bit((uint16_t)value); } void Tape::run_for_cycles(unsigned int number_of_cycles) { diff --git a/Machines/Electron/Tape.hpp b/Machines/Electron/Tape.hpp index a796e7824..2019d3a54 100644 --- a/Machines/Electron/Tape.hpp +++ b/Machines/Electron/Tape.hpp @@ -10,13 +10,16 @@ #define Electron_Tape_h #include "../../Storage/Tape/Tape.hpp" +#include "../../Storage/Tape/Parsers/Acorn.hpp" #include "Interrupts.hpp" #include namespace Electron { -class Tape: public Storage::Tape::TapePlayer { +class Tape: + public Storage::Tape::TapePlayer, + public Storage::Tape::Acorn::Shifter::Delegate { public: Tape(); @@ -39,6 +42,8 @@ class Tape: public Storage::Tape::TapePlayer { inline void set_is_enabled(bool is_enabled) { is_enabled_ = is_enabled; } void set_is_in_input_mode(bool is_in_input_mode); + void acorn_shifter_output_bit(int value); + private: void process_input_pulse(Storage::Tape::Tape::Pulse pulse); inline void push_tape_bit(uint16_t bit); @@ -62,9 +67,7 @@ class Tape: public Storage::Tape::TapePlayer { uint8_t interrupt_status_, last_posted_interrupt_status_; Delegate *delegate_; - enum { - Long, Short, Unrecognised, Recognised - } crossings_[4]; + ::Storage::Tape::Acorn::Shifter shifter_; }; } diff --git a/Storage/Tape/Parsers/Acorn.cpp b/Storage/Tape/Parsers/Acorn.cpp index f510d139d..53cc730e5 100644 --- a/Storage/Tape/Parsers/Acorn.cpp +++ b/Storage/Tape/Parsers/Acorn.cpp @@ -14,9 +14,9 @@ namespace { const int PLLClockRate = 1920000; } -Parser::Parser() : - ::Storage::Tape::PLLParser(PLLClockRate, PLLClockRate / 4800), - crc_(0x1021, 0x0000) {} +Parser::Parser() : crc_(0x1021, 0x0000) { + shifter_.set_delegate(this); +} int Parser::get_next_bit(const std::shared_ptr &tape) { SymbolType symbol = get_next_symbol(tape); @@ -56,14 +56,38 @@ int Parser::get_next_word(const std::shared_ptr &tape) { void Parser::reset_crc() { crc_.reset(); } uint16_t Parser::get_crc() { return crc_.get_value(); } -bool Parser::did_update_shifter(int new_value, int length) { - if(length < 4) return false; +void Parser::acorn_shifter_output_bit(int value) { + push_symbol(value ? SymbolType::One : SymbolType::Zero); +} - switch(new_value & 0xf) { - case 0x5: printf("0"); push_symbol(SymbolType::Zero); return true; - case 0xf: printf("1"); push_symbol(SymbolType::One); return true; - default: - printf("?"); - return false; +void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { + shifter_.process_pulse(pulse); +} + + +Shifter::Shifter() : + pll_(PLLClockRate / 4800, 15), + was_high_(false), + input_pattern_(0), + input_bit_counter_(0) { + pll_.set_delegate(this); +} + +void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) { + pll_.run_for_cycles((int)((float)PLLClockRate * pulse.length.get_float())); + + bool is_high = pulse.type == Storage::Tape::Tape::Pulse::High; + if(is_high != was_high_) { + pll_.add_pulse(); + } + was_high_ = is_high; +} + +void Shifter::digital_phase_locked_loop_output_bit(int value) { + input_pattern_ = ((input_pattern_ << 1) | (unsigned int)value) & 0xf; + switch(input_pattern_) { + case 0x5: delegate_->acorn_shifter_output_bit(0); input_pattern_ = 0; break; + case 0xf: delegate_->acorn_shifter_output_bit(1); input_pattern_ = 0; break; + default: break;; } } diff --git a/Storage/Tape/Parsers/Acorn.hpp b/Storage/Tape/Parsers/Acorn.hpp index 734daf19c..47d00472e 100644 --- a/Storage/Tape/Parsers/Acorn.hpp +++ b/Storage/Tape/Parsers/Acorn.hpp @@ -17,11 +17,37 @@ namespace Storage { namespace Tape { namespace Acorn { +class Shifter: public Storage::DigitalPhaseLockedLoop::Delegate { + public: + Shifter(); + + void process_pulse(const Storage::Tape::Tape::Pulse &pulse); + + class Delegate { + public: + virtual void acorn_shifter_output_bit(int value) = 0; + }; + void set_delegate(Delegate *delegate) { + delegate_ = delegate; + } + + void digital_phase_locked_loop_output_bit(int value); + + private: + Storage::DigitalPhaseLockedLoop pll_; + bool was_high_; + + unsigned int input_pattern_; + unsigned int input_bit_counter_; + + Delegate *delegate_; +}; + enum class SymbolType { One, Zero }; -class Parser: public Storage::Tape::PLLParser { +class Parser: public Storage::Tape::Parser, public Shifter::Delegate { public: Parser(); @@ -32,10 +58,13 @@ class Parser: public Storage::Tape::PLLParser { void reset_crc(); uint16_t get_crc(); - bool did_update_shifter(int new_value, int length); + void acorn_shifter_output_bit(int value); + void process_pulse(const Storage::Tape::Tape::Pulse &pulse); private: + bool did_update_shifter(int new_value, int length); NumberTheory::CRC16 crc_; + Shifter shifter_; }; }