Added management of tie *inside* cells.

* New: In Etesian/Placement::Area, added support to take into account
    bulk inside cells. Currently only hard-wired configuration for
    FlexLib is available. Should add a front-end to analyse the
    cells of the library to lookup for bulk ties in the future.
This commit is contained in:
Jean-Paul Chaput 2020-12-23 11:22:12 +01:00
parent 70d32528cd
commit 49ffe1e1ba
1 changed files with 274 additions and 99 deletions

View File

@ -21,9 +21,10 @@
#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/Instance.h"
#include "hurricane/Library.h"
#include "hurricane/viewer/CellWidget.h"
#include "hurricane/viewer/CellViewer.h"
#include "crlcore/AllianceFramework.h"
@ -40,18 +41,100 @@ namespace {
using Hurricane::DbU;
using Hurricane::Box;
using Hurricane::Interval;
using Hurricane::DBo;
using Hurricane::Occurrence;
using Hurricane::Instance;
using Hurricane::Path;
using Hurricane::Transformation;
using Hurricane::DataBase;
using Hurricane::Cell;
using Hurricane::Library;
using CRL::AllianceFramework;
using CRL::CatalogExtension;
using CRL::getTransformation;
using Etesian::EtesianEngine;
// -------------------------------------------------------------------
// Class : "::TieDatas".
class TieDatas {
public:
inline TieDatas ( Cell* cell=NULL, DbU::Unit leftDistance=0, DbU::Unit rightDistance=0 );
inline Cell* getCell () const;
inline DbU::Unit getLeftDistance () const;
inline DbU::Unit getRightDistance() const;
private:
Cell* _cell;
DbU::Unit _leftDistance;
DbU::Unit _rightDistance;
};
inline TieDatas::TieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
: _cell (cell)
, _leftDistance (leftDistance)
, _rightDistance(rightDistance)
{ }
inline Cell* TieDatas::getCell () const { return _cell; }
inline DbU::Unit TieDatas::getLeftDistance () const { return _leftDistance; }
inline DbU::Unit TieDatas::getRightDistance() const { return _rightDistance; }
// -------------------------------------------------------------------
// Class : "::TieLUT".
class TieLUT {
public:
inline TieLUT ();
inline const TieDatas* getTieDatas ( Cell* ) const;
inline DbU::Unit getLeftDistance ( Cell* ) const;
inline DbU::Unit getRightDistance ( Cell* ) const;
inline void addTieDatas ( Cell*, DbU::Unit leftDistance, DbU::Unit rightDistance );
private:
map< Cell*, TieDatas, DBo::CompareById > _tieLut;
};
inline TieLUT::TieLUT ()
: _tieLut()
{ }
inline void TieLUT::addTieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
{
const TieDatas* datas = getTieDatas( cell );
if (datas) {
cerr << Error( "TieLUT::addTieDatas(): Duplicate datas for % (ignoreds)."
, getString(cell).c_str()
) << endl;
}
_tieLut[ cell ] = TieDatas( cell, leftDistance, rightDistance );
}
inline const TieDatas* TieLUT::getTieDatas ( Cell* cell ) const
{
auto iDatas = _tieLut.find( cell );
return (iDatas != _tieLut.end()) ? &((*iDatas).second) : NULL;
}
inline DbU::Unit TieLUT::getLeftDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getLeftDistance() : 0;
}
inline DbU::Unit TieLUT::getRightDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getRightDistance() : 0;
}
// -------------------------------------------------------------------
// Class : "::Tile".
@ -66,6 +149,8 @@ namespace {
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline DbU::Unit getWidth () const;
inline Cell* getMasterCell () const;
inline Instance* getInstance () const;
inline const Occurrence& getOccurrence () const;
inline void translate ( DbU::Unit );
private:
@ -82,17 +167,17 @@ namespace {
inline DbU::Unit Tile::getXMax () const { return _xMin+_width; }
inline DbU::Unit Tile::getWidth () const { return _width; }
inline const Occurrence& Tile::getOccurrence () const { return _occurrence; }
inline Instance* Tile::getInstance () const { return static_cast<Instance*>( _occurrence.getEntity() ); }
inline Cell* Tile::getMasterCell () const { return getInstance()->getMasterCell(); }
inline bool Tile::isFixed () const
{
return static_cast<Instance*>( _occurrence.getEntity() )->getPlacementStatus()
== Instance::PlacementStatus::FIXED;
}
{ return getInstance()->getPlacementStatus() == Instance::PlacementStatus::FIXED; }
inline void Tile::translate ( DbU::Unit dx )
{
cerr << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << endl;
Instance* instance = static_cast<Instance*>( _occurrence.getEntity() );
cdebug_log(121,0) << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << endl;
Instance* instance = getInstance();
Transformation reference = instance->getTransformation();
Transformation transf = Transformation( reference.getTx() + dx
, reference.getTy()
@ -137,6 +222,7 @@ namespace {
SubSlice ( Slice*, const list<Tile>::iterator& beginTile );
inline const list<Tile>::iterator getBeginTile () const;
inline const list<Tile>::iterator getEndTile () const;
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
DbU::Unit getAverageChunk ( size_t& ) const;
@ -156,23 +242,25 @@ namespace {
class Slice {
public:
Slice ( Area*, DbU::Unit ybottom );
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline Interval getXSpan () const;
inline Area* getArea () const;
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
bool validate () const;
inline list<Tile>& getTiles ();
void merge ( const Occurrence&, const Box& );
void addFeeds ( size_t islice );
void fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin );
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
string _getString () const;
Slice ( Area*, DbU::Unit ybottom );
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline Interval getXSpan () const;
inline Area* getArea () const;
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
inline list<Tile>& getTiles ();
void merge ( const Occurrence&, const Box& );
void addFeeds ( size_t islice );
void fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin );
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
string _getString () const;
private:
Area* _area;
DbU::Unit _ybottom;
@ -189,15 +277,39 @@ namespace {
{ }
bool Slice::validate () const
bool Slice::validate ( DbU::Unit latchUpMax ) const
{
if (_tiles.empty()) return true;
bool validated = true;
auto iTile = _tiles.begin();
auto iTileNext = iTile;
cdebug_log(121,1) << "Slice::validate() @Y=" << DbU::getValueString(_ybottom) << endl;
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
DbU::Unit cellLength = 0;
bool validated = true;
auto iTile = _tiles.begin();
auto iTileNext = iTile;
auto iTileFeed = _tiles.begin();
++iTileNext;
while ( iTileNext != _tiles.end() ) {
cellLength += (*iTile).getWidth();
if ( ((*iTileNext).getXMin() - (*iTile).getXMax() >= feedWidth)
or ((*iTile).getMasterCell() == feed)) {
if ((*iTile).getMasterCell() == feed)
cellLength -= feedWidth;
//if (feed and ((*iTile).getMasterCell() == feed)) {
cdebug_log(121,0) << "cellLength=" << DbU::getValueString(cellLength) << endl;
if (cellLength > latchUpMax) {
while ( (iTileFeed != iTileNext) and (iTileFeed != _tiles.end()) ) {
cdebug_log(121,0) << "| " << DbU::getValueString((*iTileFeed).getXMin())
<< " " << (*iTileFeed).getOccurrence() << endl;
++iTileFeed;
}
} else {
iTileFeed = iTileNext;
}
cellLength = 0;
}
if ((*iTile).getXMax() > (*iTileNext).getXMin()) {
cerr << Error( "Slice::validate(): Overlap in slice @%s between instances,\n"
" %s @%s\n"
@ -213,6 +325,7 @@ namespace {
++iTile; ++iTileNext;
}
cdebug_log(121,-1);
return validated;
}
@ -251,23 +364,24 @@ namespace {
{
if (_tiles.empty()) return;
cerr << "+ Slice @" << DbU::getValueString(_ybottom) << endl;
cdebug_log(121,0) << "+ Slice @" << DbU::getValueString(_ybottom) << endl;
for ( const SubSlice& subSlice : _subSlices ) {
size_t count = 0;
DbU::Unit avg = subSlice.getAverageChunk( count );
cerr << "| [" << DbU::getValueString(subSlice.getXMin())
<< " " << DbU::getValueString(subSlice.getXMax())
<< "] tiles:" << count
<< " avg:" << DbU::getValueString(avg)
<< " " << endl;
cdebug_log(121,0) << "| [" << DbU::getValueString(subSlice.getXMin())
<< " " << DbU::getValueString(subSlice.getXMax())
<< "] tiles:" << count
<< " avg:" << DbU::getValueString(avg)
<< " " << endl;
}
}
void Slice::insertTies ( DbU::Unit latchUpMax )
{
cerr << "Slice::insertTies() @" << DbU::getValueString(_ybottom) << endl;
cdebug_log(121,1) << "Slice::insertTies() @" << DbU::getValueString(_ybottom) << endl;
for ( SubSlice& subSlice : _subSlices ) subSlice.insertTies( latchUpMax );
cdebug_tabw(121,-1);
}
@ -346,21 +460,24 @@ namespace {
class Area {
public:
Area ( EtesianEngine* );
~Area ();
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline void setSpinSlice0 ( size_t );
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
bool validate () const;
void merge ( const Occurrence&, const Box& );
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Area ( EtesianEngine* );
~Area ();
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline void setSpinSlice0 ( size_t );
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
void merge ( const Occurrence&, const Box& );
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
private:
EtesianEngine* _etesian;
TieLUT _tieLut;
Box _cellAb;
DbU::Unit _sliceHeight;
vector<Slice*> _slices;
@ -370,6 +487,7 @@ namespace {
Area::Area ( EtesianEngine* etesian )
: _etesian (etesian)
, _tieLut ()
, _cellAb (etesian->getBlockCell()->getAbutmentBox())
, _sliceHeight(_etesian->getSliceHeight())
, _slices ()
@ -377,6 +495,18 @@ namespace {
size_t slicesNb = _cellAb.getHeight() / _sliceHeight;
for ( size_t islice=0 ; islice<slicesNb ; ++islice )
_slices.push_back( new Slice( this, _cellAb.getYMin()+islice*_sliceHeight ) );
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
if (feed) {
Library* library = feed->getLibrary();
if (feed->getLibrary()->getName() == "FlexLib") {
cmess2 << " o Using hard-coded tie/cell datas suited for \"FlexLib\"." << endl;
Cell* masterCell = library->getCell( "sff1_x4" );
if (masterCell) {
_tieLut.addTieDatas( masterCell, DbU::fromMicrons(1.28), DbU::fromMicrons(11.7) );
}
}
}
}
@ -387,18 +517,20 @@ namespace {
}
inline EtesianEngine* Area::getEtesian () const { return _etesian; }
inline size_t Area::getSpinSlice0 () const { return _spinSlice0; }
inline void Area::setSpinSlice0 ( size_t spinSlice0 ) { _spinSlice0 = spinSlice0; }
inline DbU::Unit Area::getXMin () const { return _cellAb.getXMin(); }
inline DbU::Unit Area::getXMax () const { return _cellAb.getXMax(); }
inline EtesianEngine* Area::getEtesian () const { return _etesian; }
inline size_t Area::getSpinSlice0 () const { return _spinSlice0; }
inline void Area::setSpinSlice0 ( size_t spinSlice0 ) { _spinSlice0 = spinSlice0; }
inline DbU::Unit Area::getXMin () const { return _cellAb.getXMin(); }
inline DbU::Unit Area::getXMax () const { return _cellAb.getXMax(); }
inline DbU::Unit Area::getLeftDistance ( Cell* cell ) const { return _tieLut.getLeftDistance(cell); }
inline DbU::Unit Area::getRightDistance ( Cell* cell ) const { return _tieLut.getRightDistance(cell); }
bool Area::validate () const
bool Area::validate ( DbU::Unit latchUpMax ) const
{
bool validated = true;
for ( const Slice* slice : _slices )
validated = validated and slice->validate();
validated = slice->validate(latchUpMax) and validated;
return validated;
}
@ -438,7 +570,7 @@ namespace {
void Area::insertTies ( DbU::Unit latchUpMax )
{
for ( Slice* slice : _slices ) slice->insertTies( latchUpMax );
validate();
validate( latchUpMax );
}
@ -454,6 +586,7 @@ namespace {
}
}
inline DbU::Unit SubSlice::getYBottom () const { return _slice->getYBottom(); }
inline DbU::Unit SubSlice::getXMin () const
{ return (_beginTile == _slice->getTiles().begin()) ? _slice->getXMin() : (*_beginTile).getXMin(); }
@ -485,6 +618,16 @@ namespace {
void SubSlice::insertTies ( DbU::Unit latchUpMax )
{
size_t count = 0;
DbU::Unit averageChunk = getAverageChunk( count );
if (averageChunk > latchUpMax) {
cerr << Error( "SubSlice::insertTies(): Not enough free space to insert polarization ties.\n"
" @Y=%s, begin=%s"
, getString(DbU::getValueString(getYBottom())).c_str()
, getString((*_beginTile).getOccurrence()).c_str()
) << endl;
}
Cell* feed = _slice->getEtesian()->getFeedCells().getBiggestFeed();
if (feed == NULL) {
cerr << Error( "SubSlice::insertTies(): No feed has been registered, ignoring." ) << endl;
@ -492,8 +635,8 @@ namespace {
}
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
cerr << "SubSlice::insterTies(): LatchUpMax:" << DbU::getValueString( latchUpMax ) << endl;
cerr << " Direct subSlice walkthrough." << endl;
cdebug_log(121,1) << "SubSlice::insterTies(): LatchUpMax:" << DbU::getValueString( latchUpMax ) << endl;
cdebug_log(121,1) << "Direct subSlice walkthrough." << endl;
DbU::Unit xMin = getXMin();
DbU::Unit xMax = getXMax();
@ -514,15 +657,23 @@ namespace {
DbU::Unit tileLength = 0;
auto iTile = _beginTile;
while ( true ) {
Instance* instance = (*iTile).getInstance();
DbU::Unit cellTieLeft = _slice->getLeftDistance ( instance->getMasterCell() );
DbU::Unit cellTieRight = _slice->getRightDistance( instance->getMasterCell() );
DbU::Unit dxLeft = (*iTile).getXMin() - leftPosition;
if (dxLeft >= feedWidth) {
cerr << " Enough space, reset rigth shift." << endl;
cdebug_log(121,0) << "Enough space, reset rigth shift." << endl;
leftPosition = (*iTile).getXMin();
tileLength = 0;
}
if (cellTieLeft) {
cdebug_log(121,0) << instance->getName() << " contains a tie, reset tile length." << endl;
tileLength = cellTieRight;
}
if (tileLength + (*iTile).getWidth() > latchUpMax) {
cerr << " Length above threshold, insert tie space." << endl;
cdebug_log(121,0) << "Length above threshold, insert tie space." << endl;
leftPosition += feedWidth;
tileLength = 0;
}
@ -535,62 +686,86 @@ namespace {
++iTile;
}
cerr << " Reverse subSlice walkthrough (feedWidth:" << DbU::getValueString(feedWidth) << ")" << endl;
leftPosition = xMax;
iTile = endTile;
if (iTile == _slice->getTiles().end()) --iTile;
cdebug_tabw(121,-1);
cdebug_log(121,1) << "Reverse subSlice walkthrough, in excess of "
<< DbU::getValueString((*iTile).getXMax() - leftPosition)
<< " (feedWidth:" << DbU::getValueString(feedWidth) << ")" << endl;
if ((*iTile).getXMax() > leftPosition) {
tileLength = 0;
DbU::Unit prevDxRight = (*iTile).getXMax() - leftPosition;
DbU::Unit prevTileShift = leftPosition - (*iTile).getXMax();
while ( true ) {
DbU::Unit dxRight = (*iTile).getXMax() - leftPosition;
if (dxRight <= 0) {
cerr << " Negative dxRight, all shift has been compensated." << endl;
Instance* instance = (*iTile).getInstance();
DbU::Unit cellTieLeft = _slice->getLeftDistance ( instance->getMasterCell() );
DbU::Unit cellTieRight = _slice->getRightDistance( instance->getMasterCell() );
if (cellTieRight) {
cdebug_log(121,0) << instance->getName() << " contains a tie, reset tile length." << endl;
tileLength = cellTieLeft - (*iTile).getWidth();
}
DbU::Unit tileShift = leftPosition - (*iTile).getXMax();
cdebug_log(121,0) << "tileShift=" << DbU::getValueString(tileShift)
<< " leftHole=" << DbU::getValueString(prevTileShift-tileShift)
<< endl;
DbU::Unit holeLength = tileShift - prevTileShift;
if (holeLength == 0) {
cdebug_log(121,0) << "No change in shift (no hole, abuted tiles)." << endl;
} else {
if (holeLength < feedWidth) {
cdebug_log(121,0) << "Hole is less than a feed width ("
<< DbU::getValueString(holeLength) << " < "
<< DbU::getValueString(feedWidth) << "), should not occur." << endl;
} else {
if (tileLength+(*iTile).getWidth() < latchUpMax) {
cdebug_log(121,0) << "Absorbing whole shift (below latch up distance, tile length="
<< DbU::getValueString(tileLength) << ")" << endl;
} else {
cdebug_log(121,0) << "Absorbing shift, keeping one feed spacing." << endl;
leftPosition -= feedWidth;
tileLength = 0;
}
}
}
cdebug_log(121,0) << "Left position (+width) " << DbU::getValueString(leftPosition)
<< " width:" << DbU::getValueString((*iTile).getWidth()) << endl;
if (leftPosition > (*iTile).getXMax()) {
cdebug_log(121,0) << "Positive tileShift, all excess has been compensated." << endl;
break;
}
DbU::Unit leftHole = prevDxRight - dxRight;
if (leftHole > feedWidth) {
cerr << " Absorbing shift (wide hole)" << endl;
leftHole -= feedWidth;
leftPosition += leftHole;
prevDxRight = dxRight - leftHole;
tileLength = 0;
} else if (leftHole != 0) {
if (tileLength+(*iTile).getWidth() < latchUpMax) {
cerr << " Absorbing shift (full, below latchUp) delta leftPos:"
<< DbU::getValueString(leftHole) << endl;
leftHole = 0;
} else {
cerr << " Keeping spacing." << endl;
leftPosition -= leftHole;
tileLength = 0;
}
prevDxRight = dxRight - leftHole;
} else {
cerr << " No change in shift." << endl;
}
cerr << " Left position (+width) " << DbU::getValueString(leftPosition)
<< " width:" << DbU::getValueString((*iTile).getWidth()) << endl;
(*iTile).translate( leftPosition - (*iTile).getXMax() );
leftPosition -= (*iTile).getWidth();
tileLength += (*iTile).getWidth();
if (iTile == _beginTile) break;
if (iTile == _beginTile) {
cerr << Error( "SubSlice::insertTies(): Not enough free space to insert polarization ties.\n"
" @Y=%s, begin=%s"
, getString(DbU::getValueString(getYBottom())).c_str()
, getString((*iTile).getOccurrence()).c_str()
) << endl;
break;
}
--iTile;
}
}
cdebug_tabw(121,-2);
}
inline DbU::Unit Slice::getYBottom () const { return _ybottom; }
inline DbU::Unit Slice::getXMin () const { return _area->getXMin(); }
inline DbU::Unit Slice::getXMax () const { return _area->getXMax(); }
inline Interval Slice::getXSpan () const { return Interval( getXMin(), getXMax() ); }
inline Area* Slice::getArea () const { return _area; }
inline EtesianEngine* Slice::getEtesian () const { return getArea()->getEtesian(); }
inline size_t Slice::getSpinSlice0 () const { return getArea()->getSpinSlice0(); }
inline list<Tile>& Slice::getTiles () { return _tiles; }
inline DbU::Unit Slice::getYBottom () const { return _ybottom; }
inline DbU::Unit Slice::getXMin () const { return _area->getXMin(); }
inline DbU::Unit Slice::getXMax () const { return _area->getXMax(); }
inline DbU::Unit Slice::getLeftDistance ( Cell* cell ) const { return _area->getLeftDistance(cell); }
inline DbU::Unit Slice::getRightDistance ( Cell* cell ) const { return _area->getRightDistance(cell); }
inline Interval Slice::getXSpan () const { return Interval( getXMin(), getXMax() ); }
inline Area* Slice::getArea () const { return _area; }
inline EtesianEngine* Slice::getEtesian () const { return getArea()->getEtesian(); }
inline size_t Slice::getSpinSlice0 () const { return getArea()->getSpinSlice0(); }
inline list<Tile>& Slice::getTiles () { return _tiles; }
} // Anonymous namespace.
@ -662,8 +837,8 @@ namespace Etesian {
area.buildSubSlices();
area.showSubSlices();
if (getConfiguration()->getLatchUpDistance()) {
DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2;
Cell* feed = getFeedCells().getBiggestFeed();
DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2 - feed->getAbutmentBox().getWidth();
if (feed != NULL)
tieSpacing -= feed->getAbutmentBox().getWidth();
area.insertTies( tieSpacing );