diff --git a/NumberTheory/LFSR.hpp b/NumberTheory/LFSR.hpp new file mode 100644 index 000000000..c03fc45c7 --- /dev/null +++ b/NumberTheory/LFSR.hpp @@ -0,0 +1,60 @@ +// +// LFSR.hpp +// Clock Signal +// +// Created by Thomas Harte on 19/01/2020. +// Copyright © 2020 Thomas Harte. All rights reserved. +// + +#ifndef LFSR_h +#define LFSR_h + +template struct LSFRPolynomial { +}; + +// The following were taken 'at random' from https://users.ece.cmu.edu/~koopman/lfsr/index.html +template <> struct LSFRPolynomial { + static constexpr uint64_t value = 0x80000000000019E2; +}; + +template <> struct LSFRPolynomial { + static constexpr uint32_t value = 0x80000C34; +}; + +template <> struct LSFRPolynomial { + static constexpr uint16_t value = 0x853E; +}; + +template <> struct LSFRPolynomial { + static constexpr uint8_t value = 0xAF; +}; + +/*! + Provides a linear-feedback shift register with a random initial state; if no polynomial is supplied + then one will be picked that is guaranteed to give the maximal number of LFSR states that can fit + in the specified int type. +*/ +template ::value> class LFSR { + public: + LFSR() { + // Randomise the value, ensuring it doesn't end up being 0. + while(!value_) { + uint8_t *value_byte = reinterpret_cast(&value_); + for(size_t c = 0; c < sizeof(IntType); ++c) { + *value_byte = uint8_t(uint64_t(rand()) * 255 / RAND_MAX); + ++value_byte; + } + } + } + + IntType next() { + auto result = value_ & 1; + value_ = (value_ >> 1) ^ (result * polynomial); + return result; + } + + private: + IntType value_ = 0; +}; + +#endif /* LFSR_h */ diff --git a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj index 646fb476f..57685bf15 100644 --- a/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj +++ b/OSBindings/Mac/Clock Signal.xcodeproj/project.pbxproj @@ -1185,6 +1185,7 @@ 4B7BA03523CEB86000B98D9E /* BD500.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BD500.cpp; path = Oric/BD500.cpp; sourceTree = ""; }; 4B7BA03623CEB86000B98D9E /* BD500.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BD500.hpp; path = Oric/BD500.hpp; sourceTree = ""; }; 4B7BA03823CEB8D200B98D9E /* DiskController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DiskController.hpp; path = Oric/DiskController.hpp; sourceTree = ""; }; + 4B7BA03923D5302C00B98D9E /* LFSR.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = LFSR.hpp; path = ../../NumberTheory/LFSR.hpp; sourceTree = ""; }; 4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = ""; }; 4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = ""; }; 4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = ""; }; @@ -3186,6 +3187,7 @@ children = ( 4BB697C61D4B558F00248BDF /* Factors.hpp */, 4BF8295F1D8F3C87001BAE39 /* CRC.hpp */, + 4B7BA03923D5302C00B98D9E /* LFSR.hpp */, ); name = NumberTheory; sourceTree = ""; diff --git a/Storage/Disk/Track/PCMSegment.cpp b/Storage/Disk/Track/PCMSegment.cpp index 554882103..43fa3b99a 100644 --- a/Storage/Disk/Track/PCMSegment.cpp +++ b/Storage/Disk/Track/PCMSegment.cpp @@ -9,6 +9,7 @@ #include "PCMSegment.hpp" #include +#include using namespace Storage::Disk; @@ -70,31 +71,33 @@ void PCMSegment::rotate_right(size_t length) { } Storage::Disk::Track::Event PCMSegmentEventSource::get_next_event() { - // track the initial bit pointer for potentially considering whether this was an - // initial index hole or a subsequent one later on + // Track the initial bit pointer for potentially considering whether this was an + // initial index hole or a subsequent one later on. const std::size_t initial_bit_pointer = bit_pointer_; - // if starting from the beginning, pull half a bit backward, as if the initial bit - // is set, it should be in the centre of its window + // If starting from the beginning, pull half a bit backward, as if the initial bit + // is set, it should be in the centre of its window. next_event_.length.length = bit_pointer_ ? 0 : -(segment_->length_of_a_bit.length >> 1); // search for the next bit that is set, if any while(bit_pointer_ < segment_->data.size()) { bool bit = segment_->data[bit_pointer_]; - bit_pointer_++; // so this always points one beyond the most recent bit returned + ++bit_pointer_; // so this always points one beyond the most recent bit returned next_event_.length.length += segment_->length_of_a_bit.length; - // if this bit is set, return the event - if(bit) return next_event_; + // if this bit is set, or is fuzzy and a random bit of 1 is selected, return the event. + if(bit || + (!segment_->fuzzy_mask.empty() && segment_->fuzzy_mask[bit_pointer_] && lfsr_.next()) + ) return next_event_; } - // if the end is reached without a bit being set, it'll be index holes from now on + // If the end is reached without a bit being set, it'll be index holes from now on. next_event_.type = Track::Event::IndexHole; - // test whether this is the very first time that bits have been exhausted. If so then + // Test whether this is the very first time that bits have been exhausted. If so then // allow an extra half bit's length to run from the position of the potential final transition // event to the end of the segment. Otherwise don't allow any extra time, as it's already - // been consumed + // been consumed. if(initial_bit_pointer <= segment_->data.size()) { next_event_.length.length += (segment_->length_of_a_bit.length >> 1); bit_pointer_++; diff --git a/Storage/Disk/Track/PCMSegment.hpp b/Storage/Disk/Track/PCMSegment.hpp index b2a6fb75c..801caada4 100644 --- a/Storage/Disk/Track/PCMSegment.hpp +++ b/Storage/Disk/Track/PCMSegment.hpp @@ -14,6 +14,7 @@ #include #include "../../Storage.hpp" +#include "../../../NumberTheory/LFSR.hpp" #include "Track.hpp" namespace Storage { @@ -39,6 +40,13 @@ struct PCMSegment { */ std::vector data; + /*! + If a segment has a fuzzy mask then anywhere the mask has a value + of @c true, a random bit will be ORd onto whatever is in the + corresponding slot in @c data. + */ + std::vector fuzzy_mask; + /*! Constructs an instance of PCMSegment with the specified @c length_of_a_bit and @c data. @@ -192,6 +200,7 @@ class PCMSegmentEventSource { std::shared_ptr segment_; std::size_t bit_pointer_; Track::Event next_event_; + LFSR lfsr_; }; }