Anabatic transient commit 18. Port of Kite (Katana), Yeah, Baby! Yeah!

* Bug: In Hurricane, in StaticObservable::getObserver(), if the slot
    pointer is NULL, do not try to access the owner. Returns NULL, so
    the caller can be aware of the situation...
* Change: In Hurricane, in BreakpointWidget & ExceptionWidget some
    cosmetic changes (fonts and window sizes).
* Bug: In Anabatic, In AutoHorizontal::getConstraints(), take into account
    the constraints from the source AutoContact, as it holds the constraints
    transmitted by the RoutingPads and sets up by propageConstraintsFromRp().
    It is likely to be a bug affecting the original Katabatic as well.
* Change: In Anabatic, in RawGCellsUnder(), check that the segment is not
    completly oustside the cell abutment box and truncate the coordinates
    to the part that is inside. Use the "shrink" if we reach the east/north
    border.
* Change: In Anabatic, in Configuration, no more decorator because we will
    use a true derived relationship. Katana *derives* from *Anabatic* and do
    not *decorate* it, so the Configuration can do the same. It also implies
    that we directly create a Katana engine, not an Anabatic one.
* Change: In Anabatic, in Session, do not allow the opening of the Session
    in a standalone fashion (with a static method). Instead it must be opened
    using the relevant method of the Anabatic/Katana engine. This ensure we
    are opening the right Session type.
* Change: In Anabatic, in AutoSegment_Aligneds() collection the seed segment
    is not part of the collection by default, but will be included if the
    Flags::WithSelf is set.
* Change: In Configuration, all the flags value are now defined in two steps.
    Declared in the header and initialized in the module. This is to prevent
    the fact that on some cases, in relation with the Python "extern C" part
    modules, we need a true allocated variable. It was causing weird linking
    problems.
      A side effect is that they can no longer be used as entry is switches,
    have to replace them by if/else.
* New: In Anabatic, new GCell::getNeighborAt() utility function.
* Bug: In Anabatic, in GCell::doGrid(), tag all the GCells of the grid with
    the grid type... Back annote all the edges capacity (north & east) with
    the reserved local capacity.
* New: Complete portage of Kite over Anabatic. The new engine is christened
    "Katana" for Kite-Analogic. When it's capabilities and performances
    will be on a part with Kite, it is to completly replace it (and take
    back the "Kite" name). Preliminary tests seems to show that, contrary
    to intuition (because built on a more complex/slower grid), it is even
    slightly faster than Kite 8-).
This commit is contained in:
Jean-Paul Chaput 2016-08-15 16:30:13 +02:00
parent 248704c61c
commit 48f3a2bc3c
103 changed files with 17072 additions and 644 deletions

View File

@ -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<Segment*>() ) {
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); }

View File

@ -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 );

View File

@ -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; }

View File

@ -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 );
}
}

View File

@ -131,7 +131,7 @@ namespace Anabatic {
contact = segment->getAutoTarget();
if (contact) _stack.push( contact, segment );
progress();
if (not (_flags & Flags::WithSelf)) progress();
}

View File

@ -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; }

View File

@ -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.

View File

@ -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 ()
{ }

View File

@ -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.
}

View File

@ -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<GCell*>& gcells = getAnabatic()->getGCells();
size_t ibegin = gcells.size();
//const vector<GCell*>& 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<GCell*>(this)->updateDensity();
@ -1485,10 +1506,8 @@ namespace Anabatic {
if (isInvalidated()) const_cast<GCell*>(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<AutoSegment*>::iterator isegment;
vector<AutoSegment*>::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<AutoSegment*>::iterator iend;
set<Net*> 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<AutoSegment*>::iterator isegment;
vector<AutoSegment*>::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.

View File

@ -1,4 +1,4 @@
// -*- C++ -*-
// -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp<anabatic>" -*-
//
// 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() ) );

View File

@ -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<Net*> globalNets;
GCell::Set invalidateds;
Session::open( this );
openSession();
vector<AutoSegment*> segments;
@ -482,7 +482,7 @@ namespace Anabatic {
unsigned long global = 0;
startMeasures();
Session::open( this );
openSession();
if (Session::getAllowedDepth() >= 3) {
switch ( method ) {

View File

@ -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<double>(getCell(),"Sat.")->getData()) << endl;
startMeasures();
Session::open( this );
openSession();
forEach ( Net*, inet, getCell()->getNets() ) {
if (NetRoutingExtension::isAutomaticGlobalRoute(*inet)) {

View File

@ -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<Contact*>(*icomponent) );
for ( Component* component : rp->getSlaveComponents() ) {
cdebug_log(145,0) << "slave component: " << component << endl;
AutoContact* sourceContact = Session::lookup( dynamic_cast<Contact*>(component) );
if (sourceContact) {
cdebug_log(145,0) << "Start slave: " << sourceContact << endl;
set<AutoSegment*> verticalSegments;
set<AutoSegment*> 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<AutoSegment*>::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<AutoSegment*>::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()

View File

@ -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();
}

View File

@ -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)

View File

@ -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<NetData*>& 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<RawGCellsUnder>( 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<NetData*>& 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); }

View File

@ -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<GCell*>& ) const;
// Modifiers.
virtual void setDuSource ( DbU::Unit );

View File

@ -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<GCell*>& ) const = 0;
inline AutoContact* getAutoSource () const;

View File

@ -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<GCell*>& ) const;
// Modifiers.
virtual void setDuSource ( DbU::Unit );

View File

@ -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

View File

@ -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.

View File

@ -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; }

View File

@ -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<Net*>& );
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.

View File

@ -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<AutoSegment*>& getInvalidateds ();
static inline const vector<AutoSegment*>& getRevalidateds ();
static inline const set<AutoSegment*>& getDestroyeds ();
static inline const vector<AutoSegment*>& getDoglegs ();
static inline const set<Net*>& 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<AutoSegment*>& getInvalidateds ();
static inline const vector<AutoSegment*>& getRevalidateds ();
static inline const set<AutoSegment*>& getDestroyeds ();
static inline const vector<AutoSegment*>& getDoglegs ();
static inline const set<Net*>& 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;

View File

@ -20,6 +20,7 @@ projects = [
#, "metis"
#, "mauka"
, "anabatic"
, "katana"
, "knik"
, "katabatic"
, "kite"

98
bootstrap/refactor.py Executable file
View File

@ -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<orig>[^\s]*)\s*-->\s*(?P<replace>[^\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 )

View File

@ -2230,42 +2230,41 @@ endobj
482 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 5628>>
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$╤·,<Qr┼°Ю╫│CР╘dNeД≥╗сЫWх=рУXИ▒р#╣5у5┤ш▌~{ZТсz≥[▐GEN%┌v|&'hrлАо=░╔а8Р <-М╘И╘yпrЪ&БsXаa°zЗЙ:▄? А
ТБVШ-*
_:?;&%QК(Z≤©╫rШ╚с_²╬\y∙э$╞╡Н^°V┘ AБ°КН·Я╠%и÷╖ЛJш∙ЖeЗ ║<ЦХбK8t╝⌡О"ъXъ╒┴╚`(Ж=Uтё≥ЯЩVt╓М6*~AVWн ├Ш─e L╒╜° ╦x?╦4┐с9pЙК÷A.Ю4н┘Иh┘N▒Х■▐НgKvеrи0лйВ(x/
xÚ­XwXUW¶?È= E¼È•«€Š4%ˆhh!D@¤*MAŠô^Ä.¶˜¼Ù™Œ±‡(°aA@Å‹¢Q1V4NKŒQ!Æuî]ÞÛç&óÞ›™÷Çûæ¾}Îw9gïµ×Z{¯ßï·<C3AF>#“1zzzÆAA¾ÑŽÁyÉ9á 9…Ò³À1ƒÙ'v„ü÷<C3BC>¡ü€FÛ¦4¨T
‰¬hÁˆJ=qô q´¾(—<>f½E&ôÎÜ0îgŒ¥»9½<39>²Îèëé±Óý';MvöIOM/J_™¼ÄjIBQURnÞŠôÔ´"+»${+çÉΓèmòD«9¹¹©YÉV³r òr ŠÒssœ$ï¬tî1zC8FàG ÃXóÆ23qLSMgäf03„Ê c #Ƙ±`”ÌhÆËŒcÆ36ÌƱcìGf"3‰qbÞcœ™ÉŒ 3…qe¦2Ó˜÷<37>ñ`<™éÌLfãÃÌf|™9ŒãÏ0s™@fÄ3!L(Æ„3ó™LÉD1ÑL ³<>YÌÔ0ß0kßAŒ3NÏRo™ÞõAƒ9
?h÷ #úƒõ£õ—ëïÒ¿%K•ýĆ³짜÷>WÈUp'¸~Þ›$L|`ðó`ýÁQƒÿ<x`È”!QCV!Cm†6³vÊðÃõF{<7B>Þ¿o¼ßøã>“Õ&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þr<>4m=Vz¤ôHEmMuÍᶣߞýµ^æÖãQ…S‰ ]ŸÉ šsxàsÏdi0Ž¼&OK{jzj´Ü¿ óÐ×Vpاž¾ºãOC¸½¸Õþ˃ŠÂ—ÎÏŽIIÔ:Šæo¯ÜþêôW§/W^%7É«¬{óÚç]œV… A✞ñ±%ÉŸ§ìJÛ•öeú¾ ¡<ãèÂK<C382>8tŽß"¿X¿¢‰«`(ö=UÔ£™ñýVt¤í6*~AVWÎ †û€e ­œ ¸x?¸4ƒÓ9pêëŸA.à4Î…éh…Nè”<C3A8>îgKvÅrÉ0ÌÊ÷(x/
œ¦ƒ…=H~Fy7ZŸC§ftÚ<74>.ß'èZ€“cpb NòA+'4x ²Û`Þ
▌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╖╕аО╞└u╔хЁ`о,п╡Ж╪ТЗWq╢я┐Щ┘╬ Y╢ГуШ╣t1Xcм[3ПА╢щJЖ▀Ц8Мm╔ф┤┘ИЬ┼и╛Ь┬▀─Irm6сеХCwкo■v)*щ*}*б:Ь=┬Щё╓е╜<L!`тЬЦ╜n²Й%0▓@$Й┐оВэhh╬t╝}ЪMР=Ьg╝*WZUcПЦ~N.бg<▄ оWt╓t╓V┤wБ▓?/"9"eЙrJ;уАx9°Бю└</╬%Ч╟q&ыЁ┌ЦBb]┼p0М╒Б╗KCуъ(ы)rп'0(Т#╩a┌9РМ8╙
'O▀>к:х*хcJ8╡aхФ╒9AG┌u` 8▓:<<Щ!⌠─=u╢ЛмQ│fG╕═╟б├═а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╙я≥═ах!ЛЙHОхe║┌ЮD┌К╞п■яt║9лП┐|Р√<ЪЭаН╩ОО╫{@P/■<y╕d-мХBОЧAЩ;у┐п⌡╨чjУн~
╖J╢r9 %оЙ╩nt]╞Щ┘:!(ыj]7·L_ √■·╫л▐╡CТжE╩╢АV°шп)╜└Л'зл╢Отъ┬▐уF,фrЩ▌ЩИ╛:Щ▐Iд<L╔x╦? 5т4C,▒╚ша╘_║d∙ХM7О╝Чя FsБ'Jж░щфm@смь▒f┌╥ДУV^⌡╙Dv#╖╔КтдБvиРdм4▌─Уf0эп'lё├8ЙС┤╨0╖Т?ЮЪ■ПИЛ-[Л? Щt┘╟▒К?╙■u╟8_7RщMGщ ФК`<╙>╝д╘╢L9O%ш╙н╖⌡╙$p0(t≈ш5L!≤Eпс п°^f!HpаMТг├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╠Рyг╚Б╚Фп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 ХА Хк┴Е: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│┐ф┴Vpа▒▓$(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е;Х╥<xщСЙ8XП╔- ,╫~Я|┘╡s■Р┘B╢■©%wсZf╥л>`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╡┤Т&AШБ▐е[╙"wuJIЦbЙеtУ,съЬМ╡╜еQд⌡лY°⌡≤!╛Г╤4~v√\длъkя┐
(Z|{/t╤u>╝·jШн╔'÷X╪о≈╦пцg)╪0сТг@©FиR"Oы·[╤╒lyЕ├*r┬Tn/++ш╩ё┼4▓фУВ.ъ[╢=▐Д▓╒ кW,_╧!≈$K& КД╟П5ьY√Jы:3йxZ_≤S░⌡╪&▓д▒╦╜╠TЬгV╤m╓б├(Ыьa.мexNойrН~жNУUt⌠бt²x0F╘-уЯz╝з@ SY▄ФП²vH┬_|DN╒БВpu%KGQ≤ЕС∙°мъ╡j∙уьтЕT▀фд▀Ь ллXF.▄Qv?$>$`uhvxv\BV,Z Тп<K╒pЛЧчФнsWНтЭJН⌠▌╔█Я█▀кЭ┬╚пK;┬t!▄<;вq╝ЦНА>з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▒7v│w└В▄Д┴ЪхB#Ъ)X|уr╔ЕJO х~GrЯ{"╥╔Х}+╡╩Ю-┘чDъ┤Иm╬m©ёО$!┘ЪСlёB╒B<ЁИ#║─р√дG╪йws⌡}N|m:x(9WJЕХюnЮ<─EЧ:Э█&xNпяЛНш│~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еB²b\ж├H©╣6╒J4kY ФП└ж O┼n,├r├ =╕А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у╘Й<u║╨I(г8╬8>'*9$5$-:3Q0\╤Os©^Щдiв~л`=vР╬║bУ┬Ъ╓МОг
Žmàxܨ1ÁP3 ¶Qr#äÁ5i-µ Ÿƒâ°,ÜŒ÷Ág¸ÂøàLÿ ?…û¢IM>hÇ¢>kHWXm­®•ÓÑR;]ë„cD'­7XŠÞ¢3Œá Å?Al<>c·!hµûRbeSWø
`ÂÕß9ò°î‡ºÜÝsM0TÛ~'fËب-á Å“0ñ79Y¸3½riŲªuGÈQrxWEeEåÎ#¤‰œ^W·tqEö®%$™ä”/]V¸>ƒÄQ+Ô¹Ò®DN{nM<þec^FǤU.«XZµþïÇOO»{-‰›<F2þÿ‰sÔ¥r¿#½¼h_QuɱÿÃ\dŽ¦SÓåàÈ÷WB<57>ºRäY°çh Y{^zý«8ZŽŽ¼f<C2BC>èÁþB_ˆ…,ÚóêýZº¬±æ­øpÚn%{ŽÅqœö¶RãÃÂtüÄdV|ÄEÀ$¹6ƒébô¡»å7J»•n•>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”ìúÝ0ÁùvU…“Ž§EŸedä1%Ù0dsÑœ <>:p8:<< “€=u´ìÍQ<C38D>f °Â† Ám.o'ÿv <04>Ûg¿ý ?ß*Ù(õZsÅ<73>´†ÃpÝ5»—Qà™/åÊžƒ?ésf`zæøH@¿<>(DF¡<46><C2A1>­<EFBFBD>NŒÆÅ4ª$¥l B Œ]øÂág‡fG0œÎ$+Ô|jûb½ØÚ>1S­Çþv:o¨9)òfj¾q¤ojÿ×%Û­~¬Þ*ljð@Á;Ù•L Lкձסw!8ˆ¦þµ€íëß^ÿ–çÁ—€!Ó\0¿
æhq mªÑ™ ÁQÙÈ!ìê:<3A>ÞË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¶U<C2B6>O7UIâ`Pè.·k˜B0 g 9½ÌBpÁ 7u`ÐÚ<ý¥ <0A>JÀí †Q0Fu@ <20>µ Íh¥žûÇ}ßõQ+L#tƒaÔCGN =Áh ÑÁÍÆÍ £p¡ Š†­ï÷NëK<C3AB>¶JŒ”ê­¦\<0E>8ÆjõÆh<C386>~Ïp·$!lŽ¿¾ßû hpvBÿà7rñ)„ñ0Š¼*ì\Ô¹¨vq VéøÅøÅ ^!­HáßôÅ?ÃQ|ÄÒ
Â7”“FŸz÷Ým0VÐë¨Ä¥Áÿ¶ ô‰¼øV*Þiß²Ëi­Õ6õÍ/.Pß7íúÔë¨8s(Øè2Ä©7ËÄvÈça8yVܯŠ¯ò¥©˜˜;+|QøÂ)…öjDÍNQ!'¯szÂ:C;­U8é¢sÝœÃÆUeU/¯[^»ái%לo=ÖzìFÙ"%Ú †E çÁ Ïã¨ChChIP1Íoš_¥{XU»ªü:ü^†<>2æeÚ­¬æ¼³yG²Ë3÷eìH¤å<> „-žZLûúÙ[}J}JöÐ<>£– <0C>1mxÞý¼ûìkB•ME¶ZªiK1 zÐQLRjþªƒ%«Ð‘­÷@ GÐ(c_€ŸÿÄ 4"('öu~_û}<7D>ñ  ¢}fò½šÑügÇ—Ž \>Djcšß¼xó¢Eʪ§4Y»¦\góû<C3B3>éK¬²<C2AC>)DFQÔ—ýv èá<C3A8>_sôãÄr³{qâ~Ú•–Ÿ¦dUf¢…ô}<7D>+i¨,D~íDÅR0˃Ì>¬ÒÈ¥ÁX:0, òpÈ
4T¬î+.Lq•ÆBgZñ‡i8¦I¨}[ùséŠO×nOÚã¿ÇÿËù_ÄCó@ª9õ²L)Ûi¦]­Þ)F«ýXôç´ƒ´wð?Å;,†pbt<74>veÿ¨ÁñêâèþPZ%ÞPçʵ#Õ¹,q⪠VÛN‰¸WkLY ¤Ð"û\ÓmFAë¯Þ£”íbA1Ž“Ô›øþ=JLcQA™ÀAãD+F¸àHIªŸš<C5B8>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Å;è·<xÝóê8Xð£- ,½~ñ|…²s”ò…B´”¿%wÓZf·Ì>`M$þ´,°Šž=ãéÜꢮF]ˇAœh;z-W[ºÖ+U_¨Y& Šçe·¨°å—LZæL¬ˆgÃüîÝy},h} …cêȱÍMë6/i\Ý
ÖæÙ¥‰_DìŒØùy„N`<0F>žbëb»ÇœKpNŽùÁþ¯`Cå“.'°•W - T`£‡6Œû÷V/v-ç r$@¢èG{ÚzÚ&¡AÚŽ£å}ûö ²1‰@û]ÐðN®ÜŽ|Øu3êfþoDJϘƒïZï´Ý¾}ô%¡á=Êhóoõ;ˆúßÒhÁ<68><> Šžç…¬ÎŸ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å<33>ä4¹¸¾«¸ æTÎÙJÕR F ¬° â1*˜<>Q ÁCC¥†æ<E280A0>F¥ék<E28098>¸ØÝÕ}6™³ügÍM¥f(™µwn}xCø™¤KE±¹é9ÅÙÅÙëÒHµ7OØ—W¹¼j­÷ÊàŒø˜ø˜â0âGŽ}x/ânèçI ¦â¬öe×ËÎsÏ #/2os[œàêTL|QRA“Kõgo6Vo>üI­?ò¦öV×­®Æ¿wä즦ÕGW7®ªY^)Àâýlÿ€ÓåäZyÛɆ“ {oroÈõu<C3B5><EFBFBD>K÷&<26>â“6'Ñ?a\1…v'2«4º&º¦à4éžh¦ÊÉ£ò+'éßåò{t¤ÛCwtÇÉ^8ÍÒí‹?l©ŠÜÕ)%<25>ÓÕ³Lãß9§Ë¶Goâ»:8+(;61#BXÏmiüì,¹$ˆ™¿×¢P´øö^èlë|\<Õö<C395>KO,>±xŸq¡‡ÏRxa¦éA<C3A9><41>~<7E>¥Dž²=·lEÙòÊ Uä©Ü^VV¶wGi$<24>ë«ï]¾·h{É%E¯X¾rC.IL4i×Éaák*°³,•²7tf”ñ$´$¾0§ 7yM$‰#q[c©ð³à<C2B3>­lÛH… Qò±ÿÂ\šË𜞕)äÜý¬<C3BD>4
ê«è&…é&:ñ`Œ8R[ªãõ\µ<>"¦²Íá;í<>ÿøˆœDÅïáêJŽ¢0Ëç+9¿eÕ*«w^gP—S-/â³r^ƼŒE±aá"ÀeWðCâCW‡f‡gÇ%dEÐçyàÀ¢Å@ͳ$
Çîïmî<wåNͯä>éXÚ߸¸ÌŸ¸
ý±´ƒHÂèÀ³sç:îî£TÿÓáï—×*£×¯Ó¯Ë®–Àtº¼A9AÙ Òüó„ãõž¿rþÊwÿ¼°JÙ·šwâ*ÌfÆÁçÞɽT IÇ«)<04>£]l]ìâ$¥1‡¢xù„SOLíð¿{'öû"*ßé!ѸåÉkáÉÓ`I`ŽÐ‡Ê/ëªwo^¼ù°<C3B9>²EáG©—f¶Ïª¢PMÍXçZ‡Ïåžz„6÷Æð[á·rßÑPþ`
ÎÿÄs€•ç«^!ÛB…ÏL°6,/,/&>>˜ T©þšFÉKµ±Kø{N
)æ¿$wRÎϺ0ãÅ[
dycxGxÏHžø<C5BE>œ!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š<33><C5A1>X?÷PFYFYaÙªò5å<0F>´ïÈñÇtìºO~$¯‹`PœÐÈ6#¿Ÿ²†M‰]þÌÈ™Q©>Ä…DHÝ—Zy*÷dέŒÞäw‰Ý©G³²ËRI< +JX”+,Êó_ãJÂI趠ÒàÒðòˆC:ñ=±@Ó†Àhò®êÎÅ;<17>Þ'½4ÌTñÈç“ø½YõYõ«ZÉU<C389>žoR¹ [ùÙ¸'û²ž0¹ßŠÇÂßPicªHígG¶4|~pëÞí˜ò«6/ý8ïã¼Í9ÿóûaSþ@¯þ*]-ël®^ |<7C>
r—\ÿâ«êËÕgO¹ lçöKÔ=Z=í-ÚslžMdà@ʧ<q%<25>‰§O-»F~¤¹Ü)ºšA'ºjzXôåP©5˜“Q? eE37¥Ñ¥Ùp:óULÄuê1æ´ =¹kÚÍ šƒviÐtMµ«gcEIôºèM)ŸÒ!kïåÿœ”þÔÛoP¶fáª`ÅÊ ˜´Ëæâ—É0>Æ/€¨p&m=,Ìç I-ß×Yù„&P±<50>«GËÊÉ»—PgUb G­<47>VÅB<07>b\Ö†H¿µ6¢J4kY æð„Ö OŠn,†r†š=¦ƒ¾á1ˆ#‰IÙ&Pazn]ËG­ä)¹s°³íJë…΂‘˜©”="ÅIZ/gü<×-Ï}Eè†t)®Î̾‡›Ô¬¹¡&L£grm//~¯¾Ï‚¼ÊE¯}ÑÿEV÷Ý žªc嵤æãÃo<¾º¥¸¹øôª“%'ןþ¨™¼ =<3D>ßÜÀ<>OM^__¼d]*É"™[2¶eìHÞ½¸,ä@ÌÞäí)Û¶Äê7S@G¾¡áXuSåÉŠc;ëuGÔj<C394>‰æ”ü<é\Ù<>®Áæ^ÇÝ÷Ñó¡)™<>8Ó}Å,}<>¯GÙu<C399>랯“@NÎã[Žl¯Û^·«v·Æ¼[¶Ïê0º9Å_H¸ˆPé«|pJuFÕUýˆýG°GN 厫Èw!ÿÔ æ€Ál0M—0…¨i=\§íÉó¯<C3B3>§­ŒuŸà,ÒÁÄ h{ï)\è…&uÒ &éhàGó{~ºhBP!¼¥xlP ŒêuÇ/÷ï¿R½RS }H@/ç—<C3A7>ס÷¼Tv*»jé37=ä jbïåe*Ø…"“#=åéáÒöÒ×ýÐ7¡¯s€¡8¦Ó“÷Ȉ<>NDâhzh€>ßTßrNÕ©ê<u¡ºI(Ç8¾8>'*9$5$-:3Q0\¶Os¿^ýÄi×~Ì`=vò¾¡ˆÿáï¬
endstream
endobj
484 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 554>>
stream
xзcd`aa`ddТp┼┬ТяЖ/Hм Nл+┴Ыхq1╟thхwwц<ЛЪ~Щы/ц╧H├#┴У┤ц
xÚcd`aa`ddp ð Ñö/HÍ NÌ+‰ùÈq1°thÈwwÃ<ìÿ~ýÙ/ùH†#‰õ‡Ã
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И╔Нnэ╨iШ╪щ╥╨ОV°Lы▓╡%t│k╥swHYjbZb┘_╥÷ к·÷F©╒E©▀Ч^}┴╫ШЫ╛s+╥╝э╡sаНщ┤O≈mШ.)a╩х}z`7гОЗъ\©╔/■ВАоЙП=Б_Т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Ù²%t<>k·swHYjbZb…_·Ÿ ËžŸF¿¢E¿þ^}‰½ûù¬s+·®Ü²sÁ©î݇O—mû.)a»È}z`7Çïúß\¿¥/”÷cÿáÏêð=â_ôw«_Ñì?%ÿEþºóÛêßöZÖBÑî´)ùó*çU,jZÞ½¬{Ñ”yóæÍ<C3A6>º¼{C÷†Æås+æL)èÎï.iª¨¬¨jÊïN¥¢3dØD~[Éü|ÃÎ'Ã^*ÃêG¡™tÅ(Ñ.ÃjCqДÏÿuká÷w/Ùþ4t³Ëq1²Îçáü±B«k`g
endstream
endobj
334 0 obj
<</Type/ObjStm/N 200/First 1808/Filter/FlateDecode/Length 4191>>
<</Type/ObjStm/N 200/First 1808/Filter/FlateDecode/Length 4190>>
stream
xÚÅ[[oÛF~ß_1O­…Eä¹_ŠE<C5A0>ÔiÓ¢IÄÞÅîºy`d:&ªˆ†D§ÉþúýÎÌPñâ*ÁˆÃó<C383>û9C ©”bœ)e˜U8&¤dJ+&¼ÁÑ1©=SçxÀ×x|Œc×(+˜áGÌżã€ÁµN0ÇAï sŽ<E28093>yi"­'zïYÐGðã8œ¤cÿ0ðà  ¥,„#n
×H…ñ<•¹â$¸À*) *e5ƒ@º€\^A!¡ ˜jp×¼ ¨Œ$½4ø£ ¨Œ/*+ÀKcÊðò¸Øâ<C398>²à 05t$*@…#Q-äñ¼$ `UExGT œlª»+0`JáâLrEq È1Vb@Zà¤Ì-iᤠ-¦¤¤<C2A4>Æ€\æ,do?*½.&“(ršWÈš¬êÁK“U=<3D>!ozàN* HXDÈ¢<M2¢EZ d|¤…µ”Ä5V<>I:@L92<14>žx<05>{R'@ž@$µ9 ©‰Ÿ€¯4§ €ó5ùU ¢"߃³æä!N²><3E>¡ tDåHm<1A>&–ÈQâŒàt¦¾Ðœ§%´ÔB1MÊiØH j<C2A0><6A> t¡`0'
@ -2288,25 +2287,29 @@ h
Ú¡nAŠS$?-ÄR™K
‰¾ú0Ã~ÖCnÈ^vãe¶qjC¯çåÙ)˜aàuR};Ò0w­ü@/?Q4<51>KÏÊ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╘Л╘й<fS5iсЭ` ⌠Щ²■Т_P>l.╧>fwВ"▌u2Ёq2╦q░fzа.-?Ад*А┼%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 Я &▌:^'p═Г╔ёtX8БH/Kя{){+Т ЪВЯНХЪЫZг╖·цЮ|zhЭдAf┌ЬK■└Д&ф=U╒█ИЕмx|l╛П┐XtЧм_Ч СИБ╗
aO«GFÌ+aúeûz×9²{w÷'åS“)ëæ”æ}j…²nÒ3žŸ N+$¶4—ËÊÃG×ÂOÆ\˜d°(~˜ aR³ N ò 4ó9BM!Eê½# 窾ãC<C3A3>ܱ†NLi(g[ðPrþ†ì»px Jò¼Êçy™Ïó:Ÿç…~ÚTÂ1¯øy¾cS©+gû ¤®C)Ý©€ÒNv6©ì©Ê<fS5iÓü` “ý<E2809C>”ô_P>l.¹>fw÷"Žu2³q2¸q<C2B8>fzÁ.-?áÄ*áŠ%X~\ŠI3£Àì ƒ)ytÇP ÌV—‚ÿòÓ<C3B2>ù¹­”*!»: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/ª«úŸì<C5B8>¦»cwà¶ÝÖ·ì>>:Q/Î_mÛ‡U½=»ùÐÜßܾÿÈ~;CÒú"HÓnžU]}öìLYî¹—˜þ¯\~Íù×Äï×ûzó4þh<C3BE>ŸZû¡éÞDÝh{æüï»úׇnÝl j|¾8¾ÚD×õ§ûŸ¿=öÖŒ&º¨ºjݾ£$qñn<C3B1>ò<EFBFBD>>µÐ <C390>Jz+¾3ßab|â?ÍÑÇÄöþ¦Wí¬v8rFØ9ƒ°<C692>ÌÅB&<26>gŠôM@ÁwX$;d-½¢<12>h{7†ÎÇ·<C387> £7R \n,q:È<>n)‰‡¥÷¦\:Ôz Áèĉ
'} ½†cˆo0)pÔñúHK¯8<C2AF>=/¥ÃšÀGzYŠÞKÙ[¡×ôø¿<C3B8>wGÿÏÿÐ:>õçÓCãÿ#2ÄÿXò $$71Öè©ÊmL/oÆãàcc…Ä¢óoþò_Aâ°
endstream
endobj
486 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 1647>>
stream
xз╔S▀STГ©wщщ{A ▓x▒█╚к#+┬хП2ц"%(V┌▒г╝╟>va%рRl╢┴Ж╓1ql■■ │┬L-/≈∙в╒░e│b╛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╚+.)╛^╥\╞+ж∙К*╣MAy│O▒║ТWFg√O`яF÷Пп╟пмШ$ еG╢>╞▄╔cA╧н═q╡УY╕Kя╒⌠╝у┌y≈>C÷╔OЩЩЗ}ЗЩМJQ4╣├▓Q╚D┌ЦO]╔ЧF╚Хг╒ яг╒х╤Б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Ж╚Жц^$d1²9{·|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Ú¥SSTç¿wÝÝ{A x­«Ë#"2¼ŒÅ°H…€ÂÊC°òØÖV"-µÁFhOãÇFIˆÈÔòrYy-
](ÆŠBŠH“FÑNãL¾Ëž…é]2Ó óÍüÎ9ßœ3ßùýÎwhJ*¥hš^•˜¸cSj©®$=¿ä¸ã.y½3%= øŸãÂ,Ùìf¥ÓU%[ ü(a-øKÿ']GQt°»_zÉ<7A>N«D¤<E`Ø—)WšfÝV+}C~<>ôÎùJ<C3B9><4A>æ<>ó%:Ë+~y±AçˆñoFÂ×ÿÂ<C3BF>ººÑêôEÅå¢-Ñ/‡†ÄéôåúJ<C3BA>ÖK_žïUÈ—þÒàÈò
(Üè²Y„Ð ¯ž/:ªóÚÁJyC~¹ž/ v°õZ¦KÑSÎÕ¢y—>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Î] __U<E28098>f'ŒÃ
ãHÝ=˜};;à÷9zn9¤ãj”>FÚÓÚ3xÃ\kþôÎE LÃHå-}WñÕ°òÎ<14>äO=T¬+ŽKó‰²ûá€'*ÊTÛÞ^¸"*#Ó>Ž<1A>CI³(EDþZ]ÅÇ<4A>E©çƒ®ÑæÁšÁš¡GaîVtôÔ§CÞ™˜<E284A2>˜j@9°¸}É«rÒLTa¸÷ãËxA• Õ;®ÄÕ$Ô'_g1Œ± ŸøKÕè©û¿<C3BB>%²®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æÇ”<C387>åÛ-á´8
Ea
ç Ÿ¥MüÌÓѨ\qðµð-áùè$^´"5=ý½p0 _|dmb­Ÿw[î°—äg0ÿç¸iäFtÍÆH€”3jXôeLo Ÿ™VH%e¤M¸§²Ÿ<1B><>Ê^}·¾-·qOãž<C3A3>vÃNÈ=y°$¯$¯ðp¦!Û<>^•!¶1g çöñIxÊ¡æÌV³uâúIÙ1¥LcËá‡Í÷øöòݦM·>ÜùÍè #Qxª¯&\Ú+þ‘*tƵX§Ja0+UrÈ6[c÷øÊÝ„/ÈàH´¸ÿ-w[VÜiAÆìÄ°¯Qþ5ʈKšcFâ*Ë:gæfÿÙáZ¥ŽP1ÓÛ§}Ûq<C39B>¸…€lZ,2l•¼šèL$ø᳇óde …1°œî«d‰/“÷‡Ô 1€<`dW o:lg…*û{\2¤×ì¿sC×Uj)µ¼5
÷ ë²©ÉxÍØþÇÞÏz?»siæaœïÑôhê·C (+Û’‘š¹'öXÐ<58>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…Þ<E280A6>±<EFBFBD>ZñTôƒîÖ÷wµwµ<77>Õ>ùUÔÚ¦ëÈóïäöSÀ¬w¦e¡µ.NµÕÿUkeì
endstream
endobj
489 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 4701>>
stream
xз²WiTг╤nЮТ─2h╢Я ' ╒┌┴┬ Б┬32к══D@fd░0┬Qт╓▄Qc0 ┌" 2(Ю▄▄Б└F╫┌&N1Й█ф┌^w÷Ё╛W█yYВ╫╥чШЯж╘Ну}╙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Ф│#ХЙ+~,;AА╛3Sp7f·яg0#ф≤д≤1лф и▄bF36▄-3├╠cф1Жлглxф│qd&2÷0÷2Nлdf
xÚ<EFBFBD>WiTǶnàô€2h´ñ ' ¢‚‰ˆ âˆ32Ë  D@fd<66>0ˆQÔ¤ŒQc0 " 2(àŒŒâ„F½&N1ê<31>Æ^wŸ³¬W<C2AC>yY÷½·ÞûñÖ©îÕ}ªz×®¯öþöW:ŒBÁèèèˆsçy,ñðë<>ç·fܬø˜•r‡§ùF±ÅÖ<C396>¿ xh_©|­¾f%3FRéHêJæzÒPŇ £0˜Þ™çÆòýú ùnFo ŽëâµØÁÞaüœ¨ˆ¨ä¨ÏÃWZ® I± OHOŠŠˆ´ c9a¼Ãøqôæ`g9?>>"&Ürv|RB|RHrT|œ½ì¤¥ì¥¥ìåßotæ<74>ê+~,;Aá¬3Sp7fžÑg0#ƘĘ1ÌƚɌbF36Œ-3†±cÆ1öÌÇÌxÆ<78>qd&2Ÿ0Ÿ2NÌdf
3™ÍÌaæ2ó˜ùŒ+³€qc<ñf|˜…Œ/ãÇø3Ì"f1È1K˜¥Ì$]F‡±¦èé×y¥£ÑuÔuÕ­Ó½£g¢W¤°T¤+ö*Ž³Ž¬?ËîcŸq\%/ð1Â(ašð<C5A1>pCx«?LÿлZ¬øÎp°a˜áÃ놌"<22>ÎÏ6¾>(dPñ`¯Áƒ_}`úÁ·\b9d¦JÑ*¶^TiÜÔèß›¢ÒUŠçjCç<>TC 6ÁéÆŽ³]u<>Më~®ø¥ø™€·¸H4µY6 «¡LÙsñΕÓ§¯ýƒüH^­ºëÒ:³Í¶4!Ö1Ó=§y®t&£‰çnߢÅEªüÏû
cüæy‡º…¹§M#ã 9;ú¥ËKW<><13>OŒ< Cž<02>¬²w4U$u»«-:ZV~¼ãC¥kèŒ4'âJü¾9¶üXêiÒ*ªƒDš»<Ú7ÚãVôUrß[~¸ðPaåîS¤†”¯/N-NÛO"#µÛ©M$8ë0:5àXÚ:ÑôwdØÊ<C398>ãy`¾Æ<05>ݘ@d·œŠaÂY°§íQÀmÜG(¸ Y Ú/FûDt&8W¶+I²a˜<61>Î<>ðq Ø»€ÙЗ?x<>â-´:‹ö´ãN'%á„%8n ÚÍÅÐXvà(:AÙc/ÀØÃ0‰Œ4Ýê9*n¨ˆy\­V¡Õy³·ÁóDLÄó<C384>ƒáC¸
ã±ÒÀ×Àyøµx5l×ê[³FjK㌤û Ö" È )<29>+<2B>­Ïl!ͤ.¯¼¬¼<¯4æ̺ØÒ˜ÒyþÄ—,ÏŠ<C38F><EFBFBD>Ë !~teOÔwå€Á2N[G£†…²ÿ¿5õuñïÿ&Nþ¦‰Ôç••-Í«£<C2AB>ÿ«*ÅŽ_$/7ðš‰ÎoÍ÷¥HYÜÈ«]ð&k¤bs5WMà §ÍS±çX­1§Ý«ÒÌaé?ÿnV*ãfÂ^Q;˜{Ï®@ÄÁÇÛ×ìZ½7tOh3ÎÿoÐ ØàñWRH'yp&0¬úUço<C3A7>0%/Ò:CZÃZ]kì …ïø»ŽÕµœh)¼Mž—ý:®Ý¾ Çap”¶K„{àÄ?%W×Õ­9Tˆ÷Úቫ½²<C2BD>èWüJf>ñBC ⚺:tµGƧ´/˜£¾˜ªO«—E
@ -2318,143 +2321,143 @@ c
.ª87ÜÍ' <35> kù¬vQÉ¢¯½s=iXN)3ï{ȈÎQ<C38E>£{A)×OÕ‡äÚ5<C39A>¸­]î½ò³ H!“ 3ú7ºƒ#ÏJn6<6E>o>ßuè©$e[m,‚ãÊ„ÛBe Û4.ðX¤§Ÿ³kO¬=[ZZî^1±rÌq<C38C>²Øñ2©jÎ<>*~fÞ@Îm8—y.óBZËšB‡\Äa¥hFä¡0#`šøtbKîZR¿²4²6æDÌ•Õ?G´'<27>M©J«J?”ž—%äeì\KÖîþѨg@<vQ½•ïqзDÀíüùÔ¦ŒÖu­ëoæÞï?h ,û±ý§öôäÇSW Õa<>F¢¿K*\S¸î(©¤*è ”Ý_àbÞsp*ÝzFk«¨2>bßìÙâõ4ŒhX_¿ï:&@ïì¾nQÿ~ÎÒx˜@¶L ¨\;.|a¸Ÿgܧăˆ«<CB86>;ÕNî j+l륹…ÊŠÑ×ç^Ÿó:’†Ñ]rc_ûöÒÓ'*.Ðà¢óµ4ݨjšN<C5A1>
xÃèÞÁ 2glq7Íårogv­¹<C2AD>1êÁJÚEµÝ=ù ý˜ƒNyð‡k7lŒËñÍœdšé”³ w©<77>Ë}Uðå¡ÍeŽn*ßT±éhnYné¦ÒÍ…[òp˜T¡¤ò ͵Ÿ¦¢nΔ-<2D>tŽTŸ
F©OQ”6(±•ƒ[ôè÷9X¡Ñgwr h¿<68>5\¡d*ݵÆÚ,¼æ Gë´CXøƒÓnHŒtÅ×Æ£„± ÉÏòÚ4=
и╖Оe╨╡kLPX╢ihт╡▄╡┌└}Ёj≈─⌡Ь├°├эFР▌╪(Щ╘М~шЕ'У═/е╙©+Я'цzУS╫2щ7нё^nЛ\w5╫ЗJ#M├├B√╔-Ю╔╜Йы,,ИМд,)┐вФУ╟ХйпТ N⌡CxС:╛цЩ╜FRИпЪFЭ┬ё
ɧïeº²kLPX´ihÔ²Œ²‚„}³j—€ø†œ†ÜFòŽ¼(ý©í~Ûå'õ /Ū¿+ñ'ÃzõS½2Ý7Σ^nì\w5½#ÔúJ#M††B¥-७êÙ,,éíÄ,)ƒ×æõ°èÊ¥ÐôB× NCxó:¬Ãý­FRéÐÿ ˆˆ
endstream
endobj
491 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 436>>
stream
xзcd`aa`ddУПq ┼ТрЖ/Hм Nл+жuйоIIЬйq1╟thхwwц<Л2©yЧ╪▒АЙ∙АХeЩ!цПC√Я┤с",╡ ~yMDJ фB ╛▄▄<Н║q╔y≥nN├├z├.≥И≥%≥U╘)
xÚcd`aa`dd õu<C3B5>
Òö/HÍ NÌ+ÖuÊÏIIøÊq1°thÈwwÃ<ì2¿yþ¼áê•áèeý!ÃðCñ‡Ó",² ~yMDJ ÆB ¬ŒŒ<î¡q¥y™nN††z†.™é™%™U©)
)‰%‰
Éù•E™é%
Éš
F╨@бPGа=??='Uа9©╗ ©(╠$3?OДX░k@╝┘С─V1╠0╜Е`lg`fdTv;(цrЖ{╗ К6Q≥_^?ОЛKe~m∙ayЖ⌠WФ╥;ъ▐─Z ©в╡∙Щ√мЗmШ;▓Ц{>шЩОг╬⌡╛Ы.на'цзЫsч/^яО∙©Г\dОч<uм╪%С√╝·╠╜{В▒ф7©≈HX╝р²╜тЩ[╝[=о'ю' G╞Ш╥0┤%ШoKжъЙъmЧЯ~?З▀≈Щ┤щ▐Y╒Й┤"©3кЙч:cырЕкfnХчеЯ.dОoФъл!▒rъ/иЭjЩУИВя÷ьЫйГЪЗ╢ЮШУ≈l╨ыЕ╦Y ГСpЖППЩX!Э╢╕
Fº@ÂPGÁ=??='UÁ9¿¨ ¿(±$3?OäX<05>k@®…ó€V1±0­å`lg`fdTv;(Ãrö{¨ ë6Q™_^?ïìKe~m•ayö“Wæ·<>Z ¿×²•ýÍúmû;’ã{>ÛýïǾ›¬ù.ÎÁ'ÃÚùsÞ/^Ñï•¿ç\dïÞ<uͼ%󖮞±­{÷‘Æ7¿—HX®Ò<C2AE>­Ôý[®[=Ï'À' G¯û·0‡%ûoKÖßêßmþñ~?ú—ý‡Ý<E280A1>Y¢ê‡"¿3ËêÞ:cÙÒåËfnèÞÅñ.dïoæßÌ!rß/Éüjýõé÷ÑŸØùÊçÿú´àûõ—lºÙå¸Y çópöððýX!)|¦
endstream
endobj
493 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 1606>>
<</Subtype/Type1C/Filter/FlateDecode/Length 1607>>
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╨}<jL=гщm1гzщДAе"Ex╢n▐╝XW╙ы%ш╔*VитЦЧB>J6O=_ЖN╦"<▄еBY▄а╟'O#[g(4
Uе:┐~/Zф╚√Я╙ЪП╦Й╫╬VеяъХJЗ#З0 ТЗ(ЩwЗcЗjES3╘йо▀3ФP╖╗÷ИУТО^▒^Г╫╨╫├╫Нy⌡╫O{[ыбw╔┌kdЁTь)▒▌г╩G8┐≥(▒▌wH╓┌1В#√
ЧМ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  г?╚ю┘Ч∙$Т°Ю+>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┘|(Я╠÷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╥├y 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ï¥)<29>€¢iZò~Ôú´˜äÐ$£FŸªÒ­5äíâ?l ô¡•ó‚þ0|)úzK}ŽJÙ£B—œrÍ¥]o{¹æy»¦ Þ¢(:êMCüx œÂ!5QÃTJLÓ¬xºtÎð•ïÅl¨8^[ª)4,2ô÷òv±¶PÃ{» %…<éL¼W¤ÛǣƤÑs¬ÑíÑ×MT,R„GëöèŠu¥š]²]ªb•Lm0î/ä£dóÔóeï„+ÂÃ8P,”Å {ò4²u†B£¡PU¬3èñ¢e¼j¯ú<0F>«ÞëàkUý<>®¤?¢Ó@¡<>Ò§?¦?¡P45“
 ü¼8cuŠú™^OÿîéuÞ«ÛkØëž·Ùû´·E<C2B7>-|W*¸F6K…<4B>éx¼{„3˜éx‡D*s¿!Å?1b©àß®…®$@D5÷ZûÛì}-C0 }†¶”¶”šå€  ¨tYN²nSšþ]ˆ„Ô]Ž£ô>w€u—Ì”IBÏßã´\¸P²%<dqÈnLé¹å¿ÊÉô­d <0A> ËcÏÆ~ï"r ɬxü<78>{p†TP„5Œ§Âó:Y€‰d ™eþ¼¾¦¹! ©¡Ö|ü³
\è_‰ABÏ ¾âcã7g<37>j<EFBFBD>õ †$“iäõ»7¬ßXu?Á]x¡YíXí@A ά(Èÿsþò´ð² ÓýßØÛ{{OõUÛÁÖƒM¦&Sµt<>{H_f,3ó ù†Øm³×zø¹?ª_峸/sˆÎº¿t`ÉúžÆÐIiK¶c@(™ƒ:ÿ<>Ž¾æKænó¥ªo€%A?¦¡w¬+تÌߢ_Y†B`Qˆ%Þ"âØõv}óvx"ÒÒµéÚ÷Jå ±Çcjcj76¤´°hfˆŸÈ
È €ÌíxvçÙíB †ÇùC‰ß&ö¿ó5ú|Écž|uÛÖ7Ø7Ø|ÆX¾Z©`“„|ˆÑî <ËLÌ)b¶ÛÇÃ<C387>] ƒWȇ<12>PDû‰Æ¯ÚZºZºêÏÖXØ*QeñG•Q•ëo†œÉ«\ã®$ØV±óí!ÿ&rNè:A¾œh¥M ~qMUmŸvVtëøøkNöÿFáÛ¸8,7%@Üñõµëk”Í,Ö1O”df<59> <0B>ÛÓOt“©À¿T<7A>wPxƒa2-À Ïd/KÈ°ÈÕ-<åË6¬vk˜W!öÉ<C3B6>ñQW5ך€Âdÿ'ûñÆ[«zÖô,lD
0 Pœ¹d±B…S€òvÝZukõÓ<C3B5>d <0C>³º§íi´Ù:œì?D(2)´´q[3bóbó——…@"$šúG˜®®Vüä0<C3A4>ä 2H.+ë9åzKrz<>Ö´ói'c!”%™ªLµÒ”À55ýdŽ5Çú;Ü€ÑZçÛ[wý §Ò½š$€„8¹<38>D§HÌK¹é¦%€³êµ…v†~¿ö_Ûîn{TH( á@Äüúà77>¼'ß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ˆ®<CB86>kOjOú.uT9?=:%3>+¾$
¸Üo^!Sud)70a@¦œyôó£ñ…¡¢Ÿ¶;3#<06>vüváúek¿Õqòü•}Ùàr'
-(ãVißËa <¹1Jf_½—5°³]}VsB™°y_¶F§ÉM)<29>äv+ͬ¶¨-{»à[–˜Ü/$—¡³¼ÕØj¬Ù;@U¾» · wG^|^lkFkÁéBKù8]ævË©ÖæóÕ½œ¼½uãÏO¡G"ÏA`}h¡¢Î÷µ#¾bWËôÿe5-
endstream
endobj
495 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 6908>>
stream
<EFBFBD>yTÙ¶v!tu)L«”¥àhW먈:fÇ8
┼`1`√▒l+I▓Д°╧⌡$╘≤L╔┌q0▐9;:├К8Ц8^Ъ{у ╩\┤yО²j░.ОО╫Ъ[ЪZZPГ°зy{О┐eaA≥≥≥УК╨т}нраОх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╖q²vXj,╥ZQVяV/?KQя*WуМнЙнe²е.Ё╨lО╨╦КMК\Кь┴l.Шk╥≤n©r=8.┌шцЦ~ХпЩ┤n=Nз╟6ы╤²mСmОВД{nЙЫХСЬ^┼^сz²И=╫В~╣©З,?░▐ЕОkВ╠И⌠пГ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 Wq╣ж═b└wtьk╟G╪ц█M≥К▌╕!©Й─К╥фМH╧°t-╠2ssb]|е:длqУЭJмчsD3Жeн╘н,IDLBzj ?IS▓ZQ^╒╞VW*╥7G4Ер√й╥├кgяCt8foЮф░ u╨iН├╗БУe {%╙<║meн·9zC}² ,
х▐+н(G▄Т-╘нп'╗┴╔Rrё╤G■z2╖■Л°Йt}╒д^╜JзШ│∙·f═эЪl#ЫoA27cА≈с ╝_=sФЙ-▐сн╪÷е╠}~кVЗЫ╝\АХ╠ЩШ⌡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
⌡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┬ЙО 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'Б╬%Мg╟ гЩЫo░Й▓()НЮ└.╣R:У:G вИ░иЕжДn@zt╧Й╩МG▌ъ{xТ>╙Aуы╔≥╨лбэ"┌5:╫║&═r? м
[╢рqнЙ13 ·Ж╚═сКШЙМ■╖цуNхцг{<SЛау1To╗э╫ВЮф}┬╧yvФ╓1Сg:Р.hIcХсl=йкьл╗rkEA0Ш]─#д╓3еCщRJ▓3eш╤║QQQQ%▄+m╝╢t°╒▄nMЕujB╤ у╚@╤░ШZ╢└╚э╜╫╩ё▀лоН <аa└╧М^u3─aъMуЗ.F3≥AO'╫{ВТАk5╨ЙШМт= Шз╙╦Ш8мr[Л0eН╘╚7/°╧оЁОП>▀'≈ФOq°9wБ└YНщ╫|Н1/ЯуJV$ЮХsQ qyяyЯ(м▌u Ыf≥ц╓SP4┼)H)J+ййк$нIKM▌чw≤©┌╝lЫ╤ИН╔├g╕█Н4hйW≤ЙЛ У-т|Pxлd4sАъ$гдг╜ П┴РТЫW>;{У.²Тэ6╤ ЕGgж┼╫Ч(╔@3Y6╜Оь╥/h╚шPо┴cp|QvQN╡-FееЫ©
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Г▄Г<W╥o╬Б╠чбAь+/╒ЗТщяШ"7╜FК┌╔NjU° 2╣пIXSk}I;Iи&r+ГжмD3░Ш:оЕ╚V├LGnл8%Ч:ЦнпK}]эr╪ik]Y*e i╨$u:┴╛Т4▐ыKж9#w╡{VЭ-%XЧЭлу?║╨Ее∙╓∙!╕BЙаBиЖ2У ╓RE
f© Пё`Ч⌡юieZ┤рю╫ Хк÷QB÷`│955╗╖┘√HN▄└/■мh_|цЙ┐ч[Ф╒EлTe÷QЖ┐у╜v}ZШ;bьЧб÷бz│Щ/д$Щe}Т0У-·╦?╠`⌠╫тС√WGSщhn┴■9├}/.┌я╡nф_S Ь Р%┘х\н╣█╝▒kB╒┴К╣▐╧.Зw\!│╝.ЩPqт4Я#л``-tls╔╔юЧ)V│W!+M▀dx<┬^╟nuзbБ╟~ё·@/Ч▌²ъ~Ы┬╟_cуТ╨М]╦$/╤8МCВЧBи╙j2t F5■Л=о╫ ╚g╒≥h^└╖врЕ│▌х┴q$пЩa°З;t╣З|=# lk6K5┐гyхйp╨╙╢-7V┼▒[d]▄∙,╡╠ч ~м÷чщрИI⌡:!█И■дяmжз┼┼5П2⌡э√ш╓%▓tN╕Вш2#СМd╨]╧▌{tГUЮ▒╧wП7╤? Ь-═`║ЪиA! √ыTйujP÷^ц7рxнW@Ч=╔I²иТ©СУdy┤v)эьJYOТЫ╩л( ╕ОЧч9XЙ▀?Й╧GЦ╜й6R╥QE(=$Щ▄ ]▌╝%рQфщ^ж%}Д;еЬ▒+╢Ща└▌b╓▌├QЬEc2╝ч ▒┐8╠╕^f {⌠╔НЬпЬ°≤╖ХС▒uДбгAТА\K·BбаЛ╓ ▌& }KфaлЦ▐гЫ <Т&╗рфюdр╞wг}xo `~а4Н┤{аJ╛юТ≈═ h^▓JcE≤/@а└√B ▌┐4п?щ}ЫrэМ><N╖Ъwы
qP@ПЬА∙сФ▐ФUX)░Заз(1 ГmuАп а8фЦп┐hп╕┐А>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ВАч {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ЁG▐N©═╫#мК7п y█U<{ь-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∙wгГЬ ▒Ю╕╘+ан$=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<J╕X'Э▐√╫Ъ%k⌡FсЛ⌡ЯнЩ▀СFs┼у└■юЫRЧф/╤ T╨,[6S█╩и(pТ▀кW^РБ<э 2РZИ|┬КKRж▒\aвtf`gEх╖яъ⌠ф>╟┼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Бч≈&║<duХ┘=╘вM3о}Op╬С╚_$<Л √_╬ю]тSпрпEн °Oso╬'9;яа~Ю$▓ЁОЩ┐ЪWХ^П°[quАни:╨ ▌-╠Е╚aп≥@гtfg│▌B{╔\Ж√I°;Д╣÷XЩё├K(AbёМ╬╬ВЙу┐╩ЪД[(X┐▐Дд<)k:6%-)╠4╜┼©┤÷6╫а ^╨╡rc⌠ЦКhv8txс╟╧mB╣иu%ИЫ╧%═Й ═Й3t╠К6EЙ┐я╢,dХX╕╣©╖╔╨ЖNXъ∙BT#ИО²D▌[╫кsц|дьO]>▀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▐╪┴ъ╜г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ТТ[Q╙Iы╡Чр╒█I╩я.╢ё╨^╗╙у∙!²т*'╚UКkе1╣$╣kkiu'sCЪЪ╤Йx╦⌠`yьйJ╟ЗL|щМXH1А
Š`1`l+I䜹›$©˜q0<71>9;:†ë8ã8^ÿ{Õ »\‡yï<79>j<EFBFBD>.ïï½ÿ[ÿZZPçœÚy{ïƒeaA™™™õ˜?sºóÔŃݴá®!Ás¾œï)m<>?§Ä^fbo+JTwysÑÆ" §¼W¿?¥èMQæê®äÙ!¤³ôü¦ yRòÀZSŠ¥0+6»iöÂì·C‡<43>è1±ýàÁC¦…„Æ„iVGhFŒ?^ã£iÛÑ8ù…k5È/Q~<7E>!¡A~ÁC5 üü4«ý4þÚ@?Í´¹îKgº¹hº¸yh\ü‚ý¼Þ<E28098>ZÍ­<>_p¸Ÿ½Æ?$LØú¢ñ öÕFhCÇjÃ5^šðP?-ùÈ/ÚÇ/TÚ¢ õ Ò†‡“ß5ÚpM@˜Wp„Ÿ¯&"D£ ö Œô•Ø“uÿ<75>àMhXÙ";„”{HxD¸O˜64BC8º;9·Ê±Ú+Bâ®%ÛšrÒ7Ä'RÒ¦}/ÂK®‰ðŽ<E280B9>øxûi|µá¡<C3A1>^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Ôpj5E<>¦ÆP_Qc©qÔxj5‰úššLM¡(Gj*5<>r¢¦SΔ 5ƒšIÍ¢fSs(WÊ<57>šK¹Só¨ùÔj!åA-¢SK¨¥Ô2j9µò¤¾¡HÜ<><C39C>bv Ã¬k:273O0o6fAYô¶pµh´ÀŠÅ_ô<úœrž²ˆa˜æRG®£{ǪNã:í°ÔXnµ¢¬¢­^~¢¢U®ªÛ<C2AA>Õ<EFBFBD>Ë:]fuÙÞuq×Ö¹Ö?°Ù\ö×n1Ý~åzp.\·‡;ÆýÐ= û=Üzœ´am²m;ÛæÛÞïÉ÷ÜÔóÑçñ½½¦õ:Ó{zïýjõY~ Ëß×h¾ïcÓ'¡Ï³¾Ž* ¾áêqqA˜ÙV#½¡`K=Ûœêþ©UÌÀZ0{‚Ƚ «õ%å©%1üHºÂòªÒ È6e¤åÆÆáHáô²ZgH)MÖÓÛÖ'Ð1©é‰ úôjþ<01>Š­#M ?Òq8L¦LÒ§Ôå¨X—_½"m^Ðñ8,7-—P2 ÛrT¢Ë«®$ëOL2L¤×5'NëÁZ¡®â<èˆ-j­A!Äïè*°×`<60>x‡2×MC~Õ;Öo<C396>Ûr9éZbeææĺøŠu(ˆ™ãêù•š½çˆfìË:œS<C593>Yˆ˜„ôÔ~2¦$µ¢¼D_­®Tn nŽhÊa°¥i,•o —Ï¢‡èpÌÞÀ<C39E>!5ëtÓ*Ü QÅëËöJTyBÚÊœ=sô†ú":X<14>Wœ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~N3t |þ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(Äß¾”>°sûþ}AÛ}y•õþ3®P—WH,_š¢OQ§ Ì¬ôüÃ_sl²ˆFÄÀ)D?bà¢Â
F/ˆÇˆF
s1~ã`Ô °96Ÿ)<Jm§Ä#ïc
ÌÁü>P0R<30>Ÿ½âÐåêë;××B‡P}ô&íΕÕ.h63R‰fǸ­ŒÔj£½<C2A3>ÒÖDÖ5Å\G—"|öËÝE»Î‹Ë$™lB¤$©Ë/ÌC6-å˜WFKºJ†»mB
ÌÓ„„¸§ þû7è,pʳÇ.<2E>ÿñt<>Ïjw óÌ1<E280B9>ìÕnhAˆÿòèðÄ äꉺT\\XQyá»Æ눹ÍÍ™GžÑ!_spœè0a*3WÉÞÕß›ü lµŒµ8Cˆ&¼ÄNðˆËÏËÏËC¶ì?…Î2?N¹f§^Œ–ÆùEÅ%Ä´¦–hù¥e;ê<>מAÌ÷ç—ÍâWˆ¯WLTJ\îRÄĦ´y½ñúñ̯'O™5œ_€Ԭ؛^”•Ÿ<E280A2>˜”ÔÔ%'î‰=r4ñ8b@ùëã7<º¾âÂ×»%#B7þ bEüe_s¸ÛY¤ 6L Ýꥷò
㛨KãèÅ
Ž§ÁþPÔÑDSx$À$â{6Í/p<>!‹í¼‰NÔõŠPQ~Yñ¡MG óôœëȾ3¦Ùóó<C3B3>ÇæåGÒKŒ´¦bREüî¨kNÄ}K4°üÛÏ` <0E>ûóß ÿÔ%QRÜÁ \j¥têuŽ®Ó!“Ë­ÉÝ€ôèrÕwÛ<77>¿÷ðè}Tƒª³K3u™…¹EktzCM@å*~š¶h¥ãœÕcf<í VA§×÷ÿÔÛ)O‡«<E280A1><C2AB><EFBFBD>÷x¦Øƒ«;b¨ÞP¹{ïÁ<C3AF>ûsóìÌIcæÏtä]ÐÆЧÙz”—±™QåÖŠ`ö»GˆIgŠ‡8<º¥”$gʶmC£¢¢¢J+VÚ\ié8EÝšÊ5ê8"
Ô„lAªW<C2AA>l!öµh W¹[{wF™Ÿ'Ü<xÃ5rÛ½êfþ›ªõ]Œf2ƒžNz÷îéÃ×jtÕ÷Û©{öµTq÷/,pšå¶ØaÊÜSWo^8sŸgßá}O.ÍŸâ8sîÄ ³.Ü»{ùÜc^â«•¬H (ÀÑæ¢þâò¢óâQ*šëòÍ2‡I+¦ hS<>R”V”•—Iœ“š½7î0]ÙòmÓÝK Ï0 L*ÜiД¯0ÕÿþØê[¨ù ð˜Éhæ¿IŽ‰<C5BD>[àå<>˜éó¯>|vöê]þ::é¹mlA*Ê-Ž άPJ<50>lZß±o_ÐV·¡žÇàø¢ì¢œd[ŒŠ Šó ~ â¬âÔ" °ÔÈC_TX„t¶¨ · ‡ü·É*Î($BY9™Ù¤&Ì'<27>™X?ÊPÓÝ„š¢;î÷鸈Ñ2â3 2ó³mÊÈÊÎÈɶÉÉ&øLê@a†>/µÁäš™•‰ÒmIËÎÏÎ˶)È(É*&Âæ0*Wac-°ÈKñôw>'õAû=Æ´ä‘!½$)Ÿ<><C5B8>Ê_\n ÇŠñg‡¨ñX%rªvÝ»xïs÷þî]¥¤jòé(779%*Æ;iZŠVW‡jŒ=.00Z 6—_¾¸~|étõ
eÿ<G74q:çñ€Äji^m>sÈ");!71ó|N\8{ø/A‡<41>MÄJàÎ<C3A0>ÁvŠ)&+ÀppøÓx©X£À«dÛV4vi‰TÒŸ„šIt3Ø) <>ÀJMªD“bƒÖ'€‰Ï.Û<’â]ÎCFá<ýâî<C3A2>§<º¶êØØ<C398>çwo݇N2<4E>/ RcƒéT3-`?ü`œòÎÏy®nß|Åc;¼…ƒ8°W^Dõ黣÷EnZ<6E>×K<>Ôª8Adj¡“°¦Öú v1L,äV4έ‰f ÷užËW­ ™ŽÜ˜qJü9tÆ<74>¡—ú2º¸åxÓÖº²*TÊÒtIêtYéi³—¬sF îd÷¬ø[J°üù5˜«B?,*tË+I+CL…ÔíeêH¥ŠÌ~àGÁü7<C3BC>ÓÊ´¥<>{З?£„>Àsjj:PO -‘œ _(›Ñ¾ø†Õ½·ÌE˜©Ê>£ì«[íú´öw8Ä°ý…?…õû_0ˆIúËú èaê[<qbÁ&{©ç-¯0îò-Ž¦ºÑÜ)s û^\£eÝŒ%¾¦4ñ5kåK
¹œk]#ׄD×ks]ôï¸B]]ú¡â¨iâG˜#ÀÀZèØæJK<4A>ýS¬?®BVšÉðx½`Ýê´ÅÄaýF=<3D>%:¿ýòaÿ¾Æª3è'tÛ»pI^lqÚ‡îý…UÕdèŒj&(Ù{ž{VÏD3ѼO¯¥ËãH: ?úÃ8õwèjõùzFØÖlj1Žó<C5BD>•á>tUi[n¬#·Èº+Ydc?¼üš?½»¥%Ò“6uBÓ)ˆ£Û¬µk8àe6¹-·IK$éœLï·eFæÛÉt1ºr÷èΫÀ#sïàol4ñ[@;ÀBÿ“ƒB,³©”1êÔ* >½†o¤ñœ¯€ü{J“:“éçëÉ&òíR¸ °•²žèów™QLßý½%r° ÔÔs<C394>Æ[•m¤n ¢ŠPzHú#]K¤£Œ»½¬KúÈ=v4ŠßàðF1ð#Wh?þúƒ ÅH £ðŠ6Æd\½A""qbM½Ìö&KÝmñ¡ñ91OÑç#ëÈ9 2…<32>ƒèCù<…„k%ÙIAM4ûŒÃ˜Çp<<1E>òxèMP¥Œ<>ɤ_ïŽûðÞÀü÷•X<E280A2>é/A м$?”ÆŠ0_€-…@=h ºûòå¸Û}xœNÿï²â, €àñÃ+ \œ§ÍÍ«°R -ôµQb6ÎÚêÂ? q ŒÇ Ñ M5Â}žâ.@‡<>˜e“ž™•<E284A2>ÒãäV€H3<48>w¸ìša'Ú‚*³·¥0lùŽCv%b}·«¶L*”Æ97;p}lzJDiùáz†<7A>2D£(”ÁŸsÿOcø ÛjŒF£1
9°¡ï¯>âñÅœ5EI =ú„ìsøåî¦cè
ótÜmR³òþwÁ _*o_ó˜;{âb{ž86¬V,“@î"<22>°ÛÄybç%xV»#¦ï¤£ÈQã»'bgäÞ¤6fÔÅ1ìÎí±UkÑjÆqºÇPõpäx2ûjne†îý&5if;öîP²;…çÃn<C383>ŽÜêÙÍ×<:qØ·.¨&D7¹Üµ4L·®Ša·…U%lG»˜«<17>?V?@= çJUî^¾S²ÝåEþªý§”m0Q€ Òl'H…kÂTeœ>¹¬¢XW£ºe¦MàLl‰ì+ƒÊB“q¤ÏÌÞ´æP<16>ãSQVmL¡´ŒãGwñÏôˆéÓG<C393>t¾ù³~¾ûQ¢Å¤¶<C2A4>ª'§0ýl4(ÀâÇ<1F>&׊¹ÄÁµÝÏÒàGZœ]­äSc¤Ò<11>Ö~¿…=H³“Mc71Rñ½ìÐ`õ]ôrªî—hPŠýÀ¢¥Ÿâ2ý!¼A_ƒdðEÏo Åfb/…+<2B>-Zz-C/exjo:º¡€À<E282AC> mÄÜt ï—x%+‡el;Èi<C388> NÄî)beaÙÃtz6 ã` IÊ5D2Ó Ó‰ØvyꉟïA Œ<E28098>]yYŠ.VâØŽqil<69>×ã!°^±_&“Lê:I¦<49>
¬ý7±Ð—Vá.Âûží—¸×2Jê¿AmzD«`Ø{5—^Y˜JÆœiŠÎÊË*Léæ£$¡(«1¥¥úR骪(«„i§n¼Lǽ”<C2BD>hCý><3E>@ZûûkBü[‡§§åd¡ŒÖ±P‡Š
JJÁ\mÀ»–¤}t­”!1ézÂL¸¿,¾· Uboñ ‡miè<69>ÓJcu™åȶ²¼ŒÌ¹…¹d| H €“65É©ó7¨Ø0q,â^™Teã= ¾årj¨ÚÍJ\<18>œ•ŽR¤{³Ru>*$hù n{ñ^ÄÜ9±fï¤t¯ ,ZI:¢®cÜGólê”K_ªo¢ [/žeØ=<3D>3æx„;!ÆÙ³þÔ¥Û‡ÿà<C3BF> c{SÛdyk”e¨¼v!ô#
¡Ù%¦^qasK<73>Í.k_yõœf<C593><1E>~A{Gš×o +tò«xö°#Z°v©Îßqÿ|0á û ãñlãÀI<C380>ß¼yøèÆü7´µÖOø?û½¸F´â¼÷zÔ¸ñ{mp·_‡Aþ*ºZ{²a{͆jTÆ<54>Q)…tëÙ9ii—»†O%gÍ&ßû:Ü¿ø§èWá¢üØâtYÏ7®¦âÕr5/ ðÞhòãb®QMY§L/»5o<35>¡m9È“™áõ°äÙ°{èBÃÑÌÈWJ¹ƒh
o¹7&~Á³{ì&N°·ôè­¤¢Ä¦
0ˆLaU°œCMÙ5 {žL<9˜<39>îf7†»ÿÙ>VG D3>SšC2}ÖN<C396>t•îJ'ÞHø<48>,ª¹}î5z<35>îºW7v¤Ï@¢9Ds±Ì“%˼ô‰Æ†«êMè@ö¶ìcå#¦L¯+ãQiFIRÁÚbç?ÄŒ˜½h*ï6Ê”<C38A>Ïñs"ÁMSW<57>Izvm˜„P£é~2šî¡8‡Œàž×í”ü ú%f0ór(xöÎmÔ¼«ñ*ƒ9¥ÇB5fd´ÚWÕ°oçîò]H`Ø~âÀf%Û·]s+ð¤PîÕÇACu¸÷ê×»÷~5Öm£ûŒu{T·ÿÅw-5+[ßJÓ«Œ<C2AB>ö¡mñm(o¾¼<C2BE>ŒѦôÍÑ[Ö—KIÀÈS)ÇÉv„ö„úÑÌóCÕnÈ+b‰[åßýf eç}ö%éÅÇpx”L±Nø9-{ÿKÖ6<C396>¦Ù79âœûç<>æ« )3€ó¤ü<C2A4>!^l¨tY¶l¦w“Qàè—¯¼äÅy¸A&d*äµÒù Ö—¤¬%"¹Â ®éÌÀΊ<C38E>O£¿'<27>}`i”{(ŽÊ¦»éô&")vÄv
Ñrˆ‰)û²5÷ßÈV^ëDMûhBðNö‡"èØRóÌÑ*<‰'߃0YúÇÞ bSY÷Î^¬Çϵ4{£m…8ÕÌ™ì5-<2D>G¶aÿÙÝ[S¿kµ/<2F>oÈ:i{ÿ¹<C3BF>u v­ñ#ÓÒG ôùÇ穽њ(ߥÇÖn^…ÖÝ Çh—3íò]yë-n"ÎA&Ü"œ§©~df(¦w ¥† ¼Û7ï(Ý<> šŒºõ[¢ÊÃŒQ§•9ÔL~“[Bïr~¤šuwEÑóf3­H)<29>9<EFBFBD>ŒÃÀ4³$\êúf °`ýö Öî¸~<±ïÀ±ú}1Ž€Ð“G¿ñ¥n;¸¿$à>Fž9ìOÍ-ÕĽ/MByÈêÐ {R¯fž úžà|çW¿HxØ,¿|<7C>»¨§ ¥¡œv8ŸæÞ|Orv¢ƒýÀI$gÞûÿ¯Ðñ¾ :¼à9·âêÂ<C3AA>“ tt2[bËWà3<C2A0>ŽèÌÎ&…öJ¹0ì-“8wÈk?±úÿF —PÄF Ú}}ïÕ«wÿÉ·:2P°ɉyRÖ2tlJZRbiZ?lzƒ$¼teåÆ&ÇÖÑìpèð¦as#Ú„j“ë"JÒósK$@Õ@Õgèb+ÖmŠÔ£%hYÈбLkOKuí<75>°¾*…¨FÒß;‰·z—ç†ùˆ±Ÿº|<16>«ƒ¶Çl<C387>Ýž~7ítƶô­ ¤¿ß_†"˜E3}G}弯I]¢,OÓ'»ïq­½}ë]<5D><>ôö‡üOÄ^!®P<9sŸG Ñõ<C391>×nô7¸•ŒÒgäGV<47>Þ>ª,¹
U2‡Ï쾫¾<EFBFBD>NyæÇ•¤—µÕŤ·—êbbZr¬±Ný&€u­ô'æF –Êö«lé¨4 ´xípqù¯zÿãÏ2QvnZ¦o„SìÒY¬Ús‡Zý0ÉƬm÷[ÖWœ<57>¸{²èŠÖŠVX)šqÍ6.œë41K|žàá´ ŠšÉö¤oÿ f<C2A0>®¢ÛO7·åªüÔ&ˆV
A¿Nc;ü\MãAð\qEÖËî&µX¿–䉙èÚý !Xóé¾öíŒïŒ<04>b =ë¦ÁÅ·Ÿ>XC?%4OÒ?AÙ \¦ø îcá`,ŒP”|º—?FãÞ¸;î ÝMŸžJhGà9ïSeHkk¢çB¬·‡aØ^1ëÓÝ~ª±y¿[ Ö¬4 ŽÝè„û+0ûñÀ‡ «Ÿº™ÆcðS<ž*NÉN(M'*é ±—”¿`)%ß 6]gž†B%nÆ/צÍÎÀK…ªu0³8T¿yÛîšü"TÁ”¥êâ®Zé®ÆŽJä<16>—›–ŽQ.£2wovÝ:À<>=÷Ã+Oo -Eç¯-ˆØ†ê  É×Ôí©3l$}‰
v&»¢9¤<39>]M:3”À$éÓ6œ>Üt^-ßW·eoAež®•#2¸Æå„oE{%RçW5-ŒOMKR£„ÌšœÝÙCVbŽ¼ Q{Âׄ'G!oÂcµÐLÂ,žp)(+;>2luxl8ŠC‰ºoözŽ×­EkPX¼Öw}DZJ“þðXÚ:Œè<C592>œ1è·¢*T“²eý¥E“v£]hGu½PU«+C:©UNV«Ö׊cjIj×ÖÒêNæ†þÿmÕñp'Áò°••`õ™øºÛÿïM1¶
endstream
endobj
497 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 6274>>
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бЫ░s█ssзД╘3·[╥zцС'Nz]&W+$qЯ*я╢W^yE╢C-Й}" /VJБ╓╒ЯЬiБ$≥<Y,UM▀E╙x╠(V▓$╫╬beд╒Е Eо-\╬N╢P,+╒▓D+Sw$I╒EK%яb╘RЭ╪(V╕%Ч"┼√Ic$*┴L╙°, ╚E┴■rq╢/gD▀ЕЛ┐I"╧X▒,Q*Я÷E╔(N%U┴cD*≥H"█NJ█aмЦОceR∙H╝░АГиЬ чj╔L╘RF+$r∙[\9AюGU|■┼╣╚■Юг"Y,~3F²й·╕Ъ≥*J"U┼TБ kg┤X#Qй⌠╒ть.чJ╝░Ь]HUJ╓qw╜O)дqQ┼≤$╠р©/▀йщС┴°:J.ORШвйЭoУш≈╗■Б╓ьиwcП÷E%░*"°+2яR⌡-┐╬!ЪYbBп$b253hЯgb.ЯzП⌡°╔!╚┐жs╤QT"WасY┌ЮЯ1▄x└A<J<F▄$Ьд(┌&FАдБ Б)BH<M<K▄#ф┬Г┴┴идb*1█≤N╪Lл ЧHл$ФС┬в┴Ыддb!Я&╠┬XL,%√к┴дJb╠├XK╛#ж┬█D╠┴ьLl%╤sь4 Б<л≥хQsнsnM* ╨Э╞░-!_s╥p?#в⌠VР3ч8чUJA}Ъпяa├┤с╬5\Шх╪GЧ:=ТЭ┬ЛGГ?zЕ╠м▐ЩПь©F√СgЯ/█йu┘н6ЗКг7┤█ 3┘о ©6fЭ≤O·H{rй⌠≈·ZЫтъЯB║П╛ХQ▒Х╥PfтЕ9▀Vq~╩}Ю╖ ╥┐яmъЪппXPj╤*4ЖLп─ж╗о6ЕX▄ ╖Rx3╢+≈юkПЙ╘u?╔╓ {;╖>Б╘М▒ ▀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~╝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.P│N╞∙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┘ иL²0uК 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НС■`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╗)╞▌юЗФМГё)Ч╜%я `%╨6█Bё╞]Щ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╬СРзф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┐мтек▓▓╡Wk=С.┴▒ъЁ█ С╟╜GyТв&■╛$╗;z╣Б╡Б║╗ю·в╛фБA;Pи≤Ч─╚.┌┤Кzфщw~┤∙-Х┘·u╪!I╒╥⌡й, @UТП╣d/кчM┐>√ЕЪБKD⌠Hh`;┴╬O┌≥ТYь╦фнК?х▌╧╜О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н<iMj3·в\VВн.gg1·в.╤h%BoGiRQ"ё╓l█Pй╣Я░DмЩbЫO┌spнu╛▀°BB╞∙╛и\тЖwМч {>╤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▐╪░Ж#\┘▀н·5u█X_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▐(ч╫ЗЮnN░Lз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╢/-█бО=<wУ·|ХьgtZp√eТ╚├╢;'Ф╛@_Хr'u╥З┘╦6ё╪вШ╒╥ Go╡oсИф╔а▄7│ gб~·─фOб║┼╝vj-oClбj3ВC█~ч@!$Б|ЫЫ╞Bt╖РаЯцбgп÷╫ЁrнКKWн·╫ЛэGW/°ШDхР╞╪╫▓mХ╞?▀!w═ч╫[f╤Ч=╫╚вCЭ°2LXf╢└<s╨жyvCu╝;к²╣3$3⌡Uв~k├Д╬z╒╝ШоcFKIОЭВф
6южТХ╫ыПе/#▒ ⌡АЕ┤УЖ" Y─q3ч'▌╥о=З`Y▀~|ПЕ"^г©≥ЕСпл╟╖Q@■Х╫#шпБ Л╜_" IW╧nMмжЕИ!+<0жц╘Y~hHФe<∙ Ш│шэ╖о╘;©|aBpTr,ф>°╡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┼©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ОхЯМ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вц╬ОВбЁa
j/ЮCОЙ╘Wк ЁTW╜[╤Э╦╩ ╩**╟)╩чv_SЛУ еpб≤qл(┴%] и╫-6≤╫kB╫╬\Ф╪Згк&m╗б╠┘,Жп≥ъ0─┴]v▀Я╝Т*┴∙b┴оW█л-╒в2wбP╟ШУ∙ы▐K.┴2}кшЗнлчгН"v╥eP┴uЙf8ёdH╓э[XS╩цМ4█4 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ИТ
<EFBFBD>Z XSgÖ¾rsk-¶Æk¡KmÕ¶Z—ZglÇŽK­Ö¥¸/ˆB€°$! KHdÂ!$!awQQk]jµ­uì:m§<C2A7>ÖvÚi¬¶ýâ\þå» ˆöŸg}‚æÞï;ç{Ï9ïyϧ"$„àp8<70>F®Z1ÍäIÊŽ4å2éòçÈcÙG/ù'|Op|OŽ$| Ÿ0Ø7&d;³ûö+·î“üþ 2<>b?7?Œ?‰qøãéìÑ7ˆà\N)çÎ5Î<35>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Œ/ˆåìƒ)"¹X"Q*ñŸE¥(^-U‰cE*™H"<22>INeÍãïãdR•H®<48>áç)ø Þj¥L©RÆ($r•[\¹pQÀGUB´Šµ«”àÇ"Y~3V“Æžfà™*Z"UŠTâLkg‡X+QÊ“£ÕØ.ÞJ®<4A>ø]HSJ¤ñw¬O)ÄñÑŠØd±Ò¿/Ê<E280B9>ó‰<06>:Z.OVû×Êüo Ø—¨”â丩wbðŸE%<25>*"œ+2Ñr-C¾!ÿibRÐb*5;hñgb>ñjðëœå!«ƒÖs¶ÑTWÁÓÙ‚àñ1xˆE<L<BŒ&øÄ<12>áÄcÄãÄ“„<E2809C>O<ML &ˆg‰çˆç‰©Ä4b:1ƒ˜I¼HÌ"þHÌ&æ ˆW‰…ÄkÄ"b1ñ:±„XJ,'Þ "ˆÄJb±†XK¬#Öˆ<>D$±‰ØLl%¶óØ4 â<È™ÌQsÎs®Í * ºü¯<C3BC>-!_q·p?%דVòSÞÞUJA}ÿÀÑÓ¼9RûЇþ:3ôü¨œ‡>|åÍ<E28098>üðÈ¿FWðçð/<2F>És…Î6ö«G7‡=f
Ÿ~í±‰<C2B1>}üxúÓž¸ôäÊ'ÿ&H
…gEωŠE¿…2£ nÏY´ŠóÛ­?]¸Œnùþ‡†¦Â2³ÝP©±g<C2B1>´F}Ž)×b9•Ê¥]¹ ^<5E>—O­û)ãCmØ[¹ ™<>@m<>J\*X ë<1B>»<EFBFBD>Í&›Á–]ª ¬Õ™ô^Á…ÕPbph« ÕàûÎ*W[v‰å <C3A5>š<EFBFBD>J v­Ûà†J¨´9*lŽ"´P_òny.\¯á<C2AF>vŸ¼9µ)¾ê<C2BE>Š¥®°<C2AE>e 4S]ûÏ Àþ¬âÌRy<52>ª ²Ìá*³[ÐDµñÀ; mÍ™Õr0€Ñ—_”_TX”]f(6[óŠŒÖ<ȵR¡Hv;˜^ÄX
æp­8Ái³U¡q¨6,¹Qp°oÉítä Îvf ˆ€ êdxWnëæŠÜ Zëꚅഔꫡ<>¤àg¸±û‡Pˆ£ÊZ
Nª9­N*EYx74ï&MK“ !Çjvh.3!m“aLLžü¢×<58>CÉëÒZ´×﹊¡1ð  xÄ[ˆ¸Ò£ºr%°¾£Ç~Ïw­‡ƒ.hé®ÖÖ®.ikœPMƧ¤ÄÇïJé†ú¬¾ßh‡ûVN5ªêåèôZ óá¿fPèAO)TM¨pTvP¡Z¯/ÒËùÒtÞ`Ÿ 14|+û<ò¤¤3ªf5¬†¨LI|äÙË0<C38B>šÂƒé-/÷lèˆ?yÎÀ±šŽÎž“-ŸÃ·óõÏô­î÷¯\é^ü”€áðžÚ²xáÂ-ïß—ƒŠ½ÁèæíÑ4“°6F¯Ëi¸Ôƒ=p@qQMÉ×õa½ÏO䥩Ð`Ö Y<>Z¦Â`3¹
ê<EFBFBD>B§IT—í¬tØ«À UÆJ<C386>C_f´Ê<C2B4>šHâý}K½ß$l"ÆK_ûølOsãOß4ì…K
žþ%*X «3bâ%É©› ‰J­OkÔB<C394>³Ä]ÞVdu8ëšöTîêROìF!H²Ò&Mߺ#SÃÌa„Ôxߦk<h°ØópádáÂI<06>º ¾²Ñ¾ÉÞW¼ü˨ÕǧSÒÒ¥B<C2A5>×dµ[Y*,µ†£™­ ª\EF®ŒÓ/e<E2809A>RšêÖ8ò­9@ÉÒÒd¿<> Q¯á”ëp{wgË[p.ÆõÌí¢ø_]Ú×Ô§á€úpÒnñ¾ 5K€=³~•¼NÕ,tAE©ÝÞ¶§¥ü4P—I7GGÇmböb¤½8†knÑÌ£$cî<63>À<EFBFBD><C380>Åbž ÷Á6Œ¬„-ÕV+ØËÛ_T놶Àß&<26>ež#Ñs(<28><EFBFBD><E280B9>ŒÞb+zQÆ[æ«¡ÑV¼ƒËZVRi·»ÑÉqä¢ÃœfºÈ¤Ze«À¥ÖŠÒCu‡<75>í@½wdÓü9QqO —BŠ-¥Që4g%W¥É×\ߎF
¿‡³žÃÇ:÷Õœ„³3ã{æ!<21>$æø\y$ö¢q79¾ÅØ<C385>Xô ]<5D>F]¿ö+f…Âòü*³Ãbª¥¾¾eßæ¦×„Óà¥è׸,u.¼¯V¿ÒµwñÛ/á=8^Ó¹¿£«úœ¡÷×Ç 683j#å`xtóñžÎC@½yh˪¥â˜åØÏø.í×~ãn ÞÑ_z§{Q2þàÿè<C3A8>þBŸßßrNSÞ©Ÿ3<†šöò¬oÙ~>†âß\“¸Þ D× 1h쵫¿ àBâÉeû)þ<>ÌH$£/Žß¹5~ùò­<C3B2>'Nî¼(äßdZBÞ=³1rSÜâźNôœÚQª½‰Æ±gç `â¥è$­bFM9s`^QîNM©ÞjÀi¥RÉb<C389>¦~ ¼_|ï‹><3E>kpEý×Ô£â÷#:fÃë°)3>F§Þ«)†ûÕ´_=°·æØ J<>x´|Sdüv Ömï>{iïþw„— 3®òE|p<>oúý§#À~¿wàû¸¡<>¨<EFBFBD>F.^ï´;¡&J-e¥…Ö0³KSž FÐä˜{0 a¾LJ¹¹¼Àá.¨*/uYÊˬeP5§Ê‰ñgÔB3.&\•cÈu8˜¬æbS%¬4»*×eP^ì,õ-@ a½ PJnin±³!+'OWh +0YL`µ=§'xÏzÑ<O;¦<>Ñ tý*®ŠB?›¶Â`79 0ý#!Nð
«mPëìzÁ*&Ê—Æ$“òÀZ½AÓ·Vï09,M@½C2Ózù
õ…ö¦ë² PøðMû9MEÖŸå¢H/ÍÌ ?Ck¹¡Ù^ß4¯Ä3ºÝËŸî[ã;Oó/¯mJ°mÀ6•Á„2/
—ð˜)èa&ýYðx¿úp[GCMÔSÍ,ÿë '/7W.È5+´­xáÈ?_ò
/ò~ùð“ŸÐihÖ¶jºåN¥Õd3ÚŒ.sÛxqÓÆ<C393>·©¿ñ ±Ðf¶Sü鬈Pã“æ˜ujLßËùÐZ½Ázi±J<C2B1>$ pŒÝTáp;ù5œ¯?~²ûXøJå¡Lzˆ™(`ú± `“T§Þ'ðöòiñNÁ^Í®„VIÕ6ØLmáÁF],99)1g°fÑS?á’ý=Û¸0ûÐz”Oe"AÉJÁº£O; .+Š íù-j,´ƒ•Œé¸±ê"yx±> gÜýçwXYÑžë]Ç$z»©ÜÒTe/_Kö±ì<C2B1>4ègYþ/¾$4…„F¶“èû%˜<49><C5B8>AFm`ì¼<C3AC><71>ì˜ÛúO£²æâÓd»õ§qXíX'±§iÄšÎ1HÓéLK.(§±oäù<>/žÜôï<C3B4>æ=#©¿b|}™<>ÍÝI¸{Pª)<œxQ"¦ªç™fÆi‡÷ ½Ý(°‡îQ †À~fŸl/®©†Ö!f&
0Þå»ÃdgK®Ï$¢ñ•dØ­ö{íy×bi<62>º½€êåyC¾Æ:±‡¿ã¡Þš
<16>#ûj s|ô ²Ê½nªÌî/næ4y_Øoôò'ÃeP?<0F>&×¹Û…C¶8`7¤$lÞŽÍŸ¹Ëü naïoþL/õ=h°/ê¾d´gp¡Ý|w³å3<C3A5>Ib3ØãÉôŒ>èEW½üOÐx_8<5F>F0;¹ß’(íä2~Gå<47>¢òÚÃÇçÝ#úLÉ<Îô0ÔÃe8$ÿHaQ!É9<C389>žŸW€Ë<E282AC>õ-¥/ª¼Ø4<34>ú=Mú.=iÂøô)–„~<¯zQ9†s¾O@#g¯€û“/ƒÜ_[Ý&
çØûù‡9B2å¾'¸ <0C>ü½J#ÿMû<0E>=ô÷N­ý {xÊ÷=<3D>ÛÀ#Ì“X²¾ðO4MA|ô$š-„?Y~~}ÏÒæ×qm†üôשXŸ½4õ¹g_þqQÈçßý“Ž^/Zæçõ¯,ïl¦ÿI~=îÃÇÛöT…n¬£g|ÊðLöðìü7)#qe é㇠äåƒ «×D',2#Ø  P/šåwJáwJAÿ@Ô^gzž£>»{·ª»¾,תJGF¿×½ùÀÕý{ŽÁ;Ô/3®2cŒüO¹î¹ûs]!h
á]ìNÚùFü…}¡ùâ*º…g)_ ;vã¦it±ÓCŒzEBݶò<C2B6>8už:w¢Vï^BÚ¦nÓ_Ê}?§*¿6·.Ç•éÔöU‰óK`y«¾Ó?}—캒ì@ѱ=eù%¼­Ué{UP¶Óí9žzJ÷&vøÉëÜÂÉÌ1mÉ<6D>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âÔ—lf <9…vÑß1»¸(ˆ<ïËØU⮆æð¡õèýóí™À4ÎEéܧȹLz<jäÃrÜÕªØãËoÄŠŠL<C5A0>Uivå_À'AÁd(óHÇçGÿwHäí2TãE!×/xGü™nLÂzÈ4zàÓYŸ—<º}7ÿ43J óuQY˜ÎqæIkÓZð¼æ²ºwv;»Jð¼v±U+ªx;Ê’‹“ðµ(uk¤R®M€djþç? ÎÁ9×±F,rŠP½V²&kÝu{/ìy_Ø]ùûM. TíW‰=8£Ü¡jhÕù±î“ÍU½s4Ã:ü<>nLí!OÆï×<C3AF>ƒá­ÚîÃÝGÎÀ%xWyvËá-‡×Ô΃°Y³]B¡g#écÐÓ*kPTJ …B&—è653âôgBhwµ76¶´´;<3B>cI‰¬ñrÞÄš¥Ë7†îÖzé<>k0§Çz¢«q4&<26>ŸÄ<%„ˆÚõûcŽG]Hÿ®ÂEçÏ<>Úú&¬/[X±<58>†|ƒ15=/?Ó¬4îÈÁëXyà !ìuu65µ´v¹NÀa¬¸pvªKÒ¬fÙf¬¬¸Y¹Ú‡Y»<17>À.µ0”Wš¡˜1“Û;6W­€¹°&}˶-Û”«`),iXݽµ{Û[éÁ9ØWqª“J@ïn}p''H¦í¤{ü¨5*\‰Iý¨EAH*dÍŠ¦ìvèÀØu°;æÇîÚµoð<uÍ£÷ñ<C3B7>€ ºÁ<ËLdB&0ä3M\<5C>Ÿ«<C5B8>xÊË]à¡ZÒëääXr
¦)ù[`&™Uç©âktåç:¯bhÏ&T­õ }½÷¿pÝEáÌ9‰¾¡Ñd²œ¬ÿÃÉ]d{sÕÁn8×avZ…¥@5ÕÖµ
¡^ë–—%Ù——Eã÷œ¿zš0n O>|ì3:-8ËŽ2úUÃÚ<C383>sV  »“ºSýB\ÑÞoû£· GoªoÛåÆ¥Á<6a΄ý< =&< ‡*»;¨µ¼ q‰«XÌÜc 5úy<>ˆóÅg¿
ÑíªûÇg#œEúöÊy¯._9wîç>¼záÜÇBV•éí“ähÃ@ýY yƒõî<C3B5>ú3³õ7äé½âç”áøcÂ2£eä™ÓuΣ°jòÜÙîì<C3AE>9 ¡˜¹¬ºö[4$÷×sÈ0u=p3ZNz¾;N°¶fÄìèˆÏ<19>¤hÄ,/ÿ;¬·—ÐÌ"Œ›ñ¸}Êè™ÐûË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÷<76>Áµþ„4
 hÿó]¸7:reBæâ÷¼!¯íN«³¯utVÙ1"Mv½Ôÿ;5á-ÄB$ã}´æ­y<1D>¤M¤´'VÅB
ddÔ€Ïÿ`Ç(þ´;üü‡Õ ‡¤º¬}¬ÃþAqhá&çÐTŽŒ-%ùŸ=ÑæîêBj“<6A>YäŸNpŒŽÿ>¤úŽ¼”ç2ÆìJlØQ±ÖDµ¥¿Má!ë2å[¾õ4ó Ã<>ˆiv,"ŸFì/ò&h†¼ÅŒN¢¿¾¼rþ¼E«^xaÑÙ<C391>>¾|æ[!KOˆçE¦;ù]údÌaÍ9öºëæ·h¢Ÿú‘ ߀hͦhêH óîœyh³ŽÐ Gm-¸‹¬Éî—[«Hô¬/Š>톦ŒÖôš8H¤^{#rÖ̈ž+h«éj­´ÛB_ÙÏôŽþß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Á:ˆ®<CB86>6vi\©,`…f ܉¼À5—CSe¬†
°—Û÷gžÐŸa§ÇïÏa¹Ñ<C2B9>zh[CŠ;¦|žc™Ý\”]¢)ÕÛÁNUĘ·dø/õ¢Ç<Dâ,Hd»ëþ€Ýã>É5²ÿß³úîœ 9Ø#=¤R3‡÷Y°‡I"ÿpe="'á3÷ñú½ng4` €S.˜,Y†­ª¨Üõ YYN…¹ÌbdzJ¨ÎÙŠã¯È`_Y âÃ'5{¿‰¥ä†µ
]$P+dõÇ…h7NÚ¡=<3D>ª]Öò¢°*ü&¬¬Ù¾?¥MyPwNC«ç(õÞpÖa5ÿ8ŒÎiJ3”Ä-!ïÕ{û§‡»d@õ»Hô'æî-ü­ú<C2AD>M¿ÿ&²ß<C2B2>ú
³„{<7B>üú¶ÝÊÞ<C38A>™d¦é )0št£†½è <0C>«¿^ËÈæùôw&¹y!6ìK¸Ë>XÉøw™† °K4Y€¥u‡å+æÛ°ïûñ=€ðl†‚:ŠùзzúàÕ2È*ÓÕè""Ã"Ž»Ëñ±«Ã¡²ëm÷4Å^ß 1 'Œ™ÀŒX2Ô<32>Ò×bƒÙk°!4è+dΫo‡}¡0i3AŽ-d³×€ÎÆALì²;XŒweTK¬K|¾ `^1½!¸“†ƒ= ·’†©Ì\òH”åhï?3{g¸ƒØ<C692>A%Õ«˜‘Œ’!roQm5ì²Ó Ò4¸ÅȪջó©PT„ñ†OMC³ÍÞRÔjõÔâ1{WšG²hÅŠ…f6äfcjA»J
)ü¦RÈ(f>oáù´×yv  %£Vj•Y<E280A2>þß<8™çV¶Ö·”ºá6R<52>”hi<68> ²B©%#/O©Ëè¸|þüÂ6šKmMÅmÅnöþmW;igj±Ù?ïÏç]YqþµÄ´ŒÈ<é­–<>ý¯ ¶±¡$«Aª™³`;¶±ø—‚[£ù¹>­<> 3@oÊ<6F>+uº\ÀÂߦ®¤øó¿#¯ŒÜ‘Õ±[¥IúLȤä ÊfA5ØJÚšÛvØ ÂP«¦ø¹ç×íMßû`Wu×áö}6vŒðÿGh†Ç·ÄƒF{<R0"¸|ÂÿŽ|àƈ~g9òÆȇ|?Žù?Dàéñ
endstream
endobj
499 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 5530>>
stream
­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еф<O©жжХ
V┌C┼в╞ │+c ╓s2fV┐ygl.ЬКL─Nh9ыTф6■\h(╫RжU8pФiНсцЮ6;▓,OЦН|╟г+с>с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Э┴▀w9░J>²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Юоб╠╕%СоЁе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▒├l░Nв▄г^бcдмX╚k6А╠дqAO│⌠к≤RdJ+{T$║%┌5)8уrsБRF"║'я≤-Б╟нFG9ЦЖосXdц═▌QхылП\ v║w2ьH╒~│ф{Ъ╧< ╕≈BГHСяЧ┐БЦ?╨╬©┴Щ√лNgKтeз╗gтэ°а┴x╛ OMгFБ=▄2H╒чIc┤?Lc-o(D:yH?м`Ь` ^.x▌ ь╔п#°s@3Lъ≥╬цS. <)╚Ybuке▀≈Лп└У_╬·▀д╬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
шН°}l\зщ╬╜}[sz]йu4OвЕ╪{▌Г╠╣г\8▌Й╬xе╔┴`∙М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▄вЗе.П!я╝°{вН╝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╒·2#eRФе.v]Йl╥дсd╓░б)Х≈vе°ш╤╥m┤╒хчGCБЖ√⌡ b≈;Y89≥ЫcM!nз2ъ╛ееI┬[/\9у]ч]чшщ?H"≈&DN▐A┐f
█-≤X╠ыrш┌╛ыБ/O4y~О╗hx█╓sXсЩ{DЭ│TO©/{[Я[цЩ╝╤н▌ч┌~╦ -⌡+б+бO╞┘U0'щ0б≤└мрае│└мEПгW|V:в ▌6iоИ-bя▒c╛wZп▌█;┌В└юRpн k
╧■~·}СP╥■A║─∙!╣⌡HМо─╢ЮArоЗ uV╧` c≈;/wv\Х▀?л╕`-Ai0W>В√ {кФ≈(4·QO▒ф╣@у▌╪тs╘GЦ!╛ц<≈┤├5р╠ ╟;·]М╫р{МЭMSнмRfq?бМ╒╤╝╤╝ ≈Ыhз╕тE_2yh2█w▓сН▓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кя╤ё-┤/╫|╓У╢ю▓БЦsЪQРН╝╦ЖШK²у²у]g╨│}сЛg╗I{6Нp!Г╡S(]e
JG,3Gя╗LBJ%'╡╜╧╩
Р▐²мкм;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╛ВиОsъ÷~А;qмщ├н╤  Ж3p й3s▓s▓G▒цЯ╖╟}╒ │0▀@ХЪЖ
╢┼a0╔о©а╥я▒@ #ц#ф]ЙЙИlЯ_╛SР⌠@▄╩└5²51┬╨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УЦли°ШМШ ч╟?┼╤П/└сВE│T'WD·≈пЗ6c`Щ_╫Ж²RDЯQ╪┤╪∙v┤П~╬█ВГ+h╪▌Хр шПfё-Э.e║2QыCёУ ытБ6d1Рv%√D:FЬ├Kе1ч╟eЯTQЩЖфщM╓Гх╫ZO>z░HН"║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\„þêÄ”¤Ä”<C384>Tib©T_@ªÿ鿾“µµhMj¬Êg”Du†ÚUcõ…Ìrj•8€€`(¥E<C2A5>£ÆSS©iÔtJ<74>šIÍ¢fSÔ\Ê<>2¢L¨ù”)µ€2£Q©%ÔRjõ9eNYP6ÔjÊZCÙQö”åH9QΔ åJ¹Qî”åIyQk)oʇZG­§6P¾”åORËU)jŠ<E28093>ªµj<C2B5>jj¡Ú85µ5jáj¥ê«Õ¯Ð6t£Â|Île1ïD_ˆ~eÏiŒÑ¸¬ñtŒý˜c~לªÙ¨¢uglò8Ýq§ÆwLX9aׄ¡‰¦WOü0iã¤L>9ÅjÊnÖ6ÑÎÖ¾­ó¹ÎF<C38E>$‰úuä#¡/r…“ü1¹ §IÕœDý…|¬&'a6HèfálÌŒÜ&ïÑÈ„QˆåǸ<C387>
o¬¦vY+dÒ&8FG‡§kÝ…DzpïÈÃ3ƒ¹ƒ…=euµÕ¹õÀ¢¿bcž§ßk
kô8g+Á!Åkƒ×†À•1Ò93«Á¼36|/øu¦ @'´œl*cJ.4”^)ë*8ó4÷éápI§qw>Øã•iŸé˜áî—æ+HLNLŠËŒ&0¢:Ž<Êù!çqQoymymMNÝ( Âhú3 ©AÌŸ`øv]Fc)ÛXZS_Ú]Ö]x'çiγ#à;NBÈÓ$´-×&Åþ¥tSܦ¸¤Äèäèd—HÓï{I÷á! dwV×T×´<C397>¹,ΖàÅœ xæÕm¬Më„ÛÐ|øbvÍ™ª¢ŠÊÒÊÒžª'õ¨[¹Fw¥S¨OšOÚÚ,O`•FHƦËõ;÷;ÿ‹Ôá ((º×ø°i` ]Èà t<16>E¯Ñô~´PŒ-<ÞÑp™ >Ï
/64Ô UäTçVi€xžp˳գÕ2ß°˜ÆØÚÛ:F/¬ÂqÙìXÏ´Ÿcë¾Ú}Uü20dÇ)”ü1¹§ÔA3xþ34Sù?ÏPNUŠñLÑ8ùäv^Êñ©LZD+eÌ8þÄÅ»H%ŸÎ8<C38E>qnç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<52>“¨'ËÛø®SA#+»<>\¢± 3\3šKž úš<C3BA> ùdÆ)§3hZTØUܕߕ׽3‡±ÆI¬I˜¦Þ#?"ä¡R“Á=-Æ +@š¡‡C<E280A1>.#5@3` ½7¤5¬Å£Ò*‡=,zŸý¸¶«¯«¯èüÌ¢T<©ã Óñóa†{G0¢(æ5Üʨ—ÖEç®;ø<ÎÑÕÏÕÏ\6MoØžC,_G£,æÜI¿Ò–çV`»Òi<C392>“Ï$<
 ½˜û^¥¾ ¼‰fèÎiÅlÖ<ðgáXÓŒù˜YƒçÙb£h¼ ° `ë,yiør.šì‹–Âôîo9Ôr¨ýDgKœŽÇEèo6ÌÀÂJ绎ßž4ÐÜ$iE“ÚЄ<C390>×/ú^öý^Xí-¡§(T8@ký<C3BD>ñ[“ß°þ%ìBìõ'_¡÷ Z Ȥiß!ã·w·<77>˜Œrd
Ȇ~9œÀáe Ú'QßO#;‰á·È«nÚ”aÀ³ÈHÂSˆØø`µK \ Üñ˜8<•,­ðGG´Ž\<5C>æó™4ŸVæ1H•/¦ù>¦˜|}@@ÆÈ{ä¹lB£ZÆXéa¼4s6ˆñx0©°°<1F>MN4/I.£±dÜyýòÆ«þ¿—!šˆCß®®Œ+í›/§^G&ºvEv¹öÇìŽÙ\x`q(ÖZŽµ,æcžc<C5BE> ¥øsÀö€W5ãÏ~<7E>÷ÆMóG¶€¦ÒÏC³/±ÈTî/€ŠWÜÒF½£œ´d°xX•6dȆTilõOßY1È@nKË ≤│┘∙нw©▀} h"═╧Hр┼&╣║ ╞_Т╫ЛШ╫з[BOQ╗p─жЗ#Ц╥&©aЩKь┘$ыКO╬BО░Iр╬CфoОn!1Ех░ qXg#ŽÜˆ£œqûçÊi,²aPÇ(älfx®»Ð;l$Q¿@ã½ÿ\žÓK¡s¤ùhÿ‰Aññ]ßßÄ~Kf§³%ê2mÔ3jnÎ`áŽD<V†§¦c#ñF$Q櫓æ±7"<22><¤ŸƒæŠ0|°/<GìRèÎ9 ¦ïLßá)—§ëžŽÕ,±ºåb¬îŒ ≤│┘∙н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х≤│┘∙нw©▀} h"═╧Hр┼&╣║ ╞_Т╫ЛШ╫з[BOQ╗p─жЗ#Ц╥&©aЩKь┘$ыКO╬BО░Iр╬CфoОn!1ЕхрьЙ÷╬Ёb░│э√√2xж╟╜@И4E╤6~'©.÷,÷HЦfьcькЩЧl4▒├l░Nв▄г^бcдмX╚k6А╠дqAO│⌠к≤RdJ+{T$║%┌5)8уrsБRF"║'я≤-Б╟нFG9ЦЖосXdц═▌QхылП\ v║w2ьH╒~│ф{Ъ╧< ╕≈BГHСяЧ┐БЦ?╨╬©┴Щ√лNgKтeз╗gтэ°а┴x╛ OMгFБ=▄2H╒чIc┤?Lc-o(D:yH?м`Ь` ^.x▌ ь╔п#°s@3Lъ≥╬цS. <)╚Ybuке▀≈Лп└У_╬·▀д╬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┴о ≤│┘∙нw©▀} h"═╧Hр┼&╣║ ╞_Т╫ЛШ╫з[BOQ╗p─жЗ#Ц╥&©aЩKь┘$ыКO╬BО░Iр╬CфoОn!1ЕхJг┐4JdpR═┘-hБ┤Wh≥≤Э5 o@)Ъ Ъ╟'IютЪфsЭ{МgP└Р=█э╪K>}щ▐фёy─╤┴я^l└фАKсЯю╦GЬ4┐Cл li┬╛▀:К 0#з┌t╞^├┴≤#Х-≥C╚▒Ш
“ŒI™3h»â<11>'3ØšÎbz"üKü˼OºÞy<C39E>lá¼ (;®*®rk'|HåÔ»²7eoï_éìîì+º W¡9½2´24Û‡”eÃtð¹l˜Ñz g7gWç8§Ñ²ÍצsïàeéãþGׯ½¬Gc<1A>æYDôH<0F>(ùźëë®Û”ÎgpÝâáåæéjÉî$5J”÷Ûé§ÙOòÑ„2´<(ÿJ£‰Ì-dEfò<*›¤—¤}¤UvS¤sH³{%6&˜=7Ú0Ðj­<6A>§<EFBFBD>[<>5QU;I Ê~SóKÕ/­û{¯÷ö•\Ê£)¿/<2F>—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<E2809A>-·-Èš-þñD“ç÷ŽŠ†×H:‡5Ý¿GÄHõôû²·¿5Üïjëìè-臛в¹"¼"üôZXsÒ #ŒIØ,\HØ\|Åg¥s]Ðz éhÓöœÞ"Í9Æz§íظ#xO,ç¼°¦<C2B0>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™<79>&¡mŠA]ô%“‡&Óx'ùGe?Íë.)—ÔŸì‚ Pÿååͧ»éPü¡ðoÃÆ~“úðEÏZoŸ“8,N<>«C3häÃàôþ «4<C2AB>¤PqRhø¦  ƒO°x†¨r{íîÁUGO<14>ˆÙplÃÁõ€'€A¨¥ùæaäxÆ<78>÷1¿<C2BF>вØÚMn qÒX©4#a]~hK«µ"ȃÿ¡è¢Ê5þ¾— ɱд²_ûío~ Ä7Oú¼ë|ê–á±du<64>ã!ûc¦§}›• ÐÒP÷ª<û«Â½•Dòà÷ª{ßÝÿ¾úïB—vm{kÒuNw$Oƒ9èι|±öbíÕ¢‡§Ðâ­ºÏv^ͨ<C38D>UÈNÇ@(XIÝíCìM6†y8<>..N»—Yt^þŸtiÉmÎi:_U•_SX¬Ú¡v{QBQ‰Pð¯,Ÿtÿ4ßøˆðÄðÄÀíë€]!'â‹â‹·]„Î<E2809E>|<7C>×FÌmt§ ¥æ#îÄÍo;H<~”Ýhòo²?·Ày{´k´‡Ër69}ãdï±®ã]Ç:Ž´m;ÚrøòÑËGZ<47>¶ÿA ,™!>>÷%/êîŠk¿¿ÔÙQÝYÝu¦Ø7Í~†z<E280A0>´r.;…ÒµQ¦ tÄ2sä<11>Ê$4ñFü¡Tr"Ûš»«Š ÿØټܼ#硽Pì1]
‰;6¥neÅA¤0žJ¸öÜÎoikm©úábéÑ^ë’ħ$Ø O[koâp?:JŠíŠð‰‘ËËû·Å¼þ¿Å[Ñ ßA
UñÓ2¤[…Ö Ž;Zí>nÛŠyÌ ÒYìPæÐÈ<C390>ÁMr ^ÊGÑ8<C391>¦<E280BA>žŒÊÙïÁ„Ô0…ÜEðÿ~oίÅOjn‰«ï4´µV“Ov4Cef®ì\ò<11>‰»ý2í°á°ƒ®Ð¡Ì/91pð
ÔáYêõÀú€z§³ËÀœÒ<C593>ÂœBÝ\½ÌÙ]Ìî{²«¡C/zæZƒ¸gxE{F{zyZ²_2¹(ˆÆzŸü.,1÷ýùç¾×Ümèl«i©i?Ó— <3'9'ùp9
Û'ʳ„þo¯@«Súü| R12<bÜ¥®žÎÿÅ:%? ĸKˆQÓY#ƒ¨Kæ9Ò'•B$íöÏ´ÖÙ.×Q¼&Rloînîá´Ô«ùau™ÐãL¬S1{ÀzÀú·4ÞÁ«âÇW_í{Ú„ÔÈ8‡4ɉ<C389>¤ùÎæ{»s«ˆ²”³8R{·ÍŽ]¿0ÈÎÛÏÛÏEf¤”„47m"¢ N¾)ùñü³ú›]Í<>Í}yÀÞ†NÙ…€ZÿW°úSé|Ô'”ΡtŽ9K2œ FòËu×Ö]_]b&È ž°kbc‰|1ê†çyMËÛèer=PüMñ7gÿvê*ÝÃL<C383>{e@sLsÌÿEåÄþƒ8/ÖÜi¹“Ó?¬å<C2AC>µdÂÁš( F¾YsãÝØWp zN_©¸RÑÓÕûˆÔ±X¬±yÕžø9ÊT]=—0Kh<q´ÉdR®F5ú—”zŸNÇÞ¤ùW1#MHùoåoîwwtwööC\&MHEèiovvúÜ°y¡óÖY:¹9¹9ǹ U¢E¾ <0C>ˆ]ÒíÑ[c6Å%Å%†ú»ü;i>ðÿý¬èÁhr4¶·Ô´Õtœ¹
åPþ—ò<EFBFBD>¤m
Û(ˆ¾Š\†®qpaWÕ¶me©Å±EñEëËlkVÕú•É
R v”@%4œ®,/./l>Ñàîöþ¶#¥ MÑŒUó0CZUX”è°ÖÁKº
€óiŠ€«Ïüîm¼u6ùlòÑXˆ€õƒcc\2>6|¿õ9ásÂ77 <37>ÅD/‡RÉ©}¿ tßíª|¿“ ðzHƒ†¤ÃÏl>óeÁR| îh!]”O8BŠcÓŽöÓF žˆ7c×Ûm„ÞOV¾Ý±v<C2B1>/‰Á2×£>¼.ìZú œ<>K~{ö8G†ÿÎÈOíÝzRýiš3l¾Íf·'„Šaé9ÇæÀæ€þÔ'¤yé9Ù]Ú]ÚÛÕ7È%ÍKÐhó²Uc f®21ufÌÂ`kq°µ¯—Wù¤{×ôZJ4í&¾¶Cä ¼™á|_9íì<C3AD>',ÃΤ½†›»ÐØ­ÈÚ™—ë¹#G‰fùmÂðû>½o¯œ­<C593>÷F.Ž\”d³ÙÝÃü­n×ÏþÔ#ùº¤¥ÇMÃîX7P?Μ̹ÿѾŸà û£h ÿB8}_رAurµAäy <09>¡a3ÖÿÕkÑ)EÅÛqÈ[i'pïçÛx¾Æëˆ^+Í° o6ÚÂïR*•=4ZÏ<5A>M½!nC#oWbI¤c„o¸T<13>á !è@ÈQOÕooÜÝDzÎ<7A>Ü«õäó ‰ä.ZU÷£þ<E28098>²>ÚZm<>à<EFBFBD>ê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
<</Subtype/Type1C/Filter/FlateDecode/Length 475>>
stream
xзcd`aa`dd▐t s█ сЖ/Hм Nл+жУ,IлиLIЫкq1╟thхwwц<ЛЪ&Эы)цyS├#┴У┤ цrL?Д≥┬╡тС0и200<Ь)$/ 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†#‰õ‡ ÃrL?䙈²Ôó0É200<øAä)$/ 1°22rð¸‡'”æeº9ê¸d¦gdV¥¦(¤$$*$çTe¦g”(h$k*è C÷üüôœTçü¢‚ü¢Ä’Ìü<=<3D>ƒ@.V€¸ÎZÆh˜•_Ë°œý*úMTæ—×Ï»@ûßR™_DeXžýä•ù-ÅÎ'ÃÒ«ü§Aôq÷¥<07><ºùùÒïBßk~Ý“øÞȶä»0ëï& Å0ïá×H®\½cöÑî-Ý;÷Ulû.*Q6%wJÊä”IÙýÝ
ÝÖ¡Á!¡‰:9¿%KÔ%~'yÖy°~eû]þï\•]i@AdARJYDwvwÚ¤„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
<</Subtype/Type1C/Filter/FlateDecode/Length 1080>>
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╬"<z²╨ТЮяj⌠█сpvнjХpЗu WaС?√JнjЫ╞╚┴█IЁ≤-K╣и╗29┼Tе\y∙мb.u╗ж╞Sеедф╗дnT╫кqФ2⌠*∙Ё∙s╤"┤┘ЁjЭ╤T~_╙Ъ}╫▄┘И$╣╒dQ/хOи⌠dЫ ДГдz┌$╠┼Х#I3Ие▀Iq┬R2▌v))Тfyf!]╙Pz/╡Jи╪g╧┤IЕJ ГmПЛf┘YЧN÷LНфк!6√е©÷²╣9▀С╟х│┐GК▄╨²8ЯЖ#
├Г╟п6Щ3ЩЦХo}Hз▀≤f!┴б_╨лNб [wn≈╬A 1─%┤VОS≈i
сrrsРМИ░;Z Г]x┬<В╢Ц!сЧ╟ГЖ░{х=зr гн╞Z┴j╫Q8▓ЖmаН)L═ю_Н╤5+Zо7754т≤И° н└#╨ЦFД╩*Вз=╫+ш▒├Р=╞╖QДcдL/▄-▄щt╧╝╦:╝6У5У·Ы├ЮwНжн│²[[VC
hk2l╤wР╥d0ЁX|ГЗpв@⌠бщХ>с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<k°╩<wib╓╕Ы1ЭХСё╢ш╘╥ж'Л^`эkТh┘ж5{▒8ЦAФ╓╕к`l╡'Е&ФИ2┼Б 6WjЮ ю!МF2G╡ФЖ"
фaЬЛ`s╫╣ГR╖⌡9MБ╪ВП u┌⌠y8А╜sqМ ▌⌠чqLвнбБЫ╧ksвНщ~Рсс~$КBQ](╨)╠▄▐EцЛM<pQqwc:lщ }█А┬║б╢©тZjФ
²Ыг>├TьуdН)И╘┘÷а^ш÷#ВGНOw/
NЬ║_│Eшh4&э>┘╥яrgёwФ,zЖМ╚iD).░-Ц©]Я/\Р\
xÚ=mLSgÇïm{o¯ ¯£ÐiTlDSŽ77:6PZK{±-TP¾$Ó<>-3!š8„Œºj¡]7‰(<>MnêbæžÛ>ÅìvKüò{þçåÃù?ç<>„DB<44>$ùFöŽì=IyQš
½éã“E•a-)7úJšÕ~„äôº5¯„¿ôåYo¯bÙ´ÑR|Á‡“|„ˆ_+æYÉ'þ¢7 }ÝGÿE+Á$I<>I2²•¡áëUe‡<65>×èÍœš³p&½@«Í§÷q•fßc¬òåLÆÿJ1ê˜è£Áh5ÖèuJ]‰µDYÊUT<54>†2«r]ézeltL´J@ÌFåŽ3”ë•Éœ¹3—X<E28094>œIí³¥ôùRþïëU,L'©<13>õ‚ü”<Mž!?#<23>üœØ@0"$"ˆi ¢81)RHÆÐnå`žL÷œ ¤K•
O7«<EFBFBD>,¸—+pˆ<54>p»;—bü;í~ÚU^á°±<¬ÌÍ…X\€EV¼ðjÀ!—Ã&Æß}¢C<C2A2>ðÛf~`f~ù­I{Ó,$Q(ã CWÙûpËÜ•ß™gO…hÀ#k¨ÊÕÅ)9ù9Y4H„ì­Kë²MÂ#@dÃÓŽ‡LûÞ‰Aç s¤å02·…<C2B7>X…ê<Qx íÝ<C39D>Ó˜@¿L ´5Ë[/67Ùíµú#[¼-þ˜æ¤¯ðNË<wïªv¤¦¼/êi´æ1bfGGo8××úšzσð;wg—k—kkËZHÔÚtsºù½Â-éÌß½9Ôéj;<1B>çûá\;ÚƵüJ{A{b_µ±¦Ìd(Õiu©»Ö%{“ðX° Ë)™gÁ“û ÛŠäÖÓ¨Èó!…‹è¥Á—{-8€r‡Ò‰^)…Þ¦§y)…HÎzµ4œŸër¸n<C2B8>,ÊëÏN­JªÚ.¯J´%Ôledž¯ùÃüu6²NfEAüÎ`ÞN_B*j)šÆyKÛï}4ÔÐ{îÒ—òKg;¾è€y7;óûòZ2 °Ô²3eg䘾þ2&Ç/]ÈA¢CHس<oœ¿:e|¸¶ù1üè5㔉ä;¾v/ 0æѹS…ÖÈýHœþ 㾺 ûCl²$æ'hÒKâŠ6W©á-ÀAíQÃÙóûc0ta <61>¹ÙÚs岓9Gã÷qd¼*^…É
Ûá<EFBFBD>†ØvÇJïZgêIáÙÅùó7îM=ùéi?òïDa<44>(ÜŽ€XÆË¢!ö6 êÎëÎmLƒM 9•W«=¦­Ô,3•¸âêb[á‰=<3D> »› =ûzªGàgF°×öçðÔðÔL×3Á ?ø+°h<1B>F…Û§ð6ZfkôÌ^@Ïÿ ½u ]íGŠ‹ü—ñß®ü31òb
endstream
endobj
505 0 obj
<</Subtype/Type1C/Filter/FlateDecode/Length 392>>
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■■К≈≈≈ККЕ╔ш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ý<31>gþ!Î"÷Ћå?“,ÃAù“D~j@1Wˆ<57>[¨¡mjbQQ~yQfzF‰<46><E280B0>±ž<C2B1><C5BE>s~A%˜¯ ‘¬©`hii®£`d``©à˜Z”™œ˜§àXšXää(ç'g¦T*hØd””Xéë———ë%æëå¥Ûiê(”gd(¥§•¥¦(¸åç•(ø%æ¦*@¼¡¡œó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<C389>
endstream
endobj
509 0 obj
@ -2472,21 +2475,22 @@ endobj
488 0 obj
<</Type/ObjStm/N 37/First 312/Filter/FlateDecode/Length 1571>>
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р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аGQ█E╒╝нОс;>Х╫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,┤;щЩеВ ║6кjSж└╨■Zт°)╤Оymt╨╫МЩ[²с·Юк≤ж~╠╤С0хОЯЩSк,П"ги└╣к╚Ъя:gЙ|╓╕z╔Цvvuф!О┤Рэю(▄I Ho╟U╕Ы%С0Jqz╝&UkLй┌ Ц╛Э ёА╢└~qs⌠бЮv4х┼K(┤i9юw°9■А&╚ZцP√╬Lс!\▐C┼rОlб╢А Л2-aЧ├Хю!а1╪┘8┘3x]xfЮi~┴ Ж▀qю
)\@.!ю2Ьn ┤фPб╕Паw╦┘д/(√k4╙÷e⌠l┬╥D Ж~1╨W█^рЧt>-SсПeZ█╦┘M┤ц0║п6мЁЖ&&╞╙√Т R5уL ЫтщUEGл7Р2╩О/·AЭG/▀┼<P5Ы{⌠а8дЧU1гШeЖ=VАkх²▌yV ╦╨┼║bОWuQи╒а┴╜zД $И_vг
xÚ͘mSÛ8€¿ß¯Ð÷Nºz—<Óé BËAZ´¦LÄ×ÄNã¤-ýõ·+<>PB‡Þ1¡÷ÕîãÕ®<C395>öŽq¦Τ—XK¦<õ5ÓKb™çkÏ„ΙМBbCcÃzF•3ØwLXž0‰µs 3·$Š3äÀíF(&¥ÑÌ2©¥Æ¾fÒXÉnÑ(PàBO¸ó8`™Ê1«˜ÒÂá€gʘ„á©Êd ÚE(¦9êm$Ú <ª$qDYLìÙ„iÇ ¹g„d-Qt8jLö)êq<Ý*Æ5Ž“²x¼ÇÅgÎp§”<C2A7>ÅàPìã1Ò<\Å~óGsU ÅÅÚz´U°h Ó8n±hÏ¢q¶ZmÉ, âñÈÜ%†Yéâ ®6$-aÎà¨NªÖ%µ³-êo•ŒÀc<C380>©EÉÖ8„mâN[‰qÔ"[ZMEr ‡D«€ÇS =%rï>ÿu&ñyñ?ô³‰À,>rUbø«²üSªÚO4æ¥Þ{Šò»òŸòÔÿ«ÜµnH/ÓxŒ¶«zÉY>kÝçÓð¶ßÔòqÏd™šC߶v~{MkðæK#ï¹ÕLŒævÕx;1bÌB‰t/5†Ië,ï³ÓÌ+Ëu'i”þÒ<C3BE>6\Äào)²k‡·=žÂZP 1%ÅX„u¢¢¾”/¨/<2F>Š#D¬)XÓ¸±¢ª±(ŒjZb<•7²pÎa,Ѩ)µµV•…Hu£¿<18>”¡¸g(zòÛ¸kb|\¢ä$îÃ4„B^½£ëq€NOápv>¥<0E>ø˜]L¸§<07>lRN7é„YØKošÂzØÎûÅE_Å”A+Ûi¢¼Ýn·³{òâÝ8ä‡i^ÆC¶BÙŸdãi1‰Y׿~]Ób¾6Óñ<C3B1>] ¦”\%l”ý<E2809D> ´Š:- <0C>ðvš³þF~5 ŒÃá4Œ>0ï¡3L¯Pÿ(µÝ.~œµ„<C2B5>µÈ¤FG<46>(ösœîdÃ@FV¦âH7…¦ Mï㥼ôœW¸ð¨8Î3 8Ôn¼ß;:8º àÏ  ®l°&@Ó(¤_p9í
Ñd(d<>a·Û}ófó Õschë ¬ÉÐÝiëNظ³Û<C2B3>½Ó½ww§µÚÅðb™™þ˜Ihü"8‰Á¸EB: ÉRø¤.©ƒ[eÊzô~ÿÖÉ£®ðñþÎi¯÷y&¢Îs•)kò”Oy£;ÛG;ïBjŸ%RUGºÊ”5êRµà£¨Æ"QWç×{»Ýi|ÑÍFç³r¿È÷Z½p5[&è×%ˆŸ‡·ñûjÎOx»Ÿ7ül \|{òBÔ±™:¶Õ¬ Î6ÁÙuÁ<75>ìv7<17>]ízÉÚàüœ\'¹Y NðUäð•°%ñýÐâšw r®Nnµ kó rf!§È_䔃<E2809D>Ó­ÎÞÜË+Ó–¸É?ð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ˆ<78>~‰©å&ðDŽ/ k%Wÿ£uÎÔù42HMõJÇ­ìò2LBÞå™<C3A5>q˜<71><1A>Ž°U¦ùó0Nqz.§UkBÊ “¬üãᬄ~1¥0¸BN2²âÊaZð]'‡EeeUkÊÂ×Y:„«IHQáÝ€6lÂlCvà Óváo؃}èÂ;xЃC8áœÀ)à <Ë/PÓ~1 ˜C!…sèø„+@ÿÀÂr(` _a%Laßà;ü€køIAüœb¹F£úY6͆xKãëIåÑè•!íϦáó25 _gш+QØl8 S
m³<ë´1yUµ¤O<C2A4>ª©nÄ<6E>OÝ^UtÄ|#/³»þâ†Iñ²(¡ÈUÓï±7LBì_³I¬³o±_f?b¾…œÑé¨g•€ËË*Þ>V•,œØªGBþÛŒ¯ÿ
endstream
endobj
524 0 obj
<</Type/XRef/Root 1 0 R/Info 2 0 R/ID[<2ab318012312f01e135daa12b3a72ca8><2ab318012312f01e135daa12b3a72ca8>]/Size
525/W[1 3 2]/Filter/FlateDecode/Length 1264>>
<</Type/XRef/Root 1 0 R/Info 2 0 R/ID[<73d408f43c3219297bc0aeb795fd41f4><73d408f43c3219297bc0aeb795fd41f4>]/Size
525/W[1 3 2]/Filter/FlateDecode/Length 1261>>
stream
xз5жyPVUгЯС╪В*┬╒╝П┌┼╧Ю▓)Ф√╩╔░Б ((Н╕╓╒╦╓$╝┬ ╦╔Б.Н╝╦Эc3NКУТO65√3M⌠╫ОВС≥g~g╧┤кЕ<cлк≈#ФжЮ┼░©ё0x▄q█Гя cHzп▀>Т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С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<Y;tо5Б█;:╖7╬Z⌠ВЙ\▀Кд⌡pMГ┴w[FxUИLM>`у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:FG▐3joHШщ^е⌠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…(ö
%*Š<>ØÅ{TìbÆØ‚Ë™qR'3š<¤L^b&g2™˜{ÿ{ñò5ß.gs8ì…1Ƽzå1mîc. û«q1c°ŽÇ×q¿4†¤.‰ ½èC?0ˆºXkbFc-ŒÁÚ<ÅαO<C2B1>EûÜz‡ñ˜€‰˜„õ±6ÄFØ“1C˜ŠiØb3LÇæø¶À–Ø
[c¶Á¶bLLä<4C>…ëv¼á¥ü\öäíÅ„^êèëŒ.g4‰Iÿ]G;0º<IL»š¿A¾šú3¼‰·Ätš©s*ÅdvѺ£˜A¿hÝ 3±³˜¬
ÍßdÏ19?hÒ…d-uW1ãghÞ<68>|=uwì!&?NGßbt#uO¼‡½°7öÁ¾bæ'êª~؈)L ¸®Ž¾Íž¥bJ24y‡d˜Ò¹š $ÙÆ»j foõûD¾ƒ: ³Å”…tô]FwQÆû8sÄ”ÿ§3‡Šyö,rªïÿÑdk÷PßÅá8BÌO_êœ"™Z<E284A2>¹4XëѬÝO=F¤2Gó±äQ_Áq8'`.æáDœ$òèIølò$^÷™Ì>©§à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¸
W7ùºÎ)ïìȪ­Ó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ŠÇÄÙ:LG<4C>3joHûÝ^Óx
ËÑ~‡gð,žg_QäYGbu·óìvSœÓŸkr<6B>ä8Wnjrä¶8U{4ù˜ÄÞäöŽµ}äu/l<>ön|HÝcÑö¾GÔØëaø„/¾ ;gGúrØ8ŒÇô`"&a}ôb6À†èÃFØÛb2ú1€)ÂT b3LÇæè í†í±ºØb+´<>±ÖDÛ<44>lïëˆQØ 3±3FcWl¶gÕÂîØm·ê‰1Xë`_,ÂEØûc6@Û¡lW²<57>Èö<C388>,´<>ÂöšÁ8sp(ŽÀáh»ÀH…¶_ŒÁq8ÇãÌÅ<œˆ“Ðö‚)8§¡½ùí=lo{{ÃÏÂÙ8 ÐÞáópÎG{WÛûy!ÞÃ͸ c1Ú;ÖÞ™«p®Áu¸ËÐÞfövÚŽ{q'îÆC¸`ÃÃx
í<EFBFBD>pËÑþ…žÃ»x¯b%^ÃxˆóTôïî¡8Õú¸þ<C2B8>úß²wéóˆQ£5q“£´öˆŠÓÚ+nú%­}âööiíwìS­âÎ{¬uPܵvÄ-Ú¨uk`ª¸Kò5<C3B2>Â4qË5©…öÿíX¬‡M0±>6ÄƘ"nI¡1ÿï£b<C2A3>
endstream
endobj
startxref

View File

@ -440,6 +440,10 @@ namespace Hurricane {
}
_inConstructor = true;
#ifndef HAVE_LIBBFD
_stack.push_back( "Build without BFD (<b>libbfd</b>) support, no filename and line number." );
#endif
#if (defined __linux__ || defined __FreeBSD__ || defined __APPLE__)
void* rawStack [ _stackSize ];
size_t depth = backtrace ( rawStack, _stackSize );

View File

@ -49,7 +49,7 @@ namespace Hurricane {
void Observable::removeObserver ( BaseObserver* observer )
{
{
vector<BaseObserver*>::iterator iobserver=_observers.begin();
for ( ; iobserver!=_observers.end() ; ++iobserver ) {
if (*iobserver == observer) {

View File

@ -160,7 +160,10 @@ namespace Hurricane {
template<size_t slotsNb>
template<typename OwnerT>
inline OwnerT* StaticObservable<slotsNb>::getObserver ( size_t slot ) const
{ return (slot < _observers.size()) ? static_cast< Observer<OwnerT>* >(_observers[slot])->getOwner() : NULL; }
{
if ( (slot >= _observers.size()) or not _observers[slot]) return NULL;
return static_cast< Observer<OwnerT>* >(_observers[slot])->getOwner();
}

View File

@ -40,7 +40,7 @@ namespace Hurricane {
setWindowTitle ( "Breakpoint" );
setToolTip ( "Crush the Mush to continue..." );
_message->setTextFormat ( Qt::RichText );
//_message->setTextFormat ( Qt::RichText );
_message->setText ( "<b>No Message Yet</b>" );
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 );

View File

@ -117,6 +117,7 @@ namespace Hurricane {
_header->setText ( "<b>[ERROR]</b>" );
_message->setTextFormat ( Qt::RichText );
_message->setFont ( Graphics::getFixedFont(QFont::Normal,false,false) );
_message->setText ( "<b>Oups! I did it again!</b>" );
_trace->setTextInteractionFlags ( Qt::TextBrowserInteraction );

46
katana/CMakeLists.txt Normal file
View File

@ -0,0 +1,46 @@
# -*- explicit-buffer-name: "CMakeLists.txt<katana>" -*-
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()

View File

@ -0,0 +1 @@
install( FILES FindKATANA.cmake DESTINATION share/cmake/Modules )

View File

@ -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)

View File

@ -0,0 +1,2 @@
install ( FILES katanaInit.py DESTINATION ${PYTHON_SITE_PACKAGES}/katana )

View File

@ -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 <coriolis> 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

112
katana/src/CMakeLists.txt Normal file
View File

@ -0,0 +1,112 @@
# -*- explicit-buffer-name: "CMakeLists.txt<katana/src>" -*-
# 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 )

View File

@ -0,0 +1,199 @@
// -*- mode: C++; explicit-buffer-name: "Configuration.cpp<katana>" -*-
//
// 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 <string>
#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 ; i<MaxMetalDepth ; ++i ) {
// ostringstream paramName;
// paramName << "katana.metal" << (i+1) << "MinBreak";
// int threshold = 29*50;
// switch ( i ) {
// case 0:
// case 1:
// threshold = 2*50;
// break;
// default:
// threshold = 30*50;
// break;
// }
// Cfg::getParamDouble(paramName.str())->setDouble(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<Katana> 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 ; i<MaxMetalDepth ; ++i ) {
// ostringstream paramName;
// paramName << "metal" << (i+1) << "MinBreak";
// record->add ( DbU::getValueSlot(paramName.str(),&_globalMinBreaks[i]) );
// }
}
return record;
}
} // Katana namespace.

37
katana/src/Constants.cpp Normal file
View File

@ -0,0 +1,37 @@
// -*- mode: C++; explicit-buffer-name: "Constants.cpp<katana>" -*-
//
// 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 <string>
#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.

View File

@ -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 <cstdlib>
#include <sstream>
#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<AutoSegment*> collapseds;
vector<AutoSegment*> perpandiculars;
map<DbU::Unit,int> 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<DbU::Unit,int>::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<DbU::Unit,int>::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<DbU::Unit,int>::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.

219
katana/src/GlobalRoute.cpp Normal file
View File

@ -0,0 +1,219 @@
// -*- mode: C++; explicit-buffer-name: "GlobalRoute.cpp<katana>" -*-
//
// 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<Edge*>& 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.

View File

@ -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 <boost/bind.hpp>
#include <QAction>
#include <QMenu>
#include <QMenuBar>
#include <QApplication>
#include <hurricane/Warning.h>
#include <hurricane/Error.h>
#include <hurricane/Breakpoint.h>
#include <hurricane/DebugSession.h>
#include <hurricane/Go.h>
#include <hurricane/Net.h>
#include <hurricane/Cell.h>
#include <hurricane/viewer/Graphics.h>
#include <hurricane/viewer/CellWidget.h>
#include <hurricane/viewer/CellViewer.h>
#include <hurricane/viewer/ControllerWidget.h>
#include <hurricane/viewer/ExceptionWidget.h>
#include <crlcore/Utilities.h>
#include <crlcore/AllianceFramework.h>
#include <anabatic/GCell.h>
#include <katana/GraphicKatanaEngine.h>
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 <b>Katana</b> detailed router on pre-routed nets"
, std::bind(&GraphicKatanaEngine::_runNegociatePreRouted,this)
);
_viewer->addToMenu( "placeAndRoute.katana.stepByStep.globalRoute"
, "Katana - &Global Route"
, "Run the <b>Knik</b> global router"
, std::bind(&GraphicKatanaEngine::_globalRoute,this)
);
_viewer->addToMenu( "placeAndRoute.katana.stepByStep.detailedRoute"
, "Katana - &Detailed Route"
, "Run the <b>Katana</b> 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( "<b>Katana:</b> GraphicKatanaEngine not bound to any Viewer." );
return NULL;
}
if (_viewer->getCell() == NULL) {
throw Error( "<b>Katana:</b> 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.

View File

@ -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.

596
katana/src/KatanaEngine.cpp Normal file
View File

@ -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 <Python.h>
#include <sstream>
#include <fstream>
#include <iomanip>
#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<KatanaEngine*>(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<Isobar::Script> 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<GCell*> 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 ; itrack<tracksSize ; ++itrack ) {
Track* track = rp->getTrackByIndex( itrack );
cdebug_log(159,0) << "Capacity from: " << track << endl;
for ( size_t ielement=0 ; ielement<track->getSize() ; ++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 ; i<gcells->size()-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<TrackElement*> unrouteds;
vector<TrackElement*> 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<unrouteds.size() ; ++i ) {
cerr << " " << dec << setw(4) << (i+1) << "| " << unrouteds[i] << endl;
}
}
// if (not reduceds.empty()) {
// cerr << " o Reduced segments:" << endl;
// for ( size_t i=0; i<reduceds.size() ; ++i ) {
// cerr << " " << dec << setw(4) << (i+1) << "| " << reduceds[i] << endl;
// }
// }
result << setprecision(4) << segmentRatio
<< "% [" << routeds << "+" << unrouteds.size() << "]";
cmess1 << Dots::asString( " - Track Segment Completion Ratio", result.str() ) << endl;
result.str("");
result << setprecision(4) << wireLengthRatio
<< "% [" << totalWireLength << "+"
<< (totalWireLength - routedWireLength) << "]";
cmess1 << Dots::asString( " - Wire Length Completion Ratio", result.str() ) << endl;
float expandRatio = 1.0;
if (_minimumWL != 0.0) {
expandRatio = ((totalWireLength-_minimumWL) / _minimumWL) * 100.0;
result.str("");
result << setprecision(3) << expandRatio << "% [min:" << setprecision(9) << _minimumWL << "]";
cmess1 << Dots::asString( " - Wire Length Expand Ratio", result.str() ) << endl;
}
addMeasure<size_t> ( getCell(), "Segs" , routeds+unrouteds.size() );
addMeasure<unsigned long long>( getCell(), "DWL(l)" , totalWireLength , 12 );
addMeasure<unsigned long long>( getCell(), "fWL(l)" , totalWireLength-routedWireLength , 12 );
addMeasure<double> ( getCell(), "WLER(%)", (expandRatio-1.0)*100.0 );
}
void KatanaEngine::dumpMeasures ( ostream& out ) const
{
vector<Name> 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<Segment*>() ) {
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<Segment*>() ) {
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.

1412
katana/src/Manipulator.cpp Normal file

File diff suppressed because it is too large Load Diff

View File

@ -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 <vector>
#include <algorithm>
#include <iomanip>
#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<GCell*>& 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<TrackElement*> accounteds;
double totalWL = 0.0;
for ( size_t igcell=0 ; igcell<_gcells.size() ; ++igcell ) {
double gcellWL = 0.0;
Segment* segment;
TrackElement* trackSegment;
const vector<AutoContact*>& contacts = _gcells[igcell]->getContacts();
for ( size_t i=0 ; i<contacts.size() ; i++ ) {
for( Hook* hook : contacts[i]->getBodyHook()->getSlaveHooks() ) {
Hook* sourceHook = dynamic_cast<Segment::SourceHook*>(hook);
if (not sourceHook) continue;
segment = dynamic_cast<Segment*>(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<AutoContact*>& contacts = gcell->getContacts();
for ( size_t i=0 ; i<contacts.size() ; i++ ) {
for( Component* component : contacts[i]->getSlaveComponents() ) {
segment = dynamic_cast<Segment*>(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 << " <pack.event:" << tty::bold << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << tty::reset
<< " remains:" << right << setw(8) << setfill('0')
<< packQueue.size() << ">"
<< setfill(' ') << tty::reset << tty::cr;
cmess2.flush();
} else {
cmess2 << " <pack.event:" << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << setfill(' ') << " "
<< event->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 << " <queue:" << right << setw(8) << setfill('0') << _eventQueue.size() << ">" << 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 << " <event:" << tty::bold << right << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << tty::reset
<< " remains:" << right << setw(8) << setfill('0')
<< _eventQueue.size()
<< setfill(' ') << tty::reset << ">" << tty::cr;
cmess2.flush ();
} else {
cmess2 << " <event:" << right << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << setfill(' ') << " "
<< event->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 << " <repair.queue:" << right << setw(8) << setfill('0')
<< _eventQueue.size() << ">" << endl;
count = 0;
//_eventQueue.prepareRepair();
while ( not _eventQueue.empty() and not isInterrupted() ) {
RoutingEvent* event = _eventQueue.pop();
if (tty::enabled()) {
cmess2 << " <repair.event:" << tty::bold << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << tty::reset
<< " remains:" << right << setw(8) << setfill('0')
<< _eventQueue.size() << ">"
<< setfill(' ') << tty::reset << tty::cr;
cmess2.flush();
} else {
cmess2 << " <repair.event:" << setw(8) << setfill('0')
<< RoutingEvent::getProcesseds() << setfill(' ') << " "
<< event->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<size_t>( getCell(), "Events" , RoutingEvent::getProcesseds(), 12 );
addMeasure<size_t>( getCell(), "UEvents", RoutingEvent::getProcesseds()-RoutingEvent::getCloneds(), 12 );
Histogram* densityHistogram = new Histogram ( 1.0, 0.1, 2 );
addMeasure<Histogram>( 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<GCell*>& gcells = getKatanaEngine()->getGCells();
getKatanaEngine()->setDensityMode( Anabatic::AnabaticEngine::MaxHVDensity );
for ( size_t igcell=0 ; igcell<gcells.size() ; ++igcell ) {
densityHistogram->addSample( gcells[igcell]->getDensity(), 0 );
}
getKatanaEngine()->setDensityMode( Anabatic::AnabaticEngine::MaxDensity );
for ( size_t igcell=0 ; igcell<gcells.size() ; ++igcell ) {
densityHistogram->addSample( 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.

1329
katana/src/PowerRails.cpp Normal file

File diff suppressed because it is too large Load Diff

366
katana/src/PreProcess.cpp Normal file
View File

@ -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 <sstream>
#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<TrackElement*>& perpandiculars
)
{
TrackElement* perpandicular;
for( Segment* osegment : segment->base()->getAutoSource()->getSlaveComponents().getSubSet<Segment*>() ) {
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<Segment*>() ) {
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<TrackElement*>& faileds )
{
cdebug_log(159,0) << "Find failed caging: " << rp << endl;
TrackElement* parallel;
for( Segment* osegment : rp->getSlaveComponents().getSubSet<Segment*>() ) {
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<TrackElement*>& 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<TrackElement*> perpandiculars;
if ( not track ) {
cerr << Bug( "%s is not inserted in a <Track>", 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<RoutingPad*>(source->getAnchor());
if (rp) {
TrackElement* parallel;
for( Segment* osegment : rp->getSlaveComponents().getSubSet<Segment*>() ) {
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 <RoutingPad>\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 ; iperpand<perpandiculars.size() ; iperpand++ ) {
cdebug_log(159,0) << "Caged: " << constraints << " " << perpandiculars[iperpand] << endl;
perpandiculars[iperpand]->base()->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<RoutingPad*>(support->getAnchor());
for( Component* component : rp->getSlaveComponents() ) {
Horizontal* baseSegment = dynamic_cast<Horizontal*>( 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 ; i<track->getSize() ; ++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<RoutingPad*>(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<TrackElement*> 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.

62
katana/src/PreRouteds.cpp Normal file
View File

@ -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 <map>
#include <list>
#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 ; itrack<tracksSize ; ++itrack ) {
Track* track = rp->getTrackByIndex( itrack );
for ( size_t ielement=0 ; ielement<track->getSize() ; ++ielement ) {
TrackElement* element = track->getSegment( ielement );
if (element->getNet() == NULL) continue;
element->setRouted();
}
}
}
}
} // Katana namespace.

View File

@ -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 <map>
#include <list>
#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<Segment*> segments;
for( Segment* segment : masterNet->getSegments() ) {
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(segment->getLayer());
if ( plane == NULL ) continue;
if ( usedComponent == dynamic_cast<Component*>(segment) ) continue;
if ( not NetExternalComponents::isExternal(segment) ) continue;
//cerr << "Looking " << (void*)*isegment << ":" << *isegment << endl;
segments.push_back ( segment );
}
for ( size_t i=0 ; i<segments.size() ; ++i ) {
RoutingPlane* plane = Session::getKatanaEngine()->getRoutingPlaneByLayer(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<RoutingPad*> rps;
for ( RoutingPad* rp : net->getRoutingPads() ) {
rps.push_back( rp );
}
for ( size_t i=0 ; i<rps.size() ; ++i )
protectRoutingPad( rps[i] );
}
Session::close();
}
} // Katana namespace.

View File

@ -0,0 +1,122 @@
// -*- 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@lip6.fr |
// | =============================================================== |
// | C++ Module : "./PyGraphicKatanaEngine.cpp" |
// +-----------------------------------------------------------------+
#include "katana/PyGraphicKatanaEngine.h"
#include "hurricane/isobar/PyCell.h"
#include "hurricane/Cell.h"
#undef ACCESS_OBJECT
#undef ACCESS_CLASS
#define ACCESS_OBJECT _baseObject._object
#define ACCESS_CLASS(_pyObject) &(_pyObject->_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.

103
katana/src/PyKatana.cpp Normal file
View File

@ -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.

View File

@ -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 <functional>
# 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.

701
katana/src/RoutingEvent.cpp Normal file
View File

@ -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 <cstdlib>
#include <sstream>
#include <iomanip>
#include <algorithm>
#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<unsigned int>::max()) {
throw Error( "RoutingEvent::RoutingEvent(): Identifier counter has reached it's limit (%d bits)."
, std::numeric_limits<unsigned int>::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<TrackSegment*>(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<tt>";
const vector<RoutingEventLoop::Element>& elements = loop.getElements();
for ( size_t i=0 ; i<elements.size() ; ++i ) {
message << setw(2) << elements[i]._count << "| id:"
<< elements[i]._id << "\n";
}
message << "</tt>";
throw Error( message.str().c_str() );
}
#else
ostringstream message;
message << "[BUG] Katana has detected a loop between the following Segments:";
const vector<RoutingEventLoop::Element>& elements = loop.getElements();
for ( size_t i=0 ; i<elements.size() ; ++i ) {
message << "\n" << setw(10) << elements[i]._count << "| id:" << elements[i]._id;
}
cbug << message.str() << endl;
#endif
}
DebugSession::open( _segment->getNet(), 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 ; itrack<fsm.getCosts().size() ; itrack++ ) {
cdebug_log(9000,0) << "Deter| | Candidate Track: " << fsm.getCost(itrack) << endl;
}
}
for ( itrack=0 ; itrack<fsm.getCosts().size() ; itrack++ ) {
cdebug_log(159,0) << "Trying Track: " << itrack << endl;
if (fsm.getCost(itrack).isInfinite()) break;
if (fsm.insertInTrack(itrack)) break;
resetInsertState();
} // Next ripup is possible.
}
if (fsm.getState() != SegmentFsm::OtherRipup) {
fsm.slackenTopology();
}
}
}
} else {
// Ripup limit has been reached.
if (isOverConstrained()) {
cdebug_log(159,0) << "Immediate slackening due to overconstraint" << endl;
fsm.getData()->setState( 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.

View File

@ -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 <iomanip>
#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.

View File

@ -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 <iostream>
#include <algorithm>
#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<Element>::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<Element>::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.

View File

@ -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 <iostream>
#include <iomanip>
#include <functional>
#include <algorithm>
#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<TrackElement*>& segments )
{
for ( size_t i=0 ; i<segments.size() ; i++ ) {
if (segments[i]->getDataNegociate()->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<RoutingEvent*,RoutingEvent::Compare>::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<RoutingEvent*,RoutingEvent::Compare>::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<AutoSegment*>& invalidateds0 = Session::getInvalidateds();
TrackSegmentSet invalidateds1;
for ( size_t i=0 ; i<invalidateds0.size() ; i++ ) {
TrackSegment* segment = dynamic_cast<TrackSegment*>( 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<RoutingEvent*,RoutingEvent::Compare>::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<RoutingEvent*,RoutingEvent::Compare>::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<RoutingEvent*,RoutingEvent::Compare>::const_iterator ievent = _events.begin ();
for ( ; ievent != _events.end(); ievent++ ) {
multiset<RoutingEvent*,RoutingEvent::Compare>::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.

214
katana/src/RoutingPlane.cpp Normal file
View File

@ -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 ; index<trackNumber ; ++index ) {
if (plane->getDirection() == 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.

1241
katana/src/SegmentFsm.cpp Normal file

File diff suppressed because it is too large Load Diff

350
katana/src/Session.cpp Normal file
View File

@ -0,0 +1,350 @@
// -*- mode: C++; explicit-buffer-name: "Session.cpp<katana>" -*-
//
// 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<Session*>( 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<KatanaEngine*>(_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<Track*> 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<Track*>::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<AutoSegment*>& destroyeds = getDestroyeds();
set<AutoSegment*>::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<AutoSegment*>& revalidateds = getRevalidateds();
//const set<Net*>& netsModificateds = getNetsModificateds();
for ( size_t i=0 ; i<revalidateds.size() ; ++i ) {
if (not revalidateds[i]->isCanonical()) 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<Track*>::iterator it=packTracks.begin() ; it != packTracks.end() ; ++it )
(*it)->check( overlaps, "Session::_revalidate() - on packed track." );
for ( size_t i=0 ; i<revalidateds.size() ; ++i ) {
revalidateds[i]->check();
}
//_getKatanaEngine()->_showOverlap ();
# endif
_sortEvents.clear();
#if THIS_IS_DISABLED
if (not faileds.empty()) {
set<TrackElement*>::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 ; i<revalidateds.size() ; ++i ) {
if (revalidateds[i]->canReduce()) {
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.

726
katana/src/Track.cpp Normal file
View File

@ -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 <cstdlib>
#include <sstream>
#include <memory>
#include <algorithm>
#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<TrackElement*>& 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<TrackElement*>::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<Track*>(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<TrackMarker*>::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<TrackMarker*>::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<TrackElement*>::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<TrackElement*>::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<TrackElement*>::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.

261
katana/src/TrackCost.cpp Normal file
View File

@ -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 <cstdlib>
#include <sstream>
#include <iostream>
#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.

283
katana/src/TrackElement.cpp Normal file
View File

@ -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 <limits>
#include <sstream>
#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() <Invalidate> 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() <Revalidate> 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<GCell*>& gcells ) const
{
vector<GCell*>().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.

View File

@ -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 = "<TrackElements_Perpandiculars::Locator>";
return s;
}
string TrackElements_Perpandiculars::_getString () const
{
string s = "<TrackElements_Perpandiculars "
+ getString(_segment)
+ ">";
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 "<TrackElements_UniqCanonical>"; }
} // Katana namespace.

View File

@ -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 <sstream>
#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<RegularLayer*>(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 ; i<gcells->size() ; ++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.

132
katana/src/TrackMarker.cpp Normal file
View File

@ -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 <iomanip>
#include <sstream>
#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.

884
katana/src/TrackSegment.cpp Normal file
View File

@ -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 <sstream>
#include <limits>
#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<GCell*>& gcells ) const
{
vector<GCell*>().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<TrackElement*>& bounds )
{
bounds.clear ();
set<AutoSegment*> baseBounds;
set<AutoSegment*>::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() - <id:" << getId() << ">" << 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<Segment*>() ) {
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<Segment*>() ) {
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<Anabatic::GCell*> 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<gcells.size() ; ++igcell ) {
if (doglegGCell != gcells[igcell]) continue;
isGCellInside = true;
if (igcell == 0) {
if (hasSourceDogleg()) {
if (flags & Flags::AllowDoglegReuse) return true;
cdebug_log(159,0) << "false: Cannot dogleg again in source GCell." << endl;
cdebug_tabw(159,-1);
return false;
}
}
if (hasTargetDogleg() and (igcell == gcells.size()-1)) {
if (flags & Flags::AllowDoglegReuse) {
cdebug_log(159,0) << "true" << endl;
cdebug_tabw(159,-1);
return true;
}
cdebug_log(159,0) << "false: Cannot dogleg again in target GCell." << endl;
cdebug_tabw(159,-1);
return false;
}
break;
}
if (not isGCellInside) {
cdebug_log(159,0) << "false: dogleg GCell is outside segment support (go outside GCell active)." << endl;
cdebug_tabw(159,-1);
return false;
}
cdebug_log(159,0) << "true" << endl;
cdebug_tabw(159,-1);
return true;
}
bool TrackSegment::canDogleg ( Interval interval )
{
cdebug_log(159,0) << "TrackSegment::canDogleg(Interval) " << interval << endl;
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 (not isLocal()) {
cdebug_log(159,0) << "Failed: is not local" << endl;
return false;
}
if (hasSourceDogleg() or hasTargetDogleg() or isSlackened()) {
cdebug_log(159,0) << "Failed: already has source and/or target dogleg or slackened." << endl;
return false;
}
if (getDoglegLevel() > 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<AutoSegment*>& doglegs = Session::getDoglegs();
vector<TrackElement*> 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 ; i<doglegs.size() ; i+=3 ) {
cdebug_log(159,0) << "Looking up original: " << doglegs[i] << endl;
segments.push_back( Session::getNegociateWindow()->createTrackSegment(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 ; i<doglegs.size() ; ++i ) {
segments[i]->reschedule ( ((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.

View File

@ -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 <cstdlib>
#include <iostream>
#include <sstream>
#include <map>
#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<AutoSegment*> collapseds;
vector<AutoSegment*> perpandiculars;
map<DbU::Unit,int> 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<DbU::Unit,int>::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<DbU::Unit,int>::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<DbU::Unit,int>::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.

315
katana/src/Tracks.cpp Normal file
View File

@ -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 <iostream>
#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<Track*>()
, _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<Track*>()
, _constraints(locator._constraints)
, _track (locator._track)
{ }
Hurricane::Locator<Track*>* 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 = "<Tracks_Range::Locator ["
+ DbU::getValueString(_constraints.getVMin()) + ":"
+ DbU::getValueString(_constraints.getVMax()) + "] "
+ getString(_track) + ">";
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<Track*>()
, _routingPlane(routingPlane)
, _constraints (constraints)
{ }
Tracks_Range::Tracks_Range ( const Tracks_Range& tracks )
: Collection<Track*>()
, _routingPlane(tracks._routingPlane)
, _constraints (tracks._constraints)
{ }
Collection<Track*>* Tracks_Range::getClone () const
{ return new Tracks_Range(*this); }
Hurricane::Locator<Track*>* 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<Track*>()
, _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<Track*>()
, _optimal (locator._optimal)
, _constraints (locator._constraints)
, _minTrack (locator._minTrack)
, _maxTrack (locator._maxTrack)
, _onMin (locator._onMin)
, _inMinOptimal(locator._inMinOptimal)
, _inMaxOptimal(locator._inMaxOptimal)
{ }
Hurricane::Locator<Track*>* 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 = "<Tracks_Spiral::Locator ["
+ getString(_minTrack) + ":"
+ getString(_maxTrack) + "]"
+ getString(_onMin)
+ ">";
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<Track*>()
, _routingPlane(routingPlane)
, _optimal (optimal)
, _constraints (constraints)
{ }
Tracks_Spiral::Tracks_Spiral ( const Tracks_Spiral& tracks )
: Collection<Track*>()
, _routingPlane(tracks._routingPlane)
, _optimal (tracks._optimal)
, _constraints (tracks._constraints)
{ }
Collection<Track*>* Tracks_Spiral::getClone () const
{ return new Tracks_Spiral(*this); }
Hurricane::Locator<Track*>* 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.

View File

@ -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.

View File

@ -0,0 +1,122 @@
// -*- mode: C++; explicit-buffer-name: "Configuration.h<katana>" -*-
//
// 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 <functional>
#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<const Anabatic::Configuration*>(this); }
inline Anabatic::Configuration* Configuration::base () { return dynamic_cast<Anabatic::Configuration*>(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

View File

@ -0,0 +1,52 @@
// -*- mode: C++; explicit-buffer-name: "Constants.h<katana>" -*-
//
// 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

View File

@ -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 <string>
#include <iostream>
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<TrackElement*>& 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<DbU::Unit> _attractors;
vector<TrackElement*> _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<TrackElement*>& 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

View File

@ -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 <functional>
#include <QObject>
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

View File

@ -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

View File

@ -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 <iostream>
#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<RoutingPlane*> _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<AnabaticEngine*>(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<TrackElement>(AutoSegment::Observable::TrackSegment); }
// Variables.
extern const char* missingRW;
} // Katana namespace.
INSPECTOR_P_SUPPORT(Katana::KatanaEngine);
#endif // KATANA_KATANA_ENGINE_H

View File

@ -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

View File

@ -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 <set>
#include <queue>
#include <vector>
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<GCell*>& getGCells () const;
inline RoutingEventQueue& getEventQueue ();
inline RoutingEventHistory& getEventHistory ();
inline RoutingEventLoop& getEventLoop ();
inline Stage getStage () const;
void setGCells ( const vector<GCell*>& );
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<GCell*> _gcells;
std::vector<TrackElement*> _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<GCell*>& 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

View File

@ -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

View File

@ -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

View File

@ -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 <set>
#include <vector>
#include <cstdlib>
#include <functional>
#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<const Key&,const Key&,bool> {
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<const RoutingEvent*,const RoutingEvent*,bool> {
public:
bool operator() ( const RoutingEvent* lhs, const RoutingEvent* rhs ) const;
};
// Sub-Class: "CompareById".
class CompareById : public binary_function<const RoutingEvent*,const RoutingEvent*,bool> {
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<TrackElement*>& 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<TrackElement*> _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<TrackElement*>& RoutingEvent::getPerpandiculars () const { return _dataNegociate->getPerpandiculars(); }
//inline const vector<TrackElement*>& 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<RoutingEvent*,RoutingEvent::CompareById> 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

View File

@ -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 <iostream>
#include <vector>
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<RoutingEvent*> _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

View File

@ -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 <vector>
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<Element>& getElements () const;
void update ( size_t id );
void erase ( size_t id );
private:
std::vector<Element> _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::Element>&
RoutingEventLoop::getElements () const { return _elements; }
} // Katana namespace.
//INSPECTOR_P_SUPPORT(Katana::RoutingEvent);
#endif // KATANA_ROUTING_EVENT_LOOP_H

View File

@ -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 <set>
#include <vector>
#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<TrackElement*>& );
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<RoutingEvent*,RoutingEvent::Compare> _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

View File

@ -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<Track*> _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

View File

@ -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<TrackCost>& 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<SegmentAction>& 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<TrackCost> _costs;
vector<SegmentAction> _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<TrackCost>& 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<SegmentAction>& 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

182
katana/src/katana/Session.h Normal file
View File

@ -0,0 +1,182 @@
// -*- mode: C++; explicit-buffer-name: "Session.h<katana>" -*-
//
// 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 <set>
#include <vector>
#include <string>
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<Event> _insertEvents;
vector<Event> _removeEvents;
set<Track*> _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<Super*>(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

218
katana/src/katana/Track.h Normal file
View File

@ -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<TrackElement*>::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<TrackElement*> _segments;
vector<TrackMarker*> _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

View File

@ -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 <string>
#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

View File

@ -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 <string>
#include <map>
#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<Segment*,TrackElement*> 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<TrackElement>* 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<GCell*>& ) 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<TrackElement> _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>* 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

View File

@ -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<TrackElement*> TrackElementHF;
typedef Hurricane::Locator<TrackElement*> TrackElementHL;
typedef Hurricane::Collection<TrackElement*> TrackElementHC;
typedef GenericCollection<TrackElement*> TrackElements;
typedef GenericLocator<TrackElement*> TrackElementLocator;
typedef GenericFilter<TrackElement*> 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<TrackElement*>& );
inline TrackElements_UniqCanonical ( const TrackElements_UniqCanonical& );
virtual TrackElementHF* getClone () const;
virtual bool accept ( TrackElement* segment ) const;
virtual string _getString () const;
private:
set<TrackElement*>& _canonicals;
};
inline TrackElements_UniqCanonical::TrackElements_UniqCanonical ( set<TrackElement*>& canonicals )
: TrackElementHF()
, _canonicals(canonicals)
{}
inline TrackElements_UniqCanonical::TrackElements_UniqCanonical ( const TrackElements_UniqCanonical& filter )
: TrackElementHF()
, _canonicals(filter._canonicals)
{}
} // Katana namespace.
#endif // KATANA_TRACKELEMENTS_H

View File

@ -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

View File

@ -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

View File

@ -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 <set>
#include <functional>
#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<const TrackSegment*,const TrackSegment*,bool> {
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<GCell*>& ) const;
virtual TrackElement* getSourceDogleg ();
virtual TrackElement* getTargetDogleg ();
virtual TrackElements getPerpandiculars ();
virtual size_t getPerpandicularsBound ( set<TrackElement*>& );
// 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<TrackSegment*,TrackSegment::CompareById> TrackSegmentSet;
} // Katana namespace.
INSPECTOR_P_SUPPORT(Katana::TrackSegment);
#endif // KATANA_TRACK_SEGMENT_H

View File

@ -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 <vector>
#include <string>
#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<DbU::Unit> _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__

140
katana/src/katana/Tracks.h Normal file
View File

@ -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 <string>
#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<Track*> Tracks;
typedef GenericLocator<Track*> TrackLocator;
typedef GenericFilter<Track*> TrackFilter;
// -------------------------------------------------------------------
// Class : "Tracks_Range".
class Tracks_Range: public Collection<Track*> {
public:
// Locator Sub-Class.
class Locator : public Hurricane::Locator<Track*> {
public:
Locator ( const RoutingPlane* routingPlane
, const Interval& constraints );
Locator ( const Locator& );
virtual Hurricane::Locator<Track*>* 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<Track*>* getClone () const;
virtual Hurricane::Locator<Track*>* getLocator () const;
virtual string _getString () const;
protected:
// Tracks_Range Attributes.
const RoutingPlane* _routingPlane;
const Interval _constraints;
};
// -------------------------------------------------------------------
// Class : "Tracks_Spiral".
class Tracks_Spiral : public Collection<Track*> {
public:
// Locator Sub-Class.
class Locator : public Hurricane::Locator<Track*> {
public:
Locator ( const RoutingPlane* routingPlane
, const Interval& optimal
, const Interval& constraints );
Locator ( const Locator& );
virtual Hurricane::Locator<Track*>* 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<Track*>* getClone () const;
virtual Hurricane::Locator<Track*>* 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

View File

@ -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

View File

@ -0,0 +1,8 @@
# Refactoring patterns for Kite to Katana tool.
KITE --> KATANA
Kite --> Katana
kite --> katana
Katabatic --> Anabatic
katabatic --> anabatic
ktbt --> anbt

Some files were not shown because too many files have changed in this diff Show More