From c7554116360f98f3f6ebcd9179060fffdbae95d7 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:05:22 -0500 Subject: [PATCH 01/11] Slightly improves comments. --- Components/1770/1770.hpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/Components/1770/1770.hpp b/Components/1770/1770.hpp index 59bfac712..5793e2185 100644 --- a/Components/1770/1770.hpp +++ b/Components/1770/1770.hpp @@ -45,20 +45,20 @@ class WD1770: public Storage::Disk::MFMController { void run_for(const Cycles cycles); enum Flag: uint8_t { - NotReady = 0x80, + NotReady = 0x80, // 0x80 MotorOn = 0x80, - WriteProtect = 0x40, - RecordType = 0x20, + WriteProtect = 0x40, // 0x40 + RecordType = 0x20, // 0x20 SpinUp = 0x20, HeadLoaded = 0x20, - RecordNotFound = 0x10, + RecordNotFound = 0x10, // 0x10 SeekError = 0x10, - CRCError = 0x08, - LostData = 0x04, + CRCError = 0x08, // 0x08 + LostData = 0x04, // 0x04 TrackZero = 0x04, - DataRequest = 0x02, + DataRequest = 0x02, // 0x02 Index = 0x02, - Busy = 0x01 + Busy = 0x01 // 0x01 }; /// @returns The current value of the IRQ line output. From f3f8345e5ea54d2187dd83ab6c694a186e66d781 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:05:52 -0500 Subject: [PATCH 02/11] Corrects spelling mistake. --- Storage/Disk/DiskImage/Formats/CPCDSK.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp index 0156e156c..d22de4387 100644 --- a/Storage/Disk/DiskImage/Formats/CPCDSK.cpp +++ b/Storage/Disk/DiskImage/Formats/CPCDSK.cpp @@ -158,7 +158,7 @@ CPCDSK::CPCDSK(const std::string &file_name) : } // As per the weak/fuzzy sector extension, multiple samplings may be stored here. - // Plan to tead as many as there were. + // Plan to read as many as there were. sector.samples.emplace_back(); sector.samples.resize(number_of_samplings); while(number_of_samplings--) { From 5391a699a4208756bbe53c14e5aa24edccafb88b Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:09:11 -0500 Subject: [PATCH 03/11] Adds the ability for a PCMSegment to maintain 'fuzzy' (i.e. random) bits. Implements an LFSR for bit generation. I'm not necessarily happy with the idea of just shoving in a [pseudo-]random number generator in rather than emulating the proper process underneath, but for now I throw my arms up. --- NumberTheory/LFSR.hpp | 60 +++++++++++++++++++ .../Clock Signal.xcodeproj/project.pbxproj | 2 + Storage/Disk/Track/PCMSegment.cpp | 23 +++---- Storage/Disk/Track/PCMSegment.hpp | 9 +++ 4 files changed, 84 insertions(+), 10 deletions(-) create mode 100644 NumberTheory/LFSR.hpp 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_; }; } From 4b2c68c3d394a17546f04ed919cea49de3daf554 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:32:58 -0500 Subject: [PATCH 04/11] Documents `next`. --- NumberTheory/LFSR.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/NumberTheory/LFSR.hpp b/NumberTheory/LFSR.hpp index c03fc45c7..5dca0bb1b 100644 --- a/NumberTheory/LFSR.hpp +++ b/NumberTheory/LFSR.hpp @@ -47,6 +47,10 @@ template > 1) ^ (result * polynomial); From 84f5feab7044b51bd80f1f59fe669e817ef7aef8 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:37:54 -0500 Subject: [PATCH 05/11] Properly flags up overloads. --- Storage/Disk/Encodings/MFM/Encoder.cpp | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Storage/Disk/Encodings/MFM/Encoder.cpp b/Storage/Disk/Encodings/MFM/Encoder.cpp index c25becfca..71a9487ac 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.cpp +++ b/Storage/Disk/Encodings/MFM/Encoder.cpp @@ -27,7 +27,7 @@ class MFMEncoder: public Encoder { MFMEncoder(std::vector &target) : Encoder(target) {} virtual ~MFMEncoder() {} - void add_byte(uint8_t input) { + void add_byte(uint8_t input) final { crc_generator_.add(input); uint16_t spread_value = static_cast( @@ -45,22 +45,22 @@ class MFMEncoder: public Encoder { output_short(output); } - void add_index_address_mark() { + void add_index_address_mark() final { for(int c = 0; c < 3; c++) output_short(MFMIndexSync); add_byte(IndexAddressByte); } - void add_ID_address_mark() { + void add_ID_address_mark() final { output_sync(); add_byte(IDAddressByte); } - void add_data_address_mark() { + void add_data_address_mark() final { output_sync(); add_byte(DataAddressByte); } - void add_deleted_data_address_mark() { + void add_deleted_data_address_mark() final { output_sync(); add_byte(DeletedDataAddressByte); } @@ -76,7 +76,7 @@ class MFMEncoder: public Encoder { private: uint16_t last_output_; - void output_short(uint16_t value) { + void output_short(uint16_t value) final { last_output_ = value; Encoder::output_short(value); } @@ -92,7 +92,7 @@ class FMEncoder: public Encoder { public: FMEncoder(std::vector &target) : Encoder(target) {} - void add_byte(uint8_t input) { + void add_byte(uint8_t input) final { crc_generator_.add(input); output_short( static_cast( @@ -108,25 +108,25 @@ class FMEncoder: public Encoder { )); } - void add_index_address_mark() { + void add_index_address_mark() final { crc_generator_.reset(); crc_generator_.add(IndexAddressByte); output_short(FMIndexAddressMark); } - void add_ID_address_mark() { + void add_ID_address_mark() final { crc_generator_.reset(); crc_generator_.add(IDAddressByte); output_short(FMIDAddressMark); } - void add_data_address_mark() { + void add_data_address_mark() final { crc_generator_.reset(); crc_generator_.add(DataAddressByte); output_short(FMDataAddressMark); } - void add_deleted_data_address_mark() { + void add_deleted_data_address_mark() final { crc_generator_.reset(); crc_generator_.add(DeletedDataAddressByte); output_short(FMDeletedDataAddressMark); From c2bd5be51adb01e06f5c31b0fbaabd292ebf0eb0 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 20:42:51 -0500 Subject: [PATCH 06/11] This seems to be the proper interpretation of speeds? --- Storage/Disk/DiskImage/Formats/STX.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/STX.cpp b/Storage/Disk/DiskImage/Formats/STX.cpp index 9b53ece13..bd9c73b83 100644 --- a/Storage/Disk/DiskImage/Formats/STX.cpp +++ b/Storage/Disk/DiskImage/Formats/STX.cpp @@ -259,11 +259,11 @@ class TrackConstructor { const auto encoder_at_rate = [&encoder, &segments](unsigned int rate) -> Storage::Encodings::MFM::Encoder* { if(!encoder) { segments.emplace_back(); - segments.back().length_of_a_bit = Storage::Time(int(rate), 1); + segments.back().length_of_a_bit = Storage::Time(int(rate + 1), 1); encoder = Storage::Encodings::MFM::GetMFMEncoder(segments.back().data); } else if(segments.back().length_of_a_bit.length != rate) { segments.emplace_back(); - segments.back().length_of_a_bit = Storage::Time(int(rate), 1); + segments.back().length_of_a_bit = Storage::Time(int(rate + 1), 1); encoder->reset_target(segments.back().data); } return encoder.get(); @@ -276,7 +276,7 @@ class TrackConstructor { // assert(location->position >= track_position && location->position < track_data_.end()); // Advance to location.position. - auto default_rate_encoder = encoder_at_rate(128); + auto default_rate_encoder = encoder_at_rate(127); while(track_position < location->position) { default_rate_encoder->add_byte(*track_position); ++track_position; @@ -333,7 +333,7 @@ class TrackConstructor { // Add a CRC only if it fits (TODO: crop if necessary?). if(bytes_to_write & 127) { - default_rate_encoder = encoder_at_rate(128); + default_rate_encoder = encoder_at_rate(127); default_rate_encoder->add_crc((location->sector.status & 0x18) == 0x10); } } break; From b0326530d627b0af0c20827186edb4d43d01d837 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 21:08:15 -0500 Subject: [PATCH 07/11] Allows fuzzy masks to be fed into the FM and MFM encoders. --- Storage/Disk/Encodings/MFM/Encoder.cpp | 23 ++++++++++++----------- Storage/Disk/Encodings/MFM/Encoder.hpp | 11 ++++++----- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/Storage/Disk/Encodings/MFM/Encoder.cpp b/Storage/Disk/Encodings/MFM/Encoder.cpp index 71a9487ac..a11c6134d 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.cpp +++ b/Storage/Disk/Encodings/MFM/Encoder.cpp @@ -24,10 +24,10 @@ enum class SurfaceItem { class MFMEncoder: public Encoder { public: - MFMEncoder(std::vector &target) : Encoder(target) {} + MFMEncoder(std::vector &target, std::vector *fuzzy_target = nullptr) : Encoder(target, fuzzy_target) {} virtual ~MFMEncoder() {} - void add_byte(uint8_t input) final { + void add_byte(uint8_t input, uint8_t fuzzy_mask = 0) final { crc_generator_.add(input); uint16_t spread_value = static_cast( @@ -90,9 +90,9 @@ class MFMEncoder: public Encoder { class FMEncoder: public Encoder { // encodes each 16-bit part as clock, data, clock, data [...] public: - FMEncoder(std::vector &target) : Encoder(target) {} + FMEncoder(std::vector &target, std::vector *fuzzy_target = nullptr) : Encoder(target, fuzzy_target) {} - void add_byte(uint8_t input) final { + void add_byte(uint8_t input, uint8_t fuzzy_mask = 0) final { crc_generator_.add(input); output_short( static_cast( @@ -240,11 +240,12 @@ template std::shared_ptr return std::make_shared(std::move(segment)); } -Encoder::Encoder(std::vector &target) : - target_(&target) {} +Encoder::Encoder(std::vector &target, std::vector *fuzzy_target) : + target_(&target), fuzzy_target_(fuzzy_target) {} -void Encoder::reset_target(std::vector &target) { +void Encoder::reset_target(std::vector &target, std::vector *fuzzy_target) { target_ = ⌖ + fuzzy_target_ = fuzzy_target; } void Encoder::output_short(uint16_t value) { @@ -315,10 +316,10 @@ std::shared_ptr Storage::Encodings::MFM::GetMFMTrackWithSe 12500); // unintelligently: double the single-density bytes/rotation (or: 500kbps @ 300 rpm) } -std::unique_ptr Storage::Encodings::MFM::GetMFMEncoder(std::vector &target) { - return std::make_unique(target); +std::unique_ptr Storage::Encodings::MFM::GetMFMEncoder(std::vector &target, std::vector *fuzzy_target) { + return std::make_unique(target, fuzzy_target); } -std::unique_ptr Storage::Encodings::MFM::GetFMEncoder(std::vector &target) { - return std::make_unique(target); +std::unique_ptr Storage::Encodings::MFM::GetFMEncoder(std::vector &target, std::vector *fuzzy_target) { + return std::make_unique(target, fuzzy_target); } diff --git a/Storage/Disk/Encodings/MFM/Encoder.hpp b/Storage/Disk/Encodings/MFM/Encoder.hpp index 48a538ec8..318e821dc 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.hpp +++ b/Storage/Disk/Encodings/MFM/Encoder.hpp @@ -44,11 +44,11 @@ std::shared_ptr GetFMTrackWithSectors(const std::vector &target); + Encoder(std::vector &target, std::vector *fuzzy_target); virtual ~Encoder() {} - virtual void reset_target(std::vector &target); + virtual void reset_target(std::vector &target, std::vector *fuzzy_target = nullptr); - virtual void add_byte(uint8_t input) = 0; + virtual void add_byte(uint8_t input, uint8_t fuzzy_mask = 0) = 0; virtual void add_index_address_mark() = 0; virtual void add_ID_address_mark() = 0; virtual void add_data_address_mark() = 0; @@ -63,10 +63,11 @@ class Encoder { private: std::vector *target_ = nullptr; + std::vector *fuzzy_target_ = nullptr; }; -std::unique_ptr GetMFMEncoder(std::vector &target); -std::unique_ptr GetFMEncoder(std::vector &target); +std::unique_ptr GetMFMEncoder(std::vector &target, std::vector *fuzzy_target = nullptr); +std::unique_ptr GetFMEncoder(std::vector &target, std::vector *fuzzy_target = nullptr); } } From d27d14d2b03cc7abc2fdc5331697a96a631315ba Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 21:08:49 -0500 Subject: [PATCH 08/11] Supplies fuzzy masks where specified. --- Storage/Disk/DiskImage/Formats/STX.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/Storage/Disk/DiskImage/Formats/STX.cpp b/Storage/Disk/DiskImage/Formats/STX.cpp index bd9c73b83..88cb98ea5 100644 --- a/Storage/Disk/DiskImage/Formats/STX.cpp +++ b/Storage/Disk/DiskImage/Formats/STX.cpp @@ -260,11 +260,11 @@ class TrackConstructor { if(!encoder) { segments.emplace_back(); segments.back().length_of_a_bit = Storage::Time(int(rate + 1), 1); - encoder = Storage::Encodings::MFM::GetMFMEncoder(segments.back().data); + encoder = Storage::Encodings::MFM::GetMFMEncoder(segments.back().data, &segments.back().fuzzy_mask); } else if(segments.back().length_of_a_bit.length != rate) { segments.emplace_back(); segments.back().length_of_a_bit = Storage::Time(int(rate + 1), 1); - encoder->reset_target(segments.back().data); + encoder->reset_target(segments.back().data, &segments.back().fuzzy_mask); } return encoder.get(); }; @@ -323,11 +323,17 @@ class TrackConstructor { // (TODO: is there any benefit to optiming number of calls to encoder_at_rate?) if(!location->sector.timing.empty()) { for(size_t c = 0; c < body_bytes; ++c) { - encoder_at_rate(location->sector.timing[c >> 4])->add_byte(location->sector.contents[c]); + encoder_at_rate(location->sector.timing[c >> 4])->add_byte( + location->sector.contents[c], + location->sector.fuzzy_mask.empty() ? 0x00 : location->sector.fuzzy_mask[c] + ); } } else { for(size_t c = 0; c < body_bytes; ++c) { - default_rate_encoder->add_byte(location->sector.contents[c]); + default_rate_encoder->add_byte( + location->sector.contents[c], + location->sector.fuzzy_mask.empty() ? 0x00 : location->sector.fuzzy_mask[c] + ); } } From da3ee381f4499a15a8add75ad9568f17b1cb20de Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 21:20:21 -0500 Subject: [PATCH 09/11] Attempts a full wiring up of fuzzy bits. --- Storage/Disk/Encodings/MFM/Encoder.cpp | 52 +++++++++++++++++++++----- Storage/Disk/Encodings/MFM/Encoder.hpp | 2 +- 2 files changed, 44 insertions(+), 10 deletions(-) diff --git a/Storage/Disk/Encodings/MFM/Encoder.cpp b/Storage/Disk/Encodings/MFM/Encoder.cpp index a11c6134d..cd22ce84b 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.cpp +++ b/Storage/Disk/Encodings/MFM/Encoder.cpp @@ -29,7 +29,7 @@ class MFMEncoder: public Encoder { void add_byte(uint8_t input, uint8_t fuzzy_mask = 0) final { crc_generator_.add(input); - uint16_t spread_value = + const uint16_t spread_value = static_cast( ((input & 0x01) << 0) | ((input & 0x02) << 1) | @@ -40,9 +40,22 @@ class MFMEncoder: public Encoder { ((input & 0x40) << 6) | ((input & 0x80) << 7) ); - uint16_t or_bits = static_cast((spread_value << 1) | (spread_value >> 1) | (last_output_ << 15)); - uint16_t output = spread_value | ((~or_bits) & 0xaaaa); - output_short(output); + const uint16_t or_bits = static_cast((spread_value << 1) | (spread_value >> 1) | (last_output_ << 15)); + const uint16_t output = spread_value | ((~or_bits) & 0xaaaa); + + const uint16_t spread_mask = + static_cast( + ((fuzzy_mask & 0x01) << 0) | + ((fuzzy_mask & 0x02) << 1) | + ((fuzzy_mask & 0x04) << 2) | + ((fuzzy_mask & 0x08) << 3) | + ((fuzzy_mask & 0x10) << 4) | + ((fuzzy_mask & 0x20) << 5) | + ((fuzzy_mask & 0x40) << 6) | + ((fuzzy_mask & 0x80) << 7) + ); + + output_short(output, spread_mask); } void add_index_address_mark() final { @@ -76,9 +89,9 @@ class MFMEncoder: public Encoder { private: uint16_t last_output_; - void output_short(uint16_t value) final { + void output_short(uint16_t value, uint16_t fuzzy_mask = 0) final { last_output_ = value; - Encoder::output_short(value); + Encoder::output_short(value, fuzzy_mask); } void output_sync() { @@ -105,7 +118,18 @@ class FMEncoder: public Encoder { ((input & 0x40) << 6) | ((input & 0x80) << 7) | 0xaaaa - )); + ), + static_cast( + ((fuzzy_mask & 0x01) << 0) | + ((fuzzy_mask & 0x02) << 1) | + ((fuzzy_mask & 0x04) << 2) | + ((fuzzy_mask & 0x08) << 3) | + ((fuzzy_mask & 0x10) << 4) | + ((fuzzy_mask & 0x20) << 5) | + ((fuzzy_mask & 0x40) << 6) | + ((fuzzy_mask & 0x80) << 7) + ) + ); } void add_index_address_mark() final { @@ -248,10 +272,20 @@ void Encoder::reset_target(std::vector &target, std::vector *fuzzy_t fuzzy_target_ = fuzzy_target; } -void Encoder::output_short(uint16_t value) { +void Encoder::output_short(uint16_t value, uint16_t fuzzy_mask) { + const bool write_fuzzy_bits = fuzzy_mask; + + if(write_fuzzy_bits) { + assert(fuzzy_target_); + + // Zero-fill the bits to date, to cover any shorts written without fuzzy bits. + fuzzy_target_->resize(target_->size()); + } + uint16_t mask = 0x8000; while(mask) { - target_->push_back(!!(value & mask)); + target_->push_back(value & mask); + if(write_fuzzy_bits) fuzzy_target_->push_back(fuzzy_mask & mask); mask >>= 1; } } diff --git a/Storage/Disk/Encodings/MFM/Encoder.hpp b/Storage/Disk/Encodings/MFM/Encoder.hpp index 318e821dc..443846268 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.hpp +++ b/Storage/Disk/Encodings/MFM/Encoder.hpp @@ -53,7 +53,7 @@ class Encoder { virtual void add_ID_address_mark() = 0; virtual void add_data_address_mark() = 0; virtual void add_deleted_data_address_mark() = 0; - virtual void output_short(uint16_t value); + virtual void output_short(uint16_t value, uint16_t fuzzy_mask = 0); /// Outputs the CRC for all data since the last address mask; if @c incorrectly is @c true then outputs an incorrect CRC. void add_crc(bool incorrectly); From b0f7b762af0f3e008abc6942b8b83f8186992088 Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 21:40:30 -0500 Subject: [PATCH 10/11] Adds a possible const. --- NumberTheory/LFSR.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/NumberTheory/LFSR.hpp b/NumberTheory/LFSR.hpp index 5dca0bb1b..9848b8121 100644 --- a/NumberTheory/LFSR.hpp +++ b/NumberTheory/LFSR.hpp @@ -52,7 +52,7 @@ template > 1) ^ (result * polynomial); return result; } From 357137918dd5d41575d0f1fb6e96a125fa8ceb9f Mon Sep 17 00:00:00 2001 From: Thomas Harte Date: Sun, 19 Jan 2020 21:41:10 -0500 Subject: [PATCH 11/11] Adds fuzzy but marking through the GetTrackWithSectors interface. --- Storage/Disk/Encodings/MFM/Encoder.cpp | 34 ++++++++++++++++++++++---- 1 file changed, 29 insertions(+), 5 deletions(-) diff --git a/Storage/Disk/Encodings/MFM/Encoder.cpp b/Storage/Disk/Encodings/MFM/Encoder.cpp index cd22ce84b..aba0812e1 100644 --- a/Storage/Disk/Encodings/MFM/Encoder.cpp +++ b/Storage/Disk/Encodings/MFM/Encoder.cpp @@ -186,6 +186,7 @@ template std::shared_ptr total_sector_bytes += size_t(128 << sector->size) + 2; } + // Seek appropriate gap sizes, if the defaults don't allow all data to fit. while(true) { const size_t size = mark_size + @@ -234,7 +235,6 @@ template std::shared_ptr for(std::size_t c = 0; c < pre_data_mark_bytes; c++) shifter.add_byte(0x00); // Data, if attached. - // TODO: allow for weak/fuzzy data. if(!sector->samples.empty()) { if(sector->is_deleted) shifter.add_deleted_data_address_mark(); @@ -243,8 +243,30 @@ template std::shared_ptr std::size_t c = 0; std::size_t declared_length = static_cast(128 << sector->size); - for(c = 0; c < sector->samples[0].size() && c < declared_length; c++) { - shifter.add_byte(sector->samples[0][c]); + if(sector->samples.size() > 1) { + // For each byte, mark as fuzzy any bits that differ. Which isn't exactly the + // same thing as obeying the multiple samples, as it discards the implied + // probabilities of different values. + for(c = 0; c < sector->samples[0].size() && c < declared_length; c++) { + auto sample_iterator = sector->samples.begin(); + uint8_t value = (*sample_iterator)[c], fuzzy_mask = 0; + + ++sample_iterator; + while(sample_iterator != sector->samples.end()) { + // Mark as fuzzy any bits that differ here from the + // canonical value, and zero them out in the original. + // That might cause them to retrigger, but who cares? + fuzzy_mask |= value ^ (*sample_iterator)[c]; + value &= ~fuzzy_mask; + + ++sample_iterator; + } + shifter.add_byte(sector->samples[0][c], fuzzy_mask); + } + } else { + for(c = 0; c < sector->samples[0].size() && c < declared_length; c++) { + shifter.add_byte(sector->samples[0][c]); + } } for(; c < declared_length; c++) { shifter.add_byte(0x00); @@ -278,8 +300,10 @@ void Encoder::output_short(uint16_t value, uint16_t fuzzy_mask) { if(write_fuzzy_bits) { assert(fuzzy_target_); - // Zero-fill the bits to date, to cover any shorts written without fuzzy bits. + // Zero-fill the bits to date, to cover any shorts written without fuzzy bits, + // and make sure the value has a 0 anywhere it should be fuzzy. fuzzy_target_->resize(target_->size()); + value &= ~fuzzy_mask; } uint16_t mask = 0x8000; @@ -291,7 +315,7 @@ void Encoder::output_short(uint16_t value, uint16_t fuzzy_mask) { } void Encoder::add_crc(bool incorrectly) { - uint16_t crc_value = crc_generator_.get_value(); + const uint16_t crc_value = crc_generator_.get_value(); add_byte(crc_value >> 8); add_byte((crc_value & 0xff) ^ (incorrectly ? 1 : 0)); }