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.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() )
|
||||||
|
|
|
@ -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 ):
|
||||||
"""
|
"""
|
||||||
|
|
|
@ -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()
|
||||||
|
|
|
@ -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
|
||||||
|
|
Loading…
Reference in New Issue