latch nworst thru D->Q (eagle 20250815)

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-08-18 13:27:30 -07:00
parent 872f611fea
commit 70f4bc0459
3 changed files with 150 additions and 123 deletions

View File

@ -35,6 +35,7 @@
#include "PathAnalysisPt.hh"
#include "Tag.hh"
#include "Search.hh"
#include "Latches.hh"
#include "PathEnd.hh"
#include "Path.hh"
@ -219,7 +220,8 @@ PathEnum::reportDiversionPath(Diversion *div)
p->to_string(this).c_str(),
delayAsString(p->arrival(), this),
Path::equal(p, after_div, this) ? " <-after diversion" : "");
if (p != path && network_->isLatchData(p->pin(this)))
if (p != path
&& network_->isLatchData(p->pin(this)))
break;
p = p->prevPath();
}
@ -529,13 +531,23 @@ PathEnum::divSlack(Path *before_div,
const TimingArc *div_arc,
const PathAnalysisPt *path_ap)
{
Arrival arc_arrival = before_div->arrival();
Arrival before_div_arrival = before_div->arrival();
if (div_edge) {
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
div_arc, div_edge,
false, path_ap);
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
return div_arrival - arc_arrival;
if (div_edge->role()->isLatchDtoQ()) {
Arrival div_arrival;
ArcDelay div_delay;
Tag *q_tag;
latches_->latchOutArrival(after_div, div_arc, div_edge, path_ap,
q_tag, div_delay, div_arrival);
return div_arrival - before_div_arrival;
}
else {
ArcDelay div_delay = search_->deratedDelay(div_edge->from(graph_),
div_arc, div_edge,
false, path_ap);
Arrival div_arrival = search_->clkPathArrival(after_div) + div_delay;
return div_arrival - before_div_arrival;
}
}
else {
report()->error(1370, "path diversion missing edge.");
@ -634,39 +646,56 @@ PathEnum::updatePathHeadDelays(PathSeq &paths,
Tag *prev_tag = after_div->tag(this);
ClkInfo *prev_clk_info = prev_tag->clkInfo();
Arrival prev_arrival = search_->clkPathArrival(after_div);
for (int i = paths.size() - 1; i >= 0; i--) {
int path_idx_max = paths.size() - 1;
// paths[0] is the path endpoint
for (int i = path_idx_max; i >= 0; i--) {
Path *path = paths[i];
TimingArc *arc = path->prevArc(this);
Edge *edge = path->prevEdge(this);
if (edge) {
Arrival arrival;
PathAnalysisPt *path_ap = path->pathAnalysisPt(this);
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
arc, edge, false, path_ap);
Arrival arrival = prev_arrival + arc_delay;
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
path->vertex(this)->to_string(this).c_str(),
path->tag(this)->to_string(this).c_str(),
delayAsString(path->arrival(), this),
delayAsString(arrival, this));
path->setArrival(arrival);
prev_arrival = arrival;
const Tag *tag = path->tag(this);
const ClkInfo *clk_info = tag->clkInfo();
if (crprActive()
&& clk_info != prev_clk_info
// D->Q paths use the EN->Q clk info so no need to update.
&& arc->role() != TimingRole::latchDtoQ()) {
// When crpr is enabled the diverion may be from another crpr clk pin,
// so update the tags to use the corresponding ClkInfo.
Tag *updated_tag = search_->findTag(path->transition(this),
path_ap,
prev_clk_info,
tag->isClock(),
tag->inputDelay(),
tag->isSegmentStart(),
tag->states(), false);
path->setTag(updated_tag);
const MinMax *min_max = path->minMax(this);
if (i == path_idx_max
&& edge->role()->isLatchDtoQ()
&& min_max == MinMax::max()) {
ArcDelay arc_delay;
Tag *q_tag;
latches_->latchOutArrival(after_div, arc, edge, path_ap,
q_tag, arc_delay, arrival);
path->setArrival(arrival);
path->setTag(q_tag);
prev_clk_info = q_tag->clkInfo();
}
else {
ArcDelay arc_delay = search_->deratedDelay(edge->from(graph_),
arc, edge, false, path_ap);
arrival = prev_arrival + arc_delay;
path->setArrival(arrival);
const Tag *tag = path->tag(this);
const ClkInfo *clk_info = tag->clkInfo();
if (crprActive()
&& clk_info != prev_clk_info
// D->Q paths use the EN->Q clk info so no need to update.
&& arc->role() != TimingRole::latchDtoQ()) {
// When crpr is enabled the diverion may be from another crpr clk pin,
// so update the tags to use the corresponding ClkInfo.
Tag *updated_tag = search_->findTag(path->transition(this),
path_ap,
prev_clk_info,
tag->isClock(),
tag->inputDelay(),
tag->isSegmentStart(),
tag->states(), false);
path->setTag(updated_tag);
}
debugPrint(debug_, "path_enum", 5, "update arrival %s %s %s -> %s",
path->vertex(this)->to_string(this).c_str(),
path->tag(this)->to_string(this).c_str(),
delayAsString(path->arrival(), this),
delayAsString(arrival, this));
}
prev_arrival = arrival;
}
}
}

View File

@ -549,8 +549,7 @@ ReportPath::reportFull(const PathEndLatchCheck *end) const
if (ignore_clk_latency) {
// Based on reportSrcPath.
reportPathHeader();
reportPath3(end->path(), expanded, false, false, 0.0,
end->sourceClkOffset(this));
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
}
else
reportSrcPath(end, expanded);
@ -716,8 +715,7 @@ ReportPath::reportFull(const PathEndPathDelay *end) const
if (end->ignoreClkLatency(this)) {
// Based on reportSrcPath.
reportPathHeader();
reportPath3(end->path(), expanded, false, false, 0.0,
end->sourceClkOffset(this));
reportPath3(end->path(), expanded, false, end->sourceClkOffset(this));
}
else
reportSrcPath(end, expanded);
@ -935,11 +933,9 @@ ReportPath::reportFull(const PathEndDataCheck *end) const
const ClockEdge *tgt_clk_edge = end->targetClkEdge(this);
float prev = delayAsFloat(clk_arrival) + src_offset;
float offset = prev - delayAsFloat(clk_delay) - tgt_clk_edge->time();
reportPath5(data_clk_path, clk_expanded, clk_expanded.startIndex(),
clk_expanded.size() - 1,
data_clk_path->clkInfo(search_)->isPropagated(), false,
// Delay to startpoint is already included.
prev, offset);
// Delay to startpoint is already included.
reportPath6(data_clk_path, clk_expanded, clk_expanded.startIndex(),
true, false, prev, offset);
}
reportRequired(end, checkRoleReason(end));
reportSlack(end);
@ -1660,7 +1656,7 @@ ReportPath::reportSkewClkPath(const char *arrival_msg,
insertion, latency);
reportClkSrcLatency(insertion, clk_time, early_late);
PathExpanded clk_expanded(clk_path, this);
reportPath2(clk_path, clk_expanded, false, 0.0);
reportPath1(clk_path, clk_expanded, false, 0.0);
}
}
else {
@ -2229,8 +2225,8 @@ ReportPath::reportTgtClk(const PathEnd *end,
PathExpanded clk_expanded(clk_path, this);
float insertion_offset = tgtClkInsertionOffet(clk_path, early_late,
path_ap);
reportPath5(clk_path, clk_expanded, 0, clk_expanded.size() - 1, is_prop,
reportClkPath(), delay_zero, time_offset + insertion_offset);
reportPath6(clk_path, clk_expanded, 0, is_prop, reportClkPath(),
delay_zero, time_offset + insertion_offset);
}
else {
// Output departure.
@ -2377,7 +2373,7 @@ ReportPath::reportGenClkSrcAndPath(const Path *path,
time_offset, clk_used_as_data);
if (path) {
PathExpanded expanded(path, this);
reportPath4(path, expanded, skip_first_path, false, clk_used_as_data,
reportPath2(path, expanded, skip_first_path, clk_used_as_data,
path_time_offset);
}
}
@ -2419,7 +2415,7 @@ ReportPath::reportGenClkSrcPath1(const Clock *clk,
reportClkSrcLatency(insertion, gclk_time, early_late);
}
PathExpanded src_expanded(src_path, this);
reportPath4(src_path, src_expanded, skip_first_path, false,
reportPath2(src_path, src_expanded, skip_first_path,
clk_used_as_data, gclk_time);
if (!clk->isPropagated())
reportLine("clock network delay (ideal)", 0.0,
@ -2603,11 +2599,51 @@ ReportPath::reportPathFull(const Path *path) const
////////////////////////////////////////////////////////////////
// Main entry point for reporting a path.
void
ReportPath::reportPath1(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
float time_offset) const
{
reportPath2(path, expanded, false, clk_used_as_data, time_offset);
}
// Alternate entry point with skip_first_path arg.
void
ReportPath::reportPath2(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool clk_used_as_data,
float time_offset) const
{
bool clk_is_propagated = path->clkInfo(search_)->isPropagated();
bool report_clk_path = (reportClkPath() && clk_is_propagated)
|| clk_used_as_data;
bool propagated_clk = clk_is_propagated || clk_used_as_data;
reportPath4(path, expanded, skip_first_path, propagated_clk,
report_clk_path, time_offset);
}
// Alternate entry point with report_clk_path arg.
void
ReportPath::reportPath3(const Path *path,
const PathExpanded &expanded,
bool report_clk_path,
float time_offset) const
{
bool propagated_clk = path->clkInfo(search_)->isPropagated();
reportPath4(path, expanded, false, propagated_clk,
report_clk_path, time_offset);
}
void
ReportPath::reportPath4(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
{
const Path *d_path, *q_path;
Edge *d_q_edge;
@ -2620,11 +2656,11 @@ ReportPath::reportPath1(const Path *path,
if (latch_enable_path) {
const EarlyLate *early_late = latch_enable_path->minMax(this);
latch_enable_time = search_->clkPathArrival(latch_enable_path);
if (reportClkPath()) {
if (report_clk_path) {
PathExpanded enable_expanded(latch_enable_path, this);
// Report the path to the latch enable.
reportPath2(latch_enable_path, enable_expanded, false,
time_offset);
reportPath5(latch_enable_path, enable_expanded, skip_first_path,
propagated_clk, report_clk_path, time_offset);
}
Arrival time = latch_enable_time + latch_time_given;
Arrival incr = latch_time_given;
@ -2634,86 +2670,45 @@ ReportPath::reportPath1(const Path *path,
reportLine("time borrowed from startpoint", incr, time, early_late);
// Override latch D arrival with enable + given.
reportPathLine(expanded.path(0), delay_zero, time, "latch_D");
bool propagated_clk = path->clkInfo(search_)->isPropagated();
bool report_clk_path = path->isClock(search_) || reportClkPath();
reportPath5(path, expanded, 1, expanded.size() - 1,
propagated_clk, report_clk_path,
reportPath6(path, expanded, 1, propagated_clk, report_clk_path,
latch_enable_time + latch_time_given, time_offset);
}
}
else
reportPath2(path, expanded, clk_used_as_data, time_offset);
}
void
ReportPath::reportPath2(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
float time_offset) const
{
// Report the clock path if the end is a clock or we wouldn't have
// anything to report.
bool report_clk_path = clk_used_as_data
|| (reportClkPath()
&& path->clkInfo(search_)->isPropagated());
reportPath3(path, expanded, clk_used_as_data, report_clk_path,
delay_zero, time_offset);
}
void
ReportPath::reportPath3(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool report_clk_path,
Arrival prev_time,
float time_offset) const
{
bool propagated_clk = clk_used_as_data
|| path->clkInfo(search_)->isPropagated();
size_t path_last_index = expanded.size() - 1;
reportPath5(path, expanded, 0, path_last_index, propagated_clk,
report_clk_path, prev_time, time_offset);
}
void
ReportPath::reportPath4(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool skip_last_path,
bool clk_used_as_data,
float time_offset) const
{
size_t path_first_index = 0;
Arrival prev_time(0.0);
if (skip_first_path) {
path_first_index = 1;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
}
size_t path_last_index = expanded.size() - 1;
if (skip_last_path
&& path_last_index > 1)
path_last_index--;
bool propagated_clk = clk_used_as_data
|| path->clkInfo(search_)->isPropagated();
// Report the clock path if the end is a clock or we wouldn't have
// anything to report.
bool report_clk_path = path->isClock(search_)
|| (reportClkPath() && propagated_clk);
reportPath5(path, expanded, path_first_index, path_last_index,
propagated_clk, report_clk_path, prev_time, time_offset);
reportPath5(path, expanded, skip_first_path, propagated_clk,
report_clk_path, time_offset);
}
void
ReportPath::reportPath5(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const
{
size_t path_first_index = 0;
Arrival prev_time = 0.0;
if (skip_first_path) {
path_first_index = 1;
const Path *start = expanded.path(0);
prev_time = start->arrival() + time_offset;
}
reportPath6(path, expanded, path_first_index, propagated_clk,
report_clk_path, prev_time, time_offset);
}
// This does the real workk of reporting an expanded path.
void
ReportPath::reportPath6(const Path *path,
const PathExpanded &expanded,
size_t path_first_index,
size_t path_last_index,
bool propagated_clk,
bool report_clk_path,
Arrival prev_time,
float time_offset) const
{
size_t path_last_index = expanded.size() - 1;
const MinMax *min_max = path->minMax(this);
DcalcAnalysisPt *dcalc_ap = path->pathAnalysisPt(this)->dcalcAnalysisPt();
DcalcAPIndex ap_index = dcalc_ap->index();
@ -2989,8 +2984,7 @@ ReportPath::reportInputExternalDelay(const Path *first_path,
pathInputDelayRefPath(first_path, input_delay, ref_path);
if (!ref_path.isNull() && reportClkPath()) {
PathExpanded ref_expanded(&ref_path, this);
reportPath3(&ref_path, ref_expanded, false, true,
delay_zero, 0.0);
reportPath3(&ref_path, ref_expanded, true, 0.0);
}
}
float input_arrival =

View File

@ -302,24 +302,28 @@ protected:
float time_offset) const;
void reportPath2(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool clk_used_as_data,
float time_offset) const;
void reportPath3(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool report_clk_path,
Arrival prev_time,
float time_offset) const;
void reportPath4(const Path *path,
const PathExpanded &expanded,
bool clk_used_as_data,
bool skip_first_path,
bool skip_last_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const;
void reportPath5(const Path *path,
const PathExpanded &expanded,
bool skip_first_path,
bool propagated_clk,
bool report_clk_path,
float time_offset) const;
void reportPath6(const Path *path,
const PathExpanded &expanded,
size_t path_first_index,
size_t path_last_index,
bool propagated_clk,
bool report_clk_path,
Arrival prev_time,