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.
This commit is contained in:
parent
2e50ff4724
commit
8fdaf47f3d
|
@ -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
|
||||
|
@ -1085,6 +1094,7 @@ class BlockConf ( GaugeConf ):
|
|||
self.chipConf.addIoPad( ioPads[line], line )
|
||||
self.cfg.etesian.aspectRatio = None
|
||||
self.cfg.etesian.spaceMargin = None
|
||||
self.cfg.etesian.latchUpDistance = None
|
||||
self.cfg.block.spareSide = None
|
||||
|
||||
@property
|
||||
|
@ -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 ]
|
||||
|
||||
|
|
|
@ -135,10 +135,10 @@ class BufferPool ( object ):
|
|||
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 )
|
||||
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 )
|
||||
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()
|
||||
instance.setTransformation( transf )
|
||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
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 )
|
||||
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 ):
|
||||
|
|
|
@ -23,6 +23,7 @@
|
|||
set( mocIncludes etesian/GraphicEtesianEngine.h )
|
||||
set( cpps Configuration.cpp
|
||||
AddFeeds.cpp
|
||||
Placement.cpp
|
||||
FeedCells.cpp
|
||||
BloatCells.cpp
|
||||
BloatProperty.cpp
|
||||
|
|
|
@ -53,14 +53,17 @@ namespace Etesian {
|
|||
Configuration::Configuration ( const RoutingGauge* rg, const CellGauge* cg )
|
||||
: _rg ( NULL )
|
||||
, _cg ( NULL )
|
||||
, _placeEffort ( static_cast<Effort> (Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
||||
, _updateConf ( static_cast<GraphicUpdate> (Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
|
||||
, _placeEffort ( static_cast<Effort>
|
||||
(Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
||||
, _updateConf ( static_cast<GraphicUpdate>
|
||||
(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) {
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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 <map>
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#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<Instance*>( _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<Instance*>( _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<Tile>::iterator& beginTile );
|
||||
inline const list<Tile>::iterator getBeginTile () const;
|
||||
inline const list<Tile>::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<Tile>::iterator _beginTile;
|
||||
list<Tile>::iterator _endTile;
|
||||
};
|
||||
|
||||
inline const list<Tile>::iterator SubSlice::getBeginTile () const { return _beginTile; }
|
||||
inline const list<Tile>::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<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;
|
||||
list<Tile> _tiles;
|
||||
vector<SubSlice> _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<Tile>::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<Tile>::iterator itile = _tiles.begin();
|
||||
list<Tile>::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<Slice*> _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 ; islice<slicesNb ; ++islice )
|
||||
_slices.push_back( new Slice( this, _cellAb.getYMin()+islice*_sliceHeight ) );
|
||||
}
|
||||
|
||||
|
||||
Area::~Area ()
|
||||
{
|
||||
for ( size_t islice=0 ; islice<_slices.size() ; ++islice )
|
||||
delete _slices[islice];
|
||||
}
|
||||
|
||||
|
||||
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(); }
|
||||
|
||||
|
||||
bool Area::validate () const
|
||||
{
|
||||
bool validated = true;
|
||||
for ( const Slice* slice : _slices )
|
||||
validated = validated and slice->validate();
|
||||
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 ; islice<iend ; ++islice ) {
|
||||
_slices[islice]->merge( 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<Tile>::iterator& beginTile )
|
||||
: _slice(slice)
|
||||
, _beginTile(beginTile)
|
||||
, _endTile (beginTile)
|
||||
{
|
||||
for ( ++_endTile; _endTile != slice->getTiles().end() ; ++_endTile ) {
|
||||
Instance* instance = dynamic_cast<Instance*>( (*_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<Tile>::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<Tile>& 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<Instance*>(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.
|
|
@ -14,24 +14,19 @@
|
|||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#ifndef ETESIAN_CONFIGURATION_H
|
||||
#define ETESIAN_CONFIGURATION_H
|
||||
|
||||
#pragma once
|
||||
#include <string>
|
||||
|
||||
#include "hurricane/DbU.h"
|
||||
namespace Hurricane {
|
||||
class Layer;
|
||||
class Cell;
|
||||
}
|
||||
|
||||
#include "crlcore/RoutingGauge.h"
|
||||
#include "crlcore/CellGauge.h"
|
||||
|
||||
|
||||
namespace Etesian {
|
||||
|
||||
|
||||
using std::string;
|
||||
using Hurricane::Record;
|
||||
using Hurricane::Layer;
|
||||
|
@ -74,6 +69,7 @@ namespace Etesian {
|
|||
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;
|
||||
|
@ -92,6 +88,7 @@ namespace Etesian {
|
|||
double _aspectRatio;
|
||||
string _feedNames;
|
||||
string _bloat;
|
||||
DbU::Unit _latchUpDistance;
|
||||
private:
|
||||
Configuration ( const Configuration& );
|
||||
Configuration& operator= ( const Configuration& );
|
||||
|
@ -108,6 +105,7 @@ namespace Etesian {
|
|||
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; }
|
||||
|
||||
|
@ -115,5 +113,3 @@ namespace Etesian {
|
|||
} // Etesian namespace.
|
||||
|
||||
INSPECTOR_P_SUPPORT(Etesian::Configuration);
|
||||
|
||||
#endif // ETESIAN_CONFIGURATION_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;
|
||||
|
|
Loading…
Reference in New Issue