From 48f3a2bc3c917cc4841bb3a7a39590970a92d14d Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Mon, 15 Aug 2016 16:30:13 +0200 Subject: [PATCH] Anabatic transient commit 18. Port of Kite (Katana), Yeah, Baby! Yeah! * Bug: In Hurricane, in StaticObservable::getObserver(), if the slot pointer is NULL, do not try to access the owner. Returns NULL, so the caller can be aware of the situation... * Change: In Hurricane, in BreakpointWidget & ExceptionWidget some cosmetic changes (fonts and window sizes). * Bug: In Anabatic, In AutoHorizontal::getConstraints(), take into account the constraints from the source AutoContact, as it holds the constraints transmitted by the RoutingPads and sets up by propageConstraintsFromRp(). It is likely to be a bug affecting the original Katabatic as well. * Change: In Anabatic, in RawGCellsUnder(), check that the segment is not completly oustside the cell abutment box and truncate the coordinates to the part that is inside. Use the "shrink" if we reach the east/north border. * Change: In Anabatic, in Configuration, no more decorator because we will use a true derived relationship. Katana *derives* from *Anabatic* and do not *decorate* it, so the Configuration can do the same. It also implies that we directly create a Katana engine, not an Anabatic one. * Change: In Anabatic, in Session, do not allow the opening of the Session in a standalone fashion (with a static method). Instead it must be opened using the relevant method of the Anabatic/Katana engine. This ensure we are opening the right Session type. * Change: In Anabatic, in AutoSegment_Aligneds() collection the seed segment is not part of the collection by default, but will be included if the Flags::WithSelf is set. * Change: In Configuration, all the flags value are now defined in two steps. Declared in the header and initialized in the module. This is to prevent the fact that on some cases, in relation with the Python "extern C" part modules, we need a true allocated variable. It was causing weird linking problems. A side effect is that they can no longer be used as entry is switches, have to replace them by if/else. * New: In Anabatic, new GCell::getNeighborAt() utility function. * Bug: In Anabatic, in GCell::doGrid(), tag all the GCells of the grid with the grid type... Back annote all the edges capacity (north & east) with the reserved local capacity. * New: Complete portage of Kite over Anabatic. The new engine is christened "Katana" for Kite-Analogic. When it's capabilities and performances will be on a part with Kite, it is to completly replace it (and take back the "Kite" name). Preliminary tests seems to show that, contrary to intuition (because built on a more complex/slower grid), it is even slightly faster than Kite 8-). --- anabatic/src/AnabaticEngine.cpp | 101 +- anabatic/src/AutoContactTerminal.cpp | 4 + anabatic/src/AutoHorizontal.cpp | 32 +- anabatic/src/AutoSegment.cpp | 14 +- anabatic/src/AutoSegments.cpp | 2 +- anabatic/src/AutoVertical.cpp | 29 +- anabatic/src/Configuration.cpp | 121 +- anabatic/src/Constants.cpp | 60 + anabatic/src/Dijkstra.cpp | 1 - anabatic/src/GCell.cpp | 210 +-- anabatic/src/GlobalRoute.cpp | 8 +- anabatic/src/LayerAssign.cpp | 6 +- anabatic/src/LoadGlobalRouting.cpp | 7 +- anabatic/src/NetConstraints.cpp | 45 +- anabatic/src/PreRouteds.cpp | 4 +- anabatic/src/Session.cpp | 7 +- anabatic/src/anabatic/AnabaticEngine.h | 18 +- anabatic/src/anabatic/AutoHorizontal.h | 2 +- anabatic/src/anabatic/AutoSegment.h | 2 +- anabatic/src/anabatic/AutoVertical.h | 3 +- anabatic/src/anabatic/Configuration.h | 163 +- anabatic/src/anabatic/Constants.h | 112 +- anabatic/src/anabatic/Dijkstra.h | 2 +- anabatic/src/anabatic/GCell.h | 4 + anabatic/src/anabatic/Session.h | 152 +- bootstrap/build.conf | 1 + bootstrap/refactor.py | 98 ++ documentation/UsersGuide/UsersGuide.pdf | 276 ++-- hurricane/src/hurricane/Backtrace.cpp | 4 + hurricane/src/hurricane/Observer.cpp | 2 +- hurricane/src/hurricane/hurricane/Observer.h | 5 +- hurricane/src/viewer/BreakpointWidget.cpp | 4 +- hurricane/src/viewer/ExceptionWidget.cpp | 1 + katana/CMakeLists.txt | 46 + katana/cmake_modules/CMakeLists.txt | 1 + katana/cmake_modules/FindKATANA.cmake | 37 + katana/python/CMakeLists.txt | 2 + katana/python/katanaInit.py | 39 + katana/src/CMakeLists.txt | 112 ++ katana/src/Configuration.cpp | 199 +++ katana/src/Constants.cpp | 37 + katana/src/DataNegociate.cpp | 278 ++++ katana/src/GlobalRoute.cpp | 219 +++ katana/src/GraphicKatanaEngine.cpp | 306 ++++ katana/src/HorizontalTrack.cpp | 76 + katana/src/KatanaEngine.cpp | 596 ++++++++ katana/src/Manipulator.cpp | 1412 ++++++++++++++++++ katana/src/NegociateWindow.cpp | 631 ++++++++ katana/src/PowerRails.cpp | 1329 +++++++++++++++++ katana/src/PreProcess.cpp | 366 +++++ katana/src/PreRouteds.cpp | 62 + katana/src/ProtectRoutingPads.cpp | 182 +++ katana/src/PyGraphicKatanaEngine.cpp | 122 ++ katana/src/PyKatana.cpp | 103 ++ katana/src/PyKatanaEngine.cpp | 306 ++++ katana/src/RoutingEvent.cpp | 701 +++++++++ katana/src/RoutingEventHistory.cpp | 105 ++ katana/src/RoutingEventLoop.cpp | 85 ++ katana/src/RoutingEventQueue.cpp | 275 ++++ katana/src/RoutingPlane.cpp | 214 +++ katana/src/SegmentFsm.cpp | 1241 +++++++++++++++ katana/src/Session.cpp | 350 +++++ katana/src/Track.cpp | 726 +++++++++ katana/src/TrackCost.cpp | 261 ++++ katana/src/TrackElement.cpp | 283 ++++ katana/src/TrackElements.cpp | 136 ++ katana/src/TrackFixedSegment.cpp | 200 +++ katana/src/TrackMarker.cpp | 132 ++ katana/src/TrackSegment.cpp | 884 +++++++++++ katana/src/TrackSegmentCost.cpp | 203 +++ katana/src/Tracks.cpp | 315 ++++ katana/src/VerticalTrack.cpp | 75 + katana/src/katana/Configuration.h | 122 ++ katana/src/katana/Constants.h | 52 + katana/src/katana/DataNegociate.h | 158 ++ katana/src/katana/GraphicKatanaEngine.h | 89 ++ katana/src/katana/HorizontalTrack.h | 56 + katana/src/katana/KatanaEngine.h | 180 +++ katana/src/katana/Manipulator.h | 103 ++ katana/src/katana/NegociateWindow.h | 160 ++ katana/src/katana/PyGraphicKatanaEngine.h | 55 + katana/src/katana/PyKatanaEngine.h | 57 + katana/src/katana/RoutingEvent.h | 286 ++++ katana/src/katana/RoutingEventHistory.h | 71 + katana/src/katana/RoutingEventLoop.h | 84 ++ katana/src/katana/RoutingEventQueue.h | 82 + katana/src/katana/RoutingPlane.h | 126 ++ katana/src/katana/SegmentFsm.h | 185 +++ katana/src/katana/Session.h | 182 +++ katana/src/katana/Track.h | 218 +++ katana/src/katana/TrackCost.h | 203 +++ katana/src/katana/TrackElement.h | 260 ++++ katana/src/katana/TrackElements.h | 144 ++ katana/src/katana/TrackFixedSegment.h | 82 + katana/src/katana/TrackMarker.h | 113 ++ katana/src/katana/TrackSegment.h | 165 ++ katana/src/katana/TrackSegmentCost.h | 98 ++ katana/src/katana/Tracks.h | 140 ++ katana/src/katana/VerticalTrack.h | 56 + katana/src/katanaRefactor.conf | 8 + unicorn/CMakeLists.txt | 30 +- unicorn/src/CMakeLists.txt | 2 + unicorn/src/cgt.py | 2 + 103 files changed, 17072 insertions(+), 644 deletions(-) create mode 100755 bootstrap/refactor.py create mode 100644 katana/CMakeLists.txt create mode 100644 katana/cmake_modules/CMakeLists.txt create mode 100644 katana/cmake_modules/FindKATANA.cmake create mode 100644 katana/python/CMakeLists.txt create mode 100644 katana/python/katanaInit.py create mode 100644 katana/src/CMakeLists.txt create mode 100644 katana/src/Configuration.cpp create mode 100644 katana/src/Constants.cpp create mode 100644 katana/src/DataNegociate.cpp create mode 100644 katana/src/GlobalRoute.cpp create mode 100644 katana/src/GraphicKatanaEngine.cpp create mode 100644 katana/src/HorizontalTrack.cpp create mode 100644 katana/src/KatanaEngine.cpp create mode 100644 katana/src/Manipulator.cpp create mode 100644 katana/src/NegociateWindow.cpp create mode 100644 katana/src/PowerRails.cpp create mode 100644 katana/src/PreProcess.cpp create mode 100644 katana/src/PreRouteds.cpp create mode 100644 katana/src/ProtectRoutingPads.cpp create mode 100644 katana/src/PyGraphicKatanaEngine.cpp create mode 100644 katana/src/PyKatana.cpp create mode 100644 katana/src/PyKatanaEngine.cpp create mode 100644 katana/src/RoutingEvent.cpp create mode 100644 katana/src/RoutingEventHistory.cpp create mode 100644 katana/src/RoutingEventLoop.cpp create mode 100644 katana/src/RoutingEventQueue.cpp create mode 100644 katana/src/RoutingPlane.cpp create mode 100644 katana/src/SegmentFsm.cpp create mode 100644 katana/src/Session.cpp create mode 100644 katana/src/Track.cpp create mode 100644 katana/src/TrackCost.cpp create mode 100644 katana/src/TrackElement.cpp create mode 100644 katana/src/TrackElements.cpp create mode 100644 katana/src/TrackFixedSegment.cpp create mode 100644 katana/src/TrackMarker.cpp create mode 100644 katana/src/TrackSegment.cpp create mode 100644 katana/src/TrackSegmentCost.cpp create mode 100644 katana/src/Tracks.cpp create mode 100644 katana/src/VerticalTrack.cpp create mode 100644 katana/src/katana/Configuration.h create mode 100644 katana/src/katana/Constants.h create mode 100644 katana/src/katana/DataNegociate.h create mode 100644 katana/src/katana/GraphicKatanaEngine.h create mode 100644 katana/src/katana/HorizontalTrack.h create mode 100644 katana/src/katana/KatanaEngine.h create mode 100644 katana/src/katana/Manipulator.h create mode 100644 katana/src/katana/NegociateWindow.h create mode 100644 katana/src/katana/PyGraphicKatanaEngine.h create mode 100644 katana/src/katana/PyKatanaEngine.h create mode 100644 katana/src/katana/RoutingEvent.h create mode 100644 katana/src/katana/RoutingEventHistory.h create mode 100644 katana/src/katana/RoutingEventLoop.h create mode 100644 katana/src/katana/RoutingEventQueue.h create mode 100644 katana/src/katana/RoutingPlane.h create mode 100644 katana/src/katana/SegmentFsm.h create mode 100644 katana/src/katana/Session.h create mode 100644 katana/src/katana/Track.h create mode 100644 katana/src/katana/TrackCost.h create mode 100644 katana/src/katana/TrackElement.h create mode 100644 katana/src/katana/TrackElements.h create mode 100644 katana/src/katana/TrackFixedSegment.h create mode 100644 katana/src/katana/TrackMarker.h create mode 100644 katana/src/katana/TrackSegment.h create mode 100644 katana/src/katana/TrackSegmentCost.h create mode 100644 katana/src/katana/Tracks.h create mode 100644 katana/src/katana/VerticalTrack.h create mode 100644 katana/src/katanaRefactor.conf diff --git a/anabatic/src/AnabaticEngine.cpp b/anabatic/src/AnabaticEngine.cpp index 7b3b1529..ababcc25 100644 --- a/anabatic/src/AnabaticEngine.cpp +++ b/anabatic/src/AnabaticEngine.cpp @@ -75,21 +75,45 @@ namespace Anabatic { { cdebug_log(112,1) << "RawGCellsUnder::RawGCellsUnder(): " << segment << endl; - GCell* gsource = engine->getGCellUnder( segment->getSourcePosition() ); - GCell* gtarget = engine->getGCellUnder( segment->getTargetPosition() ); + Box gcellsArea = engine->getCell()->getAbutmentBox(); + Point sourcePosition = segment->getSourcePosition(); + Point targetPosition = segment->getTargetPosition(); - if (not gsource) { - cerr << Error( "RawGCellsUnder::RawGCellsUnder(): %s source not over a GCell (ignored)." + if ( (sourcePosition.getX() >= gcellsArea.getXMax()) + or (sourcePosition.getY() >= gcellsArea.getYMax()) + or (targetPosition.getX() <= gcellsArea.getXMin()) + or (targetPosition.getY() <= gcellsArea.getYMin()) ) { + cerr << Error( "RawGCellsUnder::RawGCellsUnder(): %s is completly outside the GCells area (ignored)." , getString(segment).c_str() ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; } + + DbU::Unit xsource = std::max( sourcePosition.getX(), gcellsArea.getXMin() ); + DbU::Unit ysource = std::max( sourcePosition.getY(), gcellsArea.getYMin() ); + DbU::Unit xtarget = std::min( targetPosition.getX(), gcellsArea.getXMax() ); + DbU::Unit ytarget = std::min( targetPosition.getY(), gcellsArea.getYMax() ); + + if (xtarget == gcellsArea.getXMax()) --xtarget; + if (ytarget == gcellsArea.getYMax()) --ytarget; + + GCell* gsource = engine->getGCellUnder( xsource, ysource ); + GCell* gtarget = engine->getGCellUnder( xtarget, ytarget ); + + if (not gsource) { + cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): %s source not under a GCell (ignored)." + , getString(segment).c_str() + ) << endl; + cdebug_tabw(112,-1); + DebugSession::close(); + return; + } if (not gtarget) { - cerr << Error( "RawGCellsUnder::RawGCellsUnder(): %s target not over a GCell (ignored)." - , getString(segment).c_str() - ) << endl; + cerr << Bug( "RawGCellsUnder::RawGCellsUnder(): %s target not under a GCell (ignored)." + , getString(segment).c_str() + ) << endl; cdebug_tabw(112,-1); DebugSession::close(); return; @@ -175,7 +199,7 @@ namespace Anabatic { AnabaticEngine::AnabaticEngine ( Cell* cell ) : Super(cell) , _timer () - , _configuration (new ConfigurationConcrete()) + , _configuration (new Configuration()) , _chipTools (cell) , _state (EngineCreation) , _matrix () @@ -251,7 +275,7 @@ namespace Anabatic { void AnabaticEngine::_gutAnabatic () { - Session::open( this ); + openSession(); _flags.reset( Flags::DestroyBaseContact|Flags::DestroyBaseSegment ); @@ -301,6 +325,21 @@ namespace Anabatic { { return _configuration; } + Interval AnabaticEngine::getUSide ( Flags direction ) const + { + Interval side; + Box bBox ( getCell()->getBoundingBox() ); + + if (direction & Flags::Horizontal) side = Interval( bBox.getXMin(), bBox.getXMax() ); + else if (direction & Flags::Vertical ) side = Interval( bBox.getYMin(), bBox.getYMax() ); + else { + cerr << Error( "AnabaticEngine::getUSide(): Unknown direction flag \"%i\"" + , getString(direction).c_str() ) << endl; + } + return side; + } + + int AnabaticEngine::getCapacity ( Interval span, Flags flags ) const { int capacity = 0; @@ -333,6 +372,10 @@ namespace Anabatic { } + void AnabaticEngine::openSession () + { Session::_open(this); } + + void AnabaticEngine::reset () { _gutAnabatic(); @@ -1013,6 +1056,46 @@ namespace Anabatic { } + void AnabaticEngine::_check ( Net* net ) const + { + cdebug_log(149,1) << "Checking " << net << endl; + for ( Segment* segment : net->getComponents().getSubSet() ) { + AutoSegment* autoSegment = _lookup( segment ); + cdebug_log(149,0) << autoSegment << endl; + if (autoSegment) { + AutoContact* autoContact = autoSegment->getAutoSource(); + cdebug_log(149,0) << autoContact << endl; + if (autoContact) autoContact->checkTopology(); + + autoContact = autoSegment->getAutoTarget(); + cdebug_log(149,0) << autoContact << endl; + if (autoContact) autoContact->checkTopology(); + } + } + cdebug_tabw(149,-1); + } + + + bool AnabaticEngine::_check ( const char* message ) const + { + bool coherency = true; + if (message) + cerr << " o checking Anabatic DB (" << message << ")." << endl; + + for ( auto element : _autoSegmentLut ) + coherency = element.second->_check() and coherency; + + for ( GCell* gcell : _gcells ) { + for ( AutoContact* contact : gcell->getContacts() ) + contact->checkTopology(); + } + + if (message) cerr << " - completed." << endl; + + return coherency; + } + + string AnabaticEngine::_getTypeName () const { return getString(_toolName); } diff --git a/anabatic/src/AutoContactTerminal.cpp b/anabatic/src/AutoContactTerminal.cpp index b7c47ee7..94196938 100644 --- a/anabatic/src/AutoContactTerminal.cpp +++ b/anabatic/src/AutoContactTerminal.cpp @@ -335,6 +335,10 @@ namespace Anabatic { message << "Terminal horizontal segment Y " << DbU::getValueString(_segment->getY()) << " axis is outside RoutingPad " << getUConstraints(Flags::Vertical) << "."; + Interval intv; + _segment->getConstraints( intv ); + message << "\n Segment constraints: " << intv << endl; + unsigned int flags = 0; if (_segment->isCreated()) flags |= Flags::CParanoid; showTopologyError( message.str(), flags ); diff --git a/anabatic/src/AutoHorizontal.cpp b/anabatic/src/AutoHorizontal.cpp index 77e8fc2d..57ebafb3 100644 --- a/anabatic/src/AutoHorizontal.cpp +++ b/anabatic/src/AutoHorizontal.cpp @@ -146,28 +146,34 @@ namespace Anabatic { constraintMax = getNativeMax(); cdebug_log(149,0) << "Native constraints: [" - << DbU::getValueString(constraintMin) << ":" - << DbU::getValueString(constraintMax) << "]" - << endl; + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; - constraintMin = max ( constraintMin, getUserConstraints().getVMin() ); - constraintMax = min ( constraintMax, getUserConstraints().getVMax() ); + constraintMin = std::max ( constraintMin, getAutoSource()->getCBYMin() ); + constraintMax = std::min ( constraintMax, getAutoSource()->getCBYMax() ); + cdebug_log(149,0) << "Merge with source constraints: [" + << DbU::getValueString(getAutoSource()->getCBYMin()) << ":" + << DbU::getValueString(getAutoSource()->getCBYMax()) << "]" + << endl; - cdebug_log(149,0) << "Merge with user constraints: " << getUserConstraints() << " [" - << DbU::getValueString(getUserConstraints().getVMin()) << ":" - << DbU::getValueString(getUserConstraints().getVMax()) << "]" - << endl; + constraintMin = std::max ( constraintMin, getUserConstraints().getVMin() ); + constraintMax = std::min ( constraintMax, getUserConstraints().getVMax() ); + cdebug_log(149,0) << "Merge with user constraints: [" + << DbU::getValueString(getUserConstraints().getVMin()) << ":" + << DbU::getValueString(getUserConstraints().getVMax()) << "]" + << endl; cdebug_log(149,0) << "Resulting constraints: " << " [" - << DbU::getValueString(constraintMin) << ":" - << DbU::getValueString(constraintMax) << "]" - << endl; + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; return true; } - unsigned int AutoHorizontal::getDirection () const + Flags AutoHorizontal::getDirection () const { return Flags::Horizontal; } diff --git a/anabatic/src/AutoSegment.cpp b/anabatic/src/AutoSegment.cpp index dd15abe9..a1f6af6c 100644 --- a/anabatic/src/AutoSegment.cpp +++ b/anabatic/src/AutoSegment.cpp @@ -685,8 +685,8 @@ namespace Anabatic { { setFlags( flags ); if (not isNotAligned()) { - forEach( AutoSegment*, isegment, getAligneds() ) - isegment->setFlags( flags ); + for( AutoSegment* segment : getAligneds() ) + segment->setFlags( flags ); } } @@ -846,8 +846,8 @@ namespace Anabatic { _setAxis( axis ); if (not isNotAligned()) { - forEach( AutoSegment*, isegment, getAligneds() ) { - isegment->_setAxis( getAxis() ); + for ( AutoSegment* segment : getAligneds() ) { + segment->_setAxis( getAxis() ); } } else { cdebug_log(149,0) << "No need to process parallels." << endl; @@ -1009,11 +1009,11 @@ namespace Anabatic { setOptimalMax( optimalMax ); processeds.insert( this ); if (not isNotAligned()) { - forEach ( AutoSegment*, autoSegment, getAligneds() ) { - cdebug_log(145,0) << "Applying constraint on: " << *autoSegment << endl; + for ( AutoSegment* autoSegment : getAligneds() ) { + cdebug_log(145,0) << "Applying constraint on: " << autoSegment << endl; autoSegment->setOptimalMin( optimalMin ); autoSegment->setOptimalMax( optimalMax ); - processeds.insert( (*autoSegment) ); + processeds.insert( autoSegment ); } } diff --git a/anabatic/src/AutoSegments.cpp b/anabatic/src/AutoSegments.cpp index 304ac2bc..358b4e29 100644 --- a/anabatic/src/AutoSegments.cpp +++ b/anabatic/src/AutoSegments.cpp @@ -131,7 +131,7 @@ namespace Anabatic { contact = segment->getAutoTarget(); if (contact) _stack.push( contact, segment ); - progress(); + if (not (_flags & Flags::WithSelf)) progress(); } diff --git a/anabatic/src/AutoVertical.cpp b/anabatic/src/AutoVertical.cpp index 948520f4..c049400c 100644 --- a/anabatic/src/AutoVertical.cpp +++ b/anabatic/src/AutoVertical.cpp @@ -139,28 +139,35 @@ namespace Anabatic { constraintMax = getNativeMax(); cdebug_log(149,0) << "Native constraints: [" - << DbU::getValueString(constraintMin) << ":" - << DbU::getValueString(constraintMax) << "]" - << endl; + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; + + constraintMin = std::max ( constraintMin, getAutoSource()->getCBXMin() ); + constraintMax = std::min ( constraintMax, getAutoSource()->getCBXMax() ); + cdebug_log(149,0) << "Merge with source constraints: [" + << DbU::getValueString(getAutoSource()->getCBXMin()) << ":" + << DbU::getValueString(getAutoSource()->getCBXMax()) << "]" + << endl; constraintMin = max ( constraintMin, getUserConstraints().getVMin() ); constraintMax = min ( constraintMax, getUserConstraints().getVMax() ); - cdebug_log(149,0) << "Merge with user constraints: " << getUserConstraints() << " [" - << DbU::getValueString(getUserConstraints().getVMin()) << ":" - << DbU::getValueString(getUserConstraints().getVMax()) << "]" - << endl; + cdebug_log(149,0) << "Merge with user constraints: [" + << DbU::getValueString(getUserConstraints().getVMin()) << ":" + << DbU::getValueString(getUserConstraints().getVMax()) << "]" + << endl; cdebug_log(149,0) << "Resulting constraints: " << " [" - << DbU::getValueString(constraintMin) << ":" - << DbU::getValueString(constraintMax) << "]" - << endl; + << DbU::getValueString(constraintMin) << ":" + << DbU::getValueString(constraintMax) << "]" + << endl; return true; } - unsigned int AutoVertical::getDirection () const + Flags AutoVertical::getDirection () const { return Flags::Vertical; } diff --git a/anabatic/src/Configuration.cpp b/anabatic/src/Configuration.cpp index 9cdf0b86..89dbded6 100644 --- a/anabatic/src/Configuration.cpp +++ b/anabatic/src/Configuration.cpp @@ -57,17 +57,8 @@ namespace Anabatic { // Class : "Anabatic::Configuration". - Configuration::Configuration () { } - Configuration::~Configuration () { } - - -// ------------------------------------------------------------------- -// Class : "Anabatic::ConfigurationConcrete". - - - ConfigurationConcrete::ConfigurationConcrete ( const CellGauge* cg, const RoutingGauge* rg ) - : Configuration () - , _cg (NULL) + Configuration::Configuration ( const CellGauge* cg, const RoutingGauge* rg ) + : _cg (NULL) , _rg (NULL) , _extensionCaps () , _saturateRatio (Cfg::getParamPercentage("katabatic.saturateRatio",80.0)->asDouble()) @@ -79,8 +70,6 @@ namespace Anabatic { , _edgeCostH (Cfg::getParamDouble("anabatic.edgeCostH", 9.0)->asDouble()) , _edgeCostK (Cfg::getParamDouble("anabatic.edgeCostK",-10.0)->asDouble()) , _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble()) - , _hEdgeLocal (Cfg::getParamInt("kite.hTracksReservedLocal",0)->asInt()) - , _vEdgeLocal (Cfg::getParamInt("kite.vTracksReservedLocal",0)->asInt()) { if (cg == NULL) cg = AllianceFramework::get()->getCellGauge(); if (rg == NULL) rg = AllianceFramework::get()->getRoutingGauge(); @@ -119,9 +108,8 @@ namespace Anabatic { } - ConfigurationConcrete::ConfigurationConcrete ( const ConfigurationConcrete& other ) - : Configuration() - , _gmetalh (other._gmetalh) + Configuration::Configuration ( const Configuration& other ) + : _gmetalh (other._gmetalh) , _gmetalv (other._gmetalv) , _gcontact (other._gcontact) , _cg (NULL) @@ -139,7 +127,7 @@ namespace Anabatic { } - ConfigurationConcrete::~ConfigurationConcrete () + Configuration::~Configuration () { cdebug_log(145,0) << "About to delete attribute _rg (RoutingGauge)." << endl; _cg->destroy (); @@ -147,99 +135,99 @@ namespace Anabatic { } - ConfigurationConcrete* ConfigurationConcrete::clone () const - { return new ConfigurationConcrete(*this); } + Configuration* Configuration::clone () const + { return new Configuration(*this); } - bool ConfigurationConcrete::isGMetal ( const Layer* layer ) const + bool Configuration::isGMetal ( const Layer* layer ) const { return (layer and ((layer == _gmetalh) or (layer == _gmetalv))); } - bool ConfigurationConcrete::isGContact ( const Layer* layer ) const + bool Configuration::isGContact ( const Layer* layer ) const { return (layer and (layer == _gcontact)); } - const Layer* ConfigurationConcrete::getGContactLayer () const + const Layer* Configuration::getGContactLayer () const { return _gcontact; } - const Layer* ConfigurationConcrete::getGHorizontalLayer () const + const Layer* Configuration::getGHorizontalLayer () const { return _gmetalh; } - const Layer* ConfigurationConcrete::getGVerticalLayer () const + const Layer* Configuration::getGVerticalLayer () const { return _gmetalv; } - size_t ConfigurationConcrete::getDepth () const + size_t Configuration::getDepth () const { return _rg->getDepth(); } - size_t ConfigurationConcrete::getAllowedDepth () const + size_t Configuration::getAllowedDepth () const { return _allowedDepth; } - size_t ConfigurationConcrete::getLayerDepth ( const Layer* layer ) const + size_t Configuration::getLayerDepth ( const Layer* layer ) const { return _rg->getLayerDepth(layer); } - CellGauge* ConfigurationConcrete::getCellGauge () const + CellGauge* Configuration::getCellGauge () const { return _cg; } - RoutingGauge* ConfigurationConcrete::getRoutingGauge () const + RoutingGauge* Configuration::getRoutingGauge () const { return _rg; } - RoutingLayerGauge* ConfigurationConcrete::getLayerGauge ( size_t depth ) const + RoutingLayerGauge* Configuration::getLayerGauge ( size_t depth ) const { return _rg->getLayerGauge(depth); } - const Layer* ConfigurationConcrete::getRoutingLayer ( size_t depth ) const + const Layer* Configuration::getRoutingLayer ( size_t depth ) const { return _rg->getRoutingLayer(depth); } - Layer* ConfigurationConcrete::getContactLayer ( size_t depth ) const + Layer* Configuration::getContactLayer ( size_t depth ) const { return _rg->getContactLayer(depth); } - DbU::Unit ConfigurationConcrete::getSliceHeight () const + DbU::Unit Configuration::getSliceHeight () const { return _cg->getSliceHeight(); } - DbU::Unit ConfigurationConcrete::getSliceStep () const + DbU::Unit Configuration::getSliceStep () const { return _cg->getSliceStep(); } - DbU::Unit ConfigurationConcrete::getPitch ( const Layer* layer, Flags flags ) const + DbU::Unit Configuration::getPitch ( const Layer* layer, Flags flags ) const { return getPitch( getLayerDepth(layer), flags ); } - DbU::Unit ConfigurationConcrete::getOffset ( const Layer* layer ) const + DbU::Unit Configuration::getOffset ( const Layer* layer ) const { return getOffset( getLayerDepth(layer) ); } - DbU::Unit ConfigurationConcrete::getExtensionCap ( const Layer* layer ) const + DbU::Unit Configuration::getExtensionCap ( const Layer* layer ) const { return getExtensionCap( getLayerDepth(layer) ); } - DbU::Unit ConfigurationConcrete::getWireWidth ( const Layer* layer ) const + DbU::Unit Configuration::getWireWidth ( const Layer* layer ) const { return getWireWidth( getLayerDepth(layer) ); } - Flags ConfigurationConcrete::getDirection ( const Layer* layer ) const + Flags Configuration::getDirection ( const Layer* layer ) const { return getDirection( getLayerDepth(layer) ); } - float ConfigurationConcrete::getSaturateRatio () const + float Configuration::getSaturateRatio () const { return _saturateRatio; } - size_t ConfigurationConcrete::getSaturateRp () const + size_t Configuration::getSaturateRp () const { return _saturateRp; } - DbU::Unit ConfigurationConcrete::getGlobalThreshold () const + DbU::Unit Configuration::getGlobalThreshold () const { return _globalThreshold; } - DbU::Unit ConfigurationConcrete::getPitch ( size_t depth, Flags flags ) const + DbU::Unit Configuration::getPitch ( size_t depth, Flags flags ) const { if (flags == Flags::NoFlags) return _rg->getLayerPitch(depth); @@ -266,27 +254,27 @@ namespace Anabatic { } - DbU::Unit ConfigurationConcrete::getOffset ( size_t depth ) const + DbU::Unit Configuration::getOffset ( size_t depth ) const { return _rg->getLayerOffset(depth); } - DbU::Unit ConfigurationConcrete::getWireWidth ( size_t depth ) const + DbU::Unit Configuration::getWireWidth ( size_t depth ) const { return _rg->getLayerWireWidth(depth); } - DbU::Unit ConfigurationConcrete::getExtensionCap ( size_t depth ) const + DbU::Unit Configuration::getExtensionCap ( size_t depth ) const { return _extensionCaps[depth]; } - Flags ConfigurationConcrete::getDirection ( size_t depth ) const + Flags Configuration::getDirection ( size_t depth ) const { return _rg->getLayerDirection(depth); } - void ConfigurationConcrete::setAllowedDepth ( size_t allowedDepth ) + void Configuration::setAllowedDepth ( size_t allowedDepth ) { _allowedDepth = (allowedDepth > getDepth()) ? getDepth() : allowedDepth; } - void ConfigurationConcrete::_setTopRoutingLayer ( Name name ) + void Configuration::_setTopRoutingLayer ( Name name ) { for ( size_t depth=0 ; depth<_rg->getDepth() ; ++depth ) { if (_rg->getRoutingLayer(depth)->getName() == name) { @@ -301,47 +289,39 @@ namespace Anabatic { } - void ConfigurationConcrete::setSaturateRatio ( float ratio ) + void Configuration::setSaturateRatio ( float ratio ) { _saturateRatio = ratio; } - void ConfigurationConcrete::setSaturateRp ( size_t threshold ) + void Configuration::setSaturateRp ( size_t threshold ) { _saturateRp = threshold; } - void ConfigurationConcrete::setGlobalThreshold ( DbU::Unit threshold ) + void Configuration::setGlobalThreshold ( DbU::Unit threshold ) { _globalThreshold = threshold; } - DbU::Unit ConfigurationConcrete::getEdgeLength () const + DbU::Unit Configuration::getEdgeLength () const { return _edgeLength; } - DbU::Unit ConfigurationConcrete::getEdgeWidth () const + DbU::Unit Configuration::getEdgeWidth () const { return _edgeWidth; } - size_t ConfigurationConcrete::getHEdgeLocal () const - { return _hEdgeLocal; } - - - size_t ConfigurationConcrete::getVEdgeLocal () const - { return _vEdgeLocal; } - - - float ConfigurationConcrete::getEdgeCostH () const + float Configuration::getEdgeCostH () const { return _edgeCostH; } - float ConfigurationConcrete::getEdgeCostK () const + float Configuration::getEdgeCostK () const { return _edgeCostK; } - float ConfigurationConcrete::getEdgeHInc () const + float Configuration::getEdgeHInc () const { return _edgeHInc; } - void ConfigurationConcrete::print ( Cell* cell ) const + void Configuration::print ( Cell* cell ) const { string topLayerName = "UNKOWN"; const Layer* topLayer = _rg->getRoutingLayer( _allowedDepth ); @@ -354,13 +334,13 @@ namespace Anabatic { } - string ConfigurationConcrete::_getTypeName () const + string Configuration::_getTypeName () const { - return "ConfigurationConcrete"; + return "Configuration"; } - string ConfigurationConcrete::_getString () const + string Configuration::_getString () const { ostringstream os; @@ -370,7 +350,7 @@ namespace Anabatic { } - Record* ConfigurationConcrete::_getRecord () const + Record* Configuration::_getRecord () const { Record* record = new Record ( _getString() ); record->add ( getSlot( "_rg" , _rg ) ); @@ -385,5 +365,4 @@ namespace Anabatic { } - } // Anabatic namespace. diff --git a/anabatic/src/Constants.cpp b/anabatic/src/Constants.cpp index 6b300503..8508d00f 100644 --- a/anabatic/src/Constants.cpp +++ b/anabatic/src/Constants.cpp @@ -22,6 +22,66 @@ namespace Anabatic { using std::string; + const unsigned int Flags::NoFlags = 0; +// Flags used for both objects states & functions arguments. + const unsigned int Flags::Horizontal = (1 << 0); + const unsigned int Flags::Vertical = (1 << 1); + const unsigned int Flags::Source = (1 << 2); + const unsigned int Flags::Target = (1 << 3); + const unsigned int Flags::Invalidated = (1 << 4); +// Flags for GCell objects states only. + const unsigned int Flags::DeviceGCell = (1 << 5); + const unsigned int Flags::ChannelGCell = (1 << 6); + const unsigned int Flags::StrutGCell = (1 << 7); + const unsigned int Flags::MatrixGCell = (1 << 8); + const unsigned int Flags::IoPadGCell = (1 << 9); + const unsigned int Flags::Saturated = (1 << 10); +// Flags for Anabatic objects states only. + const unsigned int Flags::DemoMode = (1 << 5); + const unsigned int Flags::WarnOnGCellOverload = (1 << 6); + const unsigned int Flags::DestroyGCell = (1 << 7); + const unsigned int Flags::DestroyBaseContact = (1 << 8); + const unsigned int Flags::DestroyBaseSegment = (1 << 9); +// Flags for NetDatas objects states only. + const unsigned int Flags::GlobalRouted = (1 << 5); +// Masks. + const unsigned int Flags::WestSide = Horizontal|Target; + const unsigned int Flags::EastSide = Horizontal|Source; + const unsigned int Flags::SouthSide = Vertical |Target; + const unsigned int Flags::NorthSide = Vertical |Source; + const unsigned int Flags::AllSides = WestSide|EastSide|SouthSide|NorthSide ; + const unsigned int Flags::EndsMask = Source|Target; + const unsigned int Flags::DirectionMask = Horizontal|Vertical; + const unsigned int Flags::DestroyMask = DestroyGCell|DestroyBaseContact|DestroyBaseSegment; + const unsigned int Flags::GCellTypeMask = DeviceGCell|ChannelGCell|StrutGCell|MatrixGCell|IoPadGCell; +// Flags for functions arguments only. + const unsigned int Flags::Create = (1 << 5); + const unsigned int Flags::WithPerpands = (1 << 6); + const unsigned int Flags::WithSelf = (1 << 7); + const unsigned int Flags::AboveLayer = (1 << 8); + const unsigned int Flags::BelowLayer = (1 << 9); + const unsigned int Flags::OpenSession = (1 << 10); + const unsigned int Flags::Realignate = (1 << 11); + const unsigned int Flags::NativeConstraints = (1 << 12); + const unsigned int Flags::ForceMove = (1 << 13); + const unsigned int Flags::WarnOnError = (1 << 14); + const unsigned int Flags::Topology = (1 << 15); + const unsigned int Flags::GlobalSegment = (1 << 16); + const unsigned int Flags::AllowTerminal = (1 << 17); + const unsigned int Flags::AllowLocal = (1 << 18); + const unsigned int Flags::IgnoreContacts = (1 << 19); + const unsigned int Flags::Propagate = (1 << 20); + const unsigned int Flags::Superior = (1 << 21); + const unsigned int Flags::DoglegOnLeft = (1 << 22); + const unsigned int Flags::DoglegOnRight = (1 << 23); + const unsigned int Flags::WithNeighbors = (1 << 24); + const unsigned int Flags::NoCheckLayer = (1 << 25); + const unsigned int Flags::HalfSlacken = (1 << 26); + const unsigned int Flags::NoGCellShrink = (1 << 27); + const unsigned int Flags::CParanoid = (1 << 28); + const unsigned int Flags::CheckLowDensity = (1 << 29); + const unsigned int Flags::NoUpdate = (1 << 30); + Flags::~Flags () { } diff --git a/anabatic/src/Dijkstra.cpp b/anabatic/src/Dijkstra.cpp index be1b1a90..5df42edb 100644 --- a/anabatic/src/Dijkstra.cpp +++ b/anabatic/src/Dijkstra.cpp @@ -85,7 +85,6 @@ namespace Anabatic { void Vertex::notify ( Vertex* vertex, unsigned int flags ) { - //Vertex* vertex = getOwner(); cdebug_log(111,0) << "Vertex::notify() " << vertex << endl; // Take into account the GCell modification here. } diff --git a/anabatic/src/GCell.cpp b/anabatic/src/GCell.cpp index 0985af40..58ce5c98 100644 --- a/anabatic/src/GCell.cpp +++ b/anabatic/src/GCell.cpp @@ -325,7 +325,7 @@ namespace Anabatic { if (not anabatic) throw Error( "GCell::create(): NULL anabatic argument." ); if (not anabatic->getCell()) throw Error( "GCell::create(): AnabaticEngine has no Cell loaded." ); - Session::open( anabatic ); + anabatic->openSession(); GCell* gcell = new GCell ( anabatic , anabatic->getCell()->getAbutmentBox().getXMin() , anabatic->getCell()->getAbutmentBox().getYMin() ); @@ -539,6 +539,16 @@ namespace Anabatic { } + GCell* GCell::getNeighborAt ( Flags side, DbU::Unit axis ) const + { + if (side & Flags::EastSide ) return getEast (axis); + if (side & Flags::WestSide ) return getWest (axis); + if (side & Flags::NorthSide) return getNorth(axis); + if (side & Flags::SouthSide) return getSouth(axis); + return NULL; + } + + GCell* GCell::getUnder ( DbU::Unit x, DbU::Unit y ) const { const GCell* current = this; @@ -706,10 +716,10 @@ namespace Anabatic { bool GCell::doGrid () { - Session::open( getAnabatic() ); + getAnabatic()->openSession(); - const vector& gcells = getAnabatic()->getGCells(); - size_t ibegin = gcells.size(); + //const vector& gcells = getAnabatic()->getGCells(); + //size_t ibegin = gcells.size(); DbU::Unit side = Session::getSliceHeight(); Interval hspan = getSide( Flags::Horizontal ); @@ -740,29 +750,32 @@ namespace Anabatic { for ( ; ycut < vspan.getVMax() ; ycut += side ) { column = row; row = row->hcut( ycut ); + row->setType( Flags::MatrixGCell ); for ( DbU::Unit xcut = hspan.getVMin()+side ; xcut < hspan.getVMax() ; xcut += side ) { column = column->vcut( xcut ); + column->setType( Flags::MatrixGCell ); } } column = row; for ( DbU::Unit xcut = hspan.getVMin()+side ; xcut < hspan.getVMax() ; xcut += side ) { column = column->vcut( xcut ); + column->setType( Flags::MatrixGCell ); } setType( Flags::MatrixGCell ); - size_t hLocal = - getAnabatic()->getConfiguration()->getHEdgeLocal(); - size_t vLocal = - getAnabatic()->getConfiguration()->getVEdgeLocal(); - for ( ; ibegin < gcells.size() ; ++ibegin ) { - gcells[ibegin]->setType( Flags::MatrixGCell ); + //size_t hLocal = - getAnabatic()->getConfiguration()->getHEdgeLocal(); + //size_t vLocal = - getAnabatic()->getConfiguration()->getVEdgeLocal(); + //for ( ; ibegin < gcells.size() ; ++ibegin ) { + // gcells[ibegin]->setType( Flags::MatrixGCell ); - for ( Edge* edge : gcells[ibegin]->getEdges(Flags::NorthSide|Flags::EastSide) ) { - if (edge->isHorizontal()) edge->incCapacity( hLocal ); - else edge->incCapacity( vLocal ); - } - } + // for ( Edge* edge : gcells[ibegin]->getEdges(Flags::NorthSide|Flags::EastSide) ) { + // if (edge->isHorizontal()) edge->incCapacity( hLocal ); + // else edge->incCapacity( vLocal ); + // } + //} Session::close(); return true; @@ -1049,13 +1062,8 @@ namespace Anabatic { Interval GCell::getSide ( unsigned int direction ) const { - Interval side; - switch ( direction ) { - default: - case Flags::Horizontal: side = Interval(getXMin(),getXMax()); break; - case Flags::Vertical: side = Interval(getYMin(),getYMax()); break; - } - return side; + if (direction & Flags::Vertical) return Interval( getYMin(), getYMax() ); + return Interval( getXMin(), getXMax() ); } @@ -1312,15 +1320,12 @@ namespace Anabatic { localCounts [i] = 0.0; _globalsCount[i] = 0.0; - switch ( Session::getDirection(i) ) { - case Flags::Horizontal: - ufragments[i].setSpan ( getXMin(), getXMax() ); - ufragments[i].setCapacity( (size_t)hcapacity ); - break; - case Flags::Vertical: - ufragments[i].setSpan ( getYMin(), getYMax() ); - ufragments[i].setCapacity( (size_t)vcapacity ); - break; + if (Session::getDirection(i) & Flags::Horizontal) { + ufragments[i].setSpan ( getXMin(), getXMax() ); + ufragments[i].setCapacity( (size_t)hcapacity ); + } else { + ufragments[i].setSpan ( getYMin(), getYMax() ); + ufragments[i].setCapacity( (size_t)vcapacity ); } } @@ -1330,10 +1335,10 @@ namespace Anabatic { for ( size_t i=0 ; i<_depth ; i++ ) uLengths1[i] = 0; contact->getLengths ( uLengths1, processeds ); for ( size_t i=0 ; i<_depth ; i++ ) { - switch ( Session::getDirection(i) ) { - case Flags::Horizontal: uLengths2[i] += uLengths1[i]+hpenalty; break; - case Flags::Vertical: uLengths2[i] += uLengths1[i]+vpenalty; break; - } + if (Session::getDirection(i) & Flags::Horizontal) + uLengths2[i] += uLengths1[i]+hpenalty; + else + uLengths2[i] += uLengths1[i]+vpenalty; break; } } @@ -1415,29 +1420,26 @@ namespace Anabatic { // Normalize: 0 < d < 1.0 (divide by H/V capacity). for ( size_t i=0 ; i<_depth ; i++ ) { - switch ( Session::getDirection(i) ) { - case Flags::Horizontal: - if (width) { - _densities [i] = ((float)uLengths2[i]) / ( hcapacity * (float)width ); - _feedthroughs [i] += (float)(_blockages[i] / width); - _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)width; - } else { - _densities [i] = 0; - _feedthroughs [i] = 0; - _fragmentations[i] = 0; - } - break; - case Flags::Vertical: - if (height) { - _densities [i] = ((float)uLengths2[i]) / ( vcapacity * (float)height ); - _feedthroughs [i] += (float)(_blockages[i] / height); - _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)height; - } else { - _densities [i] = 0; - _feedthroughs [i] = 0; - _fragmentations[i] = 0; - } - break; + if (Session::getDirection(i) & Flags::Horizontal) { + if (width) { + _densities [i] = ((float)uLengths2[i]) / ( hcapacity * (float)width ); + _feedthroughs [i] += (float)(_blockages[i] / width); + _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)width; + } else { + _densities [i] = 0; + _feedthroughs [i] = 0; + _fragmentations[i] = 0; + } + } else { + if (height) { + _densities [i] = ((float)uLengths2[i]) / ( vcapacity * (float)height ); + _feedthroughs [i] += (float)(_blockages[i] / height); + _fragmentations[i] = (float)ufragments[i].getMaxFree().getSize() / (float)height; + } else { + _densities [i] = 0; + _feedthroughs [i] = 0; + _fragmentations[i] = 0; + } } if (_densities[i] >= 1.0) _flags |= Flags::Saturated; @@ -1455,6 +1457,25 @@ namespace Anabatic { } + void GCell::truncDensities () + { + int hcapacity = (int)getHCapacity(); + int vcapacity = (int)getVCapacity(); + Box bBox = getBoundingBox(); + + for ( size_t i=0 ; i<_depth ; i++ ) { + if (Session::getDirection(i) & Flags::Horizontal) { + if (_blockages[i] > hcapacity * bBox.getWidth()) + _blockages[i] = hcapacity * bBox.getWidth(); + } else { + if (_blockages[i] > vcapacity * bBox.getHeight()) + _blockages[i] = vcapacity * bBox.getHeight(); + } + } + _flags &= ~Flags::Saturated; + } + + size_t GCell::checkDensity () const { if (isInvalidated()) const_cast(this)->updateDensity(); @@ -1485,10 +1506,8 @@ namespace Anabatic { if (isInvalidated()) const_cast(this)->updateDensity(); float capacity = 0.0; - switch ( Session::getDirection(depth) ) { - case Flags::Horizontal: capacity = getHCapacity(); break; - case Flags::Vertical: capacity = getVCapacity(); break; - } + if (Session::getDirection(depth) & Flags::Horizontal) capacity = getHCapacity(); + else capacity = getVCapacity(); cdebug_log(149,0) << " | hasFreeTrack [" << getId() << "] depth:" << depth << " " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() @@ -1543,15 +1562,12 @@ namespace Anabatic { vector::iterator isegment; vector::iterator iend; - switch ( Session::getDirection(depth) ) { - case Flags::Horizontal: - iend = _hsegments.end (); - isegment = _hsegments.begin(); - break; - case Flags::Vertical: - iend = _vsegments.end (); - isegment = _vsegments.begin(); - break; + if (Session::getDirection(depth) & Flags::Horizontal) { + iend = _hsegments.end (); + isegment = _hsegments.begin(); + } else { + iend = _vsegments.end (); + isegment = _vsegments.begin(); } for ( ; (isegment != iend) ; isegment++ ) { @@ -1582,15 +1598,12 @@ namespace Anabatic { vector::iterator iend; set globalNets; - switch ( Session::getDirection(depth) ) { - case Flags::Horizontal: - iend = _hsegments.end (); - isegment = _hsegments.begin(); - break; - case Flags::Vertical: - iend = _vsegments.end (); - isegment = _vsegments.begin(); - break; + if (Session::getDirection(depth) & Flags::Horizontal) { + iend = _hsegments.end (); + isegment = _hsegments.begin(); + } else { + iend = _vsegments.end (); + isegment = _vsegments.begin(); } for ( ; (isegment != iend) ; isegment++ ) { @@ -1626,15 +1639,12 @@ namespace Anabatic { vector::iterator isegment; vector::iterator iend; - switch ( Session::getDirection(depth) ) { - case Flags::Horizontal: - iend = _hsegments.end (); - isegment = _hsegments.begin (); - break; - case Flags::Vertical: - iend = _vsegments.end (); - isegment = _vsegments.begin (); - break; + if (Session::getDirection(depth) & Flags::Horizontal) { + iend = _hsegments.end (); + isegment = _hsegments.begin (); + } else { + iend = _vsegments.end (); + isegment = _vsegments.begin (); } for ( ; (isegment != iend) ; isegment++ ) { @@ -1775,4 +1785,30 @@ namespace Anabatic { } + bool isLess ( const GCell* lhs, const GCell* rhs, Flags direction ) + { + if (direction & Flags::Horizontal) { + if (lhs->getXMin() != rhs->getXMin()) return lhs->getXMin() < rhs->getXMin(); + } else { + if (direction & Flags::Vertical) { + if (lhs->getYMin() != rhs->getYMin()) return lhs->getYMin() < rhs->getYMin(); + } + } + return lhs->getId() < rhs->getId(); + } + + + bool isGreater ( const GCell* lhs, const GCell* rhs, Flags direction ) + { + if (direction & Flags::Horizontal) { + if (lhs->getXMin() != rhs->getXMin()) return lhs->getXMin() > rhs->getXMin(); + } else { + if (direction & Flags::Vertical) { + if (lhs->getYMin() != rhs->getYMin()) return lhs->getYMin() > rhs->getYMin(); + } + } + return lhs->getId() > rhs->getId(); + } + + } // Anabatic namespace. diff --git a/anabatic/src/GlobalRoute.cpp b/anabatic/src/GlobalRoute.cpp index 137d4a98..587380f1 100644 --- a/anabatic/src/GlobalRoute.cpp +++ b/anabatic/src/GlobalRoute.cpp @@ -1,4 +1,4 @@ -// -*- C++ -*- +// -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp" -*- // // This file is part of the Coriolis Software. // Copyright (c) UPMC 2016-2016, All Rights Reserved @@ -138,7 +138,6 @@ namespace Anabatic { startMeasures(); - UpdateSession::open(); if (getGCells().size() == 1) { cmess1 << " o Building regular grid..." << endl; getSouthWestGCell()->doGrid(); @@ -146,24 +145,21 @@ namespace Anabatic { cmess1 << " o Reusing existing grid." << endl; } cmess1 << Dots::asInt(" - GCells" ,getGCells().size()) << endl; - UpdateSession::close(); stopMeasures(); printMeasures( "Anabatic Grid" ); - Session::open( this ); setupSpecialNets(); setupPreRouteds (); setupNetDatas(); - Session::close(); + openSession(); startMeasures(); cmess1 << " o Running global routing..." << endl; float edgeHInc = getConfiguration()->getEdgeHInc(); - Session::open( this ); Dijkstra* dijkstra = new Dijkstra ( this ); dijkstra->setDistance( DigitalDistance( getConfiguration()->getEdgeCostH() , getConfiguration()->getEdgeCostK() ) ); diff --git a/anabatic/src/LayerAssign.cpp b/anabatic/src/LayerAssign.cpp index d08183a9..88591ba0 100644 --- a/anabatic/src/LayerAssign.cpp +++ b/anabatic/src/LayerAssign.cpp @@ -377,7 +377,7 @@ namespace Anabatic { void AnabaticEngine::_balanceGlobalDensity ( unsigned int depth ) { startMeasures(); - Session::open( this ); + openSession(); cmess1 << " o Balance Global Density " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() << endl; @@ -435,7 +435,7 @@ namespace Anabatic { set globalNets; GCell::Set invalidateds; - Session::open( this ); + openSession(); vector segments; @@ -482,7 +482,7 @@ namespace Anabatic { unsigned long global = 0; startMeasures(); - Session::open( this ); + openSession(); if (Session::getAllowedDepth() >= 3) { switch ( method ) { diff --git a/anabatic/src/LoadGlobalRouting.cpp b/anabatic/src/LoadGlobalRouting.cpp index 0d8acce5..9861359a 100644 --- a/anabatic/src/LoadGlobalRouting.cpp +++ b/anabatic/src/LoadGlobalRouting.cpp @@ -2096,7 +2096,10 @@ namespace { void GCellTopology::_doChannel () { - throw Error( "GCellTopology::_doChannel() Unimplemented, blame goes to E. Lao." ); + throw Error( "GCellTopology::_doChannel() Unimplemented, blame goes to E. Lao.\n" + " On: %s." + , getString(_gcell).c_str() + ); } @@ -2134,7 +2137,7 @@ namespace Anabatic { //cmess1 << Dots::asDouble(" - Saturation",getMeasure(getCell(),"Sat.")->getData()) << endl; startMeasures(); - Session::open( this ); + openSession(); forEach ( Net*, inet, getCell()->getNets() ) { if (NetRoutingExtension::isAutomaticGlobalRoute(*inet)) { diff --git a/anabatic/src/NetConstraints.cpp b/anabatic/src/NetConstraints.cpp index 5100dfc2..2ea1e7ca 100644 --- a/anabatic/src/NetConstraints.cpp +++ b/anabatic/src/NetConstraints.cpp @@ -63,40 +63,42 @@ namespace { { cdebug_log(145,1) << "propagateConstraintFromRp() - " << rp << endl; - forEach ( Component*, icomponent, rp->getSlaveComponents() ) { - cdebug_log(145,0) << "slave component: " << *icomponent << endl; - AutoContact* sourceContact = Session::lookup( dynamic_cast(*icomponent) ); + for ( Component* component : rp->getSlaveComponents() ) { + cdebug_log(145,0) << "slave component: " << component << endl; + AutoContact* sourceContact = Session::lookup( dynamic_cast(component) ); if (sourceContact) { cdebug_log(145,0) << "Start slave: " << sourceContact << endl; set verticalSegments; set horizontalSegments; - forEach ( AutoSegment*, isegment, sourceContact->getAutoSegments() ) { - cdebug_log(145,0) << "Examining: " << (*isegment) << endl; - AutoContact* targetContact = isegment->getOppositeAnchor(sourceContact); + for ( AutoSegment* segment : sourceContact->getAutoSegments() ) { + cdebug_log(145,0) << "Examining: " << segment << endl; + AutoContact* targetContact = segment->getOppositeAnchor(sourceContact); if (targetContact) { - if (isegment->isHorizontal()) { - cdebug_log(145,0) << "On horizontal stack " << (*isegment) << endl; - horizontalSegments.insert( (*isegment) ); + if (segment->isHorizontal()) { + cdebug_log(145,0) << "On horizontal stack " << segment << endl; + horizontalSegments.insert( segment ); } else { - cdebug_log(145,0) << "On vertical stack " << (*isegment) << endl; - verticalSegments.insert( (*isegment) ); + cdebug_log(145,0) << "On vertical stack " << segment << endl; + verticalSegments.insert( segment ); } } } Box constraintBox = sourceContact->getConstraintBox(); + cdebug_log(145,0) << "Contraint: " << constraintBox << endl; // Propagate constraint through horizontally aligned segments. cdebug_log(145,0) << "Propagate constraint on horizontal segments" << endl; - set::iterator ihorizontal = horizontalSegments.begin(); - for ( ; ihorizontal != horizontalSegments.end() ; ++ihorizontal ) { + for ( AutoSegment* horizontal : horizontalSegments ) { AutoContact* contact = NULL; - forEach ( AutoSegment*, ialigned, (*ihorizontal)->getAligneds() ) { - contact = ialigned->getAutoTarget(); + for ( AutoSegment* aligned : horizontal->getAligneds(Flags::WithSelf) ) { + cdebug_log(145,0) << "aligned horizontal: " << aligned << endl; + + contact = aligned->getAutoTarget(); cdebug_log(145,0) << "contact: " << contact << endl; if (contact) { cdebug_log(145,0) << "Apply to (target): " << contact << endl; @@ -104,7 +106,7 @@ namespace { , constraintBox.getYMax() , Flags::Horizontal|Flags::WarnOnError ); } - contact = ialigned->getAutoSource(); + contact = aligned->getAutoSource(); cdebug_log(145,0) << "contact: " << contact << endl; if (contact) { cdebug_log(145,0) << "Apply to (source): " << contact << endl; @@ -118,18 +120,19 @@ namespace { // Propagate constraint through vertically aligned segments. cdebug_log(145,0) << "Propagate constraint on vertical segments" << endl; - set::iterator ivertical = verticalSegments.begin(); - for ( ; ivertical != verticalSegments.end() ; ++ivertical ) { + for ( AutoSegment* vertical : verticalSegments ) { AutoContact* contact = NULL; - forEach ( AutoSegment*, ialigned, (*ivertical)->getAligneds() ) { - contact = ialigned->getAutoTarget(); + for ( AutoSegment* aligned : vertical->getAligneds(Flags::WithSelf) ) { + cdebug_log(145,0) << "aligned vertical: " << aligned << endl; + + contact = aligned->getAutoTarget(); if (contact) { cdebug_log(145,0) << "Apply to (target): " << contact << endl; contact->restrictConstraintBox( constraintBox.getXMin() , constraintBox.getXMax() , Flags::Vertical|Flags::WarnOnError ); } - contact = ialigned->getAutoSource(); + contact = aligned->getAutoSource(); if (contact) { cdebug_log(145,0) << "Apply to (source): " << contact << endl; contact->restrictConstraintBox( constraintBox.getXMin() diff --git a/anabatic/src/PreRouteds.cpp b/anabatic/src/PreRouteds.cpp index ea9498e0..5602792b 100644 --- a/anabatic/src/PreRouteds.cpp +++ b/anabatic/src/PreRouteds.cpp @@ -70,6 +70,8 @@ namespace Anabatic { { cmess1 << " o Looking for fixed or manually global routed nets." << endl; + openSession(); + for ( Net* net : getCell()->getNets() ) { if (net == _blockageNet) continue; if (net->getType() == Net::Type::POWER ) continue; @@ -170,7 +172,7 @@ namespace Anabatic { } } - Session::revalidate(); + Session::close(); } diff --git a/anabatic/src/Session.cpp b/anabatic/src/Session.cpp index 1849eefe..19a90e30 100644 --- a/anabatic/src/Session.cpp +++ b/anabatic/src/Session.cpp @@ -32,7 +32,7 @@ namespace { - const char* reopenSession = "Session::open(): Session already open for %s (internal error)."; + const char* reopenSession = "Anabatic::Session::_open(): Session already open for %s (internal error)."; const char* openSessionError = "%s: Session has not been opened (internal error)."; @@ -96,7 +96,6 @@ namespace Anabatic { { if (_anabatic->getState() <= EngineActive) { _revalidate (); - _anabatic->updateDensity(); } UpdateSession::close(); @@ -266,9 +265,9 @@ namespace Anabatic { } - Session* Session::open ( AnabaticEngine* anbt ) + Session* Session::_open ( AnabaticEngine* anbt ) { - cdebug_log(145,0) << "Session::open()" << endl; + cdebug_log(145,0) << "Anabatic::Session::_open()" << endl; if (_session) { if (_session->_anabatic != anbt) diff --git a/anabatic/src/anabatic/AnabaticEngine.h b/anabatic/src/anabatic/AnabaticEngine.h index f5d5be3b..32cb9bb3 100644 --- a/anabatic/src/anabatic/AnabaticEngine.h +++ b/anabatic/src/anabatic/AnabaticEngine.h @@ -107,6 +107,7 @@ namespace Anabatic { NetData ( Net* ); inline bool isGlobalRouted () const; inline bool isMixedPreRoute () const; + inline bool isFixed () const; inline Net* getNet () const; inline NetRoutingState* getNetRoutingState () const; inline const Box& getSearchArea () const; @@ -133,6 +134,7 @@ namespace Anabatic { inline bool NetData::isGlobalRouted () const { return _flags & Flags::GlobalRouted; } inline bool NetData::isMixedPreRoute () const { return (_state) ? _state->isMixedPreRoute() : false; } + inline bool NetData::isFixed () const { return (_state) ? _state->isFixed () : false; } inline Net* NetData::getNet () const { return _net; } inline NetRoutingState* NetData::getNetRoutingState () const { return _state; } inline const Box& NetData::getSearchArea () const { return _searchArea; } @@ -195,8 +197,10 @@ namespace Anabatic { inline GCell* getGCellUnder ( DbU::Unit x, DbU::Unit y ) const; inline GCell* getGCellUnder ( Point ) const; inline GCellsUnder getGCellsUnder ( Segment* ) const; + Interval getUSide ( Flags direction ) const; int getCapacity ( Interval, Flags ) const; size_t getNetsFromEdge ( const Edge*, NetSet& ); + virtual void openSession (); inline void setState ( EngineState state ); inline void setDensityMode ( unsigned int ); inline void addOv ( Edge* ); @@ -225,11 +229,14 @@ namespace Anabatic { inline size_t getSaturateRp () const; inline DbU::Unit getExtensionCap () const; inline Net* getBlockageNet () const; + inline const ChipTools& getChipTools () const; + inline const vector& getNetOrdering () const; void updateDensity (); size_t checkGCellDensities (); inline void setGlobalThreshold ( DbU::Unit ); inline void setSaturateRatio ( float ); inline void setSaturateRp ( size_t ); + inline void setBlockageNet ( Net* ); void chipPrep (); void setupSpecialNets (); void setupPreRouteds (); @@ -261,10 +268,13 @@ namespace Anabatic { void _saveNet ( Net* ); void _destroyAutoContacts (); void _destroyAutoSegments (); + void _check ( Net* net ) const; + bool _check ( const char* message ) const; // Misc. functions. inline const Flags& flags () const; inline Flags& flags (); void reset (); + inline const Timer& getTimer () const; void startMeasures (); void stopMeasures (); void printMeasures ( const string& ) const; @@ -319,6 +329,7 @@ namespace Anabatic { inline GCellsUnder AnabaticEngine::getGCellsUnder ( Segment* s ) const { return std::shared_ptr( new RawGCellsUnder(this,s) ); } inline unsigned int AnabaticEngine::getDensityMode () const { return _densityMode; } inline void AnabaticEngine::setDensityMode ( unsigned int mode ) { _densityMode=mode; } + inline void AnabaticEngine::setBlockageNet ( Net* net ) { _blockageNet = net; } inline const AutoContactLut& AnabaticEngine::_getAutoContactLut () const { return _autoContactLut; } inline const AutoSegmentLut& AnabaticEngine::_getAutoSegmentLut () const { return _autoSegmentLut; } inline const Flags& AnabaticEngine::flags () const { return _flags; } @@ -335,6 +346,8 @@ namespace Anabatic { inline void AnabaticEngine::setSaturateRatio ( float ratio ) { _configuration->setSaturateRatio(ratio); } inline void AnabaticEngine::setSaturateRp ( size_t threshold ) { _configuration->setSaturateRp(threshold); } inline Net* AnabaticEngine::getBlockageNet () const { return _blockageNet; } + inline const ChipTools& AnabaticEngine::getChipTools () const { return _chipTools; } + inline const vector& AnabaticEngine::getNetOrdering () const { return _netOrdering; } inline void AnabaticEngine::setGlobalThreshold ( DbU::Unit threshold ) { _configuration->setGlobalThreshold(threshold); } inline const NetDatas& AnabaticEngine::getNetDatas () const { return _netDatas; } inline void AnabaticEngine::_updateLookup ( GCell* gcell ) { _matrix.updateLookup(gcell); } @@ -356,8 +369,9 @@ namespace Anabatic { } } - inline int AnabaticEngine::getStamp () const { return _stamp; } - inline int AnabaticEngine::incStamp () { return ++_stamp; } + inline const Timer& AnabaticEngine::getTimer () const { return _timer; } + inline int AnabaticEngine::getStamp () const { return _stamp; } + inline int AnabaticEngine::incStamp () { return ++_stamp; } inline void AnabaticEngine::addOv ( Edge* edge ) { _ovEdges.push_back(edge); } diff --git a/anabatic/src/anabatic/AutoHorizontal.h b/anabatic/src/anabatic/AutoHorizontal.h index 762017a7..1726c3f0 100644 --- a/anabatic/src/anabatic/AutoHorizontal.h +++ b/anabatic/src/anabatic/AutoHorizontal.h @@ -48,7 +48,7 @@ namespace Anabatic { virtual bool getConstraints ( DbU::Unit& min , DbU::Unit& max ) const; virtual Interval getSourceConstraints ( unsigned int flags=0 ) const; virtual Interval getTargetConstraints ( unsigned int flags=0 ) const; - virtual unsigned int getDirection () const; + virtual Flags getDirection () const; virtual size_t getGCells ( vector& ) const; // Modifiers. virtual void setDuSource ( DbU::Unit ); diff --git a/anabatic/src/anabatic/AutoSegment.h b/anabatic/src/anabatic/AutoSegment.h index 8e93ecdc..49fda903 100644 --- a/anabatic/src/anabatic/AutoSegment.h +++ b/anabatic/src/anabatic/AutoSegment.h @@ -215,7 +215,7 @@ namespace Anabatic { // Accessors. inline unsigned long getId () const; inline unsigned int getFlags () const; - virtual unsigned int getDirection () const = 0; + virtual Flags getDirection () const = 0; inline GCell* getGCell () const; virtual size_t getGCells ( vector& ) const = 0; inline AutoContact* getAutoSource () const; diff --git a/anabatic/src/anabatic/AutoVertical.h b/anabatic/src/anabatic/AutoVertical.h index ac263f20..f212a2e5 100644 --- a/anabatic/src/anabatic/AutoVertical.h +++ b/anabatic/src/anabatic/AutoVertical.h @@ -1,4 +1,3 @@ - // -*- C++ -*- // // This file is part of the Coriolis Software. @@ -49,7 +48,7 @@ namespace Anabatic { virtual bool getConstraints ( DbU::Unit& min, DbU::Unit& max ) const; virtual Interval getSourceConstraints ( unsigned int flags=0 ) const; virtual Interval getTargetConstraints ( unsigned int flags=0 ) const; - virtual unsigned int getDirection () const; + virtual Flags getDirection () const; virtual size_t getGCells ( vector& ) const; // Modifiers. virtual void setDuSource ( DbU::Unit ); diff --git a/anabatic/src/anabatic/Configuration.h b/anabatic/src/anabatic/Configuration.h index f293817d..23789e13 100644 --- a/anabatic/src/anabatic/Configuration.h +++ b/anabatic/src/anabatic/Configuration.h @@ -50,121 +50,57 @@ namespace Anabatic { // ------------------------------------------------------------------- -// Class : "Anabatic::Configuration" (decorator). +// Class : "Anabatic::Configuration". class Configuration { public: // Constructor & Destructor. - virtual ~Configuration (); - virtual Configuration* clone () const = 0; - // Methods. - virtual bool isGMetal ( const Layer* ) const = 0; - virtual bool isGContact ( const Layer* ) const = 0; - virtual const Layer* getGContactLayer () const = 0; - virtual const Layer* getGHorizontalLayer () const = 0; - virtual const Layer* getGVerticalLayer () const = 0; - virtual size_t getDepth () const = 0; - virtual size_t getAllowedDepth () const = 0; - virtual size_t getLayerDepth ( const Layer* ) const = 0; - virtual CellGauge* getCellGauge () const = 0; - virtual RoutingGauge* getRoutingGauge () const = 0; - virtual RoutingLayerGauge* getLayerGauge ( size_t depth ) const = 0; - virtual const Layer* getRoutingLayer ( size_t depth ) const = 0; - virtual Layer* getContactLayer ( size_t depth ) const = 0; - virtual DbU::Unit getSliceHeight () const = 0; - virtual DbU::Unit getSliceStep () const = 0; - virtual DbU::Unit getPitch ( size_t depth, Flags flags ) const = 0; - virtual DbU::Unit getOffset ( size_t depth ) const = 0; - virtual DbU::Unit getWireWidth ( size_t depth ) const = 0; - virtual DbU::Unit getExtensionCap ( size_t depth ) const = 0; - virtual Flags getDirection ( size_t depth ) const = 0; - virtual DbU::Unit getPitch ( const Layer*, Flags flags ) const = 0; - virtual DbU::Unit getOffset ( const Layer* ) const = 0; - virtual DbU::Unit getWireWidth ( const Layer* ) const = 0; - virtual DbU::Unit getExtensionCap ( const Layer* ) const = 0; - virtual Flags getDirection ( const Layer* ) const = 0; - virtual float getSaturateRatio () const = 0; - virtual size_t getSaturateRp () const = 0; - virtual DbU::Unit getGlobalThreshold () const = 0; - virtual void setAllowedDepth ( size_t ) = 0; - virtual void setSaturateRatio ( float ) = 0; - virtual void setSaturateRp ( size_t ) = 0; - virtual void setGlobalThreshold ( DbU::Unit ) = 0; - virtual DbU::Unit getEdgeLength () const = 0; - virtual DbU::Unit getEdgeWidth () const = 0; - virtual float getEdgeCostH () const = 0; - virtual float getEdgeCostK () const = 0; - virtual float getEdgeHInc () const = 0; - virtual size_t getHEdgeLocal () const = 0; - virtual size_t getVEdgeLocal () const = 0; - virtual void print ( Cell* ) const = 0; - virtual Record* _getRecord () const = 0; - virtual string _getString () const = 0; - virtual string _getTypeName () const = 0; - protected: - Configuration (); - private: + Configuration ( const CellGauge* cg=NULL, const RoutingGauge* rg=NULL ); Configuration ( const Configuration& ); - Configuration& operator= ( const Configuration& ); - private: - static Configuration* _default; - }; - - -// ------------------------------------------------------------------- -// Class : "Anabatic::ConfigurationConcrete". - - class ConfigurationConcrete : public Configuration { - friend class Configuration; - public: - // Constructor & Destructor. - ConfigurationConcrete ( const CellGauge* cg=NULL, const RoutingGauge* rg=NULL ); - virtual ~ConfigurationConcrete (); - virtual ConfigurationConcrete* clone () const; + virtual ~Configuration (); + virtual Configuration* clone () const; // Methods. - virtual bool isGMetal ( const Layer* ) const; - virtual bool isGContact ( const Layer* ) const; - virtual const Layer* getGContactLayer () const; - virtual const Layer* getGHorizontalLayer () const; - virtual const Layer* getGVerticalLayer () const; - virtual size_t getDepth () const; - virtual size_t getAllowedDepth () const; - virtual size_t getLayerDepth ( const Layer* ) const; - virtual CellGauge* getCellGauge () const; - virtual RoutingGauge* getRoutingGauge () const; - virtual RoutingLayerGauge* getLayerGauge ( size_t depth ) const; - virtual const Layer* getRoutingLayer ( size_t depth ) const; - virtual Layer* getContactLayer ( size_t depth ) const; - virtual DbU::Unit getSliceHeight () const; - virtual DbU::Unit getSliceStep () const; - virtual DbU::Unit getPitch ( size_t depth, Flags flags ) const; - virtual DbU::Unit getOffset ( size_t depth ) const; - virtual DbU::Unit getWireWidth ( size_t depth ) const; - virtual DbU::Unit getExtensionCap ( size_t depth ) const; - virtual Flags getDirection ( size_t depth ) const; - virtual DbU::Unit getPitch ( const Layer*, Flags flags ) const; - virtual DbU::Unit getOffset ( const Layer* ) const; - virtual DbU::Unit getWireWidth ( const Layer* ) const; - virtual DbU::Unit getExtensionCap ( const Layer* ) const; - virtual Flags getDirection ( const Layer* ) const; - virtual float getSaturateRatio () const; - virtual size_t getSaturateRp () const; - virtual DbU::Unit getGlobalThreshold () const; - virtual void setAllowedDepth ( size_t ); - virtual void setSaturateRatio ( float ); - virtual void setSaturateRp ( size_t ); - virtual void setGlobalThreshold ( DbU::Unit ); - virtual DbU::Unit getEdgeLength () const; - virtual DbU::Unit getEdgeWidth () const; - virtual float getEdgeCostH () const; - virtual float getEdgeCostK () const; - virtual float getEdgeHInc () const; - virtual size_t getHEdgeLocal () const; - virtual size_t getVEdgeLocal () const; - virtual void print ( Cell* ) const; - virtual Record* _getRecord () const; - virtual string _getString () const; - virtual string _getTypeName () const; + bool isGMetal ( const Layer* ) const; + bool isGContact ( const Layer* ) const; + const Layer* getGContactLayer () const; + const Layer* getGHorizontalLayer () const; + const Layer* getGVerticalLayer () const; + size_t getDepth () const; + size_t getAllowedDepth () const; + size_t getLayerDepth ( const Layer* ) const; + CellGauge* getCellGauge () const; + RoutingGauge* getRoutingGauge () const; + RoutingLayerGauge* getLayerGauge ( size_t depth ) const; + const Layer* getRoutingLayer ( size_t depth ) const; + Layer* getContactLayer ( size_t depth ) const; + DbU::Unit getSliceHeight () const; + DbU::Unit getSliceStep () const; + DbU::Unit getPitch ( size_t depth, Flags flags ) const; + DbU::Unit getOffset ( size_t depth ) const; + DbU::Unit getWireWidth ( size_t depth ) const; + DbU::Unit getExtensionCap ( size_t depth ) const; + Flags getDirection ( size_t depth ) const; + DbU::Unit getPitch ( const Layer*, Flags flags ) const; + DbU::Unit getOffset ( const Layer* ) const; + DbU::Unit getWireWidth ( const Layer* ) const; + DbU::Unit getExtensionCap ( const Layer* ) const; + Flags getDirection ( const Layer* ) const; + float getSaturateRatio () const; + size_t getSaturateRp () const; + DbU::Unit getGlobalThreshold () const; + void setAllowedDepth ( size_t ); + void setSaturateRatio ( float ); + void setSaturateRp ( size_t ); + void setGlobalThreshold ( DbU::Unit ); + DbU::Unit getEdgeLength () const; + DbU::Unit getEdgeWidth () const; + float getEdgeCostH () const; + float getEdgeCostK () const; + float getEdgeHInc () const; + virtual void print ( Cell* ) const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; protected: // Attributes. const Layer* _gmetalh; @@ -182,12 +118,9 @@ namespace Anabatic { float _edgeCostH; float _edgeCostK; float _edgeHInc; - size_t _hEdgeLocal; - size_t _vEdgeLocal; private: - ConfigurationConcrete ( const ConfigurationConcrete& ); - ConfigurationConcrete& operator= ( const ConfigurationConcrete& ); - void _setTopRoutingLayer ( Name name ); + Configuration& operator= ( const Configuration& ) = delete; + void _setTopRoutingLayer ( Name name ); }; @@ -195,7 +128,5 @@ namespace Anabatic { INSPECTOR_P_SUPPORT(Anabatic::Configuration); -INSPECTOR_P_SUPPORT(Anabatic::ConfigurationConcrete); - #endif // ANABATIC_CONFIGURATION_H diff --git a/anabatic/src/anabatic/Constants.h b/anabatic/src/anabatic/Constants.h index 35a670cc..139801d0 100644 --- a/anabatic/src/anabatic/Constants.h +++ b/anabatic/src/anabatic/Constants.h @@ -24,64 +24,65 @@ namespace Anabatic { class Flags : public Hurricane::BaseFlags { public: - static const unsigned int NoFlags = 0; + static const unsigned int NoFlags ; // = 0; // Flags used for both objects states & functions arguments. - static const unsigned int Horizontal = (1 << 0); - static const unsigned int Vertical = (1 << 1); - static const unsigned int Source = (1 << 2); - static const unsigned int Target = (1 << 3); - static const unsigned int Invalidated = (1 << 4); + static const unsigned int Horizontal ; // = (1 << 0); + static const unsigned int Vertical ; // = (1 << 1); + static const unsigned int Source ; // = (1 << 2); + static const unsigned int Target ; // = (1 << 3); + static const unsigned int Invalidated ; // = (1 << 4); // Flags for GCell objects states only. - static const unsigned int DeviceGCell = (1 << 5); - static const unsigned int ChannelGCell = (1 << 6); - static const unsigned int StrutGCell = (1 << 7); - static const unsigned int MatrixGCell = (1 << 8); - static const unsigned int IoPadGCell = (1 << 9); - static const unsigned int Saturated = (1 << 10); + static const unsigned int DeviceGCell ; // = (1 << 5); + static const unsigned int ChannelGCell ; // = (1 << 6); + static const unsigned int StrutGCell ; // = (1 << 7); + static const unsigned int MatrixGCell ; // = (1 << 8); + static const unsigned int IoPadGCell ; // = (1 << 9); + static const unsigned int Saturated ; // = (1 << 10); // Flags for Anabatic objects states only. - static const unsigned int DemoMode = (1 << 5); - static const unsigned int WarnOnGCellOverload = (1 << 6); - static const unsigned int DestroyGCell = (1 << 7); - static const unsigned int DestroyBaseContact = (1 << 8); - static const unsigned int DestroyBaseSegment = (1 << 9); + static const unsigned int DemoMode ; // = (1 << 5); + static const unsigned int WarnOnGCellOverload ; // = (1 << 6); + static const unsigned int DestroyGCell ; // = (1 << 7); + static const unsigned int DestroyBaseContact ; // = (1 << 8); + static const unsigned int DestroyBaseSegment ; // = (1 << 9); // Flags for NetDatas objects states only. - static const unsigned int GlobalRouted = (1 << 5); + static const unsigned int GlobalRouted ; // = (1 << 5); // Masks. - static const unsigned int WestSide = Horizontal|Target; - static const unsigned int EastSide = Horizontal|Source; - static const unsigned int SouthSide = Vertical |Target; - static const unsigned int NorthSide = Vertical |Source; - static const unsigned int AllSides = WestSide|EastSide|SouthSide|NorthSide ; - static const unsigned int EndsMask = Source|Target; - static const unsigned int DirectionMask = Horizontal|Vertical; - static const unsigned int DestroyMask = DestroyGCell|DestroyBaseContact|DestroyBaseSegment; - static const unsigned int GCellTypeMask = DeviceGCell|ChannelGCell|StrutGCell|MatrixGCell|IoPadGCell; + static const unsigned int WestSide ; // = Horizontal|Target; + static const unsigned int EastSide ; // = Horizontal|Source; + static const unsigned int SouthSide ; // = Vertical |Target; + static const unsigned int NorthSide ; // = Vertical |Source; + static const unsigned int AllSides ; // = WestSide|EastSide|SouthSide|NorthSide ; + static const unsigned int EndsMask ; // = Source|Target; + static const unsigned int DirectionMask ; // = Horizontal|Vertical; + static const unsigned int DestroyMask ; // = DestroyGCell|DestroyBaseContact|DestroyBaseSegment; + static const unsigned int GCellTypeMask ; // = DeviceGCell|ChannelGCell|StrutGCell|MatrixGCell|IoPadGCell; // Flags for functions arguments only. - static const unsigned int AboveLayer = (1 << 5); - static const unsigned int BelowLayer = (1 << 6); - static const unsigned int OpenSession = (1 << 7); - static const unsigned int Realignate = (1 << 8); - static const unsigned int NativeConstraints = (1 << 9); - static const unsigned int ForceMove = (1 << 10); - static const unsigned int WithPerpands = (1 << 11); - static const unsigned int WarnOnError = (1 << 12); - static const unsigned int Topology = (1 << 13); - static const unsigned int GlobalSegment = (1 << 14); - static const unsigned int AllowTerminal = (1 << 15); - static const unsigned int AllowLocal = (1 << 16); - static const unsigned int IgnoreContacts = (1 << 17); - static const unsigned int Propagate = (1 << 18); - static const unsigned int Superior = (1 << 19); - static const unsigned int DoglegOnLeft = (1 << 20); - static const unsigned int DoglegOnRight = (1 << 21); - static const unsigned int WithNeighbors = (1 << 22); - static const unsigned int NoCheckLayer = (1 << 23); - static const unsigned int HalfSlacken = (1 << 24); - static const unsigned int NoGCellShrink = (1 << 25); - static const unsigned int CParanoid = (1 << 26); - static const unsigned int Create = (1 << 27); - static const unsigned int CheckLowDensity = (1 << 28); - static const unsigned int NoUpdate = (1 << 29); + static const unsigned int Create ; // = (1 << 5); + static const unsigned int WithPerpands ; + static const unsigned int WithSelf ; + static const unsigned int AboveLayer ; + static const unsigned int BelowLayer ; + static const unsigned int OpenSession ; + static const unsigned int Realignate ; + static const unsigned int NativeConstraints ; + static const unsigned int ForceMove ; + static const unsigned int WarnOnError ; + static const unsigned int Topology ; + static const unsigned int GlobalSegment ; + static const unsigned int AllowTerminal ; + static const unsigned int AllowLocal ; + static const unsigned int IgnoreContacts ; + static const unsigned int Propagate ; + static const unsigned int Superior ; + static const unsigned int DoglegOnLeft ; + static const unsigned int DoglegOnRight ; + static const unsigned int WithNeighbors ; + static const unsigned int NoCheckLayer ; + static const unsigned int HalfSlacken ; + static const unsigned int NoGCellShrink ; + static const unsigned int CParanoid ; + static const unsigned int CheckLowDensity ; + static const unsigned int NoUpdate ; public: inline Flags ( unsigned int flags = NoFlags ); inline Flags ( BaseFlags ); @@ -111,6 +112,13 @@ namespace Anabatic { }; + inline Flags perpandicularTo ( Flags direction ) + { + if (direction & Flags::Horizontal) return Flags::Vertical; + if (direction & Flags::Vertical ) return Flags::Horizontal; + return Flags::NoFlags; + } + } // Anabatic namespace. diff --git a/anabatic/src/anabatic/Dijkstra.h b/anabatic/src/anabatic/Dijkstra.h index 027359d7..0ad5a79a 100644 --- a/anabatic/src/anabatic/Dijkstra.h +++ b/anabatic/src/anabatic/Dijkstra.h @@ -147,7 +147,7 @@ namespace Anabatic { } - inline Vertex::~Vertex () { } + inline Vertex::~Vertex () { _gcell->setObserver( GCell::Observable::Vertex, NULL ); } inline Contact* Vertex::hasGContact ( Net* net ) { return _gcell->hasGContact(net); } inline unsigned int Vertex::getId () const { return _id; } inline GCell* Vertex::getGCell () const { return _gcell; } diff --git a/anabatic/src/anabatic/GCell.h b/anabatic/src/anabatic/GCell.h index 48c5d0d6..e7d1a1e5 100644 --- a/anabatic/src/anabatic/GCell.h +++ b/anabatic/src/anabatic/GCell.h @@ -164,6 +164,7 @@ namespace Anabatic { GCell* getEast ( DbU::Unit y ) const; GCell* getSouth ( DbU::Unit x ) const; GCell* getNorth ( DbU::Unit x ) const; + GCell* getNeighborAt ( Flags side, DbU::Unit axis ) const; GCell* getUnder ( DbU::Unit x, DbU::Unit y ) const; inline GCell* getUnder ( Point p ) const; GCell* hcut ( DbU::Unit y ); @@ -215,6 +216,7 @@ namespace Anabatic { void updateContacts (); size_t updateDensity (); inline void updateKey ( size_t depth ); + void truncDensities (); bool stepBalance ( size_t depth, Set& invalidateds ); void rpDesaturate ( set& ); bool stepDesaturate ( size_t depth @@ -445,6 +447,8 @@ namespace Anabatic { // Utilities. string getVectorString ( float*, size_t ); + bool isLess ( const GCell* lhs, const GCell* rhs, Flags direction ); + bool isGreater ( const GCell* lhs, const GCell* rhs, Flags direction ); } // Anabatic namespace. diff --git a/anabatic/src/anabatic/Session.h b/anabatic/src/anabatic/Session.h index 33ec8549..208f53fc 100644 --- a/anabatic/src/anabatic/Session.h +++ b/anabatic/src/anabatic/Session.h @@ -69,83 +69,83 @@ namespace Anabatic { class Session { public: // Static Methods. - static inline bool doDestroyBaseContact (); - static inline bool doDestroyBaseSegment (); - static inline bool doDestroyTool (); - static bool isInDemoMode (); - static bool doWarnGCellOverload (); - static Session* get ( const char* message=NULL ); - static inline Technology* getTechnology (); - static inline AnabaticEngine* getAnabatic (); - static inline const Configuration* getConfiguration (); - static float getSaturateRatio (); - static size_t getSaturateRp (); - static inline size_t getAllowedDepth (); - static DbU::Unit getExtensionCap (); - static inline CellGauge* getCellGauge (); - static inline DbU::Unit getSliceHeight (); - static inline DbU::Unit getSliceStep (); - static inline RoutingGauge* getRoutingGauge (); - static inline RoutingLayerGauge* getLayerGauge ( size_t depth ); - static inline size_t getDepth (); - static inline size_t getViaDepth ( const Layer* layer ); - static inline size_t getLayerDepth ( const Layer* layer ); - static inline const Layer* getRoutingLayer ( size_t ); - static inline const Layer* getContactLayer ( size_t ); - static unsigned int getDirection ( size_t depth ); - static inline DbU::Unit getPitch ( size_t depth, unsigned int flags ); - static inline DbU::Unit getOffset ( size_t depth ); - static inline DbU::Unit getWireWidth ( size_t depth ); - static inline DbU::Unit getViaWidth ( size_t depth ); - static inline unsigned int getDirection ( const Layer* ); - static inline DbU::Unit getPitch ( const Layer*, unsigned int flags ); - static inline DbU::Unit getOffset ( const Layer* ); - static inline DbU::Unit getWireWidth ( const Layer* ); - static inline DbU::Unit getViaWidth ( const Layer* ); - static inline DbU::Unit getExtensionCap ( const Layer* ); - static inline size_t getSegmentStackSize (); - static inline size_t getContactStackSize (); - static inline const vector& getInvalidateds (); - static inline const vector& getRevalidateds (); - static inline const set& getDestroyeds (); - static inline const vector& getDoglegs (); - static inline const set& getNetsModificateds (); - static Session* open ( AnabaticEngine* ); - static void close (); - static void setAnabaticFlags ( unsigned int ); - static inline void dogleg ( AutoSegment* ); - static inline void doglegReset (); - static inline void revalidateTopology (); - static inline void setInvalidateMask ( unsigned int ); - static inline void invalidate ( Net* ); - static inline void invalidate ( AutoContact* ); - static inline void invalidate ( AutoSegment* ); - static inline size_t revalidate (); - static void link ( AutoContact* ); - static void link ( AutoSegment* ); - static void unlink ( AutoContact* ); - static void unlink ( AutoSegment* ); - static AutoContact* lookup ( Contact* ); - static AutoSegment* lookup ( Segment* ); - static inline void destroyRequest ( AutoSegment* ); + static inline bool doDestroyBaseContact (); + static inline bool doDestroyBaseSegment (); + static inline bool doDestroyTool (); + static bool isInDemoMode (); + static bool doWarnGCellOverload (); + static Session* get ( const char* message=NULL ); + static inline Technology* getTechnology (); + static inline AnabaticEngine* getAnabatic (); + static inline const Configuration* getConfiguration (); + static float getSaturateRatio (); + static size_t getSaturateRp (); + static inline size_t getAllowedDepth (); + static DbU::Unit getExtensionCap (); + static inline CellGauge* getCellGauge (); + static inline DbU::Unit getSliceHeight (); + static inline DbU::Unit getSliceStep (); + static inline RoutingGauge* getRoutingGauge (); + static inline RoutingLayerGauge* getLayerGauge ( size_t depth ); + static inline size_t getDepth (); + static inline size_t getViaDepth ( const Layer* layer ); + static inline size_t getLayerDepth ( const Layer* layer ); + static inline const Layer* getRoutingLayer ( size_t ); + static inline const Layer* getContactLayer ( size_t ); + static unsigned int getDirection ( size_t depth ); + static inline DbU::Unit getPitch ( size_t depth, unsigned int flags ); + static inline DbU::Unit getOffset ( size_t depth ); + static inline DbU::Unit getWireWidth ( size_t depth ); + static inline DbU::Unit getViaWidth ( size_t depth ); + static inline unsigned int getDirection ( const Layer* ); + static inline DbU::Unit getPitch ( const Layer*, unsigned int flags ); + static inline DbU::Unit getOffset ( const Layer* ); + static inline DbU::Unit getWireWidth ( const Layer* ); + static inline DbU::Unit getViaWidth ( const Layer* ); + static inline DbU::Unit getExtensionCap ( const Layer* ); + static inline size_t getSegmentStackSize (); + static inline size_t getContactStackSize (); + static inline const vector& getInvalidateds (); + static inline const vector& getRevalidateds (); + static inline const set& getDestroyeds (); + static inline const vector& getDoglegs (); + static inline const set& getNetsModificateds (); + static void close (); + static void setAnabaticFlags ( unsigned int ); + static inline void dogleg ( AutoSegment* ); + static inline void doglegReset (); + static inline void revalidateTopology (); + static inline void setInvalidateMask ( unsigned int ); + static inline void invalidate ( Net* ); + static inline void invalidate ( AutoContact* ); + static inline void invalidate ( AutoSegment* ); + static inline size_t revalidate (); + static void link ( AutoContact* ); + static void link ( AutoSegment* ); + static void unlink ( AutoContact* ); + static void unlink ( AutoSegment* ); + static AutoContact* lookup ( Contact* ); + static AutoSegment* lookup ( Segment* ); + static inline void destroyRequest ( AutoSegment* ); // Methods. - bool _doDestroyBaseContact (); - bool _doDestroyBaseSegment (); - bool _doDestroyTool (); - virtual Configuration* _getConfiguration (); - inline void _dogleg ( AutoSegment* ); - inline void _doglegReset (); - void _invalidate ( Net* ); - inline void _invalidate ( AutoContact* ); - inline void _invalidate ( AutoSegment* ); - inline void _destroyRequest ( AutoSegment* ); - void _canonize (); - void _revalidateTopology (); - size_t _revalidate (); - DbU::Unit _getPitch ( size_t depth, unsigned int flags ) const; - Record* _getRecord () const; - string _getString () const; - inline string _getTypeName () const; + static Session* _open ( AnabaticEngine* ); + bool _doDestroyBaseContact (); + bool _doDestroyBaseSegment (); + bool _doDestroyTool (); + virtual Configuration* _getConfiguration (); + inline void _dogleg ( AutoSegment* ); + inline void _doglegReset (); + void _invalidate ( Net* ); + inline void _invalidate ( AutoContact* ); + inline void _invalidate ( AutoSegment* ); + inline void _destroyRequest ( AutoSegment* ); + void _canonize (); + void _revalidateTopology (); + virtual size_t _revalidate (); + DbU::Unit _getPitch ( size_t depth, unsigned int flags ) const; + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; protected: static Session* _session; diff --git a/bootstrap/build.conf b/bootstrap/build.conf index 8c4d6428..fbd80aea 100644 --- a/bootstrap/build.conf +++ b/bootstrap/build.conf @@ -20,6 +20,7 @@ projects = [ #, "metis" #, "mauka" , "anabatic" + , "katana" , "knik" , "katabatic" , "kite" diff --git a/bootstrap/refactor.py b/bootstrap/refactor.py new file mode 100755 index 00000000..a9e813de --- /dev/null +++ b/bootstrap/refactor.py @@ -0,0 +1,98 @@ +#!/usr/bin/env python + +import sys +import os +import os.path +import optparse +import re + + +cppPattern = re.compile( r".*\.(h|cpp)$" ) +refactorPattern = re.compile( r"^\s*(?P[^\s]*)\s*-->\s*(?P[^\s]*)\s*$" ) + + +class Refactor: + + def __init__ ( self ): + self._substitutions = [] + return + + def _addRefactor ( self, original, replacement ): + self._substitutions.append( ( re.compile(original), replacement ) ) + return + + def doLineRefactor ( self, line ): + pline = line + for (original,replacement) in self._substitutions: + pline = original.sub( replacement, pline ) + return pline + + def doFileRefactor ( self, file ): + oldFile = file + '.noRefactor' + if not os.path.isfile(oldFile): + os.rename( file, oldFile ) + + fdold = open( oldFile, 'r' ) + fdnew = open( file , 'w' ) + + while True: + oldline = fdold.readline() + if oldline == '': break + + newline = self.doLineRefactor( oldline ) + fdnew.write( newline ) + + fdnew.close() + fdold.close() + return + + def loadPatterns ( self, file ): + fd = open( file, "r" ) + if fd: + while True: + line = fd.readline() + if line == "" : break + if line[0] == '#' : continue + if line[0] == '\n': continue + + m = refactorPattern.match( line ) + if m: + print "o:\"%s\" r:\"%s\"" % ( m.group("orig"), m.group("replace") ) + self._addRefactor( m.group("orig"), m.group("replace") ) + fd.close () + return + + +if __name__ == '__main__' : + + parser = optparse.OptionParser () + parser.add_option( '-t', '--tree' , action='store' , type='string', dest='tree' ) + parser.add_option( '-p', '--patterns', action='store' , type='string', dest='patterns' ) + parser.add_option( '-f', '--file' , action='append', type='string', dest='files' ) + + (options, args) = parser.parse_args() + + if not options.patterns and not options.files: sys.exit( 1 ) + + refactor = Refactor() + refactor.loadPatterns( options.patterns ) + + rfiles = [] + if options.patterns: + if options.tree: + for (root,dirs,tfiles) in os.walk(options.tree): + if 'CVS' in dirs: dirs.remove( 'CVS' ) + if '.svn' in dirs: dirs.remove( '.svn' ) + for file in tfiles: + if cppPattern.match( file ): + rfiles.append( os.path.join(root,file) ) + + allFiles = [] + if options.files: allFiles += options.files + allFiles += rfiles + + for file in allFiles: + print file + refactor.doFileRefactor( file ) + + sys.exit( 0 ) diff --git a/documentation/UsersGuide/UsersGuide.pdf b/documentation/UsersGuide/UsersGuide.pdf index 5f0c3589..f28e4915 100644 --- a/documentation/UsersGuide/UsersGuide.pdf +++ b/documentation/UsersGuide/UsersGuide.pdf @@ -2230,42 +2230,41 @@ endobj 482 0 obj <> stream -xÚ­XwXUW¶?È= E¼È•«€Š4%ˆhh!T@:JS"½±‹-&ov&cì!Š€lXPñb„hTŒ“ÄcTˆq{×…÷ö¹É¼÷fæýñ¾ù†oŸó]ÎÙ{íµÖÞë÷ûí£ÇÈdŒžžžqL``àüŽÁyÉ9á 9…Ò³€1ƒÙ'v–„ü÷¡ü€FÛ¦4¨T -‰¬hÁˆJ=qô q´¾(—f½E&ôÎÜ0’îgŒ¥»9½²Îèëé±Óý&;MvöIOM/J_™¼ÄjIBQ‚URnÞŠ‚ôÔ´"+»${+çÉΓèmòD«¹¹¹©YÉV³r òr ŠÒssœ$ï¬tî1zC8FàG ÃXóÆ23qLSMgäf03„Ê c #Ƙ±`”ÌhÆ’ËŒcÆ36ÌÆ–±cìGf"3‰qbÞcœ™ÉŒ 3…qe¦2Ó˜÷7Æñ`<™éÌLfãÃÌfæ0s_Æñgæ1L Ä3!L(Æ„3ó™LÉD1ÑL ³YÌÔ0ß0k˜9ƒ=fœž¥Þ2½ëƒr6(~ÐîAGôëGë/×ߥK–*û‰ g ØO93î}®«àNpý¼7ÿH˜"<6øÀàçÁúƒ£ÿyðÀ)C¢†¬B†Ú mf;ì”á†ëö½5~ßx¿ñÆ}&«M®ÞkºÙôòˆìçå¦ò¹òóò·fÁfyf·Íyscs/¥ì*,P²Mr¥Æ_ýþàû—*5ÇäJÙSõ0%Žâ •ìÑE)Û&'ö6­m¨=÷e¹DάªÏ<’±'D‘ù+cÒ2âƒc§F‡v$¶ž,WÈUp'¸~Þ›$L|`ðó`ýÁQƒÿ“Õ&W‡Gï5ÝlzyDöˆórSùùyù[³`³<³Ûæ¼¹±¹—Rv(Ù&¹R ~HðýK•šcr¥ì©z˜Gñ†JöŽè¢”m““ {›ŽÖ6Ôžû²ƒ\"gVÕgÉØ“@¢Èü•1é ñÁ±S£C;[ +Ož(9EÎðÞÀ!ùTâ[y&êtþr4m=Vz¤ôHEmMuÍᶣߞýµ^æÖãQ…S‰ ]ŸÉ šsxàsÏdi0Ž¼&OK{jzj´Ü¿ óÐ×Vpاž¾ºãOC¸½¸Õþ˃ŠÂ—ÎÏŽIIÔ:Šæo¯ÜþêôW§/W^%7É«¬{óÚç]œV… A✞ñ±%ÉŸ§ìJÛ•öeú¾ ¡<ãèÂK8tŽ›ß"¿X¿¢‰«`(ö=UÔ£™ñýVt¤í6*~AVWÎ †û€e L¢­œ ¸x?¸4ƒÓ9pêëŸA.à4Î…éh…N‘è”îgKvÅrÉ0ÌÊ÷(x/ œ¦ƒ…=H~Fy7ZŸC§ftÚ.ß'èZ€“cpb NòA+'4‘x ²Û`Þ -Žmàxܨ1ÁP3 ¶Qr#äÁ5i-µ Ÿƒþâ°,ÜŒ÷Ág¸ÂøàLÿ ?…û¢IM>økÇ¢>kHWXm­®•‹ÓÑR;]ë„cD'­7XŠÞ¢3Œá Å?Al£?·!hµûR›b›eSWÌÀ„«¿säaÝu?¸»çš`¨¶ýNÌ–‹%0Q[Š'aâor²pgzåÒŠeU뎣äð®ŠÊŠÊGH9½®néþâŠì]KH2É))^º¬p}‰£V6©s¥]‰œö$Ýš,xüËÆ4¼ŒŽI«\V±´jýßž$žv÷Z7yŒdüÿæ¨Kå$~GzyѾ¢ê’cÿ‡¹$ÉM§¦6ËÁ‘﯄u¥È³`Ï,вö¼ôúWq´yÍуý…¾ Y´çÕûµt1XcÍ[3ðá´ÝJö‹ã8ím¥Æ‡…éøŠÉ¬øˆ‹€Irm6ÓÅèCwËo”v)*Ý*}*Â:ø=ˆý£¤Å­Ë:È*ÈcJ8²aÈæ¢9AG‚u` 8’:<<ý!“€=u´ìÍQfG¦ °Â† Ám.o'ÿv Ûg¿ý ?Y¨ß*Ù(õZsÅ´†ÃpÝ5»—Qà™/åÊžƒ?ésf`z |$ ïG"£ÐÎÆÖÆ'FãbU’R¶¡Æ.|áð³C3Ž#Ng’j>5ƒ‰ý -±^ìmŸ˜©V€c;ƒ7Ôœy35Kß8Ò7µÿë’íV?Vo•ãDx àŠìJ& &hÝêØëлDSÿZÀöõo¯Ëó0‡€!Ó\0¿ -æhq mªÑ™ ÁQÙÈ!ìêHïÈe¡‚àD‚ë¯Ð”Ñt¡9Ìðƒ|ò–<ÿüÁî»ïï½{@P/”®Ä©´L9O%۪Χ›ª$p0(t—Û5L!˜EÐÓ Ðœ^f!HpÁMôdž6O?iC§p»ƒa Q@`­ ÄB3Z©'Áþqßw½`Ô -ÓÝÇ`õÐæÑ„hO0šàÂDtp³q³AÃ(œF(ƒ¢aëû½Óú¤­#¥ú†F«)—C#΃±Z½1Z£ß3Ü-I›ã¯ï÷>hœÐÿø\| -a<Œ"¯ -;u.ªEˆUú¾1¾1¨WH+Rø÷}ñÏæp±´‚ð å¤Ñ§Þ}wŒô:*qið¿-}"/¾•ƒŠƒwÚ·,ÄrZkµ D}ó‹… ÆÄ÷M»>õ:*Žà\Š6º qêÍ2±òyNž·Ç«â«æÐTL̾(|á”B û 5¢f§¨“×9=a¡Ö*œtѹnîáÅ㪲ª—×-¯Ýp‚´’ëηk=v£ì ‘mPâ„ó`‡†çqÔ!´! -´$(˘æ;Í7Ò=K¬ª]U¾¾/Ã@ó2íVVsÞÙ¼#Ùå™û2v$ÒŠòÎ KÂO-¦}çÙ[}J}Jý÷У– 1mxÞý¼ûìkB•ME¶ZªiK1 zÐQLRjþªƒ%«Ð‘­÷@GÐ(c’¯¿¯ßÄ 4"('öu¾_û~ñM½  ¢}fò½šÑügÇ—Ž \>Djcšß¼xó¢Eʪ§4Y»¦\góûéK¬²)DFQÔ—ýv èáš9æèˉå:f÷âÄý´+-'>MɪÌD é?úW(ÒPYˆüÚ‰Š¥`–™}X¥‘Kƒ±t`Xäáh¨XÝW\&˜â*…δâÓpL“Pû¶òçÒŸ®Ýž´Çoߗ󿈇æTsêe™R¶ÓL»Z½SŒVû²èÇiiïàŠwX áÄèþ íÊþ-,PƒãÕ#ÅÑý#%¡´J¼¡Î•kGªsY âÄU¬¶q/®Ö˜²@¡Eö¹¦ÛŒ‚Ö1^½G)ÛÅ‚b '©7ñý{”˜Æ¢‚2ƒÆ‰VŒpÁ‘’$(T?5#õ:ºIFd=Ÿ§ -T9TãHâOæmô_9oeHÑ‚œV45¾ýת§¤‡tMjH( S…¹<}„ïÖálæ+Èøϯ¯„?Î=Úó›]÷_8páÌÅë¼ðŹ?‰ú2¥&µfÅr™Ü­nïhP5¾Øæ[Àc«¹Olr¼‚ÃBÃÜsÇëû™z¦æ•\b~¾7êQtÜrí³;ä± ¢‡Rý†ðõ`ÍîâŽÏoIRå_ÎûzíMBÅ;è·`M$þ´,°Šž=ãéÜꢮF]ˇAœh;z-W[ºÖ+U_’¨Y& Šçe·¨°å—LZæL¬ˆgÃüîÝy},h} …cêȱÍMë›6/i\Ý -ÖæÙ¥‰_DìŒØùy„N`žbëb»ÇœGpnŽùÁþ¯`Cå“.'°•W - T`£‡6Œû‹÷V/v-ç r$@¢èG{ÚzÚ&¡A?ÚŽ£å}ûö ‹‘²1‰@û]ÐðN®ÜŽ|Øu3êfþoDJϘƒïZï´Ý¾}ô%¡á=Êhókõ=ˆúßÒhÁ.° ŠtËBVçϵé2ù·¤óó¶çw]ÜÛq@;ù4( ¢ eĵ.ðZеŒ—ŸÐÚWüVBø$âùÄó)êÆÑm -‘®ã¦Œ‹—œMpÖYý“Ýs;C±VˆÓ¬O®æž6¼Ò“Œ´7¸íojœ¿ÔvéFõÔ µ¿ÚE³Pr¬½É“g¥×Ÿ<|âLy'9M.®ï*n…ù•sw…RµT‚ƒÑ+,ƒxŒ -f§CÔÀBðÐP©¡y§QizäZ#.vwäÖ0BuŸMæ,¿YóR©„JfíWÞ~&éRQlnzNqvqöº4’DÒvdíÍöåU.¯Zë½28#>&>¦8Œø‡cÞ‹¸úyRƒ©8«}Ùõ²óÜsÃÈ‹Ì[-¼ç8„:Á“„­¥_”TÃäRýÙ›Õ›RG뼩½Õu««ñ¯ä9»©iõÑÕ«j–W -°x?Û? Ät9¹VÞv²ádCÇÞÛD€…Ür}]caãÒ½ $„ød„ÍMôKWL¡Ý‰Ì*®‰®)8M:„'š©rò¨üÊIúw¹üéöÐÝq²‡N³ô&AûâÅ[ª"wuJIãbêÅtõ,ÓßøuÎí²­ÅQÄ›ÌYœ”›˜!¬ç¶4~v–\ÄÌßkу -(Z|{/t¶u>®žjûÎ¥'ŸX¼Ï—¸ÐÃg)¼0Óô Ç@¿FÉR"OÙž[¶¢lyå†*rˆTn/++Û»£Š4’ÆõUË÷.ß[´=ä’¢ ËW,_¹!—$K&š´ëä°ð5ØY–JÙ:3ÊxZ_˜S›¼&’Ä‘¸­±TøYðÇV¶m¤Â†(ùØa.ÍexNÏÊrî~ÖNõUt“Âtx0F©-Õñz®Ú@ SYŒæðvHˆ_|DN¢â÷pu%KGQ˜åó•œÍß²j•ÕØÔåT‹ÆÄ‹ø¬ ÌÌX›F.ŒQv?$>$`uhvxv\BV}ž,Z ôÐÚAõ?þ~y­2z};}»ìjiL§Ë””½0!}Á?O8îPïù+ç¯|÷Ï «”}«y'ž¡ÂlfŒqîÜKÕt¼šBÐ8ÚÅÖÅ.NRs)Š—O81õÄÔ¿;±wb¿/¢ò[ž¼ž¼9 –æ -ýw¨ü²®zwñæÅ›(‹P~”zifû¬* -ÕÔŒu®uøŒ°Yî)¨Ghso ¿~+÷ åÆ àüO 0w Xy¾úà²-TøÌ$þkÃòÂòbâãƒi Eº@•ê¯i¤‘¹ôñW»„¿ç¡bþKr'åü¬ 3Q¼¥@f‘7vw„÷Œä‰ÿÈB#ÿ)X|Õr¥åJO È~Grñ{"·¥è}+²»à-…ÞD߇ém¾m¿£ï$!…ÿ­ól£B¢B<³é#¡€Ò–ÄG¼Êws›}N|m:x(9WJå…èÀnà<€Eþ:ü&xNÐÑMÿ‰ìîÛ~4XK@zWí¦y#ŸC–‡- [3?ч¦c9,fq´nÝsä]í“+Ý]Ý·~$õäøæÓë+ÁÉ|ɶø¿ÄH\˜¬á¡MNn]ŽmŽkžÒŒfg'ÖÏ;”Q–QVX¶ª|MùƤš4í;rüÀñ»î“Éë"'t€²ÍÈ溺¡@Sb—?3rfTªq!Ñ;â+R÷¥ÖfžÊ=™s+£7ù]bwêѬ†ì²TOŠå -‹òüÖ¸’pº-¨4¸4¼<â€N|O,ÐÅ´!0š¼«ºsñÎÅ£÷I/ 3U<òù$~oV}VýªVrU çß›”@nÂVG~6®ÅÉsXO˜ÜoÅcáo(ƒ´1U¤ö³#[>?¸uïvLùU›—~œ÷qÞæœÿÈùý0 ) W•®–u6×®¼Î¹K®ñUõåê³'Ž\¶sû%ê-Ážöí96Ï&2`AåSž¸’€ŠÄS‰§–]#?Ò\î]Í ‚]5=,ÎáP©5˜‚›“Q? eE37¥Ñ¥Ùp:óULÄuê1æ´ =¹kÚÍ šƒviÐtMµ«gcEIôºèM)ŸÒ!kïåÿœ”þÔ:ùÛoP’¶fáª`ÅÊ ’˜MÉ´Ëæ–â—É0>Æ/€¨p&m=,Ìç I-ß×Yù„&P±«GËÊÉ»—PgUbG­VÅBb\Ö†H¿µ6¢J4kY æð„Ö OŠn,†r†š=¦ƒ¾Bçá19¢ˆ#‰IÙ&Pazn]ËG­ä)¹s°³íJë…΂‘˜©”=–"ÅIZ/gü<×-Ï}Eè†t)®Î̾‡›Ô¬¹¡&L£grm//~¯¾Ï‚¼ÊE¯}Ñÿ‚EV÷Ý žªc嵤æãÃo<¾º¥¸¹øôª“%'ןþ¨™¼ =ßÜÀOM^’__¼d]*É"™[2¶eìHÞ½¸,ä@ÌÞäí)Û¶ÄGâ‘ê;S@G¾¡áXuSåÉŠc;ëuGÔj‰æ”ü<é\Ù®‚Áæ^ÇÝ÷Ñó¡)™8Ó}Å,}†¯GÙu랯“@NÎ’ã[Žl¯Û^·«v·Æ¼[¶Ïê0º9üÅ_H¸PüˆPé«|pJuFÕUýˆýG°GN 厫Èw!ÿÔ æ‚Ál0M—0…¨i=\§íÉ󯧭ŒuŸà,ÒÁÄ h{ï)\è…&uÒ ‚&éhàK›ó{¾ºhBP!¼¥xlP ŒêuÇ/÷ï¿R½RS }H@/ç—ס÷¼Tv*»jé37=ä jbïåe*Ø…"“#=åéáÒöÒ•×ýÐ7¡¯s€¡8¦Ó“÷ȈNDâhzh–€>ßTßrNÕ©ê'*9$5$-:3Q0\¶Os¿^ýÄi×~Ì`=vò¾¡bõˆÿ¤íïÇ +Žmàxܨ1ÁP3 ¶Qr#äÁ5i-µ Ÿƒâ°,ÜŒ÷Ág¸ÂøàLÿ ?…û¢IM>hÇ¢>kHWXm­®•‹ÓÑR;]ë„cD'­7XŠÞ¢3Œá Å?Alc·!hµûR›b›eSWø +`ÂÕß9ò°î‡ºÜÝsM0TÛ~'fËب-á Å“0ñ79Y¸3½riŲªuGÈQrxWEeEåÎ#¤‰œ^W·tqEö®%$™ä”/]V¸>ƒÄQ+›Ô¹Ò®DN{’nM<þec^FǤU.«XZµþïÇOO»{-‰›aüÄþQÒâV¦0jüñÖ·NõI õÁ Ž +;øç{n44_:×¾ÿ&ùž€Iü3W•« +­ª1‚øq?' á3Fç+:R:R«Cˆ;qÉŸ‘‘2u9¥êp¼Nq`Bž_Ž¿ØŸ8‡ìYÁq!±.E8˜vQqÔ¥¡êo”ì9è”ú‘Ý0ÁùvU…“Ž§EŸedä1%Ù0dsÑœ #Á:p8’:<< “€=u´ìÍQfG¦ °Â† Ám.o'ÿv Ûg¿ý ?Y¨ß*Ù(õZsÅ´†ÃpÝ5»—Qà™/åÊžƒ?ésf`zæøH@¿(DF¡­NŒÆÅ4ª$¥l B Œ]øÂág‡fG0œÎ$+Ô|jûb½ØÚ>1S­Çþv:o¨9)òfj–¾q¤ojÿ×%Û­~¬Þ*ljð@Á;Ù•L Lкձסw!8ˆ¦þµ€íëß^ÿ–çÁ—€!Ó\0¿ +æhq mªÑ™ ÁQÙÈ!ìê:Þ‘ËBÁ‰×_¡)5¢é4Bs˜áùä-yþùƒÝvßß{÷€ ^(yòLÉZšÑ=„Þýƒúwª¡7u¼Õ>êý> N•hårJžÕwÝèº^û uBP²Õºn<™¾24-)=)z™?e‡è­‹v hÃ7¬8·¡SZ ÙO´™iß©¿«XŒåúûÓYuú“ˆ7x˜Jñp4k¨i†X"W·ƒS¿BÉ*Ñ›n&Þ]ý£ŒæÄO”¬!»Û€¦›)°## ÌoÉë­¼6U‰ìFNKש‰Åí’åÉšiëÍ`¸¡OØF qÔçuaNéÀÿ)áÓÙ[¶Øúé +a#×T)ë`q¾n¤º›ŽºÌ×Áx:T}\‰Si™ržJ¶UO7UIâ`Pè.·k˜B0‹ g 9½ÌBpÁ 7u`ÐÚ<ý¥ JÀí †Q0Fu@ µ‚ Íh¥žûÇ}ßõ‚Q+L#tƒaÔC›GN =Áh‚ ÑÁÍÆÍ £p¡ Š†­ï÷NëK¶JŒ”ê­¦\8ÆjõÆh~Ïp·$!lŽ¿¾ßû hpvBÿà7rñ)„ñ0Š¼*ì\Ô¹¨vq VéøÅøÅ ^!­HáßôÅ?›ÃQ|ÄÒ +Â7”“FŸz÷Ým0VÐë¨Ä¥Áÿ¶ ô‰¼øV*Þiß²Ëi­Õ6õÍ/.Pß7íúÔë¨8‚s(Øè2Ä©7ËÄvÈça8yVܯŠ¯ò¥©˜˜;+|QøÂ)…öjDÍNQ!'¯szÂ:C;­U8é¢sݜËÆUeU/¯[^»ái%לo=ÖzìFÙ"%Ú †E çÁ Ïã¨ChChIP–1Íoš_¥{–XU»ªü:ü^†2æeÚ­¬æ¼³yG²Ë3÷eìH¤å– „-žZLûú’Ù[}J}JöУ– 1mxÞý¼ûìkB•ME¶ZªiK1 zÐQLRjþªƒ%«Ð‘­÷@ GÐ(c’_€ŸÿÄ 4"('öu~_û}ñM½  ¢}fò½šÑügÇ—Ž \>Djcšß¼xó¢Eʪ§4Y»¦\góûéK¬²)DFQÔ—ýv èá_sôãÄr³{qâ~Ú•–Ÿ¦dUf¢…ô}+i¨,D~íDÅR0˃Ì>¬ÒÈ¥ÁX:0, òpÈ +4T¬î+.Lq•ÆBgZñ‡i8¦I¨}[ùséŠO×nOÚã¿ÇÿËù_ÄCó@ª9õ²L)Ûi¦]­Þ)F«ýXôç´ƒ´wð?Å;,†pbtveÿ¨Áñê‘âèþ‘’PZ%ÞPçʵ#Õ¹,q⪠VÛN‰¸‹WkLY ¤Ð"û\ÓmFAë¯Þ£”íbA1Ž“Ô›øþ=JLcQA™ÀAãD+F¸àHIªŸš‘zÝ$#²žÏUÍS9TãH@æn X9weHÑ‚œV45¾ýת§¤‡tMjH( $S…9<}„ïÖálæ+Èøϯ¯„?Î=Úó›]÷_8páÌÅë¼ðÅy‰ú2¥&µfÅr™Ü­nïhP5¾Øæ[Àc«¹Olr¼‚ÃBÃÜsÇëû™z¦æ•\b~¾7êQtÜrí³;ä± ¢‡Rý†ðõ`ÍîâŽÏoIRå_ÎûzíMBÅ;è·`M$þ´,°Šž=ãéÜꢮF]ˇAœh;z-W[ºÖ+U_’¨Y& Šçe·¨°å—LZæL¬ˆgÃüîÝy},h} …cêȱÍMë›6/i\Ý +ÖæÙ¥‰_DìŒØùy„N`žbëb»ÇœKpNŽùÁþ¯`Cå“.'°•W - T`£‡6Œû‹÷V/v-ç r$@¢èG{ÚzÚ&¡AÚŽ£å}ûö ‹‘²1‰@û]ÐðN®ÜŽ|Øu3êfþoDJϘƒïZï´Ý¾}ô%¡á=Êhóoõ;ˆúßÒhÁ.° Šžç–…¬ÎŸ5jÓeòoIççm;Îﺸ·ã€v<ò1hP@EʈkݼkA×2^~Bk_ýñ[ á“`ˆçϧ¨wG´%(DºŽ›2.^rv6ÁYgqôOvÏí`D ÅZ!N³Bþ=¹š{vþÙðJO2VÐÞ඿©ypþRÛ¥Õ?P/ÔjÍB9ȱö&Ož•^;|òð‰3åä4¹¸¾«¸ æTÎÙJÕR F ¬° â1*˜Q ÁCC¥†æF¥é‘k¸ØÝ‘[ÃÕ}6™³ügÍM¥f(™µwn}xCø™¤KE±¹é9ÅÙÅÙëÒHIÛ‘µ7OØ—W¹¼j­÷ÊàŒø˜ø˜â0âGŽ}x/ânèçI ¦â¬öe×ËÎsÏ #/2o¶s[œàêTL¶”|QRA“Kõgo6Vo>üI­?ò¦öV×­®Æ¿’wä즦ÕGW7®ªY^)Àâýlÿ€ÓåäZyÛɆ“ {oroÈõu…K÷&â“6'Ñ?a\1…v'2«4º&º¦à4éžh¦ÊÉ£ò+'éßåò{t¤ÛCwtÇÉ^8ÍÒ›í‹?l©ŠÜÕ)%‹x¨ÓÕ³Lãß9§Ë¶Goâ»:8+(;61#BXÏmiüì,¹$ˆ™¿×¢P´øö^èlë|\<ÕöKO,>±xŸq¡‡ÏRxa¦éA~’¥Dž²=·lEÙòÊ Uä©Ü^VV¶wGi$ë«–ï]¾·h{É%E–¯X¾rC.I–L4i×Éaák*°³,•²7tf”ñ$´$¾0§ 7yM$‰#q[c©ð³à­lÛH… Qò±ÿÂ\šË𜞕)äÜý¬4 +ê«è&…é&:ñ`Œ8R[ªãõ\µ"¦²Íá;íÿøˆœDÅïáêJ–Ž¢0Ëç+9›¿eÕ*«w^gP—S-/â³r^ƼŒE±aá"ÀeWðCâCW‡f‡gÇ%dEÐçyàÀ¢Å@ͳ$ +ÇîïmîéXÚ߸¸ÌŸ¸ +ý±´ƒHÂèÀ³sç:îî£TÿÓáï—×*£×¯Ó¯Ë®–Àtº¼A9AÙ Òüó„ãõž¿rþÊwÿ¼°JÙ·šwâ*ÌfÆÁçÞɽT IÇ«)£]l]ìâ$¥1‡¢xù„SOLíð¿{'öû"*ßé!ѸåÉkáÉ›Ó`I`ŽÐ‡Ê/ëªwo^¼ù°²EáG©—f¶Ïª¢PMÍXçZ‡Ï›åž‚z„6÷Æð[á·rßÑPþ` +ÎÿÄs–€•ç«^!ÛB…ÏL°6,/,/&>>˜Z¤ T©þšFÉ‘Kµ±Kø{N +)æ¿$wRÎϺ0ãÅ[ +dycxGxÏHžøœ!4òŸ‚ÅÁW-WZ®ôÔ€ìw$¿‡!r[Š¾Ñ·"» ÞRèýGô}˜Þæ×ö;úNRøOÐ:Ï6*$*Ä3›> +(mI|Äë |7·iÑÇáÄOЦƒ‡’s¥T^ˆìÎXä/¡Ãßha‚ç-ÐôûJ´`wßô£ÁZÒ»j7͹/ \¶$lIÌüDšŽå°˜ÅѺuÌ‘wµO®twußnø‘Ô“ã›O¯¯'ó%Ûâÿ#qa²†‡69¹Ut9¶9®yJ3šX?÷PFYFYaÙªò5åjÒ´ïÈñÇtìºO~$¯‹`PœÐÈ6#¿Ÿ²†M‰]þÌÈ™Q©>Ä…DHÝ—Z›y*÷dέŒÞäw‰Ý©G³²ËRI< +JX”+,Êó_ãJÂI趠ÒàÒðòˆC:ñ=±@Ó†Àhò®êÎÅ;Þ'½4ÌTñÈç“ø½YõYõ«ZÉUžoR¹ [ùÙ¸'û²ž0¹ßŠÇÂßPicªHígG¶4|~pëÞí˜ò«6/ý8ïã¼Í9ÿ‘óûaSþ@¯þ*]-ël®^ | +r—\ÿâ«êËÕgO¹ lçöKÔ=Z‚=í-ÚslžMdà‚@ʧÆ/€¨p&m=,Ìç I-ß×Yù„&P±«GËÊÉ»—PgUb G­VÅBb\Ö†H¿µ6¢J4kY æð„Ö OŠn,†r†š=¦ƒ¾Bçá19¢ˆ#‰IÙ&Pazn]ËG­ä)¹s°³íJë…΂‘˜©”=–"ÅIZ/gü<×-Ï}Eè†t)®Î̾‡›Ô¬¹¡&L£grm//~¯¾Ï‚¼ÊE¯}Ñÿ‚EV÷Ý žªc嵤æãÃo<¾º¥¸¹øôª“%'ןþ¨™¼ =ßÜÀOM^’__¼d]*É"™[2¶eìHÞ½¸,ä@ÌÞäí)Û¶ÄGâ‘ê7S@G¾¡áXuSåÉŠc;ëuGÔj‰æ”ü<é\Ù®‚Áæ^ÇÝ÷Ñó¡)™8Ó}Å,}†¯GÙu랯“@NÎ’ã[Žl¯Û^·«v·Æ¼[¶Ïê0º9Å_H¸PüˆPé«|pJuFÕUýˆýG°GN 厫Èw!ÿÔ æ€Ál0M—0…¨i=\§íÉ󯧭ŒuŸà,ÒÁÄ h{ï)\è…&uÒ ‚&éhàG›ó{~ºhBP!¼¥xlP ŒêuÇ/÷ï¿R½RS }H@/ç—ס÷¼Tv*»jé37=ä jbïåe*Ø…"“#=åéáÒöÒ•×ýÐ7¡¯s€¡8¦Ó“÷ȈNDâhzh–€>ßTßrNÕ©ê'*9$5$-:3Q0\¶Os¿^ýÄi×~Ì`=vò¾¡bõˆÿáï¬ endstream endobj 484 0 obj <> stream -xÚcd`aa`ddˆôpŠˆôÑö/HÍ NÌ+‰ùÈq1°thÈwwÃ<ìÿ~ýÙ/ùH†#‰õ‡ÃyÆ +xÚcd`aa`ddp ð Ñö/HÍ NÌ+‰ùÈq1°thÈwwÃ<ìÿ~ýÙ/ùH†#‰õ‡ÃyÆ L?˜ˆ²È200<‘·ùAäE)$˜¥„Ø9øŤBãJó2Ýœ !”„26Ô34pÉLÏ,ɬJMQHI,ITHÎ/¨,ÊLÏ(QÐHÖT0204І: îùùé9© -ÎùEùE‰%™ùyz W+€ÍÀôƒ!cÐn†ÆvÆÆN6&FeO†&FNÆ&–³ßCeX·‰ÊüòúyÈ`ÿ[*ók“¨ ˳Ÿ¼2¿¥Øù¾ø~¤à·[Ùo•ÌßÖ1¿ƒ8¾ó±­»¾öîš'k/¹1çßÏiß-~6ˆvÛÎóÛ˜°1þPé¥îKÝnܺiû¼Ý·ºïVœLÙ’²%tk·swHYjbZb…_·Ÿ ËžŸF¿¢E¿‹þ^}‰½ûù¬s+·®Ü²sÁ©î݇O—mû.)a»È}z`7Çïúß\¿¥/”÷cÿáÏêð=â_ôw«_Ñì?%ÿE‹þºóÛêßöZÖBÑî´)ùó*çU,jZÞ½¬{Ñ”yóæͺ¼{C÷†Æås+æ–L)èÎï.iª¨¬¨jÊïN¥¢3dØD~[Éü|ÃÎ'Ã^*ÃêG¡™tÅ(Ñ.ÃjCqДÏÿuká÷w/Ùþ4t³Ëq1²Îçáü±BË`q +ÎùEùE‰%™ùyz W+€ÍÀôƒ!cÐn†ÆvÆÆN6&FeO†&FNÆ&–³ßCeX·‰ÊüòúyÈ`ÿ[*ók“¨ ˳Ÿ¼2¿¥Øù¾ø~¤à·[Ùo•ÌßÖ1¿ƒ8¾ó±­»¾öîš'k/¹1çßÏiß-~6ˆvÛÎóÛ˜°1þPé¥îKÝnܺiû¼Ý·ºïVœLÙ’²%tk·swHYjbZb…_·Ÿ ËžŸF¿¢E¿‹þ^}‰½ûù¬s+·®Ü²sÁ©î݇O—mû.)a»È}z`7Çïúß\¿¥/”÷cÿáÏêð=â_ôw«_Ñì?%ÿE‹þºóÛêßöZÖBÑî´)ùó*çU,jZÞ½¬{Ñ”yóæͺ¼{C÷†Æås+æ–L)èÎï.iª¨¬¨jÊïN¥¢3dØD~[Éü|ÃÎ'Ã^*ÃêG¡™tÅ(Ñ.ÃjCqДÏÿuká÷w/Ùþ4t³Ëq1²Îçáü±B«k`g endstream endobj 334 0 obj -<> +<> stream xÚÅ[[oÛF~ß_1O­…Eä¹_ŠEÔiÓ¢IÄÞÅîºy`d:&ªˆ†D§ÉþúýÎÌPñâ*Á›@æˆÃóû9C ©”bœ)e˜U8&¤dJ+&¼ÁÑ1©=SçxÀ×x|Œc×(+˜áGÌżã€ÁµN0ÇAï s–Žyi"­'zïYÐGðã8œ¤cÿ0ðà  ¥,„#n ×H…‹ñ<•¹â$¸À*) *e5ƒ@º€\^A!¡ ˜jp×¼ ¨Œ$½4ø£ ¨Œ/*+ÀKcÊðò¸Øâ²à 05t$*@…#Q-äñ¼$ `UExGT œlª»+0`Jáâp±LrE‚q È1Vb@Zà‹¤Ì-iᤠ-¦¤¤Æ€\æ,do?*½.&“(ršWÈš¬êÁK“U=!ozàN* HXDÈ¢<M2¢EZ d|¤…µ”Ä5VI:@L92žx{R'@ž@$µ9 ©‰Ÿ€¯4§ €ó5ùU ¢"߃³æä!N²>¡ tDåHm&–ÈQâŒàt–¦¾Ðœ§%´ÔB1MÊiØH j t¡`0' @@ -2288,25 +2287,29 @@ h Ú¡‚nAŠS$?-ÄR™K ‰¾ú‹0Ã~ÖCnÈ^vãe¶qjC¯çåÙ)˜aàuR};Ò0w­ü@’/?Q4KÏÊ5Hf¡rY¾t=©²9Z¡Åç«œnÞ|M*›I•SMÈeå@®”Ë…\jªŠÙÖ5̽+ góª#=gƒµŸ6=s -vî aO«GFÌ+aúe’û‚z‘×9²{w÷'åS“)ëæ”æ}j…²nÒ3žŸ N+$¶4—Ë‹ÊÃG×ÂOÆ\˜d°(~˜ aR³ N ò 4ó9B‘M!Eê½# 窾ãCܱ†NLi(g[ðPrþ†ì»px Jò¼Êçy™Ïó:Ÿç…~ÚTÂ1¯øy¾cS©+gû ¤®C‹LÖ)Ý©€ÒNv6©ì©Êl.¹>fw÷"Žu2³q2¸qfzÁ.-?áÄ*áŠ%X~\ŠI3£Àì ƒ)ytÇP ÌV—‚ÿòÓù¹­”*!»:L­qe˜Ui°Ú‘a°ÆuýjSS÷2Šû¡fU8iUq¤zȪ‡é„Rb.øü H)ÁgôÉjÁŒ`OKêÒ*¹üTËO—}fRç'_s@öÎêEœ•Èö· ýOýo=\Žž—õMS}×~¼&8Ì•Çk±ô!C_lëªk·g/ª«úŸì¦»cwà¶ÝÖ·ì>>:Q/Î_mÛ›‡U½=»ùÐÜßܾÿÈ~;CÒ&¦ú"HÓnžU]}öìLYn…\{éÿÊåל½Hü~½¯7OãÖù©µšîMÔ¶gÎÿ¾«}èÖͪÆç‹ã«Mt]ºÿù+ÙcoÍh¢‹ª«Öí;Jï(ßècP Ú©¤×±â;ñ&Æ'þÓ}Ll¿éozÕÎj‡#g„m°˜3ƒºXÈ$ð,B‘Þ¢ (ø‹d‡¬¥WTâmÏà†ÀÐùøö‘aôFŠË%NÒ-%ñ°ôÞ”KGƒzCo!8Qᤡ÷Áp ñ &Ž:^ié'p ç¥£tX8âH/KÑ{){+ôšÿ÷ñîèÿùZǧžÃà|zhüÄAf‚øK”„ä&Æ=U¢éåÍx|l¬ðƒXtþÍ_þ óé⨠+vî aO«GFÌ+aúe’û‚z‘×9²{w÷'åS“)ëæ”æ}j…²nÒ3žŸ N+$¶4—Ë‹ÊÃG×ÂOÆ\˜d°(~˜ aR³ N ò 4ó9B‘M!Eê½# 窾ãCܱ†NLi(g[ðPrþ†ì»px Jò¼Êçy™Ïó:Ÿç…~ÚTÂ1¯øy¾cS©+gû ¤®C‹LÖ)Ý©€ÒNv6©ì©Êl.¹>fw÷"Žu2³q2¸qfzÁ.-?áÄ*áŠ%X~\ŠI3£Àì ƒ)ytÇP ÌV—‚ÿòÓù¹­”*!»:L­qe˜Ui°Ú‘a°ÆuýjSS÷2Šû¡fU8iUq¤zȪ‡é„Rb.øü H)ÁgôÉjÁŒ`OKêÒ*¹üTËO—}fRç'_s@öÎêEœ•Èö· ýOýo=\Žž—õMS}×~¼&8Ì•Çk±ô!C_lëªk·g/ª«úŸì¦»cwà¶ÝÖ·ì>>:Q/Î_mÛ›‡U½=»ùÐÜßܾÿÈ~;CÒ&¦ú"HÓnžU]}öìLYî¹—˜–þ¯\~Íù׋Äï×ûzó4þhŸZû¡éÞDÝh{æüï»úׇnÝl j|¾8¾ÚD×õ§ûŸ¿’=öÖŒ&º¨ºjݾ£$qñnò>µÐ Jz+¾3ßab|â?ÍÑÇÄö›þ¦Wí¬v8rFØ‹9ƒ°‚ÌÅB&gŠôM@ÁwX$;d-½¢h{7†ÎÇ· £7R \n,q:Èn)‰‡¥÷¦\:Ôz Áèĉ +'} ½†cˆo0)pÔñúHK¯8=/¥ÃšÀGzYŠÞKÙ[¡×ôø¿wGÿÏÿÐ:>õçÓCãÿ#2ÄÿXò $$71Öè©ÊmL/oÆãàcc…Ä¢óoþò_Aâ° endstream endobj 486 0 obj <> stream -xÚ¥S‹STç¿wÝÝ{A ’x‘«Ë#+ˆÈð2Ã"%(V‚‘Ç®°>va%ÒRl´‰ö¤1ql”” ˆL-/—•×¢eb¬H!¤ˆ¤1ií4Îä»ìY˜Þ%3ý:ßÌïœóÍ9óßï|‡¦ÄbŠ¦éU»Òr6¥•jõúcλ”õ®”øL àŽ³dwXä.Wäl¡„WRüšñ+xN¼Ž¢èO'¾ð‚]V Hy À°/Rî4Íz¬–û…þ,61ùs•Z£!ÄpÌ × -X^áôËKŒZgtÐð¦ÑitÇÑ1Ý/¨=®Õ V«+.)¬^·\¯+Ö•ë*µMAyO‘¡ôWFg–O`ÑFŸðаÐÍ„û$ ÅG´>¯Œ¥cA¹Î q²õY¦KÑ¢“®Õ‚y—>CŸ¥Oýýú}úýíJQ4µ†’Q«D‚ãO]¥þF«èÇ¢ ÑÇ¢Q¿È¶âm1#ö¯ÿ]b’‹ÇÈ^¹ÄÄÉí»f‡Y|SnoãäâoÜåø2ã!Ÿµ7ó…Äo뢞£´_T2ÙQþ[•…è¸0©}güg”D’E”@0–Ïgžw_ ìâ^@Ö7ªoªïËûmßÃc˜ÐôG÷G7øÊו!•©ÊTÅi6C0ĵeMeO• -ˆ‚õX8ÃzÙ@ãx ;¡”qG³©Õl–½r_Œ`Ÿ3ö«öÃ^$d19{ž|E~MV=œ0 ËL#uwa -þ]üeÜ@Ü€ò3ôÜ"pÈÀÕ(~„´·­gðº¥ÖòÉí V˜†‘Ê›º®’+ûaäŸ.>a8QZvä`‰¶$>Ý/Ú¡Äo”9•©¶¿½pYPF¢y==†¢fAŠHˆúª,Úp0-oÅÞ÷»F›kk†>…Y¸SÑ]Ø[XŸñ~hGRNRv˜¥Àâô'¯HI3Q„ã܇/âyE2$V¿~9¾&±>å‹áŒM?|ü¯U£'ïýnJȺ–ùÉù‰îe•`Þ0>”>Ù‚.—ØjæIíD{¿Õbm˜‚±B³çìöFŽ¬Å£öݘÂ,¦/í“ çB¡ƒ!Ñ<ÃಖsX¥|.ÿ£ÙÖ2Ô8(» =…ïb€ “³¾š¿ÅwqÛaû©˜-|²7?C6/–ªcçÔ?þiöÂÈÈûÄS‰ù -ð;ôZ²z§:Ô€. Õ '\ÞSŸ×Äb$óu&ñ,#Q@T@d¦'sósÝd%MBtàyøTÄ$º·b,? p«ÙiI+>áHŠ”,—„Iˆl©7/´2?¥ ,§Øoò§„QÈ*S4_ô4}âç–ØÞȆ@@àŠ¯Fl‰(@7À`ᢩɘɘ4„ƒIøâ#[kû¬ÛÔr›½(=oà¦mQÑ=#!R?̬aÑŸ1¿5|z -X>”‘6þ®Âq’n*{uݺ¶¼ÆÝ»?Ú; ïÄ}¾>¿èP–1ǘQ• -!®1w ÷Ö±Ix¡æ,6‹mâÚc'IÉQ¹DmÏå‡Í÷øîÒ¦M7?3Üþíèq‘y«®$^Ü#ü‘*tŵX§He0;MK²—rÉ6{.ãˆðúÊ=ø/È~àHŒ°ÿ#õXVÜeAÂèÄðoPú Jˆ[ºsFÂ*K:gæfÿÙáZ0¹–P±ÓÛ§ýÛq°…€lz2l•´šhÍ$äÁÓóde ƒ1°žê«d‰?“ÿÇ´ó±€À¨x£®@ÿ < ØÎòUŽ÷¸ȨÙw=÷º¶«ÔZj}kîB×%s“骩ýϽŸö~zûâÌø¡GÝ£®ßA, ¤lKfZÖÁ?}þrÉ('täwD•ý Í«à ±µIí©íicßea~ˆÒÙîk€ž7‚ff‰›Ž„ Âþåá8ûðþy î0cÏÉÞjÅ•ƒO{îÝ2[ÍÖº1¦¨™S «†}¯¡LöîÒ3Æë†Í}fËx×3áò¾Ýgɱd7¤Ã.ØfHVç©óTå°Tujs†Ù0 _±äŽ½˜{c=EÝšú½Âª¤Vì-Ú¯ÙŸ˜\äÛשNE?ØàN}W{WûXí_E­}ºŽ<û^ê8 ÌzWZVëæÂ_]ý_ôeô +xÚ¥S‹STç¿wÝÝ{A ’x‘­«Ë#"2¼ŒÅ°H…€ÂÊC°òØÖV"-µÁF›hOãÇFIˆÈÔòrYy- +](ÆŠBŠH“FÑNãL¾Ëž…é]2Ó óÍüÎ9ßœ3ßùýÎwhJ*¥hš^•’’’˜¸cSj©®$=¿ä¸ã.y½3%= øŸãÂ,Ùìf¥ÓU%[ ü(a-øKÿ']GQt°»_zÉN«D¤KŸ£Gýý{ú}ú<ýíLR4µ†RP«$¢ãK]£þJ«é'’@ÉÇ’I¿Äºâm)#õ®‘þMfTJÇÈ>¥ÌÈ)m»fD‡Y|Sikã”Òo\•øÆM)=gk8 » +ˆÏÖÿD¾@y¾ +èÈdEúnõ+@À]€‰è=ã;ãGd™ÄHÆüðÅÌ‹â $ž]üÀÈúBõMõ}ù í;xÚþ¨þ¨/@%àº2¤2ÔêXíf‚ض̩¬©2BQ±n g…QÛ÷¨bì¯`çc”“@"íh6¶šLŠw‚Ïâ+€á¬ýÏŒ›íšíˆ ^LcÎ] _‘_‘Uf'ŒÃ +ãHÝ=˜‚};;à÷9zn9¤ãj”>FÚÓÚ3xÃ\kþôÎE LÃHå-}WñÕ°òÎäO––=T¬+ŽKó‰²ûá€'*ÊTÛÞ^¸"*#Ó>ŽCI³(EDþZ]ÅÇJÍE©çƒ®ÑæÁšÁš¡GaîVtôÔ§C„Þ™˜˜j@9°¸}É«rÒLTa¸÷ãËxA• Õ;®ÄÕ$Ô'_g1Œ±– ŸøKÕè©û¿%²®e~r~¢{Y%˜ç§Ó†Ò†"ZÐé2[Í<­hï·˜- Sð/Vlö¼ÍÖÈ‘µx̶“™Å´¥ý2t_(°3$J`ÜBÖrv‹\È~0Y[†å§1à]ôerÔW ·….n;l?}²EHòfÈæÅ#rÍbÌœæ‡Of/Ž€‚¼OÜý0O>‡_OÒìÒ„ðè‰_ÿqü•½õ¹M,F0ÿÈ îe$ˆˆÂøtn~®›¬²IŒ¾› +ŸD×V †å'n7;,iŧI– O”²PQ,åãæ…VæÇ”åÛ-á´8 +Ea +ç Ÿ¥MüÌÓѨ\qðµð-áùè$^´"5=ý½–p0 _|dmb­Ÿw[î°—äg0ÿç¸i›äFtÍÆH€”3jXôeLo Ÿ™VH%e¤M¸§²Ÿ€Ê^}·¾-·qOãžvÃNÈ=y°$¯$¯ðp¦!Û^•!¶1g çöñIxÊ¡æÌV³uâúIÙ1¥LcËá‡Í÷øöòݦ›M·>ÜùÍè #Qxª¯&\Ú+þ‘*tƵX§Ja0+UC²–rÈ6[c÷øÊÝ„/ÈàH´¸ÿ-w[VÜiAÆìÄ°¯Qþ5ʈKšcFâ*Ë:gæfÿÙáZ¥ŽP1ÓÛ§}Ûq¸…€lZ,2l•¼šèL$ø᳇óde …1°œî«d‰/“÷‡Ô 1€<`dJÑW o:lg…*û{\2¤×ì¿‘sC×Uj)µ¼5 +÷ ë²©ÉxÍØþÇÞÏz?»siæaœïÑôhê·C (+Û’‘š¹'öXÐGø»R6ʉùU'E½¡} ¼!¦6±=¥=u,ýÛLÌ ös´û: ûÍÀÙøÙâ¢'!@ü°z4Î>zpsˆ+ÌƳG²‡·Zpåೞû·M“¥n ÆÅ)jçÔÃêaï먥½·ôœƒñºaSŸÉ<ÞõÜH¸Üoö›³ÍY i°¶ñIš\M®º<6€ºNcJ7ñÃðKîÚŠ¸G0VÑSØ­­ß'®JJžÂÚ yA…Þ±ZñTôƒîÖ÷wµwµÕ>ùUÔÚ¦ëÈóïäöSÀ¬w¦e¡µ.NµÕÿUkeì endstream endobj 489 0 obj <> stream -xÚWiTǶnàô€2h´ñ ' ¢‚‰ˆ âˆ32Ë  D@fd0ˆQÔ¤ŒQc0 ‚" 2(àŒŒâ„F½‚&N1êÆ‚^wŸ³¬WyY÷½·ÞûñÖ©îÕ}ªz×®¯öþöW:ŒBÁèèèˆî‹.ôöëç·fܬø˜•r‡§ùF±ÅÖ‚¿ xh_©|­¾f%3FRéHêJæzÒPŇ £0˜Þ™çÆòýú ùnFo ŽëâµØÁÞaüœ¨ˆ¨ä¨ÏÃWZ® I± ‹OHOŠŠˆL¶´ c9a¼Ãøqôæ`g9?>>"&Ürv|RB|RHrT|œ½ì¤¥ì¥¥ìåßotæ#èêgÌ+~,;Aá¬3Sp7fžÑg0#ƘĘ1ÌƚɌbF36Œ-3†±cÆ1öÌÇÌxÆqd&2Ÿ0Ÿ2NÌdf +xÚWiTǶnàô€2h´ñ ' ¢‚‰ˆ âˆ32Ë  D@fd0ˆQÔ¤ŒQc0 ‚" 2(àŒŒâ„F½‚&N1êÆ‚^wŸ³¬WyY÷½·ÞûñÖ©îÕ}ªz×®¯öþöW:ŒBÁèèèˆsçy,ñðëç·fܬø˜•r‡§ùF±ÅÖ‚¿ xh_©|­¾f%3FRéHêJæzÒPŇ £0˜Þ™çÆòýú ùnFo ŽëâµØÁÞaüœ¨ˆ¨ä¨ÏÃWZ® I± ‹OHOŠŠˆL¶´ c9a¼Ãøqôæ`g9?>>"&Ürv|RB|RHrT|œ½ì¤¥ì¥¥ìåßotæ#èêgÌ+~,;Aá¬3Sp7fžÑg0#ƘĘ1ÌƚɌbF36Œ-3†±cÆ1öÌÇÌxÆqd&2Ÿ0Ÿ2NÌdf 3‹™ÍÌaæ2ó˜ùŒ+³€qc<OÆ‹ñf|˜…Œ/ãÇø3Ì"f1È1K˜¥Ì$]F‡±¦èé×y¥£ÑuÔuÕ­Ó½£g¢W¤°T¤+ö*Ž³Ž¬?›ËîcŸq\%/ð1Â(ašðpCx«?LÿЇ»Z¬øÎp°a˜áÃ놌"ÎÏ6¾>(dPñ`¯Áƒ_}`úÁ·\b9d¦JÑ*¶^TiÜÔèß›¢ÒUŠçjCçTC› 6ÁéÆŽ³]uMë~®ø¥ø™€·¸H4µY6 «¡LÙsñΕÓ§¯ýƒüH^­ºëÒ:³Í¶4!Ö1Ó=§y®t&£‰çnߢÅE‹ªüÏû cüæy‡º…¹§M#ã 9;ú¥ËKWOŒ< Cž¬²w‹4U$u»«-:ZV~¼ãC¥kèŒ4'âJü¾9¶üXêiÒ*ªƒDš»<Ú7ÚãVôUr‘ß[~¸ðPaåîS¤†”¯/N-NÛO"#µÛ©M$8ë0:5àXÚ:ÑôwdØÊãy`¾Æݘ@d·œŠaÂY°§íX½QÀmÜG(¸ Y Ú/FûDt&8W¶+I²a˜Îðq Ø»€ÙЗ?xâ-´:‹ö´ã‚N'%á„%8n ÚÍÅÐXvà(:AÙc/ÀØÃ0‰Œ4Ýê9*n¨ˆy\­V¡Õy³·ÁóDLÄóƒáC¸ ã±ÒÀ×Àyøµx5l×ê[³Fj›KEélÓ㌤û Ö" È )+­Ïl!ͤ.¯¼¬¼<¯–4’æ̺ØÒ˜ÒyþÄ—,ÏŠ‹Ë !~teOÔwå€Á2N[G£†…²ÿ¿5õuñïÿ&Nþ¦‰Ôç••-Í«£ÿ«*ÅŽ_$/7ðš‰ÎoÍ÷¥HYÜÈ«]ð&k¤bs5WMà §ÍS±çX­1§Ý«ÒÌaé?ÿ‚nV*ãfÂ^Q;˜{Ï®@ÄÁÇÛ×ìZ½7tOh3ÎÿoÐ ØàñWRH'yp&0¬úUçogß0%/Ò:CZÃZ]kì …ïø»›ŽÕµœh)¼Mž—ý:®Ý¾ Ç–ap”¶K„{àÄ?%W×Õ­9‘TFüˆ÷Úቫ½²èWüJf>ñBC ⚺:tµGƧ´/˜£¾˜ªO«—E @@ -2318,143 +2321,143 @@ c .ª87ÜÍ' 5» kù¬vQÉ¢¯½s=iXN)3ï{ÈTãˆÎQ£{A)׋OÕ‡äÚ5¸­]î½ò³ H!“ 3ú7ºƒ#ÏJn6o>ßuè©$e[m,‚ãÊ„‘ÛBe Û4.ðX¤§Ÿ³kO¬=[ZZî^1±rÌq²Øñ2©jÎ*~fÞ@Îm8—y.óBZËšB‚‡\Äa¥hFä¡›0#`šøtbKîZR–¿²4²6æDÌ•Õ?G´'M©J«J?”ž—%äeì\KÖîþѨg@bßìÙâõ4ŒhX’_¿ï:&@ï’ì¾nQÿ~ÎÒx˜@¶L Zš¨\;.|a¸Ÿgܧăˆ«;‘ÕNî j+l륹…ÊŠÑ×ç^Ÿó:’†Ñ]rc_û‘öÒÓ'*.Ðà¢óµ4ݨjšN x›ÃèÞÁ 2glq7Íårogv­¹1êÁJÚEµÝ=ù ý˜ƒNyð‡k7lŒËñÍœdšé”³ w©Ë}Uðå¡Íe›Žn*ßT±éhnYné¦ÒÍ…[òp˜T¡¤ò ͵Ÿ¦¢nΔ-tŽTŸ F©OQ”6(±•ƒ[ôè÷9X¡Ñgwr h¿5\¡d*ݵÆÚ,¼æ Gë´CXøƒÓ–nHŒt’Å×Æ£„± ÉÏòÚ4= -ɧïeº²kLPX´ihÔ²Œ²‚„}³j—€›ø†œ†ÜFòŽ¼(ý©í~Ûå'õ /Ū¿+ñ'ÃzõS½2Ý7Σ^nì\w5½#ÔúJ#M††B–¥-७êÙ,,éíÄ,)ƒ×æõ°èÊ¥ÐôB× N›Cxó:¬Ãý­FRéÐÿFüˆ£ +ɧïeº²kLPX´ihÔ²Œ²‚„}³j—€›ø†œ†ÜFòŽ¼(ý©í~Ûå'õ /Ū¿+ñ'ÃzõS½2Ý7Σ^nì\w5½#ÔúJ#M††B–¥-७êÙ,,éíÄ,)ƒ×æõ°èÊ¥ÐôB× N›Cxó:¬Ãý­FRéÐÿ ˆˆ endstream endobj 491 0 obj <> stream -xÚcd`aa`ddõðq ŠôÒö/HÍ NÌ+ÖuÊÏIIøÊq1°thÈwwÃ<ì2¿yþ¼‘áê•áèeý!ÃðC–ñ‡Óyæ",² Aä~yMDJ ÆB ¬ŒŒ<î¡q¥y™nN††z†.™é™%™U©) +xÚcd`aa`dd õu + +Òö/HÍ NÌ+ÖuÊÏIIøÊq1°thÈwwÃ<ì2¿yþ¼‘áê•áèeý!ÃðC–ñ‡Óyæ",² Aä~yMDJ ÆB ¬ŒŒ<î¡q¥y™nN††z†.™é™%™U©) )‰%‰ Éù•E™é% Éš -F†º@ÂPGÁ=??='UÁ9¿¨ ¿(±$3?OäXk@®…ó€V1±0­å`lg`fdTv;(Ãrö{¨ ë6Q™_^?ïìKe~m•ayö“Wæ·;߀Z ¿×²•ý–Íúmû;’ã{>ÛýïǾ›¬ù.ÎÁ'ÃÚùsÞ/^Ñï•¿ç\dïÞÛýïǾ›¬ù.ÎÁ'ÃÚùsÞ/^Ñï•¿ç\dïÞ> +<> stream xÚ=S{TgŸ$3¥4X5 k -A‰U%õ­,-ŠËCŒŠÄMx$á•EŽm=,õê¶Û¥ ˆPŽŠ ZA$%¥Am«vA]X­–ϺÇGÏú%ÜàÙ<§ÌïwïÌý¾{sï¥)€¢iZ“®LMJM2jô©*}QØZCÞ.þÃÆ@JP9/àב¢¯ç±Ô稔=*tÉ)×\Úõ¶—kž·kºà-Š¢£Þä1ÄÇÀ)R³85L¥Ä4ÍŠ§Kç,_ù^̆Šãµ¥šBÃ"C‘A¯á°x/ok 5¼·ÛPRÈ“ÎÄ{Eº}J6O=_öN¸"<ŒÅBYŒÁ°'O#[g(4 -UÅ:ƒ~/ZÆ«–ñªÿð¸ê½¾VÅÑßèJú#ú0 ôú(ýwúcújES3©ÊÏ‹3æP§¨Ÿéõôï^‘^罺½†½îy›½O{[ÙÂw¥‚kd³TØ)‘ŽÇ»G8ƒ™(‘ŽwH¤‚1÷Rü#– -þíZèúADTs¯µ¿ÍÞ×2ÃÐghKiK©YÈŠJ—å$ë6¥éß…HHmÑõç8JïsXwÉ I™$Dñ<ü9NëÁU€k%[ÂC‡ì@9àFÀ”.œûPþ«œLßJÖ‰"¹<ölì÷."’̊ǹgHEXÃx*<¯“˜H¶YæÏëkššjÍÇ?«À…þ•$ôœà+>6~s©öX¿`H2™F^¹{Ãú]€ÕQ÷Ü…ê‘ÕŽÕ´àPÀŠ²ˆü?ç/O Ë0Ýßñ½½·±÷T_µì`=Ødj2U@¹‡ôeÆ2c‰1ßoˆÝ6{­G€Ÿû£úU>‹û2÷‡è¬ûK–  ïi ”¶d;„’9¨óèèk¾dî6_ªúXôczÁº‚­Êü-ú•e(…ø>ñ?xxÀ®·ë›·Ã_ ²(-]›®}¯T±{<¦6¦vcCJ ‹f†ø)‰¬€,² ÈÜŽgwžÝî!4`xœ?”ømbÿ;_£Ï—ì1æÉW·m}ƒ}ƒÍ·aŒå«• -ö7IȇížÀ³ÌÄü—2!f»}< ùÑÅ0x…|(ñE䱟hüª­¥+ ¥«þl…­U”QU¹îðfÈ™¼Ê5îz!I‚m;?Ðòo"ç„®äˉ6QÚÄâ×TÕöigU@籎¿ædoùo¾‹Ã"qSPÄ__»¾&±AÙÌbóDIfܸ ±=}ðôA7™ -ü‹@¡WÞYq…ç0&Ó\±ðLöâ°„ ‹\ÝRÁs!Q¾lÃj·†ybŸ uUs­ (!Lö²o¼µªgMÏÂF¤ÃÅ™K+Y8P(oGÑ­U·V?ÝI¦Á8«{ÙžF›­ÃÉþCT"“B»A·5#6/6yY$Bò§©_°x„éúàjÅ/@I¸AÞ ³ùg€ä±²žS®·$W¡×hM;Ÿv2"@Y’‘©ÊT+M \SÓOæXs¬µÃ ­už±±u×r*Ý«IHˆ“ÛItŠÄ¼”›nZ8«Y[hgè÷kÿµíî¶G…„D|áÁ¯~³qãÃ{òÝD55"·âLN§Ä¡-#LÝÃVg«³ûâ–k–_Ìÿƒ~pr”³˜ŒÏâ>Y X ¸!ÅŒ~œˆy€çYW£'P²”M;ûT}¦ëp®Ô_ì²Ú¬½uN¸—Lmj‹ª&¢aÕþm–6skIÜ«V¹F¥Âï%(Ì]¿4>{̆èÚ¸ö¤ö¤ïRG•óÓ£S2ã³âK¢€Ëýæ…б˜±2UG–rdÊ™G??ºyñ1_*úi»3c0biÇo®_¶ö['¯Á?PÙ÷— .w¢Ð‚2n•ö½–À“£döÕ{Y;ÛÕg5'T ›÷ektšÜ”ÒHn·ÒÌj‹Ú²· ¾e‰ÉýBr:Ë[­Æš=°Tå» r rwäÅçŶf´œ.´”ŸsÐen·œjm>_ÝËÉÛ[7þü$z$ò&Ї*ê|_;â+vµLÿ?´-P +A‰U%õ­,-Šå!FEbŒ&<’ðŠÊ"Çm=,õê¶Û¥ ˆPŽŠ ZA$%¥Am«vA]X­–ϺÇGÏú%ÜàÙ<§ÌïwïÌý¾{sï¥)€¢iZò~Ôú´˜äÐ$£FŸªÒ…­5äíâ?l ô¡•ó‚þ0|)úzK}ŽJÙ£B—œrÍ¥]o{¹æy»¦ Þ¢(:êMCüx œÂ!5‹QÃTJLÓ¬xºt΂ð•ïÅl¨8^[ª)4,2ô‹÷òv±¶PÃ{» %…<éL¼W¤ÛǣƤÑs¬ÑíÑs¬×MT,R„GëöèŠu¥š]²]ªb•Lm0î/ä£dóÔóeï„+ÂÃ8P,”Å {ò4²u†B£¡PU¬3èñ¢e¼j¯ú«ÞëàkUý®¤?¢Ó@¡Ò§?¦?¡P45“ + ü¼8cuŠú™^OÿîéuÞ«ÛkØëž·Ùû´·E-|W*¸F6K…éx¼{„3˜‰éx‡D*s¿!Å?1b©àß®…®$@D5÷ZûÛì}-C0 }†¶”¶”šå€  ¨tYN²nSšþ]ˆ„Ô]Ž£ô>w€u—Ì’”IBÏßã´\¸P²%¼'ßM„Q#Q#r+ÎätApJ +ÙrÑ1ÂÔ=lu¶:»/þ`¹fùÅü?èÇ!G9K€Éø,î“•€•€¢QŒÁè‡Á‰˜xžu5z%@Ù´³OÕgºwàJýÅ.«ÍÚ[ç„ëpÉÔ¦¶¨jR!VíOÐfi3·–Ľj•kT*ü^‚A€ÂÜ¥ñKã³WÀlˆ®kOjOú.uT9?=:%3>+¾$ +¸Üo^‹‹!Sud)70a@¦œyôó£›ñ…¡¢Ÿ¶;3#vüváúek¿Õqòü•}Ùàr' +-(ãVißËa <¹1Jf_½—5°³]}VsB™°y_¶F§ÉM)äv+ͬ¶¨-{»à[–˜Ü/$—¡³¼ÕØj¬Ù;@U¾» · wG^|^lkFkÁéBKù8]ævË©ÖæóÕ½œ¼½uãÏO’¡G"ÏA`}h¡¢Î÷µ#¾bWËôÿe5- endstream endobj 495 0 obj <> stream xÚyTÙ¶v!tu)L«”¥àhW먈:fÇ8 -Š`1`–‘l+I’䜹›$©˜L¥‚q09;:†ë8ã8^ÿ{Õ »\‡yïj.ïï½ÿ[ÿZZPçœÚy{ïƒeaA™™™õ˜ëºÔ}ÎÒÁnÚ ïÈp×à9_Î÷ ˆ”¶Æ‹ŸSb/3±·%ª;ˆ¼¹hc‘„SޫߟRô¦(suWòìÒYz~Ó…<) y `­)EÊŒR˜›Ý4{aöÛˆ¡ÃÇ ô˜¿Ø~ðà!ÓBBc´«#4#ƯñŽÑ´íhœüµÁšä—(¿ÀÐ ¿àˆ¡š~~šˆÕ~m ŸfÚ\÷¥3Ý\4]Ü<4.~Á~a^÷Hï@­fŽÖÇ/8ÜÏ^㦠l}Ñø„ûj#´!ÁáC5Žá/Mx¨Ÿ–|äíã*m Ñ„ú…iÃÃÉïm¸& Ì+8ÂÏW¢ÑûFúJìɺHp„&4,„ì‘BÊ=$<"Ü'L¡!Ýœ[eŒXí!ñ ×’mMˆ?9éâ)iÓ¾ᥠ×DøEGH|¼ý4¾ÚðÐ@¯— - ÓEˆ ט¸Ñ„ùx…ùú…éJV1駑iícü6Äxª¿6"Ü/ШÉÿ^i  ‰•Í-^a-R”™²¯¹;©ƒCÇÙªåš3.”¥ hŠ¡:R(KÊŠúŒRQ©.TWÊšb©nGu§zP6”-Õ“úœêM©)žêCõ¥¾ úQý©”5²§QC¨/©¡Ô0j85‚I¢FSc¨¯¨±Ô8j<5šD}MM¦¦P”#5•šF9QÓ)gÊ…šAͤfQ³©9”+åFͥܩyÔ|jµò Q‹©%ÔRjµœZAyRßPK¤î@È?1;ÐaV‡5™›™'˜7›?³ ,z[¸Z4Z`E€â/z}N9OYÄ0L s©#×ѽcU§qvXj,·ZQVÑV/?KQÑ*WÕíÎêÎeÅ.³ºlﺸëMë\ë؉l.ûk·˜n¿r=8.‚ÛÃã~èÐý‡n=NÚ°6Ù¶mómï÷ä{nêùèóø^Š^Ózé=½÷~µ¿ú,?åïk4ß÷±é“ÐçY_G ßpõ¸¸ LŸ\l«‘ÞP°¥ŠmNuÿÔª -æ `-˜‰=Aä^ÐÕú’ŠòÔ’~$] ayUé†d›ˆ2Òrcãp¤ÍpzY-É3¤”&Këémëè˜ÔôÄ}z5ÿ€NÅÖŠ‘¦…é8¦HS&éS êrT¬Ë¯Þ‘6/èx–›–K(m9*ÑåUW’õ'&&ÒkÁš“È §õ`­P Wqtĵ֠b„wtØk°G¼ÃM™ëŽ¦!¿ê€ë·ÆíH¹œt-±2ssb]|Å:ÄÌqõüJÍÞsD3öeΩÎ,IDLBzj ?IS’ZQ^¢¯VW*·7G4å0ØÒ´–Ê·†ËgÑCt8foàÆšuºiâõe {%ª<¡meΞ9zC} , -È+Î(GŒô-AÉ©ÎÐ'¨‰¥Rr£¶G”z2§”ìœêt}¢Ä^­JÚû•žf Üÿl#ùoA27cá—Ó ®_=sæê-ÓμŸÅ±}~ËVúù®\áwàè±ýû›xÜE!?xí¦ì ¯¯§tðèþM<p W^XTŒôLiš>U…²r³r[:c•MbVfJaRô©:u>*Ê+ÊgTàCâh:. g²Q–m\yb%ñž®¸´úC5‰›£ÍÅYäL -JO uÂ|qGd‡úíùâ:Vlöק”"ÆPª7ð¨07?§Èº¾E¢?wývTùEyù¨1¤ê“Õ*(¸h“©ä”ÔdeååägÞÄ]wÚ!L!MàÎX•“™›ƒ²˜d)†JQIIÕ¶[ÐátDÿDïÖüîûSõ)ˆˆ½[0‡Ýâ,ÛJÏÏÉËB¶É©Õ]ª.·0×l½&` ⎔ikŒI**Ô•> ›ÇØB—\˜­C¶½$xQvqVɲ¶‡6#ƒmijiŠ:¥çfæ`ÛU6À+M®„ -ÁÌÈÿTp0ƒ®i ähÏ€•tû9¼ÏP¶§ÌÀžt{´³CÿÿhvÉÕ0píYÒ2À”kªøZ38 çâï¿3ø_Jع}ÿ¾ í¾¼JŒzÿW¨Ë+$–/Mѧ¨SPfVzþá¯96YD#bà¢1pQaI£ŠÄcD#…‚¹¿q0j -PØ›OÁ¥¶Sâ‘÷1æ`~(©ÆÏ^qèrõõM›êëk¡C¨>z“vçÊj4›©D³c\‚VFjµÑ^È ik"냚b®£ËŒ ->{ˆåîŠ"‡]çÅe’€L¶M!R’€ÔåæÍ!›–rÌ+£%]K%ÃÝ6!æiBBÜ#X‹Óýt¸åÙc—Îÿø ºÀgµ;ÐyæŘGöj7´ ÄytxbŠaRõD]*..¬¨¼ð]ãuÄÜ¿ææÌ#Ïè/‡98Nt˜0•™«doˆêïMþ P¶ZÆZœ!D^b'xÄåçåçå¡ [öŸBg™§\³S/FKã|ƒ¢âbZSK -´‚üÒ²õÇkÏ æûóËfñÈ+Ä×+&*%.w)bbSÚ¼ÈÞxýxæד§ÌÎ/@ jVìM/ÊÊÏ@LJjj -Ë÷Äž -9šx1 üõñ]_qáëÝ’¡›±"þ²‚¯9ÜmŠ,Ò› ¦…nõÒ[y…ñMT¥qt‹b…êÇÓà (êh¢)<`q½‰‡æ‹8ÈÅvÞD'êˆzE¨(¿¬øЦ#†ƒˆyzÎudßÓìùyÈcóò#é%F ZS1©"~wÔ‰5'â¾%Xþíg° ‡Çýùoê’()îà„.µR:õ:G ×éÉåÖän@zt¹ê»íGŽß{xô>ªAÕÙ¥™ºÌÂÜ"‚5:½¡& r? Í -[´ÒqÎê13 žö« Óëûê픧ÃÕNÈÃÇ{‹'—æOqœ9wâ„Yîݽ|î1/ñÕJV$àèsQ qyÑyñ(ÍŽu ùf™Ã¤SP4Š)H)J+ÊÊË$ÎIKMŽÞw˜¿‚®lù¶ég¦î4hÊW˜êì õ-Ô|PxÌd4sáß$ÇÄÇ­ ð‰òGÌôùW>;{õ.ôÜ6¶ åGgÖŠ½þ(¥@3Y6­ïØ·/h«ÛPωcp|QvQN²-FÅ…Åù6ù¿ -PqVqjXjä¡/*,B:[T[CþÛdg¡¬œÌlRæ“NÁL¬e¨énBMÑ÷ûôŽJÜBÄhñ™™ùÙÈ6edegädÛäd|&u 0CŸ €—Ú`òHÍÌÊD鶤‚eçgçeÛd”da ó‹ -•«°±XAä¥xú»Ÿ“ˆúŠ ýcZòÈ^’”ÏÀNå/.7†cÅx‚³CÔx¬9U»î]¼wɑ𠈹{÷®RR5ùt”››œã´ --E««C5ÆžE­›Ë/_\?¾tºz…²ž£Ë8óx@bµ4¯6Ÿ9d‘”›Œ˜y> '.œ=ü€— ÃN€&b%pçÎ`;Å“`¸ 8üi¼T¬QàU²m+»´D*éOBÍ$ºìPH`%‰&U¢I±AkˆÀÄg‰mIñ.ç!£pž~q÷ÆS][ulìÎó»·îC'™ÇŽ—©±Átª™°~0NyçŒçOq ÃF̲IÏÌÊ@éŒqr+@¤È;\vÍ°mA•ÙÛR¶|GŠ!»1‡¾ÛU[&J㜛¸>6= -%¢´üp=ÃF" -ƒQŠË Ê`Ž‹Ï¹ÿ§1üˆm5F£Ñ…ØÐ÷WñxŽ¿bΚ¢$ž}BöÍ9ürwÓ1t…y:î6©Yyÿ»`‡B ˆ…/•·¯yÌ=q±=OV+–I ÷‹s‘GØmâ<±‚ó<«ÝÓwÒŒQdŽ¨ñݱ3roÒͤ[I3êâvçöتµh5ã8Ýc¨z8r<™}5·2C÷áÞ“š4³{w(ÙŠóa7HGnõìækŒ8ì[T¢›\îZ¦[WÅ°Ûª¶£]ÌÕ‹Ç« ‹ž…s¥*÷/ß)Ùîò"ÕþSÊ6˜(Ài¶¤Â5aª2NŸ\VQ¬«QݲÓ¦ -p&¶Dö•Ae¡É8RˆgfoZs(‹À€q€©¨H+Ž6¦PZF‚ñ£»øgzÄôé£F:ßüY ?ßý(ÑbRÛNÕ“S˜~6`ñã@kÅ\âàÚîgið#-ήVò©Å1RéˆNk¿ß¤Ùɦ±›©ø^vh°‰ú.ú9U÷K4(Å~`ÑÒOq™þŽÞ ƒ¯A2ø¢ç·„b3±—•Æ-½ˆ¡Š—2<µ7ÝÐŽŠ@àÀÛˆ¶ -bn:I÷K¼ƒ•ŠÃ2¶ä´À'bwŒ±²°ìa:=›†q°†$å"™é„éDl»<õÄÏ÷ „'ØHÆÇJƒ®¼,E+qlǸƒ4¶ÇëñX¯Ø/“I&u$ÓFÖþ›XèK«pá}ÏöKƒ Ük%õ_ 6½¢U0콚K¯È,L%cNŠ4Egåe¦tóQ’P”UŠ˜ÒR}©tUU”U´S7^&ãŒ^JH4Š¡~H ­ýý5!þ­ˆ9ìŒÃÓÓr²PFëX¨CE%¥`®6`‡]KRŠ>ºVʘt=a&ŠÜ_Kß[Ð*±·ø†Ã¶4ôÇi¥±ºÌrd[Y^Fæ‚‚ÜÂ\2>$ÀIÁšäÔyÁTl˜8q¯Lª²ñPKßr95Tíf%.ŒNÎÊHG)Ò½Y©:´|P·½x/bîœX³ŒwRºW­$Q×1î£y6uÊ¥Å/Õ7Ñ…­Ï2ìžF‹s<ÂãìYêÒíÃðGбŒ½©m²¼5ʲ TÞˆ»ú†ÐìS¯¸°¹¥Æƒf—µ¯¼zN³GN¿ ½#Íë7к yU<{Ø-X»Ô‰çï¸>˜ð…ý„ñƒx¶qà¤ÇoÞ<|ôcþ› ÚZë§üý^\#ZqÞ{=j܈ø=Á6¸Û¯Ã ]­=Ù°½fC5*cȨ”Bºõ윴´ÅË]ç’³f“ïýî߃üStË«pQ~lqº¬çWÓŠaÑj¹š—xo4ùq1ר¦¬SK¦—Ýš·Çжd‡ÉÌðzXòlØ=t¡áèMfä+¥ÜA4…·Ü›¿àÙ=v'ØÛMzôVRQâSD¦°*XΡ¦ìš„=O&žLHw³Š?ÃÝÿ쟿«£ ¢Ÿ)Í!™>k§FºJw¥o$üÎÕ¿Ü>÷½FwÝ+‡;Òç ÑK¢¹ŽX æÉ’eÞEúDcÃUõ&t {[ö± „òS¦×•ñ¨4£$©`m±s‰bFÌ^4•weÊÇçø¹ ‘঩+ÁÎ$=I»6L€B¨Ñt?M÷PœCFpÏk‹vJ~P ý3˜y9<{ç6jÞÕx•ÁœÒÅc¡‹32Ú4}í«jØ·swù.$0l?q`³’íÛ®‰¹xR(÷êŽã ¡C‡:Ü{õëÝ{¿ë¶Ñ}ƺ½EªÛÿâ»–š•­o¥éUFHûжx‚Ž6”7_ÞNFÛƒhSúæè-ëË¥¿$`ä©”ãd;B{Býhæù¡j7ä±Ä­Íòï~³†²ó¾û’ôâc8°Š4Ê=GeaÓÝtz‘;b;…h9ÄÄ”}Ùšûod+¯Œu¢¦}4!x'ûCtl©ùæhžÄ“áÏA˜,ýco€±©¬{g/ÖãçZš½Ñ¶BœjfŠLöš–À#Û°ÿìî- ˆ©ßµÚ—Ç7d‚´½ÿÜÎ: »Öø‘ié£ÍúüŠãóÔÞhM”ïÒÈck7¯B ëî…‚c´Ë™vù®¼õ–‚7‘ç î -ÎÓT?23Ó»…RÃÞí›w”îGPMFÝú-QåaƨÓÊj&¿É-¡¿w9?Rͺ»¢€èy³™V¤”ÆœNÆa`‡Ù.u}3X°~ûPk÷Ü ¿?žØwàØ ý¾G@èÉ£ßøR·Ü_p#Ïö§æ–jâÞ—&¡‹GÕAÛc¶ÇnO¿›v:c[úÖÒßo‹¯ -CÌ¢™¾£¾rÞפ.Q–§é“ŒÝ÷¸ÖÞ¾õ®Ç@zûCþ'b¯W(žœ¹Ï£†èúÀk7úÜJFé3ò#+HoU–\…*™ÃgvßUßG§‚‹<óãJÒËÚêâ ÒÛKu11-9ÖX§~ÀºÖ ú“s#KeûU ¶tTšZ¼‰v¸¸ü׿½‡ñg™(;7-Ó7Â)vé,Ví9ÉC-„*å~˜äã Ö6Áû-ë+ÎFÜ=YtEkE+¬”M͸‚fÎu š˜%>OðpZEÍd{Ò·‹P³NWÑÅí§›ÛrÕ ~êD+… 6YŒ_§±~®ˆ¦ñ x®¸"ëÅe÷  “Z¬Èˆ_KòÄLtíþ„¬ùt_{‚vÆwF‚N±„ƒuÓàŽâÛO¬¡Ÿš'韠ì.S|÷1„p0F(J>ÝË£qoÜ÷„OÏ%4ŒÅ#ð‚÷©2¤µ5Ñs¡ ÖÛÃ0l¯˜õén?ÕX¼‰ß­kÖÇntÂý˜ýø -àóhЋՊŠO ÝLã1ø)O§d'”¦•ôˆØKÊ_°”’ï›®3OC¡7ã—Š±ÓkÓÍæ¼S gà¥BÕ:˜ˆYªß¼mwAM~Iª`ÊRuñ W­tWcG%ò ÈŽËMKG‰(A—Q™»7»n -`Èžûᕧ7–H*Ò‹¢ó×DlCõ „äkêöÔ6’¾D»“]ÑÒF„®ÍŽ&J`’ôiNn:¯–Žï«Û²· 2OW‚Ê\ãò -·¢½©ó«šƧ¦%©QBIfMÎîìÍ¡H+1GÞ†¨=ák“£7á±Zh&aO¸”•¶:<6Å¡DÝ7{=ÇëÖ¢5(,^ë»>"-¥Ix,mFôGÎô[QªIÙ²þÒ¢I»Ñ.´£º^¨ªÕ•!Ô*'«UëkÅ1µ$µkkiu'sCÿÿ¶êx¸“`yØÊJ°úL|ÝíXH1á +Š`1`–‘l+I’䜹›$©˜L¥‚q09;:†ë8ã8^ÿ{Õ »\‡yïj.ïï½ÿ[ÿZZPçœÚy{ïƒeaA™™™õ˜?sºóÔŃݴAÞ‘á®!Ás¾œï)m?§Ä^fbo+JTwysÑÆ" §¼W¿?¥èMQæê®äÙ!¤³ôü¦ yRòÀZSŠ”¥0+6»iöÂì·C‡è1±ýàÁC¦…„Æ„iVGhFŒ?^ã£iÛÑ8ù…k‚5È/Q~!¡A~ÁC5 üü4«ý4þÚ@?Í´¹îKgº¹hº¸yh\ü‚ý¼5î‘ÞZÍ­_p¸Ÿ½Æ?$LØú¢ñ öÕFhC‚ÇjÃ5^šðP?-ùÈ/ÚÇ/TÚ¢ õ Ò†‡“ß5ÚpM@˜Wp„Ÿ¯&"D£ ö Œô•Ø“uÿàMhXÙ";„”{HxD¸O˜64BC8º;9·Ê±Ú+Bâ®%ÛšrÒ7Ä'RÒ¦}/ÂK®‰ð‹Žøxûi|µá¡^1„/!¦5Š® 0q¢ ó ð +ó ô 7Ò•¬bÒO#ÓÚ+440ÆømˆñT;mD¸_ ÿP“þÿ¼Ò*+!š9)Z½Â>Z¤(3e_s;vR‡Ž³UË5 f$\( JAÑCu¤:Q–”õ¥¢:S]¨®”5ÅRÝ(ŽêNõ l([ª'õ9Õ›RS<Õ‡êK}Aõ£úS(;j eO ¢†P_RC©aÔpj5’E¦ÆP_Qc©qÔxj5‰úššLM¡(Gj*5r¢¦SΔ 5ƒšIÍ¢fSs(WÊšK¹Só¨ùÔj!åA-¢SK¨¥Ô2j9µ‚ò¤¾¡–HÜbv Ã¬k:273O0o6fAYô¶pµh´ÀŠÅ_ô<úœrž²ˆa˜æRG®£{ǪNã:í°ÔXnµ¢¬¢­^~–¢¢U®ªÛÕË:‹]fuÙÞuq×›Ö¹Ö?°Ù\ö×n1Ý~åzp.\·‡;ÆýÐ= û=Üzœ´am²m;ÛæÛÞïÉ÷ÜÔóÑçñ½½¦õ:Ó{zïýjõY~ Ëß×h¾ïcÓ'¡Ï³¾Ž* ¾áêqqA˜>¹ÙV#½¡`K=Ûœêþ©UÌÀZ0{‚Ƚ «õ%å©%1üHºÂòªÒ È6e¤åÆÆáH›áô²Z’gH)M–ÖÓÛÖ'Ð1©é‰ úôjþŠ­#M ?Òq8L‘¦LÒ§Ôå¨X—_½"m^Ðñ8,7-—P2 ÛrT¢Ë«®$ëOL2L¤×‚5'‘NëÁZ¡®â<èˆ-j­A!Äïè*°×`x‡›2×MC~Õ;ÖoÛ‘r9éZbeææĺøŠu(ˆ™ãêù•š½çˆfìË:œSY’ˆ˜„ôÔ~’2¦$µ¢¼D_­®Tn nŽhÊa°¥i,•o —Ï¢‡èpÌÞÀ!5ëtÓ*Ü QÅëËöJTyBÚÊœ=sô†ú":XWœQŽé[þ‚’R¡OPK¥äFl(õ,dN)Ù9ÕéúD‰½Z•´ö+=Í@¹ÿÙþFòßþ‚dnÆÂ..§\¿zæÌÕ[§y?‹cûü–­ôó]¹ÂïÀÑcû÷7ñ¸‹8B~ðÚMÙA__OéàÑýšx0஼°¨é™Ò4}ª: eåfå¶tÆ*›Ä¬Ì ”¤èSuê|T”W”ϨÀ‡ÄÑt\@Îd£,Û¸òÄJâ=]qi ô‡j7G/š‹³È™”žê„;øâŽÈõÛóÅu¬Øì¯O)EŒ¡ToàQan~N‘3t |‹þDîúí¨ò‹òòQ!cHÕ'«UPpÑ&RÉ)©É<ÊÊËÉϼ‰»î´C˜BšÀ/œ±*'37e1ÉR •¢’’ªm· Ãèˆþ‰Þ­ùÝ,"ö§êS{·`»ÅY¶=”žŸ“—…l“S%ª)ºT]na® ØzMÀÄ9(ÓÖ“:TT¨+}6±….¹0[‡l zIð¢ì⬒ dlm(*.FÛÒÔÒu6JÏÍÌÁ¶«l€Wš\ ‚™‘ÿ¨à`]ÓÈÑ<ž+éösx%ž¡lO˜=éöh#f‡þÿÑì’«9`àÚ³¤e€)×Tñµfp Î7(Äßgð¾”>°sûþ}AÛ}y•õþ3®P—WH,_š¢OQ§ Ì¬ôüÃ_sl²ˆFÄÀ)D?bà¢Â’ +F/ˆÇˆF +s1~ã`Ô °96Ÿ‚)P0RŸ½âÐåêë;›6Õ××B‡P}ô&íΕÕ.h63R‰fǸ­ŒÔj£½ÒÖDÖ5Å\G—"|öËÝE»Î‹Ë$™l›B¤$©Ë/Ì›C6-å˜WFKº–J†»mB +ÌÓ„„¸G°§ þû7è,pʳÇ.ÿñtÏjw óÌ‹1ìÕnhAˆÿòèðÄ äꉺT\\XQyá»Æ눹ÍÍ™GžÑ!_spœè0a*3WÉÞÕß›ü lµŒµ8Cˆ&¼ÄNðˆËÏËÏËC¶ì?…Î2?N¹f§^Œ–ÆùEÅ%Ä´¦–hù¥e;êמAÌ÷ç—Íâ‘Wˆ¯WLTJ\îRÄĦ´y‘½ñúñ̯'O™5œ_€Ԭ؛^”•Ÿ˜”ÔÔ%–'î‰=r4ñ8b@ùëã7<º¾âÂ×»%#B7þ bEüe_s¸ÛY¤ 6L Ýꥷò +㛨KãèÅ +%Ô Ž§ÁþPÔÑDSx$À$â{6Í/p!‹í¼‰NÔõŠPQ~Yñ¡MG óôœëȾ3¦ÙóóÇæåGÒKŒ´¦bREüî¨kNÄ}K4°üÛÏ` ûóß ÿÔ%QRÜÁ \j¥têuŽ®Ó!“Ë­ÉÝ€ôèrÕwÛ¿÷ðè}Tƒª³K3u™…¹EktzCM@å*~š¶h¥ãœÕcf<í VA§×÷ÿÔÛ)O‡«‡÷x¦Øƒ«;b¨ÞP¹{ïÁûsóìÌIcæÏtä]Ð’ÆЧÙz”—±™QåÖŠ‚`ö»GˆIgŠ‡8<º¥”$gʶmC£¢¢¢J+VÚ\ié8EÝšÊ5ê8" +Ô„lAªWl!öµh W¹[{wF™Ÿ'Ü|vöê]þ::é¹mlA*Ê-Ž ά{ýPJf²lZß±o_ÐV·¡žÇàø¢ì¢œd[ŒŠ Šó lò ~ â¬âÔ" °ÔÈC_TX„t¶¨ · ‡ü·É*Î($BY9™Ù¤&Ì'‚™X?ÊPÓÝ„š¢;î÷镸…ˆÑ2â3 2ó³‘mÊÈÊÎÈɶÉÉ&øLê@a†>/µÁä‘š™•‰ÒmIËÎÏÎ˶)È(É*&Âæ0*Wac-°‚ÈKñôw>'õAû=Æ´ä‘!½$)ŸÊ_\n ÇŠñg‡¨ñX%rªvÝ»xï’#ás÷þî]¥¤jòé(779%*Æ;iZŠVW‡jŒ=‹.00Z 6—_¾¸~|étõ +eÿsÈ");!71ó|N\8{ø/A‡MÄJàÎÁvŠ)&+ÀppøÓx©X£À«dÛV4vi‰TÒŸ„šIt3Ø) ÀJMªD“bƒÖ'€‰Ï.Û<’â]ÎCFá<ýâî§<º¶êØØçwo݇N2/ RcƒéT3-`?ü`œòÎÏy®nß|Åc;¼…ƒ8°W^Dõ黣÷EnZ×KÔª8Adj¡“°¦Öú’ v’’1L,äV4έ›‰f ÷užËW­ ™ŽÜ˜qJü9tÆ¡—ú2º¸åxÓÖº²*TÊÒtIêtYéi³—¬sF îd÷¬ø[J°üù5˜«B?,*tË‹+I+CL…Ô‚…’íeêH¥ŠÌ~àGÁü7ÓÊ´¥{З?£„>Àsjj:PO -‘œ _(›Ñ¾ø†Õ½·ÌE‹˜©Ê>£ì«[íú´öw8Ä°ý…?…õû_0ˆIúËú èaê[tUi[n¬#·Èº+Ydc?¼üš?½»¥%Ò“6uBÓ)ˆ£Û¬µk8àe6¹-·IK$éœLï·eFæÛÉt1ºr÷èΫÀ#sïàol4ñ[@;ÀBÿ“ƒB,³©”1êÔ* >½†o¤ñœ¯€ü{J“:“éçëÉ&òíR¸ °•²žèów™QLßý½%r° ÔÔsÆ[•m¤n ¢ŠPzHú#Aº]K¤£Œ»½¬KúÈ=v4ŠßàðF1ð#Wh?þúƒ ÅH £ðŠ6Æd\½A""qbM½Ìö&KÝmñ¡ñ91OÑç#ëÈ9 2…ƒèCù–<…„k%‚ÙIAM4û–ŒÃ˜Çp<òxèMP¥ŒÉ¤_ïŽûðÞÀü‚iÜ÷‚•Xé/A м$?”ÆŠ0_€‚-…@=h ºûòå¸Û}xœNÿï²â, €àñÃ+ \œ§ÍÍ«°R -ô‚µQb6ÎÚêÂ? ‚q ŒÇ Ñ M5Â}žâ.@‡˜e“ž™•ÒãäV€H3w¸ìša'Ú‚*³·¥0lùŽCv%b}·«¶L*”Æ97;p}lzJDiùáz†2D£(—”ÁŸsÿOcø ÛjŒF£1 +9°¡ï¯>âñÅœ5EI =ú„ì›søåî¦cè +ótÜmR³òþwÁ… _*o_ó˜;{âb{ž86¬V,“@î!æ"°ÛÄybç%xV»#¦ï¤£ÈQã»'bgäÞ¤›I·’6fÔÅ1ìÎí±UkÑjÆqºÇPõpäx2ûjne†îý&5if;öîP²;…çÃnŽÜêÙÍ×<:qØ·.¨&D7¹Üµ4L·®Ša·…U%lG»˜«?V?@= çJUî^¾S²ÝåEþªý§”m0Q€ Òl'H…kÂTeœ>¹¬¢XW£ºe¦MàLl‰ì+ƒÊB“q¤ÏÌÞ´æPãSQ‘VmL¡´ŒãGwñÏôˆéÓGt¾ù³~¾ûQ¢Å¤¶ª'§0ýl4(ÀâÇ&׊¹ÄÁµÝÏÒàGZœ]­äS‹c¤ÒÖ~¿…=H³“Mc71Rñ½ìÐ`õ]ôrªî—hPŠýÀ¢¥Ÿâ2ý!¼A_ƒdðEÏo Åfb/…+-Zz-C/exjo:º¡€À $¶mÄÜt’ ï—x%+‡el;Èi NÄî)beaÙÃtz6 ã` IÊ5D2Ó Ó‰ØvyꉟïA N°‘Œ•]yYŠ.VâØŽqil×ã!°^±_&“Lê:I¦ +¬ý7±Ð—Vá.Âûží—¸×2Jê¿AmzD«`Ø{5—^‘Y˜JÆœiŠÎÊË*Léæ£$¡(«1¥¥úR骪(«„i§n¼Lǽ”hCý>@ZûûkBü[s؇§§åd¡ŒÖ±P‡Š +JJÁ\mÀ»–¤}t­”!1ézÂL¸¿,–¾· Uboñ ‡mièÓJcu™åȶ²¼ŒÌ¹…¹d| H €“6‚5É©ó‚7¨Ø0q,â^™Teã= –¾årj¨ÚÍJ\œ•‘ŽR¤{³Ru>*$hù n{ñ^ÄÜ9±fï¤t¯ ,ZI:¢®cÜGólê”K‹_ªo¢ [/žeØ=3æx„;!ÆÙ³þÔ¥Û‡ÿà c{SÛdyk”e¨¼v!ô# + ¡Ù%¦^qasKÍ.k_yõœf~A{Gš×o +tò«xö°#Z°v©Îßqÿ|0á û ãñlãÀIß¼yøèÆü7´µÖOø?û½¸F´â¼÷zÔ¸ñ{‚mp·_‡Aþ*ºZ{²a{͆jTÆQ)…tëÙ9ii‹—»†O%gÍ&ßû:Ü¿ø§è–Wá¢üØâtYÏ7®¦âÕr5/ ðÞhòãb®QMY§–L/»5o¡m9È“™áõ°äÙ°{èBÃÑ›ÌÈWJ¹ƒh +o¹7&~Á³{ì&N°·›ôè­¤¢Ä¦ +0ˆLaU°œCMÙ5 {žL<9˜îf7†»ÿÙ>VG D3>SšC2}ÖNt•îJ'ÞHø,ª¹}î5zîºW7v¤Ï@¢9–Ds±Ì“%˼‹ô‰Æ†«êMè@ö¶ìcå#¦L¯+ãQiFIRÁÚbç?ÄŒ˜½h*ï6Ê”Ïñs"ÁMSW‚Iz’vm˜„P£é~2šî¡8‡Œàž×í”ü ú%f0ór(xöÎmÔ¼«ñ*ƒ9¥‹ÇB5fd´iúÚWÕ°oçîò]H`Ø~âÀf%Û·]s+ð¤PîÕÇAC†u¸÷ê×»÷~5Öm£ûŒu{‹T·ÿÅw-5+[ßJÓ«Œö¡mñm(o¾¼Œ¶ѦôÍÑ[Ö—KIÀÈS)ÇÉv„ö„úÑÌóCÕnÈ+b‰[›åßýf eç}ö%éÅÇpx”L±Nø9-{ÿKÖ6¦Ù79âœûçæ« )3€ó¤ü!^l¨tY¶l¦w“Qàè—¯¼äÅy¸A&d*äµÒù Ö—¤¬%"¹Â ®éÌÀΊO£¿'}`i”{(ŽÊ¦»éô&")vÄv +Ñrˆ‰)û²5÷ßÈV^ëDMûhBðNö‡"èØRóÌÑ*<‰'߃0YúÇÞ bSY÷Î^¬Çϵ4{£m…8ÕÌ™ì5-G¶aÿÙÝ[S¿kµ/oÈ:i{ÿ¹u v­ñ#ÓÒG› ôùÇ穽њ(ߥ‘ÇÖn^…ÖÝ Çh—3íò]yë-n"ÎA&Ü"œ§©~df(¦w ¥† ¼Û7ï(Ý šŒºõ[¢ÊÃŒQ§•9ÔL~“[Bïr~¤šuwEÑóf3­H)9ŒÃÀ4³$\êúf °`ýö Öî¸~<±ïÀ±ú}1Ž€Ð“G¿ñ¥n;¸¿$à>Fž9ìOÍ-ÕĽ/MByÈêÐ {R¯›fž úžà|çW¿HxØ,¿|»¨§ ¥¡‹œv8ŸæÞ|Orv¢ƒýÀI$gÞûÿ¯Ðñ¾ :¼à9·âê“ tt2[bËWà3ŽèÌÎ&…öJ¹0ì-“8wÈk?±úÿF —P‚ÄF Ú}}ïÕ«wÿÉ·:2P°ɉyRÖ2tlJZRbiZ?lzƒ$¼teåÆ&ÇÖÑìpèð¦as#Ú„j“ë"JÒósK$@Õ@Õgèb+ÖmŠÔ£%hYÈбLkOKuí°¾*…¨FÒß;‰·z—ç†ùˆ±Ÿº|«ƒ¶ÇlÝž~7ítƶô­ ¤¿ß_†"˜E3}G}弯I]¢,OÓ'»ïq­½}ë]ôö‡üOÄ^!®P<9sŸG Ñõ×nô7¸•ŒÒgäGVÞ>ª,¹ +U2‡Ï쾫¾NyæÇ•¤—µÕŤ·—êbbZr¬±Ný&€u­ô'æF –Êö«lé¨4 ´xípqù¯zÿãÏ2QvnZ¦o„SìÒY¬Ús’‡ZUÊý0ÉƬm‚÷[ÖWœ¸{²èŠÖŠVX)›šqÍ6.œë41K|žàá´ ŠšÉö¤oÿ f®¢‹ÛO7·åªüÔ&ˆV +Al²¿Nc;ü\MãAð\qEÖ‹Ëî&µX‘¿–䉙èÚý !Xóé¾öíŒïŒb =ë¦ÁÅ·Ÿ>XC?%4OÒ?AÙ \¦ø îcá`,ŒP”|º—?FãÞ¸;î ÝMŸžJh‹Gà9ïSeHkk¢çB¬·‡aØ^1ëÓÝ~ª±y¿[ Ö¬4 ŽÝè„û+0ûñÀ‡fÑ «Ÿº™ÆcðS<ž*NÉN(M'*é ±—”¿`)%ß 6]gž†B%nÆ/b§×¦›Íx§ÎÀK…ªu0³8T¿yÛî‚šü’"TÁ”¥êâ®Zé®ÆŽJä—›–ŽQ‚.£2wovÝ:À=÷Ã+Oo -‘U¤Eç¯-ˆØ†ê  É×Ôí©3l$}‰ +v&»¢9¤]›M:3”À$éÓ6œ>Üt^-ßW·eoAež®•#2¸Æå„oE{%RçW5-ŒOMKR£„’ÌšœÝÙ›C‘VbŽ¼ Q{Âׄ'G!oÂcµÐLÂ,žp)(+;>2luxl8ŠC‰ºoözŽ×­EkPX¼Öw}DZJ“þðXÚ:Œèœ1è·¢*T“²eý¥E“v£]hGu½PU«+C:©UNV«Ö׊cjIj×ÖÒêNæ†þÿmÕñp'Áò°••`õ™øºÛÿïM1¶ endstream endobj 497 0 obj <> stream -xÚZ XSgÖ¾rsk-¶ÆkÁ¶Il«¶ÕºÔ:c;v\jµîû‚¸!K’°„„@6 ‚@B vP@pµÖ¥VÛZÇ®Óvúש¶ÓNcµíçò/ßMA´ÿ<óè4÷~ß9ß{ÎyÏ{>å!!‡ÃyüõõË­_;q¹$yGªr™LºôÅy²¤öÑ+¾'ß“ßSà Ÿ È' ö -ÙÎì¾óÚ†ûA?†?ƒL#ØÏÍâOb,þx6k$Á "8—SÂùsssÚä©3ž[·zÃó'Nz]&W+$qñ*Ñ´W^yE´C-ê}"š/VJ⤢ñøiâ$™â©í‘ ‹ka}ƒq·± Àd3زJtµ:“ÞbÀk—ó@a5ÚJC¸À¾³ÒÕšUl9h fâG…†ƒ]ë6¸¡*lŽr›£ÐÍÔW¼Ûž —à8¤Ý'oJiŒ«\V¾Ø¶Ñ¡¬†&ªs_ÃyÁØŸY”Q"¯Ö6A%T”:\¥v«©VØag-¿)£J0Zrró -ó - -³ŠÃ Efkn¡Ñš 9V*ÉîÓ K~XÀ®uéÜ'8m¶J4Õ„…"7 -ö-º3œN…lƒ*nÃÙÎŒ0A ï -ÃmÙ\žSTKmm“œ–}å’øü 7wÿð! -qTZKÀI5¥ÖJ¡(ï†fáݤ©©r!d[ÍÍe&¤u"ŒƒñIß`Bô‹²)ymj‹ œöº=WQÐ!4 -~‡xóWzTW¦Öw4æ÷|×z8è‚–îliéì”¶Ä -Õd\rr\Ü®äa¨Ïêûvx°oeTƒªN.PN¯•0ý÷«au¾ô”¢^Õ(¨‡rGE;ªõú"¼œ¯¼Hç ö¹CÃuÙ'%‘Õ«a5DfHâ"6È^…©Ô$Lm~µ{C{ܱŒ3pŽU·wtŸlþ®SÌ7?Ó·»>¸r¥ká3†Ã{fËÂùó·|p[ -^*ò£[wFÒLüÚh½.¤áRöÀE…ÕÅßÔ…õ¼8ž—¦ƒYk0dB&hmšrƒÍäʯ -&=PQTº³Âa¯7T+t}©Ñ*j<‰÷÷-ör|°‰h/}퓳ÝM ?}[¿.Q(xêWL¨`%¬NŽ“$¥l‚D*¥.µIPÕÎbwYk¡Õá¬mÜS±¨KÝ1… ÉL0uëŽ 3‹ROû6]ãA½Åž‹ 'NhÔùq½ôMô¾æå_F->>œš&‚¼:³ÍrÈRn©1Íh‰‡XPå(25re¬~,ä’·Æ‘gÍJ–š*Ûø¥~§\‡Ûº:šß†³p1¶{v'ÅÿúÒ¾ÆN8 Ô‡w‹÷m¨^”è¹õ«äµª&¡ ÊKìöÖ=Íe§º|Hº9**v“ã°#íÅ1\s'ˆf'sÏ8îLÔ ó”`x¶adÍl©ÖÔªÁ^ÞþÂ7´þ6a4ó‰^@¹\|ldôþ[yØ‹b1Þ2_5¶â\ÖÒâ -»ÝˆN¶#'æ4ÓI&Ö([v(±–—ª=ìlêý#›æΊŒ}F¸’mÉ Z§©( (¹*U¾æÆv4\ø=œõ>Ö±¯ú$œ¥Ð¨iß3¤ 1Çå°È#±½Åñ-ÄÄ Oé:4âƵ_1+”åUš;PÍuuÍû67¾!œ¯D½ùÊÆ%)³á%x½êµÆȽ ß‘|ïÃñêŽýíU'à …¸¸ñ´`#ˆ3"7R†G7ïî8Ô[‡¶¬Z,Ž^ŠýŒëÔ~ã7¾à&šçù•wª%áþ¾™è/ôùý͇à4åüÃc¨)¯ŽÀúæíç£)þ­%Ñ `%º6B£¯]ýMN.ÙOñd†#}ñp܆ˆ­qK—ní8qâpÇE!ÿÓòÞ‰è›b.ÜÔy¢ûÔþ‹ÂPí-4–=;ã/F'i3bÊô±˜s svjJôVN+•Js4åCá øòàû_ž¸Øø)\ƒ+꿦°¼}&¼ ›2â¢%±ê°šb¸_OùUÐ {« ôˆGË7EÄmjÝö®³—öîWx :b+^Æ÷ø¦>˜qª0ì÷{û¿ 0Ú‰ZiäBáuN»ªÃ¡ÄRš_R` 3»4eY`}~¶¹gæ›Ç$—™Ëòmî‚ʲW¡5¬¨ÔZ -ÅPmpªœ˜FÍ4ãbÂUÙ†lP‡ƒÉj.2ZÂJ²*s\P -eEÎß<Ö3%ç”ä!< 2³su–°|“ÅfPÛ³ëp÷¬Íñ´aÚx½D×­âªÈAô£±iË v“3Ó?â/·Ú$¸Î®·¬2`"}éaL)¬Õ4½kõ“ÃÒÔ»$3¥‡¯ðW_x`o*¡6ó°…Ý´ÓTdÝY.ŠðÒÌ4òs´–šåõMñJ<#Û¼ü©¾5¾ó4ÿòÚÆxÛ\`“™aL(ó²p™„e‚ÑŸª·¶×W7BÕÄò¿²ssrä2€³BmÜŠÿó%¯ð"ï—>ýYІ&m‹Æ¡+VîTZM6£Íè2—³7mÜxË ú -lf;ÅŸÊŠ5>i¶Y§fÁôñ½œ¼¨Åü‘—«Ô‰ÂÇØMå~·“ßÀùºã'»ŽÕ_€«ÔQšÆ„ G˜ñ&¾»6‰µê}oŸöñQïìÕìŠo‘TnƒÍÔlÔÅË’’²Wk=ó.‰‘ß³ ó°­Gyô×&”¬$¨;zµâ²â¡¨Àž×¬ÆâA;Pɘþ€«.‚‡ëzÆÝw~‡•-è…žu¼!I¢·›Ê, @Uôðµd/ËÞMƒ>–åÿâKD“Hh`;‰¾O‚™ôYظdÔÆÎë?ÈŽ¹­ï4*k>M–[߇Վu{š¬é4Îd°ä€"pûFž±qÈiðâ‰=‰ÿÞiîÓ3ûúñÆ×—ØÜ€û±¥x‘ÂÃù‡%`ªz™if¬vhÒÛÍ{ä>µ`ìgöñɶ¢ê*hdf<©ã=¾;Lv¶ä*˜§™ôtYv«ý~{Þ³XZ­n˧zøfÞ ¯±‡Nìaùïx¨·¦¥EcÉÞÈ_:}“¬ƒ²¯›*²úŠ›9M>ö›=üñäPÔÇC§Éõî6á íÆ÷ÛÆ )›·cógî1?€[˜„›?ÓÃ_}ìº/ ­Å\`7ß›ÁlùLaÙ öE{2<#zÑU/ÿSô´/œFØÜë$ -F;¹ÌÁøßQy£©¼€öðñy÷‰>D2O0ÝŒusÉ?RPX€er6¤ååæãòc}Kî*/&•å£^BD“¾GOš0>½Š%¾Ï«^T†áœëÐÈÙ#àþäK'÷×Tµ -Ã9úÁpîaŽL™ïI.Ã#¯ÒÈÓÃÞÃcýý€SãEÿžò}Oã6ð󖬯!üMF“=…f -ᇤO—ž_ß½¸éM\›!?ýu2Ö'A¯L~áùW¿C\òÅwÿd…£×‹–øyGý+Ë;›é’ßA·ûðñÖ=UG¡ ëèiŸ1|“54;ÿMÊHBý>Gúø!hyù`üê5Qñ „Ì06(Ô‹føRøRÐ?µ7˜ î¨ÏïÝ­2Û®/ͱ*€Ò‘QïÇvm>puÿžcð.õË´«Ìh£$ÿS®{áÁ\O"EšBx»·G,‹û£°74_ÞF…·ñ,åkfÇnÜ4.vzHƒQ¯ˆ¯ÝV¶§Î£“gÂêÝëOH[Õ­úK9dWæÕäÔf»Ò!Ú¾*a®`,mÑwø§ïRƒ]Wœ(:¶g±,¿ˆ·µ2m Jwº=ÇSNéÞÂ?uãÃÛB8™q º5©Aìz¹rŽ+ךîH-ÓÖA u¨»í]Á8&·G—&”ú;½ënca;]oôþæEœa?cJAœÉl'Ò÷u¢Ê¾y¾”mëzÊ™u¼Þçþ¾;¨Ù|÷[1ï~ÄVîÇXóàäXÄö_4混ѳ4ó,ºÁ­ÂìlDü\Ì„Žsº+Ým¶çÛ -<€¶ö¤‡ýD¢(_z ”Ú‹ÂÝ%.xq96$Oœú2“ÍÒT}¿'§Ð.ú;f‘ç}黊ÝUÐ>˜ p¾"㙆Ù(û 9›I‹C Ücø@Ž{Z{|ÙÀXQ‘²JÍ®¼ ø$(˜ eëæø|sèÿ‰¸B†j¼(äÆïȃ¿"ÓÍ Xù€FÝg:ëõRƒG·ïæžfF"`®.23Ó9ζCgÞ~… UùUb7ΨywBh†\u~¬{eseÏ,Í·S{È“qûuçà#x»¦ëpבú3p ÞSžÝrxËá55s`lÖl—Pèùú´f·ÈêHI–D¡É%ºÍ@M_~ús!´¹Úš›ÛœÇ±¤ÄV{9oaÍÒéEwi= ‚4È1˜Ób<‘ŽÕ8ŸžÀ<#„å5ë÷G¼ö#\…‹Îž5uX_6³b; ycJZn^†YiÜ‘×=´òÀ—BØëêhllnét€ÃXq7â -(1ìT§ZÍ6³ÍX1Pq³rµ³6/:]j`6 ¯4ƒ1c%··o®\³aMÚ–m[¶)WÁbXT¿ºkk׶·Ó>†s°¯üT(Þ½úànNLÚIwûQkP¸ ûP‹„H”ËšYmÐŽ±k`wÌݵkßâyê(šCïã!t“yžÏ„Œc˜'g"š"¸?WñÔ—•¹ÀC5§ÕÊȶdçOQ*ò¶Àt<2«ÎSE×芷Îu\ÅО¯\ëúzïẋęs}K£‰d-8Yÿ‡Þ1;ɶ¦Ê3‚Ýp,·Ýì´8 -J€j¬©mBÖ-/M´/-Âï=œ²vœYÿëYK¹è[†â=2ù—&^0ð²;Kùuí¬þ«Ø3EßfPƒ¦TëêǬgÖ½˜ E¿Y ×<#xQ0û›ÅQšL±JϱHó33 ’jÕ{ (FϧÞ{cp­/!Œ(ŠÇÿbW{uîÅ Ž™¹ø=oÐk»S«Åìkí•vŒH£]/õ¿ÄNMx ±Éx¯y{Ž`$j“$Ém •1 é†xÕïó?Ø1ŠmÀ¿x×a5È!±6së°P\8‡É98•‡"cF‹Iþ§GO´º»€ºÐ¬Ú$dø§£#¿ªÞ#/æÁ¹ŒƒÑ»êw”o…µ ÑFnékSxȺŒCù¶o=Í<ÇpÇcšÈgû‹¼…F#š!o3c…èo.¯œ;gÁª—^ZpöãO.Ÿ¹.dé ñ¼Èt·#¿GŸŒ>¬9Ç^wݺŽF ú™‘pDi6EQG™w÷̃›õrÍÐVnpôÒÖ¼{È:ì~¹µŠDÏû"éÐfhLoI«Ž…êe3¦/ï¾"€ÖêΖšFO›ý ô–ýtïÈOÑñíf«þ 22ò͹þ Ì–üwöüü]s_ÍÉŠ.!š@ò§þã³½õ­àGn…?ÌuÕTW×,„*“3ÍԘ茇M ÎüÓŠ¾Ü@A˜‚Ø+K´3ÕeÀ& ÒæpbÌ6ôNÖ‰-LÆŒ˜ª¶MìE܌լsÑH¤}Ë\“ç6Õ˳@G©Ö§/¬ƒ¨ri£a—ƕ²VhÆÀÀÀ \s94•Æ*([Q™}Æ ývzüþ–])‡¶Õ'»£Ëæ8–ØÍ…YÅš½ìTÕ1÷ ÁAŒysºßñ/ãá gAÛ]õì>÷ù‹®‘}ÿŽ˜Ù{çdÈÆé!…š>t¸ïÏ‚=L"ù‡+ë)8 Ÿ»×íu;Ë¡k,˜rÀdÉ4lUEæ¬1ÈJ³ËÍ¥;žUBu^ÌVEûJ:©ÙûL,&7¬Uè"€Z!«;.D»qÒ¾èiPí²–†Uâ7aeõöýɭʃº#pZ]ÝG©Èð†²«ùÇbtN£Pšá Dn1y¿ÞÛ7=Ü[$ýªßE¢?1ßroãè[nåïlòă7q}î¼…ÑW˜EÜäßÐõ6+{C>h’™L¦&ßhÒŒö¢3@®þz-%£™—£—¸ÓÉÌK1èÅ°a_Â]öJÆ¿ËL€X¢É(õ¨Û-_3×þïsÄ÷³a -j/àCïê©WË ³TW­[¶ü¸» »**°)»Þv_Sìõ Åp˜qÌ(‰%] ɽ-6˜½kB½¾\æ¼úNØÇË&m¨Â±…,öЙß0€‰]v‹ñ®ô*‰•b‰ÏWÌ-¢×2wÂP°ûõVâ•ÙK.‰2}ËÛúÎÌÞÇî"v·eP‰uêf8£dH¤Ü[XS»Ãí44 l1²*õî<*âb¼éSÓÐd³7¶X=5xÌÞ•ê‘,X±b¾€™É¹Ù˜’ŸÈ®’B²;³5¯1¿Ä2Š™Ë›~Ňmµž]hN¯‘ZeV£ÿÆwN溕-uÍ%n8„c#ÅZäFƒ¬@jIOÃË“kÓÛ/Ÿ?E€°¦[cQk‘›½Û•éNÜ™RdöÏûsyWVœ#!5=Y2OZ‹¥Ùbcÿ+ƒml(ά—ªdæLØŽm,ü%ÿöH~ŽOë#ètЛÒåŠ.°ð·©+(þœ…ïÊ+¢wduÌVi¢>2(y½²IP¶’ÆÖ¦6‡Ý6(7Ô¨)~Îùu{ÓöÁ>ØUÕy¸mŸ#üÿÀšîñ-ò ‘‡ .÷¿Ãº9ìæÃßÙ†¿9üߣþ²Jéô +xÚZ XSgÖ¾rsk-¶Æk¡KmÕ¶Z—ZglÇŽK­Ö¥¸/ˆB€°$! KHdÂ!$!awQQk]jµ­uì:m§ÖvÚi¬¶ýâ\þå» ˆöŸg}‚æÞï;ç{Ï9ïyϧ"$„àp8F®Z1ÍäIÊŽ4å2éòçÈ’cÙG/ù'|Op|OŽ$|‚ Ÿ0Ø7&d;³ûö+·î“üþ 2b?7?Œ?‰qøãéìÑ7ˆà\N)çÎ5ÎS§ÏzfÝê ÏNž<åU™\­Ä'¨D3^zé%ѵ¨ï‰h¡X)‰—Š&â?¤‹“eò±T5U´F,©Ä¢8I²Xôꊕ‘K"‹žY±N´X,+¢“E+Óv$KbDË%1b©Rü¬(N¦%þ"Š‘Ic%*‰Lªœ*š¯E‹”rqŒ/gƈåìƒ)"¹X‘"Q*ñŸE¥(^-U‰cE*™H"IN‹eÍãïãdR•H®áç)ø Þj¥L©RÆ($r•[\¹pQÀGUB´Šµ«”àÇ"Y~3V“Æžfà™*Z"UŠTâLkg‡X+QÊ“£ÕØ.ÞJ®ø]HSJ¤ñw¬O)ÄñÑŠØd±Ò¿/‹Êó‰:Z.OVû×Êüo Ø—¨”â丩wbðŸE%*"œ+2Ñr›-C¾!ÿibRÐb*5;hñgb>ñjðëœå!«ƒÖs¶ÑTWÁÓÙ‚àñ1‚xˆE|å‘ÍüðÈ¿FWðçð/És…Î6ö«G7‡=f +Ÿ~í±‰}üxúÓž¸ôäÊ'ÿ&H +…gEωŠE¿…2£ nÏY´ŠóÛ­?]¸Œnùþ‡†¦Â2³ÝP©±g´F}Ž)×b9•Ê›¥]¹ ^—O­û)ãCmØ[¹ ™@mJ\*X ë»Í&›Á–]ª ¬Õ™ô^Á…ÕPbph« ÕàûÎ*W[v‰å šJ v­Ûà†J¨´9*lŽ"´P_òny.\‚¯ávŸ¼9µ)¾êŠ¥®°e 4S]ûÏ Àþ¬âÌRy¶ª ²Ìá*³[ÐDµñÀ; mÍ™Õr0€Ñ’›—_”_TX”]f(6[óŠŒÖ<ȵR¡Hv;˜^ÄX +rÁæp­Kç8Ái³U¡q¨6,¹Qp°oÉí‘täTñ Îvf ˆ€ êdxWnëæŠÜ Zëꚅഔꫡ¤àg¸±û‡Pˆ£ÊZ +Nª9­N*EYx74ï&MK“ !Çjvh.3!m“aLLžü¢×XÌCÉëÒZuà´×﹊‚¡1ð  xÄ[ˆ¸Ò£ºr%°¾£Ç~Ïw­‡ƒ.hé®ÖÖ®.ikœPMƧ¤ÄÇïJé†ú¬¾ßh‡ûVN5ªêåèôZ óá¿fPèAO)TM‚¨pTvP¡Z¯/ÒËùÒ‹tÞ`Ÿ 14|+û<ò¤¤3ªf5¬†¨LI|äÙË0šÂƒé-/÷lèˆ?–yÎÀ±šŽÎž“-ŸÃ·óõÏô­î÷¯\é^ü”€áðžÚ²xáÂ-ïß„‚—ƒŠ½ÁèæíÑ4“°6F¯Ëi¸Ôƒ=p@qQMÉ×õa½ÏO䥂©Ð`Ö YZ›¦Â`3¹ +êB§IT—í¬tØ«À UÆJC_f´ÊšHâý}K½ß$l"ÆK_ûølOsãOß4ì…K +žþ%*X «3bâ%É©› ‰J­OkÔB³Ä]ÞVdu8ëšöTîêROìF!H²Ò&Mߺ#SÃÌa„Ôxߦk†âß\“¸Þ D× 1h쵫¿ àBâÉeû)þÌH$£/Žß¹5~ùò­'Nî¼(äßdZBÞ=³1rSÜâÅ›ºNôœÚQª½‰Æ±gç `â¥è$­bFM›9s`^QîNM©ÞjÀi¥RÉb¦~ ¼_|ï‹›>kpEý×Ô£â÷#:fÃë°)3>F§Þ«)†ûÕ´_=°·æØ Jx´|Sdüv Ömï>{iïþw„— 3®òE|poúý§#À~¿wàû¸¡¨F.^ï´;¡&J-e¥…Ö0³KSž FÐä˜{0 a¾LJ¹¹¼Àá.¨*/uYÊˬeP5§Ê‰ñgÔB3.&\•cÈu8˜¬æbS‘%¬4»*×eP^ì,õ-@ a½ PJnin±³!+'OWh +0YL`µ=§'xÏzÑ gÜýçwXYÑ‚žë]Ç–$z»©ÜÒTe/_Kö±ì4ègYþ/¾$4…„F¶“èû%˜IŸAFm`ì¼qðì˜ÛúO£²æâÓd»õ§qXíX'±§iÄšÎ1HÓéLK.(§±oäù‡/žÜ›ôïæ=#©¿b|}™ÍÝI¸{Pª)<œxQ"¦ªç‘™fÆi‡÷ ½Ý(°‡îQ †À~fŸl/®©†Ö!f&’ +0Þå»ÃdgK®’Ï$¢ñ•dØ­ö{íy×biº½€êå›yC¾Æ:±‡¿ã¡Þš +”#ûj s|ô ²Ê½nªÌî/næ4y_Øoôò'’ÃeP?&×¹Û…C¶›8`7¤$lÞŽÍŸ¹Ëü naïoþL/õ=h°/ê¾d´gp¡Ý|w³å3Ib3ØãÉôŒ>èEW½üOÐx_8F0;¹ß’(íä2~Gå¢òÚÃÇçÝ#úLÉ<Îô0ÔÃe8$ÿHaQ!–É9žŸW€Ëõ-¥/ª¼Ø4–ú=Mú.=iÂøô)–„~<¯zQ9†s¾O@#g¯€û“/ƒÜ_[Ý& +çØûù‡9B2å¾'¸ ü½J#ÿMû=ô÷N­ý {xÊ÷=ÛÀ#Ì“X²¾‚ðO4MA|ô$š-„’?Y~~}ÏÒæ×qm†üôשXŸ½4õ¹g_þqQÈçßý“Ž^/Zæçõ¯,ïl¦ÿI~=îÃÇÛöT…n¬£g|ÊðLöðìü7)#qe `ø é㇠äåƒ «×D',2#Ø  P/šåwJáwJAÿ@Ô^g‚zž£>»{·ª»¾,תJGF¿×½ùÀÕý{ŽÁ;Ô/3®2cŒ’üO¹î¹ûs]‰!h +á]ìNÚùFü…}¡ùâ*º…g)_ ;vã¦it±ÓCŒzEBݶò8už:w¢Vï^BÚ¦nÓ_Ê}?§*¿6·.Ç•éÔöU‰óK`y«¾Ó?}—캒ì@ѱ=‹eù%¼­Ué{UP¶Óí9žzJ÷&vøÉëÜÂÉÌ1mÉb׋Uó\yÖ GZ¹¶j©C=íï.À1¹=¦,  Ìßé]w Ûéú*à ÷7/âà ûS +âLe;‘¾¿UõÏóelk\×[Á¬ãõ=÷÷Ý!Íæ»ßzùKy÷"¶ +?Æšû'ǶŸøb0¿½…ž¦™§ÑunÍ0fg#âçb&|hœ3\n³½ÀVè´µ7#ì'Eû2j¡¬È^î.uyÀ3„Ë™°ayâÔ—›l–f <9…vÑß1»¸(ˆ<ïËØU⮆æð¡õèýóí™À4ÎEéܧȹLz|ì3:-8ËŽ2úUÃÚsV /ô »“ºSýB\›ÑÞoû£· GoªoÛåÆ¥Á<6a΄ý< =&< ‡*»;¨µ¼ q‰«XÌÜc 5úy…ˆóÅg¿ +ÑíªûÇg#œEúöÊy¯._9wîç>¼záÜÇBV•éí“ähÃ@ýY yƒõîú3³õ7äé½âç”áøcÂ2£eä™ÓuΣ°jòÜÙîì9 ¡˜¹¬ºö[4$÷×sÈ0u=p3ZNz¾;N°¶fÄìèˆÏ¤hÄ,/ÿ;¬·—ÐÌ"Œ›ñqĸ}Êè™ÐûËZôãý/ñ:þlŸ‡fFŒGQ¢÷ŽnGK'±·~Ih6]íº9=G—¯‡ìðÀX?§fŽ¡I$™ñT6ânK¿>¢îüò… ÁQɵûqÊÞipfSü¯æ,ç¢oŠw_Êä_DšxÁàËì,å×µs®bCXÌý›i@ š2­k³Þ9wc6Dý>f\KôŒ>àEÁìoþq4Gi*iÄ*=×"-ÈÊ„TH®Sï-¤=Oœv÷Áµþ„4 + hÿó]5å¸7:reBæâ÷¼!¯íN«³¯utVÙ1"Mv½Ôÿ;5á-ÄB$ã}´æ­y‚¤M–¤´'VÅB +ddÔ€Ïÿ`Ç(þ´;üü‡Õ ‡¤º¬}¬ÃþAqhá&çÐTŽŒ-%ùŸ=ÑæîêB‹j“YäŸNpŒŽÿ>¤úŽ¼”ç2ÆìJlØQ±Ö‚Dµ¥¿Má!ë2å[¾õ4ó Èiv,"ŸFì/ò&‹h†¼ÅŒN¢¿¾¼rþ¼E«^xaÑÙ>¾|æ[!KOˆçE¦;ù]údÌaÍ9öºëæ·h¢Ÿú‘ ߀hͦhêH óîœyh³ŽÐ oåGm-¸‹¬Éî—[«Hô¬/Š>톦ŒÖôš8H¤^{#rÖ̈ž+h«éj­mò´ÛB_ÙÏôŽþmñßn¶ê'³ ³ÀœçÏà¡lÉ{ÏÿÇßµ÷Ôœ¬è¢I$ú?>ÝÛÐ.päUêðÃ<PÍõõ-B¨69ÓÝÉMIÎØâ¬?­èÉu„Y!ˆ½ò¸D;Ó\lªl'ÖÁlCïâaM‘$ЂÁdÌŒ­ÞaÛÄ^ÄÍZý'!Ì9ƒDÚ7͵ùnS­±"t”j}Æ2Á:ˆ®6vi\©,`…f ܉¼À5—CSe¬† +°—Û÷gžÐŸa§ÇïÏa¹Ñzh[CŠ;¦|žc™Ý\”]¢)ÕÛÁNUsŸĘ·dø/õ¢Ç<Dâ,Hd»ë’þ€Ýã>É5²ÿß³úîœ 9Ø#=¤R3‡÷Y°‡I"ÿpe="'á3÷ñú½ng4` €S.˜,Y†­ª¨Üõ YYN…¹ÌbdzJ¨Î‹ÙŠã¯È`_Y âÃ'5{¿‰¥ä†µ +]$P+dõÇ…h7NÚ¡=ª]Öò¢°*ü&¬¬Ù¾?¥MyPwNC›«ç(õÞpÖa5ÿ8ŒÎiJ3”Ä-!ïÕ{û§‡»‹d@õ»Hô'æî-ü}íúM¿ÿ&²ß7Ñú +³„{üú¶ÝÊÞ„™d¦’é )0št£†½è «¿^ËÈæùôw&¹‚y!=ß6ìK¸Ë>XÉøw™† °K4Y€¥u‡å+æÛ°ïûñ=€ðl†‚:ŠùзzúàÕ2È*ÓÕè""Ã"Ž»Ëñ±«Ã¡›²ëm÷4Å^ß 1 'Œ™ÀŒ‘X2ÔÒ×bƒÙk°!4è+dΫo‡}¡0i3AŽ-d³×€Î‚ÆALì²;XŒweTK¬K|¾ `^1½–!¸“†ƒ= ·’†©Ì\òH”å‹hï?3{g¸ƒØ–A%Õ«˜‘Œ’!‘roQm5ì²Ó Ò4¸ÅȪջó©PT„‹ñ†OMC³ÍÞRÔjõÔâ1{WšG²hÅŠ…f6äfcjA»J +)ü¦‚RÈ(f>oáù´×yv  %£Vj•Yþß<8™çV¶Ö·”ºá6R‚”hi ²B©%#/O©Ëè¸|þüÂ6šKmMÅmÅnöþmW–;igj±Ù?ïÏç]YqþµÄ´ŒÈ<é­–‹ý¯ ¶±¡$«Aª’™³`;¶±ø—‚[£ù¹>­ 3@oÊ+uº\ÀÂߦ®¤øó¿#¯ŒÜ‘Õ±[¥IúLȤä ÊfA5ØJ›ÚšÛvØ ÂP«¦ø¹ç×íMßû`Wu×áö}6vŒðÿGh†Ç·ÄƒF{<R0"¸|ÂÿŽ|àƈ~g9òÆȇ|?Žù?Dàéñ endstream endobj 499 0 obj <> stream xÚ­x T׶v1Tu!8[@ÇVp@Aq DDdž•Iæ¡™¡A‰C®yû^£Æy@PF™AdTfDœ0q$jŒ ×x=Õ}Þ -½w%ÿ]o­·Þ{«EõªÚç|gïo{ŸV¡ÔÕ);/» ŽÆîI kCdóSCâ¤aÂ#÷éc(õ½†zÿºÑìW6H4îKØPšŸJñ~š*?]çÔwh©N£(• ‰äJ½/\&W]r¯™D©«¨ÐÖ¾ MšÙJ£¤©ÒŒˆpýðÔý°Ä¤-)Ò¨èT}Ã0#ýEf Íæ“ËB}ûÄĨ¸ýÕ‰)I‰)!©ÒÄS¨¾€Tÿ#Ò}'kkÑ*šÔX•Ï(‰ê µ9ªÆê ™åÔ*qÁP"J‹G§¦RÓ¨é”5“šEͦ ¨¹”!eD™Pó)SjeF-¢SK¨¥Ô2êsÊœ² l¨Õ”-µ†²£ì)Ê‘r¢œ)Ê•r£Ü)Ê“ò¢ÖRÞ”µŽZOm |)?ÊŸ -¤–«R*Ô,UkÕ Õ$ÕBµqj&jkÔÂÕJÕW«_¡mè8F…ùœÙÊbÞ‰¾ýÊžÓ£qYãéû1;Æü®9U³Q+DëÎØäqºãNr® CM'®žøaÒÆIÿ˜|rŠÕ”Üî87¬m¢­}[çs:IõëÈGB_ä$ -'ùcr#N“(ª9‰ú ùX þL4NÂlÐÍÂ+ؘ¹MÞ£‘ £ËqÞXMì²VÈ¥-LpŒŽO Ö6º ‰ôàÞ‘‡gs {Êê*j«sëEÅÆÓ1Ã#Ý/ÍW‘˜œ˜—M`Du -0y”óCÎã¢ÞòÚòÚšœºQ&ÿ„ÑôgRƒ˜?Áðí 0ºŒÆR¶±´¦¾´»¬»ðNÎÓœgGÀvœ„§Ih[® .l+L(Š? - üK馸MqI‰ÑÉÑÉ.‘¦Þ÷’îÃCÈ©®i;s Xœ-Á‹9ðÌ ªÛX›Ö ·¡ùðÅìš3UE•¥•¥=UOêQ·rîJ7§PŸ4Ÿ´µYžÀ*ŒL—-êwîwþ)©Ã <>P4Pt¯ña?ÒÀº(ÁAè,‹4^£éýh¡[2þx¼£á2|žë¶^.l.h*¨-*ªÈ©Î­>Ò-ð<á–g«G«e¾!` 0±µ·uŒ^X…ã²Ù7±*ži?ÇÖ}µûªøe`ÈŽS(ùcr=N©ƒfð:ügh¦ò3~*ž¡œª㙢qòÉí¼”ãS™2´ˆVʘqü‰‹w9J>q:ãÜÎóP' Δ«F(ßY°åTÆ©ÔC Û’ãã3‰7Ùÿ¡Z¢`8ˆ9”rzËG«‹Äª°¸ äx54³7c˦@䶤¸¤OË(”Š<ô‡ŒEÃ;Ð#ù^D##ш±RF‰ÈS4Yþ–S˜ ½FyIÜÍ$wƒ±ü4’"…1oA¿!¼ŒÆF"ùv¥ˆ'QO–·ñ\§2‚FV v!¹Dcf¸f4—<ô5Aó)ÈŒSNgÐ4tä´¨°«¸+¿+¯{fc“X“0M½G~DÈC¥&ƒ{[>ŒAV€$5C‡]Fj€fÀ@zoHkX‹G¥U{Xô>ûqmW_W_Ñø™E©x6RǦãçà ÷Ž`DQÌk¸•Q/­‹Î]vðyœ£«Ÿ«Ÿ¹l!šÞ°=‡X¾ŽFYÌ+¸“~)¤9,ϬÀ(v¥Ó:'ŸIx,°Ê6z1÷3¼J}xÍÐÓŠÙ¬xàϱ¦%ó1³ϳÅFÑx`ÀÖ XòÒðå\4Ù-…èÝßr¨åPû‰Î–8‹Ðßl -˜…•Îw¿‹} h" ¹HÒŠ&µ¡ ¯_ô½ìû½±Ú[BOQ¨p€Öú#ã·&¿aýKØ…$ÙëO¾Bï´IÒ¾CÆoïn!1åÈ ;ür8ÃË´O¢¾ŸFv Ão‘7WÝ´)Ã*€g‘‘„§±ñÁj+–¸¸ã1qx*YZáŽh#¹Íç3%h>­Ìc*_Ló}L1ù:,û€€Œ‘÷Èr1Ø„FµŒ±ÒÃ6yiælãñ`Ra7`? %›œ h^>’\FcɸóúåWý/C4‡¾]]W2Ú7_N½ŽLtíŠìríÙ³9¸ðÀâP¬µkYÌÇ"<ÇJñç€í¯jÆŸý:ï1šælM¤Ÿ‡f_b‘©Ü_¯¸¥zG9iÉ`ñ°*=lÈ ©ÒØꟾ³bÜ––2xÖ°­@é4E¶6~'¿.Ÿ,ŸHãfØcØËýþl4‘†lN׌Ç^ÂcÄÍX«k6á±ÄqAO“˘RdJ+{T$¡%‚5)8ÕrsâRF"¡'ј-â°ÎF¹G9ãöÏ•ÓXdàŽQÈÙÌð\ v¡w2ØH¢~Æ{ÿ¹< ¦—BçHóÑþƒâã?º¾¿‰ý–ÌNgKÔeÚ¨gÔÜœÁ6Éx¬ OMÇFâ=Œ2H¢ÞIc‡?Lc-o(D:yH?Í`ø` ^.xŽ Ø¥Ð#œs@3Lß™¾ÃS. N×<)«YbuËÅXÝ‹—¶ìЄõ_¾ž‹Ä¾h% Y$àÕHå‹Tîÿ€T»ÑÌn4£ˆä²g•e¼G’úYdïª^ëó³IŒÏMÅSðX2\L-¿p6‹!±W‡E•Nw¾‹y„·Èà,×#-¶i]ûy°°ÿUÙûÑ$éHè¥ÿ6çœ4,Þˆµ‚ðXWS  Ó˜™ÿÍ9‰Ï Jǃ4JdpR …-hâ‡Wh™˜ü5 o@)ÿ ÿ°'IÀÔÿÆsü{ígP„ò=ܼK>}ÝÆ£y€¶‰Ñ^l„ÆáKÓñÀ¸Gø4ƒCÌ liˆ¬‹:ë 0#Ú‚t¯^†‰˜#è-™C«‘û ô˜Ðñ˜Â€·ä ugã–šŒ É•Ñ¥ÒRÇ£î5ΧœM9»å\V^VþžóP -zÛÛîœ}l\Úݾ­}[sz]Êu4O×å¼{Žç±µÇ\8Žê¾xÅbË ¥‰`•íPãUåukí×kŸëeáa§a= ‹cí\6¸ø.MÁ`MRÝ 1ÕÁb+Qcêå­­_¶íìùê6R¯[ýêÞÏ÷‘ -‘z‚y?¿U•Hh=š7!jcLÄ31ؘæç1¸X¢x*°4ZBïíÞHb†Œ¸%þ;{ˆ]<%`̃ÕgýêüdWá>´ì9q­UŒ×^öQÝúÅ.ð!Ñ®œ{×î®b¢Ñ|@怴kþá—'}H»­&@>ð2äËý…W»‘Z&Ò™§X&Ì–FÑ玦ÛZF)Yì€9L‡‹Iªß’¨ÿ¬-7}êÄ(uF&F. Âc|I.îdþ:C{‡öü],¢±£4~¿Ñt=žâ—‘T=øaßSèûúGÝ8…XPŽ¡'ÒÐ'_Š,y•smç:Î\>ÕÄ``Þ¾ùûÍšG|uÇ)Nðeò ÛËwFhçˆÖT6ÐÈšA4_%)æÓØGàÝùdÅg ¤æ掦X“ žX°(a«c«ã˜W$,€&}4Ñ|¢0ɘ”y1ƒ¶+Ñx2〭é,&©'²É¿Ä¿Ìû¤á×ÈÎ ‚²ãªâ*·vÂ÷€TN½+{Sö¦ñþ•Îîξ¢›pšÓ+C+C³}HY6L7 ›Ë†­·pvsvuŽs-»Ù|m:÷^–>îtýÚËz4¦ižEDô‰’_¬»¾îºMé|p×-înQnž®–ìNR£Dy¿~šý$M(CK…,Àƒù¯4šÈÜBVôa&Ï£2°IzIÚ‘ÑGZe7E:‡4»Wbc²iõŒÑs£ ­Öúxú¸%9ÂX—QUµ¹“”ð¡ì75¿TýÒú°¿÷zo_É5¡<šòûÒ¹!x™3XË¢Y¢Ð-![ƒ3ƒ37îö‡àvnccPcZ?<§ß”½¬ø©éNÏ¥«-7ò¾ƒë0ñPÊ6¢KÊž2#eRæÅ.v]êl·ÄÓd¤Â)è—vŜ۶·m‡¢ÈÞGCâö–› b—;Y89™ùcM!nÚ2߬ũÅIˆ[/\9Õ]Þ]ÞÛÝ?H"—&DNAƒf --˜X±ÙrÛ‚¬Ùâ/O4y~ï¨hx¤sXÓý{DüTO¿/{[ñ[Ãý®¶ÎŽÞ‚~¸ -›+Â+ÂO¯…U0'Ý0˜„ÍÒÁÅ„ÍEðÇW|V:×­šŽ6iÏé-bÑ‘c¬wZÐŽ;‚÷„ÀRpÎ k -¹”~ž}óP·”A¡€•!µ›HíFûÏ€´àArφú uV¹` c—;/wv\è‹?̦`-Ai0W>÷– {Ëæ—(4žQO‘Ƶ@ÕŽ¼Ôs©Gã!¬Ã<—‡†5Ò± °;+Ôž]í½Ò{íüMSÎÍRfq?Âí¢¶®¶®š—ùhÚ¦ÔE_2yh2w’TöÓ¼î’RqqIýÉ.¸õ_^Þ|qº›Å -ÿ6ü`ì7I _$ù¬õö 1‰ÃâÔ¹º8Ô1ÓF> NéÏ°JóH -'…†oÚ±y0ø‹gˆ*·×în\uDñDñˆSŠ˜ Ç6\x„ZšaFŽgxó+)-‹­Ýä–'•J3Â!Ö凶$±úQ+‚ü7øo¹Š.ª\3à?àûw™kM+ûµÿ×þæ×@|ó$©Ï»Î§nIKV×8²?ö`ÚaqÚ·YÙP- u¯Ê³¿*Ü[I$~¯º÷Ýýï«ÿ.ti׶·&]@QçtGò$8˜ƒîœËk/Ö^-zx --ÞªûlçÕŒ -Y…ìt „‚•ÔÝ>Ä.Ødi˜—Ó‰àâàâ´ p™EçåÿÉAç‘–Ü朦óUUù5…õÇZ j·%%œoðÊòI÷OóO O ܾØur"¾(¾xÛEèüÈ÷xmdÉÜFwšPj>âNÜü¶ƒÄãGÙ€&ÿ&ûsKÀœ·¸G»F»y¸,g³˜Ó7Nöë:Þu¬ãHËѶ£-‡/½|¤õhû´À’âãsÿQò¢î®¸öûKÕÕ]gº}Óìg¨I{6îp!ç²S(]e -JG,3GѨLBoÄJ%'²­¹» - òÍËÍ;r*Ù+ ÅÓ¥¸cSê&YVD -sà©„k?Áíü–¶Ö–ªÎ!‘íµ.IA|J‚ ð´µöæ ‡ðƒ¡£©Ø~A Ÿ(¹üa±¼[Ìëÿ[L± ò¤P?-CºUh âø·£Õî㶭˜Ç¼2!ÅeÜÜ$×à¥|a»iÚèɨ<ý>LH SÈ]ÿà÷æüZü¤æ–¸úNC[k5ùd·A3TfæÊÎ%ˆ¸Û/Ó;è -Êlù’¯@½ž¥^¬¨w:» Á)Ý)Ì)ÔÍÕËœÝÅì¾'»z1ô¢g®5¸{†W´g´§—§%û%“‹‚h¬÷ÉïBÀsߟ~á;qÍ݆ζš–šö3p Ê3s’s’G‘Ãñ§°}¢ 0‹@èÿö -´Ša0¥Ï¿Á·Ñ‘@ #Ã#Æ]êêélñ_¬Sò“@Œ»„551ˆºdž#}ÒQ)„@ÒnÿL;aírÅk"ÅfñæîæNKý°šV— =ÎdÀ:³¬¬‹@Sà¼*~|õñÕ¾§MHŒsH“œøX@:‘ïl¾·¹;·ŠX°(K9‹#µwÛìØEñ ƒì¼ý¼ý\dv`IJIHcpÓ&"šðáä›’Ï?«¿ÙÕÜÙÜ—7ìmè”]¨õÏq«?•ÎG}BélJ瘳$ÃÉi$¿\wmÝõÕ%f‚Ìà +±&6&‘ÈG£nx.‘÷Ѥ±¼^V!×Åßsöo§¾©Ò≠W4Ç4Çü_TN!Hé?ˆóbÍ–;9-ðÃZþXK&¬‰j䛵9·8Þ}× çô•Š+=]½H‹Å›W퉟£LÕ%0Ñs ³„ÆG;‘L&åjT£Y@©÷)átìM:‘3Ò„”ÿVþ¦á~wGwgoa?ôÁeÒ„T„žö&hg§Ï ›:o¥“›“›sœ›P%Zä» ÂˆØ%ݽ5fS\R\bX ¿Ë¿“æÿÙÏŠŒ&Gc{KM[MÇ™«På)ßYAÚfé¡°ý‚è«ÈeèvUm+ÙV–Z[_´¾Ì¶fU­_™¬ µ`G TBÃéÊòâòÂæ=ðînïO`;RÚдÍX53¤UP…E‰k¼¤«`8Ÿö®¨¸ðÌïÞÆËQg“Ï&…X¿)88&8Æ%ãs`Á÷[Ÿ>'|s -Y¼Hô"p(•œºÑgð{Ñ@÷Ý®ÊGð;Ù° ¯‡4¸hH:¼ùÌæ3_,ÅêŽvÒEù„#¤80íh?mÄà‰x3v]±ÝFè-ñdåÛk÷øB,s=êÃ뮥Â(ØWz°ô`á·g±ˆydøïŒüÔÞ­'ÕO¦9ÃæÛlv{B¨–žsllèO}Bš—ž“ݥݥ½]}ƒìQÒ¼6/[1¶`æ*SgÆ, ¶[ûzy…‘Oº°F~M¯õ ô@ãÑnâk;D›þGÁÆŽÁ÷•CÑÎxÂ2ìLÚk¸¹ ÝŠ¬y¹.‘;r”h–ßÑF! ¿ïÓûöÊÙúxoäâÈEI6›½Ø=ÌßjéVô~ýì/H=’¡KZzÜ4¬áŽuõãÌÉœûíû Þ°?Š¶ð/„Ó÷ET'WDž—Ðú6c`ý_½öRDñQ¼‡¼•v‡ð~¾÷ç+h¼ŽèµÒ Ûðf£-ü.e¡2QÙC£õ ÙÔâ6d1òv%–D:Fø†KÅ1Þ°‚„eñTQýöÆÝM¤çȽZO>zHî"¡Uu?:á )룭ÅÑÖ ©žd[о÷ΞŸv?ßscwÃ*¾–œ!fÈí´óÐDZYÈÈ-åwŠ>=lÀ$á‰4/c††_§b Zøu´Š N‚”HOª‹Æ¥ŸQ<:ŽÞýÂ(³@4}ŒŠÚ¤ - ¾hÊÿüjà +½w%ÿ]o­·Þ{«EõªÚç|gïo{ŸV¡ÔÕ)O{?[;c÷¤ˆ„µ! ²ùŽ©!qÒ0á‘ûô1”ú^C=€Ýh‰Fö+$÷%l(ÍO¥x‰ +?M•Ÿ®Æsê;´T§Q”JÐDr¥ÞŽ®„«.¹ˆ×L¢ÔUThkß…¦ Íl¥QÒTiFD¸~xHjˆ~XbÒ–iTtª¾a˜‘þ"³…fóÉe¡‰¾}bbT\„þêÄ”¤Ä”Tib‚©T_@ªÿ鿾“µµhMj¬Êg”Du†ÚUcõ…Ìrj•8€€`(¥E£ÆSS©iÔtJšIÍ¢fSÔ\Ê2¢L¨ù”)µ€2£Q‹©%ÔRjõ9eNYP6ÔjÊ–ZCÙQö”åH9QΔ åJ¹Qî”åIyQk)oʇZG­§6P¾”åORËU)j–Šªµjj’j¡Ú85µ5jáj¥ê«Õ¯Ð6t£Â|Île1ïD_ˆ~eÏiŒÑ¸¬ñtŒý˜c~לªÙ¨¢uglò8Ýq§ÆwLX9aׄ¡‰¦WOü0iã¤L>9ÅjÊnwœÖ6ÑÎÖ¾­ó¹ÎF$‰úuä#¡/r…“ü1¹ §IÕœDý…|¬&'a6HèfálÌŒÜ&ïÑÈ„QˆåǸ +o¬¦vY+d‹Ò&8FG‡§kÝ…DzpïÈÃ3ƒ¹ƒ…=euµÕ¹õÀ¢¿bcž§ßk +kô8g+Á!Åkƒ×†À•1Ò93«Á¼36|/øu¦ @'´œl*cJ.4”^)ë*8ó4÷éáp›I–§qw>Øã•iŸé˜á‘î—æ+‹HLNLŠËŒ&0¢:Ž<Êù!çqQoymymMNÝ( “Âhú3 ©AÌŸ`øv]Fc)ÛXZS_Ú]Ö]x'çiγ#à;NBÈÓ$´-׶&Å… þ¥tSܦ¸¤Äèäèd—HÓï{I÷á! dwV×T×´¹,ΖàÅœ xæÕm¬Më„ÛÐ|øbvÍ™ª¢ŠÊÒÊÒžª'õ¨[¹Fw¥›S¨OšOÚÚ,O`•FHƦËõ;÷;ÿ‹Ôá ((º×ø°i` ]Èà tE¯Ñô~´PŒ-<ÞÑp™ >Ï‹uÛ +/64Ô UäTçVi€xžp˳գÕ2ß°˜ÆØÚÛ:F/¬Â‚qÙì›XÏ´Ÿcë¾Ú}Uü20dÇ)”ü1¹§ÔA3xþ34Sù?ÏPNUŠñLÑ8ùäv^Êñ©LZD+eÌ8þÄÅ»H%ŸÎ8qnçy¨‡Š“ç JŽÕ@#”ï,Ør*ãTê¡€ˆmÉq‰ñ™Ä›ìÿÐ -Q0ÄJ9½å£ÕEbUX\Pr¼šÙ›±åNÓ r[R\Ò§eJEúŠCÆ¢áè‘|/¢‘‘hÄX)£Dä)š,Ë)LÞˆ £¼¤Nîf’;áÁX~I‘˜· ß ^Fc#‘|»RD“¨'ËÛø®SA#+»\¢± 3\3šKž úš ùdÆ)§3h:òZTØUܕߕ׽3‡±ÆI¬I˜¦Þ#?"ä¡R“Á=‚-Æ +@’š¡‡C.#5@3` ½7¤5¬Å£Ò*‡=,zŸý¸¶«¯«¯èüÌ¢T<©ã Óñóa†{G0¢(æ5Üʨ—ÖEç®;ø<ÎÑÕÏÕÏ\6‹MoØžC,_G£,æÜI¿Ò–çV`»Òi“Ï‚$<Xå + ½˜û^¥¾ ¼‰fèÎiÅlÖ<ðgáXÓ’Œù˜YƒçÙb£h¼ ° `ë,yiør.šì‹–Âôîo9Ôr¨ýDgKœŽÇEèo6ÌÀÂJ绎ßž4ÐÜ$iE“ÚЄ×/ú^öý^‚Xí-¡§(T8@ký‘ñ[“ß°þ%ìB’ìõ'_¡÷ Z Ȥiß!ã·w·˜Œrd +Ȇ~9œÀáe Ú'QßO#;‰á·È›«nÚ”aÀ³ÈHÂSˆØø`µK \ Üñ˜8<•,­ðGG´‘Ž\æó™4ŸVæ1H•/¦ù>¦˜|–}@@ÆÈ{ä¹lB£ZÆXéa›¼4s6ˆñx0©°°’MN4/I.£±dÜyýòÆ«þ¿—!šˆCß®®Œ+í›/§^G&ºvEv¹öÇìŽÙ\x`q(ÖZŽµ,æc‘žc ¥øsÀö€W5ãÏ~÷ÆMóG¶€¦ÒÏC³/±ÈTî/€ŠWÜÒF½£œ´d°xX•6dȆTilõOßY1È@nKË }Þí‘OV q†°@jî`îàh€5Éá)€õ‹ò¶:¶:Þ‰yEÂhÒ÷HÍ' +“ŒI™3h»â'3ØšÎb’z"›üKü˼OºÞylá¼ (;®*®rk'|HåÔ»²7eoï_éìîì+º W¡9½2´24Û‡”eÃtð¹l˜Ñz g7gWç8§Ñ²›ÍצsïàeéãþGׯ½¬GcæYDôH(ùźëë®Û”ÎgpÝâáåæéjÉî$5J”÷Ûé§ÙOòÑ„2´TÈ<(‘ÿJ£‰Ì-dEfò<*›¤—¤}¤UvS¤sH³{%6&›VϘ=7Ú0Ðj­§[’#¬uÙ5QU›;I Ê~SóKÕ/­û{¯÷ö•\Ê£)¿/‚—9ƒµ,š% +ݲ5838sãnXnç665¦õÃøpúMÙËŠŸšîô\ºÚr#ï;¸¥l#š±¤lá)3R&U`^ìb×¥ÎvKü0MF +)œ‚~iW̹m{Ûv(Šì}Ô1$no¹9° v¹“…““™?Öôâ¦ý1!óÍZœZœ„¸õ•SÝåÝå½Ýýƒ$riBäô4(a¦ÐØ‚Y›-·-Èš-þ’ñD“ç÷ŽŠ†×H:‡5Ý¿GÄHõôû²·¿5Üïjëìè-臛в¹"¼"üôZXsÒ #ŒIØ,\HØ\|Åg¥s]Ðz éhÓ‘öœÞ"Í9Æz§íظ#xO,ç¼°¦Ké7àÙ7uK +hQR»‰Ôn´ÿ H $÷l¨ßPg•k†°0v¹órgÇ…¾˜ñÃl +Ö”såsoÙ°·l~‰BãIõi\ TíÈK=—z4¢Á:ÌsyøaX#›»ƒ°B­áÙÕÞ+½×Îß$0åÜ,e÷#Ü.jëjëªy™&¡mŠA]ô%“‡&Óx'ùGe?Íë.)—ÔŸì‚ Pÿååͧ»éPü¡ðoÃÆ~“úðE’ÏZoŸ“8,N«‹C3häÃàô‘þ «4¤PqRhø¦  ‘ƒO°x†¨r{íîÁUGO8¥ˆÙplÃÁõ€'€A¨¥ùæaäxÆ÷1¿‚‚вØÚMn qÒX©4#a]~hK«µ"ȃÿ™¡è¢Ê5þ¾— ɱд²_ûío~ Ä7O’ú¼ë|ê–á±duã!ûc¦§}›• ÐÒP÷ª<û«Â½•Dòà÷ª{ßÝÿ¾úïB—vm{kÒuNw$O‚ƒ9èι|±öbíÕ¢‡§Ðâ­ºÏv^ͨUÈNÇ@(XIÝíCì‚M6‘†y8..N»—Yt^þŸtiÉmÎi:_U•_SX¬Ú¡v{QBQ‰Pð¯,Ÿtÿ4ßøˆðÄðÄÀíë€]!'â‹â‹·]„Î|×F–Ìmt§ ¥æ#îÄÍo;H<~”Ýhòo²?·Ày‹{´k´›‡Ër6‹9}ãdï±®ã]Ç:Ž´m;ÚrøòÑËGZ¶ÿA ,™!>>÷%/êîŠk¿¿ÔÙQÝYÝu¦Ø7Í~†z´gãr.;…ÒµQ¦ tÄ2säÊ$4ñFü¡Tr"Ûš»«Š ÿØټܼ#ç¡’½’Pì1] +‰;6¥n’eÅA¤0žJ¸öÜÎoikm©úábéÑ^ë’ħ$Ø O[koâp?:J‘ŠíŠð‰‘ËËû·Å¼þ¿Å[Ñ ßA +UñÓ2¤[…Ö Ž;Zí>nÛŠyÌ ÒYìPæÐÈÁMr ^ÊGÑ8¶›¦žŒÊÙïÁ„Ô0…ÜEðÿ~oίÅOjn‰«ï4´µV“Ov4Cef®ì\ò‰»ý2í°á°ƒ®Ð¡Ì–/91pð +Ô‹áYêõÀú€z§³ËÀœÒÂœBÝ\½ÌÙ]Ìî{²«¡C/zæZƒ¸gxE{F{zyZ²_2¹(ˆÆzŸü.,1÷ýùç¾×Ümèl«i©i?Ó— <3'9'ùp9 +Û'ʳ„þo¯@«Súü| R12ðÿ‘ý¬èÁhr4¶·Ô´Õtœ¹ +åPþ—ò¤m– +Û(ˆ¾Š\†®qpaWÕ¶’me©Å±EñEëËlkVÕú•É +R v”@%4œ®,/./l>Ñàîöþ¶#¥ M›ÑŒUó0CZUX”è°ÖÁKº +€óiŠ€«Ïüîm¼u6ùlòÑXˆ€õ›‚ƒc‚c\2>6|¿õ9ásÂ77 Å‹D/‡RÉ©}¿ tßíª|¿“ ›ðzHƒ‹†¤Ã›Ïl>óeÁR| îh‘‘!]”O8BŠcÓŽöÓF žˆ7c×Ûm„ÞOV¾Ý±v/‰Á2×£>¼.ìZú œ‚}¥K~{ö‹8‘G†ÿÎÈOíÝzRýiš3l¾Íf·'„Šaé9ÇæÀæ€þÔ'¤yé9Ù]Ú]ÚÛÕ7È%ÍKÐhó²Uc f®21ufÌÂ`kq°µ¯—Wù¤{kä×ôZJ4í&¾¶Cä ¼™álì|_9íì',ÃΤ½†›»ÐØ­ÈÚ™—ë¹#G‰fùmÂðû>½o¯œ­÷F.Ž\”d³Ù‹ÝÃü­–nAï×Ïþ‚Ô#ùº¤¥ÇMÃîX7P?Μ̹ÿѾŸà û£h ÿB8}_ر‘AurµAäy ¡a3ÖÿÕkÑ)EÅÛqÈ[i'pïçÛx¾‚Æëˆ^+Í° o6ÚÂïR*•=4ZÏM½!nC#oWbI¤c„o¸Tá !è@ÈQOÕooÜÝDzÎÜ«õäó ‰ä.ZU÷£þ‘‘²>ÚZmàêI¶í{ïìùi÷ó=7v7¬âkÉb†ÜN;M¤•…ŒÜR~§éÓÃLžHó2fØiøu*Ö …_G«H±à$H‰ô$¬ºh\úÅ£ãèÝ/Œ2 DÓǨ¨M +ÒÒà‹¦ü?ÜÏj¼ endstream endobj 501 0 obj <> stream -xÚcd`aa`ddt s Óö/HÍ NÌ+Öõ,IÌÉLIùËq1°thÈwwÃ<ìÿ&üÙ)ÃyS†#‰õ‡ ÃYÆrL?䙈²Ôó0É200<‘øAä)$/ 1°22rð¸‡'”æeº9ê¸d¦g–dV¥¦(¤$–$*$çTe¦g”(h$k*è C÷üüôœTçü¢‚ü¢Ä’Ìü<=ƒ@.V€¸ÎZÆh$Ú˜•_Ë°œý*úMTæ—×Ï»@ûßR™_›DeXžýä•ù-ÅÎ'ÃÒ«ü§Aôq÷¥<ºùùÒïBßk~Ý“øÞȶä»0ëï& Å0ïá’c«×H®\½cöÑî-Ý;÷Ulû.*Q6%wJÊä”IÙýÝ -ÝÖ¡Á!¡‰:9¿%KÔ%~'yÖy°~eû]þï\•]i@A’dARJYDwvwÚ¤„Y¿Ù7ÔnmÙÙÍñ+éGƒè÷º_wXÛ°ý®ûw‡õûZÖÑîÜ)%sªæT/l^Ö½¢{錅K-™¶ª{Çñ¼•r™Ýùõe%eÅ 9Ýi|åóÝ™ùýÓk¶? Ýìr\ŒÌBñ<œ?VˆØg»Ì +xÚcd`aa`ddrŠŠp Ôö/HÍ NÌ+Öõ,IÌÉLIùËq1°thÈwwÃ<ìÿ&üÙ)ÃyS†#‰õ‡ ÃYÆrL?䙈²Ôó0É200<‘øAä)$/ 1°22rð¸‡'”æeº9ê¸d¦g–dV¥¦(¤$–$*$çTe¦g”(h$k*è C÷üüôœTçü¢‚ü¢Ä’Ìü<=ƒ@.V€¸ÎZÆh$Ú˜•_Ë°œý*úMTæ—×Ï»@ûßR™_›DeXžýä•ù-ÅÎ'ÃÒ«ü§Aôq÷¥<ºùùÒïBßk~Ý“øÞȶä»0ëï& Å0ïá’c«×H®\½cöÑî-Ý;÷Ulû.*Q6%wJÊä”IÙýÝ +ÝÖ¡Á!¡‰:9¿%KÔ%~'yÖy°~eû]þï\•]i@A’dARJYDwvwÚ¤„Y¿Ù7ÔnmÙÙÍñ+éGƒè÷º_wXÛ°ý®ûw‡õûZÖÑîÜ)%sªæT/l^Ö½¢{錅K-™¶ª{Çñ¼•r™Ýùõe%eÅ 9Ýi|åóÝ™ùýÓk¶? Ýìr\ŒÌBñ<œ?Vˆ¸¡»» endstream endobj 503 0 obj <> stream -xÚ=’mLSgÇïm{o¯¬^G¡ƒ‚.¾¶¢ƒ© ”ntnŠ«@€ÒRªØ‹m¡‚Êð%™ìl™ ÑĹ@2Ⱦʂ¸Á ˆ/Q$À²±IÐMYÌÜsÛ§˜Ýn‰_~Ïÿ¼|8ÿç’H’$_ËÖædé³6èÊMÖŠ¬vu¦£¨ÌRì/é"Éɵ‘/…Lú┯W¹lJÉ(>Šà£I~•ˆ_-æYÉ'2ÑëA†¿ê§,ÐOQ@"T€$%˜ IF¾"Ó7àÊá6®uÿWF؆c%U–êR«¹Øh0jw®Mõ¥àñP+VPrï¼w÷7l+RPØD£ï. —†^ì±ã@ÊN'ù¤z“žâ¥V"ë3ÐüQ~¶Û5pstAQ_wP[™R™¬¨Lr&VoeäÞ¯ùƒüU6 ²ï8ŒBøí¡|}©©¥ë—’ï}8|®÷ô…/Nu|Ñs0asçöé[2!°Ô—¶=mûš}80%|}'&'œ ÏA¢HØs†TØÕdî)é©…ŸÁ^ÛŸ#÷GîOw/ -Nø¡_EÛh4&Ü>…·Ñrg£wæ,zöí«iD).-ã¿]ñ/\ò\ +xÚ=’mLSgÇïm{o¯ ‹¯£ÐiTlDSŽ77:6PZK{±-TP¾$Ó-3!š8–„Œºj¡]7‰(–M‚nêbæžÛ>ÅìvKüò{þçåÃù?ç„DB$ùFöŽì=IyQš +½éã“E•a-)7–úJšÕ~„äôº5¯„¿ôåYo¯bÙ´‚ÑR|Á‡“|„ˆ_+æYÉ'þ¢7 ‚ }ÝGÿE+Á$I„I2²•¡áëUe‡×èÍœš³p&½@«Í§÷q•fßc¬òåLÆÿJ1ê˜è£Áh5ÖèuJ]‰µDYÊUT›†2«r]ézeltL´J@ÌFåŽ3”ë•Éœ¹‚3—XœIí³¥ôùRþïëU,L'©"Ïõ‚ü”âi ¢81)RHÆÐnå`žL÷œ ¤K• +O7«,¸—+pˆT¦p»;—bü;í~ÚU^á°±<¬ÌÍ…X\€EV¼ðjÀ!—Ã&Æß}¢CðÛf~`f~ù­I{Ó,$Q(ã CWÙûpËÜ•ß™gO…hÀ’#k¨ÊÕÅ)9ù9Y–4H„ì­Kë²MÂ#@dÃÓŽ‡LûÞ‰Aç s¤å02·…X…ê<Qx íÝ‚Ó˜@¿L ´5Ë[/67Ùíµú#[¼-þ˜æ¤¯ðNË<wïªv¤¦¼/êi´æ1bfGGo8××›úšzσð;wg—k—kkËZH‚ÔÚtsºù½Â-éÌß½9Ôéj’;çûá\;ÚƵüJ{A{b_µ±¦Ìd(Õiu©»Ö%{“ðX° Ë)™gÁ“û ÛŠäÖÓ¨Èó!…‹è¥Á—{-8€r‡Ò‰^)…Þ¦§y)…HÎzµ4œŸër¸n,ÊëÏN­JªÚ.¯J´%Ôledž¯ùÃüu6²NfEAüÎ`ÞN_B*j)šÆyKÛï}4ÔÐ{îÒ—òKg;¾è€y7;óûòZ2 °Ô›²3eg䘾þ2&Ç/]ÈA¢CHس> stream -xÚcd`aa`ddäsô ‹tñÒvö Ž44‰Øäý ùõáçlÖ2 ?dÈ1ýgþ!Î"÷Ћå?“,ÃAù“D~‘j@‚1Wˆ•‘‘[¨¡mjbQQ~yQfzF‰±ž‘s~A%˜¯ ‘¬©`hii®£`d``©à˜›Z”™œ˜§à›X’‘š›Xää(ç'g¦–T*hØd””Xéë———ë%æëå¥Ûiê(”g–d(¥§•¥¦(¸åç•(ø%æ¦*@¼¡¡œós JKR‹|óSR‹ò€.dTí LŒŒ,9?:ø~Õ|¯ÚÌxøóÏkß«DC ’šëâÜš}º»8ê§wO–›ÓÝÓÛ?wÑÛc÷¿³îœÞß×Û=©{Rk_gOüœß¼{S¿ÛtLïê«êæh®ï®—ïîœâ³Õc~mÙ«Ù*+»ËËçvÏ•ç+^üÓ~!Ûoéiìr\,æóy8'ñpõðpoæÚ̽y6ó~(ªÈŒõ +xÚcd`aa`ddäó uŠòÒvö Ž44‰Øäý ùõáçlÖ2 ?dÈ1ýgþ!Î"÷Ћå?“,ÃAù“D~‘j@‚1Wˆ•‘‘[¨¡mjbQQ~yQfzF‰±ž‘s~A%˜¯ ‘¬©`hii®£`d``©à˜›Z”™œ˜§à›X’‘š›Xää(ç'g¦–T*hØd””Xéë———ë%æëå¥Ûiê(”g–d(¥§•¥¦(¸åç•(ø%æ¦*@¼¡¡œós JKR‹|óSR‹ò€.dTí LŒŒ,9?:ø~Õ|¯ÚÌxøóÏkß«DC ’šëâÜš}º»8ê§wO–›ÓÝÓÛ?wÑÛc÷¿³îœÞß×Û=©{Rk_gOüœß¼{S¿ÛtLïê«êæh®ï®—ïîœâ³Õc~mÙ«Ù*+»ËËçvÏ•ç+^üÓ~!Ûoéiìr\,æóy8'ñpõðpoæÚ̽y6ó~(Éc endstream endobj 509 0 obj @@ -2472,21 +2475,22 @@ endobj 488 0 obj <> stream -xÚ͘[SÛ:€ßϯÐ{']Ý%Ït:Ã- -4mÊôÁA|ì4NÚÒ_vå@b'”´CÏa2B÷ÕîçÕ®öŽq¦Τ—XK¦<õ5ÓKb™çkÏ„–ΙМBbCcÃzF•3ØwLXž0‰µs 3·$Š3äÀíF(&¥ÑÌ2©¥Æ¾fÒXÉnÑ(PàBOr¦¸ó8`™’Ê1«˜ÒÂá€gʘ„á©Ê‘d‘ ÚE(¦9êm$Ú <ª$qDYLìÙ„iÇ ¹g„d-Qt8jLö)êq<Ý*Æ5Ž“²x¼ÇÅçÎp§”ÅàPìã1Ò<\Å~óGsU ÅÅÚz´U°h Ó8n±hÏ¢q¶ZmÉ, âñÈÜ%†Yéâ ®6$-aÎà¨NªÖ%µ³-êo•ŒÀc©EÉÖ8„mâN[‰qÔ"[ZMEr ‡D«€ÇS =%rï>ýu.ñyñ?ô³‰À,>rUbø³²üSªÚO4æ¥Þ{Šò»òŸòÔÿ«Ü·f¤—iüŠ¶«zÉY>kÝçÓð¶ßÔòמÉ25‡¾míüöš*ÖàÍ—F>p3ª™ Ìݪñvb,Ř…é^j “ÖY,~¶ï³ÓÌ+Ëu'i”þÒ6\Äào)²k‡·=žÂ›ZP 1%ÅX„u¢¢¾”/¨/Š#D¬)XÓ¸±¢ª±(ŒjZb<•3Y8ç0–hÔ”ÚZ«ÊB$„ºÑ_ŒGÊP܉3=ù]Ü51>.Qr÷aB!¯^ÁÙí(@»È'p:½˜P‡F¼Ï.'ƒå -Üsíl\N¶é˜Y8HgMa=ìäýâ2˯cÊ •›i¢¼NçìÝ‹£QÈOÓ¼Œ‡l‡²?ÎF“b³$®ýº¦Å|l¥£Ý]&”\%l”ýcÛ ´Š:- °7I‡Y#¿ÆátnºÌ{hÓkÔ?JÝÜ,¾Ÿ·„–µÈ¤FG(öSœngÃ@FV¦âÈazš44}ˆ—jðÒs^ _Äåã³â]žáXÀ‘¤°·»ù¡wð0@ÁŸ@]Ø0`M€¦PH¿àrÚ-0¢ÉPÈ:Ãý£vïMû' Õschë ¬ÉÐ=|iëNظ³¿ûöèìþ´Öf1¼\f¦ÿfÒ"¿Nb0nQ†C²>©ƒKêàV™²½„?|…uòKWx÷`û¤·ÿOóy&¢Îs•)kò”Oy£ß|ìž?†Ô>K¤ªŽt•)k"Õ ¤jÁGQE¢®Îï¨Ó;>è½8Ìn.¦e§ÈZ'ázºLЯK?ïâ÷ÕœŸðv%?-fül kÅ\|{òBÔ±™:¶Õ¬ Î6ÁÙuÁmu;{ݳÅcW»^²68?'ÀInV‚|9|%lI|?´ø¦æ]ƒœ«“[mšä|ƒœYÈ)ò'9å¸}Òþ°7÷òÊ´%nò¼Í [5/­­]XŽ§¶ŒNèÛA,'㤑SV›²?ײJòÛi¥×îîôº#Ï)}MÕßWš²&Ò'M,‡;ÝýÅ÷Tù ¡6ËjSÖ„º”ZÔœ)¶ïymtº½íý[Óžà˘Ö~±¶ó0ÈïñýSË,ð"ÇÉ„µË«ÿÑ:gê|¤¦z¥ãvvuÆ!ï‡òÜÀ(ŒI Ho°U¦ù%ó0Jqz®&UkLÊ‚ ã¬ü £á´„~qs“Âàv49ÉÈŠK(‡i9Àwœ9”á&«ZÃP–¾LÓ!\CŠrïlÂlôá ì2-aþ†èÀ!Á1¼…8…3x]x fài~‰šö‹qÀ -)\@.!À\Ã2ø>Ãn ‡FðÆP¦ð¾Áw¸…Ä/(–k4ªŸe“lˆ·D ö~1ºW^Òþt>-SÓðeZ¸…M‡Ã0¡Ð6ͳö&&¯ª–ô R5ÕL ùÔÝUEGÌ7ò2»ï/žAüG/‹Šÿu&ñyñ?ô³‰À,>rUbø«²üSªÚO4æ¥Þ{Šò»òŸòÔÿ«ÜµnH/ÓxŒ¶«zÉY>kÝçÓð¶ßÔòqÏd™šC߶v~{MkðæK#ï¹ÕLŒævÕx;1–bÌB‰t/5†Ië,³ï³ÓÌ+Ëu'i”þÒ6\Äào)²k‡·=žÂ›ZP 1%ÅX„u¢¢¾”/¨/Š#D¬)XÓ¸±¢ª±(ŒjZb<•7²pÎa,Ѩ)µµV•…Hu£¿”¡¸g(zòÛ¸kb|\¢ä$îÃ4„B^½‚£ëq€N‘Oápv>¥ø˜]L%ʸ§lRN7é„YØKošÂzØÎûÅE–_Å”A+Ûi¢¼Ýn·³{òâÝ8ä‡i^ÆC¶BÙŸdãi1‰Y׿~]Ób¾6Óñ›] ¦”\%l”ýcÛ ´Š:- ðvš³þF~5 ŒÃá4Œ>0ï¡3L¯Pÿ(µÝ.~œµ„–µÈ¤FG(ösœîdÃ@FV¦âH7…¦ Mï㥼ôœWÂqù¸ð¨8Î3 8’Ôn¼ß;:8º àÏ  ®l°&@Ó(¤_p9í +Ñd(da·Û}ófó Õschë ¬ÉÐÝiëNظ³Û½Ó½ww§µÚÅðb™™þ˜I‹hü"8‰Á¸EB: ÉRø¤.©ƒ[eÊzô~ÿÖÉ£®ðñþÎi¯÷Oóy&¢Îs•)kò”Oy£;ÛG;ïBjŸ%RUGºÊ”5‘êRµà£¨Æ"QWç×{»Ýi|ÑÍFç³r¿È÷Z½p5[&è×%ˆŸ‡·ñûjÎOx»’Ÿ7ül kÅ\|{òBÔ±™:¶Õ¬ Î6ÁÙuÁìv7]ízÉÚàüœ\'¹Y NðUäð•°%ñýÐ⛚w r®Nnµ k’ó rf!§È_䔃ӭÎÞÜË+Ó–¸É?ð6ƒnÕ¼´¶va9žÚ2:¡o±œŒ“FNYmÊZü _Ê*Éo§•^ûôÓÆÁÃHųCJ_Sõ˼Ҕ5‘>ib9Ø9øÔ>yª|†PUÓOW™²&Ô¥Ô¢æL±}Çkÿx§wºûbsÿðDðeLk¿XÛyäwˆxƒ~‰©å&ðDŽ/ ’ k%–Wÿ£uÎÔù42HMõJÇ­ìò2LBÞå™q˜Ž°U¦ùó0Nqz.§UkBÊ‚ “¬üãᬄ~1¥0¸BN2²âÊaZð]'‡EeeUkÊÂ×Y:„«IHQáÝ€6lÂlCvà Óváo؃}èÂ;xЃC8‚cøáœÀ)à <Ë/PÓ~1 ˜C!…sèø„+@ÿÀÂr(` _a%Laßà;ü€køIAüœb¹F£úY6͆xKbïãëIåÑè•!íϦáó25 _gш+QØl8 S +m³<ë´1yUµ¤Oª©nÄOÝ^UtÄ|#/³»þâtÁ†Iñ²(¡ÈUÓï±7LBì_³I¬³o±_f?b¾…œÑ騑g•€ËË*Þ>V•,œØªGB’þÛŒ¯ÿ endstream endobj 524 0 obj -<<2ab318012312f01e135daa12b3a72ca8>]/Size -525/W[1 3 2]/Filter/FlateDecode/Length 1264>> +<<73d408f43c3219297bc0aeb795fd41f4>]/Size +525/W[1 3 2]/Filter/FlateDecode/Length 1261>> stream -xÚ5ÖyPVUÇñó¼÷*ˆ¢®ð‚Š¹à’)æ–»¥âš((¢¸¤$®ˆš¸¥â.îa䮸üc3Në4£õGËôO65–3M“½ï÷<üó™g~g¹‡Ëå<cÌË—#æÖàŠ¿£0xŒqçÑ cH’zЋ>ôc#ÐAë`]ŒÄ(¬‡ÑXŸ§Ø9öé1hŸÛc,Æa<6Á¦Ø ›c l‰ ˜ˆALÂdl…­± ¦`[|Ûa{ì€1;ag1&:üÆBuÞðJ~.{ò®b‚/tôUFW3‡-Ĥü®£Ý]CÞDL—nš¿F¾Žú3¼7Åô˜£sªÅ¤õÒº»˜¿hÝÓ°§˜ôJÍ_gÏ"1™?hÒ‹¤˜º·˜)³5ïC¾‘º/ö“×XGß`t3u¼‹p ÂÁbÇëª!8‡‰ÉO -}u¦°¡Ž¾Éž%bŠR5y‹d›˜’…š 'Ùλj&foíûA¾“:3Ä”uômF˨Gâ=…™b*þÓ™£Å<}>Õ÷ÿh2†µ{¨ïàX'æ§/uÎx‘Ê4­'ˆ\©õ;¬ÝO=Q¤:SóIäQ_ÆÉ8§bfã4œ.òðqèlò8V÷ÉaŸƒÔ¹8gò~D¾¦3ó˜y„z–ÈyšÏ&?*ò¢®&sHNPÏÅOqήÎ\ žŽU¡óxRoj²µ'ÅÓg&ï’œ¦^„‹Å“þLGó=#žIQš¼Gržz .ÅeX€ËqâJ¬ÄU¸Z`ÕEêOp=‹·¬vç âËú.´Ê—ý‡&Yu‰Úº 7‹/·öY[Ä÷×p­oáV,ßß9šoÿ˜ŸC;ûǾԤ”íI®ãvÜ!þ ÛuÎN Lÿ6´*S{Û|È*û;½»°LsNèœÝøê¹Ö×Ð~ÿ{%ðM¤æû$â`è$Q§É~v¶ßsÚ/ü€DÞ sŠüMë+xËÅIök~Xœ­ Âý¨¤X“#ìlOr‰S:FG3joHûÝ^Å“x -+Ð~‡gð,žg_AøYGbt·óìvCœÓŸkrä¦8—ohr‘ä–85{4ù˜ÄÞäöŽµ}ä>õìˆön|@=cÐö¾‡Ô©Ø aè„Ï¿ ;g„ûrÈÆ‹qèÁxl‚MÑ‹ÉØ ›£[`KìŒ èÇ&b“0Û` -¶Em7ìŠíÐÅöØ; íŒu°.Ú~d{_wŒÄ˜†=1 -{c+´=«öÅ~h»UŒÆúØc.Ã!83pÚe»’íD¶ï¤£í¶×ŒÄQ˜‰£qŽEÛÆã´ýb"NÆY8§bfã4œŽ¶äâ œ‰öæ·÷°½íí ?çá|\€ö_„Kp1Ú»ÚÞÏKñ.nÅU¸ ÑÞ±öÎ\‹[p=nÀMXŽö6³·ÓÜ‹»p7Â}x+ñÆShXö/ôÞÁ*¼‚Õx¯ãm¼/ÎÑ¿»âü9Zë‡âúËô¿e#îÊga#'j"â&Dií7«µWÜ”KZûÄèÓÚ/î¤'ZÄ]ôHëqóÿÕÚ·`³ÖA¬ƒIâ®ÈÓ<“Å-¬Ð¤Úÿ·c°¶ÂXŒÇ¦Ø[b¢¸EùÆüòåb‘ +xÚ5ÖWPUWÆñ½n=GA¥Ùà‚Š±`‰QŒ-v…(ö +V¬%*ŠØÅ{TìbÆØ‚Ë‹™qR'3š<¤L^b&g2™˜{ÿ{ñò›5ß.gs8ì…1Ƽzå1’mîc. û«q1c°ŽÇ×q¿4†¤.‰ ½èC?0ˆºXkbFc-ŒÁÚ<ÅαOEûÜz‡ñ˜€‰˜„õ±6ÄFØ“1C˜ŠiØ›b3LÇæø¶À–Ø +[c¶Á¶bLLä…ëv¼á¥ü\öäíÅ„^êèëŒ.g4‰Iÿ]G;0º‚©§àTœÆûIùz€ÎÌgæêé"?æk>ƒü¨ÈËššÌ$9A= ?ÅÙ8G<þY:³@<­/‡Ïãɸ¥É\ÖžO·>š¼GršzÎOÖs-dôŒxÆFkò>Éyê¸a.Æ%XŒK±—árñän×=Wˆ7áxøœÞÄJMVò” ÔU¸ +W‹7ùºÎ)ï–ìȪ­Ó4ù€U©?Á5¸V¼»ªw^'¾Üï«|yh²žU—¨­p£ø¦T?k“øþ¨õmÜŒ¥âû{²æ[Ä?ìçðÎþá¯4ÙÊÎö$7pnÿ¨m:g‡&}^˜\}Û|È*û;½ƒ;q—fžÐ9»%ðÕ ­¯£ýþ÷Jà›(Í÷Ið`ø$,KÐd?;Ûïù2Ú/ü€¯Ó9Å ý¦õU<„eâ¤ù5?,Îæ‚H?*]«Év¶'9ŠÇÄÙ:LG3joHûÝ^Óx +ËÑ~‡gð,žg_QäYGbu·óìvSœÓŸkrä–8Wnjr‘ä¶8U{4ù˜ÄÞäöŽµ}äu/lön|HÝcÑö¾GÔØëaø„/¾ ;gGúrØ8ŒÇô`"&a}ôb6À†èÃFØÛb2ú1€)ÂT b3LÇæè í†í±ºØ›b+´±ÖDÛlïëˆQØ 3±3FcWl‚¶gÕÂîØm·ê‰1Xë`_,ÂEØûc6@Û¡lW²Èö,´ÂöšÁ8sp(ŽÀáh»ÀH…¶_ŒÁq8ÇãÌÅ<œˆ“Ðö‚)8§¡½ùí=lo{{ÃÏÂÙ8 ÐÞáópÎG{WÛûy!ÞÃ͸ c1Ú;ÖÞ™«p®Áu¸ËÐÞfövÚŽ{q'îÆC¸`ÃÃx +ípËÑþ…žÃ»x¯b%^ÃxˆóTôïî¡8Õú‘¸þúß²wéóˆQ£5q“£´öˆŠÓÚ+nú%­}âööiíwìS­âÎ{¬uPܵvÄ-Ú¨uk`ª¸Kò5Â4q‹Ë5©…öÿíX¬‡M0±>6ÄƘ"nI¡1ÿï£b endstream endobj startxref diff --git a/hurricane/src/hurricane/Backtrace.cpp b/hurricane/src/hurricane/Backtrace.cpp index bcb995cb..873898ab 100644 --- a/hurricane/src/hurricane/Backtrace.cpp +++ b/hurricane/src/hurricane/Backtrace.cpp @@ -440,6 +440,10 @@ namespace Hurricane { } _inConstructor = true; +#ifndef HAVE_LIBBFD + _stack.push_back( "Build without BFD (libbfd) support, no filename and line number." ); +#endif + #if (defined __linux__ || defined __FreeBSD__ || defined __APPLE__) void* rawStack [ _stackSize ]; size_t depth = backtrace ( rawStack, _stackSize ); diff --git a/hurricane/src/hurricane/Observer.cpp b/hurricane/src/hurricane/Observer.cpp index 8326cc34..5cc318c4 100644 --- a/hurricane/src/hurricane/Observer.cpp +++ b/hurricane/src/hurricane/Observer.cpp @@ -49,7 +49,7 @@ namespace Hurricane { void Observable::removeObserver ( BaseObserver* observer ) - { + { vector::iterator iobserver=_observers.begin(); for ( ; iobserver!=_observers.end() ; ++iobserver ) { if (*iobserver == observer) { diff --git a/hurricane/src/hurricane/hurricane/Observer.h b/hurricane/src/hurricane/hurricane/Observer.h index a02273ee..971bbcf6 100644 --- a/hurricane/src/hurricane/hurricane/Observer.h +++ b/hurricane/src/hurricane/hurricane/Observer.h @@ -160,7 +160,10 @@ namespace Hurricane { template template inline OwnerT* StaticObservable::getObserver ( size_t slot ) const - { return (slot < _observers.size()) ? static_cast< Observer* >(_observers[slot])->getOwner() : NULL; } + { + if ( (slot >= _observers.size()) or not _observers[slot]) return NULL; + return static_cast< Observer* >(_observers[slot])->getOwner(); + } diff --git a/hurricane/src/viewer/BreakpointWidget.cpp b/hurricane/src/viewer/BreakpointWidget.cpp index 058d30ad..0ea5d3cb 100644 --- a/hurricane/src/viewer/BreakpointWidget.cpp +++ b/hurricane/src/viewer/BreakpointWidget.cpp @@ -40,7 +40,7 @@ namespace Hurricane { setWindowTitle ( "Breakpoint" ); setToolTip ( "Crush the Mush to continue..." ); - _message->setTextFormat ( Qt::RichText ); + //_message->setTextFormat ( Qt::RichText ); _message->setText ( "No Message Yet" ); QLabel* stopLabel = new QLabel (); @@ -56,7 +56,7 @@ namespace Hurricane { vLine->setFrameShadow ( QFrame::Sunken ); QGridLayout* layout = new QGridLayout (); - layout->setSizeConstraint ( QLayout::SetFixedSize ); + //layout->setSizeConstraint ( QLayout::SetFixedSize ); layout->addWidget ( _message , 0, 0 ); layout->addWidget ( stopLabel , 1, 0 ); layout->addWidget ( _stopLevel, 1, 1 ); diff --git a/hurricane/src/viewer/ExceptionWidget.cpp b/hurricane/src/viewer/ExceptionWidget.cpp index 8b3417f6..3e2599b8 100644 --- a/hurricane/src/viewer/ExceptionWidget.cpp +++ b/hurricane/src/viewer/ExceptionWidget.cpp @@ -117,6 +117,7 @@ namespace Hurricane { _header->setText ( "[ERROR]" ); _message->setTextFormat ( Qt::RichText ); + _message->setFont ( Graphics::getFixedFont(QFont::Normal,false,false) ); _message->setText ( "Oups! I did it again!" ); _trace->setTextInteractionFlags ( Qt::TextBrowserInteraction ); diff --git a/katana/CMakeLists.txt b/katana/CMakeLists.txt new file mode 100644 index 00000000..5cd3617c --- /dev/null +++ b/katana/CMakeLists.txt @@ -0,0 +1,46 @@ +# -*- explicit-buffer-name: "CMakeLists.txt" -*- + + set(CMAKE_LEGACY_CYGWIN_WIN32 0) + project(KATANA) + + option(BUILD_DOC "Build the documentation (doxygen)" OFF) + option(CHECK_DATABASE "Run database in full check mode (very slow)" OFF) + + cmake_minimum_required(VERSION 2.8.9) + + list(INSERT CMAKE_MODULE_PATH 0 "${DESTDIR}$ENV{CORIOLIS_TOP}/share/cmake/Modules/") + find_package(Bootstrap REQUIRED) + setup_project_paths(CORIOLIS) + + set_cmake_policies() + set_lib_link_mode() + setup_boost(program_options filesystem python regex) + setup_qt() + + find_package(Libexecinfo REQUIRED) + find_package(LibXml2 REQUIRED) + find_package(PythonLibs REQUIRED) + find_package(PythonSitePackages REQUIRED) + find_package(LEFDEF REQUIRED) + find_package(VLSISAPD REQUIRED) + find_package(HURRICANE REQUIRED) + find_package(CORIOLIS REQUIRED) + find_package(ANABATIC REQUIRED) + + if(CHECK_DATABASE) + add_definitions(-DCHECK_DATABASE) + endif(CHECK_DATABASE) + if(CHECK_DETERMINISM) + add_definitions(-DCHECK_DETERMINISM) + endif(CHECK_DETERMINISM) + + add_subdirectory(src) + add_subdirectory(python) + add_subdirectory(cmake_modules) + +#if(BUILD_DOC) +# find_package(Doxygen) +# if(DOXYGEN_FOUND) +# add_subdirectory(doc) +# endif() +#endif() diff --git a/katana/cmake_modules/CMakeLists.txt b/katana/cmake_modules/CMakeLists.txt new file mode 100644 index 00000000..de6f1662 --- /dev/null +++ b/katana/cmake_modules/CMakeLists.txt @@ -0,0 +1 @@ +install( FILES FindKATANA.cmake DESTINATION share/cmake/Modules ) diff --git a/katana/cmake_modules/FindKATANA.cmake b/katana/cmake_modules/FindKATANA.cmake new file mode 100644 index 00000000..955ee52c --- /dev/null +++ b/katana/cmake_modules/FindKATANA.cmake @@ -0,0 +1,37 @@ +# - Find the Katana includes and libraries. +# The following variables are set if Coriolis is found. If KATANA is not +# found, KATANA_FOUND is set to false. +# KATANA_FOUND - True when the Coriolis include directory is found. +# KATANA_INCLUDE_DIR - the path to where the Coriolis include files are. +# KATANA_LIBRARIES - The path to where the Coriolis library files are. + + +SET(KATANA_INCLUDE_PATH_DESCRIPTION "directory containing the Katana include files. E.g /usr/local/include/coriolis or /asim/coriolis/include/coriolis") + +SET(KATANA_DIR_MESSAGE "Set the KATANA_INCLUDE_DIR cmake cache entry to the ${KATANA_INCLUDE_PATH_DESCRIPTION}") + +# don't even bother under WIN32 +IF(UNIX) + # + # Look for an installation. + # + FIND_PATH(KATANA_INCLUDE_PATH NAMES katana/KatanaEngine.h PATHS + # Look in other places. + ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES include/coriolis + # Help the user find it if we cannot. + DOC "The ${KATANA_INCLUDE_PATH_DESCRIPTION}" + ) + + FIND_LIBRARY(KATANA_LIBRARY_PATH + NAMES katana + PATHS ${CORIOLIS_DIR_SEARCH} + PATH_SUFFIXES lib${LIB_SUFFIX} + # Help the user find it if we cannot. + DOC "The ${KATANA_INCLUDE_PATH_DESCRIPTION}" + ) + + SET_LIBRARIES_PATH(KATANA KATANA) + HURRICANE_CHECK_LIBRARIES(KATANA) + +ENDIF(UNIX) diff --git a/katana/python/CMakeLists.txt b/katana/python/CMakeLists.txt new file mode 100644 index 00000000..5932bc3e --- /dev/null +++ b/katana/python/CMakeLists.txt @@ -0,0 +1,2 @@ + + install ( FILES katanaInit.py DESTINATION ${PYTHON_SITE_PACKAGES}/katana ) diff --git a/katana/python/katanaInit.py b/katana/python/katanaInit.py new file mode 100644 index 00000000..18498976 --- /dev/null +++ b/katana/python/katanaInit.py @@ -0,0 +1,39 @@ +#!/usr/bin/env python + +try: + import sys + import os.path + from helpers import ErrorMessage + from helpers import WarningMessage + import Viewer +except ImportError, e: + serror = str(e) + if serror.startswith('No module named'): + module = serror.split()[-1] + print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module + print ' Please check the integrity of the package.' + if str(e).find('cannot open shared object file'): + library = serror.split(':')[0] + print '[ERROR] The <%s> shared library cannot be loaded.' % library + print ' Under RHEL 6, you must be under devtoolset-2.' + print ' (scl enable devtoolset-2 bash)' + sys.exit(1) +except Exception, e: + print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python' + print ' modules. Something may be wrong at Python/C API level.\n' + print ' %s' % e + sys.exit(2) + + +def katanaHook ( **kw ): + katana = None + if kw.has_key('katana'): + katana = kw['katana'] + else: + print ErrorMessage( 3, 'katanaHook(): Must be run from a KatanaEngine.' ) + return + + userInit = os.path.join( os.getcwd(), '.coriolis2/katana.py' ) + if (os.path.exists(userInit)): + execfile( userInit ) + return diff --git a/katana/src/CMakeLists.txt b/katana/src/CMakeLists.txt new file mode 100644 index 00000000..e4cf1b27 --- /dev/null +++ b/katana/src/CMakeLists.txt @@ -0,0 +1,112 @@ +# -*- explicit-buffer-name: "CMakeLists.txt" -*- + +# include( ${QT_USE_FILE} ) + include_directories( ${KATANA_SOURCE_DIR}/src + ${CORIOLIS_INCLUDE_DIR} + ${HURRICANE_INCLUDE_DIR} + ${CONFIGURATION_INCLUDE_DIR} + ${WtX_INCLUDE_DIR} + ${Boost_INCLUDE_DIRS} + ${PYTHON_INCLUDE_PATH} + ) + set( includes katana/Constants.h + katana/TrackCost.h + katana/DataNegociate.h + katana/TrackElement.h katana/TrackElements.h + katana/TrackSegment.h + katana/TrackFixedSegment.h + katana/TrackMarker.h + katana/Track.h + katana/Tracks.h + katana/HorizontalTrack.h + katana/VerticalTrack.h + katana/RoutingPlane.h + katana/Session.h + katana/Manipulator.h + katana/SegmentFsm.h + katana/RoutingEvent.h + katana/RoutingEventQueue.h + katana/RoutingEventHistory.h + katana/RoutingEventLoop.h + katana/NegociateWindow.h + katana/Configuration.h + katana/KatanaEngine.h + katana/GraphicKatanaEngine.h + ) + set( pyIncludes katana/PyKatanaEngine.h + katana/PyGraphicKatanaEngine.h + ) + set( mocIncludes katana/GraphicKatanaEngine.h ) + set( cpps Constants.cpp + Configuration.cpp + DataNegociate.cpp + TrackCost.cpp + TrackElement.cpp + TrackElements.cpp + TrackSegment.cpp + TrackFixedSegment.cpp + TrackMarker.cpp + Track.cpp + Tracks.cpp + HorizontalTrack.cpp + VerticalTrack.cpp + RoutingPlane.cpp + Session.cpp + Manipulator.cpp + SegmentFsm.cpp + RoutingEvent.cpp + RoutingEventQueue.cpp + RoutingEventHistory.cpp + RoutingEventLoop.cpp + NegociateWindow.cpp + PowerRails.cpp + PreRouteds.cpp + ProtectRoutingPads.cpp + PreProcess.cpp + GlobalRoute.cpp + KatanaEngine.cpp + GraphicKatanaEngine.cpp + ) + set( pyCpps PyKatana.cpp + PyKatanaEngine.cpp + PyGraphicKatanaEngine.cpp + ) + qtX_wrap_cpp( mocCpps ${mocIncludes} ) + + set( depLibs ${ANABATIC_LIBRARIES} + ${CORIOLIS_PYTHON_LIBRARIES} + ${CORIOLIS_LIBRARIES} + ${HURRICANE_PYTHON_LIBRARIES} + ${HURRICANE_GRAPHICAL_LIBRARIES} + ${HURRICANE_LIBRARIES} + ${CONFIGURATION_LIBRARY} + ${BOOKSHELF_LIBRARY} + ${CIF_LIBRARY} + ${AGDS_LIBRARY} + ${UTILITIES_LIBRARY} + ${LEFDEF_LIBRARIES} + ${OA_LIBRARIES} + ${QtX_LIBRARIES} + ${Boost_LIBRARIES} + ${LIBXML2_LIBRARIES} + ${PYTHON_LIBRARIES} -lutil + ${LIBEXECINFO_LIBRARIES} + ) + + add_library( katana ${cpps} ${mocCpps} ${pyCpps} ) + set_target_properties( katana PROPERTIES VERSION 1.0 SOVERSION 1 ) + target_link_libraries( katana ${depLibs} ) + + add_python_module( "${pyCpps}" + "${pyIncludes}" + "Do_not_generate_C_library" + Katana + "katana;${depLibs}" + include/coriolis2/katana + ) + + install( TARGETS katana DESTINATION lib${LIB_SUFFIX} ) + install( FILES ${includes} + ${mocIncludes} DESTINATION include/coriolis2/katana ) + + diff --git a/katana/src/Configuration.cpp b/katana/src/Configuration.cpp new file mode 100644 index 00000000..d3537fe0 --- /dev/null +++ b/katana/src/Configuration.cpp @@ -0,0 +1,199 @@ +// -*- mode: C++; explicit-buffer-name: "Configuration.cpp" -*- +// +// 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 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 : "./Configuration.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "vlsisapd/configuration/Configuration.h" +#include "hurricane/Cell.h" +#include "crlcore/Utilities.h" +#include "katana/Configuration.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + + using std::cout; + using std::cerr; + using std::endl; + using std::ostringstream; + using Hurricane::tab; + using Hurricane::Error; + using Hurricane::Technology; + + +// ------------------------------------------------------------------- +// Class : "Katana::Configuration". + + + Configuration::Configuration () + : Anabatic::Configuration() + , _postEventCb () + , _hTracksReservedLocal(Cfg::getParamInt("katana.hTracksReservedLocal", 3)->asInt()) + , _vTracksReservedLocal(Cfg::getParamInt("katana.vTracksReservedLocal", 3)->asInt()) + , _ripupLimits () + , _ripupCost (Cfg::getParamInt("katana.ripupCost" , 3)->asInt()) + , _eventsLimit (Cfg::getParamInt("katana.eventsLimit" ,4000000)->asInt()) + , _flags (0) + { + _ripupLimits[StrapRipupLimit] = Cfg::getParamInt("katana.strapRipupLimit" ,16)->asInt(); + _ripupLimits[LocalRipupLimit] = Cfg::getParamInt("katana.localRipupLimit" , 7)->asInt(); + _ripupLimits[GlobalRipupLimit] = Cfg::getParamInt("katana.globalRipupLimit" , 5)->asInt(); + _ripupLimits[LongGlobalRipupLimit] = Cfg::getParamInt("katana.longGlobalRipupLimit" , 5)->asInt(); + + // for ( size_t i=0 ; isetDouble(threshold); + // _globalMinBreaks[i] = DbU::lambda (Cfg::getParamDouble(paramName.str())->asDouble()); + // } + } + + + Configuration::Configuration ( const Configuration& other ) + : Anabatic::Configuration(*other.base()) + , _postEventCb (other._postEventCb) + , _hTracksReservedLocal(other._hTracksReservedLocal) + , _vTracksReservedLocal(other._vTracksReservedLocal) + , _ripupLimits () + , _ripupCost (other._ripupCost) + , _eventsLimit (other._eventsLimit) + { + _ripupLimits[StrapRipupLimit] = other._ripupLimits[StrapRipupLimit]; + _ripupLimits[LocalRipupLimit] = other._ripupLimits[LocalRipupLimit]; + _ripupLimits[GlobalRipupLimit] = other._ripupLimits[GlobalRipupLimit]; + _ripupLimits[LongGlobalRipupLimit] = other._ripupLimits[LongGlobalRipupLimit]; + } + + + Configuration::~Configuration () + { } + + + Configuration* Configuration::clone () const + { return new Configuration(*this); } + + + void Configuration::setRipupLimit ( unsigned int type, unsigned int limit ) + { + if ( type >= RipupLimitsTableSize ) { + cerr << Error("setRipupLimit(): Bad ripup limit index: %ud (> %ud)." + ,type,RipupLimitsTableSize) << endl; + return; + } + + _ripupLimits [ type ] = limit; + } + + + void Configuration::setHTracksReservedLocal ( size_t reserved ) + { + // if (reserved > getHEdgeCapacity()) + // throw Error( "Configuration::setHTracksReservedLocal(): tracks reserved for local routing (%d) is greater than edge capacity %d." + // , reserved, getHEdgeCapacity() ); + + _hTracksReservedLocal = reserved; + } + + + void Configuration::setVTracksReservedLocal ( size_t reserved ) + { + // if (reserved > 1.0) + // throw Error( "Configuration::setVTracksReservedLocal(): tracks reserved for local routing (%d) is greater than edge capacity %d." + // , reserved, getVEdgeCapacity() ); + + _vTracksReservedLocal = reserved; + } + + + unsigned int Configuration::getRipupLimit ( unsigned int type ) const + { + if ( type >= RipupLimitsTableSize ) { + cerr << Error("getRipupLimit(): Bad ripup limit index: %u (> %u)." + ,type,RipupLimitsTableSize) << endl; + return 0; + } + return _ripupLimits[type]; + } + + + void Configuration::print ( Cell* cell ) const + { + cout << " o Configuration of ToolEngine for Cell <" << cell->getName() << ">" << endl; + cout << Dots::asUInt (" - Global router H reserved local" ,_hTracksReservedLocal) << endl; + cout << Dots::asUInt (" - Global router V reserved local" ,_vTracksReservedLocal) << endl; + cout << Dots::asULong(" - Events limit (iterations)" ,_eventsLimit) << endl; + cout << Dots::asUInt (" - Ripup limit, straps" ,_ripupLimits[StrapRipupLimit]) << endl; + cout << Dots::asUInt (" - Ripup limit, locals" ,_ripupLimits[LocalRipupLimit]) << endl; + cout << Dots::asUInt (" - Ripup limit, globals" ,_ripupLimits[GlobalRipupLimit]) << endl; + cout << Dots::asUInt (" - Ripup limit, long globals" ,_ripupLimits[LongGlobalRipupLimit]) << endl; + + Super::print ( cell ); + } + + + string Configuration::_getTypeName () const + { return "Configuration"; } + + + string Configuration::_getString () const + { + ostringstream os; + + os << "<" << _getTypeName() << " " << getRoutingGauge()->getName() << ">"; + + return os.str(); + } + + + Record* Configuration::_getRecord () const + { + Record* record = Super::_getRecord(); + if ( record ) { + record->add ( getSlot("_hTracksReservedLocal" ,_hTracksReservedLocal ) ); + record->add ( getSlot("_vTracksReservedLocal" ,_vTracksReservedLocal ) ); + record->add ( getSlot("_ripupCost" ,_ripupCost ) ); + record->add ( getSlot("_eventsLimit" ,_eventsLimit ) ); + + record->add ( getSlot("_ripupLimits[StrapRipupLimit]" ,_ripupLimits[StrapRipupLimit] ) ); + record->add ( getSlot("_ripupLimits[LocalRipupLimit]" ,_ripupLimits[LocalRipupLimit] ) ); + record->add ( getSlot("_ripupLimits[GlobalRipupLimit]" ,_ripupLimits[GlobalRipupLimit] ) ); + record->add ( getSlot("_ripupLimits[LongGlobalRipupLimit]",_ripupLimits[LongGlobalRipupLimit]) ); + + // for ( size_t i=0 ; iadd ( DbU::getValueSlot(paramName.str(),&_globalMinBreaks[i]) ); + // } + } + + return record; + } + + + +} // Katana namespace. diff --git a/katana/src/Constants.cpp b/katana/src/Constants.cpp new file mode 100644 index 00000000..a1ad8eb1 --- /dev/null +++ b/katana/src/Constants.cpp @@ -0,0 +1,37 @@ +// -*- mode: C++; explicit-buffer-name: "Constants.cpp" -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2016-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | A n a b a t i c - Global Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./Constants.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "katana/Constants.h" + + +namespace Katana { + + + const unsigned int Flags::AllowDoglegReuse = (1 << 20); + const unsigned int Flags::DataSelf = (1 << 21); + const unsigned int Flags::Nearest = (1 << 22); + const unsigned int Flags::Force = (1 << 23); + const unsigned int Flags::ResetCount = (1 << 24); + const unsigned int Flags::WithConstraints = (1 << 25); + const unsigned int Flags::MoveToLeft = (1 << 26); + const unsigned int Flags::MoveToRight = (1 << 27); + const unsigned int Flags::LoadingStage = (1 << 28); + const unsigned int Flags::SlowMotion = (1 << 29); + const unsigned int Flags::PreRoutedStage = (1 << 30); + + +} // Anabatic namespace. diff --git a/katana/src/DataNegociate.cpp b/katana/src/DataNegociate.cpp new file mode 100644 index 00000000..0014e90d --- /dev/null +++ b/katana/src/DataNegociate.cpp @@ -0,0 +1,278 @@ +// -*- 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 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 : "./DataNegociate.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Bug.h" +#include "hurricane/DebugSession.h" +#include "anabatic/AutoSegment.h" +#include "katana/DataNegociate.h" +#include "katana/RoutingEvent.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::map; + using std::multimap; + using std::make_pair; + using std::ostringstream; + using Hurricane::Bug; + using Hurricane::DebugSession; + using Hurricane::tab; + + +// ------------------------------------------------------------------- +// Class : "DataNegociate". + + + DataNegociate::DataNegociate ( TrackElement* trackSegment ) + : _trackSegment (trackSegment) + , _childSegment (NULL) + , _routingEvent (NULL) + , _net (trackSegment->getNet()) + , _state (RipupPerpandiculars) + , _stateCount (1) + , _terminals (0) + , _ripupCount (0) + , _leftMinExtend (DbU::Max) + , _rightMinExtend (DbU::Min) + , _attractors () + , _perpandiculars () + , _perpandicularFree(false) + , _reduceRanges { Interval(), Interval() } + { } + + + DataNegociate::~DataNegociate () + { } + + + DbU::Unit DataNegociate::getWiringDelta ( DbU::Unit axis ) const + { + DbU::Unit attraction = 0; + for ( size_t i=0 ; i < _attractors.size() ; i++ ) { + if ( _attractors[i] > axis ) attraction += _attractors[i] - axis; + else attraction += axis - _attractors[i]; + } + for ( size_t i=0 ; i<2 ; ++i ) { + if (_reduceRanges[i].isEmpty()) continue; + if (_reduceRanges[i].contains(axis)) attraction -= 2*_trackSegment->getPitch(); + } + return attraction; + } + + + void DataNegociate::update () + { + DebugSession::open( _trackSegment->getNet(), 150, 160 ); + + //cdebug_log(9000,0) << "Deter| DataNegociate::update() - " << _trackSegment << endl; + cdebug_log(159,1) << "DataNegociate::update() - " << _trackSegment << endl; + +#if 0 + size_t reduceCandidates = 0; + DbU::Unit pitch = _trackSegment->getPitch(); +#endif + vector collapseds; + vector perpandiculars; + map attractorSpins; + + _reduceRanges[0].makeEmpty(); + _reduceRanges[1].makeEmpty(); + _perpandiculars.clear(); + AutoSegment::getTopologicalInfos( _trackSegment->base() + , collapseds + , perpandiculars + , _leftMinExtend + , _rightMinExtend + ); + + _terminals = AutoSegment::getTerminalCount( _trackSegment->base(), collapseds ); + //cdebug_log(9000,0) << "Deter| Terminals:" << _terminals << endl; + _attractors.clear(); + _perpandiculars.clear(); + _perpandicularFree = Interval(false); + + cdebug_log(159,0) << "Extracting attractors from perpandiculars." << endl; + for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) { + Interval interval; + TrackElement* perpandicular; + + if (perpandiculars[i]->isCanonical()) { + perpandicular = Session::lookup( perpandiculars[i]->base() ); + if (perpandicular) perpandicular->getCanonical( interval ); + } else { + perpandicular = Session::lookup( perpandiculars[i]->getCanonical(interval)->base() ); + } + if (not perpandicular) { + cerr << Bug( "Not a TrackSegment: %s\n (perpandicular: %s)" + //, getString((void*)perpandiculars[i]->getCanonical(interval)->base()).c_str() + , getString(perpandiculars[i]->getCanonical(interval)).c_str() + //, getString((void*)perpandiculars[i]->base()).c_str() + , getString(perpandiculars[i]).c_str() + ) << endl; + continue; + } + + if (RoutingEvent::getStage() == RoutingEvent::Repair) + perpandicular->base()->setFlagsOnAligneds( Anabatic::SegUnbound ); + + //cerr << "perpandicular:" << perpandicular << endl; + //cerr << " " << interval << endl; + //interval.inflate( DbU::fromLambda(-0.5) ); + + cdebug_log(159,0) << "| perpandicular: " << perpandiculars[i] << endl; + cdebug_log(159,0) << "| canonical: " << perpandicular << endl; + cdebug_log(159,1) << "Canonical // interval: " << interval << endl; + + _perpandiculars.push_back( perpandicular ); + if (perpandicular->getTrack()) { + Interval trackFree = perpandicular->getFreeInterval(); + cdebug_log(159,0) << "Track Perpandicular Free: " << trackFree << endl; + + _perpandicularFree.intersection( trackFree ); + } else { + cdebug_log(159,0) << "Not in any track " << perpandicular << endl; + } + +#if 0 + if (interval.isPonctual()) { + cdebug_log(159,0) << "Punctual attractor @" << DbU::getValueString(interval.getVMin()) << endl; + _attractors.push_back( interval.getVMin() ); + cdebug_tabw(159,-1); + continue; + } + + if ( (interval.getVMin() != _trackSegment->getAxis()) + or AutoSegment::isTopologicalBound(perpandiculars[i] + ,perpandicular->isHorizontal() ? Flags::Horizontal : 0 + ) ) { + map::iterator iattractor = attractorSpins.find( interval.getVMin() ); + if (iattractor == attractorSpins.end()) { + attractorSpins.insert( make_pair(interval.getVMin(),-1) ); + } else { + iattractor->second -= 1; + } + cdebug_log(159,0) << "Left attractor @" << DbU::getValueString(interval.getVMin()) << endl; + } + + if ( (interval.getVMax() != _trackSegment->getAxis()) + or AutoSegment::isTopologicalBound(perpandiculars[i] + ,Flags::Propagate | (perpandicular->isHorizontal() ? Flags::Horizontal : 0) + ) ) { + map::iterator iattractor = attractorSpins.find( interval.getVMax() ); + if (iattractor == attractorSpins.end()) { + attractorSpins.insert( make_pair(interval.getVMax(),1) ); + } else { + iattractor->second += 1; + } + cdebug_log(159,0) << "Right attractor @" << DbU::getValueString(interval.getVMax()) << endl; + } + + if (perpandicular->base()->isReduceCandidate()) { + if (reduceCandidates < 2) { + if (interval.getVMin()+DbU::fromLambda(0.5) == _trackSegment->getAxis()) { + _reduceRanges[reduceCandidates] = Interval( interval.getVMax()-pitch + , interval.getVMax()+pitch ); + } else if (interval.getVMax()-DbU::fromLambda(0.5) == _trackSegment->getAxis()) { + _reduceRanges[reduceCandidates] = Interval( interval.getVMin()-pitch + , interval.getVMin()+pitch ); + } + ++reduceCandidates; + } + } +#endif + + cdebug_tabw(159,-1); + } + if ( not _trackSegment->isTerminal() and (_perpandiculars.size() < 2) ) + cerr << Bug( "Less than two perpandiculars on %s.", getString(_trackSegment).c_str() ) << endl; + + map::iterator iattractor = attractorSpins.begin(); + for ( ; iattractor != attractorSpins.end() ; iattractor++ ) { + if (iattractor->second != 0) + _attractors.push_back( iattractor->first ); + } + + ostringstream s; + s << "Attractors ["; + for ( size_t i=0 ; i<_attractors.size() ; i++ ) { + if ( i ) s << ", "; + s << DbU::getValueString( _attractors[i] ); + } + s << "]"; + cdebug_log(159,0) << s.str() << endl; + cdebug_log(159,0) << "Perpandicular Free: " << _perpandicularFree << endl; + + + cdebug_tabw(159,-1); + DebugSession::close(); + } + + + string DataNegociate::_getString () const + { + return "<" + _getTypeName() + " " + + getString(_trackSegment) + " " + + getString(_terminals) + + " [" + DbU::getValueString(_leftMinExtend) + + ":" + DbU::getValueString(_rightMinExtend) + + "]>"; + } + + + Record* DataNegociate::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add( getSlot ( "_routingEvent" , _routingEvent ) ); + record->add( getSlot ( "_trackSegment" , _trackSegment ) ); + record->add( getSlot ( "_childSegment" , _childSegment ) ); + record->add( getSlot ( "_terminals" , _terminals ) ); + record->add( getSlot ( "_ripupCount" , _ripupCount ) ); + record->add( DbU::getValueSlot( "_leftMinExtend" , &_leftMinExtend ) ); + record->add( DbU::getValueSlot( "_rightMinExtend", &_rightMinExtend ) ); + record->add( getSlot ( "_net" , _net ) ); + + return record; + } + + + string DataNegociate::getStateString ( DataNegociate* data ) + { + ostringstream s; + switch ( data->_state ) { + case RipupPerpandiculars: s << "RipupPerpandiculars"; break; + case Minimize: s << "Minimize"; break; + case Dogleg: s << "Dogleg"; break; + case Slacken: s << "Slacken"; break; + case ConflictSolveByHistory: s << "ConflictSolveByHistory1"; break; + case ConflictSolveByPlaceds: s << "ConflictSolveByPlaceds"; break; + case LocalVsGlobal: s << "LocalVsGlobal"; break; + case MoveUp: s << "MoveUp"; break; + case MaximumSlack: s << "MaximumSlack"; break; + case Unimplemented: s << "Unimplemented"; break; + case Repair: s << "REPAIR"; break; + default: + s << "Unknown(" << data->_state << ")"; break; + } + s << ":" << data->_stateCount; + return s.str(); + } + + +} // Katana namespace. diff --git a/katana/src/GlobalRoute.cpp b/katana/src/GlobalRoute.cpp new file mode 100644 index 00000000..97bd4ba2 --- /dev/null +++ b/katana/src/GlobalRoute.cpp @@ -0,0 +1,219 @@ +// -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp" -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2016-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | C O R I O L I S | +// | A n a b a t i c - Global Routing Toolbox | +// | | +// | Author : Jean-Paul CHAPUT | +// | E-mail : Jean-Paul.Chaput@lip6.fr | +// | =============================================================== | +// | C++ Module : "./GlobalRoute.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Cell.h" +#include "anabatic/Dijkstra.h" +#include "katana/RoutingPlane.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using std::cerr; + using std::endl; + using std::setw; + using std::left; + using std::right; + using Hurricane::DbU; + using Anabatic::Edge; + using Anabatic::Vertex; + + + class DigitalDistance { + public: + inline DigitalDistance ( float h, float k ); + DbU::Unit operator() ( const Vertex* source ,const Vertex* target,const Edge* edge ) const; + private: + // For an explanation of h & k parameters, see: + // "KNIK, routeur global pour la plateforme Coriolis", p. 52. + float _h; + float _k; + }; + + + inline DigitalDistance::DigitalDistance ( float h, float k ) : _h(h), _k(k) { } + + + DbU::Unit DigitalDistance::operator() ( const Vertex* source ,const Vertex* target,const Edge* edge ) const + { + if (edge->getCapacity() <= 0) return Vertex::unreached; + + float congestion = (float)edge->getRealOccupancy() / (float)edge->getCapacity(); + float congestionCost = 1.0 + _h / (1.0 + std::exp(_k * (congestion - 1.0))); + + float distance = (float)source->getDistance() + + congestionCost * (float)edge->getDistance(); + + edge->getHistoricCost(); + + // Edge* sourceFrom = source->getFrom(); + // if (sourceFrom) { + // distance += ((sourceFrom->isHorizontal() xor edge->isHorizontal()) ? 3.0 : 0.0) * (float)Edge::unity; + // } + cdebug_log(112,0) << "cong:" << congestion + << " ccost:" << congestionCost + << " digitalDistance:" << DbU::getValueString((DbU::Unit)distance) << endl; + + return (DbU::Unit)distance; + } + + + void computeNextHCost ( Edge* edge, float edgeHInc ) + { + float congestion = (float)edge->getRealOccupancy() / (float)edge->getCapacity(); + float hCost = edge->getHistoricCost(); + + float alpha = (congestion < 1.0) ? congestion : std::exp( std::log(8)*( congestion - 1 ) ); + + edge->setHistoricCost( alpha * (hCost + ((congestion < 1.0) ? 0.0 : edgeHInc) )); + + cdebug_log(113,0) << edge << endl; + } + + +} // Anonymous namespace. + + +namespace Katana { + + using Hurricane::Error; + using Hurricane::Timer; + using Anabatic::EngineState; + using Anabatic::Dijkstra; + using Anabatic::NetData; + + + void KatanaEngine::setupGlobalGraph ( unsigned int mode ) + { + Cell* cell = getCell(); + + cell->flattenNets( Cell::Flags::BuildRings|Cell::Flags::WarnOnUnplacedInstances ); + cell->createRoutingPadRings( Cell::Flags::BuildRings ); + + Super::chipPrep(); + + startMeasures(); + + if (getGCells().size() == 1) { + cmess1 << " o Building regular grid..." << endl; + getSouthWestGCell()->doGrid(); + } else { + cmess1 << " o Reusing existing grid." << endl; + } + cmess1 << Dots::asInt(" - GCells" ,getGCells().size()) << endl; + + stopMeasures(); + printMeasures( "Anabatic Grid" ); + + //setupSpecialNets(); + //setupPreRouteds(); + setupNetDatas(); + + for ( GCell* gcell : getGCells() ) { + if (not gcell->isMatrix()) continue; + + for ( Edge* edge : gcell->getEdges(Flags::EastSide|Flags::NorthSide) ) { + if (edge->isHorizontal()) edge->incCapacity( -getHTracksReservedLocal() ); + else edge->incCapacity( -getVTracksReservedLocal() ); + } + } + + openSession(); + size_t maxDepth = getConfiguration()->getRoutingGauge()->getDepth(); + _routingPlanes.reserve( maxDepth ); + for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { + _routingPlanes.push_back( RoutingPlane::create( this, depth ) ); + } + Session::close(); + } + + + void KatanaEngine::runGlobalRouter () + { + if (getState() >= EngineState::EngineGlobalLoaded) + throw Error ("KatanaEngine::runGlobalRouter(): Global routing already done or loaded."); + + openSession(); + + annotateGlobalGraph(); + + startMeasures(); + cmess1 << " o Running global routing..." << endl; + + float edgeHInc = getConfiguration()->getEdgeHInc(); + + openSession(); + Dijkstra* dijkstra = new Dijkstra ( this ); + dijkstra->setDistance( DigitalDistance( getConfiguration()->getEdgeCostH() + , getConfiguration()->getEdgeCostK() ) ); + + size_t iteration = 0; + size_t netCount = 0; + do { + cmess2 << " [" << setw(3) << iteration << "] nets:"; + + netCount = 0; + for ( NetData* netData : getNetOrdering() ) { + if (netData->isGlobalRouted()) continue; + + dijkstra->load( netData->getNet() ); + dijkstra->run(); + ++netCount; + } + cmess2 << left << setw(6) << netCount << right; + + const vector& ovEdges = getOvEdges(); + cmess2 << " ovEdges:" << ovEdges.size(); + + for ( Edge* edge : ovEdges ) computeNextHCost( edge, edgeHInc ); + + netCount = 0; + size_t iEdge = 0; + while ( iEdge < ovEdges.size() ) { + Edge* edge = ovEdges[iEdge]; + netCount += edge->ripup(); + + if (ovEdges[iEdge] == edge) { + cerr << Error( "AnabaticEngine::globalRoute(): Unable to ripup enough segments of edge:\n" + " %s" + , getString(edge).c_str() + ) << endl; + ++iEdge; + } + } + + dijkstra->setSearchAreaHalo( Session::getSliceHeight()*3 ); + + cmess2 << " ripup:" << netCount; + stopMeasures(); + cmess2 << " " << setw(10) << Timer::getStringTime (getTimer().getCombTime()) + << " " << setw( 6) << Timer::getStringMemory(getTimer().getIncrease()) << endl; + startMeasures(); + + ++iteration; + } while ( (netCount > 0) and (iteration < 5) ); + + stopMeasures(); + printMeasures( "Dijkstra" ); + + delete dijkstra; + Session::close(); + + setState( EngineState::EngineGlobalLoaded ); + } + + + +} // Katana namespace. diff --git a/katana/src/GraphicKatanaEngine.cpp b/katana/src/GraphicKatanaEngine.cpp new file mode 100644 index 00000000..5c9fc529 --- /dev/null +++ b/katana/src/GraphicKatanaEngine.cpp @@ -0,0 +1,306 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./GraphicKatanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +namespace Katana { + + using namespace std; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Exception; + using Hurricane::Breakpoint; + using Hurricane::DebugSession; + using Hurricane::Point; + using Hurricane::Entity; + using Hurricane::Net; + using Hurricane::Graphics; + using Hurricane::ColorScale; + using Hurricane::ControllerWidget; + using Hurricane::ExceptionWidget; + using CRL::Catalog; + using CRL::AllianceFramework; + + + size_t GraphicKatanaEngine::_references = 0; + GraphicKatanaEngine* GraphicKatanaEngine::_singleton = NULL; + + + KatanaEngine* GraphicKatanaEngine::createEngine () + { + Cell* cell = getCell (); + + KatanaEngine* katana = KatanaEngine::get( cell ); + if (not katana) { + katana = KatanaEngine::create( cell ); + katana->setPostEventCb( boost::bind(&GraphicKatanaEngine::postEvent,this) ); + katana->setViewer( _viewer ); + if (cmess1.enabled()) katana->printConfiguration(); + } else + cerr << Warning( "%s already has a Katana engine.", getString(cell).c_str() ) << endl; + + return katana; + } + + + KatanaEngine* GraphicKatanaEngine::getForFramework ( unsigned int flags ) + { + // Currently, only one framework is avalaible: Alliance. + + KatanaEngine* katana = KatanaEngine::get( getCell() ); + if (katana) return katana; + + if (flags & CreateEngine) { + katana = createEngine(); + if (not katana) + throw Error( "Failed to create Katana engine on %s.", getString(getCell()).c_str() ); + } else { + throw Error( "KatanaEngine not created yet, run the global router first." ); + } + + return katana; + } + + + void GraphicKatanaEngine::_globalRoute () + { + KatanaEngine* katana = getForFramework( CreateEngine ); + katana->runGlobalRouter(); + } + + + void GraphicKatanaEngine::_loadGlobalRouting () + { + KatanaEngine* anabatic = getForFramework( NoFlags ); + + _viewer->clearToolInterrupt(); + anabatic->loadGlobalRouting( Anabatic::EngineLoadGrByNet ); + } + + + void GraphicKatanaEngine::_balanceGlobalDensity () + { + KatanaEngine* katana = getForFramework( NoFlags ); + //katana->balanceGlobalDensity(); + katana->layerAssign( Anabatic::EngineNoNetLayerAssign ); + } + + + void GraphicKatanaEngine::_runNegociatePreRouted () + { + KatanaEngine* katana = getForFramework( CreateEngine ); + katana->runNegociate( Flags::PreRoutedStage ); + } + + + void GraphicKatanaEngine::_runNegociate () + { + KatanaEngine* katana = getForFramework( NoFlags ); + katana->runNegociate(); + } + + + void GraphicKatanaEngine::_finalize () + { + KatanaEngine* katana = getForFramework( NoFlags ); + if (katana) { + katana->finalizeLayout(); + katana->destroy(); + } + } + + + void GraphicKatanaEngine::_dumpMeasures () + { + KatanaEngine* katana = getForFramework( NoFlags ); + if (katana) katana->dumpMeasures(); + } + + + void GraphicKatanaEngine::_save () + { + Cell* cell = getCell(); + AllianceFramework* af = AllianceFramework::get(); + + string name = getString(cell->getName()) + "_katana"; + cell->setName( name ); + af->saveCell( cell, Catalog::State::Physical ); + } + + + void GraphicKatanaEngine::_detailRoute () + { + _loadGlobalRouting (); + //Breakpoint::stop( 0, "Global routing loaded." ); + _balanceGlobalDensity(); + //Breakpoint::stop( 0, "Global density balanced." ); + _runNegociate (); + } + + + void GraphicKatanaEngine::_route () + { + _runNegociatePreRouted(); + _globalRoute (); + _detailRoute (); + _finalize (); + } + + + void GraphicKatanaEngine::postEvent () + { + static unsigned int count = 0; + + if (not (count++ % 500)) { + QApplication::processEvents(); + + if (_viewer->isToolInterrupted()) { + KatanaEngine* katana = KatanaEngine::get( getCell() ); + if (katana) katana->setInterrupt( true ); + _viewer->clearToolInterrupt(); + } + } + } + + + void GraphicKatanaEngine::addToMenu ( CellViewer* viewer ) + { + assert( _viewer == NULL ); + + _viewer = viewer; + + if (_viewer->hasMenuAction("placeAndRoute.katana.route")) { + cerr << Warning( "GraphicKatanaEngine::addToMenu() - Katana detailed router already hooked in." ) << endl; + return; + } + + _viewer->addMenu ( "placeAndRoute.katana" , "Katana" ); + _viewer->addMenu ( "placeAndRoute.katana.stepByStep", "&Step by step" ); + + _viewer->addToMenu( "placeAndRoute.katana.route" + , "Katana - &Route" + , "Route the design (global & detailed)" + , std::bind(&GraphicKatanaEngine::_route,this) + ); + + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.========" ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.detailedPreRoute" + , "Katana - Detailed Pre-Route" + , "Run the Katana detailed router on pre-routed nets" + , std::bind(&GraphicKatanaEngine::_runNegociatePreRouted,this) + ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.globalRoute" + , "Katana - &Global Route" + , "Run the Knik global router" + , std::bind(&GraphicKatanaEngine::_globalRoute,this) + ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.detailedRoute" + , "Katana - &Detailed Route" + , "Run the Katana detailed router" + , std::bind(&GraphicKatanaEngine::_detailRoute,this) + ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.finalize" + , "Katana - &Finalize Routing" + , "Closing Routing" + , std::bind(&GraphicKatanaEngine::_finalize,this) + ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.dumpMeasures" + , "Katana - Dump &Measures" + , "Dumping Measurements on the disk" + , std::bind(&GraphicKatanaEngine::_dumpMeasures,this) + ); + _viewer->addToMenu( "placeAndRoute.katana.stepByStep.save" + , "Katana - &Save Design" + , "Save routed design (temporary hack)" + , std::bind(&GraphicKatanaEngine::_save,this) + ); + } + + + const Name& GraphicKatanaEngine::getName () const + { return KatanaEngine::staticGetName(); } + + + Cell* GraphicKatanaEngine::getCell () + { + if (_viewer == NULL) { + throw Error( "Katana: GraphicKatanaEngine not bound to any Viewer." ); + return NULL; + } + + if (_viewer->getCell() == NULL) { + throw Error( "Katana: No Cell is loaded into the Viewer." ); + return NULL; + } + + return _viewer->getCell(); + } + + + GraphicKatanaEngine* GraphicKatanaEngine::grab () + { + if (not _references) { + _singleton = new GraphicKatanaEngine (); + } + _references++; + + return _singleton; + } + + + size_t GraphicKatanaEngine::release () + { + --_references; + if (not _references) { + delete _singleton; + _singleton = NULL; + } + return _references; + } + + + GraphicKatanaEngine::GraphicKatanaEngine () + : GraphicTool() + , _viewer (NULL) + { } + + + GraphicKatanaEngine::~GraphicKatanaEngine () + { } + + +} // Katana namespace. diff --git a/katana/src/HorizontalTrack.cpp b/katana/src/HorizontalTrack.cpp new file mode 100644 index 00000000..0a444f73 --- /dev/null +++ b/katana/src/HorizontalTrack.cpp @@ -0,0 +1,76 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./HorizontalTrack.cpp" | +// +-----------------------------------------------------------------+ + + +#include "katana/HorizontalTrack.h" + + +namespace Katana { + + +// ------------------------------------------------------------------- +// Class : "HorizontalTrack". + + + HorizontalTrack::HorizontalTrack ( RoutingPlane* routingPlane, unsigned int index ) + : Track(routingPlane,index) + { } + + + void HorizontalTrack::_postCreate () + { } + + + HorizontalTrack* HorizontalTrack::create ( RoutingPlane* routingPlane, unsigned int index ) + { + HorizontalTrack* track = new HorizontalTrack ( routingPlane, index ); + + track->_postCreate (); + return track; + } + + + HorizontalTrack::~HorizontalTrack () + { } + + + void HorizontalTrack::_preDestroy () + { } + + + bool HorizontalTrack::isHorizontal () const { return true; } + bool HorizontalTrack::isVertical () const { return false; } + Flags HorizontalTrack::getDirection () const { return Flags::Horizontal; } + + + Point HorizontalTrack::getPosition ( DbU::Unit coordinate ) const + { + return Point ( coordinate, getAxis() ); + } + + + string HorizontalTrack::_getTypeName () const + { return "HorizontalTrack"; } + + + Record* HorizontalTrack::_getRecord () const + { + Record* record = Track::_getRecord (); + return record; + } + + +} // Katana namespace. diff --git a/katana/src/KatanaEngine.cpp b/katana/src/KatanaEngine.cpp new file mode 100644 index 00000000..7b4035cc --- /dev/null +++ b/katana/src/KatanaEngine.cpp @@ -0,0 +1,596 @@ +// -*- 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 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 : "./KatanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include "vlsisapd/utilities/Path.h" +#include "hurricane/DebugSession.h" +#include "hurricane/UpdateSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/Breakpoint.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/viewer/Script.h" +#include "crlcore/Measures.h" +#include "anabatic/AutoContact.h" +#include "katana/DataNegociate.h" +#include "katana/RoutingPlane.h" +#include "katana/Session.h" +#include "katana/TrackSegment.h" +#include "katana/NegociateWindow.h" +#include "katana/KatanaEngine.h" +#include "katana/PyKatanaEngine.h" + + +namespace Katana { + + using std::cout; + using std::cerr; + using std::endl; + using std::dec; + using std::setw; + using std::left; + using std::ostream; + using std::ofstream; + using std::ostringstream; + using std::setprecision; + using std::vector; + using std::make_pair; + using Hurricane::dbo_ptr; + using Hurricane::UpdateSession; + using Hurricane::DebugSession; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::Breakpoint; + using Hurricane::Box; + using Hurricane::Torus; + using Hurricane::Layer; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::NetRoutingExtension; + using Hurricane::Cell; + using CRL::System; + using CRL::addMeasure; + using CRL::Measures; + using CRL::MeasuresSet; + using Anabatic::EngineState; + using Anabatic::GCellsUnder; + using Anabatic::AutoContact; + using Anabatic::AutoSegmentLut; + using Anabatic::ChipTools; + + + const char* missingRW = + "%s:\n\n" + " Cell %s do not have any KatanaEngine (or not yet created).\n"; + + +// ------------------------------------------------------------------- +// Class : "Katana::KatanaEngine". + + Name KatanaEngine::_toolName = "Katana"; + + + const Name& KatanaEngine::staticGetName () + { return _toolName; } + + + KatanaEngine* KatanaEngine::get ( const Cell* cell ) + { return static_cast(ToolEngine::get(cell,staticGetName())); } + + + KatanaEngine::KatanaEngine ( Cell* cell ) + : Super (cell) + , _viewer (NULL) + , _configuration (new Configuration()) + , _routingPlanes () + , _negociateWindow(NULL) + , _minimumWL (0.0) + , _toolSuccess (false) + { } + + + void KatanaEngine::_postCreate () + { + Super::_postCreate (); + } + + + void KatanaEngine::_runKatanaInit () + { + Utilities::Path pythonSitePackages = System::getPath("pythonSitePackages"); + Utilities::Path systemConfDir = pythonSitePackages / "katana"; + Utilities::Path systemConfFile = systemConfDir / "katanaInit.py"; + + if (systemConfFile.exists()) { + Isobar::Script::addPath( systemConfDir.toString() ); + + dbo_ptr script = Isobar::Script::create( systemConfFile.stem().toString() ); + script->addKwArgument( "katana" , (PyObject*)PyKatanaEngine_Link(this) ); + script->runFunction ( "katanaHook", getCell() ); + + Isobar::Script::removePath( systemConfDir.toString() ); + } else { + cerr << Warning( "Katana system configuration file:\n <%s> not found." + , systemConfFile.toString().c_str() ) << endl; + } + } + + + void KatanaEngine::_initDataBase () + { + cdebug_log(155,1) << "KatanaEngine::_initDataBase()" << endl; + + setupGlobalGraph( Flags::NoFlags ); + setupSpecialNets(); + setupPreRouteds(); + setupPowerRails(); + protectRoutingPads(); + _runKatanaInit(); + + cdebug_tabw(155,-1); + } + + + KatanaEngine* KatanaEngine::create ( Cell* cell ) + { + KatanaEngine* katana = new KatanaEngine ( cell ); + + katana->_postCreate(); + katana->_initDataBase(); + + return katana; + } + + + void KatanaEngine::_preDestroy () + { + cdebug_log(155,1) << "KatanaEngine::_preDestroy()" << endl; + + cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <" + << _cell->getName() << ">" << endl; + + if (getState() < EngineState::EngineGutted) + setState( EngineState::EnginePreDestroying ); + + _gutKatana(); + Super::_preDestroy(); + + cmess2 << " - RoutingEvents := " << RoutingEvent::getAllocateds() << endl; + + cdebug_tabw(155,-1); + } + + + KatanaEngine::~KatanaEngine () + { delete _configuration; } + + + const Name& KatanaEngine::getName () const + { return _toolName; } + + + Configuration* KatanaEngine::getConfiguration () + { return _configuration; } + + + unsigned int KatanaEngine::getRipupLimit ( const TrackElement* segment ) const + { + if (segment->isBlockage()) return 0; + + 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* KatanaEngine::getRoutingPlaneByIndex ( size_t index ) const + { + if (index >= getRoutingPlanesSize() ) return NULL; + return _routingPlanes[index]; + } + + + RoutingPlane* KatanaEngine::getRoutingPlaneByLayer ( const Layer* layer ) const + { + for ( size_t index=0 ; index < getRoutingPlanesSize() ; index++ ) { + if (_routingPlanes[index]->getLayer() == layer) + return _routingPlanes[index]; + } + return NULL; + } + + + Track* KatanaEngine::getTrackByPosition ( const Layer* layer, DbU::Unit axis, unsigned int mode ) const + { + RoutingPlane* plane = getRoutingPlaneByLayer( layer ); + if (not plane) return NULL; + + return plane->getTrackByPosition( axis, mode ); + } + + + void KatanaEngine::openSession () + { Session::_open(this); } + + + void KatanaEngine::setInterrupt ( bool state ) + { + if (_negociateWindow) { + _negociateWindow->setInterrupt( state ); + cerr << "Interrupt [CRTL+C] of " << this << endl; + } + } + + + void KatanaEngine::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; + if (rp->getLayerGauge()->getDepth() > getConfiguration()->getAllowedDepth()) continue; + + size_t tracksSize = rp->getTracksSize(); + for ( size_t itrack=0 ; itrackgetTrackByIndex( itrack ); + + cdebug_log(159,0) << "Capacity from: " << track << endl; + + for ( size_t ielement=0 ; ielementgetSize() ; ++ielement ) { + TrackElement* element = track->getSegment( ielement ); + + if (element->getNet() == NULL) { + cdebug_log(159,0) << "Reject capacity from (not Net): " << element << endl; + continue; + } + if ( (not element->isFixed()) + and (not element->isBlockage()) + and (not element->isUserDefined()) ) { + cmess2 << "Reject capacity from (neither fixed, blockage nor user defined): " << element << endl; + continue; + } + + Segment* segment = element->base()->base(); + Flags side = Flags::EastSide; + DbU::Unit axis = segment->getY(); + if (track->getDirection() == Flags::Vertical) { + side = Flags::NorthSide; + axis = segment->getX(); + } + + int elementCapacity = -1; + cdebug_log(159,0) << "Capacity from: " << element << ":" << elementCapacity << endl; + + GCellsUnder gcells = getGCellsUnder( segment ); + if (not gcells->empty()) { + for ( size_t i=0 ; isize()-1 ; ++i ) + gcells->gcellAt(i)->getEdgeAt( side, axis )->incCapacity( elementCapacity ); + } + } + } + } + } + + + void KatanaEngine::runNegociate ( unsigned int flags ) + { + if (_negociateWindow) return; + + startMeasures(); + openSession(); + + _negociateWindow = NegociateWindow::create( this ); + _negociateWindow->setGCells( getGCells() ); + _computeCagedConstraints(); + _negociateWindow->run( flags ); + _negociateWindow->destroy(); + _negociateWindow = NULL; + + Session::close(); + stopMeasures(); + //if ( _editor ) _editor->refresh (); + + printMeasures( "algo" ); + + openSession(); + unsigned int overlaps = 0; + // size_t hTracksReservedLocal = getHTracksReservedLocal(); + // size_t vTracksReservedLocal = getVTracksReservedLocal(); + + // if (cparanoid.enabled()) { + // cparanoid << " o Post-checking Knik capacity overload h:" << hTracksReservedLocal + // << " v:." << vTracksReservedLocal << endl; + // getGCellGrid()->checkEdgeOverflow( hTracksReservedLocal, vTracksReservedLocal ); + // } + + _check( overlaps ); + Session::close(); + + _toolSuccess = _toolSuccess and (overlaps == 0); + } + + + void KatanaEngine::printCompletion () const + { + size_t routeds = 0; + unsigned long long totalWireLength = 0; + unsigned long long routedWireLength = 0; + vector unrouteds; + vector reduceds; + ostringstream result; + + AutoSegmentLut::const_iterator ilut = _getAutoSegmentLut().begin(); + for ( ; ilut != _getAutoSegmentLut().end() ; ilut++ ) { + TrackElement* segment = _lookup( ilut->second ); + if (segment == NULL) continue; + + unsigned long long wl = (unsigned long long)DbU::toLambda( segment->getLength() ); + if (wl > 100000) { + cerr << Error("KatanaEngine::printCompletion(): Suspiciously long wire: %llu for %p:%s" + ,wl,ilut->first,getString(segment).c_str()) << endl; + continue; + } + + if (segment->isFixed() or segment->isBlockage()) continue; + if (segment->isReduced()) reduceds.push_back( segment ); + + totalWireLength += wl; + if ( (segment->getTrack() != NULL) or (segment->isReduced()) ) { + routeds++; + routedWireLength += wl; + continue; + } + + unrouteds.push_back( segment ); + } + + float segmentRatio = (float)(routeds) / (float)(routeds+unrouteds.size()) * 100.0; + float wireLengthRatio = (float)(routedWireLength) / (float)(totalWireLength) * 100.0; + + _toolSuccess = (unrouteds.empty()); + + if (not unrouteds.empty()) { + cerr << " o Routing did not complete, unrouted segments:" << endl; + for ( size_t i=0; i ( getCell(), "Segs" , routeds+unrouteds.size() ); + addMeasure( getCell(), "DWL(l)" , totalWireLength , 12 ); + addMeasure( getCell(), "fWL(l)" , totalWireLength-routedWireLength , 12 ); + addMeasure ( getCell(), "WLER(%)", (expandRatio-1.0)*100.0 ); +} + + + void KatanaEngine::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; + + measures->toGnuplot( "GCells Density Histogram", getString(getCell()->getName()) ); + } + + + void KatanaEngine::dumpMeasures () const + { + ostringstream path; + path << getCell()->getName() << ".knik-katana.dat"; + + ofstream sfile ( path.str().c_str() ); + dumpMeasures( sfile ); + sfile.close(); + } + + + bool KatanaEngine::_check ( unsigned int& overlap, const char* message ) const + { + cmess1 << " o Checking Katana Database coherency." << endl; + + bool coherency = true; + coherency = coherency and Super::_check( message ); + for ( size_t i=0 ; i<_routingPlanes.size() ; i++ ) + coherency = _routingPlanes[i]->_check(overlap) and coherency; + + Anabatic::Session* anbtSession = Session::base (); + for( Net* net : getCell()->getNets() ) { + for( Segment* segment : net->getComponents().getSubSet() ) { + AutoSegment* autoSegment = anbtSession->lookup( segment ); + if (not autoSegment) continue; + if (not autoSegment->isCanonical()) continue; + + TrackElement* trackSegment = Session::lookup( segment ); + if (not trackSegment) { + coherency = false; + cerr << Bug( "%p %s without Track Segment" + , autoSegment + , getString(autoSegment).c_str() ) << endl; + } else + trackSegment->_check(); + } + } + + return coherency; + } + + + void KatanaEngine::finalizeLayout () + { + + cdebug_log(155,0) << "KatanaEngine::finalizeLayout()" << endl; + if (getState() > Anabatic::EngineDriving) return; + + cdebug_tabw(155,1); + + setState( Anabatic::EngineDriving ); + _gutKatana(); + + Super::finalizeLayout(); + cdebug_log(155,0) << "State: " << getState() << endl; + + getCell()->setFlags( Cell::Flags::Routed ); + + cdebug_tabw(155,-1); + } + + + void KatanaEngine::_gutKatana () + { + cdebug_log(155,1) << "KatanaEngine::_gutKatana()" << endl; + cdebug_log(155,0) << "State: " << getState() << endl; + + if (getState() < EngineState::EngineGutted) { + openSession(); + + size_t maxDepth = getConfiguration()->getRoutingGauge()->getDepth(); + for ( size_t depth=0 ; depth < maxDepth ; depth++ ) { + _routingPlanes[depth]->destroy(); + } + + Session::close(); + } + + cdebug_tabw(155,-1); + } + + + TrackElement* KatanaEngine::_lookup ( Segment* segment ) const + { + AutoSegment* autoSegment = Super::_lookup( segment ); + if (not autoSegment or not autoSegment->isCanonical()) return NULL; + + return _lookup( autoSegment ); + } + + + void KatanaEngine::_check ( Net* net ) const + { + cerr << " o Checking " << net << endl; + + for( Segment* segment : net->getComponents().getSubSet() ) { + TrackElement* trackSegment = _lookup( segment ); + if (trackSegment) { + trackSegment->_check(); + + AutoContact* autoContact = trackSegment->base()->getAutoSource(); + if (autoContact) autoContact->checkTopology (); + + autoContact = trackSegment->base()->getAutoTarget(); + if (autoContact) autoContact->checkTopology (); + } + } + } + + + string KatanaEngine::_getTypeName () const + { return "Katana::KatanaEngine"; } + + + string KatanaEngine::_getString () const + { + ostringstream os; + os << "<" << "KatanaEngine " << _cell->getName () << ">"; + return os.str(); + } + + + Record* KatanaEngine::_getRecord () const + { + Record* record = Super::_getRecord (); + + if (record) { + record->add( getSlot( "_routingPlanes", &_routingPlanes ) ); + record->add( getSlot( "_configuration", _configuration ) ); + } + return record; + } + + +} // Katana namespace. diff --git a/katana/src/Manipulator.cpp b/katana/src/Manipulator.cpp new file mode 100644 index 00000000..8761739c --- /dev/null +++ b/katana/src/Manipulator.cpp @@ -0,0 +1,1412 @@ +// -*- 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 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 : "./Manipulator.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/DebugSession.h" +#include "hurricane/Bug.h" +#include "katana/TrackSegment.h" +#include "katana/Track.h" +#include "katana/Tracks.h" +#include "katana/DataNegociate.h" +#include "katana/RoutingPlane.h" +#include "katana/RoutingEvent.h" +#include "katana/SegmentFsm.h" +#include "katana/Manipulator.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using namespace Katana; + using Anabatic::GCell; + + +// ------------------------------------------------------------------- +// Class : "LvGCandidate". + + class LvGCandidate { + public: + struct Compare : public binary_function { + inline bool operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const; + }; + public: + inline LvGCandidate ( TrackElement* segment=NULL, Interval overlap=Interval(), size_t terminals=0 ); + inline TrackElement* getSegment () const; + inline const Interval& getOverlap () const; + inline size_t getTerminals () const; + private: + TrackElement* _segment; + Interval _overlap; + size_t _terminals; + }; + + inline LvGCandidate::LvGCandidate ( TrackElement* segment, Interval overlap, size_t terminals ) + : _segment (segment) + , _overlap (overlap) + , _terminals(terminals) + { } + + inline TrackElement* LvGCandidate::getSegment () const { return _segment; } + inline const Interval& LvGCandidate::getOverlap () const { return _overlap; } + inline size_t LvGCandidate::getTerminals () const { return _terminals; } + + inline bool LvGCandidate::Compare::operator() ( const LvGCandidate& lhs, const LvGCandidate& rhs ) const + { + if ( lhs.getTerminals() != rhs.getTerminals() ) + return lhs.getTerminals() < rhs.getTerminals(); + + if ( lhs.getOverlap() != rhs.getOverlap() ) + return lhs.getOverlap().getSize() > rhs.getOverlap().getSize(); + + return lhs.getSegment()->getAxis() < rhs.getSegment()->getAxis(); + } + + +} // Anonymous namespace. + + +namespace Katana { + + using Hurricane::Bug; + +// ------------------------------------------------------------------- +// Class : "Manipulator". + + Manipulator::Manipulator ( TrackElement* segment, SegmentFsm& S ) + : _segment(segment) + , _data (NULL) + , _event (NULL) + , _fsm (S) + { + if (not _segment) + throw Error( "Manipulator::Manipulator(): cannot build upon a NULL TrackElement." ); + + DebugSession::open( _segment->getNet(), 150, 160 ); + + _data = _segment->getDataNegociate(); + if (_data) _event = _data->getRoutingEvent(); + } + + + Manipulator::~Manipulator () + { DebugSession::close(); } + + + bool Manipulator::canRipup ( unsigned int flags ) const + { + if (_data) { + if (not _event or _event->isUnimplemented()) return false; + + unsigned int limit = Session::getKatanaEngine()->getRipupLimit(_segment); + unsigned int count = _data->getRipupCount() + ((flags & NotOnLastRipup) ? 1 : 0); + + return (count < limit); + } + return false; + } + + + bool Manipulator::isCaged ( DbU::Unit axis ) const + { + Track* track = _segment->getTrack(); + if ( not track ) return false; + + TrackElement* neighbor = _segment->getPrevious(); + if (neighbor and (neighbor->isFixed() or neighbor->isBlockage())) { + if (abs(axis - neighbor->getTargetU()) < getPPitch()*2) + return true; + } + + neighbor = _segment->getNext(); + if (neighbor and (neighbor->isFixed() or neighbor->isBlockage())) { + if (abs(axis - neighbor->getSourceU()) < getPPitch()*2) + return true; + } + + return false; + } + + + bool Manipulator::ripup ( unsigned int type, DbU::Unit axisHint ) + { + cdebug_log(159,0) << "Manipulator::ripup() " << endl; + + if (not canRipup()) return false; + + if (_segment->isFixed()) return false; + if (_data == NULL) return true; + + _fsm.addAction( _segment, type, axisHint ); + return true; + } + + + bool Manipulator::ripupPerpandiculars ( unsigned int flags ) + { + cdebug_log(159,0) << "Manipulator::ripupPerpandiculars() - " << flags << endl; + + bool success = true; + bool cagedPerpandiculars = false; + Interval constraints ( _event->getConstraints() ); + Interval perpandicularConstraints ( constraints ); + size_t placedPerpandiculars = 0; + unsigned int parallelActionFlags = SegmentAction::SelfRipup|SegmentAction::EventLevel4; + unsigned int perpandicularActionFlags = SegmentAction::SelfRipupPerpand; + + if (flags & Manipulator::PerpandicularsFirst) { + parallelActionFlags &= ~SegmentAction::EventLevel4; + perpandicularActionFlags |= SegmentAction::EventLevel4; + if (flags & Manipulator::ToRipupLimit) + perpandicularActionFlags |= SegmentAction::ToRipupLimit; + } else { + if (flags & Manipulator::ToRipupLimit) + parallelActionFlags |= SegmentAction::ToRipupLimit; + } + + cdebug_log(159,0) << "Pure constraints: " << constraints << endl; + + Track* track = NULL; + const vector& perpandiculars = _event->getPerpandiculars(); + + for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) { + track = perpandiculars[i]->getTrack(); + if (not track) { + // The perpandicular is not placed yet. + if (flags & Manipulator::PerpandicularsFirst) { + _fsm.addAction( perpandiculars[i], perpandicularActionFlags ); + } + continue; + } + + bool dislodgeCaged = false; + if (Manipulator(perpandiculars[i],_fsm).isCaged(_event->getSegment()->getAxis())) { + cagedPerpandiculars = true; + dislodgeCaged = true; + } + + placedPerpandiculars++; + + // Try to ripup the perpandicular. + DataNegociate* data2 = perpandiculars[i]->getDataNegociate(); + cdebug_log(159,0) << "| " << perpandiculars[i] << endl; + + if ( (flags & Manipulator::ToMoveUp) and (data2->getState() < DataNegociate::MoveUp) ) + data2->setState( DataNegociate::MoveUp ); + + if (Manipulator(perpandiculars[i],_fsm).ripup(perpandicularActionFlags)) { + if (dislodgeCaged) { + _event->setAxisHint( _event->getSegment()->getAxis() + _event->getSegment()->getPitch() ); + } + continue; + } + + // Cannot ripup the perpandicular, try to ripup it's neigbors. + size_t begin; + size_t end; + track->getOverlapBounds( constraints, begin, end ); + + for ( ; (begin < end) ; begin++ ) { + TrackElement* other = track->getSegment(begin); + + if (other->getNet() == _event->getSegment()->getNet()) continue; + + Interval otherCanonical ( other->getCanonicalInterval() ); + if (not otherCanonical.intersect(constraints)) continue; + + // Try to ripup conflicting neighbor. + if (Manipulator(other,_fsm).canRipup()) { + cdebug_log(159,0) << " | Ripup: " << begin << " " << other << endl; + _fsm.addAction( other, SegmentAction::OtherRipup ); + } else { + cdebug_log(159,0) << "Aborted ripup of perpandiculars, fixed or blocked." << endl; + return false; + } + } + } + + if (cagedPerpandiculars and not placedPerpandiculars) { + cdebug_log(159,0) << "Aborted ripup of perpandiculars, constraints are due to fixed/blockage." << endl; + _fsm.addAction( _segment, SegmentAction::SelfRipup ); + return true; + } + + if (_segment->isLocal() and not placedPerpandiculars) { + cdebug_log(159,0) << "No placed perpandiculars, tight native constraints, place perpandiculars FIRST." << endl; + for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) { + _fsm.addAction( perpandiculars[i], perpandicularActionFlags|SegmentAction::EventLevel4 ); + } + _fsm.addAction( _segment, parallelActionFlags ); + return true; + } + + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_segment->getLayer()); + size_t tracksNb = 0; + + track = plane->getTrackByPosition(constraints.getVMin()); + + if (track and (track->getAxis() < constraints.getVMin())) track = track->getNextTrack(); + for ( ; track && (track->getAxis() <= constraints.getVMax()) + ; track = track->getNextTrack(), tracksNb++ ); + + if (_segment->isLocal() and (tracksNb < 2)) success = ripple(); + + _fsm.addAction( _segment, parallelActionFlags ); + return success; + } + + + bool Manipulator::relax ( Interval interval, unsigned int flags ) + { + interval.inflate( - Session::getExtensionCap(getLayer()) ); + cdebug_log(159,0) << "Manipulator::relax() of: " << _segment << " " << interval << endl; + + if (_segment->isFixed()) return false; + if (not interval.intersect(_segment->getCanonicalInterval())) return false; + if (not _data) return false; + + if ( _segment->isTerminal() + and (_segment->getLayer() == Session::getRoutingGauge()->getRoutingLayer(1)) ) { + if (interval.contains(_segment->base()->getAutoSource()->getX())) return false; + if (interval.contains(_segment->base()->getAutoTarget()->getX())) return false; + } + + cdebug_tabw(159,1); + bool success = true; + bool expand = _segment->isGlobal() and (flags&AllowExpand); + cdebug_log(159,0) << "Expand:" << expand << endl; + + vector gcells; + _segment->getGCells( gcells ); + + if (gcells.size() < 2 ){ + cerr << Bug( "relax() Cannot break %s,\n only in %s." + , getString(_segment).c_str() + , getString(gcells[0]).c_str() + ) << endl; + cdebug_tabw(159,-1); + return false; + } + + unsigned int depth = Session::getRoutingGauge()->getLayerDepth(_segment->getLayer()); + Interval uside; + size_t dogLegCount = 0; + size_t iminconflict = gcells.size(); + size_t imaxconflict = gcells.size(); + size_t igcell; + + // Look for closest enclosing min & max GCells indexes. + for ( igcell=0 ; igcellgetSide(_segment->getDirection()); + cdebug_log(159,0) << "| " << setw(3) << igcell << " " << gcells[igcell] << " uside: " << uside << endl; + + if (uside.contains(interval.getVMin())) { + iminconflict = igcell; + cdebug_log(159,0) << "> Min conflict: " << iminconflict << endl; + } + if (uside.contains(interval.getVMax())) { + imaxconflict = igcell; + cdebug_log(159,0) << "> Max conflict: " << imaxconflict << endl; + } + } + + // Expand min & max to enclose GCells of greatest or equal order + // (i.e. less saturateds) + bool minExpanded = false; + bool maxExpanded = false; + if (expand) { + if (iminconflict < gcells.size()) { + //cdebug_log(159,0) << "Expand min" << endl; + + size_t imindensity = 0; + for ( size_t iexpand=1 ; iexpandcanDogleg(gcells[iexpand],Flags::AllowDoglegReuse)) continue; + + // cdebug_log(159,0) << " Density " + // << "Density " << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() + // << " min. dens.:" << gcells[imindensity]->getDensity(depth) + // << " exp. dens.:" << gcells[iexpand ]->getDensity(depth) + // << endl; + + if (gcells[imindensity]->getDensity(depth) - gcells[iexpand]->getDensity(depth) > 1e-3) { + imindensity = iexpand; + //cdebug_log(159,0) << "Accepted expand " << imindensity << endl; + } + } + + if (iminconflict != imindensity) minExpanded = true; + iminconflict = (imindensity>0) ? imindensity : gcells.size(); + } + + if (imaxconflict < gcells.size()) { + //cdebug_log(159,0) << "Expand max" << endl; + + size_t imindensity = imaxconflict; + for ( size_t iexpand=imaxconflict+1 ; iexpandcanDogleg(gcells[iexpand],Flags::AllowDoglegReuse)) continue; + + // cdebug_log(159,0) << " Density " + // << Session::getRoutingGauge()->getRoutingLayer(depth)->getName() + // << " min. dens.:" << gcells[imindensity]->getDensity(depth) + // << " exp. dens.:" << gcells[iexpand ]->getDensity(depth) + // << endl; + + if (gcells[imindensity]->getDensity(depth) - gcells[iexpand]->getDensity(depth) > 1e-3) { + imindensity = iexpand; + //cdebug_log(159,0) << "Accepted expand " << imindensity << endl; + } + } + + if (imindensity != imaxconflict) maxExpanded = true; + imaxconflict = (imindensity < gcells.size()) ? imindensity : gcells.size(); + } + } + cdebug_log(159,0) << "minExpanded:" << minExpanded << " (" << iminconflict + << ") maxExpanded:" << maxExpanded << " (" << imaxconflict << ")" << endl; + + // Check for full enclosure. + if ( ( (iminconflict == gcells.size()) and (imaxconflict == gcells.size() ) ) + or ( (iminconflict == 0) and (imaxconflict == gcells.size()-1) )) { + cinfo << "[INFO] Manipulator::relax(): Segment fully enclosed in interval." << endl; + cdebug_tabw(159,-1); + return false; + } + + // Suppress min/max if it's the first/last. + if ((iminconflict < gcells.size()) and (imaxconflict == gcells.size()-1)) imaxconflict = gcells.size(); + if ((imaxconflict < gcells.size()) and (iminconflict == 0)) iminconflict = gcells.size(); + + // Compute number of doglegs and nature of the *first* dogleg. + // (first can be min or max, second can only be max) + bool firstDoglegIsMin = false; + if (iminconflict < gcells.size()) { dogLegCount++; firstDoglegIsMin = true; } + if (imaxconflict < gcells.size()) dogLegCount++; + + switch ( dogLegCount ) { + case 2: + // Compact only if the double dogleg is at beginning or end. + if (iminconflict == imaxconflict) { + if (iminconflict == 0) { + // First dogleg is max. + dogLegCount--; + } else if (iminconflict == gcells.size()-1) { + dogLegCount--; + firstDoglegIsMin = true; + } + } + break; + case 1: break; + case 0: + cerr << Bug( "Manipulator::relax() Can't find a GCell suitable for making dogleg." + , getString(interval).c_str() ) << endl; + cdebug_tabw(159,-1); + return false; + } + + cdebug_log(159,0) << "| Has to do " << dogLegCount << " doglegs." << endl; + + // Check of "min is less than one track close the edge" (while not expanded). + // AND we are on the first GCell AND there's one dogleg only. + if (not minExpanded and (iminconflict == 0) and (imaxconflict == gcells.size())) { + cdebug_log(159,0) << "Cannot break in first GCell only." << endl; + cdebug_tabw(159,-1); + return false; + } + + // Check of "min is less than one track close the edge" (while not expanded). + if ( /*not minExpanded and*/ (iminconflict > 0) and (iminconflict < gcells.size()) ) { + uside = gcells[iminconflict-1]->getSide(_segment->getDirection()); + cdebug_log(159,0) << "GCell Edge Comparison (min): " << uside + << " vs. " << DbU::getValueString(interval.getVMin()) << endl; + // Ugly: One lambda shrink. + if (interval.getVMin()-DbU::lambda(1.0) <= uside.getVMax()) { + cdebug_log(159,0) << "Using previous GCell." << endl; + iminconflict--; + } + } + + // Check if there is only one dogleg AND it's the last one. + if (not maxExpanded and (iminconflict == gcells.size()) and (imaxconflict == gcells.size()-1)) { + cdebug_log(159,0) << "Cannot break in last GCell only." << endl; + cdebug_tabw(159,-1); + return false; + } + + // Check of "max is less than one track close the edge" (while not expanded). + if ((imaxconflict < gcells.size()-1)) { + uside = gcells[imaxconflict+1]->getSide( _segment->getDirection() ); + cdebug_log(159,0) << "GCell Edge Comparison (max): " << uside + << " vs. " << DbU::getValueString(interval.getVMax()) << endl; + if (interval.getVMax()+getPPitch() >= uside.getVMin()) { + interval.inflate( 0, getPPitch() ); + cdebug_log(159,0) << "Using next GCell " << interval << endl; + imaxconflict++; + } + } + + size_t ifirstDogleg = gcells.size(); + size_t isecondDogleg = gcells.size(); + if (not firstDoglegIsMin) { + ifirstDogleg = imaxconflict; + } else { + ifirstDogleg = iminconflict; + isecondDogleg = imaxconflict; + } + + // Making first dogleg. + cdebug_log(159,0) << "Making FIRST dogleg at " << ifirstDogleg << endl; + TrackElement* segment1 = NULL; + TrackElement* segment2 = NULL; + Track* track = _segment->getTrack(); + Anabatic::GCell* dogLegGCell = gcells[ifirstDogleg]; + TrackElement* dogleg = NULL; + DbU::Unit doglegAxis; + bool doglegReuse1 = false; + bool doglegReuse2 = false; + + // Try to reuse existing dogleg if broken at either end. + if (ifirstDogleg == 0) dogleg = _segment->getSourceDogleg(); + if (ifirstDogleg == gcells.size()-1) dogleg = _segment->getTargetDogleg(); + if (dogleg) { + cdebug_log(159,0) << "Reusing dogleg." << endl; + doglegReuse1 = true; + segment1 = _segment; + } else { + // Try to create a new dogleg. + if (not _segment->canDogleg(dogLegGCell)) { + cdebug_log(159,0) << "Cannot create FIRST dogleg." << endl; + cdebug_tabw(159,-1); + return false; + } + _segment->makeDogleg( dogLegGCell, dogleg, segment1 ); + } + + if (firstDoglegIsMin) { + if (minExpanded) { + doglegAxis = dogLegGCell->getSide( _segment->getDirection() ).getCenter(); + //cdebug_log(159,0) << "MARK 1 doglegAxis: " << DbU::getValueString(doglegAxis) << endl; + } else { + doglegAxis = interval.getVMin() - getPPitch(); + //cdebug_log(159,0) << "MARK 2 doglegAxis: " << DbU::getValueString(doglegAxis) << endl; + } + } else { + if (maxExpanded) { + doglegAxis = dogLegGCell->getSide( _segment->getDirection() ).getVMin(); + //cdebug_log(159,0) << "MARK 3 doglegAxis: " << DbU::getValueString(doglegAxis) << endl; + } else { + doglegAxis = interval.getVMax() + getPPitch() - DbU::fromLambda(1.0); + //cdebug_log(159,0) << "MARK 4 doglegAxis: " << DbU::getValueString(doglegAxis) << endl; + } + } + if (doglegReuse1) _fsm.addAction( dogleg, SegmentAction::OtherRipup ); + else dogleg->setAxis( doglegAxis ); + + // If event is present, the dogleg is in the current RoutingSet. + RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent(); + if (event) { + cdebug_log(159,0) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl; + event->setAxisHint( doglegAxis ); + } else { + cdebug_log(159,0) << "Dogleg has no RoutingEvent yet." << endl; + } + + // Making second dogleg. + if (dogLegCount > 1) { + cdebug_log(159,0) << "Making SECOND dogleg at " << isecondDogleg + << " on " << segment1 << endl; + + dogleg = NULL; + dogLegGCell = gcells[isecondDogleg]; + + if (ifirstDogleg == isecondDogleg) { + cdebug_log(159,0) << "Double break in same GCell." << endl; + segment1->setFlags( TElemSourceDogleg ); + } + + if (isecondDogleg == gcells.size()-1) dogleg = segment1->getTargetDogleg(); + if (dogleg) { + cdebug_log(159,0) << "Reusing dogleg." << endl; + doglegReuse2 = true; + segment2 = segment1; + } else { + // Try to create a new dogleg. + if (not segment1->canDogleg(dogLegGCell)) { + cdebug_log(159,0) << "Cannot create SECOND dogleg." << endl; + cdebug_tabw(159,-1); + return false; + } + segment1->makeDogleg( dogLegGCell, dogleg, segment2 ); + } + + if (maxExpanded) { + doglegAxis = dogLegGCell->getSide(segment1->getDirection()/*,false*/).getCenter(); + } else { + doglegAxis = interval.getVMax() + getPPitch(); + } + if (doglegReuse2) _fsm.addAction( dogleg, SegmentAction::OtherRipup ); + else dogleg->setAxis( doglegAxis ); + + // If event is present, the dogleg is in the current RoutingSet. + RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent(); + if (event) { + cdebug_log(159,0) << "Set Axis Hint: @" << DbU::getValueString(doglegAxis) << " " << dogleg << endl; + event->setAxisHint( doglegAxis ); + } else { + cdebug_log(159,0) << "Dogleg has no RoutingEvent yet." << endl; + } + + // This cases seems never to occurs. + const vector& doglegs = Session::getDoglegs(); + for ( size_t i=0 ; igetTrack() and track) { + cdebug_log(159,0) << "Direct Track insert of: " << segment << endl; + Session::addInsertEvent( segment, track ); + } + } + } + + switch ( dogLegCount ) { + case 1: + if (not doglegReuse1) { + if (firstDoglegIsMin) + _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + else + segment1->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + } + if ((flags & NoDoglegReuse) and (doglegReuse1 or doglegReuse2 )) + success = false; + break; + case 2: + if (not doglegReuse1) + _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + if ( not doglegReuse2 ) + segment2->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + break; + } + + if (_segment->isLocal()) { + cdebug_log(159,0) << "Reset state of: " << _segment << endl; + _segment->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + } else { + cdebug_log(159,0) << "No state reset: " << _segment << endl; + } + + if ((not doglegReuse1) and segment1 and segment1->isLocal()) { + cdebug_log(159,0) << "Reset state of: " << segment1 << endl; + segment1->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + } + + if ((not doglegReuse2) and segment2 and segment2->isLocal()) { + cdebug_log(159,0) << "Reset state of: " << segment2 << endl; + segment2->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars, true ); + } + + cdebug_tabw(159,-1); + return success; + } + + + bool Manipulator::insertInTrack ( size_t itrack ) + { + Track* track = _fsm.getTrack(itrack); + size_t begin = _fsm.getBegin(itrack); + size_t end = _fsm.getEnd (itrack); + Net* ownerNet = _segment->getNet(); + Interval toFree (_segment->getCanonicalInterval()); + //Net* ripupNet = NULL; + set canonicals; + DbU::Unit rightAxisHint = 0; + DbU::Unit leftAxisHint = 0; + bool leftIntrication = false; + bool rightIntrication = false; + bool success = true; + + cdebug_log(159,0) << "Manipulator::insertInTrack() - " << toFree << endl; + + for ( size_t i = begin ; success && (i < end) ; i++ ) { + TrackElement* segment2 = track->getSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if ( segment2->getNet() == ownerNet ) continue; + if ( not toFree.intersect(segment2->getCanonicalInterval()) ) { + cdebug_log(159,0) << "No intersection with: " << segment2->getCanonicalInterval() << endl; + continue; + } + if ( segment2->isBlockage() or segment2->isFixed() ) { + cdebug_log(159,0) << "Ovelap is blockage or fixed." << endl; + success = false; + continue; + } + // if ( segment2->getId() >= maxId ) { + // cdebug_log(159,0) << "Ovelap has an Id superior to AutoSegment::maxId:" << maxId << "." << endl; + // continue; + // } + // ripupNet = segment2->getNet(); + + DataNegociate* data2 = segment2->getDataNegociate(); + if ( !data2 ) { + cdebug_log(159,0) << "No DataNegociate, ignoring." << endl; + continue; + } + + if ( data2->getState() == DataNegociate::MaximumSlack ) { + cdebug_log(159,0) << "At " << DataNegociate::getStateString(data2) + << " for " << segment2 << endl; + success = false; + continue; + } + + bool shrinkLeft = false; + bool shrinkRight = false; + + if ( data2->getRightMinExtend() < toFree.getVMin() ) { + cdebug_log(159,0) << "- Shrink right edge (push left) " << segment2 << endl; + shrinkRight = true; + TrackElement* rightNeighbor2 = track->getSegment(i+1); + if ( rightNeighbor2 && (rightNeighbor2->getNet() == segment2->getNet()) ) { + Interval interval1 = segment2->getCanonicalInterval(); + Interval interval2 = rightNeighbor2->getCanonicalInterval(); + + if ( interval1.intersect(interval2) && (interval2.getVMax() > interval1.getVMax()) ) + shrinkLeft = true; + } + } + + if ( data2->getLeftMinExtend() > toFree.getVMax() ) { + cdebug_log(159,0) << "- Shrink left edge (push right) " << segment2 << endl; + shrinkLeft = true; + if ( i > 0 ) { + TrackElement* leftNeighbor2 = track->getSegment(i-1); + if ( leftNeighbor2 && (leftNeighbor2->getNet() == segment2->getNet()) ) { + Interval interval1 = segment2->getCanonicalInterval(); + Interval interval2 = leftNeighbor2->getCanonicalInterval(); + + if ( interval1.intersect(interval2) && (interval2.getVMin() < interval1.getVMin()) ) + shrinkRight = true; + } + } + } + + if ( _segment->isLocal() and segment2->isLocal() ) { + if ( shrinkLeft and shrinkRight ) { + Interval interval1 = segment2->getCanonicalInterval(); + if ( toFree.getCenter() < interval1.getCenter() ) shrinkRight = false; + else shrinkLeft = false; + } + } + + cdebug_log(159,0) << "- Hard overlap/enclosure/shrink " << segment2 << endl; + if ( _segment->isStrap() and segment2->isGlobal() ) continue; + if ( not (success = Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup)) ) + continue; + + canonicals.clear (); + for( TrackElement* segment3 + : segment2->getPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) { + DataNegociate* data3 = segment3->getDataNegociate(); + if ( not data3 ) continue; + + RoutingEvent* event3 = data3->getRoutingEvent(); + if ( not event3 ) continue; + + if ( not toFree.intersect(event3->getConstraints()) ) { + cdebug_log(159,0) << " . " << segment3 << endl; + continue; + } + + cdebug_log(159,0) << " | " << segment3 << endl; + + if ( shrinkRight xor shrinkLeft ) { + if ( shrinkRight ) { + if ( not (success=Manipulator(segment3,_fsm) + .ripup( SegmentAction::OtherRipupPerpandAndPushAside + , toFree.getVMin() - getPPitch()/2 + )) ) + break; + + if ( event3->getTracksFree() == 1 ) { + cdebug_log(159,0) << "Potential left intrication with other perpandicular." << endl; + if ( segment3->getAxis() == segment2->getTargetU() - Session::getExtensionCap(getLayer()) ) { + leftIntrication = true; + leftAxisHint = segment3->getAxis(); + } + } + } + if ( shrinkLeft ) { + if ( not (success=Manipulator(segment3,_fsm) + .ripup( SegmentAction::OtherRipupPerpandAndPushAside + , toFree.getVMax() + getPPitch()/2 + )) ) + break; + if ( event3->getTracksFree() == 1 ) { + cdebug_log(159,0) << "Potential right intrication with other perpandicular." << endl; + if ( segment3->getAxis() == segment2->getSourceU() + Session::getExtensionCap(getLayer()) ) { + rightIntrication = true; + rightAxisHint = segment3->getAxis(); + } + } + } + } else { + if ( not (success=Manipulator(segment3,_fsm).ripup( SegmentAction::OtherRipup + | SegmentAction::EventLevel3 + )) ) + break; + } + } + if ( not success ) break; + } + + if ( success ) { + cdebug_log(159,0) << "Manipulator::insertInTrack() success" << endl; + + _fsm.setState ( SegmentFsm::OtherRipup ); + _fsm.addAction ( _segment + , SegmentAction::SelfInsert|SegmentAction::MoveToAxis|SegmentAction::EventLevel4 + , _fsm.getCost(itrack).getTrack()->getAxis() ); + + unsigned int flags = 0; + if ( rightIntrication ) flags |= RightAxisHint; + if ( leftIntrication ) flags |= LeftAxisHint; + if ( flags ) + Manipulator(_segment,_fsm).shrinkToTrack(itrack,flags,leftAxisHint,rightAxisHint); + } else + _fsm.clearActions (); + + return success; + } + + + bool Manipulator::forceToTrack ( size_t itrack ) + { + Track* track = _fsm.getTrack(itrack); + size_t begin = _fsm.getBegin(itrack); + size_t end = _fsm.getEnd (itrack); + Net* ownerNet = _segment->getNet(); + Interval toFree (_segment->getCanonicalInterval()); + //Net* ripupNet = NULL; + set canonicals; + bool success = true; + + cdebug_log(159,0) << "Manipulator::forceToTrack() - " << toFree << endl; + + for ( size_t i=begin ; success and (i < end) ; ++i ) { + TrackElement* segment2 = track->getSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if (segment2->getNet() == ownerNet) continue; + if (not toFree.intersect(segment2->getCanonicalInterval())) continue; + if (segment2->isFixed()) { + success = false; + continue; + } + //ripupNet = segment2->getNet(); + + DataNegociate* data2 = segment2->getDataNegociate(); + if (not data2 ) { + cdebug_log(159,0) << "No DataNegociate, ignoring." << endl; + continue; + } + + cdebug_log(159,0) << "- Forced ripup " << segment2 << endl; + if (not (success=Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup))) + continue; + + canonicals.clear(); + for( TrackElement* segment3 + : segment2->getPerpandiculars().getSubSet(TrackElements_UniqCanonical(canonicals)) ) { + DataNegociate* data3 = segment3->getDataNegociate(); + if (not data3) continue; + + RoutingEvent* event3 = data3->getRoutingEvent(); + if (not event3) continue; + + if (Manipulator(segment3,_fsm).canRipup()) + _fsm.addAction( segment3, SegmentAction::OtherRipup ); + } + } + + if (success) { + _fsm.setState ( SegmentFsm::OtherRipup ); + _fsm.addAction( _segment + , SegmentAction::SelfInsert|SegmentAction::MoveToAxis + , _fsm.getCost(itrack).getTrack()->getAxis() ); + } + + return success; + } + + + bool Manipulator::shrinkToTrack ( size_t i, unsigned int flags, DbU::Unit leftAxisHint, DbU::Unit rightAxisHint ) + { +#if THIS_IS_DISABLED + Track* track = _fsm.getTrack(i); + size_t begin = _fsm.getBegin(i); + size_t end = _fsm.getEnd (i); + Net* ownerNet = _segment->getNet(); + set canonicals; + bool success = true; + DbU::Unit leftExtend = _segment->getSourceU() + Session::getExtensionCap(getLayer()); + DbU::Unit rightExtend = _segment->getSourceU() - Session::getExtensionCap(getLayer()); + + cdebug_log(159,0) << "Manipulator::shrinkToTrack()" << endl; + + if (_segment->isLocal()) return false; + Interval shrunkFree = _segment->base()->getMinSpanU(); + + cdebug_log(159,0) << "* " << shrunkFree << endl; + + for ( size_t i = begin ; success and (i < end) ; ++i ) { + TrackElement* segment2 = track->getSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if (segment2->getNet() == ownerNet) continue; + if (segment2->isFixed()) { success = false; continue; } + if (not shrunkFree.intersect(segment2->getCanonicalInterval())) continue; + + success = false; + } + + if (success) { + set perpandiculars; + set::iterator iperpand; + + DbU::Unit axisHint; + if (not (flags & LeftAxisHint )) leftAxisHint = shrunkFree.getCenter(); + if (not (flags & RightAxisHint)) rightAxisHint = shrunkFree.getCenter(); + + _segment->getPerpandicularsBound( perpandiculars ); + for ( iperpand = perpandiculars.begin() ; iperpand != perpandiculars.end() ; ++iperpand ) { + DataNegociate* data2 = (*iperpand)->getDataNegociate(); + if (data2) { + cdebug_log(159,0) << "| perpandicular bound:" << *iperpand << endl; + success = Manipulator(*iperpand,_fsm).ripup( SegmentAction::SelfRipupPerpandWithAxisHint ); + if (success) { + if ((*iperpand)->getAxis() == leftExtend ) axisHint = leftAxisHint; + else if ((*iperpand)->getAxis() == rightExtend) axisHint = rightAxisHint; + else { + cinfo << "[INFO] Bound Axis is neither left nor right\n " << (*iperpand) << endl; + axisHint = shrunkFree.getCenter(); + } + + _fsm.getActions()[_fsm.getActions().size()-1].setAxisHint( axisHint ); + } + } + } + + _fsm.addAction( _segment, SegmentAction::SelfInsert ); + _fsm.setState ( SegmentFsm::OtherRipup ); + + cdebug_log(159,0) << "Successful shrinkToTrack." << endl; + return true; + } +#endif + + return false; + } + + + bool Manipulator::forceOverLocals () + { + cdebug_log(159,1) << "Manipulator::forceOverLocals()" << endl; + + vector& costs = _fsm.getCosts(); + size_t itrack = 0; + for ( ; itrackgetNet(); + Interval toFree (_segment->getCanonicalInterval()); + + for ( size_t i = begin ; success and (i < end) ; i++ ) { + TrackElement* segment2 = track->getSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if ( segment2->getNet() == ownerNet ) continue; + if ( not toFree.intersect(segment2->getCanonicalInterval()) ) continue; + if ( segment2->isFixed() ) { + success = false; + continue; + } + + DataNegociate* data2 = segment2->getDataNegociate(); + if ( not data2 ) { + cdebug_log(159,0) << "No DataNegociate, ignoring." << endl; + success = false; + continue; + } + + cdebug_log(159,0) << "- Forced ripup " << segment2 << endl; + if ( not (success=Manipulator(segment2,_fsm).ripup(SegmentAction::OtherRipup)) ) { + continue; + } + } + + if (success) { + _fsm.setState ( SegmentFsm::OtherRipup ); + _fsm.addAction( _segment + , SegmentAction::SelfInsert|SegmentAction::MoveToAxis + , _fsm.getCost(itrack).getTrack()->getAxis() + ); + break; + } + } + + cdebug_tabw(159,-1); + return (itrack < costs.size()); + } + + + bool Manipulator::slacken ( unsigned int flags ) + { + cdebug_log(159,0) << "Manipulator::slacken() " << _segment << endl; + + if ( _segment->isFixed ()) return false; + if (not _segment->canSlacken()) return false; + + return _segment->slacken( flags ); + } + + + bool Manipulator::ripple () + { + cdebug_log(159,0) << "Manipulator::ripple() from " << _segment << endl; + + //if (not _segment->canRipple()) return false; + if (not _segment->isLocal()) return false; + + Net* net = _segment->getNet(); + Interval uside = _segment->base()->getAutoSource()->getGCell()->getSide ( Anabatic::perpandicularTo(_segment->getDirection())/*, false*/ ); + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_segment->getLayer()); + + cdebug_tabw(159,1); + for( Track* track : Tracks_Range::get(plane,uside)) { + size_t begin; + size_t end; + + track->getOverlapBounds( _segment->getCanonicalInterval(), begin, end ); + for ( ; begin < end ; begin++ ) { + TrackElement* other = track->getSegment(begin); + cdebug_log(159,0) << "| " << other << endl; + + if (other->getNet() == net) continue; + if (not other->canRipple()) continue; + + DataNegociate* otherData = other->getDataNegociate(); + if (not otherData) continue; + + DbU::Unit shiftedAxisHint; + RoutingEvent* otherEvent = otherData->getRoutingEvent(); + + if (other->getAxis() < _segment->getAxis()) { + // Ugly: routing pitch. + shiftedAxisHint = otherEvent->getAxisHint() - getPitch(); + if (shiftedAxisHint < uside.getVMin()) + shiftedAxisHint = uside.getVMin(); + } else { + // Ugly: routing pitch. + shiftedAxisHint = otherEvent->getAxisHint() + getPitch(); + if (shiftedAxisHint > uside.getVMax()) + shiftedAxisHint = uside.getVMax(); + } + + otherEvent->setAxisHint( shiftedAxisHint ); + _fsm.addAction( other, SegmentAction::OtherRipup ); + } + } + cdebug_tabw(159,-1); + + return true; + } + + + bool Manipulator::pivotUp () + { + cdebug_log(159,0) << "Manipulator::pivotUp() " << _segment << endl; + return false; + + if (_segment->isFixed()) return false; + if (_segment->isStrap()) return false; + + float reserve = (_segment->isLocal()) ? 0.5 : 1.0; + if (not _segment->canMoveUp(reserve)) return false; + + return _segment->moveUp( Flags::NoFlags ); + } + + + bool Manipulator::pivotDown () + { + cdebug_log(159,0) << "Manipulator::pivotDown() " << _segment << endl; + return false; + + if ( _segment->isFixed () ) return false; + if ( _segment->isStrap () ) return false; + if (not _segment->canPivotDown(2.0)) return false; + + return _segment->moveDown( Flags::NoFlags ); + } + + + bool Manipulator::moveUp ( unsigned int flags ) + { + cdebug_log(159,0) << "Manipulator::moveUp() " << _segment << endl; + + unsigned int kflags = Flags::WithNeighbors; + //kflags |= (flags & AllowLocalMoveUp ) ? Flags::AutoSegment::AllowLocal : 0; + kflags |= (flags & AllowTerminalMoveUp) ? Flags::AllowTerminal : 0; + + if (_segment->isFixed()) return false; + if (not (flags & AllowLocalMoveUp)) { + if (_segment->isLocal()) { + if (not _segment->canPivotUp(0.5)) return false; + } else { + if (_segment->getLength() < 20*getPitch()) { + if (not (flags & AllowShortPivotUp)) return false; + if (not _segment->canPivotUp(1.0)) return false; + } + if (not _segment->canMoveUp(0.5,kflags)) return false; + } + } else { + if (not _segment->canMoveUp(0.5,kflags)) return false; + } + return _segment->moveUp( kflags ); + } + + + bool Manipulator::makeDogleg () + { + cdebug_log(159,0) << "Manipulator::makeDogleg() " << _segment << endl; + + if ( _segment->isFixed()) return false; + if (not _segment->isLocal()) return false; + if (_segment->getLength() < 5*getPitch()) return false; + + if (_fsm.getCosts().size()) { + Track* track = _fsm.getTrack(0); + size_t begin = _fsm.getBegin(0); + size_t end = _fsm.getEnd (0); + Net* ownerNet = _segment->getNet(); + Interval toFree (_segment->getCanonicalInterval()); + Interval overlap; + + for ( size_t i=begin ; igetSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if ( segment2->getNet() == ownerNet) continue; + if (not toFree.intersect(segment2->getCanonicalInterval())) continue; + + if (overlap.isEmpty()) + overlap = segment2->getCanonicalInterval(); + else + overlap.merge( segment2->getCanonicalInterval() ); + } + + if (not overlap.isEmpty() and makeDogleg(overlap)) return true; + } + + if (not _segment->canDogleg()) return false; + _segment->makeDogleg(); + + return true; + } + + + bool Manipulator::makeDogleg ( Interval overlap ) + { + cdebug_log(159,0) << "Manipulator::makeDogleg(Interval) " << _segment << endl; + cdebug_log(159,0) << overlap << endl; + + if ( _segment->isFixed () ) return false; + if (not _segment->canDogleg(overlap)) return false; + + unsigned int flags = 0; + TrackElement* dogleg = _segment->makeDogleg(overlap,flags); + if (dogleg) { + cdebug_log(159,0) << "Manipulator::makeDogleg(Interval) - Push dogleg to the " + << ((flags&Flags::DoglegOnLeft)?"left":"right") << endl; + if (_segment->isTerminal()) { + Anabatic::AutoContact* contact = + (flags&Flags::DoglegOnLeft) ? _segment->base()->getAutoSource() + : _segment->base()->getAutoTarget(); + DbU::Unit axisHint = (_segment->isHorizontal()) ? contact->getX() : contact->getY(); + RoutingEvent* event = dogleg->getDataNegociate()->getRoutingEvent(); + if (event) { + event->setAxisHint ( axisHint ); + event->setForcedToHint( true ); + cdebug_log(159,0) << "Forced to axis hint @" << DbU::getValueString(axisHint) << endl; + } + } + return true; + } + + return false; + } + + + bool Manipulator::makeDogleg ( DbU::Unit position ) + { + cdebug_log(159,0) << "Manipulator::makeDogleg(position) " << _segment << endl; + cdebug_log(159,0) << "Breaking position: " << DbU::getValueString(position) << endl; + + if (_segment->isFixed()) return false; + + vector gcells; + _segment->getGCells( gcells ); + + size_t igcell = 0; + for ( ; igcellgetSide(_segment->getDirection()).contains(position)) + break; + } + if (igcell == gcells.size()) return false; + if (not _segment->canDogleg(gcells[igcell])) return false; + + TrackElement* dogleg = NULL; + TrackElement* parallel = NULL; + _segment->makeDogleg( gcells[igcell], dogleg, parallel ); + return (dogleg != NULL); + } + + + bool Manipulator::minimize () + { + cdebug_log(159,0) << "Manipulator::minimize() " << _segment << endl; + + if (_segment->isFixed()) return false; + if (not _event->canMinimize()) return false; + + DbU::Unit minSpan = DbU::Max; + DbU::Unit maxSpan = DbU::Min; + Interval punctualSpan ( false ); + + if (_segment->base()->getAutoSource()->getAnchor()) { + cdebug_log(159,0) << " | " << _segment->base()->getAutoSource() << endl; + Interval constraints ( _segment->base()->getAutoSource()->getUConstraints + (perpandicularTo(_segment->getDirection())) ); + cdebug_log(159,0) << " | Constraints: " << constraints << endl; + + minSpan = min( minSpan, constraints.getVMax() ); + maxSpan = max( maxSpan, constraints.getVMin() ); + punctualSpan.intersection( constraints ); + } + + if (_segment->base()->getAutoTarget()->getAnchor()) { + cdebug_log(159,0) << " | " << _segment->base()->getAutoTarget() << endl; + Interval constraints ( _segment->base()->getAutoTarget()->getUConstraints + (perpandicularTo(_segment->getDirection())) ); + cdebug_log(159,0) << " | Constraints: " << constraints << endl; + + minSpan = min( minSpan, constraints.getVMax() ); + maxSpan = max( maxSpan, constraints.getVMin() ); + punctualSpan.intersection( constraints ); + } + + const vector& perpandiculars = _event->getPerpandiculars(); + for ( size_t i=0 ; igetDataNegociate(); + if (not data2) continue; + + cdebug_log(159,0) << " | " << perpandiculars[i] << endl; + + RoutingEvent* event2 = data2->getRoutingEvent(); + if (not event2) continue; + + cdebug_log(159,0) << " | Constraints: " << event2->getConstraints() << endl; + + minSpan = min( minSpan, event2->getConstraints().getVMax() ); + maxSpan = max( maxSpan, event2->getConstraints().getVMin() ); + punctualSpan.intersection( event2->getConstraints() ); + } + if (minSpan > maxSpan) swap( minSpan, maxSpan ); + + cdebug_log(159,0) << "punctualSpan: " << punctualSpan + << " min/max span: [" << DbU::getValueString(minSpan) + << ":" << DbU::getValueString(maxSpan) << "]" + << " long: [" << minSpan + << ":" << maxSpan << "]" << endl; + + vector holes; + for ( size_t itrack=0 ; itrack<_fsm.getCosts().size() ; itrack++ ) { + size_t begin = _fsm.getBegin(itrack); + size_t end = _fsm.getEnd (itrack); + Track* track = _fsm.getTrack(itrack); + + if (end < track->getSize()) end++; + + cdebug_log(159,0) << "Looking for holes in " << _fsm.getCost(itrack) << endl; + + TrackElement* otherPrevious = NULL; + // ToDo: Manage disjoint but subsequent segment of a Net. + // (currently, that hole will not be found). + for ( ; begin < end ; begin++ ) { + TrackElement* otherSegment = track->getSegment(begin); + if (otherSegment->getNet() == _segment->getNet()) continue; + if (not otherPrevious) { + holes.push_back( Interval(track->getMin() + ,otherSegment->getSourceU()) ); + cdebug_log(159,0) << "| First hole: " << holes.back() << " " << otherSegment << endl; + } else { + if (otherSegment->getNet() == otherPrevious->getNet()) continue; + + holes.push_back( Interval(otherPrevious->getTargetU() + ,otherSegment ->getSourceU()) ); + cdebug_log(159,0) << "| Found hole: " << holes.back() + << " " << otherPrevious << " <-> " << " " << otherSegment << endl; + } + otherPrevious = otherSegment; + } + } + + if (holes.empty()) { + cdebug_log(159,0) << "No holes found to minimize into." << endl; + return false; + } + + Interval currentSpan = _segment->getCanonicalInterval(); + Interval biggestHole; + for ( size_t i=0 ; i currentSpan.getIntersection(biggestHole).getSize() ) + biggestHole = holes[i]; + } + + DbU::Unit axisHint = 0; + if (not punctualSpan.isEmpty()) { + bool success = false; + + if (biggestHole.intersect(punctualSpan)) { + cdebug_log(159,0) << "Go as punctual into biggest hole: " << biggestHole << endl; + axisHint = biggestHole.intersection(punctualSpan).getCenter(); + success = true; + } else { + for ( size_t i=0 ; igetDataNegociate(); + if (not data2) continue; + + cdebug_log(159,0) << " | " << perpandiculars[i] << endl; + + RoutingEvent* event2 = data2->getRoutingEvent(); + if (not event2) continue; + + _fsm.addAction( perpandiculars[i], SegmentAction::SelfRipupPerpandWithAxisHint, axisHint ); + } + + _event->setMinimized(); + + return true; + } + + + void Manipulator::reprocessPerpandiculars () + { + if ( _event->getAxisHistory() == _event->getAxisHint() ) return; + + bool moveLeft = (_event->getAxisHistory() > _event->getAxisHint()); + + const vector& perpandiculars = _event->getPerpandiculars(); + for ( size_t iperpand=0 ; iperpandgetDataNegociate(); + + if ( perpandicular->isFixed() ) continue; + if ( not data ) continue; + if ( not perpandicular->getTrack() ) continue; + if ( not Manipulator(perpandicular,_fsm).canRipup() + or (data->getState() >= DataNegociate::MaximumSlack) ) continue; + + // Ugly: ExtensionCap usage. + if ( moveLeft ) { + if ( perpandicular->getTargetU()-Session::getExtensionCap(getLayer()) == _event->getAxisHistory() ) + _fsm.addAction ( perpandicular, SegmentAction::OtherRipupPerpandAndPacking ); + } else { + if ( perpandicular->getSourceU()+Session::getExtensionCap(getLayer()) == _event->getAxisHistory() ) + _fsm.addAction ( perpandicular, SegmentAction::OtherRipupPerpandAndPacking ); + } + } + } + + + void Manipulator::repackPerpandiculars () + { + cdebug_log(159,0) << "Manipulator::repackPerpandiculars()" << endl; + + const vector& perpandiculars = _event->getPerpandiculars(); + for ( size_t iperpand=0 ; iperpandgetDataNegociate(); + + if (perpandicular->isFixed ()) continue; + if (perpandicular->isGlobal()) continue; + if (not data) continue; + + if (RoutingEvent::getStage() == RoutingEvent::Repair) { + data->setState( DataNegociate::Repair ); + if (data->getStateCount() > 1) data->resetStateCount(); + } + _fsm.addAction( perpandicular, SegmentAction::SelfRipupPerpand ); + } + _fsm.addAction( _segment, SegmentAction::SelfRipup|SegmentAction::EventLevel4 ); + } + + +} // Katana namespace. diff --git a/katana/src/NegociateWindow.cpp b/katana/src/NegociateWindow.cpp new file mode 100644 index 00000000..f816be8e --- /dev/null +++ b/katana/src/NegociateWindow.cpp @@ -0,0 +1,631 @@ +// -*- 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 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 : "./NegociateWindow.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include "hurricane/Warning.h" +#include "hurricane/Bug.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/Net.h" +#include "hurricane/Cell.h" +#include "crlcore/Utilities.h" +#include "crlcore/AllianceFramework.h" +#include "crlcore/Measures.h" +#include "crlcore/Histogram.h" +#include "anabatic/AutoContact.h" +#include "katana/DataNegociate.h" +#include "katana/TrackElement.h" +#include "katana/TrackMarker.h" +#include "katana/TrackCost.h" +#include "katana/Track.h" +#include "katana/TrackSegment.h" +#include "katana/RoutingPlane.h" +#include "katana/RoutingEventQueue.h" +#include "katana/RoutingEventHistory.h" +#include "katana/RoutingEventLoop.h" +#include "katana/NegociateWindow.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using namespace CRL; + using namespace Katana; + + + void NegociateOverlapCost ( const TrackElement* segment, TrackCost& cost ) + { + cdebug_log(9000,0) << "Deter| NegociateOverlapCost() " << segment << endl; + Interval intersect = segment->getCanonicalInterval(); + + if (not intersect.intersect(cost.getInterval())) return; + + if (segment->isBlockage() or segment->isFixed()) { + cdebug_log(159,0) << "Infinite cost from: " << segment << endl; + cost.setInfinite (); + cost.setOverlap (); + cost.setHardOverlap(); + cost.setBlockage (); + return; + } + + if (cost.getInterval().getVMax() > intersect.getVMax()) cost.setLeftOverlap(); + if (cost.getInterval().getVMin() < intersect.getVMin()) cost.setRightOverlap(); + + if (not intersect.contains(cost.getInterval())) + intersect.intersection( cost.getInterval() ); + else { + cost.setLonguestOverlap( intersect.getSize() ); + cost.setGlobalEnclosed(); + } + + DataNegociate* data = segment->getDataNegociate(); + if (not data) return; + + cost.mergeRipupCount( data->getRipupCount() ); + if ( segment->isLocal() ) { + cost.mergeDataState( data->getState() ); + if (data->getState() >= DataNegociate::LocalVsGlobal) { + cdebug_log(159,0) << "MaximumSlack/LocalVsGlobal for " << segment << endl; + } + } + + if (segment->isGlobal()) { + cost.setOverlapGlobal(); + if ( (cost.getFlags() & TrackCost::LocalAndTopDepth) + and (data->getState() >= DataNegociate::MoveUp) ) { + cost.setInfinite (); + cost.setOverlap (); + cost.setHardOverlap(); + return; + } + } + + cost.setOverlap(); + if ( segment->isLocal() + or (cost.isForGlobal() and (Session::getRoutingGauge()->getLayerDepth(segment->getLayer()) < 3)) ) { + cdebug_log(9000,0) << "Deter| incTerminals() " << boolalpha << cost.isForGlobal() << " " << (data->getTerminals()*100) << endl; + cost.incTerminals( data->getTerminals()*100 ); + } else { + cdebug_log(9000,0) << "Deter| isForGlobal() " << boolalpha << cost.isForGlobal() << endl; + } + + cdebug_log(159,0) << "| Increment Delta: " << DbU::getValueString(intersect.getSize()) << endl; + cost.incDelta( intersect.getSize() ); + } + + + void loadRoutingPads ( NegociateWindow* nw ) + { + AllianceFramework* af = AllianceFramework::get (); + RoutingGauge* rg = nw->getKatanaEngine()->getConfiguration()->getRoutingGauge(); + + for( Net* net : nw->getCell()->getNets() ) { + if (net->getType() == Net::Type::POWER ) continue; + if (net->getType() == Net::Type::GROUND) continue; + if (net->getType() == Net::Type::CLOCK ) continue; + if (af->isBLOCKAGE(net->getName())) continue; + + for( RoutingPad* rp : net->getRoutingPads() ) { + size_t depth = rg->getLayerDepth(rp->getLayer()); + if (depth > 0) continue; + if (depth == 0) + TrackMarker::create( rp, 1 ); + } + } + } + + +} // Anonymous namespace. + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::setw; + using std::left; + using std::right; + using std::setprecision; + using Hurricane::Warning; + using Hurricane::Bug; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using CRL::Histogram; + using CRL::addMeasure; + using Anabatic::AutoContact; + using Anabatic::AutoSegmentLut; + using Anabatic::perpandicularTo; + + +// ------------------------------------------------------------------- +// Class : "NegociateWindow". + + + NegociateWindow::NegociateWindow ( KatanaEngine* katana ) + : _flags (Flags::NoFlags) + , _interrupt (false) + , _katana (katana) + , _gcells () + , _segments () + , _eventQueue () + , _eventHistory() + , _eventLoop (10,50) + { } + + + NegociateWindow* NegociateWindow::create ( KatanaEngine* katana ) + { + NegociateWindow* negociateWindow = new NegociateWindow ( katana ); + return negociateWindow; + } + + + NegociateWindow::~NegociateWindow () + { } + + + void NegociateWindow::destroy () + { delete this; } + + + Cell* NegociateWindow::getCell () const + { return _katana->getCell(); } + + + void NegociateWindow::setGCells ( const vector& gcells ) + { + _gcells = gcells; + + loadRoutingPads( this ); + Session::revalidate(); + + for ( auto element : Session::getKatanaEngine()->_getAutoSegmentLut() ) { + TrackElement* segment = Session::lookup( element.second ); + if (segment) segment->getDataNegociate()->update(); + } + + _statistics.setGCellsCount( _gcells.size() ); + } + + + void NegociateWindow::addRoutingEvent ( TrackElement* segment, unsigned int level ) + { + DataNegociate* data = segment->getDataNegociate(); + if (not data or not data->hasRoutingEvent()) + _eventQueue.add( segment, level ); + else + cerr << Bug( "NegociateWidow::addRoutingEvent(): Try to adds twice the same TrackElement event." + "\n %p:%s." + , (void*)segment->base()->base() + , getString(segment).c_str() + ) << endl; + } + + + TrackElement* NegociateWindow::createTrackSegment ( AutoSegment* autoSegment, unsigned int flags ) + { + cdebug_log(159,1) << "NegociateWindow::createTrackSegment() - " << autoSegment << endl; + + // Special case: fixed AutoSegments must not interfere with blockages. + // Ugly: uses of getExtensionCap(). + if (autoSegment->isFixed()) { + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(autoSegment->getLayer()); + Track* track = plane->getTrackByPosition( autoSegment->getAxis() ); + size_t begin; + size_t end; + Interval fixedSpan; + Interval blockageSpan; + + autoSegment->getCanonical( fixedSpan ); + fixedSpan.inflate( Session::getExtensionCap(autoSegment->getLayer())-1 ); + + track->getOverlapBounds( fixedSpan, begin, end ); + for ( ; (begin < end) ; begin++ ) { + + TrackElement* other = track->getSegment(begin); + cdebug_log(159,0) << "| overlap: " << other << endl; + + if (not other->isBlockage()) continue; + + other->getCanonical( blockageSpan ); + blockageSpan.inflate( Session::getExtensionCap(autoSegment->getLayer()) ); + + cdebug_log(159,0) << " fixed:" << fixedSpan << " vs. blockage:" << blockageSpan << endl; + + if (not fixedSpan.intersect(blockageSpan)) continue; + + // Overlap between fixed & blockage. + cdebug_log(159,0) << "* Blockage overlap: " << autoSegment << endl; + Session::destroyRequest( autoSegment ); + + cerr << Warning( "Overlap between fixed %s and blockage at %s." + , getString(autoSegment).c_str() + , getString(blockageSpan).c_str() ) << endl; + cdebug_tabw(159,-1); + return NULL; + } + } + + Interval span; + autoSegment = autoSegment->getCanonical( span ); + + bool created; + TrackElement* trackSegment = TrackSegment::create( autoSegment, NULL, created ); + + if (not (flags & Flags::LoadingStage)) + cdebug_log(159,0) << "* lookup: " << autoSegment << endl; + + if (created) { + cdebug_log(159,0) << "* " << trackSegment << endl; + + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(autoSegment->getLayer()); + Track* track = plane->getTrackByPosition ( autoSegment->getAxis() ); + Interval uside = autoSegment->getAutoSource()->getGCell()->getSide( perpandicularTo(autoSegment->getDirection()) ); + + if (track->getAxis() > uside.getVMax()) track = track->getPreviousTrack(); + if (track->getAxis() < uside.getVMin()) track = track->getNextTrack(); + + cdebug_log(159,0) << "* GCell U-side " << uside << endl; + cdebug_log(159,0) << "* " << plane << endl; + cdebug_log(159,0) << "* " << track << endl; + + trackSegment->setAxis( track->getAxis(), Anabatic::SegAxisSet ); + trackSegment->invalidate(); + + if (trackSegment->isFixed()) { + Session::addInsertEvent( trackSegment, track ); + } else { + _segments.push_back( trackSegment ); + } + } + + if (not created and not (flags & Flags::LoadingStage)) { + cdebug_log(159,0) << "TrackSegment already exists (and not in loading stage)." << endl; + } + + cdebug_tabw(159,-1); + + return trackSegment; + } + + + double NegociateWindow::computeWirelength () + { + set accounteds; + double totalWL = 0.0; + + for ( size_t igcell=0 ; igcell<_gcells.size() ; ++igcell ) { + double gcellWL = 0.0; + Segment* segment; + TrackElement* trackSegment; + + const vector& contacts = _gcells[igcell]->getContacts(); + for ( size_t i=0 ; igetBodyHook()->getSlaveHooks() ) { + Hook* sourceHook = dynamic_cast(hook); + if (not sourceHook) continue; + + segment = dynamic_cast(sourceHook->getComponent()); + trackSegment = Session::lookup( segment ); + if (trackSegment) { + if (accounteds.find(trackSegment) != accounteds.end()) continue; + + accounteds.insert( trackSegment ); + gcellWL += DbU::getLambda( trackSegment->getLength() ); + } + } + } + + // Partial sum to limit rounding errors. + totalWL += gcellWL; + } + + return totalWL; + } + + + void NegociateWindow::_createRouting ( Anabatic::GCell* gcell ) + { + cdebug_log(159,1) << "NegociateWindow::_createRouting() - " << gcell << endl; + + Segment* segment; + AutoSegment* autoSegment; + + cdebug_log(159,0) << "AutoSegments from AutoContacts" << endl; + const vector& contacts = gcell->getContacts(); + for ( size_t i=0 ; igetSlaveComponents() ) { + segment = dynamic_cast(component); + autoSegment = Session::base()->lookup( segment ); + cdebug_log(159,0) << autoSegment << endl; + if (autoSegment and autoSegment->isCanonical()) { + createTrackSegment( autoSegment, Flags::LoadingStage ); + } + } + } + + cdebug_log(159,0) << "_segments.size():" << _segments.size() << endl; + cdebug_tabw(159,-1); + } + + + void NegociateWindow::_pack ( size_t& count, bool last ) + { + unsigned long limit = _katana->getEventsLimit(); + unsigned int pushStage = RoutingEvent::getStage(); + RoutingEvent::setStage( RoutingEvent::Pack ); + + RoutingEventQueue packQueue; + //for ( size_t i = (count > 600) ? count-600 : 0 + // ; (i<_eventHistory.size()-(last ? 0 : 100)) and not isInterrupted() ; i++ ) { + for ( size_t i=0 ; i<_eventHistory.size() ; ++i ) { + RoutingEvent* event = _eventHistory.getNth(i); + + if ( event and not event->isCloned() ) { + cerr << "Cloned:" << event->isCloned() + << " UTurn:" << event->getSegment()->isUTurn() << " " << event->getSegment() << endl; + } + + if ( event and not event->isCloned() and event->getSegment()->isUTurn() ) { + event->reschedule( packQueue, 0 ); + } + } + packQueue.commit(); + + while ( not packQueue.empty() and not isInterrupted() ) { + RoutingEvent* event = packQueue.pop(); + + if (tty::enabled()) { + cmess2 << " " + << setfill(' ') << tty::reset << tty::cr; + cmess2.flush(); + } else { + cmess2 << " getEventLevel() << ":" << event->getPriority() << "> " + << event->getSegment() + << endl; + cmess2.flush(); + } + + event->process( packQueue, _eventHistory, _eventLoop ); + + if (RoutingEvent::getProcesseds() >= limit) setInterrupt( true ); + } + // Count will be wrong! + + RoutingEvent::setStage( pushStage ); + } + + + size_t NegociateWindow::_negociate () + { + cdebug_log(9000,0) << "Deter| NegociateWindow::_negociate()" << endl; + cdebug_log(159,1) << "NegociateWindow::_negociate() - " << _segments.size() << endl; + + cmess1 << " o Negociation Stage." << endl; + + unsigned long limit = _katana->getEventsLimit(); + + _eventHistory.clear(); + _eventQueue.load( _segments ); + cmess2 << " " << endl; + if (cdebug.enabled(9000)) _eventQueue.dump(); + + size_t count = 0; + RoutingEvent::setStage( RoutingEvent::Negociate ); + while ( not _eventQueue.empty() and not isInterrupted() ) { + RoutingEvent* event = _eventQueue.pop(); + + if (tty::enabled()) { + cmess2 << " " << tty::cr; + cmess2.flush (); + } else { + cmess2 << " getEventLevel() << ":" << event->getPriority() << "> " + << event->getSegment() + << endl; + cmess2.flush(); + } + + event->process( _eventQueue, _eventHistory, _eventLoop ); + count++; + + //if (count and not (count % 500)) { + // _pack( count, false ); + //} + + if (RoutingEvent::getProcesseds() >= limit) setInterrupt( true ); + } + //_pack( count, true ); + if (count and cmess2.enabled() and tty::enabled()) cmess1 << endl; + + cdebug_log(9000,0) << "Deter| Repair Stage" << endl; + cmess1 << " o Repair Stage." << endl; + + cdebug_log(159,0) << "Loadind Repair queue." << endl; + RoutingEvent::setStage( RoutingEvent::Repair ); + for ( size_t i=0 ; (i<_eventHistory.size()) and not isInterrupted() ; i++ ) { + RoutingEvent* event = _eventHistory.getNth(i); + + if (not event->isCloned() and event->isUnimplemented()) { + event->reschedule( _eventQueue, 0 ); + } + } + _eventQueue.commit(); + cmess2 << " " << endl; + + count = 0; + //_eventQueue.prepareRepair(); + while ( not _eventQueue.empty() and not isInterrupted() ) { + RoutingEvent* event = _eventQueue.pop(); + + if (tty::enabled()) { + cmess2 << " " + << setfill(' ') << tty::reset << tty::cr; + cmess2.flush(); + } else { + cmess2 << " getEventLevel() << ":" << event->getPriority() << "> " + << event->getSegment() + << endl; + cmess2.flush(); + } + + event->process( _eventQueue, _eventHistory, _eventLoop ); + + count++; + if (RoutingEvent::getProcesseds() >= limit ) setInterrupt( true ); + } + + if (count and cmess2.enabled() and tty::enabled()) cmess1 << endl; + + size_t eventsCount = _eventHistory.size(); + + _eventHistory.clear(); + _eventQueue.clear(); + + if (RoutingEvent::getAllocateds() > 0) { + cerr << Bug( "%d events remains after clear.", RoutingEvent::getAllocateds() ) << endl; + } + + _statistics.setEventsCount( eventsCount ); + cdebug_tabw(159,-1); + + return eventsCount; + } + + + void NegociateWindow::run ( unsigned int flags ) + { + cdebug_log(159,1) << "NegociateWindow::run()" << endl; + + cmess1 << " o Running Negociate Algorithm" << endl; + + TrackElement::setOverlapCostCB( NegociateOverlapCost ); + RoutingEvent::resetProcesseds(); + + for ( size_t igcell=0 ; igcell<_gcells.size() ; ++igcell ) { + _createRouting( _gcells[igcell] ); + } + Session::revalidate(); + + if (not (flags & Flags::PreRoutedStage)) { + _katana->preProcess(); + Session::revalidate(); + } + + _katana->setMinimumWL( computeWirelength() ); + +#if defined(CHECK_DATABASE) + unsigned int overlaps = 0; + Session::getKatanaEngine()->_check( overlaps, "after _createRouting(GCell*)" ); +#endif + + _flags |= flags; + _negociate(); + printStatistics(); + + if (flags & Flags::PreRoutedStage) { + _katana->setFixedPreRouted(); + } + + Session::revalidate(); + Session::get()->isEmpty(); + +# if defined(CHECK_DATABASE) + _katana->_check( overlaps, "after negociation" ); +# endif + + cdebug_tabw(159,-1); + } + + + void NegociateWindow::printStatistics () const + { + cmess1 << " o Computing statistics." << endl; + cmess1 << Dots::asSizet(" - Processeds Events Total",RoutingEvent::getProcesseds()) << endl; + cmess1 << Dots::asSizet(" - Unique Events Total" + ,(RoutingEvent::getProcesseds() - RoutingEvent::getCloneds())) << endl; + cmess1 << Dots::asSizet(" - # of GCells",_statistics.getGCellsCount()) << endl; + _katana->printCompletion(); + + addMeasure( getCell(), "Events" , RoutingEvent::getProcesseds(), 12 ); + addMeasure( getCell(), "UEvents", RoutingEvent::getProcesseds()-RoutingEvent::getCloneds(), 12 ); + + Histogram* densityHistogram = new Histogram ( 1.0, 0.1, 2 ); + addMeasure( getCell(), "GCells Density Histogram", densityHistogram ); + + densityHistogram->setFileExtension( ".density.histogram" ); + densityHistogram->setMainTitle ( "GCell Densities" ); + densityHistogram->setTitle ( "Avg. Density", 0 ); + densityHistogram->setTitle ( "Peak Density", 1 ); + densityHistogram->setColor ( "green", 0 ); + densityHistogram->setColor ( "red" , 1 ); + + const vector& gcells = getKatanaEngine()->getGCells(); + + getKatanaEngine()->setDensityMode( Anabatic::AnabaticEngine::MaxHVDensity ); + for ( size_t igcell=0 ; igcelladdSample( gcells[igcell]->getDensity(), 0 ); + } + + getKatanaEngine()->setDensityMode( Anabatic::AnabaticEngine::MaxDensity ); + for ( size_t igcell=0 ; igcelladdSample( gcells[igcell]->getDensity(), 1 ); + } + + densityHistogram->normalize( 0 ); + densityHistogram->normalize( 1 ); + } + + + string NegociateWindow::_getString () const + { + ostringstream os; + + os << "<" << _getTypeName() << ">"; + return os.str(); + } + + + Record* NegociateWindow::_getRecord () const + { + Record* record = new Record ( _getString() ); + + record->add( getSlot( "_gcells", _gcells ) ); + return record; + } + + +} // Katana namespace. diff --git a/katana/src/PowerRails.cpp b/katana/src/PowerRails.cpp new file mode 100644 index 00000000..88cbf6fe --- /dev/null +++ b/katana/src/PowerRails.cpp @@ -0,0 +1,1329 @@ +// -*- 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 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 : "./PowerRails.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/DebugSession.h" +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "hurricane/DataBase.h" +#include "hurricane/Technology.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/RegularLayer.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/NetExternalComponents.h" +#include "hurricane/NetRoutingProperty.h" +#include "hurricane/Instance.h" +#include "hurricane/Plug.h" +#include "hurricane/Path.h" +#include "hurricane/Query.h" +#include "crlcore/AllianceFramework.h" +#include "anabatic/GCell.h" +#include "katana/RoutingPlane.h" +#include "katana/TrackFixedSegment.h" +#include "katana/Track.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using Hurricane::DebugSession; + using Hurricane::Warning; + using Hurricane::Error; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Interval; + using Hurricane::Net; + using Hurricane::DeepNet; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::RoutingPad; + using Hurricane::NetExternalComponents; + using Hurricane::NetRoutingExtension; + using Hurricane::NetRoutingState; + using Hurricane::Instance; + using Hurricane::Plug; + using Hurricane::Path; + using Hurricane::Query; + using Hurricane::Go; + using Hurricane::Rubber; + using Hurricane::Layer; + using Hurricane::BasicLayer; + using Hurricane::RegularLayer; + using Hurricane::Transformation; + using Hurricane::Technology; + using Hurricane::DataBase; + using CRL::AllianceFramework; + using Anabatic::GCell; + using Anabatic::ChipTools; + using namespace Katana; + + +// ------------------------------------------------------------------- +// Local Functions. + + void destroyRing ( Net* net ) + { + for( RoutingPad* rp : net->getRoutingPads() ) { + bool allMasters = true; + vector ring; + for( Hook* hook : rp->getBodyHook()->getHooks() ) { + if (not hook->isMaster()) { allMasters = false; break; } + ring.push_back( hook ); + } + if (allMasters) { + for ( auto hook : ring ) { + hook->_setNextHook( hook ); + } + } + } + } + + +// ------------------------------------------------------------------- +// Class : "::GlobalNetTable". + + class GlobalNetTable { + public: + enum Flag { ClockIsRouted=0x0001 }; + public: + GlobalNetTable ( KatanaEngine* ); + bool isCoreClockNetRouted ( const Net* ) const; + inline Cell* getTopCell () const; + Net* getRootNet ( const Net*, Path ) const; + inline Net* getVdde () const; + inline Net* getVddi () const; + inline Net* getVsse () const; + inline Net* getVssi () const; + inline Net* getCk () const; + inline Net* getCki () const; + inline Net* getCko () const; + inline Net* getBlockage () const; + inline void setBlockage ( Net* ); + private: + bool guessGlobalNet ( const Name&, Net* ); + private: + unsigned int _flags; + Name _vddePadNetName; + Name _vddiPadNetName; + Name _vssePadNetName; + Name _vssiPadNetName; + Name _ckPadNetName; + Name _ckiPadNetName; + Name _ckoPadNetName; + Net* _vdde; + Net* _vddi; + Net* _vsse; + Net* _vssi; + Net* _ck; // Clock net on the (external) pad. + Net* _cki; // Clock net in the pad ring. + Net* _cko; // Clock net of the core (design). + Net* _blockage; + Cell* _topCell; + }; + + + inline Cell* GlobalNetTable::getTopCell () const { return _topCell; } + inline Net* GlobalNetTable::getVdde () const { return _vdde; } + inline Net* GlobalNetTable::getVddi () const { return _vddi; } + inline Net* GlobalNetTable::getVsse () const { return _vsse; } + inline Net* GlobalNetTable::getVssi () const { return _vssi; } + inline Net* GlobalNetTable::getCk () const { return _ck; } + inline Net* GlobalNetTable::getCki () const { return _cki; } + inline Net* GlobalNetTable::getCko () const { return _cko; } + inline Net* GlobalNetTable::getBlockage () const { return _blockage; } + inline void GlobalNetTable::setBlockage ( Net* net ) { _blockage=net; } + + GlobalNetTable::GlobalNetTable ( KatanaEngine* katana ) + : _flags (0) + , _vddePadNetName("vdde") + , _vddiPadNetName("vddi") + , _vssePadNetName("vsse") + , _vssiPadNetName("vssi") + , _ckPadNetName ("pad" ) + , _ckiPadNetName ("ck" ) + , _ckoPadNetName ("cko" ) + , _vdde (NULL) + , _vddi (NULL) + , _vsse (NULL) + , _vssi (NULL) + , _ck (NULL) + , _cki (NULL) + , _cko (NULL) + , _blockage(NULL) + , _topCell (katana->getCell()) + { + if (_topCell == NULL) return; + + cmess1 << " o Looking for powers/grounds & clocks." << endl; + + AllianceFramework* af = AllianceFramework::get(); + + bool hasPad = false; + for( Instance* instance : _topCell->getInstances() ) { + if (af->isPad(instance->getMasterCell())) { + if (not hasPad) { + cmess1 << " o Design has pads, assuming complete chip top structure." << endl; + hasPad = true; + } + + string padName = getString( instance->getMasterCell()->getName() ); + if (padName.substr(0,8) == "pvddeck_") { + cmess1 << " o Reference power pad: " << instance->getName() + << "(model:" << instance->getMasterCell()->getName() << ")." << endl; + + // Guessing the power, ground and clock nets from *this* pad connexions. + for( Plug* plug : instance->getPlugs() ) { + Net* masterNet = plug->getMasterNet(); + Net::Type netType = masterNet->getType(); + if ( (netType != Net::Type::POWER ) + and (netType != Net::Type::GROUND) + and (netType != Net::Type::CLOCK ) ) continue; + + Net* net = plug->getNet(); + if (not net) { + net = _topCell->getNet( masterNet->getName() ); + if (not net) { + cerr << Error("Missing global net <%s> at chip level.",getString(masterNet->getName()).c_str()) << endl; + continue; + } + } + + guessGlobalNet( masterNet->getName(), net ); + } + } + + padName = getString( instance->getMasterCell()->getName() ); + if (padName.substr(0,4) == "pck_") { + cmess1 << " o Reference clock pad: " << instance->getName() + << "(model:" << instance->getMasterCell()->getName() << ")." << endl; + + // Guessing external clock net *only* from *this* pad connexions. + for( Plug* plug : instance->getPlugs() ) { + Net* masterNet = plug->getMasterNet(); + Net* net = plug->getNet(); + if (not net) { + net = _topCell->getNet( masterNet->getName() ); + if (not net) { + cerr << Error("Missing global net <%s> at chip level.",getString(masterNet->getName()).c_str()) << endl; + continue; + } + } + + if (masterNet->getName() == _ckPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as external chip clock net." << endl; + _ck = net; + } + } + } + } + } + + if (hasPad) { + if (_vdde == NULL) cerr << Error("Missing net (for pads) at chip level." ) << endl; + else destroyRing( _vdde ); + if (_vsse == NULL) cerr << Error("Missing net (for pads) at chip level." ) << endl; + else destroyRing( _vsse ); + if (_vddi == NULL) cerr << Error("Missing / net (for pads) at top level." ) << endl; + else destroyRing( _vddi ); + if (_vssi == NULL) cerr << Error("Missing / net (for pads) at top level." ) << endl; + else destroyRing( _vssi ); + if (_ck == NULL) cerr << Warning("No net at (for pads) chip level." ) << endl; + if (_cki == NULL) cerr << Warning("No net at (for pads) chip level." ) << endl; + else destroyRing( _cki ); + } else { + _vddiPadNetName = ""; + _vssiPadNetName = ""; + _ckoPadNetName = ""; + + for( Net* net : _topCell->getNets() ) { + Net::Type netType = net->getType(); + + if (netType == Net::Type::CLOCK) { + if (not net->isExternal()) continue; + + if (_ckoPadNetName.isEmpty()) { + cmess1 << " - Using <" << net->getName() << "> as internal (core) clock net." << endl; + _ckoPadNetName = net->getName(); + _cko = net; + if (NetRoutingExtension::isMixedPreRoute(net)) { + cmess1 << " (core clock net is already routed)" << endl; + _flags |= ClockIsRouted; + } else { + cmess1 << " (core clock net will be routed as an ordinary signal)" << endl; + } + } else { + cerr << Error("Second clock net <%s> net at top block level will be ignored.\n" + " (will consider only <%s>)" + , getString(net ->getName()).c_str() + , getString(_cko->getName()).c_str() + ) << endl; + } + } + + if (NetRoutingExtension::isManualGlobalRoute(net)) continue; + + if (netType == Net::Type::POWER) { + if (_vddiPadNetName.isEmpty()) { + _vddiPadNetName = net->getName(); + _vddi = net; + } else { + cerr << Error("Second power supply net <%s> net at top block level will be ignored.\n" + " (will consider only <%s>)" + , getString(net ->getName()).c_str() + , getString(_vddi->getName()).c_str() + ) << endl; + } + } + + if (netType == Net::Type::GROUND) { + if (_vssiPadNetName.isEmpty()) { + _vssiPadNetName = net->getName(); + _vssi = net; + } else { + cerr << Error("Second power ground net <%s> net at top block level will be ignored.\n" + " (will consider only <%s>)" + , getString(net ->getName()).c_str() + , getString(_vssi->getName()).c_str() + ) << endl; + } + } + } + + if (_vddi == NULL) cerr << Error("Missing net at top block level." ) << endl; + else destroyRing( _vddi ); + if (_vssi == NULL) cerr << Error("Missing net at top block level." ) << endl; + else destroyRing( _vssi ); + } + + if (_cko == NULL) cparanoid << Warning("No clock net at top level." ) << endl; + } + + + bool GlobalNetTable::guessGlobalNet ( const Name& name, Net* net ) + { + if (name == _vddePadNetName) { + cmess1 << " - Using <" << net->getName() << "> as corona (external:vdde) power net." << endl; + _vdde = net; + return true; + } + + if (name == _vddiPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as core (internal:vddi) power net." << endl; + _vddi = net; + return true; + } + + if (name == _vssePadNetName) { + cmess1 << " - Using <" << net->getName() << "> as corona (external:vsse) ground net." << endl; + _vsse = net; + return true; + } + + if (name == _vssiPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as core (internal:vssi) ground net." << endl; + _vssi = net; + return true; + } + + if (name == _ckiPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as corona (external:cki) clock net." << endl; + _cki = net; + return true; + } + + if (name == _ckoPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as core (internal:cko) clock net." << endl; + _cko = net; + + if (NetRoutingExtension::isMixedPreRoute(_cko)) { + cmess1 << " (core clock net is already routed)" << endl; + _flags |= ClockIsRouted; + } else { + cmess1 << " (core clock net will be routed as an ordinary signal)" << endl; + } + return true; + } + + if (name == _ckPadNetName) { + cmess1 << " - Using <" << net->getName() << "> as external chip clock net." << endl; + _ck = net; + return true; + } + + return false; + } + + + Net* GlobalNetTable::getRootNet ( const Net* net, Path path ) const + { + cdebug_log(159,0) << " getRootNet:" << path << ":" << net << endl; + + if (net == _blockage) return _blockage; + + if (_vdde and (net->getName() == _vdde->getName())) return _vdde; + if (_vsse and (net->getName() == _vsse->getName())) return _vsse; + + if (net->getType() == Net::Type::POWER ) return _vddi; + if (net->getType() == Net::Type::GROUND) return _vssi; + if (net->getType() != Net::Type::CLOCK ) { + return NULL; + } + + // Track up, *only* for clocks. + const Net* upNet = net; + + if (not path.isEmpty()) { + DeepNet* deepClockNet = getTopCell()->getDeepNet( path, net ); + if (deepClockNet) { + cdebug_log(159,0) << " Deep Clock Net:" << deepClockNet + << " state:" << NetRoutingExtension::getFlags(deepClockNet) << endl; + + return NetRoutingExtension::isFixed(deepClockNet) ? _blockage : NULL; + } else { + cdebug_log(159,0) << " Top Clock Net:" << net + << " state:" << NetRoutingExtension::getFlags(net) << endl; + } + + Path upPath = path; + Instance* instance = NULL; + Plug* plug = NULL; + + while ( true ) { + cdebug_log(159,0) << " " << path << "+" << upNet << endl; + + if (path.isEmpty()) break; + if ((upNet == NULL) or not upNet->isExternal()) return _blockage; + + instance = path.getTailInstance(); + plug = instance->getPlug(upNet); + if (plug == NULL) return NULL; + + upNet = plug->getNet(); + path = path.getHeadPath(); + } + } + + cdebug_log(159,0) << " Check againts top clocks ck:" << ((_ck) ? _ck->getName() : "NULL") + << " cki:" << ((_cki) ? _cki->getName() : "NULL") + << " cko:" << ((_cko) ? _cko->getName() : "NULL") + << endl; + + if (_ck and (upNet->getName() == _ck->getName() )) return _ck; + if (_cki and (upNet->getName() == _cki->getName())) return _cki; + + if (_cko) { + if (upNet->getName() == _cko->getName()) { + if (isCoreClockNetRouted(upNet)) return _cko; + } + } + + return NetRoutingExtension::isFixed(upNet) ? _blockage : NULL; + } + + + bool GlobalNetTable::isCoreClockNetRouted ( const Net* net ) const + { return (net == _cko) and (_flags & ClockIsRouted); } + + +// ------------------------------------------------------------------- +// Class : "::PowerRailsPlanes". + + class PowerRailsPlanes { + public: + class Rails; + class Plane; + + class Rail { + public: + Rail ( Rails*, DbU::Unit axis, DbU::Unit width ); + inline DbU::Unit getAxis () const; + inline DbU::Unit getWidth () const; + inline Rails* getRails () const; + inline RoutingPlane* getRoutingPlane () const; + inline unsigned int getDirection () const; + inline Net* getNet () const; + void merge ( DbU::Unit source, DbU::Unit target ); + void doLayout ( const Layer* ); + string _getString () const; + private: + Rails* _rails; + DbU::Unit _axis; + DbU::Unit _width; + list _chunks; + }; + + private: + class RailCompare { + public: + bool operator() ( const Rail* lhs, const Rail* rhs ); + }; + + class RailMatch : public unary_function { + public: + inline RailMatch ( DbU::Unit axis, DbU::Unit width ); + inline bool operator() ( const Rail* ); + private: + DbU::Unit _axis; + DbU::Unit _width; + }; + + public: + class Rails { + public: + Rails ( Plane*, unsigned int direction, Net* ); + ~Rails (); + inline Plane* getPlane (); + inline RoutingPlane* getRoutingPlane (); + inline unsigned int getDirection () const; + inline Net* getNet () const; + void merge ( const Box& ); + void doLayout ( const Layer* ); + private: + Plane* _plane; + unsigned int _direction; + Net* _net; + vector _rails; + }; + + public: + class Plane { + public: + typedef map RailsMap; + public: + Plane ( const Layer*, RoutingPlane* ); + ~Plane (); + inline const Layer* getLayer () const; + inline RoutingPlane* getRoutingPlane (); + inline unsigned int getDirection () const; + inline unsigned int getPowerDirection () const; + void merge ( const Box&, Net* ); + void doLayout (); + private: + const Layer* _layer; + RoutingPlane* _routingPlane; + RailsMap _horizontalRails; + RailsMap _verticalRails; + unsigned int _powerDirection; + }; + + public: + typedef map PlanesMap; + public: + PowerRailsPlanes ( KatanaEngine* ); + ~PowerRailsPlanes (); + inline Net* getRootNet ( Net*, Path ); + inline bool isCoreClockNetRouted ( const Net* ) const; + bool hasPlane ( const BasicLayer* ); + bool setActivePlane ( const BasicLayer* ); + inline Plane* getActivePlane () const; + inline Plane* getActiveBlockagePlane () const; + void merge ( const Box&, Net* ); + void doLayout (); + private: + KatanaEngine* _katana; + GlobalNetTable _globalNets; + PlanesMap _planes; + Plane* _activePlane; + Plane* _activeBlockagePlane; + }; + + + PowerRailsPlanes::Rail::Rail ( Rails* rails, DbU::Unit axis, DbU::Unit width ) + : _rails (rails) + , _axis (axis) + , _width (width) + , _chunks() + { + cdebug_log(159,0) << " new Rail " + << " @" << DbU::getValueString(axis) + << " " << getRoutingPlane()->getLayer()->getName() + << " " << getRails()->getNet() + << " " << ((getDirection()==Flags::Horizontal) ? "Horizontal" : "Vertical")<< endl; + } + + inline DbU::Unit PowerRailsPlanes::Rail::getAxis () const { return _axis; } + inline DbU::Unit PowerRailsPlanes::Rail::getWidth () const { return _width; } + inline PowerRailsPlanes::Rails* PowerRailsPlanes::Rail::getRails () const { return _rails; } + inline RoutingPlane* PowerRailsPlanes::Rail::getRoutingPlane () const { return _rails->getRoutingPlane(); } + inline unsigned int PowerRailsPlanes::Rail::getDirection () const { return _rails->getDirection(); } + inline Net* PowerRailsPlanes::Rail::getNet () const { return _rails->getNet(); } + + + void PowerRailsPlanes::Rail::merge ( DbU::Unit source, DbU::Unit target ) + { + Interval chunkToMerge ( source, target ); + cdebug_log(159,0) << " Rail::merge() " + << ((getDirection()==Flags::Horizontal) ? "Horizontal" : "Vertical") + << " " << chunkToMerge << endl; + cdebug_log(159,0) << " | " << _getString() << endl; + + list::iterator imerge = _chunks.end(); + list::iterator ichunk = _chunks.begin(); + + while ( ichunk != _chunks.end() ) { + if (imerge == _chunks.end()) { + if (chunkToMerge.getVMax() < (*ichunk).getVMin()) { + cdebug_log(159,0) << " | Insert before " << *ichunk << endl; + imerge = _chunks.insert( ichunk, chunkToMerge ); + break; + } + + if (chunkToMerge.intersect(*ichunk)) { + cdebug_log(159,0) << " | Merge with " << *ichunk << endl; + imerge = ichunk; + (*imerge).merge( chunkToMerge ); + } + } else { + if (chunkToMerge.getVMax() >= (*ichunk).getVMin()) { + (*imerge).merge( *ichunk ); + cdebug_log(159,0) << " | Absorb (erase) " << *ichunk << endl; + ichunk = _chunks.erase( ichunk ); + continue; + } else + break; + } + + // if (chunkToMerge.intersect(*ichunk)) { + // if (imerge == _chunks.end()) { + // cdebug_log(159,0) << " | Merge with " << *ichunk << endl; + // imerge = ichunk; + // (*imerge).merge( chunkToMerge ); + // } else { + // (*imerge).merge( *ichunk ); + // cdebug_log(159,0) << " | Absorb (erase) " << *ichunk << endl; + // ichunk = _chunks.erase( ichunk ); + // continue; + // } + // } + ++ichunk; + } + + if (imerge == _chunks.end()) { + _chunks.insert( ichunk, chunkToMerge ); + cdebug_log(159,0) << " | Insert at end " << DbU::getValueString(_axis) << " " << chunkToMerge << endl; + cdebug_log(159,0) << " | " << _getString() << endl; + } + } + + + void PowerRailsPlanes::Rail::doLayout ( const Layer* layer ) + { + cdebug_log(159,0) << "Doing layout of rail: " + << " " << layer->getName() + << " " << ((getDirection()==Flags::Horizontal) ? "Horizontal" : "Vertical") + << " @" << DbU::getValueString(_axis) << endl; + cdebug_log(159,0) << _getString() << endl; + + Net* net = getNet(); + RoutingPlane* plane = getRoutingPlane(); + Segment* segment = NULL; + //DbU::Unit delta = plane->getLayerGauge()->getPitch() + // - plane->getLayerGauge()->getHalfWireWidth() + // - DbU::fromLambda(0.1); + DbU::Unit delta = plane->getLayerGauge()->getObstacleDw() - DbU::fromLambda(0.1); + DbU::Unit extension = layer->getExtentionCap(); + //DbU::Unit extension = Session::getExtentionCap(); + //unsigned int type = plane->getLayerGauge()->getType(); + const Box& coronaBb = plane->getKatanaEngine()->getChipTools().getCoronaBb(); + DbU::Unit axisMin = 0; + DbU::Unit axisMax = 0; + + cdebug_log(159,0) << " delta:" << DbU::getValueString(delta) + << " (pitch:" << DbU::getValueString(plane->getLayerGauge()->getPitch()) + << " , ww/2:" << DbU::getValueString(plane->getLayerGauge()->getHalfWireWidth()) + << ")" << endl; + + // if ( type == Constant::PinOnly ) { + // cdebug_log(159,0) << " Layer is PinOnly." << endl; + // return; + // } + + if ( getDirection() == Flags::Horizontal ) { + list::iterator ichunk = _chunks.begin(); + list::iterator ichunknext = ichunk; + ++ichunknext; + + for ( ; ichunk != _chunks.end() ; ++ichunk, ++ichunknext ) { + + if (ichunknext != _chunks.end()) { + if ((*ichunk).intersect(*ichunknext)) + cerr << Error( "Overlaping consecutive chunks in %s %s Rail @%s:\n" + " %s" + , getString(layer->getName()).c_str() + , ((getDirection()==Flags::Horizontal) ? "Horizontal" : "Vertical") + , DbU::getValueString(_axis).c_str() + , _getString().c_str() + ) << endl; + } + + cdebug_log(159,0) << " chunk: [" << DbU::getValueString((*ichunk).getVMin()) + << ":" << DbU::getValueString((*ichunk).getVMax()) << "]" << endl; + + segment = Horizontal::create ( net + , layer + , _axis + , _width + , (*ichunk).getVMin()+extension + , (*ichunk).getVMax()-extension + ); + if ( segment and net->isExternal() ) + NetExternalComponents::setExternal ( segment ); + + axisMin = _axis - _width/2; + axisMax = _axis + _width/2; + if (coronaBb.contains(segment->getBoundingBox())) { + axisMin -= delta; + axisMax += delta; + } + + Track* track = plane->getTrackByPosition ( axisMin, Constant::Superior ); + for ( ; track and (track->getAxis() <= axisMax) ; track = track->getNextTrack() ) { + TrackElement* element = TrackFixedSegment::create ( track, segment ); + cdebug_log(159,0) << " Insert in " << track << "+" << element << endl; + } + } + } else { + list::iterator ichunk = _chunks.begin(); + for ( ; ichunk != _chunks.end() ; ichunk++ ) { + cdebug_log(159,0) << " chunk: [" << DbU::getValueString((*ichunk).getVMin()) + << ":" << DbU::getValueString((*ichunk).getVMax()) << "]" << endl; + + segment = Vertical::create ( net + , layer + , _axis + , _width + , (*ichunk).getVMin()+extension + , (*ichunk).getVMax()-extension + ); + if ( segment and net->isExternal() ) + NetExternalComponents::setExternal ( segment ); + + axisMin = _axis - _width/2; + axisMax = _axis + _width/2; + //if (coronaBb.contains(segment->getBoundingBox())) { + axisMin -= delta; + axisMax += delta; + //} + + cdebug_log(159,0) << " axisMin:" << DbU::getValueString(axisMin) + << " axisMax:" << DbU::getValueString(axisMax) << endl; + + Track* track = plane->getTrackByPosition ( axisMin, Constant::Superior ); + for ( ; track and (track->getAxis() <= axisMax) ; track = track->getNextTrack() ) { + TrackElement* element = TrackFixedSegment::create ( track, segment ); + cdebug_log(159,0) << " Insert in " << track + << "+" << element + << " " << (net->isExternal() ? "external" : "internal") + << endl; + } + } + } + } + + + string PowerRailsPlanes::Rail::_getString () const + { + ostringstream os; + + os << "::const_iterator ichunk = _chunks.begin(); + for ( ; ichunk != _chunks.end() ; ++ichunk ) { + if (ichunk != _chunks.begin()) os << " "; + os << "[" << DbU::getValueString((*ichunk).getVMin()) + << " " << DbU::getValueString((*ichunk).getVMax()) << "]"; + } + os << ">"; + return os.str(); + } + + + inline bool PowerRailsPlanes::RailCompare::operator() ( const Rail* lhs, const Rail* rhs ) + { + if ( lhs->getAxis () < rhs->getAxis () ) return true; + if ( lhs->getWidth() < rhs->getWidth() ) return true; + return false; + } + + + inline PowerRailsPlanes::RailMatch::RailMatch ( DbU::Unit axis, DbU::Unit width ) + : _axis(axis) + , _width(width) + { } + + + inline bool PowerRailsPlanes::RailMatch::operator() ( const Rail* rail ) + { return (rail->getAxis() == _axis) and (rail->getWidth() == _width); } + + + PowerRailsPlanes::Rails::Rails ( PowerRailsPlanes::Plane* plane , unsigned int direction , Net* net ) + : _plane (plane) + , _direction (direction) + , _net (net) + , _rails () + { + cdebug_log(159,0) << " new Rails @" + << " " << getRoutingPlane()->getLayer()->getName() + << " " << net + << " " << ((getDirection()==Flags::Horizontal) ? "Horizontal": "Vertical") << endl; + } + + + PowerRailsPlanes::Rails::~Rails () + { + while ( not _rails.empty() ) { + delete (*_rails.begin()); + _rails.erase ( _rails.begin() ); + } + } + + + inline PowerRailsPlanes::Plane* PowerRailsPlanes::Rails::getPlane () { return _plane; } + inline RoutingPlane* PowerRailsPlanes::Rails::getRoutingPlane () { return getPlane()->getRoutingPlane(); } + inline unsigned int PowerRailsPlanes::Rails::getDirection () const { return _direction; } + inline Net* PowerRailsPlanes::Rails::getNet () const { return _net; } + + + void PowerRailsPlanes::Rails::merge ( const Box& bb ) + { + DbU::Unit axis; + DbU::Unit width; + DbU::Unit sourceU; + DbU::Unit targetU; + + if (getDirection() == Flags::Horizontal) { + axis = bb.getYCenter(); + width = bb.getHeight(); + sourceU = bb.getXMin(); + targetU = bb.getXMax(); + } else { + axis = bb.getXCenter(); + width = bb.getWidth(); + sourceU = bb.getYMin(); + targetU = bb.getYMax(); + } + + vector::iterator irail = find_if ( _rails.begin(), _rails.end(), RailMatch(axis,width) ); + + Rail* rail = NULL; + if ( irail == _rails.end() ) { + rail = new Rail(this,axis,width); + _rails.push_back ( rail ); + stable_sort ( _rails.begin(), _rails.end(), RailCompare() ); + } else { + rail = *irail; + } + + rail->merge ( sourceU, targetU ); + } + + + void PowerRailsPlanes::Rails::doLayout ( const Layer* layer ) + { + cdebug_log(159,0) << "Doing layout of rails: " << layer->getName() + << " " << ((_direction==Flags::Horizontal) ? "Horizontal" : "Vertical") + << " " << _net->getName() << endl; + + for ( size_t irail=0 ; irail<_rails.size() ; irail++ ) + _rails[irail]->doLayout ( layer ); + } + + + PowerRailsPlanes::Plane::Plane ( const Layer* layer, RoutingPlane* routingPlane ) + : _layer (layer) + , _routingPlane (routingPlane) + , _horizontalRails () + , _verticalRails () + , _powerDirection (routingPlane->getDirection()) + { + cdebug_log(159,0) << "New Plane " << _layer->getName() << " " << _routingPlane << endl; + + // Hard-coded SxLib gauge. + if (_routingPlane->getDepth() == 0) _powerDirection = Flags::Horizontal; + } + + + PowerRailsPlanes::Plane::~Plane () + { + RailsMap::iterator irail = _horizontalRails.begin(); + for ( ; irail != _horizontalRails.end() ; ++irail ) { + delete (*irail).second; + } + irail = _verticalRails.begin(); + for ( ; irail != _verticalRails.end() ; ++irail ) { + delete (*irail).second; + } + } + + + inline const Layer* PowerRailsPlanes::Plane::getLayer () const { return _layer; } + inline RoutingPlane* PowerRailsPlanes::Plane::getRoutingPlane () { return _routingPlane; } + inline unsigned int PowerRailsPlanes::Plane::getDirection () const { return _routingPlane->getDirection(); } + inline unsigned int PowerRailsPlanes::Plane::getPowerDirection () const { return _powerDirection; } + + + void PowerRailsPlanes::Plane::merge ( const Box& bb, Net* net ) + { + Rails* rails = NULL; + + cdebug_log(159,0) << " Plane::merge() " << net->getName() << " " << bb << endl; + + unsigned int direction = getDirection(); + if ( (net->getType() == Net::Type::POWER) or (net->getType() == Net::Type::GROUND) ) + direction = getPowerDirection(); + + if (direction == Flags::Horizontal) { + RailsMap::iterator irails = _horizontalRails.find(net); + if ( irails == _horizontalRails.end() ) { + rails = new Rails(this,Flags::Horizontal,net); + _horizontalRails.insert ( make_pair(net,rails) ); + } else + rails = (*irails).second; + + rails->merge ( bb ); + } else { + RailsMap::iterator irails = _verticalRails.find(net); + if ( irails == _verticalRails.end() ) { + rails = new Rails(this,Flags::Vertical,net); + _verticalRails.insert ( make_pair(net,rails) ); + } else + rails = (*irails).second; + + cdebug_log(159,0) << " Vertical Merging" << endl; + rails->merge ( bb ); + } + } + + + void PowerRailsPlanes::Plane::doLayout () + { + cdebug_log(159,0) << "Doing layout of plane: " << _layer->getName() << endl; + + RailsMap::iterator irails = _horizontalRails.begin(); + for ( ; irails != _horizontalRails.end() ; ++irails ) { + (*irails).second->doLayout(_layer); + } + irails = _verticalRails.begin(); + for ( ; irails != _verticalRails.end() ; ++irails ) { + (*irails).second->doLayout(_layer); + } + } + + + PowerRailsPlanes::PowerRailsPlanes ( KatanaEngine* katana ) + : _katana (katana) + , _globalNets (katana) + , _planes () + , _activePlane (NULL) + , _activeBlockagePlane(NULL) + { + _globalNets.setBlockage( katana->getBlockageNet() ); + + Technology* technology = DataBase::getDB()->getTechnology(); + RoutingGauge* rg = _katana->getConfiguration()->getRoutingGauge(); + + for( Layer* layer : technology->getLayers() ) { + RegularLayer* regular = dynamic_cast(layer); + if ( not regular + or (regular->getBasicLayer()->getMaterial() != BasicLayer::Material::metal) ) continue; + + RoutingLayerGauge* lg = rg->getLayerGauge(regular); + if ( not lg ) continue; + + cdebug_log(159,0) << "Gauge: [" << lg->getDepth() << "] " << lg << endl; + + RoutingPlane* rp = _katana->getRoutingPlaneByIndex(lg->getDepth()); + cdebug_log(159,0) << "Plane:" << rp << endl; + + _planes.insert( make_pair(regular->getBasicLayer(),new Plane(regular,rp)) ); + + if (lg->getType() == Constant::PinOnly) continue; + const BasicLayer* blockageLayer = regular->getBasicLayer()->getBlockageLayer(); + if (not blockageLayer) continue; + + _planes.insert( make_pair(blockageLayer,new Plane(blockageLayer,rp)) ); + } + } + + + PowerRailsPlanes::~PowerRailsPlanes () + { + while ( not _planes.empty() ) { + delete _planes.begin()->second; + _planes.erase ( _planes.begin() ); + } + } + + + inline Net* PowerRailsPlanes::getRootNet ( Net* net, Path path ) + { return _globalNets.getRootNet(net,path); } + + + inline bool PowerRailsPlanes::isCoreClockNetRouted ( const Net* net ) const + { return _globalNets.isCoreClockNetRouted(net); } + + + bool PowerRailsPlanes::hasPlane ( const BasicLayer* layer ) + { return (_planes.find(layer) != _planes.end()); } + + + bool PowerRailsPlanes::setActivePlane ( const BasicLayer* layer ) + { + PlanesMap::iterator iplane = _planes.find(layer); + if (iplane == _planes.end()) return false; + + _activePlane = iplane->second; + _activeBlockagePlane = NULL; + if (layer->getMaterial() != BasicLayer::Material::blockage) { + BasicLayer* blockageLayer = layer->getBlockageLayer(); + PlanesMap::iterator ibplane = _planes.find(blockageLayer); + if (ibplane != _planes.end()) + _activeBlockagePlane = ibplane->second; + } + return true; + } + + + inline PowerRailsPlanes::Plane* PowerRailsPlanes::getActivePlane () const + { return _activePlane; } + + + inline PowerRailsPlanes::Plane* PowerRailsPlanes::getActiveBlockagePlane () const + { return _activeBlockagePlane; } + + + void PowerRailsPlanes::merge ( const Box& bb, Net* net ) + { + if (not _activePlane) return; + + Net* topGlobalNet = _globalNets.getRootNet( net, Path() ); + if (topGlobalNet == NULL) { + cdebug_log(159,0) << "Not a global net: " << net << endl; + return; + } + + if ( (topGlobalNet == _globalNets.getBlockage()) and (_activeBlockagePlane != NULL) ) + _activeBlockagePlane->merge( bb, topGlobalNet ); + else + _activePlane->merge( bb, topGlobalNet ); + } + + + void PowerRailsPlanes::doLayout () + { + PlanesMap::iterator iplane = _planes.begin(); + for ( ; iplane != _planes.end() ; iplane++ ) + iplane->second->doLayout (); + } + + + +// ------------------------------------------------------------------- +// Class : "::QueryPowerRails". + + class QueryPowerRails : public Query { + public: + QueryPowerRails ( KatanaEngine* ); + virtual bool hasGoCallback () const; + virtual void setBasicLayer ( const BasicLayer* ); + virtual bool hasBasicLayer ( const BasicLayer* ); + virtual void goCallback ( Go* ); + virtual void rubberCallback ( Rubber* ); + virtual void extensionGoCallback ( Go* ); + virtual void masterCellCallback (); + void addToPowerRail ( const Go* go + , const BasicLayer* basicLayer + , const Box& area + , const Transformation& transformation + ); + void ringAddToPowerRails (); + virtual void doQuery (); + inline void doLayout (); + inline unsigned int getGoMatchCount () const; + private: + AllianceFramework* _framework; + KatanaEngine* _katana; + RoutingGauge* _routingGauge; + const ChipTools& _chipTools; + PowerRailsPlanes _powerRailsPlanes; + bool _isBlockagePlane; + vector _hRingSegments; + vector _vRingSegments; + unsigned int _goMatchCount; + }; + + + QueryPowerRails::QueryPowerRails ( KatanaEngine* katana ) + : Query () + , _framework (AllianceFramework::get()) + , _katana (katana) + , _routingGauge (katana->getConfiguration()->getRoutingGauge()) + , _chipTools (katana->getChipTools()) + , _powerRailsPlanes(katana) + , _isBlockagePlane (false) + , _hRingSegments () + , _vRingSegments () + , _goMatchCount (0) + { + setCell ( katana->getCell() ); + setArea ( katana->getCell()->getBoundingBox() ); + setBasicLayer ( NULL ); + setFilter ( Query::DoTerminalCells|Query::DoComponents ); + + cmess1 << " o Building power rails." << endl; + } + + + inline unsigned int QueryPowerRails::getGoMatchCount () const + { return _goMatchCount; } + + + inline void QueryPowerRails::doLayout () + { return _powerRailsPlanes.doLayout(); } + + + bool QueryPowerRails::hasBasicLayer ( const BasicLayer* basicLayer ) + { return _powerRailsPlanes.hasPlane ( basicLayer ); } + + + void QueryPowerRails::setBasicLayer ( const BasicLayer* basicLayer ) + { + _isBlockagePlane = (basicLayer) and (basicLayer->getMaterial() == BasicLayer::Material::blockage); + _powerRailsPlanes.setActivePlane ( basicLayer ); + Query::setBasicLayer ( basicLayer ); + } + + + void QueryPowerRails::doQuery () + { + PowerRailsPlanes::Plane* activePlane = _powerRailsPlanes.getActivePlane(); + + if (not activePlane) return; + + cmess1 << " - PowerRails in " << activePlane->getLayer()->getName() << " ..." << endl; + Query::doQuery(); + } + + + void QueryPowerRails::masterCellCallback () + { } + + + bool QueryPowerRails::hasGoCallback () const + { return true; } + + + void QueryPowerRails::goCallback ( Go* go ) + { + //ltrace(80) << "QueryPowerRails::goCallback() " << go->getId() << ":" << go + // << " " << getPath().getName() << endl; + addToPowerRail ( go, getBasicLayer(), getArea(), getTransformation() ); + } + + + void QueryPowerRails::addToPowerRail ( const Go* go + , const BasicLayer* basicLayer + , const Box& area + , const Transformation& transformation + ) + { + const Component* component = dynamic_cast(go); + if ( component ) { + if ( _framework->isPad(getMasterCell()) + and ( (_routingGauge->getLayerDepth(component->getLayer()) < 2) + or (component->getLayer()->getBasicLayers().getFirst()->getMaterial() != BasicLayer::Material::blockage) ) ) + return; + + Net* rootNet = _katana->getBlockageNet(); + if (not _isBlockagePlane) { + rootNet = _powerRailsPlanes.getRootNet(component->getNet(),getPath()); + } + +#if 0 + Net* rootNet = NULL; + if ( not _isBlockagePlane ) + rootNet = _powerRailsPlanes.getRootNet(component->getNet(),getPath()); + else { + rootNet = _katana->getBlockageNet(); + } +#endif + + if ( rootNet == NULL ) { + cdebug_log(159,0) << " rootNet is NULL, not taken into account." << endl; + return; + } + + cdebug_log(159,0) << " rootNet " << rootNet << " (" << rootNet->isClock() << ") " + << go->getCell() << " (" << go->getCell()->isTerminal() << ")" << endl; + + const Segment* segment = dynamic_cast(component); + if ( segment != NULL ) { + _goMatchCount++; + cdebug_log(159,0) << " Merging PowerRail element: " << segment << endl; + + Box bb = segment->getBoundingBox ( basicLayer ); + + unsigned int depth = _routingGauge->getLayerDepth ( segment->getLayer() ); + + if ( _chipTools.isChip() + and ((depth == 2) or (depth == 3)) + and (segment->getWidth () == _chipTools.getPadPowerWidth()) + and (segment->getLength() > _chipTools.getPadWidth()) + and (_katana->getChipTools().getCorona().contains(bb)) ) { + switch ( depth ) { + case 2: _vRingSegments.push_back ( segment ); break; // M3 V. + case 3: _hRingSegments.push_back ( segment ); break; // M4 H. + } + return; + } + + transformation.applyOn ( bb ); + + _powerRailsPlanes.merge ( bb, rootNet ); + } else { + const Contact* contact = dynamic_cast(component); + if ( contact != NULL ) { + _goMatchCount++; + + Box bb = contact->getBoundingBox ( basicLayer ); + transformation.applyOn ( bb ); + + cdebug_log(159,0) << " Merging PowerRail element: " << contact << " bb:" << bb + << " " << basicLayer << endl; + + _powerRailsPlanes.merge ( bb, rootNet ); + } + } + } + } + + + void QueryPowerRails::ringAddToPowerRails () + { + if ( not _hRingSegments.empty() ) { + const RegularLayer* layer = dynamic_cast(_routingGauge->getRoutingLayer(3)); + setBasicLayer ( layer->getBasicLayer() ); + + DbU::Unit xmin = DbU::Max; + DbU::Unit xmax = DbU::Min; + vector boxes; + + for ( size_t i=0 ; i<_hRingSegments.size() ; ++i ) { + boxes.push_back ( _hRingSegments[i]->getBoundingBox() ); + xmin = std::min ( xmin, boxes.back().getXMin() ); + xmax = std::max ( xmax, boxes.back().getXMax() ); + } + + for ( size_t i=0 ; i<_hRingSegments.size() ; ++i ) { + _powerRailsPlanes.merge ( Box(xmin,boxes[i].getYMin(),xmax,boxes[i].getYMax()) + , _powerRailsPlanes.getRootNet(_hRingSegments[i]->getNet(),Path()) ); + } + } + + if ( not _vRingSegments.empty() ) { + const RegularLayer* layer = dynamic_cast(_routingGauge->getRoutingLayer(2)); + setBasicLayer ( layer->getBasicLayer() ); + + DbU::Unit ymin = DbU::Max; + DbU::Unit ymax = DbU::Min; + vector boxes; + + for ( size_t i=0 ; i<_vRingSegments.size() ; ++i ) { + boxes.push_back ( _vRingSegments[i]->getBoundingBox() ); + ymin = std::min ( ymin, boxes.back().getYMin() ); + ymax = std::max ( ymax, boxes.back().getYMax() ); + } + + for ( size_t i=0 ; i<_vRingSegments.size() ; ++i ) { + _powerRailsPlanes.merge ( Box(boxes[i].getXMin(),ymin,boxes[i].getXMax(),ymax) + , _powerRailsPlanes.getRootNet(_vRingSegments[i]->getNet(),Path()) ); + } + } + } + + + void QueryPowerRails::rubberCallback ( Rubber* ) + { } + + + void QueryPowerRails::extensionGoCallback ( Go* ) + { } + + +} // End of anonymous namespace. + + +namespace Katana { + + + using Hurricane::DataBase; + using Hurricane::Technology; + using Hurricane::BasicLayer; + using Anabatic::NetRoutingState; + using Anabatic::NetData; + + + void KatanaEngine::setupPowerRails () + { + //DebugSession::open( 150, 160 ); + + openSession(); + + if (not getBlockageNet()) { + setBlockageNet( getCell()->getNet("blockagenet") ); + if (not getBlockageNet()) { + setBlockageNet( Net::create( getCell(), "blockagenet" ) ); + getBlockageNet()->setType( Net::Type::BLOCKAGE ); + } + + NetData* state = getNetData( getBlockageNet(), Flags::Create ); + state->getNetRoutingState()->setFlags( NetRoutingState::Fixed ); + } + + QueryPowerRails query ( this ); + Technology* technology = DataBase::getDB()->getTechnology(); + + for( BasicLayer* layer : technology->getBasicLayers() ) { + if ( (layer->getMaterial() != BasicLayer::Material::metal) + and (layer->getMaterial() != BasicLayer::Material::blockage) ) + continue; + if (_configuration->isGMetal(layer)) continue; + if (not query.hasBasicLayer(layer)) continue; + + query.setBasicLayer( layer ); + query.doQuery (); + } + query.ringAddToPowerRails(); + query.doLayout(); + cmess1 << " - " << query.getGoMatchCount() << " power rails elements found." << endl; + + const vector& gcells = getGCells(); + for ( auto gcell : gcells ) { + gcell->truncDensities(); + } + + Session::close(); + + //DebugSession::close(); + } + + +} // Katana namespace. diff --git a/katana/src/PreProcess.cpp b/katana/src/PreProcess.cpp new file mode 100644 index 00000000..4f203326 --- /dev/null +++ b/katana/src/PreProcess.cpp @@ -0,0 +1,366 @@ +// -*- 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 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 : "./PreProcess.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/DebugSession.h" +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" +#include "hurricane/Net.h" +#include "hurricane/Name.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/Horizontal.h" +#include "anabatic/AutoContactTerminal.h" +#include "katana/DataNegociate.h" +#include "katana/TrackElement.h" +#include "katana/Track.h" +#include "katana/RoutingPlane.h" +#include "katana/NegociateWindow.h" +#include "katana/Session.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using namespace CRL; + using namespace Katana; + using Anabatic::perpandicularTo; + using Anabatic::AutoContactTerminal; + + + void getPerpandiculars ( TrackElement* segment + , Anabatic::AutoContact* from + , unsigned int direction + , vector& perpandiculars + ) + { + TrackElement* perpandicular; + for( Segment* osegment : segment->base()->getAutoSource()->getSlaveComponents().getSubSet() ) { + perpandicular = Session::lookup ( osegment ); + cdebug_log(159,0) << "S " << perpandicular << endl; + + if ( not perpandicular or (perpandicular->getDirection() == direction) ) continue; + + perpandiculars.push_back ( perpandicular ); + } + + for( Segment* osegment : segment->base()->getAutoTarget()->getSlaveComponents().getSubSet() ) { + perpandicular = Session::lookup ( osegment ); + cdebug_log(159,0) << "T " << perpandicular << endl; + + if ( not perpandicular or (perpandicular->getDirection() == direction) ) continue; + + perpandiculars.push_back ( perpandicular ); + } + } + + + void findFailedPerpandiculars ( RoutingPad* rp, unsigned int direction, set& faileds ) + { + cdebug_log(159,0) << "Find failed caging: " << rp << endl; + + TrackElement* parallel; + for( Segment* osegment : rp->getSlaveComponents().getSubSet() ) { + parallel = Session::lookup ( osegment ); + cdebug_log(159,0) << "* " << parallel << endl; + + if ( parallel->isFixed () ) continue; + if ( parallel->getDirection() != direction ) continue; + + Anabatic::AutoContact* contact = parallel->base()->getAutoSource(); + if ( contact->base()->getAnchor() != rp ) contact = NULL; + + if ( contact == NULL ) contact = parallel->base()->getAutoTarget(); + if ( contact->base()->getAnchor() != rp ) continue; + + //parallel->makeDogLeg ( contact->getGCell() ); + faileds.insert ( parallel ); + } + } + + + void propagateCagedConstraints ( TrackElement* segment, set& faileds ) + { + if (not segment->isFixed()) return; + + cdebug_log(159,0) << "Propagate caging: " << segment << endl; + + Track* track = segment->getTrack(); + //unsigned int direction = Session::getRoutingGauge()->getLayerDirection(segment->getLayer()); + unsigned int direction = segment->getDirection(); + Anabatic::AutoContact* source = segment->base()->getAutoSource(); + RoutingPad* rp = NULL; + Interval uside = source->getGCell()->getSide(direction); + DbU::Unit minConstraint = DbU::Min; + DbU::Unit maxConstraint = DbU::Max; + vector perpandiculars; + + if ( not track ) { + cerr << Bug( "%s is not inserted in a ", getString(segment).c_str() ) << endl; + return; + } + + // Computing constraints from fixed only TrackElements (caging). + TrackElement* parallel; + size_t i = segment->getIndex(); + while ( i > 0 ) { + parallel = track->getSegment( --i ); + if (not parallel) continue; + if (parallel->getTargetU() < uside.getVMin()) break; + if (parallel->getNet() == segment->getNet()) continue; + if (not parallel->isFixed()) continue; + + cdebug_log(159,0) << "Min Constraint from: " << parallel << endl; + minConstraint = max( minConstraint, parallel->getTargetU() ); + } + + i = segment->getIndex(); + while ( i < track->getSize()-1 ) { + parallel = track->getSegment( ++i ); + if (not parallel) continue; + if (parallel->getSourceU() > uside.getVMax()) break; + if (parallel->getNet() == segment->getNet()) continue; + if (not parallel->isFixed()) continue; + + cdebug_log(159,0) << "Max Constraint from: " << parallel << endl; + maxConstraint = min( maxConstraint, parallel->getSourceU() ); + } + + if (minConstraint > maxConstraint) { + cerr << Bug( "%s have too tight caging constraints.", getString(segment).c_str() ) << endl; + return; + } + if ( (minConstraint <= uside.getVMin()) and (maxConstraint >= uside.getVMax()) ) { + cdebug_log(159,0) << "No constraints [" << DbU::getValueString(minConstraint) + << ":" << DbU::getValueString(maxConstraint) + << " vs. " << uside << endl; + return; + } + + // Finding perpandiculars, by way of the source & target RoutingPad. + if (source->getAnchor()) { + rp = dynamic_cast(source->getAnchor()); + if (rp) { + TrackElement* parallel; + for( Segment* osegment : rp->getSlaveComponents().getSubSet() ) { + parallel = Session::lookup( osegment ); + cdebug_log(159,0) << "* " << parallel << endl; + + if (parallel->isFixed ()) continue; + if (parallel->isGlobal()) continue; + getPerpandiculars( parallel, source, direction, perpandiculars ); + getPerpandiculars( parallel, segment->base()->getAutoTarget(), direction, perpandiculars ); + } + } else { + cerr << Bug( "%s is not anchored on a \n (%s)" + , getString(source).c_str() + , getString(source->getAnchor()).c_str() ) << endl; + } + } + + // Apply caging constraints to perpandiculars. + cdebug_tabw(159,1); + if (perpandiculars.size() == 0) { + cdebug_log(159,0) << "No perpandiculars to " << segment << endl; + cdebug_tabw(159,-1); + return; + } + + Interval constraints ( minConstraint, maxConstraint ); + for ( size_t iperpand=0 ; iperpandbase()->mergeUserConstraints( constraints ); + if (perpandiculars[iperpand]->base()->getUserConstraints().isEmpty()) { + cdebug_log(159,0) << "Cumulative caged constraints are too tight on " << perpandiculars[iperpand] << endl; + findFailedPerpandiculars( rp, direction, faileds ); + } + } + + cdebug_tabw(159,-1); + } + + + void moveUpCaged ( TrackElement* segment ) + { + DebugSession::open( segment->getNet(), 150, 160 ); + cdebug_log(159,1) << "::moveUpCaged() " << segment << endl; + + //Configuration* configuration = Session::getConfiguration(); + //const Layer* metal2 = configuration->getRoutingLayer( 1 ); + //const Layer* metal3 = configuration->getRoutingLayer( 2 ); + + Anabatic::AutoContact* support = segment->base()->getAutoSource(); + RoutingPad* rp = dynamic_cast(support->getAnchor()); + + for( Component* component : rp->getSlaveComponents() ) { + Horizontal* baseSegment = dynamic_cast( component ); + TrackElement* accessSegment = Session::lookup( baseSegment ); + + if (accessSegment and not accessSegment->isFixed()) { + accessSegment->moveUp( Flags::NoFlags ); + } + } + + cdebug_tabw(159,-1); + DebugSession::close(); + } + + + void protectCagedTerminals ( Track* track ) + { + cdebug_log(159,1) << "protectCagedTerminals() " << track << endl; + + DbU::Unit lastMovedUp = track->getMin(); + unsigned int moveUpCount = 0; + + Configuration* configuration = Session::getConfiguration(); + const Layer* metal2 = configuration->getRoutingLayer( 1 ); + const Layer* metal3 = configuration->getRoutingLayer( 2 ); + Net* neighborNet = NULL; + RoutingPlane* metal3plane = track->getRoutingPlane()->getTop(); + + if (track->getLayer() != metal2) { + cdebug_tabw(159,-1); + return; + } + + for ( size_t i=0 ; igetSize() ; ++i ) { + TrackElement* segment = track->getSegment(i); + if (not segment or segment->isRouted()) continue; + if (segment and segment->isFixed() and segment->isTerminal()) { + Interval freeInterval = track->getFreeInterval( segment->getSourceU(), segment->getNet() ); + DbU::Unit ppitch = segment->getPPitch(); + + //if (freeInterval.getSize() < ppitch*6) { + if ( (segment->getSourceU() - freeInterval.getVMin() < ppitch*3) + or (freeInterval.getVMax() - segment->getTargetU() < ppitch*3) ) { + cparanoid << "[INFO] Caged terminal: " << segment << endl; + if ( (segment->getLayer () != metal2) + or (segment->getLength() >= ppitch) + or (segment->getNet () == neighborNet) ) { + neighborNet = segment->getNet(); + continue; + } + + Anabatic::AutoContact* support = NULL; + Anabatic::AutoContact* turn = NULL; + if (segment->base()->isSourceTerminal()) { + support = segment->base()->getAutoSource(); + turn = segment->base()->getAutoTarget(); + } else { + support = segment->base()->getAutoTarget(); + turn = segment->base()->getAutoSource(); + } + + RoutingPad* rp = dynamic_cast(support->getAnchor()); + Track* metal3track = metal3plane->getTrackByPosition( rp->getSourcePosition().getX() ); + + turn->restrictConstraintBox( freeInterval.getVMin() + , freeInterval.getVMax() + , Flags::Vertical ); + + if (metal3track->getFreeInterval(segment->getAxis(),segment->getNet()).isEmpty()) { + cparanoid << "[INFO] Cannot protect caged terminal because top layer (metal3) is obstructed." << endl; + continue; + } + + if (segment->getSourceU() - lastMovedUp < ppitch*4) { + ++moveUpCount; + if (moveUpCount % 2 == 0) { + //moveUpCaged( segment ); + } + } else { + moveUpCount = 0; + } + lastMovedUp = segment->getSourceU(); + + Anabatic::AutoContact* source + = Anabatic::AutoContactTerminal::create( support->getGCell() + , rp + , metal3 + , rp->getSourcePosition() + , DbU::fromLambda(1.0), DbU::fromLambda(1.0) + ); + source->setFlags( Anabatic::CntIgnoreAnchor ); + + Anabatic::AutoContact* target = + Anabatic::AutoContactTerminal::create( support->getGCell() + , rp + , metal3 + , rp->getSourcePosition() + , DbU::fromLambda(1.0), DbU::fromLambda(1.0) + ); + target->setFlags( Anabatic::CntIgnoreAnchor ); + + AutoSegment* fixedSegment = AutoSegment::create( source, target, Flags::Vertical ); + fixedSegment->setFlags( Anabatic::SegFixed ); + Session::getNegociateWindow()->createTrackSegment( fixedSegment, Flags::LoadingStage ); + } + + neighborNet = segment->getNet(); + } + } + + cdebug_tabw(159,-1); + } + + +} // End of local namespace. + + +namespace Katana { + + + using Hurricane::Bug; + using Hurricane::Net; + using Hurricane::Name; + using Anabatic::AutoSegmentLut; + + + void KatanaEngine::preProcess () + { + for ( size_t i=0 ; i<_routingPlanes.size() ; ++i ) { + RoutingPlane* plane = _routingPlanes[i]; + + Track* track = plane->getTrackByIndex( 0 ); + while ( track ) { + protectCagedTerminals( track ); + track = track->getNextTrack(); + } + } + Session::revalidate (); + } + + + void KatanaEngine::_computeCagedConstraints () + { + set faileds; + + TrackElement* segment = NULL; + AutoSegmentLut::const_iterator isegment = _getAutoSegmentLut().begin(); + for ( ; isegment != _getAutoSegmentLut().end() ; isegment++ ) { + segment = _lookup( isegment->second ); + if (not segment or not segment->isFixed()) continue; + + DebugSession::open( segment->getNet(), 150, 160 ); + propagateCagedConstraints( segment, faileds ); + DebugSession::close(); + } + } + + +} // Katana namespace. diff --git a/katana/src/PreRouteds.cpp b/katana/src/PreRouteds.cpp new file mode 100644 index 00000000..ec64ac91 --- /dev/null +++ b/katana/src/PreRouteds.cpp @@ -0,0 +1,62 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2014-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./BuildPreRouteds.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Error.h" +#include "hurricane/Warning.h" +#include "katana/RoutingPlane.h" +#include "katana/TrackFixedSegment.h" +#include "katana/Track.h" +#include "katana/KatanaEngine.h" + + +namespace { + + +} // Anonymous namespace. + + +namespace Katana { + + using namespace std; + using Hurricane::Warning; + using Hurricane::Error; + + + void KatanaEngine::setFixedPreRouted () + { + for ( size_t depth=0 ; depth<_routingPlanes.size() ; ++depth ) { + RoutingPlane* rp = _routingPlanes[depth]; + if (rp->getLayerGauge()->getType() == Constant::PinOnly ) continue; + if (rp->getLayerGauge()->getDepth() > getConfiguration()->getAllowedDepth() ) continue; + + size_t tracksSize = rp->getTracksSize(); + for ( size_t itrack=0 ; itrackgetTrackByIndex( itrack ); + + for ( size_t ielement=0 ; ielementgetSize() ; ++ielement ) { + TrackElement* element = track->getSegment( ielement ); + + if (element->getNet() == NULL) continue; + element->setRouted(); + } + } + } + } + + +} // Katana namespace. diff --git a/katana/src/ProtectRoutingPads.cpp b/katana/src/ProtectRoutingPads.cpp new file mode 100644 index 00000000..71ef58f4 --- /dev/null +++ b/katana/src/ProtectRoutingPads.cpp @@ -0,0 +1,182 @@ +// -*- 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 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 : "./ProtectRoutingPads.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/DataBase.h" +#include "hurricane/Technology.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/RegularLayer.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/Occurrence.h" +#include "hurricane/Cell.h" +#include "hurricane/NetExternalComponents.h" +#include "hurricane/NetRoutingProperty.h" +#include "crlcore/Catalog.h" +#include "anabatic/AutoContact.h" +#include "anabatic/AutoSegment.h" +#include "anabatic/GCell.h" +#include "anabatic/AnabaticEngine.h" +#include "katana/RoutingPlane.h" +#include "katana/TrackSegment.h" +#include "katana/TrackFixedSegment.h" +#include "katana/Track.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Interval; + using Hurricane::Go; + using Hurricane::Layer; + using Hurricane::BasicLayer; + using Hurricane::RegularLayer; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Hurricane::Transformation; + using Hurricane::RoutingPad; + using Hurricane::Occurrence; + using Hurricane::Path; + using Hurricane::NetExternalComponents; + using Hurricane::NetRoutingExtension; + using Hurricane::NetRoutingState; + using CRL::CatalogExtension; + using Anabatic::AutoContact; + using Anabatic::AutoSegment; + using namespace Katana; + + + void protectRoutingPad ( RoutingPad* rp ) + { + Name padNetName = "pad"; + Component* usedComponent = rp->_getEntityAsComponent(); + Path path = rp->getOccurrence().getPath(); + Net* masterNet = usedComponent->getNet(); + Transformation transformation = path.getTransformation(); + + if ( CatalogExtension::isPad(masterNet->getCell()) ) { + if ( rp->getNet()->isPower() + or (rp->getNet()->getName() == padNetName) ) + return; + } + + vector segments; + + for( Segment* segment : masterNet->getSegments() ) { + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment->getLayer()); + if ( plane == NULL ) continue; + + if ( usedComponent == dynamic_cast(segment) ) continue; + if ( not NetExternalComponents::isExternal(segment) ) continue; + + //cerr << "Looking " << (void*)*isegment << ":" << *isegment << endl; + + segments.push_back ( segment ); + } + + for ( size_t i=0 ; igetRoutingPlaneByLayer(segments[i]->getLayer()); + unsigned int direction = plane->getDirection(); + DbU::Unit wireWidth = plane->getLayerGauge()->getWireWidth(); + DbU::Unit delta = plane->getLayerGauge()->getHalfPitch() + + wireWidth/2 + - DbU::fromLambda(0.1); + DbU::Unit extension = segments[i]->getLayer()->getExtentionCap(); + Box bb ( segments[i]->getBoundingBox() ); + + transformation.applyOn ( bb ); + //cinfo << "bb: " << bb << endl; + + if ( direction == Flags::Horizontal ) { + DbU::Unit axisMin = bb.getYMin() - delta; + DbU::Unit axisMax = bb.getYMax() + delta; + + Track* track = plane->getTrackByPosition ( axisMin, Constant::Superior ); + for ( ; track and (track->getAxis() <= axisMax) ; track = track->getNextTrack() ) { + Horizontal* segment = Horizontal::create ( rp->getNet() + , segments[i]->getLayer() + , track->getAxis() + , wireWidth + , bb.getXMin()+extension + , bb.getXMax()-extension + ); + TrackFixedSegment::create ( track, segment ); + } + } else { + DbU::Unit axisMin = bb.getXMin() - delta; + DbU::Unit axisMax = bb.getXMax() + delta; + + Track* track = plane->getTrackByPosition ( axisMin, Constant::Superior ); + for ( ; track and (track->getAxis() <= axisMax) ; track = track->getNextTrack() ) { + Vertical* segment = Vertical::create ( rp->getNet() + , segments[i]->getLayer() + , track->getAxis() + , wireWidth + , bb.getYMin()+extension + , bb.getYMax()-extension + ); + TrackFixedSegment::create ( track, segment ); + } + } + } + } + + +} // End of anonymous namespace. + + +namespace Katana { + + using Hurricane::DataBase; + using Hurricane::Technology; + using Hurricane::BasicLayer; + using Hurricane::Cell; + using Anabatic::NetData; + + + void KatanaEngine::protectRoutingPads () + { + cmess1 << " o Protect external components not useds as RoutingPads." << endl; + + openSession(); + + for ( Net* net : getCell()->getNets() ) { + if (net->isSupply()) continue; + + NetData* data = getNetData( net ); + if (data and data->isFixed()) continue; + + vector rps; + for ( RoutingPad* rp : net->getRoutingPads() ) { + rps.push_back( rp ); + } + + for ( size_t i=0 ; i_baseObject) +#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(GraphicKatanaEngine,gtool,function) + + +namespace Katana { + +using namespace Hurricane; +using namespace Isobar; + +extern "C" { + + +// +=================================================================+ +// | "PyGraphicKatanaEngine" Python Module Code Part | +// +=================================================================+ + +#if defined(__PYTHON_MODULE__) + + + // +-------------------------------------------------------------+ + // | "PyGraphicKatanaEngine" Attribute Methods | + // +-------------------------------------------------------------+ + + + static PyObject* PyGraphicKatanaEngine_grab ( PyObject* ) + { + cdebug_log(40,0) << "PyGraphicKatanaEngine_grab()" << endl; + PyGraphicKatanaEngine* pyGraphicKatanaEngine = NULL; + + HTRY + pyGraphicKatanaEngine = PyObject_NEW ( PyGraphicKatanaEngine, &PyTypeGraphicKatanaEngine ); + if ( pyGraphicKatanaEngine == NULL ) return NULL; + + pyGraphicKatanaEngine->ACCESS_OBJECT = GraphicKatanaEngine::grab(); + HCATCH + + return (PyObject*)pyGraphicKatanaEngine; + } + + + static PyObject* PyGraphicKatanaEngine_getCell ( PyGraphicKatanaEngine* self ) + { + cdebug_log(40,0) << "PyGraphicKatanaEngine_getCell ()" << endl; + + Cell* cell = NULL; + + HTRY + METHOD_HEAD("GraphicKatanaEngine.getCell()") + cell = gtool->getCell (); + HCATCH + + if (cell == NULL) Py_RETURN_NONE; + return PyCell_Link(cell); + } + + + GetNameMethod(GraphicKatanaEngine, gtool) + + // Standart destroy (Attribute). + + + PyMethodDef PyGraphicKatanaEngine_Methods[] = + { { "grab" , (PyCFunction)PyGraphicKatanaEngine_grab , METH_NOARGS|METH_STATIC + , "Returns the GraphicKatanaEngine singleton." } + , { "getName" , (PyCFunction)PyGraphicKatanaEngine_getName , METH_NOARGS + , "Returns the name of the GraphicKatanaEngine (class attribute)." } + , { "getCell" , (PyCFunction)PyGraphicKatanaEngine_getCell , METH_NOARGS + , "Returns the Cell on which this GraphicKatanaEngine is attached." } + , {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + // --------------------------------------------------------------- + // PyGraphicKatanaEngine Type Methods. + + + PythonOnlyDeleteMethod(GraphicKatanaEngine) + PyTypeObjectLinkPyType(GraphicKatanaEngine) + + +#else // End of Python Module Code Part. + + +// +=================================================================+ +// | "PyGraphicKatanaEngine" Shared Library Code Part | +// +=================================================================+ + + // Link/Creation Method. + LinkCreateMethod(GraphicKatanaEngine) + + PyTypeInheritedObjectDefinitions(GraphicKatanaEngine,GraphicTool) + + +#endif // End of Shared Library Code Part. + +} // extern "C". + +} // CRL namespace. diff --git a/katana/src/PyKatana.cpp b/katana/src/PyKatana.cpp new file mode 100644 index 00000000..07d041fa --- /dev/null +++ b/katana/src/PyKatana.cpp @@ -0,0 +1,103 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2012-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./PyKatana.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/isobar/PyHurricane.h" +#include "hurricane/isobar/PyCell.h" +#include "katana/PyKatanaEngine.h" +#include "katana/PyGraphicKatanaEngine.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using Hurricane::tab; + using Isobar::__cs; + using CRL::PyTypeToolEngine; + using CRL::PyTypeGraphicTool; + + +#if !defined(__PYTHON_MODULE__) + +// x=================================================================x +// | "PyKatana" Shared Library Code Part | +// x=================================================================x + + +# else // End of PyHurricane Shared Library Code Part. + + +// x=================================================================x +// | "PyKatana" Python Module Code Part | +// x=================================================================x + + +extern "C" { + + + // x-------------------------------------------------------------x + // | "PyKatana" Module Methods | + // x-------------------------------------------------------------x + + + static PyMethodDef PyKatana_Methods[] = + { {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + + + // --------------------------------------------------------------- + // Module Initialization : "initKatana ()" + + DL_EXPORT(void) initKatana () { + cdebug_log(40,0) << "initKatana()" << endl; + + PyKatanaEngine_LinkPyType(); + PyGraphicKatanaEngine_LinkPyType(); + + PYTYPE_READY_SUB( KatanaEngine , ToolEngine ); + PYTYPE_READY_SUB( GraphicKatanaEngine, GraphicTool ); + + + PyObject* module = Py_InitModule( "Katana", PyKatana_Methods ); + if (module == NULL) { + cerr << "[ERROR]\n" + << " Failed to initialize Katana module." << endl; + return; + } + + Py_INCREF( &PyTypeKatanaEngine ); + PyModule_AddObject( module, "KatanaEngine", (PyObject*)&PyTypeKatanaEngine ); + Py_INCREF( &PyTypeGraphicKatanaEngine ); + PyModule_AddObject( module, "GraphicKatanaEngine", (PyObject*)&PyTypeGraphicKatanaEngine ); + + // PyObject* dictionnary = PyModule_GetDict( module ); + // PyObject* constant; + + // LoadObjectConstant( dictionnary, KtBuildGlobalRouting, "KtBuildGlobalRouting" ); + // LoadObjectConstant( dictionnary, KtLoadGlobalRouting , "KtLoadGlobalRouting" ); + } + + +} // End of extern "C". + + +#endif // End of Python Module Code Part. + + +} // End of Katana namespace. diff --git a/katana/src/PyKatanaEngine.cpp b/katana/src/PyKatanaEngine.cpp new file mode 100644 index 00000000..ce573e44 --- /dev/null +++ b/katana/src/PyKatanaEngine.cpp @@ -0,0 +1,306 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2010-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./PyKatanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/isobar/PyCell.h" +#include "hurricane/viewer/PyCellViewer.h" +#include "hurricane/viewer/ExceptionWidget.h" +#include "hurricane/Cell.h" +#include "katana/PyKatanaEngine.h" +#include + +# undef ACCESS_OBJECT +# undef ACCESS_CLASS +# define ACCESS_OBJECT _baseObject._object +# define ACCESS_CLASS(_pyObject) &(_pyObject->_baseObject) +#define METHOD_HEAD(function) GENERIC_METHOD_HEAD(KatanaEngine,katana,function) + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::hex; + using std::ostringstream; + using Hurricane::tab; + using Hurricane::Exception; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Warning; + using Hurricane::ExceptionWidget; + using Isobar::ProxyProperty; + using Isobar::ProxyError; + using Isobar::ConstructorError; + using Isobar::HurricaneError; + using Isobar::HurricaneWarning; + using Isobar::ParseOneArg; + using Isobar::ParseTwoArg; + using Isobar::PyCell; + using Isobar::PyCell_Link; + using Isobar::PyCellViewer; + using Isobar::PyTypeCellViewer; + using CRL::PyToolEngine; + + +extern "C" { + +#if defined(__PYTHON_MODULE__) + + +#define DirectVoidToolMethod(SELF_TYPE, SELF_OBJECT, FUNC_NAME) \ + static PyObject* Py##SELF_TYPE##_##FUNC_NAME(Py##SELF_TYPE* self) \ + { \ + cdebug_log(40,0) << "Py" #SELF_TYPE "_" #FUNC_NAME "()" << endl; \ + HTRY \ + METHOD_HEAD(#SELF_TYPE "." #FUNC_NAME "()") \ + if (SELF_OBJECT->getViewer()) { \ + if (ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::FUNC_NAME,SELF_OBJECT) )) { \ + PyErr_SetString( HurricaneError, #FUNC_NAME "() has thrown an exception (C++)." ); \ + return NULL; \ + } \ + } else { \ + SELF_OBJECT->FUNC_NAME(); \ + } \ + HCATCH \ + Py_RETURN_NONE; \ + } + + +// +=================================================================+ +// | "PyKatanaEngine" Python Module Code Part | +// +=================================================================+ + + + static PyObject* PyKatanaEngine_get ( PyObject*, PyObject* args ) + { + cdebug_log(40,0) << "PyKatanaEngine_get()" << endl; + + KatanaEngine* katana = NULL; + + HTRY + PyObject* arg0; + + if (not ParseOneArg("Katana.get", args, CELL_ARG, &arg0)) return NULL; + katana = KatanaEngine::get(PYCELL_O(arg0)); + HCATCH + + return PyKatanaEngine_Link(katana); + } + + + static PyObject* PyKatanaEngine_create ( PyObject*, PyObject* args ) + { + cdebug_log(40,0) << "PyKatanaEngine_create()" << endl; + + KatanaEngine* katana = NULL; + + HTRY + PyObject* arg0; + + if (not ParseOneArg("Katana.get", args, CELL_ARG, &arg0)) return NULL; + + Cell* cell = PYCELL_O(arg0); + katana = KatanaEngine::get(cell); + + if (katana == NULL) { + katana = KatanaEngine::create(cell); + if (cmess1.enabled()) + katana->getKatanaConfiguration()->print(cell); + } else + cerr << Warning("%s already has a Katana engine.",getString(cell).c_str()) << endl; + HCATCH + + return PyKatanaEngine_Link(katana); + } + + + static PyObject* PyKatanaEngine_setViewer ( PyKatanaEngine* self, PyObject* args ) + { + cdebug_log(40,0) << "PyKatanaEngine_setViewer ()" << endl; + + HTRY + METHOD_HEAD( "KatanaEngine.setViewer()" ) + + PyObject* pyViewer = NULL; + if (not PyArg_ParseTuple(args,"O:EtesianEngine.setViewer()",&pyViewer)) { + PyErr_SetString( ConstructorError, "Bad parameters given to EtesianEngine.setViewer()." ); + return NULL; + } + if (IsPyCellViewer(pyViewer)) { + katana->setViewer( PYCELLVIEWER_O(pyViewer) ); + } + HCATCH + + Py_RETURN_NONE; + } + + + PyObject* PyKatanaEngine_runGlobalRouter ( PyKatanaEngine* self, PyObject* args ) + { + cdebug_log(40,0) << "PyKatanaEngine_runGlobalRouter()" << endl; + + HTRY + METHOD_HEAD("KatanaEngine.runGlobalRouter()") + unsigned int flags = 0; + if (PyArg_ParseTuple(args,"I:KatanaEngine.runGlobalRouter", &flags)) { + if (katana->getViewer()) { + if (ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::runGlobalRouter,katana) )) { + PyErr_SetString( HurricaneError, "KatanaEngine::runGlobalrouter() has thrown an exception (C++)." ); + return NULL; + } + } else { + katana->runGlobalRouter(); + } + } else { + PyErr_SetString(ConstructorError, "KatanaEngine.runGlobalRouter(): Invalid number/bad type of parameter."); + return NULL; + } + HCATCH + + Py_RETURN_NONE; + } + + + PyObject* PyKatanaEngine_layerAssign ( PyKatanaEngine* self, PyObject* args ) + { + cdebug_log(40,0) << "PyKatanaEngine_layerAssign()" << endl; + + HTRY + METHOD_HEAD("KatanaEngine.layerAssign()") + unsigned int flags = 0; + if (PyArg_ParseTuple(args,"I:KatanaEngine.layerAssign", &flags)) { + + if (katana->getViewer()) { + bool failure = false; + //= ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::balanceGlobalDensity,katana) ); + if (not failure) + failure = ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::layerAssign,katana,flags) ); + + if (failure) { + PyErr_SetString( HurricaneError, "EtesianEngine::place() has thrown an exception (C++)." ); + return NULL; + } + } else { + //katana->balanceGlobalDensity(); + katana->layerAssign (flags); + } + } else { + PyErr_SetString(ConstructorError, "KatanaEngine.layerAssign(): Invalid number/bad type of parameter."); + return NULL; + } + HCATCH + + Py_RETURN_NONE; + } + + + static PyObject* PyKatanaEngine_runNegociatePreRouted ( PyKatanaEngine* self ) + { + cdebug_log(40,0) << "PyKatanaEngine_runNegociatePreRouted()" << endl; + HTRY + METHOD_HEAD("KatanaEngine.runNegociatePreRouted()") + if (katana->getViewer()) { + if (ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::runNegociate,katana,Flags::PreRoutedStage) )) { + PyErr_SetString( HurricaneError, "KatanaEngine::runNegociatePreRouted() has thrown an exception (C++)." ); + return NULL; + } + } else { + katana->runNegociate( Flags::PreRoutedStage ); + } + HCATCH + Py_RETURN_NONE; + } + + + static PyObject* PyKatanaEngine_runNegociate ( PyKatanaEngine* self ) + { + cdebug_log(40,0) << "PyKatanaEngine_runNegociate()" << endl; + HTRY + METHOD_HEAD("KatanaEngine.runNegociate()") + if (katana->getViewer()) { + if (ExceptionWidget::catchAllWrapper( std::bind(&KatanaEngine::runNegociate,katana,0) )) { + PyErr_SetString( HurricaneError, "EtesianEngine::runNegociate() has thrown an exception (C++)." ); + return NULL; + } + } else { + katana->runNegociate(); + } + HCATCH + Py_RETURN_NONE; + } + + + // Standart Accessors (Attributes). + DirectVoidToolMethod(KatanaEngine,katana,printConfiguration) + DirectVoidToolMethod(KatanaEngine,katana,finalizeLayout) + DirectVoidMethod(KatanaEngine,katana,dumpMeasures) + DirectGetBoolAttribute(PyKatanaEngine_getToolSuccess,getToolSuccess,PyKatanaEngine,KatanaEngine) + + // Standart Destroy (Attribute). + DBoDestroyAttribute(PyKatanaEngine_destroy,PyKatanaEngine) + + + PyMethodDef PyKatanaEngine_Methods[] = + { { "get" , (PyCFunction)PyKatanaEngine_get , METH_VARARGS|METH_STATIC + , "Returns the Katana engine attached to the Cell, None if there isnt't." } + , { "create" , (PyCFunction)PyKatanaEngine_create , METH_VARARGS|METH_STATIC + , "Create a Katana engine on this cell." } + , { "setViewer" , (PyCFunction)PyKatanaEngine_setViewer , METH_VARARGS + , "Associate a Viewer to this KatanaEngine." } + , { "printConfiguration" , (PyCFunction)PyKatanaEngine_printConfiguration , METH_NOARGS + , "Display on the console the configuration of Katana." } + , { "getToolSuccess" , (PyCFunction)PyKatanaEngine_getToolSuccess , METH_NOARGS + , "Returns True if the detailed routing has been successful." } + , { "runGlobalRouter" , (PyCFunction)PyKatanaEngine_runGlobalRouter , METH_VARARGS + , "Run the global router (Knik)." } + , { "layerAssign" , (PyCFunction)PyKatanaEngine_layerAssign , METH_VARARGS + , "Run the layer assigment stage." } + , { "runNegociatePreRouted", (PyCFunction)PyKatanaEngine_runNegociatePreRouted, METH_NOARGS + , "Run the negociation stage for pre-routed of the detailed router." } + , { "runNegociate" , (PyCFunction)PyKatanaEngine_runNegociate , METH_NOARGS + , "Run the negociation stage of the detailed router." } + , { "finalizeLayout" , (PyCFunction)PyKatanaEngine_finalizeLayout , METH_NOARGS + , "Revert to a pure Hurricane database, remove router's additionnal data structures." } + , { "dumpMeasures" , (PyCFunction)PyKatanaEngine_dumpMeasures , METH_NOARGS + , "Dump to disk lots of statistical informations about the routing." } + , { "destroy" , (PyCFunction)PyKatanaEngine_destroy , METH_NOARGS + , "Destroy the associated hurricane object. The python object remains." } + , {NULL, NULL, 0, NULL} /* sentinel */ + }; + + + DBoDeleteMethod(KatanaEngine) + PyTypeObjectLinkPyType(KatanaEngine) + + +#else // End of Python Module Code Part. + + +// +=================================================================+ +// | "PyKatanaEngine" Shared Library Code Part | +// +=================================================================+ + + + // Link/Creation Method. + PyTypeInheritedObjectDefinitions(KatanaEngine,PyToolEngine) + DBoLinkCreateMethod(KatanaEngine) + + +#endif // Shared Library Code Part. + +} // extern "C". + +} // Katana namespace. + diff --git a/katana/src/RoutingEvent.cpp b/katana/src/RoutingEvent.cpp new file mode 100644 index 00000000..29225644 --- /dev/null +++ b/katana/src/RoutingEvent.cpp @@ -0,0 +1,701 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Module : "./RoutingEvent.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include "vlsisapd/configuration/Configuration.h" +#include "hurricane/Bug.h" +#include "hurricane/DebugSession.h" +#include "hurricane/Breakpoint.h" +#include "hurricane/Net.h" +#include "hurricane/Layer.h" +#include "anabatic/AutoContact.h" +#include "katana/DataNegociate.h" +#include "katana/TrackSegment.h" +#include "katana/Track.h" +#include "katana/Tracks.h" +#include "katana/RoutingPlane.h" +#include "katana/RoutingEvent.h" +#include "katana/RoutingEventHistory.h" +#include "katana/RoutingEventQueue.h" +#include "katana/RoutingEventLoop.h" +#include "katana/NegociateWindow.h" +#include "katana/Session.h" +#include "katana/KatanaEngine.h" +#include "katana/Manipulator.h" +#include "katana/SegmentFsm.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::setw; + using std::min; + using std::ostringstream; + using Hurricane::tab; + using Hurricane::DebugSession; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::ForEachIterator; + using Hurricane::Net; + using Hurricane::Layer; + using Anabatic::GCell; + + +// ------------------------------------------------------------------- +// Class : "RoutingEvent::Compare". + + + bool RoutingEvent::Compare::operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const + { + if (lhs == rhs) return false; + return RoutingEvent::Key::Compare()( lhs->getKey(), rhs->getKey() ); + } + + +// ------------------------------------------------------------------- +// Class : "RoutingEvent::Key". + + + bool RoutingEvent::Key::Compare::operator() ( const RoutingEvent::Key& lhs, const RoutingEvent::Key& rhs ) const + { + if (lhs._eventLevel > rhs._eventLevel) return false; + if (lhs._eventLevel < rhs._eventLevel) return true; + + // Process all M2 (terminal access) before any others. + if ((lhs._layerDepth == 1) and (rhs._layerDepth != 1)) return false; + if ((lhs._layerDepth != 1) and (rhs._layerDepth == 1)) return true; + + if (lhs._priority > rhs._priority) return false; + if (lhs._priority < rhs._priority) return true; + + if (lhs._length > rhs._length) return false; + if (lhs._length < rhs._length) return true; + + if ((lhs._segFlags & Flags::Horizontal) xor (rhs._segFlags & Flags::Horizontal)) + return (rhs._segFlags & Flags::Horizontal); + + if (lhs._axis > rhs._axis) return true; + if (lhs._axis < rhs._axis) return false; + + if (lhs._sourceU > rhs._sourceU) return true; + if (lhs._sourceU < rhs._sourceU) return false; + + if (lhs._net->getName() != rhs._net->getName()) + return lhs._net->getName() < rhs._net->getName(); + + return lhs._id < rhs._id; + } + + + RoutingEvent::Key::Key ( const RoutingEvent* event ) + : _tracksNb (event->getTracksNb()) + , _priority (event->getPriority()) + , _eventLevel (event->getEventLevel()) + , _segFlags (event->getSegment()->base()->getFlags()) + , _layerDepth (Session::getRoutingGauge()->getLayerDepth(event->getSegment()->getLayer())) + , _length (event->getSegment()->getLength()) + , _axis (event->getSegment()->getAxis()) + , _sourceU (event->getSegment()->getSourceU()) + , _net (event->getSegment()->getNet()) + , _id (event->getSegment()->getId()) + { } + + + void RoutingEvent::Key::update ( const RoutingEvent* event ) + { + if (not event) return; + + _tracksNb = event->getTracksNb(); + _priority = event->getPriority(); + _eventLevel = event->getEventLevel(); + _segFlags = event->getSegment()->base()->getFlags(); + _layerDepth = Session::getRoutingGauge()->getLayerDepth(event->getSegment()->getLayer()); + _length = event->getSegment()->getLength(); + _axis = event->getSegment()->getAxis(); + _sourceU = event->getSegment()->getSourceU(); + _id = event->getSegment()->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "RoutingEvent". + + + unsigned int RoutingEvent::_idCounter = 0; + unsigned int RoutingEvent::_stage = RoutingEvent::Negociate; + size_t RoutingEvent::_allocateds = 0; + size_t RoutingEvent::_processeds = 0; + size_t RoutingEvent::_cloneds = 0; + + + unsigned int RoutingEvent::getStage () { return _stage; } + size_t RoutingEvent::getAllocateds () { return _allocateds; } + size_t RoutingEvent::getProcesseds () { return _processeds; } + size_t RoutingEvent::getCloneds () { return _cloneds; } + void RoutingEvent::setStage ( unsigned int stage ) { _stage = stage; } + void RoutingEvent::resetProcesseds () { _processeds = 0; } + + + RoutingEvent::RoutingEvent ( TrackElement* segment, unsigned int mode ) + : _cloned (false) + , _processed (false) + , _disabled (false) + , _overConstrained (false) + , _minimized (false) + , _forceToHint (false) + , _ripedByLocal (false) + , _id (_idCounter++) + , _segment (segment) + , _dataNegociate (segment->getDataNegociate()) + , _axisHistory (segment->getAxis()) + , _axisHint (segment->getAxis()) + , _constraints () + , _optimal () + , _tracksNb (0) + , _tracksFree (0) + , _insertState (0) + , _mode (mode) + , _rippleState (0) + , _eventLevel (0) + , _priority (0.0) + , _key (this) + { + if (_idCounter == std::numeric_limits::max()) { + throw Error( "RoutingEvent::RoutingEvent(): Identifier counter has reached it's limit (%d bits)." + , std::numeric_limits::digits ); + } + + DataNegociate* data = _segment->getDataNegociate(); + if (data) data->setRoutingEvent( this ); + + cdebug_log(159,0) << "create: " << this << endl; + cdebug_log(159,0) << "Initial setAxisHint @" << DbU::getValueString(getAxisHint()) << endl; + + if (_segment->getTrack()) { + cerr << Bug( "RoutingEvent::create() - TrackElement is already inserted in a Track." + "\n %s.", getString(_segment).c_str() + ) << endl; + } + } + + + RoutingEvent* RoutingEvent::create ( TrackElement* segment, unsigned int mode ) + { + // if (not dynamic_cast(segment)) { + // cerr << Error( "RoutingEvent::create() Can only create event from TrackSegment:\n" + // " %s", getString(segment).c_str() + // ) << endl; + // } + + RoutingEvent* event = new RoutingEvent ( segment, mode ); + ++_allocateds; + + return event; + } + + + RoutingEvent* RoutingEvent::clone () const + { + _cloned = true; + + RoutingEvent* clone = new RoutingEvent ( *this ); + ++_allocateds; + ++_cloneds; + + clone->_cloned = false; + clone->_disabled = false; + clone->_eventLevel = 0; + + cdebug_log(159,0) << "RoutingEvent::clone() " << clone + << " (from: " << ")" << endl; + + return clone; + } + + + RoutingEvent::~RoutingEvent () + { + cdebug_log(159,0) << "~RoutingEvent() " << endl; + + DataNegociate* data = _segment->getDataNegociate(); + if ( data and (data->getRoutingEvent() == this) ) + data->setRoutingEvent( NULL ); + } + + + void RoutingEvent::destroy () + { + cdebug_log(159,0) << "RoutingEvent::destroy() " << this << endl; + if (_allocateds > 0) --_allocateds; + + delete this; + } + + + bool RoutingEvent::isUnimplemented () const + { return getState() == DataNegociate::Unimplemented; } + + + void RoutingEvent::setMode ( unsigned int mode ) + { _mode = mode; } + + + unsigned int RoutingEvent::getState () const + { + DataNegociate* data = _segment->getDataNegociate(); + return (data) ? data->getState() : 0; + } + + + void RoutingEvent::setState ( unsigned int state ) + { + DataNegociate* data = _segment->getDataNegociate(); + if (data) data->setState( state ); + } + + + void RoutingEvent::setAxisHint ( DbU::Unit axis ) + { + cdebug_log(159,0) << "setAxisHint @" << DbU::getValueString(axis) << " " << _segment << endl; + _axisHint = axis; + } + + + void RoutingEvent::setAxisHintFromParent () + { + if (getStage() == Repair) return; + + TrackElement* parent = _segment->getParent(); + if (not parent) return; + + RoutingEvent* parentEvent = parent->getDataNegociate()->getRoutingEvent(); + if (parentEvent == this) { + cbug << Error( "RoutingEvent::setAxisHintFromParent(): Parentage loop between\n" + " this :%p:%s\n parent:%p:%s" + , _segment->base(),getString(_segment->base()).c_str() + , parent ->base(),getString(parent ->base()).c_str() + ) << endl; + _axisHint = parent->getAxis(); + return; + } + _axisHint = parent->getAxis(); + + cdebug_log(159,0) << "setAxisHintFromParent() - hint:" << DbU::getValueString(_axisHint) + << " axis:" << DbU::getValueString(parent->getAxis()) << " parent:" << parent << endl; + return; + } + + + RoutingEvent* RoutingEvent::reschedule ( RoutingEventQueue& queue, unsigned int eventLevel ) + { + RoutingEvent* active = _segment->getDataNegociate()->getRoutingEvent(); + if (active != this) return active->reschedule( queue, eventLevel ); + + RoutingEvent* fork = NULL; + + if ( (getStage() != Repair) and isUnimplemented() ) { + cdebug_log(159,0) << "Reschedule: cancelled (Unimplemented) " + << " -> " << fork << endl; + return NULL; + } + + if (not isProcessed()) { + fork = this; + cdebug_log(159,0) << "Reschedule/Self: " + << " -> " + << eventLevel << ":" << fork << endl; + } else { + fork = clone(); + fork->_processed = false; + + _segment->getDataNegociate()->setRoutingEvent( fork ); + + cdebug_log(159,0) << "Reschedule/Fork: " + << " -> " << fork << endl; + } + + if (fork->_eventLevel < eventLevel) + fork->_eventLevel = eventLevel; + + if (getStage() == Repair) { + fork->setMode( RoutingEvent::Repair ); + _segment->getDataNegociate()->setState( DataNegociate::Repair ); + } else if (getStage() == RoutingEvent::Pack) { + fork->setMode( RoutingEvent::Pack ); + } + + queue.repush( fork ); + + return fork; + } + + + void RoutingEvent::setSegment ( TrackElement* segment ) + { + if (_segment) _segment->getDataNegociate()->setRoutingEvent( NULL ); + _segment = segment; + _segment->getDataNegociate()->setRoutingEvent( this ); + } + + + void RoutingEvent::process ( RoutingEventQueue& queue + , RoutingEventHistory& history + , RoutingEventLoop& loop + ) + { + loop.update( _segment->getId() ); + if (loop.isLooping()) { + loop.erase( _segment->getId() ); + setState( DataNegociate::Unimplemented ); + +#if LOOP_DEBUG + if (loop.getMaxCount() > 500) { + cbug << Error("Loop detected, removing event %s.",_getString().c_str()) << endl; + + ostringstream message; + message << "Katana has detected a loop between the following Segments:\n"; + + const vector& elements = loop.getElements(); + for ( size_t i=0 ; i"; + + throw Error( message.str().c_str() ); + } +#else + ostringstream message; + message << "[BUG] Katana has detected a loop between the following Segments:"; + + const vector& elements = loop.getElements(); + for ( size_t i=0 ; igetNet(), 150, 160 ); + + cdebug_log(9000,0) << "Deter| Event " + << getProcesseds() + << "," << getEventLevel() + << "," << setw(6) << getPriority() + << ": " << _segment << endl; + _processeds++; + + cdebug_tabw(159,1); + cdebug_log(159,0) << "State: *before* " + << DataNegociate::getStateString(_segment->getDataNegociate()) + << " ripup:" << _segment->getDataNegociate()->getRipupCount() + << endl; + cdebug_log(159,0) << "Level: " << getEventLevel() + << ", area: " << _segment->getFreedomDegree() << endl; + + //_preCheck( _segment ); + _eventLevel = 0; + + if (_mode != Pack) history.push( this ); + + if ( isProcessed() or isDisabled() ) { + cdebug_log(159,0) << "Already processed or disabled." << endl; + } else { + setProcessed(); + setTimeStamp( _processeds ); + + switch ( _mode ) { + case Negociate: _processNegociate( queue, history ); break; + case Pack: _processPack ( queue, history ); break; + case Repair: _processRepair ( queue, history ); break; + default: + cerr << Bug( "RoutingEvent::process() - Unknown mode value:%d.", _mode ) << endl; + break; + } + } + cdebug_tabw(159,-1); + + queue.repushInvalidateds(); + Session::revalidate(); + queue.commit(); + + //_postCheck( _segment ); +#if defined(CHECK_DATABASE) + Session::getKatanaEngine()->_check( _segment->getNet() ); +#endif + DebugSession::close(); + + if (Session::getKatanaEngine()->getPostEventCb() != NULL) + Session::getKatanaEngine()->getPostEventCb()(); + } + + + void RoutingEvent::_processNegociate ( RoutingEventQueue& queue, RoutingEventHistory& history ) + { + cdebug_log(159,0) << "* Mode:Negociation." << endl; + + SegmentFsm fsm ( this, queue, history ); + + if (fsm.getState() == SegmentFsm::MissingData) { + cbug << Error("RoutingEvent::process() - Missing datas.") << endl; + return; + } + + cdebug_tabw(159,1); + + fsm.getData()->incRipupCount(); + + size_t itrack = 0; + for ( itrack = 0 ; itrack < fsm.getCosts().size() ; itrack++ ) + cdebug_log(159,0) << "| " << fsm.getCost(itrack) << endl; + + itrack = 0; + if ( (not isOverConstrained()) and Manipulator(_segment,fsm).canRipup() ) { + if (fsm.getCosts().size() and fsm.getCost(itrack).isFree()) { + cdebug_log(159,0) << "Insert in free space " << this << endl; + resetInsertState(); + + _axisHistory = _segment->getAxis(); + _eventLevel = 0; + cdebug_log(9000,0) << "Deter| addInsertEvent() @" << fsm.getCost(itrack).getTrack() << endl; + if (not _segment->isReduced()) + Session::addInsertEvent( _segment, fsm.getCost(itrack).getTrack() ); + fsm.setState( SegmentFsm::SelfInserted ); + } else { + // Do ripup. + if (fsm.getState() == SegmentFsm::EmptyTrackList) { + Manipulator(_segment,fsm).ripupPerpandiculars(); + } else { + if (Manipulator(_segment,fsm).canRipup(Manipulator::NotOnLastRipup)) { + if (cdebug.enabled(9000)) { + for ( itrack=0 ; itracksetState( DataNegociate::Slacken ); + } + if (not fsm.slackenTopology()) { + fsm.setState( SegmentFsm::SelfMaximumSlack ); + } + } + + fsm.doActions(); + + if (itrack < fsm.getCosts().size()) { + cdebug_log(159,0) << "Placed: @" << DbU::getValueString(fsm.getCost(itrack).getTrack()->getAxis()) + << " " << this << endl; + } + + cdebug_tabw(159,-1); + } + + + void RoutingEvent::_processPack ( RoutingEventQueue& queue, RoutingEventHistory& history ) + { + cdebug_log(159,0) << "* Mode:Pack." << endl; + + if (not _segment->isUTurn()) return; + + SegmentFsm fsm ( this, queue, history ); + if (fsm.getState() == SegmentFsm::MissingData ) return; + if (fsm.getState() == SegmentFsm::EmptyTrackList) return; + + cdebug_tabw(159,1); + for ( size_t i = 0 ; i < fsm.getCosts().size() ; i++ ) + cdebug_log(159,0) << "| " << fsm.getCost(i) << endl; + cdebug_tabw(159,-1); + + if ( _segment->getTrack() + and fsm.getCosts().size() + and fsm.getCost(0).isFree() + and (fsm.getCost(0).getTrack() != _segment->getTrack()) ) { + + cerr << "_processPack(): move to " << fsm.getCost(0).getTrack() << endl; + Session::addMoveEvent( _segment, fsm.getCost(0).getTrack() ); + fsm.setState( SegmentFsm::SelfInserted ); + } + } + + + void RoutingEvent::_processRepair ( RoutingEventQueue& queue, RoutingEventHistory& history ) + { + cdebug_log(159,0) << "* Mode:Repair." << endl; + + if ( _segment->getTrack() != NULL ) { + cdebug_log(159,0) << "* Cancel: already in Track." << endl; + return; + } + + SegmentFsm fsm ( this, queue, history ); + if (fsm.getState() == SegmentFsm::MissingData ) return; + if (fsm.getState() == SegmentFsm::EmptyTrackList) return; + + cdebug_tabw(159,1); + for ( size_t i = 0 ; i < fsm.getCosts().size() ; i++ ) + cdebug_log(159,0) << "| " << fsm.getCost(i) << endl; + cdebug_tabw(159,-1); + + if (fsm.getCosts().size() and fsm.getCost(0).isFree()) { + cdebug_log(159,0) << "Insert in free space." << endl; + Session::addInsertEvent( _segment, fsm.getCost(0).getTrack() ); + fsm.setState( SegmentFsm::SelfInserted ); + } else { + switch ( fsm.getData()->getStateCount() ) { + case 1: + // First try: minimize. + Manipulator(_segment,fsm).minimize (); + fsm.addAction( _segment, SegmentAction::SelfInsert ); + fsm.doActions(); + queue.commit(); + break; + case 2: + // Second try: failed re-inserted first. + Manipulator(_segment,fsm).repackPerpandiculars (); + fsm.addAction( _segment, SegmentAction::SelfInsert ); + fsm.doActions(); + queue.commit(); + break; + default: + cdebug_log(159,0) << "Repair failed." << endl; + break; + } + } + } + + + void RoutingEvent::revalidate () + { + DebugSession::open( _segment->getNet(), 150, 160 ); + + cdebug_log(159,1) << "RoutingEvent::revalidate() - " << this << endl; + + //_dataNegociate->update(); + + setAxisHintFromParent(); + cdebug_log(159,0) << "axisHint:" << DbU::getValueString(getAxisHint()) << endl; + + _overConstrained = false; + _segment->base()->getConstraints( _constraints ); + _segment->base()->getOptimal ( _optimal ); + + cdebug_log(159,0) << "Stage:" << RoutingEvent::getStage() << endl; + if (RoutingEvent::getStage() == RoutingEvent::Repair) { + if (_segment->isStrongTerminal(Flags::Propagate)) { + cdebug_log(159,0) << "Not expanding on Terminals:" << _constraints << endl; + } else { + cdebug_log(159,0) << "Expanding:" << _constraints << endl; + _constraints.inflate( Session::getSliceHeight() ); + cdebug_log(159,0) << "Expanding (after):" << _constraints << endl; + } + } + cdebug_log(159,0) << "| Raw Track Constraint: " << _constraints << endl; + + _tracksNb = 0; + + Interval perpandicular = _constraints; + perpandicular.intersection( getPerpandicularFree()); + cdebug_log(159,0) << "| Perpandicular Free: " << perpandicular << endl; + + if (not perpandicular.isEmpty()) { + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_segment->getLayer()); + Track* track = plane->getTrackByPosition(perpandicular.getVMin()); + + if ( track and (track->getAxis() < perpandicular.getVMin()) ) track = track->getNextTrack(); + for ( ; track and (track->getAxis() <= perpandicular.getVMax()) + ; track = track->getNextTrack(), _tracksNb++ ); + } + if (not _tracksNb) { + cdebug_log(159,0) << "| Reverting to pure constraints." << endl; + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_segment->getLayer()); + Track* track = plane->getTrackByPosition(_constraints.getVMin()); + + if ( track && (track->getAxis() < _constraints.getVMin()) ) track = track->getNextTrack(); + for ( ; track && (track->getAxis() <= _constraints.getVMax()) + ; track = track->getNextTrack(), _tracksNb++ ); + } + if (not _tracksNb) { + cdebug_log(159,0) << "| Pure constraints are too tight." << endl; + if (_segment->base()) + _overConstrained = _segment->base()->getAutoSource()->isTerminal() + and _segment->base()->getAutoTarget()->isTerminal(); + } + + _priority + = (DbU::toLambda(_segment->getLength()) + 1.0) + * (DbU::toLambda(_segment->base()->getSlack()) + 1.0); + + cdebug_log(159,0) << _segment << " has " << (int)_tracksNb << " choices " << perpandicular << endl; + cdebug_tabw(159,-1); + + DebugSession::close(); + } + + + string RoutingEvent::_getTypeName () const + { return "RoutingEvent"; } + + + string RoutingEvent::_getString () const + { + string s = "<" + _getTypeName(); + + s += " " + getString(_eventLevel); + s += "," + getString((long)getPriority()); + s += " @" + DbU::getValueString(getAxisHistory()); + s += ":" + getString(_segment); + s += " " + getString(_segment->getDataNegociate()->getRipupCount()); + s += " "; + s += (isCloned ()?"C":"-"); + s += (isDisabled ()?"d":"-"); + s += (isUnimplemented()?"u":"-"); + s += ">"; + + return s; + } + + + Record* RoutingEvent::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add ( getSlot ( "_segment" , _segment ) ); + record->add ( getSlot ( "_processed" , _processed ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/RoutingEventHistory.cpp b/katana/src/RoutingEventHistory.cpp new file mode 100644 index 00000000..c09a9d77 --- /dev/null +++ b/katana/src/RoutingEventHistory.cpp @@ -0,0 +1,105 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Module : "./RoutingEventHistory.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/Error.h" +#include "katana/RoutingEvent.h" +#include "katana/RoutingEventHistory.h" + + +namespace Katana { + + using std::cerr; + using std::setw; + using std::setfill; + using std::endl; + using Hurricane::Error; + + +// ------------------------------------------------------------------- +// Class : "RoutingEventHistory". + + + RoutingEventHistory::RoutingEventHistory () + : _events () + { } + + + RoutingEventHistory::~RoutingEventHistory () + { clear (); } + + + RoutingEvent* RoutingEventHistory::getNth ( size_t index ) const + { + if ( index < size() ) return _events[index]; + return NULL; + } + + + RoutingEvent* RoutingEventHistory::getRNth ( size_t index ) const + { + if ( index < size() ) return _events[size()-index-1]; + return NULL; + } + + + void RoutingEventHistory::dump ( ostream& o, size_t depth ) const + { + o << " o Event History top stack:" << endl; + if ( _events.empty() ) return; + + size_t stop = (_events.size() > depth) ? (_events.size()-depth-1) : 0; + size_t i = _events.size()-1; + do { + o << " - [" << setfill('0') << setw(3) << i << "]: " << _events[i] << endl; + o << setfill(' '); + } while ( i && (i-- >= stop) ); + } + + + void RoutingEventHistory::push ( RoutingEvent* event ) + { _events.push_back(event); } + + + void RoutingEventHistory::clear () + { + for ( size_t i=0 ; i < _events.size() ; i++ ) + _events[i]->destroy(); + _events.clear (); + } + + + string RoutingEventHistory::_getString () const + { + string s = "<" + _getTypeName(); + + s += ":" + getString(size()); + s += ">"; + + return s; + } + + + Record* RoutingEventHistory::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add ( getSlot ( "_events", &_events ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/RoutingEventLoop.cpp b/katana/src/RoutingEventLoop.cpp new file mode 100644 index 00000000..8c9a7199 --- /dev/null +++ b/katana/src/RoutingEventLoop.cpp @@ -0,0 +1,85 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./RoutingEventLoop.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "katana/RoutingEvent.h" +#include "katana/RoutingEventLoop.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::vector; + using std::stable_sort; + + + RoutingEventLoop::RoutingEventLoop ( size_t depth, int countLimit ) + : _elements () + , _depth (depth) + , _maxCount (0) + , _countLimit(countLimit) + , _isLooping (false) + { } + + + void RoutingEventLoop::update ( size_t id ) + { + vector::iterator ielement = _elements.begin(); + for ( ; ielement != _elements.end() ; ++ielement ) { + if ( (*ielement)._id == id ) { + // Increment an already present element. + (*ielement)._count += 1; + (*ielement)._timestamp = RoutingEvent::getProcesseds(); + _maxCount = std::max ( _maxCount, (*ielement)._count ); + + if ( _maxCount > _countLimit ) _isLooping = true; + break; + } + } + + // The Event was not found. + if ( ielement == _elements.end() ) { + if ( _elements.size() >= _depth ) _elements.pop_back (); + _elements.push_back ( Element(id,RoutingEvent::getProcesseds()) ); + } + + stable_sort ( _elements.begin(), _elements.end(), CompareByTimestamp() ); + } + + + void RoutingEventLoop::erase ( size_t id ) + { + vector::iterator ielement = _elements.begin(); + for ( ; ielement != _elements.end() ; ++ielement ) { + if ( (*ielement)._id == id ) { + _elements.erase ( ielement ); + break; + } + } + + _maxCount = 0; + ielement = _elements.begin(); + for ( ; ielement != _elements.end() ; ++ielement ) { + _maxCount = std::max ( _maxCount, (*ielement)._count ); + } + + _isLooping = (_maxCount > _countLimit); + } + + +} // Katana namespace. diff --git a/katana/src/RoutingEventQueue.cpp b/katana/src/RoutingEventQueue.cpp new file mode 100644 index 00000000..e36bac60 --- /dev/null +++ b/katana/src/RoutingEventQueue.cpp @@ -0,0 +1,275 @@ +// -*- 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 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 : "./RoutingEventQueue.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include "hurricane/Bug.h" +#include "katana/DataNegociate.h" +#include "katana/TrackSegment.h" +#include "katana/RoutingEventQueue.h" +#include "katana/Session.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::setw; + using std::max; + using std::make_heap; + using std::push_heap; + using std::pop_heap; + + using Hurricane::tab; + using Hurricane::Bug; + + + +// ------------------------------------------------------------------- +// Class : "RoutingEventQueue". + + + RoutingEventQueue::RoutingEventQueue () + : _topEventLevel (0) + , _pushRequests () + , _events () + { } + + + RoutingEventQueue::~RoutingEventQueue () + { clear (); } + + + void RoutingEventQueue::load ( const vector& segments ) + { + for ( size_t i=0 ; igetDataNegociate()->getRoutingEvent()) { + cinfo << "[INFO] Already have a RoutingEvent - " << segments[i] << endl; + continue; + } + if (segments[i]->getTrack()) { + cinfo << "[INFO] Already in Track - " << segments[i] << endl; + continue; + } + RoutingEvent* event = RoutingEvent::create(segments[i]); + event->updateKey(); + _events.insert( event ); + } + } + + + void RoutingEventQueue::add ( TrackElement* segment, unsigned int level ) + { + if (segment->getTrack()) { + cinfo << "[INFO] Already in Track " << (void*)segment->base()->base() + << ":" << segment << endl; + return; + } + + RoutingEvent* event = RoutingEvent::create(segment); + event->setEventLevel( level ); + push( event ); + } + + + void RoutingEventQueue::commit () + { + cdebug_log(159,1) << "RoutingEventQueue::commit()" << endl; + + size_t addeds = _pushRequests.size(); + size_t before = _events.size(); + + RoutingEventSet::iterator ipushEvent = _pushRequests.begin(); + for ( ; ipushEvent != _pushRequests.end() ; ipushEvent++ ) { + (*ipushEvent)->updateKey(); + + _topEventLevel = max( _topEventLevel, (*ipushEvent)->getEventLevel() ); + _events.insert( (*ipushEvent) ); + + cdebug_log(159,0) << "| " << (*ipushEvent) << endl; + } + _pushRequests.clear(); +#if defined(CHECK_ROUTINGEVENT_QUEUE) + _keyCheck(); +#endif + size_t after = _events.size(); + if (after-before != addeds) { + cerr << Bug( "RoutingEventQueue::commit(): less than %d events pusheds (%d)." + , addeds,(after-before) ) << endl; + } + + cdebug_tabw(159,-1); + } + + + RoutingEvent* RoutingEventQueue::pop () + { + multiset::iterator ievent; + RoutingEvent* event = NULL; + +#if defined(CHECK_ROUTINGEVENT_QUEUE) + _keyCheck (); +#endif + + if (not _events.empty()) { + size_t beforeSize = _events.size(); + + ievent = _events.end(); + ievent--; + event = (*ievent); + _events.erase( ievent ); + + size_t afterSize = _events.size(); + + if (afterSize+1 != beforeSize) { + cerr << Bug( "RoutingEventQueue::pop(): more than one event popped: %d." + , (beforeSize-afterSize) ) << endl; + } + } + + return event; + } + + + void RoutingEventQueue::repush ( RoutingEvent* event ) + { +#if defined(CHECK_ROUTINGEVENT_QUEUE) + _keyCheck (); +#endif + + multiset::iterator ievent = _events.find(event); + size_t count = _events.count(event); + if (count > 1) { + cerr << Bug("RoutingEventQueue::repush(): %d events matches key %p.",count,event) << endl; +#if defined(CHECK_ROUTINGEVENT_QUEUE) + _keyCheck (); +#endif + } + + if (ievent != _events.end()) { + _events.erase( ievent ); + } + push ( event ); + } + + + void RoutingEventQueue::repushInvalidateds () + { + const vector& invalidateds0 = Session::getInvalidateds(); + TrackSegmentSet invalidateds1; + for ( size_t i=0 ; i( Session::lookup(invalidateds0[i]) ); + if (segment) + invalidateds1.insert( segment ); + } + + TrackSegmentSet::iterator isegment = invalidateds1.begin(); + for ( ; isegment != invalidateds1.end() ; isegment++ ) { + RoutingEvent* event = (*isegment)->getDataNegociate()->getRoutingEvent(); + if ( event + and not event->isUnimplemented() + and not event->isDisabled () + and not event->isProcessed () ) { + repush( event ); + } + } + } + + + void RoutingEventQueue::prepareRepair () + { + multiset::const_iterator ievent = _events.begin (); + for ( ; ievent != _events.end(); ++ievent ) { + (*ievent)->getSegment()->base()->toOptimalAxis(); + } + } + + + void RoutingEventQueue::clear () + { + if (not _events.empty()) { + cerr << Bug("RoutingEvent queue is not empty, %d events remains." + ,_events.size()) << endl; + } + _events.clear(); + } + + + void RoutingEventQueue::dump () const + { + multiset::const_iterator ievent = _events.begin (); + for ( ; ievent != _events.end(); ievent++ ) { + cerr << "Deter| Queue:" + << (*ievent)->getEventLevel() + << "," << setw(6) << (*ievent)->getPriority() + << " " << setw(6) << DbU::getValueString((*ievent)->getSegment()->getLength()) + << " " << (*ievent)->getSegment()->isHorizontal() + << " " << setw(6) << DbU::getValueString((*ievent)->getSegment()->getAxis()) + << " " << setw(6) << DbU::getValueString((*ievent)->getSegment()->getSourceU()) + << ": " << (*ievent)->getSegment() << endl; + } + } + + + void RoutingEventQueue::_keyCheck () const + { + multiset::const_iterator ievent = _events.begin (); + for ( ; ievent != _events.end(); ievent++ ) { + multiset::const_iterator ieventByKey + = _events.find ( *ievent ); + + if ( ieventByKey != ievent ) { + if ( ieventByKey == _events.end() ) { + cerr << Bug("Key mismatch in RoutingEvent Queue:\n" + " %p:%s wasn't found by key." + ,*ievent,getString(*ievent).c_str() + ) << endl; + } else { + cerr << Bug("Key mismatch in RoutingEvent Queue:\n" + " %p:%s has same key of\n" + " %p:%s" + ,*ievent,getString(*ievent).c_str() + ,*ieventByKey,getString(*ieventByKey).c_str() + ) << endl; + } + } + } + } + + + string RoutingEventQueue::_getString () const + { + string s = "<" + _getTypeName(); + + s += ":" + getString(size()); + s += ">"; + + return s; + } + + + Record* RoutingEventQueue::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add ( getSlot ( "_events", &_events ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/RoutingPlane.cpp b/katana/src/RoutingPlane.cpp new file mode 100644 index 00000000..af675d6f --- /dev/null +++ b/katana/src/RoutingPlane.cpp @@ -0,0 +1,214 @@ +// -*- 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 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 : "./RoutingPlane.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Error.h" +#include "hurricane/Box.h" +#include "hurricane/Cell.h" +#include "crlcore/RoutingLayerGauge.h" +#include "katana/HorizontalTrack.h" +#include "katana/VerticalTrack.h" +#include "katana/RoutingPlane.h" +#include "katana/KatanaEngine.h" + + +namespace { + + + const char* badLayerGauge = + "RoutingPlane::create() :\n\n" + " No plane at depth %u in %s."; + + +} // End of local namespace. + + +namespace Katana { + + using std::cerr; + using std::endl; + using Hurricane::tab; + using Hurricane::Error; + using Hurricane::Box; + using Hurricane::Cell; + + +// ------------------------------------------------------------------- +// Class : "RoutingPlane". + + + RoutingPlane::RoutingPlane ( KatanaEngine* katana, size_t depth ) + : _katana (katana) + , _layerGauge(katana->getConfiguration()->getLayerGauge(depth)) + , _depth (depth) + , _flags (0) + , _axisMin (0) + , _axisMax (0) + , _trackMin (0) + , _trackMax (0) + , _tracks () + { + switch ( _layerGauge->getDirection() ) { + case Constant::Horizontal: _flags |= Flags::Horizontal; break; + case Constant::Vertical: _flags |= Flags::Vertical; break; + default: + cerr << Error( "RoutingPlane::RoutingPlane() - Unknown plane direction from LayerGauge: %u" + , _layerGauge->getDirection() ) << endl; + } + } + + + RoutingPlane::~RoutingPlane () + { } + + + void RoutingPlane::destroy () + { + cdebug_log(155,1) << "RoutingPlane::destroy() - " + << (void*)this << " " << this << endl; + + for ( size_t index=0 ; index<_tracks.size() ; ++index ) + _tracks[index]->destroy(); + + delete this; + + cdebug_tabw(155,-1); + } + + + RoutingPlane* RoutingPlane::create ( KatanaEngine* katana, size_t depth ) + { + RoutingPlane* plane = new RoutingPlane ( katana, depth ); + + if (not plane->_layerGauge) + throw Error( badLayerGauge, depth, getString(katana->getConfiguration()->getRoutingGauge()).c_str() ); + + DbU::Unit hExtension = 0; + DbU::Unit vExtension = 0; + unsigned int gaugeDepth = 0; + if (Session::getLayerGauge(gaugeDepth)->getType() == Constant::PinOnly) ++gaugeDepth; + + bool HV = (Session::getLayerGauge(gaugeDepth)->getDirection() == Constant::Horizontal); + hExtension = Session::getLayerGauge( gaugeDepth + (HV?1:0) )->getPitch() / 2; + vExtension = Session::getLayerGauge( gaugeDepth + (HV?0:1) )->getPitch() / 2; + + size_t trackNumber; + Box abutmentBox = katana->getCell()->getAbutmentBox(); + // HARD CODED. + if (plane->getDirection() == Flags::Horizontal) { + plane->_trackMin = abutmentBox.getXMin() - hExtension; + plane->_trackMax = abutmentBox.getXMax() + hExtension; + plane->_axisMin = abutmentBox.getYMin(); + plane->_axisMax = abutmentBox.getYMax(); + trackNumber = plane->computeTracksSize(); + } else { + plane->_trackMin = abutmentBox.getYMin() - vExtension; + plane->_trackMax = abutmentBox.getYMax() + vExtension; + plane->_axisMin = abutmentBox.getXMin(); + plane->_axisMax = abutmentBox.getXMax(); + trackNumber = plane->computeTracksSize(); + } + + plane->_tracks.reserve( trackNumber ); + for ( size_t index=0 ; indexgetDirection() == Flags::Horizontal) { + plane->_tracks.push_back( HorizontalTrack::create( plane, index ) ); + // Ugly: Direct uses of CellGauge (middle tracks 4 & 5 for local use). + if (depth == 1) { + switch ( index%10 ) { + case 4: + case 5: + plane->_tracks.back()->setLocalAssigned( true ); + break; + } + } + } else { + plane->_tracks.push_back( VerticalTrack::create( plane, index ) ); + } + } + + return plane; + } + + + RoutingPlane* RoutingPlane::getTop () const + { return getKatanaEngine()->getRoutingPlaneByIndex( getDepth()+1 ); } + + + RoutingPlane* RoutingPlane::getBottom () const + { + if (not getDepth()) return NULL; + return getKatanaEngine()->getRoutingPlaneByIndex( getDepth()-1 ); + } + + + Track* RoutingPlane::getTrackByIndex ( size_t index ) const + { + if (index >= getTracksSize()) return NULL; + return _tracks[index]; + } + + + Track* RoutingPlane::getTrackByPosition ( DbU::Unit axis, unsigned int mode ) const + { + return getTrackByIndex( getLayerGauge()->getTrackIndex( getAxisMin() + , getAxisMax() + , axis + , mode + ) ); + } + + + bool RoutingPlane::_check ( unsigned int& overlaps ) const + { + bool coherency = true; + + for ( size_t i=0 ; i<_tracks.size() ; ++i ) { + coherency = _tracks[i]->check(overlaps) and coherency; + } + + return coherency; + } + + + string RoutingPlane::_getString () const + { + return "<" + _getTypeName() + " @" + + getString(_depth) + " " + + getString(getLayer()) + " [ " + + ((getDirection() == Flags::Horizontal) ? " horizontal [" : " vertical [") + + getString(_tracks.size()) + "/" + + getString(_tracks.capacity()) + + "]>"; + } + + + Record* RoutingPlane::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add( getSlot ( "_katana" , _katana ) ); + record->add( getSlot ( "_layerGauge" , _layerGauge ) ); + record->add( getSlot ( "_depth" , &_depth ) ); + record->add( DbU::getValueSlot( "_axisMin" , &_axisMin ) ); + record->add( DbU::getValueSlot( "_axisMax" , &_axisMax ) ); + record->add( DbU::getValueSlot( "_trackMin" , &_trackMin ) ); + record->add( DbU::getValueSlot( "_trackMax" , &_trackMax ) ); + record->add( getSlot ( "_tracks" , &_tracks ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/SegmentFsm.cpp b/katana/src/SegmentFsm.cpp new file mode 100644 index 00000000..1f430870 --- /dev/null +++ b/katana/src/SegmentFsm.cpp @@ -0,0 +1,1241 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Module : "./SegmentFsm.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/Bug.h" +#include "hurricane/DebugSession.h" +#include "katana/TrackElement.h" +#include "katana/Tracks.h" +#include "katana/RoutingPlane.h" +#include "katana/DataNegociate.h" +#include "katana/RoutingEvent.h" +#include "katana/RoutingEventQueue.h" +#include "katana/RoutingEventHistory.h" +#include "katana/Manipulator.h" +#include "katana/SegmentFsm.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using namespace Katana; + + +// ------------------------------------------------------------------- +// Class : "Cs1Candidate". + + class Cs1Candidate { + public: + inline Cs1Candidate ( Track* track=NULL, DbU::Unit ppitch=0 ); + inline Track* getTrack () const; + inline size_t getBegin () const; + inline size_t getEnd () const; + inline size_t getLength () const; + inline Interval getConflict ( size_t ); + inline Interval getLongestConflict () const; + inline DbU::Unit getBreakPos () const; + inline DbU::Unit getConflictLength () const; + inline void setBegin ( size_t ); + inline void setEnd ( size_t ); + inline void addConflict ( const Interval& ); + void consolidate (); + public: + friend inline bool operator< ( const Cs1Candidate&, const Cs1Candidate& ); + private: + Track* _track; + DbU::Unit _ppitch; + size_t _begin; + size_t _end; + vector _conflicts; + Interval _longestConflict; + DbU::Unit _breakPos; + DbU::Unit _conflictLength; + }; + + + inline Cs1Candidate::Cs1Candidate ( Track* track, DbU::Unit ppitch ) + : _track (track) + , _ppitch (ppitch) + , _begin (0) + , _end (0) + , _conflicts () + , _longestConflict() + , _breakPos (0) + , _conflictLength (0) + { } + + inline Track* Cs1Candidate::getTrack () const { return _track; } + inline size_t Cs1Candidate::getBegin () const { return _begin; } + inline size_t Cs1Candidate::getEnd () const { return _end; } + inline size_t Cs1Candidate::getLength () const { return _conflicts.size(); } + inline Interval Cs1Candidate::getLongestConflict () const { return _longestConflict; } + inline DbU::Unit Cs1Candidate::getBreakPos () const { return _breakPos; } + inline void Cs1Candidate::setBegin ( size_t i ) { _begin=i; } + inline void Cs1Candidate::setEnd ( size_t i ) { _end=i; } + + inline void Cs1Candidate::addConflict ( const Interval& conflict ) + { + _conflicts.push_back(conflict); + _conflictLength += conflict.getSize(); + + if (conflict.getSize() > _longestConflict.getSize()) + _longestConflict = conflict; + } + + inline Interval Cs1Candidate::getConflict ( size_t i ) + { + if (i >= _conflicts.size()) return Interval(); + return _conflicts[i]; + } + + inline bool operator< ( const Cs1Candidate& lhs, const Cs1Candidate& rhs ) + { + DbU::Unit delta = lhs._longestConflict.getSize() - rhs._longestConflict.getSize(); + if (delta < 0) return true; + if (delta > 0) return false; + + return lhs._conflictLength < rhs._conflictLength; + } + + + void Cs1Candidate::consolidate () + { + if (_conflicts.size() > 0) { + DbU::Unit halfConflict = 0; + size_t i = 0; + for ( ; i<_conflicts.size()-1 ; ++i ) { + halfConflict += _conflicts[i].getSize(); + if (halfConflict > _conflictLength/2) + break; + } + + // Ugly: hard-coded pitch. + _breakPos = _conflicts[i].getVMin() - _ppitch; + } + } + + +// ------------------------------------------------------------------- +// Class : "UnionItervals". + + class UnionIntervals { + public: + inline UnionIntervals (); + void addInterval ( Interval& ); + inline size_t size () const; + inline bool empty () const; + inline list::const_iterator begin () const; + inline list::const_iterator end () const; + inline DbU::Unit getVMin () const; + inline DbU::Unit getVMax () const; + string _getString (); + private: + list _intervals; + }; + + + inline UnionIntervals::UnionIntervals () : _intervals() { } + inline list::const_iterator UnionIntervals::begin () const { return _intervals.begin(); } + inline list::const_iterator UnionIntervals::end () const { return _intervals.end(); } + inline size_t UnionIntervals::size () const { return _intervals.size(); } + inline bool UnionIntervals::empty () const { return _intervals.empty(); } + inline DbU::Unit UnionIntervals::getVMin () const { return (empty()) ? DbU::Max : (*begin()).getVMin(); } + inline DbU::Unit UnionIntervals::getVMax () const { return (empty()) ? DbU::Min : (*begin()).getVMax(); } + + + void UnionIntervals::addInterval ( Interval& interval ) + { + cdebug_log(159,0) << "UnionInterval::addInterval() - " << interval << endl; + + list::iterator iintv = _intervals.begin (); + + bool merged = false; + while ( iintv != _intervals.end() ) { + if (not merged) { + if (interval.getVMax() < (*iintv).getVMin()) { _intervals.insert( iintv, interval ); return; } + if (interval.getVMin() > (*iintv).getVMax()) { ++iintv; continue; } + + merged = true; + interval = (*iintv).merge( interval ); + ++iintv; + } else { + if ((*iintv).intersect( interval )) { + interval = (*iintv).merge( interval ); + iintv = _intervals.erase( iintv ); + continue; + } else + break; + } + } + + if (not merged) _intervals.push_back( interval ); + } + + + string UnionIntervals::_getString () + { + ostringstream s; + + list::iterator iintv = _intervals.begin(); + for ( ; iintv != _intervals.end() ; ++iintv ) { + s << " [" << DbU::getValueString((*iintv).getVMin()) + << ":" << DbU::getValueString((*iintv).getVMax()) << "]"; + } + return s.str(); + } + + +// ------------------------------------------------------------------- +// Class : "RipupHistory". + + class RipupHistory { + public: + RipupHistory ( RoutingEvent* ); + inline bool isDislodger ( RoutingEvent* ) const; + inline size_t size () const; + inline size_t getDislodgersCount () const; + void addAxis ( DbU::Unit ); + void addAxis ( RoutingEvent* ); + bool hasAxis ( DbU::Unit ) const; + UnionIntervals* getUnionIntervals ( DbU::Unit ); + void addDislodger ( RoutingEvent* ); + void addDislodger ( TrackElement* ); + void print ( ostream& ); + private: + RoutingEvent* _masterEvent; + map _dislodgers; + size_t _dislodgersCount; + }; + + + RipupHistory::RipupHistory ( RoutingEvent* event ) + : _masterEvent (event) + , _dislodgers () + , _dislodgersCount(0) + { + const Interval& perpandicular = _masterEvent->getPerpandicularFree(); + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(_masterEvent->getSegment()->getLayer()); + Track* track; + + if (not perpandicular.isEmpty()) { + track = plane->getTrackByPosition(perpandicular.getVMin()); + + if (track and (track->getAxis() < perpandicular.getVMin())) track = track->getNextTrack(); + for ( ; track && (track->getAxis() <= perpandicular.getVMax()) + ; track = track->getNextTrack() ) + addAxis( track->getAxis() ); + } + + track = plane->getTrackByPosition(_masterEvent->getSegment()->getAxis()); + if (track) { + size_t begin = Track::npos; + size_t end = Track::npos; + Interval interval = _masterEvent->getSegment()->getCanonicalInterval(); + track->getOverlapBounds( interval, begin, end ); + + if (begin != Track::npos) { + for ( ; begin < end ; ++begin ) { + TrackElement* other = track->getSegment(begin); + if (other->getNet() == _masterEvent->getSegment()->getNet() ) continue; + if (not interval.intersect(other->getCanonicalInterval())) continue; + + addDislodger( other ); + } + } + } + } + + + inline bool RipupHistory::isDislodger ( RoutingEvent* event ) const { return hasAxis(event->getSegment()->getAxis()); } + inline size_t RipupHistory::size () const { return _dislodgers.size(); } + inline size_t RipupHistory::getDislodgersCount () const { return _dislodgersCount; } + + + void RipupHistory::addAxis ( DbU::Unit axis ) + { + if (hasAxis(axis)) return; + _dislodgers.insert( make_pair(axis,UnionIntervals()) ); + } + + + void RipupHistory::addAxis ( RoutingEvent* event ) + { addAxis( event->getAxisHistory() ); } + + + bool RipupHistory::hasAxis ( DbU::Unit axis ) const + { return _dislodgers.find(axis) != _dislodgers.end(); } + + + UnionIntervals* RipupHistory::getUnionIntervals ( DbU::Unit axis ) + { + map::iterator iunion = _dislodgers.find ( axis ); + if (iunion == _dislodgers.end()) return NULL; + + return &(iunion->second); + } + + + void RipupHistory::addDislodger ( RoutingEvent* event ) + { + if (event->getSegment() == _masterEvent->getSegment()) return; + if (event->getSegment()->getLayer() != _masterEvent->getSegment()->getLayer()) return; + + UnionIntervals* intervals = getUnionIntervals( event->getAxisHistory() ); + if (not intervals) return; + + Interval canonical = event->getSegment()->getCanonicalInterval(); + intervals->addInterval( canonical ); + + ++_dislodgersCount; + } + + + void RipupHistory::addDislodger ( TrackElement* segment ) + { + if (_masterEvent->getSegment()->getNet() == segment->getNet()) return; + + UnionIntervals* intervals = getUnionIntervals( segment->getAxis() ); + if (not intervals) return; + + Interval canonical = segment->getCanonicalInterval(); + intervals->addInterval( canonical ); + + ++_dislodgersCount; + } + + + void RipupHistory::print ( ostream& o ) + { + o << "[HISTORY] " << _masterEvent << endl; + + map::iterator iunion = _dislodgers.begin(); + for ( ; iunion != _dislodgers.end() ; ++iunion ) + o << " @" << DbU::getValueString(iunion->first) + << " " << (iunion->second)._getString() << endl; + } + + +} // Anonymous namespace. + + +namespace Katana { + + using std::sort; + using Hurricane::tab; + using Hurricane::DebugSession; + using Hurricane::Bug; + using Hurricane::ForEachIterator; + + +// ------------------------------------------------------------------- +// Class : "SegmentAction". + + SegmentAction::SegmentAction ( TrackElement* segment + , unsigned int type + , DbU::Unit axisHint + , unsigned int toState + ) + : _segment (segment) + , _type (type) + , _axisHint(axisHint) + , _toState (toState) + { } + + + bool SegmentAction::doAction ( RoutingEventQueue& queue ) + { + // Note: + // "_immediate" ripup flags was associated with "perpandicular", as they + // must be re-inserted *before* any parallel. Must look to solve the redundancy. + + DebugSession::open( _segment->getNet(), 150, 160 ); + + if (_type & Perpandicular) { + cdebug_log(159,0) << "* Riping Pp " << _segment << endl; + } else { + cdebug_log(159,0) << "* Riping // " << _segment << endl; + } + + if (_segment->isFixed()) { DebugSession::close(); return true; } + + DataNegociate* data = _segment->getDataNegociate(); + if (data == NULL) { DebugSession::close(); return true; } + + if (_type & ResetRipup) data->resetRipupCount(); + + if (_type & ToState) { + data->setState ( _toState ); + data->setRipupCount( Session::getKatanaEngine()->getRipupLimit(_segment) ); + } + + if (_segment->getTrack()) Session::addRemoveEvent( _segment ); + + RoutingEvent* event = data->getRoutingEvent(); + if (event == NULL) { + cerr << Bug( "Missing Event on %p:%s" + , _segment->base()->base(),getString(_segment).c_str() ) << endl; + DebugSession::close(); + return true; + } + + if ( (_type & AxisHint) /*and not _segment->isSlackenDogleg()*/ ) { + cdebug_log(159,0) << "Setting Axis Hint: @" << DbU::getValueString(_axisHint) << endl; + event->setAxisHint( _axisHint ); + } + + // It is possible that this code could be disabled. + // There should be no need to move the axis of the segment to be inserted, + // it will automatically slot into the empty track, if any. + if (_type & MoveToAxis) { + cdebug_log(159,0) << "Moving Axis To: @" << DbU::getValueString(_axisHint) << endl; + _segment->setAxis( _axisHint ); + } + + if (_type & ToRipupLimit) { + unsigned int limit = Session::getKatanaEngine()->getRipupLimit(_segment); + if (limit > data->getRipupCount()) + data->setRipupCount( limit ); + } + + unsigned int eventLevel = 0; + if (_type & EventLevel1) eventLevel = 1; + if (_type & EventLevel2) eventLevel = 2; + if (_type & EventLevel3) eventLevel = 3; + if (_type & EventLevel4) eventLevel = 4; + if (_type & EventLevel5) eventLevel = 5; + event->setRipedByLocal( _type&RipedByLocal ); + + RoutingEvent* fork = event->reschedule( queue, eventLevel ); + + if (fork) { + unsigned int mode = RoutingEvent::Repair; + if (RoutingEvent::getStage() < RoutingEvent::Repair) + mode = (_type&PackingMode) ? RoutingEvent::Pack : RoutingEvent::Negociate; + fork->setMode( mode ); + } + + DebugSession::close(); + return true; + } + + +// ------------------------------------------------------------------- +// Class : "SegmentFsm". + + + SegmentFsm::SegmentFsm ( RoutingEvent* event, RoutingEventQueue& queue, RoutingEventHistory& history ) + : _event (event) + , _queue (queue) + , _history (history) + , _state (0) + , _data (NULL) + , _constraint () + , _optimal () + , _costs () + , _actions () + , _fullBlocked(true) + { + TrackElement* segment = _event->getSegment(); + unsigned int depth = Session::getRoutingGauge()->getLayerDepth(segment->getLayer()); + _event->setTracksFree( 0 ); + + _data = segment->getDataNegociate(); + if (not _data) { + _state = MissingData; + return; + } + + _data->update(); + _event->revalidate(); + + _constraint = _event->getConstraints(); + _optimal = _event->getOptimal(); + + const Interval& perpandicular = _event->getPerpandicularFree(); + + cdebug_log(159,0) << "Anabatic intervals:" << endl; + cdebug_log(159,0) << "* Optimal: " << _optimal << endl; + cdebug_log(159,0) << "* Constraints: " << _constraint << endl; + cdebug_log(159,0) << "* Perpandicular: " << perpandicular << endl; + cdebug_log(159,0) << "* AxisHint: " << DbU::getValueString(_event->getAxisHint()) << endl; + + if (_event->getTracksNb()) { + if (_constraint.getIntersection(perpandicular).isEmpty()) { + cdebug_log(159,0) << "Perpandicular free is too tight." << endl; + _state = EmptyTrackList; + } else + _constraint.intersection( perpandicular ); + } else { + cdebug_log(159,0) << "No Track in perpandicular free." << endl; + _state = EmptyTrackList; + } + + if (_state == EmptyTrackList) return; + + cdebug_log(159,0) << "Negociate intervals:" << endl; + cdebug_log(159,0) << "* Optimal: " << _optimal << endl; + cdebug_log(159,1) << "* Constraints: " << _constraint << endl; + + // if ( segment->isLocal() and (_data->getState() >= DataNegociate::MaximumSlack) ) + // _constraint.inflate ( 0, DbU::lambda(1.0) ); + + bool inLocalDepth = (depth < 3); + bool isOneLocalTrack = (segment->isLocal()) + and (segment->base()->getAutoSource()->getGCell()->getGlobalsCount(depth) >= 9.0); + + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment->getLayer()); + for ( Track* track : Tracks_Range::get(plane,_constraint) ) { + unsigned int costflags = 0; + costflags |= (segment->isLocal() and (depth >= 3)) ? TrackCost::LocalAndTopDepth : 0; + + if (not segment->isReduced()) + _costs.push_back( track->getOverlapCost(segment,costflags) ); + else + _costs.push_back( TrackCost(track,segment->getNet()) ); + _costs.back().setAxisWeight ( _event->getAxisWeight(track->getAxis()) ); + _costs.back().incDeltaPerpand( _data->getWiringDelta(track->getAxis()) ); + if (segment->isGlobal()) { + cdebug_log(9000,0) << "Deter| setForGlobal() on " << track << endl; + _costs.back().setForGlobal(); + } + + if ( inLocalDepth and (_costs.back().getDataState() == DataNegociate::MaximumSlack) ) + _costs.back().setInfinite(); + + if ( isOneLocalTrack + and _costs.back().isOverlapGlobal() + and (_costs.back().getDataState() >= DataNegociate::ConflictSolveByHistory) ) + _costs.back().setInfinite(); + + _costs.back().consolidate(); + if ( _fullBlocked and (not _costs.back().isBlockage() and not _costs.back().isFixed()) ) + _fullBlocked = false; + + cdebug_log(159,0) << "| " << _costs.back() << ((_fullBlocked)?" FB ": " -- ") << track << endl; + } + cdebug_tabw(159,-1); + + if (_costs.empty()) { + Track* nearest = plane->getTrackByPosition(_constraint.getCenter()); + + if ( (nearest->getAxis() < _constraint.getVMin()) + or (nearest->getAxis() > _constraint.getVMax()) ) { + //setUnimplemented (); + //cerr << "[UNIMPLEMENTED] " << segment << " no Track in constraint interval " + // << _constraint << " " << "." << endl; + } else { + cerr << Bug( " %s Track_Range() failed to find Tracks in %s (they exists)." + , getString(segment).c_str() + , getString(_constraint).c_str() + ) << endl; + } + _state = EmptyTrackList; + } + + unsigned int flags = 0; + flags |= (segment->isStrap()) ? TrackCost::IgnoreAxisWeight : 0; + flags |= (segment->isLocal() + and (_data->getState() < DataNegociate::Minimize) + and (_data->getRipupCount() < 5)) + ? TrackCost::DiscardGlobals : 0; + flags |= (RoutingEvent::getStage() == RoutingEvent::Repair) ? TrackCost::IgnoreSharedLength : 0; + + if (flags & TrackCost::DiscardGlobals) { + cdebug_log(159,0) << "TrackCost::Compare() - DiscardGlobals" << endl; + } + + sort( _costs.begin(), _costs.end(), TrackCost::Compare(flags) ); + + size_t i=0; + for ( ; (i<_costs.size()) and _costs[i].isFree() ; i++ ); + _event->setTracksFree ( i ); + } + + + void SegmentFsm::addAction ( TrackElement* segment + , unsigned int type + , DbU::Unit axisHint + , unsigned int toSegmentFsm ) + { + if ( not segment->isFixed() ) { + _actions.push_back ( SegmentAction(segment,type,axisHint,toSegmentFsm) ); + cdebug_log(159,0) << "SegmentFsm::addAction(): " << segment << endl; + } + } + + + void SegmentFsm::doActions () + { + cdebug_log(159,0) << "SegmentFsm::doActions() - " << _actions.size() << endl; + + bool ripupOthersParallel = false; + bool ripedByLocal = getEvent()->getSegment()->isLocal(); + + for ( size_t i=0 ; i<_actions.size() ; i++ ) { + if ( ripedByLocal ) _actions[i].setFlag ( SegmentAction::RipedByLocal ); + if ( _actions[i].getType() & SegmentAction::OtherRipup ) { + ripupOthersParallel = true; + } + } + + for ( size_t i=0 ; i<_actions.size() ; i++ ) { + if ( (_actions[i].getType() & SegmentAction::SelfInsert) and ripupOthersParallel ) + _actions[i].setFlag ( SegmentAction::EventLevel3 ); + + DebugSession::open ( _actions[i].getSegment()->getNet(), 150, 160 ); + if ( not _actions[i].doAction(_queue) ) { + cinfo << "[INFO] Failed action on " << _actions[i].getSegment() << endl; + } + DebugSession::close (); + } + + _actions.clear (); + } + + + bool SegmentFsm::insertInTrack ( size_t i ) + { + cdebug_log(159,0) << "SegmentFsm::insertInTrack() istate:" << _event->getInsertState() + << " track:" << i << endl; + + _event->incInsertState(); + switch ( _event->getInsertState() ) { + case 1: + if ( Manipulator(_event->getSegment(),*this).insertInTrack(i) ) return true; + _event->incInsertState(); + case 2: + if ( Manipulator(_event->getSegment(),*this).shrinkToTrack(i) ) return true; + _event->incInsertState(); + case 3: + if ( Manipulator(_event->getSegment(),*this).forceToTrack(i) ) return true; + _event->incInsertState(); + } + return false; + } + + + bool SegmentFsm::conflictSolveByHistory () + { + bool success = false; + RipupHistory ripupHistory ( _event ); + RoutingEvent* event; + TrackElement* segment = _event->getSegment(); + + cdebug_log(159,0) << "SegmentFsm::conflictSolveByHistory()" << endl; + + size_t maxDepth = min( getHistory().size(), (size_t)300 ); + size_t depth = 0; + while ( (ripupHistory.getDislodgersCount() < 3) and (depth < maxDepth) ) { + event = getHistory().getRNth(depth++); + if (not event) continue; + if ( (event->getSegment() != segment) and ripupHistory.isDislodger(event) ) + ripupHistory.addDislodger( event ); + } + + //ripupHistory.print ( cout ); + + UnionIntervals* intervals = ripupHistory.getUnionIntervals( segment->getAxis() ); + if (intervals and not intervals->empty()) { + + DbU::Unit minConflict = intervals->getVMin(); + DbU::Unit maxConflict = intervals->getVMax(); + Interval canonical = segment->getCanonicalInterval(); + bool sourceDogleg = canonical.contains(minConflict); + bool targetDogleg = canonical.contains(maxConflict); + Point breakPoint; + + if (sourceDogleg) { + if (segment->isHorizontal()) { + breakPoint = Point( minConflict, segment->getAxis() ); + cdebug_log(159,0) << breakPoint << endl; + } else { + breakPoint = Point( segment->getAxis(), minConflict ); + cdebug_log(159,0) << breakPoint << endl; + } + + Anabatic::GCell* dogLegGCell = Session::getGCellUnder( breakPoint.getX(), breakPoint.getY() ); + if (dogLegGCell) { + if (segment->canDogleg(dogLegGCell)) + success = segment->makeDogleg(dogLegGCell); + } else { + cerr << Bug( "No GCell under source %s for:\n %s." + , getString(breakPoint).c_str(), getString(segment).c_str() ) << endl; + } + } + + if (not success and targetDogleg) { + if (segment->isHorizontal()) { + breakPoint = Point( maxConflict, segment->getAxis() ); + cdebug_log(159,0) << breakPoint << endl; + } else { + breakPoint = Point( segment->getAxis(), maxConflict ); + cdebug_log(159,0) << breakPoint << endl; + } + + Anabatic::GCell* dogLegGCell = Session::getGCellUnder( breakPoint.getX(), breakPoint.getY() ); + if (dogLegGCell) { + if (segment->canDogleg(dogLegGCell)) { + success = segment->makeDogleg(dogLegGCell); + } + } else { + cerr << Bug( "No GCell under target %s for:\n %s." + , getString(breakPoint).c_str(), getString(segment).c_str() ) << endl; + } + } + } else { + cdebug_log(159,0) << "No disloggers found @" << DbU::getValueString(segment->getAxis()) << endl; + + Interval freeSpan = Session::getKatanaEngine()-> + getTrackByPosition(segment->getLayer(),segment->getAxis())-> + getFreeInterval(segment->getSourceU(),segment->getNet()); + + if (freeSpan.contains(segment->getCanonicalInterval())) { + cdebug_log(159,0) << "Disloggers vanished, Segment can be re-inserted." << endl; + success = true; + } + } + + return success; + } + + + bool SegmentFsm::conflictSolveByPlaceds () + { + bool success = false; + Interval constraints; + vector candidates; + TrackElement* segment = _event->getSegment(); + bool canMoveUp = (segment->isLocal()) ? segment->canPivotUp(0.5) : segment->canMoveUp(1.0,Flags::CheckLowDensity); // MARK 1 + unsigned int relaxFlags = Manipulator::NoDoglegReuse + | ((_data and (_data->getStateCount() < 2)) ? Manipulator::AllowExpand + : Manipulator::NoExpand); + + cdebug_log(159,0) << "SegmentFsm::conflictSolveByPlaceds()" << endl; + cdebug_log(159,0) << "| Candidates Tracks: " << endl; + + segment->base()->getConstraints( constraints ); + Interval overlap = segment->getCanonicalInterval(); + RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment->getLayer()); + Track* track = plane->getTrackByPosition(constraints.getVMin(),Constant::Superior); + + if (not track) { + cerr << Bug( "SegmentFsm::conflictSolveByPlaceds():\n" + " For: %s\n" + " In %s, no Track near %s" + , getString(segment).c_str() + , getString(plane).c_str() + , DbU::getValueString(constraints.getVMin()).c_str() + ) << endl; + return false; + } + + for ( ; track and track->getAxis() <= constraints.getVMax() ; track = track->getNextTrack() ) { + candidates.push_back( Cs1Candidate(track,segment->getPPitch()) ); + + size_t begin; + size_t end; + TrackElement* other; + Net* otherNet = NULL; + Interval otherOverlap; + bool otherIsGlobal = false; + + track->getOverlapBounds( overlap, begin, end ); + candidates.back().setBegin( begin ); + candidates.back().setEnd ( end ); + + cdebug_log(159,0) << "* " << track << " [" << begin << ":" << end << "]" << endl; + + for ( ; (begin < end) ; ++begin ) { + other = track->getSegment( begin ); + + if (other->getNet() == segment->getNet()) { + cdebug_log(159,0) << " | " << begin << " Same net: " << " " << other << endl; + continue; + } + if (not other->getCanonicalInterval().intersect(overlap)) { + cdebug_log(159,0) << " | " << begin << " No Conflict: " << " " << other << endl; + if (otherNet == NULL) candidates.back().setBegin( begin+1 ); + continue; + } + cdebug_log(159,0) << " | " << begin << " Conflict: " << " " << other << endl; + + if (otherNet != other->getNet()) { + if (otherNet) { + if (otherIsGlobal) { + candidates.back().addConflict( otherOverlap ); + cdebug_log(159,0) << " | Other overlap G: " << otherOverlap << endl; + } else { + cdebug_log(159,0) << " | Other overlap L: " << otherOverlap << " ignored." << endl; + } + } + otherNet = other->getNet(); + otherOverlap = other->getCanonicalInterval(); + otherIsGlobal = other->isGlobal() or other->isBlockage() or other->isFixed(); + } else { + otherOverlap.merge(other->getCanonicalInterval()); + otherIsGlobal = otherIsGlobal or other->isGlobal() or other->isBlockage() or other->isFixed(); + } + } + if (not otherOverlap.isEmpty()) { + if (otherIsGlobal) { + candidates.back().addConflict( otherOverlap ); + cdebug_log(159,0) << " | Other overlap G: " << otherOverlap << endl; + } else { + cdebug_log(159,0) << " | Other overlap L: " << otherOverlap << " ignored." << endl; + } + } + + candidates.back().consolidate(); + } + + sort( candidates.begin(), candidates.end() ); + + for ( size_t icandidate=0 ; icandidategetSegment( overlap.getCenter() ); + if (not other) { + cbug << Error("conflictSolveByPlaceds(): No segment under overlap center.") << endl; + continue; + } + + if (other->isGlobal()) { + cdebug_log(159,0) << "conflictSolveByPlaceds() - Conflict with global, other move up" << endl; + if ((success = Manipulator(other,*this).moveUp())) break; + } + + cdebug_log(159,0) << "conflictSolveByPlaceds() - Relaxing self" << endl; + + if (Manipulator(segment,*this).relax(overlap0,relaxFlags)) { + success = true; + break; + } else { + if ( not canMoveUp + and (relaxFlags != Manipulator::NoExpand) + and Manipulator(segment,*this).relax(overlap0,Manipulator::NoExpand|Manipulator::NoDoglegReuse) ) { + cdebug_log(159,0) << "Cannot move up but successful narrow breaking." << endl; + success = true; + break; + } + } + } + + if ( not success and segment->isGlobal() and (_costs.size() <= 1) ) { + cdebug_log(159,0) << "Overconstrained perpandiculars, rip them up. On track:" << endl; + cdebug_log(159,0) << " " << track << endl; + Manipulator(segment,*this).ripupPerpandiculars (); + success = true; + } + + return success; + } + + + bool SegmentFsm::solveTerminalVsGlobal () + { + TrackElement* segment = getEvent()->getSegment(); + cdebug_log(159,0) << "SegmentFsm::solveTerminalVsGlobal: " << " " << segment << endl; + + if (not (segment->isTerminal() and segment->isLocal())) return false; + + for ( size_t icost=0 ; icost<_costs.size() ; ++icost ) { + Interval overlap = segment->getCanonicalInterval(); + size_t begin; + size_t end; + getCost(icost).getTrack()->getOverlapBounds( overlap, begin, end ); + + for ( ; begingetSegment(begin); + Interval otherOverlap = other->getCanonicalInterval(); + + if (other->getNet() == segment->getNet()) continue; + if (not other->isGlobal()) continue; + if (not otherOverlap.contains(overlap)) continue; + + cdebug_log(159,0) << "| Global candidate:" << other << endl; + if (Manipulator(other,*this).moveUp(Manipulator::AllowTerminalMoveUp)) { + cdebug_log(159,0) << "| Global candidate selected." << endl; + return true; + } + } + } + + return false; + } + + + bool SegmentFsm::solveFullBlockages () + { + bool success = false; + TrackElement* segment = getEvent()->getSegment(); + + cdebug_log(159,1) << "SegmentFsm::solveFullBlockages: " << " " << segment << endl; + + if ( segment->isLocal() ) { + success = Manipulator(segment,*this).pivotUp(); + if ( not success ) { + cdebug_log(159,0) << "Tightly constrained local segment overlapping a blockage, move up." << endl; + cdebug_log(159,0) << segment << endl; + success = Manipulator(segment,*this).moveUp + (Manipulator::AllowLocalMoveUp|Manipulator::AllowTerminalMoveUp); + } + } else { + Interval overlap = segment->getCanonicalInterval(); + size_t begin; + size_t end; + + getCost(0).getTrack()->getOverlapBounds ( overlap, begin, end ); + for ( ; begingetSegment(begin); + Interval otherOverlap = other->getCanonicalInterval(); + + if ( other->getNet() == segment->getNet() ) continue; + if ( not otherOverlap.intersect(overlap) ) continue; + + cdebug_log(159,0) << "| " << begin << " Blockage conflict: " << " " << other << endl; + if ( (success = Manipulator(segment,*this).relax + (otherOverlap,Manipulator::NoDoglegReuse|Manipulator::NoExpand)) ) { + break; + } + } + } + if ( not success ) { + cparanoid << Error( "Tighly constrained segment overlapping a blockage:\n %s" + , getString(segment).c_str() ) << endl; + cdebug_log(159,0) << "Segment is hard blocked, bypass to Unimplemented." << endl; + } + + cdebug_tabw(159,-1); + return success; + } + + + bool SegmentFsm::desaturate () + { + cdebug_log(159,1) << "SegmentFsm::desaturate()" << endl; + + size_t itrack = 0; + +#if THIS_IS_DISABLED + TrackElement* segment = _event->getSegment(); + for ( ; itrackgetNet(); + Interval toFree (segment->getCanonicalInterval()); + bool success = true; + + for ( size_t i = begin ; success and (i < end) ; i++ ) { + TrackElement* segment2 = track->getSegment(i); + + cdebug_log(159,0) << "* Looking // " << segment2 << endl; + + if ( segment2->getNet() == ownerNet ) continue; + if ( not toFree.intersect(segment2->getCanonicalInterval()) ) continue; + if ( segment2->isFixed() or not segment2->isBipoint() ) { + success = false; + continue; + } + + DataNegociate* data2 = segment2->getDataNegociate(); + if ( not data2 ) { + cdebug_log(159,0) << "No DataNegociate, ignoring." << endl; + success = false; + continue; + } + + cdebug_log(159,0) << "- Forced moveUp " << segment2 << endl; + if ( not (success=Manipulator(segment2,*this).moveUp(Manipulator::AllowTerminalMoveUp)) ) { + continue; + } + } + + if ( success ) { + setState ( SegmentFsm::OtherRipup ); + addAction( segment + , SegmentAction::SelfInsert|SegmentAction::MoveToAxis + , getCost(itrack).getTrack()->getAxis() + ); + break; + } + } + } + +#endif + cdebug_tabw(159,-1); + return (itrack < _costs.size()); + } + + + + bool SegmentFsm::_slackenStrap ( TrackElement*& segment, DataNegociate*& data, unsigned int flags ) + { + cdebug_log(159,0) << "Strap segment Fsm." << endl; + + bool success = false; + unsigned int nextState = data->getState(); + + switch ( data->getState() ) { + case DataNegociate::RipupPerpandiculars: + nextState = DataNegociate::Minimize; + success = Manipulator(segment,*this).ripupPerpandiculars(); + if (success) break; + case DataNegociate::Minimize: + if (data->getStateCount() >= 2) { + nextState = DataNegociate::MaximumSlack; + } + success = Manipulator(segment,*this).minimize(); + if (success) break; + case DataNegociate::Dogleg: + case DataNegociate::Slacken: + case DataNegociate::ConflictSolveByHistory: + case DataNegociate::ConflictSolveByPlaceds: + case DataNegociate::MoveUp: + case DataNegociate::MaximumSlack: + case DataNegociate::Unimplemented: + nextState = DataNegociate::Unimplemented; + break; + } + + if (not success and (nextState != DataNegociate::Unimplemented)) + success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit); + + if (not (flags&NoTransition)) { + data->setState( nextState ); + cdebug_log(159,0) << "Incrementing state (after): " << nextState << " count:" << data->getStateCount() << endl; + } + + return success; + } + + + bool SegmentFsm::_slackenLocal ( TrackElement*& segment, DataNegociate*& data, unsigned int flags ) + { + cdebug_log(159,0) << "Local segment Fsm." << endl; + + bool success = false; + unsigned int nextState = data->getState(); + + switch (data->getState()) { + case DataNegociate::RipupPerpandiculars: + nextState = DataNegociate::Minimize; + success = Manipulator(segment,*this).ripupPerpandiculars(); + if (success) break; + case DataNegociate::Minimize: + if (isFullBlocked() and not segment->isTerminal()) { + cdebug_log(159,0) << "Is Fully blocked." << endl; + nextState = DataNegociate::Unimplemented; + break; + } + nextState = DataNegociate::Dogleg; + success = Manipulator(segment,*this).minimize(); + if (success) break; + case DataNegociate::Dogleg: + nextState = DataNegociate::Slacken; + success = Manipulator(segment,*this).makeDogleg(); + if (success) break; + case DataNegociate::Slacken: + nextState = DataNegociate::ConflictSolveByPlaceds; + success = Manipulator(segment,*this).slacken(); + if (success) break; + case DataNegociate::ConflictSolveByHistory: + case DataNegociate::ConflictSolveByPlaceds: + nextState = DataNegociate::LocalVsGlobal; + success = conflictSolveByHistory(); + break; + case DataNegociate::LocalVsGlobal: + nextState = DataNegociate::MoveUp; + success = solveTerminalVsGlobal(); + if (success) break; + break; + case DataNegociate::MoveUp: + nextState = DataNegociate::MaximumSlack; + success = Manipulator(segment,*this).moveUp(); + if (success) break; + case DataNegociate::MaximumSlack: + if (segment->isStrap()) { + if ( (nextState < DataNegociate::MaximumSlack) or (data->getStateCount() < 2) ) { + nextState = DataNegociate::MaximumSlack; + success = conflictSolveByPlaceds(); + if (success) break; + } + } + case DataNegociate::Unimplemented: + nextState = DataNegociate::Unimplemented; + break; + } + + if (not success and (nextState != DataNegociate::Unimplemented)) { + if (data->getStateCount() < 6) + success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit); + } + + if (not success + and (nextState == DataNegociate::Unimplemented) + and segment->isSlackened() + and isFullBlocked()) { + if (solveFullBlockages()) nextState = DataNegociate::MoveUp; + } + + if (not (flags&NoTransition)) { + data->setState( nextState ); + cdebug_log(159,0) << "Incrementing state (after): " << nextState << " count:" << data->getStateCount() << endl; + } + + return success; + } + + + bool SegmentFsm::_slackenGlobal ( TrackElement*& segment, DataNegociate*& data, unsigned int flags ) + { + bool success = false; + unsigned int nextState = data->getState(); + + switch ( data->getState() ) { + case DataNegociate::RipupPerpandiculars: + case DataNegociate::Minimize: + case DataNegociate::Dogleg: + cdebug_log(159,0) << "Global, SegmentFsm: RipupPerpandiculars." << endl; + nextState = DataNegociate::Slacken; + break; + case DataNegociate::Slacken: + cdebug_log(159,0) << "Global, SegmentFsm: Slacken." << endl; + if ((success = Manipulator(segment,*this).slacken(Flags::HalfSlacken))) { + nextState = DataNegociate::RipupPerpandiculars; + break; + } + case DataNegociate::MoveUp: + cdebug_log(159,0) << "Global, SegmentFsm: MoveUp." << endl; + if ((success = Manipulator(segment,*this).moveUp(Manipulator::AllowShortPivotUp))) { + break; + } + nextState = DataNegociate::ConflictSolveByHistory; + break; + case DataNegociate::ConflictSolveByHistory: + case DataNegociate::ConflictSolveByPlaceds: + cdebug_log(159,0) << "Global, SegmentFsm: ConflictSolveByHistory or ConflictSolveByPlaceds." << endl; + if ((success = conflictSolveByPlaceds())) { + if (segment->canMoveUp(1.0,Flags::CheckLowDensity)) + nextState = DataNegociate::MoveUp; + else { + if (data->getStateCount() > 3) + nextState = DataNegociate::MaximumSlack; + } + if (segment->getDataNegociate()->getState() < DataNegociate::ConflictSolveByHistory) + nextState = segment->getDataNegociate()->getState(); + break; + } + case DataNegociate::MaximumSlack: + if ((success=Manipulator(segment,*this).forceOverLocals())) { + break; + } + case DataNegociate::Unimplemented: + cdebug_log(159,0) << "Global, SegmentFsm: MaximumSlack or Unimplemented." << endl; + nextState = DataNegociate::Unimplemented; + break; + } + + if (not success and (nextState != DataNegociate::Unimplemented)) { + if (data->getStateCount() < 6) + success = Manipulator(segment,*this).ripupPerpandiculars(Manipulator::ToRipupLimit); + } + + // Special case: all tracks are overlaping a blockage. + if (not success + and (nextState == DataNegociate::Unimplemented) + and segment->isSlackened() ) { + if (solveFullBlockages()) nextState = DataNegociate::MoveUp; + } + + if (not (flags&NoTransition)) { + if (data->getChildSegment()) { + TrackElement* child = segment; + cdebug_log(159,0) << "Incrementing state of childs (after): " << endl; + while ( child ) { + cdebug_log(159,0) << "| " << child << endl; + if (child->base()->isGlobal()) { + child->getDataNegociate()->setState( nextState ); + cdebug_log(159,0) << "| Update:" << nextState << " count:" << child->getDataNegociate()->getStateCount() << endl; + } + TrackElement* parent = child; + child = parent->getDataNegociate()->getChildSegment(); + parent->getDataNegociate()->setChildSegment( NULL ); + } + } else { + data->setState( nextState ); + cdebug_log(159,0) << "Incrementing state (after): " << segment << endl; + cdebug_log(159,0) << "| " << nextState << " count:" << data->getStateCount() << endl; + } + } + + return success; + } + + + bool SegmentFsm::slackenTopology ( unsigned int flags ) + { + bool success = false; + TrackElement* segment = getEvent()->getSegment(); + DataNegociate* data = segment->getDataNegociate (); + unsigned int actionFlags = SegmentAction::SelfInsert|SegmentAction::EventLevel5; + + DebugSession::open( segment->getNet(), 150, 160 ); + cdebug_log(159,1) << "Slacken Topology for " << segment->getNet() + << " " << segment << endl; + + if (not segment or not data) { cdebug_tabw(159,-1); DebugSession::close(); return false; } + + _event->resetInsertState(); + data->resetRipupCount(); + + if (segment->isStrap()) { success = _slackenStrap ( segment, data, flags ); } + else if (segment->isLocal()) { success = _slackenLocal ( segment, data, flags ); } + else { success = _slackenGlobal( segment, data, flags ); } + + if (success) { + actionFlags |= SegmentAction::ResetRipup; + addAction( segment, actionFlags ); + } else { + clearActions(); + if (data->getState() == DataNegociate::Unimplemented) { + cinfo << "[UNSOLVED] " << segment << " unable to slacken topology." << endl; + } + } + + cdebug_tabw(159,-1); + DebugSession::close(); + + return success; + } + + +} // Katana namespace. diff --git a/katana/src/Session.cpp b/katana/src/Session.cpp new file mode 100644 index 00000000..c8f6a6ad --- /dev/null +++ b/katana/src/Session.cpp @@ -0,0 +1,350 @@ +// -*- mode: C++; explicit-buffer-name: "Session.cpp" -*- +// +// 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 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 : "./Session.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Bug.h" +#include "hurricane/Point.h" +#include "hurricane/Error.h" +#include "katana/Session.h" +#include "katana/Track.h" +#include "katana/TrackElement.h" +#include "katana/KatanaEngine.h" + + +namespace { + + using namespace Katana; + + + const char* reopenSession = "Katana::Session::_open(): Session already open for %s (internal error)."; + + +} // Anonymous namespace. + + +namespace Katana { + + using std::cerr; + using std::endl; + using Hurricane::tab; + using Hurricane::Error; + using Hurricane::Bug; + using Hurricane::Point; + + +// ------------------------------------------------------------------- +// Class : "Session". + + Session::Session ( KatanaEngine* katana ) + : Super(katana) + , _insertEvents() + , _removeEvents() + , _sortEvents () + { } + + + void Session::_postCreate () + { Super::_postCreate(); } + + + Session::~Session () + { } + + + void Session::_preDestroy () + { + Super::_preDestroy(); + _isEmpty(); + } + + + Session* Session::_open ( KatanaEngine* katana ) + { + cdebug_log(159,0) << "Katana::Session::_open()" << endl; + + Session* session = Session::get(); + if (session) { + if (session->_getKatanaEngine() != katana) + throw Error( reopenSession, getString(session->getKatanaEngine()).c_str() ); + + return session; + } + + session = new Session ( katana ); + session->_postCreate(); + + return session; + } + + + Session* Session::get ( const char* message ) + { return dynamic_cast( Super::get(message) ); } + + + Configuration* Session::getConfiguration () + { return Session::getKatanaEngine()->getConfiguration(); } + + + TrackElement* Session::lookup ( Segment* segment ) + { return Session::get("Session::lookup(Segment*)")->_getKatanaEngine()->_lookup(segment); } + + + TrackElement* Session::lookup ( AutoSegment* segment ) + { return Session::get("lookup(AutoSegment*)")->_getKatanaEngine()->_lookup ( segment ); } + + + void Session::setInterrupt ( bool state ) + { Session::get("setInterrupt()")->_getKatanaEngine()->setInterrupt(state); } + + + KatanaEngine* Session::_getKatanaEngine () + { return static_cast(_anabatic); } + + + Net* Session::_getBlockageNet () + { return _getKatanaEngine()->getBlockageNet(); }; + + + NegociateWindow* Session::_getNegociateWindow () + { return _getKatanaEngine()->getNegociateWindow(); }; + + + unsigned int Session::_getRipupCost () + { return _getKatanaEngine()->getRipupCost(); }; + + + Anabatic::GCell* Session::_getGCellUnder ( DbU::Unit x, DbU::Unit y ) + { return _getKatanaEngine()->getGCellUnder(Point(x,y)); }; + + + void Session::_doRemovalEvents () + { + set packTracks; + + for ( size_t i=0 ; i<_removeEvents.size() ; ++i ) { + if (not _removeEvents[i]._segment->getTrack()) continue; + + packTracks.insert( _removeEvents[i]._segment->getTrack() ); + _removeEvents[i]._segment->detach(); + } + _removeEvents.clear(); + + for ( set::iterator it=packTracks.begin() ; it != packTracks.end() ; ++it ) + (*it)->doRemoval(); + } + + + size_t Session::_revalidate () + { + cdebug_log(159,1) << "Katana::Session::_revalidate()" << endl; + + _doRemovalEvents(); + + for ( size_t i=0 ; i<_insertEvents.size() ; ++i ) { + if (_insertEvents[i]._segment) { + _insertEvents[i]._track->insert( _insertEvents[i]._segment ); + } + if (_insertEvents[i]._marker) _insertEvents[i]._track->insert( _insertEvents[i]._marker ); + } + _insertEvents.clear(); + + // Check if to be destroyeds are not associateds with TrackSegments. + const set& destroyeds = getDestroyeds(); + set::const_iterator idestroyed = destroyeds.begin(); + for ( ; idestroyed != destroyeds.end() ; ++idestroyed ) { + if (lookup(*idestroyed)) { + cdebug_tabw(155,-1); + throw Error( "Destroyed AutoSegment is associated with a TrackSegment\n" + " (%s)" + , getString(*idestroyed).c_str()); + } + } + + size_t count = Super::_revalidate(); + + Interval span; + const vector& revalidateds = getRevalidateds(); + //const set& netsModificateds = getNetsModificateds(); + + for ( size_t i=0 ; iisCanonical()) continue; + + //Net* currentNet = NULL; + TrackElement* trackSegment = lookup( revalidateds[i] ); + + if (trackSegment and trackSegment->isInvalidated()) { + trackSegment->revalidate(); + } + } + _doglegReset(); + +# if defined(CHECK_DATABASE) + unsigned int overlaps = 0; +# endif + for ( Track* track : _sortEvents ) { + track->doReorder(); +# if defined(CHECK_DATABASE) + track->check( overlaps, "Session::_revalidate() - track sorting." ); +# endif + } + +# if defined(CHECK_DATABASE) + for ( set::iterator it=packTracks.begin() ; it != packTracks.end() ; ++it ) + (*it)->check( overlaps, "Session::_revalidate() - on packed track." ); + + for ( size_t i=0 ; icheck(); + } + + //_getKatanaEngine()->_showOverlap (); +# endif + + _sortEvents.clear(); + +#if THIS_IS_DISABLED + if (not faileds.empty()) { + set::iterator ifailed = faileds.begin(); + Anabatic::GCellVector gcells; + for ( ; ifailed != faileds.end() ; ++ifailed ) { + (*ifailed)->getGCells ( gcells ); + (*ifailed)->makeDogLeg( gcells[0] ); + } + + count += _revalidate(); + } +#endif + + // Looking for reduced/raised segments. + for ( size_t i=0 ; icanReduce()) { + revalidateds[i]->reduce(); + TrackElement* trackSegment = lookup( revalidateds[i] ); + if (trackSegment and trackSegment->getTrack()) _addRemoveEvent( trackSegment ); + cdebug_log(159,0) << "Session: reduce:" << revalidateds[i] << endl; + } + if (revalidateds[i]->mustRaise()) { + revalidateds[i]->raise(); + lookup( revalidateds[i] )->reschedule( 0 ); + cdebug_log(159,0) << "Session: raise:" << revalidateds[i] << endl; + } + } + + _doRemovalEvents(); + + cdebug_tabw(159,-1); + return count; + } + + + bool Session::_isEmpty () const + { + if ( not _insertEvents.empty() or not _removeEvents.empty() or not _sortEvents.empty() ) { + cerr << Bug( "Session::_isEmpty() failed :\n" + " %u inserts, %u removes and %u sort events remains." + , _insertEvents.size() + , _removeEvents.size() + , _sortEvents .size() ) << endl; + if (not _sortEvents.empty()) { + cerr << " Remaining sort events on Tracks:" << endl; + for ( Track* track : _sortEvents ) { + cerr << " | " << track << endl; + } + } + return false; + } + + return true; + } + + + void Session::_addInsertEvent ( TrackMarker* marker, Track* track ) + { + _insertEvents.push_back( Event(marker,track) ); + _addSortEvent( track, true ); + } + + + void Session::_addInsertEvent ( TrackElement* segment, Track* track ) + { + cdebug_log(159,0) << "addInsertEvent() " << segment + << "\n @" << track << endl; + + if ( segment->getTrack() != NULL ) { + cerr << Bug("Session::addInsertEvent(): Segment already in Track." + "\n %s." + "\n to %s." + ,getString(segment).c_str() + ,getString(track).c_str() + ) << endl; + return; + } + + _insertEvents.push_back( Event(segment,track) ); + _addSortEvent( track, true ); + } + + + void Session::_addRemoveEvent ( TrackElement* segment ) + { + if (not segment->getTrack()) { + cerr << Bug( " Katana::Session::addRemoveEvent() : %s is not in any Track." + , getString(segment).c_str() ) << endl; + return; + } + + cdebug_log(159,0) << "Ripup: @" << DbU::getValueString(segment->getAxis()) << " " << segment << endl; + _removeEvents.push_back( Event(segment,segment->getTrack()) ); + _addSortEvent( segment->getTrack(), true ); + } + + + void Session::_addMoveEvent ( TrackElement* segment, Track* track ) + { + if (not segment->getTrack()) { + cerr << Bug( " Katana::Session::addMoveEvent() : %s is not yet in a track." + , getString(segment).c_str() ) << endl; + } else { + _addRemoveEvent( segment ); + } + + _addInsertEvent( segment, track ); + } + + + void Session::_addSortEvent ( Track* track, bool forced ) + { + if (not track ) { + cerr << Bug( " Katana::Session::addSortEvent() : no Track to sort." ) << endl; + return; + } + if (forced) track->invalidate(); + _sortEvents.insert( track ); + } + + + string Session::_getTypeName () const + { return "Katana::Session"; } + + + Record* Session::_getRecord () const + { + Record* record = Session::_getRecord (); + record->add( getSlot( "_sortEvents" , &_sortEvents ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/Track.cpp b/katana/src/Track.cpp new file mode 100644 index 00000000..02049845 --- /dev/null +++ b/katana/src/Track.cpp @@ -0,0 +1,726 @@ +// -*- 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 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 : "./Track.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include +#include "hurricane/Warning.h" +#include "hurricane/Bug.h" +#include "hurricane/Layer.h" +#include "hurricane/Net.h" +#include "katana/RoutingPlane.h" +#include "katana/Track.h" +#include "katana/TrackMarker.h" +#include "katana/DataNegociate.h" + + +namespace { + + using namespace std; + using namespace CRL; + using namespace Katana; + + + struct isDetachedSegment { + bool operator() ( const TrackElement* s ) { return not s->getTrack(); }; + }; + + + // DbU::Unit getPositionByIterator ( const vector& v, size_t i ) + // { return (*(v.begin()+i))->getSourceU(); } + + +} // Anonymous namespace. + + +namespace Katana { + + using std::lower_bound; + using std::remove_if; + using std::sort; + using Hurricane::dbo_ptr; + using Hurricane::tab; + using Hurricane::Warning; + using Hurricane::Bug; + using Hurricane::Layer; + using Hurricane::Net; + + +// ------------------------------------------------------------------- +// Class : "Track". + + + const size_t Track::npos = (size_t)-1; + + + Track::Track ( RoutingPlane* routingPlane, unsigned int index ) + : _routingPlane (routingPlane) + , _index (index) + , _axis (routingPlane->getTrackPosition(index)) + , _min (routingPlane->getTrackMin()) + , _max (routingPlane->getTrackMax()) + , _segments () + , _markers () + , _localAssigned(false) + , _segmentsValid(false) + , _markersValid (false) + { } + + + void Track::_postCreate () + { } + + + Track::~Track () + { cdebug_log(155,0) << "Track::~Track() - " << (void*)this << endl; } + + + void Track::_preDestroy () + { + cdebug_log(155,1) << "Track::_preDestroy() - " << (void*)this << " " << this << endl; + + for ( size_t i=0 ; i<_segments.size() ; i++ ) + if (_segments[i]) { _segments[i]->detach(); _segments[i]->destroy(); } + + for ( size_t i=0 ; i<_markers.size() ; i++ ) + if (_markers[i]) _markers[i]->destroy(); + + cdebug_tabw(155,-1); + } + + + void Track::destroy () + { + cdebug_log(155,0) << "Track::destroy() - " << (void*)this << " " << this << endl; + + Track::_preDestroy(); + delete this; + } + + + KatanaEngine* Track::getKatanaEngine () const + { return _routingPlane->getKatanaEngine(); } + + + unsigned int Track::getDepth () const + { return _routingPlane->getDepth(); } + + + const Layer* Track::getLayer () const + { return _routingPlane->getLayer(); } + + + const Layer* Track::getBlockageLayer () const + { return _routingPlane->getBlockageLayer(); } + + + Track* Track::getNextTrack () const + { return getRoutingPlane()->getTrackByIndex( getIndex()+1 ); } + + + Track* Track::getPreviousTrack () const + { + if (not getIndex()) return NULL; + return getRoutingPlane()->getTrackByIndex( getIndex()-1 ); + } + + + TrackElement* Track::getSegment ( size_t index ) const + { + if ( (index == npos) or (index >= getSize()) ) return NULL; + return _segments[index]; + } + + + TrackElement* Track::getSegment ( DbU::Unit position ) const + { + unsigned int state; + size_t begin; + + getBeginIndex( position, begin, state ); + if (state & (BeginIsTrackMin|EndIsTrackMax)) return NULL; + return getSegment(begin); + } + + + TrackElement* Track::getNext ( size_t& index, Net* net ) const + { + for ( index++ ; index < _segments.size() ; index++ ) { + if (_segments[index]->getNet() == net) continue; + return _segments[index]; + } + index = npos; + + return NULL; + } + + + TrackElement* Track::getPrevious ( size_t& index, Net* net ) const + { + for ( index-- ; index != npos ; index-- ) { + if (cdebug.enabled()) { + cerr << tab << index << ":"; cerr.flush(); + cerr << _segments[index] << endl; + } + if (_segments[index]->getNet() == net) continue; + return _segments[index]; + } + index = npos; + + return NULL; + } + + + TrackElement* Track::getNextFixed ( size_t& index ) const + { + TrackElement* nextFixed = getNext ( index, NULL ); + for ( ; nextFixed ; nextFixed = getNext(index,NULL) ) { + if ( nextFixed->base()->isFixed() ) return nextFixed; + } + + return nextFixed; + } + + + void Track::getBeginIndex ( DbU::Unit position, size_t& begin, unsigned int& state ) const + { + if (_segments.empty()) { + state = EmptyTrack; + begin = 0; + return; + } + + if (position < _min) { + cerr << Warning( " Position %s inferior to the lower bound of %s. Returning npos." + , DbU::getValueString(position).c_str() + , getString(this).c_str() ) << endl; + state = BeforeFirstElement; + begin = 0; + return; + } + + if (position > _max) { + cerr << Warning( " Position %s superior to the upper bound of %s. Returning npos." + , DbU::getValueString(position).c_str() + , getString(this).c_str() ) << endl; + state = AfterLastElement; + begin = _segments.size()-1; + return; + } + + vector::const_iterator lowerBound + = lower_bound( _segments.begin(), _segments.end(), position, SourceCompare() ); + begin = lowerBound - _segments.begin(); + + // This is suspicious. + // I guess this has been written for the case of overlapping segments from the same + // net, we find the first one of the overlapped sets. But what if they are not overlapping + // but still from the same net? + size_t sameNetDelta = 0; + if (begin < _segments.size()) { + for ( ; (begin > 0) and (_segments[begin-1]->getNet() == _segments[begin]->getNet()) + ; --begin, ++sameNetDelta ); + } + + state = 0; + if ( (begin == 0) and (position < _segments[0]->getSourceU()) ) { + state = BeforeFirstElement; + } else { + if (begin and not sameNetDelta) begin -= 1; + + size_t usedBegin = begin; + Interval usedInterval = getOccupiedInterval( usedBegin ); + + if (position < usedInterval.getVMax()) + state = InsideElement; + else + if (begin+1 == _segments.size()) + state = AfterLastElement; + else + state = OutsideElement; + } + } + + + void Track::getOverlapBounds ( Interval interval, size_t& begin, size_t& end ) const + { + unsigned int iState; + + if ( _segments.empty() + or (interval.getVMax() <= _min) + or (interval.getVMin() >= _max)) { + begin = end = npos; + return; + } + + getBeginIndex ( interval.getVMin(), begin, iState ); + getOccupiedInterval( begin ); + + getBeginIndex( interval.getVMax(), end, iState ); + for ( ; end < _segments.size() ; ++end ) { + if (_segments[end]->getSourceU() >= interval.getVMax()) break; + } + + cdebug_log(159,0) << "Track::getOverlapBounds(): begin:" << begin << " end:" << end << endl; + } + + + TrackCost Track::getOverlapCost ( Interval interval + , Net* net + , size_t begin + , size_t end + , unsigned int flags ) const + { + TrackCost cost ( const_cast(this), interval, begin, end, net, flags ); + + cdebug_log(159,1) << "getOverlapCost() @" << DbU::getValueString(_axis) + << " [" << DbU::getValueString(interval.getVMin()) + << ":" << DbU::getValueString(interval.getVMax()) + << "] <-> [" << begin << ":" << end << "]" + << endl; + + vector::const_iterator lowerBound + = lower_bound( _markers.begin(), _markers.end(), interval.getVMin(), TrackMarker::Compare() ); + size_t mbegin = lowerBound - _markers.begin(); + + for ( ; (mbegin < _markers.size()) + and (_markers[mbegin]->getSourceU() <= interval.getVMax()) ; mbegin++ ) { + cdebug_log(159,0) << "| @" << DbU::getValueString(_axis) << _markers[mbegin] << endl; + if ( _markers[mbegin]->getNet() != net ) { + cdebug_log(159,0) << "* Mark: @" << DbU::getValueString(_axis) << " " << _markers[mbegin] << endl; + cost.incTerminals( _markers[mbegin]->getWeight(this) ); + } + } + + if (begin == npos) { + cdebug_log(159,0) << " begin == npos (after last TrackElement)." << endl; + cdebug_tabw(159,-1); + return cost; + } + + for ( ; begin < end ; begin++ ) { + Interval overlap = interval.getIntersection( _segments[begin]->getCanonicalInterval() ); + if ( _segments[begin]->getNet() == net ) { + cost.incDeltaShared ( overlap.getSize() ); + } + cdebug_log(159,0) << "| overlap: " << _segments[begin] << endl; + _segments[begin]->incOverlapCost( net, cost ); + if (cost.isInfinite()) break; + } + + cdebug_tabw(159,-1); + + return cost; + } + + + TrackCost Track::getOverlapCost ( Interval interval, Net* net, unsigned int flags ) const + { + size_t begin; + size_t end; + + getOverlapBounds( interval, begin, end ); + + return getOverlapCost( interval, net, begin, end, flags ); + } + + + TrackCost Track::getOverlapCost ( TrackElement* segment, unsigned int flags ) const + { return getOverlapCost ( segment->getCanonicalInterval(), segment->getNet(), flags ); } + + + void Track::getTerminalWeight ( Interval interval, Net* net, size_t& count, unsigned int& weight ) const + { + cdebug_log(159,1) << "getTerminalWeight() @" << DbU::getValueString(_axis) + << " [" << interval.getVMin() << " " << interval.getVMax() << "]" << endl; + + //count = 0; + //weight = 0; + + vector::const_iterator lowerBound + = lower_bound ( _markers.begin(), _markers.end(), interval.getVMin(), TrackMarker::Compare() ); + size_t mbegin = lowerBound - _markers.begin(); + + for ( ; (mbegin < _markers.size()) + && (_markers[mbegin]->getSourceU() <= interval.getVMax()) ; mbegin++ ) { + cdebug_log(159,0) << "| @" << DbU::getValueString(_axis) << _markers[mbegin] << endl; + if ( _markers[mbegin]->getNet() == net ) { + cdebug_log(159,0) << "* Mark: @" << DbU::getValueString(_axis) << " " << _markers[mbegin] << endl; + weight += _markers[mbegin]->getWeight(this); + ++count; + } + } + cdebug_tabw(159,-1); + } + + + size_t Track::find ( const TrackElement* segment ) const + { + if (_segments.empty()) return npos; + + vector::const_iterator lowerBound + = lower_bound( _segments.begin() + , _segments.end() + , segment + , SegmentCompare() + ); + + if (lowerBound != _segments.end()) { + while ( segment->getSourceU() == (*lowerBound)->getSourceU() ) { + if (*lowerBound == segment) return (size_t)(lowerBound-_segments.begin()); + lowerBound++; + } + } + + return npos; + } + + + Interval Track::getFreeInterval ( DbU::Unit position, Net* net ) const + { + unsigned int state; + size_t begin; + size_t end; + + if (_segments.empty()) return Interval(_min,_max); + + getBeginIndex( position, begin, state ); + if ( (state == InsideElement) and (_segments[begin]->getNet() != net) ) + return Interval(); + + end = begin; + return expandFreeInterval( begin, end, state, net ); + } + + + Interval Track::expandFreeInterval ( size_t& begin, size_t& end, unsigned int state, Net* net ) const + { + DbU::Unit minFree = _min; + + if (not (state & BeginIsTrackMin) ) { + if (_segments[begin]->getNet() == net) + getPrevious( begin, net ); + + if (begin != npos) { + minFree = getOccupiedInterval(begin).getVMax(); + } + } + + if (not (state & EndIsTrackMax) ) { + if (_segments[end]->getNet() == net) { + getNext( end, net ); + + if (end == npos) { + end = _segments.size() - 1; + setMaximalFlags( state, EndIsTrackMax ); + } else { + setMaximalFlags( state, EndIsSegmentMin ); + } + } + } + + return Interval( minFree, getMaximalPosition(end,state) ); + } + + + void Track::invalidate () + { _segmentsValid = false; } + + + void Track::insert ( TrackMarker* marker ) + { + _markers.push_back ( marker ); + _markersValid = false; + } + + + void Track::insert ( TrackElement* segment ) + { + // cdebug_log(9000,0) << "Deter| Track::insert() " << getLayer()->getName() + // << " @" << DbU::getValueString(getAxis()) << " " << segment << endl; + cdebug_log(159,0) << "Track::insert() " << getLayer()->getName() + << " @" << DbU::getValueString(getAxis()) << " " << segment << endl; + + if ( (getLayer()->getMask() != segment->getLayer()->getMask()) + and (getBlockageLayer()->getMask() != segment->getLayer()->getMask()) ) { + cerr << Bug("Track::insert(), segment %s has not the right layer." + ,getString(segment).c_str()) << endl; + } + + segment->setAxis ( getAxis() ); + _segments.push_back ( segment ); + _segmentsValid = false; + + segment->setTrack ( this ); + } + + + void Track::setSegment ( TrackElement* segment, size_t index ) + { + if ( index >= _segments.size() ) return; + _segments[index] = segment; + } + + + bool Track::check ( unsigned int& overlaps, const char* message ) const + { + bool coherency = true; + bool holes = false; + + if (message) cerr << " o Checking Track - " << message << endl; + cdebug_log(155,0) << (void*)this << ":" << this << endl; + + for ( size_t i=0 ; i<_segments.size() ; i++ ) { + if (_segments[i]) { + if (i) { + if (_segments[i-1] == _segments[i]) { + cerr << "[CHECK] incoherency at " << i << " " + << _segments[i] << " is duplicated. " << endl; + coherency = false; + } + } + if (not _segments[i]->getTrack()) { + cerr << "[CHECK] incoherency at " << i << " " + << _segments[i] << " is detached." << endl; + coherency = false; + } else { + if (_segments[i]->getTrack() != this) { + cerr << "[CHECK] incoherency at " << i << " " + << _segments[i] << " is in track " + << _segments[i]->getTrack() << endl; + coherency = false; + } + if (_segments[i]->getIndex() != i) { + cerr << "[CHECK] incoherency at " << i << " " + << _segments[i] << " has bad index " + << _segments[i]->getIndex() << endl; + coherency = false; + } + } + if (_segments[i]->getAxis() != getAxis()) { + cerr << "[CHECK] incoherency at " << i << " " + << _segments[i] << " is not on Track axis " + << DbU::getValueString(getAxis()) << "." << endl; + coherency = false; + } + + coherency = _segments[i]->_check() and coherency; + } else { + cerr << "[CHECK] Hole at position " << i << "." << endl; + holes = true; + coherency = false; + } + } + + if (not holes) + coherency = (checkOverlap(overlaps) == 0) and coherency; + + return coherency; + } + + + DbU::Unit Track::getSourcePosition ( size_t i ) const + { + if ( i == npos) return 0; + + return _segments[i]->getSourceU(); + } + + + DbU::Unit Track::getSourcePosition ( vector::iterator isegment ) const + { + if ( isegment == _segments.end() ) return 0; + + return (*isegment)->getSourceU(); + } + + + DbU::Unit Track::getMinimalPosition ( size_t index, unsigned int state ) const + { + Interval canonical; + + switch ( state & BeginMask ) { + case BeginIsTrackMin: return _min; + case BeginIsSegmentMin: return _segments[index]->getSourceU (); + case BeginIsSegmentMax: return _segments[index]->getTargetU (); + } + + cerr << Bug( " Track::getMinimalPosition(size_t,unsigned int) :" + " invalid state value %ud.", state ) << endl; + + return _min; + } + + + DbU::Unit Track::getMaximalPosition ( size_t index, unsigned int state ) const + { + Interval canonical; + + switch ( state & EndMask ) { + case EndIsTrackMax: return _max; + case EndIsSegmentMin: return _segments[index ]->getSourceU (); + case EndIsNextSegmentMin: if (index+1 >= getSize()) return _max; + return _segments[index+1]->getSourceU (); + case EndIsSegmentMax: return _segments[index ]->getTargetU (); + } + + cerr << Bug( " Track::getMaximalPosition(size_t,unsigned int) :" + " invalid state value %ud.", state ) << endl; + + return _min; + } + + + Interval Track::getOccupiedInterval ( size_t& begin ) const + { + if (begin == npos) return Interval(); + + size_t seed = begin; + Net* owner = _segments[seed]->getNet(); + + Interval segmentInterval; + Interval mergedInterval; + _segments[seed]->getCanonical( mergedInterval ); + + size_t i = seed; + while ( --i != npos ) { + if (_segments[i]->getNet() != owner) break; + + _segments[i]->getCanonical ( segmentInterval ); + if (segmentInterval.getVMax() >= mergedInterval.getVMin()) { + mergedInterval.merge( segmentInterval ); + begin = i; + } + } + + i = seed; + while ( ++i < _segments.size() ) { + if (_segments[i]->getNet() != owner) break; + + _segments[i]->getCanonical( segmentInterval ); + if (segmentInterval.getVMin() > mergedInterval.getVMax()) break; + + mergedInterval.merge( segmentInterval ); + } + + return mergedInterval; + } + + + size_t Track::doRemoval () + { + cdebug_log(159,1) << "Track::doRemoval() - " << this << endl; + + size_t size = _segments.size(); + + vector::iterator beginRemove + = remove_if( _segments.begin(), _segments.end(), isDetachedSegment() ); + + _segments.erase( beginRemove, _segments.end() ); + + cdebug_log(159,0) << "After doRemoval " << this << endl; + cdebug_tabw(159,-1); + + return size - _segments.size(); + } + + + void Track::doReorder () + { + cdebug_log(159,0) << "Track::doReorder() " << this << endl; + + if (not _segmentsValid ) { + std::sort ( _segments.begin(), _segments.end(), SegmentCompare() ); + for ( size_t i=0 ; i < _segments.size() ; i++ ) { + _segments[i]->setIndex ( i ); + } + _segmentsValid = true; + } + + if (not _markersValid ) { + std::sort ( _markers.begin(), _markers.end(), TrackMarker::Compare() ); + _markersValid = true; + } + } + + + unsigned int Track::checkOverlap ( unsigned int& overlaps ) const + { + if ( !_segments.size() ) return 0; + + size_t j = 0; + for ( size_t i=0 ; i<_segments.size()-1 ; i++ ) { + if (not _segments[i]->isBlockage() and (_segments[i]->getLayer() != getLayer()) ) { + cerr << Error( " Track vs. Segment Layer discrepency:\n %s\n %s " + , getString(this).c_str() + , getString(_segments[i]).c_str() ) << endl; + } + + if ( _segments[i]->getNet() == _segments[i+1]->getNet() ) { + if ( _segments[i]->getSourceU() == _segments[i+1]->getSourceU() ) { + if ( _segments[i]->getTargetU() < _segments[i+1]->getTargetU() ) { + cerr << Error(" Invalid sorting length order in %s:\n %s\n %s " + ,getString(this).c_str() + ,getString(_segments[i ]).c_str() + ,getString(_segments[i+1]).c_str()) << endl; + } + } + for ( j=i+1 ; (j<_segments.size()) && (_segments[i]->getNet() == _segments[j]->getNet()) ; j++ ); + } else { + j = i+1; + } + + if ( (j<_segments.size()) + && (_segments[i]->getTargetU() > _segments[j]->getSourceU()) ) { + cerr << Error("Overlap in %s between:\n %s\n %s" + ,getString(this).c_str() + ,getString(_segments[i]).c_str() + ,getString(_segments[j]).c_str()) << endl; + overlaps++; + } + } + + return overlaps; + } + + + string Track::_getString () const + { + return "<" + _getTypeName() + " " + + getString(getLayer()) + " @" + + DbU::getValueString(_axis) + " [" + + DbU::getValueString(_min) + ":" + + DbU::getValueString(_max) + "] [" + + getString(_segments.size()) + "/" + + getString(_segments.capacity()) + + "]>"; + } + + + Record* Track::_getRecord () const + { + Record* record = new Record ( _getString() ); + record->add ( getSlot ( "_routingPlane", _routingPlane ) ); + record->add ( getSlot ( "_index" , &_index ) ); + record->add ( DbU::getValueSlot ( "_axis" , &_axis ) ); + record->add ( getSlot ( "_segments" , &_segments ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackCost.cpp b/katana/src/TrackCost.cpp new file mode 100644 index 00000000..223b28be --- /dev/null +++ b/katana/src/TrackCost.cpp @@ -0,0 +1,261 @@ +// -*- 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 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 : "./TrackCost.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include "katana/Track.h" +#include "katana/TrackCost.h" +#include "katana/Session.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + + +// ------------------------------------------------------------------- +// Class : "TrackCost". + + TrackCost::TrackCost ( Track* track, Net* net ) + : _flags (ZeroCost) + , _track (track) + , _begin (Track::npos) + , _end (Track::npos) + , _interval () + , _forGlobal (false) + , _blockage (false) + , _fixed (false) + , _infinite (false) + , _hardOverlap (false) + , _overlap (false) + , _leftOverlap (false) + , _rightOverlap (false) + , _overlapGlobal (false) + , _globalEnclosed (false) + , _terminals (0) + , _delta (0) + , _deltaShared (0) + , _deltaPerpand (0) + , _axisWeight (0) + , _distanceToFixed(2*Session::getSliceHeight()) + , _longuestOverlap(0) + , _dataState (0) + , _ripupCount (0) + { } + + + TrackCost::TrackCost ( Track* track + , const Interval& interval + , size_t begin + , size_t end + , Net* net + , unsigned int flags + ) + : _flags (flags) + , _track (track) + , _begin (begin) + , _end (end) + , _interval (interval) + , _forGlobal (false) + , _blockage (false) + , _fixed (false) + , _infinite (false) + , _hardOverlap (false) + , _overlap (false) + , _leftOverlap (false) + , _rightOverlap (false) + , _overlapGlobal (false) + , _globalEnclosed (false) + , _terminals (0) + , _delta (-interval.getSize()) + , _deltaShared (0) + , _deltaPerpand (0) + , _axisWeight (0) + , _distanceToFixed(2*Session::getSliceHeight()) + , _longuestOverlap(0) + , _dataState (0) + , _ripupCount (0) + { + // This is the GCell side (it is *one* cell height from the gauge). + DbU::Unit cellHeight = Session::getSliceHeight(); + + TrackElement* neighbor; + if ( _begin != Track::npos ) { + neighbor = _track->getSegment(_begin); + if ( neighbor and (neighbor->getNet() != net) ) { + DbU::Unit distance = interval.getVMin() - neighbor->getTargetU(); + if ( distance < cellHeight ) + _distanceToFixed = distance; + } + // if ( neighbor and neighbor->isFixed() ) { + // if ( _distanceToFixed == DbU::Max ) _distanceToFixed = 0; + // _distanceToFixed += interval.getVMin() - neighbor->getTargetU(); + // } + } + if ( _end != Track::npos ) { + neighbor = _track->getSegment(_end); + if ( neighbor and (neighbor->getNet() != net) ) { + DbU::Unit distance = neighbor->getSourceU() - interval.getVMax(); + if ( _distanceToFixed == 2*cellHeight ) _distanceToFixed = 0; + if ( distance < cellHeight ) + _distanceToFixed += distance; + } + // if ( neighbor and neighbor->isFixed() ) { + // if ( _distanceToFixed == DbU::Max ) _distanceToFixed = 0; + // _distanceToFixed += neighbor->getSourceU() - interval.getVMax(); + // } + } + } + + TrackCost::~TrackCost () + { } + + + bool TrackCost::isFree () const + { + return /*(not _terminals) and*/ (not _overlap) and (not _infinite); + } + + + bool TrackCost::Compare::operator() ( const TrackCost& lhs, const TrackCost& rhs ) + { + if ( lhs._infinite xor rhs._infinite ) return rhs._infinite; + + if ( (_flags & TrackCost::DiscardGlobals) + and (lhs._overlapGlobal xor rhs._overlapGlobal) ) + return rhs._overlapGlobal; + + if ( lhs._hardOverlap xor rhs._hardOverlap ) return rhs._hardOverlap; + + if ( lhs._ripupCount + (int)Session::getRipupCost() < rhs._ripupCount ) return true; + if ( lhs._ripupCount > (int)Session::getRipupCost() + rhs._ripupCount ) return false; + + //int lhsRipupCost = (lhs._dataState<<2) + lhs._ripupCount; + //int rhsRipupCost = (rhs._dataState<<2) + rhs._ripupCount; + //if ( lhsRipupCost + (int)Session::getRipupCost() < rhsRipupCost ) return true; + //if ( lhsRipupCost > (int)Session::getRipupCost() + rhsRipupCost ) return false; + + //if ( _flags & TrackCost::DiscardGlobals ) { + // if ( lhs._longuestOverlap < rhs._longuestOverlap ) return true; + // if ( lhs._longuestOverlap > rhs._longuestOverlap ) return false; + //} + + if ( lhs._overlap xor rhs._overlap ) return rhs._overlap; + + if ( lhs._terminals < rhs._terminals ) return true; + if ( lhs._terminals > rhs._terminals ) return false; + + if ( not (_flags & TrackCost::IgnoreSharedLength) + or (lhs._delta > 0) or (rhs._delta > 0) ) { + if ( lhs._delta < rhs._delta ) return true; + if ( lhs._delta > rhs._delta ) return false; + } + +#if 0 + DbU::Unit lhsMixedWeight = 0.5*lhs._deltaPerpand; + DbU::Unit rhsMixedWeight = 0.5*rhs._deltaPerpand; + + if ( not (_flags & TrackCost::IgnoreAxisWeight) ) { + lhsMixedWeight += lhsMixedWeight; + rhsMixedWeight += rhsMixedWeight; + } + + if (lhsMixedWeight < rhsMixedWeight) return true; + if (lhsMixedWeight > rhsMixedWeight) return false; +#endif + + if ( not (_flags & TrackCost::IgnoreAxisWeight) ) { + if ( lhs._axisWeight < rhs._axisWeight ) return true; + if ( lhs._axisWeight > rhs._axisWeight ) return false; + } + + if ( lhs._deltaPerpand < rhs._deltaPerpand ) return true; + if ( lhs._deltaPerpand > rhs._deltaPerpand ) return false; + + if ( lhs._distanceToFixed > rhs._distanceToFixed ) return true; + if ( lhs._distanceToFixed < rhs._distanceToFixed ) return false; + + return lhs.getTrack()->getAxis() < rhs.getTrack()->getAxis(); + } + + + bool TrackCost::CompareByDelta::operator() ( const TrackCost& lhs, const TrackCost& rhs ) + { + return lhs.getDelta() < rhs.getDelta(); + } + + + void TrackCost::consolidate () + { + if ( not _infinite and not _hardOverlap ) { + //_deltaPerpand += - (_deltaShared << 1); + _delta += - _deltaShared; + } + } + + + string TrackCost::_getString () const + { + string s = "<" + _getTypeName(); + + s += " " + getString(_track); + s += " " + getString(_dataState); + s += "+" + getString(_ripupCount); + s += ":" + getString((_dataState<<2)+_ripupCount); + s += " " + string ( (_infinite )?"I":"-" ); + s += string ( (_blockage )?"b":"-" ); + s += string ( (_fixed )?"f":"-" ); + s += string ( (_hardOverlap )?"h":"-" ); + s += string ( (_overlap )?"o":"-" ); + s += string ( (_overlapGlobal )?"g":"-" ); + s += string ( (_globalEnclosed)?"e":"-" ); + s += " " + getString(_terminals); + s += "/" + DbU::getValueString(_delta); + s += "/" + DbU::getValueString(_axisWeight); + s += "/" + DbU::getValueString(_deltaPerpand); + s += "/" + DbU::getValueString(_distanceToFixed); + s += "/" + DbU::getValueString(_longuestOverlap); + s += " " + getString(_dataState); + s += ">"; + + return s; + } + + + Record* TrackCost::_getRecord () const + { + Record* record = new Record ( _getString() ); + record->add( getSlot ( "_track" , _track ) ); + record->add( getSlot ( "_begin" , &_begin ) ); + record->add( getSlot ( "_end" , &_end ) ); + record->add( getSlot ( "_interval" , &_interval ) ); + record->add( getSlot ( "_infinite" , _infinite ) ); + record->add( getSlot ( "_overlap" , _overlap ) ); + record->add( getSlot ( "_terminals" , _terminals ) ); + record->add( DbU::getValueSlot( "_delta" , &_delta ) ); + record->add( DbU::getValueSlot( "_deltaShared" , &_deltaShared ) ); + record->add( DbU::getValueSlot( "_deltaPerpand" , &_deltaPerpand ) ); + record->add( DbU::getValueSlot( "_axisWeight" , &_axisWeight ) ); + record->add( DbU::getValueSlot( "_distanceToFixed", &_distanceToFixed ) ); + record->add( DbU::getValueSlot( "_longuestOverlap", &_longuestOverlap ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackElement.cpp b/katana/src/TrackElement.cpp new file mode 100644 index 00000000..0eec425b --- /dev/null +++ b/katana/src/TrackElement.cpp @@ -0,0 +1,283 @@ +// -*- 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 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 : "./TrackElement.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" +#include "hurricane/Net.h" +#include "hurricane/Name.h" +#include "anabatic/AutoContact.h" +#include "anabatic/GCell.h" +#include "crlcore/RoutingGauge.h" +#include "katana/DataNegociate.h" +#include "katana/TrackElement.h" +#include "katana/TrackCost.h" +#include "katana/Track.h" +#include "katana/Session.h" +#include "katana/RoutingEvent.h" +#include "katana/NegociateWindow.h" + + +namespace { + + using namespace std; + using namespace Hurricane; + using namespace CRL; + using namespace Katana; + + + void dummyOverlapCost ( const TrackElement* segment, TrackCost& cost ) + { + cerr << Warning("No overlapCost callback has been set (%s)." + ,getString(segment).c_str()) << endl; + } + + +} // Anonymous namespace. + + +namespace Katana { + + using Hurricane::tab; + using Hurricane::Bug; + using Hurricane::Net; + using Hurricane::Name; + using Anabatic::GCell; + + +// ------------------------------------------------------------------- +// Comparison Classes. +// +// Return: lhs < rhs. + + + bool Compare::operator() ( TrackElement* lhs, TrackElement* rhs ) + { return lhs->getFreedomDegree() > rhs->getFreedomDegree(); } + + + bool CompareByPosition::operator() ( const TrackElement* lhs, const TrackElement* rhs ) const + { + if (lhs == rhs) return false; + + if (lhs->isBlockage() xor rhs->isBlockage()) return lhs->isBlockage(); + + if (lhs->getLength() < rhs->getLength()) return true; + if (lhs->getLength() > rhs->getLength()) return false; + + if (lhs->isHorizontal() xor rhs->isHorizontal()) return rhs->isHorizontal(); + + if (lhs->getAxis() > rhs->getAxis()) return true; + if (lhs->getAxis() < rhs->getAxis()) return false; + + if (lhs->getSourceU() > rhs->getSourceU()) return true; + if (lhs->getSourceU() < rhs->getSourceU()) return false; + + if (lhs->isBlockage() and rhs->isBlockage()) return false; + + return lhs->getId() < rhs->getId(); + } + + +// ------------------------------------------------------------------- +// Class : "TrackElement". + + + SegmentOverlapCostCB* TrackElement::_overlapCostCallback = dummyOverlapCost; + + + SegmentOverlapCostCB* TrackElement::setOverlapCostCB ( SegmentOverlapCostCB* cb ) + { + SegmentOverlapCostCB* oldCb = _overlapCostCallback; + _overlapCostCallback = cb; + return oldCb; + } + + + void TrackElement::notify ( TrackElement* segment, unsigned int flags ) + { + if (flags & AutoSegment::Invalidate) { + if (not segment->isInvalidated()) { + cdebug_log(159,0) << "::notify() on " << segment << endl; + segment->invalidate(); + } + } + + if (flags & AutoSegment::Revalidate) { + // Revalidation must be delayed until *all* the AutoSegments have been revalidated. + // if (segment->isInvalidated()) { + // cdebug_log(159,0) << "::notify() on " << segment << endl; + // segment->revalidate( true ); + // } + } + + if (flags & AutoSegment::RevalidatePPitch) { + segment->updatePPitch(); + } + } + + +// Wrapped AutoSegment Functions. + AutoSegment* TrackElement::base () const { return NULL; } + bool TrackElement::isFixed () const { return false; } + bool TrackElement::isLocal () const { return true; } + bool TrackElement::isGlobal () const { return not isLocal(); } + bool TrackElement::isBipoint () const { return false; } + bool TrackElement::isTerminal () const { return false; } + bool TrackElement::isStrongTerminal ( unsigned int ) const { return false; } + bool TrackElement::isStrap () const { return false; } + bool TrackElement::isSlackened () const { return false; } + bool TrackElement::isDogleg () const { return false; } + bool TrackElement::isReduced () const { return false; } + bool TrackElement::isUTurn () const { return false; } + bool TrackElement::isUserDefined () const { return false; } +// Predicates. + bool TrackElement::canSlacken () const { return false; } + bool TrackElement::canPivotUp ( float ) const { return false; }; + bool TrackElement::canPivotDown ( float ) const { return false; }; + bool TrackElement::canMoveUp ( float, unsigned int ) const { return false; }; + bool TrackElement::canDogleg () { return false; }; + bool TrackElement::canDogleg ( Interval ) { return false; }; + bool TrackElement::canDogleg ( Anabatic::GCell*, unsigned int ) { return false; }; +// Accessors. + unsigned long TrackElement::getId () const { return 0; } + unsigned long TrackElement::getFreedomDegree () const { return 0; } + DbU::Unit TrackElement::getPitch () const { return 0; } + DbU::Unit TrackElement::getPPitch () const { return 0; } + float TrackElement::getMaxUnderDensity ( unsigned int ) const { return 0.0; }; + unsigned int TrackElement::getDoglegLevel () const { return 0; } + TrackElement* TrackElement::getParent () const { return NULL; } + Interval TrackElement::getSourceConstraints () const { return Interval(); } + Interval TrackElement::getTargetConstraints () const { return Interval(); } + DataNegociate* TrackElement::getDataNegociate ( unsigned int ) const { return NULL; } + TrackElements TrackElement::getPerpandiculars () { return new TrackElements_Perpandiculars(NULL); } + void TrackElement::invalidate () { } + TrackElement* TrackElement::getCanonical ( Interval& i ) { i=Interval(getSourceU(),getTargetU()); return this; } + TrackElement* TrackElement::getSourceDogleg () { return NULL; } + TrackElement* TrackElement::getTargetDogleg () { return NULL; } +// Mutators. + void TrackElement::setTrack ( Track* track ) { _track = track; } + void TrackElement::updateFreedomDegree () { } + void TrackElement::setDoglegLevel ( unsigned int ) { } + void TrackElement::swapTrack ( TrackElement* ) { } + void TrackElement::reschedule ( unsigned int ) { } + void TrackElement::detach () { } + void TrackElement::revalidate () { } + void TrackElement::updatePPitch () { } + void TrackElement::setAxis ( DbU::Unit, unsigned int flags ) { } + TrackElement* TrackElement::makeDogleg () { return NULL; } + TrackElement* TrackElement::makeDogleg ( Interval, unsigned int& ) { return NULL; } + TrackElement* TrackElement::makeDogleg ( Anabatic::GCell*, TrackElement*&, TrackElement*& ) { return NULL; } + void TrackElement::_postDoglegs ( TrackElement*&, TrackElement*& ) { } + bool TrackElement::moveAside ( unsigned int ) { return false; } + bool TrackElement::slacken ( unsigned int ) { return false; } + bool TrackElement::moveUp ( unsigned int ) { return false; } + bool TrackElement::moveDown ( unsigned int ) { return false; } +#if THIS_IS_DISABLED + void TrackElement::desalignate () { } +#endif + bool TrackElement::_check () const { return true; } + + + TrackElement::TrackElement ( Track* track ) + : _flags (0) + , _track (track) + , _index ((size_t)-1) + , _sourceU (0) + , _targetU (0) + , _observer(this) + { } + + + void TrackElement::_postCreate () + { } + + + TrackElement::~TrackElement () + { } + + + void TrackElement::_preDestroy () + { } + + + void TrackElement::destroy () + { + _preDestroy (); + delete this; + } + + + TrackElement* TrackElement::getNext () const + { + size_t dummy = _index; + return _track->getNext( dummy, getNet() ); + } + + + TrackElement* TrackElement::getPrevious () const + { + size_t dummy = _index; + return _track->getPrevious( dummy, getNet() ); + } + + + Interval TrackElement::getFreeInterval () const + { + if (not _track) return Interval(false); + + size_t begin = _index; + size_t end = _index; + return _track->expandFreeInterval( begin, end, Track::InsideElement, getNet() ); + } + + + size_t TrackElement::getGCells ( vector& gcells ) const + { + vector().swap( gcells ); + return gcells.size(); + } + + + void TrackElement::incOverlapCost ( Net* net, TrackCost& cost ) const + { + if (not _track or (getNet() == net)) return; + _overlapCostCallback( this, cost ); + } + + + string TrackElement::_getTypeName () const + { return "TrackElement"; } + + + string TrackElement::_getString () const + { return "<"+_getTypeName()+">"; } + + + Record* TrackElement::_getRecord () const + { + Record* record = new Record( _getString() ); + record->add( getSlot( "_flags", _track ) ); + record->add( getSlot( "_track", _track ) ); + record->add( getSlot( "_index", _index ) ); + record->add( DbU::getValueSlot( "_sourceU", &_sourceU ) ); + record->add( DbU::getValueSlot( "_targetU", &_targetU ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackElements.cpp b/katana/src/TrackElements.cpp new file mode 100644 index 00000000..fec16ff7 --- /dev/null +++ b/katana/src/TrackElements.cpp @@ -0,0 +1,136 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./TrackElements.cpp" | +// +-----------------------------------------------------------------+ + + +#include "hurricane/Bug.h" +#include "hurricane/Interval.h" +#include "katana/Session.h" +#include "katana/TrackElement.h" + + +namespace Katana { + + using namespace std; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::Interval; + using Hurricane::Bug; + + +// ------------------------------------------------------------------- +// Class : "TrackElements_Perpandiculars". + + + TrackElements_Perpandiculars::Locator::Locator ( TrackElement* segment ) + : TrackElementHL () + , _locator (segment->base()) + , _element (NULL) + { + cdebug_log(155,0) << "TrackElements_Perpandiculars::Locator::Locator()" << endl; + cdebug_log(155,0) << " " << segment << endl; + + Interval bounds; + if ( _locator.isValid() ) { + _element = Session::lookup( _locator.getElement()->getCanonical(bounds)->base() ); + if ( !_element ) { + cerr << Bug("Canonical segment without TrackElement.") << endl; + progress (); + } + } + } + + + TrackElement* TrackElements_Perpandiculars::Locator::getElement () const + { return _element; } + + + void TrackElements_Perpandiculars::Locator::progress () + { + cdebug_log(155,0) << "TrackElements_Perpandiculars::Locator::progress()" << endl; + + Interval bounds; + while ( _locator.isValid() ) { + _locator.progress (); + + if ( _locator.isValid() ) { + _element = Session::lookup( _locator.getElement()->getCanonical(bounds)->base() ); + if ( !_element ) { + cerr << Bug("Canonical segment whithout TrackElement.") << endl; + continue; + } + + break; + } + } + } + + + TrackElementHL* TrackElements_Perpandiculars::Locator::getClone () const + { return new Locator(*this); } + + + bool TrackElements_Perpandiculars::Locator::isValid () const + { return _locator.isValid(); } + + + TrackElementHC* TrackElements_Perpandiculars::getClone () const + { return new TrackElements_Perpandiculars(*this); } + + + TrackElementHL* TrackElements_Perpandiculars::getLocator () const + { return new Locator(_segment); } + + + string TrackElements_Perpandiculars::Locator::_getString () const + { + string s = ""; + return s; + } + + + string TrackElements_Perpandiculars::_getString () const + { + string s = ""; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "TrackElements_UniqCanonical". + + + TrackElementHF* TrackElements_UniqCanonical::getClone () const + { return new TrackElements_UniqCanonical(_canonicals); } + + + bool TrackElements_UniqCanonical::accept ( TrackElement* segment ) const + { + if (_canonicals.find(segment) == _canonicals.end()) { + _canonicals.insert( segment ); + return true; + } + + return false; + } + + + string TrackElements_UniqCanonical::_getString () const + { return ""; } + + +} // Katana namespace. diff --git a/katana/src/TrackFixedSegment.cpp b/katana/src/TrackFixedSegment.cpp new file mode 100644 index 00000000..dc5336f6 --- /dev/null +++ b/katana/src/TrackFixedSegment.cpp @@ -0,0 +1,200 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Module : "./TrackFixedSegment.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" +#include "hurricane/Net.h" +#include "hurricane/Name.h" +#include "hurricane/RegularLayer.h" +#include "hurricane/Technology.h" +#include "hurricane/DataBase.h" +#include "hurricane/Horizontal.h" +#include "hurricane/Vertical.h" +#include "anabatic/AutoContact.h" +#include "crlcore/RoutingGauge.h" +#include "katana/DataNegociate.h" +#include "katana/TrackFixedSegment.h" +#include "katana/TrackCost.h" +#include "katana/Track.h" +#include "katana/Session.h" +#include "katana/RoutingEvent.h" +#include "katana/NegociateWindow.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + + using namespace std; + using Hurricane::Warning; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::Net; + using Hurricane::Name; + using Hurricane::RegularLayer; + using Hurricane::Technology; + using Hurricane::DataBase; + using Hurricane::Horizontal; + using Hurricane::Vertical; + using Anabatic::GCellsUnder; + + +// ------------------------------------------------------------------- +// Class : "TrackFixedSegment". + + + Net* TrackFixedSegment::_blockageNet = NULL; + + + TrackFixedSegment::TrackFixedSegment ( Track* track, Segment* segment ) + : TrackElement (NULL) + , _segment (segment) + { + Box boundingBox = segment->getBoundingBox(); + + unsigned int flags = TElemFixed | ((segment->getNet() == _blockageNet) ? TElemBlockage : 0); + setFlags( flags ); + + if (track) { + unsigned int depth = track->getDepth(); + Technology* technology = DataBase::getDB()->getTechnology(); + const Layer* layer1 = track->getLayer()->getBlockageLayer(); + RegularLayer* layer2 = dynamic_cast(technology->getLayer(layer1->getMask())); + if ( layer2 ) { + Interval uside = track->getKatanaEngine()->getUSide( track->getDirection() ); + Interval segside; + if (track->getDirection() == Flags::Horizontal) { + segside = Interval( boundingBox.getXMin(), boundingBox.getXMax() ); + _sourceU = max( boundingBox.getXMin(), uside.getVMin()); + _targetU = min( boundingBox.getXMax(), uside.getVMax()); + } else { + segside = Interval( boundingBox.getYMin(), boundingBox.getYMax() ); + _sourceU = max( boundingBox.getYMin(), uside.getVMin()); + _targetU = min( boundingBox.getYMax(), uside.getVMax()); + } + + GCellsUnder gcells = track->getKatanaEngine()->getGCellsUnder( segment ); + for ( size_t i=0 ; isize() ; ++i ) { + GCell* gcell = gcells->gcellAt(i); + gcell->addBlockage + ( depth, gcell->getSide( track->getDirection() ).getIntersection( segside ).getSize() ); + } + } + } + } + + + void TrackFixedSegment::_postCreate () + { TrackElement::_postCreate(); } + + + TrackFixedSegment::~TrackFixedSegment () + { } + + + void TrackFixedSegment::_preDestroy () + { + cdebug_log(155,0) << "TrackFixedSegment::_preDestroy() - " << (void*)this << endl; + TrackElement::_preDestroy(); + } + + + TrackElement* TrackFixedSegment::create ( Track* track, Segment* segment ) + { + if ( not _blockageNet ) _blockageNet = Session::getBlockageNet(); + + TrackFixedSegment* trackFixedSegment = NULL; + if (track) { + trackFixedSegment = new TrackFixedSegment ( track, segment ); + trackFixedSegment->_postCreate(); + + cdebug_log(159,0) << "Adding: " << segment << " on " << track << endl; + cdebug_log(159,0) << "TrackFixedSegment::create(): " << trackFixedSegment << endl; + + Session::addInsertEvent( trackFixedSegment, track ); + } + return trackFixedSegment; + } + + + AutoSegment* TrackFixedSegment::base () const { return NULL; } + DbU::Unit TrackFixedSegment::getAxis () const { return getTrack()->getAxis(); } + bool TrackFixedSegment::isHorizontal () const { return getTrack()->isHorizontal(); } + bool TrackFixedSegment::isVertical () const { return getTrack()->isVertical(); } + bool TrackFixedSegment::isFixed () const { return true; } + Flags TrackFixedSegment::getDirection () const { return getTrack()->getDirection(); } + const Layer* TrackFixedSegment::getLayer () const { return _segment->getLayer(); } + Interval TrackFixedSegment::getFreeInterval () const { return Interval(); } + + + unsigned long TrackFixedSegment::getId () const + { + cerr << Error("::getId() called on %s.",_getString().c_str()) << endl; + return 0; + } + + + Net* TrackFixedSegment::getNet () const + { + Net* realNet = _segment->getNet(); + if (realNet->isSupply() or realNet->isClock()) + return _blockageNet; + return realNet; + } + + + TrackElement* TrackFixedSegment::getNext () const + { + size_t dummy = _index; + return _track->getNext( dummy, getNet() ); + } + + + TrackElement* TrackFixedSegment::getPrevious () const + { + size_t dummy = _index; + return _track->getPrevious( dummy, getNet() ); + } + + + string TrackFixedSegment::_getTypeName () const + { return "TrackFixedSegment"; } + + + string TrackFixedSegment::_getString () const + { + string s1 = _segment->_getString(); + string s2 = " [" + DbU::getValueString(_sourceU) + + ":" + DbU::getValueString(_targetU) + "]" + + " " + DbU::getValueString(_targetU-_sourceU) + + " [" + ((_track) ? getString(_index) : "npos") + "] " + + "F" + + ((isBlockage()) ? "B" : "-"); + s1.insert ( s1.size()-1, s2 ); + + return s1; + } + + + Record* TrackFixedSegment::_getRecord () const + { + Record* record = TrackElement::_getRecord(); + record->add( getSlot( "_segment", _segment ) ); + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackMarker.cpp b/katana/src/TrackMarker.cpp new file mode 100644 index 00000000..43103c33 --- /dev/null +++ b/katana/src/TrackMarker.cpp @@ -0,0 +1,132 @@ +// -*- 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 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 : "./TrackMarker.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" +#include "hurricane/RoutingPad.h" +#include "hurricane/Net.h" +#include "hurricane/Name.h" +#include "crlcore/RoutingGauge.h" +#include "anabatic/GCell.h" +#include "katana/TrackMarker.h" +#include "katana/Track.h" +#include "katana/RoutingPlane.h" +#include "katana/Session.h" +#include "katana/RoutingEvent.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using std::ostringstream; + using std::setprecision; + using Hurricane::Bug; + using CRL::RoutingGauge; + + + TrackMarker* TrackMarker::create ( RoutingPad* rp, size_t depth ) + { + TrackMarker* segment = new TrackMarker ( rp, depth ); + return segment; + } + + + void TrackMarker::destroy () + { + if ( !--_refcount ) delete this; + } + + + TrackMarker::TrackMarker ( RoutingPad* pad, size_t depth ) + : _routingPad (pad) + , _sourcePosition(0) + , _targetPosition(0) + , _track (NULL) + , _weight (0) + , _refcount (0) + { + Point sourcePoint = pad->getSourcePosition(); + Point targetPoint = pad->getTargetPosition(); + RoutingGauge* rg = Session::getRoutingGauge(); + RoutingPlane* rp = Session::getKatanaEngine()->getRoutingPlaneByIndex(depth); + DbU::Unit pitch = DbU::toLambda(Session::getPitch(depth)); + unsigned int rpDirection = rg->getLayerDirection(depth); + Interval trackSpan; + + if ( rpDirection == Constant::Horizontal ) { + _sourcePosition = sourcePoint.getX(); + _targetPosition = targetPoint.getX(); + trackSpan = Interval ( sourcePoint.getY(), targetPoint.getY() ); + } else { + _sourcePosition = sourcePoint.getY(); + _targetPosition = targetPoint.getY(); + trackSpan = Interval ( sourcePoint.getX(), targetPoint.getX() ); + } + + if ( rpDirection xor rg->getLayerDirection(rg->getLayerDepth(pad->getLayer())) ) { + _weight = (unsigned int)(( pitch / (pitch+DbU::toLambda(trackSpan.getSize())) ) * 100.0) ; + } else { + _weight = (unsigned int)( (pitch + DbU::toLambda(trackSpan.getSize())) * 20.0 ); + } + + Track* track = rp->getTrackByPosition ( trackSpan.getVMin() ); + while ( track && (track->getAxis() <= trackSpan.getVMax()) ) { + Session::addInsertEvent ( this, track ); + track = track->getNextTrack(); + _refcount++; + } + } + + + Net* TrackMarker::getNet () const + { return _routingPad->getNet(); } + + + string TrackMarker::_getTypeName () const + { return "TrackMarker"; } + + + string TrackMarker::_getString () const + { + ostringstream s; + s << "<" << _getTypeName() + << " " << getNet()->getName() + << " [" << DbU::getValueString(_sourcePosition) + << ":" << DbU::getValueString(_targetPosition) + << " " << setprecision(3) << ((double)_weight)/100.0 + << ">"; + return s.str(); + } + + + Record* TrackMarker::_getRecord () const + { + Record* record = new Record ( _getString() ); + record->add ( getSlot ( "_routingPad" , _routingPad ) ); + record->add ( getSlot ( "_sourcePosition", _sourcePosition ) ); + record->add ( getSlot ( "_targetPosition", _targetPosition ) ); + record->add ( getSlot ( "_track" , _track ) ); + record->add ( getSlot ( "_weight" , _weight ) ); + + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackSegment.cpp b/katana/src/TrackSegment.cpp new file mode 100644 index 00000000..cf70ebad --- /dev/null +++ b/katana/src/TrackSegment.cpp @@ -0,0 +1,884 @@ +// -*- 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 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 : "./TrackSegment.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include "hurricane/Bug.h" +#include "hurricane/Warning.h" +#include "hurricane/BasicLayer.h" +#include "hurricane/Net.h" +#include "hurricane/Name.h" +#include "hurricane/RoutingPad.h" +#include "anabatic/AutoContact.h" +#include "anabatic/GCell.h" +#include "crlcore/RoutingGauge.h" +#include "katana/DataNegociate.h" +#include "katana/TrackSegment.h" +#include "katana/Track.h" +#include "katana/Session.h" +#include "katana/RoutingEvent.h" +#include "katana/NegociateWindow.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + + using namespace std; + using Hurricane::tab; + using Hurricane::ForEachIterator; + using Hurricane::Bug; + using Hurricane::Error; + using Hurricane::BasicLayer; + using Hurricane::Net; + using Hurricane::Name; + using Hurricane::RoutingPad; + using Anabatic::SegSlackened; + using Anabatic::perpandicularTo; + +// ------------------------------------------------------------------- +// Class : "TrackSegment". + + size_t TrackSegment::_allocateds = 0; + + + size_t TrackSegment::getAllocateds () + { return _allocateds; } + + + TrackSegment::TrackSegment ( AutoSegment* segment, Track* track ) + : TrackElement (track) + , _base (segment) + , _freedomDegree(0) + , _ppitch (0) + , _data (NULL) + , _dogLegLevel (0) + { + cdebug_log(155,0) << "CTOR TrackSegment " << (void*)this << ":" << this << endl; + cdebug_log(155,0) << " over " << (void*)segment << ":" << segment << endl; + + setFlags( TElemCreated|TElemLocked ); + if (segment) { + _data = new DataNegociate( this ); + _base->getCanonical( _sourceU, _targetU ); + updateFreedomDegree(); + updatePPitch(); + } + + ++_allocateds; + } + + + void TrackSegment::_postCreate () + { + TrackElement::_postCreate(); + base()->setObserver( AutoSegment::Observable::TrackSegment, getObserver() ); + } + + + TrackSegment::~TrackSegment () + { + if (_data) delete _data; + --_allocateds; + } + + + void TrackSegment::_preDestroy () + { + cdebug_log(155,0) << "TrackSegment::_preDestroy() - " << (void*)this + << " [" << (void*)_base << ", " + << (void*)(_base?_base->base():NULL) << "]" << endl; + + DbU::Unit length = base()->getLength(); + if ( (length > 0) and (length < getPPitch()) ) { + BasicLayer* layer = getLayer()->getBasicLayers().getFirst(); + DbU::Unit width = base()->getWidth(); + Contact* source = base()->getAutoSource()->base(); + Contact* target = base()->getAutoTarget()->base(); + if (isHorizontal()) { + width = std::max( width, source->getBoundingBox(layer).getHeight() ); + width = std::max( width, target->getBoundingBox(layer).getHeight() ); + } else { + width = std::max( width, source->getBoundingBox(layer).getWidth() ); + width = std::max( width, target->getBoundingBox(layer).getWidth() ); + } + base()->base()->setWidth( width ); + } + + base()->setObserver( AutoSegment::Observable::TrackSegment, NULL ); + TrackElement::_preDestroy(); + } + + + TrackElement* TrackSegment::create ( AutoSegment* segment, Track* track, bool& created ) + { + created = false; + + TrackElement* trackElement = Session::lookup( segment->base() ); + if (not trackElement) { + TrackSegment* trackSegment = new TrackSegment( segment, track ); + trackSegment->_postCreate(); + created = true; + + trackSegment->invalidate(); + + cdebug_log(159,0) << "TrackSegment::create(): " << trackSegment << endl; + trackElement = trackSegment; + } + + return trackElement; + } + + +// Formerly Inline Functions. +// Wrappeds. + AutoSegment* TrackSegment::base () const { return _base; } + bool TrackSegment::isFixed () const { return _base->isFixed(); } + bool TrackSegment::isHorizontal () const { return _base->isHorizontal(); } + bool TrackSegment::isVertical () const { return _base->isVertical(); } + bool TrackSegment::isLocal () const { return not _base->isWeakGlobal() and not _base->isGlobal(); } + bool TrackSegment::isGlobal () const { return _base->isWeakGlobal() or _base->isGlobal(); } + bool TrackSegment::isBipoint () const { return _base->isBipoint(); } + bool TrackSegment::isTerminal () const { return _base->isTerminal(); } + bool TrackSegment::isStrongTerminal ( unsigned int flags ) const { return _base->isStrongTerminal(flags); } + bool TrackSegment::isStrap () const { return _base->isStrap(); } + bool TrackSegment::isSlackened () const { return _base->isSlackened(); } + bool TrackSegment::isDogleg () const { return _base->isDogleg(); } + bool TrackSegment::isReduced () const { return _base->isReduced(); } + bool TrackSegment::isUserDefined () const { return _base->isUserDefined(); } + bool TrackSegment::isUTurn () const { return _base->isUTurn(); } +// Predicates. +// Accessors. + unsigned long TrackSegment::getId () const { return _base->getId(); } + Flags TrackSegment::getDirection () const { return _base->getDirection(); } + Net* TrackSegment::getNet () const { return _base->getNet(); } + const Layer* TrackSegment::getLayer () const { return _base->getLayer(); } + DbU::Unit TrackSegment::getPitch () const { return _base->getPitch(); } + DbU::Unit TrackSegment::getPPitch () const { return _ppitch; } + DbU::Unit TrackSegment::getAxis () const { return _base->getAxis(); } + unsigned long TrackSegment::getFreedomDegree () const { return _freedomDegree; } + unsigned int TrackSegment::getDoglegLevel () const { return _dogLegLevel; } + Interval TrackSegment::getSourceConstraints () const { return _base->getSourceConstraints(); } + Interval TrackSegment::getTargetConstraints () const { return _base->getTargetConstraints(); } + TrackElement* TrackSegment::getCanonical ( Interval& i ) { return Session::lookup( _base->getCanonical(i)->base() ); } + TrackElements TrackSegment::getPerpandiculars () { return new TrackElements_Perpandiculars(this); } +// Mutators. + void TrackSegment::invalidate () { setFlags( TElemInvalidated ); _base->invalidate(); } + + + DataNegociate* TrackSegment::getDataNegociate ( unsigned int flags ) const + { + if (flags & Flags::DataSelf) return _data; + + TrackElement* parent = getParent(); + return (parent) ? parent->getDataNegociate() : NULL; + } + + + TrackElement* TrackSegment::getNext () const + { + size_t dummy = _index; + return _track->getNext( dummy, getNet() ); + } + + + TrackElement* TrackSegment::getPrevious () const + { + size_t dummy = _index; + return _track->getPrevious( dummy, getNet() ); + } + + + TrackElement* TrackSegment::getParent () const + { + AutoSegment* baseParent = base()->getParent(); + if (not baseParent) return NULL; + + TrackElement* element = Session::lookup( baseParent ); + return element; + } + + + Interval TrackSegment::getFreeInterval () const + { + if (not _track) return Interval(false); + + size_t begin = _index; + size_t end = _index; + + return _track->expandFreeInterval( begin, end, Track::InsideElement, getNet() ); + } + + + size_t TrackSegment::getGCells ( vector& gcells ) const + { + vector().swap( gcells ); + + Flags direction = getDirection(); + GCell* sourceGCell = base()->getAutoSource()->getGCell(); + GCell* targetGCell = base()->getAutoTarget()->getGCell(); + + cdebug_log(159,0) << "getGCells(): sourceGCell: " << sourceGCell << endl; + cdebug_log(159,0) << "getGCells(): targetGCell: " << targetGCell << endl; + + for( AutoSegment* segment : base()->getAligneds() ) { + cdebug_log(159,0) << "| " << segment << endl; + + Anabatic::GCell* gcell = segment->getAutoSource()->getGCell(); + if (isLess(gcell,sourceGCell,direction)) { + sourceGCell = gcell; + cdebug_log(159,0) << "getGCells(): new sourceGCell: " << sourceGCell << endl; + } + + gcell = segment->getAutoTarget()->getGCell(); + if (isGreater(gcell,targetGCell,direction)) { + targetGCell = gcell; + cdebug_log(159,0) << "getGCells(): new targetGCell: " << targetGCell << endl; + } + } + + if (not sourceGCell or not targetGCell) return 0; + if (not sourceGCell) { gcells.push_back( targetGCell ); return 1; } + if (not targetGCell) { gcells.push_back( sourceGCell ); return 1; } + + Flags side = (direction & Flags::Horizontal) ? Flags::EastSide : Flags::NorthSide; + DbU::Unit axis = getAxis(); + + gcells.push_back( sourceGCell ); + while ( sourceGCell != targetGCell ) { + sourceGCell = sourceGCell->getNeighborAt( direction, axis ); + if (not sourceGCell) break; + + gcells.push_back( sourceGCell ); + } + + return gcells.size(); + } + + + size_t TrackSegment::getPerpandicularsBound ( set& bounds ) + { + bounds.clear (); + + set baseBounds; + set::iterator ibase; + _base->getPerpandicularsBound( baseBounds ); + + for ( ibase=baseBounds.begin() ; ibase!=baseBounds.end() ; ++ibase ) { + TrackElement* segment = Session::lookup( *ibase ); + if (segment) + bounds.insert( segment ); + } + + return bounds.size(); + } + + + void TrackSegment::setDoglegLevel ( unsigned int level ) + { + if (level > 15) { + cerr << Bug("%s has reached maximum dog leg count (15)." + ,_getString().c_str()) << endl; + level = 15; + } + _dogLegLevel = level; + } + + + void TrackSegment::updateFreedomDegree () + { _freedomDegree = _base->getSlack(); } + + + void TrackSegment::updatePPitch () + { + _ppitch = _base->getPPitch(); + //cerr << "Update P/Pitch (" << DbU::toLambda(getPPitch()) << ") on " << this << endl; + } + + + void TrackSegment::setTrack ( Track* track ) + { TrackElement::setTrack( track ); } + + + void TrackSegment::detach () + { + cdebug_log(159,0) << "TrackSegment::detach() - " << endl; + + setTrack( NULL ); + setIndex( (size_t)-1 ); + setFlags( TElemLocked ); + } + + + void TrackSegment::revalidate () + { + unsetFlags( TElemCreated ); + cdebug_log(159,0) << "revalidate() - " << this << endl; + + _base->getCanonical( _sourceU, _targetU ); + + if (_track) Session::addSortEvent( _track, true ); + unsetFlags( TElemInvalidated ); + } + + + void TrackSegment::setAxis ( DbU::Unit axis, unsigned int flags ) + { + _base->setAxis( axis, flags ); + invalidate(); + } + + + void TrackSegment::swapTrack ( TrackElement* other ) + { + if (not other) return; + + cdebug_log(159,0) << "TrackSegment::swapTrack()" << endl; + + size_t thisIndex = getIndex (); + Track* thisTrack = getTrack (); + size_t otherIndex = other->getIndex (); + Track* otherTrack = other->getTrack (); + + if (_track and otherTrack and (_track != otherTrack)) { + cerr << Error("TrackSegment::swapTrack() - swapping TrackSegments from different tracks.") << endl; + } + + setTrack( NULL ); + other->setTrack( NULL ); + + other->setTrack( thisTrack ); + other->setIndex( thisIndex ); + if (thisTrack) thisTrack->setSegment( other, thisIndex ); + + setTrack( otherTrack ); + setIndex( otherIndex ); + if (_track) _track->setSegment( this, _index ); + +#if defined(CHECK_DATABASE_DISABLED) + if (_track) _track->_check(); + else if (other->getTrack()) other->getTrack()->_check(); +#endif + + RoutingEvent* thisEvent = getDataNegociate(Flags::DataSelf)->getRoutingEvent(); + RoutingEvent* otherEvent = other->getDataNegociate()->getRoutingEvent(); + + if (thisEvent ) thisEvent ->setSegment( other ); + if (otherEvent) otherEvent->setSegment( this ); + + cdebug_log(159,0) << "| this: " << this << endl; + cdebug_log(159,0) << "| other: " << other << endl; + } + + + void TrackSegment::reschedule ( unsigned int level ) + { + cdebug_log(159,1) << "TrackSegment::reschedule() - " << this << endl; + + if (not _data or not _data->hasRoutingEvent()) + Session::getNegociateWindow()->addRoutingEvent( this, level ); + else { + if (_track != NULL) + Session::addRemoveEvent( this ); + Session::getNegociateWindow()->rescheduleEvent( _data->getRoutingEvent(), level ); + } + + cdebug_tabw(159,-1); + } + + + float TrackSegment::getMaxUnderDensity ( unsigned int flags ) const + { return _base->getMaxUnderDensity( flags ); } + + + bool TrackSegment::canPivotUp ( float reserve ) const + { return _base->canPivotUp(reserve); } + + + bool TrackSegment::canPivotDown ( float reserve ) const + { return _base->canPivotDown( reserve ); } + + + bool TrackSegment::canMoveUp ( float reserve, unsigned int flags ) const + { return _base->canMoveUp( reserve, flags ); } + + + bool TrackSegment::canSlacken () const + { + cdebug_log(159,0) << "TrackSegment::canSlacken() doglegLevel:" << getDoglegLevel() << endl; + return (not isSlackened() and (getDoglegLevel() <= 3)) ? _base->canSlacken(Flags::Propagate) : false; + } + + bool TrackSegment::slacken ( unsigned int flags ) + { + cdebug_log(159,0) << "TrackSegment::slacken()" << endl; + + bool success = false; + + if (not isSlackened()) { + TrackElement* perpandicular = NULL; + TrackElement* parallel = NULL; + + cdebug_tabw(159,1); + + success = base()->slacken( flags|Flags::Propagate ); + _postDoglegs( perpandicular, parallel ); + + cdebug_tabw(159,-1); + return success; + } else + cerr << Bug("TrackSegment::slacken(): NULL base or already slackened.") << endl; + + return success; + } + + + bool TrackSegment::moveUp ( unsigned int flags ) + { + bool success = false; + + cdebug_log(159,1) << "TrackSegment::moveUp() " << flags << endl; + + success = base()->moveUp( flags ); + if (success) { + TrackElement* perpandicular = NULL; + TrackElement* parallel = NULL; + + Session::revalidateTopology(); + _postDoglegs( perpandicular, parallel ); + } + + cdebug_tabw(159,-1); + + return success; + } + + + bool TrackSegment::moveDown ( unsigned int flags ) + { + bool success = false; + + cdebug_log(159,1) << "TrackSegment::moveDown() " << flags << endl; + + success = base()->moveDown( flags ); + if (success) { + TrackElement* perpandicular = NULL; + TrackElement* parallel = NULL; + + Session::revalidateTopology(); + _postDoglegs( perpandicular, parallel ); + } + + cdebug_tabw(159,-1); + + return success; + } + + + bool TrackSegment::moveAside ( unsigned int flags ) + { + bool success = true; + + cdebug_log(159,1) << "TrackSegment::moveAside() - " + << ((flags&Flags::MoveToLeft )?"left" :"") + << ((flags&Flags::MoveToRight)?"rigth":"") << endl; + if (flags & Flags::MoveToLeft ) base()->moveULeft (); + if (flags & Flags::MoveToRight) base()->moveURight(); + cdebug_tabw(159,-1); + + return success; + } + + + TrackElement* TrackSegment::getSourceDogleg () + { + if (not hasSourceDogleg()) return NULL; + + unsigned int direction = perpandicularTo( getDirection() ); + TrackElement* dogleg = NULL; + for( Segment* segment : base()->getAutoSource()->getSlaveComponents().getSubSet() ) { + dogleg = Session::lookup( segment ); + if (dogleg and (dogleg->getDirection() == direction)) { + cdebug_log(159,0) << "Source dogleg: " << dogleg << endl; + return dogleg; + } + } + return NULL; + } + + + TrackElement* TrackSegment::getTargetDogleg () + { + if (not hasSourceDogleg()) return NULL; + + unsigned int direction = perpandicularTo( getDirection() ); + TrackElement* dogleg = NULL; + for( Segment* segment : base()->getAutoTarget()->getSlaveComponents().getSubSet() ) { + dogleg = Session::lookup( segment ); + if (dogleg and (dogleg->getDirection() == direction)) { + cdebug_log(159,0) << "Target dogleg: " << dogleg << endl; + return dogleg; + } + } + return NULL; + } + + + bool TrackSegment::canDogleg () + { + cdebug_log(159,0) << "TrackSegment::canDogleg()" << endl; + + if (not isLocal()) { + cdebug_log(159,0) << "Failed: is not local." << endl; + return false; + } + + if (isFixed()) { + cdebug_log(159,0) << "Failed: is fixed." << endl; + return false; + } + + if (isRouted()) { + cdebug_log(159,0) << "Failed: belongs to an already routed net." << endl; + return false; + } + + if (isSlackened()) { + cdebug_log(159,0) << "Failed: is local & slackened." << endl; + return false; + } + + if (hasSourceDogleg() or hasTargetDogleg()) { + cdebug_log(159,0) << "Failed: already has source or target dogleg." << endl; + return false; + } + + if (getDoglegLevel() > 3) { + cdebug_log(159,0) << "Failed: maximum dogleg level reached (4)." << endl; + return false; + } + + return true; + } + + + bool TrackSegment::canDogleg ( Anabatic::GCell* doglegGCell, unsigned int flags ) + { + cdebug_log(159,1) << "TrackSegment::canDogleg(GCell*) " << doglegGCell << endl; + + if (doglegGCell->isIoPad()) { + cdebug_log(159,0) << "false: Cannot dogleg in a GCell under an I/O Pad." << endl; + cdebug_tabw(159,-1); + return false; + } + + if (isFixed()) { + cdebug_log(159,0) << "false: Cannot dogleg a fixed segment." << endl; + cdebug_tabw(159,-1); + return false; + } + + if (isRouted()) { + cdebug_log(159,0) << "false: Cannot dogleg a segment belonging to an already routed net." << endl; + cdebug_tabw(159,-1); + return false; + } + + if (isLocal()) { + if (hasSourceDogleg() or hasTargetDogleg()) { + cdebug_log(159,0) << "false: Cannot dogleg again a local segment." << endl; + cdebug_tabw(159,-1); + return false; + } + if (isSlackened()) { + cdebug_log(159,0) << "false: Cannot dogleg a local slackened segment." << endl; + cdebug_tabw(159,-1); + return false; + } + } + + if (getDoglegLevel() > 3) { + cdebug_log(159,0) << "Failed: maximum dogleg level reached (4)." << endl; + cdebug_tabw(159,-1); + return false; + } + + vector gcells; + getGCells( gcells ); + + cdebug_log(159,0) << "Source: " << *gcells.begin () << endl; + cdebug_log(159,0) << "Target: " << *gcells.rbegin() << endl; + + bool isGCellInside = false; + for ( size_t igcell=0 ; igcell 3) { + cdebug_log(159,0) << "Failed: maximum dogleg level reached (4)." << endl; + return false; + } + + return _base->canDogleg(interval); + } + + + TrackElement* TrackSegment::makeDogleg () + { + Anabatic::AutoContact* source = _base->getAutoSource(); + Anabatic::AutoContact* target = _base->getAutoTarget(); + Anabatic::GCell* gcell = _base->getAutoSource()->getGCell(); + + TrackElement* dogleg = NULL; + TrackElement* parallel = NULL; + makeDogleg( gcell, dogleg, parallel ); + + if (dogleg) { + if (source->isTerminal() xor target->isTerminal()) { + if (target->isTerminal()) + source = target; + + DbU::Unit axis = (_base->isHorizontal()) ? source->getX() : source->getY(); + + cdebug_log(159,0) << "Setting dogleg axis @" << DbU::getValueString(axis) << endl; + dogleg->setAxis( axis ); + } + } + return dogleg; + } + + + TrackElement* TrackSegment::makeDogleg ( Anabatic::GCell* dogLegGCell + , TrackElement*& perpandicular + , TrackElement*& parallel + ) + { + cdebug_log(159,0) << "TrackSegment::makeDogleg(GCell*)" << endl; + cdebug_log(159,0) << "Break in: " << dogLegGCell << endl; + + base()->makeDogleg( dogLegGCell ); + _postDoglegs( perpandicular, parallel ); + + return perpandicular; + } + + + TrackElement* TrackSegment::makeDogleg ( Interval interval, unsigned int& flags ) + { + TrackElement* perpandicular = NULL; + TrackElement* parallel = NULL; + + cdebug_log(159,0) << "TrackSegment::makeDogleg(Interval)" << endl; + flags = base()->makeDogleg( interval ); + _postDoglegs( perpandicular, parallel ); + + return perpandicular; + } + + + void TrackSegment::_postDoglegs ( TrackElement*& perpandicular, TrackElement*& parallel ) + { + cdebug_log(159,1) << "TrackSegment::_postDoglegs()" << endl; + + unsigned int doglegLevel = 0; + const vector& doglegs = Session::getDoglegs(); + vector segments; + + if (not doglegs.empty()) { + if (doglegs.size()%3 != 0) + cerr << Error( "Session::_postDoglegs(): Number of created segments incoherent with pure doglegs (%u)." + , doglegs.size() ) << endl; + + for ( size_t i=0 ; icreateTrackSegment(doglegs[i],0) ); + segments[i+0]->setFlags( TElemTargetDogleg ); + segments[i+0]->getDataNegociate()->resetRipupCount(); + //segments[i+0]->getDataNegociate()->resetStateCount(); + segments[i+0]->getDataNegociate()->setState( DataNegociate::RipupPerpandiculars ); + doglegLevel = segments[i+0]->getDoglegLevel(); + segments[i+0]->setDoglegLevel( doglegLevel + (segments[i]->isLocal()?1:0) ); + + cdebug_log(159,0) << "Looking up new perpand: " << doglegs[i+1] << endl; + segments.push_back( Session::getNegociateWindow()->createTrackSegment(doglegs[i+1],0) ); + segments[i+1]->setFlags( TElemSourceDogleg|TElemTargetDogleg ); + segments[i+1]->setDoglegLevel( doglegLevel + 1 ); + + cdebug_log(159,0) << "Looking up new parallel: " << doglegs[i+2] << endl; + segments.push_back( Session::getNegociateWindow()->createTrackSegment(doglegs[i+2],0) ); + segments[i+2]->setFlags( TElemSourceDogleg ); + segments[i+2]->getDataNegociate()->resetStateCount(); + segments[i+2]->getDataNegociate()->setState( segments[i+0]->getDataNegociate()->getState() ); + segments[i+2]->setDoglegLevel( doglegLevel + (segments[i]->isLocal()?1:0) ); + + segments[i+0]->getDataNegociate()->setChildSegment( segments[i+2] ); + + perpandicular = segments[i+1]; + parallel = segments[i+2]; + } + + // TO CHECK + // If the original TrackElement was inserted in a Track, must check + // if the new bit takes it's place or not. + //if ( getGCell() != originalGCell ) swapTrack ( segments[2] ); + + for ( size_t i=0 ; ireschedule ( ((i%3==1) ? 0 : 1) ); + const char* segPart = "Unknown"; + switch ( i%3 ) { + case 0: segPart = "original "; break; + case 1: segPart = "perpand "; break; + case 2: segPart = "new paral"; break; + } + cdebug_log(159,0) << "[" << (i/3) << ":" << i << "] " << segPart << ": " + << segments[i] << endl; + } + } else { + reschedule( 1 ); + } + + cdebug_tabw(159,-1); + + Session::doglegReset(); + } + + + bool TrackSegment::_check () const + { + if (not base()) return true; + + bool coherency = true; + + if (not base()->isCanonical()) { + cerr << "[CHECK] " << this << " supporting AutoSegment is not canonical." << endl; + coherency = false; + } + + DbU::Unit min; + DbU::Unit max; + base()->checkPositions(); + base()->getCanonical( min, max ); + if (getSourceU() != min) { + cerr << "[CHECK] " << this << " has bad source position " + << "cache:" << DbU::getValueString(getSourceU()) << " vs. " + << "canon:" << DbU::getValueString(min) << "." << endl; + coherency = false; + } + if (getTargetU() != max) { + cerr << "[CHECK] " << this << " has bad target position " + << "cache:" << DbU::getValueString(getTargetU()) << " vs. " + << "canon:" << DbU::getValueString(max) << "." << endl; + coherency = false; + } + + return coherency; + } + + + string TrackSegment::_getTypeName () const + { return "TrackSegment"; } + + + string TrackSegment::_getString () const + { + string s1 = _base->_getString(); + string s2 = " [" + DbU::getValueString(_sourceU) + + ":" + DbU::getValueString(_targetU) + "]" + + " " + DbU::getValueString(_targetU-_sourceU) + + " " + getString(_dogLegLevel) + + " [" + ((_track) ? getString(_index) : "npos") + "] " + + ((isRouted() ) ? "R" : "-") + + ((isSlackened() ) ? "S" : "-") + + ((_track ) ? "T" : "-") + + ((canRipple() ) ? "r" : "-") + + ((hasSourceDogleg()) ? "s" : "-") + + ((hasTargetDogleg()) ? "t" : "-"); + + s1.insert( s1.size()-1, s2 ); + + return s1; + } + + + Record* TrackSegment::_getRecord () const + { + Record* record = TrackElement::_getRecord(); + record->add( getSlot( "_base", _base ) ); + return record; + } + + +} // Katana namespace. diff --git a/katana/src/TrackSegmentCost.cpp b/katana/src/TrackSegmentCost.cpp new file mode 100644 index 00000000..d153050c --- /dev/null +++ b/katana/src/TrackSegmentCost.cpp @@ -0,0 +1,203 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./TrackSegmentCost.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#include + +#include "hurricane/Bug.h" +#include "hurricane/DebugSession.h" +#include "anabatic/AutoSegment.h" +#include "katana/TrackElement.h" +#include "katana/TrackSegmentCost.h" + + +namespace Katana { + + + using std::cerr; + using std::endl; + using std::map; + using std::multimap; + using std::make_pair; + using std::ostringstream; + using Hurricane::Bug; + using Hurricane::DebugSession; + using Hurricane::tab; + + +// ------------------------------------------------------------------- +// Class : "TrackSegmentCost". + + + TrackSegmentCost::TrackSegmentCost ( TrackElement* trackSegment ) + : _terminals (0) + , _ripupCount (0) + , _leftMinExtend (DbU::Max) + , _rightMinExtend(DbU::Min) + , _net (trackSegment->getNet()) + , _attractors () + { + //update ( trackSegment ); + } + + + TrackSegmentCost::~TrackSegmentCost () + { } + + + DbU::Unit TrackSegmentCost::getWiringDelta ( DbU::Unit axis ) const + { + DbU::Unit attraction = 0; + for ( size_t i=0 ; i < _attractors.size() ; i++ ) { + if ( _attractors[i] > axis ) attraction += _attractors[i] - axis; + else attraction += axis - _attractors[i]; + } + return attraction; + } + + + void TrackSegmentCost::update ( TrackElement* trackSegment ) + { + DebugSession::open ( trackSegment->getNet(), 150, 160 ); + + cdebug_log(159,1) << "TrackSegmentCost::update() - " << trackSegment << endl; + + vector collapseds; + vector perpandiculars; + map attractorSpins; + + AutoSegment::getTopologicalInfos ( trackSegment->base() + , collapseds + , perpandiculars + , _leftMinExtend + , _rightMinExtend + ); + + _terminals = AutoSegment::getTerminalCount ( trackSegment->base(), collapseds ); + _attractors.clear (); + + for ( size_t i=0 ; i < perpandiculars.size() ; i++ ) { + Interval interval; + TrackElement* perpandicular; + + if ( perpandiculars[i]->isCanonical() ) { + perpandicular = Session::lookup ( perpandiculars[i]->base() ); + if ( perpandicular ) + perpandicular->getCanonical ( interval ); + } else { + perpandicular = Session::lookup ( perpandiculars[i]->getCanonical(interval)->base() ); + } + + if ( not perpandicular ) { + cerr << Bug("Not a TrackSegment: %s:%s\n (perpandicular: %s:%s)" + ,getString((void*)perpandiculars[i]->getCanonical(interval)->base()).c_str() + ,getString(perpandiculars[i]->getCanonical(interval)).c_str() + ,getString((void*)perpandiculars[i]->base()).c_str() + ,getString(perpandiculars[i]).c_str() + ) << endl; + continue; + } + interval.inflate ( DbU::lambda(-1.5) ); + + cdebug_log(159,0) << "| perpandicular: " << perpandiculars[i] << endl; + cdebug_log(159,1) << "| canonical: " << perpandicular << endl; + cdebug_log(159,0) << "interval: " << interval << endl; + + if ( interval.isPonctual() ) { + cdebug_log(159,0) << "Punctual attractor @" << DbU::getValueString(interval.getVMin()) << endl; + _attractors.push_back ( interval.getVMin() ); + cdebug_tabw(159,-1); + continue; + } + + if ( ( interval.getVMin() != trackSegment->getAxis() ) + or AutoSegment::isTopologicalBound(perpandiculars[i] + ,false + ,perpandicular->isHorizontal() + ) ) { + map::iterator iattractor = attractorSpins.find ( interval.getVMin() ); + if ( iattractor == attractorSpins.end() ) { + attractorSpins.insert ( make_pair(interval.getVMin(),-1) ); + } else { + iattractor->second -= 1; + } + cdebug_log(159,0) << "Left attractor @" << DbU::getValueString(interval.getVMin()) << endl; + } + + if ( ( interval.getVMax() != trackSegment->getAxis() ) + or AutoSegment::isTopologicalBound(perpandiculars[i] + ,true + ,perpandicular->isHorizontal() + ) ) { + map::iterator iattractor = attractorSpins.find ( interval.getVMax() ); + if ( iattractor == attractorSpins.end() ) { + attractorSpins.insert ( make_pair(interval.getVMax(),1) ); + } else { + iattractor->second += 1; + } + cdebug_log(159,0) << "Right attractor @" << DbU::getValueString(interval.getVMax()) << endl; + } + + cdebug_tabw(159,-1); + } + + map::iterator iattractor = attractorSpins.begin(); + for ( ; iattractor != attractorSpins.end() ; iattractor++ ) { + if ( iattractor->second != 0 ) + _attractors.push_back ( iattractor->first ); + } + + ostringstream s; + s << "Attractors ["; + for ( size_t i=0 ; i<_attractors.size() ; i++ ) { + if ( i ) s << ", "; + s << DbU::getValueString(_attractors[i]); + } + s << "]"; + cdebug_log(159,0) << s.str() << endl; + + + cdebug_tabw(159,-1); + DebugSession::close (); + } + + + string TrackSegmentCost::_getString () const + { + return "<" + _getTypeName() + " " + + getString(_terminals) + + " [" + DbU::getValueString(_leftMinExtend) + + ":" + DbU::getValueString(_rightMinExtend) + + "]>"; + } + + + Record* TrackSegmentCost::_getRecord () const + { + Record* record = new Record ( getString(this) ); + record->add ( getSlot ( "_terminals" , _terminals ) ); + record->add ( getSlot ( "_ripupCount" , _ripupCount ) ); + record->add ( getSlot ( "_leftMinExtend" , &_leftMinExtend ) ); + record->add ( getSlot ( "_rightMinExtend", &_rightMinExtend ) ); + record->add ( getSlot ( "_net" , _net ) ); + + return record; + } + + +} // End of Katana namespace. diff --git a/katana/src/Tracks.cpp b/katana/src/Tracks.cpp new file mode 100644 index 00000000..d9bbb2c4 --- /dev/null +++ b/katana/src/Tracks.cpp @@ -0,0 +1,315 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./Tracks.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include "katana/Track.h" +#include "katana/Tracks.h" +#include "katana/RoutingPlane.h" + + +namespace Katana { + + using std::cerr; + using std::endl; + using Hurricane::tab; + + +// ------------------------------------------------------------------- +// Class : "Tracks_Range::Locator". + + + Tracks_Range::Locator::Locator ( const RoutingPlane* routingPlane + , const Interval& constraints + ) + : Hurricane::Locator() + , _constraints (constraints) + { + cdebug_log(159,0) << "Tracks_Range::Locator()" << endl; + cdebug_log(159,0) << "* Constraints: " << _constraints << endl; + + _track = routingPlane->getTrackByPosition ( _constraints.getVMin() ); + + if ( _track and (_track->getAxis() < _constraints.getVMin()) ) _track = _track->getNextTrack(); + if ( _track and (_track->getAxis() > _constraints.getVMax()) ) _track = NULL; + + cdebug_log(159,0) << "_track: " << _track << endl;; + } + + + Tracks_Range::Locator::Locator ( const Locator& locator ) + : Hurricane::Locator() + , _constraints(locator._constraints) + , _track (locator._track) + { } + + + Hurricane::Locator* Tracks_Range::Locator::getClone () const + { return new Locator(*this); } + + + bool Tracks_Range::Locator::isValid () const + { return (_track != NULL); } + + + Track* Tracks_Range::Locator::getElement () const + { return _track; } + + + + void Tracks_Range::Locator::progress () + { + if ( !_track ) return; + + _track = _track->getNextTrack(); + if ( _track and (_track->getAxis() > _constraints.getVMax()) ) _track = NULL; + } + + + string Tracks_Range::Locator::_getString () const + { + string s = ""; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "Tracks_Range". + + + Tracks Tracks_Range::get ( RoutingPlane* routingPlane + , Interval& constraints ) + { return new Tracks_Range ( routingPlane, constraints ); } + + + Tracks_Range::Tracks_Range ( const RoutingPlane* routingPlane + , const Interval& constraints ) + : Collection() + , _routingPlane(routingPlane) + , _constraints (constraints) + { } + + + Tracks_Range::Tracks_Range ( const Tracks_Range& tracks ) + : Collection() + , _routingPlane(tracks._routingPlane) + , _constraints (tracks._constraints) + { } + + + Collection* Tracks_Range::getClone () const + { return new Tracks_Range(*this); } + + + Hurricane::Locator* Tracks_Range::getLocator () const + { return new Locator(_routingPlane,_constraints); } + + + string Tracks_Range::_getString () const + { + string s = "<" + _TName("Tracks_Range") + " " + + getString(_routingPlane->getLayer()) + " [" + + getString(_constraints.getVMin()) + ":" + + getString(_constraints.getVMax()) + "]" + + ">"; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "Tracks_Spiral::Locator". + + + Tracks_Spiral::Locator::Locator ( const RoutingPlane* routingPlane + , const Interval& optimal + , const Interval& constraints + ) + : Hurricane::Locator() + , _optimal (optimal) + , _constraints (constraints) + , _onMin (false) + , _inMinOptimal(true) + , _inMaxOptimal(true) + { + cdebug_log(159,0) << "Tracks_Spiral::Locator()" << endl; + cdebug_log(159,0) << "* Optimal: " << _optimal << endl; + cdebug_log(159,0) << "* Constraints: " << _constraints << endl; + + _minTrack = _maxTrack = routingPlane->getTrackByPosition ( _optimal.getCenter() ); + + if ( _minTrack->getAxis() < _constraints.getVMin() ) _minTrack = NULL; + if ( _maxTrack->getAxis() > _constraints.getVMax() ) _maxTrack = NULL; + + if ( _minTrack && !_maxTrack ) { + _minTrack = _minTrack->getPreviousTrack(); + if (_minTrack->getAxis() < _constraints.getVMin()) _minTrack = NULL; + } + + if ( _maxTrack && !_minTrack ) { + _maxTrack = _maxTrack->getNextTrack(); + if ( _maxTrack->getAxis() > _constraints.getVMax() ) _maxTrack = NULL; + } + + if ( _minTrack && (_minTrack->getAxis() < _optimal.getVMin()) ) _inMinOptimal = false; + if ( _maxTrack && (_maxTrack->getAxis() > _optimal.getVMax()) ) _inMaxOptimal = false; + + cdebug_log(159,0) << "_minTrack: " << _minTrack << endl;; + cdebug_log(159,0) << "_maxTrack: " << _maxTrack << endl;; + } + + + Tracks_Spiral::Locator::Locator ( const Locator& locator ) + : Hurricane::Locator() + , _optimal (locator._optimal) + , _constraints (locator._constraints) + , _minTrack (locator._minTrack) + , _maxTrack (locator._maxTrack) + , _onMin (locator._onMin) + , _inMinOptimal(locator._inMinOptimal) + , _inMaxOptimal(locator._inMaxOptimal) + { } + + + Hurricane::Locator* Tracks_Spiral::Locator::getClone () const + { return new Locator(*this); } + + + bool Tracks_Spiral::Locator::isValid () const + { return _minTrack||_maxTrack; } + + + Track* Tracks_Spiral::Locator::getElement () const + { + if ( !_minTrack ) return _maxTrack; + if ( !_maxTrack ) return _minTrack; + + return (_onMin) ? _maxTrack : _minTrack; + } + + + bool Tracks_Spiral::Locator::InOptimal () const + { return _inMinOptimal&&_inMaxOptimal; } + + + + void Tracks_Spiral::Locator::progress () + { + cdebug_log(159,1) << "Track_Spiral::progress() - State:" << endl; + cdebug_log(159,0) << _onMin + << " " << _minTrack + << " " << _maxTrack << endl; + + if ( !isValid() ) { + cdebug_tabw(159,-1); + return; + } + + if ( _onMin ) { + _onMin = (_maxTrack == NULL); + if ( _minTrack ) { + _minTrack = _minTrack->getPreviousTrack(); + + if ( _minTrack ) { + if ( _minTrack->getAxis() < _optimal.getVMin() ) _inMinOptimal = false; + if ( _minTrack->getAxis() < _constraints.getVMin() ) _minTrack = NULL; + } + if ( !_minTrack && _maxTrack ) progress(); + } + } else { + _onMin = (_minTrack != NULL); + if ( _maxTrack ) { + _maxTrack = _maxTrack->getNextTrack(); + + if ( _maxTrack ) { + if ( _maxTrack->getAxis() > _optimal.getVMax() ) _inMaxOptimal = false; + if ( _maxTrack->getAxis() > _constraints.getVMax() ) _maxTrack = NULL; + } + + if ( !_maxTrack && _minTrack ) progress(); + } + } + + cdebug_log(159,0) << _onMin + << " " << _minTrack + << " " << _maxTrack << endl; + cdebug_tabw(159,-1); + } + + + string Tracks_Spiral::Locator::_getString () const + { + string s = ""; + return s; + } + + +// ------------------------------------------------------------------- +// Class : "Tracks_Spiral". + + + Tracks Tracks_Spiral::get ( RoutingPlane* routingPlane + , Interval& optimal + , Interval& constraints ) + { return new Tracks_Spiral ( routingPlane, optimal, constraints ); } + + + Tracks_Spiral::Tracks_Spiral ( const RoutingPlane* routingPlane + , const Interval& optimal + , const Interval& constraints ) + : Collection() + , _routingPlane(routingPlane) + , _optimal (optimal) + , _constraints (constraints) + { } + + + Tracks_Spiral::Tracks_Spiral ( const Tracks_Spiral& tracks ) + : Collection() + , _routingPlane(tracks._routingPlane) + , _optimal (tracks._optimal) + , _constraints (tracks._constraints) + { } + + + Collection* Tracks_Spiral::getClone () const + { return new Tracks_Spiral(*this); } + + + Hurricane::Locator* Tracks_Spiral::getLocator () const + { return new Locator(_routingPlane,_optimal,_constraints); } + + + string Tracks_Spiral::_getString () const + { + string s = "<" + _TName("Tracks_Spiral") + " " + + getString(_routingPlane->getLayer()) + " [" + + getString(_constraints.getVMin()) + " (" + + getString(_optimal.getVMin()) + ":" + + getString(_optimal.getVMax()) + ") " + + getString(_constraints.getVMax()) + "]" + + ">"; + return s; + } + + +} // Katana namespace. diff --git a/katana/src/VerticalTrack.cpp b/katana/src/VerticalTrack.cpp new file mode 100644 index 00000000..f4e20958 --- /dev/null +++ b/katana/src/VerticalTrack.cpp @@ -0,0 +1,75 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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 : "./VerticalTrack.cpp" | +// +-----------------------------------------------------------------+ + + +#include "katana/VerticalTrack.h" + + +namespace Katana { + + +// ------------------------------------------------------------------- +// Class : "VerticalTrack". + + + VerticalTrack::VerticalTrack ( RoutingPlane* routingPlane, unsigned int index ) + : Track(routingPlane,index) + { } + + + void VerticalTrack::_postCreate () + { } + + + VerticalTrack* VerticalTrack::create ( RoutingPlane* routingPlane, unsigned int index ) + { + VerticalTrack* track = new VerticalTrack ( routingPlane, index ); + + track->_postCreate (); + + return track; + } + + + VerticalTrack::~VerticalTrack () + { } + + + void VerticalTrack::_preDestroy () + { } + + + bool VerticalTrack::isHorizontal () const { return false; } + bool VerticalTrack::isVertical () const { return true; } + Flags VerticalTrack::getDirection () const { return Flags::Vertical; } + + + Point VerticalTrack::getPosition ( DbU::Unit coordinate ) const + { return Point ( getAxis(), coordinate ); } + + + string VerticalTrack::_getTypeName () const + { return "VerticalTrack"; } + + + Record* VerticalTrack::_getRecord () const + { + Record* record = Track::_getRecord (); + return record; + } + + +} // Katana namespace. diff --git a/katana/src/katana/Configuration.h b/katana/src/katana/Configuration.h new file mode 100644 index 00000000..c76dfa5e --- /dev/null +++ b/katana/src/katana/Configuration.h @@ -0,0 +1,122 @@ +// -*- mode: C++; explicit-buffer-name: "Configuration.h" -*- +// +// 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 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++ Header : "./katana/Configuration.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_CONFIGURATION_H +#define KATANA_CONFIGURATION_H + +#include +#include "anabatic/Configuration.h" +#include "katana/Constants.h" + + +namespace Katana { + + using std::string; + using Hurricane::Record; + using Hurricane::Layer; + using Hurricane::DbU; + using Hurricane::Cell; + using CRL::CellGauge; + using CRL::RoutingGauge; + using CRL::RoutingLayerGauge; + + class KatanaEngine; + + +// ------------------------------------------------------------------- +// Class : "Katana::Configuration". + + class Configuration : public Anabatic::Configuration { + public: + typedef Anabatic::Configuration Super; + public: + typedef std::function< void(void) > PostEventCb_t; + public: + enum RipupTable { StrapRipupLimit = 0 + , LocalRipupLimit = 1 + , GlobalRipupLimit = 2 + , LongGlobalRipupLimit = 3 + , RipupLimitsTableSize = 4 + }; + enum Constants { MaxMetalDepth = 20 }; + enum Flag { UseClockTree = (1 << 0) }; + public: + // Constructor & Destructor. + virtual Configuration* clone () const; + Configuration (); + ~Configuration (); + // Decorateds. + inline bool useClockTree () const; + // Methods. + inline Anabatic::Configuration* base (); + inline const Anabatic::Configuration* base () const; + inline PostEventCb_t& getPostEventCb (); + inline unsigned long getEventsLimit () const; + inline unsigned int getRipupCost () const; + unsigned int getRipupLimit ( unsigned int type ) const; + inline size_t getHTracksReservedLocal () const; + inline size_t getVTracksReservedLocal () const; + inline void setEventsLimit ( unsigned long ); + inline void setRipupCost ( unsigned int ); + void setRipupLimit ( unsigned int limit, unsigned int type ); + inline void setPostEventCb ( PostEventCb_t ); + void setHTracksReservedLocal ( size_t ); + void setVTracksReservedLocal ( size_t ); + inline void setFlags ( unsigned int ); + inline void unsetFlags ( unsigned int ); + virtual void print ( Cell* ) const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + private: + // Attributes. + PostEventCb_t _postEventCb; + size_t _hTracksReservedLocal; + size_t _vTracksReservedLocal; + unsigned int _ripupLimits [RipupLimitsTableSize]; + unsigned int _ripupCost; + unsigned long _eventsLimit; + unsigned int _flags; + private: + Configuration ( const Configuration& other ); + Configuration& operator= ( const Configuration& ); + }; + + +// Inline Functions. + inline const Anabatic::Configuration* Configuration::base () const { return dynamic_cast(this); } + inline Anabatic::Configuration* Configuration::base () { return dynamic_cast(this); } + inline Configuration::PostEventCb_t& Configuration::getPostEventCb () { return _postEventCb; } + inline unsigned long Configuration::getEventsLimit () const { return _eventsLimit; } + inline unsigned int Configuration::getRipupCost () const { return _ripupCost; } + inline size_t Configuration::getHTracksReservedLocal () const { return _hTracksReservedLocal; } + inline size_t Configuration::getVTracksReservedLocal () const { return _vTracksReservedLocal; } + inline void Configuration::setRipupCost ( unsigned int cost ) { _ripupCost = cost; } + inline void Configuration::setPostEventCb ( PostEventCb_t cb ) { _postEventCb = cb; } + inline void Configuration::setEventsLimit ( unsigned long limit ) { _eventsLimit = limit; } + inline bool Configuration::useClockTree () const { return _flags & UseClockTree; } + inline void Configuration::setFlags ( unsigned int flags ) { _flags |= flags; } + inline void Configuration::unsetFlags ( unsigned int flags ) { _flags &= ~flags; } + + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::Configuration); + + +#endif // KATANA_CONFIGURATION_H diff --git a/katana/src/katana/Constants.h b/katana/src/katana/Constants.h new file mode 100644 index 00000000..d78ef7ed --- /dev/null +++ b/katana/src/katana/Constants.h @@ -0,0 +1,52 @@ +// -*- mode: C++; explicit-buffer-name: "Constants.h" -*- +// +// 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 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++ Header : "./katana/Constants.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_CONSTANTS_H +#define KATANA_CONSTANTS_H + +#include "anabatic/Constants.h" + +namespace Katana { + + + class Flags : public Anabatic::Flags { + public: + typedef Anabatic::Flags Super; + public: + static const unsigned int AllowDoglegReuse; + static const unsigned int DataSelf; + static const unsigned int Nearest; + static const unsigned int Force; + static const unsigned int ResetCount; + static const unsigned int WithConstraints; + static const unsigned int MoveToLeft; + static const unsigned int MoveToRight; + static const unsigned int LoadingStage; + static const unsigned int SlowMotion; + static const unsigned int PreRoutedStage; + public: + inline Flags ( unsigned int ); + inline Flags ( const Super& ); + }; + + + inline Flags::Flags ( unsigned int flags ) : Super(flags) { } + inline Flags::Flags ( const Flags::Super& base ) : Super(base) { } + + +} // Katana namespace. + +#endif // KATANA_CONSTANTS_H diff --git a/katana/src/katana/DataNegociate.h b/katana/src/katana/DataNegociate.h new file mode 100644 index 00000000..bbdc49ce --- /dev/null +++ b/katana/src/katana/DataNegociate.h @@ -0,0 +1,158 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/DataNegociate.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_DATA_NEGOCIATE_H +#define KATANA_DATA_NEGOCIATE_H + +#include +#include + +namespace Hurricane { + class Record; +} + +#include "katana/TrackElement.h" +namespace Anabatic { + class AutoSegment; +} + + +namespace Katana { + + using std::string; + using std::cerr; + using std::endl; + using Hurricane::Record; + using Anabatic::AutoSegment; + + class Track; + class TrackElement; + class RoutingEvent; + + +// ------------------------------------------------------------------- +// Class : "DataNegociate". + + + class DataNegociate { + public: + enum SlackState { RipupPerpandiculars = 1 + , Minimize = 2 + , Dogleg = 3 + , Slacken = 4 + , ConflictSolveByHistory = 5 + , ConflictSolveByPlaceds = 6 + , LocalVsGlobal = 7 + , MoveUp = 8 + , MaximumSlack = 9 + , Unimplemented =10 + , Repair =11 + }; + public: + DataNegociate ( TrackElement* ); + ~DataNegociate (); + inline bool hasRoutingEvent () const; + inline RoutingEvent* getRoutingEvent () const; + inline TrackElement* getTrackSegment () const; + inline TrackElement* getChildSegment () const; + inline Track* getTrack () const; + inline DbU::Unit getLeftMinExtend () const; + inline DbU::Unit getRightMinExtend () const; + inline unsigned int getTerminals () const; + inline Net* getNet () const; + inline unsigned int getState () const; + inline unsigned int getStateCount () const; + inline unsigned int getRipupCount () const; + inline unsigned int getStateAndRipupCount () const; + DbU::Unit getWiringDelta ( DbU::Unit axis ) const; + inline const vector& getPerpandiculars () const; + inline const Interval& getPerpandicularFree () const; + inline void setState ( unsigned int, unsigned int flags=0 ); + inline void setRoutingEvent ( RoutingEvent* ); + inline void setChildSegment ( TrackElement* ); + inline void setRipupCount ( unsigned int ); + inline void incRipupCount (); + inline void decRipupCount (); + inline void resetRipupCount (); + inline void resetStateCount (); + void update (); + static string getStateString ( DataNegociate* ); + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + protected: + // Attributes. + TrackElement* _trackSegment; + TrackElement* _childSegment; + RoutingEvent* _routingEvent; + Net* _net; + unsigned int _state : 5; + unsigned int _stateCount : 5; + unsigned int _terminals : 5; + unsigned int _ripupCount : 16; + DbU::Unit _leftMinExtend; + DbU::Unit _rightMinExtend; + vector _attractors; + vector _perpandiculars; + Interval _perpandicularFree; + Interval _reduceRanges[2]; + private: + DataNegociate ( const DataNegociate& ); + DataNegociate& operator= ( const DataNegociate& ); + }; + + +// Inline Functions. + inline bool DataNegociate::hasRoutingEvent () const { return _routingEvent != NULL; } + inline RoutingEvent* DataNegociate::getRoutingEvent () const { return _routingEvent; } + inline TrackElement* DataNegociate::getTrackSegment () const { return _trackSegment; } + inline TrackElement* DataNegociate::getChildSegment () const { return _childSegment; } + inline Track* DataNegociate::getTrack () const { return _trackSegment->getTrack(); } + inline unsigned int DataNegociate::getState () const { return _state; } + inline unsigned int DataNegociate::getTerminals () const { return _terminals; } + inline unsigned int DataNegociate::getRipupCount () const { return _ripupCount; } + inline DbU::Unit DataNegociate::getLeftMinExtend () const { return _leftMinExtend; } + inline DbU::Unit DataNegociate::getRightMinExtend () const { return _rightMinExtend; } + inline Net* DataNegociate::getNet () const { return _net; } + inline const vector& DataNegociate::getPerpandiculars () const { return _perpandiculars; } + inline const Interval& DataNegociate::getPerpandicularFree () const { return _perpandicularFree; } + inline unsigned int DataNegociate::getStateCount () const { return _stateCount; } + inline void DataNegociate::resetStateCount () { _stateCount=0; } + inline void DataNegociate::setRoutingEvent ( RoutingEvent* event ) { _routingEvent = event; } + inline void DataNegociate::setChildSegment ( TrackElement* child ) { _childSegment = child; } + inline void DataNegociate::setRipupCount ( unsigned int count ) { _ripupCount = count; } + inline void DataNegociate::incRipupCount () { _ripupCount++; } + inline void DataNegociate::decRipupCount () { if (_ripupCount) _ripupCount--; } + inline void DataNegociate::resetRipupCount () { _ripupCount = 0; } + inline string DataNegociate::_getTypeName () const { return "DataNegociate"; } + + inline void DataNegociate::setState ( unsigned int state, unsigned int flags ) + { + if ( (_state != state) or (flags & Flags::ResetCount) ) { + //std::cerr << "Changing state to:" << state << std::endl; + _state = state; + _stateCount = 1; + } else + _stateCount++; + } + + inline unsigned int DataNegociate::getStateAndRipupCount () const + { return (_state << 4) + _ripupCount; } + + +} // Katana namespace. + +#endif // KATANA_DATA_NEGOCIATE_H diff --git a/katana/src/katana/GraphicKatanaEngine.h b/katana/src/katana/GraphicKatanaEngine.h new file mode 100644 index 00000000..29432356 --- /dev/null +++ b/katana/src/katana/GraphicKatanaEngine.h @@ -0,0 +1,89 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/GraphicKatanaEngine.h" | +// +-----------------------------------------------------------------+ + + + +#ifndef KATANA_GRAPHIC_KATANA_ENGINE_H +#define KATANA_GRAPHIC_KATANA_ENGINE_H + +#include +#include + +namespace Hurricane { + class Go; + class BasicLayer; + class Transformation; + class CellWidget; + class CellViewer; +} + +#include "crlcore/GraphicToolEngine.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + + using Hurricane::Go; + using Hurricane::Box; + using Hurricane::BasicLayer; + using Hurricane::Transformation; + using Hurricane::CellWidget; + using Hurricane::CellViewer; + using CRL::GraphicTool; + + +// ------------------------------------------------------------------- +// Class : "Katana::GraphicKatanaEngine". + + class GraphicKatanaEngine : public GraphicTool { + Q_OBJECT; + + public: + enum FunctionFlags { NoFlags=0x0000, CreateEngine=0x0001 }; + public: + KatanaEngine* createEngine (); + KatanaEngine* getForFramework ( unsigned int flags ); + static GraphicKatanaEngine* grab (); + virtual const Name& getName () const; + Cell* getCell (); + virtual size_t release (); + virtual void addToMenu ( CellViewer* ); + void postEvent (); + protected: + static size_t _references; + static GraphicKatanaEngine* _singleton; + CellViewer* _viewer; + protected: + GraphicKatanaEngine (); + virtual ~GraphicKatanaEngine (); + void _wipeoutRouting (); + void _route (); + void _loadGlobalSolution (); + void _saveGlobalSolution (); + void _globalRoute (); + void _loadGlobalRouting (); + void _balanceGlobalDensity (); + void _runNegociatePreRouted (); + void _runNegociate (); + void _detailRoute (); + void _finalize (); + void _save (); + void _dumpMeasures (); + }; + + +} // Katana namespace. + +#endif // KATANA_GRAPHIC_KATANA_ENGINE_H diff --git a/katana/src/katana/HorizontalTrack.h b/katana/src/katana/HorizontalTrack.h new file mode 100644 index 00000000..f4d769f5 --- /dev/null +++ b/katana/src/katana/HorizontalTrack.h @@ -0,0 +1,56 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/HorizontalTrack.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_HORIZONTAL_TRACK_H +#define KATANA_HORIZONTAL_TRACK_H + +#include "katana/Track.h" + + +namespace Katana { + + +// ------------------------------------------------------------------- +// Class : "HorizontalTrack". + + class HorizontalTrack : public Track { + + public: + static HorizontalTrack* create ( RoutingPlane*, unsigned int index ); + virtual bool isHorizontal () const; + virtual bool isVertical () const; + virtual Flags getDirection () const; + virtual Point getPosition ( DbU::Unit coordinate ) const; + virtual string _getTypeName () const; + virtual Record* _getRecord () const; + + protected: + // Constructors & Destructors. + HorizontalTrack ( RoutingPlane*, unsigned int index ); + virtual ~HorizontalTrack (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + HorizontalTrack ( const HorizontalTrack& ); + HorizontalTrack& operator= ( const HorizontalTrack& ); + }; + + +} // Katana namespace. + + +#endif // KATANA_HORIZONTAL_TRACK_H diff --git a/katana/src/katana/KatanaEngine.h b/katana/src/katana/KatanaEngine.h new file mode 100644 index 00000000..795f5504 --- /dev/null +++ b/katana/src/katana/KatanaEngine.h @@ -0,0 +1,180 @@ +// -*- 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 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++ Header : "./katana/KatanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_KATANA_ENGINE_H +#define KATANA_KATANA_ENGINE_H + +#include + +#include "hurricane/Name.h" +namespace Hurricane { + class Layer; + class Net; + class Cell; + class CellViewer; +} + +#include "crlcore/RoutingGauge.h" +#include "anabatic/AnabaticEngine.h" + +namespace Knik { + class KnikEngine; +} + +#include "katana/Constants.h" +#include "katana/TrackElement.h" +#include "katana/Configuration.h" + + +namespace Katana { + + using Hurricane::Name; + using Hurricane::Layer; + using Hurricane::Net; + using Hurricane::Cell; + using Hurricane::CellViewer; + using CRL::RoutingGauge; + using Anabatic::AnabaticEngine; + + class Track; + class RoutingPlane; + class NegociateWindow; + + +// ------------------------------------------------------------------- +// Class : "Katana::KatanaEngine". + + class KatanaEngine : public AnabaticEngine { + public: + typedef AnabaticEngine Super; + public: + static const Name& staticGetName (); + static KatanaEngine* create ( Cell* ); + static KatanaEngine* get ( const Cell* ); + public: + inline bool useClockTree () const; + inline CellViewer* getViewer () const; + inline AnabaticEngine* base (); + inline Configuration* getKatanaConfiguration (); + virtual Configuration* getConfiguration (); + inline bool getToolSuccess () const; + inline unsigned long getEventsLimit () const; + inline unsigned int getRipupLimit ( unsigned int type ) const; + unsigned int getRipupLimit ( const TrackElement* ) const; + inline unsigned int getRipupCost () const; + inline size_t getHTracksReservedLocal () const; + inline size_t getVTracksReservedLocal () const; + virtual const Name& getName () const; + inline Configuration::PostEventCb_t& + getPostEventCb (); + inline NegociateWindow* getNegociateWindow (); + inline size_t getRoutingPlanesSize () const; + RoutingPlane* getRoutingPlaneByIndex ( size_t index ) const; + RoutingPlane* getRoutingPlaneByLayer ( const Layer* ) const; + Track* getTrackByPosition ( const Layer*, DbU::Unit axis, unsigned int mode=Constant::Nearest ) const; + inline void printConfiguration () const; + void printCompletion () const; + void dumpMeasures ( std::ostream& ) const; + void dumpMeasures () const; + virtual void openSession (); + inline void setViewer ( CellViewer* ); + inline void setPostEventCb ( Configuration::PostEventCb_t ); + inline void setEventLimit ( unsigned long ); + inline void setMinimumWL ( double ); + inline void setRipupLimit ( unsigned int type, unsigned int ); + inline void setRipupCost ( unsigned int ); + inline void setHTracksReservedLocal ( size_t ); + inline void setVTracksReservedLocal ( size_t ); + void setupPowerRails (); + void protectRoutingPads (); + void preProcess (); + void setInterrupt ( bool ); + void setupGlobalGraph ( unsigned int mode ); + void annotateGlobalGraph (); + void setFixedPreRouted (); + void runNegociate ( unsigned int flags=Flags::NoFlags ); + void runGlobalRouter (); + virtual void finalizeLayout (); + void _runKatanaInit (); + void _gutKatana (); + void _computeCagedConstraints (); + TrackElement* _lookup ( Segment* ) const; + inline TrackElement* _lookup ( AutoSegment* ) const; + bool _check ( unsigned int& overlap, const char* message=NULL ) const; + void _check ( Net* ) const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + private: + // Attributes. + static Name _toolName; + protected: + CellViewer* _viewer; + Configuration* _configuration; + vector _routingPlanes; + NegociateWindow* _negociateWindow; + double _minimumWL; + mutable bool _toolSuccess; + protected: + // Constructors & Destructors. + KatanaEngine ( Cell* ); + virtual ~KatanaEngine (); + virtual void _postCreate (); + virtual void _preDestroy (); + void _initDataBase (); + private: + KatanaEngine ( const KatanaEngine& ); + KatanaEngine& operator= ( const KatanaEngine& ); + }; + + +// Inline Functions. + inline bool KatanaEngine::useClockTree () const { return _configuration->useClockTree(); } + inline CellViewer* KatanaEngine::getViewer () const { return _viewer; } + inline AnabaticEngine* KatanaEngine::base () { return static_cast(this); } + inline Configuration* KatanaEngine::getKatanaConfiguration () { return _configuration; } + inline Configuration::PostEventCb_t& KatanaEngine::getPostEventCb () { return _configuration->getPostEventCb(); } + inline bool KatanaEngine::getToolSuccess () const { return _toolSuccess; } + inline unsigned long KatanaEngine::getEventsLimit () const { return _configuration->getEventsLimit(); } + inline unsigned int KatanaEngine::getRipupCost () const { return _configuration->getRipupCost(); } + inline size_t KatanaEngine::getHTracksReservedLocal () const { return _configuration->getHTracksReservedLocal(); } + inline size_t KatanaEngine::getVTracksReservedLocal () const { return _configuration->getVTracksReservedLocal(); } + inline unsigned int KatanaEngine::getRipupLimit ( unsigned int type ) const { return _configuration->getRipupLimit(type); } + inline NegociateWindow* KatanaEngine::getNegociateWindow () { return _negociateWindow; } + inline size_t KatanaEngine::getRoutingPlanesSize () const { return _routingPlanes.size(); } + inline void KatanaEngine::setViewer ( CellViewer* viewer ) { _viewer=viewer; } + inline void KatanaEngine::setEventLimit ( unsigned long limit ) { _configuration->setEventsLimit(limit); } + inline void KatanaEngine::setRipupLimit ( unsigned int type, unsigned int limit ) { _configuration->setRipupLimit(limit,type); } + inline void KatanaEngine::setRipupCost ( unsigned int cost ) { _configuration->setRipupCost(cost); } + inline void KatanaEngine::setHTracksReservedLocal ( size_t reserved ) { _configuration->setHTracksReservedLocal(reserved); } + inline void KatanaEngine::setVTracksReservedLocal ( size_t reserved ) { _configuration->setVTracksReservedLocal(reserved); } + inline void KatanaEngine::setMinimumWL ( double minimum ) { _minimumWL = minimum; } + inline void KatanaEngine::setPostEventCb ( Configuration::PostEventCb_t cb ) { _configuration->setPostEventCb(cb); } + inline void KatanaEngine::printConfiguration () const { _configuration->print(getCell()); } + inline TrackElement* KatanaEngine::_lookup ( AutoSegment* segment ) const { return segment->getObserver(AutoSegment::Observable::TrackSegment); } + + +// Variables. + extern const char* missingRW; + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::KatanaEngine); + + +#endif // KATANA_KATANA_ENGINE_H diff --git a/katana/src/katana/Manipulator.h b/katana/src/katana/Manipulator.h new file mode 100644 index 00000000..348944f9 --- /dev/null +++ b/katana/src/katana/Manipulator.h @@ -0,0 +1,103 @@ +// -*- 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 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++ Header : "./katana/Manipulator.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_MANIPULATOR_H +#define KATANA_MANIPULATOR_H + +#include "hurricane/DbU.h" +#include "anabatic/Constants.h" + + +namespace Katana { + + using Hurricane::DbU; + + class TrackElement; + class DataNegociate; + class RoutingEvent; + class SegmentFsm; + + +// ------------------------------------------------------------------- +// Class Declaration : "::Manipulator". + + class Manipulator { + public: + enum FunctionFlag { ToRipupLimit = 0x0001 + , AllowExpand = 0x0002 + , NoExpand = 0x0004 + , PerpandicularsFirst = 0x0008 + , ToMoveUp = 0x0010 + , AllowLocalMoveUp = 0x0020 + , AllowTerminalMoveUp = 0x0040 + , AllowShortPivotUp = 0x0080 + , NoDoglegReuse = 0x0100 + , LeftAxisHint = 0x0200 + , RightAxisHint = 0x0400 + , NotOnLastRipup = 0x0800 + }; + public: + Manipulator ( TrackElement*, SegmentFsm& ); + ~Manipulator (); + inline TrackElement* getSegment () const; + inline DataNegociate* getData () const; + inline RoutingEvent* getEvent () const; + inline const Layer* getLayer () const; + inline DbU::Unit getPitch () const; + inline DbU::Unit getPPitch () const; + bool canRipup ( unsigned int flags=0 ) const; + bool isCaged ( DbU::Unit ) const; + bool ripup ( unsigned int type, DbU::Unit axisHint=0 ); + bool ripupPerpandiculars ( unsigned int flags=0 ); + void repackPerpandiculars (); + void reprocessPerpandiculars (); + bool ripple (); + bool minimize (); + bool slacken ( unsigned int flags=Flags::NoFlags ); + bool pivotUp (); + bool pivotDown (); + bool moveUp ( unsigned int flags=0 ); + bool makeDogleg (); + bool makeDogleg ( DbU::Unit ); + bool makeDogleg ( Interval ); + bool relax ( Interval, unsigned int flags=AllowExpand ); + bool insertInTrack ( size_t ); + bool shrinkToTrack ( size_t + , unsigned int flags=0 + , DbU::Unit leftAxisHint=0 + , DbU::Unit rightAxisHint=0 + ); + bool forceToTrack ( size_t ); + bool forceOverLocals (); + private: + TrackElement* _segment; + DataNegociate* _data; + RoutingEvent* _event; + SegmentFsm& _fsm; + }; + + + inline TrackElement* Manipulator::getSegment () const { return _segment; } + inline DataNegociate* Manipulator::getData () const { return _data; } + inline RoutingEvent* Manipulator::getEvent () const { return _event; } + inline const Layer* Manipulator::getLayer () const { return _segment->getLayer(); } + inline DbU::Unit Manipulator::getPitch () const { return _segment->getPitch(); } + inline DbU::Unit Manipulator::getPPitch () const { return _segment->getPPitch(); } + + +} // Katana namespace. + +#endif // KATANA_MANIPULATOR_H diff --git a/katana/src/katana/NegociateWindow.h b/katana/src/katana/NegociateWindow.h new file mode 100644 index 00000000..3aa8eb18 --- /dev/null +++ b/katana/src/katana/NegociateWindow.h @@ -0,0 +1,160 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/NegociateWindow.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_NEGOCIATE_WINDOW_H +#define KATANA_NEGOCIATE_WINDOW_H + +#include +#include +#include + +namespace Hurricane { + class Cell; +} + +#include "katana/RoutingEventQueue.h" +#include "katana/RoutingEventHistory.h" +#include "katana/RoutingEventLoop.h" + + +namespace Katana { + + class TrackElement; + class KatanaEngine; + + +// ------------------------------------------------------------------- +// Class : "Statistics". + + class Statistics { + public: + inline Statistics (); + inline size_t getGCellsCount () const; + inline size_t getSegmentsCount () const; + inline size_t getEventsCount () const; + inline void setGCellsCount ( size_t ); + inline void setSegmentsCount ( size_t ); + inline void setEventsCount ( size_t ); + inline void incGCellCount ( size_t ); + inline void incSegmentsCount ( size_t ); + inline void incEventsCount ( size_t ); + inline Statistics& operator+= ( const Statistics& ); + private: + size_t _gcellsCount; + size_t _segmentsCount; + size_t _eventsCount; + + }; + + + inline Statistics::Statistics () + : _gcellsCount (0) + , _segmentsCount (0) + , _eventsCount (0) + { } + + inline size_t Statistics::getGCellsCount () const { return _gcellsCount; } + inline size_t Statistics::getSegmentsCount () const { return _segmentsCount; } + inline size_t Statistics::getEventsCount () const { return _eventsCount; } + inline void Statistics::setGCellsCount ( size_t count ) { _gcellsCount = count; } + inline void Statistics::setSegmentsCount ( size_t count ) { _segmentsCount = count; } + inline void Statistics::setEventsCount ( size_t count ) { _eventsCount = count; } + inline void Statistics::incGCellCount ( size_t count ) { _gcellsCount += count; } + inline void Statistics::incSegmentsCount ( size_t count ) { _segmentsCount += count; } + inline void Statistics::incEventsCount ( size_t count ) { _eventsCount += count; } + + inline Statistics& Statistics::operator+= ( const Statistics& other ) + { + _gcellsCount += other._gcellsCount; + _segmentsCount += other._segmentsCount; + _eventsCount += other._eventsCount; + return *this; + } + + +// ------------------------------------------------------------------- +// Class : "Katana::NegociateWindow". + + class NegociateWindow { + + public: + enum Stage { Negociation = 1 + , Packing = 2 + }; + public: + static NegociateWindow* create ( KatanaEngine* ); + void destroy (); + inline bool isInterrupted () const; + inline KatanaEngine* getKatanaEngine () const; + Hurricane::Cell* getCell () const; + inline const vector& getGCells () const; + inline RoutingEventQueue& getEventQueue (); + inline RoutingEventHistory& getEventHistory (); + inline RoutingEventLoop& getEventLoop (); + inline Stage getStage () const; + void setGCells ( const vector& ); + inline void setInterrupt ( bool ); + inline void setStage ( Stage ); + double computeWirelength (); + TrackElement* createTrackSegment ( AutoSegment*, unsigned int flags ); + void addRoutingEvent ( TrackElement*, unsigned int level ); + inline void rescheduleEvent ( RoutingEvent*, unsigned int level ); + void run ( unsigned int flags ); + void printStatistics () const; + void _createRouting ( Anabatic::GCell* ); + void _pack ( size_t& count, bool last ); + size_t _negociate (); + Hurricane::Record* _getRecord () const; + std::string _getString () const; + inline std::string _getTypeName () const; + + private: + // Attributes. + unsigned int _flags; + bool _interrupt; + KatanaEngine* _katana; + vector _gcells; + std::vector _segments; + RoutingEventQueue _eventQueue; + RoutingEventHistory _eventHistory; + RoutingEventLoop _eventLoop; + Statistics _statistics; + + // Constructors. + protected: + NegociateWindow ( KatanaEngine* ); + ~NegociateWindow (); + private: + NegociateWindow ( const NegociateWindow& ); + NegociateWindow& operator= ( const NegociateWindow& ); + }; + + +// Inline Functions. + inline bool NegociateWindow::isInterrupted () const { return _interrupt; } + inline KatanaEngine* NegociateWindow::getKatanaEngine () const { return _katana; } + inline const vector& NegociateWindow::getGCells () const { return _gcells; } + inline RoutingEventQueue& NegociateWindow::getEventQueue () { return _eventQueue; } + inline RoutingEventHistory& NegociateWindow::getEventHistory () { return _eventHistory; } + inline void NegociateWindow::setInterrupt ( bool state ) { _interrupt = state; } + inline void NegociateWindow::rescheduleEvent ( RoutingEvent* event, unsigned int level ) { event->reschedule(_eventQueue,level); } + inline std::string NegociateWindow::_getTypeName () const { return "NegociateWindow"; } + + +} // Katana namespace. + + +#endif // KATANA_NEGOCIATE_WINDOW_H diff --git a/katana/src/katana/PyGraphicKatanaEngine.h b/katana/src/katana/PyGraphicKatanaEngine.h new file mode 100644 index 00000000..d228219e --- /dev/null +++ b/katana/src/katana/PyGraphicKatanaEngine.h @@ -0,0 +1,55 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2012-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/PyGraphicKatanaEngine.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_PY_GRAPHIC_KATANA_ENGINE_H +#define KATANA_PY_GRAPHIC_KATANA_ENGINE_H + +#include "crlcore/PyGraphicToolEngine.h" +#include "katana/GraphicKatanaEngine.h" + + +namespace Katana { + +extern "C" { + + +// ------------------------------------------------------------------- +// Python Object : "PyGraphicKatanaEngine". + + typedef struct { + CRL::PyGraphicTool _baseObject; + } PyGraphicKatanaEngine; + + +// ------------------------------------------------------------------- +// Functions & Types exported to "PyKatana.ccp". + + extern PyTypeObject PyTypeGraphicKatanaEngine; + extern PyMethodDef PyGraphicKatanaEngine_Methods[]; + + extern void PyGraphicKatanaEngine_LinkPyType (); + + +#define IsPyGraphicKatanaEngine(v) ( (v)->ob_type == &PyTypeGraphicKatanaEngine ) +#define PY_GRAPHIC_KATANA_ENGINE(v) ( (PyGraphicKatanaEngine*)(v) ) +#define PY_GRAPHIC_KATANA_ENGINE_O(v) ( PY_GRAPHIC_KATANA_ENGINE(v)->_baseObject._object ) + + +} // extern "C". + +} // Katana namespace. + +#endif // KATANA_PY_GRAPHIC_KATANA_ENGINE_H diff --git a/katana/src/katana/PyKatanaEngine.h b/katana/src/katana/PyKatanaEngine.h new file mode 100644 index 00000000..ba20339f --- /dev/null +++ b/katana/src/katana/PyKatanaEngine.h @@ -0,0 +1,57 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2010-2016, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/PyKatanaEngine.cpp" | +// +-----------------------------------------------------------------+ + + +#ifndef PY_KATANA_ENGINE_H +#define PY_KATANA_ENGINE_H + +#include "hurricane/isobar/PyHurricane.h" +#include "crlcore/PyToolEngine.h" +#include "katana/KatanaEngine.h" + + +namespace Katana { + +extern "C" { + + +// ------------------------------------------------------------------- +// Python Object : "PyKatanaEngine". + + typedef struct { + CRL::PyToolEngine _baseObject; + } PyKatanaEngine; + + +// ------------------------------------------------------------------- +// Functions & Types exported to "PyKatana.ccp". + + extern PyTypeObject PyTypeKatanaEngine; + extern PyMethodDef PyKatanaEngine_Methods[]; + + extern PyObject* PyKatanaEngine_Link ( Katana::KatanaEngine* ); + extern void PyKatanaEngine_LinkPyType (); + + +#define IsPyKatanaEngine(v) ( (v)->ob_type == &PyTypeKatanaEngine ) +#define PYKATANAENGINE(v) ( (PyKatanaEngine*)(v) ) +#define PYKATANAENGINE_O(v) ( PYKATANAENGINE(v)->_baseObject._object ) + + +} // extern "C". + +} // Katana namespace. + +#endif // PY_KATANA_ENGINE_H diff --git a/katana/src/katana/RoutingEvent.h b/katana/src/katana/RoutingEvent.h new file mode 100644 index 00000000..74a2a72c --- /dev/null +++ b/katana/src/katana/RoutingEvent.h @@ -0,0 +1,286 @@ +// -*- 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 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++ Header : "./katana/RoutingEvent.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_ROUTING_EVENT_H +#define KATANA_ROUTING_EVENT_H + +#include +#include +#include +#include + +#include "hurricane/Interval.h" +namespace Hurricane { + class Net; +} + +#include "katana/TrackCost.h" +#include "katana/TrackElement.h" +#include "katana/DataNegociate.h" +#include "katana/Session.h" + + +namespace Katana { + + using std::set; + using std::vector; + using std::binary_function; + using Hurricane::DbU; + using Hurricane::Interval; + using Hurricane::Net; + class TrackElement; + class Track; + class RoutingEventHistory; + class RoutingEventQueue; + class RoutingEventLoop; + + +// ------------------------------------------------------------------- +// Class : "RoutingEvent". + + class RoutingEvent { + + private: + class Key { + public: + class Compare : public binary_function { + public: + bool operator() ( const Key& lhs, const Key& rhs ) const; + }; + + public: + Key ( const RoutingEvent* ); + void update ( const RoutingEvent* ); + private: + unsigned int _tracksNb:6; + float _priority; + unsigned int _eventLevel; + unsigned int _segFlags; + unsigned int _layerDepth; + DbU::Unit _length; + DbU::Unit _axis; + DbU::Unit _sourceU; + Net* _net; + unsigned long _id; + friend class Compare; + }; + + public: + // Sub-Class: "Compare". + class Compare : public binary_function { + public: + bool operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const; + }; + // Sub-Class: "CompareById". + class CompareById : public binary_function { + public: + inline bool operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const; + }; + friend class Compare; + + public: + enum Mode { Negociate=1, Pack=2, Repair=3 }; + + public: + static unsigned int getStage (); + static size_t getAllocateds (); + static size_t getProcesseds (); + static size_t getCloneds (); + static void resetProcesseds (); + static void setStage ( unsigned int ); + public: + static RoutingEvent* create ( TrackElement*, unsigned int mode=Negociate ); + RoutingEvent* clone () const; + void destroy (); + inline bool isCloned () const; + inline bool isValid () const; + bool isUnimplemented () const; + inline bool isProcessed () const; + inline bool isDisabled () const; + inline bool isForcedToHint () const; + inline bool isSheared () const; + inline bool isRipedByLocal () const; + inline bool isOverConstrained () const; + inline unsigned int getId () const; + inline unsigned int getTimeStamp () const; + inline bool getMode () const; + inline bool canMinimize () const; + unsigned int getState () const; + inline const Key& getKey () const; + inline TrackElement* getSegment () const; + inline const vector& getPerpandiculars () const; + inline DbU::Unit getAxisHint () const; + inline DbU::Unit getAxisHistory () const; + inline long getAxisWeight ( DbU::Unit ) const; + inline const Interval& getConstraints () const; + inline const Interval& getOptimal () const; + inline const Interval& getPerpandicularFree () const; + inline float getPriority () const; + inline unsigned int getTracksNb () const; + inline unsigned int getTracksFree () const; + inline unsigned int getInsertState () const; + inline unsigned int getEventLevel () const; + void revalidate (); + inline void updateKey (); + void process ( RoutingEventQueue& + , RoutingEventHistory& + , RoutingEventLoop& + ); + void setSegment ( TrackElement* ); + RoutingEvent* reschedule ( RoutingEventQueue&, unsigned int eventLevel ); + void setMode ( unsigned int ); + void setState ( unsigned int ); + inline void setTimeStamp ( unsigned int ); + inline void setProcessed ( bool state=true ); + inline void setDisabled ( bool state=true ); + inline void setMinimized ( bool state=true ); + inline void setRipedByLocal ( bool state=true ); + inline void setTracksFree ( unsigned int ); + inline void setForcedToHint ( bool state = true ); + void setAxisHint ( DbU::Unit ); + void setAxisHintFromParent (); + inline void incInsertState (); + inline void resetInsertState (); + inline void setEventLevel ( unsigned int ); + void _processNegociate ( RoutingEventQueue&, RoutingEventHistory& ); + void _processPack ( RoutingEventQueue&, RoutingEventHistory& ); + void _processRepair ( RoutingEventQueue&, RoutingEventHistory& ); + Record* _getRecord () const; + string _getString () const; + string _getTypeName () const; + private: + RoutingEvent ( TrackElement*, unsigned int mode ); + ~RoutingEvent (); + + protected: + // Attributes. + static unsigned int _idCounter; + static unsigned int _stage; + static size_t _allocateds; + static size_t _processeds; + static size_t _cloneds; + mutable bool _cloned; + bool _processed; + bool _disabled; + bool _overConstrained; + bool _minimized; + bool _forceToHint; + bool _ripedByLocal; + unsigned int _id; + unsigned int _timeStamp; + TrackElement* _segment; + DataNegociate* _dataNegociate; + DbU::Unit _axisHistory; + DbU::Unit _axisHint; + Interval _constraints; + Interval _optimal; + //Interval _perpandicular; + unsigned int _tracksNb : 6; + unsigned int _tracksFree : 4; + unsigned int _insertState : 6; + unsigned int _mode : 4; + unsigned int _rippleState : 4; + unsigned int _eventLevel; + float _priority; + //vector _perpandiculars; + Key _key; + }; + + +// Inline Functions. + inline bool RoutingEvent::isCloned () const { return _cloned; } + inline bool RoutingEvent::isProcessed () const { return _processed; } + inline bool RoutingEvent::isDisabled () const { return _disabled; } + inline bool RoutingEvent::isForcedToHint () const { return _forceToHint; } + inline bool RoutingEvent::isRipedByLocal () const { return _ripedByLocal; } + inline bool RoutingEvent::isOverConstrained () const { return _overConstrained; } + inline unsigned int RoutingEvent::getId () const { return _id; } + inline unsigned int RoutingEvent::getTimeStamp () const { return _timeStamp; } + inline bool RoutingEvent::getMode () const { return _mode; } + inline bool RoutingEvent::canMinimize () const { return not _minimized; } + inline const RoutingEvent::Key& RoutingEvent::getKey () const { return _key; } + inline TrackElement* RoutingEvent::getSegment () const { return _segment; } + inline const vector& RoutingEvent::getPerpandiculars () const { return _dataNegociate->getPerpandiculars(); } +//inline const vector& RoutingEvent::getPerpandiculars () const { return _perpandiculars; } + inline DbU::Unit RoutingEvent::getAxisHistory () const { return _axisHistory; } + inline DbU::Unit RoutingEvent::getAxisHint () const { return _axisHint; } + inline long RoutingEvent::getAxisWeight ( DbU::Unit axis ) const { return abs(axis - getAxisHint()); } + inline const Interval& RoutingEvent::getConstraints () const { return _constraints; } + inline const Interval& RoutingEvent::getOptimal () const { return _optimal; } + inline const Interval& RoutingEvent::getPerpandicularFree () const { return _dataNegociate->getPerpandicularFree(); } +//inline const Interval& RoutingEvent::getPerpandicular () const { return _perpandicular; } + inline float RoutingEvent::getPriority () const { return _priority; } + inline unsigned int RoutingEvent::getEventLevel () const { return _eventLevel; } + inline unsigned int RoutingEvent::getTracksNb () const { return _tracksNb; } + inline unsigned int RoutingEvent::getTracksFree () const { return _tracksFree; } + inline unsigned int RoutingEvent::getInsertState () const { return _insertState; } + inline void RoutingEvent::setTimeStamp ( unsigned int stamp ) { _timeStamp = stamp; } + inline void RoutingEvent::setProcessed ( bool state ) { _processed = state; } + inline void RoutingEvent::setDisabled ( bool state ) { _disabled = state; } + inline void RoutingEvent::setMinimized ( bool state ) { _minimized = state; } + inline void RoutingEvent::setRipedByLocal ( bool state ) { _ripedByLocal = state; } + inline void RoutingEvent::setTracksFree ( unsigned int nb ) { _tracksFree = nb; } + inline void RoutingEvent::setForcedToHint ( bool state ) { _forceToHint = state; } + inline void RoutingEvent::incInsertState () { _insertState++; } + inline void RoutingEvent::resetInsertState () { _insertState = 0; } + inline void RoutingEvent::setEventLevel ( unsigned int level ) { _eventLevel = level; } + inline void RoutingEvent::updateKey () { revalidate(); _key.update(this); } + + inline bool RoutingEvent::CompareById::operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const + { return lhs->getId() < rhs->getId(); } + + + typedef set RoutingEventSet; + + +// ------------------------------------------------------------------- +// Macros. + + +# if !defined(NDEBUG) +# define _preCheck(segment) \ + DbU::Unit beforeMin = segment->base()->getSourcePosition(); \ + DbU::Unit beforeMax = segment->base()->getTargetPosition(); \ + segment->base()->checkPositions (); \ + if ( Session::getSegmentStackSize() ) \ + cerr << "[ERROR] Session Segment Stack is not empty (" \ + << Session::getSegmentStackSize() << ")." << endl; + +# define _postCheck(segment) \ + cdebug_log(159,0) << "Bounds := [" \ + << DbU::getValueString(segment->base()->getSourcePosition()) << ":" \ + << DbU::getValueString(segment->base()->getTargetPosition()) << "] " \ + << DbU::getValueString(segment->getAxis()) << " " \ + << segment->getTrack() << endl; \ + if ( beforeMin != segment->base()->getSourcePosition() ) \ + cerr << "[ERROR] " << segment \ + << " origin was " << DbU::getValueString(beforeMin) << endl; \ + if ( beforeMax != segment->base()->getTargetPosition() ) \ + cerr << "[ERROR] " << segment \ + << " extremity was " << DbU::getValueString(beforeMax) << endl; +# else +# define _preCheck(segment) ; +# define _postCheck(segment) ; +# endif + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::RoutingEvent); + + +#endif // KATANA_ROUTING_EVENT_H diff --git a/katana/src/katana/RoutingEventHistory.h b/katana/src/katana/RoutingEventHistory.h new file mode 100644 index 00000000..7ab600b7 --- /dev/null +++ b/katana/src/katana/RoutingEventHistory.h @@ -0,0 +1,71 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/RoutingEventHistory.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_ROUTING_EVENT_HISTORY_H +#define KATANA_ROUTING_EVENT_HISTORY_H + +#include +#include + + +namespace Katana { + + using std::vector; + using std::ostream; + + class RoutingEvent; + + +// ------------------------------------------------------------------- +// Class : "RoutingEventHistory". + + class RoutingEventHistory { + + public: + RoutingEventHistory (); + ~RoutingEventHistory (); + inline bool empty () const; + inline size_t size () const; + RoutingEvent* getNth ( size_t ) const; + RoutingEvent* getRNth ( size_t ) const; + void push ( RoutingEvent* ); + void clear (); + void dump ( ostream&, size_t depth=10 ) const; + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + + protected: + // Attributes. + vector _events; + + private: + RoutingEventHistory& operator= ( const RoutingEventHistory& ); + RoutingEventHistory ( const RoutingEventHistory& ); + + }; + + +// Inline Functions. + inline bool RoutingEventHistory::empty () const { return _events.empty(); } + inline size_t RoutingEventHistory::size () const { return _events.size(); } + inline string RoutingEventHistory::_getTypeName () const { return "RoutingEventHistory"; } + + +} // Katana namespace. + + +#endif // KATANA_ROUTING_EVENT_HISTORY_H diff --git a/katana/src/katana/RoutingEventLoop.h b/katana/src/katana/RoutingEventLoop.h new file mode 100644 index 00000000..b97e897f --- /dev/null +++ b/katana/src/katana/RoutingEventLoop.h @@ -0,0 +1,84 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/RoutingEventLoop.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_ROUTING_EVENT_LOOP_H +#define KATANA_ROUTING_EVENT_LOOP_H + +#include + + +namespace Katana { + + class RoutingEvent; + + +// ------------------------------------------------------------------- +// Class : "RoutingEventLoop". + + + class RoutingEventLoop { + public: + class Element { + public: + inline Element ( size_t id=0, size_t timestamp=0 ); + public: + size_t _id; + size_t _timestamp; + int _count; + }; + class CompareByTimestamp { + public: + inline bool operator() ( const Element& lhs, const Element& rhs ); + }; + public: + RoutingEventLoop ( size_t depth=10, int limit=20 ); + inline bool isLooping () const; + inline int getMaxCount () const; + inline const std::vector& getElements () const; + void update ( size_t id ); + void erase ( size_t id ); + private: + std::vector _elements; + size_t _depth; + int _maxCount; + int _countLimit; + bool _isLooping; + }; + + + inline RoutingEventLoop::Element::Element ( size_t id, size_t timestamp ) + : _id(id), _timestamp(timestamp), _count(1) + { } + + + inline bool RoutingEventLoop::CompareByTimestamp::operator() ( const RoutingEventLoop::Element& lhs, const RoutingEventLoop::Element& rhs ) + { return lhs._timestamp > rhs._timestamp; } + + + inline bool RoutingEventLoop::isLooping () const { return _isLooping; } + inline int RoutingEventLoop::getMaxCount () const { return _maxCount; } + inline const std::vector& + RoutingEventLoop::getElements () const { return _elements; } + + + +} // Katana namespace. + + +//INSPECTOR_P_SUPPORT(Katana::RoutingEvent); + + +#endif // KATANA_ROUTING_EVENT_LOOP_H diff --git a/katana/src/katana/RoutingEventQueue.h b/katana/src/katana/RoutingEventQueue.h new file mode 100644 index 00000000..fcf3257b --- /dev/null +++ b/katana/src/katana/RoutingEventQueue.h @@ -0,0 +1,82 @@ +// -*- 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 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++ Header : "./katana/RoutingEventQueue.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_ROUTING_EVENT_QUEUE_H +#define KATANA_ROUTING_EVENT_QUEUE_H + +#include +#include +#include "katana/RoutingEvent.h" + + +namespace Katana { + + using std::set; + using std::multiset; + using std::vector; + + +// ------------------------------------------------------------------- +// Class : "RoutingEventQueue". + + class RoutingEventQueue { + + public: + RoutingEventQueue (); + ~RoutingEventQueue (); + inline bool empty () const; + inline size_t size () const; + inline unsigned int getTopEventLevel () const; + RoutingEvent* pop (); + void load ( const vector& ); + void add ( TrackElement*, unsigned int level ); + inline void push ( RoutingEvent* ); + void repush ( RoutingEvent* ); + void repushInvalidateds (); + void commit (); + void prepareRepair (); + void clear (); + void dump () const; + void _keyCheck () const; + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + + protected: + // Attributes. + unsigned int _topEventLevel; + RoutingEventSet _pushRequests; + multiset _events; + + private: + RoutingEventQueue& operator= ( const RoutingEventQueue& ); + RoutingEventQueue ( const RoutingEventQueue& ); + + }; + + +// Inline Functions. + inline bool RoutingEventQueue::empty () const { return _events.empty(); } + inline size_t RoutingEventQueue::size () const { return _events.size(); } + inline unsigned int RoutingEventQueue::getTopEventLevel () const { return _topEventLevel; } + inline string RoutingEventQueue::_getTypeName () const { return "EventQueue"; } + inline void RoutingEventQueue::push ( RoutingEvent* event ) { _pushRequests.insert( event ); } + + +} // Katana namespace. + + +#endif // KATANA_ROUTING_EVENT_QUEUE_H diff --git a/katana/src/katana/RoutingPlane.h b/katana/src/katana/RoutingPlane.h new file mode 100644 index 00000000..dd604ed7 --- /dev/null +++ b/katana/src/katana/RoutingPlane.h @@ -0,0 +1,126 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/RoutingPlane.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_ROUTING_PLANE_H +#define KATANA_ROUTING_PLANE_H + +#include "crlcore/RoutingLayerGauge.h" +#include "katana/Track.h" + + +namespace Katana { + + using CRL::RoutingLayerGauge; + class KatanaEngine; + + +// ------------------------------------------------------------------- +// Class : "RoutingPlane". + + class RoutingPlane { + + public: + static RoutingPlane* create ( KatanaEngine*, size_t depth ); + void destroy (); + inline bool isHorizontal () const; + inline bool isVertical () const; + inline KatanaEngine* getKatanaEngine () const; + inline RoutingLayerGauge* getLayerGauge () const; + inline unsigned int getDirection () const; + inline size_t getDepth () const; + inline DbU::Unit getAxisMin () const; + inline DbU::Unit getAxisMax () const; + inline DbU::Unit getTrackMin () const; + inline DbU::Unit getTrackMax () const; + RoutingPlane* getTop () const; + RoutingPlane* getBottom () const; + inline const Layer* getLayer () const; + inline const Layer* getBlockageLayer () const; + inline size_t getTracksSize () const; + inline size_t computeTracksSize () const; + inline DbU::Unit getTrackPosition ( size_t index ) const; + Track* getTrackByIndex ( size_t index ) const; + Track* getTrackByPosition ( DbU::Unit axis, unsigned int mode=Flags::Nearest ) const; + bool _check ( unsigned int& overlaps ) const; + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + + protected: + // Sub-Class: TrackCompare. + struct TrackCompare { + inline bool operator() ( Track* track1, Track* track2 ); + }; + + protected: + // Attributes. + KatanaEngine* _katana; + RoutingLayerGauge* _layerGauge; + size_t _depth; + unsigned int _flags; + DbU::Unit _axisMin; + DbU::Unit _axisMax; + DbU::Unit _trackMin; + DbU::Unit _trackMax; + vector _tracks; + + protected: + // Constructors & Destructors. + RoutingPlane ( KatanaEngine*, size_t depth ); + ~RoutingPlane (); + private: + RoutingPlane ( const RoutingPlane& ); + RoutingPlane& operator= ( const RoutingPlane& ); + }; + + +// Inline Functions. + inline bool RoutingPlane::TrackCompare::operator() ( Track* lhs, Track* rhs ) + { return lhs->getAxis() > rhs->getAxis(); }; + + inline KatanaEngine* RoutingPlane::getKatanaEngine () const { return _katana; } + inline RoutingLayerGauge* RoutingPlane::getLayerGauge () const { return _layerGauge; } + inline unsigned int RoutingPlane::getDirection () const { return _flags & Flags::DirectionMask; } + inline size_t RoutingPlane::getDepth () const { return _depth; } + inline DbU::Unit RoutingPlane::getAxisMin () const { return _axisMin; } + inline DbU::Unit RoutingPlane::getAxisMax () const { return _axisMax; } + inline DbU::Unit RoutingPlane::getTrackMin () const { return _trackMin; } + inline DbU::Unit RoutingPlane::getTrackMax () const { return _trackMax; } + inline const Layer* RoutingPlane::getLayer () const { return getLayerGauge()->getLayer(); } + inline const Layer* RoutingPlane::getBlockageLayer () const { return getLayerGauge()->getBlockageLayer(); } + inline size_t RoutingPlane::getTracksSize () const { return _tracks.size(); } + inline string RoutingPlane::_getTypeName () const { return "RoutingPlane"; } + + inline size_t RoutingPlane::computeTracksSize () const + { return _layerGauge->getTrackNumber(_axisMin,_axisMax); } + + inline DbU::Unit RoutingPlane::getTrackPosition ( size_t index ) const + { return _layerGauge->getTrackPosition(_axisMin,index); } + + inline bool RoutingPlane::isHorizontal () const + { return (getDirection() & Flags::Horizontal); } + + inline bool RoutingPlane::isVertical () const + { return (getDirection() & Flags::Vertical); } + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::RoutingPlane); + + +#endif // KATANA_ROUTING_PLANE_H diff --git a/katana/src/katana/SegmentFsm.h b/katana/src/katana/SegmentFsm.h new file mode 100644 index 00000000..6f09de75 --- /dev/null +++ b/katana/src/katana/SegmentFsm.h @@ -0,0 +1,185 @@ +// -*- 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 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++ Header : "./katana/SegmentFsm.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_SEGMENT_FSM_H +#define KATANA_SEGMENT_FSM_H + +#include "katana/TrackCost.h" + +namespace Katana { + + class TrackElement; + class DataNegociate; + class RoutingEvent; + class RoutingEventQueue; + class RoutingEventHistory; + + +// ------------------------------------------------------------------- +// Class : "SegmentAction". + + class SegmentAction { + public: + enum Type { Self = (1<< 0) + , Other = (1<< 1) + , Perpandicular = (1<< 2) + , Insert = (1<< 3) + , Ripup = (1<< 4) + , RipedByLocal = (1<< 5) + , ResetRipup = (1<< 6) + , ToRipupLimit = (1<< 7) + , MoveToAxis = (1<< 8) + , AxisHint = (1<< 9) + , PackingMode = (1<<10) + , ToState = (1<<11) + , EventLevel1 = (1<<12) + , EventLevel2 = (1<<13) + , EventLevel3 = (1<<14) + , EventLevel4 = (1<<15) + , EventLevel5 = (1<<16) + , SelfInsert = Self |Insert + , SelfRipup = Self |Ripup + , SelfRipupPerpand = Self |Ripup|Perpandicular + , SelfRipupPerpandWithAxisHint = Self |Ripup|Perpandicular|EventLevel4|AxisHint + , OtherRipup = Other|Ripup + , OtherRipupPerpandAndPushAside = Other|Ripup|Perpandicular|EventLevel3|AxisHint + , OtherRipupPerpandAndPacking = Other|Ripup|Perpandicular|EventLevel4|PackingMode + }; + public: + SegmentAction ( TrackElement* + , unsigned int type + , DbU::Unit axisHint=0 + , unsigned int toState =0 + ); + inline TrackElement* getSegment () const; + inline unsigned int getType () const; + inline void setAxisHint ( DbU::Unit ); + inline unsigned int setFlag ( unsigned int ); + bool doAction ( RoutingEventQueue& ); + private: + TrackElement* _segment; + unsigned int _type; + DbU::Unit _axisHint; + unsigned int _toState; + }; + + + inline TrackElement* SegmentAction::getSegment () const { return _segment; } + inline unsigned int SegmentAction::getType () const { return _type; } + inline void SegmentAction::setAxisHint ( DbU::Unit axis ) { _axisHint = axis; } + inline unsigned int SegmentAction::setFlag ( unsigned int flag ) { _type |= flag; return _type; } + + +// ------------------------------------------------------------------- +// Class : "SegmentFsm". + + class SegmentFsm { + + public: + enum State { MissingData = (1<<0) + , EmptyTrackList = (1<<1) + , Inserted = (1<<2) + , Self = (1<<3) + , Other = (1<<4) + , Ripup = (1<<5) + , MaximumSlack = (1<<6) + , SelfInserted = Self | Inserted + , OtherRipup = Other | Ripup + , SelfMaximumSlack = Self | MaximumSlack + }; + enum SlackenFlags { NoRecursive = (1<<0) + , NoTransition = (1<<1) + }; + + public: + SegmentFsm ( RoutingEvent* + , RoutingEventQueue& + , RoutingEventHistory& + ); + inline bool isFullBlocked () const; + inline RoutingEvent* getEvent () const; + inline RoutingEventQueue& getQueue () const; + inline RoutingEventHistory& getHistory () const; + inline unsigned int getState () const; + inline DataNegociate* getData (); + inline Interval& getConstraint (); + inline Interval& getOptimal (); + inline vector& getCosts (); + inline TrackCost& getCost ( size_t ); + inline Track* getTrack ( size_t ); + inline size_t getBegin ( size_t ); + inline size_t getEnd ( size_t ); + inline vector& getActions (); + inline void setState ( unsigned int ); + void addAction ( TrackElement* + , unsigned int type + , DbU::Unit axisHint=0 + , unsigned int toState =0 + ); + void doActions (); + inline void clearActions (); + bool insertInTrack ( size_t ); + bool conflictSolveByHistory (); + bool conflictSolveByPlaceds (); + bool solveTerminalVsGlobal (); + bool desaturate (); + bool slackenTopology ( unsigned int flags=0 ); + bool solveFullBlockages (); + private: + bool _slackenStrap ( TrackElement*& + , DataNegociate*& + , unsigned int flags ); + bool _slackenLocal ( TrackElement*& + , DataNegociate*& + , unsigned int flags ); + bool _slackenGlobal ( TrackElement*& + , DataNegociate*& + , unsigned int flags ); + private: + RoutingEvent* _event; + RoutingEventQueue& _queue; + RoutingEventHistory& _history; + unsigned int _state; + DataNegociate* _data; + Interval _constraint; + Interval _optimal; + vector _costs; + vector _actions; + bool _fullBlocked; + }; + + + inline bool SegmentFsm::isFullBlocked () const { return _fullBlocked and _costs.size(); } + inline RoutingEvent* SegmentFsm::getEvent () const { return _event; } + inline RoutingEventQueue& SegmentFsm::getQueue () const { return _queue; } + inline RoutingEventHistory& SegmentFsm::getHistory () const { return _history; } + inline unsigned int SegmentFsm::getState () const { return _state; } + inline DataNegociate* SegmentFsm::getData () { return _data; } + inline Interval& SegmentFsm::getConstraint () { return _constraint; } + inline Interval& SegmentFsm::getOptimal () { return _optimal; } + inline vector& SegmentFsm::getCosts () { return _costs; } + inline TrackCost& SegmentFsm::getCost ( size_t i ) { return _costs[i]; } + inline Track* SegmentFsm::getTrack ( size_t i ) { return _costs[i].getTrack(); } + inline size_t SegmentFsm::getBegin ( size_t i ) { return _costs[i].getBegin(); } + inline size_t SegmentFsm::getEnd ( size_t i ) { return _costs[i].getEnd(); } + inline vector& SegmentFsm::getActions () { return _actions; } + inline void SegmentFsm::setState ( unsigned int state ) { _state = state; } + inline void SegmentFsm::clearActions () { _actions.clear(); } + + +} // Katana namespace. + +#endif // KATANA_SEGMENT_FSM_H diff --git a/katana/src/katana/Session.h b/katana/src/katana/Session.h new file mode 100644 index 00000000..35f4cdca --- /dev/null +++ b/katana/src/katana/Session.h @@ -0,0 +1,182 @@ +// -*- mode: C++; explicit-buffer-name: "Session.h" -*- +// +// 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 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++ Header : "./katana/Session.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_SESSION_H +#define KATANA_SESSION_H + +#include +#include +#include + +namespace Hurricane { + class Record; + class Net; + class Segment; +} + +#include "anabatic/Session.h" +namespace Anabatic { + class GCell; + class AutoSegment; +} + + +namespace Katana { + + using std::set; + using std::vector; + using std::string; + using Hurricane::Record; + using Hurricane::Net; + using Hurricane::Segment; + using Hurricane::DbU; + using Anabatic::AutoSegment; + + class Track; + class TrackElement; + class TrackMarker; + class NegociateWindow; + class Configuration; + class KatanaEngine; + + +// ------------------------------------------------------------------- +// Class : "Session". + + class Session : public Anabatic::Session { + public: + typedef Anabatic::Session Super; + public: + static Session* get ( const char* message=NULL ); + inline static Super* base (); + inline static bool isEmpty (); + inline static KatanaEngine* getKatanaEngine (); + static Configuration* getConfiguration (); + inline static Net* getBlockageNet (); + inline static NegociateWindow* getNegociateWindow (); + inline static unsigned int getRipupCost (); + inline static Anabatic::GCell* getGCellUnder ( DbU::Unit, DbU::Unit ); + static void setInterrupt ( bool ); + inline static void addInsertEvent ( TrackMarker* , Track* ); + inline static void addInsertEvent ( TrackElement* , Track* ); + inline static void addRemoveEvent ( TrackElement* ); + inline static void addMoveEvent ( TrackElement* , Track* ); + inline static void addSortEvent ( Track*, bool forced=false ); + inline static size_t revalidate (); + static TrackElement* lookup ( Segment* ); + static TrackElement* lookup ( AutoSegment* ); + static Session* _open ( KatanaEngine* ); + private: + KatanaEngine* _getKatanaEngine (); + Net* _getBlockageNet (); + unsigned int _getRipupCost (); + Anabatic::GCell* _getGCellUnder ( DbU::Unit, DbU::Unit ); + void _doRemovalEvents (); + virtual size_t _revalidate (); + bool _isEmpty () const; + NegociateWindow* _getNegociateWindow (); + void _addInsertEvent ( TrackMarker* , Track* ); + void _addInsertEvent ( TrackElement* , Track* ); + void _addRemoveEvent ( TrackElement* ); + void _addMoveEvent ( TrackElement* , Track* ); + void _addSortEvent ( Track*, bool forced ); + virtual Record* _getRecord () const; + virtual string _getTypeName () const; + protected: + // Internal Classes. + class Event { + public: + inline Event ( TrackElement*, Track* ); + inline Event ( TrackMarker* , Track* ); + public: + TrackElement* _segment; + TrackMarker* _marker; + Track* _track; + }; + protected: + // Attributes. + vector _insertEvents; + vector _removeEvents; + set _sortEvents; + protected: + // Constructors & Destructors. + Session ( KatanaEngine* ); + virtual ~Session (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Session ( const Session& ); + Session& operator= ( const Session& ); + }; + + +// Inline Functions. + inline Session::Event::Event ( TrackElement* segment , Track* track ) + : _segment(segment) + , _marker (NULL) + , _track (track) + { } + + inline Session::Event::Event ( TrackMarker* marker , Track* track ) + : _segment(NULL) + , _marker (marker) + , _track (track) + { } + + + inline Session::Super* Session::base () + { return static_cast(get("base()")); } + + inline KatanaEngine* Session::getKatanaEngine () + { return get("getKatanaEngine()")->_getKatanaEngine(); } + + inline Net* Session::getBlockageNet () + { return get("getBlockageNet()")->_getBlockageNet(); } + + inline NegociateWindow* Session::getNegociateWindow () + { return get("getNegociateWindow()")->_getNegociateWindow(); } + + inline unsigned int Session::getRipupCost () + { return get("getRipupCost()")->_getRipupCost(); } + + inline Anabatic::GCell* Session::getGCellUnder ( DbU::Unit x, DbU::Unit y ) + { return get("getGCellUnder()")->_getGCellUnder(x,y); } + + inline void Session::addInsertEvent ( TrackMarker* marker, Track* track ) + { get("addInsertEvent(TrackMarker*)")->_addInsertEvent(marker,track); } + + inline void Session::addInsertEvent ( TrackElement* segment, Track* track ) + { get("addInsertEvent(TrackElement*)")->_addInsertEvent(segment,track); } + + inline void Session::addRemoveEvent ( TrackElement* segment ) + { get("addRemoveEvent()")->_addRemoveEvent(segment); } + + inline void Session::addMoveEvent ( TrackElement* segment, Track* track ) + { get("addMoveEvent()")->_addMoveEvent(segment,track); } + + inline void Session::addSortEvent ( Track* track, bool forced ) + { get("addSortEvent()")->_addSortEvent(track,forced); } + + inline size_t Session::revalidate () + { return get("revalidate()")->_revalidate(); } + + inline bool Session::isEmpty () + { return get("isEmpty()")->_isEmpty(); } + + +} // Katana namespace. + +#endif // KATANA_SESSION_H diff --git a/katana/src/katana/Track.h b/katana/src/katana/Track.h new file mode 100644 index 00000000..dc70ad24 --- /dev/null +++ b/katana/src/katana/Track.h @@ -0,0 +1,218 @@ +// -*- 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 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@lip6.fr | +// | =============================================================== | +// | C++ Header : "./katana/Track.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACK_H +#define KATANA_TRACK_H + +#include "hurricane/Point.h" +namespace Hurricane { + class Layer; +} + +#include "katana/TrackCost.h" +#include "katana/TrackElement.h" + + +namespace Katana { + + using Hurricane::Point; + using Hurricane::Layer; + + class TrackMarker; + class RoutingPlane; + class KatanaEngine; + + +// ------------------------------------------------------------------- +// Class : "Track". + + class Track { + + public: + enum IndexState { BeginIsTrackMin = 0x00000001 + , BeginIsSegmentMin = 0x00000002 + , BeginIsSegmentMax = 0x00000004 + , EndIsTrackMax = 0x00000008 + , EndIsSegmentMin = 0x00000010 + , EndIsNextSegmentMin = 0x00000020 + , EndIsSegmentMax = 0x00000040 + , BeforeFirstElement = BeginIsTrackMin |EndIsSegmentMin + , InsideElement = BeginIsSegmentMin|EndIsSegmentMax + , OutsideElement = BeginIsSegmentMax|EndIsNextSegmentMin + , AfterLastElement = BeginIsSegmentMax|EndIsTrackMax + , EmptyTrack = BeginIsTrackMin |EndIsTrackMax + , BeginMask = BeginIsTrackMin |BeginIsSegmentMin|BeginIsSegmentMax + , EndMask = EndIsTrackMax |EndIsSegmentMin |EndIsNextSegmentMin|EndIsSegmentMax + }; + + public: + // Static Attributes. + static const size_t npos; + + public: + void destroy (); + virtual bool isHorizontal () const = 0; + virtual bool isVertical () const = 0; + inline bool isLocalAssigned () const; + inline RoutingPlane* getRoutingPlane () const; + KatanaEngine* getKatanaEngine () const; + virtual Flags getDirection () const = 0; + inline size_t getIndex () const; + unsigned int getDepth () const; + const Layer* getLayer () const; + const Layer* getBlockageLayer () const; + inline DbU::Unit getAxis () const; + inline DbU::Unit getMin () const; + inline DbU::Unit getMax () const; + Track* getNextTrack () const; + Track* getPreviousTrack () const; + inline size_t getSize () const; + virtual Point getPosition ( DbU::Unit coordinate ) const = 0; + TrackElement* getSegment ( size_t index ) const; + TrackElement* getSegment ( DbU::Unit position ) const; + TrackElement* getNext ( size_t& index, Net* ) const; + TrackElement* getPrevious ( size_t& index, Net* ) const; + TrackElement* getNextFixed ( size_t& index ) const; + size_t find ( const TrackElement* ) const; + DbU::Unit getSourcePosition ( vector::iterator ) const; + DbU::Unit getMinimalPosition ( size_t index, unsigned int state ) const; + DbU::Unit getMaximalPosition ( size_t index, unsigned int state ) const; + Interval getFreeInterval ( DbU::Unit position, Net* net=NULL ) const; + Interval getOccupiedInterval ( size_t& begin ) const; + Interval expandFreeInterval ( size_t& begin, size_t& end, unsigned int state, Net* ) const; + void getBeginIndex ( DbU::Unit position, size_t& begin, unsigned int& state ) const; + void getOverlapBounds ( Interval, size_t& begin, size_t& end ) const; + TrackCost getOverlapCost ( Interval, Net*, size_t begin, size_t end, unsigned int flags ) const; + TrackCost getOverlapCost ( Interval, Net*, unsigned int flags ) const; + TrackCost getOverlapCost ( TrackElement*, unsigned int flags ) const; + void getTerminalWeight ( Interval, Net*, size_t& count, unsigned int& weight ) const; + DbU::Unit getSourcePosition ( size_t index ) const; + bool check ( unsigned int& overlaps, const char* message=NULL ) const; + unsigned int checkOverlap ( unsigned int& overlaps ) const; + inline void setLocalAssigned ( bool ); + void invalidate (); + void insert ( TrackElement* ); + void insert ( TrackMarker* ); + void setSegment ( TrackElement*, size_t ); + size_t doRemoval (); + void doReorder (); + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const = 0; + + protected: + // Attributes. + RoutingPlane* _routingPlane; + size_t _index; + DbU::Unit _axis; + DbU::Unit _min; + DbU::Unit _max; + vector _segments; + vector _markers; + bool _localAssigned; + bool _segmentsValid; + bool _markersValid; + + protected: + // Constructors & Destructors. + Track ( RoutingPlane*, unsigned int index ); + virtual ~Track (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + Track ( const Track& ); + Track& operator= ( const Track& ); + protected: + // Protected functions. + inline unsigned int setMinimalFlags ( unsigned int& state, unsigned int flags ) const; + inline unsigned int setMaximalFlags ( unsigned int& state, unsigned int flags ) const; + + protected: + // Sub-Classes. + struct SourceCompare { + public: + inline bool operator() ( const TrackElement* lhs , const TrackElement* rhs ); + inline bool operator() ( DbU::Unit lhsSource, const TrackElement* rhs ); + inline bool operator() ( const TrackElement* lhs , DbU::Unit rhsSource ); + private: + inline bool lessSource ( DbU::Unit lhs , DbU::Unit rhsSource ); + }; + struct SegmentCompare { + inline bool operator() ( const TrackElement* lhs, const TrackElement* rhs ); + }; + }; + + +// Inline Functions. + inline bool Track::SourceCompare::operator() ( const TrackElement* lhs, const TrackElement* rhs ) + { return lessSource(lhs->getSourceU(),rhs->getSourceU()); } + + + inline bool Track::SourceCompare::operator() ( DbU::Unit lhsSource, const TrackElement* rhs ) + { return lessSource(lhsSource,rhs->getSourceU()); } + + + inline bool Track::SourceCompare::operator() ( const TrackElement* lhs, DbU::Unit rhsSource ) + { return lessSource(lhs->getSourceU(),rhsSource); } + + + inline bool Track::SourceCompare::lessSource ( DbU::Unit lhsSource, DbU::Unit rhsSource ) + { return lhsSource < rhsSource; } + + + inline bool Track::SegmentCompare::operator() ( const TrackElement* lhs, const TrackElement* rhs ) + { + if (lhs->getSourceU() < rhs->getSourceU()) + return true; + else { + if ( (lhs->getSourceU() == rhs->getSourceU()) + and (lhs->getTargetU() > rhs->getTargetU()) ) + return true; + } + return false; + } + + + inline bool Track::isLocalAssigned () const { return _localAssigned; } + inline RoutingPlane* Track::getRoutingPlane () const { return _routingPlane; } + inline size_t Track::getIndex () const { return _index; } + inline DbU::Unit Track::getAxis () const { return _axis; } + inline DbU::Unit Track::getMin () const { return _min; } + inline DbU::Unit Track::getMax () const { return _max; } + inline size_t Track::getSize () const { return _segments.size(); } + inline void Track::setLocalAssigned ( bool state ) { _localAssigned=state; } + + inline unsigned int Track::setMinimalFlags ( unsigned int& state, unsigned int flags ) const + { + state &= ~BeginMask; + state |= (flags & BeginMask); + return state; + } + + inline unsigned int Track::setMaximalFlags ( unsigned int& state, unsigned int flags ) const + { + state &= ~EndMask; + state |= (flags & EndMask); + return state; + } + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::Track); + +#endif // KATANA_TRACK_H diff --git a/katana/src/katana/TrackCost.h b/katana/src/katana/TrackCost.h new file mode 100644 index 00000000..c48108c0 --- /dev/null +++ b/katana/src/katana/TrackCost.h @@ -0,0 +1,203 @@ +// -*- 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 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++ Header : "./katana/TrackCost.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACK_COST_H +#define KATANA_TRACK_COST_H + +#include +#include "hurricane/Interval.h" +namespace Hurricane { + class Net; +} + + +namespace Katana { + + using std::string; + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::Interval; + using Hurricane::Net; + class Track; + + +// ------------------------------------------------------------------- +// Class : "TrackCost". + + class TrackCost { + public: + enum Flags { IgnoreAxisWeight = 0x0001 + , DiscardGlobals = 0x0002 + , IgnoreSharedLength = 0x0004 + , LocalAndTopDepth = 0x0008 + , ZeroCost = 0x0010 + }; + + public: + // Sub-Class: "CompareByDelta()". + class CompareByDelta { + public: + bool operator() ( const TrackCost& lhs, const TrackCost& rhs ); + }; + class Compare { + public: + inline Compare ( unsigned int flags=0 ); + bool operator() ( const TrackCost& lhs, const TrackCost& rhs ); + private: + unsigned int _flags; + }; + + public: + TrackCost ( Track* track + , Net* net + ); + TrackCost ( Track* track + , const Interval& interval + , size_t begin + , size_t end + , Net* net + , unsigned int flags + ); + ~TrackCost (); + inline bool isForGlobal () const; + inline bool isBlockage () const; + inline bool isFixed () const; + inline bool isInfinite () const; + inline bool isOverlap () const; + inline bool isLeftOverlap () const; + inline bool isRightOverlap () const; + inline bool isHardOverlap () const; + inline bool isOverlapGlobal () const; + inline bool isGlobalEnclosed () const; + bool isFree () const; + inline unsigned int getFlags () const; + inline Track* getTrack () const; + inline size_t getBegin () const; + inline size_t getEnd () const; + inline const Interval& getInterval () const; + inline unsigned int getTerminals () const; + inline DbU::Unit getDelta () const; + inline DbU::Unit getDeltaPerpand () const; + inline DbU::Unit getLongestOverlap () const; + inline long getAxisWeight () const; + inline int getRipupCount () const; + inline unsigned int getDataState () const; + inline void setForGlobal (); + inline void setBlockage (); + inline void setFixed (); + inline void setInfinite (); + inline void setOverlap (); + inline void setLeftOverlap (); + inline void setRightOverlap (); + inline void setHardOverlap (); + inline void setOverlapGlobal (); + inline void setGlobalEnclosed (); + inline void incTerminals ( unsigned int ); + inline void incDelta ( DbU::Unit ); + inline void incDeltaPerpand ( DbU::Unit ); + inline void incDeltaShared ( DbU::Unit ); + inline void setAxisWeight ( DbU::Unit ); + inline void setLonguestOverlap ( DbU::Unit ); + inline void mergeRipupCount ( int ); + inline void mergeDataState ( unsigned int ); + void consolidate (); + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + // Operators. + + // Attributes. + protected: + unsigned int _flags; + Track* _track; + size_t _begin; + size_t _end; + Interval _interval; + bool _forGlobal; + bool _blockage; + bool _fixed; + bool _infinite; + bool _hardOverlap; + bool _overlap; + bool _leftOverlap; + bool _rightOverlap; + bool _overlapGlobal; + bool _globalEnclosed; + unsigned int _terminals; + DbU::Unit _delta; + DbU::Unit _deltaShared; + DbU::Unit _deltaPerpand; + DbU::Unit _axisWeight; + DbU::Unit _distanceToFixed; + DbU::Unit _longuestOverlap; + unsigned int _dataState; + int _ripupCount; + + }; + + +// Inline Functions. + inline bool TrackCost::isForGlobal () const { return _forGlobal; } + inline bool TrackCost::isBlockage () const { return _blockage; } + inline bool TrackCost::isFixed () const { return _fixed; } + inline bool TrackCost::isInfinite () const { return _infinite; } + inline bool TrackCost::isOverlap () const { return _overlap; } + inline bool TrackCost::isLeftOverlap () const { return _leftOverlap; } + inline bool TrackCost::isRightOverlap () const { return _rightOverlap; } + inline bool TrackCost::isHardOverlap () const { return _hardOverlap; } + inline bool TrackCost::isOverlapGlobal () const { return _overlapGlobal; } + inline bool TrackCost::isGlobalEnclosed () const { return _globalEnclosed; } + inline unsigned int TrackCost::getFlags () const { return _flags; } + inline Track* TrackCost::getTrack () const { return _track; } + inline size_t TrackCost::getBegin () const { return _begin; } + inline size_t TrackCost::getEnd () const { return _end; } + inline const Interval& TrackCost::getInterval () const { return _interval; } + inline unsigned int TrackCost::getTerminals () const { return _terminals; } + inline DbU::Unit TrackCost::getLongestOverlap () const { return _longuestOverlap; } + inline DbU::Unit TrackCost::getDelta () const { return _delta; } + inline long TrackCost::getAxisWeight () const { return _axisWeight; } + inline int TrackCost::getRipupCount () const { return _ripupCount; } + inline unsigned int TrackCost::getDataState () const { return _dataState; } + inline void TrackCost::setForGlobal () { _forGlobal = true; } + inline void TrackCost::setBlockage () { _blockage = true; } + inline void TrackCost::setFixed () { _fixed = true; } + inline void TrackCost::setInfinite () { _infinite = true; } + inline void TrackCost::setOverlap () { _overlap = true; } + inline void TrackCost::setLeftOverlap () { _leftOverlap = true; } + inline void TrackCost::setRightOverlap () { _rightOverlap = true; } + inline void TrackCost::setHardOverlap () { _hardOverlap = true; } + inline void TrackCost::setOverlapGlobal () { _overlapGlobal = true; } + inline void TrackCost::setGlobalEnclosed () { _globalEnclosed = true; } + inline void TrackCost::incTerminals ( unsigned int terminals ) { _terminals += terminals; } + inline void TrackCost::incDelta ( DbU::Unit delta ) { _delta += delta; } + inline void TrackCost::incDeltaPerpand ( DbU::Unit delta ) { _deltaPerpand += delta; } + inline void TrackCost::incDeltaShared ( DbU::Unit delta ) { _deltaShared += delta; } + inline void TrackCost::setAxisWeight ( DbU::Unit weight ) { _axisWeight = weight; } + inline void TrackCost::setLonguestOverlap ( DbU::Unit overlap ) { _longuestOverlap = (overlap > _longuestOverlap) ? overlap : _longuestOverlap; } + inline void TrackCost::mergeRipupCount ( int count ) { _ripupCount = (count>_ripupCount)?count:_ripupCount; } + inline void TrackCost::mergeDataState ( unsigned int state ) { _dataState = (state>_dataState)?state:_dataState; } + inline string TrackCost::_getTypeName () const { return "TrackCost"; } + + inline TrackCost::Compare::Compare ( unsigned int flags ) : _flags(flags) { } + + +} // Katana namespace. + + +INSPECTOR_V_SUPPORT(Katana::TrackCost); + + +#endif // KATANA_TRACK_COST_H diff --git a/katana/src/katana/TrackElement.h b/katana/src/katana/TrackElement.h new file mode 100644 index 00000000..23de250a --- /dev/null +++ b/katana/src/katana/TrackElement.h @@ -0,0 +1,260 @@ +// -*- 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 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++ Header : "./katana/TrackElement.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACK_ELEMENT_H +#define KATANA_TRACK_ELEMENT_H + +#include +#include + +#include "hurricane/Interval.h" +#include "hurricane/Observer.h" +namespace Hurricane { + class Record; + class Net; + class Layer; +} + +#include "anabatic/AutoSegment.h" +#include "katana/Constants.h" +#include "katana/Session.h" +#include "katana/TrackElements.h" + + +namespace Katana { + + using std::string; + using std::map; + using Hurricane::Observer; + using Hurricane::Record; + using Hurricane::Interval; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Net; + using Hurricane::Layer; + using Anabatic::GCell; + using Anabatic::AutoSegment; + + class DataNegociate; + class Track; + class TrackCost; + + + typedef map TrackElementLut; + typedef void (SegmentOverlapCostCB)( const TrackElement*, TrackCost& ); + + +// ------------------------------------------------------------------- +// Class : "TrackElement". + + enum TrackElementFlags { TElemCreated =0x00000001 + , TElemBlockage =0x00000002 + , TElemFixed =0x00000004 + , TElemLocked =0x00000008 + , TElemRouted =0x00000010 + , TElemSourceDogleg=0x00000020 + , TElemTargetDogleg=0x00000040 + , TElemRipple =0x00000080 + , TElemInvalidated =0x00000100 + }; + + + struct Compare { + bool operator() ( TrackElement* lhs, TrackElement* rhs ); + }; + + struct CompareByPosition { + bool operator() ( const TrackElement* lhs, const TrackElement* rhs ) const; + }; + + + class TrackElement { + + public: + static SegmentOverlapCostCB* setOverlapCostCB ( SegmentOverlapCostCB* ); + static void notify ( TrackElement*, unsigned int flags ); + public: + void destroy (); + virtual AutoSegment* base () const; + // Wrapped AutoSegment Functions (when applicable). + virtual bool isFixed () const; + virtual bool isHorizontal () const = 0; + virtual bool isVertical () const = 0; + virtual bool isLocal () const; + virtual bool isGlobal () const; + virtual bool isBipoint () const; + virtual bool isTerminal () const; + virtual bool isStrongTerminal ( unsigned int flags=0 ) const; + virtual bool isStrap () const; + virtual bool isSlackened () const; + virtual bool isDogleg () const; + virtual bool isReduced () const; + virtual bool isUTurn () const; + virtual bool isUserDefined () const; + // Predicates. + inline bool isCreated () const; + inline bool isInvalidated () const; + inline bool isBlockage () const; + inline bool isLocked () const; + inline bool isRouted () const; + inline bool hasSourceDogleg () const; + inline bool hasTargetDogleg () const; + inline bool canRipple () const; + virtual bool canSlacken () const; + virtual bool canPivotUp ( float reserve ) const; + virtual bool canPivotDown ( float reserve ) const; + virtual bool canMoveUp ( float reserve, unsigned int flags=Flags::WithPerpands ) const; + virtual bool canDogleg (); + virtual bool canDogleg ( Interval ); + virtual bool canDogleg ( Anabatic::GCell*, unsigned int flags=0 ); + // Accessors + inline Observer* getObserver (); + virtual unsigned long getId () const; + virtual Flags getDirection () const = 0; + virtual Net* getNet () const = 0; + virtual const Layer* getLayer () const = 0; + virtual DbU::Unit getPitch () const; + virtual DbU::Unit getPPitch () const; + inline Track* getTrack () const; + inline size_t getIndex () const; + virtual unsigned long getFreedomDegree () const; + virtual float getMaxUnderDensity ( unsigned int flags=0 ) const; + inline Box getBoundingBox () const; + virtual TrackElement* getNext () const; + virtual TrackElement* getPrevious () const; + virtual DbU::Unit getAxis () const = 0; + inline DbU::Unit getSourceU () const; + inline DbU::Unit getTargetU () const; + inline DbU::Unit getLength () const; + inline Interval getCanonicalInterval () const; + virtual Interval getFreeInterval () const; + virtual Interval getSourceConstraints () const; + virtual Interval getTargetConstraints () const; + virtual DataNegociate* getDataNegociate ( unsigned int flags=Flags::DataSelf ) const; + virtual TrackElement* getCanonical ( Interval& ); + virtual size_t getGCells ( vector& ) const; + virtual TrackElement* getParent () const; + virtual unsigned int getDoglegLevel () const; + virtual TrackElement* getSourceDogleg (); + virtual TrackElement* getTargetDogleg (); + virtual TrackElements getPerpandiculars (); + // Mutators. + inline void setFlags ( unsigned int ); + inline void unsetFlags ( unsigned int ); + inline void setRouted (); + virtual void setTrack ( Track* ); + inline void setIndex ( size_t ); + virtual void updateFreedomDegree (); + virtual void setDoglegLevel ( unsigned int ); + virtual void swapTrack ( TrackElement* ); + virtual void reschedule ( unsigned int level ); + virtual void detach (); + virtual void invalidate (); + virtual void revalidate (); + virtual void updatePPitch (); + virtual void incOverlapCost ( Net*, TrackCost& ) const; + virtual void setAxis ( DbU::Unit, unsigned int flags=Anabatic::SegAxisSet ); + virtual TrackElement* makeDogleg (); + inline bool makeDogleg ( Anabatic::GCell* ); + virtual TrackElement* makeDogleg ( Anabatic::GCell*, TrackElement*& perpandicular, TrackElement*& parallel ); + virtual TrackElement* makeDogleg ( Interval, unsigned int& flags ); + virtual void _postDoglegs ( TrackElement*& perpandicular, TrackElement*& parallel ); + virtual bool moveAside ( unsigned int flags ); + virtual bool slacken ( unsigned int flags=Flags::NoFlags ); + virtual bool moveUp ( unsigned int flags ); + virtual bool moveDown ( unsigned int flags ); +#if THIS_IS_DISABLED + virtual void desalignate (); +#endif + virtual bool _check () const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + protected: + // Static Attributes. + static SegmentOverlapCostCB* _overlapCostCallback; + // Attributes. + unsigned int _flags; + Track* _track; + size_t _index; + DbU::Unit _sourceU; + DbU::Unit _targetU; + Observer _observer; + + protected: + // Constructors & Destructors. + TrackElement ( Track* ) ; + virtual ~TrackElement (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + TrackElement ( const TrackElement& ); + TrackElement& operator= ( const TrackElement& ); + + }; + + +// Inline functions. + inline Observer* TrackElement::getObserver () { return &_observer; } + inline void TrackElement::setFlags ( unsigned int flags ) { _flags|= flags; } + inline void TrackElement::unsetFlags ( unsigned int flags ) { _flags&=~flags; } + inline bool TrackElement::isCreated () const { return _flags & TElemCreated; } + inline bool TrackElement::isInvalidated () const { return _flags & TElemInvalidated; } + inline bool TrackElement::isBlockage () const { return _flags & TElemBlockage; } + inline bool TrackElement::isLocked () const { return _flags & TElemLocked; } + inline bool TrackElement::isRouted () const { return _flags & TElemRouted; } + inline bool TrackElement::hasSourceDogleg () const { return _flags & TElemSourceDogleg; } + inline bool TrackElement::hasTargetDogleg () const { return _flags & TElemTargetDogleg; } + inline bool TrackElement::canRipple () const { return _flags & TElemRipple; } + inline Track* TrackElement::getTrack () const { return _track; } + inline size_t TrackElement::getIndex () const { return _index; } + inline DbU::Unit TrackElement::getLength () const { return getTargetU() - getSourceU(); } + inline DbU::Unit TrackElement::getSourceU () const { return _sourceU; } + inline DbU::Unit TrackElement::getTargetU () const { return _targetU; } + inline Interval TrackElement::getCanonicalInterval () const { return Interval(getSourceU(),getTargetU()); } + inline void TrackElement::setIndex ( size_t index ) { _index=index; } + + inline void TrackElement::setRouted() + { + _flags |= TElemRouted; + if (base()) base()->setFlags( Anabatic::SegFixed ); + } + + inline Box TrackElement::getBoundingBox () const + { + if (getDirection() & Flags::Horizontal) + return Box( getSourceU(), getAxis()-DbU::lambda(1.0), getTargetU(), getAxis()+DbU::lambda(1.0) ); + return Box( getAxis()-DbU::lambda(1.0), getSourceU(), getAxis()+DbU::lambda(1.0), getTargetU() ); + } + + inline bool TrackElement::makeDogleg ( Anabatic::GCell* gcell ) + { + TrackElement* perpandicular = NULL; + TrackElement* parallel = NULL; + + makeDogleg( gcell, perpandicular, parallel ); + + return (perpandicular != NULL); + } + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::TrackElement); + +#endif diff --git a/katana/src/katana/TrackElements.h b/katana/src/katana/TrackElements.h new file mode 100644 index 00000000..33a70cfd --- /dev/null +++ b/katana/src/katana/TrackElements.h @@ -0,0 +1,144 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/TrackElements.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACKELEMENTS_H +#define KATANA_TRACKELEMENTS_H + +#include "anabatic/AutoSegments.h" + + +namespace Katana { + + using std::string; + using std::set; + + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Hook; + using Hurricane::Component; + using Hurricane::Contact; + using Hurricane::Segment; + using Hurricane::Net; + using Hurricane::Filter; + using Hurricane::Locator; + using Hurricane::Collection; + using Hurricane::GenericFilter; + using Hurricane::GenericLocator; + using Hurricane::GenericCollection; + + using Anabatic::AutoSegments_Perpandiculars; + + class TrackElement; + + +// ------------------------------------------------------------------- +// Collections. + + typedef Hurricane::Filter TrackElementHF; + typedef Hurricane::Locator TrackElementHL; + typedef Hurricane::Collection TrackElementHC; + typedef GenericCollection TrackElements; + typedef GenericLocator TrackElementLocator; + typedef GenericFilter TrackElementFilter; + + +// ------------------------------------------------------------------- +// Class : "TrackElements_Perpandiculars". + + class TrackElements_Perpandiculars : public TrackElementHC { + + public: + // Sub-Class: Locator. + class Locator : public TrackElementHL { + public: + Locator ( TrackElement* segment ); + inline Locator ( const Locator& ); + virtual TrackElement* getElement () const; + virtual TrackElementHL* getClone () const; + virtual bool isValid () const; + virtual void progress (); + virtual string _getString () const; + protected: + AutoSegments_Perpandiculars::Locator _locator; + TrackElement* _element; + }; + + public: + // TrackElements_Perpandiculars Methods. + inline TrackElements_Perpandiculars ( TrackElement* segment ); + inline TrackElements_Perpandiculars ( const TrackElements_Perpandiculars& ); + virtual TrackElementHC* getClone () const; + virtual TrackElementHL* getLocator () const; + virtual string _getString () const; + + protected: + // TrackElements_Perpandiculars Attributes. + TrackElement* _segment; + }; + + + inline TrackElements_Perpandiculars::Locator::Locator ( const Locator& locator ) + : TrackElementHL() + , _locator (locator._locator) + , _element (NULL) + { } + + + inline TrackElements_Perpandiculars::TrackElements_Perpandiculars ( TrackElement* segment ) + : TrackElementHC() + , _segment (segment) + { } + + + inline TrackElements_Perpandiculars::TrackElements_Perpandiculars ( const TrackElements_Perpandiculars& tracksegments ) + : TrackElementHC() + , _segment (tracksegments._segment) + { } + + +// ------------------------------------------------------------------- +// Class : "TrackElements_UniqCanonical". + + class TrackElements_UniqCanonical : public TrackElementHF { + public: + inline TrackElements_UniqCanonical ( set& ); + inline TrackElements_UniqCanonical ( const TrackElements_UniqCanonical& ); + virtual TrackElementHF* getClone () const; + virtual bool accept ( TrackElement* segment ) const; + virtual string _getString () const; + private: + set& _canonicals; + }; + + + inline TrackElements_UniqCanonical::TrackElements_UniqCanonical ( set& canonicals ) + : TrackElementHF() + , _canonicals(canonicals) + {} + + + inline TrackElements_UniqCanonical::TrackElements_UniqCanonical ( const TrackElements_UniqCanonical& filter ) + : TrackElementHF() + , _canonicals(filter._canonicals) + {} + + +} // Katana namespace. + + +#endif // KATANA_TRACKELEMENTS_H diff --git a/katana/src/katana/TrackFixedSegment.h b/katana/src/katana/TrackFixedSegment.h new file mode 100644 index 00000000..5212dd5f --- /dev/null +++ b/katana/src/katana/TrackFixedSegment.h @@ -0,0 +1,82 @@ +// -*- 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 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++ Header : "./katana/TrackFixedSegment.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACK_FIXED_SEGMENT_H +#define KATANA_TRACK_FIXED_SEGMENT_H + +#include "katana/TrackElement.h" + + +namespace Katana { + + using std::string; + using std::map; + using Hurricane::Record; + using Hurricane::Interval; + using Hurricane::DbU; + using Hurricane::Net; + using Hurricane::Layer; + + class Track; + + +// ------------------------------------------------------------------- +// Class : "TrackFixedSegment". + + class TrackFixedSegment : public TrackElement { + public: + static TrackElement* create ( Katana::Track* track , Segment* segment ); + public: + virtual AutoSegment* base () const; + virtual bool isHorizontal () const; + virtual bool isVertical () const; + virtual bool isFixed () const; + virtual unsigned long getId () const; + virtual Flags getDirection () const; + virtual Net* getNet () const; + virtual const Layer* getLayer () const; + virtual TrackElement* getNext () const; + virtual TrackElement* getPrevious () const; + virtual DbU::Unit getAxis () const; + virtual Interval getFreeInterval () const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + protected: + // Attributes. + static Net* _blockageNet; + Segment* _segment; + + protected: + // Constructors & Destructors. + TrackFixedSegment ( Track*, Segment* ) ; + virtual ~TrackFixedSegment (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + TrackFixedSegment ( const TrackFixedSegment& ); + TrackFixedSegment& operator= ( const TrackFixedSegment& ); + + }; + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::TrackFixedSegment); + +#endif // KATANA_TRACK_FIXED_SEGMENT_H diff --git a/katana/src/katana/TrackMarker.h b/katana/src/katana/TrackMarker.h new file mode 100644 index 00000000..db8c6ac6 --- /dev/null +++ b/katana/src/katana/TrackMarker.h @@ -0,0 +1,113 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/TrackMarker.h" | +// +-----------------------------------------------------------------+ + + + + +#ifndef KATANA_TRACK_MARKER_H +#define KATANA_TRACK_MARKER_H + +#include "hurricane/DbU.h" +namespace Hurricane { + class RoutingPad; + class Net; +} + + +namespace Katana { + + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::RoutingPad; + using Hurricane::Net; + + class Track; + + +// ------------------------------------------------------------------- +// Class : "TrackMarker". + + class TrackMarker { + + public: + static TrackMarker* create ( RoutingPad*, size_t depth ); + void destroy (); + public: + Net* getNet () const; + inline DbU::Unit getSourceU () const; + inline DbU::Unit getTargetU () const; + inline Track* getTrack () const; + inline unsigned int getWeight ( const Track* ) const; + inline void setTrack ( Track* ); + Record* _getRecord () const; + std::string _getString () const; + std::string _getTypeName () const; + public: + class Compare { + public: + inline bool operator() ( const TrackMarker* lhs , const TrackMarker* rhs ) const; + inline bool operator() ( DbU::Unit lhsU, const TrackMarker* rhs ) const; + inline bool operator() ( const TrackMarker* lhs , DbU::Unit rhsU ) const; + private: + inline bool markerLess ( DbU::Unit lhsU, DbU::Unit rhsU ) const; + }; + + protected: + // Attributes. + RoutingPad* _routingPad; + DbU::Unit _sourcePosition; + DbU::Unit _targetPosition; + Track* _track; + unsigned int _weight; + unsigned int _refcount; + + protected: + // Constructors & destructors. + TrackMarker ( RoutingPad*, size_t depth ); + ~TrackMarker () {}; + private: + TrackMarker ( const TrackMarker& ); + TrackMarker& operator= ( const TrackMarker& ); + }; + + +// Inline Functions. + inline DbU::Unit TrackMarker::getSourceU () const { return _sourcePosition; } + inline DbU::Unit TrackMarker::getTargetU () const { return _targetPosition; } + inline Track* TrackMarker::getTrack () const { return _track; } + inline unsigned int TrackMarker::getWeight ( const Track* track ) const { return _weight; } + inline void TrackMarker::setTrack ( Track* track ) { _track = track; } + + inline bool TrackMarker::Compare::operator() ( const TrackMarker* lhs, const TrackMarker* rhs ) const + { return markerLess ( lhs->getSourceU(), rhs->getSourceU() ); } + + inline bool TrackMarker::Compare::operator() ( DbU::Unit lhsU, const TrackMarker* rhs ) const + { return markerLess ( lhsU, rhs->getSourceU() ); } + + inline bool TrackMarker::Compare::operator() ( const TrackMarker* lhs, DbU::Unit rhsU ) const + { return markerLess ( lhs->getSourceU(), rhsU ); } + + inline bool TrackMarker::Compare::markerLess ( DbU::Unit lhsU, DbU::Unit rhsU ) const + { return ( lhsU < rhsU ); } + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::TrackMarker); + + +#endif // KATANA_TRACK_MARKER_H diff --git a/katana/src/katana/TrackSegment.h b/katana/src/katana/TrackSegment.h new file mode 100644 index 00000000..5d224cf8 --- /dev/null +++ b/katana/src/katana/TrackSegment.h @@ -0,0 +1,165 @@ +// -*- 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 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++ Header : "./katana/TrackSegment.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACK_SEGMENT_H +#define KATANA_TRACK_SEGMENT_H + +#include +#include +#include "katana/TrackElement.h" + + +namespace Katana { + + using std::string; + using std::map; + using std::set; + using std::binary_function; + using Hurricane::Record; + using Hurricane::Interval; + using Hurricane::DbU; + using Hurricane::Net; + using Hurricane::Layer; + using Anabatic::AutoSegment; + + class DataNegociate; + class Track; + class TrackCost; + + +// ------------------------------------------------------------------- +// Class : "TrackSegment". + + class TrackSegment : public TrackElement { + public: + class CompareById : public binary_function { + public: + inline bool operator() ( const TrackSegment* lhs, const TrackSegment* rhs ); + }; + + public: + static TrackElement* create ( AutoSegment*, Track*, bool& created ); + static size_t getAllocateds (); + public: + // Wrapped AutoSegment Functions (when applicable). + virtual AutoSegment* base () const; + virtual bool isFixed () const; + virtual bool isHorizontal () const; + virtual bool isVertical () const; + virtual bool isLocal () const; + virtual bool isGlobal () const; + virtual bool isBipoint () const; + virtual bool isTerminal () const; + virtual bool isStrongTerminal ( unsigned int flags=0 ) const; + virtual bool isStrap () const; + virtual bool isSlackened () const; + virtual bool isDogleg () const; + virtual bool isReduced () const; + virtual bool isUTurn () const; + virtual bool isUserDefined () const; + // Predicates. + virtual bool canDogleg (); + virtual bool canDogleg ( Interval ); + virtual bool canDogleg ( Anabatic::GCell*, unsigned int flags=0 ); + virtual bool canPivotUp ( float reserve ) const; + virtual bool canPivotDown ( float reserve ) const; + virtual bool canMoveUp ( float reserve, unsigned int flags ) const; + virtual bool canSlacken () const; + virtual float getMaxUnderDensity ( unsigned int flags ) const; + virtual unsigned long getId () const; + virtual Flags getDirection () const; + virtual Net* getNet () const; + virtual const Layer* getLayer () const; + virtual DbU::Unit getPitch () const; + virtual DbU::Unit getPPitch () const; + virtual unsigned long getFreedomDegree () const; + virtual unsigned int getDoglegLevel () const; + virtual TrackElement* getNext () const; + virtual TrackElement* getPrevious () const; + virtual TrackElement* getParent () const; + virtual DbU::Unit getAxis () const; + virtual Interval getFreeInterval () const; + virtual Interval getSourceConstraints () const; + virtual Interval getTargetConstraints () const; + virtual DataNegociate* getDataNegociate ( unsigned int flags=Flags::DataSelf ) const; + virtual TrackElement* getCanonical ( Interval& ); + virtual size_t getGCells ( vector& ) const; + virtual TrackElement* getSourceDogleg (); + virtual TrackElement* getTargetDogleg (); + virtual TrackElements getPerpandiculars (); + virtual size_t getPerpandicularsBound ( set& ); + // Mutators. + virtual void setTrack ( Track* ); + virtual void updateFreedomDegree (); + virtual void setDoglegLevel ( unsigned int ); + virtual void swapTrack ( TrackElement* ); + virtual void reschedule ( unsigned int level ); + virtual void detach (); + virtual void invalidate (); + virtual void revalidate (); + virtual void updatePPitch (); + virtual void setAxis ( DbU::Unit, unsigned int flags ); + virtual TrackElement* makeDogleg (); + virtual TrackElement* makeDogleg ( Anabatic::GCell*, TrackElement*& perpandicular, TrackElement*& parallel ); + virtual TrackElement* makeDogleg ( Interval, unsigned int& flags ); + virtual void _postDoglegs ( TrackElement*& perpandicular, TrackElement*& parallel ); + virtual bool moveAside ( unsigned int flags ); + virtual bool slacken ( unsigned int flags=Flags::NoFlags ); + virtual bool moveUp ( unsigned int flags ); + virtual bool moveDown ( unsigned int flags ); +#if THIS_IS_DISABLED + virtual void desalignate (); +#endif + virtual bool _check () const; + virtual Record* _getRecord () const; + virtual string _getString () const; + virtual string _getTypeName () const; + + protected: + // Attributes. + static size_t _allocateds; + AutoSegment* _base; + unsigned long _freedomDegree; + DbU::Unit _ppitch; + DataNegociate* _data; + unsigned int _dogLegLevel:4; + + protected: + // Constructors & Destructors. + TrackSegment ( AutoSegment*, Track* ) ; + virtual ~TrackSegment (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + TrackSegment ( const TrackSegment& ); + TrackSegment& operator= ( const TrackSegment& ); + + }; + + + inline bool TrackSegment::CompareById::operator() ( const TrackSegment* lhs, const TrackSegment* rhs ) + { return lhs->getId() < rhs->getId(); } + + + typedef set TrackSegmentSet; + + +} // Katana namespace. + + +INSPECTOR_P_SUPPORT(Katana::TrackSegment); + +#endif // KATANA_TRACK_SEGMENT_H diff --git a/katana/src/katana/TrackSegmentCost.h b/katana/src/katana/TrackSegmentCost.h new file mode 100644 index 00000000..5c5b44ff --- /dev/null +++ b/katana/src/katana/TrackSegmentCost.h @@ -0,0 +1,98 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC/LIP6 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./TrackSegmentCost.h" | +// +-----------------------------------------------------------------+ + + +#ifndef __TRACK_SEGMENT_COST__ +#define __TRACK_SEGMENT_COST__ + + +#include +#include + +#include "hurricane/DbU.h" +namespace Hurricane { + class Record; + class Net; +} + + +namespace Katana { + + + using std::vector; + using std::string; + using Hurricane::Record; + using Hurricane::DbU; + using Hurricane::Net; + + class TrackElement; + + +// ------------------------------------------------------------------- +// Class : "TrackSegmentCost". + + + class TrackSegmentCost { + + public: + TrackSegmentCost ( TrackElement* ); + ~TrackSegmentCost (); + inline unsigned int getTerminals () const; + inline unsigned int getRipupCount () const; + inline DbU::Unit getLeftMinExtend () const; + inline DbU::Unit getRightMinExtend() const; + inline Net* getNet () const; + DbU::Unit getWiringDelta ( DbU::Unit axis ) const; + inline void setRipupCount ( unsigned int ); + inline void incRipupCount (); + inline void decRipupCount (); + inline void resetRipupCount (); + void update ( TrackElement* ); + Record* _getRecord () const; + string _getString () const; + inline string _getTypeName () const; + + protected: + // Attributes. + unsigned int _terminals : 5; + unsigned int _ripupCount : 16; + DbU::Unit _leftMinExtend; + DbU::Unit _rightMinExtend; + Net* _net; + vector _attractors; + + }; + +// Inline Functions. + inline unsigned int TrackSegmentCost::getTerminals () const { return _terminals; } + inline unsigned int TrackSegmentCost::getRipupCount () const { return _ripupCount; } + inline DbU::Unit TrackSegmentCost::getLeftMinExtend () const { return _leftMinExtend; } + inline DbU::Unit TrackSegmentCost::getRightMinExtend () const { return _rightMinExtend; } + inline Net* TrackSegmentCost::getNet () const { return _net; } + inline void TrackSegmentCost::setRipupCount ( unsigned int count ) { _ripupCount = count; } + inline void TrackSegmentCost::incRipupCount () { _ripupCount++; } + inline void TrackSegmentCost::decRipupCount () { if (_ripupCount) _ripupCount--; } + inline void TrackSegmentCost::resetRipupCount () { _ripupCount = 0; } + inline string TrackSegmentCost::_getTypeName () const { return "TrackSegmentCost"; } + + +} // End of Katana namespace. + + +INSPECTOR_PV_SUPPORT(Katana::TrackSegmentCost); + + +#endif // __TRACK_SEGMENT_COST__ diff --git a/katana/src/katana/Tracks.h b/katana/src/katana/Tracks.h new file mode 100644 index 00000000..a34b1e3f --- /dev/null +++ b/katana/src/katana/Tracks.h @@ -0,0 +1,140 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/Tracks.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_TRACKS_H +#define KATANA_TRACKS_H + +#include +#include "hurricane/Collection.h" +#include "hurricane/Interval.h" + + +namespace Katana { + + using std::string; + using Hurricane::_TName; + using Hurricane::Locator; + using Hurricane::Collection; + using Hurricane::GenericLocator; + using Hurricane::GenericCollection; + using Hurricane::GenericFilter; + using Hurricane::Interval; + + class Track; + class RoutingPlane; + + typedef GenericCollection Tracks; + typedef GenericLocator TrackLocator; + typedef GenericFilter TrackFilter; + + +// ------------------------------------------------------------------- +// Class : "Tracks_Range". + + class Tracks_Range: public Collection { + + public: + // Locator Sub-Class. + class Locator : public Hurricane::Locator { + public: + Locator ( const RoutingPlane* routingPlane + , const Interval& constraints ); + Locator ( const Locator& ); + virtual Hurricane::Locator* getClone () const; + virtual bool isValid () const; + virtual Track* getElement () const; + virtual void progress (); + virtual string _getString () const; + + protected: + const Interval _constraints; + Track* _track; + }; + + public: + // Tracks_Range Methods. + static Tracks get ( RoutingPlane* routingPlane + , Interval& constraints ); + Tracks_Range ( const RoutingPlane* routingPlane + , const Interval& constraints ); + Tracks_Range ( const Tracks_Range& ); + virtual Collection* getClone () const; + virtual Hurricane::Locator* getLocator () const; + virtual string _getString () const; + + protected: + // Tracks_Range Attributes. + const RoutingPlane* _routingPlane; + const Interval _constraints; + }; + + +// ------------------------------------------------------------------- +// Class : "Tracks_Spiral". + + class Tracks_Spiral : public Collection { + + public: + // Locator Sub-Class. + class Locator : public Hurricane::Locator { + public: + Locator ( const RoutingPlane* routingPlane + , const Interval& optimal + , const Interval& constraints ); + Locator ( const Locator& ); + virtual Hurricane::Locator* getClone () const; + virtual bool isValid () const; + virtual Track* getElement () const; + virtual void progress (); + bool InOptimal () const; + virtual string _getString () const; + + protected: + const Interval _optimal; + const Interval _constraints; + Track* _minTrack; + Track* _maxTrack; + bool _onMin; + bool _inMinOptimal; + bool _inMaxOptimal; + }; + + public: + // Tracks_Spiral Methods. + static Tracks get ( RoutingPlane* routingPlane + , Interval& optimal + , Interval& constraints ); + Tracks_Spiral ( const RoutingPlane* routingPlane + , const Interval& optimal + , const Interval& constraints ); + Tracks_Spiral ( const Tracks_Spiral& ); + virtual Collection* getClone () const; + virtual Hurricane::Locator* getLocator () const; + virtual string _getString () const; + + protected: + // Tracks_Spiral Attributes. + const RoutingPlane* _routingPlane; + const Interval _optimal; + const Interval _constraints; + }; + + +} // Anabatic namespace. + + +#endif // KATANA_TRACKS_H diff --git a/katana/src/katana/VerticalTrack.h b/katana/src/katana/VerticalTrack.h new file mode 100644 index 00000000..32fc22aa --- /dev/null +++ b/katana/src/katana/VerticalTrack.h @@ -0,0 +1,56 @@ + +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2008-2013, All Rights Reserved +// +// +-----------------------------------------------------------------+ +// | 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++ Header : "./katana/VerticalTrack.h" | +// +-----------------------------------------------------------------+ + + +#ifndef KATANA_VERTICAL_TRACK_H +#define KATANA_VERTICAL_TRACK_H + +#include "katana/Track.h" + + +namespace Katana { + + +// ------------------------------------------------------------------- +// Class : "VerticalTrack". + + class VerticalTrack : public Track { + + public: + static VerticalTrack* create ( RoutingPlane*, unsigned int index ); + virtual bool isHorizontal () const; + virtual bool isVertical () const; + virtual Flags getDirection () const; + virtual Point getPosition ( DbU::Unit coordinate ) const; + virtual string _getTypeName () const; + virtual Record* _getRecord () const; + + protected: + // Constructors & Destructors. + VerticalTrack ( RoutingPlane*, unsigned int index ); + virtual ~VerticalTrack (); + virtual void _postCreate (); + virtual void _preDestroy (); + private: + VerticalTrack ( const VerticalTrack& ); + VerticalTrack& operator= ( const VerticalTrack& ); + }; + + +} // Katana namespace. + + +#endif // KATANA_VERTICAL_TRACK_H diff --git a/katana/src/katanaRefactor.conf b/katana/src/katanaRefactor.conf new file mode 100644 index 00000000..cca85573 --- /dev/null +++ b/katana/src/katanaRefactor.conf @@ -0,0 +1,8 @@ + +# Refactoring patterns for Kite to Katana tool. + KITE --> KATANA + Kite --> Katana + kite --> katana + Katabatic --> Anabatic + katabatic --> anabatic + ktbt --> anbt diff --git a/unicorn/CMakeLists.txt b/unicorn/CMakeLists.txt index 5ae9230c..3349bd1e 100644 --- a/unicorn/CMakeLists.txt +++ b/unicorn/CMakeLists.txt @@ -16,24 +16,22 @@ setup_qt() find_package(Libbfd) - find_package(LibXml2 REQUIRED) - find_package(PythonLibs REQUIRED) + find_package(LibXml2 REQUIRED) + find_package(PythonLibs REQUIRED) find_package(PythonSitePackages REQUIRED) - find_package(LEFDEF REQUIRED) + find_package(LEFDEF REQUIRED) find_package(COLOQUINTE) - find_package(VLSISAPD REQUIRED) - find_package(HURRICANE REQUIRED) - find_package(CORIOLIS REQUIRED) -#find_package(NIMBUS REQUIRED) -#find_package(METIS REQUIRED) -#find_package(MAUKA REQUIRED) - find_package(ANABATIC REQUIRED) - find_package(ETESIAN REQUIRED) - find_package(KNIK REQUIRED) - find_package(KATABATIC REQUIRED) - find_package(KITE REQUIRED) -#find_package(EQUINOX REQUIRED) -#find_package(SOLSTICE REQUIRED) + find_package(VLSISAPD REQUIRED) + find_package(HURRICANE REQUIRED) + find_package(CORIOLIS REQUIRED) + find_package(ANABATIC REQUIRED) + find_package(KATANA REQUIRED) + find_package(ETESIAN REQUIRED) + find_package(KNIK REQUIRED) + find_package(KATABATIC REQUIRED) + find_package(KITE REQUIRED) +#find_package(EQUINOX REQUIRED) +#find_package(SOLSTICE REQUIRED) if(WITH_OPENMP) find_package(OpenMP REQUIRED) diff --git a/unicorn/src/CMakeLists.txt b/unicorn/src/CMakeLists.txt index a2884517..fe8fab2d 100644 --- a/unicorn/src/CMakeLists.txt +++ b/unicorn/src/CMakeLists.txt @@ -49,6 +49,8 @@ ${KNIK_LIBRARIES} ${ETESIAN_GRAPHICAL_LIBRARIES} ${ETESIAN_LIBRARIES} + ${KATANA_GRAPHICAL_LIBRARIES} + ${KATANA_LIBRARIES} ${ANABATIC_GRAPHICAL_LIBRARIES} ${ANABATIC_LIBRARIES} ${CORIOLIS_PYTHON_LIBRARIES} diff --git a/unicorn/src/cgt.py b/unicorn/src/cgt.py index efe55c99..4c4f5c29 100755 --- a/unicorn/src/cgt.py +++ b/unicorn/src/cgt.py @@ -10,6 +10,7 @@ try: import Viewer import CRL import Anabatic + import Katana import Etesian import Katabatic import Kite @@ -183,6 +184,7 @@ if __name__ == '__main__': unicorn = Unicorn.UnicornGui.create() unicorn.setApplicationName ('cgt') unicorn.registerTool (Anabatic.GraphicAnabaticEngine.grab()) + unicorn.registerTool (Katana.GraphicKatanaEngine.grab()) unicorn.registerTool (Etesian.GraphicEtesianEngine.grab()) unicorn.registerTool (Kite.GraphicKiteEngine.grab()) #unicorn.setAnonNetSelectable(False)