diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 7f32812d..0bc7c36f 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -1001,6 +1001,75 @@ class FeedsConf ( object ): 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". @@ -1190,6 +1259,7 @@ class BlockConf ( GaugeConf ): self.bufferConf = BufferConf( self.framework ) self.constantsConf = ConstantsConf( self.framework, self.cfg ) self.feedsConf = FeedsConf( self.framework, self.cfg ) + self.powersConf = PowersConf( self.framework, self.cfg ) self.chipConf = ChipConf( self ) self.bColumns = 2 self.bRows = 2 @@ -1217,6 +1287,7 @@ class BlockConf ( GaugeConf ): self.cfg.etesian.spaceMargin = None self.cfg.etesian.latchUpDistance = None self.cfg.block.spareSide = None + self.cfg.block.vRailsPeriod = None self.cfg.katana.dumpMeasures = None self.etesian = None self.katana = None @@ -1286,6 +1357,9 @@ class BlockConf ( GaugeConf ): def createFeed ( self ): return self.feedsConf.createFeed( self.cellPnR ) + def createPower ( self ): + return self.powersConf.createPower( self.cellPnR ) + def setDeltaAb ( self, dx1, dy1, dx2, dy2 ): self.deltaAb = [ dx1, dy1, dx2, dy2 ] diff --git a/cumulus/src/plugins/alpha/block/spares.py b/cumulus/src/plugins/alpha/block/spares.py index 128d8024..1393a871 100644 --- a/cumulus/src/plugins/alpha/block/spares.py +++ b/cumulus/src/plugins/alpha/block/spares.py @@ -53,6 +53,7 @@ class BufferPool ( object ): self.selectedIndexes = [] for i in range(self.rows*self.columns): self.buffers.append( [ 0, None ] ) + self._xRight = None self._createBuffers() @property @@ -171,6 +172,10 @@ class BufferPool ( object ): instance.setTransformation( transf ) instance.setPlacementStatus( Instance.PlacementStatus.FIXED ) 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() trBufAb = self.buffers[-1][1].getAbutmentBox() self.area = Box( blBufAb.getXMin(), blBufAb.getYMin() @@ -779,6 +784,32 @@ class QuadTree ( object ): position = plugOccurrence.getBoundingBox().getCenter() 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 ): return self.area.contains( plugOccurrence.getBoundingBox().getCenter() ) @@ -1020,6 +1051,44 @@ class Spares ( object ): trace( 540, "\tX Centers of the QuadTree leaf\n" ) for x in self.quadTree.rleafX: 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, '-' ) def rshowPoolUse ( self ):