Change in feed & tie managements to fill the empty row spaces.

* Change: In EtesianEngine::_postCreate(), issue a warning if the list of
    feeds is empy (configuration: "cfg.etesian.feedNames").
* New: Add a FeedCeels::getFeedByWidth() method to get feeds by their
    width in DbU::Unit and not only pitches.
* Change: In Placement::Slice::fillHole(), invert the tie filling and
    feeds filling stage. Now we first try to fill the row hole with
    feeds, using the widest first, and if they are not configured or
    too wide, use the tie.
      As the tie *should* also be integrated in the feed list, we may
    suppress altogether the fallback tie filling step. Keep it for now.
* Change: In Placement::slice::createDiodeUnder(), the inserted diode
    *may* be smaller than the feed it replace. So, in this case, add
    a complementary feed to fill the gap.
    NOTE 1: Out of lazyness, we add only *one* complementary filler
            cell. So there *must* be one of a width wich correspond
	    exactly to the difference between the original feed and
	    the diode. Otherwise, gap will remains.
    NOTE 2: With wider feed cells, they may cross the GCell border.
            But we must insert the diode under the GCell, otherwise
	    the global routing will be defective. So, for now, reject
	    feeds that cross the boundary. Must be done more smartly
	    by inserting the diode over the left or right side of
	    the feed.
This commit is contained in:
Jean-Paul Chaput 2021-12-17 15:58:13 +01:00
parent 4ab6888b94
commit 76d468f6d5
4 changed files with 88 additions and 45 deletions

View File

@ -359,6 +359,12 @@ namespace Etesian {
string feedNames = getConfiguration()->getFeedNames();
char separator = ',';
if (feedNames.empty()) {
cerr << Warning( "EtesianEngine::_postCreate() No feed cells configured.\n"
" (please configure \"cfg.etesian.feedNames\")"
) << endl;
}
while ( not feedNames.empty() ) {
size_t cut = feedNames.find( separator );
string feedName;
@ -388,6 +394,10 @@ namespace Etesian {
tie = AllianceFramework::get()->getCell( tieName, Catalog::State::Views|Catalog::State::Foreign );
if (tie)
_feedCells.useTie( tie );
else
cerr << Warning( "EtesianEngine::_postCreate() Unable to find \"%s\" tie cell."
, tieName.c_str()
) << endl;
}
_sliceHeight = getCellGauge()->getSliceHeight();

View File

@ -101,6 +101,16 @@ namespace Etesian {
}
Cell* FeedCells::getFeedByWidth ( DbU::Unit width ) const
{
for ( auto item : _feedCells ) {
if (item.second->getAbutmentBox().getWidth() == width)
return item.second;
}
return NULL;
}
string FeedCells::getUniqueInstanceName () const
{
ostringstream name;

View File

@ -243,8 +243,45 @@ namespace Etesian {
modulo = (xmax - getXMin()) % getEtesian()->getSliceStep();
if (modulo) xmax -= modulo;
Cell* tie = getEtesian()->getFeedCells().getTie();
DbU::Unit feedWidth = 0;
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
while ( true ) {
if (xtie >= xmax) return;
if (xtie+feedWidth > xmax) {
// Feed is too big, try to find a smaller one.
feed = NULL;
int pitch = (int)((xmax-xtie) / getEtesian()->getSliceStep());
for ( ; pitch > 0 ; --pitch ) {
feed = getEtesian()->getFeedCells().getFeed( pitch );
if (feed == NULL) continue;
feedWidth = feed->getAbutmentBox().getWidth();
if (feed != NULL) break;
}
if (feed == NULL) break;
}
Point blockPoint = getEtesian()->toBlock( Point(xtie,_ybottom) );
Instance* instance = Instance::create
( getEtesian()->getBlockCell()
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, feed
, getTransformation( feed->getAbutmentBox()
, blockPoint.getX()
, blockPoint.getY()
, (yspin) ? Transformation::Orientation::MY
: Transformation::Orientation::ID
)
, Instance::PlacementStatus::PLACED
);
_tiles.insert( before
, Tile( xtie
, feed->getAbutmentBox().getWidth()
, getEtesian()->toCell( Occurrence(instance) )));
xtie += feedWidth;
}
Cell* tie = getEtesian()->getFeedCells().getTie();
feedWidth = 0;
if (tie) {
DbU::Unit feedWidth = tie->getAbutmentBox().getWidth();
if (xtie+feedWidth < xmax) {
@ -292,43 +329,6 @@ namespace Etesian {
} else {
cerr << Error("Slice::fillHole(): No tie has been registered, not inserting.") << endl;
}
feedWidth = feed->getAbutmentBox().getWidth();
while ( true ) {
if (xtie >= xmax) break;
if (xtie+feedWidth > xmax) {
// Feed is too big, try to find a smaller one.
feed = NULL;
int pitch = (int)((xmax-xtie) / getEtesian()->getSliceStep());
for ( ; pitch > 0 ; --pitch ) {
feed = getEtesian()->getFeedCells().getFeed( pitch );
if (feed == NULL) continue;
feedWidth = feed->getAbutmentBox().getWidth();
if (feed != NULL) break;
}
if (feed == NULL) break;
}
Point blockPoint = getEtesian()->toBlock( Point(xtie,_ybottom) );
Instance* instance = Instance::create
( getEtesian()->getBlockCell()
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, feed
, getTransformation( feed->getAbutmentBox()
, blockPoint.getX()
, blockPoint.getY()
, (yspin) ? Transformation::Orientation::MY
: Transformation::Orientation::ID
)
, Instance::PlacementStatus::PLACED
);
_tiles.insert( before
, Tile( xtie
, feed->getAbutmentBox().getWidth()
, getEtesian()->toCell( Occurrence(instance) )));
xtie += feedWidth;
}
}
@ -345,7 +345,7 @@ namespace Etesian {
return NULL;
}
Cell* tie = getEtesian()->getFeedCells().getTie();
if (tie == NULL) {
if (not feed and not tie) {
cerr << Error("Slice::createDiodeUnder(): No tie has been registered, ignoring.") << endl;
return NULL;
}
@ -361,6 +361,7 @@ namespace Etesian {
DbU::Unit dCandidate = 0;
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
if ((*iTile).getXMax() <= diodeArea.getXMin()) continue;
if ((*iTile).getXMin() < diodeArea.getXMin()) continue;
if ((*iTile).getXMin() >= diodeArea.getXMax()) break;
cdebug_log(147,0) << "| " << (*iTile) << endl;
if ( ((*iTile).getMasterCell() != feed)
@ -385,15 +386,17 @@ namespace Etesian {
auto before = iCandidate;
before++;
DbU::Unit xmin = (*iCandidate).getXMin();
DbU::Unit width = (*iCandidate).getWidth();
DbU::Unit xmin = (*iCandidate).getXMin();
DbU::Unit width = (*iCandidate).getWidth();
DbU::Unit fillerWidth = width - diode->getAbutmentBox().getWidth();
diodeInst = (*iCandidate).getInstance();
Transformation transf = diodeInst->getTransformation();
Transformation refTransf = diodeInst->getTransformation();
_tiles.erase( iCandidate );
diodeInst->destroy();
Occurrence rpOccurrence = rp->getPlugOccurrence();
Path instancePath = rpOccurrence.getPath();
Occurrence rpOccurrence = rp->getPlugOccurrence();
Path instancePath = rpOccurrence.getPath();
Transformation transf = refTransf;
if (instancePath.isEmpty())
transf = getEtesian()->toCell( transf );
// transf = getEtesian()->toBlock( transf );
@ -410,6 +413,24 @@ namespace Etesian {
_tiles.insert( before, Tile(xmin,width,Occurrence(diodeInst,instancePath)) );
cdebug_log(147,0) << " " << diodeInst << " @" << transf << endl;
if (fillerWidth > 0) {
Cell* filler = getEtesian()->getFeedCells().getFeedByWidth( fillerWidth );
if (not filler) {
cerr << Error("Slice::createDiodeUnder(): No gap filler of width %s."
, DbU::getValueString(fillerWidth).c_str() ) << endl;
return diodeInst;
}
transf = refTransf;
Transformation( fillerWidth, 0 ).applyOn( transf );
Instance* fillerInst = Instance::create( getEtesian()->getBlockCell()
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, filler
, transf
, Instance::PlacementStatus::FIXED );
_tiles.insert( before, Tile(xmin+width,fillerWidth,Occurrence(fillerInst,instancePath)) );
cdebug_log(147,0) << " " << fillerInst << " @" << transf << endl;
}
return diodeInst;
}

View File

@ -21,6 +21,7 @@
namespace Etesian {
using Hurricane::DbU;
using Hurricane::Cell;
class EtesianEngine;
@ -35,6 +36,7 @@ namespace Etesian {
Cell* getSmallestFeed () const;
inline Cell* getTie () const;
Cell* getFeed ( int pitches ) const;
Cell* getFeedByWidth ( DbU::Unit width ) const;
std::string getUniqueInstanceName () const;
private:
EtesianEngine* _etesian;