// OpenSTA, Static Timing Analyzer // Copyright (c) 2024, Parallax Software, Inc. // // 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 . #include "Network.hh" #include "StringUtil.hh" #include "PatternMatch.hh" #include "Liberty.hh" #include "PortDirection.hh" #include "Corner.hh" #include "ParseBus.hh" namespace sta { Network::Network() : default_liberty_(nullptr), divider_('/'), escape_('\\') { } Network::~Network() { net_drvr_pin_map_.deleteContents(); } void Network::clear() { default_liberty_ = nullptr; clearNetDrvrPinMap(); } bool Network::isLinked() const { return topInstance() != nullptr; } LibertyLibrary * Network::libertyLibrary(const Cell *cell) const { return libertyCell(cell)->libertyLibrary(); } PortSeq Network::findPortsMatching(const Cell *cell, const PatternMatch *pattern) const { PortSeq matches; bool is_bus, is_range, subscript_wild; string bus_name; int from, to; parseBusName(pattern->pattern(), '[', ']', '\\', is_bus, is_range, bus_name, from, to, subscript_wild); if (is_bus) { PatternMatch bus_pattern(bus_name.c_str(), pattern); CellPortIterator *port_iter = portIterator(cell); while (port_iter->hasNext()) { Port *port = port_iter->next(); if (isBus(port) && bus_pattern.match(name(port))) { if (is_range) { // bus[8:0] if (from > to) std::swap(from, to); for (int bit = from; bit <= to; bit++) { Port *port_bit = findBusBit(port, bit); matches.push_back(port_bit); } } else { if (subscript_wild) { PortMemberIterator *member_iter = memberIterator(port); while (member_iter->hasNext()) { Port *port_bit = member_iter->next(); matches.push_back(port_bit); } delete member_iter; } else { // bus[0] Port *port_bit = findBusBit(port, from); if (port_bit != nullptr) matches.push_back(port_bit); } } } } delete port_iter; } else { CellPortIterator *port_iter = portIterator(cell); while (port_iter->hasNext()) { Port *port = port_iter->next(); if (pattern->match(name(port))) matches.push_back(port); } delete port_iter; } return matches; } LibertyLibrary * Network::libertyLibrary(const Instance *instance) const { return libertyCell(instance)->libertyLibrary(); } void Network::readLibertyAfter(LibertyLibrary *) { } LibertyCell * Network::findLibertyCell(const char *name) const { LibertyLibraryIterator *iter = libertyLibraryIterator(); while (iter->hasNext()) { LibertyLibrary *lib = iter->next(); LibertyCell *cell = lib->findLibertyCell(name); if (cell) { delete iter; return cell; } } delete iter; return nullptr; } LibertyLibrary * Network::defaultLibertyLibrary() const { return default_liberty_; } void Network::setDefaultLibertyLibrary(LibertyLibrary *library) { default_liberty_ = library; } void Network::checkLibertyCorners() { if (corners_->count() > 1) { LibertyLibraryIterator *lib_iter = libertyLibraryIterator(); LibertyCellSet cells; while (lib_iter->hasNext()) { LibertyLibrary *lib = lib_iter->next(); LibertyCellIterator cell_iter(lib); while (cell_iter.hasNext()) { LibertyCell *cell = cell_iter.next(); LibertyCell *link_cell = findLibertyCell(cell->name()); cells.insert(link_cell); } } delete lib_iter; for (LibertyCell *cell : cells) LibertyLibrary::checkCorners(cell, corners_, report_); } } void Network::checkNetworkLibertyCorners() { if (corners_->count() > 1) { LibertyCellSet network_cells; LeafInstanceIterator *leaf_iter = network_->leafInstanceIterator(); while (leaf_iter->hasNext()) { const Instance *inst = leaf_iter->next(); LibertyCell *cell = libertyCell(inst); if (cell) network_cells.insert(cell); } delete leaf_iter; for (LibertyCell *cell : network_cells) LibertyLibrary::checkCorners(cell, corners_, report_); } } // Only used by Sta::setMinLibrary so linear search is acceptable. LibertyLibrary * Network::findLibertyFilename(const char *filename) { LibertyLibraryIterator *lib_iter = libertyLibraryIterator(); while (lib_iter->hasNext()) { LibertyLibrary *lib = lib_iter->next(); if (stringEq(lib->filename(), filename)) { delete lib_iter; return lib; } } delete lib_iter; return nullptr; } LibertyCell * Network::libertyCell(const Instance *instance) const { return libertyCell(cell(instance)); } LibertyPort * Network::libertyPort(const Pin *pin) const { Port *port = this->port(pin); if (port) return libertyPort(port); else return nullptr; } bool Network::busIndexInRange(const Port *port, int index) { int from_index = fromIndex(port); int to_index = toIndex(port); return (from_index <= to_index && index <= to_index && index >= from_index) || (from_index > to_index && index >= to_index && index <= from_index); } bool Network::hasMembers(const Port *port) const { return isBus(port) || isBundle(port); } const char * Network::pathName(const Instance *instance) const { InstanceSeq inst_path; path(instance, inst_path); size_t name_length = 0; InstanceSeq::Iterator path_iter1(inst_path); while (path_iter1.hasNext()) { const Instance *inst = path_iter1.next(); name_length += strlen(name(inst)) + 1; } char *path_name = makeTmpString(name_length + 1); char *path_ptr = path_name; // Top instance has null string name, so terminate the string here. *path_name = '\0'; while (inst_path.size()) { const Instance *inst = inst_path.back(); const char *inst_name = name(inst); strcpy(path_ptr, inst_name); path_ptr += strlen(inst_name); inst_path.pop_back(); if (inst_path.size()) *path_ptr++ = pathDivider(); *path_ptr = '\0'; } return path_name; } bool Network::pathNameLess(const Instance *inst1, const Instance *inst2) const { return pathNameCmp(inst1, inst2) < 0; } int Network::pathNameCmp(const Instance *inst1, const Instance *inst2) const { if (inst1 == nullptr && inst2) return -1; else if (inst1 && inst2 == nullptr) return 1; else if (inst1 == inst2) return 0; else { InstanceSeq path1; InstanceSeq path2; path(inst1, path1); path(inst2, path2); while (!path1.empty() && !path2.empty()) { const Instance *inst1 = path1.back(); const Instance *inst2 = path2.back(); int cmp = strcmp(name(inst1), name(inst2)); if (cmp != 0) return cmp; path1.pop_back(); path2.pop_back(); } if (path1.empty() && !path2.empty()) return -1; else if (path1.empty() && path2.empty()) return 0; else return 1; } } void Network::path(const Instance *inst, // Return value. InstanceSeq &path) const { while (!isTopInstance(inst)) { path.push_back(inst); inst = parent(inst); } } bool Network::isTopInstance(const Instance *inst) const { return inst == topInstance(); } bool Network::isInside(const Instance *inst, const Instance *hier_inst) const { while (inst) { if (inst == hier_inst) return true; inst = parent(inst); } return false; } bool Network::isHierarchical(const Instance *instance) const { return !isLeaf(instance); } //////////////////////////////////////////////////////////////// const char * Network::name(const Pin *pin) const { return pathName(pin); } const char * Network::portName(const Pin *pin) const { return name(port(pin)); } const char * Network::pathName(const Pin *pin) const { const Instance *inst = instance(pin); if (inst && inst != topInstance()) { const char *inst_name = pathName(inst); size_t inst_name_length = strlen(inst_name); const char *port_name = portName(pin); size_t port_name_length = strlen(port_name); size_t path_name_length = inst_name_length + port_name_length + 2; char *path_name = makeTmpString(path_name_length); char *path_ptr = path_name; strcpy(path_ptr, inst_name); path_ptr += inst_name_length; *path_ptr++ = pathDivider(); strcpy(path_ptr, port_name); return path_name; } else return portName(pin); } bool Network::pathNameLess(const Pin *pin1, const Pin *pin2) const { return pathNameCmp(pin1, pin2) < 0; } int Network::pathNameCmp(const Pin *pin1, const Pin *pin2) const { int inst_cmp = pathNameCmp(instance(pin1), instance(pin2)); if (inst_cmp == 0) return strcmp(portName(pin1), portName(pin2)); else return inst_cmp; } bool Network::isInside(const Net *net, const Instance *hier_inst) const { return isInside(instance(net), hier_inst); } bool Network::isLeaf(const Pin *pin) const { return isLeaf(instance(pin)); } bool Network::isHierarchical(const Pin *pin) const { return (!isLeaf(pin) && !isTopLevelPort(pin)); } bool Network::isTopLevelPort(const Pin *pin) const { return (parent(instance(pin)) == nullptr); } bool Network::isInside(const Pin *pin, const Pin *hier_pin) const { return isInside(pin, instance(hier_pin)); } bool Network::isInside(const Pin *pin, const Instance *hier_inst) const { return isInside(instance(pin), hier_inst); } bool Network::pinLess(const Pin *pin1, const Pin *pin2) const { return pathNameLess(pin1, pin2); } //////////////////////////////////////////////////////////////// const char * Network::pathName(const Net *net) const { const Instance *inst = instance(net); if (inst && inst != topInstance()) { const char *inst_name = pathName(inst); size_t inst_name_length = strlen(inst_name); const char *net_name = name(net); size_t net_name_length = strlen(net_name); size_t path_name_length = inst_name_length + net_name_length + 2; char *path_name = makeTmpString(path_name_length); char *path_ptr = path_name; strcpy(path_ptr, inst_name); path_ptr += inst_name_length; *path_ptr++ = pathDivider(); strcpy(path_ptr, net_name); return path_name; } else return name(net); } bool Network::pathNameLess(const Net *net1, const Net *net2) const { return pathNameCmp(net1, net2) < 0; } int Network::pathNameCmp(const Net *net1, const Net *net2) const { int inst_cmp = pathNameCmp(instance(net1), instance(net2)); if (inst_cmp == 0) return strcmp(name(net1), name(net2)); else return inst_cmp; } Net * Network::highestNetAbove(Net *net) const { Net *highest_net = net; // Search up from net terminals. NetTermIterator *term_iter = termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = pin(term); if (above_pin) { Net *above_net = this->net(above_pin); if (above_net) { highest_net = highestNetAbove(above_net); break; } } } delete term_iter; return highest_net; } const Net * Network::highestConnectedNet(Net *net) const { NetSet nets(this); connectedNets(net, &nets); const Net *highest_net = net; int highest_level = hierarchyLevel(net); NetSet::Iterator net_iter(nets); while (net_iter.hasNext()) { const Net *net1 = net_iter.next(); int level = hierarchyLevel(net1); if (level < highest_level || (level == highest_level && stringLess(pathName(net1), pathName(highest_net)))) { highest_net = net1; highest_level = level; } } return highest_net; } void Network::connectedNets(Net *net, NetSet *nets) const { if (!nets->hasKey(net)) { nets->insert(net); // Search up from net terminals. NetTermIterator *term_iter = termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = pin(term); if (above_pin) { Net *above_net = this->net(above_pin); if (above_net) connectedNets(above_net, nets); } } delete term_iter; // Search down from net pins. NetPinIterator *pin_iter = pinIterator(net); while (pin_iter->hasNext()) { const Pin *pin1 = pin_iter->next(); Term *below_term = term(pin1); if (below_term) { Net *below_net = this->net(below_term); if (below_net) connectedNets(below_net, nets); } } delete pin_iter; } } void Network::connectedNets(const Pin *pin, NetSet *nets) const { Net *net = this->net(pin); if (net) connectedNets(net, nets); else { Term *term = this->term(pin); if (term) { Net *below_net = this->net(term); if (below_net) connectedNets(below_net, nets); } } } int Network::hierarchyLevel(const Net *net) const { NetTermIterator *term_iter = network_->termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *pin = network_->pin(term); if (pin) { Net *above_net = network_->net(pin); if (above_net) { delete term_iter; return hierarchyLevel(above_net) + 1; } } } delete term_iter; return 0; } bool Network::isDriver(const Pin *pin) const { PortDirection *dir = direction(pin); const Instance *inst = instance(pin); return (isLeaf(inst) && dir->isAnyOutput()) // isTopLevelPort(pin) || (isTopInstance(inst) && dir->isAnyInput()); } bool Network::isLoad(const Pin *pin) const { PortDirection *dir = direction(pin); const Instance *inst = instance(pin); return (isLeaf(inst) && dir->isAnyInput()) // isTopLevelPort(pin) || (isTopInstance(inst) && dir->isAnyOutput()) // Black box unknown ports are treated as loads. || dir->isUnknown(); } bool Network::isRegClkPin(const Pin *pin) const { const LibertyPort *port = libertyPort(pin); return port && port->isRegClk(); } bool Network::isCheckClk(const Pin *pin) const { const LibertyPort *port = libertyPort(pin); return port && port->isCheckClk(); } bool Network::isLatchData(const Pin *pin) const { LibertyPort *port = libertyPort(pin); if (port) return port->libertyCell()->isLatchData(port); else return false; } //////////////////////////////////////////////////////////////// const char * Network::name(const Term *term) const { return name(pin(term)); } const char * Network::pathName(const Term *term) const { return pathName(pin(term)); } const char * Network::portName(const Term *term) const { return portName(pin(term)); } //////////////////////////////////////////////////////////////// const char * Network::cellName(const Instance *inst) const { return name(cell(inst)); } Instance * Network::findInstance(const char *path_name) const { return findInstanceRelative(topInstance(), path_name); } Instance * Network::findInstanceRelative(const Instance *inst, const char *path_name) const { char *first, *tail; pathNameFirst(path_name, first, tail); if (first) { Instance *inst1 = findChild(inst, first); stringDelete(first); while (inst1 && tail) { char *next_tail; pathNameFirst(tail, first, next_tail); if (first) { inst1 = findChild(inst1, first); stringDelete(first); } else inst1 = findChild(inst1, tail); stringDelete(tail); tail = next_tail; } stringDelete(tail); return inst1; } else return findChild(inst, path_name); } InstanceSeq Network::findInstancesMatching(const Instance *context, const PatternMatch *pattern) const { InstanceSeq matches; if (pattern->hasWildcards()) { size_t context_name_length = 0; if (context != topInstance()) // Add one for the trailing divider. context_name_length = strlen(pathName(context)) + 1; findInstancesMatching1(context, context_name_length, pattern, matches); } else { Instance *inst = findInstanceRelative(context, pattern->pattern()); if (inst) matches.push_back(inst); } return matches; } void Network::findInstancesMatching1(const Instance *context, size_t context_name_length, const PatternMatch *pattern, InstanceSeq &matches) const { InstanceChildIterator *child_iter = childIterator(context); while (child_iter->hasNext()) { Instance *child = child_iter->next(); const char *child_name = pathName(child); // Remove context prefix from the name. const char *child_context_name = &child_name[context_name_length]; if (pattern->match(child_context_name)) matches.push_back(child); if (!isLeaf(child)) findInstancesMatching1(child, context_name_length, pattern, matches); } delete child_iter; } InstanceSeq Network::findInstancesHierMatching(const Instance *instance, const PatternMatch *pattern) const { InstanceSeq matches; findInstancesHierMatching1(instance, pattern, matches); return matches; } void Network::findInstancesHierMatching1(const Instance *instance, const PatternMatch *pattern, InstanceSeq &matches) const { InstanceChildIterator *child_iter = childIterator(instance); while (child_iter->hasNext()) { Instance *child = child_iter->next(); if (pattern->match(name(child))) matches.push_back(child); if (!isLeaf(child)) findInstancesHierMatching1(child, pattern, matches); } delete child_iter; } void Network::findChildrenMatching(const Instance *parent, const PatternMatch *pattern, InstanceSeq &matches) const { if (pattern->hasWildcards()) { InstanceChildIterator *child_iter = childIterator(parent); while (child_iter->hasNext()) { Instance *child = child_iter->next(); if (pattern->match(name(child))) matches.push_back(child); } delete child_iter; } else { Instance *child = findChild(parent, pattern->pattern()); if (child) matches.push_back(child); } } Pin * Network::findPin(const char *path_name) const { return findPinRelative(topInstance(), path_name); } Pin * Network::findPinRelative(const Instance *inst, const char *path_name) const { char *inst_path, *port_name; pathNameLast(path_name, inst_path, port_name); if (inst_path) { Instance *pin_inst = findInstanceRelative(inst, inst_path); if (pin_inst) { Pin *pin = findPin(pin_inst, port_name); stringDelete(inst_path); stringDelete(port_name); return pin; } stringDelete(inst_path); stringDelete(port_name); return nullptr; } else // Top level pin. return findPin(inst, path_name); } Pin * Network::findPinLinear(const Instance *instance, const char *port_name) const { InstancePinIterator *pin_iter = pinIterator(instance); while (pin_iter->hasNext()) { Pin *pin = pin_iter->next(); if (stringEq(port_name, portName(pin))) { delete pin_iter; return pin; } } delete pin_iter; return nullptr; } Pin * Network::findPin(const Instance *instance, const Port *port) const { return findPin(instance, name(port)); } Pin * Network::findPin(const Instance *instance, const LibertyPort *port) const { return findPin(instance, port->name()); } Net * Network::findNet(const char *path_name) const { return findNetRelative(topInstance(), path_name); } Net * Network::findNetRelative(const Instance *inst, const char *path_name) const { char *inst_path, *net_name; pathNameLast(path_name, inst_path, net_name); if (inst_path) { Instance *net_inst = findInstanceRelative(inst, inst_path); if (net_inst) { Net *net = findNet(net_inst, net_name); stringDelete(inst_path); stringDelete(net_name); return net; } stringDelete(inst_path); stringDelete(net_name); return nullptr; } else // Top level net. return findNet(inst, path_name); } Net * Network::findNetLinear(const Instance *instance, const char *net_name) const { InstanceNetIterator *net_iter = netIterator(instance); while (net_iter->hasNext()) { Net *net = net_iter->next(); if (stringEq(name(net), net_name)) { delete net_iter; return net; } } delete net_iter; return nullptr; } NetSeq Network::findNetsMatching(const Instance *context, const PatternMatch *pattern) const { NetSeq matches; findNetsMatching(context, pattern, matches); return matches; } void Network::findNetsMatching(const Instance *context, const PatternMatch *pattern, NetSeq &matches) const { if (pattern->hasWildcards()) { char *inst_path, *net_name; pathNameLast(pattern->pattern(), inst_path, net_name); if (inst_path) { PatternMatch inst_pattern(inst_path, pattern); PatternMatch net_pattern(net_name, pattern); InstanceSeq insts = findInstancesMatching(context, &inst_pattern); InstanceSeq::Iterator inst_iter(insts); while (inst_iter.hasNext()) { const Instance *inst = inst_iter.next(); findNetsMatching(inst, &net_pattern, matches); } stringDelete(inst_path); stringDelete(net_name); } else // Top level net. findInstNetsMatching(context, pattern, matches); } else { Net *net = findNet(pattern->pattern()); if (net) matches.push_back(net); } } NetSeq Network::findNetsHierMatching(const Instance *instance, const PatternMatch *pattern) const { NetSeq matches; findNetsHierMatching(instance, pattern, matches); return matches; } void Network::findNetsHierMatching(const Instance *instance, const PatternMatch *pattern, NetSeq &matches) const { findInstNetsMatching(instance, pattern, matches); InstanceChildIterator *child_iter = childIterator(instance); while (child_iter->hasNext()) { Instance *child = child_iter->next(); findNetsHierMatching(child, pattern, matches); } delete child_iter; } NetSeq Network::findNetsMatchingLinear(const Instance *instance, const PatternMatch *pattern) const { NetSeq matches; InstanceNetIterator *net_iter = netIterator(instance); while (net_iter->hasNext()) { Net *net = net_iter->next(); if (pattern->match(name(net))) matches.push_back(net); } delete net_iter; return matches; } PinSeq Network::findPinsMatching(const Instance *instance, const PatternMatch *pattern) const { PinSeq matches; if (pattern->hasWildcards()) { char *inst_path, *port_name; pathNameLast(pattern->pattern(), inst_path, port_name); if (inst_path) { PatternMatch inst_pattern(inst_path, pattern); PatternMatch port_pattern(port_name, pattern); InstanceSeq insts = findInstancesMatching(instance, &inst_pattern); InstanceSeq::Iterator inst_iter(insts); while (inst_iter.hasNext()) { const Instance *inst = inst_iter.next(); findInstPinsMatching(inst, &port_pattern, matches); } stringDelete(inst_path); stringDelete(port_name); } else // Top level pin. findInstPinsMatching(instance, pattern, matches); } else { Pin *pin = findPin(pattern->pattern()); if (pin) matches.push_back(pin); } return matches; } PinSeq Network::findPinsHierMatching(const Instance *instance, const PatternMatch *pattern) const { PinSeq matches; findPinsHierMatching(instance, pattern, matches); return matches; } void Network::findPinsHierMatching(const Instance *instance, const PatternMatch *pattern, // Return value. PinSeq &matches) const { InstanceChildIterator *child_iter = childIterator(instance); while (child_iter->hasNext()) { Instance *child = child_iter->next(); findInstPinsHierMatching(child, pattern, matches); findPinsHierMatching(child, pattern, matches); } delete child_iter; } void Network::findInstPinsHierMatching(const Instance *instance, const PatternMatch *pattern, // Return value. PinSeq &matches) const { string inst_name = name(instance); InstancePinIterator *pin_iter = pinIterator(instance); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); const char *port_name = name(port(pin)); string pin_name = inst_name + divider_ + port_name; if (pattern->match(pin_name.c_str())) matches.push_back(pin); } delete pin_iter; } void Network::findInstPinsMatching(const Instance *instance, const PatternMatch *pattern, PinSeq &matches) const { if (pattern->hasWildcards()) { InstancePinIterator *pin_iter = pinIterator(instance); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (pattern->match(name(pin))) matches.push_back(pin); } delete pin_iter; } else { Pin *pin = findPin(instance, pattern->pattern()); if (pin) matches.push_back(pin); } } void Network::location(const Pin *, // Return values. double &x, double &y, bool &exists) const { x = y = 0.0; exists = false; } int Network::instanceCount(Instance *inst) { int count = 1; InstanceChildIterator *child_iter = childIterator(inst); while (child_iter->hasNext()) { Instance *child = child_iter->next(); count += instanceCount(child); } delete child_iter; return count; } int Network::instanceCount() { return instanceCount(topInstance()); } int Network::pinCount(Instance *inst) { int count = 0; InstancePinIterator *pin_iter = pinIterator(inst); while (pin_iter->hasNext()) { pin_iter->next(); count++; } delete pin_iter; InstanceChildIterator *child_iter = childIterator(inst); while (child_iter->hasNext()) { Instance *child = child_iter->next(); count += pinCount(child); } delete child_iter; return count; } int Network::pinCount() { return pinCount(topInstance()); } int Network::netCount(Instance *inst) { int count = 0; InstanceNetIterator *net_iter = netIterator(inst); while (net_iter->hasNext()) { net_iter->next(); count++; } delete net_iter; InstanceChildIterator *child_iter = childIterator(inst); while (child_iter->hasNext()) { Instance *child = child_iter->next(); count += netCount(child); } delete child_iter; return count; } int Network::netCount() { return netCount(topInstance()); } int Network::leafInstanceCount() { int count = 0; LeafInstanceIterator *leaf_iter = leafInstanceIterator(); while (leaf_iter->hasNext()) { leaf_iter->next(); count++; } delete leaf_iter; return count; } int Network::leafPinCount() { int count = 0; LeafInstanceIterator *leaf_iter = leafInstanceIterator(); while (leaf_iter->hasNext()) { Instance *leaf = leaf_iter->next(); InstancePinIterator *pin_iter = pinIterator(leaf); while (pin_iter->hasNext()) { pin_iter->next(); count++; } delete pin_iter; } delete leaf_iter; return count; } InstanceSeq Network::leafInstances() { InstanceSeq insts; LeafInstanceIterator *iter = leafInstanceIterator(); while (iter->hasNext()) { const Instance *inst = iter->next(); insts.push_back(inst); } delete iter; return insts; } void Network::setPathDivider(char divider) { divider_ = divider; } void Network::setPathEscape(char escape) { escape_ = escape; } //////////////////////////////////////////////////////////////// typedef Vector InstanceChildIteratorSeq; class LeafInstanceIterator1 : public LeafInstanceIterator { public: LeafInstanceIterator1(const Instance *inst, const Network *network); bool hasNext() { return next_; } Instance *next(); private: void nextInst(); const Network *network_; InstanceChildIteratorSeq pending_child_iters_; InstanceChildIterator *child_iter_; Instance *next_; }; LeafInstanceIterator1::LeafInstanceIterator1(const Instance *inst, const Network *network) : network_(network), child_iter_(network->childIterator(inst)), next_(nullptr) { pending_child_iters_.reserve(8); nextInst(); } Instance * LeafInstanceIterator1::next() { Instance *next = next_; nextInst(); return next; } void LeafInstanceIterator1::nextInst() { next_ = nullptr; while (child_iter_) { while (child_iter_->hasNext()) { next_ = child_iter_->next(); if (network_->isLeaf(next_)) return; else { pending_child_iters_.push_back(child_iter_); child_iter_ = network_->childIterator(next_); next_ = nullptr; } } delete child_iter_; if (pending_child_iters_.empty()) child_iter_ = nullptr; else { child_iter_ = pending_child_iters_.back(); pending_child_iters_.pop_back(); } } } LeafInstanceIterator * Network::leafInstanceIterator() const { return new LeafInstanceIterator1(topInstance(), this); } LeafInstanceIterator * Network::leafInstanceIterator(const Instance *hier_inst) const { return new LeafInstanceIterator1(hier_inst, this); } //////////////////////////////////////////////////////////////// void Network::visitConnectedPins(const Pin *pin, PinVisitor &visitor) const { NetSet visited_nets(network_); Net *pin_net = net(pin); Term *pin_term = term(pin); if (pin_net) visitConnectedPins(pin_net, visitor, visited_nets); else if (pin_term == nullptr) // Unconnected or internal pin. visitor(pin); // Search down from pin terminal. if (pin_term) { Net *term_net = net(pin_term); if (term_net) visitConnectedPins(term_net, visitor, visited_nets); } } void Network::visitConnectedPins(const Net *net, PinVisitor &visitor) const { NetSet visited_nets(this); visitConnectedPins(net, visitor, visited_nets); } void Network::visitConnectedPins(const Net *net, PinVisitor &visitor, NetSet &visited_nets) const { if (!visited_nets.hasKey(net)) { visited_nets.insert(net); // Search up from net terminals. NetTermIterator *term_iter = termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = pin(term); if (above_pin) { Net *above_net = this->net(above_pin); if (above_net) visitConnectedPins(above_net, visitor, visited_nets); else visitor(above_pin); } } delete term_iter; // Search down from net pins. NetPinIterator *pin_iter = pinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); visitor(pin); Term *below_term = term(pin); if (below_term) { Net *below_net = this->net(below_term); if (below_net) visitConnectedPins(below_net, visitor, visited_nets); } } delete pin_iter; } } //////////////////////////////////////////////////////////////// class ConnectedPinIterator1 : public ConnectedPinIterator { public: explicit ConnectedPinIterator1(PinSet *pins); virtual ~ConnectedPinIterator1(); virtual bool hasNext(); virtual const Pin *next(); protected: PinSet::Iterator pin_iter_; }; ConnectedPinIterator1::ConnectedPinIterator1(PinSet *pins) : pin_iter_(pins) { } ConnectedPinIterator1::~ConnectedPinIterator1() { delete pin_iter_.container(); } bool ConnectedPinIterator1::hasNext() { return pin_iter_.hasNext(); } const Pin * ConnectedPinIterator1::next() { return pin_iter_.next(); } class FindConnectedPins : public PinVisitor { public: explicit FindConnectedPins(PinSet *pins); virtual void operator()(const Pin *pin); protected: PinSet *pins_; }; FindConnectedPins::FindConnectedPins(PinSet *pins) : PinVisitor(), pins_(pins) { } void FindConnectedPins::operator()(const Pin *pin) { pins_->insert(pin); } NetConnectedPinIterator * Network::connectedPinIterator(const Net *net) const { PinSet *pins = new PinSet(this); FindConnectedPins visitor(pins); visitConnectedPins(net, visitor); return new ConnectedPinIterator1(pins); } PinConnectedPinIterator * Network::connectedPinIterator(const Pin *pin) const { PinSet *pins = new PinSet(this); pins->insert(const_cast(pin)); FindConnectedPins visitor(pins); Net *pin_net = net(pin); if (pin_net) visitConnectedPins(pin_net, visitor); // Search down from pin terminal. Term *pin_term = term(pin); if (pin_term) { Net *term_net = net(pin_term); if (term_net) visitConnectedPins(term_net, visitor); } return new ConnectedPinIterator1(pins); } //////////////////////////////////////////////////////////////// bool Network::isConnected(const Net *net, const Pin *pin) const { if (this->net(pin) == net) return true; else { NetSet nets(this); return isConnected(net, pin, nets); } } bool Network::isConnected(const Net *net, const Pin *pin, NetSet &nets) const { if (!nets.hasKey(net)) { nets.insert(net); // Search up from net terminals. NetTermIterator *term_iter = termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = this->pin(term); if (above_pin) { if (above_pin == pin) { delete term_iter; return true; } else { Net *above_net = this->net(above_pin); if (above_net && isConnected(above_net, pin, nets)) { delete term_iter; return true; } } } } delete term_iter; // Search down from net pins. NetPinIterator *pin_iter = pinIterator(net); while (pin_iter->hasNext()) { const Pin *pin1 = pin_iter->next(); if (pin1 == pin) { delete pin_iter; return true; } else { Term *below_term = term(pin1); if (below_term) { Net *below_net = this->net(below_term); if (below_net && isConnected(below_net, pin, nets)) { delete pin_iter; return true; } } } } delete pin_iter; } return false; } bool Network::isConnected(const Net *net1, const Net *net2) const { NetSet nets(this); return isConnected(net1, net2, nets); } bool Network::isConnected(const Net *net1, const Net *net2, NetSet &nets) const { if (net1 == net2) return true; else if (!nets.hasKey(net1)) { nets.insert(net1); // Search up from net terminals. NetTermIterator *term_iter = termIterator(net1); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = pin(term); if (above_pin) { Net *above_net = net(above_pin); if (above_net && isConnected(above_net, net2, nets)) { delete term_iter; return true; } } } delete term_iter; // Search down from net pins. NetPinIterator *pin_iter = pinIterator(net1); while (pin_iter->hasNext()) { const Pin *pin1 = pin_iter->next(); Term *below_term = term(pin1); if (below_term) { Net *below_net = net(below_term); if (below_net && isConnected(below_net, net2, nets)) { delete pin_iter; return true; } } } delete pin_iter; } return false; } //////////////////////////////////////////////////////////////// class FindDrvrPins : public PinVisitor { public: explicit FindDrvrPins(PinSet *pins, const Network *network); virtual void operator()(const Pin *pin); protected: PinSet *pins_; const Network *network_; }; FindDrvrPins::FindDrvrPins(PinSet *pins, const Network *network) : PinVisitor(), pins_(pins), network_(network) { } void FindDrvrPins::operator()(const Pin *pin) { if (network_->isDriver(pin)) pins_->insert(pin); } PinSet * Network::drivers(const Pin *pin) { const Net *net = this->net(pin); if (net) return drivers(net); else return nullptr; } void Network::clearNetDrvrPinMap() { net_drvr_pin_map_.deleteContentsClear(); } PinSet * Network::drivers(const Net *net) { PinSet *drvrs = net_drvr_pin_map_.findKey(net); if (drvrs == nullptr) { drvrs = new PinSet(this); FindDrvrPins visitor(drvrs, this); visitConnectedPins(net, visitor); net_drvr_pin_map_[net] = drvrs; } return drvrs; } //////////////////////////////////////////////////////////////// void Network::pathNameFirst(const char *path_name, char *&first, char *&tail) const { char escape = pathEscape(); char divider = pathDivider(); const char *d = strchr(path_name, divider); // Skip escaped dividers. while (d != nullptr && d > path_name && d[-1] == escape) d = strchr(d + 1, divider); if (d) { first = new char[d - path_name + 1]; strncpy(first, path_name, d - path_name); first[d - path_name] = '\0'; tail = new char[strlen(d)]; // Chop off the leading divider. strcpy(tail, d + 1); } else { // No divider in path_name. first = nullptr; tail = nullptr; } } void Network::pathNameLast(const char *path_name, char *&head, char *&last) const { char escape = pathEscape(); char divider = pathDivider(); const char *d = strrchr(path_name, divider); // Search for a non-escaped divider. if (d) { while (d > path_name && (d[0] != divider || (d[0] == divider && d > &path_name[1] && d[-1] == escape))) d--; } if (d && d != path_name) { head = new char[d - path_name + 1]; strncpy(head, path_name, d - path_name); head[d - path_name] = '\0'; last = new char[strlen(d)]; // Chop off the last divider. strcpy(last, d + 1); } else { // No divider in path_name. head = nullptr; last = nullptr; } } //////////////////////////////////////////////////////////////// NetworkEdit::NetworkEdit() : Network() { } void NetworkEdit::connectPin(Pin *pin, Net *net) { connect(instance(pin), port(pin), net); } //////////////////////////////////////////////////////////////// NetworkConstantPinIterator:: NetworkConstantPinIterator(const Network *network, NetSet &zero_nets, NetSet &one_nets) : ConstantPinIterator(), network_(network), constant_pins_{PinSet(network), PinSet(network)} { findConstantPins(zero_nets, constant_pins_[0]); findConstantPins(one_nets, constant_pins_[1]); value_ = LogicValue::zero; pin_iter_ = new PinSet::Iterator(constant_pins_[0]); } NetworkConstantPinIterator::~NetworkConstantPinIterator() { delete pin_iter_; } void NetworkConstantPinIterator::findConstantPins(NetSet &nets, PinSet &pins) { NetSet::Iterator net_iter(nets); while (net_iter.hasNext()) { const Net *net = net_iter.next(); NetConnectedPinIterator *pin_iter = network_->connectedPinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); pins.insert(pin); } delete pin_iter; } } bool NetworkConstantPinIterator::hasNext() { if (pin_iter_->hasNext()) return true; else if (value_ == LogicValue::zero) { delete pin_iter_; value_ = LogicValue::one; pin_iter_ = new PinSet::Iterator(constant_pins_[1]); return pin_iter_->hasNext(); } else return false; } void NetworkConstantPinIterator::next(const Pin *&pin, LogicValue &value) { pin = pin_iter_->next(); value = value_; } //////////////////////////////////////////////////////////////// FindNetDrvrLoads::FindNetDrvrLoads(const Pin *drvr_pin, PinSet &visited_drvrs, PinSeq &loads, PinSeq &drvrs, const Network *network) : drvr_pin_(drvr_pin), visited_drvrs_(visited_drvrs), loads_(loads), drvrs_(drvrs), network_(network) { } void FindNetDrvrLoads::operator()(const Pin *pin) { if (network_->isLoad(pin)) loads_.push_back(pin); if (network_->isDriver(pin)) { drvrs_.push_back(pin); if (pin != drvr_pin_) visited_drvrs_.insert(pin); } } //////////////////////////////////////////////////////////////// static void visitPinsAboveNet1(const Pin *hpin, Net *above_net, NetSet &visited, PinSet &above_drvrs, PinSet &above_loads, const Network *network) { visited.insert(above_net); // Visit above net pins. NetPinIterator *pin_iter = network->pinIterator(above_net); while (pin_iter->hasNext()) { const Pin *above_pin = pin_iter->next(); if (above_pin != hpin) { if (network->isDriver(above_pin)) above_drvrs.insert(above_pin); if (network->isLoad(above_pin)) above_loads.insert(above_pin); Term *above_term = network->term(above_pin); if (above_term) { Net *above_net1 = network->net(above_term); if (above_net1 && !visited.hasKey(above_net1)) visitPinsAboveNet1(above_pin, above_net1, visited, above_drvrs, above_loads, network); } } } delete pin_iter; // Search up from net terminals. NetTermIterator *term_iter = network->termIterator(above_net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = network->pin(term); if (above_pin && above_pin != hpin) { Net *above_net1 = network->net(above_pin); if (above_net1 && !visited.hasKey(above_net1)) visitPinsAboveNet1(above_pin, above_net1, visited, above_drvrs, above_loads, network); if (network->isDriver(above_pin)) above_drvrs.insert(above_pin); if (network->isLoad(above_pin)) above_loads.insert(above_pin); } } delete term_iter; } static void visitPinsBelowNet1(const Pin *hpin, Net *below_net, NetSet &visited, PinSet &below_drvrs, PinSet &below_loads, const Network *network) { visited.insert(below_net); // Visit below net pins. NetPinIterator *pin_iter = network->pinIterator(below_net); while (pin_iter->hasNext()) { const Pin *below_pin = pin_iter->next(); if (below_pin != hpin) { NetSet visited_above(network); if (network->isDriver(below_pin)) below_drvrs.insert(below_pin); if (network->isLoad(below_pin)) below_loads.insert(below_pin); if (network->isHierarchical(below_pin)) { Term *term = network->term(below_pin); if (term) { Net *below_net1 = network->net(term); if (below_net1 && !visited.hasKey(below_net1)) visitPinsBelowNet1(below_pin, below_net1, visited, below_drvrs, below_loads, network); } } } } delete pin_iter; } static void visitDrvrLoads(PinSet drvrs, PinSet loads, HierPinThruVisitor *visitor) { PinSet::Iterator drvr_iter(drvrs); while (drvr_iter.hasNext()) { const Pin *drvr = drvr_iter.next(); PinSet::Iterator load_iter(loads); while (load_iter.hasNext()) { const Pin *load = load_iter.next(); visitor->visit(drvr, load); } } } void visitDrvrLoadsThruHierPin(const Pin *hpin, const Network *network, HierPinThruVisitor *visitor) { Net *above_net = network->net(hpin); if (above_net) { // Search down from hpin terminal. Term *term = network->term(hpin); if (term) { Net *below_net = network->net(term); if (below_net) { NetSet visited(network); PinSet above_drvrs(network); PinSet above_loads(network); visitPinsAboveNet1(hpin, above_net, visited, above_drvrs, above_loads, network); PinSet below_drvrs(network); PinSet below_loads(network); visitPinsBelowNet1(hpin, below_net, visited, below_drvrs, below_loads, network); visitDrvrLoads(above_drvrs, below_loads, visitor); visitDrvrLoads(below_drvrs, above_loads, visitor); } } } } void visitDrvrLoadsThruNet(const Net *net, const Network *network, HierPinThruVisitor *visitor) { NetSet visited(network); PinSet above_drvrs(network); PinSet above_loads(network); PinSet below_drvrs(network); PinSet below_loads(network); PinSet net_drvrs(network); PinSet net_loads(network); NetPinIterator *pin_iter = network->pinIterator(net); while (pin_iter->hasNext()) { const Pin *pin = pin_iter->next(); if (network->isHierarchical(pin)) { // Search down from pin terminal. const Term *term = network->term(pin); if (term) { Net *below_net = network->net(term); if (below_net) { visitPinsBelowNet1(pin, below_net, visited, below_drvrs, below_loads, network); } } } else { if (network->isDriver(pin)) net_drvrs.insert(pin); if (network->isLoad(pin)) net_loads.insert(pin); } } delete pin_iter; NetTermIterator *term_iter = network->termIterator(net); while (term_iter->hasNext()) { Term *term = term_iter->next(); Pin *above_pin = network->pin(term); if (above_pin) { if (network->isDriver(above_pin)) above_drvrs.insert(above_pin); if (network->isLoad(above_pin)) above_loads.insert(above_pin); Net *above_net = network->net(above_pin); if (above_net) visitPinsAboveNet1(above_pin, above_net, visited, above_drvrs, above_loads, network); } } delete term_iter; visitDrvrLoads(above_drvrs, below_loads, visitor); visitDrvrLoads(above_drvrs, net_loads, visitor); visitDrvrLoads(below_drvrs, above_loads, visitor); visitDrvrLoads(below_drvrs, net_loads, visitor); visitDrvrLoads(net_drvrs, above_loads, visitor); visitDrvrLoads(net_drvrs, below_loads, visitor); visitDrvrLoads(net_drvrs, net_loads, visitor); } //////////////////////////////////////////////////////////////// char logicValueString(LogicValue value) { static char str[] = "01X^v"; return str[int(value)]; } //////////////////////////////////////////////////////////////// CellIdLess::CellIdLess(const Network *network) : network_(network) { } bool CellIdLess::operator()(const Cell *cell1, const Cell *cell2) const { return network_->id(cell1) < network_->id(cell2); } PortIdLess::PortIdLess(const Network *network) : network_(network) { } bool PortIdLess::operator()(const Port *port1, const Port *port2) const { return network_->id(port1) < network_->id(port2); } InstanceIdLess::InstanceIdLess(const Network *network) : network_(network) { } bool InstanceIdLess::operator()(const Instance *inst1, const Instance *inst2) const { return network_->id(inst1) < network_->id(inst2); } PinIdLess::PinIdLess(const Network *network) : network_(network) { } bool PinIdLess::operator()(const Pin *pin1, const Pin *pin2) const { return network_->id(pin1) < network_->id(pin2); } PinIdHash::PinIdHash(const Network *network) : network_(network) { } size_t PinIdHash::operator()(const Pin *pin) const { return network_->id(pin); } NetIdLess::NetIdLess(const Network *network) : network_(network) { } bool NetIdLess::operator()(const Net *net1, const Net *net2) const { return network_->id(net1) < network_->id(net2); } //////////////////////////////////////////////////////////////// CellSet::CellSet(const Network *network) : Set(CellIdLess(network)) { } PortSet::PortSet(const Network *network) : Set(PortIdLess(network)) { } InstanceSet::InstanceSet() : Set(InstanceIdLess(nullptr)) { } InstanceSet::InstanceSet(const Network *network) : Set(InstanceIdLess(network)) { } int InstanceSet::compare(const InstanceSet *set1, const InstanceSet *set2, const Network *network) { size_t size1 = set1 ? set1->size() : 0; size_t size2 = set2 ? set2->size() : 0; if (size1 == size2) { InstanceSet::ConstIterator iter1(set1); InstanceSet::ConstIterator iter2(set2); while (iter1.hasNext() && iter2.hasNext()) { const Instance *inst1 = iter1.next(); const Instance *inst2 = iter2.next(); ObjectId id1 = network->id(inst1); ObjectId id2 = network->id(inst2); if (id1 < id2) return -1; else if (id1 > id2) return 1; } // Sets are equal. return 0; } else return (size1 > size2) ? 1 : -1; } bool InstanceSet::intersects(const InstanceSet *set1, const InstanceSet *set2, const Network *network) { return Set::intersects(set1, set2, InstanceIdLess(network)); } //////////////////////////////////////////////////////////////// PinSet::PinSet() : Set(PinIdLess(nullptr)) { } PinSet::PinSet(const Network *network) : Set(PinIdLess(network)) { } int PinSet::compare(const PinSet *set1, const PinSet *set2, const Network *network) { size_t size1 = set1 ? set1->size() : 0; size_t size2 = set2 ? set2->size() : 0; if (size1 == size2) { PinSet::ConstIterator iter1(set1); PinSet::ConstIterator iter2(set2); while (iter1.hasNext() && iter2.hasNext()) { const Pin *pin1 = iter1.next(); const Pin *pin2 = iter2.next(); ObjectId id1 = network->id(pin1); ObjectId id2 = network->id(pin2); if (id1 < id2) return -1; else if (id1 > id2) return 1; } // Sets are equal. return 0; } else return (size1 > size2) ? 1 : -1; } bool PinSet::intersects(const PinSet *set1, const PinSet *set2, const Network *network) { return Set::intersects(set1, set2, PinIdLess(network)); } //////////////////////////////////////////////////////////////// NetSet::NetSet() : Set(NetIdLess(nullptr)) { } NetSet::NetSet(const Network *network) : Set(NetIdLess(network)) { } int NetSet::compare(const NetSet *set1, const NetSet *set2, const Network *network) { size_t size1 = set1 ? set1->size() : 0; size_t size2 = set2 ? set2->size() : 0; if (size1 == size2) { NetSet::ConstIterator iter1(set1); NetSet::ConstIterator iter2(set2); while (iter1.hasNext() && iter2.hasNext()) { const Net *net1 = iter1.next(); const Net *net2 = iter2.next(); ObjectId id1 = network->id(net1); ObjectId id2 = network->id(net2); if (id1 < id2) return -1; else if (id1 > id2) return 1; } // Sets are equal. return 0; } else return (size1 > size2) ? 1 : -1; } bool NetSet::intersects(const NetSet *set1, const NetSet *set2, const Network *network) { return Set::intersects(set1, set2, NetIdLess(network)); } } // namespace