Extend the flux pattern matcher to support trailing zeroes.

This commit is contained in:
David Given
2019-04-25 23:18:47 +02:00
parent eefecc87fe
commit 643288bef8
3 changed files with 149 additions and 51 deletions

View File

@@ -6,11 +6,12 @@
#include "fmt/format.h"
#include <numeric>
#include <math.h>
#include <strings.h>
static DoubleFlag clockDecodeThreshold(
{ "--bit-error-threshold" },
"Amount of error to tolerate in pulse timing.",
0.30);
0.10);
static DoubleFlag clockIntervalBias(
{ "--clock-interval-bias" },
@@ -54,12 +55,13 @@ unsigned FluxmapReader::readNextMatchingOpcode(uint8_t opcode)
}
FluxPattern::FluxPattern(unsigned bits, uint64_t pattern):
FluxMatcher(bits)
_bits(bits)
{
const uint64_t TOPBIT = 1ULL << 63;
assert(pattern != 0);
unsigned lowbit = ffsll(pattern)-1;
while (!(pattern & TOPBIT))
pattern <<= 1;
@@ -76,17 +78,25 @@ FluxPattern::FluxPattern(unsigned bits, uint64_t pattern):
_intervals.push_back(interval);
_length += interval;
}
if (lowbit)
{
_lowzero = true;
/* Note that length does *not* include this interval. */
_intervals.push_back(lowbit + 1);
}
}
unsigned FluxPattern::matches(const unsigned* end, double& clock) const
{
const unsigned* start = end - _intervals.size();
unsigned candidatelength = std::accumulate(start, end, 0);
unsigned candidatelength = std::accumulate(start, end - _lowzero, 0);
if (!candidatelength)
return 0;
clock = (double)candidatelength / (double)_length;
for (unsigned i=0; i<_intervals.size(); i++)
unsigned exactIntervals = _intervals.size() - _lowzero;
for (unsigned i=0; i<exactIntervals; i++)
{
double ii = clock * (double)_intervals[i];
double ci = (double)start[i];
@@ -95,11 +105,18 @@ unsigned FluxPattern::matches(const unsigned* end, double& clock) const
return 0;
}
if (_lowzero)
{
double ii = clock * (double)_intervals[exactIntervals];
double ci = (double)start[exactIntervals];
if (ci < (ii - clockDecodeThreshold*ii/ci))
return 0;
}
return _intervals.size();
}
FluxPatterns::FluxPatterns(unsigned bits, std::initializer_list<uint64_t> patterns):
FluxMatcher(bits)
FluxPatterns::FluxPatterns(unsigned bits, std::initializer_list<uint64_t> patterns)
{
_intervals = 0;
for (uint64_t p : patterns)
@@ -121,6 +138,25 @@ unsigned FluxPatterns::matches(const unsigned* intervals, double& clock) const
return 0;
}
FluxMatchers::FluxMatchers(const std::initializer_list<const FluxMatcher*> matchers):
_matchers(matchers)
{
_intervals = 0;
for (const auto* matcher : matchers)
_intervals = std::max(_intervals, matcher->intervals());
}
unsigned FluxMatchers::matches(const unsigned* intervals, double& clock) const
{
for (const auto* matcher : _matchers)
{
unsigned m = matcher->matches(intervals, clock);
if (m)
return m;
}
return 0;
}
void FluxmapReader::seek(nanoseconds_t ns)
{
unsigned ticks = ns / NS_PER_TICK;
@@ -143,23 +179,14 @@ nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern)
unsigned candidates[intervalCount+1];
Fluxmap::Position positions[intervalCount+1];
for (unsigned& i : candidates)
i = 0;
for (Fluxmap::Position& p : positions)
p = tell();
for (unsigned i=0; i<=intervalCount; i++)
{
positions[i] = tell();
candidates[i] = readNextMatchingOpcode(F_OP_PULSE);
}
while (!eof())
{
unsigned interval = readNextMatchingOpcode(F_OP_PULSE);
for (unsigned i=0; i<intervalCount; i++)
{
positions[i] = positions[i+1];
candidates[i] = candidates[i+1];
}
positions[intervalCount] = tell();
candidates[intervalCount] = interval;
double clock;
unsigned m = pattern.matches(&candidates[intervalCount+1], clock);
if (m)
@@ -167,6 +194,15 @@ nanoseconds_t FluxmapReader::seekToPattern(const FluxMatcher& pattern)
seek(positions[intervalCount-m]);
return clock * NS_PER_TICK;
}
for (unsigned i=0; i<intervalCount; i++)
{
positions[i] = positions[i+1];
candidates[i] = candidates[i+1];
}
candidates[intervalCount] = readNextMatchingOpcode(F_OP_PULSE);
positions[intervalCount] = tell();
}
return 0;

View File

@@ -7,21 +7,11 @@
class FluxMatcher
{
public:
FluxMatcher(unsigned bits):
_bits(bits)
{}
virtual ~FluxMatcher() {}
/* Returns the number of intervals matched */
virtual unsigned matches(const unsigned* intervals, double& clock) const = 0;
virtual unsigned intervals() const = 0;
unsigned bits() const
{ return _bits; }
protected:
unsigned _bits;
};
class FluxPattern : public FluxMatcher
@@ -37,6 +27,8 @@ public:
private:
std::vector<unsigned> _intervals;
unsigned _length;
unsigned _bits;
bool _lowzero = false;
public:
friend void test_patternconstruction();
@@ -58,6 +50,21 @@ private:
std::vector<std::unique_ptr<FluxPattern>> _patterns;
};
class FluxMatchers : public FluxMatcher
{
public:
FluxMatchers(const std::initializer_list<const FluxMatcher*> matchers);
unsigned matches(const unsigned* intervals, double& clock) const override;
unsigned intervals() const override
{ return _intervals; }
private:
unsigned _intervals;
std::vector<const FluxMatcher*> _matchers;
};
class FluxmapReader
{
public:
@@ -84,6 +91,7 @@ public:
Fluxmap::Position tell() const
{ return _pos; }
/* Important! You can only reliably seek to 1 bits. */
void seek(const Fluxmap::Position& pos)
{
_pos = pos;
@@ -93,7 +101,9 @@ public:
int readOpcode(unsigned& ticks);
unsigned readNextMatchingOpcode(uint8_t opcode);
/* Important! You can only reliably seek to 1 bits. */
void seek(nanoseconds_t ns);
void seekToIndexMark();
nanoseconds_t seekToPattern(const FluxMatcher& pattern);

View File

@@ -1,50 +1,86 @@
#include "globals.h"
#include "fluxmap.h"
#include "fluxmapreader.h"
#include <assert.h>
#include <sstream>
typedef std::vector<unsigned> ivector;
namespace std {
template <class T>
static std::string to_string(const std::vector<T>& vector)
{
std::stringstream s;
s << "vector{";
bool first = true;
for (const T& t : vector)
{
if (!first)
s << ", ";
first = false;
s << t;
}
s << "}";
return s.str();
}
}
#undef assert
#define assert(got, expected) assertImpl(__FILE__, __LINE__, got, expected)
template <class T>
static void assertImpl(const char filename[], int linenumber, T got, T expected)
{
if (got != expected)
{
std::cerr << "assertion failure at "
<< filename << ":" << linenumber
<< ": got " << std::to_string(got)
<< ", expected " << std::to_string(expected)
<< std::endl;
abort();
}
}
void test_patternconstruction()
{
{
FluxPattern fp(16, 0x0003);
assert(fp._bits == 16);
assert(fp._intervals == ivector{ 1 });
assert(fp._bits, 16U);
assert(fp._intervals, ivector{ 1 });
}
{
FluxPattern fp(16, 0xc000);
assert(fp._bits == 16);
assert(fp._intervals == ivector{ 1 });
assert(fp._bits, 16U);
assert(fp._intervals, (ivector{ 1, 15 }));
}
{
FluxPattern fp(16, 0x0050);
assert(fp._bits == 16);
assert(fp._intervals == ivector{ 2 });
assert(fp._bits, 16U);
assert(fp._intervals, (ivector{ 2, 5 }));
}
{
FluxPattern fp(16, 0x0070);
assert(fp._bits == 16);
assert((fp._intervals == ivector{ 1, 1 }));
assert(fp._bits, 16U);
assert(fp._intervals, (ivector{ 1, 1, 5 }));
}
{
FluxPattern fp(16, 0x0070);
assert(fp._bits == 16);
assert((fp._intervals == ivector{ 1, 1 }));
assert(fp._bits, 16U);
assert(fp._intervals, (ivector{ 1, 1, 5 }));
}
{
FluxPattern fp(16, 0x0110);
assert(fp._bits == 16);
assert((fp._intervals == ivector{ 4 }));
assert(fp._bits, 16U);
assert(fp._intervals, (ivector{ 4, 5 }));
}
}
void test_patternmatching()
void test_patternmatchingwithouttrailingzeros()
{
FluxPattern fp(16, 0x000b);
const unsigned matching[] = { 100, 100, 200, 100 };
@@ -53,10 +89,25 @@ void test_patternmatching()
const unsigned closematch2[] = { 110, 110, 220, 110 };
double clock;
assert(fp.matches(&matching[4], clock));
assert(!fp.matches(&notmatching[4], clock));
assert(fp.matches(&closematch1[4], clock));
assert(fp.matches(&closematch2[4], clock));
assert(fp.matches(&matching[4], clock), 2U);
assert(fp.matches(&notmatching[4], clock), 0U);
assert(fp.matches(&closematch1[4], clock), 2U);
assert(fp.matches(&closematch2[4], clock), 2U);
}
void test_patternmatchingwithtrailingzeros()
{
FluxPattern fp(16, 0x0016);
const unsigned matching[] = { 100, 100, 200, 100, 200 };
const unsigned notmatching[] = { 100, 200, 100, 100, 100 };
const unsigned closematch1[] = { 90, 90, 180, 90, 200 };
const unsigned closematch2[] = { 110, 110, 220, 110, 220 };
double clock;
assert(fp.matches(&matching[5], clock), 3U);
assert(fp.matches(&notmatching[5], clock), 0U);
assert(fp.matches(&closematch1[5], clock), 3U);
assert(fp.matches(&closematch2[5], clock), 3U);
}
void test_patternsmatching()
@@ -66,14 +117,15 @@ void test_patternsmatching()
const unsigned matching2[] = { 100, 100, 200, 200 };
double clock;
assert(fp.matches(&matching1[4], clock));
assert(fp.matches(&matching2[4], clock));
assert(fp.matches(&matching1[4], clock), 2U);
assert(fp.matches(&matching2[4], clock), 2U);
}
int main(int argc, const char* argv[])
{
test_patternconstruction();
test_patternmatching();
test_patternmatchingwithouttrailingzeros();
test_patternmatchingwithtrailingzeros();
test_patternsmatching();
return 0;
}