Backport cumulus/hfns4 into C++ in EtesianEngine::doHFNS().

This commit is contained in:
Jean-Paul Chaput 2021-03-23 17:14:39 +01:00
parent ec96161f0f
commit 1a918c69b1
9 changed files with 757 additions and 12 deletions

105
etesian/src/BufferCells.cpp Normal file
View File

@ -0,0 +1,105 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2021-2021, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | E t e s i a n - A n a l y t i c P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./BufferCells.cpp" |
// +-----------------------------------------------------------------+
#include <sstream>
#include "hurricane/Warning.h"
#include "etesian/BufferCells.h"
#include "etesian/EtesianEngine.h"
namespace Etesian {
using std::cerr;
using std::endl;
using std::map;
using std::string;
using std::ostringstream;
using std::make_pair;
using Hurricane::Warning;
using Hurricane::DbU;
using Hurricane::Cell;
// -------------------------------------------------------------------
// Class : "Etesian::BufferDatas".
BufferDatas::BufferDatas ( Cell* cell, int32_t drive, uint32_t maxSinks )
: _drive (drive)
, _maxSinks(maxSinks)
, _cell (cell)
, _input (_findIo(Net::Direction::DirIn))
, _output (_findIo(Net::Direction::DirOut))
{ }
Net* BufferDatas::_findIo ( uint32_t direction ) const
{
if (not _cell) return NULL;
for ( Net* net : _cell->getNets() ) {
if (net->isSupply()) continue;
if (not net->isExternal()) continue;
if (net->getDirection() & direction)
return net;
}
cerr << Warning( "BufferDatas::_findIo(): Can't find an I/O net in cell \"%s\"."
, getString(_cell->getName()).c_str() ) << endl;
return NULL;
}
// -------------------------------------------------------------------
// Class : "Etesian::BufferCells".
void BufferCells::useBuffer ( Cell* cell, int drive, uint32_t maxSinks )
{
if (not cell) return;
if (getBuffer(drive)) {
cerr << Warning( "BufferCells::useBuffer(): \"%s\" duplicate buffer for strenght %d."
, getString(cell->getName()).c_str()
, drive
) << endl;
return;
}
_bufferCells.insert( make_pair(drive,new BufferDatas(cell,drive,maxSinks)) );
}
BufferDatas* BufferCells::getBiggestBuffer () const
{
if (_bufferCells.empty()) return NULL;
return (*(--_bufferCells.end())).second;
}
BufferDatas* BufferCells::getSmallestBuffer () const
{
if (_bufferCells.empty()) return NULL;
return (*(_bufferCells.begin())).second;
}
BufferDatas* BufferCells::getBuffer ( int drive ) const
{
map<int,BufferDatas*>::const_iterator ibuffer = _bufferCells.find( drive );
if (ibuffer == _bufferCells.end()) return NULL;
return (*ibuffer).second;
}
} // Etesian namespace.

View File

@ -13,6 +13,7 @@
set( includes etesian/Configuration.h
etesian/Placement.h
etesian/FeedCells.h
etesian/BufferCells.h
etesian/BloatCells.h
etesian/BloatProperty.h
etesian/EtesianEngine.h
@ -23,10 +24,12 @@
)
set( mocIncludes etesian/GraphicEtesianEngine.h )
set( cpps Configuration.cpp
HFNS.cpp
AddFeeds.cpp
Placement.cpp
FlattenPower.cpp
FeedCells.cpp
BufferCells.cpp
BloatCells.cpp
BloatProperty.cpp
EtesianEngine.cpp

View File

@ -65,6 +65,7 @@ namespace Etesian {
( Cfg::getParamDouble ("etesian.antennaInsertThreshold", 50.0)->asDouble() )
, _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() )
, _diodeName ( Cfg::getParamString ("etesian.diodeName" ,"dio_x0" )->asString() )
, _spareBufferName( Cfg::getParamString ("spares.buffer" ,"buf_x8" )->asString() )
, _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() )
, _latchUpDistance( Cfg::getParamInt ("etesian.latchUpDistance",0 )->asInt() )
, _antennaMaxWL ( Cfg::getParamInt ("etesian.antennaMaxWL" ,0 )->asInt() )
@ -99,6 +100,7 @@ namespace Etesian {
, _antennaInsertThreshold( other._antennaInsertThreshold )
, _feedNames ( other._feedNames )
, _diodeName ( other._diodeName )
, _spareBufferName( other._spareBufferName )
, _bloat ( other._bloat )
, _latchUpDistance( other._latchUpDistance )
, _antennaMaxWL ( other._antennaMaxWL )
@ -152,19 +154,20 @@ namespace Etesian {
Record* Configuration::_getRecord () const
{
Record* record = new Record ( _getString() );
record->add ( getSlot( "_rg" , _rg ) );
record->add ( getSlot( "_cg" , _cg ) );
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
record->add ( getSlot( "_rg" , _rg ) );
record->add ( getSlot( "_cg" , _cg ) );
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
record->add ( getSlot( "_feedNames" , _feedNames ) );
record->add ( getSlot( "_diodeName" , _diodeName ) );
record->add ( getSlot( "_bloat" , _bloat ) );
record->add ( DbU::getValueSlot( "_latchUpDistance", &_latchUpDistance ) );
record->add ( DbU::getValueSlot( "_antennaMaxWL" , &_antennaMaxWL ) );
record->add ( getSlot( "_feedNames" , _feedNames ) );
record->add ( getSlot( "_diodeName" , _diodeName ) );
record->add ( getSlot( "_spareBufferName" , _spareBufferName ) );
record->add ( getSlot( "_bloat" , _bloat ) );
record->add ( DbU::getValueSlot( "_latchUpDistance", &_latchUpDistance ) );
record->add ( DbU::getValueSlot( "_antennaMaxWL" , &_antennaMaxWL ) );
return record;
}

View File

@ -314,6 +314,7 @@ namespace Etesian {
, _viewer (NULL)
, _diodeCell (NULL)
, _feedCells (this)
, _bufferCells (this)
, _bloatCells (this)
, _area (NULL)
, _yspinSlice0 (0)
@ -321,6 +322,7 @@ namespace Etesian {
, _fixedAbHeight(0)
, _fixedAbWidth (0)
, _diodeCount (0)
, _bufferCount (0)
{ }
@ -342,6 +344,16 @@ namespace Etesian {
}
_bloatCells.select( getConfiguration()->getBloat() );
string bufferName = getConfiguration()->getSpareBufferName();;
Cell* buffer = DataBase::getDB()->getCell( bufferName );
if (buffer) {
_bufferCells.useBuffer( buffer, 8, 20 );
} else {
cerr << Warning( "EtesianEngine::_postCreate() Unable to find \"%s\" spare buffer cell."
, bufferName.c_str()
) << endl;
}
string feedNames = getConfiguration()->getFeedNames();
char separator = ',';
@ -741,6 +753,11 @@ namespace Etesian {
vector< point<bool> > orientations( instancesNb+1, point<bool>(true, true) );
cmess1 << " - Converting " << instancesNb << " instances" << endl;
if (instancesNb) {
float bufferRatio = ((float)_bufferCount / (float)instancesNb) * 100.0;
cmess1 << " - Buffers " << _bufferCount
<< " (" << fixed << setprecision(2) << bufferRatio << "%)" << endl;
}
cout.flush();
cmess1 << " - Building RoutingPads (transhierarchical) ..." << endl;

513
etesian/src/HFNS.cpp Normal file
View File

@ -0,0 +1,513 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2021-2021, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | E t e s i a n - A n a l y t i c P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Module : "./HFNS.cpp" |
// +-----------------------------------------------------------------+
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/DebugSession.h"
#include "hurricane/DataBase.h"
#include "hurricane/UpdateSession.h"
#include "hurricane/DeepNet.h"
#include "hurricane/Pin.h"
#include "hurricane/Plug.h"
#include "hurricane/RoutingPad.h"
#include "hurricane/Path.h"
#include "hurricane/Library.h"
#include "hurricane/viewer/CellWidget.h"
#include "hurricane/viewer/CellViewer.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/ToolBox.h"
#include "etesian/EtesianEngine.h"
namespace Etesian {
using namespace std;
using Hurricane::tab;
using Hurricane::Warning;
using Hurricane::Error;
using Hurricane::Path;
using Hurricane::Transformation;
using Hurricane::DataBase;
using Hurricane::Library;
using Hurricane::Go;
using Hurricane::DeepNet;
using Hurricane::Pin;
using Hurricane::Plug;
using Hurricane::RoutingPad;
using Hurricane::UpdateSession;
using CRL::AllianceFramework;
using CRL::CatalogExtension;
using CRL::getTransformation;
using CRL::SubNetNames;
using Etesian::EtesianEngine;
// -------------------------------------------------------------------
// Class : "::Cluster".
class Cluster {
public:
Cluster ( EtesianEngine* );
virtual ~Cluster ();
inline size_t getSize () const;
inline EtesianEngine* getEtesian () const;
virtual Cluster* getParent () const;
virtual SubNetNames* getSubNetNames ();
inline void setParent ( Cluster* );
bool merge ( RoutingPad* );
bool merge ( Cluster* );
inline void swapRps ( Cluster* );
inline Net* getInputNet ();
inline Net* getOutputNet ();
Plug* raddTransPlug ( Net* topNet, Path );
Net* raddTransNet ( Net* topNet, Path );
Plug* getPlugByNet ( Instance* instance, Net* cellNet );
void createInput ( Net* );
void createOutput ();
virtual void splitNet ();
virtual string _getTypeName () const;
virtual string _getString () const;
private:
EtesianEngine* _etesian;
vector<RoutingPad*> _rps;
vector<Cluster*> _clusters;
Cluster* _parent;
Instance* _buffer;
Net* _driverNet;
};
Cluster::Cluster ( EtesianEngine* etesian )
: _etesian (etesian)
, _rps ()
, _clusters ()
, _parent (NULL)
, _buffer (NULL)
, _driverNet(NULL)
{ }
Cluster::~Cluster ()
{ }
inline EtesianEngine* Cluster::getEtesian () const { return _etesian; }
inline size_t Cluster::getSize () const { return _rps.size() + _clusters.size(); }
Cluster* Cluster::getParent () const { return _parent; }
SubNetNames* Cluster::getSubNetNames () { return _parent->getSubNetNames(); }
inline void Cluster::setParent ( Cluster* parent ) { _parent = parent; }
inline void Cluster::swapRps ( Cluster* other ) { _rps.swap( other->_rps ); }
bool Cluster::merge ( RoutingPad* newRp )
{
for ( RoutingPad* rp : _rps ) {
if (rp == newRp) return false;
}
_rps.push_back( newRp );
return true;
}
bool Cluster::merge ( Cluster* child )
{
for ( Cluster* cluster : _clusters ) {
if (cluster == child) return false;
}
_clusters.push_back( child );
child->setParent( this );
return true;
}
Plug* Cluster::getPlugByNet ( Instance* instance, Net* cellNet )
{
for ( Plug* plug : instance->getPlugs() ) {
if (plug->getNet() == cellNet)
return plug;
}
return NULL;
}
Plug* Cluster::raddTransPlug ( Net* topNet, Path path )
{
if (path.isEmpty()) return NULL;
if (topNet->getCell() != path.getOwnerCell() ) {
throw Error( "Cluster::raddTransPlug(): \"topNet\" and \"path\" must belong to the same cell.\n"
" * \"topNet\" is owned by %s\n"
" * \"path\" is owned by %s"
, getString(topNet->getCell()).c_str()
, getString(path.getOwnerCell()).c_str()
);
}
Path tailPath = path.getTailPath();
Instance* headInstance = path.getHeadInstance();
Plug* headPlug = getPlugByNet( headInstance, topNet );
Net* masterNet = NULL;
if (not headPlug) {
Cell* masterCell = headInstance->getMasterCell();
masterNet = masterCell->getNet( topNet->getName() );
if (not masterNet) {
masterNet = Net::create( masterCell, topNet->getName() );
masterNet->setType ( topNet->getType() );
masterNet->setDirection( Net::Direction::IN );
}
masterNet->setExternal( true );
headPlug = headInstance->getPlug( masterNet );
if (not headPlug)
throw Error( "Cluster::raddTransPlug(): Plug not created for \"%s\" on instance \"%s\" of \"%s\""
, getString(topNet->getName()).c_str()
, getString(headInstance->getName()).c_str()
, getString(masterCell->getName()).c_str() );
headPlug->setNet( topNet );
} else {
masterNet = headPlug->getMasterNet();
}
if (not tailPath.isEmpty())
headPlug = raddTransPlug( masterNet, tailPath );
return headPlug;
}
Net* Cluster::raddTransNet ( Net* topNet, Path path )
{
if (path.isEmpty()) return topNet;
return raddTransPlug( topNet, path )->getMasterNet();
}
void Cluster::createInput ( Net* upDriver )
{
Cell* topCell = _etesian->getCell();
Cell* cellPnR = _etesian->getBlockCell();
Instance* instancePnR = _etesian->getBlockInstance();
BufferDatas* bufferDatas = _etesian->getBufferCells().getBiggestBuffer();
Net* blockNet = upDriver;
Path inputPath = Path();
if (topCell != cellPnR) {
inputPath = Path( instancePnR );
blockNet = raddTransNet( upDriver, inputPath );
}
Plug* inputPlug = bufferDatas->getInput( _buffer );
inputPlug->setNet( blockNet );
RoutingPad::create( upDriver, Occurrence(inputPlug,inputPath), RoutingPad::BiggestArea );
}
void Cluster::createOutput ()
{
Cell* topCell = _etesian->getCell();
Cell* cellPnR = _etesian->getBlockCell();
Instance* instancePnR = _etesian->getBlockInstance();
BufferDatas* bufferDatas = _etesian->getBufferCells().getBiggestBuffer();
string driverName = getSubNetNames()->getSubNetName();
Net* blockNet = NULL;
Path outputPath = Path();
_buffer = Instance::create( cellPnR, driverName, bufferDatas->getCell() );
getSubNetNames()->nextSubNet();
_driverNet = Net::create( topCell, driverName );
if (topCell == cellPnR) blockNet = _driverNet;
else {
outputPath = Path( instancePnR );
blockNet = raddTransNet( _driverNet, outputPath );
}
Plug* outputPlug = bufferDatas->getOutput( _buffer );
outputPlug->setNet( blockNet );
RoutingPad::create( _driverNet, Occurrence(outputPlug,outputPath), RoutingPad::BiggestArea );
}
void Cluster::splitNet ()
{
createOutput();
for ( Cluster* cluster : _clusters ) {
cluster->createInput( _driverNet );
}
for ( RoutingPad* rp : _rps ) {
Occurrence plugOcc = rp->getPlugOccurrence();
Net* deepNet = raddTransNet( _driverNet, plugOcc.getPath() );
if (dynamic_cast<Pin*>(plugOcc.getEntity())) {
continue;
}
Plug* deepSinkPlug = dynamic_cast<Plug*>( plugOcc.getEntity() );
deepSinkPlug->setNet( deepNet );
rp->destroy();
RoutingPad::create( _driverNet, plugOcc, RoutingPad::BiggestArea );
}
}
string Cluster::_getTypeName () const
{ return "Cluster"; }
string Cluster::_getString () const
{
string s = "<" + _getTypeName() + " ";
s += getString(_rps.size()) + "+" + getString(_clusters.size()) + ">";
return s;
}
// -------------------------------------------------------------------
// Class : "::BufferTree".
class BufferTree : public Cluster {
public:
BufferTree ( EtesianEngine*, Net* );
virtual ~BufferTree ();
virtual Cluster* getParent () const;
virtual SubNetNames* getSubNetNames ();
virtual void splitNet ();
void rpartition ();
uint32_t build ();
string _getTypeName () const;
private:
SubNetNames _subNetNames;
bool _isDeepNet;
Net* _rootNet;
RoutingPad* _rpDriver;
vector< vector<Cluster*> > _clustersStack;
};
BufferTree::BufferTree ( EtesianEngine* etesian, Net* rootNet )
: Cluster(etesian)
, _subNetNames ()
, _isDeepNet (true)
, _rootNet (rootNet)
, _rpDriver (NULL)
, _clustersStack()
{
_subNetNames.match( getString(rootNet->getName()) );
cdebug_log(123,0) << "BufferTree CTOR _clustersStack.size()=" << _clustersStack.size() << endl;
}
BufferTree::~BufferTree ()
{
for ( vector<Cluster*>& clusters : _clustersStack ) {
for ( Cluster* cluster : clusters ) {
if (dynamic_cast<BufferTree*>(cluster)) continue;
delete cluster;
}
}
}
Cluster* BufferTree::getParent () const { return NULL; }
SubNetNames* BufferTree::getSubNetNames () { return &_subNetNames; }
void BufferTree::splitNet ()
{
if (not _rpDriver)
throw Error( "BufferTree::splitNet(): Missing driver on %s.", getString(_rootNet).c_str() );
Cluster::splitNet();
if (_isDeepNet) {
Cell* topCell = getEtesian()->getCell();
Name topNetName = _rootNet->getName();
Occurrence driverRpOcc = _rpDriver->getPlugOccurrence();
_rootNet->destroy();
_rootNet = Net::create( topCell, topNetName );
Net* deepDriverNet = raddTransNet( _rootNet, driverRpOcc.getPath() );
dynamic_cast<Plug*>( driverRpOcc.getEntity() )->setNet( deepDriverNet );
RoutingPad::create( _rootNet, driverRpOcc, RoutingPad::BiggestArea );
}
createInput( _rootNet );
}
void BufferTree::rpartition ()
{
cdebug_log(123,1) << "BufferTree::rpartition()" << endl;
_clustersStack.push_back( vector<Cluster*>() );
cdebug_log(123,0) << "_clustersStack.size()=" << _clustersStack.size() << endl;
_clustersStack.back().push_back( new Cluster(getEtesian()) );
cdebug_log(123,0) << "_clustersStack[0].size()=" << _clustersStack.back().size() << endl;
BufferDatas* bufferDatas = getEtesian()->getBufferCells().getBiggestBuffer();
RoutingPad* rpPin = NULL;
for ( RoutingPad* rp : _rootNet->getRoutingPads() ) {
Occurrence rpOccurrence = rp->getPlugOccurrence();
if (rpOccurrence.getPath().isEmpty())
_isDeepNet = false;
Pin* pin = dynamic_cast<Pin* >( rpOccurrence.getEntity() );
if (pin) {
if (not rpPin) {
if (dynamic_cast<Pin* >( rpOccurrence.getEntity() )) {
rpPin = rp;
}
}
cdebug_log(123,0) << "Excluded: " << pin << endl;
continue;
}
Plug* rpPlug = dynamic_cast<Plug*>( rpOccurrence.getEntity() );
Net* masterNet = rpPlug->getMasterNet();
if (masterNet->getDirection() & Net::Direction::DirIn) {
if(_clustersStack[0].back()->getSize() >= bufferDatas->getMaxSinks()) {
_clustersStack[0].push_back( new Cluster(getEtesian()) );
cdebug_log(123,0) << "_clustersStack[0].size()=" << _clustersStack[0].size() << endl;
}
cdebug_log(123,0) << "merge: " << _clustersStack[0].back()->getSize() << " " << rp << endl;
_clustersStack[0].back()->merge( rp );
} else {
_rpDriver = rp;
}
}
if (rpPin) {
if (not _rpDriver) {
_rpDriver = rpPin;
} else {
_clustersStack[0].back()->merge( rpPin );
}
}
if (_clustersStack[0].size() == 1) {
_clustersStack[0].back()->swapRps( this );
_clustersStack[0].clear();
_clustersStack[0].push_back( this );
cdebug_log(123,0) << "One cluster special case." << endl;
cdebug_tabw(123,-1);
return;
}
size_t depth = 0;
while ( _clustersStack[depth].size() > 1) {
cdebug_log(123,0) << "New depth " << (depth+1) << endl;
_clustersStack.push_back( vector<Cluster*>() );
if (_clustersStack[depth].size() <= bufferDatas->getMaxSinks()) {
_clustersStack[depth+1].push_back( this );
cdebug_log(123,0) << "TOP cluster" << endl;
}
else
_clustersStack[depth+1].push_back( new Cluster(getEtesian()) );
cdebug_log(123,0) << "CLUSTER _clustersStack[" << depth << "].size()=" << _clustersStack[depth].size() << endl;
for ( Cluster* cluster : _clustersStack[depth] ) {
if(_clustersStack[depth+1].back()->getSize() >= bufferDatas->getMaxSinks()) {
_clustersStack[depth+1].push_back( new Cluster(getEtesian()) );
cdebug_log(123,0) << "_clustersStack[" << (depth+1) << "].size()=" << _clustersStack[depth+1].size() << endl;
}
cdebug_log(123,0) << "merge: " << _clustersStack[depth+1].back()->getSize() << " " << cluster << endl;
_clustersStack[depth+1].back()->merge( cluster );
}
++depth;
}
cdebug_tabw(123,-1);
}
uint32_t BufferTree::build ()
{
uint32_t bufferCount = 0;
rpartition();
for ( vector<Cluster*>& clusters : _clustersStack ) {
for ( Cluster* cluster : clusters ) {
cluster->splitNet();
++bufferCount;
}
}
return bufferCount;
}
string BufferTree::_getTypeName () const
{ return "BufferTree"; }
uint32_t EtesianEngine::doHFNS ()
{
cmess2 << " - High Fanout Net Synthesis (HFNS)." << endl;
startMeasures();
BufferDatas* bufferDatas = getBufferCells().getBiggestBuffer();
vector< tuple<Net*,uint32_t> > netDatas;
for ( Net* net : getCell()->getNets() ) {
uint32_t rpCount = 0;
for ( RoutingPad* rp : net->getRoutingPads() ) {
Occurrence rpOcc = rp->getPlugOccurrence();
Pin* pin = dynamic_cast<Pin*>( rpOcc.getEntity() );
if (pin) {
continue;
}
if (getBlockInstance()) {
if (rpOcc.getPath().getHeadInstance() != getBlockInstance()) {
continue;
}
}
Plug* rpPlug = dynamic_cast<Plug*>( rpOcc.getEntity() );
Net* masterNet = rpPlug->getMasterNet();
if (masterNet->getDirection() & Net::Direction::DirIn) {
++rpCount;
}
}
if (rpCount > bufferDatas->getMaxSinks()) {
netDatas.push_back( make_tuple(net,rpCount) );
}
}
UpdateSession::open();
Go::disableAutoMaterialization();
_bufferCount = 0;
for ( size_t i=0 ; i<netDatas.size() ; ++i ) {
if (i) {
if ((i%10) == 0) cmess2 << "\n ";
else cmess2 << " ";
} else {
cmess2 << " ";
}
cmess2 << "[" << std::get<1>( netDatas[i] ) << "]";
Net* net = std::get<0>( netDatas[i] );
BufferTree tree ( this, net );
_bufferCount += tree.build();
}
cmess2 << endl;
// for ( tuple<Net*,uint32_t>& netData : netDatas ) {
// Net* net = std::get<0>(netData);
// cmess2 << " Net \"" << net->getName() << "\" has " << std::get<1>(netData) << " sinks." << endl;
// BufferTree tree ( this, net );
// _bufferCount += tree.build();
// }
Go::enableAutoMaterialization();
UpdateSession::close();
stopMeasures();
printMeasures();
cmess2 << " - Total added buffers " << _bufferCount << endl;
return _bufferCount;
}
} // Etesian namespace.
GETSTRING_POINTER_SUPPORT(Etesian::Cluster);
GETSTRING_POINTER_SUPPORT(Etesian::BufferTree);

View File

@ -76,6 +76,7 @@ extern "C" {
DirectVoidMethod(EtesianEngine,etesian,resetPlacement)
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
DirectVoidMethod(EtesianEngine,etesian,flattenPower)
DirectGetUIntAttribute (PyEtesianEngine_doHFNS ,doHFNS ,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
@ -264,6 +265,8 @@ extern "C" {
, "Run the placer (Etesian)." }
, { "flattenPower" , (PyCFunction)PyEtesianEngine_flattenPower , METH_NOARGS
, "Build abstract interface in top cell for supply & blockages." }
, { "doHFNS" , (PyCFunction)PyEtesianEngine_doHFNS , METH_NOARGS
, "Perform the high fanout net synthesis." }
, { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS
, "Destroy the associated hurricane object. The python object remains." }
, {NULL, NULL, 0, NULL} /* sentinel */

View File

@ -0,0 +1,92 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2021-2021, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | E t e s i a n - A n a l y t i c P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./etesian/BufferCells.h" |
// +-----------------------------------------------------------------+
#pragma once
#include <map>
#include "hurricane/Cell.h"
namespace Etesian {
using Hurricane::Cell;
using Hurricane::Net;
using Hurricane::Instance;
using Hurricane::Plug;
class EtesianEngine;
// -------------------------------------------------------------------
// Class : "Etesian::BufferDatas".
class BufferDatas {
public:
BufferDatas ( Cell*, int32_t drive, uint32_t maxSinks );
inline int32_t getDrive () const;
inline uint32_t getMaxSinks () const;
inline Cell* getCell () const;
inline Net* getInput () const;
inline Net* getOutput () const;
inline Plug* getInput ( Instance* ) const;
inline Plug* getOutput ( Instance* ) const;
private:
Net* _findIo ( uint32_t direction ) const;
private:
int32_t _drive;
uint32_t _maxSinks;
Cell* _cell;
Net* _input;
Net* _output;
};
inline int32_t BufferDatas::getDrive () const { return _drive; }
inline uint32_t BufferDatas::getMaxSinks () const { return _maxSinks; }
inline Cell* BufferDatas::getCell () const { return _cell; }
inline Net* BufferDatas::getInput () const { return _input; }
inline Net* BufferDatas::getOutput () const { return _output; }
inline Plug* BufferDatas::getInput ( Instance* instance ) const { return instance->getPlug( getInput() ); }
inline Plug* BufferDatas::getOutput ( Instance* instance ) const { return instance->getPlug( getOutput() ); }
// -------------------------------------------------------------------
// Class : "Etesian::BufferCells".
class BufferCells {
public:
inline BufferCells ( EtesianEngine* );
inline ~BufferCells ();
void useBuffer ( Cell*, int32_t drive, uint32_t maxSinks );
BufferDatas* getBiggestBuffer () const;
BufferDatas* getSmallestBuffer () const;
BufferDatas* getBuffer ( int32_t drive ) const;
private:
EtesianEngine* _etesian;
std::map<int,BufferDatas*> _bufferCells;
};
inline BufferCells::BufferCells ( EtesianEngine* etesian )
: _etesian (etesian)
, _bufferCells()
{ }
inline BufferCells::~BufferCells ()
{
for ( auto item : _bufferCells )
delete item.second;
}
} // Etesian namespace.

View File

@ -70,6 +70,7 @@ namespace Etesian {
inline double getAntennaInsertThreshold () const;
inline string getFeedNames () const;
inline string getDiodeName () const;
inline string getSpareBufferName () const;
inline string getBloat () const;
inline DbU::Unit getLatchUpDistance () const;
inline DbU::Unit getAntennaMaxWL () const;
@ -92,6 +93,7 @@ namespace Etesian {
double _antennaInsertThreshold;
string _feedNames;
string _diodeName;
string _spareBufferName;
string _bloat;
DbU::Unit _latchUpDistance;
DbU::Unit _antennaMaxWL;
@ -112,6 +114,7 @@ namespace Etesian {
inline double Configuration::getAntennaInsertThreshold () const { return _antennaInsertThreshold; }
inline string Configuration::getFeedNames () const { return _feedNames; }
inline string Configuration::getDiodeName () const { return _diodeName; }
inline string Configuration::getSpareBufferName () const { return _spareBufferName; }
inline string Configuration::getBloat () const { return _bloat; }
inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; }
inline DbU::Unit Configuration::getAntennaMaxWL () const { return _antennaMaxWL; }

View File

@ -35,6 +35,7 @@ namespace Hurricane {
#include "crlcore/ToolEngine.h"
#include "etesian/Configuration.h"
#include "etesian/FeedCells.h"
#include "etesian/BufferCells.h"
#include "etesian/BloatCells.h"
#include "etesian/Placement.h"
@ -95,6 +96,7 @@ namespace Etesian {
inline DbU::Unit getAntennaMaxWL () const;
inline DbU::Unit getLatchUpDistance () const;
inline const FeedCells& getFeedCells () const;
inline const BufferCells& getBufferCells () const;
inline Cell* getDiodeCell () const;
std::string getUniqueDiodeName ();
inline const Box& getPlaceArea () const;
@ -130,6 +132,7 @@ namespace Etesian {
void detailedPlace ( int iterations, int effort, unsigned options=0 );
void antennaProtect ();
void place ();
uint32_t doHFNS ();
inline void useFeed ( Cell* );
size_t findYSpin ();
void addFeeds ();
@ -161,6 +164,7 @@ namespace Etesian {
Hurricane::CellViewer* _viewer;
Cell* _diodeCell;
FeedCells _feedCells;
BufferCells _bufferCells;
BloatCells _bloatCells;
Area* _area;
size_t _yspinSlice0;
@ -168,6 +172,7 @@ namespace Etesian {
DbU::Unit _fixedAbHeight;
DbU::Unit _fixedAbWidth;
uint32_t _diodeCount;
uint32_t _bufferCount;
protected:
// Constructors & Destructors.
@ -208,6 +213,7 @@ namespace Etesian {
inline DbU::Unit EtesianEngine::getLatchUpDistance () const { return getConfiguration()->getLatchUpDistance(); }
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
inline const BufferCells& EtesianEngine::getBufferCells () const { return _bufferCells; }
inline Cell* EtesianEngine::getDiodeCell () const { return _diodeCell; }
inline void EtesianEngine::selectBloat ( std::string profile ) { _bloatCells.select(profile); }