coriolis/etesian/src/AddFeeds.cpp

403 lines
13 KiB
C++
Raw Normal View History

// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2015-2015, 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@asim.lip6.fr |
// | =============================================================== |
// | C++ Module : "./AddFeeds.cpp" |
// +-----------------------------------------------------------------+
#include <map>
#include <list>
#include "hurricane/Error.h"
#include "hurricane/Warning.h"
#include "hurricane/DataBase.h"
#include "hurricane/UpdateSession.h"
#include "hurricane/Instance.h"
#include "hurricane/Plug.h"
#include "hurricane/Path.h"
#include "hurricane/viewer/CellWidget.h"
#include "crlcore/AllianceFramework.h"
#include "crlcore/ToolBox.h"
#include "etesian/EtesianEngine.h"
namespace {
using namespace std;
using Hurricane::tab;
using Hurricane::inltrace;
using Hurricane::ltracein;
using Hurricane::ltraceout;
using Hurricane::ForEachIterator;
using Hurricane::Warning;
using Hurricane::Error;
using Hurricane::DbU;
using Hurricane::Box;
using Hurricane::Interval;
using Hurricane::Instance;
using Hurricane::Path;
using Hurricane::Transformation;
using Hurricane::DataBase;
using Hurricane::Cell;
using CRL::AllianceFramework;
using CRL::CatalogExtension;
using CRL::getTransformation;
using Etesian::EtesianEngine;
// -------------------------------------------------------------------
// Class : "::SliceHoles".
class SliceHoles;
class Slice {
public:
Slice ( SliceHoles*, DbU::Unit ybottom, Interval xspan );
inline DbU::Unit getYBottom () const;
inline const Interval& getXSpan () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline SliceHoles* getSliceHoles () const;
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
void merge ( DbU::Unit source, DbU::Unit target );
void addFeeds ( size_t islice );
void fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin );
string _getString () const;
private:
SliceHoles* _sliceHoles;
DbU::Unit _ybottom;
Interval _xspan;
list<Interval> _chunks;
};
class SliceHoles {
public:
SliceHoles ( EtesianEngine* );
~SliceHoles ();
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline void setSpinSlice0 ( size_t );
void merge ( const Box& );
void addFeeds ();
private:
EtesianEngine* _etesian;
Box _cellAb;
DbU::Unit _sliceHeight;
vector<Slice*> _slices;
size_t _spinSlice0;
};
Slice::Slice ( SliceHoles* sliceHoles, DbU::Unit ybottom, Interval xspan )
: _sliceHoles(sliceHoles)
, _ybottom (ybottom)
, _xspan (xspan)
, _chunks ()
{ }
inline DbU::Unit Slice::getYBottom () const { return _ybottom; }
inline DbU::Unit Slice::getXMin () const { return _xspan.getVMin(); }
inline DbU::Unit Slice::getXMax () const { return _xspan.getVMax(); }
inline const Interval& Slice::getXSpan () const { return _xspan; }
inline SliceHoles* Slice::getSliceHoles () const { return _sliceHoles; }
inline EtesianEngine* Slice::getEtesian () const { return getSliceHoles()->getEtesian(); }
inline size_t Slice::getSpinSlice0 () const { return getSliceHoles()->getSpinSlice0(); }
void Slice::merge ( DbU::Unit source, DbU::Unit target )
{
Interval chunkToMerge = _xspan.getIntersection( Interval(source,target) );
ltrace(300) << " Slice::merge() " << " " << chunkToMerge << endl;
ltrace(300) << " | " << _getString() << endl;
if (chunkToMerge.isEmpty()) return;
list<Interval>::iterator imerge = _chunks.end();
list<Interval>::iterator ichunk = _chunks.begin();
while ( ichunk != _chunks.end() ) {
if (imerge == _chunks.end()) {
if (chunkToMerge.getVMax() < (*ichunk).getVMin()) {
ltrace(300) << " | Insert before " << *ichunk << endl;
imerge = _chunks.insert( ichunk, chunkToMerge );
break;
}
if (chunkToMerge.intersect(*ichunk)) {
ltrace(300) << " | Merge with " << *ichunk << endl;
imerge = ichunk;
(*imerge).merge( chunkToMerge );
}
} else {
if (chunkToMerge.getVMax() >= (*ichunk).getVMin()) {
(*imerge).merge( *ichunk );
ltrace(300) << " | Absorb (erase) " << *ichunk << endl;
ichunk = _chunks.erase( ichunk );
continue;
} else
break;
}
++ichunk;
}
if (imerge == _chunks.end()) {
_chunks.insert( ichunk, chunkToMerge );
ltrace(300) << " | Insert at end " << DbU::getValueString(_ybottom) << " " << chunkToMerge << endl;
ltrace(300) << " | " << _getString() << endl;
}
}
void Slice::addFeeds ( size_t islice )
{
if (_chunks.empty()) {
fillHole( getXMin(), getXMax(), getYBottom(), islice%2 );
return;
}
list<Interval>::iterator ichunk = _chunks.begin();
list<Interval>::iterator ichunknext = ichunk;
++ichunknext;
// Hole before the first chunk.
if ((*ichunk).getVMin() > getXMin()) {
fillHole( getXMin(), (*ichunk).getVMin(), getYBottom(), (islice+getSpinSlice0())%2 );
}
for ( ; ichunknext != _chunks.end() ; ++ichunk, ++ichunknext ) {
fillHole( (*ichunk).getVMax(), (*ichunknext).getVMin(), getYBottom(), (islice+getSpinSlice0())%2 );
}
// Hole after the last chunk.
if ((*ichunk).getVMax() < getXMax()) {
fillHole( (*ichunk).getVMax(), getXMax(), getYBottom(), (islice+getSpinSlice0())%2 );
}
}
void Slice::fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin )
{
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
if (feed == NULL) {
cerr << Error("EtesianEngine: No feed has been registered, ignoring.") << endl;
return;
}
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
DbU::Unit xtie = xmin;
while ( true ) {
if (xtie >= xmax) break;
if (xtie+feedWidth > xmax) {
// Feed is too big, try to find a smaller one.
int pitch = (int)((xmax-xtie) / getEtesian()->getPitch());
for ( ; pitch > 0 ; --pitch ) {
feed = getEtesian()->getFeedCells().getFeed( pitch );
feedWidth = feed->getAbutmentBox().getWidth();
if (feed != NULL) break;
}
if (feed == NULL) break;
}
Instance::create ( getEtesian()->getCell()
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, feed
, getTransformation( feed->getAbutmentBox()
, xtie
, _ybottom
, (yspin)?Transformation::Orientation::MY
:Transformation::Orientation::ID
)
, Instance::PlacementStatus::PLACED
);
xtie += feedWidth;
}
}
string Slice::_getString () const
{
ostringstream os;
os << "<Slice " << " @" << DbU::getValueString(_ybottom) << " ";
list<Interval>::const_iterator ichunk = _chunks.begin();
for ( ; ichunk != _chunks.end() ; ++ichunk ) {
if (ichunk != _chunks.begin()) os << " ";
os << "[" << DbU::getValueString((*ichunk).getVMin())
<< " " << DbU::getValueString((*ichunk).getVMax()) << "]";
}
os << ">";
return os.str();
}
SliceHoles::SliceHoles ( EtesianEngine* etesian )
: _etesian (etesian)
, _cellAb (etesian->getCell()->getAbutmentBox())
, _sliceHeight(_etesian->getSliceHeight())
, _slices ()
{
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
_slices.push_back( new Slice( this
, _cellAb.getYMin()+islice*_sliceHeight
, Interval(_cellAb.getXMin(),_cellAb.getXMax()) ) );
}
SliceHoles::~SliceHoles ()
{
for ( size_t islice=0 ; islice<_slices.size() ; ++islice )
delete _slices[islice];
}
inline EtesianEngine* SliceHoles::getEtesian () const { return _etesian; }
inline size_t SliceHoles::getSpinSlice0 () const { return _spinSlice0; }
inline void SliceHoles::setSpinSlice0 ( size_t spinSlice0 ) { _spinSlice0 = spinSlice0; }
void SliceHoles::merge ( const Box& bb )
{
if (bb.getYMin() < _cellAb.getYMin()) {
cerr << Warning("Attempt to merge instance outside the Cell abutment box.") << endl;
return;
}
size_t ibegin = (bb.getYMin()-_cellAb.getYMin()) / _sliceHeight;
size_t iend = (bb.getYMax()-_cellAb.getYMin()) / _sliceHeight;
for ( size_t islice=ibegin ; islice<iend ; ++islice ) {
_slices[islice]->merge( bb.getXMin(), bb.getXMax() );
}
}
void SliceHoles::addFeeds ()
{
for ( size_t islice=0 ; islice<_slices.size() ; islice++ )
_slices[islice]->addFeeds( islice );
}
} // End of anonymous namespace.
namespace Etesian {
using Hurricane::ForEachIterator;
using Hurricane::DataBase;
using Hurricane::UpdateSession;
using Hurricane::Occurrence;
Etesian integration with Chip & ClockTree plugins. * New: In Hurricane, in DebugSession, add a new method to activate the trace inconditionally with a certain level. * New: In Hurricane, in HyperNet, allow copy construction as there is no reason to disallow it and we need it now. * New: In Hurricane, in Cell::flattenNets(), add a new option to prevent the flattening of the clock net(s). For more safety perform the DeepNet creation *outside* the Collection loop. * Bug: In Hurricane, in Cell_HyperNetRootNetOccurrences, skip the DeepNets because they are the result of another flattening operation. * New: In Isobar, in PyBasicLayer, export C++ method getBlockageLayer(). * New: In Isobar, in PyRoutingGauge, export C++ method getLayerPitch(), needed by Cumulus plugins. * New: In Etesian, EtesianEngine::findYSpin() to look for the Y orientation if some cells are already placed. Typically the buffers of a clock tree. Pass the correct orienation to row_compatible_orientation(). Do not try to add feeds in the ISPD05 benchmarks. For now the benchmarks are detected through their names (unreliable). * Change: In Knik, in KnikEngine::initGlobalRouting(), allow the clock to be routed as an ordinary signal when the clock tree is not used. * New: In Kite, in BuildPowerRails, management & detection for the pre-routed clock. In KiteEngine constructor, early initialization of the blockage net to avoid later troubles in BuildPowerRails. * New: In Cumulus, in ChipPlugin, add support for Etesian plus new configuration parameter 'clockTree.placerEngine' to select between Mauka and Etesian. * New: In Cumulus, in BlockCorona, add blockages in the vertical sides in the vertical layer to prevent the router to use the vertical tracks in under the prower lines (for example, blockage in M3 with power line M5). In Cumulus, in ChipConf add attribute to access the blockage net. * New: In Cumulus, when the clock tree is disabled, do not generate the last rail around the block (the clock rail). * Bug: In Cumulus, in ChipConf use the clock pad to guess the clock signals and *not* the power pad. Add more meaningful error messages if a pad global signal is not found (implicit connexion by name). * Bug: In Cumulus, in ClockTree, compute correctly the cells Y spin, that is *from the bottom of the cell AB* (not from 'zero').
2015-02-24 06:13:17 -06:00
size_t EtesianEngine::findYSpin ()
{
_flags &= ~YSpinSet;
_yspinSlice0 = 0;
Box topCellAb = getCell()->getAbutmentBox();
if (not topCellAb.isEmpty()) {
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )
{
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
Cell* masterCell = instance->getMasterCell();
Box instanceAb = masterCell->getAbutmentBox();
Transformation instanceTransf = instance->getTransformation();
(*ioccurrence).getPath().getTransformation().applyOn( instanceTransf );
instanceTransf.applyOn( instanceAb );
if (not topCellAb.contains(instanceAb)) continue;
_flags |= YSpinSet;
int islice = (instanceAb.getYMin() - getCell()->getAbutmentBox().getYMin()) / getSliceHeight();
switch ( instanceTransf.getOrientation() ) {
case Transformation::Orientation::ID:
case Transformation::Orientation::MX:
_yspinSlice0 = (islice % 2);
break;
case Transformation::Orientation::R2:
case Transformation::Orientation::MY:
_yspinSlice0 = ((islice+1) % 2);
break;
case Transformation::Orientation::R1:
case Transformation::Orientation::R3:
case Transformation::Orientation::XR:
case Transformation::Orientation::YR:
cerr << Warning( "Instance %s has invalid transformation %s."
, getString(instance->getName()).c_str()
, getString(instanceTransf.getOrientation()).c_str()
) << endl;
_flags &= ~YSpinSet;
break;
}
if (_flags & YSpinSet) break;
}
}
return _yspinSlice0;
}
void EtesianEngine::addFeeds ()
{
UpdateSession::open();
Etesian integration with Chip & ClockTree plugins. * New: In Hurricane, in DebugSession, add a new method to activate the trace inconditionally with a certain level. * New: In Hurricane, in HyperNet, allow copy construction as there is no reason to disallow it and we need it now. * New: In Hurricane, in Cell::flattenNets(), add a new option to prevent the flattening of the clock net(s). For more safety perform the DeepNet creation *outside* the Collection loop. * Bug: In Hurricane, in Cell_HyperNetRootNetOccurrences, skip the DeepNets because they are the result of another flattening operation. * New: In Isobar, in PyBasicLayer, export C++ method getBlockageLayer(). * New: In Isobar, in PyRoutingGauge, export C++ method getLayerPitch(), needed by Cumulus plugins. * New: In Etesian, EtesianEngine::findYSpin() to look for the Y orientation if some cells are already placed. Typically the buffers of a clock tree. Pass the correct orienation to row_compatible_orientation(). Do not try to add feeds in the ISPD05 benchmarks. For now the benchmarks are detected through their names (unreliable). * Change: In Knik, in KnikEngine::initGlobalRouting(), allow the clock to be routed as an ordinary signal when the clock tree is not used. * New: In Kite, in BuildPowerRails, management & detection for the pre-routed clock. In KiteEngine constructor, early initialization of the blockage net to avoid later troubles in BuildPowerRails. * New: In Cumulus, in ChipPlugin, add support for Etesian plus new configuration parameter 'clockTree.placerEngine' to select between Mauka and Etesian. * New: In Cumulus, in BlockCorona, add blockages in the vertical sides in the vertical layer to prevent the router to use the vertical tracks in under the prower lines (for example, blockage in M3 with power line M5). In Cumulus, in ChipConf add attribute to access the blockage net. * New: In Cumulus, when the clock tree is disabled, do not generate the last rail around the block (the clock rail). * Bug: In Cumulus, in ChipConf use the clock pad to guess the clock signals and *not* the power pad. Add more meaningful error messages if a pad global signal is not found (implicit connexion by name). * Bug: In Cumulus, in ClockTree, compute correctly the cells Y spin, that is *from the bottom of the cell AB* (not from 'zero').
2015-02-24 06:13:17 -06:00
SliceHoles sliceHoles ( this );
Box topCellAb = getCell()->getAbutmentBox();
sliceHoles.setSpinSlice0( _yspinSlice0 );
forEach ( Occurrence, ioccurrence, getCell()->getLeafInstanceOccurrences() )
{
Instance* instance = static_cast<Instance*>((*ioccurrence).getEntity());
Cell* masterCell = instance->getMasterCell();
if (CatalogExtension::isFeed(masterCell)) {
cerr << Warning( "Feed instance %s already present."
, getString(instance->getName()).c_str() ) << endl;
}
Box instanceAb = masterCell->getAbutmentBox();
Transformation instanceTransf = instance->getTransformation();
(*ioccurrence).getPath().getTransformation().applyOn( instanceTransf );
instanceTransf.applyOn( instanceAb );
Etesian integration with Chip & ClockTree plugins. * New: In Hurricane, in DebugSession, add a new method to activate the trace inconditionally with a certain level. * New: In Hurricane, in HyperNet, allow copy construction as there is no reason to disallow it and we need it now. * New: In Hurricane, in Cell::flattenNets(), add a new option to prevent the flattening of the clock net(s). For more safety perform the DeepNet creation *outside* the Collection loop. * Bug: In Hurricane, in Cell_HyperNetRootNetOccurrences, skip the DeepNets because they are the result of another flattening operation. * New: In Isobar, in PyBasicLayer, export C++ method getBlockageLayer(). * New: In Isobar, in PyRoutingGauge, export C++ method getLayerPitch(), needed by Cumulus plugins. * New: In Etesian, EtesianEngine::findYSpin() to look for the Y orientation if some cells are already placed. Typically the buffers of a clock tree. Pass the correct orienation to row_compatible_orientation(). Do not try to add feeds in the ISPD05 benchmarks. For now the benchmarks are detected through their names (unreliable). * Change: In Knik, in KnikEngine::initGlobalRouting(), allow the clock to be routed as an ordinary signal when the clock tree is not used. * New: In Kite, in BuildPowerRails, management & detection for the pre-routed clock. In KiteEngine constructor, early initialization of the blockage net to avoid later troubles in BuildPowerRails. * New: In Cumulus, in ChipPlugin, add support for Etesian plus new configuration parameter 'clockTree.placerEngine' to select between Mauka and Etesian. * New: In Cumulus, in BlockCorona, add blockages in the vertical sides in the vertical layer to prevent the router to use the vertical tracks in under the prower lines (for example, blockage in M3 with power line M5). In Cumulus, in ChipConf add attribute to access the blockage net. * New: In Cumulus, when the clock tree is disabled, do not generate the last rail around the block (the clock rail). * Bug: In Cumulus, in ChipConf use the clock pad to guess the clock signals and *not* the power pad. Add more meaningful error messages if a pad global signal is not found (implicit connexion by name). * Bug: In Cumulus, in ClockTree, compute correctly the cells Y spin, that is *from the bottom of the cell AB* (not from 'zero').
2015-02-24 06:13:17 -06:00
if (not topCellAb.contains(instanceAb)) {
cerr << Warning( "Instance %s is not fully enclosed in the top cell."
, getString(instance->getName()).c_str() ) << endl;
continue;
}
sliceHoles.merge( instanceAb );
}
sliceHoles.addFeeds();
UpdateSession::close();
if (_cellWidget) _cellWidget->refresh();
}
} // Kite namespace.