From 5a5164276edb1fcad2af62facb33c898b00f7cd4 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Tue, 19 Mar 2019 21:30:19 -0700 Subject: [PATCH] read_liberty check timing arcs --- liberty/Liberty.cc | 197 ++++++++++++++++++++++++++++++------------- liberty/Liberty.hh | 14 ++- search/ReportPath.cc | 16 ++-- search/Sta.cc | 2 +- tcl/Liberty.tcl | 2 +- 5 files changed, 159 insertions(+), 72 deletions(-) diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 72df1e4d..d2b4b37a 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -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(), diff --git a/liberty/Liberty.hh b/liberty/Liberty.hh index a226cc3f..12b47e48 100644 --- a/liberty/Liberty.hh +++ b/liberty/Liberty.hh @@ -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_; diff --git a/search/ReportPath.cc b/search/ReportPath.cc index 8b19c328..235c9ec6 100644 --- a/search/ReportPath.cc +++ b/search/ReportPath.cc @@ -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); diff --git a/search/Sta.cc b/search/Sta.cc index 976560bf..4f0d2e5c 100644 --- a/search/Sta.cc +++ b/search/Sta.cc @@ -658,7 +658,7 @@ Sta::readLibertyAfter(LibertyLibrary *liberty, { corner->addLiberty(liberty, min_max); LibertyLibrary::makeCornerMap(liberty, corner->libertyIndex(min_max), - network_); + network_, report_); } bool diff --git a/tcl/Liberty.tcl b/tcl/Liberty.tcl index 37f67c36..18fa191b 100644 --- a/tcl/Liberty.tcl +++ b/tcl/Liberty.tcl @@ -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