Support for non complete clock-tree to fill every nook and cranny.

* Change: In Cumulus/plugins.block.spares, allow the QuadTree to have
    only *some* of it's four childs (BL, TL, TR, BR).
      Modify QuandTree.getLeafUnder() so when there is no leaf under
    the point, due to an incomplete tree, we get the closer leaf.
      Leaf are suppressed when their center points (where the buffers
    are to be put) are under a FIXED Instance (that is, an opaque block).
      Those opaque blocks (or macro blocks) must be put *on the periphery*
    of the design, because the closer they got to the center, the larger
    the chunks of QuadTree that are removeds.
* Change: In Cumulus/plugins.block.clocktree, based on the spare
    QuadTree changes, can now build a clock-tree with some of the
    leaf missing. Should find a way to compensate for the missing
    leaf wires & buffer (dummies).
This commit is contained in:
Jean-Paul Chaput 2021-03-29 16:49:00 +02:00
parent f4891a0aee
commit 9dc0040703
3 changed files with 167 additions and 98 deletions

View File

@ -438,6 +438,7 @@ class Block ( object ):
self.clockTrees.append( ClockTree(self.spares,clockNet,len(self.clockTrees)) )
self.clockTrees[-1].buildHTree()
trace( 550, '-' )
Breakpoint.stop( 100, 'Block.addClockTrees() on {} done.'.format(self.conf.cellPnR) )
def splitClocks ( self ):
"""

View File

@ -104,41 +104,66 @@ class ClockTree ( object ):
hLeafDepth = gaugeConf.horizontalDepth
if gaugeConf.horizontalDepth > 2 and (gaugeConf.horizontalDepth > gaugeConf.verticalDepth):
hLeafDepth = gaugeConf.horizontalDepth - 2
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
blContact = None
brContact = None
tlContact = None
trContact = None
leftContact = None
rigthContact = None
if qt.bl:
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet )
if qt.br:
brContact = gaugeConf.rpAccessByPlugName( qt.br.buffer, bufferConf.input , ckNet )
if qt.tl:
tlContact = gaugeConf.rpAccessByPlugName( qt.tl.buffer, bufferConf.input , ckNet )
if qt.tr:
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
if qt.bl or qt.tl:
leafContact = blContact if brContact else tlContact
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
leftSourceX = gaugeConf.getNearestVerticalTrack ( leftSourceContact.getX(), 0 )
leftSourceY = gaugeConf.getNearestHorizontalTrack( leftSourceContact.getY(), 0 )
rightSourceX = gaugeConf.getNearestVerticalTrack ( rightSourceContact.getX(), 0 )
rightSourceY = gaugeConf.getNearestHorizontalTrack( rightSourceContact.getY(), 0 )
leftContact = gaugeConf.createContact( ckNet, leafContact.getX(), leftSourceContact.getY(), 0 )
leftX = gaugeConf.getNearestVerticalTrack( leftContact.getX(), 0 )
rightX = gaugeConf.getNearestVerticalTrack ( rightContact.getX(), 0 )
tlY = gaugeConf.getTrack( tlContact.getY(), hLeafDepth, 0 )
blY = gaugeConf.getTrack( blContact.getY(), hLeafDepth, 0 )
#tlY = gaugeConf.getNearestHorizontalTrack( tlContact.getY(), 0 )
#blY = gaugeConf.getNearestHorizontalTrack( blContact.getY(), 0 )
trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) ))
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
gaugeConf.setStackPosition( tlContact, leftX, tlY )
gaugeConf.setStackPosition( blContact, leftX, blY )
gaugeConf.setStackPosition( trContact, rightX, tlY )
gaugeConf.setStackPosition( brContact, rightX, blY )
leftContact .setX( leftX )
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 )
rightSourceX = gaugeConf.getNearestVerticalTrack( rightSourceContact.getX(), 0 )
rightSourceY = gaugeConf.getNearestHorizontalTrack( rightSourceContact.getY(), 0 )
rightContact = gaugeConf.createContact( ckNet, leafContact.getX(), rightSourceContact.getY(), 0 )
rightX = gaugeConf.getNearestVerticalTrack( rightContact.getX(), 0 )
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
rightContact.setX( rightX )
rightContact.setY( rightSourceY )
if qt.bl or qt.tl:
gaugeConf.createHorizontal( leftContact, leftSourceContact, leftSourceY , 0 )
if qt.br or qt.tr:
gaugeConf.createHorizontal( rightSourceContact, rightContact, rightSourceY, 0 )
gaugeConf.createVertical ( leftContact , blContact , leftX , 0 )
if tlContact:
tlY = gaugeConf.getTrack( tlContact.getY(), hLeafDepth, 0 )
elif trContact:
tlY = gaugeConf.getTrack( trContact.getY(), hLeafDepth, 0 )
if blContact:
blY = gaugeConf.getTrack( blContact.getY(), hLeafDepth, 0 )
trace( 550, '\tblY:{}\n'.format( DbU.getValueString(blY) ))
elif brContact:
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 )
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
if qt.bl:
gaugeConf.setStackPosition( blContact, leftX, blY )
gaugeConf.createVertical ( leftContact, blContact, leftX, 0 )
if qt.tr:
gaugeConf.setStackPosition( trContact, rightX, tlY )
gaugeConf.createVertical ( trContact, rightContact, rightX, 0 )
if qt.br:
gaugeConf.setStackPosition( brContact, rightX, blY )
gaugeConf.createVertical ( rightContact, brContact, rightX, 0 )
if qt.isRoot():
ckNet = self.clockNet
if not self.spares.conf.isCoreBlock:

View File

@ -1,4 +1,4 @@
#
# This file is part of the Coriolis Software.
# Copyright (c) SU 2020-2020, All Rights Reserved
#
@ -253,10 +253,43 @@ class QuadTree ( object ):
else:
area = Box( area )
spares.conf.icore.getTransformation().applyOn( area )
root = QuadTree( spares, None, area )
root = QuadTree._create( spares, None, area, 'root', raiseError=True )
root.rpartition()
return root
@staticmethod
def isUsedArea ( spares, area, rtag, raiseError ):
centerArea = Box( area.getCenter() )
sliceHeight = spares.conf.sliceHeight
centerArea.inflate( 4*sliceHeight, sliceHeight )
trace( 540, '\tQuadTree.isUnderArea(): {} {} of {}\n'.format(rtag,centerArea,spares.conf.cell) )
trace( 540, '\t{}\n'.format( spares.conf.cellPnR ))
for occurrence in spares.conf.cellPnR.getTerminalNetlistInstanceOccurrencesUnder( centerArea ):
if not isinstance(occurrence.getEntity(),Instance):
continue
instance = occurrence.getEntity()
masterCell = instance.getMasterCell()
if not masterCell.isTerminalNetlist():
continue
trace( 540, '\t| Overlap {}\n'.format(occurrence.getEntity()) )
if raiseError:
raise Error%essage( 1, [ 'QuadTree.create(): Unable to create QuadTree under area {}' \
.format(area)
, 'Area center is under fixed block {}' .format()
] )
return True
sys.stdout.flush()
sys.stderr.flush()
return False
@staticmethod
def _create ( spares, parent, area, rtag, raiseError=False ):
childRtag = parent.rtag+'_'+rtag if parent else rtag
if QuadTree.isUsedArea( spares, area, childRtag, raiseError ):
return None
qt = QuadTree( spares, parent, area, childRtag )
return qt
def __init__ ( self, spares, parent, area, rtag='root' ):
self.spares = spares
self.area = area
@ -474,14 +507,14 @@ class QuadTree ( object ):
if aspectRatio < 0.5:
self.ycut = self.spares.toYSlice( self.area.getYMin() + self.area.getHeight()/2 )
self.bl = QuadTree( self.spares
self.bl = QuadTree._create( self.spares
, self
, Box( self.area.getXMin()
, self.area.getYMin()
, self.area.getXMax()
, self.ycut )
, 'bl' )
self.tl = QuadTree( self.spares
self.tl = QuadTree._create( self.spares
, self
, Box( self.area.getXMin()
, self.ycut
@ -493,14 +526,14 @@ class QuadTree ( object ):
return True
elif aspectRatio > 2.0:
self.xcut = self.spares.toXPitch( self.area.getXMin() + self.area.getWidth()/2 )
self.bl = QuadTree( self.spares
self.bl = QuadTree._create( self.spares
, self
, Box( self.area.getXMin()
, self.area.getYMin()
, self.xcut
, self.area.getYMax() )
, 'bl' )
self.br = QuadTree( self.spares
self.br = QuadTree._create( self.spares
, self
, Box( self.xcut
, self.area.getYMin()
@ -513,28 +546,28 @@ class QuadTree ( object ):
self.ycut = self.spares.toYSlice( self.area.getYMin() + self.area.getHeight()/2 )
self.xcut = self.spares.toXPitch( self.area.getXMin() + self.area.getWidth ()/2 )
self.bl = QuadTree( self.spares
self.bl = QuadTree._create( self.spares
, self
, Box( self.area.getXMin()
, self.area.getYMin()
, self.xcut
, self.ycut )
, 'bl' )
self.br = QuadTree( self.spares
self.br = QuadTree._create( self.spares
, self
, Box( self.xcut
, self.area.getYMin()
, self.area.getXMax()
, self.ycut )
, 'br' )
self.tl = QuadTree( self.spares
self.tl = QuadTree._create( self.spares
, self
, Box( self.area.getXMin()
, self.ycut
, self.xcut
, self.area.getYMax() )
, 'tl' )
self.tr = QuadTree( self.spares
self.tr = QuadTree._create( self.spares
, self
, Box( self.xcut
, self.ycut
@ -658,11 +691,21 @@ class QuadTree ( object ):
if self.isVBipart():
if position.getY() < self.ycut: return self.bl.getLeafUnder(position)
return self.tl.getLeafUnder(position)
leaf = None
if position.getX() < self.xcut:
if position.getY() < self.ycut: return self.bl.getLeafUnder(position)
return self.tl.getLeafUnder(position)
if position.getY() < self.ycut: return self.br.getLeafUnder(position)
return self.tr.getLeafUnder(position)
if position.getY() < self.ycut: leaf = self.bl
else: leaf = self.tl
else:
if position.getY() < self.ycut: leaf = self.br
else: leaf = self.tr
if not leaf:
dx = abs( position.getX() - self.xcut )
dy = abs( position.getY() - self.ycut )
if self.tr and ((dx < dy) or not leaf): leaf = self.tr
if self.tl and ((dx < dy) or not leaf): leaf = self.tl
if self.br and ((dx >= dy) or not leaf): leaf = self.br
if self.bl and ((dx >= dy) or not leaf): leaf = self.bl
return leaf.getLeafUnder(position)
def getFreeLeafUnder ( self, area, attractor=None ):
"""
@ -867,7 +910,7 @@ class Spares ( object ):
, DbU.getValueString(7*self.conf.sliceHeight ) ))
with UpdateSession():
self.quadTree = QuadTree.create( self )
self._addCapTies()
#self._addCapTies()
trace( 540, '-' )
def rshowPoolUse ( self ):