Add management for highly loaded leafs of H-Trees.

In the LS180, probably due to the implementation of a small RAM
with DFFs, some leaf of the clock tree (H-Tree) got heavily
loaded (around 80 DFFs sinks). Implement an option that allow
the leaf of the QuadTree to use three buffers instead of one.
The sinks are partitionned using their angle from the center
of the leaf (trigonometric direction). CChoose the bigger angle
gaps to perform the split.

* Change: In Cumulus/plugins.block.configuration.GaugeConf, in
     getNearestHorizontalTrack() and getNearestVerticalTrack() add an
     offset argument to shift the position of the requested track
     by a certain amount.
* Change: In Cumulus/plugins.block.configuration.GaugeConf, in
    createHorizontal(), add a flag to make the source end of the
    segment to "stick out". Useful when connecting to a stacked
    VIA top, but using a lower layer that can be shifted.
* New: In Cumulus/plugins.block.spares.Spares, BufferPool & QuadTree,
    add support for selection and management of multiple buffers at
    the same time. Basically returns a list of selected buffer
    instances instead of just one instance.
      Added HEAVY_LEAF_LOAD flag to Spares. To be used by all tools
    classes that makes use of it.
      Added QuadTree.runselect(), be sure to call it between different
    H-Tree operations, otherwise results will be strange.
* New: In Cumulus/plugins.block.htree.HTree, in case of heavy leaf
    load, in the leaf of the tree, allocate three buffers instead
    of one. Select them to form a triangle around the main one.
    That is, use (i,j), (i+1,j) and (i,j+1).
      Added a HTree._connectLeaf() to share the handling of the child
    buffer connexions. Whether they are leaf of not and heavy or not.
* Change: Cumulus/plugins.block.Block, expand HTree support to
    manage the HEAVY_LEAF_LOAD flag.
This commit is contained in:
Jean-Paul Chaput 2021-07-01 14:01:44 +02:00
parent c6f703b1cc
commit 3687ca80e9
4 changed files with 197 additions and 83 deletions

View File

@ -306,13 +306,15 @@ class Block ( object ):
self.hfnTrees = []
self.blockInstances = []
self.placeHolderCount = 0
self.excludedNets = deepcopy( self.conf.hTreeNames )
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
, IoPin.EAST : Side( self.conf, IoPin.EAST )
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
, IoPin.NORTH : Side( self.conf, IoPin.NORTH )
}
self.etesian = None
self.excludedNets = []
for item in self.conf.hTreeDatas:
self.excludedNets.append( item[0] )
if not self.conf.cell.getAbutmentBox().isEmpty():
isBuilt = True
for instance in self.conf.cell.getInstances():
@ -503,7 +505,7 @@ class Block ( object ):
hTreeNets = []
netOcc = None
self.flattenNets()
for netName in self.conf.hTreeNames:
for netName, flags in self.conf.hTreeDatas:
netOcc = self.getFlattenedNet( netName )
#if self.conf.isCoreBlock:
# coreNet = self.conf.cell.getNet( netName )
@ -520,13 +522,13 @@ class Block ( object ):
.format( self.conf.cellPnR.getName(), netName )))
continue
trace( 550, '\tBlock.addHTrees(): Found H-Tree {}.\n'.format(netOcc) )
hTreeNets.append( netOcc )
hTreeNets.append( [ netOcc, flags ] )
self.etesian.exclude( netName )
with UpdateSession():
for hTreeNet in hTreeNets:
print( ' - "{}".'.format(hTreeNet.getName()) )
trace( 550, ',+', '\tBlock.addHTrees(): Build clock tree for {}.\n'.format(hTreeNet) )
self.hTrees.append( HTree(self.spares,hTreeNet,len(self.hTrees)) )
for netOcc, flags in hTreeNets:
print( ' - "{}".'.format(netOcc.getName()) )
trace( 550, ',+', '\tBlock.addHTrees(): Build clock tree for {}.\n'.format(netOcc) )
self.hTrees.append( HTree(self.spares,netOcc,len(self.hTrees),flags) )
self.hTrees[-1].buildHTree()
for net in self.hTrees[-1].subNets:
self.etesian.exclude( net.getName() )

View File

@ -70,6 +70,7 @@ class GaugeConf ( object ):
DeepDepth = 0x0010
UseContactWidth = 0x0020
ExpandWidth = 0x0040
SourceExtend = 0x0080
def __init__ ( self ):
self._cellGauge = None
@ -235,21 +236,24 @@ class GaugeConf ( object ):
trace( 550, ' -> utrack={}\n'.format( DbU.getValueString(utrack) ))
return utrack + offset*rg.getPitch()
def getNearestHorizontalTrack ( self, y, flags ):
def getNearestHorizontalTrack ( self, y, flags, offset=0 ):
if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth
else: depth = self.horizontalDepth
return self.getTrack( y, depth, 0 )
return self.getTrack( y, depth, offset )
def getNearestVerticalTrack ( self, x, flags ):
def getNearestVerticalTrack ( self, x, flags, offset=0 ):
if flags & GaugeConf.DeepDepth: depth = self.verticalDeepDepth
else: depth = self.verticalDepth
return self.getTrack( x, depth, 0 )
return self.getTrack( x, depth, offset )
def createHorizontal ( self, source, target, y, flags ):
if flags & GaugeConf.DeepDepth: depth = self.horizontalDeepDepth
else: depth = self.horizontalDepth
layer = self._routingGauge.getRoutingLayer(depth)
dxSource = 0
if flags & GaugeConf.SourceExtend: dxSource = self._routingGauge.getPitch(layer)
if flags & GaugeConf.UseContactWidth:
width = source.getBoundingBox(layer.getBasicLayer()).getHeight()
@ -259,6 +263,7 @@ class GaugeConf ( object ):
width += DbU.fromLambda( 1.0 )
segment = Horizontal.create( source, target, layer, y, width )
segment.setDxSource( -dxSource )
trace( 550, segment )
return segment
@ -1109,7 +1114,7 @@ class BlockConf ( GaugeConf ):
self.placeArea = None
self.deltaAb = [ 0, 0, 0, 0 ]
self.useClockTree = False
self.hTreeNames = [ ]
self.hTreeDatas = [ ]
self.useHFNS = False
self.useSpares = True
self.isBuilt = False
@ -1212,9 +1217,13 @@ class BlockConf ( GaugeConf ):
self.cloneds.append( masterCell )
return
def useHTree ( self, netName ):
if not netName in self.hTreeNames:
self.hTreeNames.append( netName );
def useHTree ( self, netName, flags=0 ):
for item in self.hTreeDatas:
if item[0] == netName:
print( WarningMessage( 'block.configuration.useHTree(): Redefinition of "{}" H-Tree ignored.' \
.format(netName)) )
return
self.hTreeDatas.append( [ netName, flags ] );
def save ( self, flags ):
"""

View File

@ -40,10 +40,11 @@ class HTree ( object ):
Build a H-Tree on a net occurrene.
"""
def __init__ ( self, spares, treeNetOcc, index ):
def __init__ ( self, spares, treeNetOcc, index, flags ):
self.spares = spares
self.treeNetOcc = treeNetOcc
self.treeIndex = index
self.flags = flags
self.subNets = []
#if not self.treeNetOcc.getEntity().isClock():
# print( WarningMessage( 'HTree.__init__(): Net "{}" is not of CLOCK type.' \
@ -80,25 +81,44 @@ class HTree ( object ):
def _rconnectHTree ( self, qt ):
if qt.isLeaf(): return False
qt.rconnectBuffer()
driverNet = qt.bOutputPlug.getNet()
driverNet = qt.bOutputPlug(0).getNet()
driverNet.setType( self.treeNet.getType() )
for leaf in qt.leafs:
leaf.bInputPlug.setNet( driverNet )
for plug in leaf.bInputPlugs:
plug.setNet( driverNet )
self._rconnectHTree( leaf )
return True
def _connectLeaf ( self, leaf, ckNet, forkContact, contact, x, y ):
gaugeConf = self.spares.conf
bufferConf = self.spares.conf.bufferConf
hLeafDepth = gaugeConf.horizontalDepth
if gaugeConf.horizontalDepth > 2 and (gaugeConf.horizontalDepth > gaugeConf.verticalDepth):
hLeafDepth = gaugeConf.horizontalDepth - 2
gaugeConf.setStackPosition( contact, x, y )
gaugeConf.createVertical ( contact, forkContact, x, 0 )
if len(leaf.buffers) > 1:
tl1Contact = gaugeConf.rpAccessByPlugName( leaf.buffers[1], bufferConf.input , ckNet, GaugeConf.DeepDepth|GaugeConf.HAccess )
tl2Contact = gaugeConf.rpAccessByPlugName( leaf.buffers[2], bufferConf.input , ckNet )
tl2Y = gaugeConf.getTrack( tl2Contact.getY(), hLeafDepth, 2 )
left1X = gaugeConf.getNearestVerticalTrack( tl1Contact.getX(), 0, 0 )
gaugeConf.expandMinArea( tl2Contact )
gaugeConf.setStackPosition( tl1Contact, left1X , y )
gaugeConf.createHorizontal( contact , tl1Contact, y , GaugeConf.DeepDepth|GaugeConf.SourceExtend )
gaugeConf.createVertical ( contact , tl2Contact, x, 0 )
def _rrouteHTree ( self, qt ):
"""
Recursively build one HTree branch for all non-terminal nodes of the QuadTree.
"""
trace( 550, ',+', '\tHTree._rrouteHTree() {}\n'.format(qt.bOutputPlug.getNet()) )
trace( 550, ',+', '\tHTree._rrouteHTree() {}\n'.format(qt.bOutputPlug(0).getNet()) )
trace( 550, '\tOn: {}\n'.format(qt) )
if qt.isLeaf():
trace( 550, '-' )
return False
gaugeConf = self.spares.conf
bufferConf = self.spares.conf.bufferConf
ckNet = qt.bOutputPlug.getNet()
ckNet = qt.bOutputPlug(0).getNet()
self.subNets.append( ckNet )
hLeafDepth = gaugeConf.horizontalDepth
if gaugeConf.horizontalDepth > 2 and (gaugeConf.horizontalDepth > gaugeConf.verticalDepth):
@ -110,16 +130,16 @@ class HTree ( object ):
leftContact = None
rigthContact = None
if qt.bl:
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet )
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffers[0], bufferConf.input , ckNet )
if qt.br:
brContact = gaugeConf.rpAccessByPlugName( qt.br.buffer, bufferConf.input , ckNet )
brContact = gaugeConf.rpAccessByPlugName( qt.br.buffers[0], bufferConf.input , ckNet )
if qt.tl:
tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffer, bufferConf.input , ckNet )
tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffers[0], bufferConf.input , ckNet )
if qt.tr:
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffers[0], bufferConf.input , ckNet )
if qt.bl or qt.tl:
leafContact = blContact if brContact else tlContact
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
leftSourceX = gaugeConf.getNearestVerticalTrack ( leftSourceContact.getX(), 0 )
leftSourceY = gaugeConf.getNearestHorizontalTrack( leftSourceContact.getY(), 0 )
leftContact = gaugeConf.createContact( ckNet, leafContact.getX(), leftSourceContact.getY(), 0 )
@ -129,7 +149,7 @@ class HTree ( object ):
leftContact .setY( leftSourceY )
if qt.br or qt.tr:
leafContact = brContact if brContact else trContact
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceX = gaugeConf.getNearestVerticalTrack( rightSourceContact.getX(), 0 )
rightSourceY = gaugeConf.getNearestHorizontalTrack( rightSourceContact.getY(), 0 )
rightContact = gaugeConf.createContact( ckNet, leafContact.getX(), rightSourceContact.getY(), 0 )
@ -152,17 +172,13 @@ class HTree ( object ):
blY = gaugeConf.getTrack( brContact.getY(), hLeafDepth, 0 )
trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) ))
if qt.tl:
gaugeConf.setStackPosition( tlContact, leftX, tlY )
gaugeConf.createVertical ( tlContact, leftContact, leftX, 0 )
self._connectLeaf( qt.tl, ckNet, leftContact, tlContact, leftX, tlY )
if qt.bl:
gaugeConf.setStackPosition( blContact, leftX, blY )
gaugeConf.createVertical ( leftContact, blContact, leftX, 0 )
self._connectLeaf( qt.bl, ckNet, leftContact, blContact, leftX, blY )
if qt.tr:
gaugeConf.setStackPosition( trContact, rightX, tlY )
gaugeConf.createVertical ( trContact, rightContact, rightX, 0 )
self._connectLeaf( qt.tr, ckNet, rightContact, trContact, rightX, tlY )
if qt.br:
gaugeConf.setStackPosition( brContact, rightX, blY )
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
self._connectLeaf( qt.br, ckNet, rightContact, brContact, rightX, blY )
if qt.isRoot():
ckNet = self.treeNet
if not self.spares.conf.isCoreBlock:
@ -173,7 +189,7 @@ class HTree ( object ):
print( WarningMessage('HTree._rrouteHTree(): Removing {}.'.format(pin)) )
pin.destroy()
layerGauge = gaugeConf.vRoutingGauge
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
rootContact = gaugeConf.rpAccessByPlugName( qt.buffers[0], bufferConf.input, ckNet, 0 )
x = gaugeConf.getNearestVerticalTrack ( rootContact.getX(), 0 )
y = gaugeConf.getNearestHorizontalTrack( rootContact.getY(), 0 )
rootPin = Pin.create( ckNet
@ -202,7 +218,10 @@ class HTree ( object ):
"""
qt = self.spares.quadTree
qt.bufferTag = self.treeNet.getName()
qt.rselectBuffer( self.treeIndex, self.treeIndex, Spares.CHECK_USED|Spares.MARK_USED)
qt.runselect()
qt.rselectBuffer( self.treeIndex
, self.treeIndex
, Spares.CHECK_USED|Spares.MARK_USED|self.flags)
with UpdateSession():
self._rconnectHTree( qt )
self._rrouteHTree ( qt )
@ -215,7 +234,8 @@ class HTree ( object ):
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree
quadTree.bufferTag = self.treeNet.getName()
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, 0 )
quadTree.runselect()
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, self.flags)
with UpdateSession():
driverPlugs = []
hyperNet = HyperNet.create( Occurrence(self.treeNet) )
@ -229,7 +249,7 @@ class HTree ( object ):
driverPlugs.append( plugOcc )
quadTree.rsplitNetlist()
if self.spares.conf.isCoreBlock:
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
plug = utils.getPlugByName( quadTree.buffers[0], bufferConf.input )
plug.setNet( self.treeNet )
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.treeNet.getName()) )
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.treeNet.getName()

View File

@ -15,6 +15,7 @@
import sys
import os.path
import math
import Cfg
from operator import itemgetter
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
@ -44,30 +45,35 @@ class BufferPool ( object ):
"""
def __init__ ( self, quadTree ):
self.quadTree = quadTree
self.columns = quadTree.spares.conf.bColumns
self.rows = quadTree.spares.conf.bRows
self.area = Box()
self.buffers = []
self.selectedIndex = None
self.quadTree = quadTree
self.columns = quadTree.spares.conf.bColumns
self.rows = quadTree.spares.conf.bRows
self.area = Box()
self.buffers = []
self.selectedIndexes = []
for i in range(self.rows*self.columns):
self.buffers.append( [ 0, None ] )
self._createBuffers()
@property
def selected ( self ):
def selecteds ( self ):
"""
Returns the selected buffer instance within the pool. Selection is to
Returns the selected(s) buffer(s) instance(s) within the pool. Selection is to
be made with either select() or selectFree().
"""
if self.selectedIndex is None:
raise ErrorMessage( 3, 'BufferPool.selected: No buffer has been selected yet.' )
return self.buffers[ self.selectedIndex ][ 1 ]
if not len(self.selectedIndexes):
raise ErrorMessage( 3, 'BufferPool.selecteds: No buffer has been selected yet.' )
selectedBuffers = []
for index in self.selectedIndexes:
selectedBuffers.append( self.buffers[ index ][ 1 ] )
return selectedBuffers
def toIndex ( self, column, row ): return column + row*self.columns
def fromIndex ( self, index ): return (index%self.columns, index/self.columns)
def unselect ( self ): self.selectedIndexes = []
def select ( self, column, row, flags=0 ):
"""
Select a specific buffer in the pool matrix. The ``flags`` arguments are
@ -99,11 +105,15 @@ class BufferPool ( object ):
trace( 540, '-' )
def _select ( self, index, flags ):
self.selectedIndex = index
selectedBuffer = self.buffers[ self.selectedIndex ]
for i in range(len(self.selectedIndexes)):
if index == self.selectedIndexes[i]:
del self.selectedIndexes[i]
break
self.selectedIndexes.append( index )
selectedBuffer = self.buffers[ self.selectedIndexes[-1] ]
if flags & Spares.CHECK_USED and selectedBuffer[0] & Spares.USED:
raise ErrorMessage( 3, 'BufferPool.select(): Buffer a index {} is already used.' \
.format(self.selectedIndex) )
.format(self.selectedIndexes[-1]) )
if flags & Spares.MARK_USED:
selectedBuffer[0] |= Spares.USED
@ -428,19 +438,25 @@ class QuadTree ( object ):
return parent
@property
def buffer ( self ):
"""The the currently selected buffer instance in the pool."""
return self.pool.selected
def buffers ( self ):
"""The the currently selected set of buffer instances in the pool."""
return self.pool.selecteds
@property
def bInputPlug ( self ):
def bInputPlugs ( self ):
"""The list of input Plugs of the currently selected buffers in the pool."""
plugs = []
for buffer in self.buffers:
plugs.append( utils.getPlugByName( buffer, self.spares.conf.bufferConf.input ))
return plugs
def bInputPlug ( self, index ):
"""The input Plug of the currently selected buffer in the pool."""
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.input )
return utils.getPlugByName( self.buffers[index], self.spares.conf.bufferConf.input )
@property
def bOutputPlug ( self ):
def bOutputPlug ( self, index ):
"""The output Plug of the currently selected buffer in the pool."""
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.output )
return utils.getPlugByName( self.buffers[index], self.spares.conf.bufferConf.output )
def selectFree ( self ):
"""
@ -451,20 +467,21 @@ class QuadTree ( object ):
def connectBuffer ( self, doLeaf=False ):
"""
Create output nets for the currently selected buffer, if they do not
Create output nets for the currently selected buffers, if they do not
already exists. The nets are created in the top level cell, and their
names are derived from the `rtag` attribute.
"""
if self.isLeaf() and not doLeaf: return
trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
plug = self.bOutputPlug
if not plug.getNet():
outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}' \
.format(self.root.bufferTag,self.rtag) )
plug.setNet( outputNetBuff )
trace( 540, '\t| {}\n'.format(plug) )
trace( 540, '\t| {}\n'.format(outputNetBuff) )
for ibuffer in range(len(self.buffers)):
plug = self.bOutputPlug(ibuffer)
if not plug.getNet():
outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}_{}' \
.format(self.root.bufferTag,self.rtag,ibuffer) )
plug.setNet( outputNetBuff )
trace( 540, '\t| {}\n'.format(plug) )
trace( 540, '\t| {}\n'.format(outputNetBuff) )
def rconnectBuffer ( self ):
"""[R]ecursive call of connectBuffer()"""
@ -484,8 +501,20 @@ class QuadTree ( object ):
self.pool.select( column, row, flags )
if not self.isLeaf():
for leaf in self.leafs: leaf.rselectBuffer( column, row, flags )
else:
if flags & Spares.HEAVY_LEAF_LOAD:
self.pool.select( column+1, row , flags )
self.pool.select( column , row+1, flags )
trace( 540, '-' )
def runselect ( self ):
"""
Clear any previous buffer selection.
"""
self.pool.unselect()
if not self.isLeaf():
for leaf in self.leafs: leaf.runselect()
def _mergeLeafX ( self, leafX ):
for x in leafX:
if not (x in self.rleafX):
@ -774,27 +803,80 @@ class QuadTree ( object ):
output net created.
"""
trace( 540, ',+', '\tQuadTree.spliNetlist()\n' )
trace( 540, '\tPlug numbers {}\n'.format(len(self.plugs)) )
trace( 540, '\tBuffers numbers {}\n'.format(len(self.buffers)) )
self.connectBuffer( doLeaf=True )
netBuff = self.bOutputPlug.getNet()
trace( 540, '\tBuffer: {}\n'.format(self.buffer) )
trace( 540, '\tBuffer output: {}\n'.format(netBuff) )
if not self.plugs:
trace( 540, '-' )
return
for plug in self.plugs:
trace( 540, '\t| Leaf: {}\n'.format(plug) )
coreTransf = Transformation()
if self.spares.conf.isCoreBlock:
coreTransf = self.spares.conf.icore.getTransformation()
maxSinks = self.spares.conf.bufferConf.maxSinks
#maxSinks = 7
plugOccsByAngle = []
areaCenter = self.area.getCenter()
#coreTransf.applyOn( areaCenter )
trace( 540, '\tArea {}\n'.format(self.area) )
trace( 540, '\tArea center {}\n'.format(areaCenter) )
for plugOcc in self.plugs:
instCenter = plugOcc.getEntity().getInstance().getAbutmentBox().getCenter()
plugOcc.getPath().getTransformation().applyOn( instCenter )
dx = instCenter.getX() - areaCenter.getX()
dy = instCenter.getY() - areaCenter.getY()
angle = math.atan2( dy, dx )
plugOccsByAngle.append( [ angle, plugOcc ] )
plugOccsByAngle.sort( key=itemgetter(0) )
splitIndexes = []
if (len(plugOccsByAngle) > maxSinks) and (len(self.buffers) > 1):
partSize = len(plugOccsByAngle) / len(self.buffers)
trace( 540, '\tpartSize: {}\n'.format(partSize) )
for isplit in range(1,len(self.buffers)):
maxdAngle = 0
maxisplit = partSize*isplit-2
for i in range(maxisplit,maxisplit+4):
dAngle = plugOccsByAngle[i+1][0] - plugOccsByAngle[i][0]
trace( 540, '\t{:-2} dAngle={}\n'.format(i,dAngle) )
if dAngle > maxdAngle:
maxdAngle = dAngle
maxisplit = i
splitIndexes.append( maxisplit )
splitIndexes.append( len(plugOccsByAngle) )
for i in range(len(plugOccsByAngle)):
angle, plugOcc = plugOccsByAngle[i]
instCenter = plugOcc.getEntity().getInstance().getAbutmentBox().getCenter()
plugOcc.getPath().getTransformation().applyOn( instCenter )
dx = instCenter.getX()
dy = instCenter.getY()
trace( 540, '\t {:-2} | {:-5.2} : dx:{} dy:{} {}\n' \
.format(i,angle,DbU.getValueString(dx),DbU.getValueString(dy),plugOcc) )
trace( 540, '\tspitIndexes = {}\n'.format(splitIndexes) )
minIndex = 0
for i in range(len(splitIndexes)):
sinks = splitIndexes[i] - minIndex
minIndex = splitIndexes[i]
if sinks > maxSinks:
print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \
.format( maxSinks
, sinks
, self.bOutputPlug(i).getNet().getName())) )
ibuffer = 0
netBuff = self.bOutputPlug(ibuffer).getNet()
for i in range(len(plugOccsByAngle)):
angle, plugOcc = plugOccsByAngle[i]
if i > splitIndexes[ibuffer]:
ibuffer += 1
netBuff = self.bOutputPlug(ibuffer).getNet()
trace( 540, '\tBuffer: {}\n'.format(self.buffers[ibuffer]) )
trace( 540, '\tBuffer output: {}\n'.format(netBuff) )
trace( 540, '\t| Leaf: {}\n'.format(plugOcc) )
trace( 540, '\t| netBuff: {}\n'.format(netBuff) )
deepPlug = self.spares.raddTransNet( netBuff, plug.getPath() )
deepPlug = self.spares.raddTransNet( netBuff, plugOcc.getPath() )
trace( 540, '\t| netBuff: {}\n'.format(netBuff) )
trace( 540, '\t| Deep Plug: {}\n'.format(deepPlug) )
deepNetBuff = deepPlug.getMasterNet() if deepPlug else netBuff
trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
plug.getEntity().setNet( deepNetBuff )
maxSinks = self.spares.conf.bufferConf.maxSinks
if len(self.plugs) > maxSinks:
print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \
.format(maxSinks,len(self.plugs),netBuff.getName())) )
plugOcc.getEntity().setNet( deepNetBuff )
trace( 540, '-' )
def rsplitNetlist ( self ):
@ -815,9 +897,10 @@ class Spares ( object ):
Excess area is put in the topmost and rightmost pools.
"""
USED = 0x00000001
CHECK_USED = 0x00010000
MARK_USED = 0x00020000
USED = 0x00000001
CHECK_USED = 0x00010000
MARK_USED = 0x00020000
HEAVY_LEAF_LOAD = 0x00040000
def __init__ ( self, block ):
self.conf = block.conf