Remove unused buffers in Block & Core2Chip.
Note: The previous strategy was not fully coherent in chip mode. Everything added, net and components must be added at corona level and not separated between corona and core. * New: In cumulus/plugins/block.configuration, new FeedsConf object to handle the feeds and provide a filling area helper. * New: In cumulus/plugins/block.spares.removeUnusedbuffers() to remove unused buffers in the pools and replace them by feedthrough. * Change: In cumulus/plugins.block.spares, unify coordinate/slice computation. If we are in chip mode, the coordinates are expressed in the corona *but* aligned on the slices of the *core* model. * Change: In cumulus/plugins.block.Block.rsave(), add the '_r' suffix to the routed cells. * Change: In cumulus/plugins.clocktree.ClockTree, when in chip mode create everything at corona level. Also forgot to set type of clock subnet as clock.
This commit is contained in:
parent
e6e667c6c7
commit
b9f2a5bf28
|
@ -401,7 +401,7 @@ class Block ( object ):
|
|||
print( ' o Building clock tree(s).' )
|
||||
af = CRL.AllianceFramework.get()
|
||||
clockNets = []
|
||||
for net in self.conf.cell.getNets():
|
||||
for net in self.conf.cellPnR.getNets():
|
||||
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
||||
if net.isClock():
|
||||
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
|
||||
|
@ -592,6 +592,7 @@ class Block ( object ):
|
|||
break
|
||||
if self.conf.useClockTree: self.splitClocks()
|
||||
if self.conf.isCoreBlock: self.doConnectCore()
|
||||
self.spares.removeUnusedBuffers()
|
||||
status = self.route()
|
||||
if not self.conf.isCoreBlock:
|
||||
self.addBlockages()
|
||||
|
|
|
@ -82,6 +82,7 @@ class ClockTree ( object ):
|
|||
if qt.isLeaf(): return False
|
||||
qt.rconnectBuffer()
|
||||
driverNet = qt.bOutputPlug.getNet()
|
||||
driverNet.setType( Net.Type.CLOCK )
|
||||
for leaf in qt.leafs:
|
||||
leaf.bInputPlug.setNet( driverNet )
|
||||
self._rconnectHTree( leaf )
|
||||
|
@ -135,13 +136,13 @@ class ClockTree ( object ):
|
|||
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
||||
if qt.isRoot():
|
||||
ckNet = self.clockNet
|
||||
trace( 550, '\tRemoving any previous pin...\n' )
|
||||
pins = []
|
||||
for pin in ckNet.getPins(): pins.append( pin )
|
||||
for pin in pins:
|
||||
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
||||
pin.destroy()
|
||||
if not self.spares.conf.isCoreBlock:
|
||||
trace( 550, '\tRemoving any previous pin...\n' )
|
||||
pins = []
|
||||
for pin in ckNet.getPins(): pins.append( pin )
|
||||
for pin in pins:
|
||||
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
||||
pin.destroy()
|
||||
layerGauge = gaugeConf.vRoutingGauge
|
||||
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
||||
|
@ -187,14 +188,19 @@ class ClockTree ( object ):
|
|||
quadTree.bufferTag = self.clockNet.getName()
|
||||
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
|
||||
with UpdateSession():
|
||||
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
|
||||
coronaPlugs = []
|
||||
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
|
||||
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
|
||||
quadTree.attachToLeaf( plugOccurrence )
|
||||
if quadTree.isUnderArea(plugOccurrence):
|
||||
quadTree.attachToLeaf( plugOccurrence )
|
||||
else:
|
||||
coronaPlugs.append( plugOccurrence )
|
||||
quadTree.rsplitNetlist()
|
||||
if self.spares.conf.isCoreBlock:
|
||||
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
||||
plug.setNet( self.clockNet )
|
||||
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
|
||||
trace( 550, '\tPlug of "{}"\n'.format(self.clockNet.getName()) )
|
||||
trace( 550, '\tPlug of "{}" (Cell:{})\n'.format(self.clockNet.getName()
|
||||
,self.clockNet.getCell()) )
|
||||
for plug in self.clockNet.getPlugs():
|
||||
trace( 550, '\t| {}\n'.format(plug) )
|
||||
|
|
|
@ -16,6 +16,7 @@ from __future__ import print_function
|
|||
import sys
|
||||
import re
|
||||
import os.path
|
||||
from operator import itemgetter
|
||||
import Cfg
|
||||
from Hurricane import Breakpoint
|
||||
from Hurricane import DbU
|
||||
|
@ -596,6 +597,67 @@ class BufferInterface ( object ):
|
|||
self.count = 0
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Class : "configuration.FeedsConf".
|
||||
|
||||
class FeedsConf ( object ):
|
||||
"""
|
||||
Store informations about feed cells and how to fill a gap.
|
||||
"""
|
||||
|
||||
def __init__ ( self, framework ):
|
||||
trace( 550, ',+', '\tFeedsConf.__init__()\n' )
|
||||
feeds = Cfg.getParamString('etesian.feedNames').asString().split(',')
|
||||
self.count = 0
|
||||
self.feeds = []
|
||||
for feedName in feeds:
|
||||
feedCell = framework.getCell( feedName, CRL.Catalog.State.Views )
|
||||
if not feedCell:
|
||||
print( WarningMessage( 'FeedConf.__init__(): Feed cell "{}" not found in library (skipped).' \
|
||||
.format(feedName)) )
|
||||
continue
|
||||
feedWidth = feedCell.getAbutmentBox().getWidth()
|
||||
self.feeds.append( (feedWidth,feedCell) )
|
||||
self.feeds.sort( key=itemgetter(0) )
|
||||
self.feeds.reverse()
|
||||
print( self.feeds )
|
||||
for i in range(len(self.feeds)):
|
||||
trace( 550, '\t[{:>2}] {:>10} {}\n' \
|
||||
.format(i,DbU.getValueString(self.feeds[i][0]),self.feeds[i][1]) )
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
def fillAt ( self, cell, transf, gapWidth ):
|
||||
"""
|
||||
In ``cell``, fill a *one* row gap starting at ``transf`` position and
|
||||
of length ``gapWidth``.
|
||||
"""
|
||||
x = transf.getTx()
|
||||
while gapWidth > 0:
|
||||
feedAdded = False
|
||||
for i in range(len(self.feeds)):
|
||||
if self.feeds[i][0] <= gapWidth:
|
||||
instance = Instance.create( cell, 'spare_feed_{}'.format(self.count), self.feeds[i][1] )
|
||||
instance.setTransformation( Transformation( x
|
||||
, transf.getTy()
|
||||
, transf.getOrientation() ))
|
||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
gapWidth -= self.feeds[i][0]
|
||||
x += self.feeds[i][0]
|
||||
self.count += 1
|
||||
feedAdded = True
|
||||
if not feedAdded: break
|
||||
if gapWidth > 0:
|
||||
print( WarningMessage( [ 'FeedConf.fillAt(): Unable to fill row gap in "{}".' \
|
||||
.format(cell.getName())
|
||||
, ' (@{}, lenght:{})' \
|
||||
.format(transf,DbU.getValueString(gapWidth))
|
||||
] ))
|
||||
|
||||
def resetFeedCount ( self ):
|
||||
self.count = 0
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Class : "configuration.IoPin".
|
||||
|
||||
|
@ -766,6 +828,7 @@ class BlockConf ( GaugeConf ):
|
|||
self.framework = CRL.AllianceFramework.get()
|
||||
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
||||
self.bufferConf = BufferInterface( self.framework )
|
||||
self.feedsConf = FeedsConf( self.framework )
|
||||
self.chipConf = ChipConf( self )
|
||||
self.bColumns = 2
|
||||
self.bRows = 2
|
||||
|
@ -833,6 +896,11 @@ class BlockConf ( GaugeConf ):
|
|||
@property
|
||||
def core ( self ): return self.cell
|
||||
|
||||
@property
|
||||
def cellPnR ( self ):
|
||||
if self.icorona: return self.corona
|
||||
return self.cell
|
||||
|
||||
def setEditor ( self, editor ): self.editor = editor
|
||||
|
||||
def refresh ( self, cell=None ):
|
||||
|
@ -843,7 +911,7 @@ class BlockConf ( GaugeConf ):
|
|||
self.editor.fit()
|
||||
|
||||
def createBuffer ( self ):
|
||||
return self.bufferConf.createBuffer( self.cell )
|
||||
return self.bufferConf.createBuffer( self.cellPnR )
|
||||
|
||||
def setDeltaAb ( self, dx1, dy1, dx2, dy2 ):
|
||||
self.deltaAb = [ dx1, dy1, dx2, dy2 ]
|
||||
|
|
|
@ -144,20 +144,21 @@ class BufferPool ( object ):
|
|||
def _createBuffers ( self ):
|
||||
"""Create the matrix of instances buffer."""
|
||||
trace( 540, ',+', '\tBufferPool.createBuffers()\n' )
|
||||
|
||||
yoffset = 0
|
||||
if self.quadTree.spares.conf.isCoreBlock:
|
||||
yoffset = self.quadTree.spares.conf.icore.getTransformation().getTy()
|
||||
conf = self.quadTree.spares.conf
|
||||
sliceHeight = conf.sliceHeight
|
||||
x = self.quadTree.onXPitch( self.quadTree.area.getXCenter()
|
||||
- (conf.bufferConf.width * self.columns)/2 )
|
||||
y = self.quadTree.onYSlice( self.quadTree.area.getYCenter()
|
||||
- (conf.bufferConf.height * self.rows)/2 )
|
||||
slice = y / sliceHeight
|
||||
|
||||
x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter()
|
||||
- (conf.bufferConf.width * self.columns)/2 )
|
||||
y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter()
|
||||
- (conf.bufferConf.height * self.rows)/2 )
|
||||
slice = (y - yoffset) / sliceHeight
|
||||
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
|
||||
|
||||
trace( 540, '\tSlice #{} (y:{})\n'.format(slice,DbU.getValueString(y)) )
|
||||
for row in range(self.rows):
|
||||
orientation = Transformation.Orientation.ID
|
||||
y = (slice+row) * sliceHeight
|
||||
y = (slice+row) * sliceHeight + yoffset
|
||||
if (slice+row)%2:
|
||||
orientation = Transformation.Orientation.MY
|
||||
y += sliceHeight
|
||||
|
@ -175,10 +176,22 @@ class BufferPool ( object ):
|
|||
, trBufAb.getXMax(), trBufAb.getYMax() )
|
||||
trace( 540, '-' )
|
||||
|
||||
def _removeUnuseds ( self ):
|
||||
conf = self.quadTree.spares.conf
|
||||
for i in range(self.rows*self.columns):
|
||||
if not (self.buffers[i][0] & Spares.USED):
|
||||
trace( 540, '\tRemove Unused Buffer[{}]: {}\n'.format(i,self.buffers[i]) )
|
||||
cell = self.buffers[i][1].getCell()
|
||||
transformation = self.buffers[i][1].getTransformation()
|
||||
gapWidth = self.buffers[i][1].getMasterCell().getAbutmentBox().getWidth()
|
||||
self.buffers[i][1].destroy()
|
||||
conf.feedsConf.fillAt( cell, transformation, gapWidth )
|
||||
|
||||
def _destroyBuffers ( self ):
|
||||
"""Destroy all the buffer instances of the pool."""
|
||||
for flags, buffer in self.buffers:
|
||||
buffer.destroy()
|
||||
if buffer is not None:
|
||||
buffer.destroy()
|
||||
|
||||
def getUse ( self ):
|
||||
"""Return the pool occupancy, a tuple ``(occupancy,capacity)``."""
|
||||
|
@ -213,7 +226,11 @@ class QuadTree ( object ):
|
|||
|
||||
@staticmethod
|
||||
def create ( spares ):
|
||||
root = QuadTree( spares, None, spares.conf.cell.getAbutmentBox() )
|
||||
area = spares.conf.cell.getAbutmentBox()
|
||||
if spares.conf.isCoreBlock:
|
||||
area = spares.conf.core.getAbutmentBox()
|
||||
spares.conf.icore.getTransformation().applyOn( area )
|
||||
root = QuadTree( spares, None, area )
|
||||
root.rpartition()
|
||||
return root
|
||||
|
||||
|
@ -261,6 +278,13 @@ class QuadTree ( object ):
|
|||
def __eq__ ( self, other ):
|
||||
return self.rtag == other.rtag
|
||||
|
||||
def removeUnusedBuffers ( self ):
|
||||
if self.bl: self.bl.removeUnusedBuffers()
|
||||
if self.br: self.br.removeUnusedBuffers()
|
||||
if self.tl: self.tl.removeUnusedBuffers()
|
||||
if self.tr: self.tr.removeUnusedBuffers()
|
||||
self.pool._removeUnuseds()
|
||||
|
||||
def rshowPoolUse ( self ):
|
||||
rused = 0
|
||||
rtotal = 0
|
||||
|
@ -354,16 +378,6 @@ class QuadTree ( object ):
|
|||
"""The output Plug of the currently selected buffer in the pool."""
|
||||
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.output )
|
||||
|
||||
def onYSlice ( self, y ):
|
||||
"""Returns the coordinate of the slice immediately inferior to Y."""
|
||||
modulo = (y - self.area.getYMin()) % self.spares.conf.sliceHeight
|
||||
return y - modulo
|
||||
|
||||
def onXPitch ( self, x ):
|
||||
"""Returns the coordinate of the pitch immediately inferior to X."""
|
||||
modulo = (x - self.area.getXMin()) % self.spares.conf.sliceStep
|
||||
return x - modulo
|
||||
|
||||
def selectFree ( self ):
|
||||
"""
|
||||
Returns the first free buffer *instance* in the pool or None if
|
||||
|
@ -382,7 +396,7 @@ class QuadTree ( object ):
|
|||
trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
|
||||
plug = self.bOutputPlug
|
||||
if not plug.getNet():
|
||||
outputNetBuff = Net.create( self.spares.conf.cell,'{}_{}' \
|
||||
outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}' \
|
||||
.format(self.root.bufferTag,self.rtag) )
|
||||
plug.setNet( outputNetBuff )
|
||||
trace( 540, '\t| {}\n'.format(plug) )
|
||||
|
@ -429,7 +443,7 @@ class QuadTree ( object ):
|
|||
return False
|
||||
|
||||
if aspectRatio < 0.5:
|
||||
self.ycut = self.spares.toYGCellGrid( self.area.getYMin() + self.area.getHeight()/2 )
|
||||
self.ycut = self.spares.toYSlice( self.area.getYMin() + self.area.getHeight()/2 )
|
||||
self.bl = QuadTree( self.spares
|
||||
, self
|
||||
, Box( self.area.getXMin()
|
||||
|
@ -448,7 +462,7 @@ class QuadTree ( object ):
|
|||
trace( 540, '-' )
|
||||
return True
|
||||
elif aspectRatio > 2.0:
|
||||
self.xcut = self.spares.toXGCellGrid( self.area.getXMin() + self.area.getWidth()/2 )
|
||||
self.xcut = self.spares.toXPitch( self.area.getXMin() + self.area.getWidth()/2 )
|
||||
self.bl = QuadTree( self.spares
|
||||
, self
|
||||
, Box( self.area.getXMin()
|
||||
|
@ -467,8 +481,8 @@ class QuadTree ( object ):
|
|||
trace( 540, '-' )
|
||||
return True
|
||||
|
||||
self.ycut = self.spares.toYGCellGrid( self.area.getYMin() + self.area.getHeight()/2 )
|
||||
self.xcut = self.spares.toXGCellGrid( self.area.getXMin() + self.area.getWidth ()/2 )
|
||||
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
|
||||
, Box( self.area.getXMin()
|
||||
|
@ -648,6 +662,9 @@ class QuadTree ( object ):
|
|||
position = plugOccurrence.getBoundingBox().getCenter()
|
||||
self.getLeafUnder(position).plugs.append( plugOccurrence )
|
||||
|
||||
def isUnderArea ( self, plugOccurrence ):
|
||||
return self.area.contains( plugOccurrence.getBoundingBox().getCenter() )
|
||||
|
||||
def splitNetlist ( self ):
|
||||
"""
|
||||
Reorganize the netlist by connecting all plugs to the output of the
|
||||
|
@ -665,15 +682,15 @@ class QuadTree ( object ):
|
|||
|
||||
2.b. Connect the plug to the buffer output net at the same level.
|
||||
|
||||
No net/buffer will be used if the plug list is empty.
|
||||
If the plug list is empty, the buffer will still be used and it's
|
||||
output net created.
|
||||
"""
|
||||
if not self.plugs: return
|
||||
|
||||
trace( 540, ',+', '\tQuadTree.spliNetlist()\n' )
|
||||
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: return
|
||||
for plug in self.plugs:
|
||||
trace( 540, '\t| Leaf: {}\n'.format(plug) )
|
||||
trace( 540, '\t| netBuff: {}\n'.format(netBuff) )
|
||||
|
@ -742,16 +759,33 @@ class Spares ( object ):
|
|||
if not areaLength:
|
||||
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
|
||||
return (float(bufferLength) * 1.4) / float(areaLength)
|
||||
|
||||
def toXPitch ( self, x ):
|
||||
"""
|
||||
Returns the coordinate of the pitch immediately inferior to X.
|
||||
If we are in a chip, compute coordinate in the *corona* system.
|
||||
"""
|
||||
offset = 0
|
||||
area = self.conf.coreAb
|
||||
if self.conf.isCoreBlock:
|
||||
offset = self.conf.icore.getTransformation().getTx()
|
||||
self.conf.icore.getTransformation().applyOn( area )
|
||||
modulo = (x - offset - area.getXMin()) % self.conf.sliceStep
|
||||
return x - modulo
|
||||
|
||||
def toXGCellGrid ( self, x ):
|
||||
"""Find the nearest X (inferior) on the Cell gauge grid (sliceStep)."""
|
||||
dx = x - self.conf.xMin
|
||||
return self.conf.xMin + (dx - dx % self.conf.sliceStep)
|
||||
|
||||
def toYGCellGrid ( self, y ):
|
||||
"""Find the nearest Y (inferior) on the Cell gauge grid (sliceHeight)."""
|
||||
dy = y - self.conf.yMin
|
||||
return self.conf.yMin + (dy - dy % self.conf.sliceHeight)
|
||||
def toYSlice ( self, y ):
|
||||
"""
|
||||
Returns the coordinate of the slice immediately inferior to Y.
|
||||
If we are in a chip, compute coordinate in the *corona* system.
|
||||
"""
|
||||
offset = 0
|
||||
area = self.conf.coreAb
|
||||
if self.conf.isCoreBlock:
|
||||
offset = self.conf.icore.getTransformation().getTy()
|
||||
self.conf.icore.getTransformation().applyOn( area )
|
||||
trace( 540, '\toffset:\n'.format(DbU.getValueString(offset)) )
|
||||
modulo = (y - offset - area.getYMin()) % self.conf.sliceHeight
|
||||
return y - modulo
|
||||
|
||||
def build ( self ):
|
||||
if not self.conf.useSpares: return
|
||||
|
@ -773,8 +807,8 @@ class Spares ( object ):
|
|||
trace( 540, ',+', '\tSpares.addStrayBuffer()\n' )
|
||||
|
||||
sliceHeight = self.conf.sliceHeight
|
||||
x = self.quadTree.onXPitch( position.getX() )
|
||||
y = self.quadTree.onYSlice( position.getY() )
|
||||
x = self.quadTree.toXPitch( position.getX() )
|
||||
y = self.quadTree.toYSlice( position.getY() )
|
||||
slice = y / sliceHeight
|
||||
orientation = Transformation.Orientation.ID
|
||||
y = slice * sliceHeight
|
||||
|
@ -845,6 +879,7 @@ class Spares ( object ):
|
|||
*plug master net* and the *tail path*.
|
||||
"""
|
||||
|
||||
trace( 540, '\tSpares.raddTransNet() top:{} path:{}\n'.format(topNet,path) )
|
||||
if path.isEmpty():
|
||||
self.addClonedCell( topNet.getCell() )
|
||||
return None
|
||||
|
@ -853,6 +888,7 @@ class Spares ( object ):
|
|||
headPlug = utils.getPlugByNet(headInstance,topNet)
|
||||
if not headPlug:
|
||||
masterCell = headInstance.getMasterCell()
|
||||
trace( 540, '\tcreate Plug in {}\n'.format(headInstance) )
|
||||
masterNet = Net.create( masterCell, topNet.getName() )
|
||||
masterNet.setExternal ( True )
|
||||
masterNet.setType ( topNet.getType() )
|
||||
|
@ -866,9 +902,14 @@ class Spares ( object ):
|
|||
self.addClonedCell( headInstance.getCell() )
|
||||
else:
|
||||
masterNet = headPlug.getMasterNet()
|
||||
trace( 540, '\ttailPath {}\n'.format(tailPath) )
|
||||
if tailPath.isEmpty(): return headPlug
|
||||
return self.raddTransNet( masterNet, tailPath )
|
||||
|
||||
def removeUnusedBuffers ( self ):
|
||||
with UpdateSession():
|
||||
self.quadTree.removeUnusedBuffers()
|
||||
|
||||
def rsave ( self, cell ):
|
||||
"""
|
||||
Save the complete cell hierarchy. Saves only the physical view, except
|
||||
|
@ -896,5 +937,7 @@ class Spares ( object ):
|
|||
for cell in self.cloneds:
|
||||
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
|
||||
cell.setName( cell.getName()+'_cts' )
|
||||
if self.conf.chip is None:
|
||||
self.conf.cell.setName( self.conf.cell.getName()+'_r' )
|
||||
self.rsave( self.conf.cell )
|
||||
return
|
||||
|
|
|
@ -148,6 +148,8 @@ class Chip ( Block ):
|
|||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
|
||||
super(Chip,self).save()
|
||||
self.conf.corona.setName( self.conf.corona.getName()+'_r' )
|
||||
self.conf.chip .setName( self.conf.chip .getName()+'_r' )
|
||||
af = CRL.AllianceFramework.get()
|
||||
af.saveCell( self.conf.corona, CRL.Catalog.State.Views )
|
||||
af.saveCell( self.conf.chip , CRL.Catalog.State.Views )
|
||||
|
|
|
@ -158,7 +158,7 @@ class ChipConf ( BlockConf ):
|
|||
#self.checkPads()
|
||||
#self.checkCorona()
|
||||
#self.computeChipSize()
|
||||
#self.checkChipSize()
|
||||
self.checkChipSize()
|
||||
self.findPowerAndClockNets()
|
||||
return
|
||||
|
||||
|
@ -577,6 +577,22 @@ class ChipConf ( BlockConf ):
|
|||
return
|
||||
|
||||
def checkChipSize ( self ):
|
||||
print( 'checkChipSize' )
|
||||
if self.chipSize[0] % self.sliceStep:
|
||||
print( WarningMessage( 'ChipConf.checkChipSize(): Width of "{}" ({})is not on sliceStep ({}), ajusted.' \
|
||||
.format( self.chipConf.name
|
||||
, DbU.getValueString(self.chipSize[0])
|
||||
, DbU.getValueString(self.sliceStep))) )
|
||||
adjust = self.sliceStep - self.chipSize[0] % self.sliceStep
|
||||
self.chipSize = (self.chipSize[0] + adjust, self.chipSize[1])
|
||||
if self.chipSize[1] % self.sliceStep:
|
||||
print( WarningMessage( 'ChipConf.checkChipSize(): Height of "{}" ({})is not on sliceStep ({}), ajusted.' \
|
||||
.format( self.chipConf.name
|
||||
, DbU.getValueString(self.chipSize[1])
|
||||
, DbU.getValueString(self.sliceStep))) )
|
||||
adjust = self.sliceStep - self.chipSize[1] % self.sliceStep
|
||||
self.chipSize = (self.chipSize[0], self.chipSize[1] + adjust)
|
||||
|
||||
#if self._coreSize.isEmpty(): return
|
||||
#
|
||||
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
|
||||
|
|
|
@ -488,6 +488,8 @@ class Builder ( object ):
|
|||
def __init__ ( self, block ):
|
||||
self.block = block
|
||||
self.innerBb = self.block.bb
|
||||
print( 'Builder.__init__(): innerBb: {}'.format(self.innerBb) )
|
||||
print( self.block.path.getTransformation())
|
||||
self.block.path.getTransformation().applyOn( self.innerBb )
|
||||
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
|
||||
self.southSide = SouthSide( self )
|
||||
|
|
|
@ -180,7 +180,7 @@ class Builder ( object ):
|
|||
def __init__ ( self, conf ):
|
||||
self.conf = conf
|
||||
self.path = Path( self.conf.icore )
|
||||
self.block = self.path.getTailInstance().getMasterCell()
|
||||
self.block = self.conf.icore.getMasterCell()
|
||||
self.bb = self.block.getAbutmentBox()
|
||||
self.planes = {}
|
||||
self.activePlane = None
|
||||
|
@ -211,27 +211,30 @@ class Builder ( object ):
|
|||
raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' )
|
||||
return
|
||||
blockCk = None
|
||||
for plug in self.path.getTailInstance().getPlugs():
|
||||
for plug in self.conf.icore.getPlugs():
|
||||
if plug.getNet() == self.conf.coronaCk:
|
||||
blockCk = plug.getMasterNet()
|
||||
if not blockCk:
|
||||
raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \
|
||||
.format(self.path.getTailInstance().getName(),self.ck.getName()) )
|
||||
.format(self.conf.icore.getName(),self.conf.coronaCk.getName()) )
|
||||
return
|
||||
htPlugs = []
|
||||
ffPlugs = []
|
||||
for plug in blockCk.getPlugs():
|
||||
if not plug.getInstance().isTerminalNetlist(): continue
|
||||
htPlugs.append( plug )
|
||||
for plug in self.conf.coronaCk.getPlugs():
|
||||
print( plug )
|
||||
if plug.getInstance().isTerminalNetlist():
|
||||
htPlugs.append( plug )
|
||||
if len(htPlugs) != 1:
|
||||
message = 'Clock "{}" of block "{}" is not organized as a H-Tree.' \
|
||||
.format(blockCk.getName(),self.path.getTailInstance().getName())
|
||||
message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
|
||||
.format( self.conf.coronaCk.getName()
|
||||
, self.conf.icore.getName()
|
||||
, len(htPlugs)) ]
|
||||
print( self.conf.icore )
|
||||
for plug in htPlugs:
|
||||
message += '\n - {}'.format(plug)
|
||||
message += [ '\n - {} {}'.format(plug,plug.getInstance()) ]
|
||||
raise ErrorMessage( 1, message )
|
||||
return
|
||||
with UpdateSession():
|
||||
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], self.path)
|
||||
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path())
|
||||
, self.conf.coronaCk
|
||||
, 0 )
|
||||
blockAb = self.block.getAbutmentBox()
|
||||
|
|
|
@ -248,8 +248,8 @@ class IoPad ( object ):
|
|||
|
||||
@property
|
||||
def pads ( self ):
|
||||
print( self.ioPadConf )
|
||||
return self.ioPadConf.pads
|
||||
print( self.ioPadConf )
|
||||
return self.ioPadConf.pads
|
||||
|
||||
def __str__ ( self ):
|
||||
s = '<IoPad "{}" '.format(self.padInstanceName)
|
||||
|
|
Loading…
Reference in New Issue