From 8fdaf47f3d0bc2a2d16e23a874526ad7ef82da36 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 17 Dec 2020 10:22:43 +0100 Subject: [PATCH] Second attempt at tie insertion. Works, but disturb placement. * New: In Etesian::Configuration, added "etesian.lacthUpDistance" to control tie cells insertion (for polarization contacts). * New: Etesian/Placement as a complete replacement for FeedCells. Rebuild the complete slicing structure of the placement to serve as a building block for post-placement changes under Coriolis. Currently used to regularly insert body ties. This is not optimal as we displace cells in each slice in a non-coordinated manner. * New: In cumulus/plugins/block.configuration.FeedsConf, register the "etesian.latchUpDistance" parameter. Provides the tie width. * New: In cumulus/plugins.block.spares, add ties around the buffer pool block and "cap ties" at both end of each slice. --- .../src/plugins/alpha/block/configuration.py | 25 +- cumulus/src/plugins/alpha/block/spares.py | 91 ++- etesian/src/CMakeLists.txt | 1 + etesian/src/Configuration.cpp | 23 +- etesian/src/EtesianEngine.cpp | 3 +- etesian/src/Placement.cpp | 679 ++++++++++++++++++ etesian/src/etesian/Configuration.h | 84 ++- etesian/src/etesian/EtesianEngine.h | 1 + 8 files changed, 815 insertions(+), 92 deletions(-) create mode 100644 etesian/src/Placement.cpp diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 472daa2b..c256b172 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -819,9 +819,11 @@ class FeedsConf ( object ): Store informations about feed cells and how to fill a gap. """ - def __init__ ( self, framework ): + def __init__ ( self, framework, cfg ): trace( 550, ',+', '\tFeedsConf.__init__()\n' ) - feeds = Cfg.getParamString('etesian.feedNames').asString().split(',') + cfg.etesian.feedNames = None + cfg.etesian.latchUpDistance = None + feeds = cfg.etesian.feedNames.split(',') self.count = 0 self.feeds = [] for feedName in feeds: @@ -832,6 +834,8 @@ class FeedsConf ( object ): continue feedWidth = feedCell.getAbutmentBox().getWidth() self.feeds.append( (feedWidth,feedCell) ) + if cfg.etesian.latchUpDistance is not None: + self.maxFeedSpacing = cfg.etesian.latchUpDistance - self.tieWidth() self.feeds.sort( key=itemgetter(0) ) self.feeds.reverse() for i in range(len(self.feeds)): @@ -840,6 +844,11 @@ class FeedsConf ( object ): trace( 550, '-' ) return + def tieWidth ( self ): + """Returns the master cell abutment box width of the tie.""" + if self.feeds: return self.feeds[0][0] + return None + def createFeed ( self, cell ): instance = Instance.create( cell, 'spare_feed_{}'.format(self.count), self.feeds[0][1] ) self.count += 1 @@ -1061,7 +1070,7 @@ class BlockConf ( GaugeConf ): self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive) self.bufferConf = BufferConf( self.framework ) self.constantsConf = ConstantsConf( self.framework, self.cfg ) - self.feedsConf = FeedsConf( self.framework ) + self.feedsConf = FeedsConf( self.framework, self.cfg ) self.chipConf = ChipConf( self ) self.bColumns = 2 self.bRows = 2 @@ -1083,9 +1092,10 @@ class BlockConf ( GaugeConf ): self.ioPins.append( IoPin( *ioPinSpec ) ) for line in range(len(ioPads)): self.chipConf.addIoPad( ioPads[line], line ) - self.cfg.etesian.aspectRatio = None - self.cfg.etesian.spaceMargin = None - self.cfg.block.spareSide = None + self.cfg.etesian.aspectRatio = None + self.cfg.etesian.spaceMargin = None + self.cfg.etesian.latchUpDistance = None + self.cfg.block.spareSide = None @property def isCoreBlock ( self ): return self.chip is not None @@ -1148,6 +1158,9 @@ class BlockConf ( GaugeConf ): def createBuffer ( self ): return self.bufferConf.createBuffer( self.cellPnR ) + def createFeed ( self ): + return self.feedsConf.createFeed( self.cellPnR ) + def setDeltaAb ( self, dx1, dy1, dx2, dy2 ): self.deltaAb = [ dx1, dy1, dx2, dy2 ] diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index e1f5de20..171cfeeb 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -133,12 +133,12 @@ class BufferPool ( object ): yoffset = 0 if self.quadTree.spares.conf.isCoreBlock: yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy() - conf = self.quadTree.spares.conf - sliceHeight = conf.sliceHeight - x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter() - - (conf.bufferConf.width * self.columns)/2 ) - y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter() - - (conf.bufferConf.height * self.rows)/2 ) + conf = self.quadTree.spares.conf + sliceHeight = conf.sliceHeight + poolHalfWidth = (conf.bufferConf.width * self.columns)/2 + conf.feedsConf.tieWidth() + poolHalfHeight = (conf.bufferConf.height * self.rows)/2 + x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter() - poolHalfWidth ) + y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter() - poolHalfHeight ) slice = (y - yoffset) / sliceHeight trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) ) trace( 540, '\tSlice #{} (y:{})\n'.format(slice,DbU.getValueString(y)) ) @@ -148,38 +148,25 @@ class BufferPool ( object ): if (slice+row)%2: orientation = Transformation.Orientation.MY y += sliceHeight - for column in range(self.columns): - index = self.toIndex(column,row) - transf = Transformation( x + column*conf.bufferConf.width, y, orientation ) - instance = conf.createBuffer() + length = 0 + for column in range(self.columns+2): + transf = Transformation( x + length, y, orientation ) + if (column > 0) and (column <= self.columns): + index = self.toIndex(column-1,row) + instance = conf.createBuffer() + self.buffers[ index ][1] = instance + trace( 540, '\tBuffer[{}]: {} @{}\n'.format(index,self.buffers[index],transf) ) + else: + instance = conf.createFeed() instance.setTransformation( transf ) instance.setPlacementStatus( Instance.PlacementStatus.FIXED ) - self.buffers[ index ][1] = instance - trace( 540, '\tBuffer[{}]: {} @{}\n'.format(index,self.buffers[index],transf) ) + length += instance.getMasterCell().getAbutmentBox().getWidth() blBufAb = self.buffers[ 0][1].getAbutmentBox() trBufAb = self.buffers[-1][1].getAbutmentBox() self.area = Box( blBufAb.getXMin(), blBufAb.getYMin() , trBufAb.getXMax(), trBufAb.getYMax() ) trace( 540, '-' ) - def _getTransformation ( self, spareX, spareY ): - """Transform (spareX,spareY) into sliced coordinates relatives to the corona.""" - conf = self.quadTree.spares.conf - yoffset = 0 - if conf.isCoreBlock: - yoffset = conf.icore.getTransformation().getTy() - sliceHeight = conf.sliceHeight - x = self.quadTree.spares.toXPitch( spareX ) - y = self.quadTree.spares.toYSlice( spareY ) - slice = (y - yoffset) / sliceHeight - orientation = Transformation.Orientation.ID - y = slice * sliceHeight + yoffset - if slice % 2: - orientation = Transformation.Orientation.MY - y += sliceHeight - transf = Transformation( x, y, orientation ) - return transf - def _createTies ( self ): trace( 540, ',+', '\tQuadTree._createTies()\n' ) conf = self.quadTree.spares.conf @@ -809,10 +796,51 @@ class Spares ( object ): if self.conf.isCoreBlock: offset = self.conf.icore.getTransformation().getTy() self.conf.icore.getTransformation().applyOn( area ) - trace( 540, '\toffset:{}\n'.format(DbU.getValueString(offset)) ) + #trace( 540, '\toffset:{}\n'.format(DbU.getValueString(offset)) ) modulo = (y - offset - area.getYMin()) % self.conf.sliceHeight return y - modulo + def _getTransformation ( self, spareX, spareY ): + """Transform (spareX,spareY) into sliced coordinates relatives to the corona.""" + yoffset = 0 + if self.conf.isCoreBlock: + yoffset = self.conf.icore.getTransformation().getTy() + sliceHeight = self.conf.sliceHeight + x = self.toXPitch( spareX ) + y = self.toYSlice( spareY ) + slice = (y - yoffset) / sliceHeight + orientation = Transformation.Orientation.ID + y = slice * sliceHeight + yoffset + if slice % 2: + orientation = Transformation.Orientation.MY + y += sliceHeight + transf = Transformation( x, y, orientation ) + return transf + + def _addCapTies ( self ): + if self.conf.cfg.etesian.latchUpDistance is None: + return + trace( 540, ',+', '\tSpares._addCapTies()\n' ) + area = self.conf.cell.getAbutmentBox() + if self.conf.isCoreBlock: + area = self.conf.core.getAbutmentBox() + self.conf.icore.getTransformation().applyOn( area ) + y = area.getYMin() + sliceHeight = self.conf.sliceHeight + tieWidth = self.conf.feedsConf.tieWidth() + trace( 540, '\tarea:{}, y:{}\n'.format( area, DbU.getValueString(y) )) + while y < area.getYMax(): + capTie = self.conf.createFeed() + capTie.setTransformation ( self._getTransformation(area.getXMin(),y) ) + capTie.setPlacementStatus( Instance.PlacementStatus.FIXED ) + trace( 540, '\t{} @{}\n'.format( capTie, capTie.getTransformation() )) + capTie = self.conf.createFeed() + capTie.setTransformation ( self._getTransformation(area.getXMax()-tieWidth,y) ) + capTie.setPlacementStatus( Instance.PlacementStatus.FIXED ) + trace( 540, '\t{} @{}\n'.format( capTie, capTie.getTransformation() )) + y += sliceHeight + trace( 540, ',-' ) + def build ( self ): if not self.conf.useSpares: return trace( 540, ',+', '\tSpares.build()\n' ) @@ -822,6 +850,7 @@ class Spares ( object ): , DbU.getValueString(7*self.conf.sliceHeight ) )) with UpdateSession(): self.quadTree = QuadTree.create( self ) + self._addCapTies() trace( 540, '-' ) def rshowPoolUse ( self ): diff --git a/etesian/src/CMakeLists.txt b/etesian/src/CMakeLists.txt index bb4d21d4..b8572efa 100644 --- a/etesian/src/CMakeLists.txt +++ b/etesian/src/CMakeLists.txt @@ -23,6 +23,7 @@ set( mocIncludes etesian/GraphicEtesianEngine.h ) set( cpps Configuration.cpp AddFeeds.cpp + Placement.cpp FeedCells.cpp BloatCells.cpp BloatProperty.cpp diff --git a/etesian/src/Configuration.cpp b/etesian/src/Configuration.cpp index 2c57d993..9eb97443 100644 --- a/etesian/src/Configuration.cpp +++ b/etesian/src/Configuration.cpp @@ -51,16 +51,19 @@ namespace Etesian { // Class : "Etesian::Configuration". Configuration::Configuration ( const RoutingGauge* rg, const CellGauge* cg ) - : _rg ( NULL ) - , _cg ( NULL ) - , _placeEffort ( static_cast (Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) ) - , _updateConf ( static_cast (Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) ) - , _spreadingConf( Cfg::getParamBool ("etesian.uniformDensity", false )->asBool()? ForceUniform : MaxDensity ) - , _routingDriven( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool()) - , _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() ) - , _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() ) - , _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() ) - , _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() ) + : _rg ( NULL ) + , _cg ( NULL ) + , _placeEffort ( static_cast + (Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) ) + , _updateConf ( static_cast + (Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) ) + , _spreadingConf ( Cfg::getParamBool ("etesian.uniformDensity" , false )->asBool()? ForceUniform : MaxDensity ) + , _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool()) + , _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() ) + , _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() ) + , _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() ) + , _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() ) + , _latchUpDistance( Cfg::getParamInt ("etesian.latchUpDistance",0 )->asInt() ) { string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString(); if (cg == NULL) { diff --git a/etesian/src/EtesianEngine.cpp b/etesian/src/EtesianEngine.cpp index 01091778..6fd8a41b 100644 --- a/etesian/src/EtesianEngine.cpp +++ b/etesian/src/EtesianEngine.cpp @@ -1160,7 +1160,8 @@ namespace Etesian { detailedPlace(detailedIterations, detailedEffort, detailedOptions); cmess2 << " o Adding feed cells." << endl; - addFeeds(); + readSlices(); + //addFeeds(); cmess1 << " o Placement finished." << endl; stopMeasures(); diff --git a/etesian/src/Placement.cpp b/etesian/src/Placement.cpp new file mode 100644 index 00000000..1555b2d2 --- /dev/null +++ b/etesian/src/Placement.cpp @@ -0,0 +1,679 @@ +// -*- C++ -*- +// +// This file is part of the Coriolis Software. +// Copyright (c) UPMC 2020-2020, 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 : "./Placement.cpp" | +// +-----------------------------------------------------------------+ + + +#include +#include +#include +#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 "hurricane/viewer/CellViewer.h" +#include "crlcore/AllianceFramework.h" +#include "crlcore/ToolBox.h" +#include "etesian/EtesianEngine.h" + + +namespace { + + using namespace std; + using Hurricane::tab; + using Hurricane::Warning; + using Hurricane::Error; + using Hurricane::DbU; + using Hurricane::Box; + using Hurricane::Interval; + using Hurricane::Occurrence; + 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 : "::Tile". + + class Area; + class Slice; + + + class Tile { + public: + inline Tile ( DbU::Unit xMin, DbU::Unit width, const Occurrence& ); + inline bool isFixed () const; + inline DbU::Unit getXMin () const; + inline DbU::Unit getXMax () const; + inline DbU::Unit getWidth () const; + inline const Occurrence& getOccurrence () const; + inline void translate ( DbU::Unit ); + private: + DbU::Unit _xMin; + DbU::Unit _width; + Occurrence _occurrence; + }; + + inline Tile::Tile ( DbU::Unit xMin, DbU::Unit width, const Occurrence& occurrence ) + : _xMin(xMin), _width(width), _occurrence(occurrence) + { } + + inline DbU::Unit Tile::getXMin () const { return _xMin; } + 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 bool Tile::isFixed () const + { + return static_cast( _occurrence.getEntity() )->getPlacementStatus() + == Instance::PlacementStatus::FIXED; + } + + inline void Tile::translate ( DbU::Unit dx ) + { + cerr << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << endl; + Instance* instance = static_cast( _occurrence.getEntity() ); + Transformation reference = instance->getTransformation(); + Transformation transf = Transformation( reference.getTx() + dx + , reference.getTy() + , reference.getOrientation() ); + instance->setTransformation( transf ); + _xMin += dx; + } + + +// ------------------------------------------------------------------- +// Class : "::Hole". + + class Area; + class Slice; + + + class Hole { + public: + inline Hole ( DbU::Unit xMin, DbU::Unit width ); + inline DbU::Unit getXMin () const; + inline DbU::Unit getXMax () const; + inline DbU::Unit getWidth () const; + private: + DbU::Unit _xMin; + DbU::Unit _width; + }; + + inline Hole::Hole ( DbU::Unit xMin, DbU::Unit width ) + : _xMin(xMin), _width(width) + { } + + inline DbU::Unit Hole::getXMin () const { return _xMin; } + inline DbU::Unit Hole::getXMax () const { return _xMin+_width; } + inline DbU::Unit Hole::getWidth () const { return _width; } + + +// ------------------------------------------------------------------- +// Class : "::SubSlice". + + class SubSlice { + public: + SubSlice ( Slice*, const list::iterator& beginTile ); + inline const list::iterator getBeginTile () const; + inline const list::iterator getEndTile () const; + inline DbU::Unit getXMin () const; + inline DbU::Unit getXMax () const; + DbU::Unit getAverageChunk ( size_t& ) const; + void insertTies ( DbU::Unit latchUpMax ); + private: + Slice* _slice; + list::iterator _beginTile; + list::iterator _endTile; + }; + + inline const list::iterator SubSlice::getBeginTile () const { return _beginTile; } + inline const list::iterator SubSlice::getEndTile () const { return _endTile; } + + +// ------------------------------------------------------------------- +// Class : "::Slice". + + 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& 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; + list _tiles; + vector _subSlices; + }; + + + Slice::Slice ( Area* area, DbU::Unit ybottom ) + : _area (area) + , _ybottom (ybottom) + , _tiles () + , _subSlices() + { } + + + bool Slice::validate () const + { + if (_tiles.empty()) return true; + + bool validated = true; + auto iTile = _tiles.begin(); + auto iTileNext = iTile; + ++iTileNext; + while ( iTileNext != _tiles.end() ) { + if ((*iTile).getXMax() > (*iTileNext).getXMin()) { + cerr << Error( "Slice::validate(): Overlap in slice @%s between instances,\n" + " %s @%s\n" + " %s @%s" + , DbU::getValueString(_ybottom).c_str() + , getString((*iTile).getOccurrence()).c_str() + , DbU::getValueString((*iTile).getXMin()).c_str() + , getString((*iTileNext).getOccurrence()).c_str() + , DbU::getValueString((*iTileNext).getXMin()).c_str() + ) << endl; + validated = false; + } + ++iTile; ++iTileNext; + } + + return validated; + } + + + void Slice::merge ( const Occurrence& occurrence, const Box& flatAb ) + { + if (_tiles.empty() or (_tiles.front().getXMin() > flatAb.getXMin())) { + _tiles.insert( _tiles.begin(), Tile(flatAb.getXMin(), flatAb.getWidth(), occurrence) ); + return; + } + + list::iterator imerge = _tiles.end(); + for ( auto itile = _tiles.begin() ; itile != _tiles.end() ; ++itile ) { + if ((*itile).getXMin() > flatAb.getXMin()) { + _tiles.insert( itile, Tile(flatAb.getXMin(), flatAb.getWidth(), occurrence) ); + return; + } + } + + _tiles.insert( _tiles.end(), Tile(flatAb.getXMin(), flatAb.getWidth(), occurrence) ); + } + + + void Slice::buildSubSlices () + { + if (not _tiles.empty() ) { + _subSlices.push_back( SubSlice( this, _tiles.begin() ) ); + while ( _subSlices.back().getEndTile() != _tiles.end() ) { + _subSlices.push_back( SubSlice( this, _subSlices.back().getEndTile() ) ); + } + } + } + + + void Slice::showSubSlices () + { + if (_tiles.empty()) return; + + cerr << "+ 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; + } + } + + + void Slice::insertTies ( DbU::Unit latchUpMax ) + { + cerr << "Slice::insertTies() @" << DbU::getValueString(_ybottom) << endl; + for ( SubSlice& subSlice : _subSlices ) subSlice.insertTies( latchUpMax ); + } + + + void Slice::addFeeds ( size_t islice ) + { + if (_tiles.empty()) { + fillHole( getXMin(), getXMax(), getYBottom(), islice%2 ); + return; + } + + list::iterator itile = _tiles.begin(); + list::iterator itilenext = itile; + ++itilenext; + + // Hole before the first chunk. + if ((*itile).getXMin() > getXMin()) { + fillHole( getXMin(), (*itile).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 ); + } + + for ( ; itilenext != _tiles.end() ; ++itile, ++itilenext ) { + fillHole( (*itile).getXMax(), (*itilenext).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 ); + } + + // Hole after the last chunk. + if ((*itile).getXMax() < getXMax()) { + fillHole( (*itile).getXMax(), 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("Slice::fillHole(): 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()->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; + } + + Instance::create ( getEtesian()->getBlockCell() + , getEtesian()->getFeedCells().getUniqueInstanceName().c_str() + , feed + , getTransformation( feed->getAbutmentBox() + , xtie + , _ybottom + , (yspin)?Transformation::Orientation::MY + :Transformation::Orientation::ID + ) + , Instance::PlacementStatus::PLACED + ); + + xtie += feedWidth; + } + } + + +// ------------------------------------------------------------------- +// Class : "::Area". + + 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 ); + private: + EtesianEngine* _etesian; + Box _cellAb; + DbU::Unit _sliceHeight; + vector _slices; + size_t _spinSlice0; + }; + + + Area::Area ( EtesianEngine* etesian ) + : _etesian (etesian) + , _cellAb (etesian->getBlockCell()->getAbutmentBox()) + , _sliceHeight(_etesian->getSliceHeight()) + , _slices () + { + size_t slicesNb = _cellAb.getHeight() / _sliceHeight; + for ( size_t islice=0 ; islicevalidate(); + return validated; + } + + + void Area::merge ( const Occurrence& occurrence, const Box& flatAb ) + { + if (flatAb.getYMin() < _cellAb.getYMin()) { + cerr << Warning("Area::merge(): Attempt to merge instance outside the Cell abutment box.") << endl; + return; + } + + size_t ibegin = (flatAb.getYMin()-_cellAb.getYMin()) / _sliceHeight; + size_t iend = (flatAb.getYMax()-_cellAb.getYMin()) / _sliceHeight; + + for ( size_t islice=ibegin ; islicemerge( occurrence, flatAb ); + } + } + + + void Area::addFeeds () + { + for ( size_t islice=0 ; islice<_slices.size() ; islice++ ) { + _slices[islice]->addFeeds( islice ); + } + } + + + void Area::buildSubSlices () + { for ( Slice* slice : _slices ) slice->buildSubSlices(); } + + + void Area::showSubSlices () + { for ( Slice* slice : _slices ) slice->showSubSlices(); } + + + void Area::insertTies ( DbU::Unit latchUpMax ) + { + for ( Slice* slice : _slices ) slice->insertTies( latchUpMax ); + validate(); + } + + + SubSlice::SubSlice ( Slice* slice, const list::iterator& beginTile ) + : _slice(slice) + , _beginTile(beginTile) + , _endTile (beginTile) + { + for ( ++_endTile; _endTile != slice->getTiles().end() ; ++_endTile ) { + Instance* instance = dynamic_cast( (*_endTile).getOccurrence().getEntity() ); + if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) + break; + } + } + + + inline DbU::Unit SubSlice::getXMin () const + { return (_beginTile == _slice->getTiles().begin()) ? _slice->getXMin() : (*_beginTile).getXMin(); } + + inline DbU::Unit SubSlice::getXMax () const + { return (_endTile == _slice->getTiles().end ()) ? _slice->getXMax() : (*_endTile).getXMax(); } + + + DbU::Unit SubSlice::getAverageChunk ( size_t& count ) const + { + count = 0; + Cell* feed = _slice->getEtesian()->getFeedCells().getBiggestFeed(); + if (feed == NULL) { + cerr << Error("SubSlice::getAverageChunk(): No feed has been registered, ignoring.") << endl; + return -1; + } + DbU::Unit feedWidth = feed->getAbutmentBox().getWidth(); + DbU::Unit usedLength = 0; + DbU::Unit xmin = getXMin(); + DbU::Unit xmax = getXMax(); + list::const_iterator iTile = _beginTile; + for ( ; iTile != _endTile ; ++iTile, ++count ) + usedLength += (*iTile).getWidth(); + + if (xmax - xmin - usedLength == 0) return 0; + return (feedWidth * (xmax - xmin)) / (xmax - xmin - usedLength); + } + + + void SubSlice::insertTies ( DbU::Unit latchUpMax ) + { + Cell* feed = _slice->getEtesian()->getFeedCells().getBiggestFeed(); + if (feed == NULL) { + cerr << Error( "SubSlice::insertTies(): No feed has been registered, ignoring." ) << endl; + return; + } + DbU::Unit feedWidth = feed->getAbutmentBox().getWidth(); + + cerr << "SubSlice::insterTies(): LatchUpMax:" << DbU::getValueString( latchUpMax ) << endl; + cerr << " Direct subSlice walkthrough." << endl; + + DbU::Unit xMin = getXMin(); + DbU::Unit xMax = getXMax(); + auto beginTile = _beginTile; + auto endTile = _endTile; + if ((*beginTile).isFixed()) { + xMin += (*beginTile).getWidth(); + ++beginTile; + } + if (endTile == _slice->getTiles().end()) { + --endTile; + } else if ((*endTile).isFixed()) { + xMax = (*endTile).getXMin(); + --endTile; + } + + DbU::Unit leftPosition = (*_beginTile).getXMin(); + DbU::Unit tileLength = 0; + auto iTile = _beginTile; + while ( true ) { + DbU::Unit dxLeft = (*iTile).getXMin() - leftPosition; + if (dxLeft >= feedWidth) { + cerr << " Enough space, reset rigth shift." << endl; + leftPosition = (*iTile).getXMin(); + tileLength = 0; + } + + if (tileLength + (*iTile).getWidth() > latchUpMax) { + cerr << " Length above threshold, insert tie space." << endl; + leftPosition += feedWidth; + tileLength = 0; + } + + (*iTile).translate( leftPosition - (*iTile).getXMin() ); + tileLength += (*iTile).getWidth(); + leftPosition += (*iTile).getWidth(); + + if (iTile == endTile) break; + ++iTile; + } + + cerr << " Reverse subSlice walkthrough (feedWidth:" << DbU::getValueString(feedWidth) << ")" << endl; + leftPosition = xMax; + iTile = endTile; + if (iTile == _slice->getTiles().end()) --iTile; + if ((*iTile).getXMax() > leftPosition) { + tileLength = 0; + DbU::Unit prevDxRight = (*iTile).getXMax() - leftPosition; + while ( true ) { + DbU::Unit dxRight = (*iTile).getXMax() - leftPosition; + if (dxRight <= 0) { + cerr << " Negative dxRight, all shift 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; + --iTile; + } + } + } + + + 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& Slice::getTiles () { return _tiles; } + + +} // Anonymous namespace. + + +namespace Etesian { + + + using Hurricane::DataBase; + using Hurricane::UpdateSession; + using Hurricane::Occurrence; + + + void EtesianEngine::readSlices () + { + if (not getFeedCells().feedNumbers()) { + cerr << Warning( "EtesianEngine::readSlices(): No feed cells available, skipping." ) << endl; + return; + } + + UpdateSession::open(); + + Area area ( this ); + Box topCellAb = getBlockCell()->getAbutmentBox(); + + area.setSpinSlice0( _yspinSlice0 ); + + if (getBlockInstance()) { + Transformation toBlockTransf = getBlockInstance()->getTransformation(); + toBlockTransf.invert(); + for ( Instance* instance : getCell()->getInstances() ) { + if (instance == getBlockInstance()) continue; + if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) { + Box overlapAb = instance->getAbutmentBox(); + toBlockTransf.applyOn( overlapAb ); + overlapAb = topCellAb.getIntersection( overlapAb ); + if (not overlapAb.isEmpty()) { + area.merge( Occurrence(instance), overlapAb ); + } + } + } + } + + for ( Occurrence occurrence : getBlockCell()->getTerminalNetlistInstanceOccurrences() ) + { + Instance* instance = static_cast(occurrence.getEntity()); + Cell* masterCell = instance->getMasterCell(); + + if (CatalogExtension::isFeed(masterCell)) { + cerr << Warning( "EtesianEngine::readSlices(): Feed instance %s already present." + , getString(instance->getName()).c_str() ) << endl; + } + + Box instanceAb = masterCell->getAbutmentBox(); + + Transformation instanceTransf = instance->getTransformation(); + occurrence.getPath().getTransformation().applyOn( instanceTransf ); + instanceTransf.applyOn( instanceAb ); + + if (not topCellAb.contains(instanceAb)) { + cerr << Warning( "EtesianEngine::readSlices(): Instance %s is not fully enclosed in the top cell." + , getString(instance->getName()).c_str() ) << endl; + continue; + } + + area.merge( occurrence, instanceAb ); + } + + area.buildSubSlices(); + area.showSubSlices(); + if (getConfiguration()->getLatchUpDistance()) { + DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2; + Cell* feed = getFeedCells().getBiggestFeed(); + if (feed != NULL) + tieSpacing -= feed->getAbutmentBox().getWidth(); + area.insertTies( tieSpacing ); + } + area.addFeeds(); + + UpdateSession::close(); + + if (_viewer) _viewer->getCellWidget()->refresh(); + } + + +} // Etesian namespace. diff --git a/etesian/src/etesian/Configuration.h b/etesian/src/etesian/Configuration.h index 67749b58..9d6a49fe 100644 --- a/etesian/src/etesian/Configuration.h +++ b/etesian/src/etesian/Configuration.h @@ -14,24 +14,19 @@ // +-----------------------------------------------------------------+ -#ifndef ETESIAN_CONFIGURATION_H -#define ETESIAN_CONFIGURATION_H - -#include - -#include "hurricane/DbU.h" +#pragma once +#include +#include "hurricane/DbU.h" namespace Hurricane { class Layer; class Cell; } - -#include "crlcore/RoutingGauge.h" -#include "crlcore/CellGauge.h" +#include "crlcore/RoutingGauge.h" +#include "crlcore/CellGauge.h" namespace Etesian { - using std::string; using Hurricane::Record; using Hurricane::Layer; @@ -60,26 +55,27 @@ namespace Etesian { class Configuration { public: // Constructor & Destructor. - Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL ); - ~Configuration (); - Configuration* clone () const; - // Methods. - inline RoutingGauge* getGauge () const; - inline CellGauge* getCellGauge () const; - inline Effort getPlaceEffort () const; - inline GraphicUpdate getUpdateConf () const; - inline Density getSpreadingConf () const; - inline bool getRoutingDriven () const; - inline double getSpaceMargin () const; - inline double getAspectRatio () const; - inline string getFeedNames () const; - inline string getBloat () const; - inline void setSpaceMargin ( double ); - inline void setAspectRatio ( double ); - void print ( Cell* ) const; - Record* _getRecord () const; - string _getString () const; - string _getTypeName () const; + Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL ); + ~Configuration (); + Configuration* clone () const; + // Methods. + inline RoutingGauge* getGauge () const; + inline CellGauge* getCellGauge () const; + inline Effort getPlaceEffort () const; + inline GraphicUpdate getUpdateConf () const; + inline Density getSpreadingConf () const; + inline bool getRoutingDriven () const; + inline double getSpaceMargin () const; + inline double getAspectRatio () const; + inline string getFeedNames () const; + inline string getBloat () const; + inline DbU::Unit getLatchUpDistance () const; + inline void setSpaceMargin ( double ); + inline void setAspectRatio ( double ); + void print ( Cell* ) const; + Record* _getRecord () const; + string _getString () const; + string _getTypeName () const; protected: // Attributes. RoutingGauge* _rg; @@ -92,28 +88,28 @@ namespace Etesian { double _aspectRatio; string _feedNames; string _bloat; + DbU::Unit _latchUpDistance; private: Configuration ( const Configuration& ); Configuration& operator= ( const Configuration& ); }; - inline RoutingGauge* Configuration::getGauge () const { return _rg; } - inline CellGauge* Configuration::getCellGauge () const { return _cg; } - inline Effort Configuration::getPlaceEffort () const { return _placeEffort; } - inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; } - inline Density Configuration::getSpreadingConf () const { return _spreadingConf; } - inline bool Configuration::getRoutingDriven () const { return _routingDriven; } - inline double Configuration::getSpaceMargin () const { return _spaceMargin; } - inline double Configuration::getAspectRatio () const { return _aspectRatio; } - inline string Configuration::getFeedNames () const { return _feedNames; } - inline string Configuration::getBloat () const { return _bloat; } - inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; } - inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; } + inline RoutingGauge* Configuration::getGauge () const { return _rg; } + inline CellGauge* Configuration::getCellGauge () const { return _cg; } + inline Effort Configuration::getPlaceEffort () const { return _placeEffort; } + inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; } + inline Density Configuration::getSpreadingConf () const { return _spreadingConf; } + inline bool Configuration::getRoutingDriven () const { return _routingDriven; } + inline double Configuration::getSpaceMargin () const { return _spaceMargin; } + inline double Configuration::getAspectRatio () const { return _aspectRatio; } + inline string Configuration::getFeedNames () const { return _feedNames; } + inline string Configuration::getBloat () const { return _bloat; } + inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; } + inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; } + inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; } } // Etesian namespace. INSPECTOR_P_SUPPORT(Etesian::Configuration); - -#endif // ETESIAN_CONFIGURATION_H diff --git a/etesian/src/etesian/EtesianEngine.h b/etesian/src/etesian/EtesianEngine.h index 84da7d51..9115fa4f 100644 --- a/etesian/src/etesian/EtesianEngine.h +++ b/etesian/src/etesian/EtesianEngine.h @@ -97,6 +97,7 @@ namespace Etesian { inline void useFeed ( Cell* ); size_t findYSpin (); void addFeeds (); + void readSlices (); inline void selectBloat ( std::string ); virtual Record* _getRecord () const; virtual std::string _getString () const;