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:
parent
c6f703b1cc
commit
3687ca80e9
|
@ -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() )
|
||||
|
|
|
@ -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 ):
|
||||
"""
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue