2680 lines
110 KiB
C++
2680 lines
110 KiB
C++
|
|
|||
|
#include <algorithm>
|
|||
|
|
|||
|
#include "hurricane/Warning.h"
|
|||
|
#include "hurricane/Name.h"
|
|||
|
#include "hurricane/Horizontal.h"
|
|||
|
#include "hurricane/Vertical.h"
|
|||
|
#include "hurricane/RoutingPad.h"
|
|||
|
#include "hurricane/Component.h"
|
|||
|
#include "hurricane/Net.h"
|
|||
|
#include "hurricane/Cell.h"
|
|||
|
#include "hurricane/Technology.h"
|
|||
|
#include "hurricane/DataBase.h"
|
|||
|
#include "hurricane/UpdateSession.h"
|
|||
|
#include "hurricane/Breakpoint.h"
|
|||
|
|
|||
|
#include "crlcore/Utilities.h"
|
|||
|
#include "crlcore/AllianceFramework.h"
|
|||
|
#include "crlcore/RoutingGauge.h"
|
|||
|
#include "crlcore/RoutingLayerGauge.h"
|
|||
|
|
|||
|
#include "knik/Configuration.h"
|
|||
|
#include "knik/Graph.h"
|
|||
|
#include "knik/Vertex.h"
|
|||
|
#include "knik/Edge.h"
|
|||
|
#include "knik/HEdge.h"
|
|||
|
#include "knik/VEdge.h"
|
|||
|
|
|||
|
#include "knik/flute.h"
|
|||
|
|
|||
|
//#define __USE_SLICINGTREE__
|
|||
|
#define __USE_MATRIXVERTEX__
|
|||
|
|
|||
|
#define EPSILON 10e-4
|
|||
|
#define FLUTE_LIMIT 150
|
|||
|
#define HISTORIC_INC 1.5 // define the increment of historic cost for ripup & reroute
|
|||
|
|
|||
|
namespace Knik {
|
|||
|
|
|||
|
int depthMaterialize;
|
|||
|
unsigned countDijkstra = 0;
|
|||
|
unsigned countMonotonic = 0;
|
|||
|
unsigned countMaterialize = 0;
|
|||
|
bool debugging;
|
|||
|
Name debugName = Name("");
|
|||
|
|
|||
|
bool __ripupMode__;
|
|||
|
|
|||
|
extern float __edge_capacity_percent__;
|
|||
|
extern unsigned __congestion__;
|
|||
|
extern unsigned __precongestion__;
|
|||
|
|
|||
|
using namespace CRL;
|
|||
|
|
|||
|
STuple::STuplePQIter STuple::_stuplePQEnd;
|
|||
|
Name STuple::CostProperty::_name = "Knik::CostProperty";
|
|||
|
|
|||
|
struct segmentStat {
|
|||
|
unsigned nbDep;
|
|||
|
unsigned nbTot;
|
|||
|
unsigned sumOv;
|
|||
|
|
|||
|
segmentStat(unsigned dep, unsigned tot, unsigned ov) { nbDep=dep; nbTot=tot; sumOv=ov; };
|
|||
|
segmentStat() {};
|
|||
|
~segmentStat() {};
|
|||
|
|
|||
|
void incNbDep() { nbDep++; };
|
|||
|
void incNbTot() { nbTot++; };
|
|||
|
void incSumOv ( unsigned inc ) { sumOv+=inc; };
|
|||
|
|
|||
|
unsigned getNbDep() const { return nbDep; };
|
|||
|
unsigned getNbTot() const { return nbTot; };
|
|||
|
unsigned getSumOv() const { return sumOv; };
|
|||
|
};
|
|||
|
|
|||
|
Graph::Graph ( Cell* cell, RoutingGrid* routingGrid, bool benchMode, bool useSegments )
|
|||
|
// **********************************************************************************************
|
|||
|
: _cell ( cell )
|
|||
|
, _benchMode ( benchMode )
|
|||
|
, _useSegments ( useSegments )
|
|||
|
, _slicingTree ( NULL )
|
|||
|
, _matrixVertex ( NULL )
|
|||
|
, _routingGrid ( routingGrid )
|
|||
|
, _working_net ( NULL )
|
|||
|
, _vertexes_to_route()
|
|||
|
, _lowerLeftVertex ( NULL )
|
|||
|
, _all_vertexes()
|
|||
|
, _all_edges()
|
|||
|
, _nbSplitters ( 0 )
|
|||
|
, _vtuplePriorityQueue()
|
|||
|
, _stuplePriorityQueue()
|
|||
|
, _searchingArea()
|
|||
|
, _xSize ( 0 )
|
|||
|
, _ySize ( 0 )
|
|||
|
//, _estimateOccupancyWindow ( NULL )
|
|||
|
//, _occupancyWindow ( NULL )
|
|||
|
, _maxEstimateOccupancy ( 0.0 )
|
|||
|
, _maxXEstimateOccupancy ( 0.0 )
|
|||
|
, _maxYEstimateOccupancy ( 0.0 )
|
|||
|
, _maxOccupancy ( 0 )
|
|||
|
, _maxXOccupancy ( 0 )
|
|||
|
, _maxYOccupancy ( 0 )
|
|||
|
, _hEdgeNormalisedLength ( 1.0 ) // au cas ou
|
|||
|
, _vEdgeNormalisedLength ( 1.0 ) // au cas ou
|
|||
|
{
|
|||
|
__ripupMode__ = false;
|
|||
|
}
|
|||
|
|
|||
|
Graph* Graph::create ( Cell* cell, RoutingGrid* routingGrid, bool benchMode, bool useSegments )
|
|||
|
// ******************************************************************************************************
|
|||
|
{
|
|||
|
Graph* _graph = new Graph ( cell, routingGrid, benchMode, useSegments );
|
|||
|
|
|||
|
_graph->_postCreate();
|
|||
|
|
|||
|
return _graph;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::_postCreate()
|
|||
|
// **********************
|
|||
|
{
|
|||
|
_netStamp = 1; // initializing netStamp here instead of in Knik::Route function (for reroute, it seems good)
|
|||
|
|
|||
|
//Cell* cell = _nimbus->getCell();
|
|||
|
//DisplaySlot* vertexDS = DisplaySlot::create( cell, Name("KnikVertexDS"),192, 0 ,192,"FFFFFFFFFFFFFFFF",1,192, 0 ,192,"FFFFFFFFFFFFFFFF",1 );
|
|||
|
//DisplaySlot* edgeDS = DisplaySlot::create( cell, Name("KnikEdgeDS") ,153,100, 17,"55AA55AA55AA55AA",1,153,100, 17,"55AA55AA55AA55AA",1 );
|
|||
|
|
|||
|
// XXX On supprime tout ce qui concerne NIMBUS et on considère qu'il existe toujours une _routingGrid XXX
|
|||
|
if ( !_routingGrid ) {
|
|||
|
#ifdef __USE_MATRIXVERTEX__
|
|||
|
_matrixVertex = MatrixVertex::create(this);
|
|||
|
if( !_matrixVertex )
|
|||
|
throw Error ("Graph::_postCreate(): cannot create MatrixVertex");
|
|||
|
_lowerLeftVertex = _matrixVertex->createRegularMatrix ();
|
|||
|
cmess2 << " - Initialization done (without routingGrid)" << endl;
|
|||
|
#else
|
|||
|
throw Error ("Graph::_postCreate(): cannot use another method than MatrixVertex");
|
|||
|
#endif
|
|||
|
// il faut définir les normalisedLength, pour l'instant on le fait pas
|
|||
|
}
|
|||
|
else {
|
|||
|
cmess2 << " - Size from routingGrid : " << _routingGrid->getNbXTiles() << ", " << _routingGrid->getNbYTiles() << endl;
|
|||
|
#ifdef __USE_MATRIXVERTEX__
|
|||
|
_matrixVertex = MatrixVertex::create(this);
|
|||
|
if( !_matrixVertex )
|
|||
|
throw Error ("Graph::_postCreate(): cannot create MatrixVertex");
|
|||
|
_lowerLeftVertex = _matrixVertex->createRegularMatrix ( _routingGrid );
|
|||
|
// initialisation des normalisedLength
|
|||
|
float hEdgeLength = _routingGrid->getTileWidth();
|
|||
|
float vEdgeLength = _routingGrid->getTileHeight();
|
|||
|
_hEdgeNormalisedLength = hEdgeLength <= vEdgeLength ? 1.0 : hEdgeLength / vEdgeLength;
|
|||
|
_vEdgeNormalisedLength = hEdgeLength <= vEdgeLength ? vEdgeLength / hEdgeLength : 1.0;
|
|||
|
cmess2 << " - Initialization done." << endl;
|
|||
|
#else
|
|||
|
throw Error ("Graph::_postCreate(): cannot use another method than MatrixVertex");
|
|||
|
#endif
|
|||
|
}
|
|||
|
// #ifdef __USE_MATRIXVERTEX__
|
|||
|
// _matrixVertex = MatrixVertex::create(this);
|
|||
|
// if ( _routingGrid ) {
|
|||
|
// _matrixVertex->createXRegular ( _routingGrid );
|
|||
|
// _matrixVertex->createYRegular ( _routingGrid );
|
|||
|
// }
|
|||
|
// else {
|
|||
|
// _matrixVertex->createXIrregular ( _nimbus );
|
|||
|
// _matrixVertex->createYIrregular ( _nimbus );
|
|||
|
// }
|
|||
|
// #endif
|
|||
|
// #ifdef __USE_SLICINGTREE__
|
|||
|
// _slicingTree = SlicingTree::create ( _nimbus );
|
|||
|
// #endif
|
|||
|
//
|
|||
|
// unsigned compteur = 0;
|
|||
|
// for_each_gcell ( gcell, _nimbus->getRoutingLeaves() )
|
|||
|
// {
|
|||
|
// compteur++;
|
|||
|
// Vertex* vertex = Vertex::create ( gcell, this );
|
|||
|
// if ( !_lowerLeftVertex )
|
|||
|
// _lowerLeftVertex = vertex;
|
|||
|
// else {
|
|||
|
// if ( vertex->getX() <= _lowerLeftVertex->getX() ) {
|
|||
|
// if ( vertex->getY() <= _lowerLeftVertex->getY() )
|
|||
|
// _lowerLeftVertex = vertex;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// _all_vertexes.push_back ( vertex );
|
|||
|
// #ifdef __USE_MATRIXVERTEX__
|
|||
|
// _matrixVertex->setVertex ( gcell->getCenter(), vertex );
|
|||
|
// #endif
|
|||
|
// #ifdef __USE_SLICINGTREE__
|
|||
|
// SlicingTreeNode* terminalNode = _slicingTree->getTerminalNode ( gcell->getCenter() );
|
|||
|
// terminalNode->setVertex ( vertex );
|
|||
|
// #endif
|
|||
|
// end_for;
|
|||
|
// }
|
|||
|
// cmess2 << " - Parcours des gcells pour créer les vertex terminé : " << compteur << " vertex" << endl;
|
|||
|
//
|
|||
|
// Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// Vertex* firstLineVertex = currentVertex;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// GCell* source = currentVertex->getGCell();
|
|||
|
// Fence* fenceUP = source->getUpFence();
|
|||
|
// GCell* targetUP = source->getUpOfMe();
|
|||
|
// if ( targetUP )
|
|||
|
// createVEdge ( currentVertex, getVertex ( targetUP->getCenter() ), fenceUP );
|
|||
|
// Fence* fenceRIGHT = source->getRightFence();
|
|||
|
// GCell* targetRIGHT = source->getRightOfMe();
|
|||
|
// if ( targetRIGHT ) {
|
|||
|
// Vertex* rightVertex = getVertex ( targetRIGHT->getCenter() );
|
|||
|
// createHEdge ( currentVertex, rightVertex, fenceRIGHT );
|
|||
|
// currentVertex = rightVertex;
|
|||
|
// }
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
|||
|
// if ( vEdgeOut )
|
|||
|
// currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// cmess2 << " - Parcours des gcells puis des fences pour créer les edges terminé" << endl;
|
|||
|
|
|||
|
for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
|
|||
|
_all_vertexes[i]->sortEdges();
|
|||
|
}
|
|||
|
cmess2 << " - Tri des edges terminé" << endl;
|
|||
|
|
|||
|
STuple::setSTuplePQEnd ( _stuplePriorityQueue.end() );
|
|||
|
|
|||
|
// cmess2 << "Petites stats :" << endl
|
|||
|
// << " gcell : " << sizeof(GCell) << endl
|
|||
|
// << " fence : " << sizeof(Fence) << endl
|
|||
|
// << " vertex : " << sizeof(Vertex) << endl
|
|||
|
// << " edge : " << sizeof (Edge) << endl
|
|||
|
// << " net : " << sizeof(Net) << endl
|
|||
|
// << " pin : " << sizeof(Pin) << endl
|
|||
|
// << " splitter : " << sizeof(Splitter) << endl
|
|||
|
// << " splitterContact : " << sizeof(SplitterContact) << endl;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void Graph::destroy()
|
|||
|
// *****************
|
|||
|
{
|
|||
|
_preDestroy();
|
|||
|
delete this;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::_preDestroy()
|
|||
|
// *********************
|
|||
|
{
|
|||
|
// Destruction of all VTuples
|
|||
|
for ( VTuplePQIter pqit = _vtuplePriorityQueue.begin() ; pqit != _vtuplePriorityQueue.end() ; pqit++ ) {
|
|||
|
(*pqit)->destroy();
|
|||
|
}
|
|||
|
|
|||
|
// Destrucion of all Edges and Vertexes
|
|||
|
Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
while ( currentVertex ) {
|
|||
|
Vertex* nextVVertex;
|
|||
|
if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
|
|||
|
nextVVertex = vEdgeOut->getOpposite ( currentVertex );
|
|||
|
else
|
|||
|
nextVVertex = NULL;
|
|||
|
|
|||
|
while ( currentVertex ) {
|
|||
|
if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
|
|||
|
vEdgeOut->destroy();
|
|||
|
|
|||
|
Vertex* nextHVertex;
|
|||
|
if ( Edge* hEdgeOut = currentVertex->getHEdgeOut() ) {
|
|||
|
nextHVertex = hEdgeOut->getOpposite ( currentVertex );
|
|||
|
hEdgeOut->destroy();
|
|||
|
}
|
|||
|
else
|
|||
|
nextHVertex = NULL;
|
|||
|
currentVertex->destroy();
|
|||
|
currentVertex = nextHVertex;
|
|||
|
}
|
|||
|
currentVertex = nextVVertex;
|
|||
|
}
|
|||
|
|
|||
|
//// Destruction of all Edges
|
|||
|
//for ( unsigned i = 0 ; i < _all_edges.size() ; i++ ) {
|
|||
|
// _all_edges[i]->destroy();
|
|||
|
//}
|
|||
|
|
|||
|
//// Destruction of all Vertexes
|
|||
|
//for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
|
|||
|
// _all_vertexes[i]->destroy();
|
|||
|
//}
|
|||
|
|
|||
|
#ifdef __USE_MATRIXVERTEX__
|
|||
|
_matrixVertex->destroy();
|
|||
|
#endif
|
|||
|
#ifdef __USE_SLICINGTREE__
|
|||
|
_slicingTree->destroy();
|
|||
|
#endif
|
|||
|
}
|
|||
|
|
|||
|
Vertex* Graph::getPredecessor ( const Vertex* vertex )
|
|||
|
// ***************************************************
|
|||
|
{
|
|||
|
assert( vertex->getPredecessor() );
|
|||
|
return vertex->getPredecessor()->getOpposite ( vertex );
|
|||
|
}
|
|||
|
|
|||
|
|
|||
|
Vertex* Graph::getCentralVertex()
|
|||
|
// ******************************
|
|||
|
{
|
|||
|
assert ( _vertexes_to_route.begin() != _vertexes_to_route.end() );
|
|||
|
// This function skims the _vertexes_to_route set and returns the most centered vertex.
|
|||
|
//
|
|||
|
// first pass : builds the bounding box of all vertexes
|
|||
|
Box vertexesBBox;
|
|||
|
VertexSetIter vsit = _vertexes_to_route.begin();
|
|||
|
while ( vsit != _vertexes_to_route.end() ) {
|
|||
|
vertexesBBox.merge((*vsit)->getPosition());
|
|||
|
vsit++;
|
|||
|
}
|
|||
|
// second pass : finds the most centered vertex
|
|||
|
Point boxCenter = vertexesBBox.getCenter();
|
|||
|
vsit = _vertexes_to_route.begin();
|
|||
|
Vertex* mostCentered = (*vsit);
|
|||
|
DbU::Unit minDistance = boxCenter.manhattanDistance ( mostCentered->getPosition() );
|
|||
|
vsit++;
|
|||
|
while ( vsit != _vertexes_to_route.end() ) {
|
|||
|
Vertex* currentVertex = (*vsit);
|
|||
|
DbU::Unit currentDistance = boxCenter.manhattanDistance( currentVertex->getPosition() );
|
|||
|
if ( currentDistance < minDistance ) {
|
|||
|
mostCentered = currentVertex;
|
|||
|
minDistance = currentDistance;
|
|||
|
}
|
|||
|
vsit++;
|
|||
|
}
|
|||
|
|
|||
|
return mostCentered;
|
|||
|
}
|
|||
|
|
|||
|
Vertex* Graph::getVertex ( Point p )
|
|||
|
// *********************************
|
|||
|
{
|
|||
|
Vertex* vertex;
|
|||
|
#ifdef __USE_MATRIXVERTEX__
|
|||
|
vertex = _matrixVertex->getVertex(p);
|
|||
|
assert(vertex);
|
|||
|
#endif
|
|||
|
#ifdef __USE_SLICINGTREE__
|
|||
|
vertex = _slicingTree->getVertex ( p );
|
|||
|
assert ( vertex );
|
|||
|
//#else // Ce n'est plus une option !
|
|||
|
// GCell* gcell = _nimbus->getRoutingLeafContaining ( p );
|
|||
|
// assert ( gcell );
|
|||
|
// vertex = getVertexOfGCell ( gcell );
|
|||
|
// assert ( vertex );
|
|||
|
#endif
|
|||
|
|
|||
|
return vertex;
|
|||
|
}
|
|||
|
|
|||
|
Vertex* Graph::getVertex ( DbU::Unit x, DbU::Unit y )
|
|||
|
// **************************************************
|
|||
|
{
|
|||
|
return getVertex ( Point ( x, y ) );
|
|||
|
}
|
|||
|
|
|||
|
unsigned Graph::getGridLength ( Segment* segment )
|
|||
|
// ***********************************************
|
|||
|
{
|
|||
|
// new time-optimized version 02/02/09
|
|||
|
unsigned sourceColId = _matrixVertex->getColumnIndex ( segment->getSourceX() );
|
|||
|
unsigned targetColId = _matrixVertex->getColumnIndex ( segment->getTargetX() );
|
|||
|
unsigned sourceRowId = _matrixVertex->getLineIndex ( segment->getSourceY() );
|
|||
|
unsigned targetRowId = _matrixVertex->getLineIndex ( segment->getTargetY() );
|
|||
|
if ( sourceColId == targetColId )
|
|||
|
return targetRowId - sourceRowId;
|
|||
|
else
|
|||
|
return targetColId - sourceColId;
|
|||
|
//if ( isAGlobalRoutingSegment(segment) ) {
|
|||
|
// if ( Horizontal* horiz = dynamic_cast<Horizontal*>(segment) ) {
|
|||
|
// unsigned sourceId = _matrixVertex->getColumnIndex ( horiz->getSourceX() );
|
|||
|
// unsigned targetId = _matrixVertex->getColumnIndex ( horiz->getTargetX() );
|
|||
|
// assert ( sourceId != targetId );
|
|||
|
// return targetId - sourceId; // On considere que les segments sont bien orientes !!!!
|
|||
|
// }
|
|||
|
// else if ( Vertical* verti = dynamic_cast<Vertical*>(segment) ) {
|
|||
|
// unsigned sourceId = _matrixVertex->getLineIndex ( verti->getSourceY() );
|
|||
|
// unsigned targetId = _matrixVertex->getLineIndex ( verti->getTargetY() );
|
|||
|
// assert ( sourceId != targetId );
|
|||
|
// return targetId - sourceId; // meme hypothese !!!
|
|||
|
// }
|
|||
|
// else
|
|||
|
// throw Error ( "Graph::getGridLength(): segment is neither horizontal nor vertical." );
|
|||
|
//}
|
|||
|
return 0;
|
|||
|
}
|
|||
|
|
|||
|
unsigned Graph::getCongestEdgeNb ( Segment* segment )
|
|||
|
// **************************************************
|
|||
|
{
|
|||
|
if ( !isAGlobalRoutingSegment(segment) ) {
|
|||
|
string message = "getCongestEdgeNb only treats global routing segment for now : ";
|
|||
|
message += getString(segment);
|
|||
|
throw Warning ( message );
|
|||
|
}
|
|||
|
unsigned nbEdge = 0;
|
|||
|
if ( dynamic_cast<Horizontal*>(segment) ) {
|
|||
|
Vertex* current = getVertex ( segment->getSource()->getCenter() );
|
|||
|
Vertex* target = getVertex ( segment->getTarget()->getCenter() );
|
|||
|
while ( current != target ) {
|
|||
|
Edge* edge = current->getHEdgeOut();
|
|||
|
if ( !edge ) throw Error ("Graph::getCongestEdgeNb(): Wow! NULL horizontal Edge.");
|
|||
|
if ( edge->isCongested() )
|
|||
|
nbEdge++;
|
|||
|
current = edge->getTo();
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( dynamic_cast<Vertical*>(segment) ) {
|
|||
|
Vertex* current = getVertex ( segment->getSource()->getCenter() );
|
|||
|
Vertex* target = getVertex ( segment->getTarget()->getCenter() );
|
|||
|
while ( current != target ) {
|
|||
|
Edge* edge = current->getVEdgeOut();
|
|||
|
if ( !edge ) throw Error ("Graph::getCongestEdgeNb(): Wow! NULL vertical Edge.");
|
|||
|
if ( edge->isCongested() )
|
|||
|
nbEdge++;
|
|||
|
current = edge->getTo();
|
|||
|
}
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::getCongestEdgeNb(): segment is neither horizontal nor vertical." );
|
|||
|
|
|||
|
return nbEdge++;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
Segment* Graph::createSegment ( Contact* initialContact, Contact* reachedContact )
|
|||
|
// *******************************************************************************
|
|||
|
{
|
|||
|
//cerr << "Graph::createSegment: " << initialContact << " -- " << reachedContact << endl;
|
|||
|
if ( initialContact->getX() == reachedContact->getX() ) {
|
|||
|
const Layer* layer = Configuration::getGMetalV();
|
|||
|
DbU::Unit xCoord = initialContact->getX();
|
|||
|
DbU::Unit width = DbU::lambda(2);
|
|||
|
|
|||
|
if ( initialContact->getY() <= reachedContact->getY() )
|
|||
|
return Vertical::create ( initialContact, reachedContact, layer, xCoord, width );
|
|||
|
else
|
|||
|
return Vertical::create ( reachedContact, initialContact, layer, xCoord, width );
|
|||
|
}
|
|||
|
else if ( initialContact->getY() == reachedContact->getY() ) {
|
|||
|
const Layer* layer = Configuration::getGMetalH();
|
|||
|
DbU::Unit yCoord = initialContact->getY();
|
|||
|
DbU::Unit height = DbU::lambda(2);
|
|||
|
|
|||
|
if ( initialContact->getX() <= reachedContact->getX() )
|
|||
|
return Horizontal::create ( initialContact, reachedContact, layer, yCoord, height );
|
|||
|
else
|
|||
|
return Horizontal::create ( reachedContact, initialContact, layer, yCoord, height );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::createSegment(): Contacts are not aligneds." );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::sortHVertexes ( Vertex*& from, Vertex*& to )
|
|||
|
// *****************************************************
|
|||
|
{
|
|||
|
// This function sorts 2 vertexes horizontally:
|
|||
|
// from will be the leftest one
|
|||
|
assert (from);
|
|||
|
assert (to);
|
|||
|
if ( from->getX() > to->getX() ) {
|
|||
|
Vertex* temp = from;
|
|||
|
from = to;
|
|||
|
to = temp;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::sortVVertexes ( Vertex*& from, Vertex*& to )
|
|||
|
// *****************************************************
|
|||
|
{
|
|||
|
// This function sorts 2 vertexes vertically:
|
|||
|
// from will be the downest one
|
|||
|
assert (from);
|
|||
|
assert (to);
|
|||
|
if ( from->getY() > to->getY() ) {
|
|||
|
Vertex* temp = from;
|
|||
|
from = to;
|
|||
|
to = temp;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
Vertex* Graph::createVertex ( Point position, DbU::Unit halfWidth, DbU::Unit halfHeight )
|
|||
|
// **************************************************************************************
|
|||
|
{
|
|||
|
Vertex* vertex = Vertex::create ( this, position, halfWidth, halfHeight );
|
|||
|
assert ( vertex );
|
|||
|
_all_vertexes.push_back ( vertex );
|
|||
|
return vertex;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::createHEdge ( Vertex* from, Vertex* to, float ecp )
|
|||
|
// **************************************************************
|
|||
|
{
|
|||
|
unsigned int capacity = 0;
|
|||
|
if ( _routingGrid ) {
|
|||
|
capacity = _routingGrid->getHCapacity();
|
|||
|
//cerr << "createHEdge capacity:" << capacity << " ecp:" << ecp << endl;
|
|||
|
} else {
|
|||
|
vector<RoutingLayerGauge*> rtLGauges = AllianceFramework::get()->getRoutingGauge()->getLayerGauges();
|
|||
|
for ( vector<RoutingLayerGauge*>::iterator it = rtLGauges.begin() ; it != rtLGauges.end() ; it++ ) {
|
|||
|
RoutingLayerGauge* routingLayerGauge = (*it);
|
|||
|
if (routingLayerGauge->getType() != Constant::Default)
|
|||
|
continue;
|
|||
|
|
|||
|
if (routingLayerGauge->getDirection() != Constant::Horizontal)
|
|||
|
continue;
|
|||
|
|
|||
|
capacity += routingLayerGauge->getTrackNumber ( from->getYMin(), from->getYMax() ) - 1;
|
|||
|
}
|
|||
|
//cerr << "createHEdge capacity:" << capacity << " ecp:" << ecp << endl;
|
|||
|
}
|
|||
|
Edge* newEdge = HEdge::create ( from, to, (unsigned)((float)(capacity)*ecp) );
|
|||
|
|
|||
|
_all_edges.push_back ( newEdge );
|
|||
|
|
|||
|
newEdge->setCost(1);
|
|||
|
|
|||
|
Edge* previousEdge = from->getHEdgeOut();
|
|||
|
if ( previousEdge )
|
|||
|
newEdge->setNextFrom ( previousEdge );
|
|||
|
from->setHEdgeOut ( newEdge );
|
|||
|
|
|||
|
previousEdge = to->getHEdgeIn();
|
|||
|
if ( previousEdge )
|
|||
|
newEdge->setNextTo ( previousEdge );
|
|||
|
to->setHEdgeIn ( newEdge );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::createVEdge ( Vertex* from, Vertex* to, float ecp )
|
|||
|
// ************************************************************
|
|||
|
{
|
|||
|
unsigned int capacity = 0;
|
|||
|
if ( _routingGrid )
|
|||
|
capacity = _routingGrid->getVCapacity();
|
|||
|
else {
|
|||
|
vector<RoutingLayerGauge*> rtLGauges = AllianceFramework::get()->getRoutingGauge()->getLayerGauges();
|
|||
|
for ( vector<RoutingLayerGauge*>::iterator it = rtLGauges.begin() ; it != rtLGauges.end() ; it++ ) {
|
|||
|
RoutingLayerGauge* routingLayerGauge = (*it);
|
|||
|
if (routingLayerGauge->getType() != Constant::Default)
|
|||
|
continue;
|
|||
|
|
|||
|
if (routingLayerGauge->getDirection() != Constant::Vertical)
|
|||
|
continue;
|
|||
|
|
|||
|
capacity += routingLayerGauge->getTrackNumber ( from->getXMin(), from->getXMax() ) - 1;
|
|||
|
}
|
|||
|
//cerr << "createVEdge capacity:" << capacity << " ecp:" << ecp << endl;
|
|||
|
}
|
|||
|
Edge* newEdge = VEdge::create ( from, to, (unsigned)((float)(capacity)*ecp) );
|
|||
|
|
|||
|
_all_edges.push_back ( newEdge );
|
|||
|
|
|||
|
newEdge->setCost(1);
|
|||
|
|
|||
|
Edge* previousEdge = from->getVEdgeOut();
|
|||
|
if ( previousEdge )
|
|||
|
newEdge->setNextFrom ( previousEdge );
|
|||
|
from->setVEdgeOut ( newEdge );
|
|||
|
|
|||
|
previousEdge = to->getVEdgeIn();
|
|||
|
if ( previousEdge )
|
|||
|
newEdge->setNextTo ( previousEdge );
|
|||
|
to->setVEdgeIn ( newEdge );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::initConnexComp ( Vertex* vertex, int newConnexID )
|
|||
|
// ***********************************************************
|
|||
|
{
|
|||
|
initConnexComp ( vertex, NULL, newConnexID );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::initConnexComp ( Vertex* vertex, Edge* arrivalEdge, int newConnexID )
|
|||
|
// ******************************************************************************
|
|||
|
{
|
|||
|
// This recursive function initializes all vertexes of same connexID and connected through edges of same connexID,
|
|||
|
// which means that the vertex's distance is set to 0 and the vertex is inserted in the VTuplePriorityQueue
|
|||
|
// If newConnexID is different from -1, then the connexID is set to newConnexID
|
|||
|
int vertexConnex = vertex->getConnexID();
|
|||
|
assert ( vertexConnex != -1 );
|
|||
|
for_each_edge ( edge, vertex->getAdjacentEdges() ) {
|
|||
|
if ( edge == arrivalEdge ) {
|
|||
|
continue;
|
|||
|
}
|
|||
|
if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
|
|||
|
initConnexComp ( edge->getOpposite(vertex), edge, newConnexID );
|
|||
|
if ( newConnexID != -1 ) {
|
|||
|
edge->setConnexID(newConnexID);
|
|||
|
}
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
|
|||
|
vertex->setDistance(0);
|
|||
|
if ( newConnexID != -1 ) {
|
|||
|
vertex->setConnexID ( newConnexID );
|
|||
|
}
|
|||
|
if ( VTuple* vtuple = vertex->getVTuple() ) {
|
|||
|
//cerr << " Vertex " << vertex << " already has a vtuple : " << vtuple << endl;
|
|||
|
assert ( vtuple->getVertex() == vertex );
|
|||
|
increaseVTuplePriority ( vtuple, 0 );
|
|||
|
}
|
|||
|
else {
|
|||
|
VTuple* vtuple = VTuple::create ( vertex, 0 );
|
|||
|
//cerr << " Vertex " << vertex << " has now a new vtuple : " << vtuple << endl;
|
|||
|
addVTupleToPriorityQueue ( vtuple );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::UpdateConnexComp ( VertexList reachedVertexes, Vertex* firstVertex )
|
|||
|
// *****************************************************************************
|
|||
|
{
|
|||
|
// XXX PLUTOT QUE DE PASSER UNE LISTE DE VERTEX EN ARG, ON DEVRAIT PASSER SEULEMENT UN VERTEX XXX
|
|||
|
// XXX proviens du fait qu'au depart on voulait reellement passer une liste mais du fait de la possiblité de chemins paralleles on evite XXX
|
|||
|
int firstConnexID = firstVertex->getConnexID();
|
|||
|
|
|||
|
VertexListIter lvit = reachedVertexes.begin();
|
|||
|
// Pour essayer d'éviter le bug des chemins parallèles si 2 vertex sont atteints avec la meme distance, on ne va updater que le premier
|
|||
|
//while ( lvit != reachedVertexes.end() ) {
|
|||
|
Vertex* currentVertex = (*lvit);
|
|||
|
int currentConnexID = currentVertex->getConnexID();
|
|||
|
|
|||
|
//cerr << "Gonna updateConnexComp : first: " << firstVertex << ", reached: " << currentVertex << endl;
|
|||
|
|
|||
|
//cerr << " vertexes_to_route :" << endl;
|
|||
|
//for ( VertexSetIter vsit = _vertexes_to_route.begin() ; vsit != _vertexes_to_route.end() ; vsit++ )
|
|||
|
// cerr << " " << (*vsit) << endl;
|
|||
|
|
|||
|
// the vertex must be removed from the _vertexes_to_route
|
|||
|
// XXX Woowoo il ne faut pas faire un erase du vertex atteint, mais rechercher le représentant de la composante connexe atteinte dans les _vertexes_to_route et faire un erase dessus !
|
|||
|
Vertex* toErase = NULL;
|
|||
|
for ( VertexSetIter vsit = _vertexes_to_route.begin() ; vsit != _vertexes_to_route.end() ; vsit++ ) {
|
|||
|
if ( (*vsit)->getConnexID() == currentConnexID )
|
|||
|
toErase = (*vsit);
|
|||
|
}
|
|||
|
|
|||
|
//cerr << " gonna erase : " << toErase << endl;
|
|||
|
// on veut updater toute la composante connexe représenter par le currentVertex
|
|||
|
unsigned deleteVertex = _vertexes_to_route.erase ( toErase );
|
|||
|
assert ( deleteVertex == 1 );
|
|||
|
// the connexe component corresponding to the vertex must be initialize with the firstConnexID
|
|||
|
initConnexComp ( currentVertex, firstConnexID );
|
|||
|
|
|||
|
// create the new connex component and initializes it :
|
|||
|
while ( Edge* predecessor = currentVertex->getPredecessor() ) {
|
|||
|
currentVertex->setPredecessor ( NULL );
|
|||
|
predecessor->setConnexID ( firstConnexID );
|
|||
|
currentVertex = predecessor->getOpposite ( currentVertex );
|
|||
|
|
|||
|
// si jamais on réatteint un vertex dejà mis à jour.
|
|||
|
if ( currentVertex->getConnexID() == firstConnexID )
|
|||
|
break;
|
|||
|
|
|||
|
currentVertex->setDistance(0);
|
|||
|
currentVertex->setConnexID(firstConnexID);
|
|||
|
|
|||
|
if ( VTuple* vtuple = currentVertex->getVTuple() ) {
|
|||
|
increaseVTuplePriority ( vtuple, 0);
|
|||
|
}
|
|||
|
else {
|
|||
|
VTuple* vtuple = VTuple::create ( currentVertex, 0 );
|
|||
|
addVTupleToPriorityQueue ( vtuple );
|
|||
|
}
|
|||
|
}
|
|||
|
//}
|
|||
|
}
|
|||
|
|
|||
|
// VTuplePriorityQueue Utility Methods
|
|||
|
// ***********************************
|
|||
|
Vertex* Graph::extractMinFromPriorityQueue()
|
|||
|
// *****************************************
|
|||
|
{
|
|||
|
if ( _vtuplePriorityQueue.begin() == _vtuplePriorityQueue.end() )
|
|||
|
return NULL;
|
|||
|
|
|||
|
VTuple* vtuple = *(_vtuplePriorityQueue.begin());
|
|||
|
Vertex* vertex = vtuple->getVertex();
|
|||
|
|
|||
|
_vtuplePriorityQueue.erase ( _vtuplePriorityQueue.begin() );
|
|||
|
vtuple->destroy();
|
|||
|
vertex->setVTuple ( NULL );
|
|||
|
|
|||
|
return vertex;
|
|||
|
}
|
|||
|
|
|||
|
Vertex* Graph::getMinFromPriorityQueue()
|
|||
|
// *************************************
|
|||
|
{
|
|||
|
if ( _vtuplePriorityQueue.begin() == _vtuplePriorityQueue.end() )
|
|||
|
return NULL;
|
|||
|
|
|||
|
VTuple* vtuple = *(_vtuplePriorityQueue.begin());
|
|||
|
Vertex* vertex = vtuple->getVertex();
|
|||
|
|
|||
|
return vertex;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::PopMinFromPriorityQueue()
|
|||
|
// **********************************
|
|||
|
{
|
|||
|
if ( _vtuplePriorityQueue.begin() != _vtuplePriorityQueue.end() ) {
|
|||
|
VTuple* vtuple = *(_vtuplePriorityQueue.begin());
|
|||
|
Vertex* vertex = vtuple->getVertex();
|
|||
|
|
|||
|
_vtuplePriorityQueue.erase ( _vtuplePriorityQueue.begin() );
|
|||
|
vtuple->destroy();
|
|||
|
vertex->setVTuple ( NULL );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::addVTupleToPriorityQueue ( VTuple* vtuple )
|
|||
|
// *************************************************
|
|||
|
{
|
|||
|
assert ( vtuple );
|
|||
|
assert ( vtuple->getVertex()->getVTuple() == vtuple );
|
|||
|
assert ( _vtuplePriorityQueue.find ( vtuple ) == _vtuplePriorityQueue.end() );
|
|||
|
//if (debugging)
|
|||
|
// cerr << " ADDING vtuple to priority queue : " << vtuple->_getString() << endl;
|
|||
|
_vtuplePriorityQueue.insert ( vtuple );
|
|||
|
//pair<VTuplePQIter,bool> p = _vtuplePriorityQueue.insert ( vtuple );
|
|||
|
//assert ( p.second );
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
void Graph::increaseVTuplePriority ( VTuple* vtuple, float distance )
|
|||
|
// ***************************************************************
|
|||
|
{
|
|||
|
assert ( vtuple );
|
|||
|
//if ( debugging )
|
|||
|
// cerr << " " << vtuple->getVertex() << " : " << vtuple->getDistance() << " > " << distance << endl;
|
|||
|
assert ( vtuple->getDistance() > distance );
|
|||
|
// Copy removeVTupleFromPriorityQueue without vtuple->destroy()
|
|||
|
VTuplePQIter pqit = _vtuplePriorityQueue.find ( vtuple );
|
|||
|
if ( pqit != _vtuplePriorityQueue.end() ) {
|
|||
|
assert ( vtuple->getVertex() == (*pqit)->getVertex() );
|
|||
|
_vtuplePriorityQueue.erase ( pqit );
|
|||
|
}
|
|||
|
// end copy
|
|||
|
vtuple->setDistance ( distance );
|
|||
|
_vtuplePriorityQueue.insert ( vtuple );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::printVTuplePriorityQueue()
|
|||
|
// **********************************
|
|||
|
{
|
|||
|
cmess2 << "*** printing VTuplePriorityQueue ***" << endl;
|
|||
|
VTuplePQIter pqit = _vtuplePriorityQueue.begin();
|
|||
|
while ( pqit != _vtuplePriorityQueue.end() ) {
|
|||
|
cmess2 << (*pqit)->getVertex() << " : " << (*pqit)->getDistance() << endl;
|
|||
|
pqit++;
|
|||
|
}
|
|||
|
cmess2 << "***********************************" << endl;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::clearPriorityQueue()
|
|||
|
// *****************************
|
|||
|
{
|
|||
|
for ( VTuplePQIter pqit = _vtuplePriorityQueue.begin() ; pqit != _vtuplePriorityQueue.end() ; pqit++ ) {
|
|||
|
(*pqit)->destroy();
|
|||
|
}
|
|||
|
_vtuplePriorityQueue.clear();
|
|||
|
}
|
|||
|
|
|||
|
// STuplePriorityQueue Utility Methods
|
|||
|
// ***********************************
|
|||
|
Segment* Graph::extractMaxFromSTuplePQ()
|
|||
|
// *************************************
|
|||
|
{
|
|||
|
if ( _stuplePriorityQueue.begin() == STuple::_stuplePQEnd )
|
|||
|
return NULL;
|
|||
|
|
|||
|
STuple* stuple = *(_stuplePriorityQueue.begin());
|
|||
|
Segment* segment = stuple->getSegment();
|
|||
|
|
|||
|
_stuplePriorityQueue.erase ( _stuplePriorityQueue.begin() );
|
|||
|
stuple->destroy();
|
|||
|
|
|||
|
return segment;
|
|||
|
}
|
|||
|
|
|||
|
STuple* Graph::getMaxFromSTuplePQ()
|
|||
|
// ********************************
|
|||
|
{
|
|||
|
if ( _stuplePriorityQueue.begin() == STuple::_stuplePQEnd )
|
|||
|
return NULL;
|
|||
|
|
|||
|
STuple* stuple = *(_stuplePriorityQueue.begin());
|
|||
|
|
|||
|
return stuple;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::popMaxFromSTuplePQ()
|
|||
|
// *********************************
|
|||
|
{
|
|||
|
if ( _stuplePriorityQueue.begin() != STuple::_stuplePQEnd ) {
|
|||
|
STuple* stuple = *(_stuplePriorityQueue.begin());
|
|||
|
STuple::CostProperty* costProperty = stuple->getCostProperty();
|
|||
|
assert ( costProperty );
|
|||
|
assert ( (*costProperty->getPQIter()) == stuple );
|
|||
|
stuple->destroy();
|
|||
|
_stuplePriorityQueue.erase ( _stuplePriorityQueue.begin());
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::addToSTuplePQ ( STuple* stuple )
|
|||
|
// *****************************************
|
|||
|
{
|
|||
|
assert ( stuple );
|
|||
|
STuple::CostProperty* costProperty = stuple->getCostProperty();
|
|||
|
assert ( costProperty );
|
|||
|
costProperty->setPQIter ( _stuplePriorityQueue.insert ( stuple ) );
|
|||
|
STuple::STuplePQIter pqit = costProperty->getPQIter();
|
|||
|
assert ( (*pqit) == stuple );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::updateSTupleCost ( STuple* stuple, unsigned cost )
|
|||
|
// ***********************************************************
|
|||
|
{
|
|||
|
assert ( stuple );
|
|||
|
STuple::CostProperty* costProperty = stuple->getCostProperty();
|
|||
|
assert ( costProperty );
|
|||
|
STuple::STuplePQIter pqit = costProperty->getPQIter();
|
|||
|
assert ( (*pqit) == stuple );
|
|||
|
_stuplePriorityQueue.erase ( pqit );
|
|||
|
stuple->setCost ( cost );
|
|||
|
costProperty->setPQIter ( _stuplePriorityQueue.insert ( stuple ) );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::printSTuplePQ()
|
|||
|
// ************************
|
|||
|
{
|
|||
|
cmess1 << "*** printing STuplePriorityQueue ***" << endl;
|
|||
|
STuple::STuplePQIter pqit = _stuplePriorityQueue.begin();
|
|||
|
while ( pqit != STuple::_stuplePQEnd ) {
|
|||
|
cmess1 << getString(*pqit) << endl;
|
|||
|
pqit++;
|
|||
|
}
|
|||
|
cmess1 << "***********************************" << endl;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::clearSTuplePQ()
|
|||
|
// ************************
|
|||
|
{
|
|||
|
for ( STuple::STuplePQIter pqit = _stuplePriorityQueue.begin() ; pqit != STuple::_stuplePQEnd ; pqit++ ) {
|
|||
|
(*pqit)->destroy();
|
|||
|
}
|
|||
|
_stuplePriorityQueue.clear();
|
|||
|
}
|
|||
|
|
|||
|
void Graph::testSTuplePQ()
|
|||
|
// ***********************
|
|||
|
{
|
|||
|
// unsigned count = 0;
|
|||
|
// Component* compo1 = NULL;
|
|||
|
// Component* compo2 = NULL;
|
|||
|
// for_each_component ( component, _nimbus->getCell()->getComponents() ) {
|
|||
|
// if ( dynamic_cast<Segment*>(component) ) {
|
|||
|
// STuple::CostProperty* costProperty = STuple::CostProperty::create (count );
|
|||
|
// component->put ( costProperty );
|
|||
|
// STuple* stuple = STuple::create ( costProperty );
|
|||
|
// addToSTuplePQ ( stuple );
|
|||
|
// if ( count == 4 ) compo1 = component;
|
|||
|
// if ( count == 8 ) compo2 = component;
|
|||
|
// count++;
|
|||
|
// if ( count >= 10 )
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// end_for;
|
|||
|
// }
|
|||
|
// printSTuplePQ();
|
|||
|
// STuple::CostProperty* costProperty = dynamic_cast<STuple::CostProperty*>(compo1->getProperty ( "Knik::CostProperty" ));
|
|||
|
// updateSTupleCost ( (*costProperty->getPQIter()), 18 );
|
|||
|
// cmess2 << "updateSTupleCost ( (*costProperty->getPQIter()), 18 )" << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
// costProperty = dynamic_cast<STuple::CostProperty*>(compo2->getProperty ( "Knik::CostProperty"));
|
|||
|
// updateSTupleCost ( (*costProperty->getPQIter()), 2 );
|
|||
|
// cmess2 << "updateSTupleCost ( (*costProperty->getPQIter()), 2 )" << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
// popMaxFromSTuplePQ();
|
|||
|
// cmess2 << "popMaxFromSTuplePQ()" << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
// cmess2 << "getString ( getMaxFromSTuplePQ() )" << endl;
|
|||
|
// cmess2 << getString ( getMaxFromSTuplePQ() ) << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
// cmess2 << "getString ( extractMaxFromSTuplePQ() )" << endl;
|
|||
|
// cmess2 << getString ( extractMaxFromSTuplePQ() ) << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
// clearSTuplePQ();
|
|||
|
// cmess2 << "clearSTuplePQ()" << endl;
|
|||
|
// printSTuplePQ();
|
|||
|
}
|
|||
|
|
|||
|
int Graph::countVertexes ( Net* net )
|
|||
|
// **********************************
|
|||
|
{
|
|||
|
assert ( net );
|
|||
|
|
|||
|
_working_net = net;
|
|||
|
forEach ( Component*, component, net->getComponents() ) {
|
|||
|
if ( RoutingPad* routingPad = dynamic_cast<RoutingPad*>(*component) ) {
|
|||
|
//cerr << routingPad << endl << routingPad->getCenter()<< endl;
|
|||
|
//if ( routingPad->getCenter().getY() < 0 ) {
|
|||
|
|
|||
|
// CEditor* editor = getCEditor ( getCell() );
|
|||
|
// editor->Select ( routingPad );
|
|||
|
// editor->Refresh();
|
|||
|
// editor->Stop ( "RoutingPad" );
|
|||
|
// editor->Unselect( routingPad );
|
|||
|
//}
|
|||
|
|
|||
|
|
|||
|
Vertex* vertex = getVertex ( routingPad->getCenter() );
|
|||
|
assert(vertex);
|
|||
|
if ( _vertexes_to_route.find ( vertex ) == _vertexes_to_route.end() ) {
|
|||
|
_vertexes_to_route.insert ( vertex );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
return _vertexes_to_route.size();
|
|||
|
}
|
|||
|
|
|||
|
int Graph::initRouting ( Net* net )
|
|||
|
// ********************************
|
|||
|
{
|
|||
|
assert ( net );
|
|||
|
_working_net = net;
|
|||
|
|
|||
|
//cerr << "[DEBUG]: Net: " << _working_net << endl;
|
|||
|
//cerr << "[DEBUG]: vertexes_to_route size: " << _vertexes_to_route.size() << endl;
|
|||
|
|
|||
|
//CEditor* editor = getCEditor( _nimbus->getCell() );
|
|||
|
//editor->Refresh();
|
|||
|
//editor->Stop ("Going to init");
|
|||
|
|
|||
|
int currentConnexID = 0;
|
|||
|
vector<Contact*> vContacts;
|
|||
|
vector<RoutingPad*> vRoutingPads;
|
|||
|
unsigned compoSize = net->getComponents().getSize();
|
|||
|
vContacts.reserve ( compoSize );
|
|||
|
vRoutingPads.reserve ( compoSize );
|
|||
|
for_each_component ( component, net->getComponents() ) {
|
|||
|
if ( dynamic_cast<RoutingPad*>(component) )
|
|||
|
vRoutingPads.push_back ( static_cast<RoutingPad*>(component) );
|
|||
|
if ( dynamic_cast<Contact*>(component) ) {
|
|||
|
Contact* contact = static_cast<Contact*>(component);
|
|||
|
if ( isAGlobalRoutingContact ( contact ) )
|
|||
|
vContacts.push_back ( contact );
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
//cerr << " vContacts size : " << vContacts.size() << endl;
|
|||
|
//cerr << " vRoutingPads size : " << vRoutingPads.size() << endl;
|
|||
|
UpdateSession::open();
|
|||
|
for ( unsigned index = 0; index < vContacts.size() ; index++ ) {
|
|||
|
Contact* contact = vContacts[index];
|
|||
|
//cerr << " [0;32mcontact : " << contact << "[0m" << endl;
|
|||
|
Vertex* contactVertex = getVertex ( contact->getCenter() );
|
|||
|
Contact* vContact = contactVertex->getContact();
|
|||
|
if ( (vContact == contact) && (contactVertex->getNetStamp() == _netStamp) ) {
|
|||
|
//cerr << " [0;32mon a deja un contact associe avec le meme netStamp ![0m" << endl;
|
|||
|
continue; // on la déjà traité à travers le parcourt de composante connexe
|
|||
|
}
|
|||
|
else {
|
|||
|
//cerr << " [0;32mrebuild connexe component " << contact << "[0m" << endl;
|
|||
|
rebuildConnexComponent ( contact, currentConnexID, NULL );
|
|||
|
//cerr << " [0;32mdone[0m" << endl;
|
|||
|
if ( _vertexes_to_route.find ( contactVertex ) == _vertexes_to_route.end() ) {
|
|||
|
//cerr << " [0;32mAdding vertex to _vertexes_to_route: continue[0m" << endl;
|
|||
|
_vertexes_to_route.insert ( contactVertex );
|
|||
|
_searchingArea.merge ( contactVertex->getBox() );
|
|||
|
contactVertex->setDistance((float)(HUGE));
|
|||
|
contactVertex->setPredecessor(NULL);
|
|||
|
currentConnexID++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
//cerr << " traitement pour les contacts : OK" << endl;
|
|||
|
//OoOoooOoooOoO A QUOI SERT CE BOOLEEN OoOoooOoooOoO ==>> pour le //5 le connexID ne doit pas avoir été augmenté ! ou alors connexID-1 !!
|
|||
|
//bool useConnexID = false;
|
|||
|
for ( unsigned index = 0 ; index < vRoutingPads.size() ; index ++ ) {
|
|||
|
RoutingPad* routingPad = vRoutingPads[index];
|
|||
|
//cerr << " [0;34mRoutingPad :[0m" << routingPad << endl;
|
|||
|
Vertex* rpVertex = getVertex ( routingPad->getCenter() );
|
|||
|
//cerr << " [0;34mVertex :[0m" << rpVertex << endl;
|
|||
|
Contact* rpContact = rpVertex->getContact();
|
|||
|
if ( rpContact && (rpContact->getNet() == routingPad->getNet()) ) {
|
|||
|
// s'il existe deja un contact pour ce vertex pour ce net, on s'y attache
|
|||
|
//cerr << " [0;34mContact already exists: attaching hooks[0m" << endl;
|
|||
|
// le contact a deja ete cree, il suffit d'ajouter le routingPad à la ronde du contact.
|
|||
|
routingPad->getBodyHook()->detach();
|
|||
|
routingPad->getBodyHook()->attach ( rpVertex->getContact()->getBodyHook() );
|
|||
|
}
|
|||
|
else {
|
|||
|
// sinon on crée un contact et on s'y attache
|
|||
|
Contact* contact = Contact::create ( _working_net
|
|||
|
, DataBase::getDB()->getTechnology()->getLayer("metal2")
|
|||
|
, rpVertex->getPosition().getX()
|
|||
|
, rpVertex->getPosition().getY()
|
|||
|
, rpVertex->getHalfWidth()/5
|
|||
|
, rpVertex->getHalfHeight()/5
|
|||
|
);
|
|||
|
rpVertex->setContact ( contact );
|
|||
|
routingPad->getBodyHook()->detach();
|
|||
|
routingPad->getBodyHook()->attach ( contact->getBodyHook() );
|
|||
|
if ( _vertexes_to_route.find ( rpVertex ) == _vertexes_to_route.end() ) {
|
|||
|
//cerr << " [0;32mAdding vertex to _vertexes_to_route: continue[0m" << endl;
|
|||
|
_vertexes_to_route.insert ( rpVertex );
|
|||
|
_searchingArea.merge ( rpVertex->getBox() );
|
|||
|
rpVertex->setConnexID ( currentConnexID );
|
|||
|
rpVertex->setNetStamp ( _netStamp );
|
|||
|
rpVertex->setDistance((float)(HUGE));
|
|||
|
rpVertex->setPredecessor(NULL);
|
|||
|
currentConnexID++;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
// for ripup & reroute purpose
|
|||
|
if ( __ripupMode__ )
|
|||
|
_searchingArea = _cell->getAbutmentBox(); // recherche sur toute la surface : trop long pour gros circuits
|
|||
|
//_searchingArea.inflate((_searchingArea.getWidth()*10)/100, (_searchingArea.getHeight()*10)/100); // raté ça ne marche pas avec les nets plats
|
|||
|
|
|||
|
//cerr << " traitement pour les routingPads : OK" << endl;
|
|||
|
UpdateSession::close();
|
|||
|
//cerr << "[DEBUG]: vertexes_to_route size (after init): " << _vertexes_to_route.size() << endl;
|
|||
|
//editor->Refresh();
|
|||
|
//editor->Stop("initDone");
|
|||
|
// 8/10/2007
|
|||
|
// {
|
|||
|
// Expand seaching area
|
|||
|
//int bottomLineIdx = (int)_matrixVertex->getLineIndex ( _searchingArea.getYMin() +1 );
|
|||
|
//int topLineIdx = (int)_matrixVertex->getLineIndex ( _searchingArea.getYMax() -1 );
|
|||
|
//int leftColumnIdx = (int)_matrixVertex->getColumnIndex ( _searchingArea.getXMin() +1 );
|
|||
|
//int rightColumnIdx = (int)_matrixVertex->getColumnIndex ( _searchingArea.getXMax() -1 );
|
|||
|
//if ( _matrixVertex->isLineIndexValid ( bottomLineIdx - 2 ) )
|
|||
|
// bottomLineIdx -= 2;
|
|||
|
//else if ( _matrixVertex->isLineIndexValid ( bottomLineIdx - 1 ) )
|
|||
|
// bottomLineIdx -= 1;
|
|||
|
|
|||
|
//if ( _matrixVertex->isLineIndexValid ( topLineIdx + 2 ) )
|
|||
|
// topLineIdx += 2;
|
|||
|
//else if ( _matrixVertex->isLineIndexValid ( topLineIdx + 1 ) )
|
|||
|
// topLineIdx += 1;
|
|||
|
|
|||
|
//if ( _matrixVertex->isColumnIndexValid ( leftColumnIdx - 2 ) )
|
|||
|
// leftColumnIdx -= 2;
|
|||
|
//else if ( _matrixVertex->isColumnIndexValid ( leftColumnIdx - 1 ) )
|
|||
|
// leftColumnIdx -= 1;
|
|||
|
|
|||
|
//if ( _matrixVertex->isColumnIndexValid ( rightColumnIdx + 2 ) )
|
|||
|
// rightColumnIdx += 2;
|
|||
|
//else if ( _matrixVertex->isColumnIndexValid ( rightColumnIdx + 1 ) )
|
|||
|
// rightColumnIdx += 1;
|
|||
|
|
|||
|
//_searchingArea.merge ( _matrixVertex->getVertexFromIndexes(bottomLineIdx, leftColumnIdx)->getGCell()->getBox() );
|
|||
|
//_searchingArea.merge ( _matrixVertex->getVertexFromIndexes(topLineIdx, rightColumnIdx)->getGCell()->getBox() );
|
|||
|
|
|||
|
//cerr << "net " << net << " has " << _vertexes_to_route.size() << " vertexes to route." << endl;
|
|||
|
//}
|
|||
|
return _vertexes_to_route.size();
|
|||
|
}
|
|||
|
|
|||
|
void Graph::Dijkstra()
|
|||
|
// *******************
|
|||
|
{
|
|||
|
//checkEmptyPriorityQueue();
|
|||
|
|
|||
|
//CEditor* editor = getCEditor( _nimbus->getCell() );
|
|||
|
countDijkstra++;
|
|||
|
|
|||
|
// first we need to choose the closest to center vertex in _vertexes_to_route
|
|||
|
Vertex* centralVertex = getCentralVertex();
|
|||
|
//ltrace(435) << " most centered vertex is " << centralVertex << endl;
|
|||
|
// we want to prepare all vertexes of the 'composante connexe'
|
|||
|
// set the distance to 0
|
|||
|
// insert each vertex in the vtuplePriorityQueue
|
|||
|
initConnexComp ( centralVertex );
|
|||
|
|
|||
|
// create a copy of _vertexes_to_route vector fo method UpdateEstimateCongestion
|
|||
|
//set<Vertex*,VertexPositionComp> copy_vertex = _vertexes_to_route; // This is no more useful
|
|||
|
|
|||
|
//#if defined ( __USE_DYNAMIC_PRECONGESTION__ )
|
|||
|
if ( !__ripupMode__ && (__precongestion__ == 2) )
|
|||
|
UpdateEstimateCongestion();
|
|||
|
//#endif
|
|||
|
|
|||
|
debugging = (_working_net->getName() == debugName );
|
|||
|
//bool debugging = false;
|
|||
|
|
|||
|
if (debugging) {
|
|||
|
cerr << "Dijkstra for net " << _working_net << " : " << _netStamp << endl;
|
|||
|
cerr << " central vertex : " << centralVertex << endl;
|
|||
|
cerr << " _vertexes_to_route.size : " << _vertexes_to_route.size() << endl;
|
|||
|
Breakpoint::stop(1, "<center><b>Dijkstra</b><br>initialized</center>");
|
|||
|
}
|
|||
|
|
|||
|
while ( _vertexes_to_route.size() > 1 ) {
|
|||
|
// Now, let's expanse the top of the queue
|
|||
|
VertexList reachedVertexes;
|
|||
|
float reachedDistance = (float)(HUGE);
|
|||
|
|
|||
|
//checkGraphConsistency();
|
|||
|
|
|||
|
// DEBUG //
|
|||
|
if ( debugging ) {
|
|||
|
cerr << " _vertexes_to_route :" << endl;
|
|||
|
VertexSetIter vsit = _vertexes_to_route.begin();
|
|||
|
while ( vsit != _vertexes_to_route.end() ) {
|
|||
|
cerr << " " << (*vsit) << endl;
|
|||
|
vsit++;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
if ( debugging ) {
|
|||
|
cerr << " source component" << endl;
|
|||
|
printVTuplePriorityQueue();
|
|||
|
cerr.flush();
|
|||
|
Breakpoint::stop(1, "<center><b>Dijkstra</b><br>source connexe component</center>");
|
|||
|
}
|
|||
|
//if ( debugging && (editor->getStopLevel() >= 1) ) {
|
|||
|
// editor->Refresh();
|
|||
|
// string stopMessage = "Source connexe component.";
|
|||
|
// editor->Stop(stopMessage);
|
|||
|
//}
|
|||
|
|
|||
|
Vertex* firstVertex = getMinFromPriorityQueue();
|
|||
|
assert ( firstVertex );
|
|||
|
Vertex* currentVertex = firstVertex;
|
|||
|
int firstVertexConnex = firstVertex->getConnexID();
|
|||
|
|
|||
|
while ( currentVertex && (currentVertex->getDistance() < reachedDistance) ) {
|
|||
|
PopMinFromPriorityQueue();
|
|||
|
assert ( !currentVertex->getVTuple() );
|
|||
|
|
|||
|
// IMPORTANT : each currentVertex considered here has been getFromPriorityQueue()
|
|||
|
// which means its NetStamp and ConnexID are set for the current _working_net : no need to check netStamp
|
|||
|
int currentVertexConnex = currentVertex->getConnexID() ;
|
|||
|
if ( (currentVertexConnex != -1) && (currentVertexConnex != firstVertexConnex) ) {
|
|||
|
reachedDistance = currentVertex->getDistance();
|
|||
|
reachedVertexes.clear();
|
|||
|
if (debugging ) {
|
|||
|
cerr << " reachedVertexes : clear + push_back vertex found in priorityQueue: " << currentVertex << endl;
|
|||
|
}
|
|||
|
reachedVertexes.push_back ( currentVertex );
|
|||
|
break;
|
|||
|
}
|
|||
|
Edge* arrivalEdgeCurrentVertex = currentVertex->getPredecessor();
|
|||
|
for_each_edge ( edge, currentVertex->getAdjacentEdges() ) {
|
|||
|
if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == firstVertexConnex) ) {
|
|||
|
// already visited edge
|
|||
|
// ok because to reach a connex component the algorithm first reach a vertex !!
|
|||
|
continue;
|
|||
|
}
|
|||
|
edge->setConnexID(-1); // reinitialize connexID for edge (was done by CleanRoutingState)
|
|||
|
//edge->setSplitter(NULL);
|
|||
|
edge->setNetStamp(_netStamp);
|
|||
|
|
|||
|
Vertex* oppositeVertex = edge->getOpposite ( currentVertex );
|
|||
|
assert ( oppositeVertex );
|
|||
|
if ( !_searchingArea.contains ( oppositeVertex->getPosition() ) )
|
|||
|
continue;
|
|||
|
float newDistance = currentVertex->getDistance() + edge->getCost ( arrivalEdgeCurrentVertex );
|
|||
|
bool updateOppositeVertex = false;
|
|||
|
// reinitialize the oppositeVertex if its netStamp is < _netStamp
|
|||
|
if ( oppositeVertex->getNetStamp() < _netStamp ) {
|
|||
|
//oppositeVertex->setLocalRingHook(NULL);
|
|||
|
oppositeVertex->setContact(NULL);
|
|||
|
oppositeVertex->setConnexID(-1);
|
|||
|
updateOppositeVertex = true;
|
|||
|
}
|
|||
|
int oppositeConnex = oppositeVertex->getConnexID();
|
|||
|
float oppositeDistance = oppositeVertex->getDistance();
|
|||
|
if ( updateOppositeVertex || (newDistance + EPSILON < oppositeDistance) ) {
|
|||
|
assert ( oppositeConnex != firstVertexConnex );
|
|||
|
oppositeVertex->setPredecessor ( edge );
|
|||
|
oppositeVertex->setDistance ( newDistance );
|
|||
|
oppositeVertex->setNetStamp ( _netStamp );
|
|||
|
if ( VTuple* oppositeVTuple = oppositeVertex->getVTuple() ) {
|
|||
|
//if (debugging) {
|
|||
|
// cerr << " increasing Priority for vertex : " << oppositeVertex
|
|||
|
// << " and corresponding vtuple : " << oppositeVTuple->_getString() << endl;
|
|||
|
//}
|
|||
|
increaseVTuplePriority ( oppositeVTuple, newDistance ); // XXX du fait de la reinit ce n'est plus seulement un increase !
|
|||
|
// Non c'est bon si on garde le CleanRoutingState (avec clearPriorityQueue)
|
|||
|
}
|
|||
|
else {
|
|||
|
VTuple* newOppositeVTuple = VTuple::create ( oppositeVertex, newDistance );
|
|||
|
//if (debugging)
|
|||
|
// cerr << " Creating new vtuple for vertex: " << oppositeVertex << "," << newDistance
|
|||
|
// << " --> " << newOppositeVTuple->_getString() << endl;
|
|||
|
addVTupleToPriorityQueue ( newOppositeVTuple );
|
|||
|
}
|
|||
|
//if ( debugging ) {
|
|||
|
// cerr << " distance has been updated : " << edge << endl;
|
|||
|
// //cerr << " current reachedDistance: " << reachedDistance << " for: " << (*(reachedVertexes.begin())) << endl;
|
|||
|
// cerr << " current reachedDistance: " << reachedDistance << endl;
|
|||
|
// printVTuplePriorityQueue();
|
|||
|
// Breakpoint::stop(1, "<center><b>Dijkstra</b><br>distance has been updated</center>");
|
|||
|
//}
|
|||
|
//if ( debugging && (editor->getStopLevel() >= 2) ) {
|
|||
|
// editor->Refresh();
|
|||
|
// string stopMessage = "distance has been updated: ";
|
|||
|
// stopMessage += getString ( edge );
|
|||
|
// editor->Stop(stopMessage);
|
|||
|
//}
|
|||
|
}
|
|||
|
if ( (oppositeConnex != -1) && (oppositeConnex != firstVertexConnex) ) {
|
|||
|
// verifier si la newDistance est inférieure a la reachedDistance,
|
|||
|
// si oui vider la liste des reachedVertex et ajouter l'oppositeVertex
|
|||
|
// si == ajouter l'oppositeVertex a la liste (a condition qu'il n'y soit pas déjà)
|
|||
|
// si > rien a faire (a verifier que la pile de priorité se comporte bien)
|
|||
|
if ( newDistance < reachedDistance ) {
|
|||
|
reachedDistance = newDistance;
|
|||
|
reachedVertexes.clear();
|
|||
|
//if (debugging ) {
|
|||
|
// cerr << " second, push_back : " << oppositeVertex << endl;
|
|||
|
// cerr << " reachedVertexes : clear + push_back reached vertex with < distance " << oppositeVertex << endl;
|
|||
|
//}
|
|||
|
reachedVertexes.push_back ( oppositeVertex );
|
|||
|
}
|
|||
|
else if ( newDistance == reachedDistance ) {
|
|||
|
VertexListIter lvit = reachedVertexes.begin();
|
|||
|
bool foundVertex = false;
|
|||
|
// on pourrait simplifier grandement tout ca : 1 seul vertex atteint sauvergardé ! conclusion qu'il ait le meme connexID ou pas
|
|||
|
// on ne fait rien, on en a deja atteint un avec la meme distance ...
|
|||
|
while ( lvit != reachedVertexes.end() ) {
|
|||
|
// the following test depends on the fact we authorize multiple representant (vertex)
|
|||
|
// of the same connexe component in reachedVertexes list
|
|||
|
//if ( (*lvit)->getConnexID() == oppositeConnex )
|
|||
|
if ( (*lvit) == oppositeVertex ) {
|
|||
|
foundVertex = true;
|
|||
|
break;
|
|||
|
}
|
|||
|
lvit++;
|
|||
|
}
|
|||
|
if ( !foundVertex ) {
|
|||
|
//if (debugging ) {
|
|||
|
// cerr << " reachedVertexes : clear + push_back reached vertex with == distance " << oppositeVertex << endl;
|
|||
|
//}
|
|||
|
reachedVertexes.push_back ( oppositeVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
// Nothing to do ?
|
|||
|
}
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
currentVertex = getMinFromPriorityQueue();
|
|||
|
}
|
|||
|
assert ( !reachedVertexes.empty() );
|
|||
|
assert ( reachedDistance < (float)(HUGE) );
|
|||
|
|
|||
|
//if(debugging) {
|
|||
|
// cerr << " updating 2 connex components : " << (*(reachedVertexes.begin())) << " & " << firstVertex << endl;
|
|||
|
// cerr.flush();
|
|||
|
// editor->Refresh();
|
|||
|
// editor->Stop("Dijkstra on 2 connex comopnents, gonna Update");
|
|||
|
//}
|
|||
|
UpdateConnexComp ( reachedVertexes, firstVertex );
|
|||
|
//if(debugging) {
|
|||
|
// editor->Refresh();
|
|||
|
// editor->Stop("Update done");
|
|||
|
//}
|
|||
|
}
|
|||
|
//cerr << "check before materialize _vertexes_to_route.size = " << _vertexes_to_route.size() << endl;
|
|||
|
//checkGraphConsistency();
|
|||
|
MaterializeRouting ( *(_vertexes_to_route.begin()) );
|
|||
|
|
|||
|
//_vertexes_to_route.clear(); // no more useful
|
|||
|
//_vertexes_to_route = copy_vertex ;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::Monotonic()
|
|||
|
// ********************
|
|||
|
{
|
|||
|
// This function execute an algorithm of monotonic routing
|
|||
|
// it assumes that _vertexes_to_route.sze is 2 (only 2 pin nets can be route with monotonic routing)
|
|||
|
assert ( _vertexes_to_route.size() == 2 );
|
|||
|
|
|||
|
countMonotonic++;
|
|||
|
|
|||
|
//cerr << "Monotonic for net " << _working_net << " : " << _netStamp << endl;
|
|||
|
//cerr << " check start monotonic" << endl;
|
|||
|
//checkGraphConsistency();
|
|||
|
|
|||
|
Vertex* source = (*_vertexes_to_route.begin());
|
|||
|
Vertex* target = (*_vertexes_to_route.rbegin());
|
|||
|
assert ( source != target );
|
|||
|
DbU::Unit sourceX = source->getPosition().getX();
|
|||
|
DbU::Unit targetX = target->getPosition().getX();
|
|||
|
|
|||
|
if ( sourceX > targetX ) {
|
|||
|
Vertex* temp = source;
|
|||
|
source = target;
|
|||
|
target = temp;
|
|||
|
}
|
|||
|
else if ( sourceX == targetX ) {
|
|||
|
if ( source->getPosition().getY() > target->getPosition().getY() ) {
|
|||
|
Vertex* temp = source;
|
|||
|
source = target;
|
|||
|
target = temp;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// POUR SIMPLIFIER : PAS DE TRAITEMENT D'UN GRAPHE DE ROUTAGE IRREGULIER POUR L'INSTANT
|
|||
|
sourceX = source->getPosition().getX();
|
|||
|
targetX = target->getPosition().getX();
|
|||
|
DbU::Unit sourceY = source->getPosition().getY();
|
|||
|
DbU::Unit targetY = target->getPosition().getY();
|
|||
|
source->setDistance ( 0 );
|
|||
|
if ( sourceY <= targetY ) {
|
|||
|
// 1st case : monotonic directions : top and right
|
|||
|
// marquing all vertexes which y-coordinates are equal to sourceY
|
|||
|
Vertex* predecessor = source;
|
|||
|
Edge* rightEdge = predecessor->getHEdgeOut();
|
|||
|
while ( rightEdge ) {
|
|||
|
Vertex* currentVertex = rightEdge->getOpposite ( predecessor );
|
|||
|
if ( currentVertex->getPosition().getX() <= targetX ) {
|
|||
|
currentVertex->setDistance ( predecessor->getDistance() + rightEdge->getCost( predecessor->getPredecessor() ) );
|
|||
|
currentVertex->setPredecessor ( rightEdge );
|
|||
|
predecessor = currentVertex;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
// marquing all vertexes which x-coordinates are equal to sourceX
|
|||
|
predecessor = source;
|
|||
|
Edge* topEdge = predecessor->getVEdgeOut();
|
|||
|
while ( topEdge ) {
|
|||
|
//while ( topEdge->getNextFrom() != NULL )
|
|||
|
// topEdge = topEdge->getNextFrom();
|
|||
|
Vertex* currentVertex = topEdge->getOpposite ( predecessor );
|
|||
|
if ( currentVertex->getPosition().getY() <= targetY ) {
|
|||
|
currentVertex->setDistance ( predecessor->getDistance() + topEdge->getCost( predecessor->getPredecessor() ) );
|
|||
|
currentVertex->setPredecessor ( topEdge );
|
|||
|
predecessor = currentVertex;
|
|||
|
topEdge = predecessor->getVEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
// marquing all others vertexes by column
|
|||
|
predecessor = source;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
while ( rightEdge ) {
|
|||
|
Vertex* baseColumn = rightEdge->getOpposite ( predecessor );
|
|||
|
if ( baseColumn->getPosition().getX() <= targetX ) {
|
|||
|
Vertex* vertPred = baseColumn;
|
|||
|
Edge* topEdge = vertPred->getVEdgeOut();
|
|||
|
while ( topEdge ) {
|
|||
|
Vertex* currentVertex = topEdge->getOpposite ( vertPred );
|
|||
|
if ( currentVertex->getPosition().getY() <= targetY ) {
|
|||
|
float vertDistance = (float)(HUGE);
|
|||
|
float horzDistance = (float)(HUGE);
|
|||
|
|
|||
|
vertDistance = vertPred->getDistance() + topEdge->getCost ( vertPred->getPredecessor() );
|
|||
|
Edge* leftEdge = currentVertex->getHEdgeIn();
|
|||
|
if ( leftEdge ) {
|
|||
|
Vertex* horzPred = leftEdge->getOpposite ( currentVertex );
|
|||
|
horzDistance = horzPred->getDistance() + leftEdge->getCost ( horzPred->getPredecessor() );
|
|||
|
}
|
|||
|
|
|||
|
if ( vertDistance < horzDistance ) {
|
|||
|
currentVertex->setDistance ( vertDistance );
|
|||
|
currentVertex->setPredecessor ( topEdge );
|
|||
|
}
|
|||
|
else {
|
|||
|
currentVertex->setDistance ( horzDistance );
|
|||
|
currentVertex->setPredecessor ( leftEdge );
|
|||
|
}
|
|||
|
|
|||
|
vertPred = currentVertex;
|
|||
|
topEdge = vertPred->getVEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
predecessor = baseColumn;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
// 2nd case : monotonic directions : down and right
|
|||
|
// marquing all vertexes which y-coordinates are equal to sourceY
|
|||
|
Vertex* predecessor = source;
|
|||
|
Edge* rightEdge = predecessor->getHEdgeOut();
|
|||
|
while ( rightEdge ) {
|
|||
|
Vertex* currentVertex = rightEdge->getOpposite ( predecessor );
|
|||
|
if ( currentVertex->getPosition().getX() <= targetX ) {
|
|||
|
currentVertex->setDistance ( predecessor->getDistance() + rightEdge->getCost ( predecessor->getPredecessor() ) );
|
|||
|
currentVertex->setPredecessor ( rightEdge );
|
|||
|
predecessor = currentVertex;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
// marquing all vertexes which x-coordinates are equal to sourceX
|
|||
|
predecessor = source;
|
|||
|
Edge* bottomEdge = predecessor->getVEdgeIn();
|
|||
|
while ( bottomEdge ) {
|
|||
|
//while ( topEdge->getNextFrom() != NULL )
|
|||
|
// topEdge = topEdge->getNextFrom();
|
|||
|
Vertex* currentVertex = bottomEdge->getOpposite ( predecessor );
|
|||
|
if ( currentVertex->getPosition().getY() >= targetY ) {
|
|||
|
currentVertex->setDistance ( predecessor->getDistance() + bottomEdge->getCost ( predecessor->getPredecessor() ) );
|
|||
|
currentVertex->setPredecessor ( bottomEdge );
|
|||
|
predecessor = currentVertex;
|
|||
|
bottomEdge = predecessor->getVEdgeIn();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
// marquing all others vertexes by column
|
|||
|
predecessor = source;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
while ( rightEdge ) {
|
|||
|
Vertex* baseColumn = rightEdge->getOpposite ( predecessor );
|
|||
|
if ( baseColumn->getPosition().getX() <= targetX ) {
|
|||
|
Vertex* vertPred = baseColumn;
|
|||
|
Edge* bottomEdge = vertPred->getVEdgeIn();
|
|||
|
while ( bottomEdge ) {
|
|||
|
Vertex* currentVertex = bottomEdge->getOpposite ( vertPred );
|
|||
|
if ( currentVertex->getPosition().getY() >= targetY ) {
|
|||
|
float vertDistance = (float)(HUGE);
|
|||
|
float horzDistance = (float)(HUGE);
|
|||
|
|
|||
|
vertDistance = vertPred->getDistance() + bottomEdge->getCost ( vertPred->getPredecessor() );
|
|||
|
Edge* leftEdge = currentVertex->getHEdgeIn();
|
|||
|
if ( leftEdge ) {
|
|||
|
Vertex* horzPred = leftEdge->getOpposite ( currentVertex );
|
|||
|
horzDistance = horzPred->getDistance() + leftEdge->getCost (horzPred->getPredecessor() );
|
|||
|
}
|
|||
|
|
|||
|
if ( vertDistance < horzDistance ) {
|
|||
|
currentVertex->setDistance ( vertDistance );
|
|||
|
currentVertex->setPredecessor ( bottomEdge );
|
|||
|
}
|
|||
|
else {
|
|||
|
currentVertex->setDistance ( horzDistance );
|
|||
|
currentVertex->setPredecessor ( leftEdge );
|
|||
|
}
|
|||
|
|
|||
|
vertPred = currentVertex;
|
|||
|
bottomEdge = vertPred->getVEdgeIn();
|
|||
|
if (!bottomEdge)
|
|||
|
break;
|
|||
|
currentVertex = bottomEdge->getOpposite ( vertPred );
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
predecessor = baseColumn;
|
|||
|
rightEdge = predecessor->getHEdgeOut();
|
|||
|
}
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
// On crée la nouvelle composante connexe à partir du chemin monotone trouvé :
|
|||
|
int sourceID = source->getConnexID();
|
|||
|
Vertex* currentVertex = target;
|
|||
|
|
|||
|
while ( Edge* predecessor = currentVertex->getPredecessor() ) {
|
|||
|
currentVertex->setConnexID ( sourceID );
|
|||
|
currentVertex->setNetStamp ( _netStamp );
|
|||
|
predecessor->setConnexID ( sourceID );
|
|||
|
predecessor->setNetStamp ( _netStamp );
|
|||
|
currentVertex = predecessor->getOpposite ( currentVertex );
|
|||
|
}
|
|||
|
source->setNetStamp ( _netStamp );
|
|||
|
|
|||
|
assert ( currentVertex == source );
|
|||
|
|
|||
|
MaterializeRouting ( source );
|
|||
|
//#if defined ( __USE_DYNAMIC_PRECONGESTION__ )
|
|||
|
if ( __precongestion__ == 2 )
|
|||
|
UpdateEstimateCongestion();
|
|||
|
//#endif
|
|||
|
}
|
|||
|
|
|||
|
FTree Graph::createFluteTree()
|
|||
|
// ***************************
|
|||
|
{
|
|||
|
int accuracy = 3; // accuracy for flute (by default 3)
|
|||
|
int d = _vertexes_to_route.size(); // degre du net, ie nombre de routingPads
|
|||
|
int *x = new int [d]; // x coordinates of the vertexes
|
|||
|
int *y = new int [d]; // y coordinates of the vertexes
|
|||
|
FTree flutetree; // the flute Steiner Tree
|
|||
|
|
|||
|
//cout << "Net : " << _working_net << endl;
|
|||
|
// scans _working_net to find x,y coordinates and fill x, y and d
|
|||
|
// parcours des _vertexes_to_route
|
|||
|
VertexSetIter vsit = _vertexes_to_route.begin();
|
|||
|
int cpt = 0;
|
|||
|
while ( vsit != _vertexes_to_route.end() ) {
|
|||
|
Point position = (*vsit)->getPosition();
|
|||
|
x[cpt] = position.getX();
|
|||
|
y[cpt] = position.getY();
|
|||
|
vsit++;
|
|||
|
cpt++;
|
|||
|
}
|
|||
|
|
|||
|
assert ( d == cpt );
|
|||
|
|
|||
|
flutetree = flute ( d, x, y, accuracy );
|
|||
|
//printtree ( flutetree );
|
|||
|
//plottree ( flutetree );
|
|||
|
//cout << endl;
|
|||
|
return flutetree;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::UpdateEstimateCongestion ( bool create )
|
|||
|
// *************************************************
|
|||
|
{
|
|||
|
if ( _vertexes_to_route.size() < 2 )
|
|||
|
return;
|
|||
|
if ( _vertexes_to_route.size() >= FLUTE_LIMIT ) {
|
|||
|
if ( create )
|
|||
|
cerr << "[INFO] Graph::UpdateEstiateGongestion(): Net " << _working_net << " has more than " << getString(FLUTE_LIMIT)
|
|||
|
<< " vertexes and can not be handled by FLUTE." << endl;
|
|||
|
return;
|
|||
|
}
|
|||
|
//cerr << "Running FLUTE for net : " << _working_net << endl;
|
|||
|
FTree flutetree = createFluteTree();
|
|||
|
|
|||
|
//parcours des branches du FTree pour créer la congestion estimée
|
|||
|
for ( int i = 0 ; i < 2*flutetree.deg-2 ; i++ ) {
|
|||
|
// int sourceX = flutetree.branch[i].x;
|
|||
|
// int sourceY = flutetree.branch[i].y;
|
|||
|
// int targetX = flutetree.branch[flutetree.branch[i].n].x;
|
|||
|
// int targetY = flutetree.branch[flutetree.branch[i].n].y;
|
|||
|
Vertex* source = getVertex ( flutetree.branch[i].x , flutetree.branch[i].y );
|
|||
|
Vertex* target = getVertex ( flutetree.branch[flutetree.branch[i].n].x, flutetree.branch[flutetree.branch[i].n].y );
|
|||
|
assert ( source );
|
|||
|
assert ( target );
|
|||
|
//Si source et target alignée -> ajoute 1 a toutes les edges sur le chemin
|
|||
|
if ( source->isVerticallyAligned ( target ) ) {
|
|||
|
sortVVertexes ( source, target );
|
|||
|
Vertex* currentVertex = source;
|
|||
|
while ( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 1.0, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
assert ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( source->isHorizontallyAligned ( target ) ) {
|
|||
|
sortHVertexes ( source, target );
|
|||
|
Vertex* currentVertex = source;
|
|||
|
while( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 1.0, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
assert ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
sortHVertexes ( source, target );
|
|||
|
if ( source->getY() < target->getY() ) {
|
|||
|
// 1st case :
|
|||
|
// +-------T +-------T T
|
|||
|
// | | | |
|
|||
|
// | | = | 0.5 + 0.5 |
|
|||
|
// | | | |
|
|||
|
// S-------+ S S-------+
|
|||
|
Vertex* currentVertex = source;
|
|||
|
while ( currentVertex->getY() < target->getY() ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
while ( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
currentVertex = source;
|
|||
|
while ( currentVertex->getX() < target->getX() ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
while ( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( edge );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
// 2nd case :
|
|||
|
// S-------+ S S-------+
|
|||
|
// | | | |
|
|||
|
// | | = | 0.5 + 0.5 |
|
|||
|
// | | | |
|
|||
|
// +-------T +-------T T
|
|||
|
Vertex* currentVertex = source;
|
|||
|
while ( currentVertex->getY() > target->getY() ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeIn();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
while ( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
currentVertex = source;
|
|||
|
while ( currentVertex->getX() < target->getX() ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( currentVertex );
|
|||
|
}
|
|||
|
while ( currentVertex != target ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeIn();
|
|||
|
// assert ( edge );
|
|||
|
edge->addSubEstimateOccupancy ( 0.5, create );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
// assert ( edge );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::UpdateMaxEstimateCongestion()
|
|||
|
// **************************************
|
|||
|
{
|
|||
|
Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
while ( currentVertex ) {
|
|||
|
Vertex* firstLineVertex = currentVertex;
|
|||
|
while ( currentVertex ) {
|
|||
|
Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
|||
|
unsigned max = 0;
|
|||
|
float maxEsti = 0.0;
|
|||
|
if ( hEdgeOut ) {
|
|||
|
unsigned maxX = hEdgeOut->getRealOccupancy();
|
|||
|
float maxXEsti = hEdgeOut->getEstimateOccupancy();
|
|||
|
max += maxX;
|
|||
|
maxEsti += maxXEsti;
|
|||
|
if ( maxX > _maxXOccupancy )
|
|||
|
_maxXOccupancy = maxX;
|
|||
|
if ( maxXEsti > _maxXEstimateOccupancy )
|
|||
|
_maxXEstimateOccupancy = maxXEsti;
|
|||
|
}
|
|||
|
Edge* vEdgeOut = currentVertex->getVEdgeOut();
|
|||
|
if ( vEdgeOut ) {
|
|||
|
unsigned maxY = vEdgeOut->getRealOccupancy();
|
|||
|
float maxYEsti = vEdgeOut->getEstimateOccupancy();
|
|||
|
max += maxY;
|
|||
|
maxEsti += maxYEsti;
|
|||
|
if ( maxY > _maxYOccupancy )
|
|||
|
_maxYOccupancy = maxY;
|
|||
|
if ( maxYEsti > _maxYEstimateOccupancy )
|
|||
|
_maxYEstimateOccupancy = maxYEsti;
|
|||
|
}
|
|||
|
if ( max > _maxOccupancy )
|
|||
|
_maxOccupancy = max;
|
|||
|
if ( maxEsti > _maxEstimateOccupancy )
|
|||
|
_maxEstimateOccupancy = maxEsti;
|
|||
|
|
|||
|
if ( hEdgeOut )
|
|||
|
currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
|||
|
if ( vEdgeOut )
|
|||
|
currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::UpdateEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, unsigned cap )
|
|||
|
// ********************************************************************************************************
|
|||
|
{
|
|||
|
if ( col1 == col2 ) {
|
|||
|
if ( row1 == row2 )
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be different." );
|
|||
|
|
|||
|
Vertex* bottomVertex = NULL;
|
|||
|
Vertex* topVertex = NULL;
|
|||
|
if ( ( row1 < row2 ) && ( row2 == row1 + 1 ) ) {
|
|||
|
bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
topVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
|
|||
|
}
|
|||
|
else if ( row1 == row2 + 1 ) {
|
|||
|
bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
|
|||
|
topVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );
|
|||
|
|
|||
|
Edge* edge = bottomVertex->getVEdgeOut();
|
|||
|
assert ( edge->getOpposite(bottomVertex) == topVertex );
|
|||
|
|
|||
|
edge->setCapacity ( cap );
|
|||
|
}
|
|||
|
else if ( row1 == row2 ) {
|
|||
|
Vertex* leftVertex = NULL;
|
|||
|
Vertex* rightVertex = NULL;
|
|||
|
if ( ( col1 < col2 ) && ( col2 == col1 + 1 ) ) {
|
|||
|
leftVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
|
|||
|
}
|
|||
|
else if ( col1 == col2 + 1 ) {
|
|||
|
leftVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
|
|||
|
rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );
|
|||
|
|
|||
|
Edge* edge = leftVertex->getHEdgeOut();
|
|||
|
assert ( edge->getOpposite(leftVertex) == rightVertex );
|
|||
|
|
|||
|
edge->setCapacity ( cap );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be vertically or horizontally aligned." );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::increaseEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, int cap )
|
|||
|
// *****************************************************************************************************
|
|||
|
{
|
|||
|
if ( col1 == col2 ) {
|
|||
|
if ( row1 == row2 )
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be different." );
|
|||
|
|
|||
|
Vertex* bottomVertex = NULL;
|
|||
|
Vertex* topVertex = NULL;
|
|||
|
if ( ( row1 < row2 ) && ( row2 == row1 + 1 ) ) {
|
|||
|
bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
topVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
|
|||
|
}
|
|||
|
else if ( row1 == row2 + 1 ) {
|
|||
|
bottomVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row2) );
|
|||
|
topVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );
|
|||
|
|
|||
|
Edge* edge = bottomVertex->getVEdgeOut();
|
|||
|
assert ( edge->getOpposite(bottomVertex) == topVertex );
|
|||
|
|
|||
|
edge->increaseCapacity ( cap );
|
|||
|
}
|
|||
|
else if ( row1 == row2 ) {
|
|||
|
Vertex* leftVertex = NULL;
|
|||
|
Vertex* rightVertex = NULL;
|
|||
|
if ( ( col1 < col2 ) && ( col2 == col1 + 1 ) ) {
|
|||
|
leftVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
|
|||
|
}
|
|||
|
else if ( col1 == col2 + 1 ) {
|
|||
|
leftVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col2, row1) );
|
|||
|
rightVertex = _matrixVertex->getVertex ( pair<unsigned int, unsigned int>(col1, row1) );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be contiguous." );
|
|||
|
|
|||
|
Edge* edge = leftVertex->getHEdgeOut();
|
|||
|
assert ( edge->getOpposite(leftVertex) == rightVertex );
|
|||
|
|
|||
|
edge->increaseCapacity ( cap );
|
|||
|
}
|
|||
|
else
|
|||
|
throw Error ( "Graph::UpdateEdgeCapacity(): the two specified vertices must be vertically or horizontally aligned." );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::updateEdgesOccupancy ( Segment* segment, bool add )
|
|||
|
// ************************************************************
|
|||
|
{
|
|||
|
if ( Horizontal* horiz = dynamic_cast<Horizontal*>(segment) ) {
|
|||
|
Vertex* currentVertex = _matrixVertex->getVertex ( Point ( horiz->getSourceX(), horiz->getY() ) );
|
|||
|
Vertex* targetVertex = _matrixVertex->getVertex ( Point ( horiz->getTargetX(), horiz->getY() ) );
|
|||
|
while ( currentVertex != targetVertex ) {
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
assert ( edge );
|
|||
|
if ( add )
|
|||
|
edge->insertSegment ( segment );
|
|||
|
else
|
|||
|
edge->removeSegment ( segment );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
assert ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
else if ( Vertical* verti = dynamic_cast<Vertical*>(segment) ) {
|
|||
|
Vertex* currentVertex = _matrixVertex->getVertex ( Point ( verti->getX(), verti->getSourceY() ) );
|
|||
|
Vertex* targetVertex = _matrixVertex->getVertex ( Point ( verti->getX(), verti->getTargetY() ) );
|
|||
|
while ( currentVertex != targetVertex ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
assert ( edge );
|
|||
|
if ( add )
|
|||
|
edge->insertSegment ( segment );
|
|||
|
else
|
|||
|
edge->removeSegment ( segment );
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
assert ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::rebuildConnexComponent ( Contact* contact, int connexID, Segment* arrivalSegment )
|
|||
|
// *******************************************************************************************
|
|||
|
{
|
|||
|
//CEditor* editor = getCEditor ( _nimbus->getCell() );
|
|||
|
Vertex* contactVertex = getVertex ( contact->getCenter() );
|
|||
|
contactVertex->setContact ( contact );
|
|||
|
contactVertex->setConnexID ( connexID );
|
|||
|
contactVertex->setNetStamp ( _netStamp );
|
|||
|
contactVertex->setDistance((float)(HUGE));
|
|||
|
contactVertex->setPredecessor(NULL);
|
|||
|
//cerr << "from :" << contact << endl;
|
|||
|
//cerr << "arrivalSegment: " << arrivalSegment << endl;
|
|||
|
for_each_component ( component, contact->getSlaveComponents() ) {
|
|||
|
if ( dynamic_cast<Segment*>(component) ) {
|
|||
|
Segment* segment = static_cast<Segment*>(component);
|
|||
|
//cerr << " a segment " << segment << endl;
|
|||
|
//editor->Stop("Guess what to do");
|
|||
|
if ( segment == arrivalSegment ) continue;
|
|||
|
//cerr << " not arrivalSegment -> setNetStampConnexID" << endl;
|
|||
|
setNetStampConnexID ( segment, connexID );
|
|||
|
//cerr << " done" << endl;
|
|||
|
if ( !dynamic_cast<Contact*>( segment->getOppositeAnchor(contact) ) )
|
|||
|
throw Error ("Graph::rebuildConnexComponent(): For the moment we do not consider Segments that anchors on something else than a Contact.");
|
|||
|
Contact* oppositeContact = static_cast<Contact*>(segment->getOppositeAnchor(contact));
|
|||
|
//cerr << " now recursive call on oppositeContact: " << oppositeContact << endl;
|
|||
|
//editor->Stop("See what has been done");
|
|||
|
rebuildConnexComponent ( oppositeContact, connexID, segment );
|
|||
|
//cerr << " done" << endl;
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::setNetStampConnexID ( Segment* segment, int connexID )
|
|||
|
// ***************************************************************
|
|||
|
{
|
|||
|
unsigned int sourceColumnIdx = _matrixVertex->getColumnIndex ( segment->getSourceX() );
|
|||
|
unsigned int sourceLineIdx = _matrixVertex->getLineIndex ( segment->getSourceY() );
|
|||
|
unsigned int targetColumnIdx = _matrixVertex->getColumnIndex ( segment->getTargetX() );
|
|||
|
unsigned int targetLineIdx = _matrixVertex->getLineIndex ( segment->getTargetY() );
|
|||
|
|
|||
|
if ( sourceColumnIdx == targetColumnIdx ) { // vertical segment
|
|||
|
for ( unsigned line = sourceLineIdx ; line < targetLineIdx ; line++ ) {
|
|||
|
Vertex* vertex = _matrixVertex->getVertexFromIndexes ( line, sourceColumnIdx );
|
|||
|
assert(vertex);
|
|||
|
vertex->setNetStamp ( _netStamp );
|
|||
|
vertex->setConnexID ( connexID );
|
|||
|
vertex->setDistance((float)(HUGE));
|
|||
|
Edge* edge = vertex->getVEdgeOut();
|
|||
|
assert(edge);
|
|||
|
edge->setNetStamp ( _netStamp );
|
|||
|
edge->setConnexID ( connexID );
|
|||
|
}
|
|||
|
Vertex* vertex = _matrixVertex->getVertexFromIndexes ( targetLineIdx, targetColumnIdx );
|
|||
|
assert(vertex);
|
|||
|
vertex->setNetStamp ( _netStamp );
|
|||
|
vertex->setConnexID ( connexID );
|
|||
|
vertex->setDistance((float)(HUGE));
|
|||
|
return;
|
|||
|
}
|
|||
|
if ( sourceLineIdx == targetLineIdx ) { // horizontal segment
|
|||
|
for ( unsigned column = sourceColumnIdx ; column < targetColumnIdx ; column++ ) {
|
|||
|
Vertex* vertex = _matrixVertex->getVertexFromIndexes ( sourceLineIdx, column );
|
|||
|
assert(vertex);
|
|||
|
vertex->setNetStamp ( _netStamp );
|
|||
|
vertex->setConnexID ( connexID );
|
|||
|
vertex->setDistance((float)(HUGE));
|
|||
|
Edge* edge = vertex->getHEdgeOut();
|
|||
|
assert(edge);
|
|||
|
edge->setNetStamp ( _netStamp );
|
|||
|
edge->setConnexID ( connexID );
|
|||
|
}
|
|||
|
Vertex* vertex = _matrixVertex->getVertexFromIndexes ( targetLineIdx, targetColumnIdx );
|
|||
|
assert(vertex);
|
|||
|
vertex->setNetStamp ( _netStamp );
|
|||
|
vertex->setConnexID ( connexID );
|
|||
|
vertex->setDistance((float)(HUGE));
|
|||
|
return;
|
|||
|
}
|
|||
|
throw Error ( "Graph::setNetStampConnexId(): what sort of segment is that, a diagonal one?" );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::insertSegment ( Segment* segment )
|
|||
|
// *******************************************
|
|||
|
{
|
|||
|
updateEdgesOccupancy ( segment, true );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::removeSegment ( Segment* segment )
|
|||
|
// *******************************************
|
|||
|
{
|
|||
|
updateEdgesOccupancy ( segment, false );
|
|||
|
}
|
|||
|
|
|||
|
float Graph::getSegmentCost ( Segment* segment )
|
|||
|
// *********************************************
|
|||
|
{
|
|||
|
unsigned nbDep = 0;
|
|||
|
unsigned nbTot = 0;
|
|||
|
unsigned sumDep = 0;
|
|||
|
Vertex* currentVertex = getVertex ( segment->getSourcePosition() );
|
|||
|
Vertex* targetVertex = getVertex ( segment->getTargetPosition() );
|
|||
|
if ( segment->getSourceY() == segment->getTargetY() ) { // which means : if it's a horizontal segment
|
|||
|
while ( currentVertex != targetVertex ) { // attention pour faire simple on code pour un grpahe regulier
|
|||
|
Edge* edge = currentVertex->getHEdgeOut(); // il faudrait choisir la bonne HEdgeOut pour un graphe irregulier
|
|||
|
unsigned ov = edge->getOverflow();
|
|||
|
if ( ov ) {
|
|||
|
nbDep++;
|
|||
|
sumDep += ov;
|
|||
|
}
|
|||
|
nbTot++;
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
while ( currentVertex != targetVertex ) {
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
unsigned ov = edge->getOverflow();
|
|||
|
if ( ov ) {
|
|||
|
nbDep++;
|
|||
|
sumDep += ov;
|
|||
|
}
|
|||
|
nbTot++;
|
|||
|
currentVertex = edge->getOpposite ( currentVertex );
|
|||
|
}
|
|||
|
}
|
|||
|
if ( !nbTot )
|
|||
|
return 0;
|
|||
|
return (float(nbDep)/float(nbTot))*sumDep;
|
|||
|
}
|
|||
|
|
|||
|
unsigned Graph::analyseRouting ( set<Segment*>& segmentsToUnroute )
|
|||
|
// ****************************************************************
|
|||
|
{
|
|||
|
// This function construct the list of segments that participate to congestion
|
|||
|
// empty Priority queue : easier than update each semgent when removing a semgent ...
|
|||
|
clearSTuplePQ();
|
|||
|
// 30/01/09 on remplace le parcours des nets/segments par un parcours des edges avec un map trié sur pointeur de segments et définissant un record : nbDep nBTot + sumOv pour chaque segment.
|
|||
|
unsigned nbEdgesTot = 0;
|
|||
|
unsigned nbEdgesOv = 0;
|
|||
|
unsigned overflow = 0;
|
|||
|
unsigned maxOv = 0;
|
|||
|
unsigned wirelength = 0;
|
|||
|
unsigned viaWirelength = 0;
|
|||
|
map<Segment*, segmentStat> segmentsMap;
|
|||
|
for ( unsigned i = 0 ; i < _all_edges.size() ; i++ )
|
|||
|
{
|
|||
|
Edge* edge = _all_edges[i];
|
|||
|
nbEdgesTot++;
|
|||
|
if ( edge->isCongested() ) {
|
|||
|
nbEdgesOv++;
|
|||
|
unsigned edgeOv = 2*edge->getOverflow();
|
|||
|
overflow += edgeOv;
|
|||
|
maxOv = edgeOv > maxOv ? edgeOv : maxOv;
|
|||
|
edge->addSubEstimateOccupancy ( HISTORIC_INC, true ); // add historic cost for each overflowed edge
|
|||
|
}
|
|||
|
forEach ( Segment*, segment, edge->getSegments() ) {
|
|||
|
map<Segment*, segmentStat>::iterator it = segmentsMap.find(*segment);
|
|||
|
if ( it != segmentsMap.end() ) {
|
|||
|
(*it).second.incNbTot();
|
|||
|
if ( edge->isCongested() ) {
|
|||
|
(*it).second.incNbDep();
|
|||
|
(*it).second.incSumOv(edge->getOverflow());
|
|||
|
}
|
|||
|
}
|
|||
|
else {
|
|||
|
if ( edge->isCongested() )
|
|||
|
segmentsMap[*segment]=segmentStat(1,1,edge->getOverflow());
|
|||
|
else
|
|||
|
segmentsMap[*segment]=segmentStat(0,1,0);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
unsigned nbDep = 0;
|
|||
|
unsigned nbTot = 0;
|
|||
|
float minimalCost = 0;
|
|||
|
float maximalCost = 0;
|
|||
|
for ( map<Segment*, segmentStat>::iterator it = segmentsMap.begin() ; it != segmentsMap.end() ; it++ ) {
|
|||
|
assert((*it).second.getNbTot() != 0);
|
|||
|
nbTot++;
|
|||
|
wirelength += getGridLength ( (*it).first );
|
|||
|
float segmentCost = (float((*it).second.getNbDep())/float((*it).second.getNbTot()))*(*it).second.getSumOv();
|
|||
|
if ( segmentCost ) {
|
|||
|
if (minimalCost == 0)
|
|||
|
minimalCost = segmentCost;
|
|||
|
minimalCost = segmentCost < minimalCost ? segmentCost : minimalCost;
|
|||
|
maximalCost = segmentCost > maximalCost ? segmentCost : maximalCost;
|
|||
|
STuple* stuple = STuple::create((*it).first, segmentCost);
|
|||
|
addToSTuplePQ(stuple);
|
|||
|
nbDep++;
|
|||
|
}
|
|||
|
}
|
|||
|
forEach ( Net*, net, _cell->getNets() ) {
|
|||
|
forEach ( Contact*, contact, net->getContacts() ) {
|
|||
|
const Layer* cLayer = contact->getLayer();
|
|||
|
if ( cLayer == Configuration::getGContact() || cLayer == Configuration::getGMetalV() )
|
|||
|
viaWirelength += 3;
|
|||
|
}
|
|||
|
}
|
|||
|
//forEach ( Net*, net, _cell->getNets() ) {
|
|||
|
// forEach ( Segment*, segment, net->getSegments() ) {
|
|||
|
// if ( isAGlobalRoutingSegment ( *segment ) ) {
|
|||
|
// float segmentCost = getSegmentCost ( *segment );
|
|||
|
// if ( segmentCost ) {
|
|||
|
// nbDep++;
|
|||
|
// STuple* stuple = NULL;
|
|||
|
// // si une CostProperty est attaché au segment et que son iterateur est différent de _stuplePQEnd
|
|||
|
// // on recupere le STuple
|
|||
|
// // sinon on cree un stuple
|
|||
|
// Hurricane::Property* property = segment->getProperty ( STuple::CostProperty::_name );
|
|||
|
// if ( STuple::CostProperty* cprop = dynamic_cast<STuple::CostProperty*>(property) ) {
|
|||
|
// STuple::STuplePQIter pqit = cprop->getPQIter();
|
|||
|
// if ( pqit != STuple::_stuplePQEnd )
|
|||
|
// stuple = (*pqit);
|
|||
|
// }
|
|||
|
// if ( !stuple )
|
|||
|
// stuple = STuple::create ( *segment, segmentCost );
|
|||
|
// addToSTuplePQ ( stuple );
|
|||
|
// }
|
|||
|
// nbTot++;
|
|||
|
// }
|
|||
|
// }
|
|||
|
//}
|
|||
|
cmess1 << " o Analyse routing :" << endl
|
|||
|
<< " - Number of overcapacity edges : " << nbEdgesOv << " / " << nbEdgesTot << endl
|
|||
|
<< " - # of overflow : " << overflow << endl
|
|||
|
<< " - max of overflow : " << maxOv << endl
|
|||
|
<< " - avg overflow : " << (float)overflow / (float)nbEdgesTot << endl
|
|||
|
<< " - grid wirelength : " << wirelength << endl
|
|||
|
<< " - # of via : " << viaWirelength/3 << endl
|
|||
|
<< " - total wirelength : " << wirelength + viaWirelength << endl
|
|||
|
<< " - Overflowed segments : " << nbDep << " / " << nbTot << endl;
|
|||
|
// construct the list on segments to unroute
|
|||
|
if ( _stuplePriorityQueue.empty() ) {
|
|||
|
cmess1 << " - Nothing to reroute !" << endl;
|
|||
|
cmess1 << " - Maximum segment cost : 0" << endl;
|
|||
|
}
|
|||
|
else {
|
|||
|
STuple* topSTuple = getMaxFromSTuplePQ();
|
|||
|
float maxCost = topSTuple->getCost();
|
|||
|
cmess1 << " - Maximum segment cost : " << maxCost << endl;
|
|||
|
float minCost = 0.20;
|
|||
|
if (_stuplePriorityQueue.size() <= 100)
|
|||
|
minCost = 0.0;
|
|||
|
//if ( maxCost > 1 )
|
|||
|
// minCost = maxCost * 0.20;
|
|||
|
|
|||
|
//cmess1 << " - Minimum segment cost considered : " << minCost << endl;
|
|||
|
//cmess1 << " - Minimal computed segment cost : " << minimalCost << endl
|
|||
|
// << " - Maximal computed segment cost : " << maximalCost << endl;
|
|||
|
segmentsToUnroute.insert ( topSTuple->getSegment() );
|
|||
|
//debugName = topSTuple->getSegment()->getNet()->getName();
|
|||
|
popMaxFromSTuplePQ();
|
|||
|
topSTuple = getMaxFromSTuplePQ();
|
|||
|
//bool fullSkim = true;
|
|||
|
//printSTuplePQ();
|
|||
|
while ( topSTuple != NULL ) {
|
|||
|
if ( topSTuple->getCost() >= minCost ) {
|
|||
|
segmentsToUnroute.insert ( topSTuple->getSegment() );
|
|||
|
popMaxFromSTuplePQ();
|
|||
|
topSTuple = getMaxFromSTuplePQ();
|
|||
|
}
|
|||
|
else {
|
|||
|
//fullSkim = false;
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
//cerr << " - fullSkim : " << fullSkim << endl;
|
|||
|
//printSTuplePQ();
|
|||
|
}
|
|||
|
return overflow;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::getHorizontalCutLines ( vector<DbU::Unit>& horizontalCutLines )
|
|||
|
// ************************************************************************
|
|||
|
{
|
|||
|
horizontalCutLines.clear();
|
|||
|
Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
horizontalCutLines.push_back ( currentVertex->getYMin() );
|
|||
|
while ( currentVertex ) {
|
|||
|
horizontalCutLines.push_back ( currentVertex->getYMax() );
|
|||
|
Edge* edge = currentVertex->getVEdgeOut();
|
|||
|
if ( edge )
|
|||
|
currentVertex = edge->getTo();
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::getVerticalCutLines ( vector<DbU::Unit>& verticalCutLines )
|
|||
|
// ********************************************************************
|
|||
|
{
|
|||
|
verticalCutLines.clear();
|
|||
|
Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
verticalCutLines.push_back ( currentVertex->getXMin() );
|
|||
|
while ( currentVertex ) {
|
|||
|
verticalCutLines.push_back ( currentVertex->getXMax() );
|
|||
|
Edge* edge = currentVertex->getHEdgeOut();
|
|||
|
if ( edge)
|
|||
|
currentVertex = edge->getTo();
|
|||
|
else
|
|||
|
break;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
bool Graph::hasGlobalRouting ( RoutingPad* routingPad )
|
|||
|
// ****************************************************
|
|||
|
{
|
|||
|
Hook* rpHook = routingPad->getBodyHook();
|
|||
|
Vertex* rpVertex = _matrixVertex->getVertex ( routingPad->getX(), routingPad->getY() );
|
|||
|
Hook* currentHook = rpHook->getNextHook();
|
|||
|
while ( currentHook != rpHook ) {
|
|||
|
if ( dynamic_cast<Segment::TargetHook*>(currentHook) ) {
|
|||
|
Segment* seg = dynamic_cast<Segment*>(currentHook->getComponent());
|
|||
|
if ( getVertex ( seg->getTargetX(), seg->getTargetY() ) == rpVertex )
|
|||
|
return true;
|
|||
|
}
|
|||
|
if ( dynamic_cast<Segment::SourceHook*>(currentHook) ) {
|
|||
|
Segment* seg = dynamic_cast<Segment*>(currentHook->getComponent());
|
|||
|
if ( getVertex ( seg->getSourceX(), seg->getSourceY() ) == rpVertex )
|
|||
|
return true;
|
|||
|
}
|
|||
|
currentHook = currentHook->getNextHook();
|
|||
|
}
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
bool Graph::isAGlobalRoutingContact ( Contact* contact )
|
|||
|
// *****************************************************
|
|||
|
{
|
|||
|
if ( contact->getLayer() == Configuration::getGMetalH () ) return true;
|
|||
|
if ( contact->getLayer() == Configuration::getGMetalV () ) return true;
|
|||
|
if ( contact->getLayer() == Configuration::getGContact() ) return true;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
bool Graph::isAGlobalRoutingSegment ( Segment* segment )
|
|||
|
// *****************************************************
|
|||
|
{
|
|||
|
if ( segment->getLayer() == Configuration::getGMetalH () ) return true;
|
|||
|
if ( segment->getLayer() == Configuration::getGMetalV () ) return true;
|
|||
|
return false;
|
|||
|
}
|
|||
|
|
|||
|
static void setContactLayer(Contact* contact)
|
|||
|
// ******************************************
|
|||
|
{
|
|||
|
bool alu2Used = false;
|
|||
|
bool alu3Used = false;
|
|||
|
|
|||
|
for_each_hook(hook, contact->getBodyHook()->getHooks()) {
|
|||
|
Component* component = hook->getComponent();
|
|||
|
if (dynamic_cast<Segment*>(component) || dynamic_cast<RoutingPad*>(component)) {
|
|||
|
const Layer* layer = component->getLayer();
|
|||
|
if (layer == Configuration::getGMetalH() || layer == Configuration::getPinMetal() ) alu2Used = true;
|
|||
|
else if (layer == Configuration::getGMetalV() ) alu3Used = true;
|
|||
|
//else assert(false); // makes non ispd07 benchs failed....
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
|
|||
|
const Layer* layer = NULL;
|
|||
|
if ( alu2Used ) {
|
|||
|
if ( alu3Used )
|
|||
|
layer = Configuration::getGContact();
|
|||
|
else
|
|||
|
layer = Configuration::getGMetalH();
|
|||
|
}
|
|||
|
else if ( alu3Used ) {
|
|||
|
layer = Configuration::getGMetalV();
|
|||
|
}
|
|||
|
else
|
|||
|
assert ( false );
|
|||
|
|
|||
|
contact->setLayer(layer);
|
|||
|
}
|
|||
|
|
|||
|
void Graph::MaterializeRouting ( Vertex* vertex )
|
|||
|
// **********************************************
|
|||
|
{
|
|||
|
// This function materializes the routing of the connexe component passed as argument
|
|||
|
|
|||
|
countMaterialize++;
|
|||
|
|
|||
|
//if ( debugging ) {
|
|||
|
// cerr << " Materialize routing" << endl;
|
|||
|
// CEditor* editor = getCEditor( _nimbus->getCell() );
|
|||
|
// editor->Refresh();
|
|||
|
// string stopMessage = "MaterializeRouting, starting vertex: ";
|
|||
|
// stopMessage += getString ( vertex );
|
|||
|
// editor->Stop(stopMessage);
|
|||
|
//}
|
|||
|
|
|||
|
depthMaterialize = 0;
|
|||
|
//cerr << "INITIAL CALL of materialize routing for net : " << _working_net << endl;
|
|||
|
Edge* arrivalEdge = NULL;
|
|||
|
Contact* initContact = NULL;
|
|||
|
if ( _useSegments ) {
|
|||
|
initContact = vertex->getContact ( arrivalEdge );
|
|||
|
assert ( initContact ); // must be != NULL because the source vertex must have a routingPad !
|
|||
|
}
|
|||
|
|
|||
|
MaterializeRouting ( vertex, arrivalEdge, initContact );
|
|||
|
}
|
|||
|
|
|||
|
void Graph::MaterializeRouting ( Vertex* vertex, Edge* arrivalEdge, Contact* initialContact )
|
|||
|
// ******************************************************************************************
|
|||
|
{
|
|||
|
depthMaterialize++;
|
|||
|
int vertexConnex = vertex->getConnexID();
|
|||
|
assert ( vertexConnex != -1 );
|
|||
|
//cerr << "--> check in MaterializeRouting " << endl;
|
|||
|
//checkGraphConsistency();
|
|||
|
//cerr << " MR:" << depthMaterialize << ": vertex " << vertex << endl;
|
|||
|
|
|||
|
//add for test ofnew MaterializeRouting 03/09/2997 d2
|
|||
|
if ( _useSegments ) {
|
|||
|
for ( unsigned i = 0 ; i < 4 ; i++ ) {
|
|||
|
if ( Edge* edge = vertex->getFirstEdges ( i ) ) {
|
|||
|
if ( edge == arrivalEdge )
|
|||
|
continue;
|
|||
|
if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
|
|||
|
Vertex* oppositeVertex = edge->getOpposite ( vertex );
|
|||
|
Contact* reachedContact = oppositeVertex->getContact(edge);
|
|||
|
Edge* straightArrivalEdge = edge;
|
|||
|
vector<Edge*> crossedEdges;
|
|||
|
crossedEdges.push_back(edge);
|
|||
|
while ( reachedContact == NULL ) {
|
|||
|
straightArrivalEdge = oppositeVertex->getFirstEdges(i);
|
|||
|
if ( straightArrivalEdge == NULL )
|
|||
|
throw Error ( "Graph:MaterializeRouting(): Cannot continue straight on." );
|
|||
|
oppositeVertex = straightArrivalEdge->getOpposite ( oppositeVertex );
|
|||
|
reachedContact = oppositeVertex->getContact ( straightArrivalEdge );
|
|||
|
//straightArrivalEdge->incOccupancy(); // put the incOccupancy in insertSegment function
|
|||
|
crossedEdges.push_back(straightArrivalEdge);
|
|||
|
}
|
|||
|
// test pour ne pas recreer le routage preexistant en cas de reroutage
|
|||
|
bool alreadyExist = false;
|
|||
|
for_each_component ( component, initialContact->getSlaveComponents() ) {
|
|||
|
if ( dynamic_cast<Segment*>(component) ) {
|
|||
|
Segment* seg = static_cast<Segment*>(component);
|
|||
|
if ( seg->getOppositeAnchor(initialContact) == (Component*)(reachedContact) ) {
|
|||
|
//cerr << " [0;33msegment already exists[0;m" << endl;
|
|||
|
alreadyExist = true;
|
|||
|
}
|
|||
|
}
|
|||
|
end_for;
|
|||
|
}
|
|||
|
if ( !alreadyExist ) {
|
|||
|
Segment* segment = createSegment ( initialContact, reachedContact );
|
|||
|
assert ( segment );
|
|||
|
for ( unsigned j = 0 ; j < crossedEdges.size(); j++ )
|
|||
|
crossedEdges[j]->insertSegment(segment);
|
|||
|
}
|
|||
|
MaterializeRouting ( oppositeVertex, straightArrivalEdge, reachedContact );
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
setContactLayer(initialContact);
|
|||
|
}
|
|||
|
//else {
|
|||
|
// for_each_edge ( edge, vertex->getAdjacentEdges() ) {
|
|||
|
// //if ( edge == arrivalEdge)
|
|||
|
// // continue;
|
|||
|
// //cerr << " MR:" << depthMaterialize<< ": edge " << edge << endl;
|
|||
|
// if ( (edge->getNetStamp() == _netStamp) && (edge->getConnexID() == vertexConnex) ) {
|
|||
|
// edge->createSplitter ( _working_net );
|
|||
|
// _nbSplitters++;
|
|||
|
// Hook* hook = edge->getSplitterHook ( vertex );
|
|||
|
// assert (hook);
|
|||
|
// if ( Hook* previousHook = vertex->getLocalRingHook() ) // XXX Attention puisqu'on vire le systeme le localRingHook au profit du contact
|
|||
|
// hook->attach ( previousHook );
|
|||
|
// vertex->setLocalRingHook ( hook );
|
|||
|
// if ( edge != arrivalEdge ) {
|
|||
|
// MaterializeRouting ( edge->getOpposite(vertex), edge);
|
|||
|
// // cleaning for next routing
|
|||
|
// edge->setSplitter(NULL);
|
|||
|
// }
|
|||
|
// end_for;
|
|||
|
// }
|
|||
|
// }
|
|||
|
//}
|
|||
|
// cleaning for next routing
|
|||
|
|
|||
|
//vertex->setLocalRingHook(NULL);
|
|||
|
vertex->setContact(NULL);
|
|||
|
depthMaterialize--;
|
|||
|
}
|
|||
|
|
|||
|
void Graph::CleanRoutingState()
|
|||
|
// ****************************
|
|||
|
{
|
|||
|
// Vide la pile
|
|||
|
clearPriorityQueue();
|
|||
|
|
|||
|
//// Pour chacun des vertex, on efface le pointeur sur la ronde locale et on reinitialise le connexID, la distance et le predecessor
|
|||
|
//// le vtuple est aussi mis a NULL, c'est pourquoi il faut que la pile ait été vidée avant ( sinon assert )
|
|||
|
//// (XXX mieux vaudrait le faire uniquement pour les vertex touchés par le routage XXX)
|
|||
|
//for ( unsigned i = 0 ; i < _all_vertexes.size() ; i++ ) {
|
|||
|
// Vertex* vertex = _all_vertexes[i];
|
|||
|
// assert (vertex);
|
|||
|
// vertex->setLocalRingHook(NULL);
|
|||
|
// vertex->setConnexID(-1);
|
|||
|
// vertex->setDistance((float)(HUGE));
|
|||
|
// vertex->setPredecessor(NULL);
|
|||
|
// assert ( vertex->getVTuple() == NULL );
|
|||
|
//}
|
|||
|
|
|||
|
//// Pour chacune des edges, on efface le pointeur sur le splitter (potentiel) et on reinitialise le connexID
|
|||
|
//for ( unsigned i = 0 ; i < _all_edges.size() ; i++ ) {
|
|||
|
// Edge* edge = _all_edges[i];
|
|||
|
// assert ( edge );
|
|||
|
// edge->setSplitter(NULL);
|
|||
|
// edge->setConnexID(-1);
|
|||
|
//}
|
|||
|
|
|||
|
// On vide le set des _vertexes_to_route
|
|||
|
_vertexes_to_route.clear();
|
|||
|
_working_net = NULL;
|
|||
|
_searchingArea.makeEmpty();
|
|||
|
}
|
|||
|
|
|||
|
void Graph::checkGraphConsistency()
|
|||
|
// ********************************
|
|||
|
{
|
|||
|
bool checkFailed = false;
|
|||
|
unsigned nbEdges= 0;
|
|||
|
for_each_edge ( edge, VectorCollection<Edge*>(_all_edges) ) {
|
|||
|
nbEdges++;
|
|||
|
if ( edge->getNetStamp() > _netStamp ) {
|
|||
|
cerr << " - " << edge << " netStamp mismatch" << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
if ( edge->getNetStamp() == _netStamp ) {
|
|||
|
int edgeID = edge->getConnexID();
|
|||
|
if ( edgeID != -1 ) {
|
|||
|
if ( edge->getFrom()->getConnexID() == -1 ) {
|
|||
|
cerr << " - from : " << edge->getFrom() << " of " << edge << " : connexID mismatch" << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
if ( edge->getTo()->getConnexID() == -1 ) {
|
|||
|
cerr << " - to : " << edge->getTo() << " of " << edge << " : connexID mismatch" << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
if ( (edge->getFrom()->getConnexID() != edgeID) && (edge->getTo()->getConnexID() != edgeID) ) {
|
|||
|
cerr << " - " << edge << " : connexID mismatch" << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
end_for
|
|||
|
}
|
|||
|
if ( checkFailed ) {
|
|||
|
cerr << " ************************************" << endl
|
|||
|
<< " * GRAPH CHECK CONSISTENCY FAILED *" << endl
|
|||
|
<< " ************************************" << endl;
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
void Graph::checkEmptyPriorityQueue()
|
|||
|
// **********************************
|
|||
|
{
|
|||
|
bool checkFailed = false;
|
|||
|
// check empty priority queue
|
|||
|
if ( !_vtuplePriorityQueue.empty() ) {
|
|||
|
checkFailed = true;
|
|||
|
cerr << " Priority Queue is not empty !!!!" << endl
|
|||
|
<< " stil in queue :" << endl;
|
|||
|
|
|||
|
VTuplePQIter pqit = _vtuplePriorityQueue.begin();
|
|||
|
while ( pqit != _vtuplePriorityQueue.end() ) {
|
|||
|
cerr << " " << (*pqit)->getVertex() << " : " << (*pqit)->getDistance() << endl;
|
|||
|
pqit++;
|
|||
|
}
|
|||
|
}
|
|||
|
//check null vtuple foreach vertex
|
|||
|
unsigned nbVertexes= 0;
|
|||
|
for_each_vertex ( vertex, VectorCollection<Vertex*>(_all_vertexes) ) {
|
|||
|
nbVertexes++;
|
|||
|
if ( vertex->getNetStamp() > _netStamp ) {
|
|||
|
cerr << " - " << vertex << " netStamp mismatch" << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
if ( vertex->getVTuple() ) {
|
|||
|
cerr << " - " << vertex << " still have a vtuple : " << vertex->getVTuple() << endl;
|
|||
|
checkFailed = true;
|
|||
|
}
|
|||
|
end_for
|
|||
|
}
|
|||
|
if ( checkFailed ) {
|
|||
|
cerr << " *********************************************" << endl
|
|||
|
<< " * GRAPH CHECK EMPTY PRIORITY QUEUE FAILED *" << endl
|
|||
|
<< " *********************************************" << endl;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
// DensityWindow* Graph::createEstimateOccupancyWindow()
|
|||
|
// // **************************************************
|
|||
|
// {
|
|||
|
// if ( _estimateOccupancyWindow ) return _estimateOccupancyWindow;
|
|||
|
|
|||
|
// unsigned int max = _ySize > _xSize ? _ySize : _xSize;
|
|||
|
// unsigned int scale = (unsigned) ceil(500.0/(double)max);
|
|||
|
|
|||
|
// _estimateOccupancyWindow = new DensityWindow ( _xSize, _ySize, 3, "fire", scale );
|
|||
|
// _estimateOccupancyWindow->setName ( 0, "Global Estimate Occupancy" );
|
|||
|
// _estimateOccupancyWindow->setName ( 1, "Horizontal Estimate Occupancy" );
|
|||
|
// _estimateOccupancyWindow->setName ( 2, "Vertical Estimate Occupancy" );
|
|||
|
|
|||
|
// return _estimateOccupancyWindow;
|
|||
|
// }
|
|||
|
|
|||
|
// void Graph::UpdateEstimateOccupancyWindow()
|
|||
|
// // ****************************************
|
|||
|
// {
|
|||
|
// if ( !_estimateOccupancyWindow )
|
|||
|
// createEstimateOccupancyWindow();
|
|||
|
|
|||
|
// _estimateOccupancyWindow->setSlice(0);
|
|||
|
// Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
// int i = 0;
|
|||
|
// int j = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// Vertex* firstLineVertex = currentVertex;
|
|||
|
// i = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// float xEstimateOccupancy = 0.0;
|
|||
|
// Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
|||
|
// if ( hEdgeOut )
|
|||
|
// xEstimateOccupancy += hEdgeOut->getEstimateOccupancy();
|
|||
|
// float yEstimateOccupancy = 0.0;
|
|||
|
// if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
|
|||
|
// yEstimateOccupancy += vEdgeOut->getEstimateOccupancy();
|
|||
|
|
|||
|
// int colorValue = _maxEstimateOccupancy != 0 ? (int)(255 * (xEstimateOccupancy + yEstimateOccupancy) / _maxEstimateOccupancy) : 0;
|
|||
|
// int colorXValue = _maxXEstimateOccupancy != 0 ? (int)(255 * xEstimateOccupancy / _maxXEstimateOccupancy) : 0;
|
|||
|
// int colorYValue = _maxYEstimateOccupancy != 0 ? (int)(255 * yEstimateOccupancy / _maxYEstimateOccupancy) : 0;
|
|||
|
// _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorValue , 0);
|
|||
|
// _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorXValue, 1);
|
|||
|
// _estimateOccupancyWindow->DrawRectangle(i, j, i, j, colorYValue, 2);
|
|||
|
// i++;
|
|||
|
// if ( hEdgeOut )
|
|||
|
// currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// j++;
|
|||
|
// Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
|||
|
// if ( vEdgeOut )
|
|||
|
// currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// _estimateOccupancyWindow->getWindow()->show();
|
|||
|
// return;
|
|||
|
// }
|
|||
|
|
|||
|
//void Graph::printStats()
|
|||
|
//// *********************
|
|||
|
//{
|
|||
|
// Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
// int i = 0;
|
|||
|
// int j = 0;
|
|||
|
// int nbEdgesTotal = 0;
|
|||
|
// int nbEdgesOver = 0;
|
|||
|
//
|
|||
|
// unsigned overflow = 0;
|
|||
|
// unsigned maxOver = 0;
|
|||
|
// //float maxOver = 0;
|
|||
|
// //float averageOver = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// Vertex* firstLineVertex = currentVertex;
|
|||
|
// i = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
|||
|
// if ( hEdgeOut ) {
|
|||
|
// nbEdgesTotal++;
|
|||
|
// int ov = 2*(hEdgeOut->getRealOccupancy() - hEdgeOut->getCapacity()); // 2 = minimum sapcing + minimum width
|
|||
|
// if ( ov > 0 ) {
|
|||
|
// nbEdgesOver++;
|
|||
|
// overflow += ov;
|
|||
|
// maxOver = ov > maxOver ? ov : maxOver;
|
|||
|
// for_each_segment ( segment, hEdgeOut->getSegments() ) {
|
|||
|
// Net* net = segment->getNet();
|
|||
|
// map<Net*, unsigned>::iterator nuit = _netNbOverEdges.find ( net );
|
|||
|
// if ( nuit != _netNbOverEdges.end() )
|
|||
|
// (*nuit).second = (*nuit).second + 1;
|
|||
|
// else
|
|||
|
// _netNbOverEdges[net] = 1;
|
|||
|
// end_for;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// //float tempOver = (float)hEdgeOut->getRealOccupancy() / (float)hEdgeOut->getCapacity();
|
|||
|
// //if ( tempOver > 0.8 ) {
|
|||
|
// // nbEdgesOver++;
|
|||
|
// // averageOver += tempOver;
|
|||
|
// // if ( tempOver > maxOver ) maxOver = tempOver;
|
|||
|
// //}
|
|||
|
// }
|
|||
|
// if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() ) {
|
|||
|
// nbEdgesTotal++;
|
|||
|
// int ov = 2*(vEdgeOut->getRealOccupancy() - vEdgeOut->getCapacity());
|
|||
|
// if ( ov > 0 ) {
|
|||
|
// nbEdgesOver++;
|
|||
|
// overflow += ov;
|
|||
|
// maxOver = ov > maxOver ? ov : maxOver;
|
|||
|
// for_each_segment ( segment, vEdgeOut->getSegments() ) {
|
|||
|
// Net* net = segment->getNet();
|
|||
|
// map<Net*, unsigned>::iterator nuit = _netNbOverEdges.find ( net );
|
|||
|
// if ( nuit != _netNbOverEdges.end() )
|
|||
|
// (*nuit).second = (*nuit).second + 1;
|
|||
|
// else
|
|||
|
// _netNbOverEdges[net] = 1;
|
|||
|
// end_for;
|
|||
|
// }
|
|||
|
// }
|
|||
|
// //float tempOver = (float)vEdgeOut->getRealOccupancy() / (float)vEdgeOut->getCapacity();
|
|||
|
// //if ( tempOver > 0.8 ) {
|
|||
|
// // nbEdgesOver++;
|
|||
|
// // averageOver += tempOver;
|
|||
|
// // if ( tempOver > maxOver ) maxOver = tempOver;
|
|||
|
// //}
|
|||
|
// }
|
|||
|
//
|
|||
|
// i++;
|
|||
|
// if ( hEdgeOut )
|
|||
|
// currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// j++;
|
|||
|
// Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
|||
|
// if ( vEdgeOut )
|
|||
|
// currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// //averageOver = nbEdgesOver == 0 ? 0 : averageOver / (float)nbEdgesOver;
|
|||
|
// //
|
|||
|
//
|
|||
|
// cerr << " - Total number of edges : " << nbEdgesTotal << endl
|
|||
|
// << " - Number of overcapacity edges : " << nbEdgesOver << endl
|
|||
|
// << " - Total calls to Dijkstra : " << countDijkstra << endl
|
|||
|
// << " - Total calls to Monotonic : " << countMonotonic << endl
|
|||
|
// << " - Total calls to Materialize : " << countMaterialize << endl
|
|||
|
// << " - Taille du Graphe de routage : " << _xSize << " x " << _ySize << endl
|
|||
|
// << endl
|
|||
|
// << " - # of overflow : " << overflow << endl
|
|||
|
// << " - max of overflow : " << maxOver << endl
|
|||
|
// << " - # of net with overflow : " << _netNbOverEdges.size() << endl;
|
|||
|
// return;
|
|||
|
//}
|
|||
|
|
|||
|
// DensityWindow* Graph::createOccupancyWindow()
|
|||
|
// // ******************************************
|
|||
|
// {
|
|||
|
// if ( _occupancyWindow ) return _occupancyWindow;
|
|||
|
|
|||
|
// unsigned int max = _ySize > _xSize ? _ySize : _xSize;
|
|||
|
// unsigned int scale = (unsigned) ceil(500.0/(double)max);
|
|||
|
|
|||
|
// _occupancyWindow = new DensityWindow ( _xSize, _ySize, 3, "fire", scale );
|
|||
|
// _occupancyWindow->setName ( 0, "Global Occupancy" );
|
|||
|
// _occupancyWindow->setName ( 1, "Horizontal Occupancy" );
|
|||
|
// _occupancyWindow->setName ( 2, "Vertical Occupancy" );
|
|||
|
|
|||
|
// return _occupancyWindow;
|
|||
|
// }
|
|||
|
|
|||
|
// void Graph::UpdateOccupancyWindow()
|
|||
|
// // ********************************
|
|||
|
// {
|
|||
|
// if ( !_occupancyWindow )
|
|||
|
// createOccupancyWindow();
|
|||
|
|
|||
|
// _occupancyWindow->setSlice(0);
|
|||
|
// Vertex* currentVertex = _lowerLeftVertex;
|
|||
|
// int i = 0;
|
|||
|
// int j = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// Vertex* firstLineVertex = currentVertex;
|
|||
|
// i = 0;
|
|||
|
// while ( currentVertex ) {
|
|||
|
// unsigned xOccupancy = 0;
|
|||
|
// Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
|||
|
// if ( hEdgeOut )
|
|||
|
// xOccupancy += hEdgeOut->getRealOccupancy();
|
|||
|
// unsigned yOccupancy = 0;
|
|||
|
// if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() )
|
|||
|
// yOccupancy += vEdgeOut->getRealOccupancy();
|
|||
|
// assert(_maxOccupancy);
|
|||
|
// assert(_maxXOccupancy);
|
|||
|
// assert(_maxYOccupancy);
|
|||
|
// _occupancyWindow->DrawRectangle(i, j, i, j, (255 * (xOccupancy + yOccupancy) / _maxOccupancy), 0);
|
|||
|
// _occupancyWindow->DrawRectangle(i, j, i, j, (255 * xOccupancy / _maxXOccupancy), 1);
|
|||
|
// _occupancyWindow->DrawRectangle(i, j, i, j, (255 * yOccupancy / _maxYOccupancy), 2);
|
|||
|
// i++;
|
|||
|
// if ( hEdgeOut )
|
|||
|
// currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// j++;
|
|||
|
// Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
|||
|
// if ( vEdgeOut )
|
|||
|
// currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
|||
|
// else
|
|||
|
// break;
|
|||
|
// }
|
|||
|
// _occupancyWindow->getWindow()->show();
|
|||
|
// return;
|
|||
|
// }
|
|||
|
|
|||
|
Record* Graph::_getRecord() const
|
|||
|
// ************************
|
|||
|
{
|
|||
|
Record* record = new Record ( getString ( this ) );
|
|||
|
|
|||
|
record->add ( getSlot ( "LowerLeftVertex", _lowerLeftVertex ) );
|
|||
|
// record->add ( getSlot ( "SlicingTree" , _slicingTree ) );
|
|||
|
record->add ( getSlot ( "WorkingNet" , _working_net ) );
|
|||
|
record->add ( getSlot ( "SearchingArea" , _searchingArea ) );
|
|||
|
record->add ( getSlot ( "xSize" , _xSize ) );
|
|||
|
record->add ( getSlot ( "ySize" , _ySize ) );
|
|||
|
record->add ( getSlot ( "maxEstimateOccupancy", _maxEstimateOccupancy ) );
|
|||
|
record->add ( getSlot ( "maxXEstimateOccupancy", _maxXEstimateOccupancy ) );
|
|||
|
record->add ( getSlot ( "maxYEstimateOccupancy", _maxYEstimateOccupancy ) );
|
|||
|
|
|||
|
return record;
|
|||
|
}
|
|||
|
|
|||
|
string Graph::_getString() const
|
|||
|
// *****************************
|
|||
|
{
|
|||
|
return "<" + _TName ( "RoutingGraph" )
|
|||
|
//+ ":" + getString ( _slicingTree )
|
|||
|
+ "," + getString ( _xSize )
|
|||
|
+ "," + getString ( _ySize )
|
|||
|
+ ">";
|
|||
|
}
|
|||
|
|
|||
|
} // namespace Knik
|