Merge pull request #150 from openroadie/master

Latest OpenSTA code (fixes hang in flow tests)
This commit is contained in:
Matt Liberty 2023-03-24 13:33:27 -07:00 committed by GitHub
commit a9980ee115
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
17 changed files with 1230 additions and 587 deletions

View File

@ -52,6 +52,21 @@ See doc/OpenSTA.pdf for command documentiaton.
See doc/StaApi.txt for timing engine API documentiaton. See doc/StaApi.txt for timing engine API documentiaton.
See doc/ChangeLog.txt for changes to commands. 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 ## Build
OpenSTA is built with CMake. 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. * 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 ## 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 OpenSTA, Static Timing Analyzer
Copyright (c) 2023, Parallax Software, Inc. 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 You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. along with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -48,4 +48,15 @@ set_delay_calc_incremental_tolerance(float tol)
sta::Sta::sta()->setIncrementalDelayTolerance(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 %} // inline

View File

@ -49,6 +49,7 @@ class StaState;
class Corner; class Corner;
class Corners; class Corners;
class DcalcAnalysisPt; class DcalcAnalysisPt;
class DriverWaveform;
typedef Map<const char*, TableTemplate*, CharPtrLess> TableTemplateMap; typedef Map<const char*, TableTemplate*, CharPtrLess> TableTemplateMap;
typedef Vector<TableTemplate*> TableTemplateSeq; typedef Vector<TableTemplate*> TableTemplateSeq;
@ -77,6 +78,7 @@ typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq; typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<const char *, float, CharPtrLess> SupplyVoltageMap; typedef Map<const char *, float, CharPtrLess> SupplyVoltageMap;
typedef Map<const char *, LibertyPgPort*, CharPtrLess> LibertyPgPortMap; typedef Map<const char *, LibertyPgPort*, CharPtrLess> LibertyPgPortMap;
typedef Map<const char *, DriverWaveform*, CharPtrLess> DriverWaveformMap;
enum class ClockGateType { none, latch_posedge, latch_negedge, other }; enum class ClockGateType { none, latch_posedge, latch_negedge, other };
@ -315,6 +317,10 @@ public:
Corners *corners, Corners *corners,
Report *report); Report *report);
DriverWaveform *findDriverWaveform(const char *name);
DriverWaveform *driverWaveformDefault() { return driver_waveform_default_; }
void addDriverWaveform(DriverWaveform *driver_waveform);
protected: protected:
float degradeWireSlew(const LibertyCell *cell, float degradeWireSlew(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
@ -363,6 +369,9 @@ protected:
OcvDerateMap ocv_derate_map_; OcvDerateMap ocv_derate_map_;
SupplyVoltageMap supply_voltage_map_; SupplyVoltageMap supply_voltage_map_;
LibertyCellSeq *buffers_; LibertyCellSeq *buffers_;
DriverWaveformMap driver_waveform_map_;
// Unnamed driver waveform.
DriverWaveform *driver_waveform_default_;
static constexpr float input_threshold_default_ = .5; static constexpr float input_threshold_default_ = .5;
static constexpr float output_threshold_default_ = .5; static constexpr float output_threshold_default_ = .5;
@ -780,6 +789,9 @@ public:
void setRelatedPowerPin(const char *related_power_pin); void setRelatedPowerPin(const char *related_power_pin);
ReceiverModelPtr receiverModel() const { return receiver_model_; } ReceiverModelPtr receiverModel() const { return receiver_model_; }
void setReceiverModel(ReceiverModelPtr 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, static bool equiv(const LibertyPort *port1,
const LibertyPort *port2); const LibertyPort *port2);
@ -820,6 +832,7 @@ protected:
const char *related_power_pin_; const char *related_power_pin_;
Vector<LibertyPort*> corner_ports_; Vector<LibertyPort*> corner_ports_;
ReceiverModelPtr receiver_model_; ReceiverModelPtr receiver_model_;
DriverWaveform *driver_waveform_[RiseFall::index_count];
unsigned int min_pulse_width_exists_:RiseFall::index_count; unsigned int min_pulse_width_exists_:RiseFall::index_count;
bool min_period_exists_:1; bool min_period_exists_:1;

View File

@ -999,13 +999,17 @@ public:
Arrival vertexArrival(Vertex *vertex, Arrival vertexArrival(Vertex *vertex,
const RiseFall *rf, const RiseFall *rf,
const ClockEdge *clk_edge, const ClockEdge *clk_edge,
const PathAnalysisPt *path_ap); const PathAnalysisPt *path_ap,
const MinMax *min_max);
// Min/max across all clock tags. // Min/max across all clock tags.
Arrival vertexArrival(Vertex *vertex, Arrival vertexArrival(Vertex *vertex,
const RiseFall *rf, const RiseFall *rf,
const PathAnalysisPt *path_ap); const PathAnalysisPt *path_ap);
Arrival vertexArrival(Vertex *vertex, Arrival vertexArrival(Vertex *vertex,
const MinMax *min_max); const MinMax *min_max);
Arrival pinArrival(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max);
Required vertexRequired(Vertex *vertex, Required vertexRequired(Vertex *vertex,
const MinMax *min_max); const MinMax *min_max);
Required vertexRequired(Vertex *vertex, Required vertexRequired(Vertex *vertex,

View File

@ -33,12 +33,12 @@ class Unit;
class Units; class Units;
class Report; class Report;
class Table; class Table;
class OutputCurrent; class OutputWaveforms;
class OutputCurrentWaveform; class Table1;
typedef Vector<float> FloatSeq; typedef Vector<float> FloatSeq;
typedef Vector<FloatSeq*> FloatTable; typedef Vector<FloatSeq*> FloatTable;
typedef Vector<OutputCurrentWaveform*> OutputCurrentWaveformSeq; typedef Vector<Table1*> Table1Seq;
TableAxisVariable TableAxisVariable
stringTableAxisVariable(const char *variable); stringTableAxisVariable(const char *variable);
@ -56,7 +56,7 @@ public:
TableModel *slew_model, TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count], TableModel *slew_sigma_models[EarlyLate::index_count],
ReceiverModelPtr receiver_model, ReceiverModelPtr receiver_model,
OutputCurrent *output_current); OutputWaveforms *output_waveforms);
virtual ~GateTableModel(); virtual ~GateTableModel();
virtual void gateDelay(const LibertyCell *cell, virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
@ -80,6 +80,8 @@ public:
const TableModel *delayModel() const { return delay_model_; } const TableModel *delayModel() const { return delay_model_; }
const TableModel *slewModel() const { return slew_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. // Check the axes before making the model.
// Return true if the model axes are supported. // Return true if the model axes are supported.
static bool checkAxes(const TablePtr table); static bool checkAxes(const TablePtr table);
@ -127,7 +129,7 @@ protected:
TableModel *slew_model_; TableModel *slew_model_;
TableModel *slew_sigma_models_[EarlyLate::index_count]; TableModel *slew_sigma_models_[EarlyLate::index_count];
ReceiverModelPtr receiver_model_; ReceiverModelPtr receiver_model_;
OutputCurrent *output_current_; OutputWaveforms *output_waveforms_;
}; };
class CheckTableModel : public CheckTimingModel class CheckTableModel : public CheckTimingModel
@ -273,16 +275,16 @@ public:
size_t axis_idx2, size_t axis_idx2,
size_t axis_idx3) const = 0; size_t axis_idx3) const = 0;
// Table interpolated lookup. // Table interpolated lookup.
virtual float findValue(float value1, virtual float findValue(float axis_value1,
float value2, float axis_value2,
float value3) const = 0; float axis_value3) const = 0;
// Table interpolated lookup with scale factor. // Table interpolated lookup with scale factor.
float findValue(const LibertyLibrary *library, float findValue(const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float axis_value1,
float value2, float axis_value2,
float value3) const; float axis_value3) const;
virtual void reportValue(const char *result_name, virtual void reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
@ -304,12 +306,12 @@ class Table0 : public Table
public: public:
Table0(float value); Table0(float value);
virtual int order() const { return 0; } virtual int order() const { return 0; }
virtual float value(size_t index1, virtual float value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const; size_t axis_index3) const;
virtual float findValue(float value1, virtual float findValue(float axis_value1,
float value2, float axis_value2,
float value3) const; float axis_value3) const;
virtual void reportValue(const char *result_name, virtual void reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
@ -333,15 +335,25 @@ private:
class Table1 : public Table class Table1 : public Table
{ {
public: public:
Table1();
Table1(FloatSeq *values, Table1(FloatSeq *values,
TableAxisPtr axis1); TableAxisPtr axis1);
virtual ~Table1(); virtual ~Table1();
Table1(Table1 &&table);
Table1 &operator= (Table1 &&table);
virtual int order() const { return 1; } virtual int order() const { return 1; }
virtual TableAxisPtr axis1() const { return axis1_; } virtual TableAxisPtr axis1() const { return axis1_; }
virtual float value(size_t index1, virtual float value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const; size_t axis_index3) const;
float value(size_t index1) 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, virtual float findValue(float value1,
float value2, float value2,
float value3) const; float value3) const;
@ -358,6 +370,7 @@ public:
string *result) const; string *result) const;
virtual void report(const Units *units, virtual void report(const Units *units,
Report *report) const; Report *report) const;
FloatSeq *values() const { return values_; }
using Table::findValue; using Table::findValue;
private: private:
@ -376,14 +389,14 @@ public:
virtual int order() const { return 2; } virtual int order() const { return 2; }
TableAxisPtr axis1() const { return axis1_; } TableAxisPtr axis1() const { return axis1_; }
TableAxisPtr axis2() const { return axis2_; } TableAxisPtr axis2() const { return axis2_; }
virtual float value(size_t index1, virtual float value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const; size_t axis_index3) const;
float value(size_t index1, float value(size_t axis_index1,
size_t index2) const; size_t axis_index2) const;
virtual float findValue(float value1, virtual float findValue(float axis_value1,
float value2, float axis_value2,
float value3) const; float axis_value3) const;
FloatTable *values3() { return values_; } FloatTable *values3() { return values_; }
virtual void reportValue(const char *result_name, virtual void reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyLibrary *library,
@ -419,12 +432,12 @@ public:
virtual ~Table3() {} virtual ~Table3() {}
virtual int order() const { return 3; } virtual int order() const { return 3; }
TableAxisPtr axis3() const { return axis3_; } TableAxisPtr axis3() const { return axis3_; }
virtual float value(size_t index1, virtual float value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const; size_t axis_index3) const;
virtual float findValue(float value1, virtual float findValue(float axis_value1,
float value2, float axis_value2,
float value3) const; float axis_value3) const;
virtual void reportValue(const char *result_name, virtual void reportValue(const char *result_name,
const LibertyLibrary *library, const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
@ -462,6 +475,8 @@ public:
size_t &index, size_t &index,
bool &exists) const; bool &exists) const;
FloatSeq *values() const { return values_; } FloatSeq *values() const { return values_; }
float min() const { return (*values_)[0]; }
float max() const { return (*values_)[values_->size() - 1]; }
private: private:
TableAxisVariable variable_; TableAxisVariable variable_;
@ -484,63 +499,47 @@ private:
TableModel *capacitance_models_[2][RiseFall::index_count]; TableModel *capacitance_models_[2][RiseFall::index_count];
}; };
class OutputCurrentWaveform // Two dimensional (slew/cap) table of one dimensional time/current tables.
class OutputWaveforms
{ {
public: public:
OutputCurrentWaveform(float axis_value1, OutputWaveforms(TableAxisPtr slew_axis,
float axis_value2, TableAxisPtr cap_axis,
TableAxisPtr axis, Table1Seq &current_waveforms,
Table1 *currents, Table1 *ref_times);
float reference_time); ~OutputWaveforms();
~OutputCurrentWaveform(); Table1 voltageWaveform(float in_slew,
float axisValue1() const { return axis_value1_; } float load_cap);
float axisValue2() const { return axis_value2_; } Table1 currentWaveform(float slew,
TableAxisPtr axis() const { return axis_; } float cap);
Table1 *currents() const { return currents_; } float referenceTime(float slew);
float referenceTime() const { return reference_time_; }
void reportWaveform(const Units *units,
int digits,
string *result);
static bool checkAxes(TableTemplate *tbl_template); 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<OutputCurrentWaveform*> &waveforms);
~OutputCurrent();
void reportWaveform(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
int digits,
string *result) const;
private: private:
void findAxisValues(float in_slew, Table1 *voltageWaveform(size_t wave_index,
float load_cap, float cap);
// Return values.
float &axis_value1,
float &axis_value2) const;
float axisValue(TableAxisPtr axis,
float in_slew,
float load_cap) const;
// Row. // Row.
TableAxisPtr axis1_; TableAxisPtr slew_axis_;
// Column. // Column.
TableAxisPtr axis2_; TableAxisPtr cap_axis_;
OutputCurrentWaveformSeq waveforms_; 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 } // namespace

View File

@ -82,7 +82,8 @@ LibertyLibrary::LibertyLibrary(const char *name,
default_operating_conditions_(nullptr), default_operating_conditions_(nullptr),
ocv_arc_depth_(0.0), ocv_arc_depth_(0.0),
default_ocv_derate_(nullptr), default_ocv_derate_(nullptr),
buffers_(nullptr) buffers_(nullptr),
driver_waveform_default_(nullptr)
{ {
// Scalar templates are builtin. // Scalar templates are builtin.
for (int i = 0; i != table_template_type_count; i++) { 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); 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) : LibertyCellIterator::LibertyCellIterator(const LibertyLibrary *library) :
@ -1920,6 +1938,7 @@ LibertyPort::LibertyPort(LibertyCell *cell,
related_ground_pin_(nullptr), related_ground_pin_(nullptr),
related_power_pin_(nullptr), related_power_pin_(nullptr),
receiver_model_(nullptr), receiver_model_(nullptr),
driver_waveform_{nullptr, nullptr},
min_pulse_width_exists_(false), min_pulse_width_exists_(false),
min_period_exists_(false), min_period_exists_(false),
is_clk_(false), is_clk_(false),
@ -2519,6 +2538,19 @@ portLibertyToSta(const char *port_name)
return sta_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 LibertyPortSeq

View File

@ -501,10 +501,14 @@ LibertyReader::defineVisitors()
defineGroupVisitor("output_current_fall", defineGroupVisitor("output_current_fall",
&LibertyReader::beginOutputCurrentFall, &LibertyReader::beginOutputCurrentFall,
&LibertyReader::endOutputCurrentRiseFall); &LibertyReader::endOutputCurrentRiseFall);
defineGroupVisitor("vector", defineGroupVisitor("vector", &LibertyReader::beginVector, &LibertyReader::endVector);
&LibertyReader::beginVector,
&LibertyReader::endVector);
defineAttrVisitor("reference_time", &LibertyReader::visitReferenceTime); 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 void
@ -2283,7 +2287,7 @@ TimingGroup::makeTableModels(LibertyReader *reader)
transition, transition,
slew_sigma_[rf_index], slew_sigma_[rf_index],
receiver_model_, receiver_model_,
output_current_[rf_index])); output_waveforms_[rf_index]));
TimingType timing_type = attrs_->timingType(); TimingType timing_type = attrs_->timingType();
if (timing_type == TimingType::clear if (timing_type == TimingType::clear
|| timing_type == TimingType::combinational || timing_type == TimingType::combinational
@ -2480,8 +2484,10 @@ void
LibertyReader::beginOutputCurrent(RiseFall *rf, LibertyReader::beginOutputCurrent(RiseFall *rf,
LibertyGroup *group) LibertyGroup *group)
{ {
if (timing_) if (timing_) {
rf_ = rf; rf_ = rf;
output_currents_.clear();
}
else else
libWarn(907, group, "output_current_%s group not in timing group.", libWarn(907, group, "output_current_%s group not in timing group.",
rf->name()); rf->name());
@ -2490,54 +2496,59 @@ LibertyReader::beginOutputCurrent(RiseFall *rf,
void void
LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group) LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
{ {
Set<float> axis_set1, axis_set2; Set<float> slew_set, cap_set;
FloatSeq *axis_values1 = new FloatSeq; FloatSeq *slew_values = new FloatSeq;
FloatSeq *axis_values2 = new FloatSeq; FloatSeq *cap_values = new FloatSeq;
for (OutputCurrentWaveform *waveform : output_current_waveforms_) { for (OutputWaveform *waveform : output_currents_) {
float axis_value1 = waveform->axisValue1(); float slew = waveform->slew();
if (!axis_set1.hasKey(axis_value1)) { if (!slew_set.hasKey(slew)) {
axis_set1.insert(axis_value1); slew_set.insert(slew);
axis_values1->push_back(axis_value1); slew_values->push_back(slew);
} }
float axis_value2 = waveform->axisValue2(); float cap = waveform->cap();
if (!axis_set2.hasKey(axis_value2)) { if (!cap_set.hasKey(cap)) {
axis_set2.insert(axis_value2); cap_set.insert(cap);
axis_values2->push_back(axis_value2); cap_values->push_back(cap);
} }
} }
sort(axis_values1, std::less<float>()); sort(slew_values, std::less<float>());
sort(axis_values2, std::less<float>()); sort(cap_values, std::less<float>());
TableAxisPtr axis1 = std::make_shared<TableAxis>(axis_[0]->variable(), TableAxisPtr slew_axis = make_shared<TableAxis>(TableAxisVariable::input_net_transition,
axis_values1); slew_values);
TableAxisPtr axis2 = std::make_shared<TableAxis>(axis_[1]->variable(), TableAxisPtr cap_axis = make_shared<TableAxis>(TableAxisVariable::total_output_net_capacitance,
axis_values2); cap_values);
Vector<OutputCurrentWaveform*> waveforms(axis1->size() * axis2->size()); FloatSeq *ref_times = new FloatSeq(slew_values->size());
for (OutputCurrentWaveform *waveform : output_current_waveforms_) { Table1Seq current_waveforms(slew_axis->size() * cap_axis->size());
size_t index1, index2; for (OutputWaveform *waveform : output_currents_) {
bool exists1, exists2; size_t slew_index, cap_index;
axis1->findAxisIndex(waveform->axisValue1(), index1, exists1); bool slew_exists, cap_exists;
axis2->findAxisIndex(waveform->axisValue2(), index2, exists2); slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
if (exists1 && exists2) { cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
size_t index = index1 * axis2->size() + index2; if (slew_exists && cap_exists) {
waveforms[index] = waveform; size_t index = slew_index * cap_axis->size() + cap_index;
current_waveforms[index] = waveform->currents();
(*ref_times)[slew_index] = waveform->referenceTime();
} }
else else
libWarn(913, group, "output current waveform %.2e %.2e not found.", libWarn(913, group, "output current waveform %.2e %.2e not found.",
waveform->axisValue1(), waveform->slew(),
waveform->axisValue2()); waveform->cap());
} }
OutputCurrent *output_current = new OutputCurrent(axis1, axis2, waveforms); Table1 *ref_time_tbl = new Table1(ref_times, slew_axis);
timing_->setOutputCurrent(rf_, output_current); OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis,
current_waveforms,
ref_time_tbl);
timing_->setOutputWaveforms(rf_, output_current);
} }
void void
LibertyReader::beginVector(LibertyGroup *group) LibertyReader::beginVector(LibertyGroup *group)
{ {
if (timing_) { if (timing_) {
beginTable(group, TableTemplateType::output_current, 1.0); beginTable(group, TableTemplateType::output_current, current_scale_);
scale_factor_type_ = ScaleFactorType::unknown; scale_factor_type_ = ScaleFactorType::unknown;
reference_time_exists_ = false; reference_time_exists_ = false;
if (!OutputCurrentWaveform::checkAxes(tbl_template_)) if (tbl_template_ && !OutputWaveforms::checkAxes(tbl_template_))
libWarn(118, group, "unsupported model axis."); libWarn(118, group, "unsupported model axis.");
} }
} }
@ -2546,32 +2557,41 @@ void
LibertyReader::visitReferenceTime(LibertyAttr *attr) LibertyReader::visitReferenceTime(LibertyAttr *attr)
{ {
getAttrFloat(attr, reference_time_, reference_time_exists_); getAttrFloat(attr, reference_time_, reference_time_exists_);
if (reference_time_exists_)
reference_time_ *= time_scale_;
} }
void void
LibertyReader::endVector(LibertyGroup *group) LibertyReader::endVector(LibertyGroup *group)
{ {
if (timing_) { if (timing_ && tbl_template_) {
FloatSeq *axis_values1 = axis_values_[0]; FloatSeq *slew_values = axis_values_[0];
FloatSeq *axis_values2 = axis_values_[1]; FloatSeq *cap_values = axis_values_[1];
if (axis_values1->size() == 1 && axis_values2->size() == 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. // Convert 1x1xN Table3 to Table1.
float axis_value1 = (*axis_values1)[0]; float slew = (*slew_values)[0];
float axis_value2 = (*axis_values2)[0]; float cap = (*cap_values)[0];
Table3 *table3 = dynamic_cast<Table3*>(table_.get()); Table3 *table3 = dynamic_cast<Table3*>(table_.get());
FloatTable *values3 = table3->values3(); FloatTable *values3 = table3->values3();
// Steal the values. // Steal the values.
FloatSeq *values = (*values3)[0]; FloatSeq *values = (*values3)[0];
(*values3)[0] = nullptr; (*values3)[0] = nullptr;
Table1 *table1 = new Table1(values, axis_[2]); Table1 *table1 = new Table1(values, axis_[2]);
OutputCurrentWaveform *waveform = new OutputCurrentWaveform(axis_value1, OutputWaveform *waveform = new OutputWaveform(slew, cap, table1, reference_time_);
axis_value2, output_currents_.push_back(waveform);
axis_[2], table1,
reference_time_);
output_current_waveforms_.push_back(waveform);
} }
else 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_) if (!reference_time_exists_)
libWarn(908, group->line(), "vector reference_time not found."); libWarn(908, group->line(), "vector reference_time not found.");
reference_time_exists_ = false; 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 void
LibertyReader::makeInternalPowers(LibertyPort *port, LibertyReader::makeInternalPowers(LibertyPort *port,
InternalPowerGroup *power_group) InternalPowerGroup *power_group)
@ -5365,7 +5447,7 @@ TimingGroup::TimingGroup(int line) :
intrinsic_exists_[rf_index] = false; intrinsic_exists_[rf_index] = false;
resistance_[rf_index] = 0.0F; resistance_[rf_index] = 0.0F;
resistance_exists_[rf_index] = false; resistance_exists_[rf_index] = false;
output_current_[rf_index] = nullptr; output_waveforms_[rf_index] = nullptr;
for (auto el_index : EarlyLate::rangeIndex()) { for (auto el_index : EarlyLate::rangeIndex()) {
delay_sigma_[rf_index][el_index] = nullptr; delay_sigma_[rf_index][el_index] = nullptr;
@ -5496,17 +5578,17 @@ TimingGroup::setReceiverModel(ReceiverModelPtr receiver_model)
receiver_model_ = receiver_model; receiver_model_ = receiver_model;
} }
OutputCurrent * OutputWaveforms *
TimingGroup::outputCurrent(RiseFall *rf) TimingGroup::outputWaveforms(RiseFall *rf)
{ {
return output_current_[rf->index()]; return output_waveforms_[rf->index()];
} }
void void
TimingGroup::setOutputCurrent(RiseFall *rf, TimingGroup::setOutputWaveforms(RiseFall *rf,
OutputCurrent *output_current) 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; 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 } // namespace

View File

@ -45,6 +45,7 @@ class LeakagePowerGroup;
class PortNameBitIterator; class PortNameBitIterator;
class TimingArcBuilder; class TimingArcBuilder;
class LibertyAttr; class LibertyAttr;
class OutputWaveform;
typedef void (LibertyReader::*LibraryAttrVisitor)(LibertyAttr *attr); typedef void (LibertyReader::*LibraryAttrVisitor)(LibertyAttr *attr);
typedef void (LibertyReader::*LibraryGroupVisitor)(LibertyGroup *group); typedef void (LibertyReader::*LibraryGroupVisitor)(LibertyGroup *group);
@ -57,7 +58,7 @@ typedef Vector<TimingGroup*> TimingGroupSeq;
typedef Vector<InternalPowerGroup*> InternalPowerGroupSeq; typedef Vector<InternalPowerGroup*> InternalPowerGroupSeq;
typedef Vector<LeakagePowerGroup*> LeakagePowerGroupSeq; typedef Vector<LeakagePowerGroup*> LeakagePowerGroupSeq;
typedef void (LibertyPort::*LibertyPortBoolSetter)(bool value); typedef void (LibertyPort::*LibertyPortBoolSetter)(bool value);
typedef Vector<OutputCurrentWaveform*> OutputCurrentWaveformSeq; typedef Vector<OutputWaveform*> OutputWaveformSeq;
class LibertyReader : public LibertyGroupVisitor class LibertyReader : public LibertyGroupVisitor
{ {
@ -443,6 +444,15 @@ public:
void endVector(LibertyGroup *group); void endVector(LibertyGroup *group);
void visitReferenceTime(LibertyAttr *attr); 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. // Visitors for derived classes to overload.
virtual void beginGroup1(LibertyGroup *) {} virtual void beginGroup1(LibertyGroup *) {}
virtual void beginGroup2(LibertyGroup *) {} virtual void beginGroup2(LibertyGroup *) {}
@ -617,10 +627,11 @@ protected:
bool have_resistance_unit_; bool have_resistance_unit_;
const char *default_operating_condition_; const char *default_operating_condition_;
ReceiverModelPtr receiver_model_; ReceiverModelPtr receiver_model_;
OutputCurrentWaveformSeq output_current_waveforms_; OutputWaveformSeq output_currents_;
OutputCurrent *output_current_; OutputWaveforms *output_waveforms_;
float reference_time_; float reference_time_;
bool reference_time_exists_; bool reference_time_exists_;
const char *driver_waveform_name_;
static constexpr char escape_ = '\\'; static constexpr char escape_ = '\\';
@ -783,9 +794,9 @@ public:
EarlyLate *early_late, EarlyLate *early_late,
TableModel *model); TableModel *model);
void setReceiverModel(ReceiverModelPtr receiver_model); void setReceiverModel(ReceiverModelPtr receiver_model);
OutputCurrent *outputCurrent(RiseFall *rf); OutputWaveforms *outputWaveforms(RiseFall *rf);
void setOutputCurrent(RiseFall *rf, void setOutputWaveforms(RiseFall *rf,
OutputCurrent *output_current); OutputWaveforms *output_current);
protected: protected:
void makeLinearModels(LibertyLibrary *library); void makeLinearModels(LibertyLibrary *library);
@ -803,7 +814,7 @@ protected:
TableModel *transition_[RiseFall::index_count]; TableModel *transition_[RiseFall::index_count];
TableModel *delay_sigma_[RiseFall::index_count][EarlyLate::index_count]; TableModel *delay_sigma_[RiseFall::index_count][EarlyLate::index_count];
TableModel *slew_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_; ReceiverModelPtr receiver_model_;
}; };
@ -858,4 +869,24 @@ protected:
unsigned size_; 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 } // namespace

View File

@ -26,6 +26,10 @@
namespace sta { namespace sta {
using std::string; using std::string;
using std::min;
using std::max;
using std::abs;
using std::make_shared;
static void static void
deleteSigmaModels(TableModel *models[EarlyLate::index_count]); deleteSigmaModels(TableModel *models[EarlyLate::index_count]);
@ -43,15 +47,19 @@ GateTableModel::GateTableModel(TableModel *delay_model,
TableModel *slew_model, TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count], TableModel *slew_sigma_models[EarlyLate::index_count],
ReceiverModelPtr receiver_model, ReceiverModelPtr receiver_model,
OutputCurrent *output_current) : OutputWaveforms *output_waveforms) :
delay_model_(delay_model), delay_model_(delay_model),
slew_model_(slew_model), slew_model_(slew_model),
receiver_model_(receiver_model), receiver_model_(receiver_model),
output_current_(output_current) output_waveforms_(output_waveforms)
{ {
for (auto el_index : EarlyLate::rangeIndex()) { for (auto el_index : EarlyLate::rangeIndex()) {
slew_sigma_models_[el_index] = slew_sigma_models ? slew_sigma_models[el_index] : nullptr; slew_sigma_models_[el_index] = slew_sigma_models
delay_sigma_models_[el_index] = delay_sigma_models ? delay_sigma_models[el_index] : nullptr; ? 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 delay_model_;
delete slew_model_; delete slew_model_;
delete output_current_; delete output_waveforms_;
deleteSigmaModels(slew_sigma_models_); deleteSigmaModels(slew_sigma_models_);
deleteSigmaModels(delay_sigma_models_); deleteSigmaModels(delay_sigma_models_);
} }
@ -165,8 +173,6 @@ GateTableModel::reportGateDelay(const LibertyCell *cell,
load_cap, related_out_cap); load_cap, related_out_cap);
if (drvr_slew < 0.0) if (drvr_slew < 0.0)
*result += "Negative slew clipped to 0.0\n"; *result += "Negative slew clipped to 0.0\n";
if (output_current_)
output_current_->reportWaveform(cell, pvt, in_slew, load_cap, digits, result);
} }
void void
@ -651,22 +657,22 @@ TableModel::axis3() const
} }
float float
TableModel::value(size_t index1, TableModel::value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const size_t axis_index3) const
{ {
return table_->value(index1, index2, index3); return table_->value(axis_index1, axis_index2, axis_index3);
} }
float float
TableModel::findValue(const LibertyLibrary *library, TableModel::findValue(const LibertyLibrary *library,
const LibertyCell *cell, const LibertyCell *cell,
const Pvt *pvt, const Pvt *pvt,
float value1, float axis_value1,
float value2, float axis_value2,
float value3) const float axis_value3) const
{ {
return table_->findValue(value1, value2, value3) return table_->findValue(axis_value1, axis_value2, axis_value3)
* scaleFactor(library, cell, pvt); * scaleFactor(library, cell, pvt);
} }
@ -801,6 +807,13 @@ Table0::report(const Units *units,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
Table1::Table1() :
Table(),
values_(nullptr),
axis1_(nullptr)
{
}
Table1::Table1(FloatSeq *values, Table1::Table1(FloatSeq *values,
TableAxisPtr axis1) : TableAxisPtr axis1) :
Table(), 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() Table1::~Table1()
{ {
delete values_; delete values_;
} }
Table1 &
Table1::operator=(Table1 &&table)
{
values_ = table.values_;
axis1_ = table.axis1_;
table.values_ = nullptr;
table.axis1_ = nullptr;
return *this;
}
float float
Table1::value(size_t index1, Table1::value(size_t axis_index1,
size_t, size_t,
size_t) const size_t) const
{ {
return value(index1); return value(axis_index1);
} }
float float
Table1::value(size_t index1) const Table1::value(size_t axis_index1) const
{ {
return (*values_)[index1]; return (*values_)[axis_index1];
} }
float float
Table1::findValue(float value1, Table1::findValue(float axis_value1,
float, float,
float) const float) const
{ {
if (axis1_->size() == 1) return findValue(axis_value1);
return value(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 { else {
size_t index1 = axis1_->findAxisIndex(value1); size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
float x1 = value1; float x1 = axis_value1;
float x1l = axis1_->axisValue(index1); float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(index1 + 1); float x1u = axis1_->axisValue(axis_index1 + 1);
float y1 = value(index1); float y1 = this->value(axis_index1);
float y2 = value(index1 + 1); float y2 = this->value(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l); 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 float
Table2::value(size_t index1, Table2::value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t) const size_t) const
{ {
return value(index1, index2); return value(axis_index1, axis_index2);
} }
float float
Table2::value(size_t index1, Table2::value(size_t axis_index1,
size_t index2) const size_t axis_index2) const
{ {
FloatSeq *row = (*values_)[index1]; FloatSeq *row = (*values_)[axis_index1];
return (*row)[index2]; return (*row)[axis_index2];
} }
// Bilinear Interpolation. // Bilinear Interpolation.
float float
Table2::findValue(float value1, Table2::findValue(float axis_value1,
float value2, float axis_value2,
float) const float) const
{ {
size_t size1 = axis1_->size(); size_t size1 = axis1_->size();
@ -965,13 +1031,13 @@ Table2::findValue(float value1,
if (size2 == 1) if (size2 == 1)
return value(0, 0); return value(0, 0);
else { else {
size_t index2 = axis2_->findAxisIndex(value2); size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
float x2 = value2; float x2 = axis_value2;
float y00 = value(0, index2); float y00 = value(0, axis_index2);
float x2l = axis2_->axisValue(index2); float x2l = axis2_->axisValue(axis_index2);
float x2u = axis2_->axisValue(index2 + 1); float x2u = axis2_->axisValue(axis_index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l); float dx2 = (x2 - x2l) / (x2u - x2l);
float y01 = value(0, index2 + 1); float y01 = value(0, axis_index2 + 1);
float tbl_value float tbl_value
= (1 - dx2) * y00 = (1 - dx2) * y00
+ dx2 * y01; + dx2 * y01;
@ -979,33 +1045,33 @@ Table2::findValue(float value1,
} }
} }
else if (size2 == 1) { else if (size2 == 1) {
size_t index1 = axis1_->findAxisIndex(value1); size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
float x1 = value1; float x1 = axis_value1;
float y00 = value(index1, 0); float y00 = value(axis_index1, 0);
float x1l = axis1_->axisValue(index1); float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(index1 + 1); float x1u = axis1_->axisValue(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l); float dx1 = (x1 - x1l) / (x1u - x1l);
float y10 = value(index1 + 1, 0); float y10 = value(axis_index1 + 1, 0);
float tbl_value float tbl_value
= (1 - dx1) * y00 = (1 - dx1) * y00
+ dx1 * y10; + dx1 * y10;
return tbl_value; return tbl_value;
} }
else { else {
size_t index1 = axis1_->findAxisIndex(value1); size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
size_t index2 = axis2_->findAxisIndex(value2); size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
float x1 = value1; float x1 = axis_value1;
float x2 = value2; float x2 = axis_value2;
float y00 = value(index1, index2); float y00 = value(axis_index1, axis_index2);
float x1l = axis1_->axisValue(index1); float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(index1 + 1); float x1u = axis1_->axisValue(axis_index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l); float dx1 = (x1 - x1l) / (x1u - x1l);
float y10 = value(index1 + 1, index2); float y10 = value(axis_index1 + 1, axis_index2);
float y11 = value(index1 + 1, index2 + 1); float y11 = value(axis_index1 + 1, axis_index2 + 1);
float x2l = axis2_->axisValue(index2); float x2l = axis2_->axisValue(axis_index2);
float x2u = axis2_->axisValue(index2 + 1); float x2u = axis2_->axisValue(axis_index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l); float dx2 = (x2 - x2l) / (x2u - x2l);
float y01 = value(index1, index2 + 1); float y01 = value(axis_index1, axis_index2 + 1);
float tbl_value float tbl_value
= (1 - dx1) * (1 - dx2) * y00 = (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10 + dx1 * (1 - dx2) * y10
@ -1123,30 +1189,30 @@ Table3::Table3(FloatTable *values,
} }
float float
Table3::value(size_t index1, Table3::value(size_t axis_index1,
size_t index2, size_t axis_index2,
size_t index3) const size_t axis_index3) const
{ {
size_t row = index1 * axis2_->size() + index2; size_t row = axis_index1 * axis2_->size() + axis_index2;
return values_->operator[](row)->operator[](index3); return values_->operator[](row)->operator[](axis_index3);
} }
// Bilinear Interpolation. // Bilinear Interpolation.
float float
Table3::findValue(float value1, Table3::findValue(float axis_value1,
float value2, float axis_value2,
float value3) const float axis_value3) const
{ {
size_t index1 = axis1_->findAxisIndex(value1); size_t axis_index1 = axis1_->findAxisIndex(axis_value1);
size_t index2 = axis2_->findAxisIndex(value2); size_t axis_index2 = axis2_->findAxisIndex(axis_value2);
size_t index3 = axis3_->findAxisIndex(value3); size_t axis_index3 = axis3_->findAxisIndex(axis_value3);
float x1 = value1; float x1 = axis_value1;
float x2 = value2; float x2 = axis_value2;
float x3 = value3; float x3 = axis_value3;
float dx1 = 0.0; float dx1 = 0.0;
float dx2 = 0.0; float dx2 = 0.0;
float dx3 = 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 y001 = 0.0;
float y010 = 0.0; float y010 = 0.0;
float y011 = 0.0; float y011 = 0.0;
@ -1156,31 +1222,31 @@ Table3::findValue(float value1,
float y111 = 0.0; float y111 = 0.0;
if (axis1_->size() != 1) { if (axis1_->size() != 1) {
float x1l = axis1_->axisValue(index1); float x1l = axis1_->axisValue(axis_index1);
float x1u = axis1_->axisValue(index1 + 1); float x1u = axis1_->axisValue(axis_index1 + 1);
dx1 = (x1 - x1l) / (x1u - x1l); dx1 = (x1 - x1l) / (x1u - x1l);
y100 = value(index1 + 1, index2, index3); y100 = value(axis_index1 + 1, axis_index2, axis_index3);
if (axis3_->size() != 1) 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) { 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) 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) { if (axis2_->size() != 1) {
float x2l = axis2_->axisValue(index2); float x2l = axis2_->axisValue(axis_index2);
float x2u = axis2_->axisValue(index2 + 1); float x2u = axis2_->axisValue(axis_index2 + 1);
dx2 = (x2 - x2l) / (x2u - x2l); dx2 = (x2 - x2l) / (x2u - x2l);
y010 = value(index1, index2 + 1, index3); y010 = value(axis_index1, axis_index2 + 1, axis_index3);
if (axis3_->size() != 1) 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) { if (axis3_->size() != 1) {
float x3l = axis3_->axisValue(index3); float x3l = axis3_->axisValue(axis_index3);
float x3u = axis3_->axisValue(index3 + 1); float x3u = axis3_->axisValue(axis_index3 + 1);
dx3 = (x3 - x3l) / (x3u - x3l); dx3 = (x3 - x3l) / (x3u - x3l);
y001 = value(index1, index2, index3 + 1); y001 = value(axis_index1, axis_index2, axis_index3 + 1);
} }
float tbl_value float tbl_value
@ -1244,15 +1310,15 @@ Table3::reportValue(const char *result_name,
*result += unit3->asString(value3, digits); *result += unit3->asString(value3, digits);
*result += '\n'; *result += '\n';
size_t index1 = axis1_->findAxisIndex(value1); size_t axis_index1 = axis1_->findAxisIndex(value1);
size_t index2 = axis2_->findAxisIndex(value2); size_t axis_index2 = axis2_->findAxisIndex(value2);
size_t index3 = axis3_->findAxisIndex(value3); size_t axis_index3 = axis3_->findAxisIndex(value3);
*result += " | | "; *result += " | | ";
*result += unit3->asString(axis3_->axisValue(index3), digits); *result += unit3->asString(axis3_->axisValue(axis_index3), digits);
if (axis3_->size() != 1) { if (axis3_->size() != 1) {
*result += " "; *result += " ";
*result += unit3->asString(axis3_->axisValue(index3 + 1), digits); *result += unit3->asString(axis3_->axisValue(axis_index3 + 1), digits);
} }
*result += '\n'; *result += '\n';
@ -1260,13 +1326,13 @@ Table3::reportValue(const char *result_name,
if (axis1_->size() != 1) { if (axis1_->size() != 1) {
*result += " "; *result += " ";
*result += unit1->asString(axis1_->axisValue(index1+1), digits); *result += unit1->asString(axis1_->axisValue(axis_index1+1), digits);
*result += " v / "; *result += " v / ";
*result += table_unit->asString(value(index1+1,index2,index3), *result += table_unit->asString(value(axis_index1+1,axis_index2,axis_index3),
digits); digits);
if (axis3_->size() != 1) { if (axis3_->size() != 1) {
*result += " "; *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); digits);
} }
} }
@ -1276,14 +1342,14 @@ Table3::reportValue(const char *result_name,
} }
*result += '\n'; *result += '\n';
*result += unit1->asString(axis1_->axisValue(index1), digits); *result += unit1->asString(axis1_->axisValue(axis_index1), digits);
*result += " "; *result += " ";
*result += unit2->asString(axis2_->axisValue(index2), digits); *result += unit2->asString(axis2_->axisValue(axis_index2), digits);
*result += " | "; *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) { if (axis3_->size() != 1) {
*result += " "; *result += " ";
*result += table_unit->asString(value(index1, index2, index3+1), *result += table_unit->asString(value(axis_index1, axis_index2, axis_index3+1),
digits); digits);
} }
*result += '\n'; *result += '\n';
@ -1291,25 +1357,25 @@ Table3::reportValue(const char *result_name,
*result += " |/ "; *result += " |/ ";
if (axis1_->size() != 1 if (axis1_->size() != 1
&& axis2_->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); digits);
if (axis3_->size() != 1) { if (axis3_->size() != 1) {
*result += " "; *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); digits);
} }
} }
*result += '\n'; *result += '\n';
*result += " "; *result += " ";
*result += unit2->asString(axis2_->axisValue(index2 + 1), digits); *result += unit2->asString(axis2_->axisValue(axis_index2 + 1), digits);
*result += " | "; *result += " | ";
if (axis2_->size() != 1) { 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); digits);
if (axis3_->size() != 1) { if (axis3_->size() != 1) {
*result += " "; *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); digits);
} }
} }
@ -1338,24 +1404,24 @@ Table3::report(const Units *units,
const Unit *unit1 = axis1_->unit(units); const Unit *unit1 = axis1_->unit(units);
const Unit *unit2 = axis2_->unit(units); const Unit *unit2 = axis2_->unit(units);
const Unit *unit3 = axis3_->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()), 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("%s", tableVariableString(axis3_->variable()));
report->reportLine(" ------------------------------"); report->reportLine(" ------------------------------");
string line = " "; string line = " ";
for (size_t index3 = 0; index3 < axis3_->size(); index3++) { for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) {
line += unit3->asString(axis3_->axisValue(index3), digits); line += unit3->asString(axis3_->axisValue(axis_index3), digits);
line += " "; line += " ";
} }
report->reportLineString(line); report->reportLineString(line);
for (size_t index2 = 0; index2 < axis2_->size(); index2++) { for (size_t axis_index2 = 0; axis_index2 < axis2_->size(); axis_index2++) {
line = unit2->asString(axis2_->axisValue(index2),digits); line = unit2->asString(axis2_->axisValue(axis_index2),digits);
line += " |"; line += " |";
for (size_t index3 = 0; index3 < axis3_->size(); index3++) { for (size_t axis_index3 = 0; axis_index3 < axis3_->size(); axis_index3++) {
line += table_unit->asString(value(index1, index2, index3), digits); line += table_unit->asString(value(axis_index1, axis_index2, axis_index3), digits);
line += " "; line += " ";
} }
report->reportLineString(line); report->reportLineString(line);
@ -1514,26 +1580,30 @@ tableVariableUnit(TableAxisVariable variable,
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
OutputCurrentWaveform::OutputCurrentWaveform(float axis_value1,
float axis_value2, ////////////////////////////////////////////////////////////////
TableAxisPtr axis,
Table1 *currents, OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
float reference_time) : TableAxisPtr cap_axis,
axis_value1_(axis_value1), Table1Seq &current_waveforms,
axis_value2_(axis_value2), Table1 *ref_times) :
axis_(axis), slew_axis_(slew_axis),
currents_(currents), cap_axis_(cap_axis),
reference_time_(reference_time) 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 bool
OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template) OutputWaveforms::checkAxes(TableTemplate *tbl_template)
{ {
TableAxisPtr axis1 = tbl_template->axis1(); TableAxisPtr axis1 = tbl_template->axis1();
TableAxisPtr axis2 = tbl_template->axis2(); TableAxisPtr axis2 = tbl_template->axis2();
@ -1549,83 +1619,215 @@ OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template)
&& axis3->variable() == TableAxisVariable::time); && axis3->variable() == TableAxisVariable::time);
} }
void Table1
OutputCurrentWaveform::reportWaveform(const Units *units, OutputWaveforms::voltageWaveform(float slew,
int digits, float cap)
string *result)
{ {
const Unit *time_unit = units->timeUnit(); size_t slew_index = slew_axis_->findAxisIndex(slew);
const Unit *current_unit = units->currentUnit(); size_t cap_index = cap_axis_->findAxisIndex(cap);
for (size_t i = 0; i < axis_->values()->size(); i++) { size_t wave_index00 = slew_index * cap_axis_->size() + cap_index;
*result += time_unit->asString(axis_->axisValue(i), digits); size_t wave_index01 = slew_index * cap_axis_->size() + (cap_index + 1);
*result += " "; 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<TableAxis>(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'; return Table1(values, time_axis);
for (size_t i = 0; i < currents_->axis1()->size(); i++) { }
*result += current_unit->asString(currents_->value(i), digits);
*result += " "; 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<TableAxis>(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, DriverWaveform::DriverWaveform(const char *name,
TableAxisPtr axis2, TablePtr waveforms) :
OutputCurrentWaveformSeq &waveforms) : name_(name),
axis1_(axis1),
axis2_(axis2),
waveforms_(waveforms) waveforms_(waveforms)
{ {
} }
OutputCurrent::~OutputCurrent() DriverWaveform::~DriverWaveform()
{ {
waveforms_.deleteContents(); stringDelete(name_);
} }
void Table1
OutputCurrent::reportWaveform(const LibertyCell *cell, DriverWaveform::waveform(float slew)
const Pvt *,
float in_slew,
float load_cap,
int digits,
string *result) const
{ {
float axis_value1, axis_value2; TableAxisPtr volt_axis = waveforms_->axis2();
findAxisValues(in_slew, load_cap, FloatSeq *time_values = new FloatSeq;
axis_value1, axis_value2); FloatSeq *volt_values = new FloatSeq;
size_t index1 = axis1_->findAxisIndex(axis_value1); for (float volt : *volt_axis->values()) {
size_t index2 = axis2_->findAxisIndex(axis_value2); float time = waveforms_->findValue(slew, volt, 0.0);
size_t index = index1 * axis2_->size() + index2; time_values->push_back(time);
waveforms_[index]->reportWaveform(cell->libertyLibrary()->units(), digits, result); volt_values->push_back(volt);
}
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 time_axis = make_shared<TableAxis>(TableAxisVariable::time,
time_values);
Table1 waveform(volt_values, time_axis);
return waveform;
} }
} // namespace } // namespace

View File

@ -1,173 +1,173 @@
0001 DmpCeff.cc:1597 cell %s delay model not supported on SPF parasitics by DMP delay calculator 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. 0002 Liberty.cc:750 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. 0003 Liberty.cc:776 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. 0004 Liberty.cc:1728 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. 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:1732 cell %s/%s %s -> %s latch enable %s_edge is inconsistent with latch group enable function negative 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. 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. 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. 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. 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. 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. 0017 Sta.cc:2093 '%s' is not a valid endpoint.
0018 Sta.cc:2017 '%s' is not a valid start point. 0018 Sta.cc:2017 '%s' is not a valid start point.
0021 SpefParse.yy:805 %d is not positive. 0021 SpefParse.yy:805 %d is not positive.
0022 SpefParse.yy:814 %.4f is not positive. 0022 SpefParse.yy:814 %.4f is not positive.
0023 SpefParse.yy:820 %.4f is not positive. 0023 SpefParse.yy:820 %.4f is not positive.
0024 WritePathSpice.cc:425 pg_pin %s/%s voltage %s not found, 0024 WritePathSpice.cc:458 pg_pin %s/%s voltage %s not found,
0025 WritePathSpice.cc:432 Liberty pg_port %s/%s missing voltage_name attribute, 0025 WritePathSpice.cc:465 Liberty pg_port %s/%s missing voltage_name attribute,
0026 WritePathSpice.cc:960 %s pg_port %s not found, 0026 WritePathSpice.cc:1037 %s pg_port %s not found,
0027 WritePathSpice.cc:1015 no register/latch found for path from %s to %s, 0027 WritePathSpice.cc:1092 no register/latch found for path from %s to %s,
0028 WritePathSpice.cc:1382 The following subkcts are missing from %s 0028 WritePathSpice.cc:1464 The subkct file %s is missing definitions for %s
0029 WritePathSpice.cc:1440 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground. 0029 WritePathSpice.cc:1562 subckt %s port %s has no corresponding liberty port, pg_port and is not power or ground.
0030 LibertyReader.cc:624 library missing name. 0030 LibertyReader.cc:628 library missing name.
0031 LibertyReader.cc:656 default_wire_load %s not found. 0031 LibertyReader.cc:660 default_wire_load %s not found.
0032 LibertyReader.cc:667 default_wire_selection %s not found. 0032 LibertyReader.cc:671 default_wire_selection %s not found.
0033 LibertyReader.cc:689 input_threshold_pct_%s not found. 0033 LibertyReader.cc:693 input_threshold_pct_%s not found.
0034 LibertyReader.cc:693 output_threshold_pct_%s not found. 0034 LibertyReader.cc:697 output_threshold_pct_%s not found.
0035 LibertyReader.cc:697 slew_lower_threshold_pct_%s not found. 0035 LibertyReader.cc:701 slew_lower_threshold_pct_%s not found.
0036 LibertyReader.cc:701 slew_upper_threshold_pct_%s not found. 0036 LibertyReader.cc:705 slew_upper_threshold_pct_%s not found.
0037 LibertyReader.cc:706 Library %s is missing one or more thresholds. 0037 LibertyReader.cc:710 Library %s is missing one or more thresholds.
0038 LibertyReader.cc:796 unknown unit multiplier %s. 0038 LibertyReader.cc:800 unknown unit multiplier %s.
0039 LibertyReader.cc:815 unknown unit scale %c. 0039 LibertyReader.cc:819 unknown unit scale %c.
0040 LibertyReader.cc:818 unknown unit suffix %s. 0040 LibertyReader.cc:822 unknown unit suffix %s.
0041 LibertyReader.cc:844 capacitive_load_units are not ff or pf. 0041 LibertyReader.cc:848 capacitive_load_units are not ff or pf.
0042 LibertyReader.cc:847 capacitive_load_units are not a string. 0042 LibertyReader.cc:851 capacitive_load_units are not a string.
0043 LibertyReader.cc:850 capacitive_load_units missing suffix. 0043 LibertyReader.cc:854 capacitive_load_units missing suffix.
0044 LibertyReader.cc:853 capacitive_load_units scale is not a float. 0044 LibertyReader.cc:857 capacitive_load_units scale is not a float.
0045 LibertyReader.cc:856 capacitive_load_units missing scale and suffix. 0045 LibertyReader.cc:860 capacitive_load_units missing scale and suffix.
0046 LibertyReader.cc:859 capacitive_load_unit missing values suffix. 0046 LibertyReader.cc:863 capacitive_load_unit missing values suffix.
0047 LibertyReader.cc:877 delay_model %s not supported. 0047 LibertyReader.cc:881 delay_model %s not supported.
0048 LibertyReader.cc:881 delay_model %s not supported. 0048 LibertyReader.cc:885 delay_model %s not supported.
0049 LibertyReader.cc:885 delay_model %s not supported. 0049 LibertyReader.cc:889 delay_model %s not supported.
0050 LibertyReader.cc:890 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. 0052 LibertyReader.cc:916 unknown bus_naming_style format.
0053 LibertyReader.cc:590 library %s already exists. 0053 LibertyReader.cc:594 library %s already exists.
0054 LibertyReader.cc:933 voltage_map voltage is not a float. 0054 LibertyReader.cc:937 voltage_map voltage is not a float.
0055 LibertyReader.cc:936 voltage_map missing voltage. 0055 LibertyReader.cc:940 voltage_map missing voltage.
0056 LibertyReader.cc:939 voltage_map supply name is not a string. 0056 LibertyReader.cc:943 voltage_map supply name is not a string.
0057 LibertyReader.cc:942 voltage_map missing supply name and voltage. 0057 LibertyReader.cc:946 voltage_map missing supply name and voltage.
0058 LibertyReader.cc:945 voltage_map missing values suffix. 0058 LibertyReader.cc:949 voltage_map missing values suffix.
0059 LibertyReader.cc:1163 default_wire_load_mode %s not found. 0059 LibertyReader.cc:1167 default_wire_load_mode %s not found.
0060 LibertyReader.cc:679 default_operating_condition %s not found. 0060 LibertyReader.cc:683 default_operating_condition %s not found.
0061 LibertyReader.cc:1334 table template missing name. 0061 LibertyReader.cc:1338 table template missing name.
0062 LibertyReader.cc:1379 missing variable_%d attribute. 0062 LibertyReader.cc:1383 missing variable_%d attribute.
0063 LibertyReader.cc:1422 axis type %s not supported. 0063 LibertyReader.cc:1426 axis type %s not supported.
0064 LibertyReader.cc:1482 bus type %s missing bit_from. 0064 LibertyReader.cc:1486 bus type %s missing bit_from.
0065 LibertyReader.cc:1484 bus type %s missing bit_to. 0065 LibertyReader.cc:1488 bus type %s missing bit_to.
0066 LibertyReader.cc:1488 type missing name. 0066 LibertyReader.cc:1492 type missing name.
0067 LibertyReader.cc:1515 scaling_factors do not have a name. 0067 LibertyReader.cc:1519 scaling_factors do not have a name.
0068 LibertyReader.cc:1683 operating_conditions missing name. 0068 LibertyReader.cc:1687 operating_conditions missing name.
0069 LibertyReader.cc:1753 wire_load missing name. 0069 LibertyReader.cc:1757 wire_load missing name.
0070 LibertyReader.cc:1796 fanout_length is missing length and fanout. 0070 LibertyReader.cc:1800 fanout_length is missing length and fanout.
0071 LibertyReader.cc:1811 wire_load_selection missing name. 0071 LibertyReader.cc:1815 wire_load_selection missing name.
0072 LibertyReader.cc:1842 wireload %s not found. 0072 LibertyReader.cc:1846 wireload %s not found.
0074 LibertyReader.cc:1849 wire_load_from_area min not a float. 0074 LibertyReader.cc:1853 wire_load_from_area min not a float.
0075 LibertyReader.cc:1852 wire_load_from_area max not a float. 0075 LibertyReader.cc:1856 wire_load_from_area max not a float.
0076 LibertyReader.cc:1855 wire_load_from_area missing parameters. 0076 LibertyReader.cc:1859 wire_load_from_area missing parameters.
0077 LibertyReader.cc:1858 wire_load_from_area missing parameters. 0077 LibertyReader.cc:1862 wire_load_from_area missing parameters.
0078 LibertyReader.cc:1875 cell missing name. 0078 LibertyReader.cc:1879 cell missing name.
0079 LibertyReader.cc:1898 cell %s ocv_derate_group %s not found. 0079 LibertyReader.cc:1902 cell %s ocv_derate_group %s not found.
0080 LibertyReader.cc:1934 port %s function size does not match port size. 0080 LibertyReader.cc:1938 port %s function size does not match port size.
0081 LibertyReader.cc:2002 %s %s bus width mismatch. 0081 LibertyReader.cc:2006 %s %s bus width mismatch.
0082 LibertyReader.cc:2013 %s %s bus width mismatch. 0082 LibertyReader.cc:2017 %s %s bus width mismatch.
0083 LibertyReader.cc:2023 clear 0083 LibertyReader.cc:2027 clear
0084 LibertyReader.cc:2033 preset 0084 LibertyReader.cc:2037 preset
0085 LibertyReader.cc:2069 latch enable function is non-unate for port %s. 0085 LibertyReader.cc:2073 latch enable function is non-unate for port %s.
0086 LibertyReader.cc:2074 latch enable function is unknown for port %s. 0086 LibertyReader.cc:2078 latch enable function is unknown for port %s.
0087 LibertyReader.cc:2150 operating conditions %s not found. 0087 LibertyReader.cc:2154 operating conditions %s not found.
0088 LibertyReader.cc:2153 scaled_cell missing operating condition. 0088 LibertyReader.cc:2157 scaled_cell missing operating condition.
0089 LibertyReader.cc:2156 scaled_cell cell %s has not been defined. 0089 LibertyReader.cc:2160 scaled_cell cell %s has not been defined.
0090 LibertyReader.cc:2159 scaled_cell missing name. 0090 LibertyReader.cc:2163 scaled_cell missing name.
0091 LibertyReader.cc:2185 scaled_cell %s, %s port functions do not match cell port functions. 0091 LibertyReader.cc:2189 scaled_cell %s, %s port functions do not match cell port functions.
0092 LibertyReader.cc:2190 scaled_cell ports do not match cell ports. 0092 LibertyReader.cc:2194 scaled_cell ports do not match cell ports.
0093 LibertyReader.cc:2192 scaled_cell %s, %s timing does not match cell timing. 0093 LibertyReader.cc:2196 scaled_cell %s, %s timing does not match cell timing.
0094 LibertyReader.cc:2211 combinational timing to an input port. 0094 LibertyReader.cc:2215 combinational timing to an input port.
0095 LibertyReader.cc:2302 missing %s_transition. 0095 LibertyReader.cc:2306 missing %s_transition.
0096 LibertyReader.cc:2304 missing cell_%s. 0096 LibertyReader.cc:2308 missing cell_%s.
0099 LibertyReader.cc:2821 scaling_factors %s not found. 0099 LibertyReader.cc:2900 scaling_factors %s not found.
0100 LibertyReader.cc:2864 pin name is not a string. 0100 LibertyReader.cc:2943 pin name is not a string.
0101 LibertyReader.cc:2883 pin name is not a string. 0101 LibertyReader.cc:2962 pin name is not a string.
0102 LibertyReader.cc:2899 pin name is not a string. 0102 LibertyReader.cc:2978 pin name is not a string.
0103 LibertyReader.cc:2977 bus %s bus_type not found. 0103 LibertyReader.cc:3056 bus %s bus_type not found.
0104 LibertyReader.cc:3033 bus_type %s not found. 0104 LibertyReader.cc:3112 bus_type %s not found.
0105 LibertyReader.cc:3036 bus_type is not a string. 0105 LibertyReader.cc:3115 bus_type is not a string.
0106 LibertyReader.cc:3054 bundle %s member not found. 0106 LibertyReader.cc:3133 bundle %s member not found.
0107 LibertyReader.cc:3081 member is not a string. 0107 LibertyReader.cc:3160 member is not a string.
0108 LibertyReader.cc:3088 members attribute is missing values. 0108 LibertyReader.cc:3167 members attribute is missing values.
0109 LibertyReader.cc:3139 unknown port direction. 0109 LibertyReader.cc:3218 unknown port direction.
0110 LibertyReader.cc:3507 pulse_latch unknown pulse type. 0110 LibertyReader.cc:3586 pulse_latch unknown pulse type.
0111 LibertyReader.cc:3885 unknown timing_type %s. 0111 LibertyReader.cc:3964 unknown timing_type %s.
0112 LibertyReader.cc:3905 unknown timing_sense %s. 0112 LibertyReader.cc:3984 unknown timing_sense %s.
0113 LibertyReader.cc:3945 mode value is not a string. 0113 LibertyReader.cc:4024 mode value is not a string.
0114 LibertyReader.cc:3948 missing mode value. 0114 LibertyReader.cc:4027 missing mode value.
0115 LibertyReader.cc:3951 mode name is not a string. 0115 LibertyReader.cc:4030 mode name is not a string.
0116 LibertyReader.cc:3954 mode missing values. 0116 LibertyReader.cc:4033 mode missing values.
0117 LibertyReader.cc:3957 mode missing mode name and value. 0117 LibertyReader.cc:4036 mode missing mode name and value.
0118 LibertyReader.cc:2541 unsupported model axis. 0118 LibertyReader.cc:2547 unsupported model axis.
0119 LibertyReader.cc:4060 unsupported model axis. 0119 LibertyReader.cc:4139 unsupported model axis.
0120 LibertyReader.cc:4089 unsupported model axis. 0120 LibertyReader.cc:4168 unsupported model axis.
0121 LibertyReader.cc:4124 unsupported model axis. 0121 LibertyReader.cc:4203 unsupported model axis.
0122 LibertyReader.cc:4179 table template %s not found. 0122 LibertyReader.cc:4258 table template %s not found.
0123 LibertyReader.cc:4258 %s is missing values. 0123 LibertyReader.cc:4337 %s is missing values.
0124 LibertyReader.cc:4283 %s is not a list of floats. 0124 LibertyReader.cc:4362 %s is not a list of floats.
0125 LibertyReader.cc:4285 table row has %u columns but axis has %d. 0125 LibertyReader.cc:4364 table row has %u columns but axis has %d.
0126 LibertyReader.cc:4295 table has %u rows but axis has %d. 0126 LibertyReader.cc:4374 table has %u rows but axis has %d.
0127 LibertyReader.cc:4348 lut output is not a string. 0127 LibertyReader.cc:4427 lut output is not a string.
0128 LibertyReader.cc:4390 mode definition missing name. 0128 LibertyReader.cc:4469 mode definition missing name.
0129 LibertyReader.cc:4407 mode value missing name. 0129 LibertyReader.cc:4486 mode value missing name.
0130 LibertyReader.cc:4421 when attribute inside table model. 0130 LibertyReader.cc:4500 when attribute inside table model.
0131 LibertyReader.cc:4470 %s attribute is not a string. 0131 LibertyReader.cc:4549 %s attribute is not a string.
0132 LibertyReader.cc:4473 %s is not a simple attribute. 0132 LibertyReader.cc:4552 %s is not a simple attribute.
0133 LibertyReader.cc:4496 %s is not a simple attribute. 0133 LibertyReader.cc:4575 %s is not a simple attribute.
0134 LibertyReader.cc:4509 %s is not a simple attribute. 0134 LibertyReader.cc:4588 %s is not a simple attribute.
0135 LibertyReader.cc:4533 %s value %s is not a float. 0135 LibertyReader.cc:4612 %s value %s is not a float.
0136 LibertyReader.cc:4562 %s missing values. 0136 LibertyReader.cc:4641 %s missing values.
0137 LibertyReader.cc:4566 %s missing values. 0137 LibertyReader.cc:4645 %s missing values.
0138 LibertyReader.cc:4569 %s is not a complex attribute. 0138 LibertyReader.cc:4648 %s is not a complex attribute.
0139 LibertyReader.cc:4595 %s is not a float. 0139 LibertyReader.cc:4674 %s is not a float.
0140 LibertyReader.cc:4618 %s is missing values. 0140 LibertyReader.cc:4697 %s is missing values.
0141 LibertyReader.cc:4621 %s has more than one string. 0141 LibertyReader.cc:4700 %s has more than one string.
0142 LibertyReader.cc:4630 %s is missing values. 0142 LibertyReader.cc:4709 %s is missing values.
0143 LibertyReader.cc:4655 %s attribute is not boolean. 0143 LibertyReader.cc:4734 %s attribute is not boolean.
0144 LibertyReader.cc:4658 %s attribute is not boolean. 0144 LibertyReader.cc:4737 %s attribute is not boolean.
0145 LibertyReader.cc:4661 %s is not a simple attribute. 0145 LibertyReader.cc:4740 %s is not a simple attribute.
0146 LibertyReader.cc:4677 attribute %s value %s not recognized. 0146 LibertyReader.cc:4756 attribute %s value %s not recognized.
0147 LibertyReader.cc:4707 unknown early/late value. 0147 LibertyReader.cc:4786 unknown early/late value.
0148 LibertyReader.cc:4933 OCV derate group named %s not found. 0148 LibertyReader.cc:5012 OCV derate group named %s not found.
0149 LibertyReader.cc:4949 ocv_derate missing name. 0149 LibertyReader.cc:5028 ocv_derate missing name.
0150 LibertyReader.cc:5002 unknown rise/fall. 0150 LibertyReader.cc:5081 unknown rise/fall.
0151 LibertyReader.cc:5022 unknown derate type. 0151 LibertyReader.cc:5101 unknown derate type.
0152 LibertyReader.cc:5054 unsupported model axis. 0152 LibertyReader.cc:5133 unsupported model axis.
0153 LibertyReader.cc:5086 unsupported model axis. 0153 LibertyReader.cc:5165 unsupported model axis.
0154 LibertyReader.cc:5118 unsupported model axis. 0154 LibertyReader.cc:5197 unsupported model axis.
0155 LibertyReader.cc:5189 unknown pg_type. 0155 LibertyReader.cc:5268 unknown pg_type.
0156 LibertyReader.cc:5584 port %s subscript out of range. 0156 LibertyReader.cc:5663 port %s subscript out of range.
0157 LibertyReader.cc:5588 port range %s of non-bus port %s. 0157 LibertyReader.cc:5667 port range %s of non-bus port %s.
0158 LibertyReader.cc:5602 port %s not found. 0158 LibertyReader.cc:5681 port %s not found.
0159 LibertyReader.cc:5672 port %s not found. 0159 LibertyReader.cc:5751 port %s not found.
0160 LibertyReader.cc:1030 default_max_transition is 0.0. 0160 LibertyReader.cc:1034 default_max_transition is 0.0.
0161 LibertyReader.cc:3395 max_transition is 0.0. 0161 LibertyReader.cc:3474 max_transition is 0.0.
0162 LibertyReader.cc:4493 %s attribute is not an integer. 0162 LibertyReader.cc:4572 %s attribute is not an integer.
0163 LibertyReader.cc:1135 default_fanout_load is 0.0. 0163 LibertyReader.cc:1139 default_fanout_load is 0.0.
0164 LibertyReader.cc:2324 timing group from output port. 0164 LibertyReader.cc:2328 timing group from output port.
0165 LibertyReader.cc:2334 timing group from output port. 0165 LibertyReader.cc:2338 timing group from output port.
0166 LibertyReader.cc:2344 timing group from output port. 0166 LibertyReader.cc:2348 timing group from output port.
0167 LibertyReader.cc:2362 timing group from output port. 0167 LibertyReader.cc:2366 timing group from output port.
0168 LibertyReader.cc:2377 timing group from output port. 0168 LibertyReader.cc:2381 timing group from output port.
0169 LibertyReader.cc:4365 cell %s test_cell redefinition. 0169 LibertyReader.cc:4444 cell %s test_cell redefinition.
0170 LibertyReader.cc:3804 timing group missing related_pin/related_bus_pin. 0170 LibertyReader.cc:3883 timing group missing related_pin/related_bus_pin.
0179 SpefReader.cc:733 %s. 0179 SpefReader.cc:734 %s.
0190 VerilogReader.cc:1756 %s is not a verilog module. 0190 VerilogReader.cc:1756 %s is not a verilog module.
0191 VerilogReader.cc:1761 %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. 0201 StaTcl.i:118 no network has been linked.
0202 StaTcl.i:131 network does not support edits. 0202 StaTcl.i:132 network does not support edits.
0204 StaTcl.i:4021 POCV support requires compilation with SSTA=1. 0204 StaTcl.i:4072 POCV support requires compilation with SSTA=1.
0206 LibertyExpr.cc:175 %s %s. 0206 LibertyExpr.cc:175 %s %s.
0207 GraphDelayCalc1.cc:738 port not found in cell 0207 GraphDelayCalc1.cc:738 port not found in cell
0208 Graph.cc:793 arc_delay_annotated array bounds exceeded 0208 Graph.cc:793 arc_delay_annotated array bounds exceeded
@ -184,20 +184,20 @@
0252 PathEnumed.cc:135 enumerated path required time 0252 PathEnumed.cc:135 enumerated path required time
0253 PathGroup.cc:399 unknown path end type 0253 PathGroup.cc:399 unknown path end type
0254 PathVertexRep.cc:145 tag group missing tag 0254 PathVertexRep.cc:145 tag group missing tag
0255 ReportPath.cc:289 unsupported path type 0255 ReportPath.cc:287 unsupported path type
0256 ReportPath.cc:310 unsupported path type 0256 ReportPath.cc:308 unsupported path type
0257 ReportPath.cc:349 unsupported path type 0257 ReportPath.cc:347 unsupported path type
0259 ReportPath.cc:2378 unsupported path type 0259 ReportPath.cc:2376 unsupported path type
0260 Search.cc:2628 max tag group index exceeded 0260 Search.cc:2628 max tag group index exceeded
0261 Search.cc:2860 max tag index exceeded 0261 Search.cc:2860 max tag index exceeded
0262 Search.cc:3551 unexpected filter path 0262 Search.cc:3551 unexpected filter path
0263 Search.cc:3719 tns incr existing vertex 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 0265 TagGroup.cc:297 tag group missing tag
0266 Sta.cc:2090 '%s' is not a valid endpoint. 0266 Sta.cc:2090 '%s' is not a valid endpoint.
0267 Sta.cc:2014 '%s' is not a valid start point. 0267 Sta.cc:2014 '%s' is not a valid start point.
0272 StaTcl.i:4007 unknown common clk pessimism mode. 0272 StaTcl.i:4058 unknown common clk pessimism mode.
0273 StaTcl.i:4963 unknown clock sense 0273 StaTcl.i:5003 unknown clock sense
0299 Power.tcl:241 activity cannot be set on clock ports. 0299 Power.tcl:241 activity cannot be set on clock ports.
0300 CmdUtil.tcl:44 no commands match '$pattern'. 0300 CmdUtil.tcl:44 no commands match '$pattern'.
0301 Power.tcl:218 activity should be 0.0 to 1.0 or 2.0 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'. 0604 Sdc.tcl:281 unknown $unit prefix '$prefix'.
0605 Sdc.tcl:3547 wire load model '$model_name' not found. 0605 Sdc.tcl:3547 wire load model '$model_name' not found.
0606 Property.tcl:77 get_property unsupported object type $object_type. 0606 Property.tcl:77 get_property unsupported object type $object_type.
0607 StaTcl.i:4257 unknown report path field %s 0607 StaTcl.i:4308 unknown report path field %s
0608 StaTcl.i:4269 unknown report path field %s 0608 StaTcl.i:4320 unknown report path field %s
0609 Search.tcl:421 -all_violators is deprecated. Use -violators 0609 Search.tcl:421 -all_violators is deprecated. Use -violators
0610 Search.tcl:501 -max_transition deprecated. Use -max_slew. 0610 Search.tcl:501 -max_transition deprecated. Use -max_slew.
0611 Search.tcl:506 -min_transition deprecated. Use -min_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. 0702 LibertyWriter.cc:436 3 axis table models not supported.
0703 LibertyWriter.cc:576 %s/%s/%s timing arc type %s 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. 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. 0706 Parasitics.tcl:70 read_spef -increment is deprecated.
0710 LumpedCapDelayCalc.cc:169 gate delay input variable is NaN 0710 LumpedCapDelayCalc.cc:169 gate delay input variable is NaN
0800 VcdReader.cc:109 unhandled vcd command. 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 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. 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. 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 0900 LibertyReader.cc:2840 level_shifter_type must be HL, LH, or HL_LH
0901 LibertyReader.cc:2797 switch_cell_type must be coarse_grain or fine_grain 0901 LibertyReader.cc:2876 switch_cell_type must be coarse_grain or fine_grain
0902 LibertyReader.cc:2460 unsupported model axis. 0902 LibertyReader.cc:2464 unsupported model axis.
0903 LibertyReader.cc:4140 %s group not in timing group. 0903 LibertyReader.cc:4219 %s group not in timing group.
0904 LibertyReader.cc:2443 receiver_capacitance group not in timing or pin group. 0904 LibertyReader.cc:2447 receiver_capacitance group not in timing or pin group.
0906 LibertyReader.cc:4033 unsupported model axis. 0906 LibertyReader.cc:4112 unsupported model axis.
0907 LibertyReader.cc:2486 output_current_%s group not in timing group. 0907 LibertyReader.cc:2492 output_current_%s group not in timing group.
0908 LibertyReader.cc:2575 vector reference_time not found. 0908 LibertyReader.cc:2591 vector reference_time not found.
0912 LibertyReader.cc:2573 vector index_1 and index_2 must have one value. 0912 LibertyReader.cc:2589 vector index_1 and index_2 must have exactly one value.
0913 LibertyReader.cc:2525 output current waveform %.2e %.2e not found. 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

View File

@ -63,6 +63,7 @@
namespace sta { namespace sta {
using std::abs; using std::abs;
using std::max;
using std::isnormal; using std::isnormal;
static bool static bool
@ -302,12 +303,16 @@ public:
virtual VertexVisitor *copy() const; virtual VertexVisitor *copy() const;
virtual void visit(Vertex *vertex); virtual void visit(Vertex *vertex);
InstanceSet &visitedRegs() { return visited_regs_; } InstanceSet &visitedRegs() { return visited_regs_; }
void init();
float maxChange() const { return max_change_; }
private: private:
bool setActivityCheck(const Pin *pin, bool setActivityCheck(const Pin *pin,
PwrActivity &activity); PwrActivity &activity);
static constexpr float change_tolerance_ = .01;
InstanceSet visited_regs_; InstanceSet visited_regs_;
float max_change_;
Power *power_; Power *power_;
BfsFwdIterator *bfs_; BfsFwdIterator *bfs_;
}; };
@ -327,6 +332,12 @@ PropActivityVisitor::copy() const
return new PropActivityVisitor(power_, bfs_); return new PropActivityVisitor(power_, bfs_);
} }
void
PropActivityVisitor::init()
{
max_change_ = 0.0;
}
void void
PropActivityVisitor::visit(Vertex *vertex) PropActivityVisitor::visit(Vertex *vertex)
{ {
@ -420,8 +431,12 @@ PropActivityVisitor::setActivityCheck(const Pin *pin,
PwrActivity &activity) PwrActivity &activity)
{ {
PwrActivity &prev_activity = power_->activity(pin); PwrActivity &prev_activity = power_->activity(pin);
if (abs(activity.activity() - prev_activity.activity()) > .001 float activity_delta = abs(activity.activity() - prev_activity.activity());
|| abs(activity.duty() - prev_activity.duty()) > .001) { 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); power_->setActivity(pin, activity);
return true; return true;
} }
@ -556,8 +571,10 @@ Power::ensureActivities()
bfs.visit(levelize_->maxLevel(), &visitor); bfs.visit(levelize_->maxLevel(), &visitor);
// Propagate activiities through registers. // Propagate activiities through registers.
InstanceSet regs = std::move(visitor.visitedRegs()); InstanceSet regs = std::move(visitor.visitedRegs());
while (!regs.empty()) { int pass = 1;
InstanceSet::Iterator reg_iter(regs); while (!regs.empty() && pass < max_activity_passes_) {
visitor.init();
InstanceSet::Iterator reg_iter(regs);
while (reg_iter.hasNext()) { while (reg_iter.hasNext()) {
const Instance *reg = reg_iter.next(); const Instance *reg = reg_iter.next();
// Propagate activiities across register D->Q. // Propagate activiities across register D->Q.
@ -567,6 +584,9 @@ Power::ensureActivities()
// combinational logic. // combinational logic.
bfs.visit(levelize_->maxLevel(), &visitor); bfs.visit(levelize_->maxLevel(), &visitor);
regs = std::move(visitor.visitedRegs()); regs = std::move(visitor.visitedRegs());
debugPrint(debug_, "power_activity", 1, "Pass %d change %.2f",
pass, visitor.maxChange());
pass++;
} }
activities_valid_ = true; activities_valid_ = true;
} }
@ -615,7 +635,7 @@ Power::seedRegOutputActivities(const Instance *inst,
&& func && func
&& (func->port() == seq->output() && (func->port() == seq->output()
|| func->port() == seq->outputInv())) { || 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_)); vertex->name(network_));
bfs.enqueue(vertex); bfs.enqueue(vertex);
} }

View File

@ -196,6 +196,7 @@ private:
PwrActivityMap activity_map_; PwrActivityMap activity_map_;
PwrSeqActivityMap seq_activity_map_; PwrSeqActivityMap seq_activity_map_;
bool activities_valid_; bool activities_valid_;
static constexpr int max_activity_passes_ = 100;
friend class PropActivityVisitor; friend class PropActivityVisitor;
}; };

View File

@ -48,6 +48,11 @@ pinSlewProperty(const Pin *pin,
const MinMax *min_max, const MinMax *min_max,
Sta *sta); Sta *sta);
static PropertyValue static PropertyValue
pinArrivalProperty(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max,
Sta *sta);
static PropertyValue
pinSlackProperty(const Pin *pin, pinSlackProperty(const Pin *pin,
const MinMax *min_max, const MinMax *min_max,
Sta *sta); Sta *sta);
@ -882,6 +887,15 @@ getProperty(const Pin *pin,
return PropertyValue(&activity); 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")) else if (stringEqual(property, "slack_max"))
return pinSlackProperty(pin, MinMax::max(), sta); return pinSlackProperty(pin, MinMax::max(), sta);
else if (stringEqual(property, "slack_max_fall")) else if (stringEqual(property, "slack_max_fall"))
@ -912,6 +926,16 @@ getProperty(const Pin *pin,
throw PropertyUnknown("pin", property); 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 static PropertyValue
pinSlackProperty(const Pin *pin, pinSlackProperty(const Pin *pin,
const MinMax *min_max, const MinMax *min_max,

View File

@ -2803,42 +2803,49 @@ Sta::vertexWorstSlackPath(Vertex *vertex,
} }
Arrival Arrival
Sta::vertexArrival(Vertex *vertex, Sta::pinArrival(const Pin *pin,
const MinMax *min_max) const RiseFall *rf,
const MinMax *min_max)
{ {
searchPreamble(); Vertex *vertex, *bidirect_vertex;
search_->findArrivals(vertex->level()); graph_->pinVertices(pin, vertex, bidirect_vertex);
Arrival arrival = min_max->initValue(); Arrival arrival;
VertexPathIterator path_iter(vertex, this); if (vertex)
while (path_iter.hasNext()) { arrival = vertexArrival(vertex, rf, clk_edge_wildcard, nullptr, min_max);
Path *path = path_iter.next(); if (bidirect_vertex) {
const Arrival &path_arrival = path->arrival(this); Arrival arrival1 = vertexArrival(bidirect_vertex, rf, clk_edge_wildcard,
ClkInfo *clk_info = path->clkInfo(search_); nullptr, min_max);
if (path->minMax(this) == min_max arrival = min_max->minMax(arrival, arrival1);
&& !clk_info->isGenClkSrcPath()
&& delayGreater(path->arrival(this), arrival, min_max, this))
arrival = path_arrival;
} }
return arrival; return arrival;
} }
Arrival
Sta::vertexArrival(Vertex *vertex,
const MinMax *min_max)
{
return vertexArrival(vertex, nullptr, nullptr, nullptr, min_max);
}
Arrival Arrival
Sta::vertexArrival(Vertex *vertex, Sta::vertexArrival(Vertex *vertex,
const RiseFall *rf, const RiseFall *rf,
const PathAnalysisPt *path_ap) const PathAnalysisPt *path_ap)
{ {
return vertexArrival(vertex, rf, clk_edge_wildcard, path_ap); return vertexArrival(vertex, rf, clk_edge_wildcard, path_ap, nullptr);
} }
Arrival Arrival
Sta::vertexArrival(Vertex *vertex, Sta::vertexArrival(Vertex *vertex,
const RiseFall *rf, const RiseFall *rf,
const ClockEdge *clk_edge, const ClockEdge *clk_edge,
const PathAnalysisPt *path_ap) const PathAnalysisPt *path_ap,
const MinMax *min_max)
{ {
searchPreamble(); searchPreamble();
search_->findArrivals(vertex->level()); 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(); Arrival arrival = min_max->initValue();
VertexPathIterator path_iter(vertex, rf, path_ap, this); VertexPathIterator path_iter(vertex, rf, path_ap, this);
while (path_iter.hasNext()) { while (path_iter.hasNext()) {

View File

@ -48,6 +48,8 @@ namespace sta {
using std::string; using std::string;
using std::ofstream; using std::ofstream;
using std::ifstream; using std::ifstream;
using std::max;
using std::set;
typedef Map<string, StringVector*> CellSpicePortNames; typedef Map<string, StringVector*> CellSpicePortNames;
typedef int Stage; typedef int Stage;
@ -79,7 +81,7 @@ private:
void writeHeader(); void writeHeader();
void writeStageInstances(); void writeStageInstances();
void writeInputSource(); void writeInputSource();
void writeStepVoltSource(const Pin *pin, void writeRampVoltSource(const Pin *pin,
const RiseFall *rf, const RiseFall *rf,
float slew, float slew,
float time, float time,
@ -98,8 +100,8 @@ private:
DcalcAPIndex dcalc_ap_index); DcalcAPIndex dcalc_ap_index);
void writeStageParasitics(Stage stage); void writeStageParasitics(Stage stage);
void writeSubckts(); void writeSubckts();
void findPathCellnames(// Return values. set<string> findPathCellnames();
StringSet &path_cell_names); void findPathCellSubckts(set<string> &path_cell_names);
void recordSpicePortNames(const char *cell_name, void recordSpicePortNames(const char *cell_name,
StringVector &tokens); StringVector &tokens);
float maxTime(); float maxTime();
@ -135,6 +137,11 @@ private:
void writeWaveformEdge(const RiseFall *rf, void writeWaveformEdge(const RiseFall *rf,
float time, float time,
float slew); float slew);
void writeWaveformVoltSource(const Pin *pin,
DriverWaveform *drvr_waveform,
const RiseFall *rf,
float slew,
int &volt_index);
void writeClkedStepSource(const Pin *pin, void writeClkedStepSource(const Pin *pin,
const RiseFall *rf, const RiseFall *rf,
const Clock *clk, const Clock *clk,
@ -162,6 +169,7 @@ private:
int &volt_index); int &volt_index);
float slewAxisMinValue(TimingArc *arc); float slewAxisMinValue(TimingArc *arc);
float pgPortVoltage(LibertyPgPort *pg_port); float pgPortVoltage(LibertyPgPort *pg_port);
void writePrintStmt();
// Stage "accessors". // Stage "accessors".
// //
@ -321,6 +329,7 @@ WritePathSpice::writeSpice()
// Find subckt port names as a side-effect of writeSubckts. // Find subckt port names as a side-effect of writeSubckts.
writeSubckts(); writeSubckts();
writeHeader(); writeHeader();
writePrintStmt();
writeStageInstances(); writeStageInstances();
writeMeasureStmts(); writeMeasureStmts();
writeInputSource(); writeInputSource();
@ -332,6 +341,18 @@ WritePathSpice::writeSpice()
throw FileNotWritable(spice_filename_); 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 void
WritePathSpice::writeHeader() WritePathSpice::writeHeader()
{ {
@ -348,12 +369,25 @@ WritePathSpice::writeHeader()
float temp = pvt->temperature(); float temp = pvt->temperature();
streamPrint(spice_stream_, ".temp %.1f\n", temp); streamPrint(spice_stream_, ".temp %.1f\n", temp);
streamPrint(spice_stream_, ".include \"%s\"\n", model_filename_); 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 max_time = maxTime();
float time_step = max_time / 1e+3; float time_step = max_time / 1e+3;
streamPrint(spice_stream_, ".tran %.3g %.3g\n\n", streamPrint(spice_stream_, ".tran %.3g %.3g\n\n",
time_step, max_time); 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 float
@ -373,9 +407,8 @@ WritePathSpice::maxTime()
} }
else { else {
float end_slew = findSlew(path_); float end_slew = findSlew(path_);
float max_time = delayAsFloat(input_slew float arrival = delayAsFloat(path_->arrival(this));
+ path_->arrival(this) float max_time = input_slew / 2.0 + arrival + end_slew;
+ end_slew * 2) * 1.5;
return max_time; return max_time;
} }
} }
@ -463,11 +496,55 @@ WritePathSpice::writeInputWaveform()
float time0 = slew0; float time0 = slew0;
int volt_index = 1; int volt_index = 1;
const Pin *drvr_pin = stageDrvrPin(input_stage); 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 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, const RiseFall *rf,
float slew, float slew,
float time, float time,
@ -928,7 +1005,7 @@ WritePathSpice::writeClkedStepSource(const Pin *pin,
Vertex *vertex = graph_->pinLoadVertex(pin); Vertex *vertex = graph_->pinLoadVertex(pin);
float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index); float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index);
float time = clkWaveformTImeOffset(clk) + clk->period() / 2.0; float time = clkWaveformTImeOffset(clk) + clk->period() / 2.0;
writeStepVoltSource(pin, rf, slew, time, volt_index); writeRampVoltSource(pin, rf, slew, time, volt_index);
} }
void void
@ -1342,8 +1419,8 @@ WritePathSpice::nodeName(ParasiticNode *node)
void void
WritePathSpice::writeSubckts() WritePathSpice::writeSubckts()
{ {
StringSet path_cell_names; set<string> path_cell_names = findPathCellnames();
findPathCellnames(path_cell_names); findPathCellSubckts(path_cell_names);
ifstream lib_subckts_stream(lib_subckt_filename_); ifstream lib_subckts_stream(lib_subckt_filename_);
if (lib_subckts_stream.is_open()) { if (lib_subckts_stream.is_open()) {
@ -1357,7 +1434,7 @@ WritePathSpice::writeSubckts()
if (tokens.size() >= 2 if (tokens.size() >= 2
&& stringEqual(tokens[0].c_str(), ".subckt")) { && stringEqual(tokens[0].c_str(), ".subckt")) {
const char *cell_name = tokens[1].c_str(); 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"; subckts_stream << line << "\n";
bool found_ends = false; bool found_ends = false;
while (getline(lib_subckts_stream, line)) { while (getline(lib_subckts_stream, line)) {
@ -1379,10 +1456,14 @@ WritePathSpice::writeSubckts()
lib_subckts_stream.close(); lib_subckts_stream.close();
if (!path_cell_names.empty()) { if (!path_cell_names.empty()) {
report_->error(28, "The following subkcts are missing from %s", string missing_cells;
lib_subckt_filename_); for (const string &cell_name : path_cell_names) {
for (const char *cell_name : path_cell_names) missing_cells += "\n";
report_->reportLine(" %s", cell_name); missing_cells += cell_name;
}
report_->error(28, "The subkct file %s is missing definitions for %s",
lib_subckt_filename_,
missing_cells.c_str());
} }
} }
else { else {
@ -1394,10 +1475,10 @@ WritePathSpice::writeSubckts()
throw FileNotReadable(lib_subckt_filename_); throw FileNotReadable(lib_subckt_filename_);
} }
void set<string>
WritePathSpice::findPathCellnames(// Return values. WritePathSpice::findPathCellnames()
StringSet &path_cell_names)
{ {
set<string> path_cell_names;
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) { for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
TimingArc *arc = stageGateArc(stage); TimingArc *arc = stageGateArc(stage);
if (arc) { if (arc) {
@ -1420,6 +1501,47 @@ WritePathSpice::findPathCellnames(// Return values.
delete pin_iter; delete pin_iter;
} }
} }
return path_cell_names;
}
// Subckts can call subckts (asap7).
void
WritePathSpice::findPathCellSubckts(set<string> &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 <cell_name> [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 void

View File

@ -49,6 +49,7 @@
#include "Transition.hh" #include "Transition.hh"
#include "TimingRole.hh" #include "TimingRole.hh"
#include "TimingArc.hh" #include "TimingArc.hh"
#include "TableModel.hh"
#include "Liberty.hh" #include "Liberty.hh"
#include "LibertyWriter.hh" #include "LibertyWriter.hh"
#include "EquivCells.hh" #include "EquivCells.hh"
@ -567,13 +568,13 @@ using namespace sta;
%typemap(in) RiseFall* { %typemap(in) RiseFall* {
int length; int length;
const char *arg = Tcl_GetStringFromObj($input, &length); const char *arg = Tcl_GetStringFromObj($input, &length);
RiseFall *tr = RiseFall::find(arg); RiseFall *rf = RiseFall::find(arg);
if (tr == nullptr) { if (rf == nullptr) {
Tcl_SetResult(interp,const_cast<char*>("Error: unknown transition name."), Tcl_SetResult(interp,const_cast<char*>("Error: unknown rise/fall edge."),
TCL_STATIC); TCL_STATIC);
return TCL_ERROR; return TCL_ERROR;
} }
$1 = tr; $1 = rf;
} }
%typemap(out) RiseFall* { %typemap(out) RiseFall* {
@ -875,6 +876,44 @@ using namespace sta;
$1 = ints; $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* { %typemap(in) MinMax* {
int length; int length;
char *arg = Tcl_GetStringFromObj($input, &length); char *arg = Tcl_GetStringFromObj($input, &length);
@ -3749,6 +3788,14 @@ format_voltage(const char *value,
return Sta::sta()->units()->voltageUnit()->asString(value1, digits); 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 * const char *
format_power(const char *value, format_power(const char *value,
int digits) int digits)
@ -4586,17 +4633,6 @@ find_clk_min_period(const Clock *clk,
return sta->findClkMinPeriod(clk, ignore_port_paths); 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 PinSeq
@ -5601,6 +5637,9 @@ full_name()
to); to);
} }
TimingArcSeq &
timing_arcs() { return self->arcs(); }
} // TimingArcSet methods } // TimingArcSet methods
%extend TimingArc { %extend TimingArc {
@ -5611,6 +5650,37 @@ const char *from_edge_name() { return self->fromEdge()->asRiseFall()->name(); }
Transition *to_edge() { return self->toEdge(); } Transition *to_edge() { return self->toEdge(); }
const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); } const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); }
TimingRole *role() { return self->role(); } TimingRole *role() { return self->role(); }
Table1
voltage_waveform(float in_slew,
float load_cap)
{
GateTableModel *gate_model = dynamic_cast<GateTableModel*>(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<GateTableModel*>(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 } // TimingArc methods
%extend Instance { %extend Instance {
@ -5847,7 +5917,7 @@ arrivals_clk(const RiseFall *rf,
clk_edge = clk->edge(clk_rf); clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) { for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge, arrivals.push_back(delayAsFloat(sta->vertexArrival(self, rf, clk_edge,
path_ap))); path_ap, nullptr)));
} }
return arrivals; return arrivals;
} }
@ -5865,7 +5935,7 @@ arrivals_clk_delays(const RiseFall *rf,
clk_edge = clk->edge(clk_rf); clk_edge = clk->edge(clk_rf);
for (auto path_ap : sta->corners()->pathAnalysisPts()) { for (auto path_ap : sta->corners()->pathAnalysisPts()) {
arrivals.push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge, arrivals.push_back(delayAsString(sta->vertexArrival(self, rf, clk_edge,
path_ap), path_ap, nullptr),
sta, digits)); sta, digits));
} }
return arrivals; return arrivals;

View File

@ -56,11 +56,13 @@ RiseFall::opposite() const
} }
RiseFall * 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_; return &rise_;
else if (stringEq(tr_str, fall_.name())) else if (stringEq(rf_str, fall_.name())
|| stringEq(rf_str, fall_.shortName()))
return &fall_; return &fall_;
else else
return nullptr; return nullptr;