From 3687ca80e916e5b3dea499923328d48de6f9fb9d Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Thu, 1 Jul 2021 14:01:44 +0200 Subject: [PATCH] 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. --- cumulus/src/plugins/alpha/block/block.py | 16 +- .../src/plugins/alpha/block/configuration.py | 25 ++- cumulus/src/plugins/alpha/block/htree.py | 66 ++++--- cumulus/src/plugins/alpha/block/spares.py | 173 +++++++++++++----- 4 files changed, 197 insertions(+), 83 deletions(-) diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index 17fdf133..e7c13cb6 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -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() ) diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index ee52136e..27bb23f2 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -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 ): """ diff --git a/cumulus/src/plugins/alpha/block/htree.py b/cumulus/src/plugins/alpha/block/htree.py index 35ef89cc..4f2063cf 100644 --- a/cumulus/src/plugins/alpha/block/htree.py +++ b/cumulus/src/plugins/alpha/block/htree.py @@ -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() diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index e0008b6e..6fe69135 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -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