mirror of
https://github.com/davidgiven/fluxengine.git
synced 2025-10-31 11:17:01 -07:00
Extend the flux pattern matcher to support trailing zeroes.
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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(¬matching[4], clock));
|
||||
assert(fp.matches(&closematch1[4], clock));
|
||||
assert(fp.matches(&closematch2[4], clock));
|
||||
assert(fp.matches(&matching[4], clock), 2U);
|
||||
assert(fp.matches(¬matching[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(¬matching[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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user