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:
parent
845729ad9f
commit
8287aec5f6
|
|
@ -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/??
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
-------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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_;
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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)];
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
31
sdc/Sdc.tcl
31
sdc/Sdc.tcl
|
|
@ -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."
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue