Add support of vertical power rails made of powmid cells in Block.

* New: In cumulus/plugins.block.congiguration: New PowersConf config
    sub-object to store characteristics of the "powmid_x0" cell.
    The name of the Cell with which to build the vertical power
    rails is given though the cfg parameter:
      "cfg.etesian.cell.power"
* New: In cumulus/plugins.block.spares, add support for creating
    vertical power lines along with the buffers pools of the H-Trees.
    At most, one vertical power rail will be put exactly at the right
    edge of the buffer pool of each leaf QuadTree. We can reduce that
    number, using the parameter:
      "cfg.block.vRailsPeriod = N"
      Which give the ratio to use (one over N QuadTree leaf).
   WARNING: This may not work if the QuadTree is "dented" not in a
            corner but in the *middle* of the side. Needs to be
	    improved and/or checked.
This commit is contained in:
Jean-Paul Chaput 2021-11-28 19:12:59 +01:00
parent df972b7250
commit b1b67d18e6
2 changed files with 143 additions and 0 deletions

View File

@ -1001,6 +1001,75 @@ class FeedsConf ( object ):
self.count = 0 self.count = 0
# ----------------------------------------------------------------------------
# Class : "configuration.PowersConf".
class PowersConf ( object ):
"""
Store informations about power cells to build vertical power rails in
technologies with low number of routing layers.
"""
def __init__ ( self, framework, cfg ):
trace( 550, ',+', '\tPowersConf.__init__()\n' )
cfg.etesian.cell.power = None
self.power = None
powerName = cfg.etesian.cell.power
self.count = 0
if cfg.etesian.cell.power:
self.power = framework.getCell( powerName, CRL.Catalog.State.Views )
if not self.power:
print( WarningMessage( 'PowersConf.__init__(): Power cell "{}" not found in library (skipped).' \
.format(powerName)) )
trace( 550, '-' )
return
def createPower ( self, cell ):
instance = Instance.create( cell, 'power_{}'.format(self.count), self.power )
self.count += 1
return instance
def columnAt ( self, cell, x, y, orient, sliceCount ):
"""
In ``cell``, build a column which bottom is at ``transf`` position and
span over ``sliceCount`` slices.
"""
sliceHeight = self.power.getAbutmentBox().getHeight()
if orient == Transformation.Orientation.ID:
offset = 1
orients = ( Transformation.Orientation.ID, Transformation.Orientation.MX )
elif orient == Transformation.Orientation.MX:
offset = 1
orients = ( Transformation.Orientation.MX, Transformation.Orientation.ID )
elif orient == Transformation.Orientation.R2:
y += sliceHeight
offset = 0
orients = ( Transformation.Orientation.R2, Transformation.Orientation.MY )
elif orient == Transformation.Orientation.MY:
y += sliceHeight
offset = 0
orients = ( Transformation.Orientation.MY, Transformation.Orientation.R2 )
else:
raise ErrorMessage( [ 'PowersConf.columnAt(): Rotations are not allowed for power columns, in "{}".' \
.format(cell.getName())
, ' (@{}, sliceCount:{})' \
.format(orient,sliceCount)
] )
for islice in range(sliceCount):
instance = Instance.create( cell, 'power_{}'.format(self.count), self.power )
instance.setTransformation( Transformation( x
, y
, orients[ islice%2 ] ))
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
if (islice+offset) % 2:
y += 2*sliceHeight
self.count += 1
def resetPowerCount ( self ):
self.count = 0
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Class : "configuration.IoPin". # Class : "configuration.IoPin".
@ -1190,6 +1259,7 @@ class BlockConf ( GaugeConf ):
self.bufferConf = BufferConf( self.framework ) self.bufferConf = BufferConf( self.framework )
self.constantsConf = ConstantsConf( self.framework, self.cfg ) self.constantsConf = ConstantsConf( self.framework, self.cfg )
self.feedsConf = FeedsConf( self.framework, self.cfg ) self.feedsConf = FeedsConf( self.framework, self.cfg )
self.powersConf = PowersConf( self.framework, self.cfg )
self.chipConf = ChipConf( self ) self.chipConf = ChipConf( self )
self.bColumns = 2 self.bColumns = 2
self.bRows = 2 self.bRows = 2
@ -1217,6 +1287,7 @@ class BlockConf ( GaugeConf ):
self.cfg.etesian.spaceMargin = None self.cfg.etesian.spaceMargin = None
self.cfg.etesian.latchUpDistance = None self.cfg.etesian.latchUpDistance = None
self.cfg.block.spareSide = None self.cfg.block.spareSide = None
self.cfg.block.vRailsPeriod = None
self.cfg.katana.dumpMeasures = None self.cfg.katana.dumpMeasures = None
self.etesian = None self.etesian = None
self.katana = None self.katana = None
@ -1286,6 +1357,9 @@ class BlockConf ( GaugeConf ):
def createFeed ( self ): def createFeed ( self ):
return self.feedsConf.createFeed( self.cellPnR ) return self.feedsConf.createFeed( self.cellPnR )
def createPower ( self ):
return self.powersConf.createPower( self.cellPnR )
def setDeltaAb ( self, dx1, dy1, dx2, dy2 ): def setDeltaAb ( self, dx1, dy1, dx2, dy2 ):
self.deltaAb = [ dx1, dy1, dx2, dy2 ] self.deltaAb = [ dx1, dy1, dx2, dy2 ]

View File

@ -53,6 +53,7 @@ class BufferPool ( object ):
self.selectedIndexes = [] 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._xRight = None
self._createBuffers() self._createBuffers()
@property @property
@ -171,6 +172,10 @@ class BufferPool ( object ):
instance.setTransformation( transf ) instance.setTransformation( transf )
instance.setPlacementStatus( Instance.PlacementStatus.FIXED ) instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
length += instance.getMasterCell().getAbutmentBox().getWidth() length += instance.getMasterCell().getAbutmentBox().getWidth()
if self._xRight is None:
self._xRight = x + length
else:
self._xRight = max( self._xRight, x+length )
blBufAb = self.buffers[ 0][1].getAbutmentBox() blBufAb = self.buffers[ 0][1].getAbutmentBox()
trBufAb = self.buffers[-1][1].getAbutmentBox() trBufAb = self.buffers[-1][1].getAbutmentBox()
self.area = Box( blBufAb.getXMin(), blBufAb.getYMin() self.area = Box( blBufAb.getXMin(), blBufAb.getYMin()
@ -779,6 +784,32 @@ class QuadTree ( object ):
position = plugOccurrence.getBoundingBox().getCenter() position = plugOccurrence.getBoundingBox().getCenter()
self.getLeafUnder(position).plugs.append( plugOccurrence ) self.getLeafUnder(position).plugs.append( plugOccurrence )
def getBottomLeafs ( self, bottoms=[] ):
"""
Recursively build a list of all the QuadTree leaf cells at the bottom
of the tree. Sorted left to right by X position.
"""
if self.isLeaf():
bottoms.append( self )
return
if self.bl: self.bl.getBottomLeafs( bottoms )
elif self.tl: self.tl.getBottomLeafs( bottoms )
if self.br: self.br.getBottomLeafs( bottoms )
elif self.tr: self.tr.getBottomLeafs( bottoms )
def getTopLeafs ( self, tops=[] ):
"""
Recursively build a list of all the QuadTree leaf cells at the top
of the tree. Sorted left to right by X position.
"""
if self.isLeaf():
tops.append( self )
return
if self.tl: self.tl.getTopLeafs( tops )
elif self.bl: self.bl.getTopLeafs( tops )
if self.tr: self.tr.getTopLeafs( tops )
elif self.br: self.br.getTopLeafs( tops )
def isUnderArea ( self, plugOccurrence ): def isUnderArea ( self, plugOccurrence ):
return self.area.contains( plugOccurrence.getBoundingBox().getCenter() ) return self.area.contains( plugOccurrence.getBoundingBox().getCenter() )
@ -1020,6 +1051,44 @@ class Spares ( object ):
trace( 540, "\tX Centers of the QuadTree leaf\n" ) trace( 540, "\tX Centers of the QuadTree leaf\n" )
for x in self.quadTree.rleafX: for x in self.quadTree.rleafX:
trace( 540, '\t| {}\n'.format(DbU.getValueString(x) )) trace( 540, '\t| {}\n'.format(DbU.getValueString(x) ))
self._buildPower()
trace( 540, '-' )
def _buildPower ( self ):
trace( 540, '+', '\tSpares._buildPower()\n' )
if not self.conf.powersConf.power: return
bottoms = []
self.quadTree.getBottomLeafs( bottoms )
trace( 540, '\tBottom leafs of the QuadTree:\n' )
for leaf in bottoms:
trace( 540, '\t| {} xRight={}\n'.format( leaf, DbU.getValueString(leaf.pool._xRight) ))
tops = []
self.quadTree.getTopLeafs( tops )
trace( 540, '\tTop leafs of the QuadTree:\n' )
for leaf in tops:
trace( 540, '\t| {} xRight={}\n'.format( leaf, DbU.getValueString(leaf.pool._xRight) ))
if len(tops) != len(bottoms):
print( ErrorMessage( 2, 'Spares._buildPower(): Discrepency between QuadTree top and bottom leafs lists, {} vs {}.'
.format( len(tops), len(bottoms) )))
trace( 540, '-' )
return
vRailsPeriod = self.conf.cfg.block.vRailsPeriod
if vRailsPeriod is None:
vRailsPeriod = 1
if vRailsPeriod == 0:
trace( 540, '-' )
return
sliceHeight = self.conf.sliceHeight
for column in range(len(bottoms)):
if column % vRailsPeriod: continue
x = bottoms[column].pool._xRight
y = bottoms[column].area.getYMin()
ymax = tops [column].area.getYMax() - sliceHeight
while y <= ymax:
power = self.conf.createPower()
power.setTransformation ( self._getTransformation(x,y) )
power.setPlacementStatus( Instance.PlacementStatus.FIXED )
y += sliceHeight
trace( 540, '-' ) trace( 540, '-' )
def rshowPoolUse ( self ): def rshowPoolUse ( self ):