Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 210bd5bf9fe3
Choose a base ref
...
head repository: azonenberg/openfpga
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: 83d0d1534c03
Choose a head ref
  • 6 commits
  • 11 files changed
  • 1 contributor

Commits on Jun 1, 2017

  1. Copy the full SHA
    fd146b7 View commit details
  2. Copy the full SHA
    408f4fa View commit details
  3. Copy the full SHA
    0261e03 View commit details
  4. Refactoring: Renamed knapsack solver to reflect the fact that it's no…

    …w a general linear solver
    azonenberg committed Jun 1, 2017
    Copy the full SHA
    d63f47d View commit details

Commits on Jun 2, 2017

  1. Solver: Fixed bug where negative coefficients were treated as zero, c…

    …ausing system to be falsely reported unsolvable
    azonenberg committed Jun 2, 2017
    Copy the full SHA
    a8569f6 View commit details
  2. Copy the full SHA
    83d0d15 View commit details
2 changes: 1 addition & 1 deletion src/gp4tchar/TimingData.cpp
Original file line number Diff line number Diff line change
@@ -26,5 +26,5 @@ using namespace std;
DevkitCalibration::DevkitCalibration()
{
for(int i=0; i<=20; i++)
pinDelays[i] = DelayPair(0, -1);
pinDelays[i] = CombinatorialDelay(0, -1);
}
28 changes: 6 additions & 22 deletions src/gp4tchar/TimingData.h
Original file line number Diff line number Diff line change
@@ -19,35 +19,17 @@
#ifndef TimingData_h
#define TimingData_h

//Delay values
class DelayPair
{
public:
DelayPair(float r = 0, float f = 0)
: rising(r)
, falling(f)
{ }

float rising;
float falling;
};
#include "../xbpar/CombinatorialDelay.h"

//Devkit calibration
class DevkitCalibration
{
public:
DevkitCalibration();

DelayPair pinDelays[21]; //0 is unused so we can use 1-based pin numbering like the chip does
//For now, only pins 3-4-5 and 13-14-15 are used
};

//Propagation delay through a cell (only one output supported for now)
class CellDelay
{
public:
//map from pin name to delay
std::map<std::string, DelayPair> delays;
//Delays from FPGA to DUT pins
CombinatorialDelay pinDelays[21]; //0 is unused so we can use 1-based pin numbering like the chip does
//For now, only pins 3-4-5 and 13-14-15 are used
};

//DUT measurements
@@ -56,11 +38,13 @@ class DeviceProperties
{
public:

/*
//Map from (src, dst) pin to delay tuple
typedef std::map<PinPair, DelayPair> IODelayMap;
//Map from drive strength to delay tuples
std::map<Greenpak4IOB::DriveStrength, IODelayMap> ioDelays;
*/
};

/*
3 changes: 2 additions & 1 deletion src/gp4tchar/main.cpp
Original file line number Diff line number Diff line change
@@ -124,10 +124,11 @@ int main(int argc, char* argv[])
//Measure delay through each element
if(!MeasurePinToPinDelays(sock, hdev))
return 1;

/*
if(!MeasureCrossConnectionDelays(sock, hdev))
return 1;
*/
/*
if(!MeasureLutDelays(sock, hdev))
return 1;
*/
230 changes: 179 additions & 51 deletions src/gp4tchar/measurements.cpp
Original file line number Diff line number Diff line change
@@ -27,14 +27,22 @@ Greenpak4IOB::PullDirection unused_pull = Greenpak4IOB::PULL_DOWN;
Greenpak4IOB::PullStrength unused_drive = Greenpak4IOB::PULL_1M;

bool PromptAndMeasureDelay(Socket& sock, int src, int dst, float& value);
bool MeasureCrossConnectionDelay(Socket& sock, hdevice hdev, unsigned int matrix, unsigned int index, float& delay);
bool MeasureCrossConnectionDelay(
Socket& sock,
hdevice hdev,
unsigned int matrix,
unsigned int index,
unsigned int src,
unsigned int dst,
float& delay);

bool MeasurePinToPinDelay(
Socket& sock,
hdevice hdev,
int src,
int dst,
Greenpak4IOB::DriveStrength drive,
bool schmitt,
float& delay);

bool ProgramAndMeasureDelay(
@@ -57,53 +65,53 @@ bool CalibrateTraceDelays(Socket& sock, hdevice hdev)
return false;

//Set up the variables
KnapsackVariable p3("FPGA pin 3 to DUT rising");
KnapsackVariable p4("FPGA pin 4 to DUT rising");
KnapsackVariable p5("FPGA pin 5 to DUT rising");
KnapsackVariable p13("FPGA pin 13 to DUT rising");
KnapsackVariable p14("FPGA pin 14 to DUT rising");
KnapsackVariable p15("FPGA pin 15 to DUT rising");
EquationVariable p3("FPGA pin 3 to DUT rising");
EquationVariable p4("FPGA pin 4 to DUT rising");
EquationVariable p5("FPGA pin 5 to DUT rising");
EquationVariable p13("FPGA pin 13 to DUT rising");
EquationVariable p14("FPGA pin 14 to DUT rising");
EquationVariable p15("FPGA pin 15 to DUT rising");

//Measure each pair of pins individually
float delay;
if(!PromptAndMeasureDelay(sock, 3, 4, delay))
return false;
KnapsackEquation e1(delay);
Equation e1(delay);
e1.AddVariable(p3);
e1.AddVariable(p4);

if(!PromptAndMeasureDelay(sock, 3, 5, delay))
return false;
KnapsackEquation e2(delay);
Equation e2(delay);
e2.AddVariable(p3);
e2.AddVariable(p5);

if(!PromptAndMeasureDelay(sock, 4, 5, delay))
return false;
KnapsackEquation e3(delay);
Equation e3(delay);
e3.AddVariable(p4);
e3.AddVariable(p5);

if(!PromptAndMeasureDelay(sock, 13, 14, delay))
return false;
KnapsackEquation e4(delay);
Equation e4(delay);
e4.AddVariable(p13);
e4.AddVariable(p14);

if(!PromptAndMeasureDelay(sock, 13, 15, delay))
return false;
KnapsackEquation e5(delay);
Equation e5(delay);
e5.AddVariable(p13);
e5.AddVariable(p15);

if(!PromptAndMeasureDelay(sock, 14, 15, delay))
return false;
KnapsackEquation e6(delay);
Equation e6(delay);
e6.AddVariable(p14);
e6.AddVariable(p15);

//Solve the system
KnapsackProblem p;
EquationSystem p;
p.AddEquation(e1);
p.AddEquation(e2);
p.AddEquation(e3);
@@ -126,18 +134,18 @@ bool CalibrateTraceDelays(Socket& sock, hdevice hdev)
LogNotice("Calculated trace delays:\n");
LogIndenter li2;
for(int i=3; i<=5; i++)
LogNotice("FPGA pin %2d to DUT rising: %.3f ns\n", i, g_devkitCal.pinDelays[i].rising);
LogNotice("FPGA pin %2d to DUT rising: %.3f ns\n", i, g_devkitCal.pinDelays[i].m_rising);
for(int i=13; i<=15; i++)
LogNotice("FPGA pin %2d to DUT rising: %.3f ns\n", i, g_devkitCal.pinDelays[i].rising);
LogNotice("FPGA pin %2d to DUT rising: %.3f ns\n", i, g_devkitCal.pinDelays[i].m_rising);
}

//Write to file
LogNotice("Writing calibration to file pincal.csv\n");
FILE* fp = fopen("pincal.csv", "w");
for(int i=3; i<=5; i++)
fprintf(fp, "%d,%.3f\n", i, g_devkitCal.pinDelays[i].rising);
fprintf(fp, "%d,%.3f\n", i, g_devkitCal.pinDelays[i].m_rising);
for(int i=13; i<=15; i++)
fprintf(fp, "%d,%.3f\n", i, g_devkitCal.pinDelays[i].rising);
fprintf(fp, "%d,%.3f\n", i, g_devkitCal.pinDelays[i].m_rising);
fclose(fp);

//Prompt to put the actual DUT in
@@ -162,7 +170,7 @@ bool ReadTraceDelays()
if( (i > 20) || (i < 1) )
continue;

g_devkitCal.pinDelays[i] = DelayPair(f, -1);
g_devkitCal.pinDelays[i] = CombinatorialDelay(f, -1);

LogNotice("FPGA pin %2d to DUT rising: %.3f ns\n", i, f);
}
@@ -235,13 +243,28 @@ bool MeasurePinToPinDelays(Socket& sock, hdevice hdev)
LogNotice("Measuring pin-to-pin delays (through same crossbar)...\n");
LogIndenter li;

/*
ASSUMPTIONS
x2 I/O buffer is exactly twice the speed of x1
Schmitt trigger vs input buffer is same speed ratio as CoolRunner-II (also 180nm but UMC vs TSMC)
XC2C32A data for reference (-4 speed)
Input buffer delay: 1.3 ns, plus 0.5 ns for LVCMOS33 = 1.8 ns
Schmitt trigger: 3 ns, plus input buffer = 4.8 ns
Output buffer delay: 1.8 ns, plus 1 ns for LVCMOS33 = 2.8 ns
Slow-slew output: 4 ns
Extrapolation: input buffer delay = 0.6 * Schmitt trigger delay
*/

int pins[] = {3, 4, 5, 13, 14, 15};
Greenpak4IOB::DriveStrength drives[] = {Greenpak4IOB::DRIVE_1X, Greenpak4IOB::DRIVE_2X};
//Greenpak4IOB::DriveStrength drives[] = {Greenpak4IOB::DRIVE_1X, Greenpak4IOB::DRIVE_2X};

//TODO: ↓
float delay;
LogNotice("+------+------+--------+--------+--------+--------+----------+----------+\n");
LogNotice("| From | To | x1 ↑ | x1 ↓ | x2 ↑ | x2 ↓ | Delta ↑ | Delta ↓ |\n");
LogNotice("+------+------+--------+--------+--------+--------+----------+----------+\n");
LogNotice("+------+------+--------+----------+----------+-----------+------------+\n");
LogNotice("| From | To | IBUF ↑ | OBUFx1 ↑ | OBUFx2 ↑ | Schmitt ↑ | Crossbar ↑ |\n");
LogNotice("+------+------+--------+----------+----------+-----------+------------+\n");
for(auto src : pins)
{
for(auto dst : pins)
@@ -257,30 +280,71 @@ bool MeasurePinToPinDelays(Socket& sock, hdevice hdev)
if(src > 10 && dst < 10)
continue;

auto sdpair = PinPair(src, dst);
for(auto drive : drives)
{
//Do the measurement
if(!MeasurePinToPinDelay(sock, hdev, src, dst, drive, delay))
return false;
g_deviceProperties.ioDelays[drive][sdpair] = DelayPair(delay, -1);
}

auto x1 = g_deviceProperties.ioDelays[drives[0]][sdpair];
auto x2 = g_deviceProperties.ioDelays[drives[1]][sdpair];
LogNotice("| %4d | %2d | %6.3f | %6.3f | %6.3f | %6.3f | %8.3f | %8.3f |\n",
//Create some variables
EquationVariable ibuf("Input buffer delay");
EquationVariable obuf("Output buffer delay");
EquationVariable schmitt("Schmitt trigger delay");
EquationVariable route("Crossbar delay");

//Set up relationships between the various signals (see assumptions above)
//TODO: FIB probing to get more accurate parameters here
Equation e1(0);
e1.AddVariable(ibuf, 1);
e1.AddVariable(schmitt, -0.6);

//Gather data from the DUT
if(!MeasurePinToPinDelay(sock, hdev, src, dst, Greenpak4IOB::DRIVE_1X, false, delay))
return false;
Equation e2(delay);
e2.AddVariable(ibuf);
e2.AddVariable(route);
e2.AddVariable(obuf);

if(!MeasurePinToPinDelay(sock, hdev, src, dst, Greenpak4IOB::DRIVE_2X, false, delay))
return false;
Equation e3(delay);
e3.AddVariable(ibuf);
e3.AddVariable(route);
e3.AddVariable(obuf, 0.5);

if(!MeasurePinToPinDelay(sock, hdev, src, dst, Greenpak4IOB::DRIVE_2X, true, delay))
return false;
Equation e4(delay);
e4.AddVariable(ibuf);
e4.AddVariable(schmitt);
e4.AddVariable(route);
e4.AddVariable(obuf, 0.5);

//Create and solve the equation system
EquationSystem sys;
sys.AddEquation(e1);
sys.AddEquation(e2);
sys.AddEquation(e3);
sys.AddEquation(e4);
if(!sys.Solve())
return false;

//auto sdpair = PinPair(src, dst);
//g_deviceProperties.ioDelays[drive][sdpair] = CombinatorialDelay(delay, -1);
//auto x1 = g_deviceProperties.ioDelays[drives[0]][sdpair];
//auto x2 = g_deviceProperties.ioDelays[drives[1]][sdpair];

LogNotice("| %4d | %2d | %6.3f | %8.3f | %8.3f | %9.3f | %8.3f |\n",
src,
dst,
x1.rising,
x1.falling,
x2.rising,
x2.falling,
x1.rising - x2.rising,
x1.falling - x2.falling
ibuf.m_value,
obuf.m_value,
obuf.m_value/2,
schmitt.m_value,
route.m_value
);
}
}
LogNotice("+------+------+--------+--------+--------+--------+----------+----------+\n");
LogNotice("+------+------+--------+----------+----------+-----------+------------+\n");

//OBSERVED TREND:
//Left half of device, delays increase as you go HIGHER in the matrix
//Right half of device, delays increase as you go LOWER in the matrix

return true;
}
@@ -294,6 +358,7 @@ bool MeasurePinToPinDelay(
int src,
int dst,
Greenpak4IOB::DriveStrength drive,
bool schmitt,
float& delay)
{
delay = -1;
@@ -309,6 +374,7 @@ bool MeasurePinToPinDelay(
auto vss = device.GetGround();
auto srciob = device.GetIOB(src);
srciob->SetInput("OE", vss);
srciob->SetSchmittTrigger(schmitt);
auto din = srciob->GetOutput("OUT");

//Configure the output pin
@@ -322,15 +388,15 @@ bool MeasurePinToPinDelay(
//Generate a bitstream
vector<uint8_t> bitstream;
device.WriteToBuffer(bitstream, 0, false);
device.WriteToFile("/tmp/test.txt", 0, false); //for debug in case of failure
//device.WriteToFile("/tmp/test.txt", 0, false); //for debug in case of failure

//Get the delay
if(!ProgramAndMeasureDelay(sock, hdev, bitstream, src, dst, delay))
return false;

//Subtract the PCB trace delay at each end of the line
delay -= g_devkitCal.pinDelays[src].rising;
delay -= g_devkitCal.pinDelays[dst].rising;
delay -= g_devkitCal.pinDelays[src].m_rising;
delay -= g_devkitCal.pinDelays[dst].m_rising;

return true;
}
@@ -343,36 +409,98 @@ bool MeasureCrossConnectionDelays(Socket& sock, hdevice hdev)
LogNotice("Measuring cross-connection delays...\n");
LogIndenter li;

float delays[20];

float d;
for(int i=0; i<10; i++)
{
//east
MeasureCrossConnectionDelay(sock, hdev, 0, i, d);
//g_eastXconnDelays[i] = DelayPair(d, -1);
MeasureCrossConnectionDelay(sock, hdev, 0, i, 3, 13, d);
LogNotice("East cross-connection %d from pins 3 to 13: %.3f\n", i, d);
//g_eastXconnDelays[i] = CombinatorialDelay(d, -1);
delays[i] = d;
}

for(int i=0; i<10; i++)
{
//west
MeasureCrossConnectionDelay(sock, hdev, 1, i, d);
//g_westXconnDelays[i] = DelayPair(d, -1);
MeasureCrossConnectionDelay(sock, hdev, 1, i, 13, 3, d);
LogNotice("West cross-connection %d from pins 13 to 3: %.3f\n", i, d);
//g_westXconnDelays[i] = CombinatorialDelay(d, -1);
delays[i+10] = d;
}

//Write the CSV
/*
FILE* fp = fopen("/tmp/xconn-temp.csv", "w");
for(int i=0; i<20; i++)
fprintf(fp, "0,x,%d,%.3f\n", i, delays[i]);
fclose(fp);
*/

return true;
}

bool MeasureCrossConnectionDelay(
Socket& /*sock*/,
hdevice /*hdev*/,
Socket& sock,
hdevice hdev,
unsigned int matrix,
unsigned int index,
unsigned int src,
unsigned int dst,
float& delay)
{
delay = -1;

//Create the device object
Greenpak4Device device(part, unused_pull, unused_drive);
device.SetIOPrecharge(false);
device.SetDisableChargePump(false);
device.SetLDOBypass(false);
device.SetNVMRetryCount(1);

//Configure the input pin
auto vss = device.GetGround();
auto srciob = device.GetIOB(src);
srciob->SetInput("OE", vss);
auto din = srciob->GetOutput("OUT");

//Configure the cross-connection
auto xc = device.GetCrossConnection(matrix, index);
xc->SetInput("I", din);

//Configure the output pin
auto vdd = device.GetPower();
auto dstiob = device.GetIOB(dst);
dstiob->SetInput("IN", xc->GetOutput("O"));
dstiob->SetInput("OE", vdd);
dstiob->SetDriveType(Greenpak4IOB::DRIVE_PUSHPULL);
dstiob->SetDriveStrength(Greenpak4IOB::DRIVE_2X);

//Generate a bitstream
vector<uint8_t> bitstream;
device.WriteToBuffer(bitstream, 0, false);
//device.WriteToFile("/tmp/test.txt", 0, false); //for debug in case of failure

//Get the delay
if(!ProgramAndMeasureDelay(sock, hdev, bitstream, src, dst, delay))
return false;

//Subtract the PCB trace delay at each end of the line
delay -= g_devkitCal.pinDelays[src].m_rising;
delay -= g_devkitCal.pinDelays[dst].m_rising;
return true;

/*
delay = -1;
//Create the device
//Done
string dir = (matrix == 0) ? "east" : "west";
LogNotice("%s %d: %.3f ns\n", dir.c_str(), index, delay);
return true;
*/
}

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
16 changes: 9 additions & 7 deletions src/gp4tchar/solver.cpp
Original file line number Diff line number Diff line change
@@ -23,16 +23,18 @@ using namespace std;

void PrintMatrix(float** rows, int numVars, int numEq);

bool KnapsackProblem::Solve()
bool EquationSystem::Solve()
{
//Create mapping of variables to column IDs
map<KnapsackVariable*, int> colmap;
map<EquationVariable*, int> colmap;
map<int, string> nmap;
int numVars = 0;
for(auto e : m_equations)
{
for(auto v : e->m_variables)
for(auto it : e->m_variables)
{
auto v = it.first;

//already have it
if(colmap.find(v) != colmap.end())
continue;
@@ -66,8 +68,8 @@ bool KnapsackProblem::Solve()
row[i] = 0;

//Add variables (coefficient of 1 to start)
for(auto v : e->m_variables)
row[colmap[v]] = 1;
for(auto it : e->m_variables)
row[colmap[it.first]] = it.second;

//Patch in the sum
row[numVars] = e->m_sum;
@@ -84,12 +86,12 @@ bool KnapsackProblem::Solve()
for(int nvar = 0; nvar < numVars; nvar ++)
{
//If we have a 0 at our diagonal location, look down until we find a row that has a nonzero value
if(rows[nvar][nvar] < epsilon)
if(fabs(rows[nvar][nvar]) < epsilon)
{
bool found = false;
for(int row=nvar+1; row<numEq; row ++)
{
if(rows[row][nvar] > epsilon)
if(fabs(rows[row][nvar]) > epsilon)
{
//LogNotice("Swapping rows %d and %d\n", row, nvar);
float* tmp = rows[nvar];
29 changes: 11 additions & 18 deletions src/gp4tchar/solver.h
Original file line number Diff line number Diff line change
@@ -19,20 +19,13 @@
#ifndef solver_h
#define solver_h

/*
This file contains a solver for the "multiple knapsack problem".
More formally, given a series of sums of the form a + b + c = 1234, where a/b/c are unknown variables that appear at
most once in any given sum (and always with a coefficient of 1), solve for the individual variables.
*/

/**
@brief A single named variable
*/
class KnapsackVariable
class EquationVariable
{
public:
KnapsackVariable(std::string n)
EquationVariable(std::string n)
: m_name(n)
, m_value(0)
{ }
@@ -46,32 +39,32 @@ class KnapsackVariable
/*
@brief A single equation in the system of equations
*/
class KnapsackEquation
class Equation
{
public:
KnapsackEquation(float sum = 0)
Equation(float sum = 0)
: m_sum(sum)
{}

void AddVariable(KnapsackVariable& v)
{ m_variables.emplace(&v); }
void AddVariable(EquationVariable& v, float coeff = 1)
{ m_variables[&v] = coeff; }

std::set<KnapsackVariable*> m_variables;
std::map<EquationVariable*, float> m_variables;
float m_sum;
};

/**
@brief A problem for the solver
@brief A system of linear equations of the form a*v1 + b*v2 + c*v3 = n
*/
class KnapsackProblem
class EquationSystem
{
public:
void AddEquation(KnapsackEquation& e)
void AddEquation(Equation& e)
{ m_equations.emplace(&e); }

bool Solve();

std::set<KnapsackEquation*> m_equations;
std::set<Equation*> m_equations;
};

#endif
2 changes: 1 addition & 1 deletion src/greenpak4/Greenpak4Device.cpp
Original file line number Diff line number Diff line change
@@ -1024,7 +1024,7 @@ bool Greenpak4Device::WriteToBuffer(vector<uint8_t>& bitstream, uint8_t userid,
return false;
}

for(int index=0; index<m_bitlen; index++)
for(size_t index=0; index<m_bitlen; index++)
{
int byteindex = index / 8;
if(byteindex >= (int)bitstream.size())
5 changes: 4 additions & 1 deletion src/greenpak4/Greenpak4IOB.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***********************************************************************************************************************
* Copyright (C) 2016 Andrew Zonenberg and contributors *
* Copyright (C) 2016-2017 Andrew Zonenberg and contributors *
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
@@ -131,6 +131,9 @@ class Greenpak4IOB : public Greenpak4BitstreamEntity
void SetDriveStrength(DriveStrength strength)
{ m_driveStrength = strength; }

void SetSchmittTrigger(bool schmitt)
{ m_schmittTrigger = schmitt; }

//Get our source (used for DRC)
Greenpak4EntityOutput GetOutputSignal()
{ return m_outputSignal; }
2 changes: 1 addition & 1 deletion src/greenpak4/Greenpak4LUT.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***********************************************************************************************************************
* Copyright (C) 2016 Andrew Zonenberg and contributors *
* Copyright (C) 2016-2017 Andrew Zonenberg and contributors *
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
35 changes: 35 additions & 0 deletions src/xbpar/CombinatorialDelay.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/***********************************************************************************************************************
* Copyright (C) 2016-2017 Andrew Zonenberg and contributors *
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied *
* warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for *
* more details. *
* *
* You should have received a copy of the GNU Lesser General Public License along with this program; if not, you may *
* find one here: *
* https://www.gnu.org/licenses/old-licenses/lgpl-2.1.txt *
* or you may search the http://www.gnu.org website for the version 2.1 license, or you may write to the Free Software *
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA *
**********************************************************************************************************************/

#ifndef CombinatorialDelay_h
#define CombinatorialDelay_h

//Combinatorial delay values
class CombinatorialDelay
{
public:
CombinatorialDelay(float r = 0, float f = 0)
: m_rising(r)
, m_falling(f)
{ }

float m_rising;
float m_falling;
};

#endif
4 changes: 3 additions & 1 deletion src/xbpar/xbpar.h
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/***********************************************************************************************************************
* Copyright (C) 2016 Andrew Zonenberg and contributors *
* Copyright (C) 2016-2017 Andrew Zonenberg and contributors *
* *
* This program is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General *
* Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) *
@@ -19,6 +19,8 @@
#ifndef xbpar_h
#define xbpar_h

#include "CombinatorialDelay.h"

#include "PARGraph.h"
#include "PARGraphNode.h"