diff --git a/dcalc/ArnoldiDelayCalc.cc b/dcalc/ArnoldiDelayCalc.cc index 5cb2cf86..20f8d9e5 100644 --- a/dcalc/ArnoldiDelayCalc.cc +++ b/dcalc/ArnoldiDelayCalc.cc @@ -1334,7 +1334,6 @@ ArnoldiDelayCalc::ra_get_s(delay_work *D, tlohi = slew_derate*delayAsFloat(s1); smin = r*c*c_smin; // c_smin = ra_hinv((1-vhi)/vhi-log(vhi)) + log(vhi); if (c_log*r*c >= tlohi) { - // printf("hit smin\n"); s = smin; } else { s = smin+0.3*tlohi; @@ -1410,7 +1409,6 @@ ArnoldiDelayCalc::ar1_ceff_delay(delay_work *D, if (debug_->check("arnoldi", 1)) { double p = 1.0/(r*ctot); double thix,tlox; - if (bad) printf("bad\n"); debugPrint(debug_, "arnoldi", 1, "at r=%s s=%s", units_->resistanceUnit()->asString(r), units_->timeUnit()->asString(s)); diff --git a/dcalc/GraphDelayCalc.cc b/dcalc/GraphDelayCalc.cc index 9d8f8435..8a96730f 100644 --- a/dcalc/GraphDelayCalc.cc +++ b/dcalc/GraphDelayCalc.cc @@ -1413,12 +1413,14 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, int slew_index = dcalc_ap->checkDataSlewIndex(); const Slew &to_slew = graph_->slew(to_vertex, to_rf, slew_index); debugPrint(debug_, "delay_calc", 3, - " %s %s -> %s %s (%s)", + " %s %s -> %s %s (%s) corner:%s/%s", arc_set->from()->name(), arc->fromEdge()->asString(), arc_set->to()->name(), arc->toEdge()->asString(), - arc_set->role()->asString()); + arc_set->role()->asString(), + dcalc_ap->corner()->name(), + dcalc_ap->delayMinMax()->asString()); debugPrint(debug_, "delay_calc", 3, " from_slew = %s to_slew = %s", delayAsString(from_slew, this), @@ -1426,7 +1428,7 @@ GraphDelayCalc::findCheckEdgeDelays(Edge *edge, float related_out_cap = 0.0; if (related_out_pin) related_out_cap = loadCap(related_out_pin, to_rf,dcalc_ap,arc_delay_calc); - ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew, + ArcDelay check_delay = arc_delay_calc->checkDelay(to_pin, arc, from_slew, to_slew, related_out_cap, dcalc_ap); debugPrint(debug_, "delay_calc", 3, @@ -1512,30 +1514,6 @@ GraphDelayCalc::reportDelayCalc(const Edge *edge, //////////////////////////////////////////////////////////////// -void -GraphDelayCalc::minPulseWidth(const Pin *pin, - const RiseFall *hi_low, - DcalcAPIndex ap_index, - const MinMax *min_max, - // Return values. - float &min_width, - bool &exists) -{ - // Sdf annotation. - graph_->widthCheckAnnotation(pin, hi_low, ap_index, - min_width, exists); - if (!exists) { - // Liberty library. - LibertyPort *port = network_->libertyPort(pin); - if (port) { - Instance *inst = network_->instance(pin); - const Pvt *pvt = inst ? sdc_->pvt(inst, min_max) : nullptr; - OperatingConditions *op_cond=sdc_->operatingConditions(min_max); - port->minPulseWidth(hi_low, op_cond, pvt, min_width, exists); - } - } -} - void GraphDelayCalc::minPeriod(const Pin *pin, // Return values. diff --git a/graph/Graph.cc b/graph/Graph.cc index 3ce7aec6..591a2271 100644 --- a/graph/Graph.cc +++ b/graph/Graph.cc @@ -47,7 +47,6 @@ Graph::Graph(StaState *sta, slew_rf_count_(slew_rf_count), have_arc_delays_(have_arc_delays), ap_count_(ap_count), - width_check_annotations_(nullptr), period_check_annotations_(nullptr), reg_clk_vertices_(new VertexSet(graph_)) { @@ -62,7 +61,6 @@ Graph::~Graph() delete reg_clk_vertices_; deleteSlewTables(); deleteArcDelayTables(); - removeWidthCheckAnnotations(); removePeriodCheckAnnotations(); } @@ -205,9 +203,9 @@ Graph::makePortInstanceEdges(const Instance *inst, // Vertices can be missing from the graph if the pins // are power or ground. if (from_vertex) { - bool is_check = arc_set->role()->isTimingCheck(); - if (to_bidirect_drvr_vertex && - !is_check) + TimingRole *role = arc_set->role(); + bool is_check = role->isTimingCheckBetween(); + if (to_bidirect_drvr_vertex && !is_check) makeEdge(from_vertex, to_bidirect_drvr_vertex, arc_set); else if (to_vertex) { makeEdge(from_vertex, to_vertex, arc_set); @@ -856,7 +854,7 @@ Graph::arcDelayAnnotated(const Edge *edge, const TimingArc *arc, DcalcAPIndex ap_index) const { - if (arc_delay_annotated_.size()) { + if (!arc_delay_annotated_.empty()) { size_t index = (edge->arcDelays() + arc->index()) * ap_count_ + ap_index; if (index >= arc_delay_annotated_.size()) report_->critical(1080, "arc_delay_annotated array bounds exceeded"); @@ -912,7 +910,6 @@ Graph::setDelayCount(DcalcAPIndex ap_count) // Discard any existing delays. deleteSlewTables(); deleteArcDelayTables(); - removeWidthCheckAnnotations(); removePeriodCheckAnnotations(); makeSlewTables(ap_count); makeArcDelayTables(ap_count); @@ -955,11 +952,11 @@ Graph::delayAnnotated(Edge *edge) TimingArcSet *arc_set = edge->timingArcSet(); for (TimingArc *arc : arc_set->arcs()) { for (DcalcAPIndex ap_index = 0; ap_index < ap_count_; ap_index++) { - if (arcDelayAnnotated(edge, arc, ap_index)) - return true; + if (!arcDelayAnnotated(edge, arc, ap_index)) + return false; } } - return false; + return true; } void @@ -994,58 +991,28 @@ Graph::makeVertexSlews(Vertex *vertex) //////////////////////////////////////////////////////////////// void -Graph::widthCheckAnnotation(const Pin *pin, - const RiseFall *rf, - DcalcAPIndex ap_index, - // Return values. - float &width, - bool &exists) +Graph::minPulseWidthArc(Vertex *vertex, + // high = rise, low = fall + const RiseFall *hi_low, + // Return values. + Edge *&edge, + TimingArc *&arc) { - exists = false; - if (width_check_annotations_) { - float *widths = width_check_annotations_->findKey(pin); - if (widths) { - int index = ap_index * RiseFall::index_count + rf->index(); - width = widths[index]; - if (width >= 0.0) - exists = true; + VertexOutEdgeIterator edge_iter(vertex, this); + while (edge_iter.hasNext()) { + edge = edge_iter.next(); + TimingArcSet *arc_set = edge->timingArcSet(); + if (arc_set->role() == TimingRole::width()) { + for (TimingArc *arc1 : arc_set->arcs()) { + if (arc1->fromEdge()->asRiseFall() == hi_low) { + arc = arc1; + return; + } + } } } -} - -void -Graph::setWidthCheckAnnotation(const Pin *pin, - const RiseFall *rf, - DcalcAPIndex ap_index, - float width) -{ - if (width_check_annotations_ == nullptr) - width_check_annotations_ = new WidthCheckAnnotations; - float *widths = width_check_annotations_->findKey(pin); - if (widths == nullptr) { - int width_count = RiseFall::index_count * ap_count_; - widths = new float[width_count]; - // Use negative (illegal) width values to indicate unannotated checks. - for (int i = 0; i < width_count; i++) - widths[i] = -1; - (*width_check_annotations_)[pin] = widths; - } - int index = ap_index * RiseFall::index_count + rf->index(); - widths[index] = width; -} - -void -Graph::removeWidthCheckAnnotations() -{ - if (width_check_annotations_) { - WidthCheckAnnotations::Iterator check_iter(width_check_annotations_); - while (check_iter.hasNext()) { - float *widths = check_iter.next(); - delete [] widths; - } - delete width_check_annotations_; - width_check_annotations_ = nullptr; - } + edge = nullptr; + arc = nullptr; } //////////////////////////////////////////////////////////////// @@ -1112,7 +1079,6 @@ Graph::removeDelaySlewAnnotations() } vertex->removeSlewAnnotated(); } - removeWidthCheckAnnotations(); removePeriodCheckAnnotations(); } diff --git a/include/sta/Graph.hh b/include/sta/Graph.hh index 593e0f2f..8bf525bc 100644 --- a/include/sta/Graph.hh +++ b/include/sta/Graph.hh @@ -46,7 +46,6 @@ typedef ArrayTable RequiredsTable; typedef ArrayTable PrevPathsTable; typedef Map PinVertexMap; typedef Iterator VertexEdgeIterator; -typedef Map WidthCheckAnnotations; typedef Map PeriodCheckAnnotations; typedef Vector DelayTableSeq; typedef ObjectId EdgeId; @@ -184,18 +183,11 @@ public: int edgeCount() { return edges_->size(); } virtual int arcCount() { return arc_count_; } - // Sdf width check annotation. - void widthCheckAnnotation(const Pin *pin, - const RiseFall *rf, - DcalcAPIndex ap_index, - // Return values. - float &width, - bool &exists); - void setWidthCheckAnnotation(const Pin *pin, - const RiseFall *rf, - DcalcAPIndex ap_index, - float width); - + void minPulseWidthArc(Vertex *vertex, + const RiseFall *hi_low, + // Return values. + Edge *&edge, + TimingArc *&arc); // Sdf period check annotation. void periodCheckAnnotation(const Pin *pin, DcalcAPIndex ap_index, @@ -229,7 +221,6 @@ protected: virtual void makePortInstanceEdges(const Instance *inst, LibertyCell *cell, LibertyPort *from_to_port); - void removeWidthCheckAnnotations(); void removePeriodCheckAnnotations(); void makeSlewTables(DcalcAPIndex count); void deleteSlewTables(); @@ -264,8 +255,6 @@ protected: DelayTableSeq slew_tables_; // [ap_index][tr_index][vertex_id] VertexId slew_count_; DelayTableSeq arc_delays_; // [ap_index][edge_arc_index] - // Sdf width check annotations. - WidthCheckAnnotations *width_check_annotations_; // Sdf period check annotations. PeriodCheckAnnotations *period_check_annotations_; // Register/latch clock vertices to search from. diff --git a/include/sta/GraphDelayCalc.hh b/include/sta/GraphDelayCalc.hh index bf69f979..5e581065 100644 --- a/include/sta/GraphDelayCalc.hh +++ b/include/sta/GraphDelayCalc.hh @@ -109,17 +109,6 @@ public: // Precedence: // SDF annotation // Liberty library - // (ignores set_min_pulse_width constraint) - void minPulseWidth(const Pin *pin, - const RiseFall *hi_low, - DcalcAPIndex ap_index, - const MinMax *min_max, - // Return values. - float &min_width, - bool &exists); - // Precedence: - // SDF annotation - // Liberty library void minPeriod(const Pin *pin, // Return values. float &min_period, diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 27f0fd1e..b9402f2c 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -728,17 +728,12 @@ public: void minPeriod(float &min_period, bool &exists) const; void setMinPeriod(float min_period); + // This corresponds to the min_pulse_width_high/low port attribute. // high = rise, low = fall void minPulseWidth(const RiseFall *hi_low, - const OperatingConditions *op_cond, - const Pvt *pvt, float &min_width, bool &exists) const; - // Unscaled value. - void minPulseWidth(const RiseFall *hi_low, - float &min_width, - bool &exists) const; - void setMinPulseWidth(RiseFall *hi_low, + void setMinPulseWidth(const RiseFall *hi_low, float min_width); bool isClock() const; void setIsClock(bool is_clk); diff --git a/include/sta/Sdc.hh b/include/sta/Sdc.hh index 5f59ebd7..2c730191 100644 --- a/include/sta/Sdc.hh +++ b/include/sta/Sdc.hh @@ -1068,7 +1068,7 @@ protected: virtual void recordPathDelayInternalEndpoints(ExceptionPath *exception); virtual void unrecordPathDelayInternalEndpoints(ExceptionPath *exception); bool pathDelayTo(const Pin *pin); - bool hasLibertyChecks(const Pin *pin); + bool hasLibertyCheckTo(const Pin *pin); void deleteMatchingExceptions(ExceptionPath *exception); void findMatchingExceptions(ExceptionPath *exception, ExceptionPathSet &matches); diff --git a/include/sta/TimingRole.hh b/include/sta/TimingRole.hh index 51cbf6b7..9dc6951b 100644 --- a/include/sta/TimingRole.hh +++ b/include/sta/TimingRole.hh @@ -65,6 +65,8 @@ public: int index() const { return index_; } bool isWire() const; bool isTimingCheck() const { return is_timing_check_; } + // TIming check but not width or period. + bool isTimingCheckBetween() const; bool isAsyncTimingCheck() const; bool isNonSeqTimingCheck() const { return is_non_seq_check_; } bool isDataCheck() const; diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index a0e00b66..4208f3ee 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -2330,28 +2330,6 @@ LibertyPort::setMinPeriod(float min_period) min_period_exists_ = true; } -void -LibertyPort::minPulseWidth(const RiseFall *hi_low, - const OperatingConditions *op_cond, - const Pvt *pvt, - float &min_width, - bool &exists) const -{ - if (scaled_ports_) { - LibertyPort *scaled_port = (*scaled_ports_)[op_cond]; - if (scaled_port) { - scaled_port->minPulseWidth(hi_low, min_width, exists); - return; - } - } - int hi_low_index = hi_low->index(); - LibertyLibrary *lib = liberty_cell_->libertyLibrary(); - min_width = min_pulse_width_[hi_low_index] - * lib->scaleFactor(ScaleFactorType::min_pulse_width, hi_low_index, - liberty_cell_, pvt); - exists = min_pulse_width_exists_ & (1 << hi_low_index); -} - void LibertyPort::minPulseWidth(const RiseFall *hi_low, float &min_width, @@ -2363,7 +2341,7 @@ LibertyPort::minPulseWidth(const RiseFall *hi_low, } void -LibertyPort::setMinPulseWidth(RiseFall *hi_low, +LibertyPort::setMinPulseWidth(const RiseFall *hi_low, float min_width) { int hi_low_index = hi_low->index(); diff --git a/liberty/LibertyBuilder.cc b/liberty/LibertyBuilder.cc index 39a1f1b8..1b353ebf 100644 --- a/liberty/LibertyBuilder.cc +++ b/liberty/LibertyBuilder.cc @@ -276,6 +276,8 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell, return makeClockTreePathArcs(cell, to_port, TimingRole::clockTreePathMax(), MinMax::max(), attrs); case TimingType::min_pulse_width: + return makeMinPulseWidthArcs(cell, from_port, to_port, related_out, + TimingRole::width(), attrs); case TimingType::minimum_period: case TimingType::nochange_high_high: case TimingType::nochange_high_low: @@ -668,6 +670,26 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell, return arc_set; } +TimingArcSet * +LibertyBuilder::makeMinPulseWidthArcs(LibertyCell *cell, + LibertyPort *from_port, + LibertyPort *to_port, + LibertyPort *related_out, + TimingRole *role, + TimingArcAttrsPtr attrs) +{ + TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out, + role, attrs); + for (auto to_rf : RiseFall::range()) { + TimingModel *model = attrs->model(to_rf); + if (model) + makeTimingArc(arc_set, to_rf->opposite(), to_rf, model); + } + return arc_set; +} + +//////////////////////////////////////////////////////////////// + TimingArcSet * LibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from, diff --git a/liberty/LibertyBuilder.hh b/liberty/LibertyBuilder.hh index 820112c0..7aed7212 100644 --- a/liberty/LibertyBuilder.hh +++ b/liberty/LibertyBuilder.hh @@ -84,6 +84,12 @@ public: TimingRole *role, const MinMax *min_max, TimingArcAttrsPtr attrs); + TimingArcSet *makeMinPulseWidthArcs(LibertyCell *cell, + LibertyPort *from_port, + LibertyPort *to_port, + LibertyPort *related_out, + TimingRole *role, + TimingArcAttrsPtr attrs); protected: ConcretePort *makeBusPort(const char *name, diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 5d394ea4..ae7cc4b9 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -1922,8 +1922,10 @@ LibertyReader::finishPortGroups() { for (PortGroup *port_group : cell_port_groups_) { int line = port_group->line(); - for (LibertyPort *port : *port_group->ports()) + for (LibertyPort *port : *port_group->ports()) { checkPort(port, line); + makeMinPulseWidthArcs(port, line); + } makeTimingArcs(port_group); makeInternalPowers(port_group); delete port_group; @@ -1947,6 +1949,47 @@ LibertyReader::checkPort(LibertyPort *port, port->setDirection(PortDirection::tristate()); } +// Make timing arcs for the port min_pulse_width_low/high attributes. +// This is redundant but makes sdf annotation consistent. +void +LibertyReader::makeMinPulseWidthArcs(LibertyPort *port, + int line) +{ + TimingArcAttrsPtr attrs = nullptr; + for (auto hi_low : RiseFall::range()) { + float min_width; + bool exists; + port->minPulseWidth(hi_low, min_width, exists); + if (exists) { + if (attrs == nullptr) { + attrs = make_shared(); + attrs->setTimingType(TimingType::min_pulse_width); + } + // rise/fall_constraint model is on the trailing edge of the pulse. + const RiseFall *model_rf = hi_low->opposite(); + TimingModel *check_model = + makeScalarCheckModel(min_width, ScaleFactorType::min_pulse_width, model_rf); + attrs->setModel(model_rf, check_model); + } + } + if (attrs) + builder_.makeTimingArcs(cell_, port, port, nullptr, attrs, line); +} + +TimingModel * +LibertyReader::makeScalarCheckModel(float value, + ScaleFactorType scale_factor_type, + const RiseFall *rf) +{ + TablePtr table = make_shared(value); + TableTemplate *tbl_template = + library_->findTableTemplate("scalar", TableTemplateType::delay); + TableModel *table_model = new TableModel(table, tbl_template, + scale_factor_type, rf); + CheckTableModel *check_model = new CheckTableModel(cell_, table_model, nullptr); + return check_model; +} + void LibertyReader::makeTimingArcs(PortGroup *port_group) { @@ -3530,7 +3573,7 @@ LibertyReader::visitMinPulseWidthHigh(LibertyAttr *attr) void LibertyReader::visitMinPulseWidth(LibertyAttr *attr, - RiseFall *rf) + const RiseFall *rf) { if (cell_) { float value; diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 6a088619..6ef9365f 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -235,7 +235,7 @@ public: virtual void visitMinPulseWidthLow(LibertyAttr *attr); virtual void visitMinPulseWidthHigh(LibertyAttr *attr); virtual void visitMinPulseWidth(LibertyAttr *attr, - RiseFall *rf); + const RiseFall *rf); virtual void visitPulseClock(LibertyAttr *attr); virtual void visitClockGateClockPin(LibertyAttr *attr); virtual void visitClockGateEnablePin(LibertyAttr *attr); @@ -479,6 +479,11 @@ public: virtual void visitAttr9(LibertyAttr *) {} protected: + TimingModel *makeScalarCheckModel(float value, + ScaleFactorType scale_factor_type, + const RiseFall *rf); + void makeMinPulseWidthArcs(LibertyPort *port, + int line); void setEnergyScale(); void defineVisitors(); virtual void begin(LibertyGroup *group); diff --git a/liberty/LibertyWriter.cc b/liberty/LibertyWriter.cc index 2a53babf..7d01985f 100644 --- a/liberty/LibertyWriter.cc +++ b/liberty/LibertyWriter.cc @@ -55,17 +55,21 @@ protected: void writePortAttrs(const LibertyPort *port); void writeTimingArcSet(const TimingArcSet *arc_set); void writeTimingModels(const TimingArc *arc, - RiseFall *rf); + const RiseFall *rf); void writeTableModel(const TableModel *model); void writeTableModel0(const TableModel *model); void writeTableModel1(const TableModel *model); void writeTableModel2(const TableModel *model); - void writeTableAxis(const TableAxis *axis, - int index); + void writeTableAxis4(const TableAxis *axis, + int index); + void writeTableAxis10(const TableAxis *axis, + int index); const char *asString(bool value); const char *asString(const PortDirection *dir); const char *timingTypeString(const TimingArcSet *arc_set); + bool isAutoWidthArc(const LibertyPort *port, + const TimingArcSet *arc_set); const LibertyLibrary *library_; const char *filename_; @@ -214,20 +218,21 @@ LibertyWriter::writeTableTemplate(const TableTemplate *tbl_template) fprintf(stream_, " variable_3 : %s;\n", tableVariableString(axis3->variable())); if (axis1) - writeTableAxis(axis1, 1); + writeTableAxis4(axis1, 1); if (axis2) - writeTableAxis(axis2, 2); + writeTableAxis4(axis2, 2); if (axis3) - writeTableAxis(axis3, 3); + writeTableAxis4(axis3, 3); fprintf(stream_, " }\n"); } } +// indent 4 void -LibertyWriter::writeTableAxis(const TableAxis *axis, - int index) +LibertyWriter::writeTableAxis4(const TableAxis *axis, + int index) { - fprintf(stream_, " index_%d (\"", index); + fprintf(stream_, " index_%d(\"", index); const Unit *unit = tableVariableUnit(axis->variable(), library_->units()); bool first = true; for (size_t i = 0; i < axis->size(); i++) { @@ -239,6 +244,15 @@ LibertyWriter::writeTableAxis(const TableAxis *axis, fprintf(stream_, "\");\n"); } +// indent 10 +void +LibertyWriter::writeTableAxis10(const TableAxis *axis, + int index) +{ + fprintf(stream_, " "); + writeTableAxis4(axis, index); +} + void LibertyWriter::writeBusDcls() { @@ -356,8 +370,25 @@ LibertyWriter::writePortAttrs(const LibertyPort *port) fprintf(stream_, " max_capacitance : %s;\n", cap_unit_->asString(limit, 3)); - for (TimingArcSet *arc_set : port->libertyCell()->timingArcSets(nullptr,port)) - writeTimingArcSet(arc_set); + for (TimingArcSet *arc_set : port->libertyCell()->timingArcSets(nullptr,port)) { + if (!isAutoWidthArc(port, arc_set)) + writeTimingArcSet(arc_set); + } +} + +// Check if arc is added for port min_pulse_width_high/low attribute. +bool +LibertyWriter::isAutoWidthArc(const LibertyPort *port, + const TimingArcSet *arc_set) +{ + if (arc_set->role() == TimingRole::width()) { + float min_width; + bool exists1, exists2; + port->minPulseWidth(RiseFall::rise(), min_width, exists1); + port->minPulseWidth(RiseFall::fall(), min_width, exists2); + return exists1 || exists2; + } + return false; } void @@ -386,7 +417,7 @@ LibertyWriter::writeTimingArcSet(const TimingArcSet *arc_set) void LibertyWriter::writeTimingModels(const TimingArc *arc, - RiseFall *rf) + const RiseFall *rf) { TimingModel *model = arc->model(); const GateTableModel *gate_model = dynamic_cast(model); @@ -450,6 +481,7 @@ LibertyWriter::writeTableModel0(const TableModel *model) void LibertyWriter::writeTableModel1(const TableModel *model) { + writeTableAxis10(model->axis1(), 1); fprintf(stream_, " values(\""); bool first_col = true; for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) { @@ -465,6 +497,8 @@ LibertyWriter::writeTableModel1(const TableModel *model) void LibertyWriter::writeTableModel2(const TableModel *model) { + writeTableAxis10(model->axis1(), 1); + writeTableAxis10(model->axis2(), 2); fprintf(stream_, " values(\""); bool first_row = true; for (size_t index1 = 0; index1 < model->axis1()->size(); index1++) { @@ -577,6 +611,8 @@ LibertyWriter::timingTypeString(const TimingArcSet *arc_set) return "min_clock_tree_path"; else if (role == TimingRole::clockTreePathMax()) return "max_clock_tree_path"; + else if (role == TimingRole::width()) + return "min_pulse_width"; else { report_->error(1333, "%s/%s/%s timing arc type %s not supported.", library_->name(), diff --git a/liberty/TimingRole.cc b/liberty/TimingRole.cc index 221f7305..deb4f762 100644 --- a/liberty/TimingRole.cc +++ b/liberty/TimingRole.cc @@ -258,6 +258,14 @@ TimingRole::isLatchDtoQ() const return this == latch_d_q_; } +bool +TimingRole::isTimingCheckBetween() const +{ + return is_timing_check_ + && this != width_ + && this != period_; +} + bool TimingRole::less(const TimingRole *role1, const TimingRole *role2) diff --git a/sdc/Sdc.cc b/sdc/Sdc.cc index 2ceb4425..c78edd4d 100644 --- a/sdc/Sdc.cc +++ b/sdc/Sdc.cc @@ -3924,7 +3924,7 @@ Sdc::recordPathDelayInternalEndpoints(ExceptionPath *exception) if (to && to->hasPins()) { for (const Pin *pin : *to->pins()) { - if (!(hasLibertyChecks(pin) + if (!(hasLibertyCheckTo(pin) || network_->isTopLevelPort(pin))) { path_delay_internal_endpoints_.insert(pin); } @@ -3940,7 +3940,7 @@ Sdc::unrecordPathDelayInternalEndpoints(ExceptionPath *exception) && to->hasPins() && !path_delay_internal_endpoints_.empty()) { for (const Pin *pin : *to->pins()) { - if (!(hasLibertyChecks(pin) + if (!(hasLibertyCheckTo(pin) || network_->isTopLevelPort(pin)) && !pathDelayTo(pin)) path_delay_internal_endpoints_.erase(pin); @@ -3949,7 +3949,7 @@ Sdc::unrecordPathDelayInternalEndpoints(ExceptionPath *exception) } bool -Sdc::hasLibertyChecks(const Pin *pin) +Sdc::hasLibertyCheckTo(const Pin *pin) { const Instance *inst = network_->instance(pin); LibertyCell *cell = network_->libertyCell(inst); @@ -3957,7 +3957,7 @@ Sdc::hasLibertyChecks(const Pin *pin) LibertyPort *port = network_->libertyPort(pin); if (port) { for (TimingArcSet *arc_set : cell->timingArcSets(nullptr, port)) { - if (arc_set->role()->isTimingCheck()) + if (arc_set->role()->isTimingCheckBetween()) return true; } } diff --git a/sdf/ReportAnnotation.cc b/sdf/ReportAnnotation.cc index f51858ba..1bfdc077 100644 --- a/sdf/ReportAnnotation.cc +++ b/sdf/ReportAnnotation.cc @@ -68,7 +68,7 @@ protected: void init(); void findCounts(); - void findWidthPeriodCount(Pin *pin); + void findPeriodCount(Pin *pin); void reportDelayCounts(); void reportCheckCounts(); void reportArcs(); @@ -78,9 +78,9 @@ protected: void reportArcs(Vertex *vertex, bool report_annotated, int &i); - void reportWidthPeriodArcs(const Pin *pin, - bool report_annotated, - int &i); + void reportPeriodArcs(const Pin *pin, + bool report_annotated, + int &i); void reportCount(const char *title, int index, int &total, @@ -282,9 +282,8 @@ ReportAnnotated::reportCheckCount(TimingRole *role, { int index = role->index(); if (edge_count_[index] > 0) { - const char *role_name = role->asString(); string title; - stringPrint(title, "cell %s arcs", role_name); + stringPrint(title, "cell %s arcs", role->asString()); reportCount(title.c_str(), index, total, annotated_total); } } @@ -345,7 +344,7 @@ ReportAnnotated::findCounts() } } } - findWidthPeriodCount(from_pin); + findPeriodCount(from_pin); } } @@ -376,7 +375,7 @@ ReportAnnotated::roleIndex(const TimingRole *role, // Width and period checks are not edges in the graph so // they require special handling. void -ReportAnnotated::findWidthPeriodCount(Pin *pin) +ReportAnnotated::findPeriodCount(Pin *pin) { LibertyPort *port = network_->libertyPort(pin); if (port) { @@ -400,27 +399,6 @@ ReportAnnotated::findWidthPeriodCount(Pin *pin) } } } - - int width_index = TimingRole::width()->index(); - if (report_role_[width_index]) { - for (auto hi_low : RiseFall::range()) { - port->minPulseWidth(hi_low, value, exists); - if (exists) { - edge_count_[width_index]++; - graph_->widthCheckAnnotation(pin, hi_low, ap_index, - value, annotated); - if (annotated) { - edge_annotated_count_[width_index]++; - if (list_annotated_) - annotated_pins_.insert(pin); - } - else { - if (list_unannotated_) - unannotated_pins_.insert(pin); - } - } - } - } } } @@ -476,7 +454,7 @@ ReportAnnotated::reportArcs(const char *header, reportArcs(vertex, report_annotated, i); if (bidirect_drvr_vertex) reportArcs(bidirect_drvr_vertex, report_annotated, i); - reportWidthPeriodArcs(pin, report_annotated, i); + reportPeriodArcs(pin, report_annotated, i); if (max_lines_ != 0 && i > max_lines_) break; } @@ -521,15 +499,13 @@ ReportAnnotated::reportArcs(Vertex *vertex, } void -ReportAnnotated::reportWidthPeriodArcs(const Pin *pin, - bool report_annotated, - int &i) +ReportAnnotated::reportPeriodArcs(const Pin *pin, + bool report_annotated, + int &i) { LibertyPort *port = network_->libertyPort(pin); if (port) { DcalcAPIndex ap_index = 0; - float value; - bool exists, annotated; int period_index = TimingRole::period()->index(); if (report_role_[period_index] && (max_lines_ == 0 || i < max_lines_)) { @@ -547,27 +523,6 @@ ReportAnnotated::reportWidthPeriodArcs(const Pin *pin, } } } - - int width_index = TimingRole::width()->index(); - if (report_role_[width_index] - && (max_lines_ == 0 || i < max_lines_)) { - bool report = false; - for (auto hi_low : RiseFall::range()) { - port->minPulseWidth(hi_low, value, exists); - if (exists) { - edge_count_[width_index]++; - graph_->widthCheckAnnotation(pin, hi_low, ap_index, - value, annotated); - report |= (annotated == report_annotated); - } - } - if (report) { - report_->reportLine(" %-18s %s", - "min width", - network_->pathName(pin)); - i++; - } - } } } diff --git a/sdf/SdfReader.cc b/sdf/SdfReader.cc index 7dff5edd..195f51be 100644 --- a/sdf/SdfReader.cc +++ b/sdf/SdfReader.cc @@ -550,22 +550,12 @@ SdfReader::timingCheckWidth(SdfPortSpec *edge, if (port) { Pin *pin = network_->findPin(instance_, port_name); if (pin) { - const RiseFall *rf = edge->transition()->asRiseFall(); - float **values = triple->values(); - float *value_ptr = values[triple_min_index_]; - if (value_ptr) { - float value = *value_ptr; - graph_->setWidthCheckAnnotation(pin, rf, arc_delay_min_index_, - value); - } - if (triple_max_index_ != null_index_) { - value_ptr = values[triple_max_index_]; - if (value_ptr) { - float value = *value_ptr; - graph_->setWidthCheckAnnotation(pin, rf, arc_delay_max_index_, - value); - } - } + const RiseFall *rf = edge->transition()->asRiseFall(); + Edge *edge; + TimingArc *arc; + graph_->minPulseWidthArc(graph_->pinLoadVertex(pin), rf, edge, arc); + if (edge) + setEdgeArcDelays(edge, arc, triple); } } } diff --git a/sdf/SdfWriter.cc b/sdf/SdfWriter.cc index 1fa32bab..22d2e24e 100644 --- a/sdf/SdfWriter.cc +++ b/sdf/SdfWriter.cc @@ -522,14 +522,12 @@ SdfWriter::writeTimingChecks(const Instance *inst, } for (auto hi_low : RiseFall::range()) { float min_width, max_width; - bool exists; - graph_delay_calc_->minPulseWidth(pin, hi_low, arc_delay_min_index_, - MinMax::min(), - min_width, exists); - graph_delay_calc_->minPulseWidth(pin, hi_low, arc_delay_max_index_, - MinMax::max(), - max_width, exists); - if (exists) { + Edge *edge; + TimingArc *arc; + graph_->minPulseWidthArc(vertex, hi_low, edge, arc); + if (edge) { + min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_)); + max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_)); ensureTimingCheckheaders(check_header, inst, inst_header); writeWidthCheck(pin, hi_low, min_width, max_width); } diff --git a/search/Bfs.cc b/search/Bfs.cc index 7971b975..bc77bb4e 100644 --- a/search/Bfs.cc +++ b/search/Bfs.cc @@ -87,10 +87,10 @@ BfsIterator::reportEntries(const Network *network) while (levelLessOrEqual(level, last_level_)) { VertexSeq &level_vertices = queue_[level]; if (!level_vertices.empty()) { - printf("Level %d\n", level); + report_->reportLine("Level %d", level); for (auto vertex : level_vertices) { if (vertex) - printf(" %s\n", vertex->name(network)); + report_->reportLine(" %s", vertex->name(network)); } } incrLevel(level); diff --git a/search/CheckMinPulseWidths.cc b/search/CheckMinPulseWidths.cc index ece0222f..6c1e35a4 100644 --- a/search/CheckMinPulseWidths.cc +++ b/search/CheckMinPulseWidths.cc @@ -424,9 +424,11 @@ MinPulseWidthCheck::minWidth(const StaState *sta) const } // Precedence: -// set_min_pulse_width constraint +// set_min_pulse_width SDC command // SDF annotation // Liberty library +// port min_pulse_width_low/high +// min_pulse_width timing group static void minPulseWidth(const Path *path, const StaState *sta, @@ -441,12 +443,17 @@ minPulseWidth(const Path *path, // set_min_pulse_width command. sdc->minPulseWidth(pin, clk, rf, min_width, exists); if (!exists) { - GraphDelayCalc *graph_dcalc = sta->graphDelayCalc(); - const MinMax *min_max = path->minMax(sta); const PathAnalysisPt *path_ap = path->pathAnalysisPt(sta); const DcalcAnalysisPt *dcalc_ap = path_ap->dcalcAnalysisPt(); - graph_dcalc->minPulseWidth(pin, rf, dcalc_ap->index(), min_max, - min_width, exists); + Vertex *vertex = path->vertex(sta); + Graph *graph = sta->graph(); + Edge *edge; + TimingArc *arc; + graph->minPulseWidthArc(vertex, rf, edge, arc); + if (edge) { + min_width = delayAsFloat(graph->arcDelay(edge, arc, dcalc_ap->index())); + exists = true; + } } } diff --git a/search/FindRegister.cc b/search/FindRegister.cc index 547474a4..90973487 100644 --- a/search/FindRegister.cc +++ b/search/FindRegister.cc @@ -530,11 +530,13 @@ FindRegClkPins::FindRegClkPins(StaState *sta) : bool FindRegClkPins::matchPin(Pin *pin) { + // Liberty port clock attribute is not present in latches (for nlc18 anyway). LibertyPort *port = network_->libertyPort(pin); LibertyCell *cell = port->libertyCell(); for (TimingArcSet *arc_set : cell->timingArcSets(port, nullptr)) { TimingRole *role = arc_set->role(); - if (role->isTimingCheck()) + if (role == TimingRole::regClkToQ() + || role == TimingRole::latchEnToQ()) return true; } return false; diff --git a/search/Sim.cc b/search/Sim.cc index 2e37b334..6c46dabe 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -142,7 +142,6 @@ Sim::funcBddSim(const FuncExpr *expr, if (port_node) { LogicValue value = logicValue(pin); int var_index = Cudd_NodeReadIndex(port_node); - //printf("%s %d %c\n", port->name(), var_index, logicValueString(value)); switch (value) { case LogicValue::zero: bdd = Cudd_bddCompose(cudd_mgr, bdd, Cudd_ReadLogicZero(cudd_mgr), var_index);