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)