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/ChangeLog.txt for changes to commands.
OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
is also licensed for commerical applications by Parallax Software without
the GPL's requirements.
OpenSTA is open source, meaning the sources are published and can be compiled locally.
Derivatives works are supported as long as they adhere to the GPL license requirements.
However, OpenSTA is not supported by a public community of developers as many other
open source projects are. The copyright and develpment are exclusive to Parallax
Software. OpenSTA does not accept external code contributions.
The official git repository is located at
https://github.com/jjcherry56/OpenSTA.git. Any forks from this code
base have not passed extensive regression testing which is not
publicly available.
## Build
OpenSTA is built with CMake.
@ -197,19 +212,8 @@ case directory.
* William Scott authored the arnoldi delay calculator at Blaze, Inc which was subsequently licensed to Nefelus, Inc that has graciously contributed it to OpenSTA.
## Contributions
External code contributions are not supported.
https://en.wikipedia.org/wiki/Contributor_License_Agreement
https://opensource.google/docs/cla/
## License
OpenSTA is dual licensed. It is released under GPL v3 as OpenSTA and
is also licensed for commerical applications by Parallax Software without
the GPL's requirements.
OpenSTA, Static Timing Analyzer
Copyright (c) 2023, Parallax Software, Inc.
@ -225,4 +229,3 @@ GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.

View File

@ -48,4 +48,15 @@ set_delay_calc_incremental_tolerance(float tol)
sta::Sta::sta()->setIncrementalDelayTolerance(tol);
}
TmpString *
report_delay_calc_cmd(Edge *edge,
TimingArc *arc,
const Corner *corner,
const MinMax *min_max,
int digits)
{
cmdLinkedNetwork();
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
}
%} // inline

View File

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

View File

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

View File

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

View File

@ -82,7 +82,8 @@ LibertyLibrary::LibertyLibrary(const char *name,
default_operating_conditions_(nullptr),
ocv_arc_depth_(0.0),
default_ocv_derate_(nullptr),
buffers_(nullptr)
buffers_(nullptr),
driver_waveform_default_(nullptr)
{
// Scalar templates are builtin.
for (int i = 0; i != table_template_type_count; i++) {
@ -860,6 +861,23 @@ LibertyLibrary::supplyExists(const char *supply_name) const
return supply_voltage_map_.hasKey(supply_name);
}
DriverWaveform *
LibertyLibrary::findDriverWaveform(const char *name)
{
return driver_waveform_map_[name];
}
void
LibertyLibrary::addDriverWaveform(DriverWaveform *driver_waveform)
{
if (driver_waveform->name())
driver_waveform_map_[driver_waveform->name()] = driver_waveform;
else {
delete driver_waveform_default_;
driver_waveform_default_ = driver_waveform;
}
}
////////////////////////////////////////////////////////////////
LibertyCellIterator::LibertyCellIterator(const LibertyLibrary *library) :
@ -1920,6 +1938,7 @@ LibertyPort::LibertyPort(LibertyCell *cell,
related_ground_pin_(nullptr),
related_power_pin_(nullptr),
receiver_model_(nullptr),
driver_waveform_{nullptr, nullptr},
min_pulse_width_exists_(false),
min_period_exists_(false),
is_clk_(false),
@ -2519,6 +2538,19 @@ portLibertyToSta(const char *port_name)
return sta_name;
}
DriverWaveform *
LibertyPort::driverWaveform(const RiseFall *rf) const
{
return driver_waveform_[rf->index()];
}
void
LibertyPort::setDriverWaveform(DriverWaveform *driver_waveform,
const RiseFall *rf)
{
driver_waveform_[rf->index()] = driver_waveform;
}
////////////////////////////////////////////////////////////////
LibertyPortSeq

View File

@ -501,10 +501,14 @@ LibertyReader::defineVisitors()
defineGroupVisitor("output_current_fall",
&LibertyReader::beginOutputCurrentFall,
&LibertyReader::endOutputCurrentRiseFall);
defineGroupVisitor("vector",
&LibertyReader::beginVector,
&LibertyReader::endVector);
defineGroupVisitor("vector", &LibertyReader::beginVector, &LibertyReader::endVector);
defineAttrVisitor("reference_time", &LibertyReader::visitReferenceTime);
defineGroupVisitor("normalized_driver_waveform",
&LibertyReader::beginNormalizedDriverWaveform,
&LibertyReader::endNormalizedDriverWaveform);
defineAttrVisitor("driver_waveform_name", &LibertyReader::visitDriverWaveformName);
defineAttrVisitor("driver_waveform_rise", &LibertyReader::visitDriverWaveformRise);
defineAttrVisitor("driver_waveform_fall", &LibertyReader::visitDriverWaveformFall);
}
void
@ -2283,7 +2287,7 @@ TimingGroup::makeTableModels(LibertyReader *reader)
transition,
slew_sigma_[rf_index],
receiver_model_,
output_current_[rf_index]));
output_waveforms_[rf_index]));
TimingType timing_type = attrs_->timingType();
if (timing_type == TimingType::clear
|| timing_type == TimingType::combinational
@ -2480,8 +2484,10 @@ void
LibertyReader::beginOutputCurrent(RiseFall *rf,
LibertyGroup *group)
{
if (timing_)
if (timing_) {
rf_ = rf;
output_currents_.clear();
}
else
libWarn(907, group, "output_current_%s group not in timing group.",
rf->name());
@ -2490,54 +2496,59 @@ LibertyReader::beginOutputCurrent(RiseFall *rf,
void
LibertyReader::endOutputCurrentRiseFall(LibertyGroup *group)
{
Set<float> axis_set1, axis_set2;
FloatSeq *axis_values1 = new FloatSeq;
FloatSeq *axis_values2 = new FloatSeq;
for (OutputCurrentWaveform *waveform : output_current_waveforms_) {
float axis_value1 = waveform->axisValue1();
if (!axis_set1.hasKey(axis_value1)) {
axis_set1.insert(axis_value1);
axis_values1->push_back(axis_value1);
Set<float> slew_set, cap_set;
FloatSeq *slew_values = new FloatSeq;
FloatSeq *cap_values = new FloatSeq;
for (OutputWaveform *waveform : output_currents_) {
float slew = waveform->slew();
if (!slew_set.hasKey(slew)) {
slew_set.insert(slew);
slew_values->push_back(slew);
}
float axis_value2 = waveform->axisValue2();
if (!axis_set2.hasKey(axis_value2)) {
axis_set2.insert(axis_value2);
axis_values2->push_back(axis_value2);
float cap = waveform->cap();
if (!cap_set.hasKey(cap)) {
cap_set.insert(cap);
cap_values->push_back(cap);
}
}
sort(axis_values1, std::less<float>());
sort(axis_values2, std::less<float>());
TableAxisPtr axis1 = std::make_shared<TableAxis>(axis_[0]->variable(),
axis_values1);
TableAxisPtr axis2 = std::make_shared<TableAxis>(axis_[1]->variable(),
axis_values2);
Vector<OutputCurrentWaveform*> waveforms(axis1->size() * axis2->size());
for (OutputCurrentWaveform *waveform : output_current_waveforms_) {
size_t index1, index2;
bool exists1, exists2;
axis1->findAxisIndex(waveform->axisValue1(), index1, exists1);
axis2->findAxisIndex(waveform->axisValue2(), index2, exists2);
if (exists1 && exists2) {
size_t index = index1 * axis2->size() + index2;
waveforms[index] = waveform;
sort(slew_values, std::less<float>());
sort(cap_values, std::less<float>());
TableAxisPtr slew_axis = make_shared<TableAxis>(TableAxisVariable::input_net_transition,
slew_values);
TableAxisPtr cap_axis = make_shared<TableAxis>(TableAxisVariable::total_output_net_capacitance,
cap_values);
FloatSeq *ref_times = new FloatSeq(slew_values->size());
Table1Seq current_waveforms(slew_axis->size() * cap_axis->size());
for (OutputWaveform *waveform : output_currents_) {
size_t slew_index, cap_index;
bool slew_exists, cap_exists;
slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
if (slew_exists && cap_exists) {
size_t index = slew_index * cap_axis->size() + cap_index;
current_waveforms[index] = waveform->currents();
(*ref_times)[slew_index] = waveform->referenceTime();
}
else
libWarn(913, group, "output current waveform %.2e %.2e not found.",
waveform->axisValue1(),
waveform->axisValue2());
waveform->slew(),
waveform->cap());
}
OutputCurrent *output_current = new OutputCurrent(axis1, axis2, waveforms);
timing_->setOutputCurrent(rf_, output_current);
Table1 *ref_time_tbl = new Table1(ref_times, slew_axis);
OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis,
current_waveforms,
ref_time_tbl);
timing_->setOutputWaveforms(rf_, output_current);
}
void
LibertyReader::beginVector(LibertyGroup *group)
{
if (timing_) {
beginTable(group, TableTemplateType::output_current, 1.0);
beginTable(group, TableTemplateType::output_current, current_scale_);
scale_factor_type_ = ScaleFactorType::unknown;
reference_time_exists_ = false;
if (!OutputCurrentWaveform::checkAxes(tbl_template_))
if (tbl_template_ && !OutputWaveforms::checkAxes(tbl_template_))
libWarn(118, group, "unsupported model axis.");
}
}
@ -2546,32 +2557,41 @@ void
LibertyReader::visitReferenceTime(LibertyAttr *attr)
{
getAttrFloat(attr, reference_time_, reference_time_exists_);
if (reference_time_exists_)
reference_time_ *= time_scale_;
}
void
LibertyReader::endVector(LibertyGroup *group)
{
if (timing_) {
FloatSeq *axis_values1 = axis_values_[0];
FloatSeq *axis_values2 = axis_values_[1];
if (axis_values1->size() == 1 && axis_values2->size() == 1) {
if (timing_ && tbl_template_) {
FloatSeq *slew_values = axis_values_[0];
FloatSeq *cap_values = axis_values_[1];
// Canonicalize axis order.
if (tbl_template_->axis1()->variable() == TableAxisVariable::input_net_transition) {
slew_values = axis_values_[0];
cap_values = axis_values_[1];
}
else {
slew_values = axis_values_[1];
cap_values = axis_values_[0];
}
if (slew_values->size() == 1 && cap_values->size() == 1) {
// Convert 1x1xN Table3 to Table1.
float axis_value1 = (*axis_values1)[0];
float axis_value2 = (*axis_values2)[0];
float slew = (*slew_values)[0];
float cap = (*cap_values)[0];
Table3 *table3 = dynamic_cast<Table3*>(table_.get());
FloatTable *values3 = table3->values3();
// Steal the values.
FloatSeq *values = (*values3)[0];
(*values3)[0] = nullptr;
Table1 *table1 = new Table1(values, axis_[2]);
OutputCurrentWaveform *waveform = new OutputCurrentWaveform(axis_value1,
axis_value2,
axis_[2], table1,
reference_time_);
output_current_waveforms_.push_back(waveform);
OutputWaveform *waveform = new OutputWaveform(slew, cap, table1, reference_time_);
output_currents_.push_back(waveform);
}
else
libWarn(912, group->line(), "vector index_1 and index_2 must have one value.");
libWarn(912,group->line(), "vector index_1 and index_2 must have exactly one value.");
if (!reference_time_exists_)
libWarn(908, group->line(), "vector reference_time not found.");
reference_time_exists_ = false;
@ -2580,6 +2600,68 @@ LibertyReader::endVector(LibertyGroup *group)
///////////////////////////////////////////////////////////////
void
LibertyReader::beginNormalizedDriverWaveform(LibertyGroup *group)
{
beginTable(group, TableTemplateType::delay, time_scale_);
driver_waveform_name_ = nullptr;
}
void
LibertyReader::visitDriverWaveformName(LibertyAttr *attr)
{
driver_waveform_name_ = stringCopy(getAttrString(attr));
}
void
LibertyReader::endNormalizedDriverWaveform(LibertyGroup *group)
{
if (table_) {
if (table_->axis1()->variable() == TableAxisVariable::input_net_transition) {
if (table_->axis2()->variable() == TableAxisVariable::normalized_voltage) {
// Null driver_waveform_name_ means it is the default unnamed waveform.
DriverWaveform *driver_waveform = new DriverWaveform(driver_waveform_name_,
table_);
library_->addDriverWaveform(driver_waveform);
}
else
libWarn(914, group, "normalized_driver_waveform variable_2 must be normalized_voltage");
}
else
libWarn(915, group, "normalized_driver_waveform variable_1 must be input_net_transition");
}
endTableModel();
}
void
LibertyReader::visitDriverWaveformRise(LibertyAttr *attr)
{
visitDriverWaveformRiseFall(attr, RiseFall::rise());
}
void
LibertyReader::visitDriverWaveformFall(LibertyAttr *attr)
{
visitDriverWaveformRiseFall(attr, RiseFall::fall());
}
void
LibertyReader::visitDriverWaveformRiseFall(LibertyAttr *attr,
const RiseFall *rf)
{
if (ports_) {
const char *driver_waveform_name = getAttrString(attr);
DriverWaveform *driver_waveform = library_->findDriverWaveform(driver_waveform_name);
if (driver_waveform) {
for (LibertyPort *port : *ports_)
port->setDriverWaveform(driver_waveform, rf);
}
}
}
///////////////////////////////////////////////////////////////
void
LibertyReader::makeInternalPowers(LibertyPort *port,
InternalPowerGroup *power_group)
@ -5365,7 +5447,7 @@ TimingGroup::TimingGroup(int line) :
intrinsic_exists_[rf_index] = false;
resistance_[rf_index] = 0.0F;
resistance_exists_[rf_index] = false;
output_current_[rf_index] = nullptr;
output_waveforms_[rf_index] = nullptr;
for (auto el_index : EarlyLate::rangeIndex()) {
delay_sigma_[rf_index][el_index] = nullptr;
@ -5496,17 +5578,17 @@ TimingGroup::setReceiverModel(ReceiverModelPtr receiver_model)
receiver_model_ = receiver_model;
}
OutputCurrent *
TimingGroup::outputCurrent(RiseFall *rf)
OutputWaveforms *
TimingGroup::outputWaveforms(RiseFall *rf)
{
return output_current_[rf->index()];
return output_waveforms_[rf->index()];
}
void
TimingGroup::setOutputCurrent(RiseFall *rf,
OutputCurrent *output_current)
TimingGroup::setOutputWaveforms(RiseFall *rf,
OutputWaveforms *output_waveforms)
{
output_current_[rf->index()] = output_current;
output_waveforms_[rf->index()] = output_waveforms;
}
////////////////////////////////////////////////////////////////
@ -5677,4 +5759,22 @@ PortNameBitIterator::findRangeBusNameNext()
range_name_next_ = nullptr;
}
////////////////////////////////////////////////////////////////
OutputWaveform::OutputWaveform(float slew,
float cap,
Table1 *currents,
float reference_time) :
slew_(slew),
cap_(cap),
currents_(currents),
reference_time_(reference_time)
{
}
OutputWaveform::~OutputWaveform()
{
delete currents_;
}
} // namespace

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -48,6 +48,11 @@ pinSlewProperty(const Pin *pin,
const MinMax *min_max,
Sta *sta);
static PropertyValue
pinArrivalProperty(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max,
Sta *sta);
static PropertyValue
pinSlackProperty(const Pin *pin,
const MinMax *min_max,
Sta *sta);
@ -882,6 +887,15 @@ getProperty(const Pin *pin,
return PropertyValue(&activity);
}
else if (stringEqual(property, "arrival_max_rise"))
return pinArrivalProperty(pin, RiseFall::rise(), MinMax::max(), sta);
else if (stringEqual(property, "arrival_max_fall"))
return pinArrivalProperty(pin, RiseFall::fall(), MinMax::max(), sta);
else if (stringEqual(property, "arrival_min_rise"))
return pinArrivalProperty(pin, RiseFall::rise(), MinMax::min(), sta);
else if (stringEqual(property, "arrival_min_fall"))
return pinArrivalProperty(pin, RiseFall::fall(), MinMax::min(), sta);
else if (stringEqual(property, "slack_max"))
return pinSlackProperty(pin, MinMax::max(), sta);
else if (stringEqual(property, "slack_max_fall"))
@ -912,6 +926,16 @@ getProperty(const Pin *pin,
throw PropertyUnknown("pin", property);
}
static PropertyValue
pinArrivalProperty(const Pin *pin,
const RiseFall *rf,
const MinMax *min_max,
Sta *sta)
{
Arrival arrival = sta->pinArrival(pin, rf, min_max);;
return PropertyValue(delayPropertyValue(arrival, sta));
}
static PropertyValue
pinSlackProperty(const Pin *pin,
const MinMax *min_max,

View File

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

View File

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

View File

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

View File

@ -56,11 +56,13 @@ RiseFall::opposite() const
}
RiseFall *
RiseFall::find(const char *tr_str)
RiseFall::find(const char *rf_str)
{
if (stringEq(tr_str, rise_.name()))
if (stringEq(rf_str, rise_.name())
|| stringEq(rf_str, rise_.shortName()))
return &rise_;
else if (stringEq(tr_str, fall_.name()))
else if (stringEq(rf_str, fall_.name())
|| stringEq(rf_str, fall_.shortName()))
return &fall_;
else
return nullptr;