rapidus liberty latch D->Q/EN->Q matching
Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
parent
8ed837d74b
commit
f1e5587fef
|
|
@ -176,6 +176,7 @@ public:
|
|||
// other conditional timing arcs between the same pins.
|
||||
bool isCondDefault() const { return is_cond_default_; }
|
||||
void setIsCondDefault(bool is_default);
|
||||
const FuncExpr *when() const { return attrs_->cond(); }
|
||||
// SDF IOPATHs match sdfCond.
|
||||
// sdfCond (IOPATH) reuses sdfCondStart (timing check) variable.
|
||||
const std::string &sdfCond() const { return attrs_->sdfCondStart(); }
|
||||
|
|
|
|||
|
|
@ -1679,45 +1679,58 @@ LibertyCell::makeLatchEnables(Report *report,
|
|||
{
|
||||
if (hasSequentials()
|
||||
|| hasInferedRegTimingArcs()) {
|
||||
for (auto en_to_q : timing_arc_sets_) {
|
||||
if (en_to_q->role() == TimingRole::latchEnToQ()) {
|
||||
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();
|
||||
const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
|
||||
if (en_rf) {
|
||||
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q,
|
||||
report);
|
||||
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
|
||||
en_to_q,
|
||||
setup_check,
|
||||
debug);
|
||||
FuncExpr *en_func = latch_enable->enableFunc();
|
||||
if (en_func) {
|
||||
TimingSense en_sense = en_func->portTimingSense(en);
|
||||
if (en_sense == TimingSense::positive_unate
|
||||
&& en_rf != RiseFall::rise())
|
||||
report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.",
|
||||
library_->name(),
|
||||
name(),
|
||||
en->name(),
|
||||
q->name(),
|
||||
en_rf == RiseFall::rise()?"rising":"falling");
|
||||
else if (en_sense == TimingSense::negative_unate
|
||||
&& en_rf != RiseFall::fall())
|
||||
report->warn(1115, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.",
|
||||
library_->name(),
|
||||
name(),
|
||||
en->name(),
|
||||
q->name(),
|
||||
en_rf == RiseFall::rise()?"rising":"falling");
|
||||
}
|
||||
for (TimingArcSet *d_to_q : timing_arc_sets_) {
|
||||
if (d_to_q->role() == TimingRole::latchDtoQ()) {
|
||||
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();
|
||||
if (en_rf) {
|
||||
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q, report);
|
||||
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
|
||||
en_to_q, setup_check, debug);
|
||||
FuncExpr *en_func = latch_enable->enableFunc();
|
||||
if (en_func) {
|
||||
TimingSense en_sense = en_func->portTimingSense(en);
|
||||
if (en_sense == TimingSense::positive_unate
|
||||
&& en_rf != RiseFall::rise())
|
||||
report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.",
|
||||
library_->name(),
|
||||
name(),
|
||||
en->name(),
|
||||
q->name(),
|
||||
en_rf == RiseFall::rise()?"rising":"falling");
|
||||
else if (en_sense == TimingSense::negative_unate
|
||||
&& en_rf != RiseFall::fall())
|
||||
report->warn(1115, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.",
|
||||
library_->name(),
|
||||
name(),
|
||||
en->name(),
|
||||
q->name(),
|
||||
en_rf == RiseFall::rise()?"rising":"falling");
|
||||
}
|
||||
}
|
||||
}
|
||||
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)
|
||||
{
|
||||
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,
|
||||
setup_check);
|
||||
latch_enables_.emplace_back(d, en, en_rf, en_func, q, d_to_q, en_to_q, setup_check);
|
||||
size_t idx = latch_enables_.size() - 1;
|
||||
latch_d_to_q_map_[d_to_q] = idx;
|
||||
latch_check_map_[setup_check] = idx;
|
||||
|
|
|
|||
|
|
@ -379,6 +379,16 @@ full_name()
|
|||
to);
|
||||
}
|
||||
|
||||
const std::string
|
||||
when()
|
||||
{
|
||||
const FuncExpr *when = self->when();
|
||||
if (when)
|
||||
return when->to_string();
|
||||
else
|
||||
return "";
|
||||
}
|
||||
|
||||
TimingArcSeq &
|
||||
timing_arcs() { return self->arcs(); }
|
||||
|
||||
|
|
|
|||
|
|
@ -126,7 +126,15 @@ proc report_timing_arcs { cell } {
|
|||
puts ""
|
||||
puts "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]"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2059,7 +2059,7 @@ LibertyReader::makeTimingModels(LibertyCell *cell,
|
|||
const LibertyGroup *timing_group,
|
||||
TimingArcAttrsPtr timing_attrs)
|
||||
{
|
||||
switch (cell->libertyLibrary()->delayModelType()) {
|
||||
switch (cell->libertyLibrary()->delayModelType()) {
|
||||
case DelayModelType::cmos_linear:
|
||||
makeLinearModels(cell, timing_group, timing_attrs);
|
||||
break;
|
||||
|
|
@ -2115,6 +2115,7 @@ LibertyReader::makeTableModels(LibertyCell *cell,
|
|||
const LibertyGroup *timing_group,
|
||||
TimingArcAttrsPtr timing_attrs)
|
||||
{
|
||||
bool found_model = false;
|
||||
for (const RiseFall *rf : RiseFall::range()) {
|
||||
std::string delay_attr_name = "cell_" + rf->to_string_long();
|
||||
TableModel *delay = readGateTableModel(timing_group, delay_attr_name.c_str(), rf,
|
||||
|
|
@ -2160,30 +2161,36 @@ LibertyReader::makeTableModels(LibertyCell *cell,
|
|||
if (delay == nullptr)
|
||||
libWarn(1211, timing_group, "missing cell_%s.", rf->name());
|
||||
}
|
||||
found_model = true;
|
||||
}
|
||||
|
||||
std::string constraint_attr_name = rf->to_string_long() + "_constraint";
|
||||
ScaleFactorType scale_factor_type =
|
||||
timingTypeScaleFactorType(timing_attrs->timingType());
|
||||
TableModel *constraint = readCheckTableModel(timing_group,
|
||||
constraint_attr_name.c_str(),
|
||||
rf, TableTemplateType::delay,
|
||||
time_scale_, scale_factor_type);
|
||||
if (constraint) {
|
||||
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string_long()
|
||||
+ "_constraint";
|
||||
TableModelsEarlyLate constraint_sigmas =
|
||||
readEarlyLateTableModels(timing_group,
|
||||
constraint_sigma_attr_name.c_str(),
|
||||
rf, TableTemplateType::delay,
|
||||
time_scale_,
|
||||
ScaleFactorType::unknown);
|
||||
timing_attrs->setModel(rf, new CheckTableModel(cell, constraint,
|
||||
std::move(constraint_sigmas)));
|
||||
else {
|
||||
std::string constraint_attr_name = rf->to_string_long() + "_constraint";
|
||||
ScaleFactorType scale_factor_type =
|
||||
timingTypeScaleFactorType(timing_attrs->timingType());
|
||||
TableModel *constraint = readCheckTableModel(timing_group,
|
||||
constraint_attr_name.c_str(),
|
||||
rf, TableTemplateType::delay,
|
||||
time_scale_, scale_factor_type);
|
||||
if (constraint) {
|
||||
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string_long()
|
||||
+ "_constraint";
|
||||
TableModelsEarlyLate constraint_sigmas =
|
||||
readEarlyLateTableModels(timing_group,
|
||||
constraint_sigma_attr_name.c_str(),
|
||||
rf, TableTemplateType::delay,
|
||||
time_scale_,
|
||||
ScaleFactorType::unknown);
|
||||
timing_attrs->setModel(rf, new CheckTableModel(cell, constraint,
|
||||
std::move(constraint_sigmas)));
|
||||
found_model = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!found_model)
|
||||
libWarn(1311, timing_group, "no table models found in timing group.");
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
LibertyReader::isGateTimingType(TimingType timing_type)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -207,7 +207,6 @@ TimingArcSet::to_string()
|
|||
std::string str = from_->name();
|
||||
str += " -> ";
|
||||
str += to_->name();
|
||||
str += " " + role()->to_string();
|
||||
return str;
|
||||
}
|
||||
|
||||
|
|
@ -333,7 +332,7 @@ TimingArcSet::isRisingFallingEdge() const
|
|||
if (from_rf1 == from_rf2)
|
||||
return from_rf1;
|
||||
}
|
||||
if (arcs_.size() == 1)
|
||||
if (arc_count == 1)
|
||||
return arcs_[0]->fromEdge()->asRiseFall();
|
||||
else
|
||||
return nullptr;
|
||||
|
|
|
|||
Loading…
Reference in New Issue