Merge remote-tracking branch 'parallax/master'

Signed-off-by: Matt Liberty <mliberty@precisioninno.com>
This commit is contained in:
Matt Liberty 2025-06-24 14:57:14 +00:00
commit 5ee1a31514
11 changed files with 136 additions and 116 deletions

View File

@ -157,7 +157,7 @@ git clone https://github.com/parallaxsw/OpenSTA.git
cd OpenSTA cd OpenSTA
mkdir build mkdir build
cd build cd build
cmake -DCUDD_DIR=<CUDD_INSTALL_DIR> ,. cmake -DCUDD_DIR=<CUDD_INSTALL_DIR> ..
make make
``` ```
The default build type is release to compile optimized code. The default build type is release to compile optimized code.

View File

@ -67,10 +67,10 @@ bool
equivCellPorts(const LibertyCell *cell1, equivCellPorts(const LibertyCell *cell1,
const LibertyCell *cell2); const LibertyCell *cell2);
// Predicate that is true when the ports and their functions match. // Predicate that is true cell functions match.
bool bool
equivCellPortsAndFuncs(const LibertyCell *cell1, equivCellFuncs(const LibertyCell *cell1,
const LibertyCell *cell2); const LibertyCell *cell2);
// Predicate that is true when the timing arc sets match. // Predicate that is true when the timing arc sets match.
bool bool

View File

@ -46,17 +46,16 @@ template<class TYPE>
class PropertyRegistry class PropertyRegistry
{ {
public: public:
void defineProperty(const std::string property, typedef std::function<PropertyValue (TYPE object, Sta *sta)> PropertyHandler;
std::function<PropertyValue (TYPE object, void defineProperty(const std::string &property,
Sta *sta)> handler); PropertyHandler handler);
PropertyValue getProperty(TYPE object, PropertyValue getProperty(TYPE object,
const std::string property, const std::string &property,
const char *type_name, const char *type_name,
Sta *sta); Sta *sta);
private: private:
std::map<const std::string, std::function<PropertyValue (TYPE object, std::map<std::string, PropertyHandler> registry_;
Sta *sta)>> registry_;
}; };
class Properties class Properties
@ -99,33 +98,24 @@ public:
// [] (const Instance *, Sta *) -> PropertyValue { // [] (const Instance *, Sta *) -> PropertyValue {
// return PropertyValue("bar"); // return PropertyValue("bar");
// }); // });
void defineProperty(std::string property, void defineProperty(std::string &property,
std::function<PropertyValue (const Library *lib, PropertyRegistry<const Library *>::PropertyHandler handler);
Sta *sta)> handler); void defineProperty(std::string &property,
void defineProperty(std::string property, PropertyRegistry<const LibertyLibrary *>::PropertyHandler handler);
std::function<PropertyValue (const LibertyLibrary *lib, void defineProperty(std::string &property,
Sta *sta)> handler); PropertyRegistry<const Cell *>::PropertyHandler handler);
void defineProperty(std::string property, void defineProperty(std::string &property,
std::function<PropertyValue (const Cell *cell, PropertyRegistry<const LibertyCell *>::PropertyHandler handler);
Sta *sta)> handler); void defineProperty(std::string &property,
void defineProperty(std::string property, PropertyRegistry<const Port *>::PropertyHandler handler);
std::function<PropertyValue (const LibertyCell *cell, void defineProperty(std::string &property,
Sta *sta)> handler); PropertyRegistry<const LibertyPort *>::PropertyHandler handler);
void defineProperty(std::string property, void defineProperty(std::string &property,
std::function<PropertyValue (const Port *Port, PropertyRegistry<const Instance *>::PropertyHandler handler);
Sta *sta)> handler); void defineProperty(std::string &property,
void defineProperty(std::string property, PropertyRegistry<const Pin *>::PropertyHandler handler);
std::function<PropertyValue (const LibertyPort *port, void defineProperty(std::string &property,
Sta *sta)> handler); PropertyRegistry<const Net *>::PropertyHandler handler);
void defineProperty(std::string property,
std::function<PropertyValue (const Instance *inst,
Sta *sta)> handler);
void defineProperty(std::string property,
std::function<PropertyValue (const Pin *pin,
Sta *sta)> handler);
void defineProperty(std::string property,
std::function<PropertyValue (const Net *net,
Sta *sta)> handler);
protected: protected:
PropertyValue portSlew(const Port *port, PropertyValue portSlew(const Port *port,

View File

@ -71,6 +71,8 @@ static unsigned
hashCellPgPorts(const LibertyCell *cell); hashCellPgPorts(const LibertyCell *cell);
static unsigned static unsigned
hashPgPort(const LibertyPgPort *port); hashPgPort(const LibertyPgPort *port);
static bool
cellHasFuncs(const LibertyCell *cell);
static bool static bool
equivCellPgPorts(const LibertyCell *cell1, equivCellPgPorts(const LibertyCell *cell1,
@ -329,35 +331,44 @@ bool
equivCells(const LibertyCell *cell1, equivCells(const LibertyCell *cell1,
const LibertyCell *cell2) const LibertyCell *cell2)
{ {
return equivCellPortsAndFuncs(cell1, cell2) return equivCellPorts(cell1, cell2)
&& equivCellFuncs(cell1, cell2)
&& equivCellPgPorts(cell1, cell2) && equivCellPgPorts(cell1, cell2)
&& equivCellSequentials(cell1, cell2) && equivCellSequentials(cell1, cell2)
&& equivCellStatetables(cell1, cell2) && equivCellStatetables(cell1, cell2)
&& equivCellTimingArcSets(cell1, cell2); // Reqwuire timing arc equivalence if there are no functions.
&& (cellHasFuncs(cell1)
|| equivCellTimingArcSets(cell1, cell2));
}
static bool
cellHasFuncs(const LibertyCell *cell)
{
LibertyCellPortIterator port_iter(cell);
while (port_iter.hasNext()) {
LibertyPort *port = port_iter.next();
if (port->function())
return true;
}
return false;
} }
bool bool
equivCellPortsAndFuncs(const LibertyCell *cell1, equivCellFuncs(const LibertyCell *cell1,
const LibertyCell *cell2) const LibertyCell *cell2)
{ {
if (cell1->portCount() != cell2->portCount()) LibertyCellPortIterator port_iter1(cell1);
return false; while (port_iter1.hasNext()) {
else { LibertyPort *port1 = port_iter1.next();
LibertyCellPortIterator port_iter1(cell1); const char *name = port1->name();
while (port_iter1.hasNext()) { LibertyPort *port2 = cell2->findLibertyPort(name);
LibertyPort *port1 = port_iter1.next(); if (!(port2
const char *name = port1->name(); && FuncExpr::equiv(port1->function(), port2->function())
LibertyPort *port2 = cell2->findLibertyPort(name); && FuncExpr::equiv(port1->tristateEnable(),
if (!(port2 port2->tristateEnable())))
&& LibertyPort::equiv(port1, port2) return false;
&& FuncExpr::equiv(port1->function(), port2->function())
&& FuncExpr::equiv(port1->tristateEnable(),
port2->tristateEnable()))){
return false;
}
}
return true;
} }
return true;
} }
bool bool

View File

@ -254,8 +254,12 @@ FuncExpr::bitSubExpr(int bit_offset)
return makePort(port); return makePort(port);
} }
else { else {
LibertyPort *port = port_->findLibertyMember(bit_offset); if (bit_offset < port_->size()) {
return makePort(port); LibertyPort *port = port_->findLibertyMember(bit_offset);
return makePort(port);
}
else
return nullptr;
} }
} }
else else

View File

@ -130,15 +130,13 @@ LibertyLibrary::~LibertyLibrary()
wireloads_.deleteContents(); wireloads_.deleteContents();
wire_load_selections_.deleteContents(); wire_load_selections_.deleteContents();
delete units_; delete units_;
// Also deletes default_ocv_derate_
ocv_derate_map_.deleteContents(); ocv_derate_map_.deleteContents();
delete buffers_; delete buffers_;
delete inverters_; delete inverters_;
driver_waveform_map_.deleteContents(); driver_waveform_map_.deleteContents();
delete driver_waveform_default_; delete driver_waveform_default_;
delete default_ocv_derate_;
default_ocv_derate_ = nullptr;
} }
LibertyCell * LibertyCell *

View File

@ -2305,8 +2305,13 @@ void
LibertyReader::checkScaledCell(LibertyGroup *group) LibertyReader::checkScaledCell(LibertyGroup *group)
{ {
if (equivCellPorts(cell_, scaled_cell_owner_)) { if (equivCellPorts(cell_, scaled_cell_owner_)) {
if (!equivCellPortsAndFuncs(cell_, scaled_cell_owner_)) if (!equivCellPorts(cell_, scaled_cell_owner_))
libWarn(1206, group, "scaled_cell %s, %s port functions do not match cell port functions.", libWarn(1206, group, "scaled_cell %s, %s ports do not match cell ports",
cell_->name(),
op_cond_->name());
if (!equivCellFuncs(cell_, scaled_cell_owner_))
libWarn(1206, group,
"scaled_cell %s, %s port functions do not match cell port functions.",
cell_->name(), cell_->name(),
op_cond_->name()); op_cond_->name());
} }
@ -4920,7 +4925,7 @@ LibertyReader::visitWhen(LibertyAttr *attr)
false, "when", attr); false, "when", attr);
} }
} }
if (timing_) { if (timing_ && !in_ccsn_) {
const char *func = getAttrString(attr); const char *func = getAttrString(attr);
if (func) { if (func) {
TimingArcAttrs *attrs = timing_->attrs().get(); TimingArcAttrs *attrs = timing_->attrs().get();

View File

@ -109,7 +109,8 @@ GenclkInfo::setFoundLatchFdbkEdges(bool found)
Genclks::Genclks(StaState *sta) : Genclks::Genclks(StaState *sta) :
StaState(sta), StaState(sta),
found_insertion_delays_(false) found_insertion_delays_(false),
vertex_src_paths_map_(graph_)
{ {
} }
@ -124,6 +125,7 @@ Genclks::clear()
{ {
found_insertion_delays_ = false; found_insertion_delays_ = false;
genclk_info_map_.deleteContentsClear(); genclk_info_map_.deleteContentsClear();
vertex_src_paths_map_.clear();
clearSrcPaths(); clearSrcPaths();
} }
@ -846,21 +848,27 @@ Genclks::findSrcArrivals(Clock *gclk,
insert_iter.visit(levelize_->maxLevel(), &arrival_visitor); insert_iter.visit(levelize_->maxLevel(), &arrival_visitor);
} }
// Copy existing generated clock source paths from vertex to tag_bldr. // Copy generated clock source paths to tag_bldr.
void void
Genclks::copyGenClkSrcPaths(Vertex *vertex, Genclks::copyGenClkSrcPaths(Vertex *vertex,
TagGroupBldr *tag_bldr) TagGroupBldr *tag_bldr)
{ {
Path *paths = graph_->paths(vertex); auto itr = vertex_src_paths_map_.find(vertex);
if (paths) { if (itr != vertex_src_paths_map_.end()) {
TagGroup *tag_group = search_->tagGroup(vertex); std::vector<const Path*> &src_paths = itr->second;
if (tag_group) { for (const Path *path : src_paths) {
for (auto const [tag, path_index] : *tag_group->pathIndexMap()) { Path src_path = *path;
if (tag->isGenClkSrcPath()) { Path *prev_path = src_path.prevPath();
Path &path = paths[path_index]; if (prev_path) {
tag_bldr->insertPath(path); Path *prev_vpath = Path::vertexPath(prev_path, this);
} src_path.setPrevPath(prev_vpath);
} }
debugPrint(debug_, "genclk", 3, "vertex %s insert genclk %s src path %s %ss",
src_path.vertex(this)->to_string(this).c_str(),
src_path.tag(this)->genClkSrcPathClk(this)->name(),
src_path.tag(this)->pathAnalysisPt(this)->pathMinMax()->to_string().c_str(),
src_path.tag(this)->to_string(true, false, this).c_str());
tag_bldr->insertPath(src_path);
} }
} }
} }
@ -941,10 +949,20 @@ Genclks::recordSrcPaths(Clock *gclk)
} }
} }
} }
if (!found_src_paths if (found_src_paths) {
// Don't warn if the master clock is ideal. for (const Path &path : src_paths) {
&& gclk->masterClk() if (!path.isNull()) {
&& gclk->masterClk()->isPropagated()) const Path *p = &path;
while (p) {
vertex_src_paths_map_[p->vertex(this)].push_back(p);
p = p->prevPath();
}
}
}
}
// Don't warn if the master clock is ideal.
else if (gclk->masterClk()
&& gclk->masterClk()->isPropagated())
report_->warn(1062, "generated clock %s source pin %s missing paths from master clock %s.", report_->warn(1062, "generated clock %s source pin %s missing paths from master clock %s.",
gclk->name(), gclk->name(),
network_->pathName(gclk_pin), network_->pathName(gclk_pin),

View File

@ -27,7 +27,7 @@
#include "Map.hh" #include "Map.hh"
#include "Transition.hh" #include "Transition.hh"
#include "NetworkClass.hh" #include "NetworkClass.hh"
#include "GraphClass.hh" #include "Graph.hh"
#include "SdcClass.hh" #include "SdcClass.hh"
#include "SearchClass.hh" #include "SearchClass.hh"
#include "StaState.hh" #include "StaState.hh"
@ -51,6 +51,7 @@ public:
typedef Map<Clock*, GenclkInfo*> GenclkInfoMap; typedef Map<Clock*, GenclkInfo*> GenclkInfoMap;
typedef Map<ClockPinPair, std::vector<Path>, ClockPinPairLess> GenclkSrcPathMap; typedef Map<ClockPinPair, std::vector<Path>, ClockPinPairLess> GenclkSrcPathMap;
typedef std::map<Vertex*, std::vector<const Path*>, VertexIdLess> VertexGenclkSrcPathsMap;
class Genclks : public StaState class Genclks : public StaState
{ {
@ -133,6 +134,7 @@ private:
bool found_insertion_delays_; bool found_insertion_delays_;
GenclkSrcPathMap genclk_src_paths_; GenclkSrcPathMap genclk_src_paths_;
GenclkInfoMap genclk_info_map_; GenclkInfoMap genclk_info_map_;
VertexGenclkSrcPathsMap vertex_src_paths_map_;
}; };
} // namespace } // namespace

View File

@ -1308,73 +1308,64 @@ Properties::capacitancePropertyValue(float cap)
//////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Library *lib, PropertyRegistry<const Library *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_library_.defineProperty(property, handler); registry_library_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const LibertyLibrary *lib, PropertyRegistry<const LibertyLibrary *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_liberty_library_.defineProperty(property, handler); registry_liberty_library_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Cell *cell, PropertyRegistry<const Cell *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_cell_.defineProperty(property, handler); registry_cell_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const LibertyCell *cell, PropertyRegistry<const LibertyCell *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_liberty_cell_.defineProperty(property, handler); registry_liberty_cell_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Port *Port, PropertyRegistry<const Port *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_port_.defineProperty(property, handler); registry_port_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const LibertyPort *port, PropertyRegistry<const LibertyPort *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_liberty_port_.defineProperty(property, handler); registry_liberty_port_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Instance *inst, PropertyRegistry<const Instance *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_instance_.defineProperty(property, handler); registry_instance_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Pin *pin, PropertyRegistry<const Pin *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_pin_.defineProperty(property, handler); registry_pin_.defineProperty(property, handler);
} }
void void
Properties::defineProperty(std::string property, Properties::defineProperty(std::string &property,
std::function<PropertyValue (const Net *net, PropertyRegistry<const Net *>::PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_net_.defineProperty(property, handler); registry_net_.defineProperty(property, handler);
} }
@ -1384,7 +1375,7 @@ Properties::defineProperty(std::string property,
template<class TYPE> template<class TYPE>
PropertyValue PropertyValue
PropertyRegistry<TYPE>::getProperty(TYPE object, PropertyRegistry<TYPE>::getProperty(TYPE object,
const std::string property, const std::string &property,
const char *type_name, const char *type_name,
Sta *sta) Sta *sta)
@ -1398,9 +1389,8 @@ PropertyRegistry<TYPE>::getProperty(TYPE object,
template<class TYPE> template<class TYPE>
void void
PropertyRegistry<TYPE>::defineProperty(const std::string property, PropertyRegistry<TYPE>::defineProperty(const std::string &property,
std::function<PropertyValue (TYPE object, PropertyHandler handler)
Sta *sta)> handler)
{ {
registry_[property] = handler; registry_[property] = handler;
} }

View File

@ -1276,8 +1276,7 @@ Search::arrivalsChanged(Vertex *vertex,
|| path1->tag(this) != path2->tag(this) || path1->tag(this) != path2->tag(this)
|| !delayEqual(path1->arrival(), path2->arrival()) || !delayEqual(path1->arrival(), path2->arrival())
|| path1->prevEdge(this) != path2->prevEdge(this) || path1->prevEdge(this) != path2->prevEdge(this)
|| path1->prevArc(this) != path2->prevArc(this) || path1->prevArc(this) != path2->prevArc(this))
|| path1->prevPath() != path2->prevPath())
return true; return true;
} }
return false; return false;
@ -1409,6 +1408,7 @@ ArrivalVisitor::seedInputDelayArrival(const Pin *pin,
{ {
TagGroupBldr tag_bldr(true, this); TagGroupBldr tag_bldr(true, this);
tag_bldr.init(vertex); tag_bldr.init(vertex);
search_->genclks()->copyGenClkSrcPaths(vertex, &tag_bldr);
search_->seedInputDelayArrival(pin, vertex, input_delay, search_->seedInputDelayArrival(pin, vertex, input_delay,
!network_->isTopLevelPort(pin), &tag_bldr); !network_->isTopLevelPort(pin), &tag_bldr);
search_->setVertexArrivals(vertex, &tag_bldr); search_->setVertexArrivals(vertex, &tag_bldr);
@ -1480,6 +1480,7 @@ Search::seedArrival(Vertex *vertex)
else if (isInputArrivalSrchStart(vertex)) { else if (isInputArrivalSrchStart(vertex)) {
TagGroupBldr tag_bldr(true, this); TagGroupBldr tag_bldr(true, this);
tag_bldr.init(vertex); tag_bldr.init(vertex);
genclks_->copyGenClkSrcPaths(vertex, &tag_bldr);
seedInputArrival(pin, vertex, &tag_bldr); seedInputArrival(pin, vertex, &tag_bldr);
setVertexArrivals(vertex, &tag_bldr); setVertexArrivals(vertex, &tag_bldr);
if (!tag_bldr.empty()) if (!tag_bldr.empty())
@ -1496,6 +1497,7 @@ Search::seedArrival(Vertex *vertex)
network_->pathName(pin)); network_->pathName(pin));
TagGroupBldr tag_bldr(true, this); TagGroupBldr tag_bldr(true, this);
tag_bldr.init(vertex); tag_bldr.init(vertex);
genclks_->copyGenClkSrcPaths(vertex, &tag_bldr);
if (makeUnclkedPaths(vertex, is_reg_clk, false, &tag_bldr)) if (makeUnclkedPaths(vertex, is_reg_clk, false, &tag_bldr))
// Only search downstream if there are no false paths from here. // Only search downstream if there are no false paths from here.
arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_); arrival_iter_->enqueueAdjacentVertices(vertex, search_adj_);
@ -1737,6 +1739,7 @@ Search::seedInputArrival(const Pin *pin,
// There can be multiple arrivals for a pin with wrt different clocks. // There can be multiple arrivals for a pin with wrt different clocks.
TagGroupBldr tag_bldr(true, this); TagGroupBldr tag_bldr(true, this);
tag_bldr.init(vertex); tag_bldr.init(vertex);
genclks_->copyGenClkSrcPaths(vertex, &tag_bldr);
InputDelaySet *input_delays = sdc_->inputDelaysLeafPin(pin); InputDelaySet *input_delays = sdc_->inputDelaysLeafPin(pin);
if (input_delays) { if (input_delays) {
for (InputDelay *input_delay : *input_delays) { for (InputDelay *input_delay : *input_delays) {
@ -3221,7 +3224,6 @@ Search::findRequireds(Level level)
seedInvalidRequireds(); seedInvalidRequireds();
int required_count = required_iter_->visitParallel(level, &req_visitor); int required_count = required_iter_->visitParallel(level, &req_visitor);
deleteTagsPrev(); deleteTagsPrev();
genclks_->updateSrcPathPrevs();
requireds_exist_ = true; requireds_exist_ = true;
debugPrint(debug_, "search", 1, "found %d requireds", required_count); debugPrint(debug_, "search", 1, "found %d requireds", required_count);
stats.report("Find requireds"); stats.report("Find requireds");