Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add clock skew and hold time checks #1360

Merged
merged 22 commits into from
Sep 24, 2024
Merged
Show file tree
Hide file tree
Changes from 20 commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
064cb39
timing: Add hold time to bound of critical path report
rowanG077 Sep 6, 2024
a69d439
timing: Allow critical path traversal for shortest paths
rowanG077 Sep 6, 2024
a7dbfa4
timing: Start identification of min_delay violations
rowanG077 Sep 11, 2024
a2f5724
common: Add some convenience functions for development
rowanG077 Sep 11, 2024
08b1dac
timing: Report min delay violated in timing logger
rowanG077 Sep 11, 2024
020f411
timing: Make hold violations an error
rowanG077 Sep 12, 2024
2a0aa90
timing: Add clock skew to arrival and required time
rowanG077 Sep 12, 2024
094f0cc
timing: integrate c2c delays and cleanup code
rowanG077 Sep 13, 2024
7108396
timing: cleanup clock2clock reporting
rowanG077 Sep 17, 2024
1976ee6
log: Remove bad usage of [[no_return]]
rowanG077 Sep 17, 2024
cf41156
report: Handle new segment types
rowanG077 Sep 17, 2024
a889c3f
report: Handle new segment types
rowanG077 Sep 17, 2024
87f002a
timing: Fix slack calculations
rowanG077 Sep 17, 2024
ac2ab40
timing: minor cleanup and stupid mistake fixups
rowanG077 Sep 17, 2024
35bb3f3
timing: Add safe zero check function for delay_t
rowanG077 Sep 17, 2024
89a9549
router: Enable clock skew analysis during routing
rowanG077 Sep 19, 2024
946e9f7
timing_log: Fix logging indendation to match master
rowanG077 Sep 19, 2024
785bf13
timing: lower clock_delay_fact to 1 to check if CI passes
rowanG077 Sep 19, 2024
2550b14
timing: remove the articial clock delay inflation
rowanG077 Sep 19, 2024
9c97b87
timing: Fix hold slack not matching reported path delay
rowanG077 Sep 20, 2024
3eeb0e2
common: Use `NPNR_ASSERT_FALSE` for unreachable case
rowanG077 Sep 23, 2024
bfb5be3
timing_log: warn on min time violation when timing fail is allowed
rowanG077 Sep 23, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
121 changes: 103 additions & 18 deletions common/kernel/nextpnr_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
#include "archdefs.h"
#include "hashlib.h"
#include "indexed_store.h"
#include "log.h"
#include "nextpnr_base_types.h"
#include "nextpnr_namespaces.h"
#include "property.h"
Expand Down Expand Up @@ -77,10 +78,20 @@ struct PortRef
IdString port;
};

// Zero checking which works regardless if delay_t is floating or integer
inline bool is_zero_delay(delay_t delay)
{
if constexpr (std::is_floating_point<delay_t>::value) {
return std::fpclassify(delay) == FP_ZERO;
} else {
return delay == 0;
}
}

// minimum and maximum delay
struct DelayPair
{
DelayPair() : min_delay(0), max_delay(0) {};
DelayPair() : min_delay(0), max_delay(0){};
explicit DelayPair(delay_t delay) : min_delay(delay), max_delay(delay) {}
DelayPair(delay_t min_delay, delay_t max_delay) : min_delay(min_delay), max_delay(max_delay) {}
delay_t minDelay() const { return min_delay; }
Expand Down Expand Up @@ -180,6 +191,20 @@ enum PortType
PORT_INOUT = 2
};

[[maybe_unused]] static const std::string portType_to_str(PortType typ)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These and other enum to string function where mainly used during development. In the past I have often defined them. And now had to again. I would prefer to keep them even if currently unused because they can be handy during development.

{
switch (typ) {
case PORT_IN:
return "PORT_IN";
case PORT_OUT:
return "PORT_OUT";
case PORT_INOUT:
return "PORT_INOUT";
default:
log_error("Impossible PortType");
rowanG077 marked this conversation as resolved.
Show resolved Hide resolved
}
}

struct PortInfo
{
IdString name;
Expand All @@ -203,12 +228,50 @@ enum TimingPortClass
TMG_IGNORE, // Asynchronous to all clocks, "don't care", and should be ignored (false path) for analysis
};

[[maybe_unused]] static const std::string timingPortClass_to_str(TimingPortClass tmg_class)
{
switch (tmg_class) {
case TMG_CLOCK_INPUT:
return "TMG_CLOCK_INPUT";
case TMG_GEN_CLOCK:
return "TMG_GEN_CLOCK";
case TMG_REGISTER_INPUT:
return "TMG_REGISTER_INPUT";
case TMG_REGISTER_OUTPUT:
return "TMG_REGISTER_OUTPUT";
case TMG_COMB_INPUT:
return "TMG_COMB_INPUT";
case TMG_COMB_OUTPUT:
return "TMG_COMB_OUTPUT";
case TMG_STARTPOINT:
return "TMG_STARTPOINT";
case TMG_ENDPOINT:
return "TMG_ENDPOINT";
case TMG_IGNORE:
return "TMG_IGNORE";
default:
log_error("Impossible TimingPortClass");
}
}

enum ClockEdge
{
RISING_EDGE,
FALLING_EDGE
};

[[maybe_unused]] static const std::string clockEdge_to_str(ClockEdge edge)
{
switch (edge) {
case RISING_EDGE:
return "RISING_EDGE";
case FALLING_EDGE:
return "FALLING_EDGE";
default:
log_error("Impossible ClockEdge");
}
}

struct TimingClockingInfo
{
IdString clock_port; // Port name of clock domain
Expand All @@ -225,7 +288,7 @@ struct PseudoCell
virtual bool getDelay(IdString fromPort, IdString toPort, DelayQuad &delay) const = 0;
virtual TimingPortClass getPortTimingClass(IdString port, int &clockInfoCount) const = 0;
virtual TimingClockingInfo getPortClockingInfo(IdString port, int index) const = 0;
virtual ~PseudoCell() {};
virtual ~PseudoCell(){};
};

struct RegionPlug : PseudoCell
Expand Down Expand Up @@ -345,13 +408,40 @@ struct CriticalPath
// Segment type
enum class Type
{
CLK_TO_Q, // Clock-to-Q delay
SOURCE, // Delayless source
LOGIC, // Combinational logic delay
ROUTING, // Routing delay
SETUP // Setup time in sink
CLK_TO_CLK, // Clock to clock delay
CLK_SKEW, // Clock skew
CLK_TO_Q, // Clock-to-Q delay
SOURCE, // Delayless source
LOGIC, // Combinational logic delay
ROUTING, // Routing delay
SETUP, // Setup time in sink
HOLD // Hold time in sink
};

[[maybe_unused]] static const std::string type_to_str(Type typ)
{
switch (typ) {
case Type::CLK_TO_CLK:
return "clk-to-clk";
case Type::CLK_SKEW:
return "clk-skew";
case Type::CLK_TO_Q:
return "clk-to-q";
case Type::SOURCE:
return "source";
case Type::LOGIC:
return "logic";
case Type::ROUTING:
return "routing";
case Type::SETUP:
return "setup";
case Type::HOLD:
return "hold";
default:
log_error("Impossible Segment::Type");
}
}

// Type
Type type;
// Net name (routing only)
Expand All @@ -361,17 +451,15 @@ struct CriticalPath
// To cell.port
std::pair<IdString, IdString> to;
// Segment delay
DelayPair delay;
delay_t delay;
};

// Clock pair
ClockPair clock_pair;
// Total path delay
DelayPair delay;

// if delay.minDelay() < bound.minDelay() then this is a hold violation
// if delay.maxDelay() > bound.maxDelay() then this is a setup violation
DelayPair bound;
// if sum[segments.delay] < 0 this is a hold/min violation
// if sum[segments.delay] > max_delay this is a setup/max violation
delay_t max_delay;

// Individual path segments
std::vector<Segment> segments;
Expand Down Expand Up @@ -402,14 +490,11 @@ struct TimingResult
// Detailed net timing data
dict<IdString, std::vector<NetSinkTiming>> detailed_net_timings;

// clock to clock delays
dict<std::pair<IdString, IdString>, delay_t> clock_delays;

// Histogram of slack
dict<int, unsigned> slack_histogram;

// TODO: Hold time violations
// dict<IdString, CriticalPath> hold_violations;
// Min delay violations, only hold time for now
std::vector<CriticalPath> min_delay_violations;
};

// Represents the contents of a non-leaf cell in a design
Expand Down
29 changes: 9 additions & 20 deletions common/kernel/report.cc
Original file line number Diff line number Diff line change
Expand Up @@ -73,22 +73,14 @@ static Json::array json_report_critical_paths(const Context *ctx)
{"port", segment.to.second.c_str(ctx)},
{"loc", Json::array({toLoc.x, toLoc.y})}});

auto minDelay = ctx->getDelayNS(segment.delay.minDelay());
auto maxDelay = ctx->getDelayNS(segment.delay.maxDelay());

auto segmentJson =
Json::object({{"delay", Json::array({minDelay, maxDelay})}, {"from", fromJson}, {"to", toJson}});

if (segment.type == CriticalPath::Segment::Type::CLK_TO_Q) {
segmentJson["type"] = "clk-to-q";
} else if (segment.type == CriticalPath::Segment::Type::SOURCE) {
segmentJson["type"] = "source";
} else if (segment.type == CriticalPath::Segment::Type::LOGIC) {
segmentJson["type"] = "logic";
} else if (segment.type == CriticalPath::Segment::Type::SETUP) {
segmentJson["type"] = "setup";
} else if (segment.type == CriticalPath::Segment::Type::ROUTING) {
segmentJson["type"] = "routing";
auto segmentJson = Json::object({
{"delay", ctx->getDelayNS(segment.delay)},
{"from", fromJson},
{"to", toJson},
});

segmentJson["type"] = CriticalPath::Segment::type_to_str(segment.type);
if (segment.type == CriticalPath::Segment::Type::ROUTING) {
segmentJson["net"] = segment.net.c_str(ctx);
}

Expand Down Expand Up @@ -194,10 +186,7 @@ Report JSON structure:
},
"type": <path segment type "clk-to-q", "source", "logic", "routing" or "setup">,
"net": <net name (for routing only!)>,
"delay": [
<minimum segment delay [ns]>,
<maximum segment delay [ns]>,
],
"delay": <segment delay [ns]>,
}
...
]
Expand Down
Loading