mirror of
https://github.com/TomHarte/CLK.git
synced 2025-08-12 09:25:19 +00:00
Eliminates the optionality of a DPLL receiver.
This commit is contained in:
@@ -70,9 +70,7 @@
|
|||||||
buildConfiguration = "Debug"
|
buildConfiguration = "Debug"
|
||||||
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
|
||||||
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
|
||||||
enableAddressSanitizer = "YES"
|
|
||||||
enableASanStackUseAfterReturn = "YES"
|
enableASanStackUseAfterReturn = "YES"
|
||||||
enableUBSanitizer = "YES"
|
|
||||||
disableMainThreadChecker = "YES"
|
disableMainThreadChecker = "YES"
|
||||||
launchStyle = "0"
|
launchStyle = "0"
|
||||||
useCustomWorkingDirectory = "NO"
|
useCustomWorkingDirectory = "NO"
|
||||||
|
@@ -15,9 +15,8 @@ using namespace Storage::Disk;
|
|||||||
Controller::Controller(Cycles clock_rate) :
|
Controller::Controller(Cycles clock_rate) :
|
||||||
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
|
clock_rate_multiplier_(128000000 / clock_rate.as_integral()),
|
||||||
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
|
clock_rate_(clock_rate.as_integral() * clock_rate_multiplier_),
|
||||||
pll_(100),
|
pll_(100, *this),
|
||||||
empty_drive_(new Drive(int(clock_rate.as_integral()), 1, 1)) {
|
empty_drive_(new Drive(int(clock_rate.as_integral()), 1, 1)) {
|
||||||
pll_.set_delegate(this);
|
|
||||||
set_expected_bit_length(Time(1));
|
set_expected_bit_length(Time(1));
|
||||||
set_drive(empty_drive_);
|
set_drive(empty_drive_);
|
||||||
}
|
}
|
||||||
|
@@ -21,6 +21,7 @@ namespace Storage {
|
|||||||
/*!
|
/*!
|
||||||
Template parameters:
|
Template parameters:
|
||||||
|
|
||||||
|
@c bit_handler A class that must implement a method, digital_phase_locked_loop_output_bit(int) for receving bits from the DPLL.
|
||||||
@c length_of_history The number of historic pulses to consider in locking to phase.
|
@c length_of_history The number of historic pulses to consider in locking to phase.
|
||||||
*/
|
*/
|
||||||
template <typename BitHandler, size_t length_of_history = 3> class DigitalPhaseLockedLoop {
|
template <typename BitHandler, size_t length_of_history = 3> class DigitalPhaseLockedLoop {
|
||||||
@@ -30,8 +31,8 @@ template <typename BitHandler, size_t length_of_history = 3> class DigitalPhaseL
|
|||||||
|
|
||||||
@param clocks_per_bit The expected number of cycles between each bit of input.
|
@param clocks_per_bit The expected number of cycles between each bit of input.
|
||||||
*/
|
*/
|
||||||
DigitalPhaseLockedLoop(int clocks_per_bit) :
|
DigitalPhaseLockedLoop(int clocks_per_bit, BitHandler &handler) :
|
||||||
window_length_(clocks_per_bit), clocks_per_bit_(clocks_per_bit) {}
|
bit_handler_(handler), window_length_(clocks_per_bit), clocks_per_bit_(clocks_per_bit) {}
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
Changes the expected window length.
|
Changes the expected window length.
|
||||||
@@ -51,12 +52,10 @@ template <typename BitHandler, size_t length_of_history = 3> class DigitalPhaseL
|
|||||||
if(phase_ >= window_length_) {
|
if(phase_ >= window_length_) {
|
||||||
auto windows_crossed = phase_ / window_length_;
|
auto windows_crossed = phase_ / window_length_;
|
||||||
|
|
||||||
// check whether this triggers any 0s, if anybody cares
|
// Check whether this triggers any 0s.
|
||||||
if(delegate_) {
|
if(window_was_filled_) --windows_crossed;
|
||||||
if(window_was_filled_) --windows_crossed;
|
for(int c = 0; c < windows_crossed; c++)
|
||||||
for(int c = 0; c < windows_crossed; c++)
|
bit_handler_.digital_phase_locked_loop_output_bit(0);
|
||||||
delegate_->digital_phase_locked_loop_output_bit(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
window_was_filled_ = false;
|
window_was_filled_ = false;
|
||||||
phase_ %= window_length_;
|
phase_ %= window_length_;
|
||||||
@@ -68,22 +67,15 @@ template <typename BitHandler, size_t length_of_history = 3> class DigitalPhaseL
|
|||||||
*/
|
*/
|
||||||
void add_pulse() {
|
void add_pulse() {
|
||||||
if(!window_was_filled_) {
|
if(!window_was_filled_) {
|
||||||
if(delegate_) delegate_->digital_phase_locked_loop_output_bit(1);
|
bit_handler_.digital_phase_locked_loop_output_bit(1);
|
||||||
window_was_filled_ = true;
|
window_was_filled_ = true;
|
||||||
post_phase_offset(phase_, offset_);
|
post_phase_offset(phase_, offset_);
|
||||||
offset_ = 0;
|
offset_ = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/*!
|
|
||||||
A receiver for PCM output data; called upon every recognised bit.
|
|
||||||
*/
|
|
||||||
void set_delegate(BitHandler *delegate) {
|
|
||||||
delegate_ = delegate;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BitHandler *delegate_ = nullptr;
|
BitHandler &bit_handler_;
|
||||||
|
|
||||||
void post_phase_offset(Cycles::IntType new_phase, Cycles::IntType new_offset) {
|
void post_phase_offset(Cycles::IntType new_phase, Cycles::IntType new_offset) {
|
||||||
// Erase the effect of whatever is currently in this slot.
|
// Erase the effect of whatever is currently in this slot.
|
||||||
|
@@ -20,12 +20,13 @@ Storage::Disk::PCMSegment Storage::Disk::track_serialisation(const Track &track,
|
|||||||
// its PCMSegment.
|
// its PCMSegment.
|
||||||
struct ResultAccumulator {
|
struct ResultAccumulator {
|
||||||
PCMSegment result;
|
PCMSegment result;
|
||||||
|
bool is_recording = false;
|
||||||
void digital_phase_locked_loop_output_bit(int value) {
|
void digital_phase_locked_loop_output_bit(int value) {
|
||||||
result.data.push_back(!!value);
|
if(is_recording) result.data.push_back(!!value);
|
||||||
}
|
}
|
||||||
} result_accumulator;
|
} result_accumulator;
|
||||||
result_accumulator.result.length_of_a_bit = length_of_a_bit;
|
result_accumulator.result.length_of_a_bit = length_of_a_bit;
|
||||||
DigitalPhaseLockedLoop<ResultAccumulator> pll(100);
|
DigitalPhaseLockedLoop<ResultAccumulator> pll(100, result_accumulator);
|
||||||
|
|
||||||
// Obtain a length multiplier which is 100 times the reciprocal
|
// Obtain a length multiplier which is 100 times the reciprocal
|
||||||
// of the expected bit length. So a perfect bit length from
|
// of the expected bit length. So a perfect bit length from
|
||||||
@@ -55,7 +56,7 @@ Storage::Disk::PCMSegment Storage::Disk::track_serialisation(const Track &track,
|
|||||||
if(!history_size) {
|
if(!history_size) {
|
||||||
track_copy->seek_to(Time(0));
|
track_copy->seek_to(Time(0));
|
||||||
time_error.set_zero();
|
time_error.set_zero();
|
||||||
pll.set_delegate(&result_accumulator);
|
result_accumulator.is_recording = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -66,13 +66,11 @@ void Parser::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
|||||||
|
|
||||||
|
|
||||||
Shifter::Shifter() :
|
Shifter::Shifter() :
|
||||||
pll_(PLLClockRate / 4800),
|
pll_(PLLClockRate / 4800, *this),
|
||||||
was_high_(false),
|
was_high_(false),
|
||||||
input_pattern_(0),
|
input_pattern_(0),
|
||||||
input_bit_counter_(0),
|
input_bit_counter_(0),
|
||||||
delegate_(nullptr) {
|
delegate_(nullptr) {}
|
||||||
pll_.set_delegate(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
void Shifter::process_pulse(const Storage::Tape::Tape::Pulse &pulse) {
|
||||||
pll_.run_for(Cycles(static_cast<int>(static_cast<float>(PLLClockRate) * pulse.length.get<float>())));
|
pll_.run_for(Cycles(static_cast<int>(static_cast<float>(PLLClockRate) * pulse.length.get<float>())));
|
||||||
|
Reference in New Issue
Block a user