read_liberty check timing arcs

This commit is contained in:
James Cherry 2019-03-19 21:30:19 -07:00
parent 5162905e11
commit 5a5164276e
5 changed files with 159 additions and 72 deletions

View File

@ -673,7 +673,8 @@ LibertyLibrary::makeScaledCell(const char *name,
void
LibertyLibrary::makeCornerMap(LibertyLibrary *lib,
int ap_index,
Network *network)
Network *network,
Report *report)
{
LibertyCellIterator cell_iter(lib);
while (cell_iter.hasNext()) {
@ -681,7 +682,7 @@ LibertyLibrary::makeCornerMap(LibertyLibrary *lib,
const char *name = cell->name();
LibertyCell *link_cell = network->findLibertyCell(name);
if (link_cell)
makeCornerMap(link_cell, cell, ap_index);
makeCornerMap(link_cell, cell, ap_index, report);
}
}
@ -690,33 +691,65 @@ LibertyLibrary::makeCornerMap(LibertyLibrary *lib,
void
LibertyLibrary::makeCornerMap(LibertyCell *link_cell,
LibertyCell *corner_cell,
int ap_index)
int ap_index,
Report *report)
{
link_cell->setCornerCell(corner_cell, ap_index);
makeCornerMap(link_cell, corner_cell, true, ap_index, report);
// Check for brain damage in the other direction.
makeCornerMap(corner_cell, link_cell, false, ap_index, report);
}
LibertyCellPortBitIterator port_iter(link_cell);
while (port_iter.hasNext()) {
LibertyPort *link_port = port_iter.next();
const char *port_name = link_port->name();
LibertyPort *corner_port = corner_cell->findLibertyPort(port_name);
if (corner_port)
link_port->setCornerPort(corner_port, ap_index);
void
LibertyLibrary::makeCornerMap(LibertyCell *cell1,
LibertyCell *cell2,
bool link,
int ap_index,
Report *report)
{
LibertyCellPortBitIterator port_iter1(cell1);
while (port_iter1.hasNext()) {
LibertyPort *port1 = port_iter1.next();
const char *port_name = port1->name();
LibertyPort *port2 = cell2->findLibertyPort(port_name);
if (port2) {
if (link)
port1->setCornerPort(port2, ap_index);
}
else
report->warn("cell %s/%s port %s not found in cell %s/%s.\n",
cell1->library()->name(),
cell1->name(),
port_name,
cell2->library()->name(),
cell2->name());
}
LibertyCellTimingArcSetIterator set_iter(link_cell);
while (set_iter.hasNext()) {
TimingArcSet *link_arc_set = set_iter.next();
TimingArcSet *corner_arc_set = corner_cell->findTimingArcSet(link_arc_set);
if (corner_arc_set) {
TimingArcSetArcIterator arc_iter(link_arc_set);
TimingArcSetArcIterator corner_arc_iter(corner_arc_set);
while (arc_iter.hasNext() && corner_arc_iter.hasNext()) {
TimingArc *link_arc = arc_iter.next();
TimingArc *corner_arc = corner_arc_iter.next();
if (TimingArc::equiv(link_arc, corner_arc))
link_arc->setCornerArc(corner_arc, ap_index);
LibertyCellTimingArcSetIterator set_iter1(cell1);
while (set_iter1.hasNext()) {
TimingArcSet *arc_set1 = set_iter1.next();
TimingArcSet *arc_set2 = cell2->findTimingArcSet(arc_set1);
if (arc_set2) {
if (link) {
TimingArcSetArcIterator arc_iter1(arc_set1);
TimingArcSetArcIterator arc_iter2(arc_set2);
while (arc_iter1.hasNext() && arc_iter2.hasNext()) {
TimingArc *arc1 = arc_iter1.next();
TimingArc *arc2 = arc_iter2.next();
if (TimingArc::equiv(arc1, arc2))
arc1->setCornerArc(arc2, ap_index);
}
}
}
else
report->warn("cell %s/%s %s -> %s timing group %s not found in cell %s/%s.\n",
cell1->library()->name(),
cell1->name(),
arc_set1->from()->name(),
arc_set1->to()->name(),
arc_set1->role()->asString(),
cell2->library()->name(),
cell2->name());
}
}
@ -1054,49 +1087,19 @@ LibertyCell::addTimingArcSet(TimingArcSet *arc_set)
{
if (timing_arc_sets_ == nullptr) {
timing_arc_sets_ = new TimingArcSetSeq;
timing_arc_set_map_ = new TimingArcSetMap;
port_timing_arc_set_map_ = new LibertyPortPairTimingArcMap;
timing_arc_set_from_map_ = new LibertyPortTimingArcMap;
timing_arc_set_to_map_ = new LibertyPortTimingArcMap;
}
int set_index = timing_arc_sets_->size();
if (set_index > timing_arc_set_index_max)
internalError("timing arc set max index exceeded");
timing_arc_sets_->push_back(arc_set);
timing_arc_set_map_->insert(arc_set);
LibertyPort *from = arc_set->from();
LibertyPort *to = arc_set->to();
TimingRole *role = arc_set->role();
if (role == TimingRole::regClkToQ()
|| role == TimingRole::latchEnToQ())
from->setIsRegClk(true);
if (role->isTimingCheck())
from->setIsCheckClk(true);
LibertyPortPair port_pair(from, to);
TimingArcSetSeq *sets = port_timing_arc_set_map_->findKey(&port_pair);
if (sets == nullptr) {
// First arc set for from/to ports.
sets = new TimingArcSetSeq;
LibertyPortPair *port_pair1 = new LibertyPortPair(from, to);
(*port_timing_arc_set_map_)[port_pair1] = sets;
}
sets->push_back(arc_set);
sets = timing_arc_set_from_map_->findKey(from);
if (sets == nullptr) {
sets = new TimingArcSetSeq;
(*timing_arc_set_from_map_)[from] = sets;
}
sets->push_back(arc_set);
sets = timing_arc_set_to_map_->findKey(to);
if (sets == nullptr) {
sets = new TimingArcSetSeq;
(*timing_arc_set_to_map_)[to] = sets;
}
sets->push_back(arc_set);
return set_index;
}
@ -1151,9 +1154,13 @@ LibertyCell::finish(bool infer_latches,
Report *report,
Debug *debug)
{
findDefaultCondArcs();
translatePresetClrCheckRoles();
makeLatchEnables(report, debug);
if (timing_arc_sets_) {
makeTimingArcMap(report);
makeTimingArcPortMaps();
findDefaultCondArcs();
makeLatchEnables(report, debug);
}
if (infer_latches
&& !interface_timing_)
inferLatchRoles(debug);
@ -1215,6 +1222,76 @@ LibertyCell::translatePresetClrCheckRoles()
}
}
void
LibertyCell::makeTimingArcMap(Report *)
{
timing_arc_set_map_ = new TimingArcSetMap;
// Filter duplicate timing arcs, keeping the later definition.
for (auto arc_set : *timing_arc_sets_)
// The last definition will be left in the set.
timing_arc_set_map_->insert(arc_set);
// Prune the arc sets not in the map.
int j = 0;
for (int i = 0; i < timing_arc_sets_->size(); i++) {
TimingArcSet *arc_set = (*timing_arc_sets_)[i];
TimingArcSet *match = timing_arc_set_map_->findKey(arc_set);
if (match != arc_set) {
// Unfortunately these errors are common in some brain damaged
// libraries.
// report->warn("cell %s/%s has duplicate %s -> %s %s timing groups.\n",
// library_->name(),
// name_,
// match->from()->name(),
// match->to()->name(),
// match->role()->asString());
}
else
// Shift arc sets down to fill holes left by removed duplicates.
(*timing_arc_sets_)[j++] = arc_set;
}
timing_arc_sets_->resize(j);
if (timing_arc_set_map_->size() != timing_arc_sets_->size())
internalError("timing arc count mismatch\n");
}
void
LibertyCell::makeTimingArcPortMaps()
{
port_timing_arc_set_map_ = new LibertyPortPairTimingArcMap;
timing_arc_set_from_map_ = new LibertyPortTimingArcMap;
timing_arc_set_to_map_ = new LibertyPortTimingArcMap;
for (auto arc_set : *timing_arc_sets_) {
LibertyPort *from = arc_set->from();
LibertyPort *to = arc_set->to();
LibertyPortPair port_pair(from, to);
TimingArcSetSeq *sets = port_timing_arc_set_map_->findKey(&port_pair);
if (sets == nullptr) {
// First arc set for from/to ports.
sets = new TimingArcSetSeq;
LibertyPortPair *port_pair1 = new LibertyPortPair(from, to);
(*port_timing_arc_set_map_)[port_pair1] = sets;
}
sets->push_back(arc_set);
sets = timing_arc_set_from_map_->findKey(from);
if (sets == nullptr) {
sets = new TimingArcSetSeq;
(*timing_arc_set_from_map_)[from] = sets;
}
sets->push_back(arc_set);
sets = timing_arc_set_to_map_->findKey(to);
if (sets == nullptr) {
sets = new TimingArcSetSeq;
(*timing_arc_set_to_map_)[to] = sets;
}
sets->push_back(arc_set);
}
}
TimingArcSetSeq *
LibertyCell::timingArcSets(const LibertyPort *from,
const LibertyPort *to) const
@ -1546,8 +1623,8 @@ LibertyCell::makeLatchEnables(Report *report,
TransRiseFall *en_tr = latch_enable->enableTransition();
TransRiseFall *check_tr = check_arc->fromTrans()->asRiseFall();
if (check_tr == en_tr) {
report->warn("%s, cell %s latch enable %s -> %s %s_edge timing arc is inconsistent with %s -> %s setup_%s check.\n",
filename_,
report->warn("cell %s/%s %s -> %s latch enable %s_edge timing arc is inconsistent with %s -> %s setup_%s check.\n",
library_->name(),
name_,
en->name(),
q->name(),
@ -1561,16 +1638,16 @@ LibertyCell::makeLatchEnables(Report *report,
TimingSense en_sense = en_func->portTimingSense(en);
if (en_sense == TimingSense::positive_unate
&& en_tr != TransRiseFall::rise())
report->warn("%s, cell %s latch enable %s -> %s %s_edge is inconsistent with latch group enable function positive sense.\n",
filename_,
report->warn("cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense.\n",
library_->name(),
name_,
en->name(),
q->name(),
en_tr == TransRiseFall::rise()?"rising":"falling");
else if (en_sense == TimingSense::negative_unate
&& en_tr != TransRiseFall::fall())
report->warn("%s, cell %s latch enable %s -> %s %s_edge is inconsistent with latch group enable function negative sense.\n",
filename_,
report->warn("cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense.\n",
library_->name(),
name_,
en->name(),
q->name(),

View File

@ -266,11 +266,19 @@ public:
static void
makeCornerMap(LibertyLibrary *lib,
int ap_index,
Network *network);
Network *network,
Report *report);
static void
makeCornerMap(LibertyCell *link_cell,
LibertyCell *map_cell,
int ap_index);
int ap_index,
Report *report);
static void
makeCornerMap(LibertyCell *cell1,
LibertyCell *cell2,
bool link,
int ap_index,
Report *report);
protected:
float degradeWireSlew(const LibertyCell *cell,
@ -488,6 +496,8 @@ protected:
virtual void translatePresetClrCheckRoles();
virtual void inferLatchRoles(Debug *debug);
void deleteInternalPowerAttrs();
void makeTimingArcMap(Report *report);
void makeTimingArcPortMaps();
LibertyLibrary *liberty_library_;
float area_;

View File

@ -381,7 +381,7 @@ ReportPath::reportEndpointHeader(PathEnd *end,
const char *setup_hold = (end->minMax(this) == MinMax::min())
? "min_delay/hold"
: "max_delay/setup";
report_->print("%s ('%s' group)\n\n",
report_->print("%s group %s\n\n",
setup_hold,
group->name());
string header;
@ -977,17 +977,17 @@ ReportPath::reportEndHeader(string &result)
// Line one.
reportDescription("", result);
result += ' ';
reportField("Required ", field_total_, result);
reportField("Required", field_total_, result);
result += ' ';
reportField("Actual ", field_total_, result);
reportField("Actual", field_total_, result);
reportEndOfLine(result);
// Line two.
reportDescription("Endpoint", result);
result += ' ';
reportField("Path Delay", field_total_, result);
reportField("Delay", field_total_, result);
result += ' ';
reportField("Path Delay", field_total_, result);
reportField("Delay", field_total_, result);
result += ' ';
reportField("Slack", field_total_, result);
reportEndOfLine(result);
@ -1169,9 +1169,9 @@ ReportPath::reportMpwHeaderShort(string &result)
reportDescription("Pin", result);
result += ' ';
reportField("width ", field_total_, result);
reportField("Width", field_total_, result);
result += ' ';
reportField("width", field_total_, result);
reportField("Width", field_total_, result);
result += ' ';
reportField("Slack", field_total_, result);
reportEndOfLine(result);
@ -1328,7 +1328,7 @@ ReportPath::reportPeriodHeaderShort(string &result)
result += ' ';
reportField("", field_total_, result);
result += ' ';
reportField("Min ", field_total_, result);
reportField("Min", field_total_, result);
result += ' ';
reportField("", field_total_, result);
reportEndOfLine(result);

View File

@ -658,7 +658,7 @@ Sta::readLibertyAfter(LibertyLibrary *liberty,
{
corner->addLiberty(liberty, min_max);
LibertyLibrary::makeCornerMap(liberty, corner->libertyIndex(min_max),
network_);
network_, report_);
}
bool

View File

@ -21,7 +21,7 @@ namespace eval sta {
define_cmd_args "read_liberty" \
{[-corner corner_name] [-min] [-max] [-no_latch_infer] filename}
proc read_liberty { args } {
proc_redirect read_liberty {
parse_key_args "read_liberty" args keys {-corner} \
flags {-min -max -no_latch_infer}
check_argc_eq1 "read_liberty" $args