diff --git a/CMakeLists.txt b/CMakeLists.txt index a361a3be..26e05729 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -339,23 +339,26 @@ find_package(TCL) set(TCL_READLINE 0) # check for tclReadline if (USE_TCL_READLINE) - find_library(TCL_READLINE_LIBRARY tclreadline) + set(TCL_READLINE_POSSIBLE_NAMES + tclreadline-2.1.0 + tclreadline-2.3.2 + tclreadline-2.3.6 + tclreadline-2.3.7 + tclreadline-2.3.8 + ) + find_library(TCL_READLINE_LIBRARY + NAMES tclreadline ${TCL_READLINE_POSSIBLE_NAMES} + PATHS ${TCL_LIB_PATHS} + ) if (TCL_READLINE_LIBRARY) - message(STATUS "TCL readline: ${TCL_READLINE_LIBRARY}") + message(STATUS "TCL readline library: ${TCL_READLINE_LIBRARY}") # Referenced by StaConfig.hh.cmake set(TCL_READLINE 1) + endif() - get_filename_component(TCL_READLINE_LIB_DIR "${TCL_READLINE_LIBRARY}" PATH) - get_filename_component(TCL_READLINE_LIB_PARENT "${TCL_READLINE_LIB_DIR}" PATH) - find_file(TCL_READLINE_HEADER tclreadline.h - PATHS ${TCL_READLINE_LIB_PARENT} - PATH_SUFFIXES include - NO_DEFAULT_PATH - ) - message(STATUS "TCL readline header: ${TCL_READLINE_HEADER}") - get_filename_component(TCL_READLINE_INCLUDE "${TCL_READLINE_HEADER}" PATH) - else() - message(STATUS "TCL readline: not found") + find_path(TCL_READLINE_INCLUDE tclreadline.h) + if (TCL_READLINE_INCLUDE) + message(STATUS "TCL readline header: ${TCL_READLINE_INCLUDE}/tclreadline.h") endif() endif() diff --git a/dcalc/ArcDcalcWaveforms.cc b/dcalc/ArcDcalcWaveforms.cc index 02f14479..954ae6eb 100644 --- a/dcalc/ArcDcalcWaveforms.cc +++ b/dcalc/ArcDcalcWaveforms.cc @@ -54,7 +54,7 @@ ArcDcalcWaveforms::inputWaveform(ArcDcalcArg &dcalc_arg, library->supplyVoltage("VDD", vdd, vdd_exists); if (!vdd_exists) report->error(1751, "VDD not defined in library %s", library->name()); - Waveform in_waveform = driver_waveform->waveform(in_slew); + Waveform in_waveform = driver_waveform->waveform(delayAsFloat(in_slew)); // Delay time axis. FloatSeq *time_values = new FloatSeq; for (float time : *in_waveform.axis1()->values()) diff --git a/dcalc/CcsCeffDelayCalc.cc b/dcalc/CcsCeffDelayCalc.cc index 45fe8fff..fbd331a4 100644 --- a/dcalc/CcsCeffDelayCalc.cc +++ b/dcalc/CcsCeffDelayCalc.cc @@ -104,7 +104,8 @@ CcsCeffDelayCalc::gateDelay(const Pin *drvr_pin, vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; vh_ = drvr_library->slewUpperThreshold(drvr_rf_) * vdd_; - drvr_cell->ensureVoltageWaveforms(dcalc_ap); + const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts(); + drvr_cell->ensureVoltageWaveforms(dcalc_aps); in_slew_ = delayAsFloat(in_slew); output_waveforms_ = output_waveforms; ref_time_ = output_waveforms_->referenceTime(in_slew_); diff --git a/dcalc/PrimaDelayCalc.cc b/dcalc/PrimaDelayCalc.cc index 32f6cf9a..3e46d07e 100644 --- a/dcalc/PrimaDelayCalc.cc +++ b/dcalc/PrimaDelayCalc.cc @@ -202,15 +202,17 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, dcalc_ap_ = dcalc_ap; drvr_rf_ = dcalc_args[0].arc()->toEdge()->asRiseFall(); parasitic_network_ = dcalc_args[0].parasitic(); + load_cap_ = dcalc_args[0].loadCap(); bool failed = false; output_waveforms_.resize(drvr_count_); + const DcalcAnalysisPtSeq &dcalc_aps = corners_->dcalcAnalysisPts(); for (size_t drvr_idx = 0; drvr_idx < drvr_count_; drvr_idx++) { ArcDcalcArg &dcalc_arg = dcalc_args[drvr_idx]; GateTableModel *table_model = dcalc_arg.arc()->gateTableModel(dcalc_ap); if (table_model && dcalc_arg.parasitic()) { OutputWaveforms *output_waveforms = table_model->outputWaveforms(); - Slew in_slew = dcalc_arg.inSlew(); + float in_slew = dcalc_arg.inSlewFlt(); if (output_waveforms // Bounds check because extrapolating waveforms does not work for shit. && output_waveforms->slewAxis()->inBounds(in_slew) @@ -225,7 +227,7 @@ PrimaDelayCalc::gateDelays(ArcDcalcArgSeq &dcalc_args, drvr_library->supplyVoltage("VDD", vdd_, vdd_exists); if (!vdd_exists) report_->error(1720, "VDD not defined in library %s", drvr_library->name()); - drvr_cell->ensureVoltageWaveforms(dcalc_ap); + drvr_cell->ensureVoltageWaveforms(dcalc_aps); if (drvr_idx == 0) { vth_ = drvr_library->outputThreshold(drvr_rf_) * vdd_; vl_ = drvr_library->slewLowerThreshold(drvr_rf_) * vdd_; @@ -321,7 +323,7 @@ PrimaDelayCalc::simulate1(const MatrixSd &G, v_ = v_prev_ = x_to_v * x_init; // voltageTime is always for a rising waveform so 0.0v is initial voltage. - double time_begin = output_waveforms_[0]->voltageTime((*dcalc_args_)[0].inSlew(), + double time_begin = output_waveforms_[0]->voltageTime((*dcalc_args_)[0].inSlewFlt(), ceff_[0], 0.0); // Limit in case load voltage waveforms don't get to final value. double time_end = time_begin + maxTime(); @@ -368,7 +370,7 @@ PrimaDelayCalc::timeStep() double PrimaDelayCalc::maxTime() { - return (*dcalc_args_)[0].inSlew() + return (*dcalc_args_)[0].inSlewFlt() + (driverResistance() + resistance_sum_) * load_cap_ * 4; } @@ -484,7 +486,7 @@ PrimaDelayCalc::initCeffIdrvr() ceff_[drvr_idx] = load_cap_; // voltageTime is always for a rising waveform so 0.0v is initial voltage. drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(), + output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), ceff_[drvr_idx], 0.0); } } @@ -615,7 +617,7 @@ PrimaDelayCalc::updateCeffIdrvr() drvr_current_[drvr_idx] = 0.0; else drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(), + output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), ceff_[drvr_idx], v1); } else { @@ -631,7 +633,7 @@ PrimaDelayCalc::updateCeffIdrvr() } else drvr_current_[drvr_idx] = - output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlew(), + output_waveforms_[drvr_idx]->voltageCurrent(dcalc_arg.inSlewFlt(), ceff_[drvr_idx], vdd_ - v1); } @@ -708,7 +710,7 @@ PrimaDelayCalc::dcalcResults() const LibertyLibrary *drvr_library = dcalc_arg.drvrLibrary(); size_t drvr_node = pin_node_map_[drvr_pin]; ThresholdTimes &drvr_times = threshold_times_[drvr_node]; - float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlew()); + float ref_time = output_waveforms_[drvr_idx]->referenceTime(dcalc_arg.inSlewFlt()); ArcDelay gate_delay = drvr_times[threshold_vth] - ref_time; Slew drvr_slew = abs(drvr_times[threshold_vh] - drvr_times[threshold_vl]); dcalc_result.setGateDelay(gate_delay); diff --git a/doc/OpenSTA.odt b/doc/OpenSTA.odt index 6fd8fedb..7d1012b7 100644 Binary files a/doc/OpenSTA.odt and b/doc/OpenSTA.odt differ diff --git a/doc/OpenSTA.pdf b/doc/OpenSTA.pdf index c39a5717..681d3745 100644 Binary files a/doc/OpenSTA.pdf and b/doc/OpenSTA.pdf differ diff --git a/graph/Graph.tcl b/graph/Graph.tcl index 72c649c0..128b55b2 100644 --- a/graph/Graph.tcl +++ b/graph/Graph.tcl @@ -230,7 +230,7 @@ proc report_pin_constant { pin } { ################################################################ -proc report_disabled_edges {} { +proc_redirect report_disabled_edges { foreach edge [disabled_edges_sorted] { if { [$edge role] == "wire" } { set from_pin_name [get_full_name [[$edge from] pin]] diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index f507c49e..0da0a530 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -80,6 +80,7 @@ typedef Vector InternalPowerAttrsSeq; typedef Map SupplyVoltageMap; typedef Map LibertyPgPortMap; typedef Map DriverWaveformMap; +typedef Vector DcalcAnalysisPtSeq; enum class ClockGateType { none, latch_posedge, latch_negedge, other }; @@ -532,7 +533,7 @@ public: // Check all liberty cells to make sure they exist // for all the defined corners. static void checkLibertyCorners(); - void ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap); + void ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps); protected: void addPort(ConcretePort *port); @@ -555,7 +556,10 @@ protected: const LibertyPort *en, const RiseFall *en_rf, const LibertyPort *q, + const TimingArcSet *en_to_q, Report *report); + bool condMatch(const TimingArcSet *arc_set1, + const TimingArcSet *arc_set2); void findDefaultCondArcs(); void translatePresetClrCheckRoles(); void inferLatchRoles(Report *report, @@ -837,6 +841,7 @@ protected: void setMinPort(LibertyPort *min); void addScaledPort(OperatingConditions *op_cond, LibertyPort *scaled_port); + RiseFallMinMax clkTreeDelays1() const; LibertyCell *liberty_cell_; BusDcl *bus_dcl_; diff --git a/include/sta/Property.hh b/include/sta/Property.hh index be06b272..c8bf3ab8 100644 --- a/include/sta/Property.hh +++ b/include/sta/Property.hh @@ -80,9 +80,9 @@ public: const Unit *unit() const { return unit_; } const char *asString(const Network *network) const; - const char *stringValue() const { return string_; } - float floatValue() const { return float_; } - bool boolValue() const { return bool_; } + const char *stringValue() const; // valid for type string + float floatValue() const; // valid for type float + bool boolValue() const; // valid for type bool const LibertyLibrary *libertyLibrary() const { return liberty_library_; } const LibertyCell *libertyCell() const { return liberty_cell_; } const LibertyPort *libertyPort() const { return liberty_port_; } diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 31d4d165..b52a4805 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -497,7 +497,7 @@ public: const TableAxis *capAxis() const { return cap_axis_.get(); } // Make voltage wavefroms from liberty time/current values. // Required before voltageTime, timeVoltage, voltageCurrent. - void makeVoltageWaveforms(float vdd); + void ensureVoltageWaveforms(float vdd); float timeCurrent(float slew, float cap, float time); diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 5acdc63b..96b24213 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -1729,11 +1729,13 @@ LibertyCell::makeLatchEnables(Report *report, LibertyPort *en = en_to_q->from(); LibertyPort *q = en_to_q->to(); for (TimingArcSet *d_to_q : timingArcSets(nullptr, q)) { - if (d_to_q->role() == TimingRole::latchDtoQ()) { + 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, report); + 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, @@ -1766,11 +1768,22 @@ LibertyCell::makeLatchEnables(Report *report, } } +bool +LibertyCell::condMatch(const TimingArcSet *arc_set1, + const TimingArcSet *arc_set2) +{ + FuncExpr *cond1 = arc_set1->cond(); + FuncExpr *cond2 = arc_set2->cond(); + return (cond1 == nullptr && cond2 == nullptr) + || FuncExpr::equiv(cond1, cond2); +} + TimingArcSet * LibertyCell::findLatchSetup(const LibertyPort *d, const LibertyPort *en, const RiseFall *en_rf, const LibertyPort *q, + const TimingArcSet *en_to_q, Report *report) { TimingArcSetSeq en_d_arcs = timingArcSets(en, d); @@ -1779,7 +1792,8 @@ LibertyCell::findLatchSetup(const LibertyPort *d, if (arc_set->role() == TimingRole::setup()) { for (TimingArc *arc : arc_set->arcs()) { const RiseFall *from_rf = arc->fromEdge()->asRiseFall(); - if (from_rf == en_rf->opposite()) + if (from_rf == en_rf->opposite() + && condMatch(arc_set, en_to_q)) return arc_set; } } @@ -1875,16 +1889,18 @@ LibertyCell::inferLatchRoles(Report *report, for (TimingArcSet *d_to_q : timingArcSets(nullptr, q)) { // Look for combinational d->q arcs. TimingRole *d_to_q_role = d_to_q->role(); - if ((d_to_q_role == TimingRole::combinational() - && d_to_q->arcCount() == 2 - && (d_to_q->sense() == TimingSense::positive_unate - || d_to_q->sense() == TimingSense::negative_unate)) - // Previously identified as D->Q arc. - || d_to_q_role == TimingRole::latchDtoQ()) { + if (((d_to_q_role == TimingRole::combinational() + && d_to_q->arcCount() == 2 + && (d_to_q->sense() == TimingSense::positive_unate + || d_to_q->sense() == TimingSense::negative_unate)) + // Previously identified as D->Q arc. + || 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, report); + TimingArcSet *setup_check = findLatchSetup(d, en, en_rf, q, en_to_q, + report); makeLatchEnable(d, en, en_rf, q, d_to_q, en_to_q, setup_check, debug); d_to_q->setRole(TimingRole::latchDtoQ()); en_to_q->setRole(TimingRole::latchEnToQ()); @@ -1933,7 +1949,7 @@ LibertyCell::latchCheckEnableEdge(TimingArcSet *check_set) } void -LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap) +LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPtSeq &dcalc_aps) { if (!have_voltage_waveforms_) { float vdd = 0.0; // shutup gcc @@ -1943,11 +1959,13 @@ LibertyCell::ensureVoltageWaveforms(const DcalcAnalysisPt *dcalc_ap) criticalError(1120, "library missing vdd"); for (TimingArcSet *arc_set : timingArcSets()) { for (TimingArc *arc : arc_set->arcs()) { - GateTableModel *model = arc->gateTableModel(dcalc_ap); - if (model) { - OutputWaveforms *output_waveforms = model->outputWaveforms(); - if (output_waveforms) - output_waveforms->makeVoltageWaveforms(vdd); + for (const DcalcAnalysisPt *dcalc_ap : dcalc_aps) { + GateTableModel *model = arc->gateTableModel(dcalc_ap); + if (model) { + OutputWaveforms *output_waveforms = model->outputWaveforms(); + if (output_waveforms) + output_waveforms->ensureVoltageWaveforms(vdd); + } } } } @@ -2627,11 +2645,17 @@ LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform, RiseFallMinMax LibertyPort::clockTreePathDelays() const { - return clkTreeDelays(); + return clkTreeDelays1(); } RiseFallMinMax LibertyPort::clkTreeDelays() const +{ + return clkTreeDelays1(); +} + +RiseFallMinMax +LibertyPort::clkTreeDelays1() const { RiseFallMinMax delays; for (const RiseFall *from_rf : RiseFall::range()) { diff --git a/liberty/Liberty.i b/liberty/Liberty.i index 8aa0d751..f6eeac35 100644 --- a/liberty/Liberty.i +++ b/liberty/Liberty.i @@ -289,9 +289,9 @@ timing_arc_sets() void ensure_voltage_waveforms() { - Corner *corner = Sta::sta()->cmdCorner(); - DcalcAnalysisPt *dcalc_ap = corner->findDcalcAnalysisPt(MinMax::max()); - self->ensureVoltageWaveforms(dcalc_ap); + Corners *corners = Sta::sta()->corners(); + const DcalcAnalysisPtSeq &dcalc_aps = corners->dcalcAnalysisPts(); + self->ensureVoltageWaveforms(dcalc_aps); } } // LibertyCell methods diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index a2123a68..5f499842 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -2351,7 +2351,8 @@ TimingGroup::makeTableModels(LibertyCell *cell, if (delay == nullptr) reader->libWarn(1211, line_, "missing cell_%s.", rf->name()); } - } else if (constraint) + } + else if (constraint) attrs_->setModel(rf, new CheckTableModel(cell, constraint, constraint_sigma_[rf_index])); } @@ -2401,23 +2402,34 @@ LibertyReader::makeTimingArcs(const char *from_port_name, else { // bus -> bus if (timing->isOneToOne()) { - if (static_cast(from_port_iter.size()) == to_port->size()) { - LibertyPortMemberIterator to_iter(to_port); - while (from_port_iter.hasNext() && to_iter.hasNext()) { - LibertyPort *from_port_bit = from_port_iter.next(); - LibertyPort *to_port_bit = to_iter.next(); - if (from_port_bit->direction()->isOutput()) - libWarn(1215, timing->line(), "timing group from output port."); - builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit, - related_out_port, timing->attrs(), - timing->line()); - } - } - else + int from_size = from_port_iter.size(); + int to_size = to_port->size(); + LibertyPortMemberIterator to_port_iter(to_port); + // warn about different sizes + if (from_size != to_size) libWarn(1216, timing->line(), "timing port %s and related port %s are different sizes.", from_port_name, to_port->name()); + // align to/from iterators for one-to-one mapping + while (from_size > to_size) { + from_size--; + from_port_iter.next(); + } + while (to_size > from_size) { + to_size--; + to_port_iter.next(); + } + // make timing arcs + while (from_port_iter.hasNext() && to_port_iter.hasNext()) { + LibertyPort *from_port_bit = from_port_iter.next(); + LibertyPort *to_port_bit = to_port_iter.next(); + if (from_port_bit->direction()->isOutput()) + libWarn(1215, timing->line(), "timing group from output port."); + builder_.makeTimingArcs(cell_, from_port_bit, to_port_bit, + related_out_port, timing->attrs(), + timing->line()); + } } else { while (from_port_iter.hasNext()) { @@ -2534,16 +2546,17 @@ LibertyReader::endReceiverCapacitanceRiseFall(LibertyGroup *group) if (ReceiverModel::checkAxes(table_)) { TableModel *table_model = new TableModel(table_, tbl_template_, scale_factor_type_, rf_); - if (timing_ && receiver_model_ == nullptr) { + if (receiver_model_ == nullptr) { receiver_model_ = make_shared(); - timing_->setReceiverModel(receiver_model_); + if (timing_) + timing_->setReceiverModel(receiver_model_); } receiver_model_->setCapacitanceModel(table_model, index_, rf_); } else libWarn(1219, group, "unsupported model axis."); + endTableModel(); } - endTableModel(); } //////////////////////////////////////////////////////////////// @@ -2576,50 +2589,52 @@ LibertyReader::beginOutputCurrent(RiseFall *rf, void LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) { - Set slew_set, cap_set; - FloatSeq *slew_values = new FloatSeq; - FloatSeq *cap_values = new FloatSeq; - for (OutputWaveform *waveform : output_currents_) { - float slew = waveform->slew(); - if (!slew_set.hasKey(slew)) { - slew_set.insert(slew); - slew_values->push_back(slew); + if (timing_) { + Set slew_set, cap_set; + FloatSeq *slew_values = new FloatSeq; + FloatSeq *cap_values = new FloatSeq; + for (OutputWaveform *waveform : output_currents_) { + float slew = waveform->slew(); + if (!slew_set.hasKey(slew)) { + slew_set.insert(slew); + slew_values->push_back(slew); + } + float cap = waveform->cap(); + if (!cap_set.hasKey(cap)) { + cap_set.insert(cap); + cap_values->push_back(cap); + } } - float cap = waveform->cap(); - if (!cap_set.hasKey(cap)) { - cap_set.insert(cap); - cap_values->push_back(cap); + sort(slew_values, std::less()); + sort(cap_values, std::less()); + TableAxisPtr slew_axis = make_shared(TableAxisVariable::input_net_transition, + slew_values); + TableAxisPtr cap_axis = make_shared(TableAxisVariable::total_output_net_capacitance, + cap_values); + FloatSeq *ref_times = new FloatSeq(slew_values->size()); + Table1Seq current_waveforms(slew_axis->size() * cap_axis->size()); + for (OutputWaveform *waveform : output_currents_) { + size_t slew_index, cap_index; + bool slew_exists, cap_exists; + slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists); + cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists); + if (slew_exists && cap_exists) { + size_t index = slew_index * cap_axis->size() + cap_index; + current_waveforms[index] = waveform->stealCurrents(); + (*ref_times)[slew_index] = waveform->referenceTime(); + } + else + libWarn(1221, group, "output current waveform %.2e %.2e not found.", + waveform->slew(), + waveform->cap()); } + Table1 *ref_time_tbl = new Table1(ref_times, slew_axis); + OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, rf_, + current_waveforms, + ref_time_tbl); + timing_->setOutputWaveforms(rf_, output_current); + output_currents_.deleteContentsClear(); } - sort(slew_values, std::less()); - sort(cap_values, std::less()); - TableAxisPtr slew_axis = make_shared(TableAxisVariable::input_net_transition, - slew_values); - TableAxisPtr cap_axis = make_shared(TableAxisVariable::total_output_net_capacitance, - cap_values); - FloatSeq *ref_times = new FloatSeq(slew_values->size()); - Table1Seq current_waveforms(slew_axis->size() * cap_axis->size()); - for (OutputWaveform *waveform : output_currents_) { - size_t slew_index, cap_index; - bool slew_exists, cap_exists; - slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists); - cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists); - if (slew_exists && cap_exists) { - size_t index = slew_index * cap_axis->size() + cap_index; - current_waveforms[index] = waveform->stealCurrents(); - (*ref_times)[slew_index] = waveform->referenceTime(); - } - else - libWarn(1221, group, "output current waveform %.2e %.2e not found.", - waveform->slew(), - waveform->cap()); - } - Table1 *ref_time_tbl = new Table1(ref_times, slew_axis); - OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, rf_, - current_waveforms, - ref_time_tbl); - timing_->setOutputWaveforms(rf_, output_current); - output_currents_.deleteContentsClear(); } void diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 21786e63..fe430ef0 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -1664,17 +1664,19 @@ OutputWaveforms::checkAxes(const TableTemplate *tbl_template) } void -OutputWaveforms::makeVoltageWaveforms(float vdd) +OutputWaveforms::ensureVoltageWaveforms(float vdd) { - vdd_ = vdd; - size_t size = current_waveforms_.size(); - voltage_waveforms_.resize(size); - voltage_currents_.resize(size); - size_t cap_count = cap_axis_->size(); - for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) { - for (size_t cap_index = 0; cap_index < cap_count; cap_index++) { - size_t wave_index = slew_index * cap_count + cap_index; - findVoltages(wave_index, cap_axis_->axisValue(cap_index)); + if (voltage_waveforms_.empty()) { + vdd_ = vdd; + size_t size = current_waveforms_.size(); + voltage_waveforms_.resize(size); + voltage_currents_.resize(size); + size_t cap_count = cap_axis_->size(); + for (size_t slew_index = 0; slew_index < slew_axis_->size(); slew_index++) { + for (size_t cap_index = 0; cap_index < cap_count; cap_index++) { + size_t wave_index = slew_index * cap_count + cap_index; + findVoltages(wave_index, cap_axis_->axisValue(cap_index)); + } } } } diff --git a/power/ReadVcdActivities.cc b/power/ReadVcdActivities.cc index fec6b2d3..894525b0 100644 --- a/power/ReadVcdActivities.cc +++ b/power/ReadVcdActivities.cc @@ -29,6 +29,7 @@ namespace sta { +using std::abs; using std::min; using std::to_string; diff --git a/sdc/Sdc.i b/sdc/Sdc.i index 909bb927..92639c8f 100644 --- a/sdc/Sdc.i +++ b/sdc/Sdc.i @@ -1270,30 +1270,41 @@ all_outputs_cmd() return sta->sdc()->allOutputs(); } +template Vector +filter_objects(const char *property, + const char *op, + const char *pattern, + Vector *objects) +{ + Vector filtered_objects; + if (objects) { + Sta *sta = Sta::sta(); + bool exact_match = stringEq(op, "=="); + bool pattern_match = stringEq(op, "=~"); + bool not_match = stringEq(op, "!="); + bool not_pattern_match = stringEq(op, "!~"); + for (T *object : *objects) { + PropertyValue value(getProperty(object, property, sta)); + const char *prop = value.asString(sta->network()); + if (prop && + ((exact_match && stringEq(prop, pattern)) + || (not_match && !stringEq(prop, pattern)) + || (pattern_match && patternMatch(pattern, prop)) + || (not_pattern_match && !patternMatch(pattern, prop)))) + filtered_objects.push_back(object); + } + delete objects; + } + return filtered_objects; +} + PortSeq filter_ports(const char *property, const char *op, const char *pattern, PortSeq *ports) { - PortSeq filtered_ports; - if (ports) { - Sta *sta = Sta::sta(); - bool exact_match = stringEq(op, "=="); - bool pattern_match = stringEq(op, "=~"); - bool not_match = stringEq(op, "!="); - for (const Port *port : *ports) { - PropertyValue value(getProperty(port, property, sta)); - const char *prop = value.stringValue(); - if (prop && - ((exact_match && stringEq(prop, pattern)) - || (not_match && !stringEq(prop, pattern)) - || (pattern_match && patternMatch(pattern, prop)))) - filtered_ports.push_back(port); - } - delete ports; - } - return filtered_ports; + return filter_objects(property, op, pattern, ports); } InstanceSeq @@ -1302,25 +1313,7 @@ filter_insts(const char *property, const char *pattern, InstanceSeq *insts) { - InstanceSeq filtered_insts; - if (insts) { - Sta *sta = Sta::sta(); - cmdLinkedNetwork(); - bool exact_match = stringEq(op, "=="); - bool pattern_match = stringEq(op, "=~"); - bool not_match = stringEq(op, "!="); - for (const Instance *inst : *insts) { - PropertyValue value(getProperty(inst, property, sta)); - const char *prop = value.stringValue(); - if (prop && - ((exact_match && stringEq(prop, pattern)) - || (not_match && !stringEq(prop, pattern)) - || (pattern_match && patternMatch(pattern, prop)))) - filtered_insts.push_back(inst); - } - delete insts; - } - return filtered_insts; + return filter_objects(property, op, pattern, insts); } PinSeq @@ -1329,24 +1322,7 @@ filter_pins(const char *property, const char *pattern, PinSeq *pins) { - PinSeq filtered_pins; - if (pins) { - Sta *sta = Sta::sta(); - bool exact_match = stringEq(op, "=="); - bool pattern_match = stringEq(op, "=~"); - bool not_match = stringEq(op, "!="); - for (const Pin *pin : *pins) { - PropertyValue value(getProperty(pin, property, sta)); - const char *prop = value.asString(sta->sdcNetwork()); - if (prop && - ((exact_match && stringEq(prop, pattern)) - || (not_match && !stringEq(prop, pattern)) - || (pattern_match && patternMatch(pattern, prop)))) - filtered_pins.push_back(pin); - } - delete pins; - } - return filtered_pins; + return filter_objects(property, op, pattern, pins); } EdgeSeq @@ -1355,22 +1331,7 @@ filter_timing_arcs(const char *property, const char *pattern, EdgeSeq *edges) { - Sta *sta = Sta::sta(); - EdgeSeq filtered_edges; - bool exact_match = stringEq(op, "=="); - bool pattern_match = stringEq(op, "=~"); - bool not_match = stringEq(op, "!="); - for (Edge *edge : *edges) { - PropertyValue value(getProperty(edge, property, sta)); - const char *prop = value.stringValue(); - if (prop && - ((exact_match && stringEq(prop, pattern)) - || (not_match && !stringEq(prop, pattern)) - || (pattern_match && patternMatch(pattern, prop)))) - filtered_edges.push_back(edge); - } - delete edges; - return filtered_edges; + return filter_objects(property, op, pattern, edges); } //////////////////////////////////////////////////////////////// diff --git a/sdc/Sdc.tcl b/sdc/Sdc.tcl index e840545d..eb52c098 100644 --- a/sdc/Sdc.tcl +++ b/sdc/Sdc.tcl @@ -935,7 +935,7 @@ proc get_ports { args } { return $ports } -variable filter_regexp1 {@?([a-zA-Z_]+) *(==|!=|=~) *([0-9a-zA-Z_\*]+)} +variable filter_regexp1 {@?([a-zA-Z_]+) *(==|!=|=~|!~) *([0-9a-zA-Z_\*]+)} variable filter_or_regexp "($filter_regexp1) *\\|\\| *($filter_regexp1)" variable filter_and_regexp "($filter_regexp1) *&& *($filter_regexp1)" diff --git a/search/Property.cc b/search/Property.cc index d51b5303..1477856f 100644 --- a/search/Property.cc +++ b/search/Property.cc @@ -126,6 +126,35 @@ PropertyUnknown::what() const noexcept //////////////////////////////////////////////////////////////// +class PropertyTypeWrong : public Exception +{ +public: + PropertyTypeWrong(const char *accessor, + const char *type); + virtual ~PropertyTypeWrong() {} + virtual const char *what() const noexcept; + +private: + const char *accessor_; + const char *type_; +}; + +PropertyTypeWrong::PropertyTypeWrong(const char *accessor, + const char *type) : + Exception(), + accessor_(accessor), + type_(type) +{ +} + +const char * +PropertyTypeWrong::what() const noexcept +{ + return stringPrint("property accessor %s is only valid for %s properties.", + accessor_, type_); +} +//////////////////////////////////////////////////////////////// + PropertyValue::PropertyValue() : type_(type_none), unit_(nullptr) @@ -620,6 +649,30 @@ PropertyValue::asString(const Network *network) const return nullptr; } +const char * +PropertyValue::stringValue() const +{ + if (type_ != Type::type_string) + throw PropertyTypeWrong("stringValue", "string"); + return string_; +} + +float +PropertyValue::floatValue() const +{ + if (type_ != Type::type_float) + throw PropertyTypeWrong("floatValue", "float"); + return float_; +} + +bool +PropertyValue::boolValue() const +{ + if (type_ != Type::type_bool) + throw PropertyTypeWrong("boolValue", "boolt"); + return bool_; +} + //////////////////////////////////////////////////////////////// PropertyValue diff --git a/search/Sim.cc b/search/Sim.cc index 720a0811..f603880c 100644 --- a/search/Sim.cc +++ b/search/Sim.cc @@ -148,6 +148,7 @@ Sim::funcBddSim(const FuncExpr *expr, } } } + delete pin_iter; return bdd; } diff --git a/tcl/StaTclTypes.i b/tcl/StaTclTypes.i index 648f7961..08c30144 100644 --- a/tcl/StaTclTypes.i +++ b/tcl/StaTclTypes.i @@ -192,7 +192,7 @@ tclListNetworkSet1(Tcl_Obj *const source, return set; } -StringSet * +static StringSet * tclListSetConstChar(Tcl_Obj *const source, Tcl_Interp *interp) { @@ -212,7 +212,7 @@ tclListSetConstChar(Tcl_Obj *const source, return nullptr; } -StringSeq * +static StringSeq * tclListSeqConstChar(Tcl_Obj *const source, Tcl_Interp *interp) { @@ -232,7 +232,7 @@ tclListSeqConstChar(Tcl_Obj *const source, return nullptr; } -StdStringSet * +static StdStringSet * tclListSetStdString(Tcl_Obj *const source, Tcl_Interp *interp) { @@ -317,7 +317,7 @@ setPtrTclList(SET_TYPE *set, //////////////////////////////////////////////////////////////// -void +static void tclArgError(Tcl_Interp *interp, const char *msg, const char *arg) @@ -330,7 +330,7 @@ tclArgError(Tcl_Interp *interp, stringDelete(error); } -void +static void objectListNext(const char *list, const char *type, // Return values. @@ -366,7 +366,7 @@ objectListNext(const char *list, } } -Tcl_Obj * +static Tcl_Obj * tclArcDcalcArg(ArcDcalcArg &gate, Tcl_Interp *interp) { @@ -405,7 +405,7 @@ tclArcDcalcArg(ArcDcalcArg &gate, return list; } -ArcDcalcArg +static ArcDcalcArg arcDcalcArgTcl(Tcl_Obj *obj, Tcl_Interp *interp) { diff --git a/test/liberty_arcs_one2one.lib b/test/liberty_arcs_one2one.lib new file mode 100644 index 00000000..7eebe107 --- /dev/null +++ b/test/liberty_arcs_one2one.lib @@ -0,0 +1,93 @@ +library (one_to_one_mismatched_width) { + delay_model : "table_lookup"; + simulation : false; + capacitive_load_unit (1,pF); + leakage_power_unit : "1pW"; + current_unit : "1A"; + pulling_resistance_unit : "1kohm"; + time_unit : "1ns"; + voltage_unit : "1v"; + library_features : "report_delay_calculation"; + input_threshold_pct_rise : 50; + input_threshold_pct_fall : 50; + output_threshold_pct_rise : 50; + output_threshold_pct_fall : 50; + slew_lower_threshold_pct_rise : 30; + slew_lower_threshold_pct_fall : 30; + slew_upper_threshold_pct_rise : 70; + slew_upper_threshold_pct_fall : 70; + slew_derate_from_library : 1.0; + nom_process : 1.0; + nom_temperature : 85.0; + nom_voltage : 0.75; + type (bus8) { + base_type : "array"; + data_type : "bit"; + bit_width : 8; + bit_from : 7; + bit_to : 0; + } + type (bus4) { + base_type : "array"; + data_type : "bit"; + bit_width : 4; + bit_from : 3; + bit_to : 0; + } + + cell (inv_8_to_4) { + bus (A) { + capacitance : 1; + bus_type : "bus8"; + direction : "input"; + } + bus (Y) { + function : "!A"; + bus_type : "bus4"; + direction : "output"; + timing () { + related_pin : "A"; + cell_rise (scalar) { + values ("1"); + } + cell_fall (scalar) { + values ("1"); + } + rise_transition (scalar) { + values ("1"); + } + fall_transition (scalar) { + values ("1"); + } + } + } + } + + cell (inv_4_to_8) { + bus (A) { + capacitance : 1; + bus_type : "bus4"; + direction : "input"; + } + bus (Y) { + function : "!A"; + bus_type : "bus8"; + direction : "output"; + timing () { + related_pin : "A"; + cell_rise (scalar) { + values ("1"); + } + cell_fall (scalar) { + values ("1"); + } + rise_transition (scalar) { + values ("1"); + } + fall_transition (scalar) { + values ("1"); + } + } + } + } +} \ No newline at end of file diff --git a/test/liberty_arcs_one2one.ok b/test/liberty_arcs_one2one.ok new file mode 100644 index 00000000..22d298ef --- /dev/null +++ b/test/liberty_arcs_one2one.ok @@ -0,0 +1,220 @@ +Warning: liberty_arcs_one2one.lib line 48, timing port A and related port Y are different sizes. +Warning: liberty_arcs_one2one.lib line 76, timing port A and related port Y are different sizes. +TEST 1: +Startpoint: a[0] (input port clocked by clk) +Endpoint: y[0] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[0] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[0] (inv_8_to_4) + 0.00 1.00 ^ y[0] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[1] (input port clocked by clk) +Endpoint: y[1] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[1] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[1] (inv_8_to_4) + 0.00 1.00 ^ y[1] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[2] (input port clocked by clk) +Endpoint: y[2] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[2] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[2] (inv_8_to_4) + 0.00 1.00 ^ y[2] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[3] (input port clocked by clk) +Endpoint: y[3] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[3] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[3] (inv_8_to_4) + 0.00 1.00 ^ y[3] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +TEST 2: +Startpoint: a[0] (input port clocked by clk) +Endpoint: y[0] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[0] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[0] (inv_4_to_8) + 0.00 1.00 ^ y[0] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[1] (input port clocked by clk) +Endpoint: y[1] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[1] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[1] (inv_4_to_8) + 0.00 1.00 ^ y[1] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[2] (input port clocked by clk) +Endpoint: y[2] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[2] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[2] (inv_4_to_8) + 0.00 1.00 ^ y[2] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + +Startpoint: a[3] (input port clocked by clk) +Endpoint: y[3] (output port clocked by clk) +Path Group: clk +Path Type: max + + Delay Time Description +--------------------------------------------------------- + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 v input external delay + 0.00 0.00 v a[3] (in) + 1.00 1.00 ^ partial_wide_inv_cell/Y[3] (inv_4_to_8) + 0.00 1.00 ^ y[3] (out) + 1.00 data arrival time + + 0.00 0.00 clock clk (rise edge) + 0.00 0.00 clock network delay (ideal) + 0.00 0.00 clock reconvergence pessimism + 0.00 0.00 output external delay + 0.00 data required time +--------------------------------------------------------- + 0.00 data required time + -1.00 data arrival time +--------------------------------------------------------- + -1.00 slack (VIOLATED) + + diff --git a/test/liberty_arcs_one2one.tcl b/test/liberty_arcs_one2one.tcl new file mode 100644 index 00000000..38bac255 --- /dev/null +++ b/test/liberty_arcs_one2one.tcl @@ -0,0 +1,17 @@ +read_liberty liberty_arcs_one2one.lib + +puts "TEST 1:" +read_verilog liberty_arcs_one2one_1.v +link_design liberty_arcs_one2one_1 +create_clock -name clk -period 0 +set_input_delay -clock clk 0 [all_inputs] +set_output_delay -clock clk 0 [all_outputs] +report_checks -group_count 5 + +puts "TEST 2:" +read_verilog liberty_arcs_one2one_2.v +link_design liberty_arcs_one2one_2 +create_clock -name clk -period 0 +set_input_delay -clock clk 0 [all_inputs] +set_output_delay -clock clk 0 [all_outputs] +report_checks -group_count 5 diff --git a/test/liberty_arcs_one2one_1.v b/test/liberty_arcs_one2one_1.v new file mode 100644 index 00000000..46d11e2a --- /dev/null +++ b/test/liberty_arcs_one2one_1.v @@ -0,0 +1,13 @@ +// Liberty file test: one-to-one mapping with mismatched bit widths +// Should generate warning but still create timing arcs between bits with same index +module liberty_arcs_one2one_1 ( + input wire [7:0] a, + output wire [3:0] y +); + + inv_8_to_4 partial_wide_inv_cell ( + .A(a), + .Y(y) + ); + +endmodule \ No newline at end of file diff --git a/test/liberty_arcs_one2one_2.v b/test/liberty_arcs_one2one_2.v new file mode 100644 index 00000000..8bc66fad --- /dev/null +++ b/test/liberty_arcs_one2one_2.v @@ -0,0 +1,13 @@ +// Liberty file test: one-to-one mapping with mismatched bit widths +// Should generate warning but still create timing arcs between bits with same index +module liberty_arcs_one2one_2 ( + input wire [3:0] a, + output wire [7:0] y +); + + inv_4_to_8 partial_wide_inv_cell ( + .A(a), + .Y(y) + ); + +endmodule \ No newline at end of file diff --git a/test/regression_vars.tcl b/test/regression_vars.tcl index 8fde713d..5ecca193 100644 --- a/test/regression_vars.tcl +++ b/test/regression_vars.tcl @@ -124,6 +124,7 @@ record_example_tests { record_sta_tests { prima3 verilog_attribute + liberty_arcs_one2one } define_test_group fast [group_tests all]