From 1a918c69b177f507d851ef23d8812ae583eeb50a Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Tue, 23 Mar 2021 17:14:39 +0100 Subject: [PATCH] Backport cumulus/hfns4 into C++ in EtesianEngine::doHFNS(). --- etesian/src/BufferCells.cpp | 105 ++++++ etesian/src/CMakeLists.txt | 3 + etesian/src/Configuration.cpp | 27 +- etesian/src/EtesianEngine.cpp | 17 + etesian/src/HFNS.cpp | 513 ++++++++++++++++++++++++++++ etesian/src/PyEtesianEngine.cpp | 3 + etesian/src/etesian/BufferCells.h | 92 +++++ etesian/src/etesian/Configuration.h | 3 + etesian/src/etesian/EtesianEngine.h | 6 + 9 files changed, 757 insertions(+), 12 deletions(-) create mode 100644 etesian/src/BufferCells.cpp create mode 100644 etesian/src/HFNS.cpp create mode 100644 etesian/src/etesian/BufferCells.h diff --git a/etesian/src/BufferCells.cpp b/etesian/src/BufferCells.cpp new file mode 100644 index 00000000..2eb91f59 --- /dev/null +++ b/etesian/src/BufferCells.cpp @@ -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 +#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::const_iterator ibuffer = _bufferCells.find( drive ); + if (ibuffer == _bufferCells.end()) return NULL; + + return (*ibuffer).second; + } + + +} // Etesian namespace. diff --git a/etesian/src/CMakeLists.txt b/etesian/src/CMakeLists.txt index 9d15d126..f6497523 100644 --- a/etesian/src/CMakeLists.txt +++ b/etesian/src/CMakeLists.txt @@ -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 diff --git a/etesian/src/Configuration.cpp b/etesian/src/Configuration.cpp index 199cd6df..6973b146 100644 --- a/etesian/src/Configuration.cpp +++ b/etesian/src/Configuration.cpp @@ -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; } diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index c46049b8..58fefc22 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -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 > orientations( instancesNb+1, point(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; diff --git a/etesian/src/HFNS.cpp b/etesian/src/HFNS.cpp new file mode 100644 index 00000000..88ce5217 --- /dev/null +++ b/etesian/src/HFNS.cpp @@ -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 _rps; + vector _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(plugOcc.getEntity())) { + continue; + } + Plug* deepSinkPlug = dynamic_cast( 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 > _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& clusters : _clustersStack ) { + for ( Cluster* cluster : clusters ) { + if (dynamic_cast(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( 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() ); + 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( rpOccurrence.getEntity() ); + if (pin) { + if (not rpPin) { + if (dynamic_cast( rpOccurrence.getEntity() )) { + rpPin = rp; + } + } + cdebug_log(123,0) << "Excluded: " << pin << endl; + continue; + } + Plug* rpPlug = dynamic_cast( 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() ); + 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& 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 > netDatas; + for ( Net* net : getCell()->getNets() ) { + uint32_t rpCount = 0; + for ( RoutingPad* rp : net->getRoutingPads() ) { + Occurrence rpOcc = rp->getPlugOccurrence(); + Pin* pin = dynamic_cast( rpOcc.getEntity() ); + if (pin) { + continue; + } + + if (getBlockInstance()) { + if (rpOcc.getPath().getHeadInstance() != getBlockInstance()) { + continue; + } + } + + Plug* rpPlug = dynamic_cast( 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[i] ) << "]"; + Net* net = std::get<0>( netDatas[i] ); + BufferTree tree ( this, net ); + _bufferCount += tree.build(); + } + cmess2 << endl; + // for ( tuple& 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); diff --git a/etesian/src/PyEtesianEngine.cpp b/etesian/src/PyEtesianEngine.cpp index baefcda5..8ad38c2e 100644 --- a/etesian/src/PyEtesianEngine.cpp +++ b/etesian/src/PyEtesianEngine.cpp @@ -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 */ diff --git a/etesian/src/etesian/BufferCells.h b/etesian/src/etesian/BufferCells.h new file mode 100644 index 00000000..76746f1c --- /dev/null +++ b/etesian/src/etesian/BufferCells.h @@ -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 +#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 _bufferCells; + }; + + + inline BufferCells::BufferCells ( EtesianEngine* etesian ) + : _etesian (etesian) + , _bufferCells() + { } + + inline BufferCells::~BufferCells () + { + for ( auto item : _bufferCells ) + delete item.second; + } + +} // Etesian namespace. diff --git a/etesian/src/etesian/Configuration.h b/etesian/src/etesian/Configuration.h index 406924f0..a145e302 100644 --- a/etesian/src/etesian/Configuration.h +++ b/etesian/src/etesian/Configuration.h @@ -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; } diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index dd3ca0ae..8122c564 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -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); }