liberty reader rewrite

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2026-02-27 16:57:08 -08:00
parent a47a8dd831
commit c010a0f99e
33 changed files with 4109 additions and 6830 deletions

View File

@ -17,4 +17,3 @@ define_scene ff -liberty NangateOpenCellLibrary_fast
report_checks -path_delay min_max
# report typical scene
report_checks -scene tt

View File

@ -1236,6 +1236,8 @@ Edge::to_string(const StaState *sta) const
string str = from(graph)->to_string(sta);
str += " -> ";
str += to(graph)->to_string(sta);
str += " ";
str += role()->to_string();
FuncExpr *when = arc_set_->cond();
if (when) {
str += " ";

View File

@ -171,6 +171,7 @@ path_iterator(const RiseFall *rf,
} // Vertex methods
%extend Edge {
std::string to_string() { return self->to_string(Sta::sta()); };
Vertex *from() { return self->from(Sta::sta()->graph()); }
Vertex *to() { return self->to(Sta::sta()->graph()); }
Pin *from_pin() { return self->from(Sta::sta()->graph())->pin(); }

View File

@ -253,7 +253,7 @@ public:
float wire_delay) const;
// Check for supported axis variables.
// Return true if axes are supported.
static bool checkSlewDegradationAxes(const TablePtr &table);
static bool checkSlewDegradationAxes(const TableModel *table_model);
float defaultInputPinCap() const { return default_input_pin_cap_; }
void setDefaultInputPinCap(float cap);
@ -1051,7 +1051,7 @@ public:
void setScale(ScaleFactorType type,
ScaleFactorPvt pvt,
float scale);
void print();
void report(Report *report);
protected:
std::string name_;

View File

@ -49,6 +49,7 @@ using FloatTable = std::vector<FloatSeq>;
// Sequence of 1D tables (order 1).
using Table1Seq = std::vector<Table*>;
using Waveform = Table;
using TableModelsEarlyLate = std::array<TableModel*, EarlyLate::index_count>;
TableAxisVariable
stringTableAxisVariable(const char *variable);
@ -63,11 +64,14 @@ class GateTableModel : public GateTimingModel
public:
GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *delay_sigma_models[EarlyLate::index_count],
TableModelsEarlyLate delay_sigma_models,
TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count],
TableModelsEarlyLate slew_sigma_models,
ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms);
GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *slew_model);
~GateTableModel() override;
void gateDelay(const Pvt *pvt,
float in_slew,
@ -100,7 +104,7 @@ public:
OutputWaveforms *outputWaveforms() const { return output_waveforms_.get(); }
// Check the axes before making the model.
// Return true if the model axes are supported.
static bool checkAxes(const TablePtr &table);
static bool checkAxes(const TableModel *table);
protected:
void maxCapSlew(float in_slew,
@ -135,9 +139,9 @@ protected:
static bool checkAxis(const TableAxis *axis);
std::unique_ptr<TableModel> delay_model_;
std::array<std::unique_ptr<TableModel>, EarlyLate::index_count> delay_sigma_models_;
TableModelsEarlyLate delay_sigma_models_;
std::unique_ptr<TableModel> slew_model_;
std::array<std::unique_ptr<TableModel>, EarlyLate::index_count> slew_sigma_models_;
TableModelsEarlyLate slew_sigma_models_;
ReceiverModelPtr receiver_model_;
std::unique_ptr<OutputWaveforms> output_waveforms_;
};
@ -147,7 +151,9 @@ class CheckTableModel : public CheckTimingModel
public:
CheckTableModel(LibertyCell *cell,
TableModel *model,
TableModel *sigma_models[EarlyLate::index_count]);
TableModelsEarlyLate sigma_models);
CheckTableModel(LibertyCell *cell,
TableModel *model);
~CheckTableModel() override;
ArcDelay checkDelay(const Pvt *pvt,
float from_slew,
@ -166,7 +172,7 @@ public:
// Check the axes before making the model.
// Return true if the model axes are supported.
static bool checkAxes(const TablePtr table);
static bool checkAxes(const TableModel *table);
protected:
void setIsScaled(bool is_scaled) override;
@ -197,7 +203,7 @@ protected:
static bool checkAxis(const TableAxis *axis);
std::unique_ptr<TableModel> model_;
std::array<std::unique_ptr<TableModel>, EarlyLate::index_count> sigma_models_;
TableModelsEarlyLate sigma_models_;
};
class TableAxis
@ -254,6 +260,8 @@ public:
const TableAxis *axis2() const { return axis2_.get(); }
const TableAxis *axis3() const { return axis3_.get(); }
const TableAxisPtr axis1ptr() const { return axis1_; }
const TableAxisPtr axis2ptr() const { return axis2_; }
const TableAxisPtr axis3ptr() const { return axis3_; }
void setIsScaled(bool is_scaled);
float value(size_t axis_idx1,
@ -409,7 +417,7 @@ public:
void setCapacitanceModel(TableModel table_model,
size_t segment,
const RiseFall *rf);
static bool checkAxes(TablePtr table);
static bool checkAxes(const TableModel *table);
private:
std::vector<TableModel> capacitance_models_;

View File

@ -99,7 +99,7 @@ class TimingArcAttrs
public:
TimingArcAttrs();
TimingArcAttrs(TimingSense sense);
virtual ~TimingArcAttrs();
~TimingArcAttrs();
TimingType timingType() const { return timing_type_; }
void setTimingType(TimingType type);
TimingSense timingSense() const { return timing_sense_; }
@ -145,7 +145,8 @@ class TimingArcSet
friend class LibertyCell;
public:
virtual ~TimingArcSet();
~TimingArcSet();
std::string to_string();
LibertyCell *libertyCell() const;
LibertyPort *from() const { return from_; }
LibertyPort *to() const { return to_; }
@ -249,7 +250,7 @@ public:
TimingArcSet *set() const { return set_; }
TimingSense sense() const;
// Index in TimingArcSet.
unsigned index() const { return index_; }
size_t index() const { return index_; }
TimingModel *model() const { return model_; }
GateTimingModel *gateModel(const Scene *scene,
const MinMax *min_max) const;
@ -270,7 +271,7 @@ public:
protected:
TimingModel *model(const Scene *scene,
const MinMax *min_max) const;
void setIndex(unsigned index);
void setIndex(size_t index);
void addScaledModel(const OperatingConditions *op_cond,
TimingModel *scaled_model);

View File

@ -24,8 +24,13 @@
#pragma once
#include <vector>
#include <string>
namespace sta {
using StdStringSeq = std::vector<std::string>;
// Iterate over the tokens in str separated by character sep.
// Similar in functionality to strtok, but does not leave the string
// side-effected. This is preferable to using strtok because it leaves
@ -49,4 +54,9 @@ private:
bool first_;
};
// Parse delimiter separated tokens and skipp spaces.
StdStringSeq
parseTokens(const std::string &s,
const char delimiter);
} // namespace

View File

@ -48,6 +48,7 @@ public:
static const RiseFall *fall() { return &fall_; }
static int riseIndex() { return rise_.sdf_triple_index_; }
static int fallIndex() { return fall_.sdf_triple_index_; }
const std::string &to_string_long() const { return name_; }
const std::string &to_string() const { return short_name_; }
const char *name() const { return name_.c_str(); }
const char *shortName() const { return short_name_.c_str(); }

View File

@ -37,7 +37,7 @@ namespace sta {
FuncExpr *
parseFuncExpr(const char *func,
LibertyCell *cell,
const LibertyCell *cell,
const char *error_msg,
Report *report)
{
@ -56,7 +56,7 @@ parseFuncExpr(const char *func,
}
LibExprReader::LibExprReader(const char *func,
LibertyCell *cell,
const LibertyCell *cell,
const char *error_msg,
Report *report) :
func_(func),
@ -69,7 +69,7 @@ LibExprReader::LibExprReader(const char *func,
// defined in LibertyReader.cc
LibertyPort *
libertyReaderFindPort(LibertyCell *cell,
libertyReaderFindPort(const LibertyCell *cell,
const char *port_name);
FuncExpr *

View File

@ -32,7 +32,7 @@ class LibertyCell;
FuncExpr *
parseFuncExpr(const char *func,
LibertyCell *cell,
const LibertyCell *cell,
const char *error_msg,
Report *report);

View File

@ -35,7 +35,7 @@ class LibExprReader
{
public:
LibExprReader(const char *func,
LibertyCell *cell,
const LibertyCell *cell,
const char *error_msg,
Report *report);
FuncExpr *makeFuncExprPort(const char *port_name);
@ -55,7 +55,7 @@ public:
private:
const char *func_;
LibertyCell *cell_;
const LibertyCell *cell_;
const char *error_msg_;
Report *report_;
FuncExpr *result_;

View File

@ -111,8 +111,6 @@ LibertyLibrary::LibertyLibrary(const char *name,
LibertyLibrary::~LibertyLibrary()
{
delete scale_factors_;
for (auto rf_index : RiseFall::rangeIndex()) {
TableModel *model = wire_slew_degradation_tbls_[rf_index];
delete model;
@ -271,14 +269,14 @@ LibertyLibrary::setScaleFactors(ScaleFactors *scales)
ScaleFactors *
LibertyLibrary::makeScaleFactors(const char *name)
{
auto [it, inserted] = scale_factors_map_.emplace(std::string(name), name);
auto [it, inserted] = scale_factors_map_.emplace(name, name);
return &it->second;
}
ScaleFactors *
LibertyLibrary::findScaleFactors(const char *name)
{
return findKeyValuePtr(scale_factors_map_, std::string(name));
return findKeyValuePtr(scale_factors_map_, name);
}
float
@ -400,20 +398,20 @@ LibertyLibrary::degradeWireSlew(const TableModel *model,
// Check for supported axis variables.
// Return true if axes are supported.
bool
LibertyLibrary::checkSlewDegradationAxes(const TablePtr &table)
LibertyLibrary::checkSlewDegradationAxes(const TableModel *table_model)
{
switch (table->order()) {
switch (table_model->order()) {
case 0:
return true;
case 1: {
const TableAxis *axis1 = table->axis1();
const TableAxis *axis1 = table_model->axis1();
TableAxisVariable var1 = axis1->variable();
return var1 == TableAxisVariable::output_pin_transition
|| var1 == TableAxisVariable::connect_delay;
}
case 2: {
const TableAxis *axis1 = table->axis1();
const TableAxis *axis2 = table->axis2();
const TableAxis *axis1 = table_model->axis1();
const TableAxis *axis2 = table_model->axis2();
TableAxisVariable var1 = axis1->variable();
TableAxisVariable var2 = axis2->variable();
return (var1 == TableAxisVariable::output_pin_transition
@ -1269,8 +1267,7 @@ LibertyCell::makeInternalPower(LibertyPort *port,
const std::shared_ptr<FuncExpr> &when,
InternalPowerModels &models)
{
internal_powers_.emplace_back(port, related_port, related_pg_pin,
when, models);
internal_powers_.emplace_back(port, related_port, related_pg_pin, when, models);
port_internal_powers_[port].push_back(internal_powers_.size() - 1);
}
@ -1485,6 +1482,10 @@ LibertyCell::makeSequential(int size,
port_to_seq_map_[sequentials_.back().output()] = idx;
port_to_seq_map_[sequentials_.back().outputInv()] = idx;
}
delete clk;
delete data;
delete clear;
delete preset;
}
Sequential *
@ -3087,7 +3088,8 @@ OperatingConditions::setWireloadTree(WireloadTree tree)
static EnumNameMap<ScaleFactorType> scale_factor_type_map =
{{ScaleFactorType::pin_cap, "pin_cap"},
{ScaleFactorType::wire_cap, "wire_res"},
{ScaleFactorType::wire_cap, "wire_cap"},
{ScaleFactorType::wire_res, "wire_res"},
{ScaleFactorType::min_period, "min_period"},
{ScaleFactorType::cell, "cell"},
{ScaleFactorType::hold, "hold"},
@ -3124,7 +3126,9 @@ scaleFactorTypeRiseFallSuffix(ScaleFactorType type)
|| type == ScaleFactorType::recovery
|| type == ScaleFactorType::removal
|| type == ScaleFactorType::nochange
|| type == ScaleFactorType::skew;
|| type == ScaleFactorType::skew
|| type == ScaleFactorType::leakage_power
|| type == ScaleFactorType::internal_power;
}
bool
@ -3144,7 +3148,8 @@ scaleFactorTypeLowHighSuffix(ScaleFactorType type)
EnumNameMap<ScaleFactorPvt> scale_factor_pvt_names =
{{ScaleFactorPvt::process, "process"},
{ScaleFactorPvt::volt, "volt"},
{ScaleFactorPvt::temp, "temp"}
{ScaleFactorPvt::temp, "temp"},
{ScaleFactorPvt::unknown, "unknown"}
};
ScaleFactorPvt
@ -3214,31 +3219,32 @@ ScaleFactors::scale(ScaleFactorType type,
}
void
ScaleFactors::print()
ScaleFactors::report(Report *report)
{
printf("%10s", " ");
std::string line = " ";
for (int pvt_index = 0; pvt_index < scale_factor_pvt_count; pvt_index++) {
ScaleFactorPvt pvt = (ScaleFactorPvt) pvt_index;
printf("%10s", scaleFactorPvtName(pvt));
stringAppend(line, "%10s", scaleFactorPvtName(pvt));
}
printf("\n");
report->reportLineString(line);
for (int type_index = 0; type_index < scale_factor_type_count; type_index++) {
ScaleFactorType type = (ScaleFactorType) type_index;
printf("%10s ", scaleFactorTypeName(type));
stringPrint(line, "%10s ", scaleFactorTypeName(type));
for (int pvt_index = 0; pvt_index < scale_factor_pvt_count; pvt_index++) {
if (scaleFactorTypeRiseFallSuffix(type)
|| scaleFactorTypeRiseFallPrefix(type)
|| scaleFactorTypeLowHighSuffix(type)) {
printf(" %.3f,%.3f",
scales_[type_index][pvt_index][RiseFall::riseIndex()],
scales_[type_index][pvt_index][RiseFall::fallIndex()]);
stringAppend(line, " %.3f,%.3f",
scales_[type_index][pvt_index][RiseFall::riseIndex()],
scales_[type_index][pvt_index][RiseFall::fallIndex()]);
}
else {
printf(" %.3f",
scales_[type_index][pvt_index][0]);
stringAppend(line, " %.3f",
scales_[type_index][pvt_index][0]);
}
}
printf("\n");
report->reportLineString(line);
}
}

View File

@ -363,6 +363,7 @@ scan_signal_type()
%extend TimingArcSet {
LibertyPort *from() { return self->from(); }
LibertyPort *to() { return self->to(); }
std::string to_string() { return self->to_string(); }
const TimingRole *role() { return self->role(); }
const char *sdf_cond() { return self->sdfCond().c_str(); }

View File

@ -74,6 +74,11 @@ proc report_lib_cell_ { cell scene } {
if { $filename != "" } {
report_line "File $filename"
}
report_lib_ports $cell $scene
report_timing_arcs $cell
}
proc report_lib_ports { cell scene } {
set iter [$cell liberty_port_iterator]
while {[$iter has_next]} {
set port [$iter next]
@ -115,5 +120,16 @@ proc report_lib_port { port scene } {
report_line " ${indent}$port_name [liberty_port_direction $port]$enable$func[port_capacitance_str $port $scene $sta_report_default_digits]"
}
proc report_timing_arcs { cell } {
set timing_arcs [$cell timing_arc_sets]
if { [llength $timing_arcs] > 0 } {
puts ""
puts "Timing arcs"
foreach timing_arc $timing_arcs {
puts [$timing_arc to_string]
}
}
}
# sta namespace end
}

View File

@ -35,14 +35,11 @@
namespace sta {
using std::string;
void
LibertyBuilder::init(Debug *debug,
Report *report)
LibertyBuilder::LibertyBuilder(Debug *debug,
Report *report) :
debug_(debug),
report_(report)
{
debug_ = debug;
report_ = report;
}
LibertyCell *
@ -105,7 +102,7 @@ LibertyBuilder::makeBusPortBit(ConcreteLibrary *library,
const char *bus_name,
int bit_index)
{
string bit_name;
std::string bit_name;
stringPrint(bit_name, "%s%c%d%c",
bus_name,
library->busBrktLeft(),
@ -189,6 +186,7 @@ LibertyBuilder::makeTimingArcs(LibertyCell *cell,
case TimingType::combinational:
if (seq
&& seq->isLatch()
&& seq->data()
&& seq->data()->hasPort(from_port))
// Latch D->Q timing arcs.
return makeLatchDtoQArcs(cell, from_port, to_port,
@ -307,8 +305,9 @@ LibertyBuilder::makeCombinationalArcs(LibertyCell *cell,
{
FuncExpr *func = to_port->function();
FuncExpr *enable = to_port->tristateEnable();
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::combinational(), attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port, nullptr,
TimingRole::combinational(),
attrs);
TimingSense sense = attrs->timingSense();
if (sense == TimingSense::unknown) {
// Timing sense not specified - find it from function.
@ -388,8 +387,9 @@ LibertyBuilder::makeLatchDtoQArcs(LibertyCell *cell,
TimingSense sense,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::latchDtoQ(), attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port, nullptr,
TimingRole::latchDtoQ(),
attrs);
TimingModel *model;
const RiseFall *to_rf = RiseFall::rise();
model = attrs->model(to_rf);
@ -456,8 +456,8 @@ LibertyBuilder::makeFromTransitionArcs(LibertyCell *cell,
const TimingRole *role,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
related_out, role, attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port,
related_out, role, attrs);
for (auto to_rf : RiseFall::range()) {
TimingModel *model = attrs->model(to_rf);
if (model)
@ -476,8 +476,8 @@ LibertyBuilder::makePresetClrArcs(LibertyCell *cell,
TimingArcSet *arc_set = nullptr;
TimingModel *model = attrs->model(to_rf);
if (model) {
arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::regSetClr(), attrs);
arc_set = cell->makeTimingArcSet(from_port, to_port, nullptr,
TimingRole::regSetClr(), attrs);
const RiseFall *opp_rf = to_rf->opposite();
switch (attrs->timingSense()) {
case TimingSense::positive_unate:
@ -509,8 +509,9 @@ LibertyBuilder::makeTristateEnableArcs(LibertyCell *cell,
bool to_fall,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::tristateEnable(), attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port, nullptr,
TimingRole::tristateEnable(),
attrs);
FuncExpr *tristate_enable = to_port->tristateEnable();
TimingSense sense = attrs->timingSense();
if (sense == TimingSense::unknown && tristate_enable)
@ -579,9 +580,9 @@ LibertyBuilder::makeTristateDisableArcs(LibertyCell *cell,
bool to_fall,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port,
TimingRole::tristateDisable(),
attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port, nullptr,
TimingRole::tristateDisable(),
attrs);
TimingSense sense = attrs->timingSense();
FuncExpr *tristate_enable = to_port->tristateEnable();
if (sense == TimingSense::unknown && tristate_enable)
@ -648,7 +649,8 @@ LibertyBuilder::makeClockTreePathArcs(LibertyCell *cell,
const TimingRole *role,
TimingArcAttrsPtr attrs)
{
TimingArcSet *arc_set = makeTimingArcSet(cell, nullptr, to_port, role, attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(nullptr, to_port, nullptr,
role, attrs);
for (const RiseFall *to_rf : RiseFall::range()) {
TimingModel *model = attrs->model(to_rf);
if (model) {
@ -683,8 +685,8 @@ LibertyBuilder::makeMinPulseWidthArcs(LibertyCell *cell,
{
if (from_port == nullptr)
from_port = to_port;
TimingArcSet *arc_set = makeTimingArcSet(cell, from_port, to_port, related_out,
role, attrs);
TimingArcSet *arc_set = cell->makeTimingArcSet(from_port, to_port, related_out,
role, attrs);
for (const RiseFall *from_rf : RiseFall::range()) {
TimingModel *model = attrs->model(from_rf);
if (model)
@ -695,27 +697,6 @@ LibertyBuilder::makeMinPulseWidthArcs(LibertyCell *cell,
////////////////////////////////////////////////////////////////
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
const TimingRole *role,
TimingArcAttrsPtr attrs)
{
return cell->makeTimingArcSet(from, to, nullptr, role, attrs);
}
TimingArcSet *
LibertyBuilder::makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
const TimingRole *role,
TimingArcAttrsPtr attrs)
{
return cell->makeTimingArcSet(from, to, related_out, role, attrs);
}
TimingArc *
LibertyBuilder::makeTimingArc(TimingArcSet *set,
const RiseFall *from_rf,

View File

@ -38,23 +38,21 @@ class Report;
class LibertyBuilder
{
public:
LibertyBuilder() {}
virtual ~LibertyBuilder() {}
void init(Debug *debug,
Report *report);
virtual LibertyCell *makeCell(LibertyLibrary *library,
const char *name,
const char *filename);
virtual LibertyPort *makePort(LibertyCell *cell,
const char *name);
virtual LibertyPort *makeBusPort(LibertyCell *cell,
const char *bus_name,
int from_index,
int to_index,
BusDcl *bus_dcl);
virtual LibertyPort *makeBundlePort(LibertyCell *cell,
const char *name,
ConcretePortSeq *members);
LibertyBuilder(Debug *debug,
Report *report);
LibertyCell *makeCell(LibertyLibrary *library,
const char *name,
const char *filename);
LibertyPort *makePort(LibertyCell *cell,
const char *name);
LibertyPort *makeBusPort(LibertyCell *cell,
const char *bus_name,
int from_index,
int to_index,
BusDcl *bus_dcl);
LibertyPort *makeBundlePort(LibertyCell *cell,
const char *name,
ConcretePortSeq *members);
// Build timing arc sets and their arcs given a type and sense.
// Port functions and cell latches are also used by this builder
// to get the correct roles.
@ -100,29 +98,18 @@ protected:
int from_index,
int to_index);
// Bus port bit (internal to makeBusPortBits).
virtual LibertyPort *makePort(LibertyCell *cell,
const char *bit_name,
int bit_index);
LibertyPort *makePort(LibertyCell *cell,
const char *bit_name,
int bit_index);
void makeBusPortBit(ConcreteLibrary *library,
LibertyCell *cell,
ConcretePort *bus_port,
const char *bus_name,
int index);
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
const TimingRole *role,
TimingArcAttrsPtr attrs);
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell,
LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
const TimingRole *role,
TimingArcAttrsPtr attrs);
virtual TimingArc *makeTimingArc(TimingArcSet *set,
const Transition *from_rf,
const Transition *to_rf,
TimingModel *model);
TimingArc *makeTimingArc(TimingArcSet *set,
const Transition *from_rf,
const Transition *to_rf,
TimingModel *model);
TimingArc *makeTimingArc(TimingArcSet *set,
const RiseFall *from_rf,
const RiseFall *to_rf,

View File

@ -42,8 +42,8 @@ using sta::Report;
using sta::Debug;
using sta::Network;
using sta::LibertyReader;
using sta::LibertyAttr;
using sta::LibertyGroup;
using sta::LibertySimpleAttr;
using sta::TimingGroup;
using sta::LibertyCell;
using sta::LibertyPort;
@ -164,13 +164,6 @@ class BigcoLibertyBuilder : public LibertyBuilder
public:
virtual LibertyCell *makeCell(LibertyLibrary *library, const char *name,
const char *filename);
protected:
virtual TimingArcSet *makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
const TimingRole *role,
TimingArcAttrsPtr attrs) override;
};
LibertyCell *
@ -182,16 +175,6 @@ BigcoLibertyBuilder::makeCell(LibertyLibrary *library, const char *name,
return cell;
}
TimingArcSet *
BigcoLibertyBuilder::makeTimingArcSet(LibertyCell *cell, LibertyPort *from,
LibertyPort *to,
LibertyPort *related_out,
const TimingRole *role,
TimingArcAttrsPtr attrs)
{
return cell->makeTimingArcSet(from, to, related_out, role, attrs);
}
////////////////////////////////////////////////////////////////
// Liberty reader to parse Bigco attributes.
@ -201,22 +184,18 @@ public:
BigcoLibertyReader(LibertyBuilder *builder);
protected:
virtual void visitAttr1(LibertyAttr *attr);
virtual void visitAttr2(LibertyAttr *attr);
virtual void beginLibrary(LibertyGroup *group);
virtual void visitAttr1(const LibertySimpleAttr *attr);
virtual void visitAttr2(const LibertySimpleAttr *attr);
virtual void beginLibrary(const LibertyGroup *group,
const LibertyGroup *library_group);
virtual TimingGroup *makeTimingGroup(int line);
virtual void beginCell(LibertyGroup *group);
virtual void beginCell(const LibertyGroup *group,
const LibertyGroup *library_group);
};
BigcoLibertyReader::BigcoLibertyReader(LibertyBuilder *builder) :
LibertyReader(builder)
{
// Define a visitor for the "thingy" attribute.
// Note that the function descriptor passed to defineAttrVisitor
// must be defined by the LibertyVisitor class, so a number of
// extra visitor functions are pre-defined for extensions.
defineAttrVisitor("thingy", &LibertyReader::visitAttr1);
defineAttrVisitor("frob", &LibertyReader::visitAttr2);
}
bool
@ -228,12 +207,13 @@ libertyCellRequired(const char *)
// Prune cells from liberty file based on libertyCellRequired predicate.
void
BigcoLibertyReader::beginCell(LibertyGroup *group)
BigcoLibertyReader::beginCell(const LibertyGroup *group,
const LibertyGroup *library_group)
{
const char *name = group->firstName();
if (name
&& libertyCellRequired(name))
LibertyReader::beginCell(group);
LibertyReader::beginCell(group, library_group);
}
TimingGroup *
@ -244,15 +224,16 @@ BigcoLibertyReader::makeTimingGroup(int line)
// Called at the beginning of a library group.
void
BigcoLibertyReader::beginLibrary(LibertyGroup *group)
BigcoLibertyReader::beginLibrary(const LibertyGroup *group,
const LibertyGroup *library_group)
{
LibertyReader::beginLibrary(group);
LibertyReader::beginLibrary(group, library_group);
// Do Bigco stuff here.
printf("Bigco was here.\n");
}
void
BigcoLibertyReader::visitAttr1(LibertyAttr *attr)
BigcoLibertyReader::visitAttr1(const LibertySimpleAttr *attr)
{
const char *thingy = getAttrString(attr);
if (thingy) {
@ -263,7 +244,7 @@ BigcoLibertyReader::visitAttr1(LibertyAttr *attr)
}
void
BigcoLibertyReader::visitAttr2(LibertyAttr *attr)
BigcoLibertyReader::visitAttr2(const LibertySimpleAttr *attr)
{
const char *frob = getAttrString(attr);
if (frob) {

View File

@ -87,14 +87,14 @@ EOL \r?\n
{FLOAT}{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(yyleng - 1);
yylval->emplace<float>(strtod(yytext, nullptr));
yylval->emplace<float>(strtof(yytext, nullptr));
return token::FLOAT;
}
{ALPHA}({ALPHA}|_|{DIGIT})*{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(yyleng - 1);
yylval->emplace<std::string>(yytext);
yylval->emplace<std::string>(yytext, yyleng);
return token::KEYWORD;
}
@ -107,7 +107,7 @@ EOL \r?\n
{TOKEN}{TOKEN_END} {
/* Push back the TOKEN_END character. */
yyless(yyleng - 1);
yylval->emplace<std::string>(yytext);
yylval->emplace<std::string>(yytext, yyleng);
return token::STRING;
}
@ -141,7 +141,7 @@ EOL \r?\n
<qstring>{EOL} {
error("unterminated string constant");
BEGIN(INITIAL);
yylval->emplace<std::string>(token_);
yylval->emplace<std::string>(token_);
return token::STRING;
}

View File

@ -52,7 +52,7 @@ sta::LibertyParse::error(const location_type &loc,
%require "3.2"
%skeleton "lalr1.cc"
%debug
//%debug
%define api.namespace {sta}
%locations
%define api.location.file "LibertyLocation.hh"
@ -72,7 +72,7 @@ sta::LibertyParse::error(const location_type &loc,
%left '^'
%left '!'
%type <sta::LibertyStmt *> statement complex_attr simple_attr variable group file
%type <void *> statement complex_attr simple_attr variable group file
%type <sta::LibertyAttrValueSeq *> attr_values
%type <sta::LibertyAttrValue *> attr_value
%type <std::string> string expr expr_term expr_term1 volt_expr
@ -158,11 +158,11 @@ string:
attr_value:
FLOAT
{ $$ = reader->makeFloatAttrValue($1); }
{ $$ = reader->makeAttrValueFloat($1); }
| expr
{ $$ = reader->makeStringAttrValue(std::move($1)); }
{ $$ = reader->makeAttrValueString(std::move($1)); }
| volt_expr
{ $$ = reader->makeStringAttrValue(std::move($1)); }
{ $$ = reader->makeAttrValueString(std::move($1)); }
;
/* Voltage expressions are ignored. */

View File

@ -70,21 +70,23 @@ LibertyParser::setFilename(const string &filename)
filename_ = filename;
}
LibertyStmt *
LibertyParser::makeDefine(LibertyAttrValueSeq *values,
LibertyDefine *
LibertyParser::makeDefine(const LibertyAttrValueSeq *values,
int line)
{
LibertyDefine *define = nullptr;
if (values->size() == 3) {
std::string define_name = (*values)[0]->stringValue();
const std::string &define_name = (*values)[0]->stringValue();
const std::string &group_type_name = (*values)[1]->stringValue();
const std::string &value_type_name = (*values)[2]->stringValue();
LibertyAttrType value_type = attrValueType(value_type_name.c_str());
LibertyGroupType group_type = groupType(group_type_name.c_str());
define = new LibertyDefine(std::move(define_name), group_type,
value_type, line);
LibertyAttrType value_type = attrValueType(value_type_name);
LibertyGroupType group_type = groupType(group_type_name);
define = new LibertyDefine(std::move(define_name), group_type, value_type, line);
LibertyGroup *group = this->group();
group->addStmt(define);
group->addDefine(define);
for (auto value : *values)
delete value;
delete values;
}
else
report_->fileWarn(24, filename_.c_str(), line,
@ -96,42 +98,47 @@ LibertyParser::makeDefine(LibertyAttrValueSeq *values,
// used to define valid attribute types. Beyond "string" these are
// guesses.
LibertyAttrType
LibertyParser::attrValueType(const char *value_type_name)
LibertyParser::attrValueType(const std::string &value_type_name)
{
if (stringEq(value_type_name, "string"))
if (value_type_name == "string")
return LibertyAttrType::attr_string;
else if (stringEq(value_type_name, "integer"))
else if (value_type_name == "integer")
return LibertyAttrType::attr_int;
else if (stringEq(value_type_name, "float"))
else if (value_type_name == "float")
return LibertyAttrType::attr_double;
else if (stringEq(value_type_name, "boolean"))
else if (value_type_name == "boolean")
return LibertyAttrType::attr_boolean;
else
return LibertyAttrType::attr_unknown;
}
LibertyGroupType
LibertyParser::groupType(const char *group_type_name)
LibertyParser::groupType(const std::string &group_type_name)
{
if (stringEq(group_type_name, "library"))
if (group_type_name == "library")
return LibertyGroupType::library;
else if (stringEq(group_type_name, "cell"))
else if (group_type_name == "cell")
return LibertyGroupType::cell;
else if (stringEq(group_type_name, "pin"))
else if (group_type_name == "pin")
return LibertyGroupType::pin;
else if (stringEq(group_type_name, "timing"))
else if (group_type_name == "timing")
return LibertyGroupType::timing;
else
return LibertyGroupType::unknown;
}
void
LibertyParser::groupBegin(std::string type,
LibertyParser::groupBegin(const std::string type,
LibertyAttrValueSeq *params,
int line)
{
LibertyGroup *group = new LibertyGroup(std::move(type), params, line);
group_visitor_->begin(group);
LibertyGroup *group =
new LibertyGroup(std::move(type),
params ? std::move(*params) : LibertyAttrValueSeq(),
line);
delete params;
LibertyGroup *parent_group = group_stack_.empty() ? nullptr : group_stack_.back();
group_visitor_->begin(group, parent_group);
group_stack_.push_back(group);
}
@ -139,20 +146,13 @@ LibertyGroup *
LibertyParser::groupEnd()
{
LibertyGroup *group = this->group();
group_visitor_->end(group);
group_stack_.pop_back();
LibertyGroup *parent =
group_stack_.empty() ? nullptr : group_stack_.back();
if (parent && group_visitor_->save(group)) {
parent->addStmt(group);
return group;
}
else if (group_visitor_->save(group))
return group;
else {
delete group;
return nullptr;
}
if (parent)
parent->addSubgroup(group);
group_visitor_->end(group, parent);
return group;
}
LibertyGroup *
@ -167,240 +167,65 @@ LibertyParser::deleteGroups()
deleteContents(group_stack_);
}
LibertyStmt *
LibertyParser::makeSimpleAttr(std::string name,
LibertyAttrValue *value,
LibertySimpleAttr *
LibertyParser::makeSimpleAttr(const std::string name,
const LibertyAttrValue *value,
int line)
{
LibertyAttr *attr = new LibertySimpleAttr(std::move(name), value, line);
group_visitor_->visitAttr(attr);
LibertySimpleAttr *attr = new LibertySimpleAttr(std::move(name),
std::move(*value), line);
delete value;
LibertyGroup *group = this->group();
if (group && group_visitor_->save(attr)) {
group->addStmt(attr);
return attr;
}
else {
delete attr;
return nullptr;
}
group->addAttr(attr);
group_visitor_->visitAttr(attr);
return attr;
}
LibertyStmt *
LibertyParser::makeComplexAttr(std::string name,
LibertyAttrValueSeq *values,
LibertyComplexAttr *
LibertyParser::makeComplexAttr(const std::string name,
const LibertyAttrValueSeq *values,
int line)
{
// Defines have the same syntax as complex attributes.
// Detect and convert them.
if (name == "define") {
LibertyStmt *define = makeDefine(values, line);
deleteContents(values);
delete values;
return define;
makeDefine(values, line);
return nullptr; // Define is not a complex attr; already added to group
}
else {
LibertyAttr *attr = new LibertyComplexAttr(std::move(name), values, line);
LibertyComplexAttr *attr = new LibertyComplexAttr(std::move(name),
std::move(*values),
line);
delete values;
LibertyGroup *group = this->group();
group->addAttr(attr);
group_visitor_->visitAttr(attr);
if (group_visitor_->save(attr)) {
LibertyGroup *group = this->group();
group->addStmt(attr);
return attr;
}
delete attr;
return nullptr;
return attr;
}
}
LibertyStmt *
LibertyParser::makeVariable(std::string var,
LibertyVariable *
LibertyParser::makeVariable(const std::string var,
float value,
int line)
{
LibertyVariable *variable = new LibertyVariable(std::move(var), value, line);
LibertyGroup *group = this->group();
group->addVariable(variable);
group_visitor_->visitVariable(variable);
if (group_visitor_->save(variable))
return variable;
else {
delete variable;
return nullptr;
}
return variable;
}
LibertyAttrValue *
LibertyParser::makeStringAttrValue(std::string value)
LibertyParser::makeAttrValueString(std::string value)
{
return new LibertyStringAttrValue(std::move(value));
return new LibertyAttrValue(std::move(value));
}
LibertyAttrValue *
LibertyParser::makeFloatAttrValue(float value)
{
return new LibertyFloatAttrValue(value);
}
const std::string &
LibertyFloatAttrValue::stringValue() const
{
criticalError(1127, "LibertyStringAttrValue called for float value");
static std::string null;
return null;
}
////////////////////////////////////////////////////////////////
LibertyStmt::LibertyStmt(int line) :
line_(line)
{
}
LibertyGroup::LibertyGroup(std::string type,
LibertyAttrValueSeq *params,
int line) :
LibertyStmt(line),
type_(std::move(type)),
params_(params),
stmts_(nullptr)
{
}
void
LibertyGroup::addStmt(LibertyStmt *stmt)
{
if (stmts_ == nullptr)
stmts_ = new LibertyStmtSeq;
stmts_->push_back(stmt);
}
LibertyGroup::~LibertyGroup()
{
if (params_) {
deleteContents(params_);
delete params_;
}
if (stmts_) {
deleteContents(stmts_);
delete stmts_;
}
}
const char *
LibertyGroup::firstName()
{
if (params_ && params_->size() > 0) {
LibertyAttrValue *value = (*params_)[0];
if (value->isString())
return value->stringValue().c_str();
}
return nullptr;
}
const char *
LibertyGroup::secondName()
{
if (params_ && params_->size() > 1) {
LibertyAttrValue *value = (*params_)[1];
if (value->isString())
return value->stringValue().c_str();
}
return nullptr;
}
////////////////////////////////////////////////////////////////
LibertyAttr::LibertyAttr(std::string name,
int line) :
LibertyStmt(line),
name_(std::move(name))
{
}
LibertySimpleAttr::LibertySimpleAttr(std::string name,
LibertyAttrValue *value,
int line) :
LibertyAttr(std::move(name), line),
value_(value)
{
}
LibertySimpleAttr::~LibertySimpleAttr()
{
delete value_;
}
LibertyAttrValueSeq *
LibertySimpleAttr::values() const
{
criticalError(1125, "valueIterator called for LibertySimpleAttribute");
return nullptr;
}
////////////////////////////////////////////////////////////////
LibertyComplexAttr::LibertyComplexAttr(std::string name,
LibertyAttrValueSeq *values,
int line) :
LibertyAttr(std::move(name), line),
values_(values)
{
}
LibertyComplexAttr::~LibertyComplexAttr()
{
if (values_) {
deleteContents(values_);
delete values_;
}
}
LibertyAttrValue *
LibertyComplexAttr::firstValue()
{
if (values_ && values_->size() > 0)
return (*values_)[0];
else
return nullptr;
}
LibertyStringAttrValue::LibertyStringAttrValue(std::string value) :
LibertyAttrValue(),
value_(std::move(value))
{
}
float
LibertyStringAttrValue::floatValue() const
{
criticalError(1126, "LibertyStringAttrValue called for float value");
return 0.0;
}
LibertyFloatAttrValue::LibertyFloatAttrValue(float value) :
value_(value)
{
}
////////////////////////////////////////////////////////////////
LibertyDefine::LibertyDefine(std::string name,
LibertyGroupType group_type,
LibertyAttrType value_type,
int line) :
LibertyStmt(line),
name_(std::move(name)),
group_type_(group_type),
value_type_(value_type)
{
}
////////////////////////////////////////////////////////////////
LibertyVariable::LibertyVariable(std::string var,
float value,
int line) :
LibertyStmt(line),
var_(std::move(var)),
value_(value)
LibertyParser::makeAttrValueFloat(float value)
{
return new LibertyAttrValue(value);
}
////////////////////////////////////////////////////////////////
@ -425,13 +250,13 @@ LibertyScanner::includeBegin()
error("nested include_file's are not supported");
else {
// include_file(filename);
std::regex include_regexp("include_file *\\( *([^)]+) *\\) *;?");
static const std::regex include_regexp("include_file *\\( *([^)]+) *\\) *;?");
std::cmatch matches;
if (std::regex_match(yytext, matches, include_regexp)) {
string filename = matches[1].str();
gzstream::igzstream *stream = new gzstream::igzstream(filename.c_str());
if (stream->is_open()) {
yypush_buffer_state(yy_create_buffer(stream, 256));
yypush_buffer_state(yy_create_buffer(stream, 16384));
filename_prev_ = filename_;
stream_prev_ = stream_;
@ -471,4 +296,323 @@ LibertyScanner::error(const char *msg)
report_->fileError(1866, filename_.c_str(), lineno(), "%s", msg);
}
////////////////////////////////////////////////////////////////
LibertyGroup::LibertyGroup(std::string type,
LibertyAttrValueSeq params,
int line) :
type_(std::move(type)),
params_(std::move(params)),
line_(line)
{
}
LibertyGroup::~LibertyGroup()
{
clear();
}
void
LibertyGroup::clear()
{
deleteContents(params_);
deleteContents(simple_attr_map_);
for (auto &attr : complex_attr_map_)
deleteContents(attr.second);
complex_attr_map_.clear();
deleteContents(subgroups_);
subgroup_map_.clear();
deleteContents(define_map_);
deleteContents(variables_);
}
void
LibertyGroup::addSubgroup(LibertyGroup *subgroup)
{
subgroups_.push_back(subgroup);
subgroup_map_[subgroup->type()].push_back(subgroup);
}
void
LibertyGroup::deleteSubgroup(const LibertyGroup *subgroup)
{
if (subgroup == subgroups_.back()) {
subgroups_.pop_back();
subgroup_map_[subgroup->type()].pop_back();
delete subgroup;
}
else
criticalError(1128, "LibertyAttrValue::floatValue() called on string");
}
void
LibertyGroup::addDefine(LibertyDefine *define)
{
const string &define_name = define->name();
LibertyDefine *prev_define = findKey(define_map_, define_name);
if (prev_define) {
define_map_.erase(define_name);
delete prev_define;
}
define_map_[define_name] = define;
}
void
LibertyGroup::addAttr(LibertySimpleAttr *attr)
{
// Only keep the most recent simple attribute value.
const auto &itr = simple_attr_map_.find(attr->name());
if (itr != simple_attr_map_.end())
delete itr->second;
simple_attr_map_[attr->name()] = attr;
}
void
LibertyGroup::addAttr(LibertyComplexAttr *attr)
{
complex_attr_map_[attr->name()].push_back(attr);
}
void
LibertyGroup::addVariable(LibertyVariable *var)
{
variables_.push_back(var);
}
const char *
LibertyGroup::firstName() const
{
if (params_.size() >= 1) {
LibertyAttrValue *value = params_[0];
if (value->isString())
return value->stringValue().c_str();
}
return nullptr;
}
const char *
LibertyGroup::secondName() const
{
LibertyAttrValue *value = params_[1];
if (value->isString())
return value->stringValue().c_str();
else
return nullptr;
}
const LibertyGroupSeq &
LibertyGroup::findSubgroups(const std::string type) const
{
return findKeyValue(subgroup_map_, type);
}
const LibertyGroup *
LibertyGroup::findSubgroup(const std::string type) const
{
const LibertyGroupSeq &groups = findKeyValue(subgroup_map_, type);
if (groups.size() >= 1)
return groups[0];
else
return nullptr;
}
const LibertySimpleAttr *
LibertyGroup::findSimpleAttr(const std::string attr_name) const
{
return findKeyValue(simple_attr_map_, attr_name);
}
const LibertyComplexAttrSeq &
LibertyGroup::findComplexAttrs(const std::string attr_name) const
{
return findKeyValue(complex_attr_map_, attr_name);
}
const LibertyComplexAttr *
LibertyGroup::findComplexAttr(const std::string attr_name) const
{
const LibertyComplexAttrSeq &attrs = findKeyValue(complex_attr_map_, attr_name);
if (attrs.size() >= 1)
return attrs[0];
else
return nullptr;
}
const std::string *
LibertyGroup::findAttrString(const std::string attr_name) const
{
const LibertySimpleAttr *attr = findSimpleAttr(attr_name);
if (attr)
return &attr->value().stringValue();
else
return nullptr;
}
void
LibertyGroup::findAttrFloat(const std::string attr_name,
// Return values.
float &value,
bool &exists) const
{
const LibertySimpleAttr *attr = findSimpleAttr(attr_name);
if (attr) {
const LibertyAttrValue &attr_value = attr->value();
if (attr_value.isFloat()) {
value = attr_value.floatValue();
exists = true;
return;
}
else {
// Possibly quoted string float.
const std::string &float_str = attr_value.stringValue();
char *end = nullptr;
value = std::strtof(float_str.c_str(), &end);
if (end) {
exists = true;
return;
}
}
}
exists = false;
}
void
LibertyGroup::findAttrInt(const std::string attr_name,
// Return values.
int &value,
bool &exists) const
{
const LibertySimpleAttr *attr = findSimpleAttr(attr_name);
if (attr) {
const LibertyAttrValue &attr_value = attr->value();
if (attr_value.isFloat()) {
value = static_cast<int>(attr_value.floatValue());
exists = true;
return;
}
}
exists = false;
}
////////////////////////////////////////////////////////////////
LibertySimpleAttr::LibertySimpleAttr(const std::string name,
const LibertyAttrValue value,
int line) :
name_(std::move(name)),
line_(line),
value_(std::move(value))
{
}
const std::string *
LibertySimpleAttr::stringValue() const
{
return &value().stringValue();
}
////////////////////////////////////////////////////////////////
LibertyComplexAttr::LibertyComplexAttr(std::string name,
const LibertyAttrValueSeq values,
int line) :
name_(std::move(name)),
values_(std::move(values)),
line_(line)
{
}
LibertyComplexAttr::~LibertyComplexAttr()
{
deleteContents(values_);
}
const LibertyAttrValue *
LibertyComplexAttr::firstValue() const
{
if (values_.size() > 0)
return values_[0];
else
return nullptr;
}
////////////////////////////////////////////////////////////////
LibertyAttrValue::LibertyAttrValue(std::string value) :
string_value_(std::move(value))
{
}
LibertyAttrValue::LibertyAttrValue(float value) :
float_value_(value)
{
}
bool
LibertyAttrValue::isFloat() const
{
return string_value_.empty();
}
bool
LibertyAttrValue::isString() const
{
return !string_value_.empty();
}
float
LibertyAttrValue::floatValue() const
{
if (!string_value_.empty())
criticalError(1127, "LibertyAttrValue::floatValue() called on string");
return float_value_;
}
void
LibertyAttrValue::floatValue(// Return values.
float &value,
bool &valid) const
{
valid = false;
if (string_value_.empty()) {
value = float_value_;
valid = true;
}
else {
// Some floats are enclosed in quotes.
char *end;
value = strtof(string_value_.c_str(), &end);
if ((*end == '\0'
|| isspace(*end))
// strtof support INF as a valid float.
&& string_value_ != "inf") {
valid = true;
}
}
}
////////////////////////////////////////////////////////////////
LibertyDefine::LibertyDefine(std::string name,
LibertyGroupType group_type,
LibertyAttrType value_type,
int line) :
name_(std::move(name)),
group_type_(group_type),
value_type_(value_type),
line_(line)
{
}
////////////////////////////////////////////////////////////////
LibertyVariable::LibertyVariable(std::string var,
float value,
int line) :
var_(std::move(var)),
value_(value),
line_(line)
{
}
} // namespace

View File

@ -34,20 +34,22 @@ namespace sta {
class Report;
class LibertyGroupVisitor;
class LibertyStmt;
class LibertyGroup;
class LibertyAttr;
class LibertyDefine;
class LibertySimpleAttr;
class LibertyComplexAttr;
class LibertyAttrValue;
class LibertyVariable;
class LibertyScanner;
using LibertyStmtSeq = std::vector<LibertyStmt*>;
using LibertyGroupSeq = std::vector<LibertyGroup*>;
using LibertyAttrSeq = std::vector<LibertyAttr*>;
using LibertyAttrMap = std::map<std::string, LibertyAttr*>;
using LibertySubGroupMap = std::map<std::string, LibertyGroupSeq>;
using LibertySimpleAttrMap = std::map<std::string, LibertySimpleAttr*>;
using LibertyComplexAttrSeq = std::vector<LibertyComplexAttr*>;
using LibertyComplexAttrMap = std::map<std::string, LibertyComplexAttrSeq>;
using LibertyDefineMap = std::map<std::string, LibertyDefine*>;
using LibertyAttrValueSeq = std::vector<LibertyAttrValue*>;
using LibertyVariableSeq = std::vector<LibertyVariable*>;
using LibertyVariableMap = std::map<std::string, float>;
using LibertyGroupVisitorMap = std::map<std::string, LibertyGroupVisitor*>;
@ -65,27 +67,27 @@ public:
const std::string &filename() const { return filename_; }
void setFilename(const std::string &filename);
Report *report() const { return report_; }
LibertyStmt *makeDefine(LibertyAttrValueSeq *values,
int line);
LibertyAttrType attrValueType(const char *value_type_name);
LibertyGroupType groupType(const char *group_type_name);
void groupBegin(std::string type,
LibertyDefine *makeDefine(const LibertyAttrValueSeq *values,
int line);
LibertyAttrType attrValueType(const std::string &value_type_name);
LibertyGroupType groupType(const std::string &group_type_name);
void groupBegin(const std::string type,
LibertyAttrValueSeq *params,
int line);
LibertyGroup *groupEnd();
LibertyGroup *group();
void deleteGroups();
LibertyStmt *makeSimpleAttr(std::string name,
LibertyAttrValue *value,
int line);
LibertyStmt *makeComplexAttr(std::string name,
LibertyAttrValueSeq *values,
int line);
LibertyAttrValue *makeStringAttrValue(std::string value);
LibertyAttrValue *makeFloatAttrValue(float value);
LibertyStmt *makeVariable(std::string var,
float value,
int line);
LibertySimpleAttr *makeSimpleAttr(const std::string name,
const LibertyAttrValue *value,
int line);
LibertyComplexAttr *makeComplexAttr(const std::string name,
const LibertyAttrValueSeq *values,
int line);
LibertyAttrValue *makeAttrValueString(const std::string value);
LibertyAttrValue *makeAttrValueFloat(float value);
LibertyVariable *makeVariable(const std::string var,
float value,
int line);
private:
std::string filename_;
@ -94,178 +96,171 @@ private:
LibertyGroupSeq group_stack_;
};
// Abstract base class for liberty statements.
class LibertyStmt
{
public:
LibertyStmt(int line);
virtual ~LibertyStmt() {}
int line() const { return line_; }
virtual bool isGroup() const { return false; }
virtual bool isAttribute() const { return false; }
virtual bool isSimpleAttr() const { return false; }
virtual bool isComplexAttr() const { return false; }
virtual bool isDefine() const { return false; }
virtual bool isVariable() const { return false; }
protected:
int line_;
};
// Groups are a type keyword with a set of parameters and statements
// enclosed in brackets.
// type([param1][, param2]...) { stmts.. }
class LibertyGroup : public LibertyStmt
{
public:
LibertyGroup(std::string type,
LibertyAttrValueSeq *params,
int line);
virtual ~LibertyGroup();
virtual bool isGroup() const { return true; }
const std::string &type() const { return type_; }
LibertyAttrValueSeq *params() const { return params_; }
// First param as a string.
const char *firstName();
// Second param as a string.
const char *secondName();
void addStmt(LibertyStmt *stmt);
LibertyStmtSeq *stmts() const { return stmts_; }
protected:
void parseNames(LibertyAttrValueSeq *values);
std::string type_;
LibertyAttrValueSeq *params_;
LibertyStmtSeq *stmts_;
};
// Abstract base class for attributes.
class LibertyAttr : public LibertyStmt
{
public:
LibertyAttr(std::string name,
int line);
const std::string &name() const { return name_; }
virtual LibertyAttrValueSeq *values() const = 0;
virtual LibertyAttrValue *firstValue() = 0;
protected:
std::string name_;
};
// Abstract base class for simple attributes.
// name : value;
class LibertySimpleAttr : public LibertyAttr
{
public:
LibertySimpleAttr(std::string name,
LibertyAttrValue *value,
int line);
virtual ~LibertySimpleAttr();
bool isSimpleAttr() const override { return true; };
LibertyAttrValue *firstValue() override { return value_; };
LibertyAttrValueSeq *values() const override;
private:
LibertyAttrValue *value_;
};
// Complex attributes have multiple values.
// name(attr_value1[, attr_value2]...);
class LibertyComplexAttr : public LibertyAttr
{
public:
LibertyComplexAttr(std::string name,
LibertyAttrValueSeq *values,
int line);
virtual ~LibertyComplexAttr();
bool isComplexAttr() const override { return true; };
LibertyAttrValue *firstValue() override ;
LibertyAttrValueSeq *values() const override { return values_; }
private:
LibertyAttrValueSeq *values_;
};
// Attribute values are a string or float.
class LibertyAttrValue
{
public:
LibertyAttrValue() {}
virtual ~LibertyAttrValue() {}
virtual bool isString() const = 0;
virtual bool isFloat() const = 0;
virtual float floatValue() const = 0;
virtual const std::string &stringValue() const = 0;
};
class LibertyStringAttrValue : public LibertyAttrValue
{
public:
LibertyStringAttrValue(std::string value);
virtual ~LibertyStringAttrValue() {}
bool isFloat() const override { return false; }
bool isString() const override { return true; }
float floatValue() const override ;
const std::string &stringValue() const override { return value_; }
LibertyAttrValue(float value);
LibertyAttrValue(std::string value);
bool isString() const;
bool isFloat() const;
float floatValue() const;
void floatValue(// Return values.
float &value,
bool &valid) const;
const std::string &stringValue() const { return string_value_; }
private:
std::string value_;
float float_value_;
std::string string_value_;
};
class LibertyFloatAttrValue : public LibertyAttrValue
// Groups are a type keyword with a set of parameters and statements
// enclosed in brackets.
// type([param1][, param2]...) { stmts.. }
class LibertyGroup
{
public:
LibertyFloatAttrValue(float value);
virtual ~LibertyFloatAttrValue() {}
bool isString() const override { return false; }
bool isFloat() const override { return true; }
float floatValue() const override { return value_; }
const std::string &stringValue() const override;
LibertyGroup(const std::string type,
const LibertyAttrValueSeq params,
int line);
~LibertyGroup();
void clear();
const std::string &type() const { return type_; }
const LibertyAttrValueSeq &params() const { return params_; }
// First param as a string.
const char *firstName() const;
// Second param as a string.
const char *secondName() const;
int line() const { return line_; }
const LibertyGroupSeq &findSubgroups(const std::string type) const;
const LibertyGroup *findSubgroup(const std::string type) const;
const LibertySimpleAttr *findSimpleAttr(const std::string attr_name) const;
const LibertyComplexAttrSeq &findComplexAttrs(const std::string attr_name) const;
const LibertyComplexAttr *findComplexAttr(const std::string attr_name) const;
const std::string *findAttrString(const std::string attr_name) const;
void findAttrFloat(const std::string attr_name,
// Return values.
float &value,
bool &exists) const;
void findAttrInt(const std::string attr_name,
// Return values.
int &value,
bool &exists) const;
const LibertyGroupSeq &subgroups() const { return subgroups_; }
const LibertyDefineMap &defineMap() const { return define_map_; }
void addSubgroup(LibertyGroup *subgroup);
void deleteSubgroup(const LibertyGroup *subgroup);
void addAttr(LibertySimpleAttr *attr);
void addAttr(LibertyComplexAttr *attr);
void addDefine(LibertyDefine *define);
void addVariable(LibertyVariable *var);
protected:
std::string type_;
LibertyAttrValueSeq params_;
int line_;
LibertySimpleAttrMap simple_attr_map_;
LibertyComplexAttrMap complex_attr_map_;
LibertyGroupSeq subgroups_;
LibertySubGroupMap subgroup_map_;
LibertyDefineMap define_map_;
LibertyVariableSeq variables_;
};
class LibertyGroupLineLess
{
public:
bool
operator()(const LibertyGroup *group1,
const LibertyGroup *group2) const {
return group1->line() < group2->line();
}
};
// Simple attributes: name : value;
class LibertySimpleAttr
{
public:
LibertySimpleAttr(const std::string name,
const LibertyAttrValue value,
int line);
const std::string &name() const { return name_; }
const LibertyAttrValue &value() const { return value_; };
const std::string *stringValue() const;
int line() const { return line_; }
private:
float value_;
std::string name_;
int line_;
LibertyAttrValue value_;
};
// Complex attributes have multiple values.
// name(attr_value1[, attr_value2]...);
class LibertyComplexAttr
{
public:
LibertyComplexAttr(const std::string name,
const LibertyAttrValueSeq values,
int line);
~LibertyComplexAttr();
const std::string &name() const { return name_; }
const LibertyAttrValue *firstValue() const;
const LibertyAttrValueSeq &values() const { return values_; }
int line() const { return line_; }
private:
std::string name_;
LibertyAttrValueSeq values_;
int line_;
};
// Define statements define new simple attributes.
// define(attribute_name, group_name, attribute_type);
// attribute_type is string|integer|float.
class LibertyDefine : public LibertyStmt
class LibertyDefine
{
public:
LibertyDefine(std::string name,
LibertyGroupType group_type,
LibertyAttrType value_type,
int line);
virtual bool isDefine() const { return true; }
const std::string &name() const { return name_; }
LibertyGroupType groupType() const { return group_type_; }
LibertyAttrType valueType() const { return value_type_; }
int line() const { return line_; }
private:
std::string name_;
LibertyGroupType group_type_;
LibertyAttrType value_type_;
int line_;
};
// The Liberty User Guide Version 2003.12 fails to document variables.
// var = value;
// The only example I have only uses float values, so I am assuming
// that is all that is supported (which is probably wrong).
class LibertyVariable : public LibertyStmt
class LibertyVariable
{
public:
LibertyVariable(std::string var,
float value,
int line);
bool isVariable() const override { return true; }
int line() const { return line_; }
const std::string &variable() const { return var_; }
float value() const { return value_; }
private:
std::string var_;
float value_;
int line_;
};
class LibertyGroupVisitor
@ -273,14 +268,13 @@ class LibertyGroupVisitor
public:
LibertyGroupVisitor() {}
virtual ~LibertyGroupVisitor() {}
virtual void begin(LibertyGroup *group) = 0;
virtual void end(LibertyGroup *group) = 0;
virtual void visitAttr(LibertyAttr *attr) = 0;
virtual void begin(const LibertyGroup *group,
LibertyGroup *parent_group) = 0;
virtual void end(const LibertyGroup *group,
LibertyGroup *parent_group) = 0;
virtual void visitAttr(const LibertySimpleAttr *attr) = 0;
virtual void visitAttr(const LibertyComplexAttr *attr) = 0;
virtual void visitVariable(LibertyVariable *variable) = 0;
// Predicates to save parse structure after visits.
virtual bool save(LibertyGroup *group) = 0;
virtual bool save(LibertyAttr *attr) = 0;
virtual bool save(LibertyVariable *variable) = 0;
};
void

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -45,9 +45,7 @@ size_t
findValueIndex(float value,
const FloatSeq *values);
static void
sigmaModelsMvOwner(TableModel *models[EarlyLate::index_count],
std::array<std::unique_ptr<TableModel>,
EarlyLate::index_count> &out);
sigmaModelsDelete(TableModelsEarlyLate &models);
static string
reportPvt(const LibertyCell *cell,
const Pvt *pvt,
@ -63,40 +61,50 @@ TimingModel::TimingModel(LibertyCell *cell) :
GateTableModel::GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *delay_sigma_models[EarlyLate::index_count],
TableModelsEarlyLate delay_sigma_models,
TableModel *slew_model,
TableModel *slew_sigma_models[EarlyLate::index_count],
TableModelsEarlyLate slew_sigma_models,
ReceiverModelPtr receiver_model,
OutputWaveforms *output_waveforms) :
GateTimingModel(cell),
delay_model_(delay_model),
delay_sigma_models_(std::move(delay_sigma_models)),
slew_model_(slew_model),
slew_sigma_models_(std::move(slew_sigma_models)),
receiver_model_(receiver_model),
output_waveforms_(output_waveforms)
{
sigmaModelsMvOwner(delay_sigma_models, delay_sigma_models_);
sigmaModelsMvOwner(slew_sigma_models, slew_sigma_models_);
}
GateTableModel::~GateTableModel() = default;
GateTableModel::GateTableModel(LibertyCell *cell,
TableModel *delay_model,
TableModel *slew_model) :
GateTimingModel(cell),
delay_model_(delay_model),
delay_sigma_models_{},
slew_model_(slew_model),
slew_sigma_models_{},
receiver_model_(nullptr),
output_waveforms_(nullptr)
{
}
GateTableModel::~GateTableModel()
{
sigmaModelsDelete(slew_sigma_models_);
sigmaModelsDelete(delay_sigma_models_);
}
static void
sigmaModelsMvOwner(TableModel *models[EarlyLate::index_count],
std::array<std::unique_ptr<TableModel>,
EarlyLate::index_count> &out)
sigmaModelsDelete(TableModelsEarlyLate &models)
{
TableModel *early_model = models ? models[EarlyLate::earlyIndex()] : nullptr;
TableModel *late_model = models ? models[EarlyLate::lateIndex()] : nullptr;
if (early_model) {
out[EarlyLate::earlyIndex()].reset(early_model);
if (late_model && late_model != early_model) {
out[EarlyLate::lateIndex()].reset(late_model);
} else if (late_model == early_model) {
out[EarlyLate::lateIndex()] =
std::make_unique<TableModel>(*out[EarlyLate::earlyIndex()]);
}
} else if (late_model) {
out[EarlyLate::lateIndex()].reset(late_model);
TableModel *early_model = models[EarlyLate::earlyIndex()];
TableModel *late_model = models[EarlyLate::lateIndex()];
if (early_model == late_model)
delete early_model;
else {
delete early_model;
delete late_model;
}
}
@ -122,19 +130,19 @@ GateTableModel::gateDelay(const Pvt *pvt,
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()].get(),
sigma_early = findValue(pvt, delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()].get(),
sigma_late = findValue(pvt, delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0);
gate_delay = makeDelay(delay, sigma_early, sigma_late);
float slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()].get(),
sigma_early = findValue(pvt, slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()].get(),
sigma_late = findValue(pvt, slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0);
// Clip negative slews to zero.
if (slew < 0.0)
@ -166,22 +174,22 @@ GateTableModel::reportGateDelay(const Pvt *pvt,
load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Delay sigma(early)", pvt,
delay_sigma_models_[EarlyLate::earlyIndex()].get(),
delay_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && delay_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Delay sigma(late)", pvt,
delay_sigma_models_[EarlyLate::lateIndex()].get(),
delay_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0, digits);
result += '\n';
result += reportTableLookup("Slew", pvt, slew_model_.get(), in_slew,
load_cap, 9.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::earlyIndex()])
result += reportTableLookup("Slew sigma(early)", pvt,
slew_sigma_models_[EarlyLate::earlyIndex()].get(),
slew_sigma_models_[EarlyLate::earlyIndex()],
in_slew, load_cap, 0.0, digits);
if (pocv_enabled && slew_sigma_models_[EarlyLate::lateIndex()])
result += reportTableLookup("Slew sigma(late)", pvt,
slew_sigma_models_[EarlyLate::lateIndex()].get(),
slew_sigma_models_[EarlyLate::lateIndex()],
in_slew, load_cap, 0.0, digits);
float drvr_slew = findValue(pvt, slew_model_.get(), in_slew, load_cap, 0.0);
if (drvr_slew < 0.0)
@ -285,13 +293,13 @@ GateTableModel::driveResistance(const Pvt *pvt) const
const TableModel *
GateTableModel::delaySigmaModel(const EarlyLate *el) const
{
return delay_sigma_models_[el->index()].get();
return delay_sigma_models_[el->index()];
}
const TableModel *
GateTableModel::slewSigmaModel(const EarlyLate *el) const
{
return slew_sigma_models_[el->index()].get();
return slew_sigma_models_[el->index()];
}
void
@ -354,7 +362,7 @@ GateTableModel::axisValue(const TableAxis *axis,
}
bool
GateTableModel::checkAxes(const TablePtr &table)
GateTableModel::checkAxes(const TableModel *table)
{
const TableAxis *axis1 = table->axis1();
const TableAxis *axis2 = table->axis2();
@ -395,7 +403,7 @@ ReceiverModel::setCapacitanceModel(TableModel table_model,
}
bool
ReceiverModel::checkAxes(TablePtr table)
ReceiverModel::checkAxes(const TableModel *table)
{
const TableAxis *axis1 = table->axis1();
const TableAxis *axis2 = table->axis2();
@ -415,14 +423,25 @@ ReceiverModel::checkAxes(TablePtr table)
CheckTableModel::CheckTableModel(LibertyCell *cell,
TableModel *model,
TableModel *sigma_models[EarlyLate::index_count]) :
TableModelsEarlyLate sigma_models) :
CheckTimingModel(cell),
model_(model)
model_(model),
sigma_models_(std::move(sigma_models))
{
sigmaModelsMvOwner(sigma_models, sigma_models_);
}
CheckTableModel::~CheckTableModel() = default;
CheckTableModel::CheckTableModel(LibertyCell *cell,
TableModel *model) :
CheckTimingModel(cell),
model_(model),
sigma_models_{}
{
}
CheckTableModel::~CheckTableModel()
{
sigmaModelsDelete(sigma_models_);
}
void
CheckTableModel::setIsScaled(bool is_scaled)
@ -434,7 +453,7 @@ CheckTableModel::setIsScaled(bool is_scaled)
const TableModel *
CheckTableModel::sigmaModel(const EarlyLate *el) const
{
return sigma_models_[el->index()].get();
return sigma_models_[el->index()];
}
ArcDelay
@ -449,10 +468,10 @@ CheckTableModel::checkDelay(const Pvt *pvt,
float sigma_early = 0.0;
float sigma_late = 0.0;
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()].get(),
sigma_early = findValue(pvt, sigma_models_[EarlyLate::earlyIndex()],
from_slew, to_slew, related_out_cap);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()].get(),
sigma_late = findValue(pvt, sigma_models_[EarlyLate::lateIndex()],
from_slew, to_slew, related_out_cap);
return makeDelay(mean, sigma_early, sigma_late);
}
@ -491,12 +510,12 @@ CheckTableModel::reportCheckDelay(const Pvt *pvt,
related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::earlyIndex()])
result += reportTableDelay("Check sigma early", pvt,
sigma_models_[EarlyLate::earlyIndex()].get(),
sigma_models_[EarlyLate::earlyIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
if (pocv_enabled && sigma_models_[EarlyLate::lateIndex()])
result += reportTableDelay("Check sigma late", pvt,
sigma_models_[EarlyLate::lateIndex()].get(),
sigma_models_[EarlyLate::lateIndex()],
from_slew, from_slew_annotation, to_slew,
related_out_cap, digits);
return result;
@ -587,7 +606,7 @@ CheckTableModel::axisValue(const TableAxis *axis,
}
bool
CheckTableModel::checkAxes(const TablePtr table)
CheckTableModel::checkAxes(const TableModel *table)
{
const TableAxis *axis1 = table->axis1();
const TableAxis *axis2 = table->axis2();

View File

@ -204,6 +204,16 @@ TimingArcSet::TimingArcSet(const TimingRole *role,
{
}
std::string
TimingArcSet::to_string()
{
std::string str = from_->name();
str += " -> ";
str += to_->name();
str += " " + role()->to_string();
return str;
}
TimingArcSet::~TimingArcSet()
{
deleteContents(arcs_);
@ -622,7 +632,7 @@ TimingArc::equiv(const TimingArc *arc1,
}
void
TimingArc::setIndex(unsigned index)
TimingArc::setIndex(size_t index)
{
index_ = index;
}

View File

@ -292,7 +292,7 @@ Power::reportDesign(const Scene *scene,
PowerResult total, sequential, combinational, clock, macro, pad;
power(scene, total, sequential, combinational, clock, macro, pad);
ReportPower report_power(this);
report_power.reportDesign(total, sequential, combinational, clock, macro, pad, digits);
report_power.reportDesign(total, sequential, combinational, clock, macro, pad, digits);
}
void

View File

@ -79,7 +79,7 @@ MakeTimingModel::MakeTimingModel(const char *lib_name,
scene_(scene),
cell_(nullptr),
min_max_(MinMax::max()),
lib_builder_(new LibertyBuilder),
lib_builder_(new LibertyBuilder(debug_, report_)),
tbl_template_index_(1),
sdc_(scene->sdc()),
sdc_backup_(nullptr),
@ -611,7 +611,7 @@ MakeTimingModel::makeScalarCheckModel(float value,
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *table_model = new TableModel(table, tbl_template,
scale_factor_type, rf);
CheckTableModel *check_model = new CheckTableModel(cell_, table_model, nullptr);
CheckTableModel *check_model = new CheckTableModel(cell_, table_model);
return check_model;
}
@ -628,9 +628,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
ScaleFactorType::cell, rf);
TableModel *slew_model = new TableModel(slew_table, tbl_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr,
slew_model, nullptr,
nullptr, nullptr);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, slew_model);
return gate_model;
}
@ -643,9 +641,7 @@ MakeTimingModel::makeGateModelScalar(Delay delay,
library_->findTableTemplate("scalar", TableTemplateType::delay);
TableModel *delay_model = new TableModel(delay_table, tbl_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr,
nullptr, nullptr,
nullptr, nullptr);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model, nullptr);
return gate_model;
}
@ -721,10 +717,8 @@ MakeTimingModel::makeGateModelTable(const Pin *output_pin,
ScaleFactorType::cell, rf);
TableModel *slew_model = new TableModel(slew_table, model_template,
ScaleFactorType::cell, rf);
GateTableModel *gate_model = new GateTableModel(cell_,
delay_model, nullptr,
slew_model, nullptr,
nullptr, nullptr);
GateTableModel *gate_model = new GateTableModel(cell_, delay_model,
slew_model);
return gate_model;
}
}

View File

@ -1178,7 +1178,7 @@ PathEndLatchCheck::sourceClkOffset(const StaState *sta) const
const TimingRole *
PathEndLatchCheck::checkRole(const StaState *sta) const
{
if (clk_path_->clkInfo(sta)->isPulseClk())
if (clk_path_ && clk_path_->clkInfo(sta)->isPulseClk())
// Pulse latches use register cycle accounting.
return TimingRole::setup();
else

View File

@ -1,4 +1,4 @@
# Tests whether the is_memory attribute works for cells and libcells
# Tests whether the is_memory attribute works for instances and cells
read_liberty gf180mcu_sram.lib.gz
read_liberty asap7_small.lib.gz
read_verilog get_is_memory.v

Binary file not shown.

View File

@ -1,3 +1,4 @@
Warning 1195: liberty_arcs_one2one_1.lib line 45, port Y function size does not match port size.
Warning 1216: liberty_arcs_one2one_1.lib line 48, timing port A and related port Y are different sizes.
report_edges -from partial_wide_inv_cell/A[0]
A[0] -> Y[0] combinational

View File

@ -1,3 +1,4 @@
Warning 1195: liberty_arcs_one2one_2.lib line 45, port Y function size does not match port size.
Warning 1216: liberty_arcs_one2one_2.lib line 48, timing port A and related port Y are different sizes.
report_edges -to partial_wide_inv_cell/Y[0]
A[0] -> Y[0] combinational

View File

@ -87,4 +87,27 @@ TokenParser::next()
return token_;
}
////////////////////////////////////////////////////////////////
// Parse space separated tokens.
StdStringSeq
parseTokens(const std::string &s,
const char delimiter)
{
StdStringSeq tokens;
size_t i = 0;
while (i < s.size()) {
while (i < s.size() && std::isspace(s[i]))
++i;
size_t start = i;
while (i < s.size() && s[i] != delimiter)
++i;
if (start < i) {
tokens.emplace_back(s, start, i - start);
++i;
}
}
return tokens;
}
} // namespace