Verilog make pins for liberty pg_pins resolves #326

commit b4a89c93965c49a8685fd41cb6aee10635d7a7f3
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 7 11:48:10 2025 -0700

    pg_ -> PwrGnd

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

commit 12ddba4bf220cec8459c15e483a871b13e507bf2
Author: James Cherry <cherry@parallaxsw.com>
Date:   Fri Nov 7 08:56:02 2025 -0700

    pg_port

    Signed-off-by: James Cherry <cherry@parallaxsw.com>

Signed-off-by: James Cherry <cherry@parallaxsw.com>
This commit is contained in:
James Cherry 2025-11-07 11:55:43 -07:00
parent 845729ad9f
commit 8287aec5f6
19 changed files with 226 additions and 275 deletions

View File

@ -50,6 +50,9 @@ The following classes now return const objects.
Transition
TimingRole
Liberty PgPorts are now LibertyPorts with additional member functions for
liberty pg_pins.
Release 2.6.1 2025/03/??
-------------------------

View File

@ -17,6 +17,8 @@ to remove paths through identical pins and rise/fall edges.
report_checks [-unique_edges_to_endpoint]
Instances now have pins for verilog netlist power/ground connections,
Release 2.6.1 2025/03/30
-------------------------

View File

@ -43,7 +43,6 @@ class WriteTimingModel;
class LibertyCellIterator;
class LibertyCellPortIterator;
class LibertyCellPortBitIterator;
class LibertyCellPgPortIterator;
class LibertyPortMemberIterator;
class ModeValueDef;
class TestCell;
@ -56,7 +55,6 @@ class LibertyReader;
class OcvDerate;
class TimingArcAttrs;
class InternalPowerAttrs;
class LibertyPgPort;
class StaState;
class Corner;
class Corners;
@ -90,7 +88,6 @@ typedef Vector<LatchEnable*> LatchEnableSeq;
typedef Map<const char *, OcvDerate*, CharPtrLess> OcvDerateMap;
typedef Vector<InternalPowerAttrs*> InternalPowerAttrsSeq;
typedef Map<std::string, float> SupplyVoltageMap;
typedef Map<std::string, LibertyPgPort*> LibertyPgPortMap;
typedef Map<std::string, DriverWaveform*> DriverWaveformMap;
typedef Vector<DcalcAnalysisPt*> DcalcAnalysisPtSeq;
@ -100,6 +97,12 @@ enum class DelayModelType { cmos_linear, cmos_pwl, cmos2, table, polynomial, dcm
enum class ScanSignalType { enable, enable_inverted, clock, clock_a, clock_b,
input, input_inverted, output, output_inverted, none };
enum class PwrGndType { none,
primary_power, primary_ground,
backup_power, backup_ground,
internal_power, internal_ground,
nwell, pwell,
deepnwell, deeppwell};
enum class ScaleFactorPvt { process, volt, temp, unknown };
constexpr int scale_factor_pvt_count = int(ScaleFactorPvt::unknown) + 1;
@ -423,8 +426,6 @@ public:
LibertyPort *findLibertyPort(const char *name) const;
LibertyPortSeq findLibertyPortsMatching(PatternMatch *pattern) const;
bool hasInternalPorts() const { return has_internal_ports_; }
LibertyPgPort *findPgPort(const char *name) const;
size_t pgPortCount() const { return pg_port_map_.size(); }
ScaleFactors *scaleFactors() const { return scale_factors_; }
void setScaleFactors(ScaleFactors *scale_factors);
ModeDef *makeModeDef(const char *name);
@ -533,7 +534,6 @@ public:
void setOcvArcDepth(float depth);
void setOcvDerate(OcvDerate *derate);
void addOcvDerate(OcvDerate *derate);
void addPgPort(LibertyPgPort *pg_port);
void setTestCell(TestCell *test);
void setHasInferedRegTimingArcs(bool infered);
void setIsDisabledConstraint(bool is_disabled);
@ -643,7 +643,6 @@ protected:
Vector<LibertyCell*> corner_cells_;
float leakage_power_;
bool leakage_power_exists_;
LibertyPgPortMap pg_port_map_;
bool has_internal_ports_;
std::atomic<bool> have_voltage_waveforms_;
std::mutex waveform_lock_;
@ -653,7 +652,6 @@ protected:
private:
friend class LibertyLibrary;
friend class LibertyCellPortIterator;
friend class LibertyCellPgPortIterator;
friend class LibertyPort;
friend class LibertyBuilder;
};
@ -681,17 +679,6 @@ private:
ConcreteCellPortBitIterator *iter_;
};
class LibertyCellPgPortIterator : public Iterator<LibertyPgPort*>
{
public:
LibertyCellPgPortIterator(const LibertyCell *cell);
bool hasNext();
LibertyPgPort *next();
private:
LibertyPgPortMap::Iterator iter_;
};
////////////////////////////////////////////////////////////////
class LibertyPort : public ConcretePort
@ -704,6 +691,16 @@ public:
LibertyPort *bundlePort() const;
BusDcl *busDcl() const { return bus_dcl_; }
void setDirection(PortDirection *dir);
////////////////////////////////////////////////////////////////
// pg_pin functions
bool isPwrGnd() const;
PwrGndType pwrGndType() const { return pwr_gnd_type_; }
void setPwrGndType(PwrGndType type);
const char *voltageName() const { return voltage_name_.c_str(); }
void setVoltageName(const char *voltage_name);
////////////////////////////////////////////////////////////////
ScanSignalType scanSignalType() const { return scan_signal_type_; }
void setScanSignalType(ScanSignalType type);
void fanoutLoad(// Return values.
@ -887,8 +884,10 @@ protected:
LibertyCell *liberty_cell_;
BusDcl *bus_dcl_;
FuncExpr *function_;
PwrGndType pwr_gnd_type_;
std::string voltage_name_;
ScanSignalType scan_signal_type_;
FuncExpr *function_;
FuncExpr *tristate_enable_;
ScaledPortMap *scaled_ports_;
RiseFallMinMax capacitance_;
@ -1136,37 +1135,13 @@ private:
TablePtr derate_[RiseFall::index_count][EarlyLate::index_count][path_type_count];
};
// Power/ground port.
class LibertyPgPort
{
public:
enum PgType { unknown,
primary_power, primary_ground,
backup_power, backup_ground,
internal_power, internal_ground,
nwell, pwell,
deepnwell, deeppwell};
LibertyPgPort(const char *name,
LibertyCell *cell);
const char *name() const { return name_.c_str(); }
LibertyCell *cell() const { return cell_; }
PgType pgType() const { return pg_type_; }
void setPgType(PgType type);
const char *voltageName() const { return voltage_name_.c_str(); }
void setVoltageName(const char *voltage_name);
static bool equiv(const LibertyPgPort *port1,
const LibertyPgPort *port2);
private:
std::string name_;
PgType pg_type_;
std::string voltage_name_;
LibertyCell *cell_;
};
std::string
portLibertyToSta(const char *port_name);
const char *
scanSignalTypeName(ScanSignalType scan_type);
const char *
pwrGndTypeName(PwrGndType pwr_gnd_type);
PwrGndType
findPwrGndType(const char *pg_name);
} // namespace

View File

@ -67,17 +67,9 @@ static unsigned
hashFuncExpr(const FuncExpr *expr);
static unsigned
hashPort(const LibertyPort *port);
static unsigned
hashCellPgPorts(const LibertyCell *cell);
static unsigned
hashPgPort(const LibertyPgPort *port);
static bool
cellHasFuncs(const LibertyCell *cell);
static bool
equivCellPgPorts(const LibertyCell *cell1,
const LibertyCell *cell2);
static float
cellDriveResistance(const LibertyCell *cell)
{
@ -201,7 +193,6 @@ static unsigned
hashCell(const LibertyCell *cell)
{
return hashCellPorts(cell)
+ hashCellPgPorts(cell)
+ hashCellSequentials(cell);
}
@ -226,25 +217,6 @@ hashPort(const LibertyPort *port)
+ port->direction()->index() * 5;
}
static unsigned
hashCellPgPorts(const LibertyCell *cell)
{
unsigned hash = 0;
LibertyCellPgPortIterator port_iter(cell);
while (port_iter.hasNext()) {
LibertyPgPort *port = port_iter.next();
hash += hashPgPort(port);
}
return hash;
}
static unsigned
hashPgPort(const LibertyPgPort *port)
{
return hashString(port->name()) * 3
+ static_cast<int>(port->pgType()) * 5;
}
static unsigned
hashCellSequentials(const LibertyCell *cell)
{
@ -333,7 +305,6 @@ equivCells(const LibertyCell *cell1,
{
return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions.
@ -347,7 +318,6 @@ equivCellsArcs(const LibertyCell *cell1,
{
return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2)
// Reqwuire timing arc equivalence if there are no functions.
@ -403,25 +373,6 @@ equivCellPorts(const LibertyCell *cell1,
}
}
static bool
equivCellPgPorts(const LibertyCell *cell1,
const LibertyCell *cell2)
{
if (cell1->pgPortCount() != cell2->pgPortCount())
return false;
else {
LibertyCellPgPortIterator port_iter1(cell1);
while (port_iter1.hasNext()) {
LibertyPgPort *port1 = port_iter1.next();
const char* name = port1->name();
LibertyPgPort *port2 = cell2->findPgPort(name);
if (!(port2 && LibertyPgPort::equiv(port1, port2)))
return false;
}
return true;
}
}
bool
equivCellSequentials(const LibertyCell *cell1,
const LibertyCell *cell2)

View File

@ -975,8 +975,6 @@ LibertyCell::~LibertyCell()
delete test_cell_;
ocv_derate_map_.deleteContents();
pg_port_map_.deleteContents();
}
LibertyPort *
@ -1021,18 +1019,6 @@ LibertyCell::setHasInternalPorts(bool has_internal)
has_internal_ports_ = has_internal;
}
void
LibertyCell::addPgPort(LibertyPgPort *pg_port)
{
pg_port_map_[pg_port->name()] = pg_port;
}
LibertyPgPort *
LibertyCell::findPgPort(const char *name) const
{
return pg_port_map_.findKey(name);
}
ModeDef *
LibertyCell::makeModeDef(const char *name)
{
@ -2093,8 +2079,9 @@ LibertyPort::LibertyPort(LibertyCell *cell,
ConcretePort(name, is_bus, from_index, to_index, is_bundle, members, cell),
liberty_cell_(cell),
bus_dcl_(bus_dcl),
function_(nullptr),
pwr_gnd_type_(PwrGndType::none),
scan_signal_type_(ScanSignalType::none),
function_(nullptr),
tristate_enable_(nullptr),
scaled_ports_(nullptr),
fanout_load_(0.0),
@ -2168,6 +2155,50 @@ static EnumNameMap<ScanSignalType> scan_signal_type_map =
{ScanSignalType::output_inverted, "output_inverted"},
{ScanSignalType::none, "none"}};
bool
LibertyPort::isPwrGnd() const
{
return pwr_gnd_type_ != PwrGndType::none;
}
void
LibertyPort::setPwrGndType(PwrGndType type)
{
pwr_gnd_type_ = type;
}
void
LibertyPort::setVoltageName(const char *voltage_name)
{
voltage_name_ = voltage_name;
}
static EnumNameMap<PwrGndType> pwr_gnd_type_map =
{{PwrGndType::none, "node"},
{PwrGndType::primary_power, "primary_power"},
{PwrGndType::primary_ground, "primary_ground"},
{PwrGndType::backup_power, "backup_power"},
{PwrGndType::backup_ground, "backup_ground"},
{PwrGndType::internal_power, "internal_power"},
{PwrGndType::internal_ground, "internal_ground"},
{PwrGndType::nwell, "nwell"},
{PwrGndType::pwell, "pwell"},
{PwrGndType::deepnwell, "deepnwell"},
{PwrGndType::deeppwell, "deeppwell"}};
const char *
pwrGndTypeName(PwrGndType pg_type)
{
return pwr_gnd_type_map.find(pg_type);
}
PwrGndType
findPwrGndType(const char *pg_name)
{
return pwr_gnd_type_map.find(pg_name, PwrGndType::none);
}
////////////////////////////////////////////////////////////////
const char *
scanSignalTypeName(ScanSignalType scan_type)
@ -2526,7 +2557,8 @@ LibertyPort::equiv(const LibertyPort *port1,
return (port1 == nullptr && port2 == nullptr)
|| (port1 != nullptr && port2 != nullptr
&& stringEq(port1->name(), port2->name())
&& port1->direction() == port2->direction());
&& port1->direction() == port2->direction()
&& port1->pwr_gnd_type_ == port2->pwr_gnd_type_);
}
bool
@ -3330,56 +3362,4 @@ OcvDerate::setDerateTable(const RiseFall *rf,
derate_[rf->index()][early_late->index()][int(path_type)] = derate;
}
////////////////////////////////////////////////////////////////
LibertyPgPort::LibertyPgPort(const char *name,
LibertyCell *cell) :
name_(name),
pg_type_(unknown),
cell_(cell)
{
}
void
LibertyPgPort::setPgType(PgType type)
{
pg_type_ = type;
}
void
LibertyPgPort::setVoltageName(const char *voltage_name)
{
voltage_name_ = voltage_name;
}
bool
LibertyPgPort::equiv(const LibertyPgPort *port1,
const LibertyPgPort *port2)
{
return port1->name_ == port2->name_
&& port1->pg_type_ == port2->pg_type_;
}
////////////////////////////////////////////////////////////////
LibertyCellPgPortIterator::LibertyCellPgPortIterator(const LibertyCell *cell) :
iter_(const_cast<LibertyCell*>(cell)->pg_port_map_)
{
}
bool
LibertyCellPgPortIterator::hasNext()
{
return iter_.hasNext();
}
LibertyPgPort *
LibertyCellPgPortIterator::next()
{
string name;
LibertyPgPort *port;
iter_.next(name, port);
return port;
}
} // namespace

View File

@ -317,6 +317,7 @@ bool has_members() { return self->hasMembers(); }
LibertyPortMemberIterator *
member_iterator() { return new LibertyPortMemberIterator(self); }
LibertyPort *bundle_port() { return self->bundlePort(); }
bool is_pwr_gnd() { return self->isPwrGnd(); }
string
function()

View File

@ -5670,8 +5670,7 @@ LibertyReader::beginPgPin(LibertyGroup *group)
{
if (cell_) {
const char *name = group->firstName();
pg_port_ = new LibertyPgPort(name, cell_);
cell_->addPgPort(pg_port_);
pg_port_ = builder_.makePort(cell_, name);
}
}
@ -5686,35 +5685,27 @@ LibertyReader::visitPgType(LibertyAttr *attr)
{
if (pg_port_) {
const char *type_name = getAttrString(attr);
LibertyPgPort::PgType type = LibertyPgPort::PgType::unknown;
if (stringEqual(type_name, "primary_ground"))
type = LibertyPgPort::PgType::primary_ground;
else if (stringEqual(type_name, "primary_power"))
type = LibertyPgPort::PgType::primary_power;
else if (stringEqual(type_name, "backup_ground"))
type = LibertyPgPort::PgType::backup_ground;
else if (stringEqual(type_name, "backup_power"))
type = LibertyPgPort::PgType::backup_power;
else if (stringEqual(type_name, "internal_ground"))
type = LibertyPgPort::PgType::internal_ground;
else if (stringEqual(type_name, "internal_power"))
type = LibertyPgPort::PgType::internal_power;
else if (stringEqual(type_name, "nwell"))
type = LibertyPgPort::PgType::nwell;
else if (stringEqual(type_name, "pwell"))
type = LibertyPgPort::PgType::pwell;
else if (stringEqual(type_name, "deepnwell"))
type = LibertyPgPort::PgType::deepnwell;
else if (stringEqual(type_name, "deeppwell"))
type = LibertyPgPort::PgType::deeppwell;
else
PwrGndType type = findPwrGndType(type_name);
PortDirection *dir = PortDirection::unknown();
switch (type) {
case PwrGndType::primary_ground:;
case PwrGndType::backup_ground:
case PwrGndType::internal_ground:
dir = PortDirection::ground();
break;
case PwrGndType::primary_power:
case PwrGndType::backup_power:
case PwrGndType::internal_power:
dir = PortDirection::power();
break;
case PwrGndType::none:
libError(1291, attr, "unknown pg_type.");
pg_port_->setPgType(type);
break;
default:
break;
}
pg_port_->setPwrGndType(type);
pg_port_->setDirection(dir);
}
}

View File

@ -651,7 +651,7 @@ protected:
const EarlyLateAll *derate_type_;
const EarlyLateAll *sigma_type_;
PathType path_type_;
LibertyPgPort *pg_port_;
LibertyPort *pg_port_;
ScaleFactorType scale_factor_type_;
TableAxisPtr axis_[3];
TablePtr table_;

View File

@ -59,6 +59,7 @@ protected:
void writeCells();
void writeCell(const LibertyCell *cell);
void writePort(const LibertyPort *port);
void writePwrGndPort(const LibertyPort *port);
void writeBusPort(const LibertyPort *port);
void writePortAttrs(const LibertyPort *port);
void writeTimingArcSet(const TimingArcSet *arc_set);
@ -310,7 +311,9 @@ LibertyWriter::writeCell(const LibertyCell *cell)
while (port_iter.hasNext()) {
const LibertyPort *port = port_iter.next();
if (!port->direction()->isInternal()) {
if (port->isBus())
if (port->isPwrGnd())
writePwrGndPort(port);
else if (port->isBus())
writeBusPort(port);
else if (port->isBundle())
report_->error(1340, "%s/%s bundled ports not supported.",
@ -394,6 +397,15 @@ LibertyWriter::writePortAttrs(const LibertyPort *port)
}
}
void
LibertyWriter::writePwrGndPort(const LibertyPort *port)
{
fprintf(stream_, " pg_pin(\"%s\") {\n", port->name());
fprintf(stream_, " pg_type : \"%s\";\n", pwrGndTypeName(port->pwrGndType()));
fprintf(stream_, " voltage_name : \"%s\";\n", port->voltageName());
fprintf(stream_, " }\n");
}
// Check if arc is added for port min_pulse_width_high/low attribute.
bool
LibertyWriter::isAutoWidthArc(const LibertyPort *port,

View File

@ -753,6 +753,15 @@ bool is_top_level_port() { return Sta::sta()->ensureLinked()->isTopLevelPort(sel
PinConnectedPinIterator *connected_pin_iterator()
{ return Sta::sta()->ensureLinked()->connectedPinIterator(self); }
bool
is_pwr_gnd()
{
sta::Sta *sta = Sta::sta();
Network *network = sta->network();
LibertyPort *lib_port = network->libertyPort(self);
return lib_port && lib_port->isPwrGnd();
}
Vertex **
vertices()
{

View File

@ -1368,7 +1368,7 @@ Power::pgNameVoltage(LibertyCell *cell,
const DcalcAnalysisPt *dcalc_ap)
{
if (pg_port_name) {
LibertyPgPort *pg_port = cell->findPgPort(pg_port_name);
LibertyPort *pg_port = cell->findLibertyPort(pg_port_name);
if (pg_port) {
const char *volt_name = pg_port->voltageName();
LibertyLibrary *library = cell->libertyLibrary();
@ -1484,14 +1484,17 @@ Power::findUnannotatedPins(const Instance *inst,
InstancePinIterator *pin_iter = network_->pinIterator(inst);
while (pin_iter->hasNext()) {
const Pin *pin = pin_iter->next();
LibertyPort *liberty_port = sdc_network_->libertyPort(pin);
if (!network_->direction(pin)->isInternal()
&& !network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd())
&& user_activity_map_.find(pin) == user_activity_map_.end())
unannotated_pins.push_back(pin);
}
delete pin_iter;
}
// leaf pins - internal pins + top instance pins
// leaf pins - internal pins - power/ground pins + top instance pins
size_t
Power::pinCount()
{
@ -1502,7 +1505,10 @@ Power::pinCount()
InstancePinIterator *pin_iter = network_->pinIterator(leaf);
while (pin_iter->hasNext()) {
const Pin *pin = pin_iter->next();
if (!network_->direction(pin)->isInternal())
LibertyPort *liberty_port = sdc_network_->libertyPort(pin);
if (!network_->direction(pin)->isInternal()
&& !network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd()))
count++;
}
delete pin_iter;

View File

@ -33,6 +33,7 @@
#include "Report.hh"
#include "Network.hh"
#include "PortDirection.hh"
#include "Liberty.hh"
#include "Sdc.hh"
#include "Power.hh"
#include "power/SaifReaderPvt.hh"
@ -168,9 +169,11 @@ SaifReader::setNetDurations(const char *net_name,
if (parent) {
string unescaped_name = unescaped(net_name);
const Pin *pin = sdc_network_->findPin(parent, unescaped_name.c_str());
LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr;
if (pin
&& !sdc_network_->isHierarchical(pin)
&& !sdc_network_->direction(pin)->isInternal()) {
&& !sdc_network_->direction(pin)->isInternal()
&& !(liberty_port && liberty_port->isPwrGnd())) {
double t1 = durations[static_cast<int>(SaifState::T1)];
float duty = t1 / duration_;
double tc = durations[static_cast<int>(SaifState::TC)];

View File

@ -30,6 +30,7 @@
#include "VcdParse.hh"
#include "Debug.hh"
#include "Network.hh"
#include "Liberty.hh"
#include "PortDirection.hh"
#include "VerilogNamespace.hh"
#include "ParseBus.hh"
@ -284,13 +285,16 @@ VcdCountReader::addVarPin(const string &pin_name,
size_t bit_idx)
{
const Pin *pin = sdc_network_->findPin(pin_name.c_str());
LibertyPort *liberty_port = pin ? sdc_network_->libertyPort(pin) : nullptr;
if (pin
&& !sdc_network_->isHierarchical(pin)
&& !sdc_network_->direction(pin)->isInternal()) {
&& !sdc_network_->direction(pin)->isInternal()
&& !sdc_network_->direction(pin)->isPowerGround()
&& !(liberty_port && liberty_port->isPwrGnd())) {
VcdCounts &vcd_counts = vcd_count_map_[id];
vcd_counts.resize(width);
vcd_counts[bit_idx].addPin(pin);
debugPrint(debug_, "read_vcd_activities", 2, "id %s pin %s",
debugPrint(debug_, "read_vcd", 2, "id %s pin %s",
id.c_str(),
pin_name.c_str());
}
@ -304,11 +308,11 @@ VcdCountReader::varAppendValue(const string &id,
const auto &itr = vcd_count_map_.find(id);
if (itr != vcd_count_map_.end()) {
VcdCounts &vcd_counts = itr->second;
if (debug_->check("read_vcd_activities", 3)) {
if (debug_->check("read_vcd", 3)) {
for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) {
VcdCount &vcd_count = vcd_counts[bit_idx];
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 3, "%s time %" PRIu64 " value %c",
debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c",
sdc_network_->pathName(pin),
time,
value);
@ -333,9 +337,9 @@ VcdCountReader::varAppendBusValue(const string &id,
for (size_t bit_idx = 0; bit_idx < vcd_counts.size(); bit_idx++) {
char bit_value = ((bus_value >> bit_idx) & 0x1) ? '1' : '0';
VcdCount &vcd_count = vcd_counts[bit_idx];
if (debug_->check("read_vcd_activities", 3)) {
if (debug_->check("read_vcd", 3)) {
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 3, "%s time %" PRIu64 " value %c",
debugPrint(debug_, "read_vcd", 3, "%s time %" PRIu64 " value %c",
sdc_network_->pathName(pin),
time,
bit_value);
@ -420,9 +424,9 @@ ReadVcdActivities::setActivities()
VcdTime high_time = vcd_count.highTime(time_max);
float duty = static_cast<double>(high_time) / time_delta;
float density = transition_count / (time_delta * time_scale);
if (debug_->check("read_vcd_activities", 1)) {
if (debug_->check("read_vcd", 1)) {
for (const Pin *pin : vcd_count.pins()) {
debugPrint(debug_, "read_vcd_activities", 1,
debugPrint(debug_, "read_vcd", 1,
"%s transitions %.1f activity %.2f duty %.2f",
sdc_network_->pathName(pin),
transition_count,

View File

@ -578,7 +578,12 @@ proc get_lib_pins { args } {
}
set libcells [get_libcells_error "objects" $keys(-of_objects)]
foreach libcell $libcells {
lappend ports {*}[$libcell find_liberty_ports_matching * 0 1]
foreach port [$libcell find_liberty_ports_matching * 0 1] {
# Filter pg ports.
if { ![$port is_pwr_gnd] } {
lappend ports $port
}
}
}
} else {
foreach pattern $patterns {
@ -610,8 +615,11 @@ proc get_lib_pins { args } {
set matches [$cell find_liberty_ports_matching $port_pattern \
$regexp $nocase]
foreach match $matches {
lappend ports $match
set found_match 1
# Filter pg ports.
if { ![$match is_pwr_gnd] } {
lappend ports $match
set found_match 1
}
}
}
}
@ -814,7 +822,10 @@ proc get_pins { args } {
set pin_iter [$inst pin_iterator]
while { [$pin_iter has_next] } {
set pin [$pin_iter next]
lappend pins $pin
# Filter pg ports.
if { ![$pin is_pwr_gnd] } {
lappend pins $pin
}
}
$pin_iter finish
}
@ -822,7 +833,10 @@ proc get_pins { args } {
set pin_iter [$net pin_iterator]
while { [$pin_iter has_next] } {
set pin [$pin_iter next]
lappend pins $pin
# Filter pg ports.
if { ![$pin is_pwr_gnd] } {
lappend pins $pin
}
}
$pin_iter finish
}
@ -852,7 +866,12 @@ proc get_pins { args } {
} else {
set matches [find_pins_matching $pattern $regexp $nocase]
}
set pins [concat $pins $matches]
foreach match $matches {
# Filter pg ports.
if { ![$match is_pwr_gnd] } {
lappend pins $match
}
}
if { $matches == {} && !$quiet } {
sta_warn 363 "pin '$pattern' not found."
}

View File

@ -514,42 +514,44 @@ SdfWriter::writeTimingChecks(const Instance *inst,
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
Vertex *vertex = graph_->pinLoadVertex(pin);
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
const TimingRole *role = edge->role();
const char *sdf_check = nullptr;
if (role == TimingRole::setup())
sdf_check = "SETUP";
else if (role == TimingRole::hold())
sdf_check = "HOLD";
else if (role == TimingRole::recovery())
sdf_check = "RECOVERY";
else if (role == TimingRole::removal())
sdf_check = "REMOVAL";
if (sdf_check) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writeCheck(edge, sdf_check);
if (vertex) {
VertexOutEdgeIterator edge_iter(vertex, graph_);
while (edge_iter.hasNext()) {
Edge *edge = edge_iter.next();
const TimingRole *role = edge->role();
const char *sdf_check = nullptr;
if (role == TimingRole::setup())
sdf_check = "SETUP";
else if (role == TimingRole::hold())
sdf_check = "HOLD";
else if (role == TimingRole::recovery())
sdf_check = "RECOVERY";
else if (role == TimingRole::removal())
sdf_check = "REMOVAL";
if (sdf_check) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writeCheck(edge, sdf_check);
}
}
}
for (auto hi_low : RiseFall::range()) {
float min_width, max_width;
Edge *edge;
TimingArc *arc;
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
if (edge) {
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
ensureTimingCheckheaders(check_header, inst, inst_header);
writeWidthCheck(pin, hi_low, min_width, max_width);
for (auto hi_low : RiseFall::range()) {
float min_width, max_width;
Edge *edge;
TimingArc *arc;
graph_->minPulseWidthArc(vertex, hi_low, edge, arc);
if (edge) {
min_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_min_index_));
max_width = delayAsFloat(graph_->arcDelay(edge, arc, arc_delay_max_index_));
ensureTimingCheckheaders(check_header, inst, inst_header);
writeWidthCheck(pin, hi_low, min_width, max_width);
}
}
float min_period;
bool exists;
graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period);
}
}
float min_period;
bool exists;
graph_delay_calc_->minPeriod(pin, corner_, min_period, exists);
if (exists) {
ensureTimingCheckheaders(check_header, inst, inst_header);
writePeriodCheck(pin, min_period);
}
}
delete pin_iter;

View File

@ -4303,7 +4303,8 @@ Sta::replaceEquivCellBefore(const Instance *inst,
else {
// Force delay calculation on output pins.
Vertex *vertex = graph_->pinDrvrVertex(pin);
graph_delay_calc_->delayInvalid(vertex);
if (vertex)
graph_delay_calc_->delayInvalid(vertex);
}
}
}

View File

@ -261,7 +261,7 @@ WriteSpice::recordSpicePortNames(const char *cell_name,
for (size_t i = 2; i < tokens.size(); i++) {
const char *port_name = tokens[i].c_str();
LibertyPort *port = cell->findLibertyPort(port_name);
LibertyPgPort *pg_port = cell->findPgPort(port_name);
LibertyPort *pg_port = cell->findLibertyPort(port_name);
if (port == nullptr
&& pg_port == nullptr
&& !stringEqual(port_name, power_name_)
@ -326,7 +326,7 @@ WriteSpice::writeSubcktInst(const Instance *inst)
for (string subckt_port_name : spice_port_names) {
const char *subckt_port_cname = subckt_port_name.c_str();
Pin *pin = network_->findPin(inst, subckt_port_cname);
LibertyPgPort *pg_port = cell->findPgPort(subckt_port_cname);
LibertyPort *pg_port = cell->findLibertyPort(subckt_port_cname);
const char *pin_name;
if (pin) {
pin_name = network_->pathName(pin);
@ -357,13 +357,13 @@ WriteSpice::writeSubcktInstVoltSrcs(const Instance *inst,
const char *subckt_port_name = subckt_port_sname.c_str();
LibertyPort *port = cell->findLibertyPort(subckt_port_name);
const Pin *pin = port ? network_->findPin(inst, port) : nullptr;
LibertyPgPort *pg_port = cell->findPgPort(subckt_port_name);
bool is_pg_port = port && port->isPwrGnd();
debugPrint(debug_, "write_spice", 2, " port %s%s",
subckt_port_name,
pg_port ? " pwr/gnd" : "");
if (pg_port)
is_pg_port ? " pwr/gnd" : "");
if (is_pg_port)
writeVoltageSource(inst_name, subckt_port_name,
pgPortVoltage(pg_port));
pgPortVoltage(port));
else if (stringEq(subckt_port_name, power_name_))
writeVoltageSource(inst_name, subckt_port_name, power_voltage_);
else if (stringEq(subckt_port_name, gnd_name_))
@ -420,7 +420,7 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
float voltage)
{
if (pg_port_name) {
LibertyPgPort *pg_port = cell->findPgPort(pg_port_name);
LibertyPort *pg_port = cell->findLibertyPort(pg_port_name);
if (pg_port)
voltage = pgPortVoltage(pg_port);
else
@ -433,9 +433,9 @@ WriteSpice::writeVoltageSource(LibertyCell *cell,
}
float
WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
WriteSpice::pgPortVoltage(LibertyPort *pg_port)
{
LibertyLibrary *liberty = pg_port->cell()->libertyLibrary();
LibertyLibrary *liberty = pg_port->libertyCell()->libertyLibrary();
float voltage = 0.0;
bool exists;
const char *voltage_name = pg_port->voltageName();
@ -448,14 +448,14 @@ WriteSpice::pgPortVoltage(LibertyPgPort *pg_port)
voltage = gnd_voltage_;
else
report_->error(1601 , "pg_pin %s/%s voltage %s not found,",
pg_port->cell()->name(),
pg_port->libertyCell()->name(),
pg_port->name(),
voltage_name);
}
}
else
report_->error(1602, "Liberty pg_port %s/%s missing voltage_name attribute,",
pg_port->cell()->name(),
pg_port->libertyCell()->name(),
pg_port->name());
return voltage;
}

View File

@ -73,7 +73,7 @@ protected:
void writeSubcktInstVoltSrcs(const Instance *inst,
LibertyPortLogicValues &port_values,
const PinSet &excluded_input_pins);
float pgPortVoltage(LibertyPgPort *pg_port);
float pgPortVoltage(LibertyPort *pg_port);
void writeVoltageSource(const char *inst_name,
const char *port_name,
float voltage);

View File

@ -1900,19 +1900,11 @@ VerilogReader::makeNamedInstPins(Cell *cell,
delete net_name_iter;
}
}
else {
LibertyPgPort *pg_port = nullptr;
LibertyCell *lib_cell = network_->libertyCell(cell);
if (lib_cell)
pg_port = lib_cell->findPgPort(port_name);
// Do not warn about connections to pg ports (which are ignored).
if (pg_port == nullptr) {
linkWarn(201, parent_module->filename(), mod_inst->line(),
"instance %s port %s not found.",
inst_vname.c_str(),
port_name);
}
}
else
linkWarn(201, parent_module->filename(), mod_inst->line(),
"instance %s port %s not found.",
inst_vname.c_str(),
port_name);
}
}