Add support for Antenna/Diode insertion in Etesian.

* New: In Etesian::Configuration add new parameters for antenna
    effect management:
    * "etesian.diodeName"    : the name of the diode cell.
    * "etesian.antennaMaxwl" : maximum length above which antenna
         effect can occur. Must be the maximum for all the normal
	 routing layers.
    * "etesian.antennaInsertThreshold" : during the placement steps,
         threshold for linear disruption at which we will look for
	 the RSMT and insert diodes.
* New: In EtesianEngine::antennaProtect(), at a designated point
    in the placement iteratives step, when the spreading starts to
    be significant enough estimate the RSMT length and add a diode
    if need be. The diode will be put side by side with the driver
    cell. This is done by enlarging the driver cell of the diode
    width.
* New: In EtesianEngine::_updatePlacement(), in the final stage,
    modify the netlist to connect the diode. The diode will be
    put on the side of the cell closest to the driver. This may
    alow to make the connexion directly in METAL1 in the future.
* Change: In etesian/Placement.cpp, make the whole placement
    structure a persistent attribute of the EtesianEngine so
    it can be used afterwards.
      Add a post-placement diode insertion feature. Finally
    unused as they are added on the fly during placement.
      In the Area, add data about the diode tie in the TieLut.
* Change: Add EtesianEnginea::clearColoquinte(), to keep the
    post-placement structure while purging the Coloquinte one.
* Change: In cumulus/plugins.block.block, keep the Etesian engine
    until the whole P&R is done, so we potentially can exploit
    the post-placement datas.
* Bug: In cumulus/plugins.chip.power.GoCb(), for the METAL1 power
    and ground wires coming from the standard cell, it was assumed
    they where made of Horizontal segments, this is not the case
    in FlexLib... So force to consider the plane as Horizontal when
    we are processing that plane.
      Better solution should be to use Horizontals...
This commit is contained in:
Jean-Paul Chaput 2021-01-13 19:36:20 +01:00
parent 78cbb662e6
commit 087ef239c2
13 changed files with 1009 additions and 592 deletions

View File

@ -527,32 +527,37 @@ class Block ( object ):
def place ( self ): def place ( self ):
editor = self.conf.editor editor = self.conf.editor
if self.conf.isCoreBlock: if self.conf.isCoreBlock:
etesian = Etesian.EtesianEngine.create( self.conf.corona ) self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
etesian.setBlock( self.conf.icore ) self.etesian.setBlock( self.conf.icore )
if editor: if editor:
editor.setCell( self.conf.cell ) editor.setCell( self.conf.cell )
Breakpoint.stop( 100, 'Block.place(), corona loaded.') Breakpoint.stop( 100, 'Block.place(), corona loaded.')
else: else:
etesian = Etesian.EtesianEngine.create( self.conf.cell ) self.etesian = Etesian.EtesianEngine.create( self.conf.cell )
etesian.place() self.etesian.place()
etesian.destroy() Breakpoint.stop( 100, 'Placement done.' )
self.etesian.clearColoquinte()
def route ( self ): def route ( self ):
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
katana = Katana.KatanaEngine.create( routedCell ) self.katana = Katana.KatanaEngine.create( routedCell )
#katana.printConfiguration () #self.katana.printConfiguration()
katana.digitalInit () self.katana.digitalInit ()
#katana.runNegociatePreRouted() #katana.runNegociatePreRouted()
Breakpoint.stop( 100, 'Block.route() Before global routing.' ) Breakpoint.stop( 100, 'Block.route() Before global routing.' )
katana.runGlobalRouter ( Katana.Flags.NoFlags ) self.katana.runGlobalRouter ( Katana.Flags.NoFlags )
katana.loadGlobalRouting ( Anabatic.EngineLoadGrByNet ) self.katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
Breakpoint.stop( 100, 'Block.route() After global routing.' ) Breakpoint.stop( 100, 'Block.route() After global routing.' )
katana.layerAssign ( Anabatic.EngineNoNetLayerAssign ) self.katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
katana.runNegociate ( Katana.Flags.NoFlags ) self.katana.runNegociate ( Katana.Flags.NoFlags )
success = katana.isDetailedRoutingSuccess() success = self.katana.isDetailedRoutingSuccess()
Breakpoint.stop( 100, 'Block.route() done, success:{}.'.format(success) ) Breakpoint.stop( 100, 'Block.route() done, success:{}.'.format(success) )
katana.finalizeLayout() self.katana.finalizeLayout()
katana.destroy() self.katana.destroy()
self.katana = None
if self.etesian:
self.etesian.destroy()
self.etesian = None
return success return success
def addBlockages ( self ): def addBlockages ( self ):

View File

@ -133,6 +133,8 @@ class GaugeConf ( object ):
@property @property
def routingBb ( self ): return self._routingBb def routingBb ( self ): return self._routingBb
def getLayerDepth ( self, layer ): return self._routingGauge.getLayerDepth( layer )
def getPitch ( self, layer ): return self._routingGauge.getPitch( layer ) def getPitch ( self, layer ): return self._routingGauge.getPitch( layer )
def setRoutingBb ( self, bb ): def setRoutingBb ( self, bb ):
@ -1100,6 +1102,8 @@ class BlockConf ( GaugeConf ):
self.cfg.etesian.spaceMargin = None self.cfg.etesian.spaceMargin = None
self.cfg.etesian.latchUpDistance = None self.cfg.etesian.latchUpDistance = None
self.cfg.block.spareSide = None self.cfg.block.spareSide = None
self.etesian = None
self.katana = None
@property @property
def isCoreBlock ( self ): return self.chip is not None def isCoreBlock ( self ): return self.chip is not None

View File

@ -536,7 +536,7 @@ class Builder ( object ):
def __init__ ( self, block ): def __init__ ( self, block ):
self.block = block self.block = block
self.innerBb = self.block.bb self.innerBb = self.block.icoreAb
self.block.path.getTransformation().applyOn( self.innerBb ) self.block.path.getTransformation().applyOn( self.innerBb )
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 ) self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
self.southSide = SouthSide( self ) self.southSide = SouthSide( self )

View File

@ -36,8 +36,8 @@ plugins.chip.importConstants( globals() )
class Side ( object ): class Side ( object ):
def __init__ ( self, block, side, net, metal ): def __init__ ( self, builder, side, net, metal ):
self.block = block self.builder = builder
self.side = side self.side = side
self.net = net self.net = net
self.metal = metal self.metal = metal
@ -74,16 +74,16 @@ class Side ( object ):
def doLayout ( self ): def doLayout ( self ):
if self.side == West: if self.side == West:
width = 0 width = 0
x = self.block.bb.getXMin() x = self.builder.icoreAb.getXMin()
elif self.side == East: elif self.side == East:
width = 0 width = 0
x = self.block.bb.getXMax() x = self.builder.icoreAb.getXMax()
elif self.side == South: elif self.side == South:
height = 0 height = 0
y = self.block.bb.getYMin() y = self.builder.icoreAb.getYMin()
elif self.side == North: elif self.side == North:
height = 0 height = 0
y = self.block.bb.getYMax() y = self.builder.icoreAb.getYMax()
minWidth = DbU.fromLambda( 6.0 ) minWidth = DbU.fromLambda( 6.0 )
for terminal in self.terminals: for terminal in self.terminals:
if self.side == West or self.side == East: if self.side == West or self.side == East:
@ -94,7 +94,7 @@ class Side ( object ):
center = Point( terminal[0].getCenter(), y ) center = Point( terminal[0].getCenter(), y )
width = terminal[0].getSize() - self.deltaWidth width = terminal[0].getSize() - self.deltaWidth
if width < minWidth: width = minWidth if width < minWidth: width = minWidth
self.block.path.getTransformation().applyOn( center ) self.builder.path.getTransformation().applyOn( center )
contact = Contact.create( self.net, self.metal, center.getX(), center.getY(), width, height ) contact = Contact.create( self.net, self.metal, center.getX(), center.getY(), width, height )
terminal[ 1 ] = contact terminal[ 1 ] = contact
@ -107,28 +107,33 @@ class Plane ( object ):
Horizontal = 0001 Horizontal = 0001
Vertical = 0002 Vertical = 0002
def __init__ ( self, block, metal ): def __init__ ( self, builder, metal ):
self.block = block self.builder = builder
self.metal = metal self.metal = metal
self.sides = {} self.sides = {}
def addTerminal ( self, net, direction, bb ): def addTerminal ( self, net, direction, bb ):
if not self.sides.has_key(net): if not self.sides.has_key(net):
self.sides[ net ] = { North : Side(self.block,North,net,self.metal) self.sides[ net ] = { North : Side(self.builder,North,net,self.metal)
, South : Side(self.block,South,net,self.metal) , South : Side(self.builder,South,net,self.metal)
, East : Side(self.block,East ,net,self.metal) , East : Side(self.builder,East ,net,self.metal)
, West : Side(self.block,West ,net,self.metal) , West : Side(self.builder,West ,net,self.metal)
} }
sides = self.sides[ net ] sides = self.sides[ net ]
trace( 550, '\tPlane.addTerminal() net={} bb={} direction={}\n' \
.format( net.getName(), bb, direction ))
trace( 550, '\tbuilder.icoreAb={}\n'.format( self.builder.icoreAb ))
if direction == Plane.Horizontal: if direction == Plane.Horizontal:
if bb.getXMin() <= self.block.bb.getXMin(): trace( 550, '\t| Horizontal\n' )
if bb.getXMin() <= self.builder.icoreAb.getXMin():
sides[West].addTerminal( bb.getCenter().getY(), bb.getHeight() ) sides[West].addTerminal( bb.getCenter().getY(), bb.getHeight() )
if bb.getXMax() >= self.block.bb.getXMax(): if bb.getXMax() >= self.builder.icoreAb.getXMax():
sides[East].addTerminal( bb.getCenter().getY(), bb.getHeight() ) sides[East].addTerminal( bb.getCenter().getY(), bb.getHeight() )
if direction == Plane.Vertical: if direction == Plane.Vertical:
if bb.getYMin() <= self.block.bb.getYMin(): trace( 550, '\t| Vertical\n' )
if bb.getYMin() <= self.builder.icoreAb.getYMin():
sides[South].addTerminal( bb.getCenter().getX(), bb.getWidth() ) sides[South].addTerminal( bb.getCenter().getX(), bb.getWidth() )
if bb.getYMax() >= self.block.bb.getYMax(): if bb.getYMax() >= self.builder.icoreAb.getYMax():
sides[North].addTerminal( bb.getCenter().getX(), bb.getWidth() ) sides[North].addTerminal( bb.getCenter().getX(), bb.getWidth() )
def doLayout ( self ): def doLayout ( self ):
@ -142,25 +147,28 @@ class Plane ( object ):
class GoCb ( object ): class GoCb ( object ):
def __init__ ( self, block ): def __init__ ( self, builder ):
self.block = block self.builder = builder
def __call__ ( self, query, go ): def __call__ ( self, query, go ):
direction = None direction = None
if isinstance(go,Horizontal): direction = Plane.Horizontal if isinstance(go,Horizontal): direction = Plane.Horizontal
if isinstance(go,Vertical): direction = Plane.Vertical if isinstance(go,Vertical): direction = Plane.Vertical
if not direction: return if not direction: return
trace( 550, '\t| go={}\n'.format( go ))
rootNet = None rootNet = None
if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.block.conf.coronaVdd if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.builder.conf.coronaVdd
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.block.conf.coronaVss if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.builder.conf.coronaVss
if not rootNet: return if not rootNet: return
if self.block.activePlane: if self.builder.activePlane:
layer = self.block.activePlane.metal layer = self.builder.activePlane.metal
if layer.isSymbolic(): if layer.isSymbolic():
layer = layer.getBasicLayer() layer = layer.getBasicLayer()
if self.builder.conf.getLayerDepth(layer) == 0:
direction = Plane.Horizontal
bb = go.getBoundingBox( layer ) bb = go.getBoundingBox( layer )
query.getPath().getTransformation().applyOn( bb ) query.getPath().getTransformation().applyOn( bb )
self.block.activePlane.addTerminal( rootNet, direction, bb ) self.builder.activePlane.addTerminal( rootNet, direction, bb )
else: else:
print WarningMessage( 'BlockPower.GoCb() callback called without an active plane.' ) print WarningMessage( 'BlockPower.GoCb() callback called without an active plane.' )
return return
@ -173,9 +181,9 @@ class Builder ( object ):
def __init__ ( self, conf ): def __init__ ( self, conf ):
self.conf = conf self.conf = conf
self.path = Path( self.conf.icore ) self.path = Path()
self.block = self.conf.icore.getMasterCell() self.corona = self.conf.icorona.getMasterCell()
self.bb = self.block.getAbutmentBox() self.icoreAb = self.conf.icore.getAbutmentBox()
self.planes = {} self.planes = {}
self.activePlane = None self.activePlane = None
for layerGauge in self.conf.routingGauge.getLayerGauges(): for layerGauge in self.conf.routingGauge.getLayerGauges():
@ -188,8 +196,8 @@ class Builder ( object ):
goCb = GoCb( self ) goCb = GoCb( self )
query = Query() query = Query()
query.setGoCallback( goCb ) query.setGoCallback( goCb )
query.setCell( self.block ) query.setCell( self.corona )
query.setArea( self.block.getAbutmentBox() ) query.setArea( self.icoreAb )
query.setFilter( Query.DoComponents|Query.DoTerminalCells ) query.setFilter( Query.DoComponents|Query.DoTerminalCells )
for layerGauge in self.conf.routingGauge.getLayerGauges(): for layerGauge in self.conf.routingGauge.getLayerGauges():
self.activePlane = self.planes[ layerGauge.getLayer().getName() ] self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
@ -226,13 +234,11 @@ class Builder ( object ):
with UpdateSession(): with UpdateSession():
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 ) bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 )
self.conf.expandMinArea( bufferRp ) self.conf.expandMinArea( bufferRp )
blockAb = self.block.getAbutmentBox()
self.path.getTransformation().applyOn( blockAb )
layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth) layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth)
contact = Contact.create( ck contact = Contact.create( ck
, self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth) , self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth)
, bufferRp.getX() , bufferRp.getX()
, blockAb.getYMax() , self.icoreAb.getYMax()
, layerGauge.getViaWidth() , layerGauge.getViaWidth()
, layerGauge.getViaWidth() , layerGauge.getViaWidth()
) )
@ -242,7 +248,6 @@ class Builder ( object ):
if layer.isSymbolic(): if layer.isSymbolic():
layer = layer.getBasicLayer() layer = layer.getBasicLayer()
bb = segment.getBoundingBox( layer ) bb = segment.getBoundingBox( layer )
self.path.getTransformation().getInvert().applyOn( bb )
self.activePlane.addTerminal( ck, Plane.Vertical, bb ) self.activePlane.addTerminal( ck, Plane.Vertical, bb )
trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) ) trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) )

View File

@ -15,24 +15,13 @@
import sys import sys
from Hurricane import DbU from Hurricane import DbU, Point, Transformation, Box, Interval, \
from Hurricane import Point Path, Occurrence, UpdateSession, Net, \
from Hurricane import Transformation Contact, Horizontal, Vertical, Query
from Hurricane import Box
from Hurricane import Interval
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import UpdateSession
from Hurricane import Net
from Hurricane import Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Query
import CRL import CRL
import helpers import helpers
from helpers import trace from helpers import trace
from helpers.io import ErrorMessage from helpers.io import ErrorMessage, WarningMessage
from helpers.io import WarningMessage
import plugins import plugins
import plugins.chip import plugins.chip
@ -134,6 +123,8 @@ class Plane ( object ):
, West : Side(self.block,West ,net,self.metal) , West : Side(self.block,West ,net,self.metal)
} }
sides = self.sides[ net ] sides = self.sides[ net ]
trace( 550, '\tPlane.addTerminal() net={} bb={} direction={}\n' \
.format( net.getName(), bb, direction ))
if direction == Plane.Horizontal: if direction == Plane.Horizontal:
if bb.getXMin() <= self.block.bb.getXMin(): if bb.getXMin() <= self.block.bb.getXMin():

View File

@ -11,6 +11,7 @@
${PYTHON_INCLUDE_PATH} ${PYTHON_INCLUDE_PATH}
) )
set( includes etesian/Configuration.h set( includes etesian/Configuration.h
etesian/Placement.h
etesian/FeedCells.h etesian/FeedCells.h
etesian/BloatCells.h etesian/BloatCells.h
etesian/BloatProperty.h etesian/BloatProperty.h

View File

@ -61,9 +61,13 @@ namespace Etesian {
, _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool()) , _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() ) , _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.0)->asDouble() )
, _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() ) , _aspectRatio ( Cfg::getParamPercentage("etesian.aspectRatio" ,100.0)->asDouble() )
, _antennaInsertThreshold
( Cfg::getParamDouble ("etesian.antennaInsertThreshold", 50.0)->asDouble() )
, _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() ) , _feedNames ( Cfg::getParamString ("etesian.feedNames" ,"tie_x0,rowend_x0")->asString() )
, _diodeName ( Cfg::getParamString ("etesian.diodeName" ,"dio_x0" )->asString() )
, _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() ) , _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() )
, _latchUpDistance( Cfg::getParamInt ("etesian.latchUpDistance",0 )->asInt() ) , _latchUpDistance( Cfg::getParamInt ("etesian.latchUpDistance",0 )->asInt() )
, _antennaMaxWL ( Cfg::getParamInt ("etesian.antennaMaxWL" ,0 )->asInt() )
{ {
string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString(); string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString();
if (cg == NULL) { if (cg == NULL) {
@ -85,15 +89,19 @@ namespace Etesian {
Configuration::Configuration ( const Configuration& other ) Configuration::Configuration ( const Configuration& other )
: _rg (NULL) : _rg (NULL)
, _cg (NULL) , _cg (NULL)
, _placeEffort ( other._placeEffort ) , _placeEffort ( other._placeEffort )
, _updateConf ( other._updateConf ) , _updateConf ( other._updateConf )
, _spreadingConf( other._spreadingConf ) , _spreadingConf ( other._spreadingConf )
, _spaceMargin ( other._spaceMargin ) , _spaceMargin ( other._spaceMargin )
, _aspectRatio ( other._aspectRatio ) , _aspectRatio ( other._aspectRatio )
, _feedNames ( other._feedNames ) , _antennaInsertThreshold( other._antennaInsertThreshold )
, _bloat ( other._bloat ) , _feedNames ( other._feedNames )
, _diodeName ( other._diodeName )
, _bloat ( other._bloat )
, _latchUpDistance( other._latchUpDistance )
, _antennaMaxWL ( other._antennaMaxWL )
{ {
if (other._rg) _rg = other._rg->getClone(); if (other._rg) _rg = other._rg->getClone();
if (other._cg) _cg = other._cg->getClone(); if (other._cg) _cg = other._cg->getClone();
@ -113,14 +121,17 @@ namespace Etesian {
void Configuration::print ( Cell* cell ) const void Configuration::print ( Cell* cell ) const
{ {
cmess1 << " o Configuration of ToolEngine<Etesian> for Cell <" << cell->getName() << ">" << endl; cmess1 << " o Configuration of ToolEngine<Etesian> for Cell <" << cell->getName() << ">" << endl;
cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl; cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl; cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl; cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
cmess1 << Dots::asInt (" - Spreading Conf",_spreadingConf) << endl; cmess1 << Dots::asInt (" - Spreading Conf" ,_spreadingConf ) << endl;
cmess1 << Dots::asBool (" - Routing driven",_routingDriven) << endl; cmess1 << Dots::asBool (" - Routing driven" ,_routingDriven ) << endl;
cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl; cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl; cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl;
cmess1 << Dots::asString (" - Bloat model" ,_bloat ) << endl; cmess1 << Dots::asString (" - Bloat model" ,_bloat ) << endl;
cmess1 << Dots::asPercentage(" - Antenna Insert" ,_antennaInsertThreshold ) << endl;
cmess1 << Dots::asString (" - Antenna Max. WL" ,DbU::getValueString(_antennaMaxWL )) << endl;
cmess1 << Dots::asString (" - Latch up Distance",DbU::getValueString(_latchUpDistance)) << endl;
} }
@ -141,15 +152,19 @@ namespace Etesian {
Record* Configuration::_getRecord () const Record* Configuration::_getRecord () const
{ {
Record* record = new Record ( _getString() ); Record* record = new Record ( _getString() );
record->add ( getSlot( "_rg" , _rg ) ); record->add ( getSlot( "_rg" , _rg ) );
record->add ( getSlot( "_cg" , _cg ) ); record->add ( getSlot( "_cg" , _cg ) );
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) ); record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
record->add ( getSlot( "_updateConf" , (int)_updateConf ) ); record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) ); record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) ); record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) ); record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
record->add ( getSlot( "_feedNames" , _feedNames ) ); record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
record->add ( getSlot( "_bloat" , _bloat ) ); record->add ( getSlot( "_feedNames" , _feedNames ) );
record->add ( getSlot( "_diodeName" , _diodeName ) );
record->add ( getSlot( "_bloat" , _bloat ) );
record->add ( DbU::getValueSlot( "_latchUpDistance", &_latchUpDistance ) );
record->add ( DbU::getValueSlot( "_antennaMaxWL" , &_antennaMaxWL ) );
return record; return record;
} }

View File

@ -19,6 +19,7 @@
#include <fstream> #include <fstream>
#include <iomanip> #include <iomanip>
#include "coloquinte/circuit.hxx" #include "coloquinte/circuit.hxx"
#include "coloquinte/circuit_helper.hxx"
#include "coloquinte/legalizer.hxx" #include "coloquinte/legalizer.hxx"
#include "vlsisapd/configuration/Configuration.h" #include "vlsisapd/configuration/Configuration.h"
#include "vlsisapd/utilities/Dots.h" #include "vlsisapd/utilities/Dots.h"
@ -39,6 +40,7 @@
#include "hurricane/Vertical.h" #include "hurricane/Vertical.h"
#include "hurricane/Horizontal.h" #include "hurricane/Horizontal.h"
#include "hurricane/RoutingPad.h" #include "hurricane/RoutingPad.h"
#include "hurricane/NetExternalComponents.h"
#include "hurricane/UpdateSession.h" #include "hurricane/UpdateSession.h"
#include "hurricane/viewer/CellWidget.h" #include "hurricane/viewer/CellWidget.h"
#include "hurricane/viewer/CellViewer.h" #include "hurricane/viewer/CellViewer.h"
@ -55,6 +57,7 @@ namespace {
using coloquinte::int_t; using coloquinte::int_t;
using coloquinte::float_t; using coloquinte::float_t;
using coloquinte::point; using coloquinte::point;
using Etesian::EtesianEngine;
// Options for both placers // Options for both placers
unsigned const SteinerModel = 0x0001; unsigned const SteinerModel = 0x0001;
@ -174,6 +177,42 @@ namespace {
return Transformation( tx, ty, orient ); return Transformation( tx, ty, orient );
} }
uint32_t getOutputSide ( Cell* cell )
{
static map<Cell*,uint32_t> cache;
auto icache = cache.find( cell );
if (icache != cache.end()) return (*icache).second;
Net* output = NULL;
for ( Net* net : cell->getNets() ) {
if (net->isSupply()) continue;
if (net->getDirection() & Net::Direction::DirOut) {
output = net;
break;
}
}
if (not output) return EtesianEngine::RightSide;
Box ab = cell->getAbutmentBox();
DbU::Unit left = ab.getWidth();
DbU::Unit right = ab.getWidth();
for ( Component* comp : NetExternalComponents::get(output) ) {
Box bb = comp->getBoundingBox();
DbU::Unit distance = bb.getXMin() - ab.getXMin();
left = std::min( left, distance );
distance = ab.getXMax() - bb.getXMax();
right = std::min( right, distance );
}
uint32_t flags = (left < right) ? EtesianEngine::LeftSide : EtesianEngine::RightSide;
cache[ cell ] = flags;
return flags;
}
} // Anonymous namespace. } // Anonymous namespace.
@ -256,19 +295,24 @@ namespace Etesian {
, _block (NULL) , _block (NULL)
, _ySpinSet (false) , _ySpinSet (false)
, _flatDesign (false) , _flatDesign (false)
, _surface () , _surface (NULL)
, _circuit () , _circuit (NULL)
, _placementLB () , _placementLB (NULL)
, _placementUB () , _placementUB (NULL)
, _densityLimits(NULL)
, _cellsToIds () , _cellsToIds ()
, _idsToInsts () , _idsToInsts ()
, _idsToNets ()
, _viewer (NULL) , _viewer (NULL)
, _diodeCell (NULL)
, _feedCells (this) , _feedCells (this)
, _bloatCells (this) , _bloatCells (this)
, _area (NULL)
, _yspinSlice0 (0) , _yspinSlice0 (0)
, _sliceHeight (0) , _sliceHeight (0)
, _fixedAbHeight(0) , _fixedAbHeight(0)
, _fixedAbWidth (0) , _fixedAbWidth (0)
, _diodeCount (0)
{ {
} }
@ -283,6 +327,13 @@ namespace Etesian {
cmess2 << " o ISPD benchmark <" << getCell()->getName() cmess2 << " o ISPD benchmark <" << getCell()->getName()
<< ">, no feed cells will be added." << endl; << ">, no feed cells will be added." << endl;
} else { } else {
_diodeCell = DataBase::getDB()->getCell( getConfiguration()->getDiodeName() );;
if (not _diodeCell) {
cerr << Warning( "EtesianEngine::_postCreate() Unable to find \"%s\" diode cell."
, getConfiguration()->getDiodeName().c_str()
) << endl;
}
_bloatCells.select( getConfiguration()->getBloat() ); _bloatCells.select( getConfiguration()->getBloat() );
string feedNames = getConfiguration()->getFeedNames(); string feedNames = getConfiguration()->getFeedNames();
@ -330,23 +381,53 @@ namespace Etesian {
void EtesianEngine::_preDestroy () void EtesianEngine::_preDestroy ()
{ {
cdebug_log(129,1) << "EtesianEngine::_preDestroy()" << endl; cdebug_log(120,1) << "EtesianEngine::_preDestroy()" << endl;
cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <" cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <"
<< getCell()->getName() << ">" << endl; << getCell()->getName() << ">" << endl;
Super::_preDestroy(); Super::_preDestroy();
cdebug.log(129,-1); cdebug.log(120,-1);
} }
EtesianEngine::~EtesianEngine () EtesianEngine::~EtesianEngine ()
{ {
clearColoquinte();
delete _area;
delete _configuration; delete _configuration;
} }
void EtesianEngine::clearColoquinte ()
{
cmess1 << " o Clearing Coloquinte data-structures on <" << getCell()->getName() << ">" << endl;
delete _surface;
delete _circuit;
delete _placementLB;
delete _placementUB;
delete _densityLimits;
unordered_map<string,unsigned int> emptyCellsToIds;
_cellsToIds.swap( emptyCellsToIds );
vector<InstanceInfos> emptyIdsToInsts;
_idsToInsts.swap( emptyIdsToInsts );
vector<NetInfos> emptyIdsToNets;
_idsToNets.swap( emptyIdsToNets );
_surface = NULL;
_circuit = NULL;
_placementLB = NULL;
_placementUB = NULL;
_densityLimits = NULL;
_diodeCount = 0;
}
const Name& EtesianEngine::getName () const const Name& EtesianEngine::getName () const
{ return _toolName; } { return _toolName; }
@ -645,7 +726,7 @@ namespace Etesian {
instances[instanceId].attributes = 0; instances[instanceId].attributes = 0;
_cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) ); _cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) );
_idsToInsts.push_back( instance ); _idsToInsts.push_back( make_tuple(instance,0,0) );
// cerr << "FIXED id=" << instanceId // cerr << "FIXED id=" << instanceId
// << " " << instance << " size:(" << xsize << " " << ysize // << " " << instance << " size:(" << xsize << " " << ysize
// << ") pos:(" << xpos << " " << ypos << ")" << endl; // << ") pos:(" << xpos << " " << ypos << ")" << endl;
@ -719,7 +800,7 @@ namespace Etesian {
} }
_cellsToIds.insert( make_pair(instanceName,instanceId) ); _cellsToIds.insert( make_pair(instanceName,instanceId) );
_idsToInsts.push_back( instance ); _idsToInsts.push_back( make_tuple(instance,0,0) );
++instanceId; ++instanceId;
dots.dot(); dots.dot();
} }
@ -767,6 +848,7 @@ namespace Etesian {
vector<temporary_net> nets ( netsNb ); vector<temporary_net> nets ( netsNb );
vector<temporary_pin> pins; vector<temporary_pin> pins;
_idsToNets.resize( netsNb );
unsigned int netId = 0; unsigned int netId = 0;
for ( Net* net : getCell()->getNets() ) for ( Net* net : getCell()->getNets() )
@ -781,6 +863,7 @@ namespace Etesian {
dots.dot(); dots.dot();
nets[netId] = temporary_net( netId, 1 ); nets[netId] = temporary_net( netId, 1 );
_idsToNets[netId] = make_tuple( net, _cellsToIds.size(), 0 );
//cerr << "+ " << net << endl; //cerr << "+ " << net << endl;
@ -822,6 +905,14 @@ namespace Etesian {
} }
} else { } else {
pins.push_back( temporary_pin( point<int_t>(xpin,ypin), (*iid).second, netId ) ); pins.push_back( temporary_pin( point<int_t>(xpin,ypin), (*iid).second, netId ) );
Net* rpNet = NULL;
Plug* plug = dynamic_cast<Plug*>( rp->getPlugOccurrence().getEntity() );
if (plug) {
rpNet = plug->getMasterNet();
if (rpNet->getDirection() & Net::Direction::DirOut) {
std::get<1>( _idsToNets[netId] ) = (*iid).second;
}
}
} }
//cerr << "| " << rp << " pos:(" << xpin << " " << ypin << ")" << endl; //cerr << "| " << rp << " pos:(" << xpin << " " << ypin << ")" << endl;
@ -831,16 +922,18 @@ namespace Etesian {
} }
dots.finish( Dots::Reset ); dots.finish( Dots::Reset );
_surface = box<int_t>( (int_t)(topAb.getXMin() / vpitch) _densityLimits = new coloquinte::density_restrictions ();
, (int_t)(topAb.getXMax() / vpitch) _surface = new box<int_t>( (int_t)(topAb.getXMin() / vpitch)
, (int_t)(topAb.getYMin() / hpitch) , (int_t)(topAb.getXMax() / vpitch)
, (int_t)(topAb.getYMax() / hpitch) , (int_t)(topAb.getYMin() / hpitch)
); , (int_t)(topAb.getYMax() / hpitch)
_circuit = netlist( instances, nets, pins ); );
_circuit.selfcheck(); _circuit = new netlist( instances, nets, pins );
_placementLB.positions_ = positions; _circuit->selfcheck();
_placementLB.orientations_ = orientations; _placementLB = new coloquinte::placement_t ();
_placementUB = _placementLB; _placementLB->positions_ = positions;
_placementLB->orientations_ = orientations;
_placementUB = new coloquinte::placement_t ( *_placementLB );
return instancesNb-fixedNb; return instancesNb-fixedNb;
} }
@ -890,18 +983,18 @@ namespace Etesian {
// Perform a very quick legalization pass // Perform a very quick legalization pass
cmess2 << " o Simple legalization." << endl; cmess2 << " o Simple legalization." << endl;
auto first_legalizer = region_distribution::uniform_density_distribution(_surface, _circuit, _placementLB); auto first_legalizer = region_distribution::uniform_density_distribution(*_surface, *_circuit, *_placementLB);
first_legalizer.selfcheck(); first_legalizer.selfcheck();
get_rough_legalization( _circuit, _placementUB, first_legalizer); get_rough_legalization( *_circuit, *_placementUB, first_legalizer);
_placementLB = _placementUB; *_placementLB = *_placementUB;
// Early topology-independent solution with a star model + negligible pulling forces to avoid dumb solutions // Early topology-independent solution with a star model + negligible pulling forces to avoid dumb solutions
// Spreads well to help subsequent optimization passes // Spreads well to help subsequent optimization passes
cmess2 << " o Star (*) Optimization." << endl; cmess2 << " o Star (*) Optimization." << endl;
auto solv = get_star_linear_system( _circuit, _placementLB, 1.0, 0, 10) // Limit the number of pins: don't want big awful nets with high weight auto solv = get_star_linear_system( *_circuit, *_placementLB, 1.0, 0, 10) // Limit the number of pins: don't want big awful nets with high weight
+ get_pulling_forces( _circuit, _placementUB, 1000000.0); + get_pulling_forces( *_circuit, *_placementUB, 1000000.0);
solve_linear_system( _circuit, _placementLB, solv, 200 ); solve_linear_system( *_circuit, *_placementLB, solv, 200 );
_progressReport2(" [---]" ); _progressReport2(" [---]" );
} }
@ -911,8 +1004,8 @@ namespace Etesian {
using namespace coloquinte::gp; using namespace coloquinte::gp;
// Create a legalizer and bipartition it until we have sufficient precision // Create a legalizer and bipartition it until we have sufficient precision
auto legalizer = (options & ForceUniformDensity) != 0 ? auto legalizer = (options & ForceUniformDensity) != 0 ?
region_distribution::uniform_density_distribution (_surface, _circuit, _placementLB, _densityLimits) region_distribution::uniform_density_distribution (*_surface, *_circuit, *_placementLB, *_densityLimits)
: region_distribution::full_density_distribution (_surface, _circuit, _placementLB, _densityLimits); : region_distribution::full_density_distribution (*_surface, *_circuit, *_placementLB, *_densityLimits);
while(legalizer.region_dimensions().x > 2*legalizer.region_dimensions().y) while(legalizer.region_dimensions().x > 2*legalizer.region_dimensions().y)
legalizer.x_bipartition(); legalizer.x_bipartition();
while(2*legalizer.region_dimensions().x < legalizer.region_dimensions().y) while(2*legalizer.region_dimensions().x < legalizer.region_dimensions().y)
@ -927,9 +1020,9 @@ namespace Etesian {
legalizer.selfcheck(); legalizer.selfcheck();
} }
// Keep the orientation between LB and UB // Keep the orientation between LB and UB
_placementUB = _placementLB; *_placementUB = *_placementLB;
// Update UB // Update UB
get_rough_legalization( _circuit, _placementUB, legalizer ); get_rough_legalization( *_circuit, *_placementUB, legalizer );
} }
@ -942,11 +1035,12 @@ namespace Etesian {
{ {
using namespace coloquinte::gp; using namespace coloquinte::gp;
bool antennaDone = false;
float_t penaltyIncrease = minInc; float_t penaltyIncrease = minInc;
float_t linearDisruption = get_mean_linear_disruption(_circuit, _placementLB, _placementUB); float_t linearDisruption = get_mean_linear_disruption(*_circuit, *_placementLB, *_placementUB);
float_t pullingForce = initPenalty; float_t pullingForce = initPenalty;
float_t upperWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementUB)), float_t upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB)),
lowerWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementLB)); lowerWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementLB));
float_t prevOptRatio = lowerWL / upperWL; float_t prevOptRatio = lowerWL / upperWL;
index_t i=0; index_t i=0;
@ -957,32 +1051,37 @@ namespace Etesian {
ostringstream label; ostringstream label;
label.str(""); label.str("");
label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] Bipart."; label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "] "
<< setw(5) << setprecision(4) << linearDisruption << "% Bipart.";
_progressReport1(label.str() ); _progressReport1(label.str() );
upperWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementUB)); upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB));
//float_t legRatio = lowerWL / upperWL; //float_t legRatio = lowerWL / upperWL;
// Get the system to optimize (tolerance, maximum and minimum pin counts) // Get the system to optimize (tolerance, maximum and minimum pin counts)
// and the pulling forces (threshold distance) // and the pulling forces (threshold distance)
auto opt_problem = (options & SteinerModel) ? auto opt_problem = (options & SteinerModel) ?
get_RSMT_linear_system ( _circuit, _placementLB, minDisruption, 2, 100000 ) get_RSMT_linear_system ( *_circuit, *_placementLB, minDisruption, 2, 100000 )
: get_HPWLF_linear_system ( _circuit, _placementLB, minDisruption, 2, 100000 ); : get_HPWLF_linear_system ( *_circuit, *_placementLB, minDisruption, 2, 100000 );
auto solv = opt_problem auto solv = opt_problem
+ get_linear_pulling_forces( _circuit, _placementUB, _placementLB, pullingForce, 2.0f * linearDisruption); + get_linear_pulling_forces( *_circuit
solve_linear_system( _circuit, _placementLB, solv, 200 ); // 200 iterations , *_placementUB
_progressReport2(" Linear." ); , *_placementLB
, pullingForce
, 2.0f * linearDisruption);
solve_linear_system( *_circuit, *_placementLB, solv, 200 ); // 200 iterations
_progressReport2(" Linear." );
if(options & UpdateLB) if(options & UpdateLB)
_updatePlacement( _placementLB ); _updatePlacement( _placementUB );
// Optimize orientation sometimes // Optimize orientation sometimes
if (i%5 == 0) { if (i%5 == 0) {
optimize_exact_orientations( _circuit, _placementLB ); optimize_exact_orientations( *_circuit, *_placementLB );
_progressReport2(" Orient." ); _progressReport2(" Orient." );
} }
lowerWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementLB)); lowerWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementLB));
float_t optRatio = lowerWL / upperWL; float_t optRatio = lowerWL / upperWL;
/* /*
@ -1000,8 +1099,13 @@ namespace Etesian {
pullingForce += penaltyIncrease; pullingForce += penaltyIncrease;
prevOptRatio = optRatio; prevOptRatio = optRatio;
linearDisruption = get_mean_linear_disruption(_circuit, _placementLB, _placementUB); linearDisruption = get_mean_linear_disruption(*_circuit, *_placementLB, *_placementUB);
++i; ++i;
if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) {
antennaProtect();
antennaDone = true;
}
// First way to exit the loop: UB and LB difference is <10% // First way to exit the loop: UB and LB difference is <10%
// Second way to exit the loop: the legalization is close enough to the previous result // Second way to exit the loop: the legalization is close enough to the previous result
} while (linearDisruption > minDisruption and prevOptRatio <= 0.9); } while (linearDisruption > minDisruption and prevOptRatio <= 0.9);
@ -1023,52 +1127,94 @@ namespace Etesian {
label.str(""); label.str("");
label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "]"; label << " [" << setw(3) << setfill('0') << i << setfill(' ') << "]";
optimize_x_orientations( _circuit, _placementUB ); // Don't disrupt VDD/VSS connections in a row optimize_x_orientations( *_circuit, *_placementUB ); // Don't disrupt VDD/VSS connections in a row
_progressReport1(label.str() + " Oriented ......." ); _progressReport1(label.str() + " Oriented ......." );
if(options & UpdateDetailed) if(options & UpdateDetailed)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight ); auto legalizer = legalize( *_circuit, *_placementUB, *_surface, sliceHeight );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
_progressReport1(" Legalized ......" ); _progressReport1(" Legalized ......" );
if(options & UpdateDetailed) if(options & UpdateDetailed)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
row_compatible_orientation( _circuit, legalizer, true ); row_compatible_orientation( *_circuit, legalizer, true );
swaps_global_HPWL( _circuit, legalizer, 3, 4 ); swaps_global_HPWL( *_circuit, legalizer, 3, 4 );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
_progressReport1(" Global Swaps ..." ); _progressReport1(" Global Swaps ..." );
if(options & UpdateDetailed) if(options & UpdateDetailed)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
if(options & SteinerModel) if(options & SteinerModel)
OSRP_noncvx_RSMT( _circuit, legalizer ); OSRP_noncvx_RSMT( *_circuit, legalizer );
else else
OSRP_convex_HPWL( _circuit, legalizer ); OSRP_convex_HPWL( *_circuit, legalizer );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
_progressReport1(" Row Optimization" ); _progressReport1(" Row Optimization" );
if(options & UpdateDetailed) if(options & UpdateDetailed)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
if(options & SteinerModel) if(options & SteinerModel)
swaps_row_noncvx_RSMT( _circuit, legalizer, effort+2 ); swaps_row_noncvx_RSMT( *_circuit, legalizer, effort+2 );
else else
swaps_row_convex_HPWL( _circuit, legalizer, effort+2 ); swaps_row_convex_HPWL( *_circuit, legalizer, effort+2 );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
_progressReport1(" Local Swaps ...." ); _progressReport1(" Local Swaps ...." );
if(options & UpdateDetailed) if(options & UpdateDetailed)
_updatePlacement( _placementUB ); _updatePlacement( _placementUB );
if (i == iterations-1) { if (i == iterations-1) {
//swaps_row_convex_RSMT( _circuit, legalizer, 4 ); //swaps_row_convex_RSMT( *_circuit, legalizer, 4 );
row_compatible_orientation( _circuit, legalizer, true ); row_compatible_orientation( *_circuit, legalizer, true );
coloquinte::dp::get_result( _circuit, legalizer, _placementUB ); coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
verify_placement_legality( _circuit, _placementUB, _surface ); verify_placement_legality( *_circuit, *_placementUB, *_surface );
_progressReport1(" Final Legalize ." ); _progressReport1(" Final Legalize ." );
} }
} }
_placementLB = _placementUB; // In case we run other passes *_placementLB = *_placementUB; // In case we run other passes
_updatePlacement( _placementUB ); _updatePlacement( _placementUB, FinalStage );
}
void EtesianEngine::antennaProtect ()
{
DbU::Unit maxWL = getAntennaMaxWL();
if (not maxWL) return;
cmess1 << " o Inserting antenna effect protection." << endl;
uint32_t count = 0;
int_t diodeWidth = _diodeCell->getAbutmentBox().getWidth() / getSliceStep();
cdebug_log(122,0) << "diodeWidth=" << diodeWidth << "p" << endl;
for ( coloquinte::index_t inet=0 ; inet < _circuit->net_cnt() ; ++inet ) {
DbU::Unit rsmt = toDbU( coloquinte::get_RSMT_length( *_circuit, *_placementUB, inet ) );
size_t idriver = std::get<1>( _idsToNets[inet] );
if (idriver >= _cellsToIds.size()) continue;
Instance* instance = std::get<0>( _idsToInsts[idriver] );
string masterName = getString( instance->getMasterCell()->getName() );
uint32_t drivePower = 1;
if (masterName.substr(masterName.size()-3,2) == "_x") {
drivePower = std::stoi( masterName.substr(masterName.size()-1) );
}
if (rsmt > drivePower*maxWL) {
Net* net = std::get<0>( _idsToNets[inet] );
cdebug_log(122,0) << "| Net [" << inet << "] \"" << net->getName() << "\" may have antenna effect, "
<< DbU::getValueString(rsmt)
<< " drive=" << drivePower
<< " \"" << masterName << "\""
<< endl;
std::get<2>( _idsToNets [inet ] ) |= NeedsDiode;
std::get<2>( _idsToInsts[idriver] ) |= NeedsDiode;
std::get<1>( _idsToInsts[idriver] ) = inet;
coloquinte::point<int_t> cell_size = _circuit->get_cell_size(idriver);
cell_size.x += diodeWidth;
_circuit->set_cell_size( idriver, cell_size );
++count;
}
}
cmess1 << ::Dots::asInt( " - Inserted diodes", count ) << endl;
} }
@ -1163,17 +1309,18 @@ namespace Etesian {
cmess1 << " o Detailed Placement." << endl; cmess1 << " o Detailed Placement." << endl;
detailedPlace(detailedIterations, detailedEffort, detailedOptions); detailedPlace(detailedIterations, detailedEffort, detailedOptions);
Breakpoint::stop( 100, "Before adding feeds." );
cmess2 << " o Adding feed cells." << endl; cmess2 << " o Adding feed cells." << endl;
readSlices(); toHurricane();
//addFeeds(); //addFeeds();
cmess1 << " o Placement finished." << endl; cmess1 << " o Placement finished." << endl;
stopMeasures(); stopMeasures();
printMeasures(); printMeasures();
cmess1 << ::Dots::asString cmess1 << ::Dots::asString
( " - HPWL", DbU::getValueString( (DbU::Unit)coloquinte::gp::get_HPWL_wirelength(_circuit,_placementUB )*getSliceStep() ) ) << endl; ( " - HPWL", DbU::getValueString( (DbU::Unit)coloquinte::gp::get_HPWL_wirelength(*_circuit,*_placementUB )*getSliceStep() ) ) << endl;
cmess1 << ::Dots::asString cmess1 << ::Dots::asString
( " - RMST", DbU::getValueString( (DbU::Unit)coloquinte::gp::get_RSMT_wirelength(_circuit,_placementUB )*getSliceStep() ) ) << endl; ( " - RMST", DbU::getValueString( (DbU::Unit)coloquinte::gp::get_RSMT_wirelength(*_circuit,*_placementUB )*getSliceStep() ) ) << endl;
UpdateSession::open(); UpdateSession::open();
for ( Net* net : getCell()->getNets() ) { for ( Net* net : getCell()->getNets() ) {
@ -1202,12 +1349,12 @@ namespace Etesian {
} }
cmess2 << label cmess2 << label
<< " HPWL:" << setw(11) << coloquinte::gp::get_HPWL_wirelength( _circuit, _placementUB ) << " HPWL=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_HPWL_wirelength( *_circuit, *_placementUB )))
<< " RMST:" << setw(11) << coloquinte::gp::get_RSMT_wirelength( _circuit, _placementUB ) << " RMST=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_RSMT_wirelength( *_circuit, *_placementUB )))
<< endl; << endl;
cparanoid << indent cparanoid << indent
<< " L-Dsrpt:" << setw(8) << coloquinte::gp::get_mean_linear_disruption ( _circuit, _placementLB, _placementUB ) << " L-Dsrpt=" << setw(8) << coloquinte::gp::get_mean_linear_disruption ( *_circuit, *_placementLB, *_placementUB )
<< " Q-Dsrpt:" << setw(8) << coloquinte::gp::get_mean_quadratic_disruption( _circuit, _placementLB, _placementUB ) << " Q-Dsrpt=" << setw(8) << coloquinte::gp::get_mean_quadratic_disruption( *_circuit, *_placementLB, *_placementUB )
<< endl; << endl;
} }
@ -1222,13 +1369,13 @@ namespace Etesian {
} }
cmess2 << label cmess2 << label
<< " HPWL:" << setw(11) << coloquinte::gp::get_HPWL_wirelength( _circuit, _placementLB ) << " HPWL=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_HPWL_wirelength( *_circuit, *_placementLB )))
<< " RMST:" << setw(11) << coloquinte::gp::get_RSMT_wirelength( _circuit, _placementLB ) << " RMST=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_RSMT_wirelength( *_circuit, *_placementLB )))
<< endl; << endl;
} }
void EtesianEngine::_updatePlacement ( const coloquinte::placement_t& placement ) void EtesianEngine::_updatePlacement ( const coloquinte::placement_t* placement, uint32_t flags )
{ {
UpdateSession::open(); UpdateSession::open();
@ -1236,6 +1383,8 @@ namespace Etesian {
if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation(); if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation();
topTransformation.invert(); topTransformation.invert();
vector< tuple<Occurrence,size_t,Transformation> > diodeMasters;
for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) ) for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) )
{ {
DbU::Unit hpitch = getSliceStep(); DbU::Unit hpitch = getSliceStep();
@ -1254,29 +1403,106 @@ namespace Etesian {
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED) if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
continue; continue;
point<int_t> position = placement.positions_[(*iid).second]; uint32_t outputSide = getOutputSide( instance->getMasterCell() );
Transformation trans = toTransformation( position point<int_t> position = placement->positions_[(*iid).second];
, placement.orientations_[(*iid).second] Transformation cellTrans = toTransformation( position
, instance->getMasterCell() , placement->orientations_[(*iid).second]
, hpitch , instance->getMasterCell()
, vpitch , hpitch
); , vpitch
);
topTransformation.applyOn( cellTrans );
//cerr << "Setting <" << instanceName << " @" << instancePosition << endl; //cerr << "Setting <" << instanceName << " @" << instancePosition << endl;
if ((flags & FinalStage) and (std::get<2>(_idsToInsts[(*iid).second]) & NeedsDiode)) {
Transformation diodeTrans;
if (outputSide & RightSide) {
DbU::Unit dx = instance ->getMasterCell()->getAbutmentBox().getWidth();
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
dx = -dx;
diodeTrans = Transformation( cellTrans.getTx() + dx
, cellTrans.getTy()
, cellTrans.getOrientation() );
} else {
DbU::Unit dx = _diodeCell->getAbutmentBox().getWidth();
if ( (cellTrans.getOrientation() == Transformation::Orientation::R2)
or (cellTrans.getOrientation() == Transformation::Orientation::MX))
dx = -dx;
diodeTrans = cellTrans;
cellTrans = Transformation( diodeTrans.getTx() + dx
, diodeTrans.getTy()
, diodeTrans.getOrientation() );
}
diodeMasters.push_back( make_tuple( occurrence
, std::get<1>(_idsToInsts[(*iid).second])
, diodeTrans ));
}
// This is temporary as it's not trans-hierarchic: we ignore the positions // This is temporary as it's not trans-hierarchic: we ignore the positions
// of all the intermediary instances. // of all the intermediary instances.
topTransformation.applyOn( trans ); instance->setTransformation( cellTrans );
instance->setTransformation( trans );
instance->setPlacementStatus( Instance::PlacementStatus::PLACED ); instance->setPlacementStatus( Instance::PlacementStatus::PLACED );
} }
} }
if (_diodeCell) {
Net* diodeOutput = NULL;
for ( Net* net : _diodeCell->getNets() ) {
if (net->isSupply() or not net->isExternal()) continue;
diodeOutput = net;
break;
}
for ( auto diodeInfos : diodeMasters ) {
Net* topNet = std::get<0>( _idsToNets[ std::get<1>(diodeInfos) ] );
Instance* instance = static_cast<Instance*>( std::get<0>(diodeInfos).getEntity() );
Cell* ownerCell = instance->getCell();
Instance* diode = _createDiode( ownerCell );
diode->setTransformation( std::get<2>( diodeInfos ));
diode->setPlacementStatus( Instance::PlacementStatus::PLACED );
Net* driverOutput = NULL;
for ( Net* net : instance->getMasterCell()->getNets() ) {
if (net->isSupply() or not net->isExternal()) continue;
if (net->getDirection() & Net::Direction::DirOut) {
driverOutput = net;
break;
}
}
if (diodeOutput and driverOutput) {
cdebug_log(122,0) << "Bind:" << endl;
Plug* diodePlug = diode ->getPlug( diodeOutput );
Plug* driverPlug = instance->getPlug( driverOutput );
diodePlug->setNet( driverPlug->getNet() );
cdebug_log(122,0) << " Driver net=" << topNet << endl;
cdebug_log(122,0) << " " << instance << " @" << instance->getTransformation() << endl;
cdebug_log(122,0) << " " << diode << " @" << diode ->getTransformation() << endl;
cdebug_log(122,0) << " topNet->getCell():" << topNet->getCell() << endl;
cdebug_log(122,0) << " " << std::get<0>(diodeInfos).getPath() << endl;
Path path = std::get<0>(diodeInfos).getPath();
RoutingPad::create( topNet, Occurrence(diodePlug,path), RoutingPad::BiggestArea );
}
}
}
UpdateSession::close(); UpdateSession::close();
if (_viewer) _viewer->getCellWidget()->refresh(); if (_viewer) _viewer->getCellWidget()->refresh();
} }
Instance* EtesianEngine::_createDiode ( Cell* owner )
{
if (not _diodeCell) return NULL;
return Instance::create( owner, string("diode_")+getString(_getNewDiodeId()), _diodeCell );
}
string EtesianEngine::_getTypeName () const string EtesianEngine::_getTypeName () const
{ return "Etesian::EtesianEngine"; } { return "Etesian::EtesianEngine"; }
@ -1295,6 +1521,8 @@ namespace Etesian {
if (record) { if (record) {
record->add( getSlot( "_configuration", _configuration ) ); record->add( getSlot( "_configuration", _configuration ) );
record->add( getSlot( "_area" , _area ) );
record->add( getSlot( "_diodeCount" , _diodeCount ) );
} }
return record; return record;
} }

View File

@ -14,16 +14,12 @@
// +-----------------------------------------------------------------+ // +-----------------------------------------------------------------+
#include <map>
#include <list>
#include <tuple>
#include "hurricane/Error.h" #include "hurricane/Error.h"
#include "hurricane/Warning.h" #include "hurricane/Warning.h"
#include "hurricane/DataBase.h" #include "hurricane/DataBase.h"
#include "hurricane/UpdateSession.h" #include "hurricane/UpdateSession.h"
#include "hurricane/Plug.h" #include "hurricane/Plug.h"
#include "hurricane/Path.h" #include "hurricane/Path.h"
#include "hurricane/Instance.h"
#include "hurricane/Library.h" #include "hurricane/Library.h"
#include "hurricane/viewer/CellWidget.h" #include "hurricane/viewer/CellWidget.h"
#include "hurricane/viewer/CellViewer.h" #include "hurricane/viewer/CellViewer.h"
@ -32,242 +28,40 @@
#include "etesian/EtesianEngine.h" #include "etesian/EtesianEngine.h"
namespace { namespace Etesian {
using namespace std; using namespace std;
using Hurricane::tab; using Hurricane::tab;
using Hurricane::Warning; using Hurricane::Warning;
using Hurricane::Error; using Hurricane::Error;
using Hurricane::DbU;
using Hurricane::Box;
using Hurricane::Interval;
using Hurricane::DBo;
using Hurricane::Occurrence;
using Hurricane::Instance;
using Hurricane::Path; using Hurricane::Path;
using Hurricane::Transformation; using Hurricane::Transformation;
using Hurricane::DataBase; using Hurricane::DataBase;
using Hurricane::Cell;
using Hurricane::Library; using Hurricane::Library;
using Hurricane::UpdateSession;
using CRL::AllianceFramework; using CRL::AllianceFramework;
using CRL::CatalogExtension; using CRL::CatalogExtension;
using CRL::getTransformation; using CRL::getTransformation;
using Etesian::EtesianEngine; using Etesian::EtesianEngine;
// -------------------------------------------------------------------
// Class : "::TieDatas".
class TieDatas {
public:
inline TieDatas ( Cell* cell=NULL, DbU::Unit leftDistance=0, DbU::Unit rightDistance=0 );
inline Cell* getCell () const;
inline DbU::Unit getLeftDistance () const;
inline DbU::Unit getRightDistance() const;
private:
Cell* _cell;
DbU::Unit _leftDistance;
DbU::Unit _rightDistance;
};
inline TieDatas::TieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
: _cell (cell)
, _leftDistance (leftDistance)
, _rightDistance(rightDistance)
{ }
inline Cell* TieDatas::getCell () const { return _cell; }
inline DbU::Unit TieDatas::getLeftDistance () const { return _leftDistance; }
inline DbU::Unit TieDatas::getRightDistance() const { return _rightDistance; }
// -------------------------------------------------------------------
// Class : "::TieLUT".
class TieLUT {
public:
inline TieLUT ();
inline const TieDatas* getTieDatas ( Cell* ) const;
inline DbU::Unit getLeftDistance ( Cell* ) const;
inline DbU::Unit getRightDistance ( Cell* ) const;
inline void addTieDatas ( Cell*, DbU::Unit leftDistance, DbU::Unit rightDistance );
private:
map< Cell*, TieDatas, DBo::CompareById > _tieLut;
};
inline TieLUT::TieLUT ()
: _tieLut()
{ }
inline void TieLUT::addTieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
{
const TieDatas* datas = getTieDatas( cell );
if (datas) {
cerr << Error( "TieLUT::addTieDatas(): Duplicate datas for % (ignoreds)."
, getString(cell).c_str()
) << endl;
}
_tieLut[ cell ] = TieDatas( cell, leftDistance, rightDistance );
}
inline const TieDatas* TieLUT::getTieDatas ( Cell* cell ) const
{
auto iDatas = _tieLut.find( cell );
return (iDatas != _tieLut.end()) ? &((*iDatas).second) : NULL;
}
inline DbU::Unit TieLUT::getLeftDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getLeftDistance() : 0;
}
inline DbU::Unit TieLUT::getRightDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getRightDistance() : 0;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Class : "::Tile". // Class : "::Tile".
class Area;
class Slice;
Record* Tile::_getRecord () const
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 Cell* getMasterCell () const;
inline Instance* getInstance () 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 Instance* Tile::getInstance () const { return static_cast<Instance*>( _occurrence.getEntity() ); }
inline Cell* Tile::getMasterCell () const { return getInstance()->getMasterCell(); }
inline bool Tile::isFixed () const
{ return getInstance()->getPlacementStatus() == Instance::PlacementStatus::FIXED; }
inline void Tile::translate ( DbU::Unit dx )
{ {
cdebug_log(121,0) << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << endl; Record* record = new Record(getString(this));
Instance* instance = getInstance(); record->add( getSlot( "_occurrence", _occurrence ) );
Transformation reference = instance->getTransformation(); record->add( DbU::getValueSlot( "_xMin" , &_xMin ) );
Transformation transf = Transformation( reference.getTx() + dx record->add( DbU::getValueSlot( "_width", &_width ) );
, reference.getTy() return record;
, 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 getYBottom () 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".
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;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) 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 ) Slice::Slice ( Area* area, DbU::Unit ybottom )
: _area (area) : _area (area)
@ -388,7 +182,7 @@ namespace {
void Slice::addFeeds ( size_t islice ) void Slice::addFeeds ( size_t islice )
{ {
if (_tiles.empty()) { if (_tiles.empty()) {
fillHole( getXMin(), getXMax(), getYBottom(), islice%2 ); fillHole( _tiles.end(), getXMin(), getXMax(), getYBottom(), islice%2 );
return; return;
} }
@ -398,21 +192,27 @@ namespace {
// Hole before the first chunk. // Hole before the first chunk.
if ((*itile).getXMin() > getXMin()) { if ((*itile).getXMin() > getXMin()) {
fillHole( getXMin(), (*itile).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 ); fillHole( itile, getXMin(), (*itile).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 );
} }
for ( ; itilenext != _tiles.end() ; ++itile, ++itilenext ) { while ( itilenext != _tiles.end() ) {
fillHole( (*itile).getXMax(), (*itilenext).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 ); fillHole( itilenext, (*itile).getXMax(), (*itilenext).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 );
itile = itilenext;
++itilenext;
} }
// Hole after the last chunk. // Hole after the last chunk.
if ((*itile).getXMax() < getXMax()) { if ((*itile).getXMax() < getXMax()) {
fillHole( (*itile).getXMax(), getXMax(), getYBottom(), (islice+getSpinSlice0())%2 ); fillHole( _tiles.end(), (*itile).getXMax(), getXMax(), getYBottom(), (islice+getSpinSlice0())%2 );
} }
} }
void Slice::fillHole ( DbU::Unit xmin, DbU::Unit xmax, DbU::Unit ybottom, size_t yspin ) void Slice::fillHole ( std::list<Tile>::iterator before
, DbU::Unit xmin
, DbU::Unit xmax
, DbU::Unit ybottom
, size_t yspin )
{ {
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed(); Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
if (feed == NULL) { if (feed == NULL) {
@ -438,52 +238,65 @@ namespace {
if (feed == NULL) break; if (feed == NULL) break;
} }
Instance::create ( getEtesian()->getBlockCell() Instance* instance = Instance::create
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str() ( getEtesian()->getBlockCell()
, feed , getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
, getTransformation( feed->getAbutmentBox() , feed
, xtie , getTransformation( feed->getAbutmentBox()
, _ybottom , xtie
, (yspin)?Transformation::Orientation::MY , _ybottom
:Transformation::Orientation::ID , (yspin)?Transformation::Orientation::MY
) :Transformation::Orientation::ID
, Instance::PlacementStatus::PLACED )
); , Instance::PlacementStatus::PLACED
);
_tiles.insert( before
, Tile( xtie, feed->getAbutmentBox().getWidth(), Occurrence(instance) ));
xtie += feedWidth; xtie += feedWidth;
} }
} }
Instance* Slice::createDiodeUnder ( const Box& diodeArea )
{
Cell* diode = getEtesian()->getDiodeCell();
if (diode == NULL) {
cerr << Error("Slice::createDiodeUnder(): No diode cell has been registered, ignoring.") << endl;
return NULL;
}
Cell* feed = getEtesian()->getFeedCells().getBiggestFeed();
if (feed == NULL) {
cerr << Error("Slice::createDiodeUnder(): No feed has been registered, ignoring.") << endl;
return NULL;
}
Instance* diodeInst = NULL;
for ( auto iTile=_tiles.begin() ; iTile != _tiles.end() ; ++iTile ) {
if ((*iTile).getXMax() < diodeArea.getXMin()) continue;
if ((*iTile).getXMax() >= diodeArea.getXMax()) break;
if ((*iTile).getMasterCell() != feed) continue;
diodeInst = (*iTile).getInstance();
diodeInst->setMasterCell( diode );
break;
}
return diodeInst;
}
Record* Slice::_getRecord () const
{
Record* record = new Record(getString(this));
record->add( getSlot( "_area" , _area ) );
record->add( DbU::getValueSlot( "_ybottom", &_ybottom ) );
record->add( getSlot( "_tiles" , &_tiles ) );
record->add( getSlot( "_subSlices" , &_subSlices ) );
return record;
}
// ------------------------------------------------------------------- // -------------------------------------------------------------------
// Class : "::Area". // 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;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
void merge ( const Occurrence&, const Box& );
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
private:
EtesianEngine* _etesian;
TieLUT _tieLut;
Box _cellAb;
DbU::Unit _sliceHeight;
vector<Slice*> _slices;
size_t _spinSlice0;
};
Area::Area ( EtesianEngine* etesian ) Area::Area ( EtesianEngine* etesian )
: _etesian (etesian) : _etesian (etesian)
@ -505,6 +318,10 @@ namespace {
if (masterCell) { if (masterCell) {
_tieLut.addTieDatas( masterCell, DbU::fromMicrons(1.28), DbU::fromMicrons(11.7) ); _tieLut.addTieDatas( masterCell, DbU::fromMicrons(1.28), DbU::fromMicrons(11.7) );
} }
masterCell = library->getCell( "dio_x0" );
if (masterCell) {
_tieLut.addTieDatas( masterCell, DbU::fromMicrons(6.5), DbU::fromMicrons(6.5) );
}
} }
} }
} }
@ -517,15 +334,6 @@ namespace {
} }
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(); }
inline DbU::Unit Area::getLeftDistance ( Cell* cell ) const { return _tieLut.getLeftDistance(cell); }
inline DbU::Unit Area::getRightDistance ( Cell* cell ) const { return _tieLut.getRightDistance(cell); }
bool Area::validate ( DbU::Unit latchUpMax ) const bool Area::validate ( DbU::Unit latchUpMax ) const
{ {
bool validated = true; bool validated = true;
@ -573,6 +381,19 @@ namespace {
validate( latchUpMax ); validate( latchUpMax );
} }
Record* Area::_getRecord () const
{
Record* record = new Record(getString(this));
record->add( getSlot( "_etesian" , _etesian ) );
record->add( getSlot( "_tieLut" , &_tieLut ) );
record->add( getSlot( "_cellAb" , _cellAb ) );
record->add( DbU::getValueSlot( "_sliceHeight", &_sliceHeight ) );
record->add( getSlot( "_slices" , &_slices ) );
record->add( getSlot( "_spinSlice0" , _spinSlice0 ) );
return record;
}
SubSlice::SubSlice ( Slice* slice, const list<Tile>::iterator& beginTile ) SubSlice::SubSlice ( Slice* slice, const list<Tile>::iterator& beginTile )
: _slice(slice) : _slice(slice)
@ -586,14 +407,6 @@ namespace {
} }
} }
inline DbU::Unit SubSlice::getYBottom () const { return _slice->getYBottom(); }
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 DbU::Unit SubSlice::getAverageChunk ( size_t& count ) const
{ {
@ -755,31 +568,23 @@ namespace {
cdebug_tabw(121,-2); cdebug_tabw(121,-2);
} }
Instance* Area::createDiodeUnder ( const Box& diodeArea )
{
DbU::Unit y = diodeArea.getYCenter();
inline DbU::Unit Slice::getYBottom () const { return _ybottom; } if ((y < _cellAb.getYMin()) or (y >= _cellAb.getYMax())) return NULL;
inline DbU::Unit Slice::getXMin () const { return _area->getXMin(); } if (not diodeArea.intersect(_cellAb)) return NULL;
inline DbU::Unit Slice::getXMax () const { return _area->getXMax(); }
inline DbU::Unit Slice::getLeftDistance ( Cell* cell ) const { return _area->getLeftDistance(cell); } size_t islice = (y - _cellAb.getYMin()) / _sliceHeight;
inline DbU::Unit Slice::getRightDistance ( Cell* cell ) const { return _area->getRightDistance(cell); } return _slices[islice]->createDiodeUnder( diodeArea );
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. // -------------------------------------------------------------------
// Class : "::EtesianEngine".
void EtesianEngine::toHurricane ()
namespace Etesian {
using Hurricane::DataBase;
using Hurricane::UpdateSession;
using Hurricane::Occurrence;
void EtesianEngine::readSlices ()
{ {
if (not getFeedCells().feedNumbers()) { if (not getFeedCells().feedNumbers()) {
cerr << Warning( "EtesianEngine::readSlices(): No feed cells available, skipping." ) << endl; cerr << Warning( "EtesianEngine::readSlices(): No feed cells available, skipping." ) << endl;
@ -788,10 +593,11 @@ namespace Etesian {
UpdateSession::open(); UpdateSession::open();
Area area ( this ); if (_area) delete _area;
_area = new Area ( this );
Box topCellAb = getBlockCell()->getAbutmentBox(); Box topCellAb = getBlockCell()->getAbutmentBox();
area.setSpinSlice0( _yspinSlice0 ); _area->setSpinSlice0( _yspinSlice0 );
if (getBlockInstance()) { if (getBlockInstance()) {
Transformation toBlockTransf = getBlockInstance()->getTransformation(); Transformation toBlockTransf = getBlockInstance()->getTransformation();
@ -803,7 +609,7 @@ namespace Etesian {
toBlockTransf.applyOn( overlapAb ); toBlockTransf.applyOn( overlapAb );
overlapAb = topCellAb.getIntersection( overlapAb ); overlapAb = topCellAb.getIntersection( overlapAb );
if (not overlapAb.isEmpty()) { if (not overlapAb.isEmpty()) {
area.merge( Occurrence(instance), overlapAb ); _area->merge( Occurrence(instance), overlapAb );
} }
} }
} }
@ -831,19 +637,19 @@ namespace Etesian {
continue; continue;
} }
area.merge( occurrence, instanceAb ); _area->merge( occurrence, instanceAb );
} }
area.buildSubSlices(); _area->buildSubSlices();
area.showSubSlices(); _area->showSubSlices();
if (getConfiguration()->getLatchUpDistance()) { if (getConfiguration()->getLatchUpDistance()) {
Cell* feed = getFeedCells().getBiggestFeed(); Cell* feed = getFeedCells().getBiggestFeed();
DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2 - feed->getAbutmentBox().getWidth(); DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2 - feed->getAbutmentBox().getWidth();
if (feed != NULL) if (feed != NULL)
tieSpacing -= feed->getAbutmentBox().getWidth(); tieSpacing -= feed->getAbutmentBox().getWidth();
area.insertTies( tieSpacing ); _area->insertTies( tieSpacing );
} }
area.addFeeds(); _area->addFeeds();
UpdateSession::close(); UpdateSession::close();

View File

@ -71,6 +71,7 @@ extern "C" {
DirectVoidMethod(EtesianEngine,etesian,setDefaultAb) DirectVoidMethod(EtesianEngine,etesian,setDefaultAb)
DirectVoidMethod(EtesianEngine,etesian,resetPlacement) DirectVoidMethod(EtesianEngine,etesian,resetPlacement)
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine) DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine) DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine) DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
@ -233,6 +234,8 @@ extern "C" {
, "Override the configuration aspect ratio parameter value." } , "Override the configuration aspect ratio parameter value." }
, { "resetPlacement" , (PyCFunction)PyEtesianEngine_resetPlacement , METH_NOARGS , { "resetPlacement" , (PyCFunction)PyEtesianEngine_resetPlacement , METH_NOARGS
, "Compute and set the abutment box using the aspect ratio and the space margin." } , "Compute and set the abutment box using the aspect ratio and the space margin." }
, { "clearColoquinte" , (PyCFunction)PyEtesianEngine_clearColoquinte , METH_NOARGS
, "De-allocate the Coloquinte related data structures." }
, { "place" , (PyCFunction)PyEtesianEngine_place , METH_NOARGS , { "place" , (PyCFunction)PyEtesianEngine_place , METH_NOARGS
, "Run the placer (Etesian)." } , "Run the placer (Etesian)." }
, { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS , { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS

View File

@ -55,27 +55,30 @@ 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 double getAntennaInsertThreshold () const;
inline string getBloat () const; inline string getFeedNames () const;
inline DbU::Unit getLatchUpDistance () const; inline string getDiodeName () const;
inline void setSpaceMargin ( double ); inline string getBloat () const;
inline void setAspectRatio ( double ); inline DbU::Unit getLatchUpDistance () const;
void print ( Cell* ) const; inline DbU::Unit getAntennaMaxWL () const;
Record* _getRecord () const; inline void setSpaceMargin ( double );
string _getString () const; inline void setAspectRatio ( double );
string _getTypeName () const; void print ( Cell* ) const;
Record* _getRecord () const;
string _getString () const;
string _getTypeName () const;
protected: protected:
// Attributes. // Attributes.
RoutingGauge* _rg; RoutingGauge* _rg;
@ -86,28 +89,34 @@ namespace Etesian {
bool _routingDriven; bool _routingDriven;
double _spaceMargin; double _spaceMargin;
double _aspectRatio; double _aspectRatio;
double _antennaInsertThreshold;
string _feedNames; string _feedNames;
string _diodeName;
string _bloat; string _bloat;
DbU::Unit _latchUpDistance; DbU::Unit _latchUpDistance;
DbU::Unit _antennaMaxWL;
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 double Configuration::getAntennaInsertThreshold () const { return _antennaInsertThreshold; }
inline string Configuration::getBloat () const { return _bloat; } inline string Configuration::getFeedNames () const { return _feedNames; }
inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; } inline string Configuration::getDiodeName () const { return _diodeName; }
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; } inline string Configuration::getBloat () const { return _bloat; }
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; } inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; }
inline DbU::Unit Configuration::getAntennaMaxWL () const { return _antennaMaxWL; }
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
} // Etesian namespace. } // Etesian namespace.

View File

@ -15,6 +15,7 @@
#pragma once #pragma once
#include <tuple>
#include <iostream> #include <iostream>
#include <unordered_map> #include <unordered_map>
#include "coloquinte/circuit.hxx" #include "coloquinte/circuit.hxx"
@ -34,6 +35,7 @@ namespace Hurricane {
#include "etesian/Configuration.h" #include "etesian/Configuration.h"
#include "etesian/FeedCells.h" #include "etesian/FeedCells.h"
#include "etesian/BloatCells.h" #include "etesian/BloatCells.h"
#include "etesian/Placement.h"
namespace Etesian { namespace Etesian {
@ -52,56 +54,70 @@ namespace Etesian {
class EtesianEngine : public CRL::ToolEngine { class EtesianEngine : public CRL::ToolEngine {
public: public:
typedef ToolEngine Super; static const uint32_t NeedsDiode = (1<<0);
static const uint32_t FinalStage = (1<<1);
static const uint32_t RightSide = (1<<2);
static const uint32_t LeftSide = (1<<3);
public: public:
static const Name& staticGetName (); typedef ToolEngine Super;
static EtesianEngine* create ( Cell* ); typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
static EtesianEngine* get ( const Cell* ); typedef std::tuple<Instance*,int32_t,uint32_t> InstanceInfos;
public: public:
virtual Configuration* getConfiguration (); static const Name& staticGetName ();
virtual const Configuration* getConfiguration () const; static EtesianEngine* create ( Cell* );
virtual const Name& getName () const; static EtesianEngine* get ( const Cell* );
inline RoutingGauge* getGauge () const; public:
inline CellGauge* getCellGauge () const; virtual Configuration* getConfiguration ();
inline DbU::Unit getHorizontalPitch () const; virtual const Configuration* getConfiguration () const;
inline DbU::Unit getVerticalPitch () const; virtual const Name& getName () const;
inline DbU::Unit getSliceHeight () const; inline RoutingGauge* getGauge () const;
inline DbU::Unit getSliceStep () const; inline CellGauge* getCellGauge () const;
inline DbU::Unit getFixedAbHeight () const; inline DbU::Unit getHorizontalPitch () const;
inline DbU::Unit getFixedAbWidth () const; inline DbU::Unit getVerticalPitch () const;
inline Effort getPlaceEffort () const; inline DbU::Unit getSliceHeight () const;
inline GraphicUpdate getUpdateConf () const; inline DbU::Unit getSliceStep () const;
inline Density getSpreadingConf () const; inline DbU::Unit getFixedAbHeight () const;
inline double getSpaceMargin () const; inline DbU::Unit getFixedAbWidth () const;
inline double getAspectRatio () const; inline Effort getPlaceEffort () const;
inline const FeedCells& getFeedCells () const; inline GraphicUpdate getUpdateConf () const;
inline Hurricane::CellViewer* getViewer () const; inline Density getSpreadingConf () const;
inline void setViewer ( Hurricane::CellViewer* ); inline double getSpaceMargin () const;
inline Cell* getBlockCell () const; inline double getAspectRatio () const;
inline Instance* getBlockInstance () const; inline double getAntennaInsertThreshold () const;
inline void setBlock ( Instance* ); inline DbU::Unit getAntennaMaxWL () const;
inline void setFixedAbHeight ( DbU::Unit ); inline DbU::Unit getLatchUpDistance () const;
inline void setFixedAbWidth ( DbU::Unit ); inline const FeedCells& getFeedCells () const;
inline void setSpaceMargin ( double ); inline Cell* getDiodeCell () const;
inline void setAspectRatio ( double ); inline Hurricane::CellViewer* getViewer () const;
void setDefaultAb (); inline void setViewer ( Hurricane::CellViewer* );
void adjustSliceHeight (); inline Cell* getBlockCell () const;
void resetPlacement (); inline Instance* getBlockInstance () const;
void loadLeafCellLayouts (); inline void setBlock ( Instance* );
size_t toColoquinte (); inline void setFixedAbHeight ( DbU::Unit );
void preplace (); inline void setFixedAbWidth ( DbU::Unit );
void roughLegalize ( float minDisruption, unsigned options ); inline void setSpaceMargin ( double );
void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 ); inline void setAspectRatio ( double );
void detailedPlace ( int iterations, int effort, unsigned options=0 ); void setDefaultAb ();
void place (); void adjustSliceHeight ();
inline void useFeed ( Cell* ); void resetPlacement ();
size_t findYSpin (); void clearColoquinte ();
void addFeeds (); void loadLeafCellLayouts ();
void readSlices (); inline DbU::Unit toDbU ( int64_t ) const;
inline void selectBloat ( std::string ); size_t toColoquinte ();
virtual Record* _getRecord () const; void preplace ();
virtual std::string _getString () const; void roughLegalize ( float minDisruption, unsigned options );
virtual std::string _getTypeName () const; void globalPlace ( float initPenalty, float minDisruption, float targetImprovement, float minInc, float maxInc, unsigned options=0 );
void detailedPlace ( int iterations, int effort, unsigned options=0 );
void antennaProtect ();
void place ();
inline void useFeed ( Cell* );
size_t findYSpin ();
void addFeeds ();
void toHurricane ();
inline void selectBloat ( std::string );
virtual Record* _getRecord () const;
virtual std::string _getString () const;
virtual std::string _getTypeName () const;
private: private:
// Attributes. // Attributes.
static Name _toolName; static Name _toolName;
@ -111,20 +127,24 @@ namespace Etesian {
bool _placed; bool _placed;
bool _ySpinSet; bool _ySpinSet;
bool _flatDesign; bool _flatDesign;
coloquinte::box<coloquinte::int_t> _surface; coloquinte::box<coloquinte::int_t>* _surface;
coloquinte::netlist _circuit; coloquinte::netlist* _circuit;
coloquinte::placement_t _placementLB; coloquinte::placement_t* _placementLB;
coloquinte::placement_t _placementUB; coloquinte::placement_t* _placementUB;
coloquinte::density_restrictions _densityLimits; coloquinte::density_restrictions* _densityLimits;
std::unordered_map<string,unsigned int> _cellsToIds; std::unordered_map<string,unsigned int> _cellsToIds;
std::vector<Instance*> _idsToInsts; std::vector<InstanceInfos> _idsToInsts;
std::vector<NetInfos> _idsToNets;
Hurricane::CellViewer* _viewer; Hurricane::CellViewer* _viewer;
Cell* _diodeCell;
FeedCells _feedCells; FeedCells _feedCells;
BloatCells _bloatCells; BloatCells _bloatCells;
Area* _area;
size_t _yspinSlice0; size_t _yspinSlice0;
DbU::Unit _sliceHeight; DbU::Unit _sliceHeight;
DbU::Unit _fixedAbHeight; DbU::Unit _fixedAbHeight;
DbU::Unit _fixedAbWidth; DbU::Unit _fixedAbWidth;
uint32_t _diodeCount;
protected: protected:
// Constructors & Destructors. // Constructors & Destructors.
@ -136,39 +156,47 @@ namespace Etesian {
EtesianEngine ( const EtesianEngine& ); EtesianEngine ( const EtesianEngine& );
EtesianEngine& operator= ( const EtesianEngine& ); EtesianEngine& operator= ( const EtesianEngine& );
private: private:
void _updatePlacement ( const coloquinte::placement_t& ); inline uint32_t _getNewDiodeId ();
Instance* _createDiode ( Cell* );
void _updatePlacement ( const coloquinte::placement_t*, uint32_t flags=0 );
void _progressReport1 ( string label ) const; void _progressReport1 ( string label ) const;
void _progressReport2 ( string label ) const; void _progressReport2 ( string label ) const;
}; };
// Inline Functions. // Inline Functions.
inline void EtesianEngine::setViewer ( Hurricane::CellViewer* viewer ) { _viewer = viewer; } inline void EtesianEngine::setViewer ( Hurricane::CellViewer* viewer ) { _viewer = viewer; }
inline Hurricane::CellViewer* EtesianEngine::getViewer () const { return _viewer; } inline Hurricane::CellViewer* EtesianEngine::getViewer () const { return _viewer; }
inline RoutingGauge* EtesianEngine::getGauge () const { return getConfiguration()->getGauge(); } inline RoutingGauge* EtesianEngine::getGauge () const { return getConfiguration()->getGauge(); }
inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); } inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); }
inline DbU::Unit EtesianEngine::getHorizontalPitch () const { return getGauge()->getHorizontalPitch(); } inline DbU::Unit EtesianEngine::getHorizontalPitch () const { return getGauge()->getHorizontalPitch(); }
inline DbU::Unit EtesianEngine::getVerticalPitch () const { return getGauge()->getVerticalPitch(); } inline DbU::Unit EtesianEngine::getVerticalPitch () const { return getGauge()->getVerticalPitch(); }
inline DbU::Unit EtesianEngine::getSliceHeight () const { return _sliceHeight; } inline DbU::Unit EtesianEngine::getSliceHeight () const { return _sliceHeight; }
inline DbU::Unit EtesianEngine::getSliceStep () const { return getCellGauge()->getSliceStep(); } inline DbU::Unit EtesianEngine::getSliceStep () const { return getCellGauge()->getSliceStep(); }
inline DbU::Unit EtesianEngine::getFixedAbHeight () const { return _fixedAbHeight; } inline DbU::Unit EtesianEngine::getFixedAbHeight () const { return _fixedAbHeight; }
inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; } inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; }
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); } inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); } inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); } inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); } inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); } inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); } inline double EtesianEngine::getAntennaInsertThreshold () const { return getConfiguration()->getAntennaInsertThreshold(); }
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; } inline DbU::Unit EtesianEngine::getAntennaMaxWL () const { return getConfiguration()->getAntennaMaxWL(); }
inline void EtesianEngine::selectBloat ( std::string profile ) { _bloatCells.select(profile); } inline DbU::Unit EtesianEngine::getLatchUpDistance () const { return getConfiguration()->getLatchUpDistance(); }
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
inline Cell* EtesianEngine::getBlockCell () const { return (_block) ? _block->getMasterCell() : getCell(); } inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
inline Instance* EtesianEngine::getBlockInstance () const { return _block; } inline Cell* EtesianEngine::getDiodeCell () const { return _diodeCell; }
inline void EtesianEngine::setBlock ( Instance* block ) { _block = block; _placed = _block->getMasterCell()->isPlaced(); } inline void EtesianEngine::selectBloat ( std::string profile ) { _bloatCells.select(profile); }
inline void EtesianEngine::setFixedAbHeight ( DbU::Unit abHeight ) { _fixedAbHeight = abHeight; }
inline void EtesianEngine::setFixedAbWidth ( DbU::Unit abWidth ) { _fixedAbWidth = abWidth; } inline Cell* EtesianEngine::getBlockCell () const { return (_block) ? _block->getMasterCell() : getCell(); }
inline void EtesianEngine::setSpaceMargin ( double margin ) { getConfiguration()->setSpaceMargin(margin); } inline Instance* EtesianEngine::getBlockInstance () const { return _block; }
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); } inline void EtesianEngine::setBlock ( Instance* block ) { _block = block; _placed = _block->getMasterCell()->isPlaced(); }
inline void EtesianEngine::setFixedAbHeight ( DbU::Unit abHeight ) { _fixedAbHeight = abHeight; }
inline void EtesianEngine::setFixedAbWidth ( DbU::Unit abWidth ) { _fixedAbWidth = abWidth; }
inline void EtesianEngine::setSpaceMargin ( double margin ) { getConfiguration()->setSpaceMargin(margin); }
inline void EtesianEngine::setAspectRatio ( double ratio ) { getConfiguration()->setAspectRatio(ratio); }
inline DbU::Unit EtesianEngine::toDbU ( int64_t v ) const { return v*getSliceStep(); }
inline uint32_t EtesianEngine::_getNewDiodeId () { return _diodeCount++; }
// Variables. // Variables.
extern const char* missingEtesian; extern const char* missingEtesian;

View File

@ -0,0 +1,322 @@
// -*- 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++ Header : "./Placement.h" |
// +-----------------------------------------------------------------+
#pragma once
#include <map>
#include <list>
#include "hurricane/Box.h"
#include "hurricane/Interval.h"
#include "hurricane/Instance.h"
#include "hurricane/Occurrence.h"
namespace Etesian {
using Hurricane::Error;
using Hurricane::Record;
using Hurricane::DbU;
using Hurricane::Box;
using Hurricane::Interval;
using Hurricane::DBo;
using Hurricane::Cell;
using Hurricane::Instance;
using Hurricane::Transformation;
using Hurricane::Occurrence;
class EtesianEngine;
// -------------------------------------------------------------------
// Class : "::TieDatas".
class TieDatas {
public:
inline TieDatas ( Cell* cell=NULL, DbU::Unit leftDistance=0, DbU::Unit rightDistance=0 );
inline Cell* getCell () const;
inline DbU::Unit getLeftDistance () const;
inline DbU::Unit getRightDistance() const;
private:
Cell* _cell;
DbU::Unit _leftDistance;
DbU::Unit _rightDistance;
};
inline TieDatas::TieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
: _cell (cell)
, _leftDistance (leftDistance)
, _rightDistance(rightDistance)
{ }
inline Cell* TieDatas::getCell () const { return _cell; }
inline DbU::Unit TieDatas::getLeftDistance () const { return _leftDistance; }
inline DbU::Unit TieDatas::getRightDistance() const { return _rightDistance; }
// -------------------------------------------------------------------
// Class : "::TieLUT".
class TieLUT {
public:
inline TieLUT ();
inline const TieDatas* getTieDatas ( Cell* ) const;
inline DbU::Unit getLeftDistance ( Cell* ) const;
inline DbU::Unit getRightDistance ( Cell* ) const;
inline void addTieDatas ( Cell*, DbU::Unit leftDistance, DbU::Unit rightDistance );
private:
std::map< Cell*, TieDatas, DBo::CompareById > _tieLut;
};
inline TieLUT::TieLUT ()
: _tieLut()
{ }
inline void TieLUT::addTieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
{
const TieDatas* datas = getTieDatas( cell );
if (datas) {
std::cerr << Error( "TieLUT::addTieDatas(): Duplicate datas for % (ignoreds)."
, getString(cell).c_str()
) << std::endl;
}
_tieLut[ cell ] = TieDatas( cell, leftDistance, rightDistance );
}
inline const TieDatas* TieLUT::getTieDatas ( Cell* cell ) const
{
auto iDatas = _tieLut.find( cell );
return (iDatas != _tieLut.end()) ? &((*iDatas).second) : NULL;
}
inline DbU::Unit TieLUT::getLeftDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getLeftDistance() : 0;
}
inline DbU::Unit TieLUT::getRightDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getRightDistance() : 0;
}
// -------------------------------------------------------------------
// 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 Cell* getMasterCell () const;
inline Instance* getInstance () const;
inline const Occurrence& getOccurrence () const;
inline void translate ( DbU::Unit );
inline std::string _getString () const;
Record* _getRecord () const;
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 Instance* Tile::getInstance () const { return static_cast<Instance*>( _occurrence.getEntity() ); }
inline Cell* Tile::getMasterCell () const { return getInstance()->getMasterCell(); }
inline bool Tile::isFixed () const
{ return getInstance()->getPlacementStatus() == Instance::PlacementStatus::FIXED; }
inline void Tile::translate ( DbU::Unit dx )
{
cdebug_log(121,0) << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << std::endl;
Instance* instance = getInstance();
Transformation reference = instance->getTransformation();
Transformation transf = Transformation( reference.getTx() + dx
, reference.getTy()
, reference.getOrientation() );
instance->setTransformation( transf );
_xMin += dx;
}
inline std::string Tile::_getString () const
{
string s = "<Tile @" + DbU::getValueString(_xMin)
+ " w=" + DbU::getValueString(_width)
+ " \"" + getString(getInstance()->getName())
+ "\">";
return s;
}
// -------------------------------------------------------------------
// Class : "::SubSlice".
class SubSlice {
public:
SubSlice ( Slice*, const std::list<Tile>::iterator& beginTile );
inline const std::list<Tile>::iterator getBeginTile () const;
inline const std::list<Tile>::iterator getEndTile () const;
inline DbU::Unit getYBottom () 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;
std::list<Tile>::iterator _beginTile;
std::list<Tile>::iterator _endTile;
};
inline const std::list<Tile>::iterator SubSlice::getBeginTile () const { return _beginTile; }
inline const std::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;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
inline std::list<Tile>& getTiles ();
void merge ( const Occurrence&, const Box& );
void addFeeds ( size_t islice );
void fillHole ( std::list<Tile>::iterator before
, DbU::Unit xmin
, DbU::Unit xmax
, DbU::Unit ybottom
, size_t yspin );
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
inline std::string _getString () const;
Record* _getRecord () const;
private:
Area* _area;
DbU::Unit _ybottom;
std::list<Tile> _tiles;
std::vector<SubSlice> _subSlices;
};
inline std::string Slice::_getString () const
{
string s = "<Slice @" + DbU::getValueString(_ybottom) + ">";
return s;
}
// -------------------------------------------------------------------
// 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;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
void merge ( const Occurrence&, const Box& );
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
inline std::string _getString () const;
Record* _getRecord () const;
private:
EtesianEngine* _etesian;
TieLUT _tieLut;
Box _cellAb;
DbU::Unit _sliceHeight;
std::vector<Slice*> _slices;
size_t _spinSlice0;
};
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(); }
inline DbU::Unit Area::getLeftDistance ( Cell* cell ) const { return _tieLut.getLeftDistance(cell); }
inline DbU::Unit Area::getRightDistance ( Cell* cell ) const { return _tieLut.getRightDistance(cell); }
inline string Area::_getString () const { return "<Etesian::Area>"; }
inline DbU::Unit SubSlice::getYBottom () const { return _slice->getYBottom(); }
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(); }
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 DbU::Unit Slice::getLeftDistance ( Cell* cell ) const { return _area->getLeftDistance(cell); }
inline DbU::Unit Slice::getRightDistance ( Cell* cell ) const { return _area->getRightDistance(cell); }
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 std::list<Tile>& Slice::getTiles () { return _tiles; }
} // Etesian namespace.
INSPECTOR_PR_SUPPORT(Etesian::Tile);
INSPECTOR_P_SUPPORT(Etesian::Slice);
INSPECTOR_P_SUPPORT(Etesian::Area);