diff --git a/README.md b/README.md
index 5e15721b..3d4ca48d 100644
--- a/README.md
+++ b/README.md
@@ -52,6 +52,21 @@ See doc/OpenSTA.pdf for command documentiaton.
See doc/StaApi.txt for timing engine API documentiaton.
See doc/ChangeLog.txt for changes to commands.
+OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
+is also licensed for commerical applications by Parallax Software without
+the GPL's requirements.
+
+OpenSTA is open source, meaning the sources are published and can be compiled locally.
+Derivatives works are supported as long as they adhere to the GPL license requirements.
+However, OpenSTA is not supported by a public community of developers as many other
+open source projects are. The copyright and develpment are exclusive to Parallax
+Software. OpenSTA does not accept external code contributions.
+
+The official git repository is located at
+https://github.com/jjcherry56/OpenSTA.git. Any forks from this code
+base have not passed extensive regression testing which is not
+publicly available.
+
## Build
OpenSTA is built with CMake.
@@ -197,19 +212,8 @@ case directory.
* William Scott authored the arnoldi delay calculator at Blaze, Inc which was subsequently licensed to Nefelus, Inc that has graciously contributed it to OpenSTA.
-## Contributions
-
-External code contributions are not supported.
-
-https://en.wikipedia.org/wiki/Contributor_License_Agreement
-https://opensource.google/docs/cla/
-
## License
-OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
-is also licensed for commerical applications by Parallax Software without
-the GPL's requirements.
-
OpenSTA, Static Timing Analyzer
Copyright (c) 2023, Parallax Software, Inc.
@@ -225,4 +229,3 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
-
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/Sta.hh b/include/sta/Sta.hh
index 9ae4a6f2..36bd2ef4 100644
--- a/include/sta/Sta.hh
+++ b/include/sta/Sta.hh
@@ -999,13 +999,17 @@ public:
Arrival vertexArrival(Vertex *vertex,
const RiseFall *rf,
const ClockEdge *clk_edge,
- const PathAnalysisPt *path_ap);
+ const PathAnalysisPt *path_ap,
+ const MinMax *min_max);
// Min/max across all clock tags.
Arrival vertexArrival(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap);
Arrival vertexArrival(Vertex *vertex,
const MinMax *min_max);
+ Arrival pinArrival(const Pin *pin,
+ const RiseFall *rf,
+ const MinMax *min_max);
Required vertexRequired(Vertex *vertex,
const MinMax *min_max);
Required vertexRequired(Vertex *vertex,
diff --git a/include/sta/TableModel.hh b/include/sta/TableModel.hh
index 39375eb7..39d1c320 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 Table1;
typedef Vector FloatSeq;
typedef Vector FloatTable;
-typedef Vector OutputCurrentWaveformSeq;
+typedef Vector Table1Seq;
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
@@ -273,16 +275,16 @@ public:
size_t axis_idx2,
size_t axis_idx3) const = 0;
// Table interpolated lookup.
- virtual float findValue(float value1,
- float value2,
- float value3) const = 0;
+ virtual float findValue(float axis_value1,
+ float axis_value2,
+ float axis_value3) const = 0;
// Table interpolated lookup with scale factor.
float findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
- float value1,
- float value2,
- float value3) const;
+ float axis_value1,
+ float axis_value2,
+ float axis_value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
@@ -304,12 +306,12 @@ class Table0 : public Table
public:
Table0(float value);
virtual int order() const { return 0; }
- virtual float value(size_t index1,
- size_t index2,
- size_t index3) const;
- virtual float findValue(float value1,
- float value2,
- float value3) const;
+ virtual float value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const;
+ virtual float findValue(float axis_value1,
+ float axis_value2,
+ float axis_value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
@@ -333,15 +335,25 @@ 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;
+ virtual float value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const;
float value(size_t index1) const;
+ float findValue(float axis_value1) const;
+ void findValue(float axis_value1,
+ // Return values.
+ float &value,
+ bool &extrapolated) const;
+ float findValueClip(float axis_value1,
+ float clip_value) const;
virtual float findValue(float value1,
float value2,
float value3) const;
@@ -358,6 +370,7 @@ public:
string *result) const;
virtual void report(const Units *units,
Report *report) const;
+ FloatSeq *values() const { return values_; }
using Table::findValue;
private:
@@ -376,14 +389,14 @@ public:
virtual int order() const { return 2; }
TableAxisPtr axis1() const { return axis1_; }
TableAxisPtr axis2() const { return axis2_; }
- virtual float value(size_t index1,
- size_t index2,
- size_t index3) const;
- float value(size_t index1,
- size_t index2) const;
- virtual float findValue(float value1,
- float value2,
- float value3) const;
+ virtual float value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const;
+ float value(size_t axis_index1,
+ size_t axis_index2) const;
+ virtual float findValue(float axis_value1,
+ float axis_value2,
+ float axis_value3) const;
FloatTable *values3() { return values_; }
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
@@ -419,12 +432,12 @@ public:
virtual ~Table3() {}
virtual int order() const { return 3; }
TableAxisPtr axis3() const { return axis3_; }
- virtual float value(size_t index1,
- size_t index2,
- size_t index3) const;
- virtual float findValue(float value1,
- float value2,
- float value3) const;
+ virtual float value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const;
+ virtual float findValue(float axis_value1,
+ float axis_value2,
+ float axis_value3) const;
virtual void reportValue(const char *result_name,
const LibertyLibrary *library,
const LibertyCell *cell,
@@ -462,6 +475,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 +499,47 @@ private:
TableModel *capacitance_models_[2][RiseFall::index_count];
};
-class OutputCurrentWaveform
+// Two dimensional (slew/cap) table of one dimensional time/current tables.
+class OutputWaveforms
{
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_; }
- Table1 *currents() const { return currents_; }
- float referenceTime() const { return reference_time_; }
- void reportWaveform(const Units *units,
- int digits,
- string *result);
+ OutputWaveforms(TableAxisPtr slew_axis,
+ TableAxisPtr cap_axis,
+ Table1Seq ¤t_waveforms,
+ Table1 *ref_times);
+ ~OutputWaveforms();
+ Table1 voltageWaveform(float in_slew,
+ float load_cap);
+ Table1 currentWaveform(float slew,
+ float cap);
+ float referenceTime(float slew);
static bool checkAxes(TableTemplate *tbl_template);
-
-private:
- float axis_value1_;
- float axis_value2_;
- TableAxisPtr axis_;
- Table1 *currents_;
- float reference_time_;
-};
-
-// Two dimensional table of one dimensional time/current tables.
-class OutputCurrent
-{
-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;
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;
+ Table1 *voltageWaveform(size_t wave_index,
+ float cap);
// Row.
- TableAxisPtr axis1_;
+ TableAxisPtr slew_axis_;
// Column.
- TableAxisPtr axis2_;
- OutputCurrentWaveformSeq waveforms_;
+ TableAxisPtr cap_axis_;
+ Table1Seq current_waveforms_;
+ Table1Seq voltage_waveforms_;
+ Table1 *ref_times_;
+};
+
+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 9a656adf..e47fc6e0 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,59 @@ 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;
- waveforms[index] = waveform;
+ 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->currents();
+ (*ref_times)[slew_index] = waveform->referenceTime();
}
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);
+ Table1 *ref_time_tbl = new Table1(ref_times, slew_axis);
+ OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis,
+ current_waveforms,
+ ref_time_tbl);
+ 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 (!OutputCurrentWaveform::checkAxes(tbl_template_))
+ if (tbl_template_ && !OutputWaveforms::checkAxes(tbl_template_))
libWarn(118, group, "unsupported model axis.");
}
}
@@ -2546,32 +2557,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_) {
- FloatSeq *axis_values1 = axis_values_[0];
- FloatSeq *axis_values2 = axis_values_[1];
- if (axis_values1->size() == 1 && axis_values2->size() == 1) {
+ if (timing_ && tbl_template_) {
+ 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 +2600,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 +5447,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 +5578,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;
}
////////////////////////////////////////////////////////////////
@@ -5677,4 +5759,22 @@ PortNameBitIterator::findRangeBusNameNext()
range_name_next_ = nullptr;
}
+////////////////////////////////////////////////////////////////
+
+OutputWaveform::OutputWaveform(float slew,
+ float cap,
+ Table1 *currents,
+ float reference_time) :
+ slew_(slew),
+ cap_(cap),
+ currents_(currents),
+ reference_time_(reference_time)
+{
+}
+
+OutputWaveform::~OutputWaveform()
+{
+ delete currents_;
+}
+
} // namespace
diff --git a/liberty/LibertyReaderPvt.hh b/liberty/LibertyReaderPvt.hh
index 23749183..15f3af0a 100644
--- a/liberty/LibertyReaderPvt.hh
+++ b/liberty/LibertyReaderPvt.hh
@@ -45,6 +45,7 @@ class LeakagePowerGroup;
class PortNameBitIterator;
class TimingArcBuilder;
class LibertyAttr;
+class OutputWaveform;
typedef void (LibertyReader::*LibraryAttrVisitor)(LibertyAttr *attr);
typedef void (LibertyReader::*LibraryGroupVisitor)(LibertyGroup *group);
@@ -57,7 +58,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 +444,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 +627,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 +794,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 +814,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_;
};
@@ -858,4 +869,24 @@ protected:
unsigned size_;
};
+class OutputWaveform
+{
+public:
+ OutputWaveform(float axis_value1,
+ float axis_value2,
+ Table1 *currents,
+ float reference_time);
+ ~OutputWaveform();
+ float slew() const { return slew_; }
+ float cap() const { return cap_; }
+ Table1 *currents() const { return currents_; }
+ float referenceTime() const { return reference_time_; }
+
+private:
+ float slew_;
+ float cap_;
+ Table1 *currents_;
+ float reference_time_;
+};
+
} // namespace
diff --git a/liberty/TableModel.cc b/liberty/TableModel.cc
index 1429e5ed..8bb00889 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
@@ -651,22 +657,22 @@ TableModel::axis3() const
}
float
-TableModel::value(size_t index1,
- size_t index2,
- size_t index3) const
+TableModel::value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const
{
- return table_->value(index1, index2, index3);
+ return table_->value(axis_index1, axis_index2, axis_index3);
}
float
TableModel::findValue(const LibertyLibrary *library,
const LibertyCell *cell,
const Pvt *pvt,
- float value1,
- float value2,
- float value3) const
+ float axis_value1,
+ float axis_value2,
+ float axis_value3) const
{
- return table_->findValue(value1, value2, value3)
+ return table_->findValue(axis_value1, axis_value2, axis_value3)
* scaleFactor(library, cell, pvt);
}
@@ -801,6 +807,13 @@ Table0::report(const Units *units,
////////////////////////////////////////////////////////////////
+Table1::Table1() :
+ Table(),
+ values_(nullptr),
+ axis1_(nullptr)
+{
+}
+
Table1::Table1(FloatSeq *values,
TableAxisPtr axis1) :
Table(),
@@ -809,41 +822,94 @@ 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,
+Table1::value(size_t axis_index1,
size_t,
size_t) const
{
- return value(index1);
+ return value(axis_index1);
}
float
-Table1::value(size_t index1) const
+Table1::value(size_t axis_index1) const
{
- return (*values_)[index1];
+ return (*values_)[axis_index1];
}
float
-Table1::findValue(float value1,
+Table1::findValue(float axis_value1,
float,
float) const
{
- if (axis1_->size() == 1)
- return value(value1);
+ return findValue(axis_value1);
+}
+
+float
+Table1::findValue(float axis_value1) const
+{
+ float value;
+ bool extrapolated;
+ findValue(axis_value1, value, extrapolated);
+ return value;
+}
+
+float
+Table1::findValueClip(float axis_value1,
+ float clip_value) const
+{
+ float value;
+ bool extrapolated;
+ findValue(axis_value1, value, extrapolated);
+ if (extrapolated)
+ return clip_value;
+ else
+ return value;
+}
+
+void
+Table1::findValue(float axis_value1,
+ // Return values.
+ float &value,
+ bool &extrapolated) const
+{
+ if (axis1_->size() == 1) {
+ value = this->value(axis_value1);
+ extrapolated = false;
+ }
else {
- size_t index1 = axis1_->findAxisIndex(value1);
- float x1 = value1;
- float x1l = axis1_->axisValue(index1);
- float x1u = axis1_->axisValue(index1 + 1);
- float y1 = value(index1);
- float y2 = value(index1 + 1);
+ size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
+ float x1 = axis_value1;
+ float x1l = axis1_->axisValue(axis_index1);
+ float x1u = axis1_->axisValue(axis_index1 + 1);
+ float y1 = this->value(axis_index1);
+ float y2 = this->value(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
- return (1 - dx1) * y1 + dx1 * y2;
+ value = (1 - dx1) * y1 + dx1 * y2;
+ extrapolated = (x1 < x1l || x1 >= x1u);
}
}
@@ -938,25 +1004,25 @@ Table2::~Table2()
}
float
-Table2::value(size_t index1,
- size_t index2,
+Table2::value(size_t axis_index1,
+ size_t axis_index2,
size_t) const
{
- return value(index1, index2);
+ return value(axis_index1, axis_index2);
}
float
-Table2::value(size_t index1,
- size_t index2) const
+Table2::value(size_t axis_index1,
+ size_t axis_index2) const
{
- FloatSeq *row = (*values_)[index1];
- return (*row)[index2];
+ FloatSeq *row = (*values_)[axis_index1];
+ return (*row)[axis_index2];
}
// Bilinear Interpolation.
float
-Table2::findValue(float value1,
- float value2,
+Table2::findValue(float axis_value1,
+ float axis_value2,
float) const
{
size_t size1 = axis1_->size();
@@ -965,13 +1031,13 @@ Table2::findValue(float value1,
if (size2 == 1)
return value(0, 0);
else {
- size_t index2 = axis2_->findAxisIndex(value2);
- float x2 = value2;
- float y00 = value(0, index2);
- float x2l = axis2_->axisValue(index2);
- float x2u = axis2_->axisValue(index2 + 1);
+ size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
+ float x2 = axis_value2;
+ float y00 = value(0, axis_index2);
+ float x2l = axis2_->axisValue(axis_index2);
+ float x2u = axis2_->axisValue(axis_index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
- float y01 = value(0, index2 + 1);
+ float y01 = value(0, axis_index2 + 1);
float tbl_value
= (1 - dx2) * y00
+ dx2 * y01;
@@ -979,33 +1045,33 @@ Table2::findValue(float value1,
}
}
else if (size2 == 1) {
- size_t index1 = axis1_->findAxisIndex(value1);
- float x1 = value1;
- float y00 = value(index1, 0);
- float x1l = axis1_->axisValue(index1);
- float x1u = axis1_->axisValue(index1 + 1);
+ size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
+ float x1 = axis_value1;
+ float y00 = value(axis_index1, 0);
+ float x1l = axis1_->axisValue(axis_index1);
+ float x1u = axis1_->axisValue(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
- float y10 = value(index1 + 1, 0);
+ float y10 = value(axis_index1 + 1, 0);
float tbl_value
= (1 - dx1) * y00
+ dx1 * y10;
return tbl_value;
}
else {
- size_t index1 = axis1_->findAxisIndex(value1);
- size_t index2 = axis2_->findAxisIndex(value2);
- float x1 = value1;
- float x2 = value2;
- float y00 = value(index1, index2);
- float x1l = axis1_->axisValue(index1);
- float x1u = axis1_->axisValue(index1 + 1);
+ size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
+ size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
+ float x1 = axis_value1;
+ float x2 = axis_value2;
+ float y00 = value(axis_index1, axis_index2);
+ float x1l = axis1_->axisValue(axis_index1);
+ float x1u = axis1_->axisValue(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
- float y10 = value(index1 + 1, index2);
- float y11 = value(index1 + 1, index2 + 1);
- float x2l = axis2_->axisValue(index2);
- float x2u = axis2_->axisValue(index2 + 1);
+ float y10 = value(axis_index1 + 1, axis_index2);
+ float y11 = value(axis_index1 + 1, axis_index2 + 1);
+ float x2l = axis2_->axisValue(axis_index2);
+ float x2u = axis2_->axisValue(axis_index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
- float y01 = value(index1, index2 + 1);
+ float y01 = value(axis_index1, axis_index2 + 1);
float tbl_value
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
@@ -1123,30 +1189,30 @@ Table3::Table3(FloatTable *values,
}
float
-Table3::value(size_t index1,
- size_t index2,
- size_t index3) const
+Table3::value(size_t axis_index1,
+ size_t axis_index2,
+ size_t axis_index3) const
{
- size_t row = index1 * axis2_->size() + index2;
- return values_->operator[](row)->operator[](index3);
+ size_t row = axis_index1 * axis2_->size() + axis_index2;
+ return values_->operator[](row)->operator[](axis_index3);
}
// Bilinear Interpolation.
float
-Table3::findValue(float value1,
- float value2,
- float value3) const
+Table3::findValue(float axis_value1,
+ float axis_value2,
+ float axis_value3) const
{
- size_t index1 = axis1_->findAxisIndex(value1);
- size_t index2 = axis2_->findAxisIndex(value2);
- size_t index3 = axis3_->findAxisIndex(value3);
- float x1 = value1;
- float x2 = value2;
- float x3 = value3;
+ size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
+ size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
+ size_t axis_index3 = axis3_->findAxisIndex(axis_value3);
+ float x1 = axis_value1;
+ float x2 = axis_value2;
+ float x3 = axis_value3;
float dx1 = 0.0;
float dx2 = 0.0;
float dx3 = 0.0;
- float y000 = value(index1, index2, index3);
+ float y000 = value(axis_index1, axis_index2, axis_index3);
float y001 = 0.0;
float y010 = 0.0;
float y011 = 0.0;
@@ -1156,31 +1222,31 @@ Table3::findValue(float value1,
float y111 = 0.0;
if (axis1_->size() != 1) {
- float x1l = axis1_->axisValue(index1);
- float x1u = axis1_->axisValue(index1 + 1);
+ float x1l = axis1_->axisValue(axis_index1);
+ float x1u = axis1_->axisValue(axis_index1 + 1);
dx1 = (x1 - x1l) / (x1u - x1l);
- y100 = value(index1 + 1, index2, index3);
+ y100 = value(axis_index1 + 1, axis_index2, axis_index3);
if (axis3_->size() != 1)
- y101 = value(index1 + 1, index2, index3 + 1);
+ y101 = value(axis_index1 + 1, axis_index2, axis_index3 + 1);
if (axis2_->size() != 1) {
- y110 = value(index1 + 1, index2 + 1, index3);
+ y110 = value(axis_index1 + 1, axis_index2 + 1, axis_index3);
if (axis3_->size() != 1)
- y111 = value(index1 + 1, index2 + 1, index3 + 1);
+ y111 = value(axis_index1 + 1, axis_index2 + 1, axis_index3 + 1);
}
}
if (axis2_->size() != 1) {
- float x2l = axis2_->axisValue(index2);
- float x2u = axis2_->axisValue(index2 + 1);
+ float x2l = axis2_->axisValue(axis_index2);
+ float x2u = axis2_->axisValue(axis_index2 + 1);
dx2 = (x2 - x2l) / (x2u - x2l);
- y010 = value(index1, index2 + 1, index3);
+ y010 = value(axis_index1, axis_index2 + 1, axis_index3);
if (axis3_->size() != 1)
- y011 = value(index1, index2 + 1, index3 + 1);
+ y011 = value(axis_index1, axis_index2 + 1, axis_index3 + 1);
}
if (axis3_->size() != 1) {
- float x3l = axis3_->axisValue(index3);
- float x3u = axis3_->axisValue(index3 + 1);
+ float x3l = axis3_->axisValue(axis_index3);
+ float x3u = axis3_->axisValue(axis_index3 + 1);
dx3 = (x3 - x3l) / (x3u - x3l);
- y001 = value(index1, index2, index3 + 1);
+ y001 = value(axis_index1, axis_index2, axis_index3 + 1);
}
float tbl_value
@@ -1244,15 +1310,15 @@ Table3::reportValue(const char *result_name,
*result += unit3->asString(value3, digits);
*result += '\n';
- size_t index1 = axis1_->findAxisIndex(value1);
- size_t index2 = axis2_->findAxisIndex(value2);
- size_t index3 = axis3_->findAxisIndex(value3);
+ size_t axis_index1 = axis1_->findAxisIndex(value1);
+ size_t axis_index2 = axis2_->findAxisIndex(value2);
+ size_t axis_index3 = axis3_->findAxisIndex(value3);
*result += " | | ";
- *result += unit3->asString(axis3_->axisValue(index3), digits);
+ *result += unit3->asString(axis3_->axisValue(axis_index3), digits);
if (axis3_->size() != 1) {
*result += " ";
- *result += unit3->asString(axis3_->axisValue(index3 + 1), digits);
+ *result += unit3->asString(axis3_->axisValue(axis_index3 + 1), digits);
}
*result += '\n';
@@ -1260,13 +1326,13 @@ Table3::reportValue(const char *result_name,
if (axis1_->size() != 1) {
*result += " ";
- *result += unit1->asString(axis1_->axisValue(index1+1), digits);
+ *result += unit1->asString(axis1_->axisValue(axis_index1+1), digits);
*result += " v / ";
- *result += table_unit->asString(value(index1+1,index2,index3),
+ *result += table_unit->asString(value(axis_index1+1,axis_index2,axis_index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
- *result += table_unit->asString(value(index1+1,index2,index3+1),
+ *result += table_unit->asString(value(axis_index1+1,axis_index2,axis_index3+1),
digits);
}
}
@@ -1276,14 +1342,14 @@ Table3::reportValue(const char *result_name,
}
*result += '\n';
- *result += unit1->asString(axis1_->axisValue(index1), digits);
+ *result += unit1->asString(axis1_->axisValue(axis_index1), digits);
*result += " ";
- *result += unit2->asString(axis2_->axisValue(index2), digits);
+ *result += unit2->asString(axis2_->axisValue(axis_index2), digits);
*result += " | ";
- *result += table_unit->asString(value(index1, index2, index3), digits);
+ *result += table_unit->asString(value(axis_index1, axis_index2, axis_index3), digits);
if (axis3_->size() != 1) {
*result += " ";
- *result += table_unit->asString(value(index1, index2, index3+1),
+ *result += table_unit->asString(value(axis_index1, axis_index2, axis_index3+1),
digits);
}
*result += '\n';
@@ -1291,25 +1357,25 @@ Table3::reportValue(const char *result_name,
*result += " |/ ";
if (axis1_->size() != 1
&& axis2_->size() != 1) {
- *result += table_unit->asString(value(index1+1,index2+1,index3),
+ *result += table_unit->asString(value(axis_index1+1,axis_index2+1,axis_index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
- *result +=table_unit->asString(value(index1+1,index2+1,index3+1),
+ *result +=table_unit->asString(value(axis_index1+1,axis_index2+1,axis_index3+1),
digits);
}
}
*result += '\n';
*result += " ";
- *result += unit2->asString(axis2_->axisValue(index2 + 1), digits);
+ *result += unit2->asString(axis2_->axisValue(axis_index2 + 1), digits);
*result += " | ";
if (axis2_->size() != 1) {
- *result += table_unit->asString(value(index1, index2+1, index3),
+ *result += table_unit->asString(value(axis_index1, axis_index2+1, axis_index3),
digits);
if (axis3_->size() != 1) {
*result += " ";
- *result +=table_unit->asString(value(index1, index2+1,index3+1),
+ *result +=table_unit->asString(value(axis_index1, axis_index2+1,axis_index3+1),
digits);
}
}
@@ -1338,24 +1404,24 @@ Table3::report(const Units *units,
const Unit *unit1 = axis1_->unit(units);
const Unit *unit2 = axis2_->unit(units);
const Unit *unit3 = axis3_->unit(units);
- for (size_t index1 = 0; index1 < axis1_->size(); index1++) {
+ for (size_t axis_index1 = 0; axis_index1 < axis1_->size(); axis_index1++) {
report->reportLine("%s %s", tableVariableString(axis1_->variable()),
- unit1->asString(axis1_->axisValue(index1), digits));
+ unit1->asString(axis1_->axisValue(axis_index1), digits));
report->reportLine("%s", tableVariableString(axis3_->variable()));
report->reportLine(" ------------------------------");
string line = " ";
- for (size_t index3 = 0; index3 < axis3_->size(); index3++) {
- line += unit3->asString(axis3_->axisValue(index3), digits);
+ for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) {
+ line += unit3->asString(axis3_->axisValue(axis_index3), digits);
line += " ";
}
report->reportLineString(line);
- for (size_t index2 = 0; index2 < axis2_->size(); index2++) {
- line = unit2->asString(axis2_->axisValue(index2),digits);
+ for (size_t axis_index2 = 0; axis_index2 < axis2_->size(); axis_index2++) {
+ line = unit2->asString(axis2_->axisValue(axis_index2),digits);
line += " |";
- for (size_t index3 = 0; index3 < axis3_->size(); index3++) {
- line += table_unit->asString(value(index1, index2, index3), digits);
+ for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) {
+ line += table_unit->asString(value(axis_index1, axis_index2, axis_index3), digits);
line += " ";
}
report->reportLineString(line);
@@ -1514,26 +1580,30 @@ 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),
- currents_(currents),
- reference_time_(reference_time)
+
+////////////////////////////////////////////////////////////////
+
+OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
+ TableAxisPtr cap_axis,
+ Table1Seq ¤t_waveforms,
+ Table1 *ref_times) :
+ slew_axis_(slew_axis),
+ cap_axis_(cap_axis),
+ current_waveforms_(current_waveforms),
+ voltage_waveforms_(current_waveforms.size()),
+ ref_times_(ref_times)
{
}
-OutputCurrentWaveform::~OutputCurrentWaveform()
+OutputWaveforms::~OutputWaveforms()
{
- delete currents_;
+ current_waveforms_.deleteContents();
+ voltage_waveforms_.deleteContents();
+ delete ref_times_;
}
bool
-OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template)
+OutputWaveforms::checkAxes(TableTemplate *tbl_template)
{
TableAxisPtr axis1 = tbl_template->axis1();
TableAxisPtr axis2 = tbl_template->axis2();
@@ -1549,83 +1619,215 @@ OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template)
&& axis3->variable() == TableAxisVariable::time);
}
-void
-OutputCurrentWaveform::reportWaveform(const Units *units,
- int digits,
- string *result)
+Table1
+OutputWaveforms::voltageWaveform(float slew,
+ float cap)
{
- 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 += " ";
+ 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);
+ float cap0 = cap_axis_->axisValue(cap_index);
+ float cap1 = cap_axis_->axisValue(cap_index + 1);
+ const Table1 *values00 = voltageWaveform(wave_index00, cap0);
+ const Table1 *values01 = voltageWaveform(wave_index01, cap1);
+ const Table1 *values10 = voltageWaveform(wave_index10, cap0);
+ const Table1 *values11 = voltageWaveform(wave_index11, cap1);
+ TableAxisPtr time_axis00 = values00->axis1();
+ TableAxisPtr time_axis01 = values01->axis1();
+ TableAxisPtr time_axis10 = values10->axis1();
+ TableAxisPtr time_axis11 = values11->axis1();
+
+ // 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);
+
+ // Interpolate waveform samples at time steps.
+ float value = values00->value(values00->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 *values = new FloatSeq;
+ bool waveform_started = false;
+ float prev_value = 0.0;
+ constexpr float value_tol = .01;
+ float value_end = value * (1.0 - value_tol);
+ for (size_t i = 0; i <= time_step_count; i++) {
+ float time = time_min + time_step * i;
+ float y00 = values00->findValue(time);
+ float y10 = values10->findValue(time);
+ float y11 = values11->findValue(time);
+ float y01 = values01->findValue(time);
+ float voltage
+ = (1 - dx1) * (1 - dx2) * y00
+ + dx1 * (1 - dx2) * y10
+ + dx1 * dx2 * y11
+ + (1 - dx1) * dx2 * y01;
+ if (voltage > value_tol)
+ waveform_started = true;
+ if (waveform_started) {
+ time_values->push_back(time);
+ values->push_back(voltage);
+ }
+ if (prev_value > value_end)
+ break;
+ prev_value = voltage;
}
- *result += '\n';
- for (size_t i = 0; i < currents_->axis1()->size(); i++) {
- *result += current_unit->asString(currents_->value(i), digits);
- *result += " ";
+ return Table1(values, time_axis);
+}
+
+Table1 *
+OutputWaveforms::voltageWaveform(size_t wave_index,
+ float cap)
+{
+ Table1 *voltages = voltage_waveforms_[wave_index];
+ if (voltages == nullptr) {
+ FloatSeq *voltages1 = new FloatSeq;
+ Table1 *currents = current_waveforms_[wave_index];
+ voltages = new Table1(voltages1, currents->axis1());
+ voltage_waveforms_[wave_index] = voltages;
+
+ // 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;
+ voltages1->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;
+ voltages1->push_back(voltage);
+ prev_time = time;
+ prev_current = current;
+ }
}
- *result += '\n';
+ return voltages;
+}
+
+Table1
+OutputWaveforms::currentWaveform(float slew,
+ float cap)
+{
+ 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);
+ const Table1 *values00 = current_waveforms_[wave_index00];
+ const Table1 *values01 = current_waveforms_[wave_index01];
+ const Table1 *values10 = current_waveforms_[wave_index10];
+ const Table1 *values11 = current_waveforms_[wave_index11];
+ TableAxisPtr time_axis00 = values00->axis1();
+ TableAxisPtr time_axis01 = values01->axis1();
+ TableAxisPtr time_axis10 = values10->axis1();
+ TableAxisPtr time_axis11 = values11->axis1();
+
+ // 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);
+
+ // Interpolate waveform samples at time steps.
+ 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 *values = new FloatSeq;
+ for (size_t i = 0; i <= time_step_count; i++) {
+ float time = time_min + time_step * i;
+ float y00 = values00->findValueClip(time, 0.0);
+ float y10 = values10->findValueClip(time, 0.0);
+ float y11 = values11->findValueClip(time, 0.0);
+ float y01 = values01->findValueClip(time, 0.0);
+ float value
+ = (1 - dx1) * (1 - dx2) * y00
+ + dx1 * (1 - dx2) * y10
+ + dx1 * dx2 * y11
+ + (1 - dx1) * dx2 * y01;
+ time_values->push_back(time);
+ values->push_back(value);
+ if (time > time_max)
+ break;
+ }
+ return Table1(values, time_axis);
+}
+
+float
+OutputWaveforms::referenceTime(float slew)
+{
+ return ref_times_->findValue(slew);
}
////////////////////////////////////////////////////////////////
-OutputCurrent::OutputCurrent(TableAxisPtr axis1,
- TableAxisPtr axis2,
- OutputCurrentWaveformSeq &waveforms) :
- axis1_(axis1),
- axis2_(axis2),
+DriverWaveform::DriverWaveform(const char *name,
+ TablePtr waveforms) :
+ name_(name),
waveforms_(waveforms)
{
}
-OutputCurrent::~OutputCurrent()
+DriverWaveform::~DriverWaveform()
{
- waveforms_.deleteContents();
+ stringDelete(name_);
}
-void
-OutputCurrent::reportWaveform(const LibertyCell *cell,
- const Pvt *,
- float in_slew,
- float load_cap,
- int digits,
- string *result) const
+Table1
+DriverWaveform::waveform(float slew)
{
- 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);
-}
-
-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);
-}
-
-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;
+ 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/power/Power.cc b/power/Power.cc
index 2feac82c..773219ee 100644
--- a/power/Power.cc
+++ b/power/Power.cc
@@ -63,6 +63,7 @@
namespace sta {
using std::abs;
+using std::max;
using std::isnormal;
static bool
@@ -302,12 +303,16 @@ public:
virtual VertexVisitor *copy() const;
virtual void visit(Vertex *vertex);
InstanceSet &visitedRegs() { return visited_regs_; }
+ void init();
+ float maxChange() const { return max_change_; }
private:
bool setActivityCheck(const Pin *pin,
PwrActivity &activity);
+ static constexpr float change_tolerance_ = .01;
InstanceSet visited_regs_;
+ float max_change_;
Power *power_;
BfsFwdIterator *bfs_;
};
@@ -327,6 +332,12 @@ PropActivityVisitor::copy() const
return new PropActivityVisitor(power_, bfs_);
}
+void
+PropActivityVisitor::init()
+{
+ max_change_ = 0.0;
+}
+
void
PropActivityVisitor::visit(Vertex *vertex)
{
@@ -420,8 +431,12 @@ PropActivityVisitor::setActivityCheck(const Pin *pin,
PwrActivity &activity)
{
PwrActivity &prev_activity = power_->activity(pin);
- if (abs(activity.activity() - prev_activity.activity()) > .001
- || abs(activity.duty() - prev_activity.duty()) > .001) {
+ float activity_delta = abs(activity.activity() - prev_activity.activity());
+ float duty_delta = abs(activity.duty() - prev_activity.duty());
+ if (activity_delta > change_tolerance_
+ || duty_delta > change_tolerance_) {
+ max_change_ = max(max_change_, activity_delta);
+ max_change_ = max(max_change_, duty_delta);
power_->setActivity(pin, activity);
return true;
}
@@ -556,8 +571,10 @@ Power::ensureActivities()
bfs.visit(levelize_->maxLevel(), &visitor);
// Propagate activiities through registers.
InstanceSet regs = std::move(visitor.visitedRegs());
- while (!regs.empty()) {
- InstanceSet::Iterator reg_iter(regs);
+ int pass = 1;
+ while (!regs.empty() && pass < max_activity_passes_) {
+ visitor.init();
+ InstanceSet::Iterator reg_iter(regs);
while (reg_iter.hasNext()) {
const Instance *reg = reg_iter.next();
// Propagate activiities across register D->Q.
@@ -567,6 +584,9 @@ Power::ensureActivities()
// combinational logic.
bfs.visit(levelize_->maxLevel(), &visitor);
regs = std::move(visitor.visitedRegs());
+ debugPrint(debug_, "power_activity", 1, "Pass %d change %.2f",
+ pass, visitor.maxChange());
+ pass++;
}
activities_valid_ = true;
}
@@ -615,7 +635,7 @@ Power::seedRegOutputActivities(const Instance *inst,
&& func
&& (func->port() == seq->output()
|| func->port() == seq->outputInv())) {
- debugPrint(debug_, "power_activity", 3, "enqueue reg output %s",
+ debugPrint(debug_, "power_reg", 1, "enqueue reg output %s",
vertex->name(network_));
bfs.enqueue(vertex);
}
diff --git a/power/Power.hh b/power/Power.hh
index b9296727..3cc5a1b3 100644
--- a/power/Power.hh
+++ b/power/Power.hh
@@ -196,6 +196,7 @@ private:
PwrActivityMap activity_map_;
PwrSeqActivityMap seq_activity_map_;
bool activities_valid_;
+ static constexpr int max_activity_passes_ = 100;
friend class PropActivityVisitor;
};
diff --git a/search/Property.cc b/search/Property.cc
index cdc39d11..8abc350c 100644
--- a/search/Property.cc
+++ b/search/Property.cc
@@ -48,6 +48,11 @@ pinSlewProperty(const Pin *pin,
const MinMax *min_max,
Sta *sta);
static PropertyValue
+pinArrivalProperty(const Pin *pin,
+ const RiseFall *rf,
+ const MinMax *min_max,
+ Sta *sta);
+static PropertyValue
pinSlackProperty(const Pin *pin,
const MinMax *min_max,
Sta *sta);
@@ -882,6 +887,15 @@ getProperty(const Pin *pin,
return PropertyValue(&activity);
}
+ else if (stringEqual(property, "arrival_max_rise"))
+ return pinArrivalProperty(pin, RiseFall::rise(), MinMax::max(), sta);
+ else if (stringEqual(property, "arrival_max_fall"))
+ return pinArrivalProperty(pin, RiseFall::fall(), MinMax::max(), sta);
+ else if (stringEqual(property, "arrival_min_rise"))
+ return pinArrivalProperty(pin, RiseFall::rise(), MinMax::min(), sta);
+ else if (stringEqual(property, "arrival_min_fall"))
+ return pinArrivalProperty(pin, RiseFall::fall(), MinMax::min(), sta);
+
else if (stringEqual(property, "slack_max"))
return pinSlackProperty(pin, MinMax::max(), sta);
else if (stringEqual(property, "slack_max_fall"))
@@ -912,6 +926,16 @@ getProperty(const Pin *pin,
throw PropertyUnknown("pin", property);
}
+static PropertyValue
+pinArrivalProperty(const Pin *pin,
+ const RiseFall *rf,
+ const MinMax *min_max,
+ Sta *sta)
+{
+ Arrival arrival = sta->pinArrival(pin, rf, min_max);;
+ return PropertyValue(delayPropertyValue(arrival, sta));
+}
+
static PropertyValue
pinSlackProperty(const Pin *pin,
const MinMax *min_max,
diff --git a/search/Sta.cc b/search/Sta.cc
index e7fb9e01..0e9d4904 100644
--- a/search/Sta.cc
+++ b/search/Sta.cc
@@ -2803,42 +2803,49 @@ Sta::vertexWorstSlackPath(Vertex *vertex,
}
Arrival
-Sta::vertexArrival(Vertex *vertex,
- const MinMax *min_max)
+Sta::pinArrival(const Pin *pin,
+ const RiseFall *rf,
+ const MinMax *min_max)
{
- searchPreamble();
- search_->findArrivals(vertex->level());
- Arrival arrival = min_max->initValue();
- VertexPathIterator path_iter(vertex, this);
- while (path_iter.hasNext()) {
- Path *path = path_iter.next();
- const Arrival &path_arrival = path->arrival(this);
- ClkInfo *clk_info = path->clkInfo(search_);
- if (path->minMax(this) == min_max
- && !clk_info->isGenClkSrcPath()
- && delayGreater(path->arrival(this), arrival, min_max, this))
- arrival = path_arrival;
+ Vertex *vertex, *bidirect_vertex;
+ graph_->pinVertices(pin, vertex, bidirect_vertex);
+ Arrival arrival;
+ if (vertex)
+ arrival = vertexArrival(vertex, rf, clk_edge_wildcard, nullptr, min_max);
+ if (bidirect_vertex) {
+ Arrival arrival1 = vertexArrival(bidirect_vertex, rf, clk_edge_wildcard,
+ nullptr, min_max);
+ arrival = min_max->minMax(arrival, arrival1);
}
return arrival;
}
+Arrival
+Sta::vertexArrival(Vertex *vertex,
+ const MinMax *min_max)
+{
+ return vertexArrival(vertex, nullptr, nullptr, nullptr, min_max);
+}
+
Arrival
Sta::vertexArrival(Vertex *vertex,
const RiseFall *rf,
const PathAnalysisPt *path_ap)
{
- return vertexArrival(vertex, rf, clk_edge_wildcard, path_ap);
+ return vertexArrival(vertex, rf, clk_edge_wildcard, path_ap, nullptr);
}
Arrival
Sta::vertexArrival(Vertex *vertex,
const RiseFall *rf,
const ClockEdge *clk_edge,
- const PathAnalysisPt *path_ap)
+ const PathAnalysisPt *path_ap,
+ const MinMax *min_max)
{
searchPreamble();
search_->findArrivals(vertex->level());
- const MinMax *min_max = path_ap->pathMinMax();
+ if (min_max == nullptr)
+ min_max = path_ap->pathMinMax();
Arrival arrival = min_max->initValue();
VertexPathIterator path_iter(vertex, rf, path_ap, this);
while (path_iter.hasNext()) {
diff --git a/search/WritePathSpice.cc b/search/WritePathSpice.cc
index bba79426..97caf9ac 100644
--- a/search/WritePathSpice.cc
+++ b/search/WritePathSpice.cc
@@ -48,6 +48,8 @@ namespace sta {
using std::string;
using std::ofstream;
using std::ifstream;
+using std::max;
+using std::set;
typedef Map CellSpicePortNames;
typedef int Stage;
@@ -79,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,
@@ -98,8 +100,8 @@ private:
DcalcAPIndex dcalc_ap_index);
void writeStageParasitics(Stage stage);
void writeSubckts();
- void findPathCellnames(// Return values.
- StringSet &path_cell_names);
+ set findPathCellnames();
+ void findPathCellSubckts(set &path_cell_names);
void recordSpicePortNames(const char *cell_name,
StringVector &tokens);
float maxTime();
@@ -135,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,
@@ -162,6 +169,7 @@ private:
int &volt_index);
float slewAxisMinValue(TimingArc *arc);
float pgPortVoltage(LibertyPgPort *pg_port);
+ void writePrintStmt();
// Stage "accessors".
//
@@ -321,6 +329,7 @@ WritePathSpice::writeSpice()
// Find subckt port names as a side-effect of writeSubckts.
writeSubckts();
writeHeader();
+ writePrintStmt();
writeStageInstances();
writeMeasureStmts();
writeInputSource();
@@ -332,6 +341,18 @@ WritePathSpice::writeSpice()
throw FileNotWritable(spice_filename_);
}
+// Use c++17 fs::path(filename).stem()
+static string
+filenameStem(const char *filename)
+{
+ string filename1 = filename;
+ const size_t last_slash_idx = filename1.find_last_of("\\/");
+ if (last_slash_idx != std::string::npos)
+ return filename1.substr(last_slash_idx + 1);
+ else
+ return filename1;
+}
+
void
WritePathSpice::writeHeader()
{
@@ -348,12 +369,25 @@ WritePathSpice::writeHeader()
float temp = pvt->temperature();
streamPrint(spice_stream_, ".temp %.1f\n", temp);
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_);
- streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_);
+ string subckt_filename_stem = filenameStem(subckt_filename_);
+ streamPrint(spice_stream_, ".include \"%s\"\n", subckt_filename_stem.c_str());
float max_time = maxTime();
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
@@ -373,9 +407,8 @@ WritePathSpice::maxTime()
}
else {
float end_slew = findSlew(path_);
- float max_time = delayAsFloat(input_slew
- + path_->arrival(this)
- + end_slew * 2) * 1.5;
+ float arrival = delayAsFloat(path_->arrival(this));
+ float max_time = input_slew / 2.0 + arrival + end_slew;
return max_time;
}
}
@@ -463,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,
@@ -928,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
@@ -1342,8 +1419,8 @@ WritePathSpice::nodeName(ParasiticNode *node)
void
WritePathSpice::writeSubckts()
{
- StringSet path_cell_names;
- findPathCellnames(path_cell_names);
+ set path_cell_names = findPathCellnames();
+ findPathCellSubckts(path_cell_names);
ifstream lib_subckts_stream(lib_subckt_filename_);
if (lib_subckts_stream.is_open()) {
@@ -1357,7 +1434,7 @@ WritePathSpice::writeSubckts()
if (tokens.size() >= 2
&& stringEqual(tokens[0].c_str(), ".subckt")) {
const char *cell_name = tokens[1].c_str();
- if (path_cell_names.hasKey(cell_name)) {
+ if (path_cell_names.find(cell_name) != path_cell_names.end()) {
subckts_stream << line << "\n";
bool found_ends = false;
while (getline(lib_subckts_stream, line)) {
@@ -1379,10 +1456,14 @@ WritePathSpice::writeSubckts()
lib_subckts_stream.close();
if (!path_cell_names.empty()) {
- report_->error(28, "The following subkcts are missing from %s",
- lib_subckt_filename_);
- for (const char *cell_name : path_cell_names)
- report_->reportLine(" %s", cell_name);
+ string missing_cells;
+ for (const string &cell_name : path_cell_names) {
+ missing_cells += "\n";
+ missing_cells += cell_name;
+ }
+ report_->error(28, "The subkct file %s is missing definitions for %s",
+ lib_subckt_filename_,
+ missing_cells.c_str());
}
}
else {
@@ -1394,10 +1475,10 @@ WritePathSpice::writeSubckts()
throw FileNotReadable(lib_subckt_filename_);
}
-void
-WritePathSpice::findPathCellnames(// Return values.
- StringSet &path_cell_names)
+set
+WritePathSpice::findPathCellnames()
{
+ set path_cell_names;
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
TimingArc *arc = stageGateArc(stage);
if (arc) {
@@ -1420,6 +1501,47 @@ WritePathSpice::findPathCellnames(// Return values.
delete pin_iter;
}
}
+ return path_cell_names;
+}
+
+// Subckts can call subckts (asap7).
+void
+WritePathSpice::findPathCellSubckts(set &path_cell_names)
+{
+ ifstream lib_subckts_stream(lib_subckt_filename_);
+ if (lib_subckts_stream.is_open()) {
+ string line;
+ while (getline(lib_subckts_stream, line)) {
+ // .subckt [args..]
+ StringVector tokens;
+ split(line, " \t", tokens);
+ if (tokens.size() >= 2
+ && stringEqual(tokens[0].c_str(), ".subckt")) {
+ const char *cell_name = tokens[1].c_str();
+ if (path_cell_names.find(cell_name) != path_cell_names.end()) {
+ // Scan the subckt definition for subckt calls.
+ string stmt;
+ while (getline(lib_subckts_stream, line)) {
+ if (line[0] == '+')
+ stmt += line.substr(1);
+ else {
+ // Process previous statement.
+ if (tolower(stmt[0]) == 'x') {
+ split(stmt, " \t", tokens);
+ string &subckt_cell = tokens[tokens.size() - 1];
+ path_cell_names.insert(subckt_cell);
+ }
+ stmt = line;
+ }
+ if (stringBeginEqual(line.c_str(), ".ends"))
+ break;
+ }
+ }
+ }
+ }
+ }
+ else
+ throw FileNotReadable(lib_subckt_filename_);
}
void
diff --git a/tcl/StaTcl.i b/tcl/StaTcl.i
index 067d34bd..1b37d6b8 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);
@@ -3749,6 +3788,14 @@ format_voltage(const char *value,
return Sta::sta()->units()->voltageUnit()->asString(value1, digits);
}
+const char *
+format_current(const char *value,
+ int digits)
+{
+ float value1 = strtof(value, nullptr);
+ return Sta::sta()->units()->currentUnit()->asString(value1, digits);
+}
+
const char *
format_power(const char *value,
int digits)
@@ -4586,17 +4633,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 +5637,9 @@ full_name()
to);
}
+TimingArcSeq &
+timing_arcs() { return self->arcs(); }
+
} // TimingArcSet methods
%extend TimingArc {
@@ -5611,6 +5650,37 @@ 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 *waveforms = gate_model->outputWaveforms();
+ if (waveforms) {
+ Table1 waveform = waveforms->voltageWaveform(in_slew, load_cap);
+ return waveform;
+ }
+ }
+ return Table1();
+}
+
+Table1
+current_waveform(float in_slew,
+ float load_cap)
+{
+ GateTableModel *gate_model = dynamic_cast(self->model());
+ if (gate_model) {
+ OutputWaveforms *waveforms = gate_model->outputWaveforms();
+ if (waveforms) {
+ Table1 waveform = waveforms->currentWaveform(in_slew, load_cap);
+ return waveform;
+ }
+ }
+ return Table1();
+}
+
} // TimingArc methods
%extend Instance {
@@ -5847,7 +5917,7 @@ arrivals_clk(const RiseFall *rf,
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge,
- path_ap)));
+ path_ap, nullptr)));
}
return arrivals;
}
@@ -5865,7 +5935,7 @@ arrivals_clk_delays(const RiseFall *rf,
clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge,
- path_ap),
+ path_ap, nullptr),
sta, digits));
}
return arrivals;
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;