refactor SdcNetwork

This commit is contained in:
James Cherry 2019-06-30 17:17:03 -07:00
parent 93f5f9d664
commit d76ee0ca62
5 changed files with 412 additions and 530 deletions

View File

@ -32,7 +32,7 @@ verilog
Verilog netlist reader that implements the network API.
graph
Timing graph built from network and library cell timing arcs.
constraints
sdc
SDC timing constraint classes.
sdf
SDF reader, writer and annotator.
@ -59,16 +59,16 @@ the code.
STA API
-------
Major components of the STA such as the network, timing graph,
constraints, and search are implemented as separate classes. The Sta
class contains an instance of each of these components.
Major components of the STA such as the network, timing graph, sdc,
and search are implemented as separate classes. The Sta class
contains an instance of each of these components.
The Sta class defines the bulk of the externally visible API used by
the Tcl interface, and coordinates operations that involve multiple
components. For example, when a false path command is entered into
the Tcl command interpreter the Sta passes the declaration on to the
Constraints component and tells the Search component to invalidate all
arrival and required times.
the Tcl command interpreter, the Sta passes the declaration on to the
Sdc component and tells the Search component to invalidate all arrival
and required times.
Applications should call functions defined by the Sta class rather
than functions defined by the components. Calling functions defined
@ -337,11 +337,11 @@ constructed using:
Graph(this, 2, true, ap_count);
Constraints
-----------
SDC
---
There is no support for updating constraints when network edits delete
the instance, pin, or net objects refered to by the constraints.
There is no support for updating SDC when network edits delete
the instance, pin, or net objects refered to by the SDC.
Delay Calculation
-----------------
@ -399,12 +399,12 @@ record signal arrival and required times. As each vertex is visited
in the forward search its required time is found using If the vertex
is constrained by setup or hold timing checks, min/max path delay
exceptions or gated timing checks its required time is found from the
constraints. The slack is the difference between the vertex required
time and arrival time. If the vertex is constrained it is scheduled
for a breadth first backward search to propagate required times to the
fanin vertices. Separate events (and hence arrival and required
times) are used for each clock edge and exception set that cause a
vertex to change.
SDC. The slack is the difference between the vertex required time and
arrival time. If the vertex is constrained it is scheduled for a
breadth first backward search to propagate required times to the fanin
vertices. Separate events (and hence arrival and required times) are
used for each clock edge and exception set that cause a vertex to
change.
Arrival, required and slack calculations are incremental using a level
based "lazy evaluation" algorithm. The first time arrival/required

View File

@ -29,471 +29,6 @@ static const char *
escapeBrackets(const char *token,
const Network *network);
////////////////////////////////////////////////////////////////
// Helper to parse an instance path (with optional net/port tail).
// Since dividers are not escaped in SDC, look for an instance for
// each sub-section of the path. If none is found, escape the divider
// and keep looking. For the path a/b/c this looks for instances
// a
// a\/b
// a\/b\/c
class SdcPathParser
{
public:
SdcPathParser(const char *path,
const Network *network);
~SdcPathParser();
Instance *instance() const { return inst_; }
const char *pathTail() const { return path_tail_; }
protected:
void initialScan(const char *path);
void parsePath(const char *path);
int path_length_;
const Network *network_;
char divider_;
char escape_;
// Unescaped divider count.
int divider_count_;
char *inst_path_;
Instance *inst_;
const char *path_tail_;
private:
DISALLOW_COPY_AND_ASSIGN(SdcPathParser);
};
SdcPathParser::SdcPathParser(const char *path,
const Network *network) :
network_(network),
divider_(network->pathDivider()),
escape_(network->pathEscape()),
inst_path_(nullptr),
inst_(nullptr)
{
initialScan(path);
if (divider_count_ > 0)
parsePath(path);
else
path_tail_ = path;
}
SdcPathParser::~SdcPathParser()
{
stringDelete(inst_path_);
}
// Scan the path for unescaped dividers.
void
SdcPathParser::initialScan(const char *path)
{
divider_count_ = 0;
path_length_ = 0;
for (const char *s = path; *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
s++;
path_length_++;
}
}
else if (ch == divider_)
divider_count_++;
path_length_++;
}
}
void
SdcPathParser::parsePath(const char *path)
{
Instance *parent = network_->topInstance();
// Leave room to escape all the dividers and '\0'.
int inst_path_length = path_length_ + divider_count_ + 1;
inst_path_ = new char[inst_path_length];
path_tail_ = inst_path_;
char *p = inst_path_;
for (const char *s = path; *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
*p++ = ch;
*p++ = s[1];
s++;
}
}
else if (ch == divider_) {
// Terminate the sub-path up to this divider.
*p = '\0';
Instance *child = network_->findChild(parent, inst_path_);
if (child) {
// Found an instance for the sub-path up to this divider.
parent = inst_ = child;
// Reset the instance path.
path_tail_ = p = inst_path_;
}
else {
// No match for sub-path. Escape the divider and keep looking.
*p++ = escape_;
*p++ = divider_;
}
}
else
*p++ = ch;
if (p - inst_path_ + 1 > inst_path_length)
internalError("inst path string lenth estimate busted");
}
*p = '\0';
}
////////////////////////////////////////////////////////////////
// Helper to visit an instance path matches.
// Since dividers are not escaped in SDC, look for instance matches for
// each sub-section of the path. If none are found, escape the divider
// and keep looking. For the path a/b/c this looks for instances
// This base class is specialized by defining visitTail.
// a
// a\/b
// a\/b\/c
class SdcPathMatcher
{
public:
SdcPathMatcher(const Network *network);
void findMatches(const Instance *parent,
const PatternMatch *pattern);
virtual bool visitTail(const Instance *instance,
const PatternMatch *tail) = 0;
protected:
void initialScan(const PatternMatch *pattern);
bool visitMatches(const Instance *parent,
const PatternMatch *tail);
int path_length_;
const Network *network_;
char divider_;
char escape_;
int divider_count_;
private:
DISALLOW_COPY_AND_ASSIGN(SdcPathMatcher);
};
SdcPathMatcher::SdcPathMatcher(const Network *network) :
network_(network),
divider_(network->pathDivider()),
escape_(network->pathEscape())
{
}
void
SdcPathMatcher::findMatches(const Instance *parent,
const PatternMatch *pattern)
{
initialScan(pattern);
visitMatches(parent, pattern);
}
// Scan the path for unescaped dividers.
void
SdcPathMatcher::initialScan(const PatternMatch *pattern)
{
divider_count_ = 0;
path_length_ = 0;
for (const char *s = pattern->pattern(); *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
s++;
path_length_++;
}
}
else if (ch == divider_)
divider_count_++;
path_length_++;
}
}
bool
SdcPathMatcher::visitMatches(const Instance *parent,
const PatternMatch *tail)
{
// Leave room to escape all the dividers and '\0'.
int inst_path_length = path_length_ + divider_count_ + 1;
char *inst_path = new char[inst_path_length];
char *p = inst_path;
bool has_brkts = false;
bool found_match = false;
for (const char *s = tail->pattern(); *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
*p++ = ch;
*p++ = s[1];
s++;
}
}
else if (ch == divider_) {
// Terminate the sub-path up to this divider.
*p = '\0';
PatternMatch matcher(inst_path, tail);
InstanceSeq matches;
network_->findChildrenMatching(parent, &matcher, &matches);
if (has_brkts && matches.empty()) {
// Look for matches after escaping brackets.
const PatternMatch escaped_brkts(escapeBrackets(inst_path, network_),
tail);
network_->findChildrenMatching(parent, &escaped_brkts, &matches);
}
if (!matches.empty()) {
// Found instance matches for the sub-path up to this divider.
const PatternMatch tail_pattern(s + 1, tail);
InstanceSeq::Iterator match_iter(matches);
while (match_iter.hasNext()) {
Instance *match = match_iter.next();
// Recurse to save the iterator state so we can iterate over
// multiple nested partial matches.
found_match |= visitMatches(match, &tail_pattern);
}
}
// Escape the divider and keep looking.
*p++ = escape_;
*p++ = divider_;
}
else {
if (ch == '[' || ch == ']')
has_brkts = true;
*p++ = ch;
}
if (p - inst_path + 1 > inst_path_length)
internalError("inst path string lenth estimate busted");
}
*p = '\0';
if (!found_match) {
PatternMatch tail_pattern(inst_path, tail);
found_match |= visitTail(parent, &tail_pattern);
if (!found_match && has_brkts) {
// Look for matches after escaping brackets.
char *escaped_path = stringCopy(escapeBrackets(inst_path, network_));
const PatternMatch escaped_tail(escaped_path, tail);
found_match |= visitTail(parent, &escaped_tail);
stringDelete(escaped_path);
}
}
stringDelete(inst_path);
return found_match;
}
////////////////////////////////////////////////////////////////
class SdcInstanceMatcher : public SdcPathMatcher
{
public:
SdcInstanceMatcher(const Network *network,
InstanceSeq *insts);
virtual bool visitTail(const Instance *instance,
const PatternMatch *tail);
protected:
InstanceSeq *insts_;
private:
DISALLOW_COPY_AND_ASSIGN(SdcInstanceMatcher);
};
SdcInstanceMatcher::SdcInstanceMatcher(const Network *network,
InstanceSeq *insts) :
SdcPathMatcher(network),
insts_(insts)
{
}
bool
SdcInstanceMatcher::visitTail(const Instance *instance,
const PatternMatch *tail)
{
size_t match_count = insts_->size();
network_->findChildrenMatching(instance, tail, insts_);
return insts_->size() != match_count;
}
void
SdcNetwork::findInstancesMatching(const Instance *context,
const PatternMatch *pattern,
InstanceSeq *insts) const
{
SdcInstanceMatcher matcher(network_, insts);
matcher.findMatches(context, pattern);
}
////////////////////////////////////////////////////////////////
class SdcNetMatcher : public SdcPathMatcher
{
public:
SdcNetMatcher(const Network *network,
NetSeq *nets);
virtual bool visitTail(const Instance *instance,
const PatternMatch *tail);
protected:
DISALLOW_COPY_AND_ASSIGN(SdcNetMatcher);
NetSeq *nets_;
};
SdcNetMatcher::SdcNetMatcher(const Network *network,
NetSeq *nets) :
SdcPathMatcher(network),
nets_(nets)
{
}
bool
SdcNetMatcher::visitTail(const Instance *instance,
const PatternMatch *tail)
{
size_t match_count = nets_->size();
network_->findInstNetsMatching(instance, tail, nets_);
return nets_->size() != match_count;
}
void
SdcNetwork::findNetsMatching(const Instance *parent,
const PatternMatch *pattern,
NetSeq *nets) const
{
SdcNetMatcher matcher(this, nets);
matcher.findMatches(parent, pattern);
}
void
SdcNetwork::findInstNetsMatching(const Instance *instance,
const PatternMatch *pattern,
NetSeq *nets) const
{
network_->findInstNetsMatching(instance, pattern, nets);
if (nets->empty()) {
// Look for matches after escaping path dividers.
const PatternMatch escaped_dividers(escapeDividers(pattern->pattern(),
this),
pattern);
network_->findInstNetsMatching(instance, &escaped_dividers, nets);
if (nets->empty()) {
// Look for matches after escaping brackets.
const PatternMatch escaped_brkts(escapeBrackets(pattern->pattern(),this),
pattern);
network_->findInstNetsMatching(instance, &escaped_brkts, nets);
}
}
}
////////////////////////////////////////////////////////////////
class SdcPinMatcher : public SdcPathMatcher
{
public:
SdcPinMatcher(const Network *network,
PinSeq *pins);
virtual bool visitTail(const Instance *instance,
const PatternMatch *tail);
protected:
DISALLOW_COPY_AND_ASSIGN(SdcPinMatcher);
PinSeq *pins_;
};
SdcPinMatcher::SdcPinMatcher(const Network *network,
PinSeq *pins) :
SdcPathMatcher(network),
pins_(pins)
{
}
bool
SdcPinMatcher::visitTail(const Instance *instance,
const PatternMatch *tail)
{
bool found_match = false;
if (instance != network_->topInstance()) {
Cell *cell = network_->cell(instance);
CellPortIterator *port_iter = network_->portIterator(cell);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
const char *port_name = network_->name(port);
if (network_->hasMembers(port)) {
bool bus_matches = tail->match(port_name)
|| tail->match(escapeDividers(port_name, network_));
PortMemberIterator *member_iter = network_->memberIterator(port);
while (member_iter->hasNext()) {
Port *member_port = member_iter->next();
Pin *pin = network_->findPin(instance, member_port);
if (pin) {
if (bus_matches) {
pins_->push_back(pin);
found_match = true;
}
else {
const char *member_name = network_->name(member_port);
if (tail->match(member_name)
|| tail->match(escapeDividers(member_name, network_))) {
pins_->push_back(pin);
found_match = true;
}
}
}
}
delete member_iter;
}
else if (tail->match(port_name)
|| tail->match(escapeDividers(port_name, network_))) {
Pin *pin = network_->findPin(instance, port);
if (pin) {
pins_->push_back(pin);
found_match = true;
}
}
}
delete port_iter;
}
return found_match;
}
// Top level ports are not considered pins by get_pins.
void
SdcNetwork::findPinsMatching(const Instance *instance,
const PatternMatch *pattern,
PinSeq *pins) const
{
if (stringEq(pattern->pattern(), "*")) {
// Pattern of '*' matches all child instance pins.
InstanceChildIterator *child_iter = childIterator(instance);
while (child_iter->hasNext()) {
Instance *child = child_iter->next();
InstancePinIterator *pin_iter = pinIterator(child);
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
pins->push_back(pin);
}
delete pin_iter;
}
delete child_iter;
}
else {
SdcPinMatcher matcher(network_, pins);
matcher.findMatches(instance, pattern);
}
}
////////////////////////////////////////////////////////////////
NetworkNameAdapter::NetworkNameAdapter(Network *network) :
NetworkEdit(),
network_(network),
@ -731,6 +266,12 @@ NetworkNameAdapter::toIndex(const Port *port) const
return network_->toIndex(port);
}
bool
NetworkNameAdapter::hasMembers(const Port *port) const
{
return network_->hasMembers(port);
}
Port *
NetworkNameAdapter::findMember(const Port *port,
int index) const
@ -1071,12 +612,6 @@ SdcNetwork::busName(const Port *port) const
return staToSdc(network_->busName(port));
}
bool
SdcNetwork::hasMembers(const Port *port) const
{
return network_->hasMembers(port);
}
const char *
SdcNetwork::name(const Instance *instance) const
{
@ -1113,17 +648,34 @@ SdcNetwork::pathName(const Net *net) const
return staToSdc(network_->pathName(net));
}
////////////////////////////////////////////////////////////////
Instance *
SdcNetwork::findInstance(const char *path_name) const
{
SdcPathParser path_parser(path_name, this);
Instance *parent = path_parser.instance();
const char *child_name;
Instance *parent;
parsePath(path_name, parent, child_name);
if (parent == nullptr)
parent = network_->topInstance();
const char *child_name = path_parser.pathTail();
return findChild(parent, child_name);
}
void
SdcNetwork::findInstancesMatching(const Instance *context,
const PatternMatch *pattern,
InstanceSeq *insts) const
{
visitMatches(context, pattern,
[&](const Instance *instance,
const PatternMatch *tail)
{
size_t match_count = insts->size();
network_->findChildrenMatching(instance, tail, insts);
return insts->size() != match_count;
});
}
Instance *
SdcNetwork::findChild(const Instance *parent,
const char *name) const
@ -1136,14 +688,16 @@ SdcNetwork::findChild(const Instance *parent,
return child;
}
////////////////////////////////////////////////////////////////
Net *
SdcNetwork::findNet(const char *path_name) const
{
SdcPathParser path_parser(path_name, this);
const Instance *inst = path_parser.instance();
const char *net_name;
Instance *inst;
parsePath(path_name, inst, net_name);
if (inst == nullptr)
inst = network_->topInstance();
const char *net_name = path_parser.pathTail();
return findNet(inst, net_name);
}
@ -1159,16 +713,52 @@ SdcNetwork::findNet(const Instance *instance,
return net;
}
void
SdcNetwork::findNetsMatching(const Instance *parent,
const PatternMatch *pattern,
NetSeq *nets) const
{
visitMatches(parent, pattern,
[&](const Instance *instance,
const PatternMatch *tail)
{
size_t match_count = nets->size();
network_->findInstNetsMatching(instance, tail, nets);
return nets->size() != match_count;
});
}
void
SdcNetwork::findInstNetsMatching(const Instance *instance,
const PatternMatch *pattern,
NetSeq *nets) const
{
network_->findInstNetsMatching(instance, pattern, nets);
if (nets->empty()) {
// Look for matches after escaping path dividers.
const PatternMatch escaped_dividers(escapeDividers(pattern->pattern(),
this),
pattern);
network_->findInstNetsMatching(instance, &escaped_dividers, nets);
if (nets->empty()) {
// Look for matches after escaping brackets.
const PatternMatch escaped_brkts(escapeBrackets(pattern->pattern(),this),
pattern);
network_->findInstNetsMatching(instance, &escaped_brkts, nets);
}
}
}
////////////////////////////////////////////////////////////////
Pin *
SdcNetwork::findPin(const char *path_name) const
{
SdcPathParser path_parser(path_name, this);
const Instance *inst = path_parser.instance();
const char *port_name;
Instance *inst;
parsePath(path_name, inst, port_name);
if (inst == nullptr)
inst = network_->topInstance();
const char *port_name = path_parser.pathTail();
return findPin(inst, port_name);
}
@ -1185,6 +775,85 @@ SdcNetwork::findPin(const Instance *instance,
return pin;
}
// Top level ports are not considered pins by get_pins.
void
SdcNetwork::findPinsMatching(const Instance *instance,
const PatternMatch *pattern,
PinSeq *pins) const
{
if (stringEq(pattern->pattern(), "*")) {
// Pattern of '*' matches all child instance pins.
InstanceChildIterator *child_iter = childIterator(instance);
while (child_iter->hasNext()) {
Instance *child = child_iter->next();
InstancePinIterator *pin_iter = pinIterator(child);
while (pin_iter->hasNext()) {
Pin *pin = pin_iter->next();
pins->push_back(pin);
}
delete pin_iter;
}
delete child_iter;
}
else
visitMatches(instance, pattern,
[&](const Instance *instance,
const PatternMatch *tail)
{
return visitPinTail(instance, tail, pins);
});
}
bool
SdcNetwork::visitPinTail(const Instance *instance,
const PatternMatch *tail,
PinSeq *pins) const
{
bool found_match = false;
if (instance != network_->topInstance()) {
Cell *cell = network_->cell(instance);
CellPortIterator *port_iter = network_->portIterator(cell);
while (port_iter->hasNext()) {
Port *port = port_iter->next();
const char *port_name = network_->name(port);
if (network_->hasMembers(port)) {
bool bus_matches = tail->match(port_name)
|| tail->match(escapeDividers(port_name, network_));
PortMemberIterator *member_iter = network_->memberIterator(port);
while (member_iter->hasNext()) {
Port *member_port = member_iter->next();
Pin *pin = network_->findPin(instance, member_port);
if (pin) {
if (bus_matches) {
pins->push_back(pin);
found_match = true;
}
else {
const char *member_name = network_->name(member_port);
if (tail->match(member_name)
|| tail->match(escapeDividers(member_name, network_))) {
pins->push_back(pin);
found_match = true;
}
}
}
}
delete member_iter;
}
else if (tail->match(port_name)
|| tail->match(escapeDividers(port_name, network_))) {
Pin *pin = network_->findPin(instance, port);
if (pin) {
pins->push_back(pin);
found_match = true;
}
}
}
delete port_iter;
}
return found_match;
}
Instance *
SdcNetwork::makeInstance(LibertyCell *cell,
const char *name,
@ -1204,6 +873,190 @@ SdcNetwork::makeNet(const char *name,
////////////////////////////////////////////////////////////////
// Helper to parse an instance path (with optional net/port tail).
// Since dividers are not escaped in SDC, look for an instance for
// each sub-section of the path. If none is found, escape the divider
// and keep looking. For the path a/b/c this looks for instances
// a
// a\/b
// a\/b\/c
void
SdcNetwork::parsePath(const char *path,
// Return values.
Instance *&inst,
const char *&path_tail) const
{
int divider_count, path_length;
scanPath(path, divider_count, path_length);
if (divider_count > 0)
parsePath(path, divider_count, path_length, inst, path_tail);
else {
inst = nullptr;
path_tail = path;
}
}
// Scan the path for unescaped dividers.
void
SdcNetwork::scanPath(const char *path,
// Return values.
// Unescaped divider count.
int &divider_count,
int &path_length) const
{
divider_count = 0;
path_length = 0;
for (const char *s = path; *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
s++;
path_length++;
}
}
else if (ch == divider_)
divider_count++;
path_length++;
}
}
void
SdcNetwork::parsePath(const char *path,
int divider_count,
int path_length,
// Return values.
Instance *&inst,
const char *&path_tail) const
{
Instance *parent = topInstance();
// Leave room to escape all the dividers and '\0'.
int inst_path_length = path_length + divider_count + 1;
char *inst_path = new char[inst_path_length];
inst = nullptr;
path_tail = inst_path;
char *p = inst_path;
for (const char *s = path; *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
*p++ = ch;
*p++ = s[1];
s++;
}
}
else if (ch == divider_) {
// Terminate the sub-path up to this divider.
*p = '\0';
Instance *child = findChild(parent, inst_path);
if (child) {
// Found an instance for the sub-path up to this divider.
parent = inst = child;
// Reset the instance path.
path_tail = p = inst_path;
}
else {
// No match for sub-path. Escape the divider and keep looking.
*p++ = escape_;
*p++ = divider_;
}
}
else
*p++ = ch;
if (p - inst_path + 1 > inst_path_length)
internalError("inst path string lenth estimate busted");
}
*p = '\0';
stringDelete(inst_path);
}
// Helper to visit instance path matches.
// Since dividers are not escaped in SDC, look for instance matches for
// each sub-section of the path. If none are found, escape the divider
// and keep looking. For the path a/b/c this looks for instances
// a
// a\/b
// a\/b\/c
bool
SdcNetwork::visitMatches(const Instance *parent,
const PatternMatch *pattern,
const std::function<bool (const Instance *instance,
const PatternMatch *tail)>
visit_tail) const
{
int divider_count, path_length;
scanPath(pattern->pattern(), divider_count, path_length);
// Leave room to escape all the dividers and '\0'.
int inst_path_length = path_length + divider_count + 1;
char *inst_path = new char[inst_path_length];
char *p = inst_path;
bool has_brkts = false;
bool found_match = false;
for (const char *s = pattern->pattern(); *s; s++) {
char ch = *s;
if (ch == escape_) {
// Make sure we don't skip the null if escape is the last char.
if (s[1] != '\0') {
*p++ = ch;
*p++ = s[1];
s++;
}
}
else if (ch == divider_) {
// Terminate the sub-path up to this divider.
*p = '\0';
PatternMatch matcher(inst_path, pattern);
InstanceSeq matches;
findChildrenMatching(parent, &matcher, &matches);
if (has_brkts && matches.empty()) {
// Look for matches after escaping brackets.
const PatternMatch escaped_brkts(escapeBrackets(inst_path, this),
pattern);
network_->findChildrenMatching(parent, &escaped_brkts, &matches);
}
if (!matches.empty()) {
// Found instance matches for the sub-path up to this divider.
const PatternMatch tail_pattern(s + 1, pattern);
InstanceSeq::Iterator match_iter(matches);
while (match_iter.hasNext()) {
Instance *match = match_iter.next();
// Recurse to save the iterator state so we can iterate over
// multiple nested partial matches.
found_match |= visitMatches(match, &tail_pattern, visit_tail);
}
}
// Escape the divider and keep looking.
*p++ = escape_;
*p++ = divider_;
}
else {
if (ch == '[' || ch == ']')
has_brkts = true;
*p++ = ch;
}
if (p - inst_path + 1 > inst_path_length)
internalError("inst path string lenth estimate busted");
}
*p = '\0';
if (!found_match) {
PatternMatch tail_pattern(inst_path, pattern);
found_match |= visit_tail(parent, &tail_pattern);
if (!found_match && has_brkts) {
// Look for matches after escaping brackets.
char *escaped_path = stringCopy(escapeBrackets(inst_path, this));
const PatternMatch escaped_tail(escaped_path, pattern);
found_match |= visit_tail(parent, &escaped_tail);
stringDelete(escaped_path);
}
}
stringDelete(inst_path);
return found_match;
}
////////////////////////////////////////////////////////////////
static const char *
escapeDividers(const char *token,
const Network *network)

View File

@ -76,6 +76,7 @@ public:
virtual Port *findMember(const Port *port,
int index) const;
virtual PortMemberIterator *memberIterator(const Port *port) const;
virtual bool hasMembers(const Port *port) const;
virtual Instance *topInstance() const;
virtual Cell *cell(const Instance *instance) const;
@ -178,7 +179,6 @@ public:
PortSeq *ports) const;
virtual const char *name(const Port *port) const;
virtual const char *busName(const Port *port) const;
virtual bool hasMembers(const Port *port) const;
virtual const char *name(const Instance *instance) const;
virtual const char *pathName(const Instance *instance) const;
@ -223,6 +223,30 @@ public:
using Network::findPin;
protected:
void parsePath(const char *path,
// Return values.
Instance *&inst,
const char *&path_tail) const;
void scanPath(const char *path,
// Return values.
// Unescaped divider count.
int &divider_count,
int &path_length) const;
void parsePath(const char *path,
int divider_count,
int path_length,
// Return values.
Instance *&inst,
const char *&path_tail) const;
bool visitMatches(const Instance *parent,
const PatternMatch *pattern,
std::function<bool (const Instance *instance,
const PatternMatch *tail)>
visit_tail) const;
bool visitPinTail(const Instance *instance,
const PatternMatch *tail,
PinSeq *pins) const;
const char *staToSdc(const char *sta_name) const;
private:

View File

@ -91,7 +91,7 @@ PropertyUnknown::PropertyUnknown(const char *type,
const char *
PropertyUnknown::what() const throw()
{
return stringPrint("%s objects do not have a %s property.",
return stringPrint("Error: %s objects do not have a %s property.",
type_, property_);
}
@ -692,7 +692,8 @@ getProperty(const Pin *pin,
auto network = sta->cmdNetwork();
if (stringEqual(property, "direction"))
return PropertyValue(network->direction(pin)->name());
else if (stringEqual(property, "full_name"))
else if (stringEqual(property, "name")
|| stringEqual(property, "full_name"))
return PropertyValue(network->pathName(pin));
else if (stringEqual(property, "lib_pin_name"))
return PropertyValue(network->portName(pin));

View File

@ -1821,37 +1821,41 @@ proc get_property_cmd { cmd type_key cmd_args } {
}
proc get_object_property { object prop } {
set object_type [object_type $object]
if { $object_type == "Instance" } {
return [instance_property $object $prop]
} elseif { $object_type == "Pin" } {
return [pin_property $object $prop]
} elseif { $object_type == "Net" } {
return [net_property $object $prop]
} elseif { $object_type == "Clock" } {
return [clock_property $object $prop]
} elseif { $object_type == "Port" } {
return [port_property $object $prop]
} elseif { $object_type == "LibertyPort" } {
return [liberty_port_property $object $prop]
} elseif { $object_type == "LibertyCell" } {
return [liberty_cell_property $object $prop]
} elseif { $object_type == "Cell" } {
return [cell_property $object $prop]
} elseif { $object_type == "Library" } {
return [library_property $object $prop]
} elseif { $object_type == "LibertyLibrary" } {
return [liberty_library_property $object $prop]
} elseif { $object_type == "Edge" } {
return [edge_property $object $prop]
} elseif { $object_type == "PathEnd" } {
return [path_end_property $object $prop]
} elseif { $object_type == "PathRef" } {
return [path_ref_property $object $prop]
} elseif { $object_type == "TimingArcSet" } {
return [timing_arc_set_property $object $prop]
if { [is_object $object] } {
set object_type [object_type $object]
if { $object_type == "Instance" } {
return [instance_property $object $prop]
} elseif { $object_type == "Pin" } {
return [pin_property $object $prop]
} elseif { $object_type == "Net" } {
return [net_property $object $prop]
} elseif { $object_type == "Clock" } {
return [clock_property $object $prop]
} elseif { $object_type == "Port" } {
return [port_property $object $prop]
} elseif { $object_type == "LibertyPort" } {
return [liberty_port_property $object $prop]
} elseif { $object_type == "LibertyCell" } {
return [liberty_cell_property $object $prop]
} elseif { $object_type == "Cell" } {
return [cell_property $object $prop]
} elseif { $object_type == "Library" } {
return [library_property $object $prop]
} elseif { $object_type == "LibertyLibrary" } {
return [liberty_library_property $object $prop]
} elseif { $object_type == "Edge" } {
return [edge_property $object $prop]
} elseif { $object_type == "PathEnd" } {
return [path_end_property $object $prop]
} elseif { $object_type == "PathRef" } {
return [path_ref_property $object $prop]
} elseif { $object_type == "TimingArcSet" } {
return [timing_arc_set_property $object $prop]
} else {
sta_error "get_property unsupported object type $object_type."
}
} else {
sta_error "get_property unsupported object type object_type."
sta_error "get_property $object is not an object."
}
}