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.
|
// 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(); }
|
||||||
|
|
|
||||||
|
|
@ -1679,45 +1679,58 @@ 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 *d = d_to_q->from();
|
||||||
LibertyPort *q = en_to_q->to();
|
LibertyPort *q = d_to_q->to();
|
||||||
for (TimingArcSet *d_to_q : timingArcSetsTo(q)) {
|
TimingArcSet *en_to_q = nullptr;
|
||||||
if (d_to_q->role() == TimingRole::latchDtoQ()
|
TimingArcSet *en_to_q_when = nullptr;
|
||||||
&& condMatch(en_to_q, d_to_q)) {
|
// Prefer en_to_q with matching when.
|
||||||
LibertyPort *d = d_to_q->from();
|
for (TimingArcSet *arc_to_q : timingArcSetsTo(q)) {
|
||||||
const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
|
if (arc_to_q->role() == TimingRole::latchEnToQ()) {
|
||||||
if (en_rf) {
|
if (condMatch(arc_to_q, d_to_q))
|
||||||
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q,
|
en_to_q_when = arc_to_q;
|
||||||
report);
|
else
|
||||||
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
|
en_to_q = arc_to_q;
|
||||||
en_to_q,
|
}
|
||||||
setup_check,
|
}
|
||||||
debug);
|
if (en_to_q_when)
|
||||||
FuncExpr *en_func = latch_enable->enableFunc();
|
en_to_q = en_to_q_when;
|
||||||
if (en_func) {
|
if (en_to_q) {
|
||||||
TimingSense en_sense = en_func->portTimingSense(en);
|
LibertyPort *en = en_to_q->from();
|
||||||
if (en_sense == TimingSense::positive_unate
|
const RiseFall *en_rf = en_to_q->isRisingFallingEdge();
|
||||||
&& en_rf != RiseFall::rise())
|
if (en_rf) {
|
||||||
report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.",
|
TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, d_to_q, report);
|
||||||
library_->name(),
|
LatchEnable *latch_enable = makeLatchEnable(d, en, en_rf, q, d_to_q,
|
||||||
name(),
|
en_to_q, setup_check, debug);
|
||||||
en->name(),
|
FuncExpr *en_func = latch_enable->enableFunc();
|
||||||
q->name(),
|
if (en_func) {
|
||||||
en_rf == RiseFall::rise()?"rising":"falling");
|
TimingSense en_sense = en_func->portTimingSense(en);
|
||||||
else if (en_sense == TimingSense::negative_unate
|
if (en_sense == TimingSense::positive_unate
|
||||||
&& en_rf != RiseFall::fall())
|
&& en_rf != RiseFall::rise())
|
||||||
report->warn(1115, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.",
|
report->warn(1114, "cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.",
|
||||||
library_->name(),
|
library_->name(),
|
||||||
name(),
|
name(),
|
||||||
en->name(),
|
en->name(),
|
||||||
q->name(),
|
q->name(),
|
||||||
en_rf == RiseFall::rise()?"rising":"falling");
|
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)
|
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;
|
||||||
|
|
|
||||||
|
|
@ -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(); }
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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]"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2059,7 +2059,7 @@ LibertyReader::makeTimingModels(LibertyCell *cell,
|
||||||
const LibertyGroup *timing_group,
|
const LibertyGroup *timing_group,
|
||||||
TimingArcAttrsPtr timing_attrs)
|
TimingArcAttrsPtr timing_attrs)
|
||||||
{
|
{
|
||||||
switch (cell->libertyLibrary()->delayModelType()) {
|
switch (cell->libertyLibrary()->delayModelType()) {
|
||||||
case DelayModelType::cmos_linear:
|
case DelayModelType::cmos_linear:
|
||||||
makeLinearModels(cell, timing_group, timing_attrs);
|
makeLinearModels(cell, timing_group, timing_attrs);
|
||||||
break;
|
break;
|
||||||
|
|
@ -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,30 +2161,36 @@ 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());
|
||||||
TableModel *constraint = readCheckTableModel(timing_group,
|
TableModel *constraint = readCheckTableModel(timing_group,
|
||||||
constraint_attr_name.c_str(),
|
constraint_attr_name.c_str(),
|
||||||
rf, TableTemplateType::delay,
|
rf, TableTemplateType::delay,
|
||||||
time_scale_, scale_factor_type);
|
time_scale_, scale_factor_type);
|
||||||
if (constraint) {
|
if (constraint) {
|
||||||
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string_long()
|
std::string constraint_sigma_attr_name = "ocv_sigma_" + rf->to_string_long()
|
||||||
+ "_constraint";
|
+ "_constraint";
|
||||||
TableModelsEarlyLate constraint_sigmas =
|
TableModelsEarlyLate constraint_sigmas =
|
||||||
readEarlyLateTableModels(timing_group,
|
readEarlyLateTableModels(timing_group,
|
||||||
constraint_sigma_attr_name.c_str(),
|
constraint_sigma_attr_name.c_str(),
|
||||||
rf, TableTemplateType::delay,
|
rf, TableTemplateType::delay,
|
||||||
time_scale_,
|
time_scale_,
|
||||||
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)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -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;
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue