// // LFSR.hpp // Clock Signal // // Created by Thomas Harte on 19/01/2020. // Copyright © 2020 Thomas Harte. All rights reserved. // #pragma once #include #include #include "Sizes.hpp" namespace Numeric { 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: /*! Constructs an LFSR with a random initial value. */ constexpr LFSR() noexcept { // Randomise the value, ensuring it doesn't end up being 0; // don't set any top bits, in case this is a signed type. 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()) * 127 / RAND_MAX); ++value_byte; } } } /*! Constructs an LFSR with the specified initial value. An initial value of 0 is invalid. */ LFSR(IntType initial_value) : value_(initial_value) {} /*! Advances the LSFR, returning either an @c IntType of value @c 1 or @c 0, determining the bit that was just shifted out. */ IntType next() { const auto result = IntType(value_ & 1); value_ = IntType((value_ >> 1) ^ (result * polynomial)); return result; } private: IntType value_ = 0; }; template class LFSRv: public LFSR::type, polynomial> {}; }