2010-06-13 16:06:23 -05:00
|
|
|
|
|
|
|
|
|
// This file is part of the Coriolis Project.
|
|
|
|
|
// Copyright (C) Laboratoire LIP6 - Departement ASIM
|
|
|
|
|
// Universite Pierre et Marie Curie
|
|
|
|
|
//
|
|
|
|
|
// Main contributors :
|
|
|
|
|
// Christophe Alexandre <Christophe.Alexandre@lip6.fr>
|
|
|
|
|
// Hugo Cl<43>ment <Hugo.Clement@lip6.fr>
|
|
|
|
|
// Jean-Paul Chaput <Jean-Paul.Chaput@lip6.fr>
|
|
|
|
|
// Christian Masson <Christian.Masson@lip6.fr>
|
|
|
|
|
//
|
|
|
|
|
// The Coriolis Project is free software; you can redistribute it and/or
|
|
|
|
|
// modify it under the terms of the GNU General Public License as
|
|
|
|
|
// published by the Free Software Foundation; either version 2 of the
|
|
|
|
|
// License, or (at your option) any later version.
|
|
|
|
|
//
|
|
|
|
|
// The Coriolis Project is distributed in the hope that it will be useful,
|
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
|
// General Public License for more details.
|
|
|
|
|
//
|
|
|
|
|
// You should have received a copy of the GNU General Public License
|
|
|
|
|
// along with the Coriolis Project; if not, write to the Free Software
|
|
|
|
|
// Foundation, inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
|
|
|
|
//
|
|
|
|
|
//
|
|
|
|
|
// License-Tag
|
|
|
|
|
//
|
|
|
|
|
// Date : 29/01/2004
|
|
|
|
|
// Author : Christophe Alexandre <Christophe.Alexandre@lip6.fr>
|
|
|
|
|
//
|
|
|
|
|
// Authors-Tag
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <cmath>
|
|
|
|
|
using namespace std;
|
|
|
|
|
|
2010-06-18 09:14:33 -05:00
|
|
|
|
#include "vlsisapd/configuration/Configuration.h"
|
2010-06-13 16:06:23 -05:00
|
|
|
|
#include "hurricane/Warning.h"
|
|
|
|
|
#include "hurricane/Net.h"
|
|
|
|
|
#include "hurricane/Instance.h"
|
|
|
|
|
#include "hurricane/Plug.h"
|
|
|
|
|
#include "hurricane/Timer.h"
|
|
|
|
|
#include "crlcore/ToolBox.h"
|
|
|
|
|
#include "crlcore/AllianceFramework.h"
|
|
|
|
|
using namespace CRL;
|
|
|
|
|
|
|
|
|
|
#include "nimbus/NimbusEngine.h"
|
|
|
|
|
using namespace Nimbus;
|
|
|
|
|
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
#include "metis/MetisGraph.h"
|
|
|
|
|
#endif
|
|
|
|
|
#include "metis/MetisEngine.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace Metis {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Name MetisEngine::_toolName = "Metis";
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MetisEngine::MetisEngine ( Cell* cell )
|
|
|
|
|
: Inherit (cell)
|
2010-06-18 09:14:33 -05:00
|
|
|
|
, _configuration(new Configuration())
|
2010-06-13 16:06:23 -05:00
|
|
|
|
, _step (0)
|
2014-12-09 16:49:46 -06:00
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
2010-06-13 16:06:23 -05:00
|
|
|
|
, _actualGraphs ()
|
|
|
|
|
, _newGraphs ()
|
2014-12-09 16:49:46 -06:00
|
|
|
|
#endif
|
2010-06-13 16:06:23 -05:00
|
|
|
|
, _globalEdgeCut(0)
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
|
|
|
|
|
NimbusEngine* nimbus = NimbusEngine::get ( getCell() );
|
|
|
|
|
if ( nimbus == NULL )
|
|
|
|
|
throw Error ("Nimbus must be created before Metis, on cell <%s>"
|
|
|
|
|
,getString(getCell()->getName()).c_str());
|
|
|
|
|
|
|
|
|
|
_actualGraphs = new MetisGraphs();
|
|
|
|
|
_newGraphs = new MetisGraphs();
|
|
|
|
|
_actualGraphs->push_back ( new MetisGraph(this,nimbus->getGrid()->getRoot()) );
|
|
|
|
|
|
|
|
|
|
// What the fuck does this loop do?
|
|
|
|
|
// forEach ( Net*, inet, getCell()->getNets() ) {
|
|
|
|
|
// if ( inet->isGlobal() ) continue;
|
|
|
|
|
// if ( inet->isSupply() ) continue;
|
|
|
|
|
// }
|
|
|
|
|
#endif // HAVE_HMETIS_LIB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MetisEngine::~MetisEngine ()
|
|
|
|
|
{ delete _configuration; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MetisEngine* MetisEngine::create ( Cell* cell )
|
|
|
|
|
{
|
|
|
|
|
MetisEngine* metis = new MetisEngine(cell);
|
|
|
|
|
|
|
|
|
|
metis->_postCreate();
|
|
|
|
|
return metis;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MetisEngine::_preDestroy ()
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
for (MetisGraphs::iterator mgit = _actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit)
|
|
|
|
|
delete *mgit;
|
|
|
|
|
for (MetisGraphs::iterator mgit = _newGraphs->begin(); mgit != _newGraphs->end(); ++mgit)
|
|
|
|
|
delete *mgit;
|
|
|
|
|
|
|
|
|
|
delete _actualGraphs;
|
|
|
|
|
delete _newGraphs;
|
|
|
|
|
#endif // HAVE_HMETIS_LIB
|
|
|
|
|
Inherit::_preDestroy();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool MetisEngine::isHMetisCapable ()
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
ExtensionCap support and source/target terminal flags in Katabatic & Kite.
Placement management:
* Change: In <metis>, always disable the hMetis support regardless of
it being detected or not as the placer is still unable manage the
final bin contents.
Routing gauge management:
* Bug: In CRL Core, <vsclib/alliance.conf>, set the correct pitches and
size for the routing layers and the cell gauge.
* Change: In Katabatic & Kite, extract the correct extension cap for each
routing layer from the layers characteristics (cache then in
Katabatic::Configuration).
* Change: In Katabatic, <AutoSegment>, create segment with the wire width
defined in the gauge. For AutoSegment created on already existing
Segment from the global routing, adjust the width.
* Change: In Katabatic, <AutoSegment>, more accurate information about how
a segment is connected to terminal via source and/or target.
The flag SegStrongTerminal is splitted into SegSourceTerminal and
SegSourceTarget (but still used as a mask). So now we can know by
which end an AutoSegment is connected to a terminal.
* Change: In Katabatic, ::doRp_Access(), create constraint freeing segments
not only when HSmall but also when VSmall (more critical for <vsclib>).
Otherwise we may see AutoSegments with incompatible source/target
constraints.
* Change: In Kite, BuildPowerRails, do not create blockage on PinOnly
layers *but* still create power rails planes. This is a temporary
workaround for <vsclib> where the METAL1 blockages overlaps the
terminals (it was fine for Nero, but they shouldn't for Kite).
* Change: In Kite, <RoutingEvent>, if a TrackSegment is overconstrained,
directly bybass it's slackening state to DataNegociate::Slacken.
Also rename the flag "_canHandleConstraints" to "_overConstrained",
seems clearer to me.
Miscellaneous:
* Change: In CRL Core, <Utilities>, add a "pass-though" capability on the
mstream to temporarily make them print everything.
2014-05-25 08:00:35 -05:00
|
|
|
|
return false;
|
2010-06-13 16:06:23 -05:00
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif // HAVE_HMETIS_LIB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Record* MetisEngine::_getRecord () const
|
|
|
|
|
{
|
|
|
|
|
Record* record = Inherit::_getRecord();
|
|
|
|
|
if (record) {
|
|
|
|
|
record->add ( getSlot("step", _step) );
|
|
|
|
|
}
|
|
|
|
|
return record;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MetisEngine::run ()
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
cmess2 << " o hMetis quadri-partition step." << endl;
|
|
|
|
|
|
|
|
|
|
Timer timer;
|
|
|
|
|
timer.start();
|
|
|
|
|
|
|
|
|
|
NimbusEngine* nimbus = NimbusEngine::get ( getCell() );
|
|
|
|
|
|
|
|
|
|
forEach ( GCell*, igcell, nimbus->getPlacementLeaves() ) {
|
|
|
|
|
if ( not igcell->hasSubGCells() )
|
|
|
|
|
throw Warning("You must first progress in Nimbus before calling Metis");
|
|
|
|
|
|
|
|
|
|
if ( igcell->getSubGCells().getSize() < 2 )
|
|
|
|
|
throw Error("Metis needs at least 2 Nimbus subboxes");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
_globalEdgeCut = 0;
|
|
|
|
|
|
|
|
|
|
linefill output (" ",cmess2);
|
|
|
|
|
|
|
|
|
|
for ( MetisGraphs::iterator mgit = _actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit ) {
|
|
|
|
|
MetisGraph* graph = *mgit;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
_globalEdgeCut += graph->part ( output );
|
|
|
|
|
}
|
|
|
|
|
catch ( MetisGraph::TooLowNVTXSException& e ) {
|
2010-06-22 09:09:20 -05:00
|
|
|
|
if ( cmess2.enabled() ) cerr << "\n";
|
2010-06-13 16:06:23 -05:00
|
|
|
|
cerr << Warning("Impossible to part graph, only %d nodes",e._nvtxs);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for ( size_t id=0; id < graph->_partResultVector.size(); ++id ) {
|
|
|
|
|
_newGraphs->push_back
|
|
|
|
|
( new MetisGraph(this
|
|
|
|
|
,graph
|
|
|
|
|
,graph->_partResultVector[id]->first
|
|
|
|
|
,graph->_partResultVector[id]->second
|
|
|
|
|
) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-22 09:09:20 -05:00
|
|
|
|
output << "\n";
|
2010-06-13 16:06:23 -05:00
|
|
|
|
|
|
|
|
|
for ( MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit )
|
|
|
|
|
delete *mgit;
|
|
|
|
|
delete _actualGraphs;
|
|
|
|
|
|
|
|
|
|
_actualGraphs = _newGraphs;
|
|
|
|
|
_newGraphs = new MetisGraphs ();
|
|
|
|
|
|
|
|
|
|
save ( ++_step );
|
|
|
|
|
|
|
|
|
|
timer.stop();
|
|
|
|
|
cmess2 << " - Refine placement done in " << getString(timer.getUserTime()) << "s." << endl;
|
|
|
|
|
|
|
|
|
|
if ( getRefreshCb() != NULL ) getRefreshCb() ();
|
|
|
|
|
#else
|
|
|
|
|
throw Warning ( "hmetis library is needed to use Metis ToolEngine" );
|
|
|
|
|
#endif // HAVE_HMETIS_LIB
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MetisEngine::save ( unsigned step )
|
|
|
|
|
{
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
//for ( MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit)
|
|
|
|
|
// (*mgit)->save ( step );
|
|
|
|
|
grabPlacementModificationFlag ();
|
|
|
|
|
#else
|
|
|
|
|
throw Warning ( "hmetis library is needed to use Metis ToolEngine" );
|
|
|
|
|
#endif /* HAVE_HMETIS_LIB */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
int MetisEngine::getGlobalEdgeCut () const
|
|
|
|
|
{ return _globalEdgeCut; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Name& MetisEngine::staticGetName ()
|
|
|
|
|
{ return _toolName; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const Name& MetisEngine::getName () const
|
|
|
|
|
{ return _toolName; }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
MetisEngine* MetisEngine::get ( Cell* cell )
|
|
|
|
|
{ return dynamic_cast<MetisEngine*> ( ToolEngine::get(cell,_toolName) ); }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
bool MetisEngine::_reInit()
|
|
|
|
|
{
|
|
|
|
|
#if 0
|
|
|
|
|
#ifdef HAVE_HMETIS_LIB
|
|
|
|
|
for (MetisGraphs::iterator mgit=_actualGraphs->begin(); mgit != _actualGraphs->end(); ++mgit)
|
|
|
|
|
delete *mgit;
|
|
|
|
|
for (MetisGraphs::iterator mgit=_newGraphs->begin(); mgit != _newGraphs->end(); ++mgit)
|
|
|
|
|
delete *mgit;
|
|
|
|
|
|
|
|
|
|
delete _actualGraphs;
|
|
|
|
|
delete _newGraphs;
|
|
|
|
|
|
|
|
|
|
_actualGraphs = new MetisGraphs();
|
|
|
|
|
_newGraphs = new MetisGraphs();
|
|
|
|
|
|
|
|
|
|
NimbusEngine* nimbus = NimbusEngine::get ( getCell() );
|
|
|
|
|
bool partToBeDone = false;
|
|
|
|
|
|
|
|
|
|
forEach ( GCell*, igcell, nimbus->getPlacementLeaves() ) {
|
|
|
|
|
Instances instances = getCell()->getInstancesUnder(**igcell);
|
|
|
|
|
|
|
|
|
|
if ( instances.getSize() >= getNumberOfInstancesStopCriterion() ) {
|
|
|
|
|
if ( not partToBeDone ) {
|
|
|
|
|
partToBeDone = true;
|
|
|
|
|
++_step;
|
|
|
|
|
}
|
|
|
|
|
_actualGraphs->push_back ( new MetisGraph(this,instances,igcell) );
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if ( not partToBeDone )
|
|
|
|
|
throw Warning("Not enough instances to part, minimum is %d",getNumberOfInstancesStopCriterion());
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
#else
|
|
|
|
|
throw Warning ( "hmetis library is needed to use Metis ToolEngine" );
|
|
|
|
|
#endif // HAVE_HMETIS_LIB
|
|
|
|
|
#else
|
|
|
|
|
return false;
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
2010-06-22 09:09:20 -05:00
|
|
|
|
unsigned int MetisEngine::computeQuadriPartitions ( Cell* cell, int& xsplits, int& ysplits )
|
2010-06-13 16:06:23 -05:00
|
|
|
|
{
|
2010-06-22 09:09:20 -05:00
|
|
|
|
size_t gates = getInstancesCount ( cell );
|
|
|
|
|
Box ab = cell->getAbutmentBox();
|
|
|
|
|
double aspectRatio = (double)(ab.getWidth()) / (double)(ab.getHeight());
|
|
|
|
|
|
|
|
|
|
if ( aspectRatio >= 1.0 ) {
|
|
|
|
|
xsplits = ((int)(trunc ( aspectRatio +0.5 ) )) * 2;
|
|
|
|
|
ysplits = 2;
|
|
|
|
|
} else {
|
|
|
|
|
xsplits = 2;
|
|
|
|
|
ysplits = ((int)(trunc ( (1.0/aspectRatio)+0.5 ) )) * 2;
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-22 15:51:02 -05:00
|
|
|
|
|
|
|
|
|
size_t partitionSizeStop = Cfg::getParamInt("metis.numberOfInstancesStopCriterion",45)->asInt();
|
|
|
|
|
if ( gates / (xsplits*ysplits) < partitionSizeStop )
|
|
|
|
|
throw Error("Design <%s> is too small to be quadri-partionned, only %d gates."
|
|
|
|
|
,getString(cell->getName()).c_str(),gates);
|
|
|
|
|
|
|
|
|
|
double quadPartitions = log((double)gates / (double)(partitionSizeStop*xsplits*ysplits) ) / log(4.0) + 1.0;
|
2010-06-13 16:06:23 -05:00
|
|
|
|
|
2010-06-22 09:09:20 -05:00
|
|
|
|
return (unsigned int)(quadPartitions);
|
2010-06-13 16:06:23 -05:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
void MetisEngine::doQuadriPart ( Cell* cell )
|
|
|
|
|
{
|
|
|
|
|
if ( not isHMetisCapable() )
|
|
|
|
|
throw Error ("Metis::doQuadriPart(): HMetis wasn't found at compile time <%s>"
|
|
|
|
|
,getString(cell->getName()).c_str());
|
|
|
|
|
|
|
|
|
|
// MetisEngine* metis = MetisEngine::get ( cell );
|
|
|
|
|
// if ( metis != NULL )
|
|
|
|
|
// throw Error ("Metis::doQuadriPart(): Metis already exists on <%s>"
|
|
|
|
|
// ,getString(cell->getName()).c_str());
|
|
|
|
|
|
|
|
|
|
// NimbusEngine* nimbus = NimbusEngine::get ( cell );
|
|
|
|
|
// if ( nimbus != NULL )
|
|
|
|
|
// throw Error ("Metis::doQuadriPart(): Nimbus already exists on <%s>"
|
|
|
|
|
// ,getString(cell->getName()).c_str());
|
|
|
|
|
|
|
|
|
|
NimbusEngine* nimbus = NimbusEngine::get ( cell );
|
|
|
|
|
if ( nimbus == NULL )
|
|
|
|
|
nimbus = NimbusEngine::create ( cell );
|
|
|
|
|
|
|
|
|
|
MetisEngine* metis = MetisEngine::get ( cell );
|
|
|
|
|
if ( metis == NULL )
|
|
|
|
|
metis = MetisEngine ::create ( cell );
|
|
|
|
|
|
2010-06-22 09:09:20 -05:00
|
|
|
|
int xsplits;
|
|
|
|
|
int ysplits;
|
|
|
|
|
size_t partitions = computeQuadriPartitions ( cell, xsplits, ysplits );
|
|
|
|
|
|
2010-06-13 16:06:23 -05:00
|
|
|
|
for ( size_t part=0 ; part<partitions ; ++part ) {
|
2010-06-22 09:09:20 -05:00
|
|
|
|
nimbus->progress ( xsplits, ysplits );
|
2010-06-13 16:06:23 -05:00
|
|
|
|
metis-> run ();
|
2010-06-22 09:09:20 -05:00
|
|
|
|
|
|
|
|
|
xsplits = 2;
|
|
|
|
|
ysplits = 2;
|
2010-06-13 16:06:23 -05:00
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
} // End of Metis namespace.
|