rapidus liberty latch D->Q/EN->Q matching

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-03-05 18:41:25 -07:00
parent 8ed837d74b
commit f1e5587fef
6 changed files with 98 additions and 61 deletions

View File

@ -176,6 +176,7 @@ public:
// other conditional timing arcs between the same pins. // other conditional timing arcs between the same pins.
bool isCondDefault() const { return is_cond_default_; } bool isCondDefault() const { return is_cond_default_; }
void setIsCondDefault(bool is_default); void setIsCondDefault(bool is_default);
const FuncExpr *when() const { return attrs_->cond(); }
// SDF IOPATHs match sdfCond. // SDF IOPATHs match sdfCond.
// sdfCond (IOPATH) reuses sdfCondStart (timing check) variable. // sdfCond (IOPATH) reuses sdfCondStart (timing check) variable.
const std::string &sdfCond() const { return attrs_->sdfCondStart(); } const std::string &sdfCond() const { return attrs_->sdfCondStart(); }

View File

@ -1679,22 +1679,30 @@ LibertyCell::makeLatchEnables(Report *report,
{ {
if (hasSequentials() if (hasSequentials()
|| hasInferedRegTimingArcs()) { || hasInferedRegTimingArcs()) {
for (auto en_to_q : timing_arc_sets_) { for (TimingArcSet *d_to_q : timing_arc_sets_) {
if (en_to_q->role() == TimingRole::latchEnToQ()) { if (d_to_q->role() == TimingRole::latchDtoQ()) {
LibertyPort *en = en_to_q->from();
LibertyPort *q = en_to_q->to();
for (TimingArcSet *d_to_q : timingArcSetsTo(q)) {
if (d_to_q->role() == TimingRole::latchDtoQ()
&& condMatch(en_to_q, d_to_q)) {
LibertyPort *d = d_to_q->from(); LibertyPort *d = d_to_q->from();
LibertyPort *q = d_to_q->to();
TimingArcSet *en_to_q = nullptr;
TimingArcSet *en_to_q_when = nullptr;
// Prefer en_to_q with matching when.
for (TimingArcSet *arc_to_q : timingArcSetsTo(q)) {
if (arc_to_q->role() == TimingRole::latchEnToQ()) {
if (condMatch(arc_to_q, d_to_q))
en_to_q_when = arc_to_q;
else
en_to_q = arc_to_q;
}
}
if (en_to_q_when)
en_to_q = en_to_q_when;
if (en_to_q) {
LibertyPort *en = en_to_q->from();
const RiseFall *en_rf = en_to_q->isRisingFallingEdge(); const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
if (en_rf) { if (en_rf) {
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q, TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q, report);
report);
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q, LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
en_to_q, en_to_q, setup_check, debug);
setup_check,
debug);
FuncExpr *en_func = latch_enable->enableFunc(); FuncExpr *en_func = latch_enable->enableFunc();
if (en_func) { if (en_func) {
TimingSense en_sense = en_func->portTimingSense(en); TimingSense en_sense = en_func->portTimingSense(en);
@ -1717,7 +1725,12 @@ LibertyCell::makeLatchEnables(Report *report,
} }
} }
} }
} else
report->warn(1121, "cell %s/%s no latch enable found for %s -> %s.",
library_->name(),
name(),
d->name(),
q->name());
} }
} }
} }
@ -1810,8 +1823,7 @@ LibertyCell::makeLatchEnable(LibertyPort *d,
Debug *debug) Debug *debug)
{ {
FuncExpr *en_func = findLatchEnableFunc(d, en, en_rf); FuncExpr *en_func = findLatchEnableFunc(d, en, en_rf);
latch_enables_.emplace_back(d, en, en_rf, en_func, q, d_to_q, en_to_q, latch_enables_.emplace_back(d, en, en_rf, en_func, q, d_to_q, en_to_q, setup_check);
setup_check);
size_t idx = latch_enables_.size() - 1; size_t idx = latch_enables_.size() - 1;
latch_d_to_q_map_[d_to_q] = idx; latch_d_to_q_map_[d_to_q] = idx;
latch_check_map_[setup_check] = idx; latch_check_map_[setup_check] = idx;

View File

@ -379,6 +379,16 @@ full_name()
to); to);
} }
const std::string
when()
{
const FuncExpr *when = self->when();
if (when)
return when->to_string();
else
return "";
}
TimingArcSeq & TimingArcSeq &
timing_arcs() { return self->arcs(); } timing_arcs() { return self->arcs(); }

View File

@ -126,7 +126,15 @@ proc report_timing_arcs { cell } {
puts "" puts ""
puts "Timing arcs" puts "Timing arcs"
foreach timing_arc $timing_arcs { foreach timing_arc $timing_arcs {
puts [$timing_arc to_string] puts " [$timing_arc to_string]"
puts " [$timing_arc role]"
set when [$timing_arc when]
if { $when != "" } {
puts " when $when"
}
foreach arc [$timing_arc timing_arcs] {
puts " [$arc from_edge] -> [$arc to_edge]"
}
} }
} }
} }

View File

@ -2115,6 +2115,7 @@ LibertyReader::makeTableModels(LibertyCell *cell,
const LibertyGroup *timing_group, const LibertyGroup *timing_group,
TimingArcAttrsPtr timing_attrs) TimingArcAttrsPtr timing_attrs)
{ {
bool found_model = false;
for (const RiseFall *rf : RiseFall::range()) { for (const RiseFall *rf : RiseFall::range()) {
std::string delay_attr_name = "cell_" + rf->to_string_long(); std::string delay_attr_name = "cell_" + rf->to_string_long();
TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf, TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf,
@ -2160,8 +2161,9 @@ LibertyReader::makeTableModels(LibertyCell *cell,
if (delay == nullptr) if (delay == nullptr)
libWarn(1211, timing_group, "missing cell_%s.", rf->name()); libWarn(1211, timing_group, "missing cell_%s.", rf->name());
} }
found_model = true;
} }
else {
std::string constraint_attr_name = rf->to_string_long() + "_constraint"; std::string constraint_attr_name = rf->to_string_long() + "_constraint";
ScaleFactorType scale_factor_type = ScaleFactorType scale_factor_type =
timingTypeScaleFactorType(timing_attrs->timingType()); timingTypeScaleFactorType(timing_attrs->timingType());
@ -2180,9 +2182,14 @@ LibertyReader::makeTableModels(LibertyCell *cell,
ScaleFactorType::unknown); ScaleFactorType::unknown);
timing_attrs->setModel(rf, new CheckTableModel(cell, constraint, timing_attrs->setModel(rf, new CheckTableModel(cell, constraint,
std::move(constraint_sigmas))); std::move(constraint_sigmas)));
found_model = true;
} }
} }
} }
if (!found_model)
libWarn(1311, timing_group, "no table models found in timing group.");
}
bool bool
LibertyReader::isGateTimingType(TimingType timing_type) LibertyReader::isGateTimingType(TimingType timing_type)

View File

@ -207,7 +207,6 @@ TimingArcSet::to_string()
std::string str = from_->name(); std::string str = from_->name();
str += " -> "; str += " -> ";
str += to_->name(); str += to_->name();
str += " " + role()->to_string();
return str; return str;
} }
@ -333,7 +332,7 @@ TimingArcSet::isRisingFallingEdge() const
if (from_rf1 == from_rf2) if (from_rf1 == from_rf2)
return from_rf1; return from_rf1;
} }
if (arcs_.size() == 1) if (arc_count == 1)
return arcs_[0]->fromEdge()->asRiseFall(); return arcs_[0]->fromEdge()->asRiseFall();
else else
return nullptr; return nullptr;