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:
parent
78cbb662e6
commit
087ef239c2
|
@ -527,32 +527,37 @@ class Block ( object ):
|
|||
def place ( self ):
|
||||
editor = self.conf.editor
|
||||
if self.conf.isCoreBlock:
|
||||
etesian = Etesian.EtesianEngine.create( self.conf.corona )
|
||||
etesian.setBlock( self.conf.icore )
|
||||
self.etesian = Etesian.EtesianEngine.create( self.conf.corona )
|
||||
self.etesian.setBlock( self.conf.icore )
|
||||
if editor:
|
||||
editor.setCell( self.conf.cell )
|
||||
Breakpoint.stop( 100, 'Block.place(), corona loaded.')
|
||||
else:
|
||||
etesian = Etesian.EtesianEngine.create( self.conf.cell )
|
||||
etesian.place()
|
||||
etesian.destroy()
|
||||
self.etesian = Etesian.EtesianEngine.create( self.conf.cell )
|
||||
self.etesian.place()
|
||||
Breakpoint.stop( 100, 'Placement done.' )
|
||||
self.etesian.clearColoquinte()
|
||||
|
||||
def route ( self ):
|
||||
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
|
||||
katana = Katana.KatanaEngine.create( routedCell )
|
||||
#katana.printConfiguration ()
|
||||
katana.digitalInit ()
|
||||
self.katana = Katana.KatanaEngine.create( routedCell )
|
||||
#self.katana.printConfiguration()
|
||||
self.katana.digitalInit ()
|
||||
#katana.runNegociatePreRouted()
|
||||
Breakpoint.stop( 100, 'Block.route() Before global routing.' )
|
||||
katana.runGlobalRouter ( Katana.Flags.NoFlags )
|
||||
katana.loadGlobalRouting ( Anabatic.EngineLoadGrByNet )
|
||||
self.katana.runGlobalRouter ( Katana.Flags.NoFlags )
|
||||
self.katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
|
||||
Breakpoint.stop( 100, 'Block.route() After global routing.' )
|
||||
katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
|
||||
katana.runNegociate ( Katana.Flags.NoFlags )
|
||||
success = katana.isDetailedRoutingSuccess()
|
||||
self.katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
|
||||
self.katana.runNegociate ( Katana.Flags.NoFlags )
|
||||
success = self.katana.isDetailedRoutingSuccess()
|
||||
Breakpoint.stop( 100, 'Block.route() done, success:{}.'.format(success) )
|
||||
katana.finalizeLayout()
|
||||
katana.destroy()
|
||||
self.katana.finalizeLayout()
|
||||
self.katana.destroy()
|
||||
self.katana = None
|
||||
if self.etesian:
|
||||
self.etesian.destroy()
|
||||
self.etesian = None
|
||||
return success
|
||||
|
||||
def addBlockages ( self ):
|
||||
|
|
|
@ -133,6 +133,8 @@ class GaugeConf ( object ):
|
|||
@property
|
||||
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 setRoutingBb ( self, bb ):
|
||||
|
@ -1100,6 +1102,8 @@ class BlockConf ( GaugeConf ):
|
|||
self.cfg.etesian.spaceMargin = None
|
||||
self.cfg.etesian.latchUpDistance = None
|
||||
self.cfg.block.spareSide = None
|
||||
self.etesian = None
|
||||
self.katana = None
|
||||
|
||||
@property
|
||||
def isCoreBlock ( self ): return self.chip is not None
|
||||
|
|
|
@ -536,7 +536,7 @@ class Builder ( object ):
|
|||
|
||||
def __init__ ( self, block ):
|
||||
self.block = block
|
||||
self.innerBb = self.block.bb
|
||||
self.innerBb = self.block.icoreAb
|
||||
self.block.path.getTransformation().applyOn( self.innerBb )
|
||||
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
|
||||
self.southSide = SouthSide( self )
|
||||
|
|
|
@ -36,8 +36,8 @@ plugins.chip.importConstants( globals() )
|
|||
|
||||
class Side ( object ):
|
||||
|
||||
def __init__ ( self, block, side, net, metal ):
|
||||
self.block = block
|
||||
def __init__ ( self, builder, side, net, metal ):
|
||||
self.builder = builder
|
||||
self.side = side
|
||||
self.net = net
|
||||
self.metal = metal
|
||||
|
@ -74,16 +74,16 @@ class Side ( object ):
|
|||
def doLayout ( self ):
|
||||
if self.side == West:
|
||||
width = 0
|
||||
x = self.block.bb.getXMin()
|
||||
x = self.builder.icoreAb.getXMin()
|
||||
elif self.side == East:
|
||||
width = 0
|
||||
x = self.block.bb.getXMax()
|
||||
x = self.builder.icoreAb.getXMax()
|
||||
elif self.side == South:
|
||||
height = 0
|
||||
y = self.block.bb.getYMin()
|
||||
y = self.builder.icoreAb.getYMin()
|
||||
elif self.side == North:
|
||||
height = 0
|
||||
y = self.block.bb.getYMax()
|
||||
y = self.builder.icoreAb.getYMax()
|
||||
minWidth = DbU.fromLambda( 6.0 )
|
||||
for terminal in self.terminals:
|
||||
if self.side == West or self.side == East:
|
||||
|
@ -94,7 +94,7 @@ class Side ( object ):
|
|||
center = Point( terminal[0].getCenter(), y )
|
||||
width = terminal[0].getSize() - self.deltaWidth
|
||||
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 )
|
||||
terminal[ 1 ] = contact
|
||||
|
||||
|
@ -107,28 +107,33 @@ class Plane ( object ):
|
|||
Horizontal = 0001
|
||||
Vertical = 0002
|
||||
|
||||
def __init__ ( self, block, metal ):
|
||||
self.block = block
|
||||
self.metal = metal
|
||||
self.sides = {}
|
||||
def __init__ ( self, builder, metal ):
|
||||
self.builder = builder
|
||||
self.metal = metal
|
||||
self.sides = {}
|
||||
|
||||
def addTerminal ( self, net, direction, bb ):
|
||||
if not self.sides.has_key(net):
|
||||
self.sides[ net ] = { North : Side(self.block,North,net,self.metal)
|
||||
, South : Side(self.block,South,net,self.metal)
|
||||
, East : Side(self.block,East ,net,self.metal)
|
||||
, West : Side(self.block,West ,net,self.metal)
|
||||
self.sides[ net ] = { North : Side(self.builder,North,net,self.metal)
|
||||
, South : Side(self.builder,South,net,self.metal)
|
||||
, East : Side(self.builder,East ,net,self.metal)
|
||||
, West : Side(self.builder,West ,net,self.metal)
|
||||
}
|
||||
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 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() )
|
||||
if bb.getXMax() >= self.block.bb.getXMax():
|
||||
if bb.getXMax() >= self.builder.icoreAb.getXMax():
|
||||
sides[East].addTerminal( bb.getCenter().getY(), bb.getHeight() )
|
||||
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() )
|
||||
if bb.getYMax() >= self.block.bb.getYMax():
|
||||
if bb.getYMax() >= self.builder.icoreAb.getYMax():
|
||||
sides[North].addTerminal( bb.getCenter().getX(), bb.getWidth() )
|
||||
|
||||
def doLayout ( self ):
|
||||
|
@ -142,25 +147,28 @@ class Plane ( object ):
|
|||
|
||||
class GoCb ( object ):
|
||||
|
||||
def __init__ ( self, block ):
|
||||
self.block = block
|
||||
def __init__ ( self, builder ):
|
||||
self.builder = builder
|
||||
|
||||
def __call__ ( self, query, go ):
|
||||
direction = None
|
||||
if isinstance(go,Horizontal): direction = Plane.Horizontal
|
||||
if isinstance(go,Vertical): direction = Plane.Vertical
|
||||
if not direction: return
|
||||
trace( 550, '\t| go={}\n'.format( go ))
|
||||
rootNet = None
|
||||
if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.block.conf.coronaVdd
|
||||
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.block.conf.coronaVss
|
||||
if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.builder.conf.coronaVdd
|
||||
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.builder.conf.coronaVss
|
||||
if not rootNet: return
|
||||
if self.block.activePlane:
|
||||
layer = self.block.activePlane.metal
|
||||
if self.builder.activePlane:
|
||||
layer = self.builder.activePlane.metal
|
||||
if layer.isSymbolic():
|
||||
layer = layer.getBasicLayer()
|
||||
if self.builder.conf.getLayerDepth(layer) == 0:
|
||||
direction = Plane.Horizontal
|
||||
bb = go.getBoundingBox( layer )
|
||||
query.getPath().getTransformation().applyOn( bb )
|
||||
self.block.activePlane.addTerminal( rootNet, direction, bb )
|
||||
self.builder.activePlane.addTerminal( rootNet, direction, bb )
|
||||
else:
|
||||
print WarningMessage( 'BlockPower.GoCb() callback called without an active plane.' )
|
||||
return
|
||||
|
@ -173,9 +181,9 @@ class Builder ( object ):
|
|||
|
||||
def __init__ ( self, conf ):
|
||||
self.conf = conf
|
||||
self.path = Path( self.conf.icore )
|
||||
self.block = self.conf.icore.getMasterCell()
|
||||
self.bb = self.block.getAbutmentBox()
|
||||
self.path = Path()
|
||||
self.corona = self.conf.icorona.getMasterCell()
|
||||
self.icoreAb = self.conf.icore.getAbutmentBox()
|
||||
self.planes = {}
|
||||
self.activePlane = None
|
||||
for layerGauge in self.conf.routingGauge.getLayerGauges():
|
||||
|
@ -188,8 +196,8 @@ class Builder ( object ):
|
|||
goCb = GoCb( self )
|
||||
query = Query()
|
||||
query.setGoCallback( goCb )
|
||||
query.setCell( self.block )
|
||||
query.setArea( self.block.getAbutmentBox() )
|
||||
query.setCell( self.corona )
|
||||
query.setArea( self.icoreAb )
|
||||
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
||||
for layerGauge in self.conf.routingGauge.getLayerGauges():
|
||||
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
|
||||
|
@ -226,13 +234,11 @@ class Builder ( object ):
|
|||
with UpdateSession():
|
||||
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 )
|
||||
self.conf.expandMinArea( bufferRp )
|
||||
blockAb = self.block.getAbutmentBox()
|
||||
self.path.getTransformation().applyOn( blockAb )
|
||||
layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth)
|
||||
contact = Contact.create( ck
|
||||
, self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth)
|
||||
, bufferRp.getX()
|
||||
, blockAb.getYMax()
|
||||
, self.icoreAb.getYMax()
|
||||
, layerGauge.getViaWidth()
|
||||
, layerGauge.getViaWidth()
|
||||
)
|
||||
|
@ -242,7 +248,6 @@ class Builder ( object ):
|
|||
if layer.isSymbolic():
|
||||
layer = layer.getBasicLayer()
|
||||
bb = segment.getBoundingBox( layer )
|
||||
self.path.getTransformation().getInvert().applyOn( bb )
|
||||
self.activePlane.addTerminal( ck, Plane.Vertical, bb )
|
||||
trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) )
|
||||
|
||||
|
|
|
@ -15,24 +15,13 @@
|
|||
|
||||
|
||||
import sys
|
||||
from Hurricane import DbU
|
||||
from Hurricane import Point
|
||||
from Hurricane import Transformation
|
||||
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
|
||||
from Hurricane import DbU, Point, Transformation, Box, Interval, \
|
||||
Path, Occurrence, UpdateSession, Net, \
|
||||
Contact, Horizontal, Vertical, Query
|
||||
import CRL
|
||||
import helpers
|
||||
from helpers import trace
|
||||
from helpers.io import ErrorMessage
|
||||
from helpers.io import WarningMessage
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
import plugins
|
||||
import plugins.chip
|
||||
|
||||
|
@ -134,6 +123,8 @@ class Plane ( object ):
|
|||
, West : Side(self.block,West ,net,self.metal)
|
||||
}
|
||||
sides = self.sides[ net ]
|
||||
trace( 550, '\tPlane.addTerminal() net={} bb={} direction={}\n' \
|
||||
.format( net.getName(), bb, direction ))
|
||||
|
||||
if direction == Plane.Horizontal:
|
||||
if bb.getXMin() <= self.block.bb.getXMin():
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
${PYTHON_INCLUDE_PATH}
|
||||
)
|
||||
set( includes etesian/Configuration.h
|
||||
etesian/Placement.h
|
||||
etesian/FeedCells.h
|
||||
etesian/BloatCells.h
|
||||
etesian/BloatProperty.h
|
||||
|
|
|
@ -61,9 +61,13 @@ namespace Etesian {
|
|||
, _routingDriven ( Cfg::getParamBool ("etesian.routingDriven" , false )->asBool())
|
||||
, _spaceMargin ( Cfg::getParamPercentage("etesian.spaceMargin" , 5.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() )
|
||||
, _diodeName ( Cfg::getParamString ("etesian.diodeName" ,"dio_x0" )->asString() )
|
||||
, _bloat ( Cfg::getParamString ("etesian.bloat" ,"disabled" )->asString() )
|
||||
, _latchUpDistance( Cfg::getParamInt ("etesian.latchUpDistance",0 )->asInt() )
|
||||
, _antennaMaxWL ( Cfg::getParamInt ("etesian.antennaMaxWL" ,0 )->asInt() )
|
||||
{
|
||||
string gaugeName = Cfg::getParamString("anabatic.routingGauge","sxlib")->asString();
|
||||
if (cg == NULL) {
|
||||
|
@ -85,15 +89,19 @@ namespace Etesian {
|
|||
|
||||
|
||||
Configuration::Configuration ( const Configuration& other )
|
||||
: _rg (NULL)
|
||||
, _cg (NULL)
|
||||
, _placeEffort ( other._placeEffort )
|
||||
, _updateConf ( other._updateConf )
|
||||
, _spreadingConf( other._spreadingConf )
|
||||
, _spaceMargin ( other._spaceMargin )
|
||||
, _aspectRatio ( other._aspectRatio )
|
||||
, _feedNames ( other._feedNames )
|
||||
, _bloat ( other._bloat )
|
||||
: _rg (NULL)
|
||||
, _cg (NULL)
|
||||
, _placeEffort ( other._placeEffort )
|
||||
, _updateConf ( other._updateConf )
|
||||
, _spreadingConf ( other._spreadingConf )
|
||||
, _spaceMargin ( other._spaceMargin )
|
||||
, _aspectRatio ( other._aspectRatio )
|
||||
, _antennaInsertThreshold( other._antennaInsertThreshold )
|
||||
, _feedNames ( other._feedNames )
|
||||
, _diodeName ( other._diodeName )
|
||||
, _bloat ( other._bloat )
|
||||
, _latchUpDistance( other._latchUpDistance )
|
||||
, _antennaMaxWL ( other._antennaMaxWL )
|
||||
{
|
||||
if (other._rg) _rg = other._rg->getClone();
|
||||
if (other._cg) _cg = other._cg->getClone();
|
||||
|
@ -113,14 +121,17 @@ namespace Etesian {
|
|||
void Configuration::print ( Cell* cell ) const
|
||||
{
|
||||
cmess1 << " o Configuration of ToolEngine<Etesian> for Cell <" << cell->getName() << ">" << endl;
|
||||
cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
|
||||
cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
|
||||
cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
|
||||
cmess1 << Dots::asInt (" - Spreading Conf",_spreadingConf) << endl;
|
||||
cmess1 << Dots::asBool (" - Routing driven",_routingDriven) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << endl;
|
||||
cmess1 << Dots::asString (" - Bloat model" ,_bloat ) << endl;
|
||||
cmess1 << Dots::asIdentifier(" - Cell Gauge" ,getString(_cg->getName())) << endl;
|
||||
cmess1 << Dots::asInt (" - Place Effort" ,_placeEffort ) << endl;
|
||||
cmess1 << Dots::asInt (" - Update Conf" ,_updateConf ) << endl;
|
||||
cmess1 << Dots::asInt (" - Spreading Conf" ,_spreadingConf ) << endl;
|
||||
cmess1 << Dots::asBool (" - Routing driven" ,_routingDriven ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Space Margin" ,_spaceMargin ) << endl;
|
||||
cmess1 << Dots::asPercentage(" - Aspect Ratio" ,_aspectRatio ) << 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* record = new Record ( _getString() );
|
||||
record->add ( getSlot( "_rg" , _rg ) );
|
||||
record->add ( getSlot( "_cg" , _cg ) );
|
||||
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
|
||||
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
|
||||
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
|
||||
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
|
||||
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
|
||||
record->add ( getSlot( "_feedNames" , _feedNames ) );
|
||||
record->add ( getSlot( "_bloat" , _bloat ) );
|
||||
record->add ( getSlot( "_rg" , _rg ) );
|
||||
record->add ( getSlot( "_cg" , _cg ) );
|
||||
record->add ( getSlot( "_placeEffort" , (int)_placeEffort ) );
|
||||
record->add ( getSlot( "_updateConf" , (int)_updateConf ) );
|
||||
record->add ( getSlot( "_spreadingConf" , (int)_spreadingConf ) );
|
||||
record->add ( getSlot( "_spaceMargin" , _spaceMargin ) );
|
||||
record->add ( getSlot( "_aspectRatio" , _aspectRatio ) );
|
||||
record->add ( getSlot( "_antennaInsertThreshold", _antennaInsertThreshold ) );
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
#include <fstream>
|
||||
#include <iomanip>
|
||||
#include "coloquinte/circuit.hxx"
|
||||
#include "coloquinte/circuit_helper.hxx"
|
||||
#include "coloquinte/legalizer.hxx"
|
||||
#include "vlsisapd/configuration/Configuration.h"
|
||||
#include "vlsisapd/utilities/Dots.h"
|
||||
|
@ -39,6 +40,7 @@
|
|||
#include "hurricane/Vertical.h"
|
||||
#include "hurricane/Horizontal.h"
|
||||
#include "hurricane/RoutingPad.h"
|
||||
#include "hurricane/NetExternalComponents.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
#include "hurricane/viewer/CellWidget.h"
|
||||
#include "hurricane/viewer/CellViewer.h"
|
||||
|
@ -55,6 +57,7 @@ namespace {
|
|||
using coloquinte::int_t;
|
||||
using coloquinte::float_t;
|
||||
using coloquinte::point;
|
||||
using Etesian::EtesianEngine;
|
||||
|
||||
// Options for both placers
|
||||
unsigned const SteinerModel = 0x0001;
|
||||
|
@ -174,6 +177,42 @@ namespace {
|
|||
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.
|
||||
|
||||
|
||||
|
@ -256,19 +295,24 @@ namespace Etesian {
|
|||
, _block (NULL)
|
||||
, _ySpinSet (false)
|
||||
, _flatDesign (false)
|
||||
, _surface ()
|
||||
, _circuit ()
|
||||
, _placementLB ()
|
||||
, _placementUB ()
|
||||
, _surface (NULL)
|
||||
, _circuit (NULL)
|
||||
, _placementLB (NULL)
|
||||
, _placementUB (NULL)
|
||||
, _densityLimits(NULL)
|
||||
, _cellsToIds ()
|
||||
, _idsToInsts ()
|
||||
, _idsToNets ()
|
||||
, _viewer (NULL)
|
||||
, _diodeCell (NULL)
|
||||
, _feedCells (this)
|
||||
, _bloatCells (this)
|
||||
, _area (NULL)
|
||||
, _yspinSlice0 (0)
|
||||
, _sliceHeight (0)
|
||||
, _fixedAbHeight(0)
|
||||
, _fixedAbWidth (0)
|
||||
, _diodeCount (0)
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -283,6 +327,13 @@ namespace Etesian {
|
|||
cmess2 << " o ISPD benchmark <" << getCell()->getName()
|
||||
<< ">, no feed cells will be added." << endl;
|
||||
} 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() );
|
||||
|
||||
string feedNames = getConfiguration()->getFeedNames();
|
||||
|
@ -330,23 +381,53 @@ namespace Etesian {
|
|||
|
||||
void EtesianEngine::_preDestroy ()
|
||||
{
|
||||
cdebug_log(129,1) << "EtesianEngine::_preDestroy()" << endl;
|
||||
cdebug_log(120,1) << "EtesianEngine::_preDestroy()" << endl;
|
||||
|
||||
cmess1 << " o Deleting ToolEngine<" << getName() << "> from Cell <"
|
||||
<< getCell()->getName() << ">" << endl;
|
||||
|
||||
Super::_preDestroy();
|
||||
|
||||
cdebug.log(129,-1);
|
||||
cdebug.log(120,-1);
|
||||
}
|
||||
|
||||
|
||||
EtesianEngine::~EtesianEngine ()
|
||||
{
|
||||
clearColoquinte();
|
||||
delete _area;
|
||||
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
|
||||
{ return _toolName; }
|
||||
|
||||
|
@ -645,7 +726,7 @@ namespace Etesian {
|
|||
instances[instanceId].attributes = 0;
|
||||
|
||||
_cellsToIds.insert( make_pair(getString(instance->getName()),instanceId) );
|
||||
_idsToInsts.push_back( instance );
|
||||
_idsToInsts.push_back( make_tuple(instance,0,0) );
|
||||
// cerr << "FIXED id=" << instanceId
|
||||
// << " " << instance << " size:(" << xsize << " " << ysize
|
||||
// << ") pos:(" << xpos << " " << ypos << ")" << endl;
|
||||
|
@ -719,7 +800,7 @@ namespace Etesian {
|
|||
}
|
||||
|
||||
_cellsToIds.insert( make_pair(instanceName,instanceId) );
|
||||
_idsToInsts.push_back( instance );
|
||||
_idsToInsts.push_back( make_tuple(instance,0,0) );
|
||||
++instanceId;
|
||||
dots.dot();
|
||||
}
|
||||
|
@ -767,6 +848,7 @@ namespace Etesian {
|
|||
|
||||
vector<temporary_net> nets ( netsNb );
|
||||
vector<temporary_pin> pins;
|
||||
_idsToNets.resize( netsNb );
|
||||
|
||||
unsigned int netId = 0;
|
||||
for ( Net* net : getCell()->getNets() )
|
||||
|
@ -781,6 +863,7 @@ namespace Etesian {
|
|||
dots.dot();
|
||||
|
||||
nets[netId] = temporary_net( netId, 1 );
|
||||
_idsToNets[netId] = make_tuple( net, _cellsToIds.size(), 0 );
|
||||
|
||||
//cerr << "+ " << net << endl;
|
||||
|
||||
|
@ -822,6 +905,14 @@ namespace Etesian {
|
|||
}
|
||||
} else {
|
||||
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;
|
||||
|
@ -831,16 +922,18 @@ namespace Etesian {
|
|||
}
|
||||
dots.finish( Dots::Reset );
|
||||
|
||||
_surface = box<int_t>( (int_t)(topAb.getXMin() / vpitch)
|
||||
, (int_t)(topAb.getXMax() / vpitch)
|
||||
, (int_t)(topAb.getYMin() / hpitch)
|
||||
, (int_t)(topAb.getYMax() / hpitch)
|
||||
);
|
||||
_circuit = netlist( instances, nets, pins );
|
||||
_circuit.selfcheck();
|
||||
_placementLB.positions_ = positions;
|
||||
_placementLB.orientations_ = orientations;
|
||||
_placementUB = _placementLB;
|
||||
_densityLimits = new coloquinte::density_restrictions ();
|
||||
_surface = new box<int_t>( (int_t)(topAb.getXMin() / vpitch)
|
||||
, (int_t)(topAb.getXMax() / vpitch)
|
||||
, (int_t)(topAb.getYMin() / hpitch)
|
||||
, (int_t)(topAb.getYMax() / hpitch)
|
||||
);
|
||||
_circuit = new netlist( instances, nets, pins );
|
||||
_circuit->selfcheck();
|
||||
_placementLB = new coloquinte::placement_t ();
|
||||
_placementLB->positions_ = positions;
|
||||
_placementLB->orientations_ = orientations;
|
||||
_placementUB = new coloquinte::placement_t ( *_placementLB );
|
||||
|
||||
return instancesNb-fixedNb;
|
||||
}
|
||||
|
@ -890,18 +983,18 @@ namespace Etesian {
|
|||
|
||||
// Perform a very quick legalization pass
|
||||
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();
|
||||
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
|
||||
// Spreads well to help subsequent optimization passes
|
||||
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
|
||||
+ get_pulling_forces( _circuit, _placementUB, 1000000.0);
|
||||
solve_linear_system( _circuit, _placementLB, solv, 200 );
|
||||
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);
|
||||
solve_linear_system( *_circuit, *_placementLB, solv, 200 );
|
||||
_progressReport2(" [---]" );
|
||||
}
|
||||
|
||||
|
@ -911,8 +1004,8 @@ namespace Etesian {
|
|||
using namespace coloquinte::gp;
|
||||
// Create a legalizer and bipartition it until we have sufficient precision
|
||||
auto legalizer = (options & ForceUniformDensity) != 0 ?
|
||||
region_distribution::uniform_density_distribution (_surface, _circuit, _placementLB, _densityLimits)
|
||||
: region_distribution::full_density_distribution (_surface, _circuit, _placementLB, _densityLimits);
|
||||
region_distribution::uniform_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)
|
||||
legalizer.x_bipartition();
|
||||
while(2*legalizer.region_dimensions().x < legalizer.region_dimensions().y)
|
||||
|
@ -927,9 +1020,9 @@ namespace Etesian {
|
|||
legalizer.selfcheck();
|
||||
}
|
||||
// Keep the orientation between LB and UB
|
||||
_placementUB = _placementLB;
|
||||
*_placementUB = *_placementLB;
|
||||
// Update UB
|
||||
get_rough_legalization( _circuit, _placementUB, legalizer );
|
||||
get_rough_legalization( *_circuit, *_placementUB, legalizer );
|
||||
}
|
||||
|
||||
|
||||
|
@ -942,11 +1035,12 @@ namespace Etesian {
|
|||
{
|
||||
using namespace coloquinte::gp;
|
||||
|
||||
bool antennaDone = false;
|
||||
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 upperWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementUB)),
|
||||
lowerWL = static_cast<float_t>(get_HPWL_wirelength(_circuit, _placementLB));
|
||||
float_t upperWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementUB)),
|
||||
lowerWL = static_cast<float_t>(get_HPWL_wirelength(*_circuit, *_placementLB));
|
||||
float_t prevOptRatio = lowerWL / upperWL;
|
||||
|
||||
index_t i=0;
|
||||
|
@ -957,32 +1051,37 @@ namespace Etesian {
|
|||
|
||||
ostringstream label;
|
||||
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() );
|
||||
|
||||
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;
|
||||
|
||||
// Get the system to optimize (tolerance, maximum and minimum pin counts)
|
||||
// and the pulling forces (threshold distance)
|
||||
auto opt_problem = (options & SteinerModel) ?
|
||||
get_RSMT_linear_system ( _circuit, _placementLB, minDisruption, 2, 100000 )
|
||||
: get_HPWLF_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 );
|
||||
auto solv = opt_problem
|
||||
+ get_linear_pulling_forces( _circuit, _placementUB, _placementLB, pullingForce, 2.0f * linearDisruption);
|
||||
solve_linear_system( _circuit, _placementLB, solv, 200 ); // 200 iterations
|
||||
_progressReport2(" Linear." );
|
||||
+ get_linear_pulling_forces( *_circuit
|
||||
, *_placementUB
|
||||
, *_placementLB
|
||||
, pullingForce
|
||||
, 2.0f * linearDisruption);
|
||||
solve_linear_system( *_circuit, *_placementLB, solv, 200 ); // 200 iterations
|
||||
_progressReport2(" Linear." );
|
||||
|
||||
if(options & UpdateLB)
|
||||
_updatePlacement( _placementLB );
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
// Optimize orientation sometimes
|
||||
if (i%5 == 0) {
|
||||
optimize_exact_orientations( _circuit, _placementLB );
|
||||
_progressReport2(" Orient." );
|
||||
optimize_exact_orientations( *_circuit, *_placementLB );
|
||||
_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;
|
||||
|
||||
/*
|
||||
|
@ -1000,8 +1099,13 @@ namespace Etesian {
|
|||
pullingForce += penaltyIncrease;
|
||||
prevOptRatio = optRatio;
|
||||
|
||||
linearDisruption = get_mean_linear_disruption(_circuit, _placementLB, _placementUB);
|
||||
linearDisruption = get_mean_linear_disruption(*_circuit, *_placementLB, *_placementUB);
|
||||
++i;
|
||||
|
||||
if ((linearDisruption < getAntennaInsertThreshold()*100.0) and not antennaDone) {
|
||||
antennaProtect();
|
||||
antennaDone = true;
|
||||
}
|
||||
// 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
|
||||
} while (linearDisruption > minDisruption and prevOptRatio <= 0.9);
|
||||
|
@ -1023,52 +1127,94 @@ namespace Etesian {
|
|||
label.str("");
|
||||
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 ......." );
|
||||
if(options & UpdateDetailed)
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
auto legalizer = legalize( _circuit, _placementUB, _surface, sliceHeight );
|
||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||
auto legalizer = legalize( *_circuit, *_placementUB, *_surface, sliceHeight );
|
||||
coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
|
||||
_progressReport1(" Legalized ......" );
|
||||
if(options & UpdateDetailed)
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
row_compatible_orientation( _circuit, legalizer, true );
|
||||
swaps_global_HPWL( _circuit, legalizer, 3, 4 );
|
||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||
row_compatible_orientation( *_circuit, legalizer, true );
|
||||
swaps_global_HPWL( *_circuit, legalizer, 3, 4 );
|
||||
coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
|
||||
_progressReport1(" Global Swaps ..." );
|
||||
if(options & UpdateDetailed)
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
if(options & SteinerModel)
|
||||
OSRP_noncvx_RSMT( _circuit, legalizer );
|
||||
OSRP_noncvx_RSMT( *_circuit, legalizer );
|
||||
else
|
||||
OSRP_convex_HPWL( _circuit, legalizer );
|
||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||
OSRP_convex_HPWL( *_circuit, legalizer );
|
||||
coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
|
||||
_progressReport1(" Row Optimization" );
|
||||
if(options & UpdateDetailed)
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
if(options & SteinerModel)
|
||||
swaps_row_noncvx_RSMT( _circuit, legalizer, effort+2 );
|
||||
swaps_row_noncvx_RSMT( *_circuit, legalizer, effort+2 );
|
||||
else
|
||||
swaps_row_convex_HPWL( _circuit, legalizer, effort+2 );
|
||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||
swaps_row_convex_HPWL( *_circuit, legalizer, effort+2 );
|
||||
coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
|
||||
_progressReport1(" Local Swaps ...." );
|
||||
if(options & UpdateDetailed)
|
||||
_updatePlacement( _placementUB );
|
||||
|
||||
if (i == iterations-1) {
|
||||
//swaps_row_convex_RSMT( _circuit, legalizer, 4 );
|
||||
row_compatible_orientation( _circuit, legalizer, true );
|
||||
coloquinte::dp::get_result( _circuit, legalizer, _placementUB );
|
||||
verify_placement_legality( _circuit, _placementUB, _surface );
|
||||
//swaps_row_convex_RSMT( *_circuit, legalizer, 4 );
|
||||
row_compatible_orientation( *_circuit, legalizer, true );
|
||||
coloquinte::dp::get_result( *_circuit, legalizer, *_placementUB );
|
||||
verify_placement_legality( *_circuit, *_placementUB, *_surface );
|
||||
_progressReport1(" Final Legalize ." );
|
||||
}
|
||||
}
|
||||
_placementLB = _placementUB; // In case we run other passes
|
||||
_updatePlacement( _placementUB );
|
||||
*_placementLB = *_placementUB; // In case we run other passes
|
||||
_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;
|
||||
detailedPlace(detailedIterations, detailedEffort, detailedOptions);
|
||||
|
||||
Breakpoint::stop( 100, "Before adding feeds." );
|
||||
cmess2 << " o Adding feed cells." << endl;
|
||||
readSlices();
|
||||
toHurricane();
|
||||
//addFeeds();
|
||||
|
||||
cmess1 << " o Placement finished." << endl;
|
||||
stopMeasures();
|
||||
printMeasures();
|
||||
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
|
||||
( " - 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();
|
||||
for ( Net* net : getCell()->getNets() ) {
|
||||
|
@ -1202,12 +1349,12 @@ namespace Etesian {
|
|||
}
|
||||
|
||||
cmess2 << label
|
||||
<< " HPWL:" << setw(11) << coloquinte::gp::get_HPWL_wirelength( _circuit, _placementUB )
|
||||
<< " RMST:" << setw(11) << coloquinte::gp::get_RSMT_wirelength( _circuit, _placementUB )
|
||||
<< " HPWL=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_HPWL_wirelength( *_circuit, *_placementUB )))
|
||||
<< " RMST=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_RSMT_wirelength( *_circuit, *_placementUB )))
|
||||
<< endl;
|
||||
cparanoid << indent
|
||||
<< " 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 )
|
||||
<< " 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 )
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
@ -1222,13 +1369,13 @@ namespace Etesian {
|
|||
}
|
||||
|
||||
cmess2 << label
|
||||
<< " HPWL:" << setw(11) << coloquinte::gp::get_HPWL_wirelength( _circuit, _placementLB )
|
||||
<< " RMST:" << setw(11) << coloquinte::gp::get_RSMT_wirelength( _circuit, _placementLB )
|
||||
<< " HPWL=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_HPWL_wirelength( *_circuit, *_placementLB )))
|
||||
<< " RMST=" << setw(14) << DbU::getValueString(toDbU(coloquinte::gp::get_RSMT_wirelength( *_circuit, *_placementLB )))
|
||||
<< endl;
|
||||
}
|
||||
|
||||
|
||||
void EtesianEngine::_updatePlacement ( const coloquinte::placement_t& placement )
|
||||
void EtesianEngine::_updatePlacement ( const coloquinte::placement_t* placement, uint32_t flags )
|
||||
{
|
||||
UpdateSession::open();
|
||||
|
||||
|
@ -1236,6 +1383,8 @@ namespace Etesian {
|
|||
if (getBlockInstance()) topTransformation = getBlockInstance()->getTransformation();
|
||||
topTransformation.invert();
|
||||
|
||||
vector< tuple<Occurrence,size_t,Transformation> > diodeMasters;
|
||||
|
||||
for ( Occurrence occurrence : getCell()->getTerminalNetlistInstanceOccurrences(getBlockInstance()) )
|
||||
{
|
||||
DbU::Unit hpitch = getSliceStep();
|
||||
|
@ -1254,29 +1403,106 @@ namespace Etesian {
|
|||
if (instance->getPlacementStatus() == Instance::PlacementStatus::FIXED)
|
||||
continue;
|
||||
|
||||
point<int_t> position = placement.positions_[(*iid).second];
|
||||
Transformation trans = toTransformation( position
|
||||
, placement.orientations_[(*iid).second]
|
||||
, instance->getMasterCell()
|
||||
, hpitch
|
||||
, vpitch
|
||||
);
|
||||
uint32_t outputSide = getOutputSide( instance->getMasterCell() );
|
||||
point<int_t> position = placement->positions_[(*iid).second];
|
||||
Transformation cellTrans = toTransformation( position
|
||||
, placement->orientations_[(*iid).second]
|
||||
, instance->getMasterCell()
|
||||
, hpitch
|
||||
, vpitch
|
||||
);
|
||||
topTransformation.applyOn( cellTrans );
|
||||
//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
|
||||
// of all the intermediary instances.
|
||||
topTransformation.applyOn( trans );
|
||||
instance->setTransformation( trans );
|
||||
instance->setTransformation( cellTrans );
|
||||
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();
|
||||
|
||||
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
|
||||
{ return "Etesian::EtesianEngine"; }
|
||||
|
||||
|
@ -1295,6 +1521,8 @@ namespace Etesian {
|
|||
|
||||
if (record) {
|
||||
record->add( getSlot( "_configuration", _configuration ) );
|
||||
record->add( getSlot( "_area" , _area ) );
|
||||
record->add( getSlot( "_diodeCount" , _diodeCount ) );
|
||||
}
|
||||
return record;
|
||||
}
|
||||
|
|
|
@ -14,16 +14,12 @@
|
|||
// +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
#include <map>
|
||||
#include <list>
|
||||
#include <tuple>
|
||||
#include "hurricane/Error.h"
|
||||
#include "hurricane/Warning.h"
|
||||
#include "hurricane/DataBase.h"
|
||||
#include "hurricane/UpdateSession.h"
|
||||
#include "hurricane/Plug.h"
|
||||
#include "hurricane/Path.h"
|
||||
#include "hurricane/Instance.h"
|
||||
#include "hurricane/Library.h"
|
||||
#include "hurricane/viewer/CellWidget.h"
|
||||
#include "hurricane/viewer/CellViewer.h"
|
||||
|
@ -32,242 +28,40 @@
|
|||
#include "etesian/EtesianEngine.h"
|
||||
|
||||
|
||||
namespace {
|
||||
namespace Etesian {
|
||||
|
||||
using namespace std;
|
||||
using Hurricane::tab;
|
||||
using Hurricane::Warning;
|
||||
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::Transformation;
|
||||
using Hurricane::DataBase;
|
||||
using Hurricane::Cell;
|
||||
using Hurricane::Library;
|
||||
using Hurricane::UpdateSession;
|
||||
using CRL::AllianceFramework;
|
||||
using CRL::CatalogExtension;
|
||||
using CRL::getTransformation;
|
||||
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 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 );
|
||||
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 )
|
||||
Record* Tile::_getRecord () const
|
||||
{
|
||||
cdebug_log(121,0) << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << endl;
|
||||
Instance* instance = getInstance();
|
||||
Transformation reference = instance->getTransformation();
|
||||
Transformation transf = Transformation( reference.getTx() + dx
|
||||
, reference.getTy()
|
||||
, reference.getOrientation() );
|
||||
instance->setTransformation( transf );
|
||||
_xMin += dx;
|
||||
Record* record = new Record(getString(this));
|
||||
record->add( getSlot( "_occurrence", _occurrence ) );
|
||||
record->add( DbU::getValueSlot( "_xMin" , &_xMin ) );
|
||||
record->add( DbU::getValueSlot( "_width", &_width ) );
|
||||
return record;
|
||||
}
|
||||
|
||||
|
||||
// -------------------------------------------------------------------
|
||||
// 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 {
|
||||
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 )
|
||||
: _area (area)
|
||||
|
@ -388,7 +182,7 @@ namespace {
|
|||
void Slice::addFeeds ( size_t islice )
|
||||
{
|
||||
if (_tiles.empty()) {
|
||||
fillHole( getXMin(), getXMax(), getYBottom(), islice%2 );
|
||||
fillHole( _tiles.end(), getXMin(), getXMax(), getYBottom(), islice%2 );
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -398,21 +192,27 @@ namespace {
|
|||
|
||||
// Hole before the first chunk.
|
||||
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 ) {
|
||||
fillHole( (*itile).getXMax(), (*itilenext).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 );
|
||||
while ( itilenext != _tiles.end() ) {
|
||||
fillHole( itilenext, (*itile).getXMax(), (*itilenext).getXMin(), getYBottom(), (islice+getSpinSlice0())%2 );
|
||||
itile = itilenext;
|
||||
++itilenext;
|
||||
}
|
||||
|
||||
// Hole after the last chunk.
|
||||
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();
|
||||
if (feed == NULL) {
|
||||
|
@ -438,52 +238,65 @@ namespace {
|
|||
if (feed == NULL) break;
|
||||
}
|
||||
|
||||
Instance::create ( getEtesian()->getBlockCell()
|
||||
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
|
||||
, feed
|
||||
, getTransformation( feed->getAbutmentBox()
|
||||
, xtie
|
||||
, _ybottom
|
||||
, (yspin)?Transformation::Orientation::MY
|
||||
:Transformation::Orientation::ID
|
||||
)
|
||||
, Instance::PlacementStatus::PLACED
|
||||
);
|
||||
|
||||
Instance* instance = Instance::create
|
||||
( getEtesian()->getBlockCell()
|
||||
, getEtesian()->getFeedCells().getUniqueInstanceName().c_str()
|
||||
, feed
|
||||
, getTransformation( feed->getAbutmentBox()
|
||||
, xtie
|
||||
, _ybottom
|
||||
, (yspin)?Transformation::Orientation::MY
|
||||
:Transformation::Orientation::ID
|
||||
)
|
||||
, Instance::PlacementStatus::PLACED
|
||||
);
|
||||
_tiles.insert( before
|
||||
, Tile( xtie, feed->getAbutmentBox().getWidth(), Occurrence(instance) ));
|
||||
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 {
|
||||
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 )
|
||||
: _etesian (etesian)
|
||||
|
@ -505,6 +318,10 @@ namespace {
|
|||
if (masterCell) {
|
||||
_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 validated = true;
|
||||
|
@ -573,6 +381,19 @@ namespace {
|
|||
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 )
|
||||
: _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
|
||||
{
|
||||
|
@ -755,31 +568,23 @@ namespace {
|
|||
cdebug_tabw(121,-2);
|
||||
}
|
||||
|
||||
|
||||
Instance* Area::createDiodeUnder ( const Box& diodeArea )
|
||||
{
|
||||
DbU::Unit y = diodeArea.getYCenter();
|
||||
|
||||
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 list<Tile>& Slice::getTiles () { return _tiles; }
|
||||
if ((y < _cellAb.getYMin()) or (y >= _cellAb.getYMax())) return NULL;
|
||||
if (not diodeArea.intersect(_cellAb)) return NULL;
|
||||
|
||||
size_t islice = (y - _cellAb.getYMin()) / _sliceHeight;
|
||||
return _slices[islice]->createDiodeUnder( diodeArea );
|
||||
}
|
||||
|
||||
|
||||
} // Anonymous namespace.
|
||||
// -------------------------------------------------------------------
|
||||
// Class : "::EtesianEngine".
|
||||
|
||||
|
||||
namespace Etesian {
|
||||
|
||||
|
||||
using Hurricane::DataBase;
|
||||
using Hurricane::UpdateSession;
|
||||
using Hurricane::Occurrence;
|
||||
|
||||
|
||||
void EtesianEngine::readSlices ()
|
||||
void EtesianEngine::toHurricane ()
|
||||
{
|
||||
if (not getFeedCells().feedNumbers()) {
|
||||
cerr << Warning( "EtesianEngine::readSlices(): No feed cells available, skipping." ) << endl;
|
||||
|
@ -788,10 +593,11 @@ namespace Etesian {
|
|||
|
||||
UpdateSession::open();
|
||||
|
||||
Area area ( this );
|
||||
if (_area) delete _area;
|
||||
_area = new Area ( this );
|
||||
Box topCellAb = getBlockCell()->getAbutmentBox();
|
||||
|
||||
area.setSpinSlice0( _yspinSlice0 );
|
||||
_area->setSpinSlice0( _yspinSlice0 );
|
||||
|
||||
if (getBlockInstance()) {
|
||||
Transformation toBlockTransf = getBlockInstance()->getTransformation();
|
||||
|
@ -803,7 +609,7 @@ namespace Etesian {
|
|||
toBlockTransf.applyOn( overlapAb );
|
||||
overlapAb = topCellAb.getIntersection( overlapAb );
|
||||
if (not overlapAb.isEmpty()) {
|
||||
area.merge( Occurrence(instance), overlapAb );
|
||||
_area->merge( Occurrence(instance), overlapAb );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -831,19 +637,19 @@ namespace Etesian {
|
|||
continue;
|
||||
}
|
||||
|
||||
area.merge( occurrence, instanceAb );
|
||||
_area->merge( occurrence, instanceAb );
|
||||
}
|
||||
|
||||
area.buildSubSlices();
|
||||
area.showSubSlices();
|
||||
_area->buildSubSlices();
|
||||
_area->showSubSlices();
|
||||
if (getConfiguration()->getLatchUpDistance()) {
|
||||
Cell* feed = getFeedCells().getBiggestFeed();
|
||||
DbU::Unit tieSpacing = getConfiguration()->getLatchUpDistance()*2 - feed->getAbutmentBox().getWidth();
|
||||
if (feed != NULL)
|
||||
tieSpacing -= feed->getAbutmentBox().getWidth();
|
||||
area.insertTies( tieSpacing );
|
||||
_area->insertTies( tieSpacing );
|
||||
}
|
||||
area.addFeeds();
|
||||
_area->addFeeds();
|
||||
|
||||
UpdateSession::close();
|
||||
|
||||
|
|
|
@ -71,6 +71,7 @@ extern "C" {
|
|||
|
||||
DirectVoidMethod(EtesianEngine,etesian,setDefaultAb)
|
||||
DirectVoidMethod(EtesianEngine,etesian,resetPlacement)
|
||||
DirectVoidMethod(EtesianEngine,etesian,clearColoquinte)
|
||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbHeight,setFixedAbHeight,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetLongAttribute (PyEtesianEngine_setFixedAbWidth ,setFixedAbWidth ,PyEtesianEngine,EtesianEngine)
|
||||
DirectSetDoubleAttribute(PyEtesianEngine_setSpaceMargin ,setSpaceMargin ,PyEtesianEngine,EtesianEngine)
|
||||
|
@ -233,6 +234,8 @@ extern "C" {
|
|||
, "Override the configuration aspect ratio parameter value." }
|
||||
, { "resetPlacement" , (PyCFunction)PyEtesianEngine_resetPlacement , METH_NOARGS
|
||||
, "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
|
||||
, "Run the placer (Etesian)." }
|
||||
, { "destroy" , (PyCFunction)PyEtesianEngine_destroy , METH_NOARGS
|
||||
|
|
|
@ -55,27 +55,30 @@ namespace Etesian {
|
|||
class Configuration {
|
||||
public:
|
||||
// Constructor & Destructor.
|
||||
Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL );
|
||||
~Configuration ();
|
||||
Configuration* clone () const;
|
||||
// Methods.
|
||||
inline RoutingGauge* getGauge () const;
|
||||
inline CellGauge* getCellGauge () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline bool getRoutingDriven () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline string getFeedNames () const;
|
||||
inline string getBloat () const;
|
||||
inline DbU::Unit getLatchUpDistance () const;
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void print ( Cell* ) const;
|
||||
Record* _getRecord () const;
|
||||
string _getString () const;
|
||||
string _getTypeName () const;
|
||||
Configuration ( const RoutingGauge* rg=NULL, const CellGauge* cg=NULL );
|
||||
~Configuration ();
|
||||
Configuration* clone () const;
|
||||
// Methods.
|
||||
inline RoutingGauge* getGauge () const;
|
||||
inline CellGauge* getCellGauge () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline bool getRoutingDriven () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline string getFeedNames () const;
|
||||
inline string getDiodeName () const;
|
||||
inline string getBloat () const;
|
||||
inline DbU::Unit getLatchUpDistance () const;
|
||||
inline DbU::Unit getAntennaMaxWL () const;
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void print ( Cell* ) const;
|
||||
Record* _getRecord () const;
|
||||
string _getString () const;
|
||||
string _getTypeName () const;
|
||||
protected:
|
||||
// Attributes.
|
||||
RoutingGauge* _rg;
|
||||
|
@ -86,28 +89,34 @@ namespace Etesian {
|
|||
bool _routingDriven;
|
||||
double _spaceMargin;
|
||||
double _aspectRatio;
|
||||
double _antennaInsertThreshold;
|
||||
string _feedNames;
|
||||
string _diodeName;
|
||||
string _bloat;
|
||||
DbU::Unit _latchUpDistance;
|
||||
DbU::Unit _antennaMaxWL;
|
||||
private:
|
||||
Configuration ( const Configuration& );
|
||||
Configuration& operator= ( const Configuration& );
|
||||
};
|
||||
|
||||
|
||||
inline RoutingGauge* Configuration::getGauge () const { return _rg; }
|
||||
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
||||
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
||||
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
||||
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
||||
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
||||
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
||||
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
||||
inline string Configuration::getFeedNames () const { return _feedNames; }
|
||||
inline string Configuration::getBloat () const { return _bloat; }
|
||||
inline DbU::Unit Configuration::getLatchUpDistance () const { return _latchUpDistance; }
|
||||
inline void Configuration::setSpaceMargin ( double margin ) { _spaceMargin = margin; }
|
||||
inline void Configuration::setAspectRatio ( double ratio ) { _aspectRatio = ratio; }
|
||||
inline RoutingGauge* Configuration::getGauge () const { return _rg; }
|
||||
inline CellGauge* Configuration::getCellGauge () const { return _cg; }
|
||||
inline Effort Configuration::getPlaceEffort () const { return _placeEffort; }
|
||||
inline GraphicUpdate Configuration::getUpdateConf () const { return _updateConf; }
|
||||
inline Density Configuration::getSpreadingConf () const { return _spreadingConf; }
|
||||
inline bool Configuration::getRoutingDriven () const { return _routingDriven; }
|
||||
inline double Configuration::getSpaceMargin () const { return _spaceMargin; }
|
||||
inline double Configuration::getAspectRatio () const { return _aspectRatio; }
|
||||
inline double Configuration::getAntennaInsertThreshold () const { return _antennaInsertThreshold; }
|
||||
inline string Configuration::getFeedNames () const { return _feedNames; }
|
||||
inline string Configuration::getDiodeName () const { return _diodeName; }
|
||||
inline string Configuration::getBloat () const { return _bloat; }
|
||||
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.
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
|
||||
|
||||
#pragma once
|
||||
#include <tuple>
|
||||
#include <iostream>
|
||||
#include <unordered_map>
|
||||
#include "coloquinte/circuit.hxx"
|
||||
|
@ -34,6 +35,7 @@ namespace Hurricane {
|
|||
#include "etesian/Configuration.h"
|
||||
#include "etesian/FeedCells.h"
|
||||
#include "etesian/BloatCells.h"
|
||||
#include "etesian/Placement.h"
|
||||
|
||||
|
||||
namespace Etesian {
|
||||
|
@ -52,56 +54,70 @@ namespace Etesian {
|
|||
|
||||
class EtesianEngine : public CRL::ToolEngine {
|
||||
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:
|
||||
static const Name& staticGetName ();
|
||||
static EtesianEngine* create ( Cell* );
|
||||
static EtesianEngine* get ( const Cell* );
|
||||
public:
|
||||
virtual Configuration* getConfiguration ();
|
||||
virtual const Configuration* getConfiguration () const;
|
||||
virtual const Name& getName () const;
|
||||
inline RoutingGauge* getGauge () const;
|
||||
inline CellGauge* getCellGauge () const;
|
||||
inline DbU::Unit getHorizontalPitch () const;
|
||||
inline DbU::Unit getVerticalPitch () const;
|
||||
inline DbU::Unit getSliceHeight () const;
|
||||
inline DbU::Unit getSliceStep () const;
|
||||
inline DbU::Unit getFixedAbHeight () const;
|
||||
inline DbU::Unit getFixedAbWidth () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline const FeedCells& getFeedCells () const;
|
||||
inline Hurricane::CellViewer* getViewer () const;
|
||||
inline void setViewer ( Hurricane::CellViewer* );
|
||||
inline Cell* getBlockCell () const;
|
||||
inline Instance* getBlockInstance () const;
|
||||
inline void setBlock ( Instance* );
|
||||
inline void setFixedAbHeight ( DbU::Unit );
|
||||
inline void setFixedAbWidth ( DbU::Unit );
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void setDefaultAb ();
|
||||
void adjustSliceHeight ();
|
||||
void resetPlacement ();
|
||||
void loadLeafCellLayouts ();
|
||||
size_t toColoquinte ();
|
||||
void preplace ();
|
||||
void roughLegalize ( float minDisruption, unsigned options );
|
||||
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 place ();
|
||||
inline void useFeed ( Cell* );
|
||||
size_t findYSpin ();
|
||||
void addFeeds ();
|
||||
void readSlices ();
|
||||
inline void selectBloat ( std::string );
|
||||
virtual Record* _getRecord () const;
|
||||
virtual std::string _getString () const;
|
||||
virtual std::string _getTypeName () const;
|
||||
typedef ToolEngine Super;
|
||||
typedef std::tuple<Net*,int32_t,uint32_t> NetInfos;
|
||||
typedef std::tuple<Instance*,int32_t,uint32_t> InstanceInfos;
|
||||
public:
|
||||
static const Name& staticGetName ();
|
||||
static EtesianEngine* create ( Cell* );
|
||||
static EtesianEngine* get ( const Cell* );
|
||||
public:
|
||||
virtual Configuration* getConfiguration ();
|
||||
virtual const Configuration* getConfiguration () const;
|
||||
virtual const Name& getName () const;
|
||||
inline RoutingGauge* getGauge () const;
|
||||
inline CellGauge* getCellGauge () const;
|
||||
inline DbU::Unit getHorizontalPitch () const;
|
||||
inline DbU::Unit getVerticalPitch () const;
|
||||
inline DbU::Unit getSliceHeight () const;
|
||||
inline DbU::Unit getSliceStep () const;
|
||||
inline DbU::Unit getFixedAbHeight () const;
|
||||
inline DbU::Unit getFixedAbWidth () const;
|
||||
inline Effort getPlaceEffort () const;
|
||||
inline GraphicUpdate getUpdateConf () const;
|
||||
inline Density getSpreadingConf () const;
|
||||
inline double getSpaceMargin () const;
|
||||
inline double getAspectRatio () const;
|
||||
inline double getAntennaInsertThreshold () const;
|
||||
inline DbU::Unit getAntennaMaxWL () const;
|
||||
inline DbU::Unit getLatchUpDistance () const;
|
||||
inline const FeedCells& getFeedCells () const;
|
||||
inline Cell* getDiodeCell () const;
|
||||
inline Hurricane::CellViewer* getViewer () const;
|
||||
inline void setViewer ( Hurricane::CellViewer* );
|
||||
inline Cell* getBlockCell () const;
|
||||
inline Instance* getBlockInstance () const;
|
||||
inline void setBlock ( Instance* );
|
||||
inline void setFixedAbHeight ( DbU::Unit );
|
||||
inline void setFixedAbWidth ( DbU::Unit );
|
||||
inline void setSpaceMargin ( double );
|
||||
inline void setAspectRatio ( double );
|
||||
void setDefaultAb ();
|
||||
void adjustSliceHeight ();
|
||||
void resetPlacement ();
|
||||
void clearColoquinte ();
|
||||
void loadLeafCellLayouts ();
|
||||
inline DbU::Unit toDbU ( int64_t ) const;
|
||||
size_t toColoquinte ();
|
||||
void preplace ();
|
||||
void roughLegalize ( float minDisruption, unsigned options );
|
||||
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:
|
||||
// Attributes.
|
||||
static Name _toolName;
|
||||
|
@ -111,20 +127,24 @@ namespace Etesian {
|
|||
bool _placed;
|
||||
bool _ySpinSet;
|
||||
bool _flatDesign;
|
||||
coloquinte::box<coloquinte::int_t> _surface;
|
||||
coloquinte::netlist _circuit;
|
||||
coloquinte::placement_t _placementLB;
|
||||
coloquinte::placement_t _placementUB;
|
||||
coloquinte::density_restrictions _densityLimits;
|
||||
coloquinte::box<coloquinte::int_t>* _surface;
|
||||
coloquinte::netlist* _circuit;
|
||||
coloquinte::placement_t* _placementLB;
|
||||
coloquinte::placement_t* _placementUB;
|
||||
coloquinte::density_restrictions* _densityLimits;
|
||||
std::unordered_map<string,unsigned int> _cellsToIds;
|
||||
std::vector<Instance*> _idsToInsts;
|
||||
std::vector<InstanceInfos> _idsToInsts;
|
||||
std::vector<NetInfos> _idsToNets;
|
||||
Hurricane::CellViewer* _viewer;
|
||||
Cell* _diodeCell;
|
||||
FeedCells _feedCells;
|
||||
BloatCells _bloatCells;
|
||||
Area* _area;
|
||||
size_t _yspinSlice0;
|
||||
DbU::Unit _sliceHeight;
|
||||
DbU::Unit _fixedAbHeight;
|
||||
DbU::Unit _fixedAbWidth;
|
||||
uint32_t _diodeCount;
|
||||
|
||||
protected:
|
||||
// Constructors & Destructors.
|
||||
|
@ -136,39 +156,47 @@ namespace Etesian {
|
|||
EtesianEngine ( const EtesianEngine& );
|
||||
EtesianEngine& operator= ( const EtesianEngine& );
|
||||
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 _progressReport2 ( string label ) const;
|
||||
};
|
||||
|
||||
|
||||
// Inline Functions.
|
||||
inline void EtesianEngine::setViewer ( Hurricane::CellViewer* viewer ) { _viewer = viewer; }
|
||||
inline Hurricane::CellViewer* EtesianEngine::getViewer () const { return _viewer; }
|
||||
inline RoutingGauge* EtesianEngine::getGauge () const { return getConfiguration()->getGauge(); }
|
||||
inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); }
|
||||
inline DbU::Unit EtesianEngine::getHorizontalPitch () const { return getGauge()->getHorizontalPitch(); }
|
||||
inline DbU::Unit EtesianEngine::getVerticalPitch () const { return getGauge()->getVerticalPitch(); }
|
||||
inline DbU::Unit EtesianEngine::getSliceHeight () const { return _sliceHeight; }
|
||||
inline DbU::Unit EtesianEngine::getSliceStep () const { return getCellGauge()->getSliceStep(); }
|
||||
inline DbU::Unit EtesianEngine::getFixedAbHeight () const { return _fixedAbHeight; }
|
||||
inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; }
|
||||
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
|
||||
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
|
||||
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
|
||||
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
|
||||
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
|
||||
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
|
||||
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
|
||||
inline void EtesianEngine::selectBloat ( std::string profile ) { _bloatCells.select(profile); }
|
||||
|
||||
inline Cell* EtesianEngine::getBlockCell () const { return (_block) ? _block->getMasterCell() : getCell(); }
|
||||
inline Instance* EtesianEngine::getBlockInstance () const { return _block; }
|
||||
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 void EtesianEngine::setViewer ( Hurricane::CellViewer* viewer ) { _viewer = viewer; }
|
||||
inline Hurricane::CellViewer* EtesianEngine::getViewer () const { return _viewer; }
|
||||
inline RoutingGauge* EtesianEngine::getGauge () const { return getConfiguration()->getGauge(); }
|
||||
inline CellGauge* EtesianEngine::getCellGauge () const { return getConfiguration()->getCellGauge(); }
|
||||
inline DbU::Unit EtesianEngine::getHorizontalPitch () const { return getGauge()->getHorizontalPitch(); }
|
||||
inline DbU::Unit EtesianEngine::getVerticalPitch () const { return getGauge()->getVerticalPitch(); }
|
||||
inline DbU::Unit EtesianEngine::getSliceHeight () const { return _sliceHeight; }
|
||||
inline DbU::Unit EtesianEngine::getSliceStep () const { return getCellGauge()->getSliceStep(); }
|
||||
inline DbU::Unit EtesianEngine::getFixedAbHeight () const { return _fixedAbHeight; }
|
||||
inline DbU::Unit EtesianEngine::getFixedAbWidth () const { return _fixedAbWidth; }
|
||||
inline Effort EtesianEngine::getPlaceEffort () const { return getConfiguration()->getPlaceEffort(); }
|
||||
inline GraphicUpdate EtesianEngine::getUpdateConf () const { return getConfiguration()->getUpdateConf(); }
|
||||
inline Density EtesianEngine::getSpreadingConf () const { return getConfiguration()->getSpreadingConf(); }
|
||||
inline double EtesianEngine::getSpaceMargin () const { return getConfiguration()->getSpaceMargin(); }
|
||||
inline double EtesianEngine::getAspectRatio () const { return getConfiguration()->getAspectRatio(); }
|
||||
inline double EtesianEngine::getAntennaInsertThreshold () const { return getConfiguration()->getAntennaInsertThreshold(); }
|
||||
inline DbU::Unit EtesianEngine::getAntennaMaxWL () const { return getConfiguration()->getAntennaMaxWL(); }
|
||||
inline DbU::Unit EtesianEngine::getLatchUpDistance () const { return getConfiguration()->getLatchUpDistance(); }
|
||||
inline void EtesianEngine::useFeed ( Cell* cell ) { _feedCells.useFeed(cell); }
|
||||
inline const FeedCells& EtesianEngine::getFeedCells () const { return _feedCells; }
|
||||
inline Cell* EtesianEngine::getDiodeCell () const { return _diodeCell; }
|
||||
inline void EtesianEngine::selectBloat ( std::string profile ) { _bloatCells.select(profile); }
|
||||
|
||||
inline Cell* EtesianEngine::getBlockCell () const { return (_block) ? _block->getMasterCell() : getCell(); }
|
||||
inline Instance* EtesianEngine::getBlockInstance () const { return _block; }
|
||||
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.
|
||||
extern const char* missingEtesian;
|
||||
|
|
|
@ -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);
|
Loading…
Reference in New Issue