1333 lines
54 KiB
C++
1333 lines
54 KiB
C++
// -*- C++ -*-
|
||
//
|
||
// This file is part of the Coriolis Software.
|
||
// Copyright (c) UPMC 2006-2016, All Rights Reserved
|
||
//
|
||
// x-----------------------------------------------------------------x
|
||
// | C O R I O L I S |
|
||
// | K n i k - G l o b a l R o u t e r |
|
||
// | |
|
||
// | Author : Damien Dupuis |
|
||
// | E-mail : Damien.Dupuis@lip6.fr |
|
||
// | =============================================================== |
|
||
// | C++ Header : "./KnikEngine.cpp" |
|
||
// x-----------------------------------------------------------------x
|
||
|
||
|
||
#include <climits>
|
||
#include "hurricane/Warning.h"
|
||
#include "hurricane/Property.h"
|
||
#include "hurricane/NetRoutingProperty.h"
|
||
#include "hurricane/RoutingPad.h"
|
||
#include "hurricane/Contact.h"
|
||
#include "hurricane/Horizontal.h"
|
||
#include "hurricane/Vertical.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/ToolBox.h"
|
||
#include "crlcore/Measures.h"
|
||
#include "crlcore/RoutingGauge.h"
|
||
#include "crlcore/RoutingLayerGauge.h"
|
||
#include "crlcore/AllianceFramework.h"
|
||
#include "knik/Configuration.h"
|
||
#include "knik/Edge.h"
|
||
#include "knik/Vertex.h"
|
||
#include "knik/Graph.h"
|
||
#include "knik/RoutingGrid.h"
|
||
#include "knik/NetExtension.h"
|
||
#include "knik/KnikEngine.h"
|
||
#include "knik/flute.h"
|
||
|
||
|
||
#define MAX_RUNTIME 86400
|
||
#define MAX_ITERATION UINT_MAX
|
||
|
||
|
||
namespace Knik {
|
||
|
||
using Hurricane::Warning;
|
||
using Hurricane::NetRoutingExtension;
|
||
using Hurricane::NetRoutingState;
|
||
using CRL::addMeasure;
|
||
using CRL::RoutingGauge;
|
||
using CRL::RoutingLayerGauge;
|
||
using CRL::AllianceFramework;
|
||
|
||
|
||
// Global Variables
|
||
unsigned int __congestion__;
|
||
unsigned int __precongestion__;
|
||
float __edge_cost__;
|
||
bool __initialized__;
|
||
|
||
extern bool __ripupMode__;
|
||
|
||
const Name KnikEngine::_toolName = "Knik::KnikEngine";
|
||
size_t KnikEngine::_hEdgeReservedLocal = 0;
|
||
size_t KnikEngine::_vEdgeReservedLocal = 0;
|
||
|
||
|
||
KnikEngine::KnikEngine ( Cell* cell
|
||
, unsigned congestion
|
||
, unsigned precongestion
|
||
, bool benchMode
|
||
, bool useSegments
|
||
, float edgeCost )
|
||
: CRL::ToolEngine ( cell )
|
||
, _routingGauge ( NULL )
|
||
, _allowedDepth ( 0)
|
||
, _routingGraph ( NULL )
|
||
, _routingGrid ( NULL )
|
||
, _timer ()
|
||
, _nets_to_route ()
|
||
, _benchMode ( benchMode )
|
||
, _useSegments ( useSegments )
|
||
, _routingDone ( false )
|
||
, _rerouteIteration( 0 )
|
||
, _segmentOverEdges()
|
||
, _sortSegmentOv ()
|
||
{
|
||
if (congestion > 1)
|
||
throw Error ( "KnikEngine::KnikEngine(): congestion argument must be 0 (None) or 1 (Congestion) : %s."
|
||
, getString(congestion).c_str() );
|
||
__congestion__ = congestion;
|
||
|
||
if ( precongestion > 2 )
|
||
throw Error ( "KnikEngine::KnikEngine(): precongestion argument must be 0 (None), 1 (Static) or 2 (Dynamic) : %s."
|
||
, getString(precongestion).c_str() );
|
||
|
||
__precongestion__ = precongestion;
|
||
__edge_cost__ = edgeCost;
|
||
__initialized__ = false;
|
||
}
|
||
|
||
|
||
KnikEngine::~KnikEngine ()
|
||
// ***********************
|
||
{
|
||
}
|
||
|
||
KnikEngine* KnikEngine::create ( Cell* cell, unsigned congestion, unsigned precongestion, bool benchMode, bool useSegments, float edgeCost )
|
||
// *****************************************************************************************************************************************
|
||
{
|
||
CRL::deleteEmptyNets ( cell );
|
||
KnikEngine* _knik = new KnikEngine ( cell, congestion, precongestion, benchMode, useSegments, edgeCost );
|
||
|
||
_knik->_postCreate();
|
||
|
||
// This is also printed in the banner of Unicorn/Cgt, no need to remind it here again.
|
||
// cout << " o Knik -- Global router makes use of FLUTE software" << endl;
|
||
// cout << Dots::asIdentifier(" - Author" ,"Chris C. N. CHU") << endl;
|
||
// cout << Dots::asIdentifier(" - Prof. Ident. ","Iowa State University") << endl;
|
||
// cout << Dots::asIdentifier(" - URL" ,"http://home.eng.iastate.edu/~cnchu") << endl;
|
||
|
||
return _knik;
|
||
}
|
||
|
||
void KnikEngine::_postCreate()
|
||
// ***************************
|
||
{
|
||
Inherit::_postCreate();
|
||
|
||
// For Flute : readLUT to be able to use POWV9.dat & POST9.dat
|
||
readLUT();
|
||
|
||
return;
|
||
}
|
||
|
||
void KnikEngine::destroy()
|
||
// ***********************
|
||
{
|
||
_preDestroy();
|
||
delete this;
|
||
}
|
||
|
||
void KnikEngine::_preDestroy()
|
||
// ***************************
|
||
{
|
||
_routingGraph->destroy();
|
||
Inherit::_preDestroy();
|
||
//Configuration::get()->destroy();
|
||
return;
|
||
}
|
||
|
||
|
||
void KnikEngine::setRoutingGauge ( RoutingGauge* rg )
|
||
{
|
||
_routingGauge = rg;
|
||
_allowedDepth = rg->getDepth();
|
||
}
|
||
|
||
|
||
void KnikEngine::setAllowedDepth ( unsigned int allowedDepth )
|
||
{
|
||
if (not _routingGauge)
|
||
cerr << Error( "KnikEngine::setAllowedDepth(): Must set the RoutingGauge before the allowed depth." ) << endl;
|
||
|
||
_allowedDepth = (allowedDepth < _routingGauge->getDepth()) ? allowedDepth : _routingGauge->getDepth();
|
||
}
|
||
|
||
|
||
void KnikEngine::MakeRoutingLeaves()
|
||
// *********************************
|
||
{
|
||
//unsigned steps = getCell()->getAbutmentBox().getHeight() / DbU::lambda(50); // +o( mieux vaudrait recuperer le slice !
|
||
//if ( _nimbus->getDepth() < steps ) {
|
||
// _nimbus->progress ( steps - _nimbus->getDepth() );
|
||
// _nimbus->PlacementLeavesDown();
|
||
//}
|
||
// for_each_gcell(gcell, _nimbus->getPlacementLeaves()) {
|
||
// //if (_metisseLimit) // dans un premier temps on se limite <20> respecter les placementLeaves (on ne descend pas en dessous)
|
||
// if (gcell->isAStrictSubGCellOf(gcell->getPlacementLeaf()))
|
||
// break;
|
||
// gcell->setAsRoutingLeaf();
|
||
// for_each_fence (fence, gcell->getSurroundingFences()) {
|
||
// fence->setAsRoutingFence();
|
||
// end_for;
|
||
// }
|
||
// end_for;
|
||
// }
|
||
return;
|
||
}
|
||
|
||
void KnikEngine::initGlobalRouting( const map<Name,Net*>& excludedNets )
|
||
// *********************************************************************
|
||
{
|
||
assert( _nets_to_route.empty() );
|
||
cmess2 << " o Initializing global routing." << endl;
|
||
//#if defined(__USE_STATIC_PRECONGESTION__) || defined(__USE_DYNAMIC_PRECONGESTION__)
|
||
cmess1 << Dots::asUInt ( " - Congestion Mode" , __congestion__ ) << endl;
|
||
cmess1 << Dots::asUInt ( " - Pre-Congestion Mode", __precongestion__ ) << endl;
|
||
cmess1 << Dots::asDouble( " - Edge Cost" , __edge_cost__ ) << endl;
|
||
//#endif
|
||
|
||
if (not _routingGraph) {
|
||
_timer.resetIncrease();
|
||
_timer.start();
|
||
|
||
_routingGraph = Graph::create ( this, _routingGrid, _benchMode, _useSegments );
|
||
cmess2 << " - Created RoutingGraph [" << _routingGraph->getXSize()
|
||
<< "x" << _routingGraph->getYSize() << "]." << endl;
|
||
|
||
_timer.stop();
|
||
} else {
|
||
cmess2 << " - Reusing pre-existing graph." << endl;
|
||
}
|
||
|
||
_timer.resetIncrease();
|
||
_timer.start();
|
||
|
||
cmess2 << " o Selecting nets to route and create precongestion." << endl;
|
||
|
||
const unsigned int MaxDegree = 13000;
|
||
Name obstacleNetName ("obstaclenet");
|
||
|
||
forEach ( Net*, inet, getCell()->getNets() ) {
|
||
if (excludedNets.find(inet->getName()) != excludedNets.end()) {
|
||
if (NetRoutingExtension::isUnconnected(*inet))
|
||
cparanoid << " - <" << inet->getName() << "> not routed (unconnected)." << endl;
|
||
else
|
||
cparanoid << " - <" << inet->getName() << "> not routed (pre-routing found)." << endl;
|
||
continue;
|
||
}
|
||
|
||
if ( inet->isGlobal()
|
||
or inet->isSupply()
|
||
or (inet->getName() == obstacleNetName) ) {
|
||
cmess2 << " - <" << inet->getName() << "> not routed (global, supply, clock or obstacle)." << endl;
|
||
continue;
|
||
}
|
||
|
||
// We want to route nets with more than 2 and less than MaxDegree vertexes
|
||
unsigned netDegree = _routingGraph->countVertexes ( *inet );
|
||
if ( (netDegree > 1) and (netDegree < MaxDegree) ) {
|
||
Box bbox = inet->getBoundingBox();
|
||
NetRecord record ( *inet, (long int)((DbU::getLambda(bbox.getWidth())+1)*(DbU::getLambda(bbox.getHeight())+1)) );
|
||
assert( record._net );
|
||
assert( record._exArea > 0 );
|
||
|
||
_nets_to_route.push_back( record );
|
||
//#if defined(__USE_STATIC_PRECONGESTION__) || defined(__USE_DYNAMIC_PRECONGESTION__)
|
||
if (__precongestion__)
|
||
_routingGraph->UpdateEstimateCongestion( true );
|
||
//#endif
|
||
} else {
|
||
if (netDegree > MaxDegree-1)
|
||
cmess1 << Warning("%s has a not a degree in [2:%u[ (%d), not routed."
|
||
,getString(*inet).c_str(),MaxDegree,netDegree) << endl;
|
||
}
|
||
|
||
_routingGraph->resetVertexes();
|
||
}
|
||
|
||
stable_sort( _nets_to_route.begin(), _nets_to_route.end(), NetSurfacesComp() );
|
||
NetVector::iterator new_end = unique( _nets_to_route.begin(), _nets_to_route.end() );
|
||
_nets_to_route.erase( new_end, _nets_to_route.end() );
|
||
|
||
_timer.stop();
|
||
cmess2 << " - # of Nets to route:" << _nets_to_route.size() << endl;
|
||
|
||
// for ( NetRecord record : _nets_to_route ) {
|
||
// cerr << "Route: " << record._net << endl;
|
||
// }
|
||
|
||
__initialized__ = true;
|
||
}
|
||
|
||
|
||
void KnikEngine::createRoutingGrid ( unsigned nbXTiles
|
||
, unsigned nbYTiles
|
||
, const Box& boundingBox
|
||
, DbU::Unit tileWidth
|
||
, DbU::Unit tileHeight
|
||
, unsigned hcapacity
|
||
, unsigned vcapacity )
|
||
{
|
||
_routingGrid = RoutingGrid::create ( nbXTiles
|
||
, nbYTiles
|
||
, boundingBox
|
||
, tileWidth
|
||
, tileHeight
|
||
, hcapacity
|
||
, vcapacity );
|
||
}
|
||
|
||
|
||
void KnikEngine::createRoutingGraph()
|
||
// **********************************
|
||
{
|
||
_routingGraph = Graph::create ( this, _routingGrid, _benchMode, _useSegments );
|
||
|
||
//Breakpoint::stop ( 0, "Point d'arret:<br> <b>createGlobalGraph()</b> "
|
||
// "after Knik createGlobalGraph()." );
|
||
}
|
||
|
||
void KnikEngine::addRoutingPadToGraph ( RoutingPad* routingPad )
|
||
// *************************************************************
|
||
{
|
||
Vertex* rpVertex = _routingGraph->getVertex ( routingPad->getCenter() );
|
||
Contact* rpContact = rpVertex->getContact();
|
||
if ( !rpContact || (rpContact->getNet() != routingPad->getNet()) ) {
|
||
Contact* contact = Contact::create ( routingPad->getNet()
|
||
, DataBase::getDB()->getTechnology()->getLayer("metal2")
|
||
, DbU::lambda(floor(DbU::getLambda(rpVertex->getPosition().getX())))
|
||
, DbU::lambda(floor(DbU::getLambda(rpVertex->getPosition().getY())))
|
||
, rpVertex->getHalfWidth()/5
|
||
, rpVertex->getHalfHeight()/5
|
||
);
|
||
rpVertex->setContact ( contact );
|
||
}
|
||
}
|
||
|
||
Edge* KnikEngine::getEdge ( unsigned col1, unsigned row1, unsigned col2, unsigned row2 )
|
||
// *************************************************************************************
|
||
{
|
||
return _routingGraph->getEdge ( col1, row1, col2, row2 );
|
||
}
|
||
|
||
void KnikEngine::updateEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, unsigned capacity )
|
||
// ******************************************************************************************************************
|
||
{
|
||
_routingGraph->UpdateEdgeCapacity ( col1, row1, col2, row2, capacity );
|
||
}
|
||
|
||
void KnikEngine::increaseEdgeCapacity ( unsigned col1, unsigned row1, unsigned col2, unsigned row2, int capacity )
|
||
// ***************************************************************************************************************
|
||
{
|
||
_routingGraph->increaseEdgeCapacity ( col1, row1, col2, row2, capacity );
|
||
}
|
||
|
||
void KnikEngine::insertSegment ( Segment* segment )
|
||
// ************************************************
|
||
{
|
||
_routingGraph->insertSegment ( segment );
|
||
}
|
||
|
||
Vertex* KnikEngine::getVertex ( Point position )
|
||
// *********************************************
|
||
{
|
||
return _routingGraph->getVertex ( position );
|
||
}
|
||
|
||
Vertex* KnikEngine::getVertex ( DbU::Unit x, DbU::Unit y )
|
||
// *******************************************************
|
||
{
|
||
return _routingGraph->getVertex ( x, y );
|
||
}
|
||
|
||
|
||
void KnikEngine::printTime()
|
||
// *************************
|
||
{
|
||
cmess2 << " + Done in " << Timer::getStringTime(_timer.getCombTime())
|
||
<< " [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl;
|
||
cmess2 << " (raw measurements : " << _timer.getCombTime()
|
||
<< "s [+" << (_timer.getIncrease()>>10) << "Ko/"
|
||
<< (_timer.getMemorySize()>>10) << "Ko])" << endl;
|
||
|
||
|
||
}
|
||
// void KnikEngine::showEstimateOccupancy()
|
||
// // *************************************
|
||
// {
|
||
// if ( _routingGraph )
|
||
// _routingGraph->UpdateEstimateOccupancyWindow();
|
||
// }
|
||
|
||
inline bool netId_sort(Net* net1, Net* net2) { return NetExtension::getId(net1) < NetExtension::getId(net2); }
|
||
|
||
string KnikEngine::_getSolutionName() const
|
||
// ****************************************
|
||
{
|
||
return getString(_cell->getName()) + ".kgr";
|
||
}
|
||
|
||
void KnikEngine::saveSolution ( const string& fileName )
|
||
// *****************************************************
|
||
{
|
||
Name obstacleNetName ("obstaclenet");
|
||
|
||
string saveFileName = fileName;
|
||
if ( saveFileName.empty() )
|
||
saveFileName = _getSolutionName();
|
||
|
||
_nets_to_route.clear();
|
||
vector<Net*> all_nets;
|
||
forEach (Net*, net, _cell->getNets()) {
|
||
if ( net->isGlobal()
|
||
or net->isSupply()
|
||
or net->isClock()
|
||
or (net->getName() == obstacleNetName)
|
||
or not NetRoutingExtension::isAutomaticGlobalRoute(*net) ) continue;
|
||
all_nets.push_back(*net);
|
||
}
|
||
stable_sort ( all_nets.begin(), all_nets.end(), netId_sort );
|
||
|
||
CRL::IoFile saveStream ( saveFileName );
|
||
saveStream.open ("w");
|
||
FILE* saveFile = saveStream.getFile();
|
||
if ( !saveFile )
|
||
throw Error ("Cannot open solution file to write !");
|
||
|
||
const Layer* gcontact = Configuration::getGContact();
|
||
const Layer* gmetalh = Configuration::getGMetalH();
|
||
const Layer* gmetalv = Configuration::getGMetalV();
|
||
|
||
for ( size_t i=0 ; i<all_nets.size() ; ++i ) {
|
||
Net* net = all_nets[i];
|
||
long netId = NetExtension::getId ( net );
|
||
//assert ( netId >= 0 );
|
||
|
||
vector<Contact*> viaContacts;
|
||
forEach ( Contact*, icontact, net->getContacts() ) {
|
||
if ( (icontact->getLayer() == gcontact) or (icontact->getLayer() == gmetalv) )
|
||
viaContacts.push_back ( *icontact );
|
||
}
|
||
|
||
vector<Segment*> grSegments;
|
||
forEach ( Segment*, isegment, net->getSegments() ) {
|
||
if ( (isegment->getLayer() == gmetalh) or (isegment->getLayer() == gmetalv) ) {
|
||
grSegments.push_back ( *isegment );
|
||
}
|
||
}
|
||
|
||
unsigned nbEntries = grSegments.size() + viaContacts.size();
|
||
fprintf ( saveFile, "%s %ld %d\n", getString(net->getName()).c_str(), netId, nbEntries );
|
||
|
||
for ( size_t j=0 ; j<grSegments.size() ; ++j ) {
|
||
unsigned layer = (dynamic_cast<Horizontal*>(grSegments[j]))? 1 : 2;
|
||
fprintf ( saveFile, "(%d,%d,%d)-(%d,%d,%d)\n"
|
||
, (unsigned)DbU::getLambda(grSegments[j]->getSourceX())
|
||
, (unsigned)DbU::getLambda(grSegments[j]->getSourceY())
|
||
, layer
|
||
, (unsigned)DbU::getLambda(grSegments[j]->getTargetX())
|
||
, (unsigned)DbU::getLambda(grSegments[j]->getTargetY())
|
||
, layer
|
||
);
|
||
|
||
//if ( layer == 2 ) { // pour rajouter les vias de descentes aux connecteurs
|
||
// if ( segment->getSource()->getLayer() == layerGMetalV ) {
|
||
// unsigned x = (unsigned)DbU::getLambda(segment->getSourceX());
|
||
// unsigned y = (unsigned)DbU::getLambda(segment->getSourceY());
|
||
// fprintf(saveFile, "(%d,%d,1)-(%d,%d,2)\n", x, y, x, y);
|
||
// }
|
||
// if ( segment->getTarget()->getLayer() == layerGMetalV ) {
|
||
// unsigned x = (unsigned)DbU::getLambda(segment->getTargetX());
|
||
// unsigned y = (unsigned)DbU::getLambda(segment->getTargetY());
|
||
// fprintf(saveFile, "(%d,%d,1)-(%d,%d,2)\n", x, y ,x, y);
|
||
// }
|
||
//}
|
||
}
|
||
|
||
for ( size_t i=0 ; i<viaContacts.size() ; i++ ) {
|
||
Contact* contact = viaContacts[i];
|
||
fprintf ( saveFile, "(%d,%d,1)-(%d,%d,2)\n"
|
||
, (unsigned)DbU::getLambda(contact->getX())
|
||
, (unsigned)DbU::getLambda(contact->getY())
|
||
, (unsigned)DbU::getLambda(contact->getX())
|
||
, (unsigned)DbU::getLambda(contact->getY())
|
||
);
|
||
}
|
||
fprintf ( saveFile, "!\n" );
|
||
}
|
||
saveStream.close ();
|
||
}
|
||
|
||
void KnikEngine::getHorizontalCutLines ( vector<DbU::Unit>& horizontalCutLines )
|
||
// *****************************************************************************
|
||
{
|
||
_routingGraph->getHorizontalCutLines ( horizontalCutLines );
|
||
}
|
||
|
||
void KnikEngine::getVerticalCutLines ( vector<DbU::Unit>& verticalCutLines )
|
||
// *************************************************************************
|
||
{
|
||
_routingGraph->getVerticalCutLines ( verticalCutLines );
|
||
}
|
||
|
||
void KnikEngine::unrouteSelected()
|
||
// *******************************
|
||
{
|
||
// static const Layer* layerGAlu2 = NULL;
|
||
// static const Layer* layerGAlu3 = NULL;
|
||
// static const Layer* layerGCont = NULL;
|
||
// if ( !layerGAlu2 ) {
|
||
// Technology* technology = DataBase::getDB()->getTechnology();
|
||
// layerGAlu2 = technology->getLayer(Name("GALU2"));
|
||
// layerGAlu3 = technology->getLayer(Name("GALU3"));
|
||
// layerGCont = technology->getLayer(Name("GCONTACT"));
|
||
// }
|
||
|
||
// set<Segment*> segmentsToUnroute;
|
||
// CEditor* editor = getCEditor ( getCell() );
|
||
// if (editor->hasSomethingSelected() ) {
|
||
// for_each_selector ( selector, editor->getSelectors() ) {
|
||
// if ( Segment* segment = dynamic_cast<Segment*>(selector->getOccurrence().getEntity()) ) {
|
||
// Layer* layer = segment->getLayer();
|
||
// if ( (layer == layerGAlu2) || (layer == layerGAlu3) || (layer == layerGCont) ) {
|
||
// //cerr << "segment " << segment << " passes " << _routingGraph->getCongestEdgeNb(segment) << endl;
|
||
// segmentsToUnroute.insert ( segment );
|
||
// }
|
||
// }
|
||
// end_for;
|
||
// }
|
||
// }
|
||
|
||
// UpdateSession::open();
|
||
// // Previous call to recursive function
|
||
// //while ( !segmentsToUnroute.empty() ) {
|
||
// // Segment* seg = (*segmentsToUnroute.begin());
|
||
// // unroute ( seg, segmentsToUnroute );
|
||
|
||
// //}
|
||
// do {
|
||
// set<Contact*> contacts;
|
||
// while ( !segmentsToUnroute.empty() ) { // on parcourt tous les segments a derouter
|
||
// Segment* segment = (*segmentsToUnroute.begin());
|
||
// if ( !dynamic_cast<Contact*>(segment->getSource()) ) throw Error ( "unroute segment : segment's source is not a contact !" );
|
||
// if ( !dynamic_cast<Contact*>(segment->getTarget()) ) throw Error ( "unroute segment : segment's target is not a contact !" );
|
||
// // on insere les contacts source et target dans le set
|
||
// contacts.insert ( static_cast<Contact*>(segment->getSource()) );
|
||
// contacts.insert ( static_cast<Contact*>(segment->getTarget()) );
|
||
// segmentsToUnroute.erase ( segment ); // suppression du segment dans le set
|
||
// _routingGraph->removeSegment ( segment ); // il faut mettre a jour les occupations des edges dans le graph !
|
||
// segment->getSourceHook()->detach();
|
||
// segment->getTargetHook()->detach();
|
||
// segment->destroy(); // delete du segment
|
||
// }
|
||
// for ( set<Contact*>::iterator cit = contacts.begin(); cit != contacts.end() ; cit++ ) { // pour chacun des contacts du set
|
||
// Contact* contact = (*cit);
|
||
// Vertex* contactVertex = _routingGraph->getVertex(contact->getCenter());
|
||
// Hook* contactHook = contact->getBodyHook();
|
||
// bool routingPadPresent = false;
|
||
// Hook* currentHook = contactHook->getNextHook();
|
||
// // on verifie si le contact est associe a un routingPad
|
||
// while ( currentHook != contactHook ) {
|
||
// if ( dynamic_cast<RoutingPad*>(currentHook->getComponent()) ) {
|
||
// RoutingPad* rp = static_cast<RoutingPad*>(currentHook->getComponent());
|
||
// if ( _routingGraph->getVertex(rp->getCenter()) == contactVertex ) {
|
||
// routingPadPresent = true;
|
||
// break;
|
||
// }
|
||
// }
|
||
// currentHook = currentHook->getNextHook();
|
||
// }
|
||
// // si le contact est associe a un routingPad, on passe au contact suivant
|
||
// if ( routingPadPresent ) continue;
|
||
// unsigned nbSegments = contact->getSlaveComponents().getSize();
|
||
// // sinon s'il a au moins 2 segments on passe au suivant aussi
|
||
// if ( nbSegments >= 2 ) continue;
|
||
// // sinon s'il n'a qu'un segment, on ajoutele segment au set des segments a derouter
|
||
// if ( nbSegments == 1 ) {
|
||
// if ( !dynamic_cast<Segment*>(contact->getSlaveComponents().getFirst()) ) throw Error ("somthing else than a segment is on a contact ...");
|
||
// segmentsToUnroute.insert(static_cast<Segment*>(contact->getSlaveComponents().getFirst()));
|
||
// continue;
|
||
// }
|
||
// // sinon sile contact est "seul", on le delete, apres vérif tout de meme
|
||
// if ( nbSegments == 0 ) {
|
||
// contactVertex->setContact( NULL ); // pour etre surqu'on ne pointe pas sur un objet efface
|
||
// contact->destroy();
|
||
// }
|
||
// }
|
||
// } while ( !segmentsToUnroute.empty() );
|
||
// UpdateSession::close();
|
||
|
||
// editor->UnselectAll();
|
||
// editor->Refresh();
|
||
}
|
||
|
||
string KnikEngine::adaptString ( string s )
|
||
// ****************************************
|
||
{
|
||
string adapt = s;
|
||
unsigned pos = adapt.find ( '<' );
|
||
while ( pos < adapt.size() ) {
|
||
adapt.replace ( pos, 1, "<" );
|
||
pos = adapt.find ( '<', pos );
|
||
}
|
||
pos = adapt.find ( '>' );
|
||
while ( pos < adapt.size() ) {
|
||
adapt.replace ( pos, 1, ">" );
|
||
pos = adapt.find ( '>', pos );
|
||
}
|
||
return adapt;
|
||
}
|
||
|
||
void KnikEngine::unrouteOvSegments()
|
||
// *********************************
|
||
{
|
||
//cmess2 << " o Unroute overflowed segments :" << endl;
|
||
unsigned countSegments = 0;
|
||
unsigned countContacts = 0;
|
||
UpdateSession::open();
|
||
_timer.resume();
|
||
do {
|
||
set<Contact*> contacts;
|
||
while ( !_segmentsToUnroute.empty() ) { // on parcourt tous les segments a derouter
|
||
Segment* segment = (*_segmentsToUnroute.begin());
|
||
assert(segment);
|
||
if ( !dynamic_cast<Contact*>(segment->getSource()) )
|
||
throw Error ( "unroute segment : segment's source is not a contact !" );
|
||
if ( !dynamic_cast<Contact*>(segment->getTarget()) )
|
||
throw Error ( "unroute segment : segment's target is not a contact !" );
|
||
// on insere les contacts source et target dans le set
|
||
contacts.insert ( static_cast<Contact*>(segment->getSource()) );
|
||
contacts.insert ( static_cast<Contact*>(segment->getTarget()) );
|
||
_segmentsToUnroute.erase ( segment ); // suppression du segment dans le set
|
||
_routingGraph->removeSegment ( segment ); // il faut mettre a jour les occupations des edges dans le graph !
|
||
countSegments++;
|
||
segment->getSourceHook()->detach();
|
||
segment->getTargetHook()->detach();
|
||
segment->destroy(); // delete du segment
|
||
}
|
||
for ( set<Contact*>::iterator cit = contacts.begin(); cit != contacts.end() ; cit++ ) { // pour chacun des contacts du set
|
||
Contact* contact = (*cit);
|
||
Vertex* contactVertex = _routingGraph->getVertex(contact->getCenter());
|
||
Hook* contactHook = contact->getBodyHook();
|
||
bool routingPadPresent = false;
|
||
Hook* currentHook = contactHook->getNextHook();
|
||
// on verifie si le contact est associe a un routingPad
|
||
while ( currentHook != contactHook ) {
|
||
if ( dynamic_cast<RoutingPad*>(currentHook->getComponent()) ) {
|
||
RoutingPad* rp = static_cast<RoutingPad*>(currentHook->getComponent());
|
||
if ( _routingGraph->getVertex(rp->getCenter()) == contactVertex ) {
|
||
routingPadPresent = true;
|
||
break;
|
||
}
|
||
}
|
||
currentHook = currentHook->getNextHook();
|
||
}
|
||
// si le contact est associe a un routingPad, on passe au contact suivant
|
||
if ( routingPadPresent ) continue;
|
||
unsigned nbSegments = contact->getSlaveComponents().getSize();
|
||
// sinon s'il a plus de 2 segments on passe au suivant aussi
|
||
if ( nbSegments > 2 ) continue;
|
||
// s'il y a 2 segments
|
||
if ( nbSegments == 2 ) {
|
||
// s'ils sont de meme direction : on les fusionne
|
||
Segment* segment1 = NULL;
|
||
Segment* segment2 = NULL;
|
||
forEach ( Component*, component, contact->getSlaveComponents() ) {
|
||
if ( !dynamic_cast<Segment*>(*component) )
|
||
throw Error ("I did did see a pussy cat");
|
||
Segment* segment = static_cast<Segment*>(*component);
|
||
if ( !segment1 )
|
||
segment1 = segment;
|
||
else if ( !segment2 )
|
||
segment2 = segment;
|
||
else
|
||
throw Error ("Houston we've got a problem");
|
||
}
|
||
// on remove les 2 segments dans le graphe pour que les occupations et les références dans les edges soient correctes!
|
||
if ( dynamic_cast<Horizontal*>(segment1) && dynamic_cast<Horizontal*>(segment2) ) {
|
||
//cerr << "On remplace : " << segment1 << " et " << segment2 << " par:" << endl;
|
||
_routingGraph->removeSegment(segment1);
|
||
_routingGraph->removeSegment(segment2);
|
||
Horizontal* horiz1 = static_cast<Horizontal*>(segment1);
|
||
Horizontal* horiz2 = static_cast<Horizontal*>(segment2);
|
||
assert(horiz1->getNet() == horiz2->getNet());
|
||
Contact* toDel = NULL;
|
||
if ( horiz1->getSourceX() < horiz2->getSourceX() ) {
|
||
Contact* target = dynamic_cast<Contact*>(horiz2->getTarget());
|
||
toDel = dynamic_cast<Contact*>(horiz1->getTarget());
|
||
if (!target || !toDel)
|
||
throw Error ("Mummy help me !");
|
||
Hook* hook = horiz1->getTargetHook();
|
||
hook->detach();
|
||
hook->attach(target->getBodyHook());
|
||
}
|
||
else {
|
||
Contact* source = dynamic_cast<Contact*>(horiz2->getSource());
|
||
toDel = dynamic_cast<Contact*>(horiz1->getSource());
|
||
if (!source || !toDel)
|
||
throw Error ("It's not my fault");
|
||
Hook* hook = horiz1->getSourceHook();
|
||
hook->detach();
|
||
hook->attach(source->getBodyHook());
|
||
}
|
||
// il est tres important de verifier que le segment qui va etre implicitement detruit n'est pas présent dans _segmentsToUnroute !
|
||
set<Segment*>::iterator horiz2it = _segmentsToUnroute.find(horiz2);
|
||
if ( horiz2it != _segmentsToUnroute.end() ) {
|
||
//throw Error ("Implicity destroying a horizontal segment that is present in _segmentToUnroute !");
|
||
_segmentsToUnroute.erase(horiz2it); // doit-on rajouter horiz1 dans _segmentsToUnroute ?
|
||
_segmentsToUnroute.insert(horiz1); // oui puique horiz2 y était et que horiz1 remplace en partie horiz2
|
||
}
|
||
toDel->destroy(); // le segment horiz2 s'appuie sur le contact et il est donc destroy implicitement
|
||
//cerr << " " << segment1 << endl;
|
||
// on rajoute le segment1 agrandi dans le graphe, toujours pour les edges A NE FAIRE QUE SI LES SEG SONT DE MEME TYPE
|
||
_routingGraph->insertSegment(segment1);
|
||
}
|
||
else if ( dynamic_cast<Vertical*>(segment1) && dynamic_cast<Vertical*>(segment2) ) {
|
||
//cerr << "On remplace : " << segment1 << " et " << segment2 << " par:" << endl;
|
||
_routingGraph->removeSegment(segment1);
|
||
_routingGraph->removeSegment(segment2);
|
||
Vertical* verti1 = static_cast<Vertical*>(segment1);
|
||
Vertical* verti2 = static_cast<Vertical*>(segment2);
|
||
assert(verti1->getNet() == verti2->getNet());
|
||
Contact* toDel = NULL;
|
||
if ( verti1->getSourceY() < verti2->getSourceY() ) {
|
||
Contact* target = dynamic_cast<Contact*>(verti2->getTarget());
|
||
toDel = dynamic_cast<Contact*>(verti1->getTarget());
|
||
if (!target || !toDel)
|
||
throw Error ("Not again!");
|
||
Hook* hook = verti1->getTargetHook();
|
||
hook->detach();
|
||
hook->attach(target->getBodyHook());
|
||
}
|
||
else {
|
||
Contact* source = dynamic_cast<Contact*>(verti2->getSource());
|
||
toDel = dynamic_cast<Contact*>(verti1->getSource());
|
||
if (!source || !toDel)
|
||
throw Error ("Please reboot computer ... or not.");
|
||
Hook* hook = verti1->getSourceHook();
|
||
hook->detach();
|
||
hook->attach(source->getBodyHook());
|
||
}
|
||
// il est tres important de verifier que le segment qui va etre implicitement detruit n'est pas présent dans _segmentsToUnroute !
|
||
set<Segment*>::iterator verti2it = _segmentsToUnroute.find(verti2);
|
||
if ( verti2it != _segmentsToUnroute.end() ) {
|
||
//throw Error ("Implicity destroying a vertical segment that is present in _segmentToUnroute !");
|
||
_segmentsToUnroute.erase(verti2it);
|
||
_segmentsToUnroute.insert(verti1);
|
||
}
|
||
toDel->destroy(); // le segment verti2 s'appuie sur le contact et il est donc destroy implicitement
|
||
//cerr << " " << segment1 << endl;
|
||
// on rajoute le segment1 agrandi dans le graphe, toujours pour les edges A NE FAIRE QUE SI LES SEG SONT DE MEME TYPE
|
||
_routingGraph->insertSegment(segment1);
|
||
}
|
||
// sinon on continue
|
||
else
|
||
continue;
|
||
}
|
||
// sinon s'il n'a qu'un segment, on ajoute le segment au set des segments a derouter
|
||
if ( nbSegments == 1 ) {
|
||
if ( !dynamic_cast<Segment*>(contact->getSlaveComponents().getFirst()) )
|
||
throw Error ("somthing else than a segment is on a contact ...");
|
||
_segmentsToUnroute.insert(static_cast<Segment*>(contact->getSlaveComponents().getFirst())); // XXX euh oui mais s'il est déjà présent dans le set ? il se passe quoi ? XXX
|
||
continue;
|
||
}
|
||
// sinon si le contact est "seul", on le delete, apres vérif tout de meme
|
||
if ( nbSegments == 0 ) {
|
||
contactVertex->setContact( NULL ); // pour etre surqu'on ne pointe pas sur un objet efface
|
||
contact->destroy();
|
||
countContacts++;
|
||
}
|
||
}
|
||
} while ( !_segmentsToUnroute.empty() );
|
||
|
||
_timer.suspend();
|
||
//cmess2 << " + Done in " << _timer.getCombTime()
|
||
// << "s [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl;
|
||
|
||
UpdateSession::close();
|
||
//cmess2 << " - Segments destroyed : " << countSegments << endl
|
||
// << " - Contacts destroyed : " << countContacts << endl;
|
||
|
||
cmess2 << " Destroyed. Segments: " << countSegments
|
||
<< " Contacts:" << countContacts << endl;
|
||
|
||
}
|
||
|
||
void KnikEngine::unroute ( Segment* segment, set<Segment*> &segmentsToUnroute, Contact* fromContact )
|
||
// **************************************************************************************************
|
||
{
|
||
bool deleteSource = false;
|
||
bool deleteTarget = false;
|
||
if ( !dynamic_cast<Contact*>(segment->getSource()) )
|
||
throw Error ( "KnikEngine::unroute(): found a Segment not based on a Contact." );
|
||
Contact* sourceContact = static_cast<Contact*>(segment->getSource());
|
||
if ( sourceContact != fromContact ) {
|
||
Hook* contactHook = sourceContact->getBodyHook();
|
||
Hook* tempHook = contactHook->getNextHook();
|
||
Segment* firstSeg = NULL;
|
||
Segment* secondSeg = NULL;
|
||
unsigned NbSeg = 0;
|
||
bool routingPadPresent = false;
|
||
while ( tempHook != contactHook ) {
|
||
if ( dynamic_cast<Segment*>(tempHook->getComponent()) ) {
|
||
NbSeg++;
|
||
if ( NbSeg > 2 )
|
||
break; // ca sert a rien de continuer on a au moins 3 elements
|
||
if ( !firstSeg )
|
||
firstSeg = static_cast<Segment*>(tempHook->getComponent());
|
||
else
|
||
secondSeg = static_cast<Segment*>(tempHook->getComponent());
|
||
}
|
||
if ( dynamic_cast<RoutingPad*>(tempHook->getComponent()) ) {
|
||
routingPadPresent = true;
|
||
break;
|
||
}
|
||
|
||
tempHook = tempHook->getNextHook();
|
||
}
|
||
if ( !routingPadPresent && (NbSeg == 2) ) { // on doit "unroute" l'autre segment aussi
|
||
if ( firstSeg == segment )
|
||
unroute ( secondSeg, segmentsToUnroute, sourceContact );
|
||
else if ( secondSeg == segment )
|
||
unroute ( firstSeg, segmentsToUnroute, sourceContact );
|
||
else
|
||
throw Error ("KnikEngine::unroute(): Wow how did I do that!");
|
||
deleteSource = true;
|
||
}
|
||
}
|
||
if ( !dynamic_cast<Contact*>(segment->getTarget()) )
|
||
throw Error ( "KnikEngine::unroute(): found a Segment not based on a Contact." );
|
||
Contact* targetContact = static_cast<Contact*>(segment->getTarget());
|
||
if ( targetContact != fromContact ) {
|
||
Hook* contactHook = targetContact->getBodyHook();
|
||
Hook* tempHook = contactHook->getNextHook();
|
||
Segment* firstSeg = NULL;
|
||
Segment* secondSeg = NULL;
|
||
unsigned NbSeg = 0;
|
||
bool routingPadPresent = false;
|
||
while ( tempHook != contactHook ) {
|
||
if ( Segment* seg = dynamic_cast<Segment*>(tempHook->getComponent()) ) {
|
||
NbSeg++;
|
||
if ( NbSeg > 2 )
|
||
break; // ca sert a rien de continuer on a au moins 3 <20>l<EFBFBD>ments
|
||
if ( !firstSeg )
|
||
firstSeg = seg;
|
||
else
|
||
secondSeg = seg;
|
||
}
|
||
if ( dynamic_cast<RoutingPad*>(tempHook->getComponent()) ) {
|
||
routingPadPresent = true;
|
||
break;
|
||
}
|
||
|
||
tempHook = tempHook->getNextHook();
|
||
}
|
||
if ( !routingPadPresent && (NbSeg == 2) ) { // on doit "unroute" l'autre segment aussi
|
||
if ( firstSeg == segment )
|
||
unroute ( secondSeg, segmentsToUnroute, targetContact );
|
||
else if ( secondSeg == segment )
|
||
unroute ( firstSeg, segmentsToUnroute, targetContact );
|
||
else
|
||
throw Error ("KnikEngine::unroute(): Once again, how did I do that!");
|
||
deleteTarget = true;
|
||
}
|
||
}
|
||
segmentsToUnroute.erase ( segment );
|
||
_routingGraph->removeSegment ( segment ); // il faut mettre a jour les occupations des edges dans le graph !
|
||
segment->getSourceHook()->detach();
|
||
segment->getTargetHook()->detach();
|
||
segment->destroy();
|
||
if ( deleteSource )
|
||
sourceContact->destroy();
|
||
if ( deleteTarget )
|
||
targetContact->destroy();
|
||
}
|
||
|
||
void KnikEngine::computeOverflow()
|
||
// *******************************
|
||
{
|
||
//cmess1 << " o Computing Statistics" << endl;
|
||
Vertex* currentVertex = _routingGraph->getLowerLeftVertex();
|
||
int nbEdgesTotal = 0;
|
||
int nbEdgesOver = 0;
|
||
|
||
unsigned overflow = 0;
|
||
unsigned maxOver = 0;
|
||
//float maxOver = 0;
|
||
//float averageOver = 0;
|
||
while ( currentVertex ) {
|
||
Vertex* firstLineVertex = currentVertex;
|
||
while ( currentVertex ) {
|
||
Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
||
if ( hEdgeOut ) {
|
||
nbEdgesTotal++;
|
||
int ov = 2*(hEdgeOut->getRealOccupancy() - hEdgeOut->getCapacity()); // 2 = minimum spacing + minimum width
|
||
if ( ov > 0 ) {
|
||
nbEdgesOver++;
|
||
overflow += ov;
|
||
maxOver = (unsigned)ov > maxOver ? ov : maxOver;
|
||
}
|
||
for_each_segment ( segment, hEdgeOut->getSegments() ) {
|
||
map<Segment*,SegRecord>::iterator ssit = _segmentOverEdges.find ( segment );
|
||
SegRecord record;
|
||
if ( ssit != _segmentOverEdges.end() )
|
||
record = (*ssit).second;
|
||
else
|
||
record = SegRecord();
|
||
|
||
record.incNbTotEdges();
|
||
if ( ov > 0 ) {
|
||
record.incNbOvEdges();
|
||
record.incSumOv ( ov );
|
||
record.UpdateMaxOv ( ov );
|
||
}
|
||
end_for;
|
||
}
|
||
}
|
||
if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() ) {
|
||
nbEdgesTotal++;
|
||
int ov = 2*(vEdgeOut->getRealOccupancy() - vEdgeOut->getCapacity());
|
||
if ( ov > 0 ) {
|
||
nbEdgesOver++;
|
||
overflow += ov;
|
||
maxOver = (unsigned)ov > maxOver ? ov : maxOver;
|
||
}
|
||
for_each_segment ( segment, vEdgeOut->getSegments() ) {
|
||
map<Segment*,SegRecord>::iterator ssit = _segmentOverEdges.find ( segment );
|
||
SegRecord record;
|
||
if ( ssit != _segmentOverEdges.end() )
|
||
record = (*ssit).second;
|
||
else
|
||
record = SegRecord();
|
||
|
||
record.incNbTotEdges();
|
||
if ( ov > 0 ) {
|
||
record.incNbOvEdges();
|
||
record.incSumOv ( ov );
|
||
record.UpdateMaxOv ( ov );
|
||
}
|
||
end_for;
|
||
}
|
||
}
|
||
|
||
if ( hEdgeOut )
|
||
currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
||
else
|
||
break;
|
||
}
|
||
Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
||
if ( vEdgeOut )
|
||
currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
||
else
|
||
break;
|
||
}
|
||
//cmess2 << " - first skimming through edges done (overflow computed)" << endl;
|
||
//averageOver = nbEdgesOver == 0 ? 0 : averageOver / (float)nbEdgesOver;
|
||
|
||
// Now we've got the max we can print more detailed statistics about edges overflow
|
||
// except if there is no overflow...
|
||
vector<unsigned> ovEdgesStats;
|
||
if ( maxOver ) {
|
||
Vertex* currentVertex = _routingGraph->getLowerLeftVertex();
|
||
unsigned maxOvIdx = maxOver / (int)(10);
|
||
ovEdgesStats.resize(maxOvIdx+1);
|
||
while ( currentVertex ) {
|
||
Vertex* firstLineVertex = currentVertex;
|
||
while ( currentVertex ) {
|
||
Edge* hEdgeOut = currentVertex->getHEdgeOut();
|
||
if ( hEdgeOut ) {
|
||
int ov = 2*(hEdgeOut->getRealOccupancy() - hEdgeOut->getCapacity()); // 2 = minimum sapcing + minimum width
|
||
if ( ov > 0 ) {
|
||
unsigned ovIdx = ov / int(10);
|
||
ovEdgesStats[ovIdx]++;
|
||
}
|
||
}
|
||
if ( Edge* vEdgeOut = currentVertex->getVEdgeOut() ) {
|
||
int ov = 2*(vEdgeOut->getRealOccupancy() - vEdgeOut->getCapacity());
|
||
if ( ov > 0 ) {
|
||
unsigned ovIdx = ov / int(10);
|
||
ovEdgesStats[ovIdx]++;
|
||
}
|
||
}
|
||
|
||
if ( hEdgeOut )
|
||
currentVertex = hEdgeOut->getOpposite ( currentVertex );
|
||
else
|
||
break;
|
||
}
|
||
Edge* vEdgeOut = firstLineVertex->getVEdgeOut();
|
||
if ( vEdgeOut )
|
||
currentVertex = vEdgeOut->getOpposite ( firstLineVertex );
|
||
else
|
||
break;
|
||
}
|
||
//cmess2 << " - second skimming through edges done (overflow details)" << endl;
|
||
}
|
||
|
||
unsigned _wirelength = 0;
|
||
unsigned _gridWirelength = 0;
|
||
unsigned _gridWirelengthWoVia = 0;
|
||
Layer* layerContact = DataBase::getDB()->getTechnology()->getLayer(Name("GCONTACT"));
|
||
//for ( unsigned i = 0 ; i < _nets_to_route.size() ; i++ ) {
|
||
// Net* net = _nets_to_route[i]._net;
|
||
forEach ( Net*, net, _cell->getNets() ) {
|
||
unsigned netWirelength = 0;
|
||
for_each_segment ( segment, net->getSegments() ) {
|
||
_wirelength += (unsigned)DbU::getLambda ( segment->getLength() );
|
||
unsigned gridWirelength = _routingGraph->getGridLength ( segment );
|
||
_gridWirelength += gridWirelength;
|
||
_gridWirelengthWoVia += gridWirelength;
|
||
netWirelength += gridWirelength;
|
||
end_for;
|
||
}
|
||
for_each_contact ( contact, net->getContacts() ) {
|
||
if ( contact->getLayer() == layerContact ) {
|
||
_gridWirelength += 3;
|
||
netWirelength += 3;
|
||
}
|
||
end_for;
|
||
}
|
||
NetExtension::setWireLength ( *net, netWirelength );
|
||
}
|
||
//cmess2 << " - Wirelength computed" << endl;
|
||
// *** Cannot build column several times, no hasColumn function ***
|
||
// CEditor* editor = getCEditor ( getCell() );
|
||
// CNetListWindow* netListWindow = editor->getNetListWindow();
|
||
// if ( ! netListWindow->hasColumn ( "GridWirelength" ) ) {
|
||
// netListWindow->addColumn ( "GridWirelength", getNetWirelength, NetExtension::compare, CListWidget::RightJustify );
|
||
// netListWindow->Rebuild();
|
||
// }
|
||
// cmess2 << " - Netlist window rebuild" << endl;
|
||
// cmess1 << " - Total number of edges : " << nbEdgesTotal << endl
|
||
// cmess1 << " - Number of overcapacity edges : " << nbEdgesOver << " / " << nbEdgesTotal << 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
|
||
// << " - # of overflow : " << overflow << endl
|
||
// << " - max of overflow : " << maxOver << endl;
|
||
// // << " - # of net with overflow : " << _netNbOverEdges.size() << endl
|
||
// cmess1 << " - grid wirelength : " << _gridWirelength << endl;
|
||
// cmess2 << " - grid wirelength : " << _gridWirelength << endl
|
||
// << " - grid wirelength w/o via : " << _gridWirelengthWoVia << endl
|
||
// << " - real wirelength : " << _wirelength << endl;
|
||
|
||
//if ( ! ovEdgesStats.empty() ) {
|
||
// // print details about edges overflow
|
||
// cmess2 << endl
|
||
// << " - Number of edges for overflow interval :" << endl;
|
||
// for ( unsigned i = 0 ; i < ovEdgesStats.size() ; i++ ) {
|
||
// unsigned first = i*10;
|
||
// unsigned second = (i+1)*10 > maxOver ? maxOver : (i+1)*10;
|
||
// cmess2 << " - " << first << " - " << second << " : " << ovEdgesStats[i] << endl;
|
||
// }
|
||
//}
|
||
|
||
return;
|
||
}
|
||
|
||
// void KnikEngine::showOccupancy()
|
||
// // *****************************
|
||
// {
|
||
// if ( _routingGraph )
|
||
// _routingGraph->UpdateOccupancyWindow();
|
||
// }
|
||
|
||
void KnikEngine::run( const map<Name,Net*>& excludedNets )
|
||
// *******************************************************
|
||
{
|
||
Route( excludedNets );
|
||
bool done = analyseRouting();
|
||
while ( !done ) {
|
||
unrouteOvSegments();
|
||
reroute();
|
||
done = analyseRouting();
|
||
}
|
||
|
||
ostringstream result;
|
||
|
||
result << Timer::getStringTime(_timer.getCombTime())
|
||
<< ", " << Timer::getStringMemory(_timer.getIncrease());
|
||
cmess1 << " o Global Routing Completed." << endl;
|
||
cmess1 << Dots::asString( " - Done in", result.str() ) << endl;
|
||
|
||
addMeasure<double> ( getCell(), "knikT", _timer.getCombTime () );
|
||
addMeasure<size_t> ( getCell(), "knikS", (_timer.getMemorySize() >> 20) );
|
||
|
||
computeSymbolicWireLength ();
|
||
}
|
||
|
||
void KnikEngine::Route( const map<Name,Net*>& excludedNets )
|
||
// *********************************************************
|
||
{
|
||
UpdateSession::open();
|
||
if ( !__initialized__ )
|
||
initGlobalRouting( excludedNets );
|
||
|
||
_timer.resetIncrease();
|
||
_timer.start();
|
||
|
||
cmess1 << " o Global Routing." << endl;
|
||
cmess2 << " Iteration INIT"
|
||
<< " # of nets to route:" << left << _nets_to_route.size() << endl;
|
||
|
||
// initializing netStamp for routingGraph:
|
||
//_routingGraph->setNetStamp(1); // Maybe NetStamp should not be initialized here !
|
||
// Be aware that initializingthe NetStamp in the construction of the routingGraph, might be a bad idea, if a lotof rerouting processes are run, it may overpass the unsigne limit (really ?)
|
||
|
||
Name nameDebug ("ck_dpt");
|
||
unsigned size = _nets_to_route.size();
|
||
for ( unsigned i = 0 ; i < size ; i++ ) {
|
||
Net* net = _nets_to_route[i]._net;
|
||
assert ( net );
|
||
|
||
//_routingGraph->checkGraphConsistency();
|
||
switch ( _routingGraph->initRouting ( net ) ) {
|
||
case 0:
|
||
case 1:
|
||
//cerr << "Nothing to global route" << endl;
|
||
break;
|
||
case 2:
|
||
//_routingGraph->Monotonic();
|
||
//break;
|
||
default:
|
||
_routingGraph->Dijkstra();
|
||
break;
|
||
}
|
||
|
||
_routingGraph->incNetStamp();
|
||
_routingGraph->CleanRoutingState();
|
||
//cmess1 << " - [";
|
||
//cmess1.width(3);
|
||
//cmess1 << floor((float)(i*100)/(float)(size));
|
||
//cmess1 << "%]\r";
|
||
}
|
||
_timer.suspend();
|
||
|
||
cmess2 << " Elapsed time: " << _timer.getCombTime()
|
||
<< " Memory: " << Timer::getStringMemory(_timer.getIncrease()) << endl;
|
||
|
||
// Comment to test with transhierarchic MIPS
|
||
//computeOverflow();
|
||
|
||
// To be able to plot congestionMap, we need to UpdateMaxEstimateCongestion :
|
||
//_routingGraph->UpdateMaxEstimateCongestion(); // no more useful since qe use QT which allow to see colored edges.
|
||
|
||
// passage en mode PERFORMANCE !
|
||
//_routingGraph->testSTuplePQ();
|
||
|
||
// While not debugging, comment this out :
|
||
//_routingGraph->destroy();
|
||
UpdateSession::close();
|
||
|
||
_routingDone = true;
|
||
}
|
||
|
||
bool KnikEngine::analyseRouting()
|
||
// ******************************
|
||
{
|
||
//computeOverflow();
|
||
if (_routingDone)
|
||
_timer.resume();
|
||
else {
|
||
_timer.resetIncrease();
|
||
_timer.start();
|
||
}
|
||
|
||
unsigned overflow = _routingGraph->analyseRouting (_segmentsToUnroute);
|
||
//cmess2 << " - Segments to unroute : " << _segmentsToUnroute.size() << endl;
|
||
|
||
// redefine the new _nets_to_route vector
|
||
_nets_to_route.clear();
|
||
|
||
for ( set<Segment*>::iterator it = _segmentsToUnroute.begin() ; it != _segmentsToUnroute.end() ; it++ ) {
|
||
//cmess2 << " "<< (*it) << endl;
|
||
Net* net = (*it)->getNet();
|
||
|
||
bool present = false;
|
||
for ( unsigned i = 0 ; i < _nets_to_route.size() ; i++ ) {
|
||
if ( _nets_to_route[i]._net == net ) {
|
||
present = true;
|
||
break;
|
||
}
|
||
}
|
||
if ( !present ) {
|
||
Box bbox = net->getBoundingBox();
|
||
NetRecord record ( net, (long int)((DbU::getLambda(bbox.getWidth())+1)*(DbU::getLambda(bbox.getHeight())+1)) );
|
||
_nets_to_route.push_back ( record );
|
||
}
|
||
}
|
||
|
||
// Il est nécessaire de retrier les nets à rerouter de façon uqe le Dijkstra soit optimisé
|
||
stable_sort ( _nets_to_route.begin(), _nets_to_route.end(), NetSurfacesComp() );
|
||
|
||
NetVector::iterator new_end = unique ( _nets_to_route.begin(), _nets_to_route.end() );
|
||
_nets_to_route.erase ( new_end, _nets_to_route.end() );
|
||
|
||
//cmess1 << " - Nets to reroute : " << _nets_to_route.size() << endl;
|
||
//cmess1 << " ";
|
||
//for ( unsigned i = 0 ; i < _nets_to_route.size() ; i++ )
|
||
// cmess1 << _nets_to_route[i]._net->getName() << "|";
|
||
//cmess1 << endl;
|
||
|
||
_timer.suspend();
|
||
// cmess1 << " + Done in " << _timer.getCombTime()
|
||
// << "s [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl;
|
||
|
||
bool done = false;
|
||
if ( (overflow==0) || (_timer.getCombTime() >= MAX_RUNTIME) || (_rerouteIteration >= MAX_ITERATION) )
|
||
done = true;
|
||
return done;
|
||
}
|
||
|
||
void KnikEngine::reroute()
|
||
// ***********************
|
||
{
|
||
UpdateSession::open();
|
||
|
||
//Breakpoint::setStopLevel(1);
|
||
//analyseRouting();
|
||
//unrouteOvSegments();
|
||
|
||
cmess2 << " Iteration " << right << setw(4) << setfill('0') << ++_rerouteIteration
|
||
<< " # of nets to route:" << left << _nets_to_route.size() << endl;
|
||
|
||
_timer.resume();
|
||
|
||
unsigned int size = _nets_to_route.size();
|
||
__ripupMode__ = true;
|
||
|
||
for ( unsigned i = 0 ; i < size ; ++i ) {
|
||
Net* net = _nets_to_route[i]._net;
|
||
assert( net );
|
||
//_routingGraph->checkGraphConsistency();
|
||
|
||
switch ( _routingGraph->initRouting(net) ) {
|
||
case 0:
|
||
case 1:
|
||
//cerr << "Nothing to global route" << endl;
|
||
break;
|
||
default:
|
||
_routingGraph->Dijkstra();
|
||
break;
|
||
}
|
||
|
||
_routingGraph->incNetStamp();
|
||
_routingGraph->CleanRoutingState();
|
||
}
|
||
|
||
_timer.suspend();
|
||
|
||
cmess2 << " Elapsed time: " << _timer.getCombTime()
|
||
<< " Memory: " << Timer::getStringMemory(_timer.getIncrease()) << endl;
|
||
|
||
// cmess2 << " + Done in " << _timer.getCombTime()
|
||
// << " [+" << Timer::getStringMemory(_timer.getIncrease()) << "]." << endl;
|
||
// cmess2 << " (raw measurements : " << _timer.getCombTime()
|
||
// << "s [+" << (_timer.getIncrease()>>10) << "Ko/"
|
||
// << (_timer.getMemorySize()>>10) << "Ko])" << endl;
|
||
|
||
// Comment to test with transhierarchic MIPS
|
||
//computeOverflow();
|
||
|
||
// While not debugging, comment this out :
|
||
//_routingGraph->destroy();
|
||
UpdateSession::close();
|
||
|
||
}
|
||
|
||
|
||
void KnikEngine::computeSymbolicWireLength ()
|
||
{
|
||
if (not _routingGauge)
|
||
throw Error( "KnikEngine::computeSymbolicWireLength(): The routing gauge has not been set." );
|
||
|
||
size_t hEdgeCapacity = 0;
|
||
size_t vEdgeCapacity = 0;
|
||
DbU::Unit gcellSide = DbU::fromLambda( 50.0 );
|
||
|
||
vector<RoutingLayerGauge*>::const_iterator ilayerGauge = _routingGauge->getLayerGauges().begin();
|
||
for ( ; ilayerGauge != _routingGauge->getLayerGauges().end() ; ++ilayerGauge ) {
|
||
RoutingLayerGauge* layerGauge = (*ilayerGauge);
|
||
if (layerGauge->getType() != Constant::Default) continue;
|
||
if (layerGauge->getDepth() > _allowedDepth) continue;
|
||
|
||
if (layerGauge->getDirection() == Constant::Horizontal) {
|
||
hEdgeCapacity += layerGauge->getTrackNumber( 0, gcellSide ) - 1;
|
||
} else if ( layerGauge->getDirection() == Constant::Vertical ) {
|
||
vEdgeCapacity += layerGauge->getTrackNumber( 0, gcellSide ) - 1;
|
||
}
|
||
}
|
||
|
||
// Complete formula: unitarian Wirelength/Area for one GCell.
|
||
// (side*(hEdgeCapacity+vEdgeCapacity)) / (side * side).
|
||
const double normalize = ((double)(hEdgeCapacity+vEdgeCapacity)) / DbU::toLambda(gcellSide);
|
||
unsigned long long symbolicWireLength = 0;
|
||
|
||
forEach ( Net*, net, getCell()->getNets() ) {
|
||
if ( net->isGlobal()
|
||
or net->isSupply()
|
||
or net->isClock() ) {
|
||
continue;
|
||
}
|
||
|
||
forEach ( Segment*, isegment, net->getSegments() ) {
|
||
symbolicWireLength += (unsigned long long)DbU::getLambda ( isegment->getLength() );
|
||
}
|
||
}
|
||
|
||
addMeasure<unsigned long long> ( getCell(), "GWL(l)", symbolicWireLength, 14 );
|
||
|
||
Box ab ( getCell()->getAbutmentBox() );
|
||
double area = (DbU::getLambda(ab.getWidth()) * DbU::getLambda(ab.getHeight()) );
|
||
|
||
addMeasure<double> ( getCell(), "Area(l2)", area, 14 );
|
||
addMeasure<double> ( getCell(), "Sat." , (symbolicWireLength/area)/normalize );
|
||
}
|
||
|
||
|
||
Record* KnikEngine::_getRecord() const
|
||
// *****************************
|
||
{
|
||
Record* record = Inherit::_getRecord();
|
||
|
||
if ( !record )
|
||
record = new Record ( getString ( this ) );
|
||
|
||
record->add ( getSlot ( "RoutingGraph", _routingGraph ) );
|
||
|
||
return record;
|
||
}
|
||
|
||
KnikEngine* KnikEngine::get (const Cell* cell )
|
||
// ********************************************
|
||
{
|
||
return ( dynamic_cast<KnikEngine*> ( ToolEngine::get ( cell, KnikEngine::staticGetName() ) ) );
|
||
}
|
||
|
||
} // namespace Knik
|
||
|
||
|
||
// *********************************************************************
|
||
// Copyright (C) UPMC/LIP6/ASIM 2003-2004 All rights reserved
|
||
// *********************************************************************
|