// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC/LIP6 2008-2010, All Rights Reserved // // =================================================================== // // $Id$ // // x-----------------------------------------------------------------x // | | // | C O R I O L I S | // | K i t e - D e t a i l e d R o u t e r | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@asim.lip6.fr | // | =============================================================== | // | C++ Module : "./KiteEngine.cpp" | // | *************************************************************** | // | U p d a t e s | // | | // x-----------------------------------------------------------------x #include #include #include #include "hurricane/Bug.h" #include "hurricane/Error.h" #include "hurricane/Warning.h" #include "hurricane/Layer.h" #include "hurricane/Net.h" #include "hurricane/Pad.h" #include "hurricane/Plug.h" #include "hurricane/Cell.h" #include "hurricane/Instance.h" #include "hurricane/Vertical.h" #include "hurricane/Horizontal.h" #include "hurricane/UpdateSession.h" #include "crlcore/Measures.h" #include "knik/KnikEngine.h" #include "katabatic/AutoContact.h" #include "kite/DataNegociate.h" #include "kite/GCellGrid.h" #include "kite/RoutingPlane.h" #include "kite/Session.h" #include "kite/GCellRoutingSet.h" #include "kite/NegociateWindow.h" #include "kite/KiteEngine.h" namespace Kite { using std::cout; using std::cerr; using std::endl; using std::setw; using std::left; using std::ofstream; using std::ostringstream; using std::setprecision; using Hurricane::tab; using Hurricane::inltrace; using Hurricane::ltracein; using Hurricane::ltraceout; using Hurricane::ForEachIterator; using Hurricane::Bug; using Hurricane::Error; using Hurricane::Warning; using Hurricane::Layer; using Hurricane::Cell; using CRL::addMeasure; using CRL::Measures; using CRL::MeasuresSet; using Knik::KnikEngine; const char* missingRW = "%s :\n\n" " Cell %s do not have any KiteEngine (or not yet created).\n"; // ------------------------------------------------------------------- // Class : "Kite::KiteEngine". Name KiteEngine::_toolName = "Kite"; const Name& KiteEngine::staticGetName () { return _toolName; } KiteEngine* KiteEngine::get ( const Cell* cell ) { return static_cast(ToolEngine::get(cell,staticGetName())); } KiteEngine::KiteEngine ( Cell* cell ) : KatabaticEngine (cell) , _knik (NULL) , _obstacleNet (NULL) , _configuration (new Configuration(getKatabaticConfiguration())) , _routingPlanes () , _kiteGrid (NULL) , _negociateWindow (NULL) , _trackSegmentLut () , _minimumWL (0.0) , _toolSuccess (false) { //_configuration->setAllowedDepth ( 3 ); } void KiteEngine::_postCreate () { KatabaticEngine::_postCreate (); #ifdef KNIK_NOT_EMBEDDED size_t maxDepth = getRoutingGauge()->getDepth(); _kiteGrid = GCellGrid::create ( this ); _routingPlanes.reserve ( maxDepth ); for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { _routingPlanes.push_back ( RoutingPlane::create ( this, depth ) ); } #endif } KiteEngine* KiteEngine::create ( Cell* cell ) { KiteEngine* kite = new KiteEngine ( cell ); kite->_postCreate (); return kite; } void KiteEngine::_preDestroy () { ltrace(90) << "KiteEngine::_preDestroy ()" << endl; ltracein(90); cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <" << _cell->getName() << ">" << endl; if ( getState() < Katabatic::StateGutted ) setState ( Katabatic::StatePreDestroying ); _gutKite (); KatabaticEngine::_preDestroy (); cmess2 << " - RoutingEvents := " << RoutingEvent::getAllocateds() << endl; //_knik->destroy (); ltraceout(90); } KiteEngine::~KiteEngine () { delete _configuration; } const Name& KiteEngine::getName () const { return _toolName; } Configuration* KiteEngine::getConfiguration () { return _configuration; } unsigned int KiteEngine::getRipupLimit ( const TrackElement* segment ) const { if ( segment->isBlockage() ) return 0; if ( segment->getDataNegociate() ) { if ( segment->getDataNegociate()->isBorder() ) return _configuration->getRipupLimit(Configuration::BorderRipupLimit); if ( segment->getDataNegociate()->isRing() ) return _configuration->getRipupLimit(Configuration::GlobalRipupLimit); } if ( segment->isStrap () ) return _configuration->getRipupLimit(Configuration::StrapRipupLimit); if ( segment->isGlobal() ) { vector gcells; segment->getGCells(gcells); if ( gcells.size() > 2 ) return _configuration->getRipupLimit(Configuration::LongGlobalRipupLimit); return _configuration->getRipupLimit(Configuration::GlobalRipupLimit); } return _configuration->getRipupLimit(Configuration::LocalRipupLimit); } RoutingPlane* KiteEngine::getRoutingPlaneByIndex ( size_t index ) const { if ( index >= getRoutingPlanesSize() ) return NULL; return _routingPlanes[index]; } RoutingPlane* KiteEngine::getRoutingPlaneByLayer ( const Layer* layer ) const { for ( size_t index=0 ; index < getRoutingPlanesSize() ; index++ ) { if ( _routingPlanes[index]->getLayer() == layer ) return _routingPlanes[index]; } return NULL; } Track* KiteEngine::getTrackByPosition ( const Layer* layer, DbU::Unit axis, unsigned int mode ) const { RoutingPlane* plane = getRoutingPlaneByLayer ( layer ); if ( !plane ) return NULL; return plane->getTrackByPosition ( axis, mode ); } void KiteEngine::setInterrupt ( bool state ) { if ( _negociateWindow ) { _negociateWindow->setInterrupt ( state ); cerr << "Interrupt [CRTL+C] of " << this << endl; } } void KiteEngine::createGlobalGraph ( unsigned int mode ) { Cell* cell = getCell(); if ( not _knik ) { if ( cell->getRubbers().getFirst() == NULL ) cell->flattenNets ( (mode==BuildGlobalSolution) ); KnikEngine::setEdgeCapacityPercent ( getEdgeCapacityPercent() ); _knik = KnikEngine::create ( cell , 1 // _congestion , 2 // _preCongestion , false // _benchMode , true // _useSegments , 2.5 // _edgeCost ); //if ( mode == LoadGlobalSolution ) _knik->createRoutingGraph (); } } void KiteEngine::createDetailedGrid () { KatabaticEngine::createDetailedGrid (); _kiteGrid = GCellGrid::create ( this ); size_t maxDepth = getRoutingGauge()->getDepth(); _routingPlanes.reserve ( maxDepth ); for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { _routingPlanes.push_back ( RoutingPlane::create ( this, depth ) ); } } void KiteEngine::saveGlobalSolution () { if ( getState() < Katabatic::StateGlobalLoaded ) throw Error ("KiteEngine::saveGlobalSolution() : global routing not present yet."); if ( getState() > Katabatic::StateGlobalLoaded ) throw Error ("KiteEngine::saveGlobalSolution() : cannot save after detailed routing."); _knik->saveSolution (); } void KiteEngine::annotateGlobalGraph () { cmess1 << " o Back annotate global routing graph." << endl; for ( size_t depth=0 ; depth<_routingPlanes.size() ; ++depth ) { RoutingPlane* rp = _routingPlanes[depth]; if ( rp->getLayerGauge()->getType() == Constant::PinOnly ) continue; size_t tracksSize = rp->getTracksSize(); for ( size_t itrack=0 ; itrackgetTrackByIndex ( itrack ); TrackElement* element = track->getSegment ( (size_t)0 ); if ( element == NULL ) continue; if ( element->getNet() == NULL ) continue; if ( not element->getNet()->isSupply() ) continue; cinfo << "Capacity from: " << element << endl; if ( track->getDirection() == Constant::Horizontal ) { for ( ; element != NULL ; element = element->getNext() ) { GCell* gcell = _kiteGrid->getGCell ( Point(element->getSourceU(),track->getAxis()) ); GCell* end = _kiteGrid->getGCell ( Point(element->getTargetU(),track->getAxis()) ); GCell* right = NULL; if ( not gcell ) { cerr << Warning("annotageGlobalGraph(): TrackElement outside GCell grid.") << endl; continue; } while ( gcell and (gcell != end) ) { right = gcell->getRight(); if ( right == NULL ) break; _knik->increaseEdgeCapacity ( gcell->getColumn() , gcell->getRow() , right->getColumn() , right->getRow() , -1 ); gcell = right; } } } else { for ( ; element != NULL ; element = element->getNext() ) { GCell* gcell = _kiteGrid->getGCell ( Point(track->getAxis(),element->getSourceU()) ); GCell* end = _kiteGrid->getGCell ( Point(track->getAxis(),element->getTargetU()) ); GCell* up = NULL; if ( not gcell ) { cerr << Warning("annotageGlobalGraph(): TrackElement outside GCell grid.") << endl; continue; } while ( gcell and (gcell != end) ) { up = gcell->getUp(); if ( up == NULL ) break; _knik->increaseEdgeCapacity ( gcell->getColumn() , gcell->getRow() , up->getColumn() , up->getRow() , -1 ); gcell = up; } } } } } } void KiteEngine::runGlobalRouter ( unsigned int mode ) { if ( getState() >= Katabatic::StateGlobalLoaded ) throw Error ("KiteEngine::runGlobalRouter() : global routing already done or loaded."); Session::open ( this ); createGlobalGraph ( mode ); createDetailedGrid (); buildBlockages (); buildPowerRails (); if ( mode == LoadGlobalSolution ) { _knik->loadSolution (); } else { annotateGlobalGraph (); _knik->run (); } setState ( Katabatic::StateGlobalLoaded ); Session::close (); } void KiteEngine::loadGlobalRouting ( unsigned int method, KatabaticEngine::NetSet& nets ) { KatabaticEngine::loadGlobalRouting ( method, nets ); Session::open ( this ); getGCellGrid()->checkEdgeSaturation ( getEdgeCapacityPercent() ); Session::close (); } void KiteEngine::runNegociate ( unsigned int slowMotion ) { if ( _negociateWindow ) return; unsigned int rows = _kiteGrid->getRows(); unsigned int columns = _kiteGrid->getColumns(); startMeasures (); Session::open ( this ); cmess1 << " o Running Negociate Algorithm" << endl; _negociateWindow = NegociateWindow::create ( this, 0, 0, columns, rows ); _negociateWindow->loadRouting (); preProcess (); _computeCagedConstraints (); _negociateWindow->run ( slowMotion ); _negociateWindow->printStatistics (); _negociateWindow->destroy (); _negociateWindow = NULL; Session::close (); //if ( _editor ) _editor->refresh (); stopMeasures (); printMeasures ( "algo" ); printCompletion (); Session::open ( this ); unsigned int overlaps = 0; float edgeCapacity = 1.0; KnikEngine* knik = KnikEngine::get ( getCell() ); if ( knik ) edgeCapacity = knik->getEdgeCapacityPercent(); cmess2 << " o Post-checking Knik capacity overload " << (edgeCapacity*100.0) << "%." << endl; _kiteGrid->base()->checkEdgeSaturation ( edgeCapacity ); _check ( overlaps ); Session::close (); _toolSuccess = _toolSuccess and (overlaps == 0); } void KiteEngine::printCompletion () const { cout << " o Computing Completion ratios." << endl; cout << " - Unrouted segments :" << endl; size_t routeds = 0; size_t unrouteds = 0; unsigned long long totalWireLength = 0; unsigned long long routedWireLength = 0; TrackElementLut::const_iterator ilut = _trackSegmentLut.begin(); for ( ; ilut != _trackSegmentLut.end() ; ilut++ ) { unsigned long long wl = (unsigned long long)DbU::getLambda(ilut->second->getLength()); if ( wl > 100000 ) { cerr << Error("KiteEngine::printCompletion(): Suspiciously long wire: %llu for %p:%s" ,wl,ilut->first,getString(ilut->second).c_str()) << endl; continue; } totalWireLength += wl; if ( ilut->second->getTrack() != NULL ) { routeds++; routedWireLength += wl; } else { cout << " " << setw(4) << ++unrouteds << "| " << ilut->second << endl; } } float segmentRatio = (float)(routeds) / (float)(_trackSegmentLut.size()) * 100.0; float wireLengthRatio = (float)(routedWireLength) / (float)(totalWireLength) * 100.0; cout << " - Track Segment Completion Ratio := " << setprecision(4) << segmentRatio << "% [" << routeds << "/" << _trackSegmentLut.size() << "] " << (_trackSegmentLut.size() - routeds) << " remains." << endl; cout << " - Wire Length Completion Ratio := " << setprecision(4) << wireLengthRatio << "% [" << totalWireLength << "] " << (totalWireLength - routedWireLength) << " remains." << endl; float expandRatio = 1.0; if ( _minimumWL != 0.0 ) { expandRatio = totalWireLength / _minimumWL; cout << " - Wire Length Expand Ratio := " << setprecision(4) << expandRatio << "% [min:" << setprecision(9) << _minimumWL << "] " << endl; } _toolSuccess = (unrouteds == 0); addMeasure ( getCell(), "Segs" , routeds+unrouteds ); addMeasure ( getCell(), "DWL(l)" , totalWireLength , 12 ); addMeasure ( getCell(), "fWL(l)" , totalWireLength-routedWireLength , 12); addMeasure ( getCell(), "WLER(%)", (expandRatio-1.0)*100.0 ); } void KiteEngine::dumpMeasures ( ostream& out ) const { vector measuresLabels; measuresLabels.push_back ( "Gates" ); measuresLabels.push_back ( "GCells" ); measuresLabels.push_back ( "knikT" ); measuresLabels.push_back ( "knikS" ); measuresLabels.push_back ( "GWL(l)" ); measuresLabels.push_back ( "Area(l2)"); measuresLabels.push_back ( "Sat." ); measuresLabels.push_back ( "loadT" ); measuresLabels.push_back ( "loadS" ); measuresLabels.push_back ( "Globals" ); measuresLabels.push_back ( "Edges" ); measuresLabels.push_back ( "assignT" ); measuresLabels.push_back ( "algoT" ); measuresLabels.push_back ( "algoS" ); measuresLabels.push_back ( "finT" ); measuresLabels.push_back ( "Segs" ); measuresLabels.push_back ( "DWL(l)" ); measuresLabels.push_back ( "fWL(l)" ); measuresLabels.push_back ( "WLER(%)" ); measuresLabels.push_back ( "Events" ); measuresLabels.push_back ( "UEvents" ); const MeasuresSet* measures = Measures::get(getCell()); out << "#" << endl; out << "# " << getCell()->getName() << endl; out << measures->toStringHeaders(measuresLabels) << endl; out << measures->toStringDatas (measuresLabels) << endl; } void KiteEngine::dumpMeasures () const { ostringstream path; path << getCell()->getName() << ".knik-kite.dat"; ofstream sfile ( path.str().c_str() ); dumpMeasures ( sfile ); sfile.close (); } bool KiteEngine::_check ( unsigned int& overlap, const char* message ) const { cmess1 << " o Checking Kite Database coherency." << endl; bool coherency = true; coherency = coherency && KatabaticEngine::_check ( message ); for ( size_t i=0 ; i<_routingPlanes.size() ; i++ ) coherency = _routingPlanes[i]->_check(overlap) && coherency; Katabatic::Session* ktbtSession = Session::base (); forEach ( Net*, inet, getCell()->getNets() ) { forEach ( Segment*, isegment, inet->getComponents().getSubSet() ) { AutoSegment* autoSegment = ktbtSession->lookup ( *isegment ); if ( !autoSegment ) continue; if ( !autoSegment->isCanonical() ) continue; TrackElement* trackSegment = Session::lookup ( *isegment ); if ( !trackSegment ) { coherency = false; cerr << Bug("%p %s whithout Track Segment" ,autoSegment ,getString(autoSegment).c_str() ) << endl; } else trackSegment->_check (); } } #if defined(CHECK_DATABASE) //Session::getKiteEngine()->setInterrupt ( !coherency ); #endif return coherency; } void KiteEngine::finalizeLayout () { ltrace(90) << "KiteEngine::finalizeLayout()" << endl; if ( getState() > Katabatic::StateDriving ) return; ltracein(90); setState ( Katabatic::StateDriving ); _gutKite (); KatabaticEngine::finalizeLayout (); ltrace(90) << "State: " << getState() << endl; ltraceout(90); } void KiteEngine::_gutKite () { ltrace(90) << "KiteEngine::_gutKite()" << endl; ltracein(90); ltrace(90) << "State: " << getState() << endl; if ( getState() < Katabatic::StateGutted ) { Session::open ( this ); size_t maxDepth = getRoutingGauge()->getDepth(); for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { _routingPlanes[depth]->destroy (); } _kiteGrid->destroy (); _kiteGrid = NULL; Session::close (); } ltraceout(90); } TrackElement* KiteEngine::_lookup ( Segment* segment ) const { TrackElementLut::const_iterator it = _trackSegmentLut.find ( segment ); if ( it == _trackSegmentLut.end() ) { AutoSegment* autoSegment = KatabaticEngine::_lookup ( segment ); if ( not autoSegment or autoSegment->isCanonical() ) return NULL; Interval dummy; autoSegment = autoSegment->getCanonical ( dummy ); it = _trackSegmentLut.find ( autoSegment->base() ); if ( it == _trackSegmentLut.end() ) return NULL; } return (*it).second; } void KiteEngine::_link ( TrackElement* trackSegment ) { if ( getState() > Katabatic::StateActive ) return; if ( !trackSegment ) { cerr << Bug("KiteEngine::_link(): Rejecting NULL TrackElement.") << endl; return; } _trackSegmentLut [ trackSegment->base()->base() ] = trackSegment; // Not needed: Canonical search is done before lookup. // forEach ( AutoSegment*, isegment, trackSegment->base()->getCollapseds() ) { // _trackSegmentLut [ isegment->base() ] = trackSegment; // } } void KiteEngine::_unlink ( TrackElement* trackSegment ) { if ( getState() > Katabatic::StateActive ) return; TrackElementLut::iterator it = _trackSegmentLut.find ( trackSegment->base()->base() ); if ( it != _trackSegmentLut.end() ) _trackSegmentLut.erase ( it ); // Not needed: Canonical search is done before lookup. // forEach ( AutoSegment*, isegment, trackSegment->base()->getCollapseds() ) { // TrackElementLut::iterator it = _trackSegmentLut.find ( isegment->base() ); // if ( it != _trackSegmentLut.end() ) // _trackSegmentLut.erase ( it ); // } } void KiteEngine::_check ( Net* net ) const { cerr << " o Checking " << net << endl; forEach ( Segment*, isegment, net->getComponents().getSubSet() ) { TrackElement* trackSegment = _lookup ( *isegment ); if ( trackSegment ) { trackSegment->_check (); AutoContact* autoContact = trackSegment->base()->getAutoSource(); if ( autoContact ) autoContact->checkTopology (); autoContact = trackSegment->base()->getAutoTarget(); if ( autoContact ) autoContact->checkTopology (); } } } string KiteEngine::_getTypeName () const { return "Kite::KiteEngine"; } string KiteEngine::_getString () const { ostringstream os; os << "<" << "KiteEngine " << _cell->getName () << " " // << getString(_rg->getName()) << ">"; return os.str(); } Record* KiteEngine::_getRecord () const { Record* record = KatabaticEngine::_getRecord (); record->add ( getSlot ( "_routingPlanes", &_routingPlanes ) ); return record; } } // End of Kite namespace.