// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2021-2021, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | A n a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./AntennaProtect.cpp" | // +-----------------------------------------------------------------+ #include #include #include #include "hurricane/Bug.h" #include "hurricane/Warning.h" #include "hurricane/DebugSession.h" #include "hurricane/Breakpoint.h" #include "hurricane/Net.h" #include "hurricane/NetExternalComponents.h" #include "hurricane/NetRoutingProperty.h" #include "hurricane/Layer.h" #include "hurricane/RoutingPad.h" #include "hurricane/Pad.h" #include "hurricane/Plug.h" #include "hurricane/Instance.h" #include "hurricane/Vertical.h" #include "hurricane/Horizontal.h" #include "hurricane/Cell.h" #include "crlcore/RoutingGauge.h" #include "etesian/EtesianEngine.h" #include "anabatic/AutoContactTerminal.h" #include "anabatic/AutoSegment.h" #include "anabatic/AnabaticEngine.h" namespace { using namespace std; using namespace CRL; using namespace Hurricane; using namespace Anabatic; using Etesian::EtesianEngine; class CompareByLength { public: inline bool operator() ( const Segment* lhs, const Segment* rhs ) const { DbU::Unit delta = lhs->getLength() - rhs->getLength(); if (delta < 0) return false; if (delta > 0) return true; return lhs->getId() < rhs->getId(); } }; class CompareBySegmentBox { public: inline bool operator() ( const Box& lhs, const Box& rhs ) const { bool lhsH = (lhs.getWidth() >= lhs.getHeight()); bool rhsH = (rhs.getWidth() >= rhs.getHeight()); if (lhsH xor rhsH) return lhsH; DbU::Unit lhsLength = (lhsH) ? lhs.getWidth() : lhs.getHeight(); DbU::Unit rhsLength = (rhsH) ? rhs.getWidth() : rhs.getHeight(); return lhsLength > rhsLength; } }; typedef tuple RPInfosItem; class CompareRPInfos { public: inline bool operator () ( const RPInfosItem& lhs, const RPInfosItem& rhs ) const; }; inline bool CompareRPInfos::operator () ( const RPInfosItem& lhs, const RPInfosItem& rhs ) const { return std::get<0>(lhs)->getId() < std::get<0>(rhs)->getId(); } typedef tuple GCellInfosItem; inline const uint32_t& elemFlags ( const GCellInfosItem& item ) { return std::get<1>(item); } inline uint32_t& elemFlags ( GCellInfosItem& item ) { return std::get<1>(item); } inline GCell* elemGCell ( const GCellInfosItem& item ) { return std::get<0>(item); } class CompareGCellInfos { public: inline bool operator () ( const GCellInfosItem& lhs, const GCellInfosItem& rhs ) const; }; inline bool CompareGCellInfos::operator () ( const GCellInfosItem& lhs, const GCellInfosItem& rhs ) const { if (std::get<1>(lhs) != std::get<1>(rhs)) return std::get<1>(lhs) < std::get<1>(rhs); return std::get<0>(lhs)->getId() < std::get<0>(rhs)->getId(); } typedef set RoutingPadInfos; typedef set GCellArea; inline DbU::Unit getBoxLength ( const Box& bb ) { return (bb.getWidth() > bb.getHeight()) ? bb.getWidth() : bb.getHeight(); } // ----------------------------------------------------------------- // Class : "::DiodeCluster". class DiodeCluster { public: static const uint32_t IsDriver; static const uint32_t IsSink; static const uint32_t HasDiode; static const uint32_t IsSegSource; static const uint32_t InCluster; static string toStr ( uint32_t ); public: template inline const DerivedT* as () const { return dynamic_cast( this ); } template inline DerivedT* as () { return dynamic_cast( this ); } public: DiodeCluster ( AnabaticEngine*, RoutingPad* ); virtual ~DiodeCluster (); DbU::Unit getAntennaGateMaxWL () const; DbU::Unit getAntennaDiodeMaxWL () const; inline bool hasRp ( RoutingPad* ) const; bool hasGCell ( GCell* ) const; inline Net* getTopNet () const; inline RoutingPad* getRefRp () const; inline vector& _getAreas (); inline AnabaticEngine* _getAnabatic () const; inline const RoutingPadInfos& getRoutingPads () const; inline RoutingPadInfos& _getRoutingPads () ; inline const set& getNeighbors () const; inline const vector& getDiodes () const; inline vector& _getDiodes (); inline uint32_t getForcedDiodes () const; inline DbU::Unit getWL () const; inline DbU::Unit& _getWL (); void showArea () const; virtual bool needsDiode () const = 0; Box getBoundingBox () const; inline void addNeighbor ( size_t ); inline void addForcedDiodes ( uint32_t ); void merge ( GCell*, uint32_t distance, GCell* back=NULL ); virtual void merge ( RoutingPad* ); virtual void merge ( Segment* ) = 0; void mergeForcedHalo ( size_t iarea, GCell*, uint32_t distance ); virtual void mergeHalo ( Segment*, uint32_t flags ); virtual void inflateArea (); Instance* _createDiode ( Etesian::Area*, const Box&, DbU::Unit uHint ); Instance* _createDiode ( Etesian::Area*, GCell*, GCell* ); virtual const vector& createDiodes ( Etesian::Area* ); bool connectDiodes (); private: AnabaticEngine* _anabatic; DbU::Unit _WL; RoutingPadInfos _routingPads; vector _areas; vector _diodes; set _neighbors; uint32_t _forcedDiodes; }; const uint32_t DiodeCluster::IsDriver = (1 << 0); const uint32_t DiodeCluster::IsSink = (1 << 1); const uint32_t DiodeCluster::HasDiode = (1 << 2); const uint32_t DiodeCluster::IsSegSource = (1 << 3); const uint32_t DiodeCluster::InCluster = (1 << 4); string DiodeCluster::toStr ( uint32_t flags ) { string s; s += (flags & IsDriver ) ? 'd' : '-'; s += (flags & IsSink ) ? 's' : '-'; s += (flags & HasDiode ) ? 'D' : '-'; s += (flags & IsSegSource) ? 'S' : '-'; s += (flags & InCluster ) ? 'C' : '-'; return s; } DiodeCluster::DiodeCluster ( AnabaticEngine* anabatic, RoutingPad* rp ) : _anabatic(anabatic) , _WL(0) , _routingPads() , _areas(1) , _diodes() , _neighbors() , _forcedDiodes(0) { merge( rp ); } DiodeCluster::~DiodeCluster () { } inline AnabaticEngine* DiodeCluster::_getAnabatic () const { return _anabatic; } inline vector& DiodeCluster::_getAreas () { return _areas; } inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); } inline DbU::Unit DiodeCluster::getWL () const { return _WL; } inline DbU::Unit& DiodeCluster::_getWL () { return _WL; } inline const RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; } inline RoutingPadInfos& DiodeCluster::_getRoutingPads () { return _routingPads; } inline const vector& DiodeCluster::getDiodes () const { return _diodes; } inline vector& DiodeCluster::_getDiodes () { return _diodes; } inline const set& DiodeCluster::getNeighbors () const { return _neighbors; } inline void DiodeCluster::addNeighbor ( size_t neighbor ) { _neighbors.insert(neighbor); } inline uint32_t DiodeCluster::getForcedDiodes () const { return _forcedDiodes; } inline void DiodeCluster::addForcedDiodes ( uint32_t count ) { _forcedDiodes += count; } DbU::Unit DiodeCluster::getAntennaGateMaxWL () const { EtesianEngine* etesian = static_cast ( ToolEngine::get( _getAnabatic()->getCell(), EtesianEngine::staticGetName() )); return etesian->getAntennaGateMaxWL(); } DbU::Unit DiodeCluster::getAntennaDiodeMaxWL () const { EtesianEngine* etesian = static_cast ( ToolEngine::get( _getAnabatic()->getCell(), EtesianEngine::staticGetName() )); return etesian->getAntennaDiodeMaxWL(); } inline bool DiodeCluster::hasRp ( RoutingPad* rp ) const { return (_routingPads.find(make_tuple(rp,0)) != _routingPads.end()); } inline bool DiodeCluster::hasGCell ( GCell* gcell ) const { if (not gcell) return false; for ( auto& item : _areas[0] ) { if (elemGCell(item) == gcell) return true; } return false; } inline RoutingPad* DiodeCluster::getRefRp () const { if (not _routingPads.empty()) return std::get<0>( *_routingPads.begin() ); return NULL; } void DiodeCluster::showArea () const { cdebug_log(147,1) << "GCell diode areas:" << endl; for ( size_t i=0 ; i<_areas.size() ; ++i ) { cdebug_log(147,0) << "GCell diode area [" << i << "]" << endl; for ( auto& item : _areas[i] ) { cdebug_log(147,0) << " | d=" << std::get<1>(item) << " " << std::get<0>(item) << " back=" << std::get<2>(item) << endl; } } cdebug_tabw(147,-1); } void DiodeCluster::merge ( RoutingPad* rp ) { Plug* rpPlug = dynamic_cast( rp->getPlugOccurrence().getEntity() ); if (rpPlug) { DiodeCluster::merge( _getAnabatic()->getGCellUnder( rp->getPosition() ), 0 ); if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) { cdebug_log(147,0) << "| Sink " << rp << endl; _getRoutingPads().insert( make_tuple(rp,IsSink) ); } else { _getRoutingPads().insert( make_tuple(rp,IsDriver) ); cdebug_log(147,0) << "| Driver " << rp << endl; } } else { Pin* rpPin = dynamic_cast( rp->getPlugOccurrence().getEntity() ); if (rpPin) { _getRoutingPads().insert( make_tuple(rp,IsDriver) ); cdebug_log(147,0) << "| Pin (considered driver) " << rp << endl; } } } void DiodeCluster::merge ( GCell* gcell, uint32_t distance, GCell* back ) { if (not gcell) return; if (hasGCell(gcell)) return; if (back) distance += 20; _areas[0].insert( make_tuple(gcell,distance,back) ); } void DiodeCluster::mergeForcedHalo ( size_t iarea, GCell* gcell, uint32_t distance ) { if (not gcell) return; while ( iarea >= _areas.size() ) _areas.push_back( GCellArea() ); _areas[iarea].insert( make_tuple(gcell,distance,(GCell*)NULL) ); } Box DiodeCluster::getBoundingBox () const { Box bb; for ( auto& item : _areas[0] ) bb.merge( elemGCell(item)->getBoundingBox() ); return bb; } void DiodeCluster::mergeHalo ( Segment* segment, uint32_t flags ) { cerr << Error( "DiodeCluster::mergeHalo(Segment*): Unimplemented (%s). " , getString(segment).c_str() ) << endl; } void DiodeCluster::inflateArea () { cerr << Error( "DiodeCluster::inflateArea(): Unimplemented. " ) << endl; } Instance* DiodeCluster::_createDiode ( Etesian::Area* area, const Box& bb, DbU::Unit uHint ) { cdebug_log(147,1) << "DiodeCluster::_createDiode(): under=" << bb << " uHint=" << DbU::getValueString(uHint) << endl; Instance* diode = area->createDiodeUnder( getRefRp(), bb, uHint ); if (diode) { cdebug_log(147,0) << "| New diode " << diode << endl; _diodes.push_back( diode ); GCell* gcell = _anabatic->getGCellUnder( diode->getAbutmentBox().getCenter() ); Contact* contact = gcell->hasGContact( getTopNet() ); if (not contact) contact = gcell->breakGoThrough( getTopNet() ); cdebug_log(147,0) << "| breakGoThrough(), contact= " << contact << endl; } cdebug_tabw(147,-1); return diode; } Instance* DiodeCluster::_createDiode ( Etesian::Area* area, GCell* gcell, GCell* backGCell ) { cdebug_log(147,1) << "DiodeCluster::_createDiode(): under=" << gcell << endl; Box bb = gcell->getBoundingBox(); cdebug_log(147,0) << "> GCell area: " << bb << endl; Instance* diode = area->createDiodeUnder( getRefRp(), bb, 0 ); if (diode) { cdebug_log(147,0) << "| New diode " << diode << endl; _diodes.push_back( diode ); Transformation trans = getRefRp()->getPlugOccurrence().getPath().getTransformation(); Point center = diode->getAbutmentBox().getCenter(); trans.applyOn( center ); bool newContact = false; Contact* contact = gcell->hasGContact( getTopNet() ); if (not contact) { newContact = true; contact = gcell->breakGoThrough( getTopNet() ); } cdebug_log(147,0) << "| breakGoThrough(), contact= " << contact << endl; if (backGCell and newContact) { Contact* backContact = backGCell->breakGoThrough( getTopNet() ); if (backContact->getY() == contact->getY()) { if (contact->getX() > backContact->getX()) std::swap( backContact, contact ); Horizontal::create( contact , backContact , _anabatic->getConfiguration()->getGHorizontalLayer() , contact->getY() , _anabatic->getConfiguration()->getGHorizontalPitch() ); } else { if (backContact->getX() == contact->getX()) { if (contact->getY() > backContact->getY()) std::swap( backContact, contact ); Vertical::create( contact , backContact , _anabatic->getConfiguration()->getGHorizontalLayer() , contact->getX() , _anabatic->getConfiguration()->getGHorizontalPitch() ); } else { cerr << Error( "DiodeCluster::_createDiode(): Back GCell not aligned with diode GCell.\n" " * %s\n" " * %s" , getString(gcell).c_str() , getString(backGCell).c_str() ) << endl; } } } } cdebug_tabw(147,-1); return diode; } const vector& DiodeCluster::createDiodes ( Etesian::Area* area ) { if (not needsDiode()) return _diodes; DbU::Unit antennaDiodeMaxWL = getAntennaDiodeMaxWL(); size_t diodeCount = getWL() / antennaDiodeMaxWL; if (not diodeCount) diodeCount = 1; showArea(); cdebug_log(147,1) << "DiodeCluster::createDiodes() count=" << diodeCount << ", forcedHalo=" << (_areas.size()-1) << endl; Instance* diode = NULL; //for ( size_t i=(_areas.size() == 1)?0:1 ; i<_areas.size() ; ++i ) { for ( size_t i=0 ; i<_areas.size() ; ++i ) { if (i) diodeCount = 1; cdebug_log(147,0) << "Diode for area [" << i << "]" << endl; for ( auto& item : _areas[i] ) { GCell* gcell = std::get<0>( item ); GCell* backGCell = std::get<2>( item ); cdebug_log(147,0) << "| d=" << std::get<1>(item) << " " << gcell << endl; diode = _createDiode( area, gcell, backGCell ); if (diode) { if (_diodes.size() < diodeCount) { diode = NULL; continue; } break; } } } cdebug_tabw(147,-1); return _diodes; } bool DiodeCluster::connectDiodes () { EtesianEngine* etesian = static_cast ( ToolEngine::get( _anabatic->getCell(), EtesianEngine::staticGetName() )); Cell* diodeCell = etesian->getDiodeCell(); Net* diodeOutput = NULL; for ( Net* net : diodeCell->getNets() ) { if (net->isSupply() or not net->isExternal()) continue; diodeOutput = net; break; } Net* topNet = getTopNet(); Net* diodeNet = topNet; Plug* sinkPlug = dynamic_cast( getRefRp()->getPlugOccurrence().getEntity() ); Path path = Path(); if (sinkPlug) { diodeNet = sinkPlug->getNet(); path = getRefRp()->getOccurrence().getPath().getHeadPath(); } for ( Instance* diode : _diodes ) { cdebug_log(147,0) << " Bind diode input:" << endl; cdebug_log(147,0) << " " << diode << " @" << diode->getTransformation() << endl; cdebug_log(147,0) << " topNet->getCell():" << topNet->getCell() << endl; cdebug_log(147,0) << " " << getRefRp()->getOccurrence().getPath() << endl; Plug* diodePlug = diode->getPlug( diodeOutput ); diodePlug->setNet( diodeNet ); RoutingPad* diodeRp = RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea ); cdebug_log(147,0) << " " << getRefRp() << endl; GCell* gcell = _anabatic->getGCellUnder( diodeRp->getPosition() ); if (gcell) { Contact* contact = gcell->breakGoThrough( topNet ); contact->getBodyHook()->merge( diodeRp->getBodyHook() ); } } return true; } // ----------------------------------------------------------------- // Class : "::DiodeRps". class DiodeRps : public DiodeCluster { public: DiodeRps ( AnabaticEngine*, RoutingPad* ); virtual bool needsDiode () const; virtual void merge ( Segment* ); virtual void mergeHalo ( Segment*, uint32_t flags ); virtual void inflateArea (); }; DiodeRps::DiodeRps ( AnabaticEngine* anabatic, RoutingPad* rp ) : DiodeCluster(anabatic,rp) { } bool DiodeRps::needsDiode () const { if (getForcedDiodes()) return true; for ( auto& infos : getRoutingPads() ) { if (std::get<1>(infos) & IsSink) return true; } return false; } void DiodeRps::merge ( Segment* segment ) { _getWL() += segment->getLength(); GCellsUnder gcells = _getAnabatic()->getGCellsUnder( segment ); if (not gcells->empty()) { for ( size_t i=0 ; isize() ; ++i ) { DiodeCluster::merge( gcells->gcellAt(i), 0 ); } } } void DiodeRps::mergeHalo ( Segment* segment, uint32_t flags ) { cdebug_log(147,0) << "DiodeRps::mergeHalo(): " << segment << endl; if (not segment) return; // if ( (dynamic_cast(segment)) // and (getWL() + segment->getLength() > getAntennaGateMaxWL())) { if (dynamic_cast(segment)) { cdebug_log(147,0) << " Put in forced halo." << segment << endl; GCellsUnder gcells = _getAnabatic()->getGCellsUnder( segment ); if (not gcells->empty()) { size_t iarea = _getAreas().size(); size_t count = std::min( gcells->size(), (size_t)50 ); for ( size_t i=0 ; isize()-1-i); DiodeCluster::mergeForcedHalo( iarea, gcells->gcellAt(igcell), i ); } } return; } GCellsUnder gcells = _getAnabatic()->getGCellsUnder( segment ); if (not gcells->empty()) { size_t count = std::min( gcells->size(), (size_t)10 ); for ( size_t i=0 ; isize()-1-i); DiodeCluster::merge( gcells->gcellAt(igcell), i+1 ); } } } void DiodeRps::inflateArea () { vector< tuple > border; for ( auto& item : _getAreas()[0] ) { GCell* current = std::get<0>( item ); if (std::get<2>(item)) continue; GCell* neighbor = current->getEast(); if (neighbor and not neighbor->hasNet(getTopNet())) border.push_back( make_tuple(neighbor,current) ); neighbor = current->getWest(); if (neighbor and not neighbor->hasNet(getTopNet())) border.push_back( make_tuple(neighbor,current) ); } for ( auto& item : _getAreas()[0] ) { GCell* current = std::get<0>( item ); if (std::get<2>(item)) continue; GCell* neighbor = current->getNorth(); if (neighbor and not neighbor->hasNet(getTopNet())) border.push_back( make_tuple(neighbor,current) ); neighbor = current->getSouth(); if (neighbor and not neighbor->hasNet(getTopNet())) border.push_back( make_tuple(neighbor,current) ); } for ( auto& item : border ) { DiodeCluster::merge( std::get<0>(item), 1, std::get<1>(item) ); } } // ----------------------------------------------------------------- // Class : "::DiodeWire". class DiodeWire : public DiodeCluster { public: DiodeWire ( AnabaticEngine*, RoutingPad* ); virtual bool needsDiode () const; virtual void merge ( Segment* ); virtual const vector& createDiodes ( Etesian::Area* ); inline const set& getSegments () const; private: set _boxes; set _contacts; set _segments; }; inline const set& DiodeWire::getSegments () const { return _segments; } DiodeWire::DiodeWire ( AnabaticEngine* anabatic, RoutingPad* rp ) : DiodeCluster(anabatic,rp) , _boxes() , _contacts() , _segments() { } bool DiodeWire::needsDiode () const { return getWL() >= getAntennaDiodeMaxWL(); } void DiodeWire::merge ( Segment* segment ) { if (_segments.find(segment) != _segments.end()) return; Box bb = segment->getBoundingBox(); cdebug_log(147,0) << "| merge: " << segment << endl; _segments.insert( segment ); _boxes.insert( bb ); _getWL() += segment->getLength(); } const vector& DiodeWire::createDiodes ( Etesian::Area* area ) { cdebug_log(147,1) << "DiodeWire::createDiodes() on " << _boxes.size() << " boxes." << endl; ostringstream m; m << "Neighbors: ["; for ( size_t neighbor : getNeighbors() ) { m << " " << neighbor; } m << " ]"; cdebug_log(147,0) << m.str() << endl; DbU::Unit antennaDiodeMaxWL = getAntennaDiodeMaxWL(); size_t diodeCount = getWL() / antennaDiodeMaxWL; if (not diodeCount) return _getDiodes(); for ( const Box& bb : _boxes ) { bool bbH = (bb.getWidth() >= bb.getHeight()); DbU::Unit bbLength = (bbH) ? bb.getWidth() : bb.getHeight(); size_t segDiodeCount = bbLength / antennaDiodeMaxWL; if (not segDiodeCount) ++segDiodeCount; bool isH = (bb.getWidth() >= bb.getHeight()); cdebug_log(147,0) << "Processing wire diodes=" << segDiodeCount << " " << bb << " isH=" << isH << " length:" << DbU::getValueString(getBoxLength(bb)) << endl; //if (bbLength < antennaDiodeMaxWL/4) continue; if (bbH) { DbU::Unit uHint = bb.getXMin(); DbU::Unit uMax = bb.getXMax(); while ( uHint < uMax ) { _createDiode( area, bb, uHint ); uHint += antennaDiodeMaxWL; } } else { GCellsUnder gcells = _getAnabatic()->getGCellsUnder( Point(bb.getXCenter(),bb.getYMin()) , Point(bb.getXCenter(),bb.getYMax()) ); if (gcells->size()) { size_t gcellPeriod = antennaDiodeMaxWL / gcells->gcellAt(0)->getHeight(); for ( size_t i=0 ; isize() ; ++i ) { Instance* diode = _createDiode( area, gcells->gcellAt(i), NULL ); if (diode) { i += gcellPeriod - (i%gcellPeriod); } } } } if (_getDiodes().size() >= diodeCount) { cdebug_log(147,0) << "Added enough diodes " << _getDiodes().size() << endl; break; } } if (_getDiodes().size() < diodeCount) { cerr << Error( "DiodeWire::createDiode(): On cluster of net \"%s\",\n" " Allocated only %u diodes of %u." , getString(getTopNet()->getName()).c_str() , _getDiodes().size() , diodeCount ) << endl; } cdebug_tabw(147,-1); return _getDiodes(); } // ----------------------------------------------------------------- // Local functions. } // Anonymous namespace. namespace Anabatic { using namespace Hurricane; using CRL::ToolEngine; using Etesian::EtesianEngine; //! \function AnabaticEngine::antennaProtect( Net* net, uint32_t& failed, uint32_t& total ); //! \param net The net to protect against antenna effects. //! \param failed A reference to the global counter of diodes that we //! where unsucessful to allocate. //! \param total The total number of diode that where requesteds. //! counting both successful and unsuccessful allocations. //! //! \section antennaSettings Configuration Variable for Antenna Effect //! //!
//! //!
\c etesian.antennaMaxWL //! The maximum wirelength whitout a diode effect //!
//!
//! //! //! \section antennaAlgo A Brief Description of the Antenna Protection Algorithm. //! //! The brute force approach would be to put a diode near all sink //! points of the net. To reduce that number, we create clusters whose //! total wirelength is less than the one triggering an antenna effect. //! //! The antenna protection stage is called after the global routing //! and before the detailed routing. The computed wirelength will be //! slightly inaccurate but it allow us to directly amend the global //! routing so the detailed router needs no modification. //! //! To build the clusters: //! //!
    //!
  1. Select an unreached (not part of a cluster) RoutingPad.
  2. //!
  3. Perform a depth-first search (DFS) using the segments as edges //! and the Hook rings as nodes. Use a stack to store the search //! state. An element of the stack is a \c tuple of //! \c(Hook*,Segment*,size_t,uint32_t) : //! //!
      //!
    1. \c Hook* : the hook of the Segment we are coming \e from.
    2. //!
    3. \c Segment* : the segment we are to process.
    4. //!
    5. \c size_t : the index, in the stack, of the predecessor //! segment.
    6. //!
    7. \c uint32_t : flags. If this segment is \b already part //! of the cluster. //!
    //! //! All the elements are kept in the stack until the cluster is //! completed. The current top of the stack is given by the \c stackTop //! index. //! //! When exploring a new node (ring of Hook), all the adjacent segments //! are put on top of the stack. Their suitablility is assesssed only //! when they are popped up. //!
  4. //!
  5. When looking at a new stack element (incrementing \c stackTop, not //! really popping up): //! //!
      //!
    1. If the segment length is greater than half the maximum antenna //! wirelength, skip it (assume it connects two clusters).
    2. //!
    3. If the segment length, added to the cluster total length, //! is greater than the antenna length, skip it. //!
    4. If the segment is connected to another RoutingPad, agglomerate //! this one the the cluster and merge the segment and all it's //! predecessors to the cluster. Using the back index and setting //! the DiodeCluster::InCluster flags. //!
    //!
  6. //!
  7. When we reach the end of the stack, close the cluster and build //! it's halo. Go through each elements of the stack again and look //! for segments not part of it, but directly connected to it //! (that is, they have not the InCluster flags set, but their //! immediate predecessor has). //!
  8. //!
//! //! Structure of a Cluster: //! //!
    //!
  1. A vector of RoutingPad.
  2. //!
  3. A set of GCells, ordered by priority (distance). //!
      //!
    1. A distance of zero means we are under the Segments belonging //! to the cluster itself (directly connecting the RoutingPad). //!
    2. //!
    3. A distance between 1 to 9 means we are under the halo, that //! is, Segments that connects to the cluster, with the //! increasing distance. //!
    4. //!
    5. A distance between 10 to 19 means a GCell which is an //! immediate neighbor of the core or halo segments. //!
    6. //!
    //!
  4. //!
//! //! We try to create the cluster's diode in the GCell of the lowest distance //! possible. void AnabaticEngine::antennaProtect ( Net* net, uint32_t& failed, uint32_t& total ) { // tuple is: Hook (S or T), From segment, back segment index, flags. typedef tuple StackItem; DebugSession::open( net, 145, 150 ); cdebug_log(147,1) << "Net \"" << net->getName() << endl; EtesianEngine* etesian = static_cast ( ToolEngine::get( getCell(), EtesianEngine::staticGetName() )); DbU::Unit antennaGateMaxWL = etesian->getAntennaGateMaxWL(); vector clusters; map rpsDone; map clusterSegments; for ( RoutingPad* rp : net->getRoutingPads() ) { set segmentsDone; if (rpsDone.find(rp) != rpsDone.end()) continue; cdebug_log(147,0) << "New Cluster [" << clusters.size() << "] from " << rp << endl; DiodeCluster* cluster = new DiodeRps ( this, rp ); clusters.push_back( cluster ); rpsDone.insert( make_pair( rp, clusters.size()-1 ) ); size_t stackTop = 0; vector< StackItem > hooksStack; hooksStack.push_back( make_tuple( rp->getBodyHook() , (Segment*)NULL , 0 , DiodeCluster::InCluster ) ); while ( stackTop < hooksStack.size() ) { Hook* toHook = std::get<0>( hooksStack[stackTop] ); Segment* fromSegment = std::get<1>( hooksStack[stackTop] ); DbU::Unit branchWL = 0; cdebug_log(147,0) << "| PROCESS [" << stackTop << "] " << fromSegment << endl; if (fromSegment) { if (fromSegment->getLength() > antennaGateMaxWL/2) { cdebug_log(147,0) << "| Long connecting wire, skipping" << endl; ++stackTop; continue; } size_t backIndex = stackTop; while ( backIndex ) { Segment* segment = std::get<1>( hooksStack[backIndex] ); branchWL += segment->getLength(); backIndex = std::get<2>( hooksStack[backIndex] ); if (not backIndex) break; if (std::get<3>( hooksStack[backIndex] ) & DiodeCluster::InCluster) break; } } cdebug_log(147,0) << "| wl=" << DbU::getValueString(cluster->getWL()) << " + " << DbU::getValueString(branchWL) << endl; if (cluster->getWL() + branchWL > antennaGateMaxWL) { cdebug_log(147,0) << "| Cluster above maximul WL, skipping" << endl; ++stackTop; continue; } rp = NULL; for ( Hook* hook : toHook->getHooks() ) { RoutingPad* toRp = dynamic_cast( hook->getComponent() ); if (toRp) { if (rpsDone.find(toRp) == rpsDone.end()) { cdebug_log(147,0) << "> Agglomerate " << toRp << endl; cluster->merge( toRp ); rpsDone.insert( make_pair( toRp, clusters.size()-1 ) ); rp = toRp; } } } if (rp) { size_t backIndex = stackTop; cdebug_log(147,1) << "+ Backtrack" << endl; while ( backIndex ) { Segment* segment = std::get<1>( hooksStack[backIndex] ); if (segment->getLength() <= branchWL) branchWL -= segment->getLength(); else branchWL = 0; cluster->merge( segment ); std::get<3>( hooksStack[backIndex] ) |= DiodeCluster::InCluster; clusterSegments.insert( make_pair( segment, clusters.size()-1 ) ); cdebug_log(147,0) << "| back=" << backIndex << " -> " << std::get<2>( hooksStack[backIndex] ) << " " << DbU::getValueString(segment->getLength()) << " " << segment << endl; backIndex = std::get<2>( hooksStack[backIndex] ); if (std::get<3>( hooksStack[backIndex] ) & DiodeCluster::InCluster) { cdebug_log(147,0) << "| stop=" << backIndex << " is part of the cluster" << endl; break; } } cdebug_tabw(147,-1); } for ( Hook* hook : toHook->getHooks() ) { Segment* segment = dynamic_cast( hook->getComponent() ); if (segment) { if (segment == fromSegment) continue; cdebug_log(147,0) << "| progress wl=" << DbU::getValueString(cluster->getWL()) << " + " << DbU::getValueString(branchWL) << " / " << DbU::getValueString(segment->getLength()) << " " << segment << endl; if (segmentsDone.find(segment) != segmentsDone.end()) continue; segmentsDone.insert( segment ); uint32_t flags = (segment->getSourceHook() == hook) ? DiodeCluster::IsSegSource : 0; if (dynamic_cast(hook)) { hooksStack.push_back( make_tuple( segment->getTargetHook(), segment, stackTop, flags ) ); } else { hooksStack.push_back( make_tuple( segment->getSourceHook(), segment, stackTop, flags ) ); } } } ++stackTop; } cdebug_log(147,0) << "Cluster halo" << endl; for ( size_t i=1 ; i( hooksStack[i] ); uint32_t flags = std::get<3>( hooksStack[i] ); cdebug_log(147,0) << "| [" << i << "] flags=" << flags << " " << segment << endl; if (not (flags & DiodeCluster::InCluster)) { size_t j = std::get<2>( hooksStack[i] ); if (std::get<3>(hooksStack[j]) & DiodeCluster::InCluster) { cdebug_log(147,0) << "> Put in halo." << endl; cluster->mergeHalo( segment, flags ); } } } cdebug_log(147,0) << "Cluster border" << endl; cluster->inflateArea(); } if (clusters.size() > 1) { NetData* netData = getNetData( net ); size_t rpClustersSize = clusters.size(); if (netData) { for ( auto item : clusterSegments ) { cdebug_log(147,0) << "No move up: " << item.first << endl; netData->setNoMoveUp( item.first ); } } cdebug_log(147,0) << "Cluster wiring, rpClustersSize=" << rpClustersSize << endl; for ( Segment* segment : net->getSegments() ) { if (clusterSegments.find(segment) != clusterSegments.end()) continue; cdebug_log(147,0) << "New Cluster [" << clusters.size() << "] wiring from " << segment << endl; DiodeWire* cluster = new DiodeWire( this, clusters[0]->getRefRp() ); cluster->merge( segment ); clusters.push_back( cluster ); clusterSegments.insert( make_pair( segment, clusters.size()-1 ) ); size_t stackTop = 0; vector< StackItem > hooksStack; hooksStack.push_back( make_tuple( segment->getSourceHook() , segment , 0 , DiodeCluster::IsSegSource ) ); hooksStack.push_back( make_tuple( segment->getTargetHook() , segment , 0 , 0 ) ); while ( stackTop < hooksStack.size() ) { Hook* toHook = std::get<0>( hooksStack[stackTop] ); Segment* fromSegment = std::get<1>( hooksStack[stackTop] ); bool hasRp = false; for ( Hook* hook : toHook->getHooks() ) { RoutingPad* rp = dynamic_cast( hook->getComponent() ); if (rp) { hasRp = true; auto irp = rpsDone.find( rp ); if (irp != rpsDone.end()) { size_t neighbor = (*irp).second; cdebug_log(147,0) << "| " << rp << " belongs to [" << neighbor << "]" << endl; cluster->addNeighbor( neighbor ); } break; } } if (not hasRp) { for ( Hook* hook : toHook->getHooks() ) { Segment* segment = dynamic_cast( hook->getComponent() ); if (segment) { if (segment == fromSegment) continue; auto iclusterSegment = clusterSegments.find( segment ); if (iclusterSegment != clusterSegments.end()) { size_t neighbor = (*iclusterSegment).second; cdebug_log(147,0) << "| " << segment << " belongs to [" << neighbor << "]" << endl; if (neighbor < rpClustersSize) cluster->addNeighbor( neighbor ); continue; } clusterSegments.insert( make_pair( segment, clusters.size()-1 ) ); cluster->merge( segment ); uint32_t flags = (segment->getSourceHook() == hook) ? DiodeCluster::IsSegSource : 0; if (dynamic_cast(hook)) { hooksStack.push_back( make_tuple( segment->getTargetHook(), segment, stackTop, flags ) ); } else { hooksStack.push_back( make_tuple( segment->getSourceHook(), segment, stackTop, flags ) ); } } } } ++stackTop; } } total += clusters.size(); cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl; size_t i = clusters.size()-1; while ( true ) { cdebug_log(147,1) << "Cluster [" << i << "] needsDiode=" << clusters[i]->needsDiode() << " bb=" << clusters[i]->getBoundingBox() << endl; cdebug_log(147,0) << " WL=" << DbU::getValueString(clusters[i]->getWL()) << endl; for ( auto& item : clusters[i]->getRoutingPads() ) { cdebug_log(147,0) << "| flags=" << DiodeCluster::toStr(std::get<1>(item)) << " " << std::get<0>(item) << endl; } if (clusters[i]->needsDiode()) { const vector& diodes = clusters[i]->createDiodes( etesian->getArea() ); if (not diodes.empty()) { clusters[i]->connectDiodes(); } else { cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n" " Cannot find a diode nearby %s." , getString(net).c_str() , rpsDone.size() , clusters.size() , getString(clusters[i]->getRefRp()).c_str() ) << endl; failed += 1; for ( size_t icluster : clusters[i]->getNeighbors() ) { clusters[icluster]->addForcedDiodes( 1 ); } } } cdebug_tabw(147,-1); if (i == 0) break; --i; } cdebug_tabw(147,-1); } if ((rpsDone.size() == 2) and (clusters.size() == 2)) { cerr << "Long bipoint " << net << endl; } for ( DiodeCluster* cluster : clusters ) delete cluster; cdebug_tabw(147,-1); DebugSession::close(); } void AnabaticEngine::antennaProtect () { //DebugSession::open( 145, 150 ); if (not ToolEngine::get( getCell(), EtesianEngine::staticGetName() )) { cerr << Warning( "AnabaticEngine::antennaProtect(): No EtesianEngine found, skipped." ) << endl; return; } EtesianEngine* etesian = static_cast ( ToolEngine::get( getCell(), EtesianEngine::staticGetName() )); if (not etesian->getDiodeCell()) { cerr << Warning( "AnabaticEngine::antennaProtect(): No diode cell found, skipped." ) << endl; return; } if (etesian->getAntennaDiodeMaxWL() <= 0) { cerr << Warning( "AnabaticEngine::antennaProtect(): Maximum antenna diode WL not set, skipped." ) << endl; return; } DbU::Unit segmentMaxWL = etesian->getAntennaDiodeMaxWL() / 2; cmess1 << " o Antenna effect protection." << endl; startMeasures(); openSession(); uint32_t failed = 0; uint32_t total = 0; for ( Net* net : getCell()->getNets() ) { if (net->isSupply()) continue; if ( NetRoutingExtension::isManualDetailRoute(net) or NetRoutingExtension::isFixed(net)) continue; antennaProtect( net, failed, total ); } cmess2 << Dots::asString ( " - Antenna gate maximum WL" , DbU::getValueString(etesian->getAntennaGateMaxWL()) ) << endl; cmess2 << Dots::asString ( " - Antenna diode maximum WL" , DbU::getValueString(etesian->getAntennaDiodeMaxWL()) ) << endl; cmess2 << Dots::asString ( " - Antenna segment maximum WL", DbU::getValueString(segmentMaxWL) ) << endl; cmess2 << Dots::asInt ( " - Total needed diodes", total ) << endl; cmess2 << Dots::asInt ( " - Failed to allocate" , failed ) << endl; cmess2 << Dots::asPercentage( " - Success ratio" , (float)(total-failed)/(float)total ) << endl; stopMeasures(); printMeasures( "antennas" ); Session::close(); //DebugSession::close(); Breakpoint::stop( 99, "After diodes insertions." ); } } // Anabatic namespace.