Merge branch 'devel_anabatic' of ssh://bop.soc.lip6.fr/users/largo2/git/coriolis into devel_anabatic

Conflicts:
	anabatic/src/LoadGlobalRouting.cpp
This commit is contained in:
EricLaoGitHub 2016-08-15 17:35:34 +02:00
commit 6d0b26b956
113 changed files with 17236 additions and 700 deletions

View File

@ -18,6 +18,7 @@
#include <iostream>
#include "hurricane/Bug.h"
#include "hurricane/Error.h"
#include "hurricane/Breakpoint.h"
#include "hurricane/RegularLayer.h"
#include "hurricane/Horizontal.h"
#include "hurricane/RoutingPad.h"
@ -38,6 +39,7 @@ namespace Anabatic {
using std::ostringstream;
using Hurricane::Bug;
using Hurricane::Error;
using Hurricane::Breakpoint;
using Hurricane::RegularLayer;
using Hurricane::Component;
using Hurricane::Horizontal;
@ -73,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;
@ -173,7 +199,7 @@ namespace Anabatic {
AnabaticEngine::AnabaticEngine ( Cell* cell )
: Super(cell)
, _timer ()
, _configuration (new ConfigurationConcrete())
, _configuration (new Configuration())
, _chipTools (cell)
, _state (EngineCreation)
, _matrix ()
@ -249,7 +275,7 @@ namespace Anabatic {
void AnabaticEngine::_gutAnabatic ()
{
Session::open( this );
openSession();
_flags.reset( Flags::DestroyBaseContact|Flags::DestroyBaseSegment );
@ -299,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;
@ -331,6 +372,10 @@ namespace Anabatic {
}
void AnabaticEngine::openSession ()
{ Session::_open(this); }
void AnabaticEngine::reset ()
{
_gutAnabatic();
@ -554,6 +599,7 @@ namespace Anabatic {
void AnabaticEngine::ripup ( Segment* seed, Flags flags )
{
Net* net = seed->getNet();
DebugSession::open( net, 112, 120 );
@ -614,6 +660,8 @@ namespace Anabatic {
Contact* source = dynamic_cast<Contact*>( segment->getSource() );
Contact* target = dynamic_cast<Contact*>( segment->getTarget() );
segment->getSourceHook()->detach();
segment->getTargetHook()->detach();
segment->destroy();
bool deletedSource = gcells->gcellAt( 0 )->unrefContact( source );
bool deletedTarget = gcells->gcellAt( gcells->size()-1 )->unrefContact( target );
@ -635,7 +683,7 @@ namespace Anabatic {
getNetData( net )->setGlobalRouted( false );
cdebug_tabw(111,-1);
cdebug_tabw(112,-1);
DebugSession::close();
}
@ -1008,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())
@ -78,8 +69,7 @@ namespace Anabatic {
, _edgeWidth (DbU::fromLambda(Cfg::getParamInt("anabatic.edgeWidth" , 4)->asInt()))
, _edgeCostH (Cfg::getParamDouble("anabatic.edgeCostH", 9.0)->asDouble())
, _edgeCostK (Cfg::getParamDouble("anabatic.edgeCostK",-10.0)->asDouble())
, _hEdgeLocal (Cfg::getParamInt("kite.hTracksReservedLocal",0)->asInt())
, _vEdgeLocal (Cfg::getParamInt("kite.vTracksReservedLocal",0)->asInt())
, _edgeHInc (Cfg::getParamDouble("anabatic.edgeHInc" , 1.5)->asDouble())
{
if (cg == NULL) cg = AllianceFramework::get()->getCellGauge();
if (rg == NULL) rg = AllianceFramework::get()->getRoutingGauge();
@ -118,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)
@ -131,13 +120,14 @@ namespace Anabatic {
, _allowedDepth (other._allowedDepth)
, _edgeCostH (other._edgeCostH)
, _edgeCostK (other._edgeCostK)
, _edgeHInc (other._edgeHInc)
{
if (other._cg) _cg = other._cg->getClone();
if (other._rg) _rg = other._rg->getClone();
}
ConfigurationConcrete::~ConfigurationConcrete ()
Configuration::~Configuration ()
{
cdebug_log(145,0) << "About to delete attribute _rg (RoutingGauge)." << endl;
_cg->destroy ();
@ -145,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);
@ -264,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) {
@ -299,44 +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 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 );
@ -349,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;
@ -365,7 +350,7 @@ namespace Anabatic {
}
Record* ConfigurationConcrete::_getRecord () const
Record* Configuration::_getRecord () const
{
Record* record = new Record ( _getString() );
record->add ( getSlot( "_rg" , _rg ) );
@ -380,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.
}
@ -172,17 +171,18 @@ namespace Anabatic {
Dijkstra::Dijkstra ( AnabaticEngine* anabatic )
: _anabatic (anabatic)
, _vertexes ()
, _distanceCb (_distance)
, _mode (Mode::Standart)
, _net (NULL)
, _stamp (-1)
, _sources ()
, _targets ()
, _searchArea ()
, _connectedsId(-1)
, _queue ()
: _anabatic (anabatic)
, _vertexes ()
, _distanceCb (_distance)
, _mode (Mode::Standart)
, _net (NULL)
, _stamp (-1)
, _sources ()
, _targets ()
, _searchArea ()
, _searchAreaHalo(0)
, _connectedsId (-1)
, _queue ()
{
const vector<GCell*>& gcells = _anabatic->getGCells();
for ( GCell* gcell : gcells ) {
@ -216,6 +216,8 @@ namespace Anabatic {
for ( auto rp : rps ) {
Point center = rp->getBoundingBox().getCenter();
GCell* gcell = _anabatic->getGCellUnder( center );
cdebug_log(112,0) << "| " << rp << endl;
if (not gcell) {
cerr << Error( "Dijkstra::load(): %s of %s is not under any GCell.\n"
@ -244,7 +246,7 @@ namespace Anabatic {
vertex->setFrom ( NULL );
vertex->clearRestriction();
_targets.insert( vertex );
cdebug_log(112,0) << "Add Vertex: " << vertex << endl;
cdebug_log(112,0) << "| Add: " << vertex << endl;
}
}
@ -254,6 +256,7 @@ namespace Anabatic {
rp->getBodyHook()->attach( vcontact->getBodyHook() );
}
_searchArea.inflate( _searchAreaHalo );
cdebug_log(112,0) << "Search area: " << _searchArea << endl;
cdebug_tabw(112,-1);
DebugSession::close();

View File

@ -39,6 +39,7 @@ namespace Anabatic {
, _capacity (0)
, _realOccupancy (0)
, _estimateOccupancy(0.0)
, _historicCost (0.0)
, _source (source)
, _target (target)
, _axis (0)
@ -222,6 +223,25 @@ namespace Anabatic {
}
size_t Edge::ripup ()
{
AnabaticEngine* anabatic = getAnabatic();
DbU::Unit globalThreshold = Session::getSliceHeight()*3;
size_t netCount = 0;
for ( size_t i=0 ; i<_segments.size(); ) {
if (_segments[i]->getLength() >= globalThreshold) {
NetData* netData = anabatic->getNetData( _segments[i]->getNet() );
if (netData->isGlobalRouted()) ++netCount;
anabatic->ripup( _segments[i], Flags::Propagate );
} else
++i;
}
return netCount;
}
void Edge::_setSource ( GCell* source )
{
if (source == _target)
@ -299,6 +319,7 @@ namespace Anabatic {
s.insert( s.size()-1, " "+DbU::getValueString(_axis) );
s.insert( s.size()-1, " "+getString(_realOccupancy) );
s.insert( s.size()-1, "/"+getString(_capacity) );
s.insert( s.size()-1, " h:"+getString(_historicCost) );
s.insert( s.size()-1, " "+getString(_flags) );
return s;
}

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;
@ -594,7 +604,7 @@ namespace Anabatic {
GCell* GCell::vcut ( DbU::Unit x )
{
cdebug_log(119,1) << "GCell::vcut() @x:" << DbU::getValueString(x) << " " << this << endl;
cdebug_log(110,1) << "GCell::vcut() @x:" << DbU::getValueString(x) << " " << this << endl;
if ( (x < getXMin()) or (x > getXMax()) )
throw Error( "GCell::vcut(): Vertical cut axis at %s is outside GCell box,\n"
@ -604,7 +614,7 @@ namespace Anabatic {
);
GCell* chunk = _create( x, getYMin() );
cdebug_log(119,0) << "New chunk:" << chunk << endl;
cdebug_log(110,0) << "New chunk:" << chunk << endl;
_moveEdges( chunk, 0, Flags::EastSide );
Edge::create( this, chunk, Flags::Horizontal );
@ -646,7 +656,7 @@ namespace Anabatic {
_revalidate();
chunk->_revalidate();
cdebug_tabw(119,-1);
cdebug_tabw(110,-1);
return chunk;
}
@ -654,7 +664,7 @@ namespace Anabatic {
GCell* GCell::hcut ( DbU::Unit y )
{
cdebug_log(119,1) << "GCell::hcut() @y:" << DbU::getValueString(y) << " " << this << endl;
cdebug_log(110,1) << "GCell::hcut() @y:" << DbU::getValueString(y) << " " << this << endl;
if ( (y < getYMin()) or (y > getYMax()) )
throw Error( "GCell::hcut(): Horizontal cut axis at %s is outside GCell box,\n"
@ -664,7 +674,7 @@ namespace Anabatic {
);
GCell* chunk = _create( getXMin(), y );
cdebug_log(119,0) << "New chunk:" << chunk << endl;
cdebug_log(110,0) << "New chunk:" << chunk << endl;
_moveEdges( chunk, 0, Flags::NorthSide );
Edge::create( this, chunk, Flags::Vertical );
@ -698,7 +708,7 @@ namespace Anabatic {
_revalidate();
chunk->_revalidate();
cdebug_tabw(119,-1);
cdebug_tabw(110,-1);
return chunk;
}
@ -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
@ -63,7 +63,9 @@ namespace {
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();
float distance = (float)source->getDistance()
+ congestionCost * (float)edge->getDistance();
+ edge->getHistoricCost();
// Edge* sourceFrom = source->getFrom();
// if (sourceFrom) {
@ -77,6 +79,19 @@ namespace {
}
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.
@ -119,10 +134,10 @@ namespace Anabatic {
//DebugSession::addToTrace( cell->getNet("a_from_pads(0)") );
//DebugSession::addToTrace( cell->getNet("ialu.not_aux104") );
//DebugSession::addToTrace( cell->getNet("mips_r3000_1m_dp_shift32_rshift_se_muxoutput(159)") );
//DebugSession::addToTrace( cell->getNet("mips_r3000_1m_dp_shift32_rshift_se_c1(3)") );
startMeasures();
UpdateSession::open();
if (getGCells().size() == 1) {
cmess1 << " o Building regular grid..." << endl;
getSouthWestGCell()->doGrid();
@ -130,22 +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;
UpdateSession::open();
float edgeHInc = getConfiguration()->getEdgeHInc();
Dijkstra* dijkstra = new Dijkstra ( this );
dijkstra->setDistance( DigitalDistance( getConfiguration()->getEdgeCostH()
, getConfiguration()->getEdgeCostK() ) );
@ -165,24 +179,31 @@ namespace Anabatic {
}
cmess2 << left << setw(6) << netCount << right;
//Session::revalidate();
const vector<Edge*>& ovEdges = getOvEdges();
cmess2 << " ovEdges:" << ovEdges.size();
for ( Edge* edge : ovEdges ) computeNextHCost( edge, edgeHInc );
netCount = 0;
while ( not ovEdges.empty() ) {
Edge* ovEdge = ovEdges[0];
size_t iEdge = 0;
while ( iEdge < ovEdges.size() ) {
Edge* edge = ovEdges[iEdge];
netCount += edge->ripup();
vector<Segment*> segments = ovEdge->getSegments();
for ( Segment* segment : segments ) {
NetData* netData = getNetData( segment->getNet() );
if (netData->isGlobalRouted()) ++netCount;
ripup( segment, Flags::Propagate );
if (ovEdges[iEdge] == edge) {
cerr << Error( "AnabaticEngine::globalRoute(): Unable to ripup enough segments of edge:\n"
" %s"
, getString(edge).c_str()
) << endl;
++iEdge;
}
}
cmess2 << " ripup:" << netCount;
dijkstra->setSearchAreaHalo( Session::getSliceHeight()*3 );
cmess2 << " ripup:" << netCount;
stopMeasures();
cmess2 << " " << setw(10) << Timer::getStringTime (_timer.getCombTime())
<< " " << setw( 6) << Timer::getStringMemory(_timer.getIncrease()) << endl;
@ -218,7 +239,7 @@ namespace Anabatic {
printMeasures( "Dijkstra" );
delete dijkstra;
UpdateSession::close();
Session::close();
_state = EngineGlobalLoaded;
}

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

@ -2154,7 +2154,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()
);*/
}
@ -2192,7 +2195,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,119 +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 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 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;
@ -179,12 +117,10 @@ namespace Anabatic {
DbU::Unit _edgeWidth;
float _edgeCostH;
float _edgeCostK;
size_t _hEdgeLocal;
size_t _vEdgeLocal;
float _edgeHInc;
private:
ConfigurationConcrete ( const ConfigurationConcrete& );
ConfigurationConcrete& operator= ( const ConfigurationConcrete& );
void _setTopRoutingLayer ( Name name );
Configuration& operator= ( const Configuration& ) = delete;
void _setTopRoutingLayer ( Name name );
};
@ -192,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; }
@ -293,7 +293,9 @@ namespace Anabatic {
inline bool isBipoint () const;
inline bool isSourceVertex ( Vertex* ) const;
inline bool isTargetVertex ( Vertex* ) const;
inline DbU::Unit getSearchAreaHalo () const;
inline void setDistance ( distance_t );
inline void setSearchAreaHalo ( DbU::Unit );
void load ( Net* );
void run ( Mode mode=Mode::Standart );
private:
@ -319,6 +321,7 @@ namespace Anabatic {
VertexSet _sources;
VertexSet _targets;
Box _searchArea;
DbU::Unit _searchAreaHalo;
int _connectedsId;
PriorityQueue _queue;
};
@ -327,10 +330,12 @@ namespace Anabatic {
inline Dijkstra::Mode::Mode ( unsigned int flags ) : BaseFlags(flags) { }
inline Dijkstra::Mode::Mode ( BaseFlags base ) : BaseFlags(base) { }
inline bool Dijkstra::isBipoint () const { return _net and (_targets.size()+_sources.size() == 2); }
inline bool Dijkstra::isSourceVertex ( Vertex* v ) const { return (_sources.find(v) != _sources.end()); }
inline bool Dijkstra::isTargetVertex ( Vertex* v ) const { return (_targets.find(v) != _targets.end()); }
inline void Dijkstra::setDistance ( distance_t cb ) { _distanceCb = cb; }
inline bool Dijkstra::isBipoint () const { return _net and (_targets.size()+_sources.size() == 2); }
inline bool Dijkstra::isSourceVertex ( Vertex* v ) const { return (_sources.find(v) != _sources.end()); }
inline bool Dijkstra::isTargetVertex ( Vertex* v ) const { return (_targets.find(v) != _targets.end()); }
inline DbU::Unit Dijkstra::getSearchAreaHalo () const { return _searchAreaHalo; }
inline void Dijkstra::setDistance ( distance_t cb ) { _distanceCb = cb; }
inline void Dijkstra::setSearchAreaHalo ( DbU::Unit halo ) { _searchAreaHalo = halo; }
} // Anabatic namespace.

View File

@ -62,6 +62,7 @@ namespace Anabatic {
inline unsigned int getCapacity () const;
inline unsigned int getRealOccupancy () const;
inline unsigned int getEstimateOccupancy () const;
inline float getHistoricCost () const;
DbU::Unit getDistance () const;
inline GCell* getSource () const;
inline GCell* getTarget () const;
@ -74,9 +75,11 @@ namespace Anabatic {
inline const vector<Segment*>& getSegments () const;
inline void incCapacity ( int );
void incRealOccupancy ( int );
inline void setHistoricCost ( float );
void add ( Segment* );
void remove ( Segment* );
void replace ( Segment* orig, Segment* repl );
size_t ripup ();
inline const Flags& flags () const;
inline Flags& flags ();
inline void revalidate () const;
@ -110,6 +113,7 @@ namespace Anabatic {
unsigned int _capacity;
unsigned int _realOccupancy;
float _estimateOccupancy;
float _historicCost;
GCell* _source;
GCell* _target;
DbU::Unit _axis;
@ -124,11 +128,13 @@ namespace Anabatic {
inline unsigned int Edge::getCapacity () const { return _capacity; }
inline unsigned int Edge::getRealOccupancy () const { return _realOccupancy; }
inline unsigned int Edge::getEstimateOccupancy () const { return _estimateOccupancy; }
inline float Edge::getHistoricCost () const { return _historicCost; }
inline GCell* Edge::getSource () const { return _source; }
inline GCell* Edge::getTarget () const { return _target; }
inline DbU::Unit Edge::getAxis () const { return _axis; }
inline const vector<Segment*>& Edge::getSegments () const { return _segments; }
inline void Edge::incCapacity ( int delta ) { _capacity = ((int)_capacity+delta > 0) ? _capacity+delta : 0; }
inline void Edge::setHistoricCost ( float hcost ) { _historicCost = hcost; }
inline const Flags& Edge::flags () const { return _flags; }
inline Flags& Edge::flags () { return _flags; }
inline void Edge::revalidate () const { /*if (_flags&Flags::Invalidated)*/ const_cast<Edge*>(this)->_revalidate(); }

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

@ -398,7 +398,8 @@ class Report ( object ):
for attachement in self.attachements:
self.message.attach( attachement )
print "Sending mail report to <%s>" % self.conf.receivers
print "Sending mail report to:"
for receiver in self.conf.receivers: print ' <%s>' % receiver
session = smtplib.SMTP( 'localhost' )
session.sendmail( self.conf.sender, self.conf.receivers, self.message.as_string() )
session.quit()
@ -434,6 +435,9 @@ try:
if options.rmSource or options.rmAll: conf.rmSource = True
if options.rmBuild or options.rmAll: conf.rmBuild = True
if conf.doBuild: conf.openLog( 'build' )
if conf.doBenchs: conf.openLog( 'benchs' )
gitSupports = []
for supportRepo in conf.supportRepos:
gitSupports.append( GitRepository( supportRepo, conf.srcDir+'/support' ) )
@ -472,9 +476,6 @@ try:
, ' <%s>' % ccbBin
] )
if conf.doBuild: conf.openLog( 'build' )
if conf.doBenchs: conf.openLog( 'benchs' )
buildCommand = '%s --root=%s --project=support --project=coriolis --project=chams --make="-j%%d install" %%s' \
% (ccbBin,conf.rootDir)
benchsCommand = 'cd %s/benchs && ./bin/go.sh clean && ./bin/go.sh lvx' \

View File

@ -55,8 +55,13 @@ namespace CRL {
//_view->resizeColumnToContents ( 1 );
QHeaderView* horizontalHeader = _view->horizontalHeader();
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
horizontalHeader->setSectionResizeMode ( 0, QHeaderView::Stretch );
horizontalHeader->setSectionResizeMode ( 1, QHeaderView::ResizeToContents );
#else
horizontalHeader->setResizeMode ( 0, QHeaderView::Stretch );
horizontalHeader->setResizeMode ( 1, QHeaderView::ResizeToContents );
#endif
//horizontalHeader->setStretchLastSection( false );
QHeaderView* verticalHeader = _view->verticalHeader();

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

@ -262,7 +262,6 @@ namespace {
return;
}
}
}
}
@ -414,6 +413,7 @@ namespace Hurricane {
// Class : "Hurricane::Backtrace".
bool Backtrace::_inConstructor = false;
TextTranslator Backtrace::_textTranslator = TextTranslator::toTextTranslator();
const size_t Backtrace::_stackSize = 50;
@ -428,6 +428,22 @@ namespace Hurricane {
Backtrace::Backtrace ()
: _stack()
{
if (_inConstructor) {
_stack.push_back( "[BUG] Backtrace::Backtrace(): An error occurred in the backtace *istself*." );
_stack.push_back( "" );
_stack.push_back( " Under RHEL 6, this may be due to a link with a wrong version of <libbfd>," );
_stack.push_back( " please check that you have the <devtoolset-2-binutils-devel> package" );
_stack.push_back( " installed." );
_stack.push_back( "" );
_stack.push_back( " For other OSs, check for any problems related to BFD." );
return;
}
_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 );
@ -472,6 +488,7 @@ namespace Hurricane {
_stack.push_back( symbols[i] );
}
}
#else
# ifdef __APPLE__
boost::regex re ( "(\\d+)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)\\s+\\+\\s+(\\d+)" );
boost::cmatch match;
@ -495,9 +512,14 @@ namespace Hurricane {
_stack.push_back( "Backtrace only supported under FreeBSD, Linux and OSX." );
# endif
#endif
_inConstructor = false;
}
Backtrace::~Backtrace ()
{ }
string Backtrace::htmlWhere () const
{
ostringstream where;

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

@ -43,15 +43,17 @@ namespace Hurricane {
class Backtrace {
public:
Backtrace ();
~Backtrace ();
inline std::string where () const;
inline std::string textWhere () const;
std::string htmlWhere () const;
inline std::string _getTypeName () const;
inline std::string _getString () const;
private:
static TextTranslator _textTranslator;
static const size_t _stackSize;
std::vector<std::string> _stack;
static bool _inConstructor;
static TextTranslator _textTranslator;
static const size_t _stackSize;
std::vector<std::string> _stack;
};

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

View File

@ -65,8 +65,13 @@ namespace Hurricane {
QHeaderView* horizontalHeader = _view->header();
horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter );
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 600 : 300 );
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
horizontalHeader->setResizeMode ( 0, QHeaderView::Interactive );
horizontalHeader->setResizeMode ( 1, QHeaderView::Interactive );
// #else
// horizontalHeader->setSectionResizeMode ( 0, QHeaderView::Interactive );
// horizontalHeader->setSectionResizeMode ( 1, QHeaderView::Interactive );
#endif
horizontalHeader->setStretchLastSection( true );
QLabel* filterPatternLabel = new QLabel(tr("&Filter pattern:"), this);
@ -219,7 +224,8 @@ namespace Hurricane {
{
if (delta == 0) return;
QModelIndex newIndex = _baseModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() );
//QModelIndex newIndex =
_baseModel->index( _view->currentIndex().row()+delta, 0, QModelIndex() );
//if (newIndex.isValid())
// _view->selectRow( newIndex.row() );

View File

@ -71,9 +71,6 @@ namespace Hurricane {
QHeaderView* horizontalHeader = _view->horizontalHeader();
horizontalHeader->setDefaultAlignment ( Qt::AlignHCenter );
horizontalHeader->setMinimumSectionSize( (Graphics::isHighDpi()) ? 300 : 150 );
horizontalHeader->setResizeMode ( 0, QHeaderView::Interactive );
horizontalHeader->setResizeMode ( 1, QHeaderView::Interactive );
horizontalHeader->setResizeMode ( 2, QHeaderView::Interactive );
horizontalHeader->setStretchLastSection( true );
QHeaderView* verticalHeader = _view->verticalHeader();

View File

@ -66,8 +66,9 @@ namespace Hurricane {
inline void HierarchyModel::setCell ( Cell* cell )
{
beginResetModel();
_root.setCell( cell );
reset();
endResetModel();
}

View File

@ -66,17 +66,14 @@ namespace Hurricane {
template<typename InformationType>
void NetlistModel::setCell ( Cell* cell )
{
if ( _cell != cell ) {
if ( _cell )
delete _netlist;
if (_cell != cell) {
if (_cell) delete _netlist;
_cell = cell;
_netlist = new NetInformationsVector<InformationType>();
if ( _cell ) {
forEach ( Net*, net, _cell->getNets() ) {
_netlist->addNet ( *net );
}
if (_cell) {
for ( Net* net : _cell->getNets() ) _netlist->addNet( net );
}
emit layoutChanged ();
@ -84,7 +81,6 @@ namespace Hurricane {
}
} // End of Hurricane namespace.
} // Hurricane namespace.
#endif // __NETLIST_MODEL_H__
#endif // HURRICANE_NETLIST_MODEL_H

View File

@ -18,10 +18,10 @@
#ifndef HURRICANE_NETLIST_WIDGET_H
#define HURRICANE_NETLIST_WIDGET_H
#include <set>
#include <QWidget>
#include <QTableView>
#include <QHeaderView>
#include <QItemDelegate>
#include <QSortFilterProxyModel>
#include "hurricane/Commons.h"
@ -187,9 +187,17 @@ namespace Hurricane {
string windowTitle = "Netlist" + getString(cell);
setWindowTitle( tr(windowTitle.c_str()) );
QHeaderView* header = _view->horizontalHeader();
_view->selectRow( 0 );
for ( int i=0 ; i<_baseModel->columnCount() ; ++i )
for ( int i=0 ; i<_baseModel->columnCount() ; ++i ) {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
header->setSectionResizeMode( i, QHeaderView::Interactive );
#else
header->setResizeMode( i, QHeaderView::Interactive );
#endif
_view->resizeColumnToContents( i );
}
_view->setVisible( true );
}

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

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