diff --git a/anabatic/CMakeLists.txt b/anabatic/CMakeLists.txt index 4d6c97d7..9786c67f 100644 --- a/anabatic/CMakeLists.txt +++ b/anabatic/CMakeLists.txt @@ -24,6 +24,7 @@ find_package(VLSISAPD REQUIRED) find_package(HURRICANE REQUIRED) find_package(CORIOLIS REQUIRED) + find_package(ETESIAN REQUIRED) find_package(Doxygen) add_subdirectory(src) diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index 9f1d4530..c7d6a805 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -1004,6 +1004,8 @@ namespace Anabatic { if (_state > EngineGlobalLoaded) throw Error ("AnabaticEngine::loadGlobalRouting() : global routing already loaded."); + antennaProtect(); + if (method == EngineLoadGrByNet ) { _loadGrByNet(); } else { throw Error( badMethod, "Anabatic::loadGlobalRouting()", method, getString(_cell).c_str() ); diff --git a/anabatic/src/AntennaProtect.cpp b/anabatic/src/AntennaProtect.cpp new file mode 100644 index 00000000..2c49ca13 --- /dev/null +++ b/anabatic/src/AntennaProtect.cpp @@ -0,0 +1,642 @@ +// -*- 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 CompareGCellByXMin { + public: + inline bool operator () ( const GCell* lhs, const GCell* rhs ) const; + }; + + + inline bool CompareGCellByXMin::operator () ( const GCell* lhs, const GCell* rhs ) const + { return lhs->getXMin() < rhs->getXMin(); } + + +// ----------------------------------------------------------------- +// 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 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; + bool hasGCell ( GCell* ) const; + inline Net* getTopNet () const; + inline RoutingPad* getRefRp () const; + inline const RoutingPadInfos& getRoutingPads () const; + inline const vector& getDiodes () const; + inline DbU::Unit getWL () const; + bool needsDiode () const; + Box getBoundingBox () const; + void merge ( GCell* ); + 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 ); + 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; + }; + + + 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); + + + string DiodeCluster::toStr ( uint32_t flags ) + { + string s; + s += (flags & IsDriver ) ? 'd' : '-'; + s += (flags & IsSink ) ? 's' : '-'; + s += (flags & HasDiode ) ? 'D' : '-'; + s += (flags & IsSegSource) ? 'S' : '-'; + return s; + } + + + DiodeCluster::DiodeCluster ( RoutingPad* rp, AnabaticEngine* anabatic ) + : _anabatic(anabatic) + , _sortArea(true) + , _WL(0) + , _routingPads() + , _horizontals() + , _verticals() + , _horizontalHalo() + , _verticalHalo() + , _area() + , _diodes() + { + merge( rp ); + } + + + 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; } + + bool DiodeCluster::needsDiode () const + { + for ( auto& item : _routingPads ) { + if (std::get<0>(item.second) & IsSink) return true; + } + return false; + } + + + inline bool DiodeCluster::hasRp ( RoutingPad* rp ) const + { return (_routingPads.find(rp) != _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; + return false; + } + + + inline RoutingPad* DiodeCluster::getRefRp () const + { + if (not _routingPads.empty()) return (*_routingPads.begin()).first; + return NULL; + } + + + void DiodeCluster::merge ( RoutingPad* rp ) + { + Plug* rpPlug = dynamic_cast( rp->getPlugOccurrence().getEntity() ); + if (rpPlug) { + merge( _anabatic->getGCellUnder( rp->getPosition() )); + if (rpPlug->getMasterNet()->getDirection() & Net::Direction::DirIn) { + _routingPads.insert( make_pair(rp,make_tuple(IsSink,(Segment*)NULL)) ); + } else { + _routingPads.insert( make_pair(rp,make_tuple(IsDriver,(Segment*)NULL)) ); + 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)) ); + cdebug_log(147,0) << "| Pin (considered driver) " << rp << endl; + } + } + } + + + void DiodeCluster::merge ( Segment* segment ) + { + _WL += segment->getLength(); + GCellsUnder gcells = _anabatic->getGCellsUnder( segment ); + if (not gcells->empty()) { + _sortArea = true; + for ( size_t i=0 ; isize() ; ++i ) { + merge( gcells->gcellAt(i) ); + } + } + } + + + void DiodeCluster::merge ( GCell* gcell ) + { + 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 ); + } + + + Box DiodeCluster::getBoundingBox () const + { + Box bb; + for ( auto& item : _routingPads ) bb.merge( item.first->getPosition() ); + return bb; + } + + + void DiodeCluster::forceDiodeOn ( RoutingPad* rp, Segment* segment, Flags 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::forceDiodeOn(): No RP registered." << endl; + } + + + Instance* DiodeCluster::createDiode ( Etesian::Area* area, GCell* gcell, Flags side, uint32_t distance ) + { + cdebug_log(147,0) << "DiodeCluster::createDiode(): from=" << gcell + << " distance=" << distance << endl; + + GCell* neighbor = gcell; + for ( uint32_t i=0 ; igetWest(); + else if (side.contains(Flags::EastSide )) neighbor = neighbor->getEast(); + else if (side.contains(Flags::NorthSide)) neighbor = neighbor->getNorth(); + else if (side.contains(Flags::SouthSide)) neighbor = neighbor->getSouth(); + } + if (not neighbor) return NULL; + + 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 ); + if (diode) { + _diodes.push_back( diode ); + cdebug_log(147,0) << "> GCell area (neighbor): " << bb << endl; + Contact* sourceContact = gcell->breakGoThrough( getTopNet() ); + Contact* targetContact = neighbor->hasGContact( getTopNet() ); + + if (not targetContact) { + bool hasGoThrough = (neighbor->hasGoThrough(getTopNet()) != NULL); + targetContact = neighbor->breakGoThrough( getTopNet() ); + + if (not hasGoThrough) { + 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() + ); + } + } + } + } + return diode; + } + + + const vector& DiodeCluster::createDiodes ( Etesian::Area* area ) + { + if (not needsDiode()) return _diodes; + _consolidate(); + + 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; + } + } + } + + 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. + + +namespace Anabatic { + + using namespace Hurricane; + using CRL::ToolEngine; + using Etesian::EtesianEngine; + + + void AnabaticEngine::antennaProtect ( Net* net, uint32_t& failed, uint32_t& total ) + { + DebugSession::open( net, 145, 150 ); + cdebug_log(147,1) << "Net \"" << net->getName() << endl; + + EtesianEngine* etesian = static_cast + ( ToolEngine::get( getCell(), EtesianEngine::staticGetName() )); + + DbU::Unit antennaMaxWL = etesian->getAntennaMaxWL(); + + vector clusters; + set rpsDone; + set segmentsDone; + for ( RoutingPad* rp : net->getRoutingPads() ) { + if (rpsDone.find(rp) != rpsDone.end()) continue; + + DiodeCluster* cluster = new DiodeCluster ( rp, this ); + clusters.push_back( cluster ); + + 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(); + + 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 ); + } + } + + for ( Hook* hook : topHook->getHooks() ) { + Segment* segment = dynamic_cast( hook->getComponent() ); + if (segment) { + cdebug_log(147,0) << "| " << 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 ); + if (dynamic_cast(hook)) { + hooksStack.push_back( segment->getTargetHook() ); + } else { + hooksStack.push_back( segment->getSourceHook() ); + } + } + } + } + } + + Cell* diodeCell = etesian->getDiodeCell(); + Net* diodeOutput = NULL; + for ( Net* net : diodeCell->getNets() ) { + if (net->isSupply() or not net->isExternal()) continue; + diodeOutput = net; + break; + } + + if (clusters.size() > 1) { + total += clusters.size(); + cdebug_log(147,1) << "Net \"" << net->getName() << " has " << clusters.size() << " diode clusters." << endl; + for ( size_t i=0 ; ineedsDiode()) continue; + + const vector diodes = clusters[i]->createDiodes( etesian->getArea() ); + RoutingPad* rp = clusters[i]->getRefRp(); + if (not diodes.empty()) { + Net* topNet = rp->getNet(); + Plug* sinkPlug = dynamic_cast( rp->getPlugOccurrence().getEntity() ); + Path path = rp->getOccurrence().getPath().getHeadPath(); + if (sinkPlug) { + 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) << " " << rp->getOccurrence().getPath() << endl; + //Path path = rp->getOccurrence().getPath().getHeadPath(); + Plug* diodePlug = diode->getPlug( diodeOutput ); + diodePlug->setNet( sinkPlug->getNet() ); + RoutingPad* diodeRp = RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea ); + + GCell* gcell = getGCellUnder( diodeRp->getPosition() ); + if (gcell) { + Contact* contact = gcell->breakGoThrough( topNet ); + contact->getBodyHook()->merge( diodeRp->getBodyHook() ); + } + } + } else { + cerr << Error( "EtesianEngine::antennaProtect(): For %s (rps:%u, clusters:%u)\n" + " Cannot get a Plug from %s (?)." + , getString(net).c_str() + , rpsDone.size() + , clusters.size() + , getString(clusters[i]->getRefRp()).c_str() + ) << endl; + } + } 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; + } + } + cdebug_tabw(147,-1); + } + + 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() )); + DbU::Unit segmentMaxWL = etesian->getAntennaMaxWL() / 2; + + if (not etesian->getDiodeCell()) { + cerr << Warning( "AnabaticEngine::antennaProtect(): No diode cell found, skipped." ) << endl; + return; + } + + startMeasures(); + openSession(); + + uint32_t failed = 0; + uint32_t total = 0; + for ( Net* net : getCell()->getNets() ) { + if (net->isSupply()) continue; + if (net->isClock ()) continue; + antennaProtect( net, failed, total ); + } + cmess2 << Dots::asString ( " - Antenna maximum WL" , DbU::getValueString(etesian->getAntennaMaxWL()) ) << endl; + cmess2 << Dots::asString ( " - 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" ); + + // 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." ); + } + + +} // Anabatic namespace. diff --git a/anabatic/src/CMakeLists.txt b/anabatic/src/CMakeLists.txt index ae1c93c7..7597035f 100644 --- a/anabatic/src/CMakeLists.txt +++ b/anabatic/src/CMakeLists.txt @@ -63,13 +63,15 @@ endif ( CHECK_DETERMINISM ) NetBuilderVH.cpp ChipTools.cpp LayerAssign.cpp + AntennaProtect.cpp PreRouteds.cpp AnabaticEngine.cpp ) set( pyCpps PyAnabatic.cpp ) - set( depLibs ${CORIOLIS_PYTHON_LIBRARIES} + set( depLibs ${ETESIAN_LIBRARIES} + ${CORIOLIS_PYTHON_LIBRARIES} ${CORIOLIS_LIBRARIES} ${HURRICANE_PYTHON_LIBRARIES} ${HURRICANE_GRAPHICAL_LIBRARIES} diff --git a/anabatic/src/Configuration.cpp b/anabatic/src/Configuration.cpp index 21d85d48..c081813f 100644 --- a/anabatic/src/Configuration.cpp +++ b/anabatic/src/Configuration.cpp @@ -90,6 +90,7 @@ namespace Anabatic { , _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble()) , _edgeHScaling (Cfg::getParamDouble("anabatic.edgeHScaling" , 1.0)->asDouble()) , _globalIterations(Cfg::getParamInt ("anabatic.globalIterations", 10 )->asInt()) + , _antennaMaxWL (Cfg::getParamInt ("etesian.antennaMaxWL" , 0 )->asInt()) { GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() ); @@ -180,6 +181,7 @@ namespace Anabatic { , _edgeHInc (other._edgeHInc) , _edgeHScaling (other._edgeHScaling) , _globalIterations(other._globalIterations) + , _antennaMaxWL (other._antennaMaxWL) { GCell::setDisplayMode( Cfg::getParamEnumerate("anabatic.gcell.displayMode", GCell::Boundary)->asInt() ); @@ -576,17 +578,21 @@ namespace Anabatic { Record* Configuration::_getRecord () const { Record* record = new Record ( _getString() ); - record->add ( getSlot( "_gdepthh" , _gdepthh ) ); - record->add ( getSlot( "_gdepthv" , _gdepthv ) ); - record->add ( getSlot( "_rg" , _rg ) ); - record->add ( getSlot( "_gmetalh" , _gmetalh ) ); - record->add ( getSlot( "_gmetalv" , _gmetalv ) ); - record->add ( getSlot( "_gcontact" , _gcontact ) ); - record->add ( getSlot( "_allowedDepth", _allowedDepth ) ); - record->add ( getSlot( "_edgeCostH" , _edgeCostH ) ); - record->add ( getSlot( "_edgeCostK" , _edgeCostK ) ); + record->add( getSlot( "_gdepthh" , _gdepthh ) ); + record->add( getSlot( "_gdepthv" , _gdepthv ) ); + record->add( getSlot( "_rg" , _rg ) ); + record->add( getSlot( "_gmetalh" , _gmetalh ) ); + record->add( getSlot( "_gmetalv" , _gmetalv ) ); + record->add( getSlot( "_gcontact" , _gcontact ) ); + record->add( getSlot( "_allowedDepth" , _allowedDepth ) ); + record->add( getSlot( "_edgeCostH" , _edgeCostH ) ); + record->add( getSlot( "_edgeCostK" , _edgeCostK ) ); + record->add( getSlot( "_edgeHInc" , _edgeHInc ) ); + record->add( getSlot( "_edgeHScaling" , _edgeHScaling ) ); + record->add( getSlot( "_globalIterations", _globalIterations ) ); + record->add( DbU::getValueSlot( "_antennaMaxWL", &_antennaMaxWL ) ); - return ( record ); + return record; } diff --git a/anabatic/src/Dijkstra.cpp b/anabatic/src/Dijkstra.cpp index 7a5122c7..bff4ded9 100644 --- a/anabatic/src/Dijkstra.cpp +++ b/anabatic/src/Dijkstra.cpp @@ -1459,6 +1459,10 @@ namespace Anabatic { } + DbU::Unit Dijkstra::getAntennaMaxWL () const + { return _anabatic->getAntennaMaxWL(); } + + Point Dijkstra::_getPonderedPoint() const { vector rps; @@ -1533,12 +1537,13 @@ namespace Anabatic { cdebug_log(112,1) << "Dijkstra::load() " << _net << endl; vector rps; - NetRoutingState* state = NetRoutingExtension::get( _net ); + NetRoutingState* state = NetRoutingExtension::get( _net ); if (state) { if (state->isSelfSym()) { cdebug_log(112,0) << "Dijkstra::SELF SYMMETRY CASE " << DbU::getValueString(state->getSymAxis()) << endl; } + state->unsetFlags( NetRoutingState::HasAntenna ); } for ( Component* component : _net->getComponents() ) { @@ -2196,6 +2201,7 @@ namespace Anabatic { if (_sources.size() < 2) { cdebug_tabw(112,-1); return; } + DbU::Unit gWL = 0; NetRoutingState* state = NetRoutingExtension::get( _net ); //cerr << "state: " << state << endl; @@ -2226,8 +2232,8 @@ namespace Anabatic { vector aligneds; aligneds.push_back( from ); - Vertex* target = source->getPredecessor(); - Interval constraint = from->getSide(); + Vertex* target = source->getPredecessor(); + Interval constraint = from->getSide(); source->setFrom( NULL ); cdebug_log(112,0) << "| " << target << endl; @@ -2286,6 +2292,7 @@ namespace Anabatic { , constraint.getCenter() , width ); + gWL += segment->getLength(); cdebug_log(112,0) << "| ref: " << segment << endl; for ( Edge* through : aligneds ) through->add( segment ); @@ -2305,6 +2312,7 @@ namespace Anabatic { , constraint.getCenter() , width ); + gWL += segment->getLength(); cdebug_log(112,0) << "| ref: " << segment << endl; for ( Edge* through : aligneds ) through->add( segment ); @@ -2322,6 +2330,14 @@ namespace Anabatic { } } + if (gWL > getAntennaMaxWL()) { + cdebug_log(113,0) << "| \"" << _net->getName() << "\" may have antenna effect, " + << DbU::getValueString(gWL) + << endl; + if (state) + state->setFlags( NetRoutingState::HasAntenna ); + } + cdebug_tabw(112,-1); } diff --git a/anabatic/src/GCell.cpp b/anabatic/src/GCell.cpp index 83690322..17e5a8f6 100644 --- a/anabatic/src/GCell.cpp +++ b/anabatic/src/GCell.cpp @@ -508,6 +508,22 @@ namespace Anabatic { } + Segment* GCell::hasGoThrough ( Net* net ) const + { + for ( Edge* edge : _eastEdges ) { + for ( Segment* segment : edge->getSegments() ) { + if (segment->getNet() == net) return segment; + } + } + for ( Edge* edge : _northEdges ) { + for ( Segment* segment : edge->getSegments() ) { + if (segment->getNet() == net) return segment; + } + } + return NULL; + } + + Edge* GCell::getEdgeTo ( GCell* neighbor, Flags sideHint ) const { for ( Edge* edge : getEdges(sideHint) ) { diff --git a/anabatic/src/anabatic/AnabaticEngine.h b/anabatic/src/anabatic/AnabaticEngine.h index ec56fc58..47d1d058 100644 --- a/anabatic/src/anabatic/AnabaticEngine.h +++ b/anabatic/src/anabatic/AnabaticEngine.h @@ -245,6 +245,7 @@ namespace Anabatic { inline bool doDestroyBaseContact () const; inline bool doDestroyBaseSegment () const; inline bool doDestroyTool () const; + inline DbU::Unit getAntennaMaxWL () const; inline DbU::Unit getGlobalThreshold () const; inline float getSaturateRatio () const; inline size_t getSaturateRp () const; @@ -261,6 +262,8 @@ namespace Anabatic { inline void setBlockageNet ( Net* ); void chipPrep (); void computeEdgeCapacities ( int maxHCap, int maxVCap, int termSatThreshold, int maxTermSat ); + void antennaProtect ( Net*, uint32_t& failed, uint32_t& total ); + void antennaProtect (); void setupSpecialNets (); size_t setupPreRouteds (); void loadGlobalRouting ( uint32_t method ); @@ -367,6 +370,7 @@ namespace Anabatic { inline bool AnabaticEngine::doWarnOnGCellOverload () const { return _flags & Flags::WarnOnGCellOverload; } inline bool AnabaticEngine::isInDemoMode () const { return _flags & Flags::DemoMode; } inline bool AnabaticEngine::isChip () const { return _chipTools.isChip(); } + inline DbU::Unit AnabaticEngine::getAntennaMaxWL () const { return getConfiguration()->getAntennaMaxWL(); } inline DbU::Unit AnabaticEngine::getGlobalThreshold () const { return _configuration->getGlobalThreshold(); } inline float AnabaticEngine::getSaturateRatio () const { return _configuration->getSaturateRatio(); } inline size_t AnabaticEngine::getSaturateRp () const { return _configuration->getSaturateRp(); } diff --git a/anabatic/src/anabatic/Configuration.h b/anabatic/src/anabatic/Configuration.h index 32bfbc5b..ad1fc09a 100644 --- a/anabatic/src/anabatic/Configuration.h +++ b/anabatic/src/anabatic/Configuration.h @@ -14,9 +14,7 @@ // +-----------------------------------------------------------------+ -#ifndef ANABATIC_CONFIGURATION_H -#define ANABATIC_CONFIGURATION_H - +#pragma once #include #include @@ -117,6 +115,7 @@ namespace Anabatic { Flags getDirection ( const Layer* ) const; float getSaturateRatio () const; size_t getSaturateRp () const; + inline DbU::Unit getAntennaMaxWL () const; DbU::Unit getGlobalThreshold () const; void setAllowedDepth ( size_t ); void setSaturateRatio ( float ); @@ -159,6 +158,7 @@ namespace Anabatic { float _edgeHInc; float _edgeHScaling; int _globalIterations; + DbU::Unit _antennaMaxWL; private: Configuration& operator= ( const Configuration& ) = delete; void _setTopRoutingLayer ( Name name ); @@ -186,11 +186,10 @@ namespace Anabatic { inline const Layer* Configuration::getDContactLayer () const { return getContactLayer( getDContactDepth() ); } inline DbU::Unit Configuration::getDContactWidth () const { return getWireWidth ( getDContactDepth() ); } inline DbU::Unit Configuration::getDContactPitch () const { return getPitch ( getDContactDepth(), Flags::NoFlags ); } + inline DbU::Unit Configuration::getAntennaMaxWL () const { return _antennaMaxWL; } } // Anabatic namespace. INSPECTOR_P_SUPPORT(Anabatic::Configuration); - -#endif // ANABATIC_CONFIGURATION_H diff --git a/anabatic/src/anabatic/Dijkstra.h b/anabatic/src/anabatic/Dijkstra.h index d2a689fa..53377220 100644 --- a/anabatic/src/anabatic/Dijkstra.h +++ b/anabatic/src/anabatic/Dijkstra.h @@ -522,6 +522,7 @@ namespace Anabatic { inline bool isSourceVertex ( Vertex* ) const; inline Net* getNet () const; inline bool isTargetVertex ( Vertex* ) const; + DbU::Unit getAntennaMaxWL () const; inline DbU::Unit getSearchAreaHalo () const; template inline DistanceT* setDistance ( DistanceT ); diff --git a/anabatic/src/anabatic/GCell.h b/anabatic/src/anabatic/GCell.h index 91757fb1..2495d6d1 100644 --- a/anabatic/src/anabatic/GCell.h +++ b/anabatic/src/anabatic/GCell.h @@ -213,7 +213,8 @@ namespace Anabatic { bool doGrid (); Contact* getGContact ( Net* ); inline const vector& getGContacts () const; - Contact* breakGoThrough ( Net* net ); + Segment* hasGoThrough ( Net* ) const; + Contact* breakGoThrough ( Net* ); bool unrefContact ( Contact* ); void setSouthWestCorner ( DbU::Unit x, DbU::Unit y ); void cleanupGlobal (); diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index 0454c1e9..487796d9 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -72,6 +72,12 @@ namespace { //unsigned const NonConvexOpt = 0x0200; + Instance* extractInstance ( const RoutingPad* rp ) + { + return rp->getOccurrence().getPath().getTailInstance(); + } + + string extractInstanceName ( const RoutingPad* rp ) { ostringstream name; @@ -300,7 +306,8 @@ namespace Etesian { , _placementLB (NULL) , _placementUB (NULL) , _densityLimits(NULL) - , _cellsToIds () + , _netsToIds () + , _instsToIds () , _idsToInsts () , _idsToNets () , _viewer (NULL) @@ -410,8 +417,11 @@ namespace Etesian { delete _placementUB; delete _densityLimits; - unordered_map emptyCellsToIds; - _cellsToIds.swap( emptyCellsToIds ); + NetsToIds emptyNetsToIds; + _netsToIds.swap( emptyNetsToIds ); + + InstancesToIds emptyInstsToIds; + _instsToIds.swap( emptyInstsToIds ); vector emptyIdsToInsts; _idsToInsts.swap( emptyIdsToInsts ); @@ -701,8 +711,8 @@ namespace Etesian { cmess1 << " - Building RoutingPads (transhierarchical) ..." << endl; //getCell()->flattenNets( Cell::Flags::BuildRings|Cell::Flags::NoClockFlatten ); - getCell()->flattenNets( getBlockInstance(), Cell::Flags::NoClockFlatten ); - + //getCell()->flattenNets( getBlockInstance(), Cell::Flags::NoClockFlatten ); + getCell()->flattenNets( NULL, Cell::Flags::NoClockFlatten ); bool tooManyInstances = false; index_t instanceId = 0; @@ -725,8 +735,8 @@ namespace Etesian { positions[instanceId] = point( xpos, ypos ); instances[instanceId].attributes = 0; - _cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) ); - _idsToInsts.push_back( make_tuple(instance,0,0) ); + _instsToIds.insert( make_pair(instance,instanceId) ); + _idsToInsts.push_back( make_tuple(instance,vector()) ); // cerr << "FIXED id=" << instanceId // << " " << instance << " size:(" << xsize << " " << ysize // << ") pos:(" << xpos << " " << ypos << ")" << endl; @@ -799,8 +809,8 @@ namespace Etesian { // << ") pos:(" << xpos << " " << ypos << ")" << endl; } - _cellsToIds.insert( make_pair(instanceName,instanceId) ); - _idsToInsts.push_back( make_tuple(instance,0,0) ); + _instsToIds.insert( make_pair(instance,instanceId) ); + _idsToInsts.push_back( make_tuple(instance,vector()) ); ++instanceId; dots.dot(); } @@ -862,45 +872,56 @@ namespace Etesian { dots.dot(); + _netsToIds.insert( make_pair(net,netId) ); + _idsToNets[netId] = make_tuple( net, _instsToIds.size(), 0 ); nets[netId] = temporary_net( netId, 1 ); - _idsToNets[netId] = make_tuple( net, _cellsToIds.size(), 0 ); //cerr << "+ " << net << endl; - - for ( Pin* pin : net->getPins() ) { - // For Gabriel Gouvine : the position of this pin should be added as a fixed - // attractor in Coloquinte. May be outside the placement area. - Point pt = pin->getPosition(); - topTransformation.applyOn(pt); - int_t xpin = pt.getX() / vpitch; - int_t ypin = pt.getY() / hpitch; - // Dummy last instance - pins.push_back( temporary_pin( point(xpin,ypin), instanceId, netId ) ); - //cerr << "Outside Pin: " << pin << endl; - } string topCellInstancePin = getString(getCell()->getName()) + ":C"; for ( RoutingPad* rp : net->getRoutingPads() ) { - if (getBlockInstance() and (rp->getOccurrence().getPath().getHeadInstance() != getBlockInstance())) { + Path path = rp->getOccurrence().getPath(); + Pin* pin = dynamic_cast( rp->getOccurrence().getEntity() ); + if (pin) { + if (path.isEmpty()) { + Point pt = rp->getCenter(); + int_t xpin = pt.getX() / vpitch; + int_t ypin = pt.getY() / hpitch; + // Dummy last instance + pins.push_back( temporary_pin( point(xpin,ypin), instanceId, netId ) ); + } + continue; + } + + if (getBlockInstance()) { // For Gabriel Gouvine : if there are multiple blocks (i.e. we have a true // floorplan, there may be RoutingPad that are elsewhere. We should check // that the RP is placed or is inside a define area (the abutment box of // it's own block). No example yet of that case, though. - cerr << Warning("Net %s has a routing pad that is not rooted at the placed instance.", getString(net).c_str()) << endl; - //cerr << "Outside RP: " << rp << endl; - continue; + if (path.getHeadInstance() != getBlockInstance()) { + cerr << Warning( "EtesianEngine::toColoquinte(): Net %s has a RoutingPad that is not rooted at the placed instance.\n" + " * Placed instance: %s\n" + " * RoutingPad: %s" + , getString(net).c_str() + , getString(getBlockInstance()).c_str() + , getString(rp->getOccurrence()).c_str() + ) << endl; + //cerr << "Outside RP: " << rp << endl; + continue; + } } - string insName = extractInstanceName( rp ); - Point offset = extractRpOffset ( rp ); + Instance* instance = extractInstance ( rp ); + string insName = extractInstanceName( rp ); + Point offset = extractRpOffset ( rp ); int_t xpin = offset.getX() / vpitch; int_t ypin = offset.getY() / hpitch; - auto iid = _cellsToIds.find( insName ); - if (iid == _cellsToIds.end()) { - if (insName != topCellInstancePin) { + auto iid = _instsToIds.find( instance ); + if (iid == _instsToIds.end()) { + if (not instance) { cerr << Error( "Unable to lookup instance \"%s\".", insName.c_str() ) << endl; } } else { @@ -914,8 +935,6 @@ namespace Etesian { } } } - - //cerr << "| " << rp << " pos:(" << xpin << " " << ypin << ")" << endl; } netId++; @@ -1052,7 +1071,7 @@ namespace Etesian { ostringstream label; label.str(""); label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] " - << setw(5) << setprecision(4) << linearDisruption << "% Bipart."; + << setw(7) << fixed << setprecision(1) << linearDisruption << "% Bipart."; _progressReport1(label.str() ); upperWL = static_cast(get_HPWL_wirelength(*_circuit, *_placementUB)); @@ -1070,7 +1089,7 @@ namespace Etesian { , pullingForce , 2.0f * linearDisruption); solve_linear_system( *_circuit, *_placementLB, solv, 200 ); // 200 iterations - _progressReport2(" Linear." ); + _progressReport2(" Linear." ); if(options & UpdateLB) _updatePlacement( _placementUB ); @@ -1078,7 +1097,7 @@ namespace Etesian { // Optimize orientation sometimes if (i%5 == 0) { optimize_exact_orientations( *_circuit, *_placementLB ); - _progressReport2(" Orient." ); + _progressReport2(" Orient." ); } lowerWL = static_cast(get_HPWL_wirelength(*_circuit, *_placementLB)); @@ -1093,8 +1112,8 @@ namespace Etesian { penaltyIncrease = std::min(maxInc, std::max(minInc, penaltyIncrease * std::sqrt( targetImprovement / (optRatio - prevOptRatio) ) ) ); - cparanoid << " L/U ratio: " << 100*optRatio << "% (previous: " << 100*prevOptRatio << "%)\n" - << " Pulling force: " << pullingForce << " Increase: " << penaltyIncrease << endl; + cparanoid << " L/U ratio: " << 100*optRatio << "% (previous: " << 100*prevOptRatio << "%)\n" + << " Pulling force: " << pullingForce << " Increase: " << penaltyIncrease << endl; pullingForce += penaltyIncrease; prevOptRatio = optRatio; @@ -1103,7 +1122,7 @@ namespace Etesian { ++i; if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) { - antennaProtect(); + //antennaProtect(); antennaDone = true; } // First way to exit the loop: UB and LB difference is <10% @@ -1187,31 +1206,33 @@ namespace Etesian { cdebug_log(122,0) << "diodeWidth=" << diodeWidth << "p" << endl; for ( coloquinte::index_t inet=0 ; inet < _circuit->net_cnt() ; ++inet ) { - DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) ); - size_t idriver = std::get<1>( _idsToNets[inet] ); - if (idriver >= _cellsToIds.size()) continue; + DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) ); + Net* net = std::get<0>( _idsToNets[inet] ); - Instance* instance = std::get<0>( _idsToInsts[idriver] ); - string masterName = getString( instance->getMasterCell()->getName() ); - uint32_t drivePower = 1; - if (masterName.substr(masterName.size()-3,2) == "_x") { - drivePower = std::stoi( masterName.substr(masterName.size()-1) ); - } - - if (rsmt > drivePower*maxWL) { - Net* net = std::get<0>( _idsToNets[inet] ); + if ((rsmt > maxWL) or net->isExternal()) { cdebug_log(122,0) << "| Net [" << inet << "] \"" << net->getName() << "\" may have antenna effect, " << DbU::getValueString(rsmt) - << " drive=" << drivePower - << " \"" << masterName << "\"" << endl; - std::get<2>( _idsToNets [inet ] ) |= NeedsDiode; - std::get<2>( _idsToInsts[idriver] ) |= NeedsDiode; - std::get<1>( _idsToInsts[idriver] ) = inet; - coloquinte::point cell_size = _circuit->get_cell_size(idriver); - cell_size.x += diodeWidth; - _circuit->set_cell_size( idriver, cell_size ); - ++count; + std::get<2>( _idsToNets[inet] ) |= NeedsDiode; + + for ( RoutingPad* rp : net->getRoutingPads() ) { + Segment* segment = dynamic_cast( rp->getOccurrence().getEntity() ); + if (not segment) continue; + if (segment->getNet()->getDirection() & Net::Direction::DirOut) continue; + + Instance* instance = extractInstance( rp ); + if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) + continue; + + auto iinst = _instsToIds.find( instance ); + if (iinst == _instsToIds.end()) continue; + + std::get<1>( _idsToInsts[ (*iinst).second ] ).push_back( rp ); + coloquinte::point cell_size = _circuit->get_cell_size( (*iinst).second ); + cell_size.x += 2*diodeWidth; + _circuit->set_cell_size( (*iinst).second, cell_size ); + ++count; + } } } cmess1 << ::Dots::asInt( " - Inserted diodes", count ) << endl; @@ -1383,7 +1404,8 @@ namespace Etesian { if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation(); topTransformation.invert(); - vector< tuple > diodeMasters; + DbU::Unit diodeWidth = (_diodeCell) ? _diodeCell->getAbutmentBox().getWidth() : 0; + vector< tuple > diodeInsts; for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) ) { @@ -1396,14 +1418,14 @@ namespace Etesian { instanceName.erase( 0, 1 ); instanceName.erase( instanceName.size()-1 ); - auto iid = _cellsToIds.find( instanceName ); - if (iid == _cellsToIds.end() ) { + auto iid = _instsToIds.find( instance ); + if (iid == _instsToIds.end() ) { cerr << Error( "Unable to lookup instance <%s>.", instanceName.c_str() ) << endl; } else { if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) continue; - uint32_t outputSide = getOutputSide( instance->getMasterCell() ); + //uint32_t outputSide = getOutputSide( instance->getMasterCell() ); point position = placement->positions_[(*iid).second]; Transformation cellTrans = toTransformation( position , placement->orientations_[(*iid).second] @@ -1412,33 +1434,28 @@ namespace Etesian { , vpitch ); topTransformation.applyOn( cellTrans ); - //cerr << "Setting <" << instanceName << " @" << instancePosition << endl; + //if (flags & FinalStage) + // cerr << "Raw position of <" << instanceName << " @" << cellTrans << endl; - if ((flags & FinalStage) and (std::get<2>(_idsToInsts[(*iid).second]) & NeedsDiode)) { - Transformation diodeTrans; - - if (outputSide & RightSide) { - DbU::Unit dx = instance ->getMasterCell()->getAbutmentBox().getWidth(); - if ( (cellTrans.getOrientation() == Transformation::Orientation::R2) - or (cellTrans.getOrientation() == Transformation::Orientation::MX)) - dx = -dx; - diodeTrans = Transformation( cellTrans.getTx() + dx - , cellTrans.getTy() - , cellTrans.getOrientation() ); - } else { - DbU::Unit dx = _diodeCell->getAbutmentBox().getWidth(); - if ( (cellTrans.getOrientation() == Transformation::Orientation::R2) - or (cellTrans.getOrientation() == Transformation::Orientation::MX)) - dx = -dx; - diodeTrans = cellTrans; - cellTrans = Transformation( diodeTrans.getTx() + dx - , diodeTrans.getTy() - , diodeTrans.getOrientation() ); + const vector& rps = std::get<1>( _idsToInsts[(*iid).second] ); + if ((flags & FinalStage) and not rps.empty()) { + DbU::Unit sign = 1; + DbU::Unit cellWidth = instance->getMasterCell()->getAbutmentBox().getWidth(); + cdebug_log(122,0) << "cellWidth=" << DbU::getValueString(cellWidth) << endl; + cdebug_log(122,0) << "diodeWidth=" << DbU::getValueString(diodeWidth) << endl; + if ( (cellTrans.getOrientation() == Transformation::Orientation::R2) + or (cellTrans.getOrientation() == Transformation::Orientation::MX)) { + sign = -1; + } + for ( size_t i=0 ; i(_idsToInsts[(*iid).second]) - , diodeTrans )); } // This is temporary as it's not trans-hierarchic: we ignore the positions @@ -1456,35 +1473,28 @@ namespace Etesian { break; } - for ( auto diodeInfos : diodeMasters ) { - Net* topNet = std::get<0>( _idsToNets[ std::get<1>(diodeInfos) ] ); - Instance* instance = static_cast( std::get<0>(diodeInfos).getEntity() ); - Cell* ownerCell = instance->getCell(); - Instance* diode = _createDiode( ownerCell ); - diode->setTransformation( std::get<2>( diodeInfos )); + for ( auto diodeInfos : diodeInsts ) { + RoutingPad* rp = std::get<0>( diodeInfos ); + Net* topNet = rp->getNet(); + Instance* instance = extractInstance( rp ); + Cell* ownerCell = instance->getCell(); + Instance* diode = _createDiode( ownerCell ); + diode->setTransformation ( std::get<1>( diodeInfos )); diode->setPlacementStatus( Instance::PlacementStatus::PLACED ); - Net* driverOutput = NULL; - for ( Net* net : instance->getMasterCell()->getNets() ) { - if (net->isSupply() or not net->isExternal()) continue; - if (net->getDirection() & Net::Direction::DirOut) { - driverOutput = net; - break; - } - } + cdebug_log(122,0) << "Driver net=" << topNet << endl; + cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl; - if (diodeOutput and driverOutput) { - cdebug_log(122,0) << "Bind:" << endl; - Plug* diodePlug = diode ->getPlug( diodeOutput ); - Plug* driverPlug = instance->getPlug( driverOutput ); - diodePlug->setNet( driverPlug->getNet() ); + Plug* sinkPlug = dynamic_cast( rp->getPlugOccurrence().getEntity() ); + if (sinkPlug) { + cdebug_log(122,0) << " Bind diode input:" << endl; + Plug* diodePlug = diode->getPlug( diodeOutput ); + diodePlug->setNet( sinkPlug->getNet() ); - cdebug_log(122,0) << " Driver net=" << topNet << endl; - cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl; - cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl; - cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl; - cdebug_log(122,0) << " " << std::get<0>(diodeInfos).getPath() << endl; - Path path = std::get<0>(diodeInfos).getPath(); + cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl; + cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl; + cdebug_log(122,0) << " " << rp->getOccurrence().getPath() << endl; + Path path = rp->getOccurrence().getPath().getHeadPath(); RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea ); } } @@ -1499,7 +1509,15 @@ namespace Etesian { Instance* EtesianEngine::_createDiode ( Cell* owner ) { if (not _diodeCell) return NULL; - return Instance::create( owner, string("diode_")+getString(_getNewDiodeId()), _diodeCell ); + return Instance::create( owner, getUniqueDiodeName(), _diodeCell ); + } + + + string EtesianEngine::getUniqueDiodeName () + { + ostringstream os; + os << "diode_" << _getNewDiodeId(); + return os.str(); } diff --git a/etesian/src/Placement.cpp b/etesian/src/Placement.cpp index ab189df1..b7c0d24a 100644 --- a/etesian/src/Placement.cpp +++ b/etesian/src/Placement.cpp @@ -18,7 +18,9 @@ #include "hurricane/Warning.h" #include "hurricane/DataBase.h" #include "hurricane/UpdateSession.h" +#include "hurricane/DeepNet.h" #include "hurricane/Plug.h" +#include "hurricane/RoutingPad.h" #include "hurricane/Path.h" #include "hurricane/Library.h" #include "hurricane/viewer/CellWidget.h" @@ -38,6 +40,9 @@ namespace Etesian { using Hurricane::Transformation; using Hurricane::DataBase; using Hurricane::Library; + using Hurricane::DeepNet; + using Hurricane::Plug; + using Hurricane::RoutingPad; using Hurricane::UpdateSession; using CRL::AllianceFramework; using CRL::CatalogExtension; @@ -238,26 +243,29 @@ namespace Etesian { if (feed == NULL) break; } - Instance* instance = Instance::create + Point blockPoint = getEtesian()->toBlock( Point(xtie,_ybottom) ); + Instance* instance = Instance::create ( getEtesian()->getBlockCell() , getEtesian()->getFeedCells().getUniqueInstanceName().c_str() , feed , getTransformation( feed->getAbutmentBox() - , xtie - , _ybottom - , (yspin)?Transformation::Orientation::MY - :Transformation::Orientation::ID + , blockPoint.getX() + , blockPoint.getY() + , (yspin) ? Transformation::Orientation::MY + : Transformation::Orientation::ID ) , Instance::PlacementStatus::PLACED ); _tiles.insert( before - , Tile( xtie, feed->getAbutmentBox().getWidth(), Occurrence(instance) )); + , Tile( xtie + , feed->getAbutmentBox().getWidth() + , getEtesian()->toCell( Occurrence(instance) ))); xtie += feedWidth; } } - Instance* Slice::createDiodeUnder ( const Box& diodeArea ) + Instance* Slice::createDiodeUnder ( RoutingPad* rp, const Box& diodeArea, DbU::Unit xHint ) { Cell* diode = getEtesian()->getDiodeCell(); if (diode == NULL) { @@ -270,15 +278,61 @@ namespace Etesian { return NULL; } - Instance* diodeInst = NULL; + cdebug_log(147,0) << "Slice::createDiodeUnder(): xHint=" << DbU::getValueString(xHint) << endl; + cdebug_log(147,0) << " rp=" << rp << endl; + cdebug_log(147,0) << " diodeArea=" << diodeArea << endl; + + Instance* blockInst = getEtesian()->getBlockInstance(); + Instance* diodeInst = NULL; + bool foundCandidate = false; + auto iCandidate = _tiles.begin(); + DbU::Unit dCandidate = 0; for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) { - if ((*iTile).getXMax() < diodeArea.getXMin()) continue; - if ((*iTile).getXMax() >= diodeArea.getXMax()) break; + if ((*iTile).getXMax() <= diodeArea.getXMin()) continue; + if ((*iTile).getXMin() >= diodeArea.getXMax()) break; if ((*iTile).getMasterCell() != feed) continue; - diodeInst = (*iTile).getInstance(); - diodeInst->setMasterCell( diode ); - break; + if (blockInst) { + if ((*iTile).getOccurrence().getPath().getHeadInstance() != blockInst) + continue; + } + DbU::Unit distance = std::abs( (*iTile).getXMin() - xHint ); + if (not foundCandidate or (distance < dCandidate)) { + foundCandidate = true; + iCandidate = iTile; + dCandidate = distance; + } } + + if (not foundCandidate) return NULL; + + auto before = iCandidate; + before++; + + DbU::Unit xmin = (*iCandidate).getXMin(); + DbU::Unit width = (*iCandidate).getWidth(); + diodeInst = (*iCandidate).getInstance(); + Transformation transf = diodeInst->getTransformation(); + diodeInst->destroy(); + _tiles.erase( iCandidate ); + + Occurrence rpOccurrence = rp->getPlugOccurrence(); + Path instancePath = rpOccurrence.getPath(); + if (instancePath.isEmpty()) + transf = getEtesian()->toCell( transf ); + // transf = getEtesian()->toBlock( transf ); + // if (instancePath.isEmpty() and blockInst) { + // Transformation blockTransf = blockInst->getTransformation(); + // blockTransf.applyOn( transf ); + // } + Plug* plug = static_cast( rpOccurrence.getEntity() ); + diodeInst = Instance::create( plug->getCell() + , getEtesian()->getUniqueDiodeName() + , diode + , transf + , Instance::PlacementStatus::FIXED ); + _tiles.insert( before, Tile(xmin,width,Occurrence(diodeInst,instancePath)) ); + cdebug_log(147,0) << " " << diodeInst << " @" << transf << endl; + return diodeInst; } @@ -301,10 +355,13 @@ namespace Etesian { Area::Area ( EtesianEngine* etesian ) : _etesian (etesian) , _tieLut () - , _cellAb (etesian->getBlockCell()->getAbutmentBox()) + , _cellAb (etesian->getCell()->getAbutmentBox()) , _sliceHeight(_etesian->getSliceHeight()) , _slices () { + if (etesian->getBlockInstance()) + _cellAb = etesian->getBlockInstance()->getAbutmentBox(); + size_t slicesNb = _cellAb.getHeight() / _sliceHeight; for ( size_t islice=0 ; islicegetBlockInstance()->getTransformation(); + //toBlockTransf.invert(); + Box blockDiodeArea ( diodeArea ); + //toBlockTransf.applyOn( blockDiodeArea ); + //xHint += toBlockTransf.getTx(); + + DbU::Unit y = blockDiodeArea.getYCenter(); if ((y < _cellAb.getYMin()) or (y >= _cellAb.getYMax())) return NULL; - if (not diodeArea.intersect(_cellAb)) return NULL; + if (not blockDiodeArea.intersect(_cellAb)) return NULL; size_t islice = (y - _cellAb.getYMin()) / _sliceHeight; - return _slices[islice]->createDiodeUnder( diodeArea ); + return _slices[islice]->createDiodeUnder( rp, blockDiodeArea, xHint ); } @@ -595,18 +658,16 @@ namespace Etesian { if (_area) delete _area; _area = new Area ( this ); - Box topCellAb = getBlockCell()->getAbutmentBox(); + Box topCellAb = getCell()->getAbutmentBox(); _area->setSpinSlice0( _yspinSlice0 ); if (getBlockInstance()) { - Transformation toBlockTransf = getBlockInstance()->getTransformation(); - toBlockTransf.invert(); + topCellAb = getBlockInstance()->getAbutmentBox(); for ( Instance* instance : getCell()->getInstances() ) { if (instance == getBlockInstance()) continue; if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) { Box overlapAb = instance->getAbutmentBox(); - toBlockTransf.applyOn( overlapAb ); overlapAb = topCellAb.getIntersection( overlapAb ); if (not overlapAb.isEmpty()) { _area->merge( Occurrence(instance), overlapAb ); @@ -617,7 +678,7 @@ namespace Etesian { for ( Occurrence occurrence : getBlockCell()->getTerminalNetlistInstanceOccurrences() ) { - Instance* instance = static_cast(occurrence.getEntity()); + Instance* instance = static_cast( occurrence.getEntity() ); Cell* masterCell = instance->getMasterCell(); if (CatalogExtension::isFeed(masterCell)) { @@ -625,19 +686,23 @@ namespace Etesian { , getString(instance->getName()).c_str() ) << endl; } - Box instanceAb = masterCell->getAbutmentBox(); - - Transformation instanceTransf = instance->getTransformation(); - occurrence.getPath().getTransformation().applyOn( instanceTransf ); - instanceTransf.applyOn( instanceAb ); + Box instanceAb = instance->getAbutmentBox(); + Occurrence cellOccurrence = toCell( occurrence ); + cellOccurrence.getPath().getTransformation().applyOn( instanceAb ); if (not topCellAb.contains(instanceAb)) { - cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell." - , getString(instance->getName()).c_str() ) << endl; + cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell.\n" + " * topCellAb=%s\n" + " * instanceAb=%s cell=%s" + , getString(instance->getName()).c_str() + , getString(topCellAb).c_str() + , getString(instanceAb).c_str() + , getString(instance->getCell()).c_str() + ) << endl; continue; } - _area->merge( occurrence, instanceAb ); + _area->merge( cellOccurrence, instanceAb ); } _area->buildSubSlices(); diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index 5c06c828..88e9f337 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -25,6 +25,7 @@ namespace Hurricane { class Layer; class Net; + class RoutingPad; class Cell; class CellWidget; class CellViewer; @@ -43,10 +44,15 @@ namespace Etesian { using Hurricane::Timer; using Hurricane::Name; using Hurricane::Layer; + using Hurricane::DBo; using Hurricane::Net; + using Hurricane::RoutingPad; using Hurricane::Cell; using Hurricane::Record; using Hurricane::Instance; + using Hurricane::Point; + using Hurricane::Path; + using Hurricane::Transformation; // ------------------------------------------------------------------- @@ -60,8 +66,10 @@ namespace Etesian { static const uint32_t LeftSide = (1<<3); public: typedef ToolEngine Super; - typedef std::tuple NetInfos; - typedef std::tuple InstanceInfos; + typedef std::tuple NetInfos; + typedef std::tuple > InstanceInfos; + typedef std::map InstancesToIds; + typedef std::map NetsToIds; public: static const Name& staticGetName (); static EtesianEngine* create ( Cell* ); @@ -88,6 +96,8 @@ namespace Etesian { inline DbU::Unit getLatchUpDistance () const; inline const FeedCells& getFeedCells () const; inline Cell* getDiodeCell () const; + std::string getUniqueDiodeName (); + inline Area* getArea () const; inline Hurricane::CellViewer* getViewer () const; inline void setViewer ( Hurricane::CellViewer* ); inline Cell* getBlockCell () const; @@ -103,6 +113,13 @@ namespace Etesian { void clearColoquinte (); void loadLeafCellLayouts (); inline DbU::Unit toDbU ( int64_t ) const; + inline Occurrence toCell ( Occurrence ) const; + inline Point toCell ( const Point& ) const; + inline Transformation toCell ( Transformation ) const; + inline Path toBlock ( Path ) const; + inline Occurrence toBlock ( Occurrence ) const; + inline Point toBlock ( const Point& ) const; + inline Transformation toBlock ( const Transformation& ) const; size_t toColoquinte (); void preplace (); void roughLegalize ( float minDisruption, unsigned options ); @@ -120,31 +137,32 @@ namespace Etesian { virtual std::string _getTypeName () const; private: // Attributes. - static Name _toolName; + static Name _toolName; protected: - Configuration* _configuration; - Instance* _block; - bool _placed; - bool _ySpinSet; - bool _flatDesign; - coloquinte::box* _surface; - coloquinte::netlist* _circuit; - coloquinte::placement_t* _placementLB; - coloquinte::placement_t* _placementUB; - coloquinte::density_restrictions* _densityLimits; - std::unordered_map _cellsToIds; - std::vector _idsToInsts; - std::vector _idsToNets; - Hurricane::CellViewer* _viewer; - Cell* _diodeCell; - FeedCells _feedCells; - BloatCells _bloatCells; - Area* _area; - size_t _yspinSlice0; - DbU::Unit _sliceHeight; - DbU::Unit _fixedAbHeight; - DbU::Unit _fixedAbWidth; - uint32_t _diodeCount; + Configuration* _configuration; + Instance* _block; + bool _placed; + bool _ySpinSet; + bool _flatDesign; + coloquinte::box* _surface; + coloquinte::netlist* _circuit; + coloquinte::placement_t* _placementLB; + coloquinte::placement_t* _placementUB; + coloquinte::density_restrictions* _densityLimits; + NetsToIds _netsToIds; + InstancesToIds _instsToIds; + std::vector _idsToInsts; + std::vector _idsToNets; + Hurricane::CellViewer* _viewer; + Cell* _diodeCell; + FeedCells _feedCells; + BloatCells _bloatCells; + Area* _area; + size_t _yspinSlice0; + DbU::Unit _sliceHeight; + DbU::Unit _fixedAbHeight; + DbU::Unit _fixedAbWidth; + uint32_t _diodeCount; protected: // Constructors & Destructors. @@ -197,6 +215,81 @@ namespace Etesian { inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); } inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); } inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; } + inline Area* EtesianEngine::getArea () const { return _area; } + + + inline Occurrence EtesianEngine::toCell ( Occurrence blockOccurrence ) const + { + if (not _block) return blockOccurrence; + if (blockOccurrence.getOwnerCell() != getBlockCell()) { + std::cerr << Error( "EtesianEngine::toCell(Occurrence): %s" + "\n Is *not* rooted to the block %s but to %s." + , getString(blockOccurrence).c_str() + , getString(getBlockCell()).c_str() + , getString(blockOccurrence.getOwnerCell()).c_str() + ) << std::endl; + return blockOccurrence; + } + return Occurrence( blockOccurrence.getEntity(), Path(_block,blockOccurrence.getPath()) ); + } + + + inline Point EtesianEngine::toCell ( const Point& blockPoint ) const + { + if (not _block) return blockPoint; + Point cellPoint = blockPoint; + _block->getTransformation().applyOn( cellPoint ); + return cellPoint; + } + + + inline Transformation EtesianEngine::toCell ( Transformation blockTransf ) const + { + if (not _block) return blockTransf; + return _block->getTransformation().getTransformation( blockTransf ); + } + + + inline Path EtesianEngine::toBlock ( Path cellPath ) const + { + if (not _block) return cellPath; + if (cellPath.getHeadInstance() != getBlockInstance()) { + std::cerr << Error( "EtesianEngine::toBlock(Path): %s" + "\n Do *not* go through the block %s but through %s." + , getString(cellPath).c_str() + , getString(getBlockInstance()).c_str() + , getString(cellPath.getHeadInstance()).c_str() + ) << std::endl; + return cellPath; + } + return cellPath.getTailPath(); + } + + + inline Occurrence EtesianEngine::toBlock ( Occurrence cellOccurrence ) const + { + if (not _block) return cellOccurrence; + return Occurrence( cellOccurrence.getEntity(), toBlock(cellOccurrence.getPath()) ); + } + + + inline Point EtesianEngine::toBlock ( const Point& cellPoint ) const + { + if (not _block) return cellPoint; + Point blockPoint = cellPoint; + Transformation blockTransf = _block->getTransformation(); + blockTransf.invert().applyOn( blockPoint ); + return blockPoint; + } + + + inline Transformation EtesianEngine::toBlock ( const Transformation& cellTransf ) const + { + if (not _block) return cellTransf; + Transformation blockTransf = _block->getTransformation(); + return blockTransf.invert().getTransformation( cellTransf ); + } + // Variables. extern const char* missingEtesian; diff --git a/etesian/src/etesian/Placement.h b/etesian/src/etesian/Placement.h index 330c896a..f71c566b 100644 --- a/etesian/src/etesian/Placement.h +++ b/etesian/src/etesian/Placement.h @@ -21,6 +21,9 @@ #include "hurricane/Interval.h" #include "hurricane/Instance.h" #include "hurricane/Occurrence.h" +namespace Hurricane { + class RoutingPad; +} namespace Etesian { @@ -32,6 +35,7 @@ namespace Etesian { using Hurricane::Interval; using Hurricane::DBo; using Hurricane::Cell; + using Hurricane::RoutingPad; using Hurricane::Instance; using Hurricane::Transformation; using Hurricane::Occurrence; @@ -232,7 +236,7 @@ namespace Etesian { void buildSubSlices (); void showSubSlices (); void insertTies ( DbU::Unit latchUpMax ); - Instance* createDiodeUnder ( const Box& ); + Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint ); inline std::string _getString () const; Record* _getRecord () const; private: @@ -270,7 +274,7 @@ namespace Etesian { void buildSubSlices (); void showSubSlices (); void insertTies ( DbU::Unit latchUpMax ); - Instance* createDiodeUnder ( const Box& ); + Instance* createDiodeUnder ( RoutingPad*, const Box&, DbU::Unit xHint ); inline std::string _getString () const; Record* _getRecord () const; private: diff --git a/katana/src/GlobalRoute.cpp b/katana/src/GlobalRoute.cpp index 808e3c5d..9d7a96f7 100644 --- a/katana/src/GlobalRoute.cpp +++ b/katana/src/GlobalRoute.cpp @@ -494,7 +494,7 @@ namespace Katana { throw Error ("KatanaEngine::runGlobalRouter(): Global routing already done or loaded."); if (flags & Flags::ShowBloatedInstances) selectBloatedInstances( this ); - Breakpoint::stop( 1, "Bloated cells from previous placement iteration." ); + Breakpoint::stop( 100, "Bloated cells from previous placement iteration." ); startMeasures(); cmess1 << " o Running global routing." << endl;