From bb5c99247a89b7fc892aeb61904ddab2b6e01b59 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 4 May 2021 19:31:12 +0200 Subject: [PATCH] Complete rewrite of the diode insertion algorithm. First part of the antenna effect protection : diode insertions. Anabatic::antennaProtect(Net*) and it's supporting infrastructure has been rewritten & simplificated. Must be used in conjuction with the "Flexlib" bloat model of Etesian. A cursory description of the algorithm has been added in the source file. * New: GCell::hasNet() to tell if net is going through a GCell, either as a straigth wire or has a local GContact (turn, branch, terminal). * New: Etesian::BloatFlexib class (tagged "Flexlib") suited for flexlib uses. It is derived from "nsxlib". To have enough space to insert all the wanted diodes, we enlarge "mx2_x2" & "mx3_x2" of resp. 1 and 2 pitches. This is an empiric finding, Yosys seems very fond of thoses gates and we often see them underneath area where no space was available to put a diode... May need some more fine grained analysis. --- anabatic/src/AntennaProtect.cpp | 644 ++++++++++++++++++------------- anabatic/src/GCell.cpp | 20 + anabatic/src/anabatic/GCell.h | 1 + etesian/src/BloatCells.cpp | 24 ++ etesian/src/Placement.cpp | 6 +- etesian/src/etesian/BloatCells.h | 15 +- 6 files changed, 431 insertions(+), 279 deletions(-) diff --git a/anabatic/src/AntennaProtect.cpp b/anabatic/src/AntennaProtect.cpp index 3465de3a..c2f7dc38 100644 --- a/anabatic/src/AntennaProtect.cpp +++ b/anabatic/src/AntennaProtect.cpp @@ -48,15 +48,36 @@ namespace { using namespace Anabatic; using Etesian::EtesianEngine; + typedef tuple RPInfosItem; - class CompareGCellByXMin { + class CompareRPInfos { public: - inline bool operator () ( const GCell* lhs, const GCell* rhs ) const; + inline bool operator () ( const RPInfosItem& lhs, const RPInfosItem& rhs ) const; }; - inline bool CompareGCellByXMin::operator () ( const GCell* lhs, const GCell* rhs ) const - { return lhs->getXMin() < rhs->getXMin(); } + 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 uint32_t& flags ( GCellInfosItem& item ) { return std::get<1>(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; // ----------------------------------------------------------------- @@ -68,13 +89,8 @@ namespace { 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: - typedef tuple RPInfos; - typedef map RoutingPadInfos; - typedef set HorizontalSet; - typedef set VerticalSet; - typedef map< DbU::Unit, vector > GCellArea; public: DiodeCluster ( RoutingPad*, AnabaticEngine* ); inline bool hasRp ( RoutingPad* ) const; @@ -84,26 +100,21 @@ namespace { inline const RoutingPadInfos& getRoutingPads () const; inline const vector& getDiodes () const; inline DbU::Unit getWL () const; + void showArea () const; bool needsDiode () const; Box getBoundingBox () const; - void merge ( GCell* ); + void merge ( GCell*, uint32_t distance, GCell* back=NULL ); void merge ( RoutingPad* ); void merge ( Segment* ); - void mergeHalo ( Segment* ); - void forceDiodeOn ( RoutingPad*, Segment*, Flags ); - Instance* createDiode ( Etesian::Area*, GCell*, Flags side, uint32_t distance=1 ); + void mergeHalo ( Segment*, uint32_t flags ); + void inflateArea (); + Instance* createDiode ( Etesian::Area*, GCell*, GCell* ); const vector& createDiodes ( Etesian::Area* ); - private: - void _consolidate (); private: AnabaticEngine* _anabatic; bool _sortArea; DbU::Unit _WL; RoutingPadInfos _routingPads; - HorizontalSet _horizontals; - VerticalSet _verticals; - HorizontalSet _horizontalHalo; - VerticalSet _verticalHalo; GCellArea _area; vector _diodes; }; @@ -113,6 +124,7 @@ namespace { 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 ) @@ -122,6 +134,7 @@ namespace { s += (flags & IsSink ) ? 's' : '-'; s += (flags & HasDiode ) ? 'D' : '-'; s += (flags & IsSegSource) ? 'S' : '-'; + s += (flags & InCluster ) ? 'C' : '-'; return s; } @@ -131,10 +144,6 @@ namespace { , _sortArea(true) , _WL(0) , _routingPads() - , _horizontals() - , _verticals() - , _horizontalHalo() - , _verticalHalo() , _area() , _diodes() { @@ -142,57 +151,70 @@ namespace { } - inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); } - inline DbU::Unit DiodeCluster::getWL () const { return _WL; } - inline const DiodeCluster::RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; } - inline const vector& DiodeCluster::getDiodes () const { return _diodes; } + inline Net* DiodeCluster::getTopNet () const { return getRefRp()->getNet(); } + inline DbU::Unit DiodeCluster::getWL () const { return _WL; } + inline const RoutingPadInfos& DiodeCluster::getRoutingPads () const { return _routingPads; } + inline const vector& DiodeCluster::getDiodes () const { return _diodes; } + bool DiodeCluster::needsDiode () const { - for ( auto& item : _routingPads ) { - if (std::get<0>(item.second) & IsSink) return true; + for ( auto& infos : _routingPads ) { + if (std::get<1>(infos) & IsSink) return true; } return false; } inline bool DiodeCluster::hasRp ( RoutingPad* rp ) const - { return (_routingPads.find(rp) != _routingPads.end()); } + { return (_routingPads.find(make_tuple(rp,0)) != _routingPads.end()); } inline bool DiodeCluster::hasGCell ( GCell* gcell ) const { if (not gcell) return false; - auto islice = _area.find( gcell->getYMin()); - if (islice == _area.end()) return false; - for ( const GCell* igcell : (*islice).second ) - if (igcell == gcell) return true; + for ( auto& item : _area ) { + if (std::get<0>(item) == gcell) return true; + } return false; } inline RoutingPad* DiodeCluster::getRefRp () const { - if (not _routingPads.empty()) return (*_routingPads.begin()).first; + if (not _routingPads.empty()) return std::get<0>( *_routingPads.begin() ); return NULL; } + void DiodeCluster::showArea () const + { + cdebug_log(147,1) << "GCell diode area" << endl; + for ( auto& item : _area ) { + 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) { - merge( _anabatic->getGCellUnder( rp->getPosition() )); + merge( _anabatic->getGCellUnder( rp->getPosition() ), 0 ); if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) { - _routingPads.insert( make_pair(rp,make_tuple(IsSink,(Segment*)NULL)) ); + cdebug_log(147,0) << "| Sink " << rp << endl; + _routingPads.insert( make_tuple(rp,IsSink) ); } else { - _routingPads.insert( make_pair(rp,make_tuple(IsDriver,(Segment*)NULL)) ); + _routingPads.insert( make_tuple(rp,IsDriver) ); cdebug_log(147,0) << "| Driver " << rp << endl; } } else { Pin* rpPin = dynamic_cast( rp->getPlugOccurrence().getEntity() ); if (rpPin) { - _routingPads.insert( make_pair(rp,make_tuple(IsDriver,(Segment*)NULL)) ); + _routingPads.insert( make_tuple(rp,IsDriver) ); cdebug_log(147,0) << "| Pin (considered driver) " << rp << endl; } } @@ -206,114 +228,129 @@ namespace { if (not gcells->empty()) { _sortArea = true; for ( size_t i=0 ; isize() ; ++i ) { - merge( gcells->gcellAt(i) ); + merge( gcells->gcellAt(i), 0 ); } } } - void DiodeCluster::merge ( GCell* gcell ) + void DiodeCluster::merge ( GCell* gcell, uint32_t distance, GCell* back ) { if (not gcell) return; - auto islice = _area.find( gcell->getYMin()); - if (islice == _area.end()) - islice = _area.insert( make_pair(gcell->getYMin(),vector()) ).first; - for ( const GCell* igcell : (*islice).second ) { - if (igcell == gcell) return; - } - (*islice).second.push_back( gcell ); + if (hasGCell(gcell)) return; + if (back) distance += 20; + _area.insert( make_tuple(gcell,distance,back) ); } Box DiodeCluster::getBoundingBox () const { Box bb; - for ( auto& item : _routingPads ) bb.merge( item.first->getPosition() ); + for ( auto& infos : _routingPads ) bb.merge( std::get<0>(infos)->getPosition() ); return bb; } - void DiodeCluster::forceDiodeOn ( RoutingPad* rp, Segment* segment, Flags flags ) + void DiodeCluster::mergeHalo ( Segment* segment, uint32_t flags ) { - cdebug_log(147,0) << "DiodeCluster::forceDiodeOn(): " << endl; - cdebug_log(147,0) << " rp=" << rp << endl; - cdebug_log(147,0) << " seg=" << segment << endl; - if (not rp or not segment) return; - for ( auto& item : _routingPads ) { - if (item.first == rp) { - std::get<0>(item.second) |= HasDiode; - if (flags & Flags::Source) std::get<0>(item.second) |= IsSegSource; - std::get<1>(item.second) = segment; - return; + cdebug_log(147,0) << "DiodeCluster::mergeHalo(): " << segment << endl; + if (not segment) return; + + GCellsUnder gcells = _anabatic->getGCellsUnder( segment ); + if (not gcells->empty()) { + size_t count = std::min( gcells->size(), (size_t)10 ); + for ( size_t i=0 ; isize()-1-i); + merge( gcells->gcellAt(igcell), i+1 ); } } - cdebug_log(147,0) << "DiodeCluster::forceDiodeOn(): No RP registered." << endl; + } + + + void DiodeCluster::inflateArea () + { + vector< tuple > border; + for ( auto& item : _area ) { + 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 : _area ) { + 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 ) { + merge( std::get<0>(item), 1, std::get<1>(item) ); + } } - Instance* DiodeCluster::createDiode ( Etesian::Area* area, GCell* gcell, Flags side, uint32_t distance ) + Instance* DiodeCluster::createDiode ( Etesian::Area* area, GCell* gcell, GCell* backGCell ) { - cdebug_log(147,0) << "DiodeCluster::createDiode(): from=" << gcell - << " distance=" << distance << endl; + cdebug_log(147,0) << "DiodeCluster::createDiode(): from=" << gcell << endl; - GCell* neighbor = gcell; - GCell* current = gcell; - uint32_t i = 0; - while ( igetWest(); - else if (side.contains(Flags::EastSide )) current = current->getEast(); - else if (side.contains(Flags::NorthSide)) current = current->getNorth(); - else if (side.contains(Flags::SouthSide)) current = current->getSouth(); - if (not current) break; - neighbor = current; - ++i; - } + Box bb = gcell->getBoundingBox(); + cdebug_log(147,0) << "> GCell area: " << bb << endl; - DbU::Unit xHint = 0; - if (side.contains(Flags::WestSide )) xHint = neighbor->getBoundingBox().getXMax(); - else if (side.contains(Flags::EastSide )) xHint = neighbor->getBoundingBox().getXMin(); - else if (side.contains(Flags::NorthSide)) xHint = neighbor->getBoundingBox().getXCenter(); - else if (side.contains(Flags::SouthSide)) xHint = neighbor->getBoundingBox().getXCenter(); - - Box bb = neighbor->getBoundingBox(); - Instance* diode = area->createDiodeUnder( getRefRp(), bb, xHint ); + Instance* diode = area->createDiodeUnder( getRefRp(), bb, 0 ); if (diode) { _diodes.push_back( diode ); Transformation trans = getRefRp()->getPlugOccurrence().getPath().getTransformation(); Point center = diode->getAbutmentBox().getCenter(); trans.applyOn( center ); - neighbor = _anabatic->getGCellUnder( center ); - cdebug_log(147,0) << "> GCell area (neighbor): " << bb << endl; - Contact* sourceContact = gcell->breakGoThrough( getTopNet() ); - Contact* targetContact = neighbor->hasGContact( getTopNet() ); + 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 (not targetContact) { - bool hasGoThrough = (neighbor->hasGoThrough(getTopNet()) != NULL); - targetContact = neighbor->breakGoThrough( getTopNet() ); - cdebug_log(147,0) << "| breakGoThrough(), targetContact= " << targetContact << endl; + if (backGCell and newContact) { + Contact* backContact = backGCell->breakGoThrough( getTopNet() ); + if (backContact->getY() == contact->getY()) { + if (contact->getX() > backContact->getX()) + std::swap( backContact, contact ); - if (not hasGoThrough) { - cdebug_log(147,0) << "| Target GCell do not have a go-through, connecting. " << endl; - if (side & Flags::Horizontal) { - if (sourceContact->getX() > targetContact->getX()) - std::swap( sourceContact, targetContact ); - - Horizontal::create( sourceContact - , targetContact - , _anabatic->getConfiguration()->getGHorizontalLayer() - , bb.getCenter().getY() - , _anabatic->getConfiguration()->getGHorizontalPitch() - ); - } else { - if (sourceContact->getY() > targetContact->getY()) - std::swap( sourceContact, targetContact ); - - Vertical::create( sourceContact - , targetContact - , _anabatic->getConfiguration()->getGVerticalLayer() - , bb.getCenter().getX() - , _anabatic->getConfiguration()->getGVerticalPitch() + 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; } } } @@ -325,139 +362,23 @@ namespace { const vector& DiodeCluster::createDiodes ( Etesian::Area* area ) { if (not needsDiode()) return _diodes; - _consolidate(); + showArea(); + cdebug_log(147,1) << "DiodeCluster::createDiodes()" << endl; Instance* diode = NULL; - - for ( auto& item : _routingPads ) { - if (not (std::get<0>(item.second) & HasDiode)) continue; - - diode = NULL; - GCell* gcell = _anabatic->getGCellUnder( item.first->getPosition() ); - - Horizontal* h = dynamic_cast(std::get<1>(item.second)); - if (h) { - cdebug_log(147,0) << "> Long segment (forced diode) h=" << h << endl; - diode = area->createDiodeUnder( getRefRp() - , h->getBoundingBox() - , item.first->getPosition().getX() ); - if (diode) { - _diodes.push_back( diode ); - continue; - } - } - - auto islice = _area.find( gcell->getYMin()); - if (islice != _area.end()) { - Box gcellsBb; - bool containsRp = false; - vector& slice = (*islice).second; - for ( size_t i=0 ; i < slice.size() ; ++i ) { - if (slice[i] == gcell) containsRp = true; - if ((i > 0) and (slice[i-1]->getXMax() < slice[i]->getXMin())) { - cdebug_log(147,0) << "> GCell area (forced diode): " << gcellsBb << endl; - if (containsRp) { - diode = area->createDiodeUnder( getRefRp(), gcellsBb, item.first->getPosition().getX() ); - if (diode) { - _diodes.push_back( diode ); - containsRp = false; - break; - } - } - gcellsBb.makeEmpty(); - } - gcellsBb.merge( slice[i]->getBoundingBox() ); - } - if (diode) continue; - if (containsRp and not gcellsBb.isEmpty()) { - cdebug_log(147,0) << "> GCell area (forced diode, end): " << gcellsBb << endl; - diode = area->createDiodeUnder( getRefRp(), gcellsBb, item.first->getPosition().getX() ); - if (diode) { - _diodes.push_back( diode ); - continue; - } - } - - cdebug_log(147,0) << "> Try along connecting segment" << endl; - Horizontal* h = dynamic_cast( std::get<1>(item.second) ); - if (h) { - if (std::get<0>(item.second) & IsSegSource) { - for ( uint32_t i=0 ; i<3 ; ++i ) { - if ((diode = createDiode(area,gcell,Flags::EastSide,i))) break; - } - } else { - for ( uint32_t i=0 ; i<3 ; ++i ) { - if ((diode = createDiode(area,gcell,Flags::WestSide,i))) break; - } - } - } else { - if (std::get<0>(item.second) & IsSegSource) { - for ( uint32_t i=0 ; i<3 ; ++i ) { - if ((diode = createDiode(area,gcell,Flags::NorthSide,i))) break; - } - } else { - for ( uint32_t i=0 ; i<3 ; ++i ) { - if ((diode = createDiode(area,gcell,Flags::SouthSide,i))) break; - } - } - } - } - } - if (diode) return _diodes; - for ( auto& item : _area ) { - cdebug_log(147,0) << "+ Slice @" << DbU::getValueString(item.first) << endl; - Box gcellsBb; - vector& slice = item.second; - for ( size_t i=0 ; (i < slice.size()) and not diode ; ++i ) { - if ((i > 0) and (slice[i-1]->getXMax() < slice[i]->getXMin())) { - cdebug_log(147,0) << "> GCell area: " << gcellsBb << endl; - diode = area->createDiodeUnder( getRefRp(), gcellsBb, gcellsBb.getXCenter() ); - if (diode) { - _diodes.push_back( diode ); - return _diodes; - } - gcellsBb.makeEmpty(); - } - cdebug_log(147,0) << "| Agglomerate [" << i << "]: " << slice[i] << endl; - gcellsBb.merge( slice[i]->getBoundingBox() ); - } - if (not gcellsBb.isEmpty()) { - cdebug_log(147,0) << "> GCell area (end): " << gcellsBb << endl; - diode = area->createDiodeUnder( getRefRp(), gcellsBb, gcellsBb.getXCenter() ); - if (diode) { - _diodes.push_back( diode ); - return _diodes; - } - } + 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) break; } + cdebug_tabw(147,-1); - for ( auto& item : _area ) { - vector& slice = item.second; - if (createDiode(area,slice[0 ],Flags::WestSide)) return _diodes; - if (createDiode(area,slice[slice.size()-1],Flags::EastSide)) return _diodes; - } - - for ( auto& item : _routingPads ) { - GCell* gcell = _anabatic->getGCellUnder( item.first->getPosition() ); - if (createDiode(area,gcell,Flags::NorthSide)) return _diodes; - if (createDiode(area,gcell,Flags::SouthSide)) return _diodes; - } - return _diodes; } - void DiodeCluster::_consolidate () - { - if (not _sortArea) return; - for ( auto& item : _area ) { - std::sort( item.second.begin(), item.second.end(), CompareGCellByXMin() ); - } - _sortArea = false; - } - - } // Anonymous namespace. @@ -468,8 +389,111 @@ namespace Anabatic { 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; @@ -480,53 +504,126 @@ namespace Anabatic { vector clusters; set rpsDone; - set segmentsDone; for ( RoutingPad* rp : net->getRoutingPads() ) { + set segmentsDone; + if (rpsDone.find(rp) != rpsDone.end()) continue; + cdebug_log(147,0) << "New cluster from " << rp << endl; DiodeCluster* cluster = new DiodeCluster ( rp, this ); clusters.push_back( cluster ); + rpsDone.insert( rp ); - vector hooksStack; - hooksStack.push_back( rp->getBodyHook() ); - while ( not hooksStack.empty() ) { - Hook* topHook = hooksStack.back(); - RoutingPad* topRp = dynamic_cast( topHook->getComponent() ); - RoutingPad* connexRp = NULL; - hooksStack.pop_back(); + 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; - for ( Hook* hook : topHook->getHooks() ) { - RoutingPad* gcellRp = dynamic_cast( hook->getComponent() ); - if (gcellRp) { - if (not connexRp) connexRp = gcellRp; - if (rpsDone.find(gcellRp) == rpsDone.end()) - cluster->merge( gcellRp ); - rpsDone.insert( gcellRp ); + cdebug_log(147,0) << "| PROCESS [" << stackTop << "] " << fromSegment << endl; + if (fromSegment) { + if (fromSegment->getLength() > antennaMaxWL/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 > antennaMaxWL) { + 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( toRp ); + 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; + 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 : topHook->getHooks() ) { + for ( Hook* hook : toHook->getHooks() ) { Segment* segment = dynamic_cast( hook->getComponent() ); if (segment) { - cdebug_log(147,0) << "| " << DbU::getValueString(segment->getLength()) + 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 ); - if (segment->getLength() > antennaMaxWL/2) { - Flags flags = (segment->getSourceHook() == hook) ? Flags::Source : Flags::Target; - if (not connexRp) connexRp = topRp; - cluster->forceDiodeOn( connexRp, segment, flags ); - continue; - } - cluster->merge( segment ); + uint32_t flags = (segment->getSourceHook() == hook) ? DiodeCluster::IsSegSource : 0; if (dynamic_cast(hook)) { - hooksStack.push_back( segment->getTargetHook() ); + hooksStack.push_back( make_tuple( segment->getTargetHook(), segment, stackTop, flags ) ); } else { - hooksStack.push_back( segment->getSourceHook() ); + 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(); } Cell* diodeCell = etesian->getDiodeCell(); @@ -541,13 +638,16 @@ namespace Anabatic { total += clusters.size(); cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl; for ( size_t i=0 ; i(item) << endl; + } + if (not clusters[i]->needsDiode()) { + cdebug_tabw(147,-1); + continue; } - if (not clusters[i]->needsDiode()) continue; const vector diodes = clusters[i]->createDiodes( etesian->getArea() ); RoutingPad* rp = clusters[i]->getRefRp(); @@ -565,6 +665,7 @@ namespace Anabatic { Plug* diodePlug = diode->getPlug( diodeOutput ); diodePlug->setNet( sinkPlug->getNet() ); RoutingPad* diodeRp = RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea ); + cdebug_log(147,0) << " " << rp << endl; GCell* gcell = getGCellUnder( diodeRp->getPosition() ); if (gcell) { @@ -591,6 +692,7 @@ namespace Anabatic { ) << endl; failed += 1; } + cdebug_tabw(147,-1); } cdebug_tabw(147,-1); } @@ -619,6 +721,7 @@ namespace Anabatic { return; } + cmess1 << " o Antenna effect protection." << endl; startMeasures(); openSession(); @@ -638,11 +741,6 @@ namespace Anabatic { stopMeasures(); printMeasures( "antennas" ); - // cmess2 << " - Total segments : " << total << endl; - // cmess2 << " - Global segments : " << global << endl; - // cmess2 << " - Ratio : " - // << ((float)global/(float)total)*100.0 << "%." << endl; - Session::close(); //DebugSession::close(); Breakpoint::stop( 99, "After diodes insertions." ); diff --git a/anabatic/src/GCell.cpp b/anabatic/src/GCell.cpp index b668f5a7..c1454f1a 100644 --- a/anabatic/src/GCell.cpp +++ b/anabatic/src/GCell.cpp @@ -476,6 +476,26 @@ namespace Anabatic { } + bool GCell::hasNet ( const Net* net ) const + { + if (hasGContact(net)) return true; + + for ( Edge* edge : _eastEdges ) { + for ( Segment* segment : edge->getSegments() ) { + if (segment->getNet() == net) return true; + } + } + + for ( Edge* edge : _northEdges ) { + for ( Segment* segment : edge->getSegments() ) { + if (segment->getNet() == net) return true; + } + } + + return false; + } + + Contact* GCell::hasGContact ( const Contact* owned ) const { for ( Contact* contact : _gcontacts ) { diff --git a/anabatic/src/anabatic/GCell.h b/anabatic/src/anabatic/GCell.h index 92812651..8660d7c5 100644 --- a/anabatic/src/anabatic/GCell.h +++ b/anabatic/src/anabatic/GCell.h @@ -163,6 +163,7 @@ namespace Anabatic { bool isEast ( GCell* ) const; bool isNorth ( GCell* ) const; bool isSouth ( GCell* ) const; + bool hasNet ( const Net* ) const; Contact* hasGContact ( const Contact* ) const; Contact* hasGContact ( const Net* ) const; bool isHorizontalPlane ( size_t depth ) const; diff --git a/etesian/src/BloatCells.cpp b/etesian/src/BloatCells.cpp index 13713659..55508190 100644 --- a/etesian/src/BloatCells.cpp +++ b/etesian/src/BloatCells.cpp @@ -89,6 +89,30 @@ namespace Etesian { } + BloatFlexlib::BloatFlexlib () + : BloatCell("Flexlib") + { } + + + BloatFlexlib::~BloatFlexlib () + { } + + + DbU::Unit BloatFlexlib::getDx ( const Cell* cell, const EtesianEngine* etesian ) const + { + Box ab ( cell->getAbutmentBox() ); + DbU::Unit vpitch = etesian->getSliceStep();; + int xsize = (ab.getWidth() + vpitch - 1) / vpitch; + + if (cell->getName() == "mx2_x2" ) return vpitch; + if (cell->getName() == "mx3_x2" ) return 2*vpitch; + if (cell->getName() == "sff1r_x4") return vpitch; + if (xsize < 6) return vpitch*2; + + return 0; + } + + Bloat3Metals::Bloat3Metals () : BloatCell("3metals") { } diff --git a/etesian/src/Placement.cpp b/etesian/src/Placement.cpp index 05360d65..575d14d8 100644 --- a/etesian/src/Placement.cpp +++ b/etesian/src/Placement.cpp @@ -301,13 +301,17 @@ namespace Etesian { for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) { if ((*iTile).getXMax() <= diodeArea.getXMin()) continue; if ((*iTile).getXMin() >= diodeArea.getXMax()) break; + cdebug_log(147,0) << "| " << (*iTile) << endl; if ((*iTile).getMasterCell() != feed) continue; if (blockInst) { - if ((*iTile).getOccurrence().getPath().getHeadInstance() != blockInst) + if ((*iTile).getOccurrence().getPath().getHeadInstance() != blockInst) { + cdebug_log(147,0) << "> Reject, not in block instance" << endl; continue; + } } DbU::Unit distance = std::abs( (*iTile).getXMin() - xHint ); if (not foundCandidate or (distance < dCandidate)) { + cdebug_log(147,0) << "> candidate" << endl; foundCandidate = true; iCandidate = iTile; dCandidate = distance; diff --git a/etesian/src/etesian/BloatCells.h b/etesian/src/etesian/BloatCells.h index 8bce2c13..80e1fbb4 100644 --- a/etesian/src/etesian/BloatCells.h +++ b/etesian/src/etesian/BloatCells.h @@ -14,9 +14,7 @@ // +-----------------------------------------------------------------+ -#ifndef ETESIAN_BLOATCELLS_H -#define ETESIAN_BLOATCELLS_H - +#pragma once #include #include "hurricane/Box.h" #include "hurricane/Cell.h" @@ -85,6 +83,14 @@ namespace Etesian { }; + class BloatFlexlib : public BloatCell { + public: + BloatFlexlib (); + virtual ~BloatFlexlib (); + virtual DbU::Unit getDx ( const Cell*, const EtesianEngine* ) const; + }; + + class Bloat3Metals : public BloatCell { public: Bloat3Metals (); @@ -125,6 +131,7 @@ namespace Etesian { { _bloatCells.insert( new BloatDisabled () ); _bloatCells.insert( new BloatNsxlib () ); + _bloatCells.insert( new BloatFlexlib () ); _bloatCells.insert( new Bloat3Metals () ); _bloatCells.insert( new Bloat90Percents() ); select( "disabled" ); @@ -142,5 +149,3 @@ namespace Etesian { } // Etesian namespace. - -#endif // ETESIAN_BLOATCELLS_H