// -*- C++ -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2008-2016, All Rights Reserved // // +-----------------------------------------------------------------+ // | C O R I O L I S | // | K a t a b a t i c - Routing Toolbox | // | | // | Author : Jean-Paul CHAPUT | // | E-mail : Jean-Paul.Chaput@lip6.fr | // | =============================================================== | // | C++ Module : "./LayerAssign.cpp" | // +-----------------------------------------------------------------+ #include #include #include "hurricane/Bug.h" #include "hurricane/Warning.h" #include "hurricane/DebugSession.h" #include "hurricane/Net.h" #include "hurricane/NetExternalComponents.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 "katabatic/AutoContact.h" #include "katabatic/AutoSegment.h" #include "katabatic/GCellGrid.h" #include "katabatic/KatabaticEngine.h" namespace Katabatic { using Hurricane::DebugSession; using Hurricane::ForEachIterator; using Hurricane::Warning; void KatabaticEngine::_desaturate ( unsigned int depth , set& globalNets , unsigned long& total , unsigned long& globals ) { if (depth+2 > Session::getConfiguration()->getAllowedDepth()) { cerr << Warning("Katabatic::_desaturate(): %s, no remaining upper layers." ,getString(Session::getRoutingGauge()->getRoutingLayer(depth)->getName()).c_str() ) << endl; return; } cmess1 << " o Desaturate layer " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() << endl; GCellDensitySet queue ( depth, *(_gcellGrid->getGCellVector()) ); GCell::SetIndex invalidateds; bool optimized = true; while ( optimized ) { Session::revalidate (); optimized = false; queue.requeue (); std::set::const_iterator igcell = queue.getGCells().begin(); size_t i = 0; for ( ; igcell!=queue.getGCells().end() ; ++igcell, ++i ) { cdebug.log(149) << "_desaturate: [" << depth << "]:" << (*igcell)->getDensity(depth) << " " << *igcell << endl; if (not (*igcell)->isSaturated(depth)) { cdebug.log(149) << "STOP desaturated: @" << i << " " << *igcell << endl; for ( ; igcell!=queue.getGCells().end() ; ++igcell ) { if ( (*igcell)->isSaturated( depth ) ) { cparanoid << "[ERROR] Still saturated: @" << i << " " << *igcell << endl; break; } } break; } optimized = (*igcell)->stepNetDesaturate( depth, globalNets, invalidateds ); if ( optimized ) { for ( GCell::SetIndex::iterator igcell=invalidateds.begin() ; igcell!=invalidateds.end() ; ++igcell ) { queue.unqueue( *igcell ); } break; } } } } void KatabaticEngine::_layerAssignByLength ( Net* net, unsigned long& total, unsigned long& global, set& globalNets ) { DebugSession::open ( net, 140, 150 ); cdebug.log(149) << "Katabatic::_layerAssignByLength( " << net << " )" << endl; cdebug.tabw(145,1); bool isGlobal = false; set globalContacts; forEach ( Segment*, isegment, net->getSegments() ) { total++; if ( (*isegment)->getLength() > getGlobalThreshold() ) { if (not isGlobal) { isGlobal = true; globalNets.insert( net ); } global++; if ((*isegment)->getLayer() == Session::getRoutingLayer(1)) (*isegment)->setLayer( Session::getRoutingLayer(3) ); if ((*isegment)->getLayer() == Session::getRoutingLayer(2)) (*isegment)->setLayer( Session::getRoutingLayer(4) ); } } cdebug.tabw(145,-1); DebugSession::close(); } void KatabaticEngine::_layerAssignByLength ( unsigned long& total, unsigned long& global, set& globalNets ) { cmess1 << " o Assign Layer (simple wirelength)." << endl; forEach ( Net* , inet , getCell()->getNets() ) { if (NetRoutingExtension::get(*inet)->isAutomaticGlobalRoute()) { _layerAssignByLength ( *inet, total, global, globalNets ); } } // forEach(Net*) } void KatabaticEngine::_layerAssignByTrunk ( Net* net, set& globalNets, unsigned long& total, unsigned long& global ) { DebugSession::open( net, 140, 150 ); cdebug.log(149) << "Katabatic::_layerAssignByTrunk ( " << net << " )" << endl; cdebug.tabw(145,1); bool isGlobal = false; unsigned long netGlobal = 0; unsigned long netTotal = 0; set globalContacts; forEach ( Segment*, isegment, net->getSegments() ) { netTotal++; if ((*isegment)->getLength() > getGlobalThreshold()) { isGlobal = true; netTotal = 0; globalNets.insert( net ); break; } } if (isGlobal) { forEach ( Segment*, isegment, net->getSegments() ) { netTotal++; AutoSegment* autoSegment = Session::lookup( *isegment ); if ( autoSegment and not autoSegment->isStrongTerminal() ) { netGlobal++; cdebug.log(145) << "Migrate to M4/M5: " << autoSegment << endl; if (autoSegment->isHorizontal()) autoSegment->setLayer( Session::getRoutingLayer(3) ); if (autoSegment->isVertical ()) autoSegment->setLayer( Session::getRoutingLayer(4) ); } } } total += netTotal; global += netGlobal; cdebug.tabw(145,-1); DebugSession::close(); } void KatabaticEngine::_layerAssignByTrunk ( unsigned long& total, unsigned long& global, set& globalNets ) { cmess1 << " o Assign Layer (whole net trunk)." << endl; forEach ( Net* , inet , getCell()->getNets() ) { if (NetRoutingExtension::get(*inet)->isAutomaticGlobalRoute()) { _layerAssignByTrunk( *inet, globalNets, total, global ); } } } void KatabaticEngine::moveULeft ( AutoSegment* seed, set& globalNets, GCell::SetIndex& invalidateds ) { Net* net = seed->getNet(); DebugSession::open( net, 140, 150 ); cdebug.log(9000) << "Deter| Move left: " << seed << endl; seed->moveULeft(); globalNets.insert( net ); GCell* begin = seed->getAutoSource()->getGCell(); GCell* end = seed->getAutoTarget()->getGCell(); if (seed->isHorizontal()) { for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) invalidateds.insert( gcell ); begin = begin->getDown(); end = end ->getDown(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) invalidateds.insert( gcell ); } else { for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) invalidateds.insert( gcell ); begin = begin->getLeft(); end = end ->getLeft(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) invalidateds.insert( gcell ); } DebugSession::close(); } void KatabaticEngine::moveURight ( AutoSegment* seed, set& globalNets, GCell::SetIndex& invalidateds ) { Net* net = seed->getNet(); DebugSession::open( net, 140, 150 ); cdebug.log(9000) << "Deter| Move right: " << seed << endl; seed->moveURight(); globalNets.insert( net ); GCell* begin = seed->getAutoSource()->getGCell(); GCell* end = seed->getAutoTarget()->getGCell(); if (seed->isHorizontal()) { for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) invalidateds.insert( gcell ); begin = begin->getUp(); end = end ->getUp(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getRight() ) invalidateds.insert( gcell ); } else { for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) invalidateds.insert( gcell ); begin = begin->getRight(); end = end ->getRight(); for ( GCell* gcell=begin ; gcell and gcell!=end ; gcell=gcell->getUp() ) invalidateds.insert( gcell ); } DebugSession::close(); } bool KatabaticEngine::moveUpNetTrunk2 ( AutoSegment* seed, set& globalNets, GCell::SetIndex& invalidateds ) { Net* net = seed->getNet(); unsigned int seedDepth = Session::getRoutingGauge()->getLayerDepth(seed->getLayer()); DebugSession::open( net, 140, 150 ); cdebug.log(9000) << "Deter| moveUpNetTrunk() depth:" << seedDepth << " " << seed << endl; if (not seed->canMoveUp( 1.0, KbPropagate|KbAllowTerminal|KbNoCheckLayer) ) { cdebug.log(9000) << "Deter| Reject seed move up, cannot move up." << endl; DebugSession::close(); return false; } cdebug.tabw(149,1); globalNets.insert( net ); vector< pair > stack; vector globals; vector locals; stack.push_back( pair(NULL,seed) ); while ( not stack.empty() ) { AutoContact* from = stack.back().first; AutoSegment* segment = stack.back().second; stack.pop_back(); if (segment->isLocal()) { if (not segment->isStrongTerminal()) locals.push_back( segment ); continue; } if ( (segment->getLength() < 3*Session::getSliceHeight()) and (segment != seed) ) { locals.push_back( segment ); continue; } // Do something here. if (not segment->canMoveUp(1.0,KbPropagate|KbAllowTerminal|KbNoCheckLayer|KbCheckLowDensity) ) continue; globals.push_back( segment ); AutoContact* source = segment->getAutoSource(); if (source != from) { for ( AutoSegment* connected : source->getAutoSegments() ) { if (connected != segment) { stack.push_back( make_pair(source,connected) ); } } } AutoContact* target = segment->getAutoTarget(); if (target != from) { for ( AutoSegment* connected : target->getAutoSegments() ) { if (connected != segment) { stack.push_back( make_pair(target,connected) ); } } } } for ( size_t i=0 ; igetLayerDepth( globals[i]->getLayer() ); globals[i]->changeDepth( depth+2, KbWithNeighbors ); vector gcells; globals[i]->getGCells( gcells ); for ( size_t j=0 ; jgetLayerDepth(locals[i]->getLayer()); if (depth > seedDepth+1) continue; if (locals[i]->canPivotUp(2.0,KbPropagate|KbNoCheckLayer)) { locals[i]->changeDepth( depth+2, KbWithNeighbors ); //cdebug.log(9000) << "Deter| Trunk move up L:" << locals[i] << endl; vector gcells; locals[i]->getGCells( gcells ); for ( size_t j=0 ; j& globalNets, GCell::SetIndex& invalidateds ) { Net* net = seed->getNet(); unsigned int seedDepth = Session::getRoutingGauge()->getLayerDepth(seed->getLayer()); DebugSession::open( net, 140, 150 ); cdebug.log(9000) << "Deter| moveUpNetTrunk() depth:" << seedDepth << " " << seed << endl; if (not seed->canMoveUp( 1.0, KbPropagate|KbAllowTerminal|KbNoCheckLayer) ) { cdebug.log(9000) << "Deter| Reject seed move up, cannot move up." << endl; DebugSession::close(); return false; } cdebug.tabw(149,1); globalNets.insert( net ); vector globals; vector locals; forEach ( Segment*, isegment, net->getSegments() ) { AutoSegment* autoSegment = Session::lookup( *isegment ); //cdebug.log(9000) << "Deter| Loop " << autoSegment << endl; if (not autoSegment) continue; if (autoSegment->isLocal()) { if (autoSegment->isStrongTerminal()) continue; locals.push_back( autoSegment ); } else { // Ugly: Hard-coded GCell side. if ( (autoSegment->getLength() < 3*Session::getSliceHeight()) and (autoSegment != seed) ) locals.push_back( autoSegment ); else globals.push_back( autoSegment ); } } sort( globals.begin(), globals.end(), AutoSegment::CompareId() ); sort( locals.begin(), locals.end(), AutoSegment::CompareId() ); for ( size_t i=0 ; igetLayerDepth( globals[i]->getLayer() ); if (depth > seedDepth+1) continue; if ( globals[i]->isVertical() and (globals[i] != seed) ) continue; if ( globals[i]->canMoveUp(1.0,KbPropagate|KbAllowTerminal|KbNoCheckLayer) ) { globals[i]->changeDepth( depth+2, KbWithNeighbors ); //cdebug.log(9000) << "Deter| Trunk move up G:" << globals[i] << endl; vector gcells; globals[i]->getGCells( gcells ); for ( size_t j=0 ; jgetLayerDepth(locals[i]->getLayer()); if (depth > seedDepth+1) continue; if (locals[i]->canPivotUp(2.0,KbPropagate|KbNoCheckLayer)) { locals[i]->changeDepth( depth+2, KbWithNeighbors ); //cdebug.log(9000) << "Deter| Trunk move up L:" << locals[i] << endl; vector gcells; locals[i]->getGCells( gcells ); for ( size_t j=0 ; jgetRoutingLayer(depth)->getName() << endl; GCellDensitySet queue ( depth, *(_gcellGrid->getGCellVector()) ); GCell::SetIndex invalidateds; bool optimized = true; while ( optimized ) { Session::revalidate(); optimized = false; queue.requeue(); std::set::const_iterator igcell = queue.getGCells().begin(); size_t i = 0; for ( ; igcell!=queue.getGCells().end() ; ++igcell, ++i ) { cdebug.log(149) << "_balance: [" << depth << "]:" << (*igcell)->getDensity(depth) << " " << *igcell << endl; if (not (*igcell)->isSaturated(depth)) { cdebug.log(149) << "STOP desaturated: @" << i << " " << *igcell << endl; for ( ; igcell!=queue.getGCells().end() ; ++igcell ) { if ((*igcell)->isSaturated(depth)) { cparanoid << Error( "Still saturated: @%d %s", i, getString(*igcell).c_str() ) << endl; break; } } break; } optimized = (*igcell)->stepBalance( depth, invalidateds ); if (optimized) { for ( GCell::SetIndex::iterator igcell=invalidateds.begin() ; igcell!=invalidateds.end() ; ++igcell ) { queue.unqueue( *igcell ); } break; } } } Session::close(); stopMeasures(); printMeasures( "balance" ); } void KatabaticEngine::balanceGlobalDensity () { cdebug.log(9000) << "Deter| Balance Global Density" << endl; //_balanceGlobalDensity( 1 ); // metal2 //_balanceGlobalDensity( 2 ); // metal3 set globalNets; GCell::SetIndex invalidateds; Session::open( this ); vector segments; AutoSegmentLut::iterator ilut = _autoSegmentLut.begin(); for ( ; ilut!=_autoSegmentLut.end() ; ++ilut ) { AutoSegment* segment = (*ilut).second; if (segment->isLocal() or segment->isFixed()) continue; if (not segment->isCanonical()) continue; segments.push_back( segment ); } // Sort on id before moving to ensure determinism. sort( segments.begin(), segments.end(), AutoSegment::CompareId() ); for ( size_t i=0 ; icanMoveULeft(0.10)) { getGCellGrid()->getKatabatic()->moveULeft(segments[i],globalNets,invalidateds); } else if (segments[i]->canMoveURight(0.10)) { getGCellGrid()->getKatabatic()->moveURight(segments[i],globalNets,invalidateds); } for ( GCell::SetIndex::iterator igcell=invalidateds.begin() ; igcell!=invalidateds.end() ; ++igcell ) { (*igcell)->updateDensity(); } invalidateds.clear(); Session::revalidate(); } Session::close(); } void KatabaticEngine::layerAssign ( unsigned int method ) { cdebug.log(9000) << "Deter| Layer Assignment" << endl; set globalNets; unsigned long total = 0; unsigned long global = 0; startMeasures(); Session::open( this ); if (Session::getAllowedDepth() >= 3) { switch ( method ) { case EngineLayerAssignByLength: _layerAssignByLength( total, global, globalNets ); break; case EngineLayerAssignByTrunk: _layerAssignByTrunk ( total, global, globalNets ); break; case EngineNoNetLayerAssign: break; default: stopMeasures(); Session::close(); throw Error( badMethod , "Katabatic::layerAssign()" , method , getString(_cell).c_str() ); } globalNets.clear(); Session::revalidate(); if (getConfiguration()->getAllowedDepth() > 2) { //for ( int i=0 ; i < 3 ; i++ ) { for ( size_t depth=1 ; depth <= getConfiguration()->getAllowedDepth()-2; ++depth ) { _desaturate( depth, globalNets, total, global ); if ( (depth > 1) and ((depth-1)%2 == 1) ) Session::revalidate(); } globalNets.clear (); // if (not _gcellGrid->updateDensity()) break; //} Session::revalidate(); } #if defined(CHECK_DATABASE) _check( "after layer assignment" ); #endif Session::setKatabaticFlags( EngineWarnOnGCellOverload ); } _gcellGrid->checkDensity(); Session::close(); stopMeasures(); printMeasures( "assign" ); // cmess2 << " - Total segments : " << total << endl; // cmess2 << " - Global segments : " << global << endl; // cmess2 << " - Ratio : " // << ((float)global/(float)total)*100.0 << "%." << endl; } } // Katabatic namespace.