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:
parent
4ab6888b94
commit
76d468f6d5
|
@ -359,6 +359,12 @@ namespace Etesian {
|
||||||
string feedNames = getConfiguration()->getFeedNames();
|
string feedNames = getConfiguration()->getFeedNames();
|
||||||
char separator = ',';
|
char separator = ',';
|
||||||
|
|
||||||
|
if (feedNames.empty()) {
|
||||||
|
cerr << Warning( "EtesianEngine::_postCreate() No feed cells configured.\n"
|
||||||
|
" (please configure \"cfg.etesian.feedNames\")"
|
||||||
|
) << endl;
|
||||||
|
}
|
||||||
|
|
||||||
while ( not feedNames.empty() ) {
|
while ( not feedNames.empty() ) {
|
||||||
size_t cut = feedNames.find( separator );
|
size_t cut = feedNames.find( separator );
|
||||||
string feedName;
|
string feedName;
|
||||||
|
@ -388,6 +394,10 @@ namespace Etesian {
|
||||||
tie = AllianceFramework::get()->getCell( tieName, Catalog::State::Views|Catalog::State::Foreign );
|
tie = AllianceFramework::get()->getCell( tieName, Catalog::State::Views|Catalog::State::Foreign );
|
||||||
if (tie)
|
if (tie)
|
||||||
_feedCells.useTie( tie );
|
_feedCells.useTie( tie );
|
||||||
|
else
|
||||||
|
cerr << Warning( "EtesianEngine::_postCreate() Unable to find \"%s\" tie cell."
|
||||||
|
, tieName.c_str()
|
||||||
|
) << endl;
|
||||||
}
|
}
|
||||||
_sliceHeight = getCellGauge()->getSliceHeight();
|
_sliceHeight = getCellGauge()->getSliceHeight();
|
||||||
|
|
||||||
|
|
|
@ -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
|
string FeedCells::getUniqueInstanceName () const
|
||||||
{
|
{
|
||||||
ostringstream name;
|
ostringstream name;
|
||||||
|
|
|
@ -243,8 +243,45 @@ namespace Etesian {
|
||||||
modulo = (xmax - getXMin()) % getEtesian()->getSliceStep();
|
modulo = (xmax - getXMin()) % getEtesian()->getSliceStep();
|
||||||
if (modulo) xmax -= modulo;
|
if (modulo) xmax -= modulo;
|
||||||
|
|
||||||
Cell* tie = getEtesian()->getFeedCells().getTie();
|
DbU::Unit feedWidth = feed->getAbutmentBox().getWidth();
|
||||||
DbU::Unit feedWidth = 0;
|
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) {
|
if (tie) {
|
||||||
DbU::Unit feedWidth = tie->getAbutmentBox().getWidth();
|
DbU::Unit feedWidth = tie->getAbutmentBox().getWidth();
|
||||||
if (xtie+feedWidth < xmax) {
|
if (xtie+feedWidth < xmax) {
|
||||||
|
@ -292,43 +329,6 @@ namespace Etesian {
|
||||||
} else {
|
} else {
|
||||||
cerr << Error("Slice::fillHole(): No tie has been registered, not inserting.") << endl;
|
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;
|
return NULL;
|
||||||
}
|
}
|
||||||
Cell* tie = getEtesian()->getFeedCells().getTie();
|
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;
|
cerr << Error("Slice::createDiodeUnder(): No tie has been registered, ignoring.") << endl;
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
@ -361,6 +361,7 @@ namespace Etesian {
|
||||||
DbU::Unit dCandidate = 0;
|
DbU::Unit dCandidate = 0;
|
||||||
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
|
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
|
||||||
if ((*iTile).getXMax() <= diodeArea.getXMin()) continue;
|
if ((*iTile).getXMax() <= diodeArea.getXMin()) continue;
|
||||||
|
if ((*iTile).getXMin() < diodeArea.getXMin()) continue;
|
||||||
if ((*iTile).getXMin() >= diodeArea.getXMax()) break;
|
if ((*iTile).getXMin() >= diodeArea.getXMax()) break;
|
||||||
cdebug_log(147,0) << "| " << (*iTile) << endl;
|
cdebug_log(147,0) << "| " << (*iTile) << endl;
|
||||||
if ( ((*iTile).getMasterCell() != feed)
|
if ( ((*iTile).getMasterCell() != feed)
|
||||||
|
@ -385,15 +386,17 @@ namespace Etesian {
|
||||||
auto before = iCandidate;
|
auto before = iCandidate;
|
||||||
before++;
|
before++;
|
||||||
|
|
||||||
DbU::Unit xmin = (*iCandidate).getXMin();
|
DbU::Unit xmin = (*iCandidate).getXMin();
|
||||||
DbU::Unit width = (*iCandidate).getWidth();
|
DbU::Unit width = (*iCandidate).getWidth();
|
||||||
|
DbU::Unit fillerWidth = width - diode->getAbutmentBox().getWidth();
|
||||||
diodeInst = (*iCandidate).getInstance();
|
diodeInst = (*iCandidate).getInstance();
|
||||||
Transformation transf = diodeInst->getTransformation();
|
Transformation refTransf = diodeInst->getTransformation();
|
||||||
_tiles.erase( iCandidate );
|
_tiles.erase( iCandidate );
|
||||||
diodeInst->destroy();
|
diodeInst->destroy();
|
||||||
|
|
||||||
Occurrence rpOccurrence = rp->getPlugOccurrence();
|
Occurrence rpOccurrence = rp->getPlugOccurrence();
|
||||||
Path instancePath = rpOccurrence.getPath();
|
Path instancePath = rpOccurrence.getPath();
|
||||||
|
Transformation transf = refTransf;
|
||||||
if (instancePath.isEmpty())
|
if (instancePath.isEmpty())
|
||||||
transf = getEtesian()->toCell( transf );
|
transf = getEtesian()->toCell( transf );
|
||||||
// transf = getEtesian()->toBlock( transf );
|
// transf = getEtesian()->toBlock( transf );
|
||||||
|
@ -410,6 +413,24 @@ namespace Etesian {
|
||||||
_tiles.insert( before, Tile(xmin,width,Occurrence(diodeInst,instancePath)) );
|
_tiles.insert( before, Tile(xmin,width,Occurrence(diodeInst,instancePath)) );
|
||||||
cdebug_log(147,0) << " " << diodeInst << " @" << transf << endl;
|
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;
|
return diodeInst;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,6 +21,7 @@
|
||||||
|
|
||||||
namespace Etesian {
|
namespace Etesian {
|
||||||
|
|
||||||
|
using Hurricane::DbU;
|
||||||
using Hurricane::Cell;
|
using Hurricane::Cell;
|
||||||
class EtesianEngine;
|
class EtesianEngine;
|
||||||
|
|
||||||
|
@ -35,6 +36,7 @@ namespace Etesian {
|
||||||
Cell* getSmallestFeed () const;
|
Cell* getSmallestFeed () const;
|
||||||
inline Cell* getTie () const;
|
inline Cell* getTie () const;
|
||||||
Cell* getFeed ( int pitches ) const;
|
Cell* getFeed ( int pitches ) const;
|
||||||
|
Cell* getFeedByWidth ( DbU::Unit width ) const;
|
||||||
std::string getUniqueInstanceName () const;
|
std::string getUniqueInstanceName () const;
|
||||||
private:
|
private:
|
||||||
EtesianEngine* _etesian;
|
EtesianEngine* _etesian;
|
||||||
|
|
Loading…
Reference in New Issue