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

View File

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

View File

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

View File

@ -15,6 +15,7 @@
import sys import sys
import os.path import os.path
import math
import Cfg import Cfg
from operator import itemgetter from operator import itemgetter
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \ from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
@ -44,30 +45,35 @@ class BufferPool ( object ):
""" """
def __init__ ( self, quadTree ): def __init__ ( self, quadTree ):
self.quadTree = quadTree self.quadTree = quadTree
self.columns = quadTree.spares.conf.bColumns self.columns = quadTree.spares.conf.bColumns
self.rows = quadTree.spares.conf.bRows self.rows = quadTree.spares.conf.bRows
self.area = Box() self.area = Box()
self.buffers = [] self.buffers = []
self.selectedIndex = None self.selectedIndexes = []
for i in range(self.rows*self.columns): for i in range(self.rows*self.columns):
self.buffers.append( [ 0, None ] ) self.buffers.append( [ 0, None ] )
self._createBuffers() self._createBuffers()
@property @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(). be made with either select() or selectFree().
""" """
if self.selectedIndex is None: if not len(self.selectedIndexes):
raise ErrorMessage( 3, 'BufferPool.selected: No buffer has been selected yet.' ) raise ErrorMessage( 3, 'BufferPool.selecteds: No buffer has been selected yet.' )
return self.buffers[ self.selectedIndex ][ 1 ] 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 toIndex ( self, column, row ): return column + row*self.columns
def fromIndex ( self, index ): return (index%self.columns, index/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 ): def select ( self, column, row, flags=0 ):
""" """
Select a specific buffer in the pool matrix. The ``flags`` arguments are Select a specific buffer in the pool matrix. The ``flags`` arguments are
@ -99,11 +105,15 @@ class BufferPool ( object ):
trace( 540, '-' ) trace( 540, '-' )
def _select ( self, index, flags ): def _select ( self, index, flags ):
self.selectedIndex = index for i in range(len(self.selectedIndexes)):
selectedBuffer = self.buffers[ self.selectedIndex ] 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: if flags & Spares.CHECK_USED and selectedBuffer[0] & Spares.USED:
raise ErrorMessage( 3, 'BufferPool.select(): Buffer a index {} is already used.' \ raise ErrorMessage( 3, 'BufferPool.select(): Buffer a index {} is already used.' \
.format(self.selectedIndex) ) .format(self.selectedIndexes[-1]) )
if flags & Spares.MARK_USED: if flags & Spares.MARK_USED:
selectedBuffer[0] |= Spares.USED selectedBuffer[0] |= Spares.USED
@ -428,19 +438,25 @@ class QuadTree ( object ):
return parent return parent
@property @property
def buffer ( self ): def buffers ( self ):
"""The the currently selected buffer instance in the pool.""" """The the currently selected set of buffer instances in the pool."""
return self.pool.selected return self.pool.selecteds
@property @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.""" """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, index ):
def bOutputPlug ( self ):
"""The output Plug of the currently selected buffer in the pool.""" """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 ): def selectFree ( self ):
""" """
@ -451,20 +467,21 @@ class QuadTree ( object ):
def connectBuffer ( self, doLeaf=False ): 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 already exists. The nets are created in the top level cell, and their
names are derived from the `rtag` attribute. names are derived from the `rtag` attribute.
""" """
if self.isLeaf() and not doLeaf: return if self.isLeaf() and not doLeaf: return
trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) ) trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
plug = self.bOutputPlug for ibuffer in range(len(self.buffers)):
if not plug.getNet(): plug = self.bOutputPlug(ibuffer)
outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}' \ if not plug.getNet():
.format(self.root.bufferTag,self.rtag) ) outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}_{}' \
plug.setNet( outputNetBuff ) .format(self.root.bufferTag,self.rtag,ibuffer) )
trace( 540, '\t| {}\n'.format(plug) ) plug.setNet( outputNetBuff )
trace( 540, '\t| {}\n'.format(outputNetBuff) ) trace( 540, '\t| {}\n'.format(plug) )
trace( 540, '\t| {}\n'.format(outputNetBuff) )
def rconnectBuffer ( self ): def rconnectBuffer ( self ):
"""[R]ecursive call of connectBuffer()""" """[R]ecursive call of connectBuffer()"""
@ -484,8 +501,20 @@ class QuadTree ( object ):
self.pool.select( column, row, flags ) self.pool.select( column, row, flags )
if not self.isLeaf(): if not self.isLeaf():
for leaf in self.leafs: leaf.rselectBuffer( column, row, flags ) 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, '-' ) 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 ): def _mergeLeafX ( self, leafX ):
for x in leafX: for x in leafX:
if not (x in self.rleafX): if not (x in self.rleafX):
@ -774,27 +803,80 @@ class QuadTree ( object ):
output net created. output net created.
""" """
trace( 540, ',+', '\tQuadTree.spliNetlist()\n' ) 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 ) 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: if not self.plugs:
trace( 540, '-' ) trace( 540, '-' )
return return
for plug in self.plugs: coreTransf = Transformation()
trace( 540, '\t| Leaf: {}\n'.format(plug) ) 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) ) 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| netBuff: {}\n'.format(netBuff) )
trace( 540, '\t| Deep Plug: {}\n'.format(deepPlug) ) trace( 540, '\t| Deep Plug: {}\n'.format(deepPlug) )
deepNetBuff = deepPlug.getMasterNet() if deepPlug else netBuff deepNetBuff = deepPlug.getMasterNet() if deepPlug else netBuff
trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) ) trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
plug.getEntity().setNet( deepNetBuff ) plugOcc.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())) )
trace( 540, '-' ) trace( 540, '-' )
def rsplitNetlist ( self ): def rsplitNetlist ( self ):
@ -815,9 +897,10 @@ class Spares ( object ):
Excess area is put in the topmost and rightmost pools. Excess area is put in the topmost and rightmost pools.
""" """
USED = 0x00000001 USED = 0x00000001
CHECK_USED = 0x00010000 CHECK_USED = 0x00010000
MARK_USED = 0x00020000 MARK_USED = 0x00020000
HEAVY_LEAF_LOAD = 0x00040000
def __init__ ( self, block ): def __init__ ( self, block ):
self.conf = block.conf self.conf = block.conf