Add support for Antenna/Diode insertion in Etesian.

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

View File

@ -527,32 +527,37 @@ class Block ( object ):
def place ( self ):
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 ):

View File

@ -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

View File

@ -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 )

View File

@ -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) )

View File

@ -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():

View File

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

View File

@ -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;
}

View File

@ -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;
}

View File

@ -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();

View File

@ -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

View File

@ -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.

View File

@ -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;

View File

@ -0,0 +1,322 @@
// -*- C++ -*-
//
// This file is part of the Coriolis Software.
// Copyright (c) UPMC 2020-2020, All Rights Reserved
//
// +-----------------------------------------------------------------+
// | C O R I O L I S |
// | E t e s i a n - A n a l y t i c P l a c e r |
// | |
// | Author : Jean-Paul CHAPUT |
// | E-mail : Jean-Paul.Chaput@lip6.fr |
// | =============================================================== |
// | C++ Header : "./Placement.h" |
// +-----------------------------------------------------------------+
#pragma once
#include <map>
#include <list>
#include "hurricane/Box.h"
#include "hurricane/Interval.h"
#include "hurricane/Instance.h"
#include "hurricane/Occurrence.h"
namespace Etesian {
using Hurricane::Error;
using Hurricane::Record;
using Hurricane::DbU;
using Hurricane::Box;
using Hurricane::Interval;
using Hurricane::DBo;
using Hurricane::Cell;
using Hurricane::Instance;
using Hurricane::Transformation;
using Hurricane::Occurrence;
class EtesianEngine;
// -------------------------------------------------------------------
// Class : "::TieDatas".
class TieDatas {
public:
inline TieDatas ( Cell* cell=NULL, DbU::Unit leftDistance=0, DbU::Unit rightDistance=0 );
inline Cell* getCell () const;
inline DbU::Unit getLeftDistance () const;
inline DbU::Unit getRightDistance() const;
private:
Cell* _cell;
DbU::Unit _leftDistance;
DbU::Unit _rightDistance;
};
inline TieDatas::TieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
: _cell (cell)
, _leftDistance (leftDistance)
, _rightDistance(rightDistance)
{ }
inline Cell* TieDatas::getCell () const { return _cell; }
inline DbU::Unit TieDatas::getLeftDistance () const { return _leftDistance; }
inline DbU::Unit TieDatas::getRightDistance() const { return _rightDistance; }
// -------------------------------------------------------------------
// Class : "::TieLUT".
class TieLUT {
public:
inline TieLUT ();
inline const TieDatas* getTieDatas ( Cell* ) const;
inline DbU::Unit getLeftDistance ( Cell* ) const;
inline DbU::Unit getRightDistance ( Cell* ) const;
inline void addTieDatas ( Cell*, DbU::Unit leftDistance, DbU::Unit rightDistance );
private:
std::map< Cell*, TieDatas, DBo::CompareById > _tieLut;
};
inline TieLUT::TieLUT ()
: _tieLut()
{ }
inline void TieLUT::addTieDatas ( Cell* cell, DbU::Unit leftDistance, DbU::Unit rightDistance )
{
const TieDatas* datas = getTieDatas( cell );
if (datas) {
std::cerr << Error( "TieLUT::addTieDatas(): Duplicate datas for % (ignoreds)."
, getString(cell).c_str()
) << std::endl;
}
_tieLut[ cell ] = TieDatas( cell, leftDistance, rightDistance );
}
inline const TieDatas* TieLUT::getTieDatas ( Cell* cell ) const
{
auto iDatas = _tieLut.find( cell );
return (iDatas != _tieLut.end()) ? &((*iDatas).second) : NULL;
}
inline DbU::Unit TieLUT::getLeftDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getLeftDistance() : 0;
}
inline DbU::Unit TieLUT::getRightDistance ( Cell* cell ) const
{
const TieDatas* datas = getTieDatas( cell );
return (datas) ? datas->getRightDistance() : 0;
}
// -------------------------------------------------------------------
// Class : "::Tile".
class Area;
class Slice;
class Tile {
public:
inline Tile ( DbU::Unit xMin, DbU::Unit width, const Occurrence& );
inline bool isFixed () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline DbU::Unit getWidth () const;
inline Cell* getMasterCell () const;
inline Instance* getInstance () const;
inline const Occurrence& getOccurrence () const;
inline void translate ( DbU::Unit );
inline std::string _getString () const;
Record* _getRecord () const;
private:
DbU::Unit _xMin;
DbU::Unit _width;
Occurrence _occurrence;
};
inline Tile::Tile ( DbU::Unit xMin, DbU::Unit width, const Occurrence& occurrence )
: _xMin(xMin), _width(width), _occurrence(occurrence)
{ }
inline DbU::Unit Tile::getXMin () const { return _xMin; }
inline DbU::Unit Tile::getXMax () const { return _xMin+_width; }
inline DbU::Unit Tile::getWidth () const { return _width; }
inline const Occurrence& Tile::getOccurrence () const { return _occurrence; }
inline Instance* Tile::getInstance () const { return static_cast<Instance*>( _occurrence.getEntity() ); }
inline Cell* Tile::getMasterCell () const { return getInstance()->getMasterCell(); }
inline bool Tile::isFixed () const
{ return getInstance()->getPlacementStatus() == Instance::PlacementStatus::FIXED; }
inline void Tile::translate ( DbU::Unit dx )
{
cdebug_log(121,0) << " Tile::translate(), dx:" << DbU::getValueString(dx) << ", " << _occurrence << std::endl;
Instance* instance = getInstance();
Transformation reference = instance->getTransformation();
Transformation transf = Transformation( reference.getTx() + dx
, reference.getTy()
, reference.getOrientation() );
instance->setTransformation( transf );
_xMin += dx;
}
inline std::string Tile::_getString () const
{
string s = "<Tile @" + DbU::getValueString(_xMin)
+ " w=" + DbU::getValueString(_width)
+ " \"" + getString(getInstance()->getName())
+ "\">";
return s;
}
// -------------------------------------------------------------------
// Class : "::SubSlice".
class SubSlice {
public:
SubSlice ( Slice*, const std::list<Tile>::iterator& beginTile );
inline const std::list<Tile>::iterator getBeginTile () const;
inline const std::list<Tile>::iterator getEndTile () const;
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
DbU::Unit getAverageChunk ( size_t& ) const;
void insertTies ( DbU::Unit latchUpMax );
private:
Slice* _slice;
std::list<Tile>::iterator _beginTile;
std::list<Tile>::iterator _endTile;
};
inline const std::list<Tile>::iterator SubSlice::getBeginTile () const { return _beginTile; }
inline const std::list<Tile>::iterator SubSlice::getEndTile () const { return _endTile; }
// -------------------------------------------------------------------
// Class : "::Slice".
class Slice {
public:
Slice ( Area*, DbU::Unit ybottom );
inline DbU::Unit getYBottom () const;
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline Interval getXSpan () const;
inline Area* getArea () const;
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
inline std::list<Tile>& getTiles ();
void merge ( const Occurrence&, const Box& );
void addFeeds ( size_t islice );
void fillHole ( std::list<Tile>::iterator before
, DbU::Unit xmin
, DbU::Unit xmax
, DbU::Unit ybottom
, size_t yspin );
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
inline std::string _getString () const;
Record* _getRecord () const;
private:
Area* _area;
DbU::Unit _ybottom;
std::list<Tile> _tiles;
std::vector<SubSlice> _subSlices;
};
inline std::string Slice::_getString () const
{
string s = "<Slice @" + DbU::getValueString(_ybottom) + ">";
return s;
}
// -------------------------------------------------------------------
// Class : "::Area".
class Area {
public:
Area ( EtesianEngine* );
~Area ();
inline EtesianEngine* getEtesian () const;
inline size_t getSpinSlice0 () const;
inline void setSpinSlice0 ( size_t );
inline DbU::Unit getXMin () const;
inline DbU::Unit getXMax () const;
inline DbU::Unit getLeftDistance ( Cell* cell ) const;
inline DbU::Unit getRightDistance ( Cell* cell ) const;
bool validate ( DbU::Unit latchUpMax ) const;
void merge ( const Occurrence&, const Box& );
void addFeeds ();
void buildSubSlices ();
void showSubSlices ();
void insertTies ( DbU::Unit latchUpMax );
Instance* createDiodeUnder ( const Box& );
inline std::string _getString () const;
Record* _getRecord () const;
private:
EtesianEngine* _etesian;
TieLUT _tieLut;
Box _cellAb;
DbU::Unit _sliceHeight;
std::vector<Slice*> _slices;
size_t _spinSlice0;
};
inline EtesianEngine* Area::getEtesian () const { return _etesian; }
inline size_t Area::getSpinSlice0 () const { return _spinSlice0; }
inline void Area::setSpinSlice0 ( size_t spinSlice0 ) { _spinSlice0 = spinSlice0; }
inline DbU::Unit Area::getXMin () const { return _cellAb.getXMin(); }
inline DbU::Unit Area::getXMax () const { return _cellAb.getXMax(); }
inline DbU::Unit Area::getLeftDistance ( Cell* cell ) const { return _tieLut.getLeftDistance(cell); }
inline DbU::Unit Area::getRightDistance ( Cell* cell ) const { return _tieLut.getRightDistance(cell); }
inline string Area::_getString () const { return "<Etesian::Area>"; }
inline DbU::Unit SubSlice::getYBottom () const { return _slice->getYBottom(); }
inline DbU::Unit SubSlice::getXMin () const
{ return (_beginTile == _slice->getTiles().begin()) ? _slice->getXMin() : (*_beginTile).getXMin(); }
inline DbU::Unit SubSlice::getXMax () const
{ return (_endTile == _slice->getTiles().end ()) ? _slice->getXMax() : (*_endTile).getXMax(); }
inline DbU::Unit Slice::getYBottom () const { return _ybottom; }
inline DbU::Unit Slice::getXMin () const { return _area->getXMin(); }
inline DbU::Unit Slice::getXMax () const { return _area->getXMax(); }
inline DbU::Unit Slice::getLeftDistance ( Cell* cell ) const { return _area->getLeftDistance(cell); }
inline DbU::Unit Slice::getRightDistance ( Cell* cell ) const { return _area->getRightDistance(cell); }
inline Interval Slice::getXSpan () const { return Interval( getXMin(), getXMax() ); }
inline Area* Slice::getArea () const { return _area; }
inline EtesianEngine* Slice::getEtesian () const { return getArea()->getEtesian(); }
inline size_t Slice::getSpinSlice0 () const { return getArea()->getSpinSlice0(); }
inline std::list<Tile>& Slice::getTiles () { return _tiles; }
} // Etesian namespace.
INSPECTOR_PR_SUPPORT(Etesian::Tile);
INSPECTOR_P_SUPPORT(Etesian::Slice);
INSPECTOR_P_SUPPORT(Etesian::Area);