522 lines
17 KiB
C++
522 lines
17 KiB
C++
// -*- 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:
|
|
const uint32_t AS_DRIVER = (1<<0);
|
|
const uint32_t AS_SINK = (1<<1);
|
|
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, uint32_t flags );
|
|
Net* raddTransNet ( Net* topNet, Path, uint32_t flags );
|
|
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, uint32_t flags )
|
|
{
|
|
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() );
|
|
}
|
|
uint32_t direction = masterNet->getDirection();
|
|
if (flags & AS_DRIVER) direction |= Net::Direction::OUT;
|
|
if (flags & AS_SINK ) direction |= Net::Direction::IN;
|
|
masterNet->setDirection( (Net::Direction::Code)direction );
|
|
|
|
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, flags );
|
|
|
|
return headPlug;
|
|
}
|
|
|
|
|
|
Net* Cluster::raddTransNet ( Net* topNet, Path path, uint32_t flags )
|
|
{
|
|
if (path.isEmpty()) return topNet;
|
|
return raddTransPlug( topNet, path, flags )->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, AS_SINK );
|
|
}
|
|
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();
|
|
|
|
driverName.insert( 0, "cmpt_" );
|
|
_buffer = Instance::create( cellPnR, driverName, bufferDatas->getCell() );
|
|
|
|
getSubNetNames()->nextSubNet();
|
|
_driverNet = Net::create( topCell, driverName );
|
|
_driverNet->setDirection( Net::Direction::OUT );
|
|
if (topCell == cellPnR) blockNet = _driverNet;
|
|
else {
|
|
outputPath = Path( instancePnR );
|
|
blockNet = raddTransNet( _driverNet, outputPath, AS_DRIVER );
|
|
}
|
|
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(), AS_SINK );
|
|
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(), AS_DRIVER );
|
|
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);
|