mirror of
https://github.com/TomHarte/CLK.git
synced 2024-12-23 20:29:42 +00:00
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.
This commit is contained in:
parent
f3f8345e5e
commit
5391a699a4
60
NumberTheory/LFSR.hpp
Normal file
60
NumberTheory/LFSR.hpp
Normal file
@ -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 <typename IntType> struct LSFRPolynomial {
|
||||
};
|
||||
|
||||
// The following were taken 'at random' from https://users.ece.cmu.edu/~koopman/lfsr/index.html
|
||||
template <> struct LSFRPolynomial<uint64_t> {
|
||||
static constexpr uint64_t value = 0x80000000000019E2;
|
||||
};
|
||||
|
||||
template <> struct LSFRPolynomial<uint32_t> {
|
||||
static constexpr uint32_t value = 0x80000C34;
|
||||
};
|
||||
|
||||
template <> struct LSFRPolynomial<uint16_t> {
|
||||
static constexpr uint16_t value = 0x853E;
|
||||
};
|
||||
|
||||
template <> struct LSFRPolynomial<uint8_t> {
|
||||
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 <typename IntType = uint64_t, IntType polynomial = LSFRPolynomial<IntType>::value> class LFSR {
|
||||
public:
|
||||
LFSR() {
|
||||
// Randomise the value, ensuring it doesn't end up being 0.
|
||||
while(!value_) {
|
||||
uint8_t *value_byte = reinterpret_cast<uint8_t *>(&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 */
|
@ -1185,6 +1185,7 @@
|
||||
4B7BA03523CEB86000B98D9E /* BD500.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = BD500.cpp; path = Oric/BD500.cpp; sourceTree = "<group>"; };
|
||||
4B7BA03623CEB86000B98D9E /* BD500.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = BD500.hpp; path = Oric/BD500.hpp; sourceTree = "<group>"; };
|
||||
4B7BA03823CEB8D200B98D9E /* DiskController.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = DiskController.hpp; path = Oric/DiskController.hpp; sourceTree = "<group>"; };
|
||||
4B7BA03923D5302C00B98D9E /* LFSR.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; name = LFSR.hpp; path = ../../NumberTheory/LFSR.hpp; sourceTree = "<group>"; };
|
||||
4B7F188C2154825D00388727 /* MasterSystem.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MasterSystem.cpp; sourceTree = "<group>"; };
|
||||
4B7F188D2154825D00388727 /* MasterSystem.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = MasterSystem.hpp; sourceTree = "<group>"; };
|
||||
4B7F1895215486A100388727 /* StaticAnalyser.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = StaticAnalyser.hpp; sourceTree = "<group>"; };
|
||||
@ -3186,6 +3187,7 @@
|
||||
children = (
|
||||
4BB697C61D4B558F00248BDF /* Factors.hpp */,
|
||||
4BF8295F1D8F3C87001BAE39 /* CRC.hpp */,
|
||||
4B7BA03923D5302C00B98D9E /* LFSR.hpp */,
|
||||
);
|
||||
name = NumberTheory;
|
||||
sourceTree = "<group>";
|
||||
|
@ -9,6 +9,7 @@
|
||||
#include "PCMSegment.hpp"
|
||||
|
||||
#include <cassert>
|
||||
#include <cstdlib>
|
||||
|
||||
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_++;
|
||||
|
@ -14,6 +14,7 @@
|
||||
#include <vector>
|
||||
|
||||
#include "../../Storage.hpp"
|
||||
#include "../../../NumberTheory/LFSR.hpp"
|
||||
#include "Track.hpp"
|
||||
|
||||
namespace Storage {
|
||||
@ -39,6 +40,13 @@ struct PCMSegment {
|
||||
*/
|
||||
std::vector<bool> 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<bool> 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<PCMSegment> segment_;
|
||||
std::size_t bit_pointer_;
|
||||
Track::Event next_event_;
|
||||
LFSR<uint64_t> lfsr_;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user