liberty driver_waveform

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2023-03-22 09:57:54 -07:00
parent 55fc69577a
commit 6c3ba16e07
11 changed files with 849 additions and 379 deletions

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

@ -33,12 +33,12 @@ class Unit;
class Units;
class Report;
class Table;
class OutputCurrent;
class OutputCurrentWaveform;
class OutputWaveforms;
class OutputWaveform;
typedef Vector<float> FloatSeq;
typedef Vector<FloatSeq*> FloatTable;
typedef Vector<OutputCurrentWaveform*> OutputCurrentWaveformSeq;
typedef Vector<OutputWaveform*> OutputWaveformSeq;
TableAxisVariable
stringTableAxisVariable(const char *variable);
@ -56,7 +56,7 @@ public:
TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count],
ReceiverModelPtr receiver_model,
OutputCurrent *output_current);
OutputWaveforms *output_waveforms);
virtual ~GateTableModel();
virtual void gateDelay(const LibertyCell *cell,
const Pvt *pvt,
@ -80,6 +80,8 @@ public:
const TableModel *delayModel() const { return delay_model_; }
const TableModel *slewModel() const { return slew_model_; }
ReceiverModelPtr receiverModel() const { return receiver_model_; }
OutputWaveforms *outputWaveforms() const { return output_waveforms_; }
// Check the axes before making the model.
// Return true if the model axes are supported.
static bool checkAxes(const TablePtr table);
@ -127,7 +129,7 @@ protected:
TableModel *slew_model_;
TableModel *slew_sigma_models_[EarlyLate::index_count];
ReceiverModelPtr receiver_model_;
OutputCurrent *output_current_;
OutputWaveforms *output_waveforms_;
};
class CheckTableModel : public CheckTimingModel
@ -333,15 +335,21 @@ private:
class Table1 : public Table
{
public:
Table1();
Table1(FloatSeq *values,
TableAxisPtr axis1);
virtual ~Table1();
Table1(Table1 &&table);
Table1 &operator= (Table1 &&table);
virtual int order() const { return 1; }
virtual TableAxisPtr axis1() const { return axis1_; }
virtual float value(size_t index1,
size_t index2,
size_t index3) const;
float value(size_t index1) const;
float findValue(float value1) const;
float findValue(float value1,
bool extrapolate) const;
virtual float findValue(float value1,
float value2,
float value3) const;
@ -358,6 +366,7 @@ public:
string *result) const;
virtual void report(const Units *units,
Report *report) const;
FloatSeq *values() const { return values_; }
using Table::findValue;
private:
@ -462,6 +471,8 @@ public:
size_t &index,
bool &exists) const;
FloatSeq *values() const { return values_; }
float min() const { return (*values_)[0]; }
float max() const { return (*values_)[values_->size() - 1]; }
private:
TableAxisVariable variable_;
@ -484,63 +495,74 @@ private:
TableModel *capacitance_models_[2][RiseFall::index_count];
};
class OutputCurrentWaveform
class OutputWaveform
{
public:
OutputCurrentWaveform(float axis_value1,
float axis_value2,
TableAxisPtr axis,
Table1 *currents,
float reference_time);
~OutputCurrentWaveform();
float axisValue1() const { return axis_value1_; }
float axisValue2() const { return axis_value2_; }
TableAxisPtr axis() const { return axis_; }
OutputWaveform(float axis_value1,
float axis_value2,
Table1 *currents,
float reference_time);
OutputWaveform(float slew,
float cap,
Table1 *currents,
Table1 *voltages,
float reference_time);
~OutputWaveform();
float slew() const { return slew_; }
float cap() const { return cap_; }
TableAxisPtr timeAxis() const { return currents_->axis1(); }
Table1 *currents() const { return currents_; }
Table1 *voltages();
float referenceTime() const { return reference_time_; }
void reportWaveform(const Units *units,
int digits,
string *result);
static bool checkAxes(TableTemplate *tbl_template);
string reportCurrentWaveform(const Units *units,
int digits) const;
string reportVoltageWaveform(const Units *units,
int digits) const;
string reportWaveform(const Table1 *waveform,
const Unit *time_unit,
const Unit *waveform_unit,
int digits) const;
private:
float axis_value1_;
float axis_value2_;
TableAxisPtr axis_;
float slew_;
float cap_;
Table1 *currents_;
Table1 *voltages_;
float reference_time_;
};
// Two dimensional table of one dimensional time/current tables.
class OutputCurrent
// Two dimensional (slew/cap) table of one dimensional time/current tables.
class OutputWaveforms
{
public:
OutputCurrent(TableAxisPtr axis1,
TableAxisPtr axis2,
Vector<OutputCurrentWaveform*> &waveforms);
~OutputCurrent();
void reportWaveform(const LibertyCell *cell,
const Pvt *pvt,
float in_slew,
float load_cap,
int digits,
string *result) const;
OutputWaveforms(TableAxisPtr slew_axis,
TableAxisPtr cap_axis,
Vector<OutputWaveform*> &waveforms);
~OutputWaveforms();
OutputWaveform voltageWaveform(float in_slew,
float load_cap);
private:
void findAxisValues(float in_slew,
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2) const;
float axisValue(TableAxisPtr axis,
float in_slew,
float load_cap) const;
// Row.
TableAxisPtr axis1_;
TableAxisPtr slew_axis_;
// Column.
TableAxisPtr axis2_;
OutputCurrentWaveformSeq waveforms_;
TableAxisPtr cap_axis_;
OutputWaveformSeq waveforms_;
};
class DriverWaveform
{
public:
DriverWaveform(const char *name,
TablePtr waveforms);
~DriverWaveform();
const char *name() const { return name_; }
Table1 waveform(float slew);
private:
const char *name_;
TablePtr waveforms_;
};
} // namespace

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,54 @@ 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;
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);
Vector<OutputWaveform*> waveforms(slew_axis->size() * cap_axis->size());
for (OutputWaveform *waveform : output_currents_) {
size_t slew_index, cap_index;
bool slew_exists, cap_exists;
slew_axis->findAxisIndex(waveform->slew(), slew_index, slew_exists);
cap_axis->findAxisIndex(waveform->cap(), cap_index, cap_exists);
if (slew_exists && cap_exists) {
size_t index = slew_index * cap_axis->size() + cap_index;
waveforms[index] = waveform;
}
else
libWarn(913, group, "output current waveform %.2e %.2e not found.",
waveform->axisValue1(),
waveform->axisValue2());
waveform->slew(),
waveform->cap());
}
OutputCurrent *output_current = new OutputCurrent(axis1, axis2, waveforms);
timing_->setOutputCurrent(rf_, output_current);
OutputWaveforms *output_current = new OutputWaveforms(slew_axis, cap_axis, waveforms);
timing_->setOutputWaveforms(rf_, output_current);
}
void
LibertyReader::beginVector(LibertyGroup *group)
{
if (timing_) {
beginTable(group, TableTemplateType::output_current, 1.0);
beginTable(group, TableTemplateType::output_current, current_scale_);
scale_factor_type_ = ScaleFactorType::unknown;
reference_time_exists_ = false;
if (tbl_template_ && !OutputCurrentWaveform::checkAxes(tbl_template_))
if (tbl_template_ && !OutputWaveform::checkAxes(tbl_template_))
libWarn(118, group, "unsupported model axis.");
}
}
@ -2546,32 +2552,41 @@ void
LibertyReader::visitReferenceTime(LibertyAttr *attr)
{
getAttrFloat(attr, reference_time_, reference_time_exists_);
if (reference_time_exists_)
reference_time_ *= time_scale_;
}
void
LibertyReader::endVector(LibertyGroup *group)
{
if (timing_ && tbl_template_) {
FloatSeq *axis_values1 = axis_values_[0];
FloatSeq *axis_values2 = axis_values_[1];
if (axis_values1->size() == 1 && axis_values2->size() == 1) {
FloatSeq *slew_values = axis_values_[0];
FloatSeq *cap_values = axis_values_[1];
// Canonicalize axis order.
if (tbl_template_->axis1()->variable() == TableAxisVariable::input_net_transition) {
slew_values = axis_values_[0];
cap_values = axis_values_[1];
}
else {
slew_values = axis_values_[1];
cap_values = axis_values_[0];
}
if (slew_values->size() == 1 && cap_values->size() == 1) {
// Convert 1x1xN Table3 to Table1.
float axis_value1 = (*axis_values1)[0];
float axis_value2 = (*axis_values2)[0];
float slew = (*slew_values)[0];
float cap = (*cap_values)[0];
Table3 *table3 = dynamic_cast<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 +2595,68 @@ LibertyReader::endVector(LibertyGroup *group)
///////////////////////////////////////////////////////////////
void
LibertyReader::beginNormalizedDriverWaveform(LibertyGroup *group)
{
beginTable(group, TableTemplateType::delay, time_scale_);
driver_waveform_name_ = nullptr;
}
void
LibertyReader::visitDriverWaveformName(LibertyAttr *attr)
{
driver_waveform_name_ = stringCopy(getAttrString(attr));
}
void
LibertyReader::endNormalizedDriverWaveform(LibertyGroup *group)
{
if (table_) {
if (table_->axis1()->variable() == TableAxisVariable::input_net_transition) {
if (table_->axis2()->variable() == TableAxisVariable::normalized_voltage) {
// Null driver_waveform_name_ means it is the default unnamed waveform.
DriverWaveform *driver_waveform = new DriverWaveform(driver_waveform_name_,
table_);
library_->addDriverWaveform(driver_waveform);
}
else
libWarn(914, group, "normalized_driver_waveform variable_2 must be normalized_voltage");
}
else
libWarn(915, group, "normalized_driver_waveform variable_1 must be input_net_transition");
}
endTableModel();
}
void
LibertyReader::visitDriverWaveformRise(LibertyAttr *attr)
{
visitDriverWaveformRiseFall(attr, RiseFall::rise());
}
void
LibertyReader::visitDriverWaveformFall(LibertyAttr *attr)
{
visitDriverWaveformRiseFall(attr, RiseFall::fall());
}
void
LibertyReader::visitDriverWaveformRiseFall(LibertyAttr *attr,
const RiseFall *rf)
{
if (ports_) {
const char *driver_waveform_name = getAttrString(attr);
DriverWaveform *driver_waveform = library_->findDriverWaveform(driver_waveform_name);
if (driver_waveform) {
for (LibertyPort *port : *ports_)
port->setDriverWaveform(driver_waveform, rf);
}
}
}
///////////////////////////////////////////////////////////////
void
LibertyReader::makeInternalPowers(LibertyPort *port,
InternalPowerGroup *power_group)
@ -5365,7 +5442,7 @@ TimingGroup::TimingGroup(int line) :
intrinsic_exists_[rf_index] = false;
resistance_[rf_index] = 0.0F;
resistance_exists_[rf_index] = false;
output_current_[rf_index] = nullptr;
output_waveforms_[rf_index] = nullptr;
for (auto el_index : EarlyLate::rangeIndex()) {
delay_sigma_[rf_index][el_index] = nullptr;
@ -5496,17 +5573,17 @@ TimingGroup::setReceiverModel(ReceiverModelPtr receiver_model)
receiver_model_ = receiver_model;
}
OutputCurrent *
TimingGroup::outputCurrent(RiseFall *rf)
OutputWaveforms *
TimingGroup::outputWaveforms(RiseFall *rf)
{
return output_current_[rf->index()];
return output_waveforms_[rf->index()];
}
void
TimingGroup::setOutputCurrent(RiseFall *rf,
OutputCurrent *output_current)
TimingGroup::setOutputWaveforms(RiseFall *rf,
OutputWaveforms *output_waveforms)
{
output_current_[rf->index()] = output_current;
output_waveforms_[rf->index()] = output_waveforms;
}
////////////////////////////////////////////////////////////////

View File

@ -57,7 +57,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 +443,15 @@ public:
void endVector(LibertyGroup *group);
void visitReferenceTime(LibertyAttr *attr);
void beginNormalizedDriverWaveform(LibertyGroup *group);
void endNormalizedDriverWaveform(LibertyGroup *group);
void visitDriverWaveformName(LibertyAttr *attr);
void visitDriverWaveformRise(LibertyAttr *attr);
void visitDriverWaveformFall(LibertyAttr *attr);
void visitDriverWaveformRiseFall(LibertyAttr *attr,
const RiseFall *rf);
// Visitors for derived classes to overload.
virtual void beginGroup1(LibertyGroup *) {}
virtual void beginGroup2(LibertyGroup *) {}
@ -617,10 +626,11 @@ protected:
bool have_resistance_unit_;
const char *default_operating_condition_;
ReceiverModelPtr receiver_model_;
OutputCurrentWaveformSeq output_current_waveforms_;
OutputCurrent *output_current_;
OutputWaveformSeq output_currents_;
OutputWaveforms *output_waveforms_;
float reference_time_;
bool reference_time_exists_;
const char *driver_waveform_name_;
static constexpr char escape_ = '\\';
@ -783,9 +793,9 @@ public:
EarlyLate *early_late,
TableModel *model);
void setReceiverModel(ReceiverModelPtr receiver_model);
OutputCurrent *outputCurrent(RiseFall *rf);
void setOutputCurrent(RiseFall *rf,
OutputCurrent *output_current);
OutputWaveforms *outputWaveforms(RiseFall *rf);
void setOutputWaveforms(RiseFall *rf,
OutputWaveforms *output_current);
protected:
void makeLinearModels(LibertyLibrary *library);
@ -803,7 +813,7 @@ protected:
TableModel *transition_[RiseFall::index_count];
TableModel *delay_sigma_[RiseFall::index_count][EarlyLate::index_count];
TableModel *slew_sigma_[RiseFall::index_count][EarlyLate::index_count];
OutputCurrent *output_current_[RiseFall::index_count];
OutputWaveforms *output_waveforms_[RiseFall::index_count];
ReceiverModelPtr receiver_model_;
};

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
@ -801,6 +807,13 @@ Table0::report(const Units *units,
////////////////////////////////////////////////////////////////
Table1::Table1() :
Table(),
values_(nullptr),
axis1_(nullptr)
{
}
Table1::Table1(FloatSeq *values,
TableAxisPtr axis1) :
Table(),
@ -809,11 +822,30 @@ Table1::Table1(FloatSeq *values,
{
}
Table1::Table1(Table1 &&table) :
Table(),
values_(table.values_),
axis1_(table.axis1_)
{
table.values_ = nullptr;
table.axis1_ = nullptr;
}
Table1::~Table1()
{
delete values_;
}
Table1 &
Table1::operator=(Table1 &&table)
{
values_ = table.values_;
axis1_ = table.axis1_;
table.values_ = nullptr;
table.axis1_ = nullptr;
return *this;
}
float
Table1::value(size_t index1,
size_t,
@ -832,6 +864,19 @@ float
Table1::findValue(float value1,
float,
float) const
{
return findValue(value1);
}
float
Table1::findValue(float value1) const
{
return findValue(value1, true);
}
float
Table1::findValue(float value1,
bool extrapolate) const
{
if (axis1_->size() == 1)
return value(value1);
@ -843,7 +888,12 @@ Table1::findValue(float value1,
float y1 = value(index1);
float y2 = value(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
return (1 - dx1) * y1 + dx1 * y2;
if (x1 <= x1l && !extrapolate)
return y1;
else if (x1 >= x1u && !extrapolate)
return y2;
else
return (1 - dx1) * y1 + dx1 * y2;
}
}
@ -1514,26 +1564,67 @@ tableVariableUnit(TableAxisVariable variable,
////////////////////////////////////////////////////////////////
OutputCurrentWaveform::OutputCurrentWaveform(float axis_value1,
float axis_value2,
TableAxisPtr axis,
Table1 *currents,
float reference_time) :
axis_value1_(axis_value1),
axis_value2_(axis_value2),
axis_(axis),
OutputWaveform::OutputWaveform(float slew,
float cap,
Table1 *currents,
float reference_time) :
slew_(slew),
cap_(cap),
currents_(currents),
voltages_(nullptr),
reference_time_(reference_time)
{
}
OutputCurrentWaveform::~OutputCurrentWaveform()
OutputWaveform::OutputWaveform(float slew,
float cap,
Table1 *currents,
Table1 *voltages,
float reference_time) :
slew_(slew),
cap_(cap),
currents_(currents),
voltages_(voltages),
reference_time_(reference_time)
{
}
OutputWaveform::~OutputWaveform()
{
delete currents_;
delete voltages_;
}
Table1 *
OutputWaveform::voltages()
{
if (voltages_ == nullptr) {
FloatSeq *voltages = new FloatSeq;
voltages_ = new Table1(voltages, currents_->axis1());
// i = C dv/dt
// Integrate current waveform to find voltage waveform.
TableAxisPtr time_axis = currents_->axis1();
float prev_time = time_axis->axisValue(0);
float prev_current = currents_->value(0);
float voltage = 0.0;
voltages->push_back(voltage);
bool invert = currents_->value(time_axis->size() - 1) < 0.0;
for (size_t i = 1; i < time_axis->size(); i++) {
float time = time_axis->axisValue(i);
float current = currents_->value(i);
float dv = (current + prev_current) / 2.0 * (time - prev_time) / cap_;
voltage += invert ? -dv : dv;
voltages->push_back(voltage);
prev_time = time;
prev_current = current;
}
}
return voltages_;
}
bool
OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template)
OutputWaveform::checkAxes(TableTemplate *tbl_template)
{
TableAxisPtr axis1 = tbl_template->axis1();
TableAxisPtr axis2 = tbl_template->axis2();
@ -1549,83 +1640,181 @@ OutputCurrentWaveform::checkAxes(TableTemplate *tbl_template)
&& axis3->variable() == TableAxisVariable::time);
}
void
OutputCurrentWaveform::reportWaveform(const Units *units,
int digits,
string *result)
string
OutputWaveform::reportCurrentWaveform(const Units *units,
int digits) const
{
TableAxisPtr time_axis = currents_->axis1();
const Unit *time_unit = units->timeUnit();
const Unit *current_unit = units->currentUnit();
for (size_t i = 0; i < axis_->values()->size(); i++) {
*result += time_unit->asString(axis_->axisValue(i), digits);
*result += " ";
return reportWaveform(currents_, time_unit, current_unit, digits);
}
string
OutputWaveform::reportVoltageWaveform(const Units *units,
int digits) const
{
TableAxisPtr time_axis = voltages_->axis1();
const Unit *time_unit = units->timeUnit();
const Unit *voltage_unit = units->voltageUnit();
return reportWaveform(voltages_, time_unit, voltage_unit, digits);
}
string
OutputWaveform::reportWaveform(const Table1 *waveform,
const Unit *time_unit,
const Unit *waveform_unit,
int digits) const
{
string result;
TableAxisPtr time_axis = waveform->axis1();
for (size_t i = 0; i < time_axis->values()->size(); i++) {
float time = time_axis->axisValue(i);
result += time_unit->asString(time, digits);
result += " ";
}
*result += '\n';
for (size_t i = 0; i < currents_->axis1()->size(); i++) {
*result += current_unit->asString(currents_->value(i), digits);
*result += " ";
result += '\n';
for (size_t i = 0; i < time_axis->size(); i++) {
float value = waveform->value(i);
result += waveform_unit->asString(value, digits);
result += " ";
}
*result += '\n';
return result;
}
////////////////////////////////////////////////////////////////
OutputCurrent::OutputCurrent(TableAxisPtr axis1,
TableAxisPtr axis2,
OutputCurrentWaveformSeq &waveforms) :
axis1_(axis1),
axis2_(axis2),
OutputWaveforms::OutputWaveforms(TableAxisPtr slew_axis,
TableAxisPtr cap_axis,
OutputWaveformSeq &waveforms) :
slew_axis_(slew_axis),
cap_axis_(cap_axis),
waveforms_(waveforms)
{
}
OutputCurrent::~OutputCurrent()
OutputWaveforms::~OutputWaveforms()
{
waveforms_.deleteContents();
}
void
OutputCurrent::reportWaveform(const LibertyCell *cell,
const Pvt *,
float in_slew,
float load_cap,
int digits,
string *result) const
OutputWaveform
OutputWaveforms::voltageWaveform(float slew,
float cap)
{
float axis_value1, axis_value2;
findAxisValues(in_slew, load_cap,
axis_value1, axis_value2);
size_t index1 = axis1_->findAxisIndex(axis_value1);
size_t index2 = axis2_->findAxisIndex(axis_value2);
size_t index = index1 * axis2_->size() + index2;
waveforms_[index]->reportWaveform(cell->libertyLibrary()->units(), digits, result);
}
size_t slew_index = slew_axis_->findAxisIndex(slew);
size_t cap_index = cap_axis_->findAxisIndex(cap);
size_t wave_index00 = slew_index * cap_axis_->size() + cap_index;
size_t wave_index01 = slew_index * cap_axis_->size() + (cap_index + 1);
size_t wave_index10 = (slew_index + 1) * cap_axis_->size() + cap_index;
size_t wave_index11 = (slew_index + 1) * cap_axis_->size() + (cap_index + 1);
OutputWaveform *waveform00 = waveforms_[wave_index00];
OutputWaveform *waveform01 = waveforms_[wave_index01];
OutputWaveform *waveform10 = waveforms_[wave_index10];
OutputWaveform *waveform11 = waveforms_[wave_index11];
const Table1 *voltages00 = waveform00->voltages();
const Table1 *voltages01 = waveform01->voltages();
const Table1 *voltages10 = waveform10->voltages();
const Table1 *voltages11 = waveform11->voltages();
TableAxisPtr time_axis00 = voltages00->axis1();
TableAxisPtr time_axis01 = voltages01->axis1();
TableAxisPtr time_axis10 = voltages10->axis1();
TableAxisPtr time_axis11 = voltages11->axis1();
void
OutputCurrent::findAxisValues(float in_slew,
float load_cap,
// Return values.
float &axis_value1,
float &axis_value2) const
{
axis_value1 = axisValue(axis1_, in_slew, load_cap);
axis_value2 = axisValue(axis2_, in_slew, load_cap);
}
// Find time axis min/max.
size_t time_step_count = 20;
float time_min = time_axis00->min();
time_min = min(time_min, time_axis01->min());
time_min = min(time_min, time_axis10->min());
time_min = min(time_min, time_axis11->min());
float time_max = time_axis00->max();
time_max = max(time_max, time_axis01->max());
time_max = max(time_max, time_axis10->max());
time_max = max(time_max, time_axis11->max());
float time_step = (time_max - time_min) / time_step_count;
FloatSeq *time_values = new FloatSeq;
TableAxisPtr time_axis = make_shared<TableAxis>(time_axis00->variable(),
time_values);
float
OutputCurrent::axisValue(TableAxisPtr axis,
float in_slew,
float load_cap) const
{
TableAxisVariable var = axis->variable();
if (var == TableAxisVariable::input_net_transition)
return in_slew;
else if (var == TableAxisVariable::total_output_net_capacitance)
return load_cap;
else {
criticalError(240, "unsupported table axes");
return 0.0;
// Interpolate waveform samples at time steps.
float volt_max = voltages00->value(voltages00->values()->size() - 1);
size_t index1 = slew_index;
size_t index2 = cap_index;
float x1 = slew;
float x2 = cap;
float x1l = slew_axis_->axisValue(index1);
float x1u = slew_axis_->axisValue(index1 + 1);
float dx1 = (x1 - x1l) / (x1u - x1l);
float x2l = cap_axis_->axisValue(index2);
float x2u = cap_axis_->axisValue(index2 + 1);
float dx2 = (x2 - x2l) / (x2u - x2l);
FloatSeq *voltages = new FloatSeq;
bool waveform_started = false;
float prev_volt = 0.0;
constexpr float volt_tol = .01;
float volt_end = volt_max * (1.0 - volt_tol);
for (size_t i = 0; i <= time_step_count; i++) {
float time = time_min + time_step * i;
float y00 = voltages00->findValue(time, true);
float y10 = voltages10->findValue(time, true);
float y11 = voltages11->findValue(time, true);
float y01 = voltages01->findValue(time, true);
float voltage
= (1 - dx1) * (1 - dx2) * y00
+ dx1 * (1 - dx2) * y10
+ dx1 * dx2 * y11
+ (1 - dx1) * dx2 * y01;
if (voltage > volt_tol)
waveform_started = true;
if (waveform_started) {
time_values->push_back(time);
voltages->push_back(voltage);
}
if (prev_volt > volt_end)
break;
prev_volt = voltage;
}
// Interpolate reference time.
// (only depends on slew)
float ref_time
= (1 - dx1) * waveform00->referenceTime()
+ dx1 * waveform10->referenceTime();
Table1 *waveform = new Table1(voltages, time_axis);
return OutputWaveform(slew, cap, nullptr, waveform, ref_time);
}
////////////////////////////////////////////////////////////////
DriverWaveform::DriverWaveform(const char *name,
TablePtr waveforms) :
name_(name),
waveforms_(waveforms)
{
}
DriverWaveform::~DriverWaveform()
{
stringDelete(name_);
}
Table1
DriverWaveform::waveform(float slew)
{
TableAxisPtr volt_axis = waveforms_->axis2();
FloatSeq *time_values = new FloatSeq;
FloatSeq *volt_values = new FloatSeq;
for (float volt : *volt_axis->values()) {
float time = waveforms_->findValue(slew, volt, 0.0);
time_values->push_back(time);
volt_values->push_back(volt);
}
TableAxisPtr time_axis = make_shared<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

@ -81,7 +81,7 @@ private:
void writeHeader();
void writeStageInstances();
void writeInputSource();
void writeStepVoltSource(const Pin *pin,
void writeRampVoltSource(const Pin *pin,
const RiseFall *rf,
float slew,
float time,
@ -137,6 +137,11 @@ private:
void writeWaveformEdge(const RiseFall *rf,
float time,
float slew);
void writeWaveformVoltSource(const Pin *pin,
DriverWaveform *drvr_waveform,
const RiseFall *rf,
float slew,
int &volt_index);
void writeClkedStepSource(const Pin *pin,
const RiseFall *rf,
const Clock *clk,
@ -164,6 +169,7 @@ private:
int &volt_index);
float slewAxisMinValue(TimingArc *arc);
float pgPortVoltage(LibertyPgPort *pg_port);
void writePrintStmt();
// Stage "accessors".
//
@ -323,6 +329,7 @@ WritePathSpice::writeSpice()
// Find subckt port names as a side-effect of writeSubckts.
writeSubckts();
writeHeader();
writePrintStmt();
writeStageInstances();
writeMeasureStmts();
writeInputSource();
@ -369,6 +376,18 @@ WritePathSpice::writeHeader()
float time_step = max_time / 1e+3;
streamPrint(spice_stream_, ".tran %.3g %.3g\n\n",
time_step, max_time);
streamPrint(spice_stream_, ".options nomod\n");
}
void
WritePathSpice::writePrintStmt()
{
streamPrint(spice_stream_, ".print tran");
for (Stage stage = stageFirst(); stage <= stageLast(); stage++) {
streamPrint(spice_stream_, " v(%s)", stageDrvrPinName(stage));
streamPrint(spice_stream_, " v(%s)", stageLoadPinName(stage));
}
streamPrint(spice_stream_, "\n\n");
}
float
@ -477,11 +496,55 @@ WritePathSpice::writeInputWaveform()
float time0 = slew0;
int volt_index = 1;
const Pin *drvr_pin = stageDrvrPin(input_stage);
writeStepVoltSource(drvr_pin, rf, slew0, time0, volt_index);
const Pin *load_pin = stageLoadPin(input_stage);
const LibertyPort *load_port = network_->libertyPort(load_pin);
DriverWaveform *drvr_waveform = nullptr;
if (load_port)
drvr_waveform = load_port->driverWaveform(rf);
if (drvr_waveform)
writeWaveformVoltSource(drvr_pin, drvr_waveform,
rf, slew0, volt_index);
else
writeRampVoltSource(drvr_pin, rf, slew0, time0, volt_index);
}
void
WritePathSpice::writeStepVoltSource(const Pin *pin,
WritePathSpice::writeWaveformVoltSource(const Pin *pin,
DriverWaveform *drvr_waveform,
const RiseFall *rf,
float slew,
int &volt_index)
{
float volt0, volt1, volt_factor;
if (rf == RiseFall::rise()) {
volt0 = gnd_voltage_;
volt1 = power_voltage_;
volt_factor = power_voltage_;
}
else {
volt0 = power_voltage_;
volt1 = gnd_voltage_;
volt_factor = -power_voltage_;
}
streamPrint(spice_stream_, "v%d %s 0 pwl(\n",
volt_index,
network_->pathName(pin));
streamPrint(spice_stream_, "+%.3e %.3e\n", 0.0, volt0);
Table1 waveform = drvr_waveform->waveform(slew);
TableAxisPtr time_axis = waveform.axis1();
for (size_t time_index = 0; time_index < time_axis->size(); time_index++) {
float time = time_axis->axisValue(time_index);
float wave_volt = waveform.value(time_index);
float volt = volt0 + wave_volt * volt_factor;
streamPrint(spice_stream_, "+%.3e %.3e\n", time, volt);
}
streamPrint(spice_stream_, "+%.3e %.3e\n", maxTime(), volt1);
streamPrint(spice_stream_, "+)\n");
volt_index++;
}
void
WritePathSpice::writeRampVoltSource(const Pin *pin,
const RiseFall *rf,
float slew,
float time,
@ -942,7 +1005,7 @@ WritePathSpice::writeClkedStepSource(const Pin *pin,
Vertex *vertex = graph_->pinLoadVertex(pin);
float slew = findSlew(vertex, rf, nullptr, dcalc_ap_index);
float time = clkWaveformTImeOffset(clk) + clk->period() / 2.0;
writeStepVoltSource(pin, rf, slew, time, volt_index);
writeRampVoltSource(pin, rf, slew, time, volt_index);
}
void

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);
@ -4586,17 +4625,6 @@ find_clk_min_period(const Clock *clk,
return sta->findClkMinPeriod(clk, ignore_port_paths);
}
TmpString *
report_delay_calc_cmd(Edge *edge,
TimingArc *arc,
const Corner *corner,
const MinMax *min_max,
int digits)
{
cmdLinkedNetwork();
return Sta::sta()->reportDelayCalc(edge, arc, corner, min_max, digits);
}
////////////////////////////////////////////////////////////////
PinSeq
@ -5601,6 +5629,9 @@ full_name()
to);
}
TimingArcSeq &
timing_arcs() { return self->arcs(); }
} // TimingArcSet methods
%extend TimingArc {
@ -5611,6 +5642,24 @@ const char *from_edge_name() { return self->fromEdge()->asRiseFall()->name(); }
Transition *to_edge() { return self->toEdge(); }
const char *to_edge_name() { return self->toEdge()->asRiseFall()->name(); }
TimingRole *role() { return self->role(); }
Table1
voltage_waveform(float in_slew,
float load_cap)
{
GateTableModel *gate_model = dynamic_cast<GateTableModel*>(self->model());
if (gate_model) {
OutputWaveforms *output_waveforms = gate_model->outputWaveforms();
if (output_waveforms) {
OutputWaveform voltage_waveform =
output_waveforms->voltageWaveform(in_slew, load_cap);
Table1 voltages(std::move(*voltage_waveform.voltages()));
return voltages;
}
}
return Table1();
}
} // TimingArc methods
%extend Instance {

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;