| // OpenSTA, Static Timing Analyzer |
| // Copyright (c) 2022, 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 <https://www.gnu.org/licenses/>. |
| |
| #include "ConcreteNetwork.hh" |
| |
| #include "DisallowCopyAssign.hh" |
| #include "PatternMatch.hh" |
| #include "Report.hh" |
| #include "Liberty.hh" |
| #include "PortDirection.hh" |
| #include "ConcreteLibrary.hh" |
| #include "Network.hh" |
| |
| namespace sta { |
| |
| static void |
| makeChildNetwork(Instance *proto, |
| Instance *parent, |
| ConcreteBindingTbl *parent_bindings, |
| NetworkReader *network); |
| static void |
| makeClonePins(Instance *proto, |
| Instance *clone, |
| Instance *clone_view, |
| ConcreteBindingTbl *bindings, |
| Instance *parent, |
| ConcreteBindingTbl *parent_bindings, |
| NetworkReader *network); |
| |
| NetworkReader * |
| makeConcreteNetwork() |
| { |
| return new ConcreteNetwork; |
| } |
| |
| class ConcreteInstanceChildIterator : public InstanceChildIterator |
| { |
| public: |
| explicit ConcreteInstanceChildIterator(ConcreteInstanceChildMap *map); |
| bool hasNext(); |
| Instance *next(); |
| |
| private: |
| ConcreteInstanceChildMap::ConstIterator iter_; |
| }; |
| |
| ConcreteInstanceChildIterator:: |
| ConcreteInstanceChildIterator(ConcreteInstanceChildMap *map) : |
| iter_(map) |
| { |
| } |
| |
| bool |
| ConcreteInstanceChildIterator::hasNext() |
| { |
| return iter_.hasNext(); |
| } |
| |
| Instance * |
| ConcreteInstanceChildIterator::next() |
| { |
| return reinterpret_cast<Instance*>(iter_.next()); |
| } |
| |
| class ConcreteInstanceNetIterator : public InstanceNetIterator |
| { |
| public: |
| explicit ConcreteInstanceNetIterator(ConcreteInstanceNetMap *nets); |
| bool hasNext(); |
| Net *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteInstanceNetIterator); |
| void findNext(); |
| |
| ConcreteInstanceNetMap::Iterator iter_; |
| ConcreteNet *next_; |
| }; |
| |
| ConcreteInstanceNetIterator:: |
| ConcreteInstanceNetIterator(ConcreteInstanceNetMap *nets): |
| iter_(nets), |
| next_(nullptr) |
| { |
| findNext(); |
| } |
| |
| bool |
| ConcreteInstanceNetIterator::hasNext() |
| { |
| return next_ != nullptr; |
| } |
| |
| // Skip nets that have been merged. |
| void |
| ConcreteInstanceNetIterator::findNext() |
| { |
| while (iter_.hasNext()) { |
| next_ = iter_.next(); |
| if (next_->mergedInto() == nullptr) |
| return; |
| } |
| next_ = nullptr; |
| } |
| |
| Net * |
| ConcreteInstanceNetIterator::next() |
| { |
| ConcreteNet *next = next_; |
| findNext(); |
| return reinterpret_cast<Net*>(next); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteInstancePinIterator : public InstancePinIterator |
| { |
| public: |
| ConcreteInstancePinIterator(const ConcreteInstance *inst, |
| int pin_count); |
| bool hasNext(); |
| Pin *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteInstancePinIterator); |
| void findNext(); |
| |
| ConcretePin **pins_; |
| int pin_count_; |
| int pin_index_; |
| ConcretePin *next_; |
| }; |
| |
| ConcreteInstancePinIterator:: |
| ConcreteInstancePinIterator(const ConcreteInstance *inst, |
| int pin_count) : |
| pins_(inst->pins_), |
| pin_count_(pin_count), |
| pin_index_(0) |
| { |
| findNext(); |
| } |
| |
| bool |
| ConcreteInstancePinIterator::hasNext() |
| { |
| return next_ != nullptr; |
| } |
| |
| Pin * |
| ConcreteInstancePinIterator::next() |
| { |
| ConcretePin *next = next_; |
| findNext(); |
| return reinterpret_cast<Pin*>(next); |
| } |
| |
| // Skip over missing pins. |
| void |
| ConcreteInstancePinIterator::findNext() |
| { |
| while (pin_index_ < pin_count_) { |
| next_ = pins_[pin_index_++]; |
| if (next_) |
| return; |
| } |
| next_ = nullptr; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteNetPinIterator : public NetPinIterator |
| { |
| public: |
| explicit ConcreteNetPinIterator(const ConcreteNet *net); |
| bool hasNext(); |
| Pin *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteNetPinIterator); |
| |
| ConcretePin *next_; |
| }; |
| |
| ConcreteNetPinIterator::ConcreteNetPinIterator(const ConcreteNet *net) : |
| next_(net->pins_) |
| { |
| } |
| |
| bool |
| ConcreteNetPinIterator::hasNext() |
| { |
| return next_ != nullptr; |
| } |
| |
| Pin * |
| ConcreteNetPinIterator::next() |
| { |
| ConcretePin *next = next_; |
| next_ = next_->net_next_; |
| return reinterpret_cast<Pin*>(next); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteNetTermIterator : public NetTermIterator |
| { |
| public: |
| explicit ConcreteNetTermIterator(const ConcreteNet *net); |
| bool hasNext(); |
| Term *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteNetTermIterator); |
| |
| ConcreteTerm *next_; |
| }; |
| |
| ConcreteNetTermIterator::ConcreteNetTermIterator(const ConcreteNet *net) : |
| next_(net->terms_) |
| { |
| } |
| |
| bool |
| ConcreteNetTermIterator::hasNext() |
| { |
| return next_ != nullptr; |
| } |
| |
| Term * |
| ConcreteNetTermIterator::next() |
| { |
| ConcreteTerm *next = next_; |
| next_ = next_->net_next_; |
| return reinterpret_cast<Term*>(next); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| ConcreteNetwork::ConcreteNetwork() : |
| NetworkReader(), |
| top_instance_(nullptr), |
| link_func_(nullptr) |
| { |
| } |
| |
| ConcreteNetwork::~ConcreteNetwork() |
| { |
| clear(); |
| } |
| |
| void |
| ConcreteNetwork::clear() |
| { |
| deleteTopInstance(); |
| deleteCellNetworkViews(); |
| library_seq_.deleteContentsClear(); |
| library_map_.clear(); |
| Network::clear(); |
| } |
| |
| void |
| ConcreteNetwork::deleteTopInstance() |
| { |
| if (top_instance_) { |
| deleteInstance(top_instance_); |
| top_instance_ = nullptr; |
| } |
| } |
| |
| void |
| ConcreteNetwork::deleteCellNetworkViews() |
| { |
| CellNetworkViewMap::Iterator view_iter(cell_network_view_map_); |
| while (view_iter.hasNext()) { |
| Instance *view = view_iter.next(); |
| if (view) |
| deleteInstance(view); |
| } |
| cell_network_view_map_.clear(); |
| } |
| |
| Instance * |
| ConcreteNetwork::topInstance() const |
| { |
| return top_instance_; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteLibraryIterator1 : public Iterator<Library*> |
| { |
| public: |
| explicit ConcreteLibraryIterator1(const ConcreteLibrarySeq &lib_seq_); |
| virtual bool hasNext(); |
| virtual Library *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteLibraryIterator1); |
| |
| ConcreteLibraryIterator iter_; |
| }; |
| |
| ConcreteLibraryIterator1::ConcreteLibraryIterator1(const ConcreteLibrarySeq &lib_seq_): |
| iter_(lib_seq_) |
| { |
| } |
| |
| bool |
| ConcreteLibraryIterator1::hasNext() |
| { |
| return iter_.hasNext(); |
| } |
| |
| Library * |
| ConcreteLibraryIterator1::next() |
| { |
| return reinterpret_cast<Library*>(iter_.next()); |
| } |
| |
| LibraryIterator * |
| ConcreteNetwork::libraryIterator() const |
| { |
| return new ConcreteLibraryIterator1(library_seq_); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteLibertyLibraryIterator : public Iterator<LibertyLibrary*> |
| { |
| public: |
| explicit ConcreteLibertyLibraryIterator(const ConcreteNetwork *network); |
| virtual ~ConcreteLibertyLibraryIterator(); |
| virtual bool hasNext(); |
| virtual LibertyLibrary *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteLibertyLibraryIterator); |
| void findNext(); |
| |
| ConcreteLibrarySeq::ConstIterator iter_; |
| LibertyLibrary *next_; |
| }; |
| |
| ConcreteLibertyLibraryIterator:: |
| ConcreteLibertyLibraryIterator(const ConcreteNetwork *network): |
| iter_(network->library_seq_), |
| next_(nullptr) |
| { |
| findNext(); |
| } |
| |
| ConcreteLibertyLibraryIterator::~ConcreteLibertyLibraryIterator() |
| { |
| } |
| |
| bool |
| ConcreteLibertyLibraryIterator::hasNext() |
| { |
| return next_ != nullptr; |
| } |
| |
| LibertyLibrary * |
| ConcreteLibertyLibraryIterator::next() |
| { |
| LibertyLibrary *next = next_; |
| findNext(); |
| return next; |
| } |
| |
| void |
| ConcreteLibertyLibraryIterator::findNext() |
| { |
| next_ = nullptr; |
| while (iter_.hasNext()) { |
| ConcreteLibrary *lib = iter_.next(); |
| if (lib->isLiberty()) { |
| LibertyLibrary *liberty = static_cast<LibertyLibrary*>(lib); |
| if (liberty) { |
| next_ = liberty; |
| break; |
| } |
| } |
| } |
| } |
| |
| LibertyLibraryIterator * |
| ConcreteNetwork::libertyLibraryIterator() const |
| { |
| return new ConcreteLibertyLibraryIterator(this); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| Library * |
| ConcreteNetwork::makeLibrary(const char *name, |
| const char *filename) |
| { |
| ConcreteLibrary *library = new ConcreteLibrary(name, filename, false); |
| addLibrary(library); |
| return reinterpret_cast<Library*>(library); |
| } |
| |
| LibertyLibrary * |
| ConcreteNetwork::makeLibertyLibrary(const char *name, |
| const char *filename) |
| { |
| LibertyLibrary *library = new LibertyLibrary(name, filename); |
| addLibrary(library); |
| return library; |
| } |
| |
| void |
| ConcreteNetwork::addLibrary(ConcreteLibrary *library) |
| { |
| library_seq_.push_back(library); |
| library_map_[library->name()] = library; |
| } |
| |
| Library * |
| ConcreteNetwork::findLibrary(const char *name) |
| { |
| return reinterpret_cast<Library*>(library_map_.findKey(name)); |
| } |
| |
| void |
| ConcreteNetwork::deleteLibrary(Library *library) |
| { |
| ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(library); |
| library_map_.erase(clib->name()); |
| library_seq_.eraseObject(clib); |
| delete clib; |
| } |
| |
| const char * |
| ConcreteNetwork::name(const Library *library) const |
| { |
| const ConcreteLibrary *clib = |
| reinterpret_cast<const ConcreteLibrary*>(library); |
| return clib->name(); |
| } |
| |
| LibertyLibrary * |
| ConcreteNetwork::findLiberty(const char *name) |
| { |
| ConcreteLibrary *lib = library_map_.findKey(name); |
| if (lib) { |
| if (lib->isLiberty()) |
| return static_cast<LibertyLibrary*>(lib); |
| // Potential name conflict |
| else { |
| for (ConcreteLibrary *lib : library_seq_) { |
| if (stringEq(lib->name(), name) |
| && lib->isLiberty()) |
| return static_cast<LibertyLibrary*>(lib); |
| } |
| } |
| } |
| return nullptr; |
| } |
| |
| LibertyLibrary * |
| ConcreteNetwork::libertyLibrary(Library *library) const |
| { |
| ConcreteLibrary *lib = reinterpret_cast<ConcreteLibrary*>(library); |
| return static_cast<LibertyLibrary*>(lib); |
| } |
| |
| Cell * |
| ConcreteNetwork::makeCell(Library *library, |
| const char *name, |
| bool is_leaf, |
| const char *filename) |
| { |
| ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(library); |
| return reinterpret_cast<Cell*>(clib->makeCell(name, is_leaf, filename)); |
| } |
| |
| Cell * |
| ConcreteNetwork::findCell(const Library *library, |
| const char *name) const |
| { |
| const ConcreteLibrary *clib = |
| reinterpret_cast<const ConcreteLibrary*>(library); |
| return reinterpret_cast<Cell*>(clib->findCell(name)); |
| } |
| |
| Cell * |
| ConcreteNetwork::findAnyCell(const char *name) |
| { |
| ConcreteLibrarySeq::Iterator lib_iter(library_seq_); |
| while (lib_iter.hasNext()) { |
| ConcreteLibrary *lib = lib_iter.next(); |
| ConcreteCell *cell = lib->findCell(name); |
| if (cell) |
| return reinterpret_cast<Cell*>(cell); |
| } |
| return nullptr; |
| } |
| |
| void |
| ConcreteNetwork::findCellsMatching(const Library *library, |
| const PatternMatch *pattern, |
| CellSeq *cells) const |
| { |
| const ConcreteLibrary *clib = |
| reinterpret_cast<const ConcreteLibrary*>(library); |
| clib->findCellsMatching(pattern, cells); |
| } |
| |
| void |
| ConcreteNetwork::deleteCell(Cell *cell) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ConcreteLibrary *clib = ccell->library(); |
| clib->deleteCell(ccell); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| const char * |
| ConcreteNetwork::name(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return ccell->name(); |
| } |
| |
| void |
| ConcreteNetwork::setName(Cell *cell, |
| const char *name) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ccell->setName(name); |
| } |
| |
| void |
| ConcreteNetwork::setIsLeaf(Cell *cell, |
| bool is_leaf) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ccell->setIsLeaf(is_leaf); |
| } |
| |
| Library * |
| ConcreteNetwork::library(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return reinterpret_cast<Library*>(ccell->library()); |
| } |
| |
| LibertyCell * |
| ConcreteNetwork::libertyCell(Cell *cell) const |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| return ccell->libertyCell(); |
| } |
| |
| const LibertyCell * |
| ConcreteNetwork::libertyCell(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return ccell->libertyCell(); |
| } |
| |
| Cell * |
| ConcreteNetwork::cell(LibertyCell *cell) const |
| { |
| return reinterpret_cast<Cell*>(cell); |
| } |
| |
| const Cell * |
| ConcreteNetwork::cell(const LibertyCell *cell) const |
| { |
| return reinterpret_cast<const Cell*>(cell); |
| } |
| |
| const char * |
| ConcreteNetwork::filename(const Cell *cell) |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return ccell->filename(); |
| } |
| |
| Port * |
| ConcreteNetwork::findPort(const Cell *cell, |
| const char *name) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return reinterpret_cast<Port*>(ccell->findPort(name)); |
| } |
| |
| void |
| ConcreteNetwork::findPortsMatching(const Cell *cell, |
| const PatternMatch *pattern, |
| PortSeq *ports) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| ccell->findPortsMatching(pattern, ports); |
| } |
| |
| bool |
| ConcreteNetwork::isLeaf(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return ccell->isLeaf(); |
| } |
| |
| Port * |
| ConcreteNetwork::makePort(Cell *cell, |
| const char *name) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ConcretePort *port = ccell->makePort(name); |
| return reinterpret_cast<Port*>(port); |
| } |
| |
| Port * |
| ConcreteNetwork::makeBusPort(Cell *cell, |
| const char *name, |
| int from_index, |
| int to_index) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ConcretePort *port = ccell->makeBusPort(name, from_index, to_index); |
| return reinterpret_cast<Port*>(port); |
| } |
| |
| void |
| ConcreteNetwork::groupBusPorts(Cell *cell, |
| std::function<bool(const char*)> port_msb_first) |
| { |
| Library *lib = library(cell); |
| ConcreteLibrary *clib = reinterpret_cast<ConcreteLibrary*>(lib); |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ccell->groupBusPorts(clib->busBrktLeft(), clib->busBrktRight(), port_msb_first); |
| } |
| |
| Port * |
| ConcreteNetwork::makeBundlePort(Cell *cell, |
| const char *name, |
| PortSeq *members) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| ConcretePortSeq *cmembers = reinterpret_cast<ConcretePortSeq*>(members); |
| ConcretePort *port = ccell->makeBundlePort(name, cmembers); |
| return reinterpret_cast<Port*>(port); |
| } |
| |
| void |
| ConcreteNetwork::setDirection(Port *port, |
| PortDirection *dir) |
| { |
| ConcretePort *cport = reinterpret_cast<ConcretePort*>(port); |
| cport->setDirection(dir); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteCellPortIterator1 : public CellPortIterator |
| { |
| public: |
| explicit ConcreteCellPortIterator1(const ConcreteCell *cell); |
| ~ConcreteCellPortIterator1(); |
| virtual bool hasNext() { return iter_->hasNext(); } |
| virtual Port *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteCellPortIterator1); |
| |
| ConcreteCellPortIterator *iter_; |
| }; |
| |
| ConcreteCellPortIterator1::ConcreteCellPortIterator1(const ConcreteCell *cell): |
| iter_(cell->portIterator()) |
| { |
| } |
| |
| ConcreteCellPortIterator1::~ConcreteCellPortIterator1() |
| { |
| delete iter_; |
| } |
| |
| Port * |
| ConcreteCellPortIterator1::next() |
| { |
| return reinterpret_cast<Port*>(iter_->next()); |
| } |
| |
| CellPortIterator * |
| ConcreteNetwork::portIterator(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return new ConcreteCellPortIterator1(ccell); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcreteCellPortBitIterator1 : public CellPortIterator |
| { |
| public: |
| explicit ConcreteCellPortBitIterator1(const ConcreteCell *cell); |
| ~ConcreteCellPortBitIterator1(); |
| virtual bool hasNext() { return iter_->hasNext(); } |
| virtual Port *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteCellPortBitIterator1); |
| |
| ConcreteCellPortBitIterator *iter_; |
| }; |
| |
| ConcreteCellPortBitIterator1::ConcreteCellPortBitIterator1(const ConcreteCell *cell): |
| iter_(cell->portBitIterator()) |
| { |
| } |
| |
| ConcreteCellPortBitIterator1::~ConcreteCellPortBitIterator1() |
| { |
| delete iter_; |
| } |
| |
| Port * |
| ConcreteCellPortBitIterator1::next() |
| { |
| return reinterpret_cast<Port*>(iter_->next()); |
| } |
| |
| CellPortBitIterator * |
| ConcreteNetwork::portBitIterator(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return new ConcreteCellPortBitIterator1(ccell); |
| } |
| |
| int |
| ConcreteNetwork::portBitCount(const Cell *cell) const |
| { |
| const ConcreteCell *ccell = reinterpret_cast<const ConcreteCell*>(cell); |
| return ccell->portBitCount(); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| const char * |
| ConcreteNetwork::name(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->name(); |
| } |
| |
| Cell * |
| ConcreteNetwork::cell(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->cell(); |
| } |
| |
| LibertyPort * |
| ConcreteNetwork::libertyPort(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->libertyPort(); |
| } |
| |
| PortDirection * |
| ConcreteNetwork::direction(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->direction(); |
| } |
| |
| bool |
| ConcreteNetwork::isBundle(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->isBundle(); |
| } |
| |
| bool |
| ConcreteNetwork::isBus(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->isBus(); |
| } |
| |
| const char * |
| ConcreteNetwork::busName(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->busName(); |
| } |
| |
| int |
| ConcreteNetwork::size(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->size(); |
| } |
| |
| int |
| ConcreteNetwork::fromIndex(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->fromIndex(); |
| } |
| |
| int |
| ConcreteNetwork::toIndex(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->toIndex(); |
| } |
| |
| Port * |
| ConcreteNetwork::findBusBit(const Port *port, |
| int index) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return reinterpret_cast<Port*>(cport->findBusBit(index)); |
| } |
| |
| Port * |
| ConcreteNetwork::findMember(const Port *port, |
| int index) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return reinterpret_cast<Port*>(cport->findMember(index)); |
| } |
| |
| bool |
| ConcreteNetwork::hasMembers(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return cport->hasMembers(); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| class ConcretePortMemberIterator1 : public PortMemberIterator |
| { |
| public: |
| explicit ConcretePortMemberIterator1(const ConcretePort *port); |
| ~ConcretePortMemberIterator1(); |
| virtual bool hasNext() { return iter_->hasNext(); } |
| virtual Port *next(); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcretePortMemberIterator1); |
| |
| ConcretePortMemberIterator *iter_; |
| }; |
| |
| ConcretePortMemberIterator1::ConcretePortMemberIterator1(const ConcretePort * |
| port) : |
| iter_(port->memberIterator()) |
| { |
| } |
| |
| ConcretePortMemberIterator1::~ConcretePortMemberIterator1() |
| { |
| delete iter_; |
| } |
| |
| Port * |
| ConcretePortMemberIterator1::next() |
| { |
| return reinterpret_cast<Port*>(iter_->next()); |
| } |
| |
| PortMemberIterator * |
| ConcreteNetwork::memberIterator(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return new ConcretePortMemberIterator1(cport); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| const char * |
| ConcreteNetwork::name(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return inst->name(); |
| } |
| |
| Cell * |
| ConcreteNetwork::cell(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return inst->cell(); |
| } |
| |
| Instance * |
| ConcreteNetwork::parent(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return reinterpret_cast<Instance*>(inst->parent()); |
| } |
| |
| bool |
| ConcreteNetwork::isLeaf(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(inst->cell()); |
| return ccell->isLeaf(); |
| } |
| |
| Instance * |
| ConcreteNetwork::findChild(const Instance *parent, |
| const char *name) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(parent); |
| return inst->findChild(name); |
| } |
| |
| Pin * |
| ConcreteNetwork::findPin(const Instance *instance, |
| const char *port_name) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return reinterpret_cast<Pin*>(inst->findPin(port_name)); |
| } |
| |
| Pin * |
| ConcreteNetwork::findPin(const Instance *instance, |
| const Port *port) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return reinterpret_cast<Pin*>(inst->findPin(port)); |
| } |
| |
| Net * |
| ConcreteNetwork::findNet(const Instance *instance, |
| const char *net_name) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return reinterpret_cast<Net*>(inst->findNet(net_name)); |
| } |
| |
| void |
| ConcreteNetwork::findInstNetsMatching(const Instance *instance, |
| const PatternMatch *pattern, |
| NetSeq *nets) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| inst->findNetsMatching(pattern, nets); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| InstanceChildIterator * |
| ConcreteNetwork::childIterator(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return inst->childIterator(); |
| } |
| |
| InstancePinIterator * |
| ConcreteNetwork::pinIterator(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| ConcreteCell *cell = reinterpret_cast<ConcreteCell*>(inst->cell()); |
| int pin_count = cell->portBitCount(); |
| return new ConcreteInstancePinIterator(inst, pin_count); |
| } |
| |
| InstanceNetIterator * |
| ConcreteNetwork::netIterator(const Instance *instance) const |
| { |
| const ConcreteInstance *inst = |
| reinterpret_cast<const ConcreteInstance*>(instance); |
| return inst->netIterator(); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| Instance * |
| ConcreteNetwork::instance(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| return reinterpret_cast<Instance*>(cpin->instance()); |
| } |
| |
| Net * |
| ConcreteNetwork::net(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| return reinterpret_cast<Net*>(cpin->net()); |
| } |
| |
| Term * |
| ConcreteNetwork::term(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| return reinterpret_cast<Term*>(cpin->term()); |
| } |
| |
| Port * |
| ConcreteNetwork::port(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| return reinterpret_cast<Port*>(cpin->port()); |
| } |
| |
| PortDirection * |
| ConcreteNetwork::direction(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| const ConcretePort *cport = cpin->port(); |
| return cport->direction(); |
| } |
| |
| VertexId |
| ConcreteNetwork::vertexId(const Pin *pin) const |
| { |
| const ConcretePin *cpin = reinterpret_cast<const ConcretePin*>(pin); |
| return cpin->vertexId(); |
| } |
| |
| void |
| ConcreteNetwork::setVertexId(Pin *pin, |
| VertexId id) |
| { |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin); |
| cpin->setVertexId(id); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| Net * |
| ConcreteNetwork::net(const Term *term) const |
| { |
| const ConcreteTerm *cterm = reinterpret_cast<const ConcreteTerm*>(term); |
| return reinterpret_cast<Net*>(cterm->net()); |
| } |
| |
| Pin * |
| ConcreteNetwork::pin(const Term *term) const |
| { |
| const ConcreteTerm *cterm = reinterpret_cast<const ConcreteTerm*>(term); |
| return reinterpret_cast<Pin*>(cterm->pin()); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| const char * |
| ConcreteNetwork::name(const Net *net) const |
| { |
| const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net); |
| return cnet->name(); |
| } |
| |
| Instance * |
| ConcreteNetwork::instance(const Net *net) const |
| { |
| const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net); |
| return reinterpret_cast<Instance*>(cnet->instance()); |
| } |
| |
| bool |
| ConcreteNetwork::isPower(const Net *net) const |
| { |
| return constant_nets_[int(LogicValue::one)].hasKey(const_cast<Net*>(net)); |
| } |
| |
| bool |
| ConcreteNetwork::isGround(const Net *net) const |
| { |
| return constant_nets_[int(LogicValue::zero)].hasKey(const_cast<Net*>(net)); |
| } |
| |
| NetPinIterator * |
| ConcreteNetwork::pinIterator(const Net *net) const |
| { |
| const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net); |
| return new ConcreteNetPinIterator(cnet); |
| } |
| |
| NetTermIterator * |
| ConcreteNetwork::termIterator(const Net *net) const |
| { |
| const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net); |
| return new ConcreteNetTermIterator(cnet); |
| } |
| |
| void |
| ConcreteNetwork::mergeInto(Net *net, |
| Net *into_net) |
| { |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| ConcreteNet *cinto_net = reinterpret_cast<ConcreteNet*>(into_net); |
| cnet->mergeInto(cinto_net); |
| clearNetDrvrPinMap(); |
| } |
| |
| Net * |
| ConcreteNetwork::mergedInto(Net *net) |
| { |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| return reinterpret_cast<Net*>(cnet->mergedInto()); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| Cell * |
| ConcreteInstance::cell() const |
| { |
| return reinterpret_cast<Cell*>(cell_); |
| } |
| |
| Instance * |
| ConcreteNetwork::makeInstance(Cell *cell, |
| const char *name, |
| Instance *parent) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| return makeConcreteInstance(ccell, name, parent); |
| } |
| |
| Instance * |
| ConcreteNetwork::makeInstance(LibertyCell *cell, |
| const char *name, |
| Instance *parent) |
| { |
| return makeConcreteInstance(cell, name, parent); |
| } |
| |
| Instance * |
| ConcreteNetwork::makeConcreteInstance(ConcreteCell *cell, |
| const char *name, |
| Instance *parent) |
| { |
| ConcreteInstance *cparent = |
| reinterpret_cast<ConcreteInstance*>(parent); |
| ConcreteInstance *inst = new ConcreteInstance(cell, name, cparent); |
| if (parent) |
| cparent->addChild(inst); |
| return reinterpret_cast<Instance*>(inst); |
| } |
| |
| void |
| ConcreteNetwork::makePins(Instance *inst) |
| { |
| CellPortBitIterator *port_iterator = portBitIterator(cell(inst)); |
| while (port_iterator->hasNext()) { |
| Port *port = port_iterator->next(); |
| makePin(inst, port, nullptr); |
| } |
| delete port_iterator; |
| } |
| |
| void |
| ConcreteNetwork::replaceCell(Instance *inst, |
| Cell *cell) |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell); |
| int port_count = ccell->portBitCount(); |
| ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst); |
| // Port count picked from Instance instead of Target cells-Dinesh A |
| ConcreteCell *instcell = reinterpret_cast<ConcreteCell*>(cinst->cell()); |
| int inst_port_count = instcell->portBitCount(); |
| ConcretePin **pins = cinst->pins_; |
| ConcretePin **rpins = new ConcretePin*[port_count]; |
| for (int i = 0; i < port_count; i++) |
| rpins[i] = pins[inst_port_count-1]; |
| for (int i = 0; i < inst_port_count; i++) { |
| ConcretePin *cpin = pins[i]; |
| if (cpin) { |
| ConcretePort *pin_cport = reinterpret_cast<ConcretePort*>(cpin->port()); |
| ConcretePort *cport = ccell->findPort(pin_cport->name()); |
| if (cport) { |
| rpins[cport->pinIndex()] = cpin; |
| cpin->port_ = cport; |
| } |
| } |
| } |
| delete [] pins; |
| cinst->pins_ = rpins; |
| cinst->setCell(ccell); |
| } |
| |
| void |
| ConcreteNetwork::deleteInstance(Instance *inst) |
| { |
| ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst); |
| |
| // Delete nets first (so children pin deletes are not required). |
| ConcreteInstanceNetMap::Iterator net_iter(cinst->nets_); |
| while (net_iter.hasNext()) { |
| ConcreteNet *cnet = net_iter.next(); |
| Net *net = reinterpret_cast<Net*>(cnet); |
| // Delete terminals connected to net. |
| NetTermIterator *term_iter = termIterator(net); |
| while (term_iter->hasNext()) { |
| ConcreteTerm *term = reinterpret_cast<ConcreteTerm*>(term_iter->next()); |
| delete term; |
| } |
| delete term_iter; |
| deleteNet(net); |
| } |
| |
| // Delete children. |
| InstanceChildIterator *child_iter = childIterator(inst); |
| while (child_iter->hasNext()) { |
| Instance *child = child_iter->next(); |
| deleteInstance(child); |
| } |
| delete child_iter; |
| |
| InstancePinIterator *pin_iter = pinIterator(inst); |
| while (pin_iter->hasNext()) { |
| Pin *pin = pin_iter->next(); |
| deletePin(pin); |
| } |
| delete pin_iter; |
| |
| Instance *parent_inst = parent(inst); |
| if (parent_inst) { |
| ConcreteInstance *cparent = |
| reinterpret_cast<ConcreteInstance*>(parent_inst); |
| cparent->deleteChild(cinst); |
| } |
| delete cinst; |
| } |
| |
| Pin * |
| ConcreteNetwork::makePin(Instance *inst, |
| Port *port, |
| Net *net) |
| { |
| ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst); |
| ConcretePort *cport = reinterpret_cast<ConcretePort*>(port); |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| ConcretePin *cpin = new ConcretePin(cinst, cport, cnet); |
| cinst->addPin(cpin); |
| if (cnet) |
| connectNetPin(cnet, cpin); |
| return reinterpret_cast<Pin*>(cpin); |
| } |
| |
| Term * |
| ConcreteNetwork::makeTerm(Pin *pin, |
| Net *net) |
| { |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin); |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| ConcreteTerm *cterm = new ConcreteTerm(cpin, cnet); |
| if (cnet) |
| cnet->addTerm(cterm); |
| cpin->term_ = cterm; |
| return reinterpret_cast<Term*>(cterm); |
| } |
| |
| Pin * |
| ConcreteNetwork::connect(Instance *inst, |
| LibertyPort *port, |
| Net *net) |
| { |
| return connect(inst, reinterpret_cast<Port*>(port), net); |
| } |
| |
| Pin * |
| ConcreteNetwork::connect(Instance *inst, |
| Port *port, |
| Net *net) |
| { |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| ConcreteInstance *cinst = reinterpret_cast<ConcreteInstance*>(inst); |
| ConcretePort *cport = reinterpret_cast<ConcretePort*>(port); |
| ConcretePin *cpin = cinst->findPin(port); |
| if (cpin) { |
| ConcreteNet *prev_net = cpin->net_; |
| if (prev_net) |
| disconnectNetPin(prev_net, cpin); |
| } |
| else { |
| cpin = new ConcretePin(cinst, cport, cnet); |
| cinst->addPin(cpin); |
| } |
| if (inst == top_instance_) { |
| // makeTerm |
| ConcreteTerm *cterm = new ConcreteTerm(cpin, cnet); |
| cnet->addTerm(cterm); |
| cpin->term_ = cterm; |
| cpin->net_ = nullptr; |
| } |
| else { |
| cpin->net_ = cnet; |
| connectNetPin(cnet, cpin); |
| } |
| return reinterpret_cast<Pin*>(cpin); |
| } |
| |
| void |
| ConcreteNetwork::connectNetPin(ConcreteNet *cnet, |
| ConcretePin *cpin) |
| { |
| cnet->addPin(cpin); |
| |
| // If there are no terminals the net does not span hierarchy levels |
| // and it is safe to incrementally update the drivers. |
| Pin *pin = reinterpret_cast<Pin*>(cpin); |
| if (isDriver(pin)) { |
| if (cnet->terms_ == nullptr) { |
| Net *net = reinterpret_cast<Net*>(cnet); |
| PinSet *drvrs = net_drvr_pin_map_.findKey(net); |
| if (drvrs) |
| drvrs->insert(pin); |
| } |
| else |
| clearNetDrvrPinMap(); |
| } |
| } |
| |
| void |
| ConcreteNetwork::disconnectPin(Pin *pin) |
| { |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin); |
| if (reinterpret_cast<Instance*>(cpin->instance()) == top_instance_) { |
| ConcreteTerm *cterm = cpin->term_; |
| if (cterm) { |
| ConcreteNet *cnet = cterm->net_; |
| if (cnet) { |
| cnet->deleteTerm(cterm); |
| clearNetDrvrPinMap(); |
| } |
| cpin->term_ = nullptr; |
| delete cterm; |
| } |
| } |
| else { |
| ConcreteNet *cnet = cpin->net(); |
| if (cnet) |
| disconnectNetPin(cnet, cpin); |
| cpin->net_ = nullptr; |
| } |
| } |
| |
| void |
| ConcreteNetwork::disconnectNetPin(ConcreteNet *cnet, |
| ConcretePin *cpin) |
| { |
| cnet->deletePin(cpin); |
| |
| Pin *pin = reinterpret_cast<Pin*>(cpin); |
| if (isDriver(pin)) { |
| ConcreteNet *cnet = cpin->net(); |
| // If there are no terminals the net does not span hierarchy levels |
| // and it is safe to incrementally update the drivers. |
| if (cnet->terms_ == nullptr) { |
| Net *net = reinterpret_cast<Net*>(cnet); |
| PinSet *drvrs = net_drvr_pin_map_.findKey(net); |
| if (drvrs) |
| drvrs->erase(pin); |
| } |
| else |
| clearNetDrvrPinMap(); |
| } |
| } |
| |
| void |
| ConcreteNetwork::deletePin(Pin *pin) |
| { |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin); |
| ConcreteNet *cnet = cpin->net(); |
| if (cnet) |
| disconnectNetPin(cnet, cpin); |
| ConcreteInstance *cinst = |
| reinterpret_cast<ConcreteInstance*>(cpin->instance()); |
| if (cinst) |
| cinst->deletePin(cpin); |
| delete cpin; |
| } |
| |
| Net * |
| ConcreteNetwork::makeNet(const char *name, |
| Instance *parent) |
| { |
| ConcreteInstance *cparent = reinterpret_cast<ConcreteInstance*>(parent); |
| ConcreteNet *net = new ConcreteNet(name, cparent); |
| cparent->addNet(net); |
| return reinterpret_cast<Net*>(net); |
| } |
| |
| void |
| ConcreteNetwork::deleteNet(Net *net) |
| { |
| ConcreteNet *cnet = reinterpret_cast<ConcreteNet*>(net); |
| ConcreteNetPinIterator pin_iter(cnet); |
| while (pin_iter.hasNext()) { |
| ConcretePin *pin = reinterpret_cast<ConcretePin*>(pin_iter.next()); |
| // Do NOT use net->disconnectPin because it would be N^2 |
| // to delete all of the pins from the net. |
| pin->net_ = nullptr; |
| } |
| |
| constant_nets_[int(LogicValue::zero)].erase(net); |
| constant_nets_[int(LogicValue::one)].erase(net); |
| PinSet *drvrs = net_drvr_pin_map_.findKey(net); |
| if (drvrs) { |
| delete drvrs; |
| net_drvr_pin_map_.erase(net); |
| } |
| |
| ConcreteInstance *cinst = |
| reinterpret_cast<ConcreteInstance*>(cnet->instance()); |
| cinst->deleteNet(cnet); |
| delete cnet; |
| } |
| |
| void |
| ConcreteNetwork::clearConstantNets() |
| { |
| constant_nets_[int(LogicValue::zero)].clear(); |
| constant_nets_[int(LogicValue::one)].clear(); |
| } |
| |
| void |
| ConcreteNetwork::addConstantNet(Net *net, |
| LogicValue value) |
| { |
| if (value == LogicValue::zero |
| || value == LogicValue::one) |
| constant_nets_[int(value)].insert(net); |
| } |
| |
| ConstantPinIterator * |
| ConcreteNetwork::constantPinIterator() |
| { |
| return new NetworkConstantPinIterator(this, |
| constant_nets_[int(LogicValue::zero)], |
| constant_nets_[int(LogicValue::one)]); |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| // Optimized version of Network::visitConnectedPins. |
| void |
| ConcreteNetwork::visitConnectedPins(const Net *net, |
| PinVisitor &visitor, |
| ConstNetSet &visited_nets) const |
| { |
| if (!visited_nets.hasKey(net)) { |
| visited_nets.insert(net); |
| // Search up from net terminals. |
| const ConcreteNet *cnet = reinterpret_cast<const ConcreteNet*>(net); |
| for (ConcreteTerm *term = cnet->terms_; term; term = term->net_next_) { |
| ConcretePin *above_pin = term->pin_; |
| if (above_pin) { |
| ConcreteNet *above_net = above_pin->net_; |
| if (above_net) |
| visitConnectedPins(reinterpret_cast<Net*>(above_net), |
| visitor, visited_nets); |
| else |
| visitor(reinterpret_cast<Pin*>(above_pin)); |
| } |
| } |
| |
| // Search down from net pins. |
| for (ConcretePin *pin = cnet->pins_; pin; pin = pin->net_next_) { |
| visitor(reinterpret_cast<Pin*>(pin)); |
| ConcreteTerm *below_term = pin->term_; |
| if (below_term) { |
| ConcreteNet *below_net = below_term->net_; |
| if (below_net) |
| visitConnectedPins(reinterpret_cast<Net*>(below_net), |
| visitor, visited_nets); |
| } |
| } |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| ConcreteInstance::ConcreteInstance(ConcreteCell *cell, |
| const char *name, |
| ConcreteInstance *parent) : |
| cell_(cell), |
| name_(stringCopy(name)), |
| parent_(parent), |
| children_(nullptr), |
| nets_(nullptr) |
| { |
| initPins(); |
| } |
| |
| void |
| ConcreteInstance::initPins() |
| { |
| int pin_count = reinterpret_cast<ConcreteCell*>(cell_)->portBitCount(); |
| if (pin_count) { |
| pins_ = new ConcretePin*[pin_count]; |
| for (int i = 0; i < pin_count; i++) |
| pins_[i] = nullptr; |
| } |
| else |
| pins_ = nullptr; |
| } |
| |
| ConcreteInstance::~ConcreteInstance() |
| { |
| stringDelete(name_); |
| delete [] pins_; |
| delete children_; |
| delete nets_; |
| } |
| |
| Instance * |
| ConcreteInstance::findChild(const char *name) const |
| { |
| if (children_) |
| return reinterpret_cast<Instance*>(children_->findKey(name)); |
| else |
| return nullptr; |
| } |
| |
| ConcretePin * |
| ConcreteInstance::findPin(const char *port_name) const |
| { |
| ConcreteCell *ccell = reinterpret_cast<ConcreteCell*>(cell_); |
| const ConcretePort *cport = |
| reinterpret_cast<const ConcretePort*>(ccell->findPort(port_name)); |
| if (cport |
| && !cport->isBus()) |
| return pins_[cport->pinIndex()]; |
| else |
| return nullptr; |
| } |
| |
| ConcretePin * |
| ConcreteInstance::findPin(const Port *port) const |
| { |
| const ConcretePort *cport = reinterpret_cast<const ConcretePort*>(port); |
| return pins_[cport->pinIndex()]; |
| } |
| |
| ConcreteNet * |
| ConcreteInstance::findNet(const char *net_name) const |
| { |
| ConcreteNet *net = nullptr; |
| if (nets_) { |
| net = nets_->findKey(net_name); |
| // Follow merge pointer to surviving net. |
| if (net) { |
| while (net->mergedInto()) |
| net = net->mergedInto(); |
| } |
| } |
| return net; |
| } |
| |
| void |
| ConcreteInstance::findNetsMatching(const PatternMatch *pattern, |
| NetSeq *nets) const |
| { |
| if (pattern->hasWildcards()) { |
| ConcreteInstanceNetMap::Iterator net_iter(nets_); |
| while (net_iter.hasNext()) { |
| const char *net_name; |
| ConcreteNet *cnet; |
| net_iter.next(net_name, cnet); |
| if (pattern->match(net_name)) |
| nets->push_back(reinterpret_cast<Net*>(cnet)); |
| } |
| } |
| else { |
| ConcreteNet *cnet = findNet(pattern->pattern()); |
| if (cnet) |
| nets->push_back(reinterpret_cast<Net*>(cnet)); |
| } |
| } |
| |
| InstanceNetIterator * |
| ConcreteInstance::netIterator() const |
| { |
| return reinterpret_cast<InstanceNetIterator*> |
| (new ConcreteInstanceNetIterator(nets_)); |
| } |
| |
| InstanceChildIterator * |
| ConcreteInstance::childIterator() const |
| { |
| return new ConcreteInstanceChildIterator(children_); |
| } |
| |
| void |
| ConcreteInstance::addChild(ConcreteInstance *child) |
| { |
| if (children_ == nullptr) |
| children_ = new ConcreteInstanceChildMap; |
| (*children_)[child->name()] = child; |
| } |
| |
| void |
| ConcreteInstance::deleteChild(ConcreteInstance *child) |
| { |
| children_->erase(child->name()); |
| } |
| |
| void |
| ConcreteInstance::addPin(ConcretePin *pin) |
| { |
| ConcretePort *cport = reinterpret_cast<ConcretePort *>(pin->port()); |
| pins_[cport->pinIndex()] = pin; |
| } |
| |
| void |
| ConcreteInstance::deletePin(ConcretePin *pin) |
| { |
| ConcretePort *cport = reinterpret_cast<ConcretePort *>(pin->port()); |
| pins_[cport->pinIndex()] = nullptr; |
| } |
| |
| void |
| ConcreteInstance::addNet(ConcreteNet *net) |
| { |
| if (nets_ == nullptr) |
| nets_ = new ConcreteInstanceNetMap; |
| (*nets_)[net->name()] = net; |
| } |
| |
| void |
| ConcreteInstance::addNet(const char *name, |
| ConcreteNet *net) |
| { |
| if (nets_ == nullptr) |
| nets_ = new ConcreteInstanceNetMap; |
| (*nets_)[name] = net; |
| } |
| |
| void |
| ConcreteInstance::deleteNet(ConcreteNet *net) |
| { |
| nets_->erase(net->name()); |
| } |
| |
| void |
| ConcreteInstance::setCell(ConcreteCell *cell) |
| { |
| cell_ = cell; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| ConcretePin::ConcretePin(ConcreteInstance *instance, |
| ConcretePort *port, |
| ConcreteNet *net) : |
| instance_(instance), |
| port_(port), |
| net_(net), |
| term_(nullptr), |
| net_next_(nullptr), |
| net_prev_(nullptr), |
| vertex_id_(vertex_id_null) |
| { |
| } |
| |
| const char * |
| ConcretePin::name() const |
| { |
| return port_->name(); |
| } |
| |
| void |
| ConcretePin::setVertexId(VertexId id) |
| { |
| vertex_id_ = id; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| const char * |
| ConcreteTerm::name() const |
| { |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin_); |
| const ConcretePort *cport = |
| reinterpret_cast<const ConcretePort*>(cpin->port()); |
| return cport->name(); |
| } |
| |
| ConcreteTerm::ConcreteTerm(ConcretePin *pin, |
| ConcreteNet *net) : |
| pin_(pin), |
| net_(net), |
| net_next_(nullptr) |
| { |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| ConcreteNet::ConcreteNet(const char *name, |
| ConcreteInstance *instance) : |
| name_(stringCopy(name)), |
| instance_(instance), |
| pins_(nullptr), |
| terms_(nullptr), |
| merged_into_(nullptr) |
| { |
| } |
| |
| ConcreteNet::~ConcreteNet() |
| { |
| stringDelete(name_); |
| } |
| |
| // Merged nets are kept around to serve as name aliases. |
| // Only Instance::findNet and InstanceNetIterator need to know |
| // the net has been merged. |
| void |
| ConcreteNet::mergeInto(ConcreteNet *net) |
| { |
| ConcreteNetPinIterator pin_iter(this); |
| while (pin_iter.hasNext()) { |
| Pin *pin = pin_iter.next(); |
| ConcretePin *cpin = reinterpret_cast<ConcretePin*>(pin); |
| net->addPin(cpin); |
| cpin->net_ = net; |
| } |
| pins_ = nullptr; |
| ConcreteNetTermIterator term_iter(this); |
| while (term_iter.hasNext()) { |
| Term *term = term_iter.next(); |
| ConcreteTerm *cterm = reinterpret_cast<ConcreteTerm*>(term); |
| net->addTerm(cterm); |
| cterm->net_ = net; |
| } |
| terms_ = nullptr; |
| // Leave name map pointing to merged net because otherwise a top |
| // level merged net has no pointer to it and it is leaked. |
| merged_into_ = net; |
| } |
| |
| void |
| ConcreteNet::addPin(ConcretePin *pin) |
| { |
| if (pins_) |
| pins_->net_prev_ = pin; |
| pin->net_next_ = pins_; |
| pin->net_prev_ = nullptr; |
| pins_ = pin; |
| } |
| |
| void |
| ConcreteNet::deletePin(ConcretePin *pin) |
| { |
| ConcretePin *prev = pin->net_prev_; |
| ConcretePin *next = pin->net_next_; |
| if (prev) |
| prev->net_next_ = next; |
| if (next) |
| next->net_prev_ = prev; |
| if (pins_ == pin) |
| pins_ = next; |
| } |
| |
| void |
| ConcreteNet::addTerm(ConcreteTerm *term) |
| { |
| ConcreteTerm *next = terms_; |
| terms_ = term; |
| term->net_next_ = next; |
| } |
| |
| void |
| ConcreteNet::deleteTerm(ConcreteTerm *term) |
| { |
| ConcreteTerm *net_prev_term = nullptr; |
| for (ConcreteTerm *net_term=terms_;net_term;net_term=net_term->net_next_) { |
| if (net_term == term) { |
| if (net_prev_term) |
| net_prev_term->net_next_ = term->net_next_; |
| else |
| terms_ = term->net_next_; |
| break; |
| } |
| net_prev_term = net_term; |
| } |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| typedef Map<Net*, Net*> BindingMap; |
| |
| // Binding table used for linking/expanding network. |
| class ConcreteBindingTbl |
| { |
| public: |
| explicit ConcreteBindingTbl(NetworkEdit *network); |
| Net *ensureBinding(Net *proto_net, |
| Instance *parent); |
| Net *find(Net *net); |
| void bind(Net *proto_net, |
| Net *clone_net); |
| |
| private: |
| DISALLOW_COPY_AND_ASSIGN(ConcreteBindingTbl); |
| |
| BindingMap map_; |
| NetworkEdit *network_; |
| }; |
| |
| void |
| ConcreteNetwork::setCellNetworkView(Cell *cell, |
| Instance *inst) |
| { |
| cell_network_view_map_[cell] = inst; |
| } |
| |
| Instance * |
| ConcreteNetwork::cellNetworkView(Cell *cell) |
| { |
| return cell_network_view_map_.findKey(cell); |
| } |
| |
| void |
| ConcreteNetwork::readNetlistBefore() |
| { |
| clearConstantNets(); |
| deleteTopInstance(); |
| clearNetDrvrPinMap(); |
| } |
| |
| void |
| ConcreteNetwork::setTopInstance(Instance *top_inst) |
| { |
| if (top_instance_) { |
| deleteInstance(top_instance_); |
| clearConstantNets(); |
| clearNetDrvrPinMap(); |
| } |
| top_instance_ = top_inst; |
| } |
| |
| void |
| ConcreteNetwork::setLinkFunc(LinkNetworkFunc *link) |
| { |
| link_func_ = link; |
| } |
| |
| bool |
| ConcreteNetwork::linkNetwork(const char *top_cell_name, |
| bool make_black_boxes, |
| Report *report) |
| { |
| if (link_func_) { |
| clearConstantNets(); |
| deleteTopInstance(); |
| top_instance_ = link_func_(top_cell_name, make_black_boxes, report, this); |
| return top_instance_ != nullptr; |
| } |
| else { |
| report->error(8, "cell type %s can not be linked.", top_cell_name); |
| return false; |
| } |
| } |
| |
| Instance * |
| linkReaderNetwork(Cell *top_cell, |
| bool, Report *, |
| NetworkReader *network) |
| { |
| Instance *view = network->cellNetworkView(top_cell); |
| if (view) { |
| // Seed the recursion for expansion with the top level instance. |
| Instance *top_instance = network->makeInstance(top_cell, "", nullptr); |
| ConcreteBindingTbl bindings(network); |
| makeClonePins(view, top_instance, view, &bindings, nullptr, nullptr, network); |
| InstanceChildIterator *child_iter = network->childIterator(view); |
| while (child_iter->hasNext()) { |
| Instance *child = child_iter->next(); |
| makeChildNetwork(child, top_instance, &bindings, network); |
| } |
| delete child_iter; |
| network->deleteCellNetworkViews(); |
| return top_instance; |
| } |
| return nullptr; |
| } |
| |
| static void |
| makeChildNetwork(Instance *proto, |
| Instance *parent, |
| ConcreteBindingTbl *parent_bindings, |
| NetworkReader *network) |
| { |
| Cell *proto_cell = network->cell(proto); |
| Instance *clone = network->makeInstance(proto_cell, network->name(proto), |
| parent); |
| if (network->isLeaf(proto_cell)) |
| makeClonePins(proto, clone, nullptr, nullptr, parent, parent_bindings, network); |
| else { |
| // Recurse if this isn't a leaf cell. |
| ConcreteBindingTbl bindings(network); |
| Instance *clone_view = network->cellNetworkView(proto_cell); |
| makeClonePins(proto, clone, clone_view, &bindings, parent, |
| parent_bindings, network); |
| if (clone_view) { |
| InstanceChildIterator *child_iter = network->childIterator(clone_view); |
| while (child_iter->hasNext()) { |
| Instance *child = child_iter->next(); |
| makeChildNetwork(child, clone, &bindings, network); |
| } |
| delete child_iter; |
| } |
| } |
| } |
| |
| static void |
| makeClonePins(Instance *proto, |
| Instance *clone, |
| Instance *clone_view, |
| ConcreteBindingTbl *bindings, |
| Instance *parent, |
| ConcreteBindingTbl *parent_bindings, |
| NetworkReader *network) |
| { |
| InstancePinIterator *proto_pin_iter = network->pinIterator(proto); |
| while (proto_pin_iter->hasNext()) { |
| Pin *proto_pin = proto_pin_iter->next(); |
| Net *proto_net = network->net(proto_pin); |
| Port *proto_port = network->port(proto_pin); |
| Net *clone_net = nullptr; |
| if (proto_net && parent_bindings) |
| clone_net = parent_bindings->ensureBinding(proto_net, parent); |
| Pin *clone_pin = network->connect(clone, proto_port, clone_net); |
| if (clone_view) { |
| Pin *clone_proto_pin = network->findPin(clone_view, proto_port); |
| Net *clone_proto_net = network->net(clone_proto_pin); |
| Net *clone_child_net = nullptr; |
| if (clone_proto_net) |
| clone_child_net = bindings->ensureBinding(clone_proto_net, clone); |
| network->makeTerm(clone_pin, clone_child_net); |
| } |
| } |
| delete proto_pin_iter; |
| } |
| |
| //////////////////////////////////////////////////////////////// |
| |
| ConcreteBindingTbl::ConcreteBindingTbl(NetworkEdit *network) : |
| network_(network) |
| { |
| } |
| |
| // Follow the merged_into pointers rather than update the |
| // binding tables up the call tree when nodes are merged |
| // because the name changes up the hierarchy. |
| Net * |
| ConcreteBindingTbl::find(Net *proto_net) |
| { |
| ConcreteNet *net = reinterpret_cast<ConcreteNet*>(map_.findKey(proto_net)); |
| while (net && net->mergedInto()) |
| net = net->mergedInto(); |
| return reinterpret_cast<Net*>(net); |
| } |
| |
| void |
| ConcreteBindingTbl::bind(Net *proto_net, |
| Net *net) |
| { |
| map_[proto_net] = net; |
| } |
| |
| Net * |
| ConcreteBindingTbl::ensureBinding(Net *proto_net, |
| Instance *parent) |
| { |
| Net *net = find(proto_net); |
| if (net == nullptr) { |
| net = network_->makeNet(network_->name(proto_net), parent); |
| map_[proto_net] = net; |
| } |
| return net; |
| } |
| |
| } // namespace |