From 6c3ba16e0767f6dc371c5d4c4a0501be97f14906 Mon Sep 17 00:00:00 2001 From: James Cherry Date: Wed, 22 Mar 2023 09:57:54 -0700 Subject: [PATCH] liberty driver_waveform Signed-off-by: James Cherry --- dcalc/DelayCalc.i | 11 ++ include/sta/Liberty.hh | 13 ++ include/sta/TableModel.hh | 112 +++++++----- liberty/Liberty.cc | 34 +++- liberty/LibertyReader.cc | 187 +++++++++++++------ liberty/LibertyReaderPvt.hh | 24 ++- liberty/TableModel.cc | 337 ++++++++++++++++++++++++++-------- messages.txt | 352 ++++++++++++++++++------------------ search/WritePathSpice.cc | 71 +++++++- tcl/StaTcl.i | 79 ++++++-- util/Transition.cc | 8 +- 11 files changed, 849 insertions(+), 379 deletions(-) diff --git a/dcalc/DelayCalc.i b/dcalc/DelayCalc.i index 64424f19..561f4c1d 100644 --- a/dcalc/DelayCalc.i +++ b/dcalc/DelayCalc.i @@ -48,4 +48,15 @@ set_delay_calc_incremental_tolerance(float tol) sta::Sta::sta()->setIncrementalDelayTolerance(tol); } +TmpString * +report_delay_calc_cmd(Edge *edge, + TimingArc *arc, + const Corner *corner, + const MinMax *min_max, + int digits) +{ + cmdLinkedNetwork(); + return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); +} + %} // inline diff --git a/include/sta/Liberty.hh b/include/sta/Liberty.hh index 04753cc7..db628187 100644 --- a/include/sta/Liberty.hh +++ b/include/sta/Liberty.hh @@ -49,6 +49,7 @@ class StaState; class Corner; class Corners; class DcalcAnalysisPt; +class DriverWaveform; typedef Map TableTemplateMap; typedef Vector TableTemplateSeq; @@ -77,6 +78,7 @@ typedef Map OcvDerateMap; typedef Vector InternalPowerAttrsSeq; typedef Map SupplyVoltageMap; typedef Map LibertyPgPortMap; +typedef Map DriverWaveformMap; enum class ClockGateType { none, latch_posedge, latch_negedge, other }; @@ -315,6 +317,10 @@ public: Corners *corners, Report *report); + DriverWaveform *findDriverWaveform(const char *name); + DriverWaveform *driverWaveformDefault() { return driver_waveform_default_; } + void addDriverWaveform(DriverWaveform *driver_waveform); + protected: float degradeWireSlew(const LibertyCell *cell, const Pvt *pvt, @@ -363,6 +369,9 @@ protected: OcvDerateMap ocv_derate_map_; SupplyVoltageMap supply_voltage_map_; LibertyCellSeq *buffers_; + DriverWaveformMap driver_waveform_map_; + // Unnamed driver waveform. + DriverWaveform *driver_waveform_default_; static constexpr float input_threshold_default_ = .5; static constexpr float output_threshold_default_ = .5; @@ -780,6 +789,9 @@ public: void setRelatedPowerPin(const char *related_power_pin); ReceiverModelPtr receiverModel() const { return receiver_model_; } void setReceiverModel(ReceiverModelPtr receiver_model); + DriverWaveform *driverWaveform(const RiseFall *rf) const; + void setDriverWaveform(DriverWaveform *driver_waveform, + const RiseFall *rf); static bool equiv(const LibertyPort *port1, const LibertyPort *port2); @@ -820,6 +832,7 @@ protected: const char *related_power_pin_; Vector corner_ports_; ReceiverModelPtr receiver_model_; + DriverWaveform *driver_waveform_[RiseFall::index_count]; unsigned int min_pulse_width_exists_:RiseFall::index_count; bool min_period_exists_:1; diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh index 39375eb7..2d08f089 100644 --- a/include/sta/TableModel.hh +++ b/include/sta/TableModel.hh @@ -33,12 +33,12 @@ class Unit; class Units; class Report; class Table; -class OutputCurrent; -class OutputCurrentWaveform; +class OutputWaveforms; +class OutputWaveform; typedef Vector FloatSeq; typedef Vector FloatTable; -typedef Vector OutputCurrentWaveformSeq; +typedef Vector OutputWaveformSeq; TableAxisVariable stringTableAxisVariable(const char *variable); @@ -56,7 +56,7 @@ public: TableModel *slew_model, TableModel *slew_sigma_models[EarlyLate::index_count], ReceiverModelPtr receiver_model, - OutputCurrent *output_current); + OutputWaveforms *output_waveforms); virtual ~GateTableModel(); virtual void gateDelay(const LibertyCell *cell, const Pvt *pvt, @@ -80,6 +80,8 @@ public: const TableModel *delayModel() const { return delay_model_; } const TableModel *slewModel() const { return slew_model_; } + ReceiverModelPtr receiverModel() const { return receiver_model_; } + OutputWaveforms *outputWaveforms() const { return output_waveforms_; } // Check the axes before making the model. // Return true if the model axes are supported. static bool checkAxes(const TablePtr table); @@ -127,7 +129,7 @@ protected: TableModel *slew_model_; TableModel *slew_sigma_models_[EarlyLate::index_count]; ReceiverModelPtr receiver_model_; - OutputCurrent *output_current_; + OutputWaveforms *output_waveforms_; }; class CheckTableModel : public CheckTimingModel @@ -333,15 +335,21 @@ private: class Table1 : public Table { public: + Table1(); Table1(FloatSeq *values, TableAxisPtr axis1); virtual ~Table1(); + Table1(Table1 &&table); + Table1 &operator= (Table1 &&table); virtual int order() const { return 1; } virtual TableAxisPtr axis1() const { return axis1_; } virtual float value(size_t index1, size_t index2, size_t index3) const; float value(size_t index1) const; + float findValue(float value1) const; + float findValue(float value1, + bool extrapolate) const; virtual float findValue(float value1, float value2, float value3) const; @@ -358,6 +366,7 @@ public: string *result) const; virtual void report(const Units *units, Report *report) const; + FloatSeq *values() const { return values_; } using Table::findValue; private: @@ -462,6 +471,8 @@ public: size_t &index, bool &exists) const; FloatSeq *values() const { return values_; } + float min() const { return (*values_)[0]; } + float max() const { return (*values_)[values_->size() - 1]; } private: TableAxisVariable variable_; @@ -484,63 +495,74 @@ private: TableModel *capacitance_models_[2][RiseFall::index_count]; }; -class OutputCurrentWaveform +class OutputWaveform { public: - OutputCurrentWaveform(float axis_value1, - float axis_value2, - TableAxisPtr axis, - Table1 *currents, - float reference_time); - ~OutputCurrentWaveform(); - float axisValue1() const { return axis_value1_; } - float axisValue2() const { return axis_value2_; } - TableAxisPtr axis() const { return axis_; } + OutputWaveform(float axis_value1, + float axis_value2, + Table1 *currents, + float reference_time); + OutputWaveform(float slew, + float cap, + Table1 *currents, + Table1 *voltages, + float reference_time); + ~OutputWaveform(); + float slew() const { return slew_; } + float cap() const { return cap_; } + TableAxisPtr timeAxis() const { return currents_->axis1(); } Table1 *currents() const { return currents_; } + Table1 *voltages(); float referenceTime() const { return reference_time_; } - void reportWaveform(const Units *units, - int digits, - string *result); static bool checkAxes(TableTemplate *tbl_template); + string reportCurrentWaveform(const Units *units, + int digits) const; + string reportVoltageWaveform(const Units *units, + int digits) const; + string reportWaveform(const Table1 *waveform, + const Unit *time_unit, + const Unit *waveform_unit, + int digits) const; private: - float axis_value1_; - float axis_value2_; - TableAxisPtr axis_; + float slew_; + float cap_; Table1 *currents_; + Table1 *voltages_; float reference_time_; }; -// Two dimensional table of one dimensional time/current tables. -class OutputCurrent +// Two dimensional (slew/cap) table of one dimensional time/current tables. +class OutputWaveforms { public: - OutputCurrent(TableAxisPtr axis1, - TableAxisPtr axis2, - Vector &waveforms); - ~OutputCurrent(); - void reportWaveform(const LibertyCell *cell, - const Pvt *pvt, - float in_slew, - float load_cap, - int digits, - string *result) const; + OutputWaveforms(TableAxisPtr slew_axis, + TableAxisPtr cap_axis, + Vector &waveforms); + ~OutputWaveforms(); + OutputWaveform voltageWaveform(float in_slew, + float load_cap); private: - void findAxisValues(float in_slew, - float load_cap, - // Return values. - float &axis_value1, - float &axis_value2) const; - float axisValue(TableAxisPtr axis, - float in_slew, - float load_cap) const; - // Row. - TableAxisPtr axis1_; + TableAxisPtr slew_axis_; // Column. - TableAxisPtr axis2_; - OutputCurrentWaveformSeq waveforms_; + TableAxisPtr cap_axis_; + OutputWaveformSeq waveforms_; +}; + +class DriverWaveform +{ +public: + DriverWaveform(const char *name, + TablePtr waveforms); + ~DriverWaveform(); + const char *name() const { return name_; } + Table1 waveform(float slew); + +private: + const char *name_; + TablePtr waveforms_; }; } // namespace diff --git a/liberty/Liberty.cc b/liberty/Liberty.cc index 4762e2be..69e3780d 100644 --- a/liberty/Liberty.cc +++ b/liberty/Liberty.cc @@ -82,7 +82,8 @@ LibertyLibrary::LibertyLibrary(const char *name, default_operating_conditions_(nullptr), ocv_arc_depth_(0.0), default_ocv_derate_(nullptr), - buffers_(nullptr) + buffers_(nullptr), + driver_waveform_default_(nullptr) { // Scalar templates are builtin. for (int i = 0; i != table_template_type_count; i++) { @@ -860,6 +861,23 @@ LibertyLibrary::supplyExists(const char *supply_name) const return supply_voltage_map_.hasKey(supply_name); } +DriverWaveform * +LibertyLibrary::findDriverWaveform(const char *name) +{ + return driver_waveform_map_[name]; +} + +void +LibertyLibrary::addDriverWaveform(DriverWaveform *driver_waveform) +{ + if (driver_waveform->name()) + driver_waveform_map_[driver_waveform->name()] = driver_waveform; + else { + delete driver_waveform_default_; + driver_waveform_default_ = driver_waveform; + } +} + //////////////////////////////////////////////////////////////// LibertyCellIterator::LibertyCellIterator(const LibertyLibrary *library) : @@ -1920,6 +1938,7 @@ LibertyPort::LibertyPort(LibertyCell *cell, related_ground_pin_(nullptr), related_power_pin_(nullptr), receiver_model_(nullptr), + driver_waveform_{nullptr, nullptr}, min_pulse_width_exists_(false), min_period_exists_(false), is_clk_(false), @@ -2519,6 +2538,19 @@ portLibertyToSta(const char *port_name) return sta_name; } +DriverWaveform * +LibertyPort::driverWaveform(const RiseFall *rf) const +{ + return driver_waveform_[rf->index()]; +} + +void +LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform, + const RiseFall *rf) +{ + driver_waveform_[rf->index()] = driver_waveform; +} + //////////////////////////////////////////////////////////////// LibertyPortSeq diff --git a/liberty/LibertyReader.cc b/liberty/LibertyReader.cc index 7a8e805c..3ce401f4 100644 --- a/liberty/LibertyReader.cc +++ b/liberty/LibertyReader.cc @@ -501,10 +501,14 @@ LibertyReader::defineVisitors() defineGroupVisitor("output_current_fall", &LibertyReader::beginOutputCurrentFall, &LibertyReader::endOutputCurrentRiseFall); - defineGroupVisitor("vector", - &LibertyReader::beginVector, - &LibertyReader::endVector); + defineGroupVisitor("vector", &LibertyReader::beginVector, &LibertyReader::endVector); defineAttrVisitor("reference_time", &LibertyReader::visitReferenceTime); + defineGroupVisitor("normalized_driver_waveform", + &LibertyReader::beginNormalizedDriverWaveform, + &LibertyReader::endNormalizedDriverWaveform); + defineAttrVisitor("driver_waveform_name", &LibertyReader::visitDriverWaveformName); + defineAttrVisitor("driver_waveform_rise", &LibertyReader::visitDriverWaveformRise); + defineAttrVisitor("driver_waveform_fall", &LibertyReader::visitDriverWaveformFall); } void @@ -2283,7 +2287,7 @@ TimingGroup::makeTableModels(LibertyReader *reader) transition, slew_sigma_[rf_index], receiver_model_, - output_current_[rf_index])); + output_waveforms_[rf_index])); TimingType timing_type = attrs_->timingType(); if (timing_type == TimingType::clear || timing_type == TimingType::combinational @@ -2480,8 +2484,10 @@ void LibertyReader::beginOutputCurrent(RiseFall *rf, LibertyGroup *group) { - if (timing_) + if (timing_) { rf_ = rf; + output_currents_.clear(); + } else libWarn(907, group, "output_current_%s group not in timing group.", rf->name()); @@ -2490,54 +2496,54 @@ LibertyReader::beginOutputCurrent(RiseFall *rf, void LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) { - Set axis_set1, axis_set2; - FloatSeq *axis_values1 = new FloatSeq; - FloatSeq *axis_values2 = new FloatSeq; - for (OutputCurrentWaveform *waveform : output_current_waveforms_) { - float axis_value1 = waveform->axisValue1(); - if (!axis_set1.hasKey(axis_value1)) { - axis_set1.insert(axis_value1); - axis_values1->push_back(axis_value1); + 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 axis_value2 = waveform->axisValue2(); - if (!axis_set2.hasKey(axis_value2)) { - axis_set2.insert(axis_value2); - axis_values2->push_back(axis_value2); + float cap = waveform->cap(); + if (!cap_set.hasKey(cap)) { + cap_set.insert(cap); + cap_values->push_back(cap); } } - sort(axis_values1, std::less()); - sort(axis_values2, std::less()); - TableAxisPtr axis1 = std::make_shared(axis_[0]->variable(), - axis_values1); - TableAxisPtr axis2 = std::make_shared(axis_[1]->variable(), - axis_values2); - Vector waveforms(axis1->size() * axis2->size()); - for (OutputCurrentWaveform *waveform : output_current_waveforms_) { - size_t index1, index2; - bool exists1, exists2; - axis1->findAxisIndex(waveform->axisValue1(), index1, exists1); - axis2->findAxisIndex(waveform->axisValue2(), index2, exists2); - if (exists1 && exists2) { - size_t index = index1 * axis2->size() + index2; + 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); + Vector 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; waveforms[index] = waveform; } else libWarn(913, group, "output current waveform %.2e %.2e not found.", - waveform->axisValue1(), - waveform->axisValue2()); + waveform->slew(), + waveform->cap()); } - OutputCurrent *output_current = new OutputCurrent(axis1, axis2, waveforms); - timing_->setOutputCurrent(rf_, output_current); + OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, waveforms); + timing_->setOutputWaveforms(rf_, output_current); } void LibertyReader::beginVector(LibertyGroup *group) { if (timing_) { - beginTable(group, TableTemplateType::output_current, 1.0); + beginTable(group, TableTemplateType::output_current, current_scale_); scale_factor_type_ = ScaleFactorType::unknown; reference_time_exists_ = false; - if (tbl_template_ && !OutputCurrentWaveform::checkAxes(tbl_template_)) + if (tbl_template_ && !OutputWaveform::checkAxes(tbl_template_)) libWarn(118, group, "unsupported model axis."); } } @@ -2546,32 +2552,41 @@ void LibertyReader::visitReferenceTime(LibertyAttr *attr) { getAttrFloat(attr, reference_time_, reference_time_exists_); + if (reference_time_exists_) + reference_time_ *= time_scale_; } void LibertyReader::endVector(LibertyGroup *group) { if (timing_ && tbl_template_) { - FloatSeq *axis_values1 = axis_values_[0]; - FloatSeq *axis_values2 = axis_values_[1]; - if (axis_values1->size() == 1 && axis_values2->size() == 1) { + FloatSeq *slew_values = axis_values_[0]; + FloatSeq *cap_values = axis_values_[1]; + // Canonicalize axis order. + if (tbl_template_->axis1()->variable() == TableAxisVariable::input_net_transition) { + slew_values = axis_values_[0]; + cap_values = axis_values_[1]; + } + else { + slew_values = axis_values_[1]; + cap_values = axis_values_[0]; + } + + if (slew_values->size() == 1 && cap_values->size() == 1) { // Convert 1x1xN Table3 to Table1. - float axis_value1 = (*axis_values1)[0]; - float axis_value2 = (*axis_values2)[0]; + float slew = (*slew_values)[0]; + float cap = (*cap_values)[0]; Table3 *table3 = dynamic_cast(table_.get()); FloatTable *values3 = table3->values3(); // Steal the values. FloatSeq *values = (*values3)[0]; (*values3)[0] = nullptr; Table1 *table1 = new Table1(values, axis_[2]); - OutputCurrentWaveform *waveform = new OutputCurrentWaveform(axis_value1, - axis_value2, - axis_[2], table1, - reference_time_); - output_current_waveforms_.push_back(waveform); + OutputWaveform *waveform = new OutputWaveform(slew, cap, table1, reference_time_); + output_currents_.push_back(waveform); } else - libWarn(912, group->line(), "vector index_1 and index_2 must have one value."); + libWarn(912,group->line(), "vector index_1 and index_2 must have exactly one value."); if (!reference_time_exists_) libWarn(908, group->line(), "vector reference_time not found."); reference_time_exists_ = false; @@ -2580,6 +2595,68 @@ LibertyReader::endVector(LibertyGroup *group) /////////////////////////////////////////////////////////////// +void +LibertyReader::beginNormalizedDriverWaveform(LibertyGroup *group) +{ + beginTable(group, TableTemplateType::delay, time_scale_); + driver_waveform_name_ = nullptr; +} + +void +LibertyReader::visitDriverWaveformName(LibertyAttr *attr) +{ + driver_waveform_name_ = stringCopy(getAttrString(attr)); +} + +void +LibertyReader::endNormalizedDriverWaveform(LibertyGroup *group) +{ + if (table_) { + if (table_->axis1()->variable() == TableAxisVariable::input_net_transition) { + if (table_->axis2()->variable() == TableAxisVariable::normalized_voltage) { + // Null driver_waveform_name_ means it is the default unnamed waveform. + DriverWaveform *driver_waveform = new DriverWaveform(driver_waveform_name_, + table_); + library_->addDriverWaveform(driver_waveform); + + } + else + libWarn(914, group, "normalized_driver_waveform variable_2 must be normalized_voltage"); + } + else + libWarn(915, group, "normalized_driver_waveform variable_1 must be input_net_transition"); + } + endTableModel(); +} + +void +LibertyReader::visitDriverWaveformRise(LibertyAttr *attr) +{ + visitDriverWaveformRiseFall(attr, RiseFall::rise()); +} + +void +LibertyReader::visitDriverWaveformFall(LibertyAttr *attr) +{ + visitDriverWaveformRiseFall(attr, RiseFall::fall()); +} + +void +LibertyReader::visitDriverWaveformRiseFall(LibertyAttr *attr, + const RiseFall *rf) +{ + if (ports_) { + const char *driver_waveform_name = getAttrString(attr); + DriverWaveform *driver_waveform = library_->findDriverWaveform(driver_waveform_name); + if (driver_waveform) { + for (LibertyPort *port : *ports_) + port->setDriverWaveform(driver_waveform, rf); + } + } +} + +/////////////////////////////////////////////////////////////// + void LibertyReader::makeInternalPowers(LibertyPort *port, InternalPowerGroup *power_group) @@ -5365,7 +5442,7 @@ TimingGroup::TimingGroup(int line) : intrinsic_exists_[rf_index] = false; resistance_[rf_index] = 0.0F; resistance_exists_[rf_index] = false; - output_current_[rf_index] = nullptr; + output_waveforms_[rf_index] = nullptr; for (auto el_index : EarlyLate::rangeIndex()) { delay_sigma_[rf_index][el_index] = nullptr; @@ -5496,17 +5573,17 @@ TimingGroup::setReceiverModel(ReceiverModelPtr receiver_model) receiver_model_ = receiver_model; } -OutputCurrent * -TimingGroup::outputCurrent(RiseFall *rf) +OutputWaveforms * +TimingGroup::outputWaveforms(RiseFall *rf) { - return output_current_[rf->index()]; + return output_waveforms_[rf->index()]; } void -TimingGroup::setOutputCurrent(RiseFall *rf, - OutputCurrent *output_current) +TimingGroup::setOutputWaveforms(RiseFall *rf, + OutputWaveforms *output_waveforms) { - output_current_[rf->index()] = output_current; + output_waveforms_[rf->index()] = output_waveforms; } //////////////////////////////////////////////////////////////// diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh index 23749183..03bd7326 100644 --- a/liberty/LibertyReaderPvt.hh +++ b/liberty/LibertyReaderPvt.hh @@ -57,7 +57,7 @@ typedef Vector TimingGroupSeq; typedef Vector InternalPowerGroupSeq; typedef Vector LeakagePowerGroupSeq; typedef void (LibertyPort::*LibertyPortBoolSetter)(bool value); -typedef Vector OutputCurrentWaveformSeq; +typedef Vector OutputWaveformSeq; class LibertyReader : public LibertyGroupVisitor { @@ -443,6 +443,15 @@ public: void endVector(LibertyGroup *group); void visitReferenceTime(LibertyAttr *attr); + void beginNormalizedDriverWaveform(LibertyGroup *group); + void endNormalizedDriverWaveform(LibertyGroup *group); + void visitDriverWaveformName(LibertyAttr *attr); + + void visitDriverWaveformRise(LibertyAttr *attr); + void visitDriverWaveformFall(LibertyAttr *attr); + void visitDriverWaveformRiseFall(LibertyAttr *attr, + const RiseFall *rf); + // Visitors for derived classes to overload. virtual void beginGroup1(LibertyGroup *) {} virtual void beginGroup2(LibertyGroup *) {} @@ -617,10 +626,11 @@ protected: bool have_resistance_unit_; const char *default_operating_condition_; ReceiverModelPtr receiver_model_; - OutputCurrentWaveformSeq output_current_waveforms_; - OutputCurrent *output_current_; + OutputWaveformSeq output_currents_; + OutputWaveforms *output_waveforms_; float reference_time_; bool reference_time_exists_; + const char *driver_waveform_name_; static constexpr char escape_ = '\\'; @@ -783,9 +793,9 @@ public: EarlyLate *early_late, TableModel *model); void setReceiverModel(ReceiverModelPtr receiver_model); - OutputCurrent *outputCurrent(RiseFall *rf); - void setOutputCurrent(RiseFall *rf, - OutputCurrent *output_current); + OutputWaveforms *outputWaveforms(RiseFall *rf); + void setOutputWaveforms(RiseFall *rf, + OutputWaveforms *output_current); protected: void makeLinearModels(LibertyLibrary *library); @@ -803,7 +813,7 @@ protected: TableModel *transition_[RiseFall::index_count]; TableModel *delay_sigma_[RiseFall::index_count][EarlyLate::index_count]; TableModel *slew_sigma_[RiseFall::index_count][EarlyLate::index_count]; - OutputCurrent *output_current_[RiseFall::index_count]; + OutputWaveforms *output_waveforms_[RiseFall::index_count]; ReceiverModelPtr receiver_model_; }; diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc index 1429e5ed..d703993f 100644 --- a/liberty/TableModel.cc +++ b/liberty/TableModel.cc @@ -26,6 +26,10 @@ namespace sta { using std::string; +using std::min; +using std::max; +using std::abs; +using std::make_shared; static void deleteSigmaModels(TableModel *models[EarlyLate::index_count]); @@ -43,15 +47,19 @@ GateTableModel::GateTableModel(TableModel *delay_model, TableModel *slew_model, TableModel *slew_sigma_models[EarlyLate::index_count], ReceiverModelPtr receiver_model, - OutputCurrent *output_current) : + OutputWaveforms *output_waveforms) : delay_model_(delay_model), slew_model_(slew_model), receiver_model_(receiver_model), - output_current_(output_current) + output_waveforms_(output_waveforms) { for (auto el_index : EarlyLate::rangeIndex()) { - slew_sigma_models_[el_index] = slew_sigma_models ? slew_sigma_models[el_index] : nullptr; - delay_sigma_models_[el_index] = delay_sigma_models ? delay_sigma_models[el_index] : nullptr; + slew_sigma_models_[el_index] = slew_sigma_models + ? slew_sigma_models[el_index] + : nullptr; + delay_sigma_models_[el_index] = delay_sigma_models + ? delay_sigma_models[el_index] + : nullptr; } } @@ -59,7 +67,7 @@ GateTableModel::~GateTableModel() { delete delay_model_; delete slew_model_; - delete output_current_; + delete output_waveforms_; deleteSigmaModels(slew_sigma_models_); deleteSigmaModels(delay_sigma_models_); } @@ -165,8 +173,6 @@ GateTableModel::reportGateDelay(const LibertyCell *cell, load_cap, related_out_cap); if (drvr_slew < 0.0) *result += "Negative slew clipped to 0.0\n"; - if (output_current_) - output_current_->reportWaveform(cell, pvt, in_slew, load_cap, digits, result); } void @@ -801,6 +807,13 @@ Table0::report(const Units *units, //////////////////////////////////////////////////////////////// +Table1::Table1() : + Table(), + values_(nullptr), + axis1_(nullptr) +{ +} + Table1::Table1(FloatSeq *values, TableAxisPtr axis1) : Table(), @@ -809,11 +822,30 @@ Table1::Table1(FloatSeq *values, { } +Table1::Table1(Table1 &&table) : + Table(), + values_(table.values_), + axis1_(table.axis1_) +{ + table.values_ = nullptr; + table.axis1_ = nullptr; +} + Table1::~Table1() { delete values_; } +Table1 & +Table1::operator=(Table1 &&table) +{ + values_ = table.values_; + axis1_ = table.axis1_; + table.values_ = nullptr; + table.axis1_ = nullptr; + return *this; +} + float Table1::value(size_t index1, size_t, @@ -832,6 +864,19 @@ float Table1::findValue(float value1, float, float) const +{ + return findValue(value1); +} + +float +Table1::findValue(float value1) const +{ + return findValue(value1, true); +} + +float +Table1::findValue(float value1, + bool extrapolate) const { if (axis1_->size() == 1) return value(value1); @@ -843,7 +888,12 @@ Table1::findValue(float value1, float y1 = value(index1); float y2 = value(index1 + 1); float dx1 = (x1 - x1l) / (x1u - x1l); - return (1 - dx1) * y1 + dx1 * y2; + if (x1 <= x1l && !extrapolate) + return y1; + else if (x1 >= x1u && !extrapolate) + return y2; + else + return (1 - dx1) * y1 + dx1 * y2; } } @@ -1514,26 +1564,67 @@ tableVariableUnit(TableAxisVariable variable, //////////////////////////////////////////////////////////////// -OutputCurrentWaveform::OutputCurrentWaveform(float axis_value1, - float axis_value2, - TableAxisPtr axis, - Table1 *currents, - float reference_time) : - axis_value1_(axis_value1), - axis_value2_(axis_value2), - axis_(axis), +OutputWaveform::OutputWaveform(float slew, + float cap, + Table1 *currents, + float reference_time) : + slew_(slew), + cap_(cap), currents_(currents), + voltages_(nullptr), reference_time_(reference_time) { } -OutputCurrentWaveform::~OutputCurrentWaveform() +OutputWaveform::OutputWaveform(float slew, + float cap, + Table1 *currents, + Table1 *voltages, + float reference_time) : + slew_(slew), + cap_(cap), + currents_(currents), + voltages_(voltages), + reference_time_(reference_time) +{ +} + +OutputWaveform::~OutputWaveform() { delete currents_; + delete voltages_; +} + +Table1 * +OutputWaveform::voltages() +{ + if (voltages_ == nullptr) { + FloatSeq *voltages = new FloatSeq; + voltages_ = new Table1(voltages, currents_->axis1()); + + // i = C dv/dt + // Integrate current waveform to find voltage waveform. + TableAxisPtr time_axis = currents_->axis1(); + float prev_time = time_axis->axisValue(0); + float prev_current = currents_->value(0); + float voltage = 0.0; + voltages->push_back(voltage); + bool invert = currents_->value(time_axis->size() - 1) < 0.0; + for (size_t i = 1; i < time_axis->size(); i++) { + float time = time_axis->axisValue(i); + float current = currents_->value(i); + float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap_; + voltage += invert ? -dv : dv; + voltages->push_back(voltage); + prev_time = time; + prev_current = current; + } + } + return voltages_; } bool -OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template) +OutputWaveform::checkAxes(TableTemplate *tbl_template) { TableAxisPtr axis1 = tbl_template->axis1(); TableAxisPtr axis2 = tbl_template->axis2(); @@ -1549,83 +1640,181 @@ OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template) && axis3->variable() == TableAxisVariable::time); } -void -OutputCurrentWaveform::reportWaveform(const Units *units, - int digits, - string *result) +string +OutputWaveform::reportCurrentWaveform(const Units *units, + int digits) const { + TableAxisPtr time_axis = currents_->axis1(); const Unit *time_unit = units->timeUnit(); const Unit *current_unit = units->currentUnit(); - for (size_t i = 0; i < axis_->values()->size(); i++) { - *result += time_unit->asString(axis_->axisValue(i), digits); - *result += " "; + return reportWaveform(currents_, time_unit, current_unit, digits); +} + +string +OutputWaveform::reportVoltageWaveform(const Units *units, + int digits) const +{ + TableAxisPtr time_axis = voltages_->axis1(); + const Unit *time_unit = units->timeUnit(); + const Unit *voltage_unit = units->voltageUnit(); + return reportWaveform(voltages_, time_unit, voltage_unit, digits); +} + +string +OutputWaveform::reportWaveform(const Table1 *waveform, + const Unit *time_unit, + const Unit *waveform_unit, + int digits) const +{ + string result; + TableAxisPtr time_axis = waveform->axis1(); + for (size_t i = 0; i < time_axis->values()->size(); i++) { + float time = time_axis->axisValue(i); + result += time_unit->asString(time, digits); + result += " "; } - *result += '\n'; - for (size_t i = 0; i < currents_->axis1()->size(); i++) { - *result += current_unit->asString(currents_->value(i), digits); - *result += " "; + result += '\n'; + + for (size_t i = 0; i < time_axis->size(); i++) { + float value = waveform->value(i); + result += waveform_unit->asString(value, digits); + result += " "; } - *result += '\n'; + return result; } //////////////////////////////////////////////////////////////// -OutputCurrent::OutputCurrent(TableAxisPtr axis1, - TableAxisPtr axis2, - OutputCurrentWaveformSeq &waveforms) : - axis1_(axis1), - axis2_(axis2), +OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis, + TableAxisPtr cap_axis, + OutputWaveformSeq &waveforms) : + slew_axis_(slew_axis), + cap_axis_(cap_axis), waveforms_(waveforms) { } -OutputCurrent::~OutputCurrent() +OutputWaveforms::~OutputWaveforms() { waveforms_.deleteContents(); } -void -OutputCurrent::reportWaveform(const LibertyCell *cell, - const Pvt *, - float in_slew, - float load_cap, - int digits, - string *result) const +OutputWaveform +OutputWaveforms::voltageWaveform(float slew, + float cap) { - float axis_value1, axis_value2; - findAxisValues(in_slew, load_cap, - axis_value1, axis_value2); - size_t index1 = axis1_->findAxisIndex(axis_value1); - size_t index2 = axis2_->findAxisIndex(axis_value2); - size_t index = index1 * axis2_->size() + index2; - waveforms_[index]->reportWaveform(cell->libertyLibrary()->units(), digits, result); -} + size_t slew_index = slew_axis_->findAxisIndex(slew); + size_t cap_index = cap_axis_->findAxisIndex(cap); + size_t wave_index00 = slew_index * cap_axis_->size() + cap_index; + size_t wave_index01 = slew_index * cap_axis_->size() + (cap_index + 1); + size_t wave_index10 = (slew_index + 1) * cap_axis_->size() + cap_index; + size_t wave_index11 = (slew_index + 1) * cap_axis_->size() + (cap_index + 1); + OutputWaveform *waveform00 = waveforms_[wave_index00]; + OutputWaveform *waveform01 = waveforms_[wave_index01]; + OutputWaveform *waveform10 = waveforms_[wave_index10]; + OutputWaveform *waveform11 = waveforms_[wave_index11]; + const Table1 *voltages00 = waveform00->voltages(); + const Table1 *voltages01 = waveform01->voltages(); + const Table1 *voltages10 = waveform10->voltages(); + const Table1 *voltages11 = waveform11->voltages(); + TableAxisPtr time_axis00 = voltages00->axis1(); + TableAxisPtr time_axis01 = voltages01->axis1(); + TableAxisPtr time_axis10 = voltages10->axis1(); + TableAxisPtr time_axis11 = voltages11->axis1(); -void -OutputCurrent::findAxisValues(float in_slew, - float load_cap, - // Return values. - float &axis_value1, - float &axis_value2) const -{ - axis_value1 = axisValue(axis1_, in_slew, load_cap); - axis_value2 = axisValue(axis2_, in_slew, load_cap); -} + // Find time axis min/max. + size_t time_step_count = 20; + float time_min = time_axis00->min(); + time_min = min(time_min, time_axis01->min()); + time_min = min(time_min, time_axis10->min()); + time_min = min(time_min, time_axis11->min()); + float time_max = time_axis00->max(); + time_max = max(time_max, time_axis01->max()); + time_max = max(time_max, time_axis10->max()); + time_max = max(time_max, time_axis11->max()); + float time_step = (time_max - time_min) / time_step_count; + FloatSeq *time_values = new FloatSeq; + TableAxisPtr time_axis = make_shared(time_axis00->variable(), + time_values); -float -OutputCurrent::axisValue(TableAxisPtr axis, - float in_slew, - float load_cap) const -{ - TableAxisVariable var = axis->variable(); - if (var == TableAxisVariable::input_net_transition) - return in_slew; - else if (var == TableAxisVariable::total_output_net_capacitance) - return load_cap; - else { - criticalError(240, "unsupported table axes"); - return 0.0; + // Interpolate waveform samples at time steps. + float volt_max = voltages00->value(voltages00->values()->size() - 1); + size_t index1 = slew_index; + size_t index2 = cap_index; + float x1 = slew; + float x2 = cap; + float x1l = slew_axis_->axisValue(index1); + float x1u = slew_axis_->axisValue(index1 + 1); + float dx1 = (x1 - x1l) / (x1u - x1l); + float x2l = cap_axis_->axisValue(index2); + float x2u = cap_axis_->axisValue(index2 + 1); + float dx2 = (x2 - x2l) / (x2u - x2l); + FloatSeq *voltages = new FloatSeq; + bool waveform_started = false; + float prev_volt = 0.0; + constexpr float volt_tol = .01; + float volt_end = volt_max * (1.0 - volt_tol); + for (size_t i = 0; i <= time_step_count; i++) { + float time = time_min + time_step * i; + float y00 = voltages00->findValue(time, true); + float y10 = voltages10->findValue(time, true); + float y11 = voltages11->findValue(time, true); + float y01 = voltages01->findValue(time, true); + float voltage + = (1 - dx1) * (1 - dx2) * y00 + + dx1 * (1 - dx2) * y10 + + dx1 * dx2 * y11 + + (1 - dx1) * dx2 * y01; + if (voltage > volt_tol) + waveform_started = true; + if (waveform_started) { + time_values->push_back(time); + voltages->push_back(voltage); + } + if (prev_volt > volt_end) + break; + prev_volt = voltage; } + + // Interpolate reference time. + // (only depends on slew) + float ref_time + = (1 - dx1) * waveform00->referenceTime() + + dx1 * waveform10->referenceTime(); + + Table1 *waveform = new Table1(voltages, time_axis); + return OutputWaveform(slew, cap, nullptr, waveform, ref_time); +} + +//////////////////////////////////////////////////////////////// + +DriverWaveform::DriverWaveform(const char *name, + TablePtr waveforms) : + name_(name), + waveforms_(waveforms) +{ +} + +DriverWaveform::~DriverWaveform() +{ + stringDelete(name_); +} + +Table1 +DriverWaveform::waveform(float slew) +{ + TableAxisPtr volt_axis = waveforms_->axis2(); + FloatSeq *time_values = new FloatSeq; + FloatSeq *volt_values = new FloatSeq; + for (float volt : *volt_axis->values()) { + float time = waveforms_->findValue(slew, volt, 0.0); + time_values->push_back(time); + volt_values->push_back(volt); + } + TableAxisPtr time_axis = make_shared(TableAxisVariable::time, + time_values); + Table1 waveform(volt_values, time_axis); + return waveform; } } // namespace diff --git a/messages.txt b/messages.txt index 099ef8ab..328128f1 100644 --- a/messages.txt +++ b/messages.txt @@ -1,173 +1,173 @@ 0001 DmpCeff.cc:1597 cell %s delay model not supported on SPF parasitics by DMP delay calculator -0002 Liberty.cc:749 cell %s/%s port %s not found in cell %s/%s. -0003 Liberty.cc:775 cell %s/%s %s -> %s timing group %s not found in cell %s/%s. -0004 Liberty.cc:1710 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check. -0005 Liberty.cc:1724 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense. -0006 Liberty.cc:1732 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense. +0002 Liberty.cc:750 cell %s/%s port %s not found in cell %s/%s. +0003 Liberty.cc:776 cell %s/%s %s -> %s timing group %s not found in cell %s/%s. +0004 Liberty.cc:1728 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with %s -> %s setup_%s check. +0005 Liberty.cc:1742 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function positive sense. +0006 Liberty.cc:1750 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative sense. 0007 LibertyExpr.cc:82 %s references unknown port %s. -0008 ConcreteNetwork.cc:1924 cell type %s can not be linked. +0008 ConcreteNetwork.cc:1917 cell type %s can not be linked. 0009 CycleAccting.cc:87 No common period was found between clocks %s and %s. 0010 Genclks.cc:274 no master clock found for generated clock %s. 0013 Genclks.cc:938 generated clock %s source pin %s missing paths from master clock %s. 0015 Sim.cc:865 propagated logic value %c differs from constraint value of %c on pin %s. -0016 LibertyReader.cc:1045 default_max_fanout is 0.0. +0016 LibertyReader.cc:1049 default_max_fanout is 0.0. 0017 Sta.cc:2093 '%s' is not a valid endpoint. 0018 Sta.cc:2017 '%s' is not a valid start point. 0021 SpefParse.yy:805 %d is not positive. 0022 SpefParse.yy:814 %.4f is not positive. 0023 SpefParse.yy:820 %.4f is not positive. -0024 WritePathSpice.cc:425 pg_pin %s/%s voltage %s not found, -0025 WritePathSpice.cc:432 Liberty pg_port %s/%s missing voltage_name attribute, -0026 WritePathSpice.cc:960 %s pg_port %s not found, -0027 WritePathSpice.cc:1015 no register/latch found for path from %s to %s, -0028 WritePathSpice.cc:1382 The following subkcts are missing from %s -0029 WritePathSpice.cc:1440 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. -0030 LibertyReader.cc:624 library missing name. -0031 LibertyReader.cc:656 default_wire_load %s not found. -0032 LibertyReader.cc:667 default_wire_selection %s not found. -0033 LibertyReader.cc:689 input_threshold_pct_%s not found. -0034 LibertyReader.cc:693 output_threshold_pct_%s not found. -0035 LibertyReader.cc:697 slew_lower_threshold_pct_%s not found. -0036 LibertyReader.cc:701 slew_upper_threshold_pct_%s not found. -0037 LibertyReader.cc:706 Library %s is missing one or more thresholds. -0038 LibertyReader.cc:796 unknown unit multiplier %s. -0039 LibertyReader.cc:815 unknown unit scale %c. -0040 LibertyReader.cc:818 unknown unit suffix %s. -0041 LibertyReader.cc:844 capacitive_load_units are not ff or pf. -0042 LibertyReader.cc:847 capacitive_load_units are not a string. -0043 LibertyReader.cc:850 capacitive_load_units missing suffix. -0044 LibertyReader.cc:853 capacitive_load_units scale is not a float. -0045 LibertyReader.cc:856 capacitive_load_units missing scale and suffix. -0046 LibertyReader.cc:859 capacitive_load_unit missing values suffix. -0047 LibertyReader.cc:877 delay_model %s not supported. -0048 LibertyReader.cc:881 delay_model %s not supported. -0049 LibertyReader.cc:885 delay_model %s not supported. -0050 LibertyReader.cc:890 delay_model %s not supported. +0024 WritePathSpice.cc:458 pg_pin %s/%s voltage %s not found, +0025 WritePathSpice.cc:465 Liberty pg_port %s/%s missing voltage_name attribute, +0026 WritePathSpice.cc:1037 %s pg_port %s not found, +0027 WritePathSpice.cc:1092 no register/latch found for path from %s to %s, +0028 WritePathSpice.cc:1464 The subkct file %s is missing definitions for %s +0029 WritePathSpice.cc:1562 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. +0030 LibertyReader.cc:628 library missing name. +0031 LibertyReader.cc:660 default_wire_load %s not found. +0032 LibertyReader.cc:671 default_wire_selection %s not found. +0033 LibertyReader.cc:693 input_threshold_pct_%s not found. +0034 LibertyReader.cc:697 output_threshold_pct_%s not found. +0035 LibertyReader.cc:701 slew_lower_threshold_pct_%s not found. +0036 LibertyReader.cc:705 slew_upper_threshold_pct_%s not found. +0037 LibertyReader.cc:710 Library %s is missing one or more thresholds. +0038 LibertyReader.cc:800 unknown unit multiplier %s. +0039 LibertyReader.cc:819 unknown unit scale %c. +0040 LibertyReader.cc:822 unknown unit suffix %s. +0041 LibertyReader.cc:848 capacitive_load_units are not ff or pf. +0042 LibertyReader.cc:851 capacitive_load_units are not a string. +0043 LibertyReader.cc:854 capacitive_load_units missing suffix. +0044 LibertyReader.cc:857 capacitive_load_units scale is not a float. +0045 LibertyReader.cc:860 capacitive_load_units missing scale and suffix. +0046 LibertyReader.cc:863 capacitive_load_unit missing values suffix. +0047 LibertyReader.cc:881 delay_model %s not supported. +0048 LibertyReader.cc:885 delay_model %s not supported. +0049 LibertyReader.cc:889 delay_model %s not supported. +0050 LibertyReader.cc:894 delay_model %s not supported. . -0051 LibertyReader.cc:893 unknown delay_model %s +0051 LibertyReader.cc:897 unknown delay_model %s . -0052 LibertyReader.cc:912 unknown bus_naming_style format. -0053 LibertyReader.cc:590 library %s already exists. -0054 LibertyReader.cc:933 voltage_map voltage is not a float. -0055 LibertyReader.cc:936 voltage_map missing voltage. -0056 LibertyReader.cc:939 voltage_map supply name is not a string. -0057 LibertyReader.cc:942 voltage_map missing supply name and voltage. -0058 LibertyReader.cc:945 voltage_map missing values suffix. -0059 LibertyReader.cc:1163 default_wire_load_mode %s not found. -0060 LibertyReader.cc:679 default_operating_condition %s not found. -0061 LibertyReader.cc:1334 table template missing name. -0062 LibertyReader.cc:1379 missing variable_%d attribute. -0063 LibertyReader.cc:1422 axis type %s not supported. -0064 LibertyReader.cc:1482 bus type %s missing bit_from. -0065 LibertyReader.cc:1484 bus type %s missing bit_to. -0066 LibertyReader.cc:1488 type missing name. -0067 LibertyReader.cc:1515 scaling_factors do not have a name. -0068 LibertyReader.cc:1683 operating_conditions missing name. -0069 LibertyReader.cc:1753 wire_load missing name. -0070 LibertyReader.cc:1796 fanout_length is missing length and fanout. -0071 LibertyReader.cc:1811 wire_load_selection missing name. -0072 LibertyReader.cc:1842 wireload %s not found. -0074 LibertyReader.cc:1849 wire_load_from_area min not a float. -0075 LibertyReader.cc:1852 wire_load_from_area max not a float. -0076 LibertyReader.cc:1855 wire_load_from_area missing parameters. -0077 LibertyReader.cc:1858 wire_load_from_area missing parameters. -0078 LibertyReader.cc:1875 cell missing name. -0079 LibertyReader.cc:1898 cell %s ocv_derate_group %s not found. -0080 LibertyReader.cc:1934 port %s function size does not match port size. -0081 LibertyReader.cc:2002 %s %s bus width mismatch. -0082 LibertyReader.cc:2013 %s %s bus width mismatch. -0083 LibertyReader.cc:2023 clear -0084 LibertyReader.cc:2033 preset -0085 LibertyReader.cc:2069 latch enable function is non-unate for port %s. -0086 LibertyReader.cc:2074 latch enable function is unknown for port %s. -0087 LibertyReader.cc:2150 operating conditions %s not found. -0088 LibertyReader.cc:2153 scaled_cell missing operating condition. -0089 LibertyReader.cc:2156 scaled_cell cell %s has not been defined. -0090 LibertyReader.cc:2159 scaled_cell missing name. -0091 LibertyReader.cc:2185 scaled_cell %s, %s port functions do not match cell port functions. -0092 LibertyReader.cc:2190 scaled_cell ports do not match cell ports. -0093 LibertyReader.cc:2192 scaled_cell %s, %s timing does not match cell timing. -0094 LibertyReader.cc:2211 combinational timing to an input port. -0095 LibertyReader.cc:2302 missing %s_transition. -0096 LibertyReader.cc:2304 missing cell_%s. -0099 LibertyReader.cc:2821 scaling_factors %s not found. -0100 LibertyReader.cc:2864 pin name is not a string. -0101 LibertyReader.cc:2883 pin name is not a string. -0102 LibertyReader.cc:2899 pin name is not a string. -0103 LibertyReader.cc:2977 bus %s bus_type not found. -0104 LibertyReader.cc:3033 bus_type %s not found. -0105 LibertyReader.cc:3036 bus_type is not a string. -0106 LibertyReader.cc:3054 bundle %s member not found. -0107 LibertyReader.cc:3081 member is not a string. -0108 LibertyReader.cc:3088 members attribute is missing values. -0109 LibertyReader.cc:3139 unknown port direction. -0110 LibertyReader.cc:3507 pulse_latch unknown pulse type. -0111 LibertyReader.cc:3885 unknown timing_type %s. -0112 LibertyReader.cc:3905 unknown timing_sense %s. -0113 LibertyReader.cc:3945 mode value is not a string. -0114 LibertyReader.cc:3948 missing mode value. -0115 LibertyReader.cc:3951 mode name is not a string. -0116 LibertyReader.cc:3954 mode missing values. -0117 LibertyReader.cc:3957 mode missing mode name and value. -0118 LibertyReader.cc:2541 unsupported model axis. -0119 LibertyReader.cc:4060 unsupported model axis. -0120 LibertyReader.cc:4089 unsupported model axis. -0121 LibertyReader.cc:4124 unsupported model axis. -0122 LibertyReader.cc:4179 table template %s not found. -0123 LibertyReader.cc:4258 %s is missing values. -0124 LibertyReader.cc:4283 %s is not a list of floats. -0125 LibertyReader.cc:4285 table row has %u columns but axis has %d. -0126 LibertyReader.cc:4295 table has %u rows but axis has %d. -0127 LibertyReader.cc:4348 lut output is not a string. -0128 LibertyReader.cc:4390 mode definition missing name. -0129 LibertyReader.cc:4407 mode value missing name. -0130 LibertyReader.cc:4421 when attribute inside table model. -0131 LibertyReader.cc:4470 %s attribute is not a string. -0132 LibertyReader.cc:4473 %s is not a simple attribute. -0133 LibertyReader.cc:4496 %s is not a simple attribute. -0134 LibertyReader.cc:4509 %s is not a simple attribute. -0135 LibertyReader.cc:4533 %s value %s is not a float. -0136 LibertyReader.cc:4562 %s missing values. -0137 LibertyReader.cc:4566 %s missing values. -0138 LibertyReader.cc:4569 %s is not a complex attribute. -0139 LibertyReader.cc:4595 %s is not a float. -0140 LibertyReader.cc:4618 %s is missing values. -0141 LibertyReader.cc:4621 %s has more than one string. -0142 LibertyReader.cc:4630 %s is missing values. -0143 LibertyReader.cc:4655 %s attribute is not boolean. -0144 LibertyReader.cc:4658 %s attribute is not boolean. -0145 LibertyReader.cc:4661 %s is not a simple attribute. -0146 LibertyReader.cc:4677 attribute %s value %s not recognized. -0147 LibertyReader.cc:4707 unknown early/late value. -0148 LibertyReader.cc:4933 OCV derate group named %s not found. -0149 LibertyReader.cc:4949 ocv_derate missing name. -0150 LibertyReader.cc:5002 unknown rise/fall. -0151 LibertyReader.cc:5022 unknown derate type. -0152 LibertyReader.cc:5054 unsupported model axis. -0153 LibertyReader.cc:5086 unsupported model axis. -0154 LibertyReader.cc:5118 unsupported model axis. -0155 LibertyReader.cc:5189 unknown pg_type. -0156 LibertyReader.cc:5584 port %s subscript out of range. -0157 LibertyReader.cc:5588 port range %s of non-bus port %s. -0158 LibertyReader.cc:5602 port %s not found. -0159 LibertyReader.cc:5672 port %s not found. -0160 LibertyReader.cc:1030 default_max_transition is 0.0. -0161 LibertyReader.cc:3395 max_transition is 0.0. -0162 LibertyReader.cc:4493 %s attribute is not an integer. -0163 LibertyReader.cc:1135 default_fanout_load is 0.0. -0164 LibertyReader.cc:2324 timing group from output port. -0165 LibertyReader.cc:2334 timing group from output port. -0166 LibertyReader.cc:2344 timing group from output port. -0167 LibertyReader.cc:2362 timing group from output port. -0168 LibertyReader.cc:2377 timing group from output port. -0169 LibertyReader.cc:4365 cell %s test_cell redefinition. -0170 LibertyReader.cc:3804 timing group missing related_pin/related_bus_pin. -0179 SpefReader.cc:733 %s. +0052 LibertyReader.cc:916 unknown bus_naming_style format. +0053 LibertyReader.cc:594 library %s already exists. +0054 LibertyReader.cc:937 voltage_map voltage is not a float. +0055 LibertyReader.cc:940 voltage_map missing voltage. +0056 LibertyReader.cc:943 voltage_map supply name is not a string. +0057 LibertyReader.cc:946 voltage_map missing supply name and voltage. +0058 LibertyReader.cc:949 voltage_map missing values suffix. +0059 LibertyReader.cc:1167 default_wire_load_mode %s not found. +0060 LibertyReader.cc:683 default_operating_condition %s not found. +0061 LibertyReader.cc:1338 table template missing name. +0062 LibertyReader.cc:1383 missing variable_%d attribute. +0063 LibertyReader.cc:1426 axis type %s not supported. +0064 LibertyReader.cc:1486 bus type %s missing bit_from. +0065 LibertyReader.cc:1488 bus type %s missing bit_to. +0066 LibertyReader.cc:1492 type missing name. +0067 LibertyReader.cc:1519 scaling_factors do not have a name. +0068 LibertyReader.cc:1687 operating_conditions missing name. +0069 LibertyReader.cc:1757 wire_load missing name. +0070 LibertyReader.cc:1800 fanout_length is missing length and fanout. +0071 LibertyReader.cc:1815 wire_load_selection missing name. +0072 LibertyReader.cc:1846 wireload %s not found. +0074 LibertyReader.cc:1853 wire_load_from_area min not a float. +0075 LibertyReader.cc:1856 wire_load_from_area max not a float. +0076 LibertyReader.cc:1859 wire_load_from_area missing parameters. +0077 LibertyReader.cc:1862 wire_load_from_area missing parameters. +0078 LibertyReader.cc:1879 cell missing name. +0079 LibertyReader.cc:1902 cell %s ocv_derate_group %s not found. +0080 LibertyReader.cc:1938 port %s function size does not match port size. +0081 LibertyReader.cc:2006 %s %s bus width mismatch. +0082 LibertyReader.cc:2017 %s %s bus width mismatch. +0083 LibertyReader.cc:2027 clear +0084 LibertyReader.cc:2037 preset +0085 LibertyReader.cc:2073 latch enable function is non-unate for port %s. +0086 LibertyReader.cc:2078 latch enable function is unknown for port %s. +0087 LibertyReader.cc:2154 operating conditions %s not found. +0088 LibertyReader.cc:2157 scaled_cell missing operating condition. +0089 LibertyReader.cc:2160 scaled_cell cell %s has not been defined. +0090 LibertyReader.cc:2163 scaled_cell missing name. +0091 LibertyReader.cc:2189 scaled_cell %s, %s port functions do not match cell port functions. +0092 LibertyReader.cc:2194 scaled_cell ports do not match cell ports. +0093 LibertyReader.cc:2196 scaled_cell %s, %s timing does not match cell timing. +0094 LibertyReader.cc:2215 combinational timing to an input port. +0095 LibertyReader.cc:2306 missing %s_transition. +0096 LibertyReader.cc:2308 missing cell_%s. +0099 LibertyReader.cc:2900 scaling_factors %s not found. +0100 LibertyReader.cc:2943 pin name is not a string. +0101 LibertyReader.cc:2962 pin name is not a string. +0102 LibertyReader.cc:2978 pin name is not a string. +0103 LibertyReader.cc:3056 bus %s bus_type not found. +0104 LibertyReader.cc:3112 bus_type %s not found. +0105 LibertyReader.cc:3115 bus_type is not a string. +0106 LibertyReader.cc:3133 bundle %s member not found. +0107 LibertyReader.cc:3160 member is not a string. +0108 LibertyReader.cc:3167 members attribute is missing values. +0109 LibertyReader.cc:3218 unknown port direction. +0110 LibertyReader.cc:3586 pulse_latch unknown pulse type. +0111 LibertyReader.cc:3964 unknown timing_type %s. +0112 LibertyReader.cc:3984 unknown timing_sense %s. +0113 LibertyReader.cc:4024 mode value is not a string. +0114 LibertyReader.cc:4027 missing mode value. +0115 LibertyReader.cc:4030 mode name is not a string. +0116 LibertyReader.cc:4033 mode missing values. +0117 LibertyReader.cc:4036 mode missing mode name and value. +0118 LibertyReader.cc:2547 unsupported model axis. +0119 LibertyReader.cc:4139 unsupported model axis. +0120 LibertyReader.cc:4168 unsupported model axis. +0121 LibertyReader.cc:4203 unsupported model axis. +0122 LibertyReader.cc:4258 table template %s not found. +0123 LibertyReader.cc:4337 %s is missing values. +0124 LibertyReader.cc:4362 %s is not a list of floats. +0125 LibertyReader.cc:4364 table row has %u columns but axis has %d. +0126 LibertyReader.cc:4374 table has %u rows but axis has %d. +0127 LibertyReader.cc:4427 lut output is not a string. +0128 LibertyReader.cc:4469 mode definition missing name. +0129 LibertyReader.cc:4486 mode value missing name. +0130 LibertyReader.cc:4500 when attribute inside table model. +0131 LibertyReader.cc:4549 %s attribute is not a string. +0132 LibertyReader.cc:4552 %s is not a simple attribute. +0133 LibertyReader.cc:4575 %s is not a simple attribute. +0134 LibertyReader.cc:4588 %s is not a simple attribute. +0135 LibertyReader.cc:4612 %s value %s is not a float. +0136 LibertyReader.cc:4641 %s missing values. +0137 LibertyReader.cc:4645 %s missing values. +0138 LibertyReader.cc:4648 %s is not a complex attribute. +0139 LibertyReader.cc:4674 %s is not a float. +0140 LibertyReader.cc:4697 %s is missing values. +0141 LibertyReader.cc:4700 %s has more than one string. +0142 LibertyReader.cc:4709 %s is missing values. +0143 LibertyReader.cc:4734 %s attribute is not boolean. +0144 LibertyReader.cc:4737 %s attribute is not boolean. +0145 LibertyReader.cc:4740 %s is not a simple attribute. +0146 LibertyReader.cc:4756 attribute %s value %s not recognized. +0147 LibertyReader.cc:4786 unknown early/late value. +0148 LibertyReader.cc:5012 OCV derate group named %s not found. +0149 LibertyReader.cc:5028 ocv_derate missing name. +0150 LibertyReader.cc:5081 unknown rise/fall. +0151 LibertyReader.cc:5101 unknown derate type. +0152 LibertyReader.cc:5133 unsupported model axis. +0153 LibertyReader.cc:5165 unsupported model axis. +0154 LibertyReader.cc:5197 unsupported model axis. +0155 LibertyReader.cc:5268 unknown pg_type. +0156 LibertyReader.cc:5663 port %s subscript out of range. +0157 LibertyReader.cc:5667 port range %s of non-bus port %s. +0158 LibertyReader.cc:5681 port %s not found. +0159 LibertyReader.cc:5751 port %s not found. +0160 LibertyReader.cc:1034 default_max_transition is 0.0. +0161 LibertyReader.cc:3474 max_transition is 0.0. +0162 LibertyReader.cc:4572 %s attribute is not an integer. +0163 LibertyReader.cc:1139 default_fanout_load is 0.0. +0164 LibertyReader.cc:2328 timing group from output port. +0165 LibertyReader.cc:2338 timing group from output port. +0166 LibertyReader.cc:2348 timing group from output port. +0167 LibertyReader.cc:2366 timing group from output port. +0168 LibertyReader.cc:2381 timing group from output port. +0169 LibertyReader.cc:4444 cell %s test_cell redefinition. +0170 LibertyReader.cc:3883 timing group missing related_pin/related_bus_pin. +0179 SpefReader.cc:734 %s. 0190 VerilogReader.cc:1756 %s is not a verilog module. 0191 VerilogReader.cc:1761 %s is not a verilog module. -0201 StaTcl.i:117 no network has been linked. -0202 StaTcl.i:131 network does not support edits. -0204 StaTcl.i:4021 POCV support requires compilation with SSTA=1. +0201 StaTcl.i:118 no network has been linked. +0202 StaTcl.i:132 network does not support edits. +0204 StaTcl.i:4072 POCV support requires compilation with SSTA=1. 0206 LibertyExpr.cc:175 %s %s. 0207 GraphDelayCalc1.cc:738 port not found in cell 0208 Graph.cc:793 arc_delay_annotated array bounds exceeded @@ -184,20 +184,20 @@ 0252 PathEnumed.cc:135 enumerated path required time 0253 PathGroup.cc:399 unknown path end type 0254 PathVertexRep.cc:145 tag group missing tag -0255 ReportPath.cc:289 unsupported path type -0256 ReportPath.cc:310 unsupported path type -0257 ReportPath.cc:349 unsupported path type -0259 ReportPath.cc:2378 unsupported path type +0255 ReportPath.cc:287 unsupported path type +0256 ReportPath.cc:308 unsupported path type +0257 ReportPath.cc:347 unsupported path type +0259 ReportPath.cc:2376 unsupported path type 0260 Search.cc:2628 max tag group index exceeded 0261 Search.cc:2860 max tag index exceeded 0262 Search.cc:3551 unexpected filter path 0263 Search.cc:3719 tns incr existing vertex -0264 Sta.cc:4174 corresponding timing arc set not found in equiv cells +0264 Sta.cc:4180 corresponding timing arc set not found in equiv cells 0265 TagGroup.cc:297 tag group missing tag 0266 Sta.cc:2090 '%s' is not a valid endpoint. 0267 Sta.cc:2014 '%s' is not a valid start point. -0272 StaTcl.i:4007 unknown common clk pessimism mode. -0273 StaTcl.i:4963 unknown clock sense +0272 StaTcl.i:4058 unknown common clk pessimism mode. +0273 StaTcl.i:5003 unknown clock sense 0299 Power.tcl:241 activity cannot be set on clock ports. 0300 CmdUtil.tcl:44 no commands match '$pattern'. 0301 Power.tcl:218 activity should be 0.0 to 1.0 or 2.0 @@ -461,8 +461,8 @@ 0604 Sdc.tcl:281 unknown $unit prefix '$prefix'. 0605 Sdc.tcl:3547 wire load model '$model_name' not found. 0606 Property.tcl:77 get_property unsupported object type $object_type. -0607 StaTcl.i:4257 unknown report path field %s -0608 StaTcl.i:4269 unknown report path field %s +0607 StaTcl.i:4308 unknown report path field %s +0608 StaTcl.i:4320 unknown report path field %s 0609 Search.tcl:421 -all_violators is deprecated. Use -violators 0610 Search.tcl:501 -max_transition deprecated. Use -max_slew. 0611 Search.tcl:506 -min_transition deprecated. Use -min_slew. @@ -480,7 +480,7 @@ 0702 LibertyWriter.cc:436 3 axis table models not supported. 0703 LibertyWriter.cc:576 %s/%s/%s timing arc type %s not supported. 0704 LibertyWriter.cc:289 %s/%s bundled ports not supported. -0705 Liberty.cc:794 Liberty cell %s/%s for corner %s/%s not found. +0705 Liberty.cc:795 Liberty cell %s/%s for corner %s/%s not found. 0706 Parasitics.tcl:70 read_spef -increment is deprecated. 0710 LumpedCapDelayCalc.cc:169 gate delay input variable is NaN 0800 VcdReader.cc:109 unhandled vcd command. @@ -491,13 +491,15 @@ 0806 ReadVcdActivities.cc:247 clock %s vcd period %s differs from SDC clock period %s 0807 Sdc.tcl:394 only one of -cells, -data_pins, -clock_pins, -async_pins, -output_pins are suppported. 0810 MakeTimingModel.cc:189 clock %s pin %s is inside model block. -0900 LibertyReader.cc:2761 level_shifter_type must be HL, LH, or HL_LH -0901 LibertyReader.cc:2797 switch_cell_type must be coarse_grain or fine_grain -0902 LibertyReader.cc:2460 unsupported model axis. -0903 LibertyReader.cc:4140 %s group not in timing group. -0904 LibertyReader.cc:2443 receiver_capacitance group not in timing or pin group. -0906 LibertyReader.cc:4033 unsupported model axis. -0907 LibertyReader.cc:2486 output_current_%s group not in timing group. -0908 LibertyReader.cc:2575 vector reference_time not found. -0912 LibertyReader.cc:2573 vector index_1 and index_2 must have one value. -0913 LibertyReader.cc:2525 output current waveform %.2e %.2e not found. +0900 LibertyReader.cc:2840 level_shifter_type must be HL, LH, or HL_LH +0901 LibertyReader.cc:2876 switch_cell_type must be coarse_grain or fine_grain +0902 LibertyReader.cc:2464 unsupported model axis. +0903 LibertyReader.cc:4219 %s group not in timing group. +0904 LibertyReader.cc:2447 receiver_capacitance group not in timing or pin group. +0906 LibertyReader.cc:4112 unsupported model axis. +0907 LibertyReader.cc:2492 output_current_%s group not in timing group. +0908 LibertyReader.cc:2591 vector reference_time not found. +0912 LibertyReader.cc:2589 vector index_1 and index_2 must have exactly one value. +0913 LibertyReader.cc:2531 output current waveform %.2e %.2e not found. +0914 LibertyReader.cc:2624 normalized_driver_waveform variable_2 must be normalized_voltage +0915 LibertyReader.cc:2627 normalized_driver_waveform variable_1 must be input_net_transition diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc index 4fe8e625..97caf9ac 100644 --- a/search/WritePathSpice.cc +++ b/search/WritePathSpice.cc @@ -81,7 +81,7 @@ private: void writeHeader(); void writeStageInstances(); void writeInputSource(); - void writeStepVoltSource(const Pin *pin, + void writeRampVoltSource(const Pin *pin, const RiseFall *rf, float slew, float time, @@ -137,6 +137,11 @@ private: void writeWaveformEdge(const RiseFall *rf, float time, float slew); + void writeWaveformVoltSource(const Pin *pin, + DriverWaveform *drvr_waveform, + const RiseFall *rf, + float slew, + int &volt_index); void writeClkedStepSource(const Pin *pin, const RiseFall *rf, const Clock *clk, @@ -164,6 +169,7 @@ private: int &volt_index); float slewAxisMinValue(TimingArc *arc); float pgPortVoltage(LibertyPgPort *pg_port); + void writePrintStmt(); // Stage "accessors". // @@ -323,6 +329,7 @@ WritePathSpice::writeSpice() // Find subckt port names as a side-effect of writeSubckts. writeSubckts(); writeHeader(); + writePrintStmt(); writeStageInstances(); writeMeasureStmts(); writeInputSource(); @@ -369,6 +376,18 @@ WritePathSpice::writeHeader() float time_step = max_time / 1e+3; streamPrint(spice_stream_, ".tran %.3g %.3g\n\n", time_step, max_time); + streamPrint(spice_stream_, ".options nomod\n"); +} + +void +WritePathSpice::writePrintStmt() +{ + streamPrint(spice_stream_, ".print tran"); + for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { + streamPrint(spice_stream_, " v(%s)", stageDrvrPinName(stage)); + streamPrint(spice_stream_, " v(%s)", stageLoadPinName(stage)); + } + streamPrint(spice_stream_, "\n\n"); } float @@ -477,11 +496,55 @@ WritePathSpice::writeInputWaveform() float time0 = slew0; int volt_index = 1; const Pin *drvr_pin = stageDrvrPin(input_stage); - writeStepVoltSource(drvr_pin, rf, slew0, time0, volt_index); + const Pin *load_pin = stageLoadPin(input_stage); + const LibertyPort *load_port = network_->libertyPort(load_pin); + DriverWaveform *drvr_waveform = nullptr; + if (load_port) + drvr_waveform = load_port->driverWaveform(rf); + if (drvr_waveform) + writeWaveformVoltSource(drvr_pin, drvr_waveform, + rf, slew0, volt_index); + else + writeRampVoltSource(drvr_pin, rf, slew0, time0, volt_index); } void -WritePathSpice::writeStepVoltSource(const Pin *pin, +WritePathSpice::writeWaveformVoltSource(const Pin *pin, + DriverWaveform *drvr_waveform, + const RiseFall *rf, + float slew, + int &volt_index) +{ + float volt0, volt1, volt_factor; + if (rf == RiseFall::rise()) { + volt0 = gnd_voltage_; + volt1 = power_voltage_; + volt_factor = power_voltage_; + } + else { + volt0 = power_voltage_; + volt1 = gnd_voltage_; + volt_factor = -power_voltage_; + } + streamPrint(spice_stream_, "v%d %s 0 pwl(\n", + volt_index, + network_->pathName(pin)); + streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0); + Table1 waveform = drvr_waveform->waveform(slew); + TableAxisPtr time_axis = waveform.axis1(); + for (size_t time_index = 0; time_index < time_axis->size(); time_index++) { + float time = time_axis->axisValue(time_index); + float wave_volt = waveform.value(time_index); + float volt = volt0 + wave_volt * volt_factor; + streamPrint(spice_stream_, "+%.3e %.3e\n", time, volt); + } + streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1); + streamPrint(spice_stream_, "+)\n"); + volt_index++; +} + +void +WritePathSpice::writeRampVoltSource(const Pin *pin, const RiseFall *rf, float slew, float time, @@ -942,7 +1005,7 @@ WritePathSpice::writeClkedStepSource(const Pin *pin, Vertex *vertex = graph_->pinLoadVertex(pin); float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index); float time = clkWaveformTImeOffset(clk) + clk->period() / 2.0; - writeStepVoltSource(pin, rf, slew, time, volt_index); + writeRampVoltSource(pin, rf, slew, time, volt_index); } void diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i index 43c5d8c9..c74b3426 100644 --- a/tcl/StaTcl.i +++ b/tcl/StaTcl.i @@ -49,6 +49,7 @@ #include "Transition.hh" #include "TimingRole.hh" #include "TimingArc.hh" +#include "TableModel.hh" #include "Liberty.hh" #include "LibertyWriter.hh" #include "EquivCells.hh" @@ -567,13 +568,13 @@ using namespace sta; %typemap(in) RiseFall* { int length; const char *arg = Tcl_GetStringFromObj($input, &length); - RiseFall *tr = RiseFall::find(arg); - if (tr == nullptr) { - Tcl_SetResult(interp,const_cast("Error: unknown transition name."), + RiseFall *rf = RiseFall::find(arg); + if (rf == nullptr) { + Tcl_SetResult(interp,const_cast("Error: unknown rise/fall edge."), TCL_STATIC); return TCL_ERROR; } - $1 = tr; + $1 = rf; } %typemap(out) RiseFall* { @@ -875,6 +876,44 @@ using namespace sta; $1 = ints; } +%typemap(out) Table1 { + Table1 &table = $1; + Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); + Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); + for (float f : *table.axis1()->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list1, obj); + } + Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); + for (float f : *table.values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list2, obj); + } + Tcl_ListObjAppendElement(interp, list3, list1); + Tcl_ListObjAppendElement(interp, list3, list2); + Tcl_SetObjResult(interp, list3); +} + +%typemap(out) Table1* { + Table1 *table = $1; + Tcl_Obj *list3 = Tcl_NewListObj(0, nullptr); + if (table) { + Tcl_Obj *list1 = Tcl_NewListObj(0, nullptr); + for (float f : *table->axis1()->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list1, obj); + } + Tcl_Obj *list2 = Tcl_NewListObj(0, nullptr); + for (float f : *table->values()) { + Tcl_Obj *obj = Tcl_NewDoubleObj(f); + Tcl_ListObjAppendElement(interp, list2, obj); + } + Tcl_ListObjAppendElement(interp, list3, list1); + Tcl_ListObjAppendElement(interp, list3, list2); + } + Tcl_SetObjResult(interp, list3); +} + %typemap(in) MinMax* { int length; char *arg = Tcl_GetStringFromObj($input, &length); @@ -4586,17 +4625,6 @@ find_clk_min_period(const Clock *clk, return sta->findClkMinPeriod(clk, ignore_port_paths); } -TmpString * -report_delay_calc_cmd(Edge *edge, - TimingArc *arc, - const Corner *corner, - const MinMax *min_max, - int digits) -{ - cmdLinkedNetwork(); - return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits); -} - //////////////////////////////////////////////////////////////// PinSeq @@ -5601,6 +5629,9 @@ full_name() to); } +TimingArcSeq & +timing_arcs() { return self->arcs(); } + } // TimingArcSet methods %extend TimingArc { @@ -5611,6 +5642,24 @@ const char *from_edge_name() { return self->fromEdge()->asRiseFall()->name(); } Transition *to_edge() { return self->toEdge(); } const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); } TimingRole *role() { return self->role(); } + +Table1 +voltage_waveform(float in_slew, + float load_cap) +{ + GateTableModel *gate_model = dynamic_cast(self->model()); + if (gate_model) { + OutputWaveforms *output_waveforms = gate_model->outputWaveforms(); + if (output_waveforms) { + OutputWaveform voltage_waveform = + output_waveforms->voltageWaveform(in_slew, load_cap); + Table1 voltages(std::move(*voltage_waveform.voltages())); + return voltages; + } + } + return Table1(); +} + } // TimingArc methods %extend Instance { diff --git a/util/Transition.cc b/util/Transition.cc index b5380006..b77b46ae 100644 --- a/util/Transition.cc +++ b/util/Transition.cc @@ -56,11 +56,13 @@ RiseFall::opposite() const } RiseFall * -RiseFall::find(const char *tr_str) +RiseFall::find(const char *rf_str) { - if (stringEq(tr_str, rise_.name())) + if (stringEq(rf_str, rise_.name()) + || stringEq(rf_str, rise_.shortName())) return &rise_; - else if (stringEq(tr_str, fall_.name())) + else if (stringEq(rf_str, fall_.name()) + || stringEq(rf_str, fall_.shortName())) return &fall_; else return nullptr;