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.
|
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' )
|
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.count = 0
|
||||||
self.feeds = []
|
self.feeds = []
|
||||||
for feedName in feeds:
|
for feedName in feeds:
|
||||||
|
@ -832,6 +834,8 @@ class FeedsConf ( object ):
|
||||||
continue
|
continue
|
||||||
feedWidth = feedCell.getAbutmentBox().getWidth()
|
feedWidth = feedCell.getAbutmentBox().getWidth()
|
||||||
self.feeds.append( (feedWidth,feedCell) )
|
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.sort( key=itemgetter(0) )
|
||||||
self.feeds.reverse()
|
self.feeds.reverse()
|
||||||
for i in range(len(self.feeds)):
|
for i in range(len(self.feeds)):
|
||||||
|
@ -840,6 +844,11 @@ class FeedsConf ( object ):
|
||||||
trace( 550, '-' )
|
trace( 550, '-' )
|
||||||
return
|
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 ):
|
def createFeed ( self, cell ):
|
||||||
instance = Instance.create( cell, 'spare_feed_{}'.format(self.count), self.feeds[0][1] )
|
instance = Instance.create( cell, 'spare_feed_{}'.format(self.count), self.feeds[0][1] )
|
||||||
self.count += 1
|
self.count += 1
|
||||||
|
@ -1061,7 +1070,7 @@ class BlockConf ( GaugeConf ):
|
||||||
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
||||||
self.bufferConf = BufferConf( self.framework )
|
self.bufferConf = BufferConf( self.framework )
|
||||||
self.constantsConf = ConstantsConf( self.framework, self.cfg )
|
self.constantsConf = ConstantsConf( self.framework, self.cfg )
|
||||||
self.feedsConf = FeedsConf( self.framework )
|
self.feedsConf = FeedsConf( self.framework, self.cfg )
|
||||||
self.chipConf = ChipConf( self )
|
self.chipConf = ChipConf( self )
|
||||||
self.bColumns = 2
|
self.bColumns = 2
|
||||||
self.bRows = 2
|
self.bRows = 2
|
||||||
|
@ -1083,9 +1092,10 @@ class BlockConf ( GaugeConf ):
|
||||||
self.ioPins.append( IoPin( *ioPinSpec ) )
|
self.ioPins.append( IoPin( *ioPinSpec ) )
|
||||||
for line in range(len(ioPads)):
|
for line in range(len(ioPads)):
|
||||||
self.chipConf.addIoPad( ioPads[line], line )
|
self.chipConf.addIoPad( ioPads[line], line )
|
||||||
self.cfg.etesian.aspectRatio = None
|
self.cfg.etesian.aspectRatio = None
|
||||||
self.cfg.etesian.spaceMargin = None
|
self.cfg.etesian.spaceMargin = None
|
||||||
self.cfg.block.spareSide = None
|
self.cfg.etesian.latchUpDistance = None
|
||||||
|
self.cfg.block.spareSide = None
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def isCoreBlock ( self ): return self.chip is not None
|
def isCoreBlock ( self ): return self.chip is not None
|
||||||
|
@ -1148,6 +1158,9 @@ class BlockConf ( GaugeConf ):
|
||||||
def createBuffer ( self ):
|
def createBuffer ( self ):
|
||||||
return self.bufferConf.createBuffer( self.cellPnR )
|
return self.bufferConf.createBuffer( self.cellPnR )
|
||||||
|
|
||||||
|
def createFeed ( self ):
|
||||||
|
return self.feedsConf.createFeed( self.cellPnR )
|
||||||
|
|
||||||
def setDeltaAb ( self, dx1, dy1, dx2, dy2 ):
|
def setDeltaAb ( self, dx1, dy1, dx2, dy2 ):
|
||||||
self.deltaAb = [ dx1, dy1, dx2, dy2 ]
|
self.deltaAb = [ dx1, dy1, dx2, dy2 ]
|
||||||
|
|
||||||
|
|
|
@ -133,12 +133,12 @@ class BufferPool ( object ):
|
||||||
yoffset = 0
|
yoffset = 0
|
||||||
if self.quadTree.spares.conf.isCoreBlock:
|
if self.quadTree.spares.conf.isCoreBlock:
|
||||||
yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy()
|
yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy()
|
||||||
conf = self.quadTree.spares.conf
|
conf = self.quadTree.spares.conf
|
||||||
sliceHeight = conf.sliceHeight
|
sliceHeight = conf.sliceHeight
|
||||||
x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter()
|
poolHalfWidth = (conf.bufferConf.width * self.columns)/2 + conf.feedsConf.tieWidth()
|
||||||
- (conf.bufferConf.width * self.columns)/2 )
|
poolHalfHeight = (conf.bufferConf.height * self.rows)/2
|
||||||
y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter()
|
x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter() - poolHalfWidth )
|
||||||
- (conf.bufferConf.height * self.rows)/2 )
|
y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter() - poolHalfHeight )
|
||||||
slice = (y - yoffset) / sliceHeight
|
slice = (y - yoffset) / sliceHeight
|
||||||
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
|
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
|
||||||
trace( 540, '\tSlice #{} (y:{})\n'.format(slice,DbU.getValueString(y)) )
|
trace( 540, '\tSlice #{} (y:{})\n'.format(slice,DbU.getValueString(y)) )
|
||||||
|
@ -148,38 +148,25 @@ class BufferPool ( object ):
|
||||||
if (slice+row)%2:
|
if (slice+row)%2:
|
||||||
orientation = Transformation.Orientation.MY
|
orientation = Transformation.Orientation.MY
|
||||||
y += sliceHeight
|
y += sliceHeight
|
||||||
for column in range(self.columns):
|
length = 0
|
||||||
index = self.toIndex(column,row)
|
for column in range(self.columns+2):
|
||||||
transf = Transformation( x + column*conf.bufferConf.width, y, orientation )
|
transf = Transformation( x + length, y, orientation )
|
||||||
instance = conf.createBuffer()
|
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.setTransformation( transf )
|
||||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||||
self.buffers[ index ][1] = instance
|
length += instance.getMasterCell().getAbutmentBox().getWidth()
|
||||||
trace( 540, '\tBuffer[{}]: {} @{}\n'.format(index,self.buffers[index],transf) )
|
|
||||||
blBufAb = self.buffers[ 0][1].getAbutmentBox()
|
blBufAb = self.buffers[ 0][1].getAbutmentBox()
|
||||||
trBufAb = self.buffers[-1][1].getAbutmentBox()
|
trBufAb = self.buffers[-1][1].getAbutmentBox()
|
||||||
self.area = Box( blBufAb.getXMin(), blBufAb.getYMin()
|
self.area = Box( blBufAb.getXMin(), blBufAb.getYMin()
|
||||||
, trBufAb.getXMax(), trBufAb.getYMax() )
|
, trBufAb.getXMax(), trBufAb.getYMax() )
|
||||||
trace( 540, '-' )
|
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 ):
|
def _createTies ( self ):
|
||||||
trace( 540, ',+', '\tQuadTree._createTies()\n' )
|
trace( 540, ',+', '\tQuadTree._createTies()\n' )
|
||||||
conf = self.quadTree.spares.conf
|
conf = self.quadTree.spares.conf
|
||||||
|
@ -809,10 +796,51 @@ class Spares ( object ):
|
||||||
if self.conf.isCoreBlock:
|
if self.conf.isCoreBlock:
|
||||||
offset = self.conf.icore.getTransformation().getTy()
|
offset = self.conf.icore.getTransformation().getTy()
|
||||||
self.conf.icore.getTransformation().applyOn( area )
|
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
|
modulo = (y - offset - area.getYMin()) % self.conf.sliceHeight
|
||||||
return y - modulo
|
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 ):
|
def build ( self ):
|
||||||
if not self.conf.useSpares: return
|
if not self.conf.useSpares: return
|
||||||
trace( 540, ',+', '\tSpares.build()\n' )
|
trace( 540, ',+', '\tSpares.build()\n' )
|
||||||
|
@ -822,6 +850,7 @@ class Spares ( object ):
|
||||||
, DbU.getValueString(7*self.conf.sliceHeight ) ))
|
, DbU.getValueString(7*self.conf.sliceHeight ) ))
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
self.quadTree = QuadTree.create( self )
|
self.quadTree = QuadTree.create( self )
|
||||||
|
self._addCapTies()
|
||||||
trace( 540, '-' )
|
trace( 540, '-' )
|
||||||
|
|
||||||
def rshowPoolUse ( self ):
|
def rshowPoolUse ( self ):
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
set( mocIncludes etesian/GraphicEtesianEngine.h )
|
set( mocIncludes etesian/GraphicEtesianEngine.h )
|
||||||
set( cpps Configuration.cpp
|
set( cpps Configuration.cpp
|
||||||
AddFeeds.cpp
|
AddFeeds.cpp
|
||||||
|
Placement.cpp
|
||||||
FeedCells.cpp
|
FeedCells.cpp
|
||||||
BloatCells.cpp
|
BloatCells.cpp
|
||||||
BloatProperty.cpp
|
BloatProperty.cpp
|
||||||
|
|
|
@ -51,16 +51,19 @@ namespace Etesian {
|
||||||
// Class : "Etesian::Configuration".
|
// Class : "Etesian::Configuration".
|
||||||
|
|
||||||
Configuration::Configuration ( const RoutingGauge* rg, const CellGauge* cg )
|
Configuration::Configuration ( const RoutingGauge* rg, const CellGauge* cg )
|
||||||
: _rg ( NULL )
|
: _rg ( NULL )
|
||||||
, _cg ( NULL )
|
, _cg ( NULL )
|
||||||
, _placeEffort ( static_cast<Effort> (Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
, _placeEffort ( static_cast<Effort>
|
||||||
, _updateConf ( static_cast<GraphicUpdate> (Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
|
(Cfg::getParamEnumerate ("etesian.effort" , Standard )->asInt()) )
|
||||||
, _spreadingConf( Cfg::getParamBool ("etesian.uniformDensity", false )->asBool()? ForceUniform : MaxDensity )
|
, _updateConf ( static_cast<GraphicUpdate>
|
||||||
, _routingDriven( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
|
(Cfg::getParamEnumerate ("etesian.graphics" , LowerBound )->asInt()) )
|
||||||
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
|
, _spreadingConf ( Cfg::getParamBool ("etesian.uniformDensity" , false )->asBool()? ForceUniform : MaxDensity )
|
||||||
, _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() )
|
, _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
|
||||||
, _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() )
|
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
|
||||||
, _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() )
|
, _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();
|
string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString();
|
||||||
if (cg == NULL) {
|
if (cg == NULL) {
|
||||||
|
|
|
@ -1160,7 +1160,8 @@ namespace Etesian {
|
||||||
detailedPlace(detailedIterations, detailedEffort, detailedOptions);
|
detailedPlace(detailedIterations, detailedEffort, detailedOptions);
|
||||||
|
|
||||||
cmess2 << " o Adding feed cells." << endl;
|
cmess2 << " o Adding feed cells." << endl;
|
||||||
addFeeds();
|
readSlices();
|
||||||
|
//addFeeds();
|
||||||
|
|
||||||
cmess1 << " o Placement finished." << endl;
|
cmess1 << " o Placement finished." << endl;
|
||||||
stopMeasures();
|
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
|
#pragma once
|
||||||
#define ETESIAN_CONFIGURATION_H
|
#include <string>
|
||||||
|
#include "hurricane/DbU.h"
|
||||||
#include <string>
|
|
||||||
|
|
||||||
#include "hurricane/DbU.h"
|
|
||||||
namespace Hurricane {
|
namespace Hurricane {
|
||||||
class Layer;
|
class Layer;
|
||||||
class Cell;
|
class Cell;
|
||||||
}
|
}
|
||||||
|
#include "crlcore/RoutingGauge.h"
|
||||||
#include "crlcore/RoutingGauge.h"
|
#include "crlcore/CellGauge.h"
|
||||||
#include "crlcore/CellGauge.h"
|
|
||||||
|
|
||||||
|
|
||||||
namespace Etesian {
|
namespace Etesian {
|
||||||
|
|
||||||
|
|
||||||
using std::string;
|
using std::string;
|
||||||
using Hurricane::Record;
|
using Hurricane::Record;
|
||||||
using Hurricane::Layer;
|
using Hurricane::Layer;
|
||||||
|
@ -60,26 +55,27 @@ namespace Etesian {
|
||||||
class Configuration {
|
class Configuration {
|
||||||
public:
|
public:
|
||||||
// Constructor & Destructor.
|
// Constructor & Destructor.
|
||||||
Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL );
|
Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL );
|
||||||
~Configuration ();
|
~Configuration ();
|
||||||
Configuration* clone () const;
|
Configuration* clone () const;
|
||||||
// Methods.
|
// Methods.
|
||||||
inline RoutingGauge* getGauge () const;
|
inline RoutingGauge* getGauge () const;
|
||||||
inline CellGauge* getCellGauge () const;
|
inline CellGauge* getCellGauge () const;
|
||||||
inline Effort getPlaceEffort () const;
|
inline Effort getPlaceEffort () const;
|
||||||
inline GraphicUpdate getUpdateConf () const;
|
inline GraphicUpdate getUpdateConf () const;
|
||||||
inline Density getSpreadingConf () const;
|
inline Density getSpreadingConf () const;
|
||||||
inline bool getRoutingDriven () const;
|
inline bool getRoutingDriven () const;
|
||||||
inline double getSpaceMargin () const;
|
inline double getSpaceMargin () const;
|
||||||
inline double getAspectRatio () const;
|
inline double getAspectRatio () const;
|
||||||
inline string getFeedNames () const;
|
inline string getFeedNames () const;
|
||||||
inline string getBloat () const;
|
inline string getBloat () const;
|
||||||
inline void setSpaceMargin ( double );
|
inline DbU::Unit getLatchUpDistance () const;
|
||||||
inline void setAspectRatio ( double );
|
inline void setSpaceMargin ( double );
|
||||||
void print ( Cell* ) const;
|
inline void setAspectRatio ( double );
|
||||||
Record* _getRecord () const;
|
void print ( Cell* ) const;
|
||||||
string _getString () const;
|
Record* _getRecord () const;
|
||||||
string _getTypeName () const;
|
string _getString () const;
|
||||||
|
string _getTypeName () const;
|
||||||
protected:
|
protected:
|
||||||
// Attributes.
|
// Attributes.
|
||||||
RoutingGauge* _rg;
|
RoutingGauge* _rg;
|
||||||
|
@ -92,28 +88,28 @@ namespace Etesian {
|
||||||
double _aspectRatio;
|
double _aspectRatio;
|
||||||
string _feedNames;
|
string _feedNames;
|
||||||
string _bloat;
|
string _bloat;
|
||||||
|
DbU::Unit _latchUpDistance;
|
||||||
private:
|
private:
|
||||||
Configuration ( const Configuration& );
|
Configuration ( const Configuration& );
|
||||||
Configuration& operator= ( const Configuration& );
|
Configuration& operator= ( const Configuration& );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
inline RoutingGauge* Configuration::getGauge () const { return _rg; }
|
inline RoutingGauge* Configuration::getGauge () const { return _rg; }
|
||||||
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
||||||
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
||||||
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
||||||
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
||||||
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
||||||
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
||||||
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
||||||
inline string Configuration::getFeedNames () const { return _feedNames; }
|
inline string Configuration::getFeedNames () const { return _feedNames; }
|
||||||
inline string Configuration::getBloat () const { return _bloat; }
|
inline string Configuration::getBloat () const { return _bloat; }
|
||||||
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
|
inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; }
|
||||||
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
|
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
|
||||||
|
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
|
||||||
|
|
||||||
|
|
||||||
} // Etesian namespace.
|
} // Etesian namespace.
|
||||||
|
|
||||||
INSPECTOR_P_SUPPORT(Etesian::Configuration);
|
INSPECTOR_P_SUPPORT(Etesian::Configuration);
|
||||||
|
|
||||||
#endif // ETESIAN_CONFIGURATION_H
|
|
||||||
|
|
|
@ -97,6 +97,7 @@ namespace Etesian {
|
||||||
inline void useFeed ( Cell* );
|
inline void useFeed ( Cell* );
|
||||||
size_t findYSpin ();
|
size_t findYSpin ();
|
||||||
void addFeeds ();
|
void addFeeds ();
|
||||||
|
void readSlices ();
|
||||||
inline void selectBloat ( std::string );
|
inline void selectBloat ( std::string );
|
||||||
virtual Record* _getRecord () const;
|
virtual Record* _getRecord () const;
|
||||||
virtual std::string _getString () const;
|
virtual std::string _getString () const;
|
||||||
|
|
Loading…
Reference in New Issue