OpenSTA/network/SdcNetwork.cc

1124 lines
25 KiB
C++
Raw Normal View History

2018-09-28 17:54:21 +02:00
// OpenSTA, Static Timing Analyzer
2020-03-07 03:50:37 +01:00
// Copyright (c) 2020, Parallax Software, Inc.
2018-09-28 17:54:21 +02:00
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
2020-04-05 20:35:51 +02:00
#include "network/SdcNetwork.hh"
#include "util/StringUtil.hh"
#include "util/PatternMatch.hh"
#include "network/ParseBus.hh"
2018-09-28 17:54:21 +02:00
namespace sta {
static const char *
escapeDividers(const char *token,
const Network *network);
static const char *
escapeBrackets(const char *token,
const Network *network);
NetworkNameAdapter::NetworkNameAdapter(Network *network) :
NetworkEdit(),
network_(network),
network_edit_(dynamic_cast<NetworkEdit*>(network))
{
}
bool
NetworkNameAdapter::linkNetwork(const char *top_cell_name,
bool make_black_boxes,
Report *report)
{
return network_->linkNetwork(top_cell_name, make_black_boxes, report);
}
Instance *
NetworkNameAdapter::topInstance() const
{
return network_->topInstance();
}
LibraryIterator *
NetworkNameAdapter::libraryIterator() const
{
return network_->libraryIterator();
}
LibertyLibraryIterator *
NetworkNameAdapter::libertyLibraryIterator() const
{
return network_->libertyLibraryIterator();
}
Library *
NetworkNameAdapter::findLibrary(const char *name)
{
return network_->findLibrary(name);
}
LibertyLibrary *
NetworkNameAdapter::findLiberty(const char *name)
{
return network_->findLiberty(name);
}
LibertyLibrary *
NetworkNameAdapter::findLibertyFilename(const char *filename)
{
return network_->findLibertyFilename(filename);
}
const char *
NetworkNameAdapter::name(const Library *library) const
{
return network_->name(library);
}
Cell *
NetworkNameAdapter::findCell(const Library *library,
const char *name) const
{
return network_->findCell(library, name);
}
void
NetworkNameAdapter::findCellsMatching(const Library *library,
const PatternMatch *pattern,
CellSeq *cells) const
{
network_->findCellsMatching(library, pattern, cells);
}
////////////////////////////////////////////////////////////////
const char *
NetworkNameAdapter::name(const Cell *cell) const
{
return network_->name(cell);
}
Library *
NetworkNameAdapter::library(const Cell *cell) const
{
return network_->library(cell);
}
const char *
NetworkNameAdapter::filename(const Cell *cell)
{
return network_->filename(cell);
}
LibertyCell *
NetworkNameAdapter::libertyCell(Cell *cell) const
{
return network_->libertyCell(cell);
}
const LibertyCell *
NetworkNameAdapter::libertyCell(const Cell *cell) const
{
return network_->libertyCell(cell);
}
2019-06-14 21:05:34 +02:00
Cell *
NetworkNameAdapter::cell(LibertyCell *cell) const
{
return network_->cell(cell);
}
const Cell *
NetworkNameAdapter::cell(const LibertyCell *cell) const
{
return network_->cell(cell);
}
2018-09-28 17:54:21 +02:00
Port *
NetworkNameAdapter::findPort(const Cell *cell,
const char *name) const
{
return network_->findPort(cell, name);
}
void
NetworkNameAdapter::findPortsMatching(const Cell *cell,
const PatternMatch *pattern,
PortSeq *ports) const
{
network_->findPortsMatching(cell, pattern, ports);
}
bool
NetworkNameAdapter::isLeaf(const Cell *cell) const
{
return network_->isLeaf(cell);
}
CellPortIterator *
NetworkNameAdapter::portIterator(const Cell *cell) const
{
return network_->portIterator(cell);
}
CellPortBitIterator *
NetworkNameAdapter::portBitIterator(const Cell *cell) const
{
return network_->portBitIterator(cell);
}
int
NetworkNameAdapter::portBitCount(const Cell *cell) const
{
return network_->portBitCount(cell);
}
////////////////////////////////////////////////////////////////
const char *
NetworkNameAdapter::name(const Port *port) const
{
return network_->name(port);
}
Cell *
NetworkNameAdapter::cell(const Port *port) const
{
return network_->cell(port);
}
LibertyPort *
NetworkNameAdapter::libertyPort(const Port *port) const
2018-09-28 17:54:21 +02:00
{
return network_->libertyPort(port);
}
PortDirection *
NetworkNameAdapter::direction(const Port *port) const
{
return network_->direction(port);
}
2019-11-11 16:28:42 +01:00
VertexId
2019-11-11 17:38:25 +01:00
NetworkNameAdapter::vertexId(const Pin *pin) const
2018-09-28 17:54:21 +02:00
{
2019-11-11 17:38:25 +01:00
return network_->vertexId(pin);
2018-09-28 17:54:21 +02:00
}
void
2019-11-11 17:38:25 +01:00
NetworkNameAdapter::setVertexId(Pin *pin,
VertexId id)
2018-09-28 17:54:21 +02:00
{
2019-11-11 17:38:25 +01:00
network_->setVertexId(pin, id);
2018-09-28 17:54:21 +02:00
}
bool
NetworkNameAdapter::isBundle(const Port *port) const
{
return network_->isBundle(port);
}
bool
NetworkNameAdapter::isBus(const Port *port) const
{
return network_->isBus(port);
}
const char *
NetworkNameAdapter::busName(const Port *port) const
{
return network_->busName(port);
}
Port *
NetworkNameAdapter::findBusBit(const Port *port,
int index) const
{
return network_->findMember(port, index);
}
int
NetworkNameAdapter::size(const Port *port) const
{
return network_->size(port);
}
int
NetworkNameAdapter::fromIndex(const Port *port) const
{
return network_->fromIndex(port);
}
int
NetworkNameAdapter::toIndex(const Port *port) const
{
return network_->toIndex(port);
}
2019-07-01 02:17:03 +02:00
bool
NetworkNameAdapter::hasMembers(const Port *port) const
{
return network_->hasMembers(port);
}
2018-09-28 17:54:21 +02:00
Port *
NetworkNameAdapter::findMember(const Port *port,
int index) const
{
return network_->findMember(port, index);
}
PortMemberIterator *
NetworkNameAdapter::memberIterator(const Port *port) const
{
return network_->memberIterator(port);
}
////////////////////////////////////////////////////////////////
Cell *
NetworkNameAdapter::cell(const Instance *instance) const
{
return network_->cell(instance);
}
Instance *
NetworkNameAdapter::parent(const Instance *instance) const
{
return network_->parent(instance);
}
bool
NetworkNameAdapter::isLeaf(const Instance *instance) const
{
return network_->isLeaf(instance);
}
Pin *
NetworkNameAdapter::findPin(const Instance *instance,
const Port *port) const
{
return network_->findPin(instance, port);
}
Pin *
NetworkNameAdapter::findPin(const Instance *instance,
const LibertyPort *port) const
{
return network_->findPin(instance, port);
}
InstanceChildIterator *
NetworkNameAdapter::childIterator(const Instance *instance) const
{
return network_->childIterator(instance);
}
InstancePinIterator *
NetworkNameAdapter::pinIterator(const Instance *instance) const
{
return network_->pinIterator(instance);
}
InstanceNetIterator *
NetworkNameAdapter::netIterator(const Instance *instance) const
{
return network_->netIterator(instance);
}
Port *
NetworkNameAdapter::port(const Pin *pin) const
{
return network_->port(pin);
}
Instance *
NetworkNameAdapter::instance(const Pin *pin) const
{
return network_->instance(pin);
}
Net *
NetworkNameAdapter::net(const Pin *pin) const
{
return network_->net(pin);
}
Term *
NetworkNameAdapter::term(const Pin *pin) const
{
return network_->term(pin);
}
PortDirection *
NetworkNameAdapter::direction(const Pin *pin) const
{
return network_->direction(pin);
}
Net *
NetworkNameAdapter::net(const Term *term) const
{
return network_->net(term);
}
Pin *
NetworkNameAdapter::pin(const Term *term) const
{
return network_->pin(term);
}
Instance *
NetworkNameAdapter::instance(const Net *net) const
{
return network_->instance(net);
}
NetPinIterator *
NetworkNameAdapter::pinIterator(const Net *net) const
{
return network_->pinIterator(net);
}
NetTermIterator *
NetworkNameAdapter::termIterator(const Net *net) const
{
return network_->termIterator(net);
}
bool
NetworkNameAdapter::isPower(const Net *net) const
{
return network_->isPower(net);
}
bool
NetworkNameAdapter::isGround(const Net *net) const
{
return network_->isGround(net);
}
ConstantPinIterator *
NetworkNameAdapter::constantPinIterator()
{
return network_->constantPinIterator();
}
char
NetworkNameAdapter::pathDivider() const
{
return network_->pathDivider();
}
void
NetworkNameAdapter::setPathDivider(char divider)
{
network_->setPathDivider(divider);
}
char
NetworkNameAdapter::pathEscape() const
{
return network_->pathEscape();
}
void
NetworkNameAdapter::setPathEscape(char escape)
{
network_->setPathEscape(escape);
}
bool
NetworkNameAdapter::isEditable() const
{
return network_->isEditable();
}
LibertyLibrary *
NetworkNameAdapter::makeLibertyLibrary(const char *name,
const char *filename)
{
return network_edit_->makeLibertyLibrary(name, filename);
}
Instance *
NetworkNameAdapter::makeInstance(LibertyCell *cell,
const char *name,
Instance *parent)
{
return network_edit_->makeInstance(cell, name, parent);
}
void
2019-01-20 18:44:24 +01:00
NetworkNameAdapter::makePins(Instance *inst)
2018-09-28 17:54:21 +02:00
{
2019-01-20 18:44:24 +01:00
network_edit_->makePins(inst);
2018-09-28 17:54:21 +02:00
}
void
NetworkNameAdapter::mergeInto(Net *net,
Net *into_net)
{
network_edit_->mergeInto(net, into_net);
}
Net *
NetworkNameAdapter::mergedInto(Net *net)
{
return network_edit_->mergedInto(net);
}
Net *
NetworkNameAdapter::makeNet(const char *name,
Instance *parent)
{
return network_edit_->makeNet(name, parent);
}
void
NetworkNameAdapter::replaceCell(Instance *inst,
2019-06-14 21:05:34 +02:00
Cell *to_cell)
2018-09-28 17:54:21 +02:00
{
2019-06-14 21:05:34 +02:00
network_edit_->replaceCell(inst, to_cell);
2018-09-28 17:54:21 +02:00
}
Pin *
NetworkNameAdapter::connect(Instance *inst,
Port *port,
Net *net)
{
return network_edit_->connect(inst, port, net);
}
2019-05-03 17:07:00 +02:00
Pin *
NetworkNameAdapter::connect(Instance *inst,
LibertyPort *port,
Net *net)
{
return network_edit_->connect(inst, port, net);
}
2018-09-28 17:54:21 +02:00
void
NetworkNameAdapter::disconnectPin(Pin *pin)
{
network_edit_->disconnectPin(pin);
}
void
NetworkNameAdapter::deleteNet(Net *net)
{
network_edit_->deleteNet(net);
}
void
NetworkNameAdapter::deletePin(Pin *pin)
{
network_edit_->deletePin(pin);
}
void
NetworkNameAdapter::deleteInstance(Instance *inst)
{
network_edit_->deleteInstance(inst);
}
////////////////////////////////////////////////////////////////
Network *
makeSdcNetwork(Network *network)
{
return new SdcNetwork(network);
}
SdcNetwork::SdcNetwork(Network *network) :
NetworkNameAdapter(network)
{
}
// Translate sta namespace to sdc namespace.
// Remove all escapes.
const char *
SdcNetwork::staToSdc(const char *sta_name) const
{
char escape = pathEscape();
char *sdc_name = makeTmpString(strlen(sta_name) + 1);
char *d = sdc_name;
for (const char *s = sta_name; *s; s++) {
char ch = s[0];
if (ch == escape) {
char next_ch = s[1];
// Escaped escape.
if (next_ch == escape) {
*d++ = ch;
*d++ = next_ch;
s++;
}
}
else
// Non escape.
*d++ = ch;
}
*d++ = '\0';
return sdc_name;
}
Port *
SdcNetwork::findPort(const Cell *cell,
const char *name) const
{
Port *port = network_->findPort(cell, name);
2019-03-13 01:25:53 +01:00
if (port == nullptr) {
2018-09-28 17:54:21 +02:00
// Look for matches after escaping brackets.
char *bus_name;
int index;
2019-08-14 06:34:35 +02:00
parseBusName(name, '[', ']', pathEscape(), bus_name, index);
if (bus_name) {
const char *escaped1 = escapeBrackets(name, this);
port = network_->findPort(cell, escaped1);
if (port == nullptr
&& bus_name[strlen(bus_name) - 1] == ']') {
// Try escaping base foo\[0\][1]
const char *escaped2 = stringPrintTmp("%s[%d]",
escapeBrackets(bus_name, this),
index);
port = network_->findPort(cell, escaped2);
}
2019-08-13 07:56:32 +02:00
stringDelete(bus_name);
}
2018-09-28 17:54:21 +02:00
}
return port;
}
void
SdcNetwork::findPortsMatching(const Cell *cell,
const PatternMatch *pattern,
PortSeq *ports) const
{
network_->findPortsMatching(cell, pattern, ports);
if (ports->empty()) {
// Look for matches after escaping brackets.
char *bus_name;
int index;
2019-08-14 06:34:35 +02:00
parseBusName(pattern->pattern(), '[', ']', pathEscape(), bus_name, index);
if (bus_name) {
const char *escaped1 = escapeBrackets(pattern->pattern(), this);
PatternMatch escaped_pattern1(escaped1, pattern);
network_->findPortsMatching(cell, &escaped_pattern1, ports);
if (ports->empty()
&& bus_name[strlen(bus_name) - 1] == ']') {
// Try escaping base foo\[0\][1]
const char *escaped2 = stringPrintTmp("%s[%d]",
escapeBrackets(bus_name, this),
index);
PatternMatch escaped_pattern2(escaped2, pattern);
network_->findPortsMatching(cell, &escaped_pattern2, ports);
}
2019-08-13 07:56:32 +02:00
stringDelete(bus_name);
}
2018-09-28 17:54:21 +02:00
}
}
const char *
SdcNetwork::name(const Port *port) const
{
return staToSdc(network_->name(port));
}
const char *
SdcNetwork::busName(const Port *port) const
{
return staToSdc(network_->busName(port));
}
const char *
SdcNetwork::name(const Instance *instance) const
{
return staToSdc(network_->name(instance));
}
const char *
SdcNetwork::pathName(const Instance *instance) const
{
return staToSdc(network_->pathName(instance));
}
const char *
SdcNetwork::pathName(const Pin *pin) const
{
return staToSdc(network_->pathName(pin));
}
const char *
SdcNetwork::portName(const Pin *pin) const
{
return staToSdc(network_->portName(pin));
}
const char *
SdcNetwork::name(const Net *net) const
{
return staToSdc(network_->name(net));
}
const char *
SdcNetwork::pathName(const Net *net) const
{
return staToSdc(network_->pathName(net));
}
2019-07-01 02:17:03 +02:00
////////////////////////////////////////////////////////////////
2018-09-28 17:54:21 +02:00
Instance *
SdcNetwork::findInstance(const char *path_name) const
{
2019-07-01 02:17:03 +02:00
const char *child_name;
Instance *parent;
parsePath(path_name, parent, child_name);
2019-03-13 01:25:53 +01:00
if (parent == nullptr)
2018-09-28 17:54:21 +02:00
parent = network_->topInstance();
2019-07-01 19:26:59 +02:00
Instance *child = findChild(parent, child_name);
if (child == nullptr)
child = findChild(parent, escapeDividers(child_name, this));
return child;
2018-09-28 17:54:21 +02:00
}
2019-07-01 02:17:03 +02:00
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;
});
}
2018-09-28 17:54:21 +02:00
Instance *
SdcNetwork::findChild(const Instance *parent,
const char *name) const
{
Instance *child = network_->findChild(parent, name);
2019-03-13 01:25:53 +01:00
if (child == nullptr) {
2018-09-28 17:54:21 +02:00
const char *escaped = escapeBrackets(name, this);
child = network_->findChild(parent, escaped);
}
return child;
}
2019-07-01 02:17:03 +02:00
////////////////////////////////////////////////////////////////
2018-09-28 17:54:21 +02:00
Net *
SdcNetwork::findNet(const char *path_name) const
{
2019-07-01 02:17:03 +02:00
const char *net_name;
Instance *inst;
parsePath(path_name, inst, net_name);
2019-03-13 01:25:53 +01:00
if (inst == nullptr)
2018-09-28 17:54:21 +02:00
inst = network_->topInstance();
return findNet(inst, net_name);
}
Net *
SdcNetwork::findNet(const Instance *instance,
const char *net_name) const
{
Net *net = network_->findNet(instance, net_name);
2019-03-13 01:25:53 +01:00
if (net == nullptr) {
2018-09-28 17:54:21 +02:00
const char *net_name_ = escapeBrackets(net_name, this);
net = network_->findNet(instance, net_name_);
}
return net;
}
2019-07-01 02:17:03 +02:00
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);
}
}
}
2018-09-28 17:54:21 +02:00
////////////////////////////////////////////////////////////////
Pin *
SdcNetwork::findPin(const char *path_name) const
{
2019-07-01 02:17:03 +02:00
const char *port_name;
Instance *inst;
parsePath(path_name, inst, port_name);
2019-03-13 01:25:53 +01:00
if (inst == nullptr)
2018-09-28 17:54:21 +02:00
inst = network_->topInstance();
return findPin(inst, port_name);
}
Pin *
SdcNetwork::findPin(const Instance *instance,
const char *port_name) const
{
Pin *pin = network_->findPin(instance, port_name);
2019-03-13 01:25:53 +01:00
if (pin == nullptr) {
2018-09-28 17:54:21 +02:00
// Look for match after escaping brackets.
char *bus_name;
int index;
2019-08-14 06:34:35 +02:00
parseBusName(port_name, '[', ']', pathEscape(), bus_name, index);
if (bus_name) {
const char *escaped1 = escapeBrackets(port_name, this);
pin = network_->findPin(instance, escaped1);
if (pin == nullptr
&& bus_name[strlen(bus_name) - 1] == ']') {
// Try escaping base foo\[0\][1]
const char *escaped2 = stringPrintTmp("%s[%d]",
escapeBrackets(bus_name, this),
index);
pin = network_->findPin(instance, escaped2);
}
2019-08-13 07:56:32 +02:00
stringDelete(bus_name);
}
2018-09-28 17:54:21 +02:00
}
return pin;
}
2019-07-01 02:17:03 +02:00
// 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;
}
2018-09-28 17:54:21 +02:00
Instance *
SdcNetwork::makeInstance(LibertyCell *cell,
const char *name,
Instance *parent)
{
const char *escaped_name = escapeDividers(name, this);
return network_edit_->makeInstance(cell, escaped_name, parent);
}
Net *
SdcNetwork::makeNet(const char *name,
Instance *parent)
{
const char *escaped_name = escapeDividers(name, this);
return network_edit_->makeNet(escaped_name, parent);
}
////////////////////////////////////////////////////////////////
2019-07-01 02:17:03 +02:00
// 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;
2019-07-01 19:26:59 +02:00
path_tail = path;
2019-07-01 02:17:03 +02:00
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.
2019-07-01 19:26:59 +02:00
p = inst_path;
path_tail = s + 1;
2019-07-01 02:17:03 +02:00
}
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';
2019-07-01 19:26:59 +02:00
stringDelete(inst_path);
2019-07-01 02:17:03 +02:00
}
// 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;
}
////////////////////////////////////////////////////////////////
2018-09-28 17:54:21 +02:00
static const char *
escapeDividers(const char *token,
const Network *network)
{
return escapeChars(token, network->pathDivider(), '\0',
network->pathEscape());
}
static const char *
escapeBrackets(const char *token,
const Network *network)
{
return escapeChars(token, '[', ']', network->pathEscape());
}
} // namespace