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).' )
|
print( ' o Building clock tree(s).' )
|
||||||
af = CRL.AllianceFramework.get()
|
af = CRL.AllianceFramework.get()
|
||||||
clockNets = []
|
clockNets = []
|
||||||
for net in self.conf.cell.getNets():
|
for net in self.conf.cellPnR.getNets():
|
||||||
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
||||||
if net.isClock():
|
if net.isClock():
|
||||||
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
|
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
|
||||||
|
@ -592,6 +592,7 @@ class Block ( object ):
|
||||||
break
|
break
|
||||||
if self.conf.useClockTree: self.splitClocks()
|
if self.conf.useClockTree: self.splitClocks()
|
||||||
if self.conf.isCoreBlock: self.doConnectCore()
|
if self.conf.isCoreBlock: self.doConnectCore()
|
||||||
|
self.spares.removeUnusedBuffers()
|
||||||
status = self.route()
|
status = self.route()
|
||||||
if not self.conf.isCoreBlock:
|
if not self.conf.isCoreBlock:
|
||||||
self.addBlockages()
|
self.addBlockages()
|
||||||
|
|
|
@ -82,6 +82,7 @@ class ClockTree ( object ):
|
||||||
if qt.isLeaf(): return False
|
if qt.isLeaf(): return False
|
||||||
qt.rconnectBuffer()
|
qt.rconnectBuffer()
|
||||||
driverNet = qt.bOutputPlug.getNet()
|
driverNet = qt.bOutputPlug.getNet()
|
||||||
|
driverNet.setType( Net.Type.CLOCK )
|
||||||
for leaf in qt.leafs:
|
for leaf in qt.leafs:
|
||||||
leaf.bInputPlug.setNet( driverNet )
|
leaf.bInputPlug.setNet( driverNet )
|
||||||
self._rconnectHTree( leaf )
|
self._rconnectHTree( leaf )
|
||||||
|
@ -135,13 +136,13 @@ class ClockTree ( object ):
|
||||||
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
||||||
if qt.isRoot():
|
if qt.isRoot():
|
||||||
ckNet = self.clockNet
|
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:
|
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
|
layerGauge = gaugeConf.vRoutingGauge
|
||||||
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||||
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
||||||
|
@ -187,14 +188,19 @@ class ClockTree ( object ):
|
||||||
quadTree.bufferTag = self.clockNet.getName()
|
quadTree.bufferTag = self.clockNet.getName()
|
||||||
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
|
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
|
coronaPlugs = []
|
||||||
|
hyperClock = HyperNet.create( Occurrence(self.clockNet) )
|
||||||
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
|
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
|
||||||
quadTree.attachToLeaf( plugOccurrence )
|
if quadTree.isUnderArea(plugOccurrence):
|
||||||
|
quadTree.attachToLeaf( plugOccurrence )
|
||||||
|
else:
|
||||||
|
coronaPlugs.append( plugOccurrence )
|
||||||
quadTree.rsplitNetlist()
|
quadTree.rsplitNetlist()
|
||||||
if self.spares.conf.isCoreBlock:
|
if self.spares.conf.isCoreBlock:
|
||||||
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
||||||
plug.setNet( self.clockNet )
|
plug.setNet( self.clockNet )
|
||||||
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
|
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():
|
for plug in self.clockNet.getPlugs():
|
||||||
trace( 550, '\t| {}\n'.format(plug) )
|
trace( 550, '\t| {}\n'.format(plug) )
|
||||||
|
|
|
@ -16,6 +16,7 @@ from __future__ import print_function
|
||||||
import sys
|
import sys
|
||||||
import re
|
import re
|
||||||
import os.path
|
import os.path
|
||||||
|
from operator import itemgetter
|
||||||
import Cfg
|
import Cfg
|
||||||
from Hurricane import Breakpoint
|
from Hurricane import Breakpoint
|
||||||
from Hurricane import DbU
|
from Hurricane import DbU
|
||||||
|
@ -596,6 +597,67 @@ class BufferInterface ( object ):
|
||||||
self.count = 0
|
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".
|
# Class : "configuration.IoPin".
|
||||||
|
|
||||||
|
@ -766,6 +828,7 @@ class BlockConf ( GaugeConf ):
|
||||||
self.framework = CRL.AllianceFramework.get()
|
self.framework = CRL.AllianceFramework.get()
|
||||||
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
||||||
self.bufferConf = BufferInterface( self.framework )
|
self.bufferConf = BufferInterface( self.framework )
|
||||||
|
self.feedsConf = FeedsConf( self.framework )
|
||||||
self.chipConf = ChipConf( self )
|
self.chipConf = ChipConf( self )
|
||||||
self.bColumns = 2
|
self.bColumns = 2
|
||||||
self.bRows = 2
|
self.bRows = 2
|
||||||
|
@ -833,6 +896,11 @@ class BlockConf ( GaugeConf ):
|
||||||
@property
|
@property
|
||||||
def core ( self ): return self.cell
|
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 setEditor ( self, editor ): self.editor = editor
|
||||||
|
|
||||||
def refresh ( self, cell=None ):
|
def refresh ( self, cell=None ):
|
||||||
|
@ -843,7 +911,7 @@ class BlockConf ( GaugeConf ):
|
||||||
self.editor.fit()
|
self.editor.fit()
|
||||||
|
|
||||||
def createBuffer ( self ):
|
def createBuffer ( self ):
|
||||||
return self.bufferConf.createBuffer( self.cell )
|
return self.bufferConf.createBuffer( 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 ]
|
||||||
|
|
|
@ -144,20 +144,21 @@ class BufferPool ( object ):
|
||||||
def _createBuffers ( self ):
|
def _createBuffers ( self ):
|
||||||
"""Create the matrix of instances buffer."""
|
"""Create the matrix of instances buffer."""
|
||||||
trace( 540, ',+', '\tBufferPool.createBuffers()\n' )
|
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
|
conf = self.quadTree.spares.conf
|
||||||
sliceHeight = conf.sliceHeight
|
sliceHeight = conf.sliceHeight
|
||||||
x = self.quadTree.onXPitch( self.quadTree.area.getXCenter()
|
x = self.quadTree.spares.toXPitch( self.quadTree.area.getXCenter()
|
||||||
- (conf.bufferConf.width * self.columns)/2 )
|
- (conf.bufferConf.width * self.columns)/2 )
|
||||||
y = self.quadTree.onYSlice( self.quadTree.area.getYCenter()
|
y = self.quadTree.spares.toYSlice( self.quadTree.area.getYCenter()
|
||||||
- (conf.bufferConf.height * self.rows)/2 )
|
- (conf.bufferConf.height * self.rows)/2 )
|
||||||
slice = y / sliceHeight
|
slice = (y - yoffset) / sliceHeight
|
||||||
|
|
||||||
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(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):
|
for row in range(self.rows):
|
||||||
orientation = Transformation.Orientation.ID
|
orientation = Transformation.Orientation.ID
|
||||||
y = (slice+row) * sliceHeight
|
y = (slice+row) * sliceHeight + yoffset
|
||||||
if (slice+row)%2:
|
if (slice+row)%2:
|
||||||
orientation = Transformation.Orientation.MY
|
orientation = Transformation.Orientation.MY
|
||||||
y += sliceHeight
|
y += sliceHeight
|
||||||
|
@ -175,10 +176,22 @@ class BufferPool ( object ):
|
||||||
, trBufAb.getXMax(), trBufAb.getYMax() )
|
, trBufAb.getXMax(), trBufAb.getYMax() )
|
||||||
trace( 540, '-' )
|
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 ):
|
def _destroyBuffers ( self ):
|
||||||
"""Destroy all the buffer instances of the pool."""
|
"""Destroy all the buffer instances of the pool."""
|
||||||
for flags, buffer in self.buffers:
|
for flags, buffer in self.buffers:
|
||||||
buffer.destroy()
|
if buffer is not None:
|
||||||
|
buffer.destroy()
|
||||||
|
|
||||||
def getUse ( self ):
|
def getUse ( self ):
|
||||||
"""Return the pool occupancy, a tuple ``(occupancy,capacity)``."""
|
"""Return the pool occupancy, a tuple ``(occupancy,capacity)``."""
|
||||||
|
@ -213,7 +226,11 @@ class QuadTree ( object ):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def create ( spares ):
|
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()
|
root.rpartition()
|
||||||
return root
|
return root
|
||||||
|
|
||||||
|
@ -261,6 +278,13 @@ class QuadTree ( object ):
|
||||||
def __eq__ ( self, other ):
|
def __eq__ ( self, other ):
|
||||||
return self.rtag == other.rtag
|
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 ):
|
def rshowPoolUse ( self ):
|
||||||
rused = 0
|
rused = 0
|
||||||
rtotal = 0
|
rtotal = 0
|
||||||
|
@ -354,16 +378,6 @@ class QuadTree ( object ):
|
||||||
"""The output Plug of the currently selected buffer in the pool."""
|
"""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.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 ):
|
def selectFree ( self ):
|
||||||
"""
|
"""
|
||||||
Returns the first free buffer *instance* in the pool or None if
|
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) )
|
trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
|
||||||
plug = self.bOutputPlug
|
plug = self.bOutputPlug
|
||||||
if not plug.getNet():
|
if not plug.getNet():
|
||||||
outputNetBuff = Net.create( self.spares.conf.cell,'{}_{}' \
|
outputNetBuff = Net.create( self.spares.conf.cellPnR,'{}_{}' \
|
||||||
.format(self.root.bufferTag,self.rtag) )
|
.format(self.root.bufferTag,self.rtag) )
|
||||||
plug.setNet( outputNetBuff )
|
plug.setNet( outputNetBuff )
|
||||||
trace( 540, '\t| {}\n'.format(plug) )
|
trace( 540, '\t| {}\n'.format(plug) )
|
||||||
|
@ -429,7 +443,7 @@ class QuadTree ( object ):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
if aspectRatio < 0.5:
|
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.bl = QuadTree( self.spares
|
||||||
, self
|
, self
|
||||||
, Box( self.area.getXMin()
|
, Box( self.area.getXMin()
|
||||||
|
@ -448,7 +462,7 @@ class QuadTree ( object ):
|
||||||
trace( 540, '-' )
|
trace( 540, '-' )
|
||||||
return True
|
return True
|
||||||
elif aspectRatio > 2.0:
|
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.bl = QuadTree( self.spares
|
||||||
, self
|
, self
|
||||||
, Box( self.area.getXMin()
|
, Box( self.area.getXMin()
|
||||||
|
@ -467,8 +481,8 @@ class QuadTree ( object ):
|
||||||
trace( 540, '-' )
|
trace( 540, '-' )
|
||||||
return True
|
return True
|
||||||
|
|
||||||
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.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.bl = QuadTree( self.spares
|
||||||
, self
|
, self
|
||||||
, Box( self.area.getXMin()
|
, Box( self.area.getXMin()
|
||||||
|
@ -648,6 +662,9 @@ class QuadTree ( object ):
|
||||||
position = plugOccurrence.getBoundingBox().getCenter()
|
position = plugOccurrence.getBoundingBox().getCenter()
|
||||||
self.getLeafUnder(position).plugs.append( plugOccurrence )
|
self.getLeafUnder(position).plugs.append( plugOccurrence )
|
||||||
|
|
||||||
|
def isUnderArea ( self, plugOccurrence ):
|
||||||
|
return self.area.contains( plugOccurrence.getBoundingBox().getCenter() )
|
||||||
|
|
||||||
def splitNetlist ( self ):
|
def splitNetlist ( self ):
|
||||||
"""
|
"""
|
||||||
Reorganize the netlist by connecting all plugs to the output of the
|
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.
|
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' )
|
trace( 540, ',+', '\tQuadTree.spliNetlist()\n' )
|
||||||
self.connectBuffer( doLeaf=True )
|
self.connectBuffer( doLeaf=True )
|
||||||
netBuff = self.bOutputPlug.getNet()
|
netBuff = self.bOutputPlug.getNet()
|
||||||
trace( 540, '\tBuffer: {}\n'.format(self.buffer) )
|
trace( 540, '\tBuffer: {}\n'.format(self.buffer) )
|
||||||
trace( 540, '\tBuffer output: {}\n'.format(netBuff) )
|
trace( 540, '\tBuffer output: {}\n'.format(netBuff) )
|
||||||
|
if not self.plugs: return
|
||||||
for plug in self.plugs:
|
for plug in self.plugs:
|
||||||
trace( 540, '\t| Leaf: {}\n'.format(plug) )
|
trace( 540, '\t| Leaf: {}\n'.format(plug) )
|
||||||
trace( 540, '\t| netBuff: {}\n'.format(netBuff) )
|
trace( 540, '\t| netBuff: {}\n'.format(netBuff) )
|
||||||
|
@ -743,15 +760,32 @@ class Spares ( object ):
|
||||||
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
|
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
|
||||||
return (float(bufferLength) * 1.4) / float(areaLength)
|
return (float(bufferLength) * 1.4) / float(areaLength)
|
||||||
|
|
||||||
def toXGCellGrid ( self, x ):
|
def toXPitch ( self, x ):
|
||||||
"""Find the nearest X (inferior) on the Cell gauge grid (sliceStep)."""
|
"""
|
||||||
dx = x - self.conf.xMin
|
Returns the coordinate of the pitch immediately inferior to X.
|
||||||
return self.conf.xMin + (dx - dx % self.conf.sliceStep)
|
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 toYGCellGrid ( self, y ):
|
def toYSlice ( self, y ):
|
||||||
"""Find the nearest Y (inferior) on the Cell gauge grid (sliceHeight)."""
|
"""
|
||||||
dy = y - self.conf.yMin
|
Returns the coordinate of the slice immediately inferior to Y.
|
||||||
return self.conf.yMin + (dy - dy % self.conf.sliceHeight)
|
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 ):
|
def build ( self ):
|
||||||
if not self.conf.useSpares: return
|
if not self.conf.useSpares: return
|
||||||
|
@ -773,8 +807,8 @@ class Spares ( object ):
|
||||||
trace( 540, ',+', '\tSpares.addStrayBuffer()\n' )
|
trace( 540, ',+', '\tSpares.addStrayBuffer()\n' )
|
||||||
|
|
||||||
sliceHeight = self.conf.sliceHeight
|
sliceHeight = self.conf.sliceHeight
|
||||||
x = self.quadTree.onXPitch( position.getX() )
|
x = self.quadTree.toXPitch( position.getX() )
|
||||||
y = self.quadTree.onYSlice( position.getY() )
|
y = self.quadTree.toYSlice( position.getY() )
|
||||||
slice = y / sliceHeight
|
slice = y / sliceHeight
|
||||||
orientation = Transformation.Orientation.ID
|
orientation = Transformation.Orientation.ID
|
||||||
y = slice * sliceHeight
|
y = slice * sliceHeight
|
||||||
|
@ -845,6 +879,7 @@ class Spares ( object ):
|
||||||
*plug master net* and the *tail path*.
|
*plug master net* and the *tail path*.
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
trace( 540, '\tSpares.raddTransNet() top:{} path:{}\n'.format(topNet,path) )
|
||||||
if path.isEmpty():
|
if path.isEmpty():
|
||||||
self.addClonedCell( topNet.getCell() )
|
self.addClonedCell( topNet.getCell() )
|
||||||
return None
|
return None
|
||||||
|
@ -853,6 +888,7 @@ class Spares ( object ):
|
||||||
headPlug = utils.getPlugByNet(headInstance,topNet)
|
headPlug = utils.getPlugByNet(headInstance,topNet)
|
||||||
if not headPlug:
|
if not headPlug:
|
||||||
masterCell = headInstance.getMasterCell()
|
masterCell = headInstance.getMasterCell()
|
||||||
|
trace( 540, '\tcreate Plug in {}\n'.format(headInstance) )
|
||||||
masterNet = Net.create( masterCell, topNet.getName() )
|
masterNet = Net.create( masterCell, topNet.getName() )
|
||||||
masterNet.setExternal ( True )
|
masterNet.setExternal ( True )
|
||||||
masterNet.setType ( topNet.getType() )
|
masterNet.setType ( topNet.getType() )
|
||||||
|
@ -866,9 +902,14 @@ class Spares ( object ):
|
||||||
self.addClonedCell( headInstance.getCell() )
|
self.addClonedCell( headInstance.getCell() )
|
||||||
else:
|
else:
|
||||||
masterNet = headPlug.getMasterNet()
|
masterNet = headPlug.getMasterNet()
|
||||||
|
trace( 540, '\ttailPath {}\n'.format(tailPath) )
|
||||||
if tailPath.isEmpty(): return headPlug
|
if tailPath.isEmpty(): return headPlug
|
||||||
return self.raddTransNet( masterNet, tailPath )
|
return self.raddTransNet( masterNet, tailPath )
|
||||||
|
|
||||||
|
def removeUnusedBuffers ( self ):
|
||||||
|
with UpdateSession():
|
||||||
|
self.quadTree.removeUnusedBuffers()
|
||||||
|
|
||||||
def rsave ( self, cell ):
|
def rsave ( self, cell ):
|
||||||
"""
|
"""
|
||||||
Save the complete cell hierarchy. Saves only the physical view, except
|
Save the complete cell hierarchy. Saves only the physical view, except
|
||||||
|
@ -896,5 +937,7 @@ class Spares ( object ):
|
||||||
for cell in self.cloneds:
|
for cell in self.cloneds:
|
||||||
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
|
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
|
||||||
cell.setName( cell.getName()+'_cts' )
|
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 )
|
self.rsave( self.conf.cell )
|
||||||
return
|
return
|
||||||
|
|
|
@ -148,6 +148,8 @@ class Chip ( Block ):
|
||||||
if not self.conf.validated:
|
if not self.conf.validated:
|
||||||
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
|
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
|
||||||
super(Chip,self).save()
|
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 = CRL.AllianceFramework.get()
|
||||||
af.saveCell( self.conf.corona, CRL.Catalog.State.Views )
|
af.saveCell( self.conf.corona, CRL.Catalog.State.Views )
|
||||||
af.saveCell( self.conf.chip , CRL.Catalog.State.Views )
|
af.saveCell( self.conf.chip , CRL.Catalog.State.Views )
|
||||||
|
|
|
@ -158,7 +158,7 @@ class ChipConf ( BlockConf ):
|
||||||
#self.checkPads()
|
#self.checkPads()
|
||||||
#self.checkCorona()
|
#self.checkCorona()
|
||||||
#self.computeChipSize()
|
#self.computeChipSize()
|
||||||
#self.checkChipSize()
|
self.checkChipSize()
|
||||||
self.findPowerAndClockNets()
|
self.findPowerAndClockNets()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -577,6 +577,22 @@ class ChipConf ( BlockConf ):
|
||||||
return
|
return
|
||||||
|
|
||||||
def checkChipSize ( self ):
|
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
|
#if self._coreSize.isEmpty(): return
|
||||||
#
|
#
|
||||||
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
|
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
|
||||||
|
|
|
@ -488,6 +488,8 @@ class Builder ( object ):
|
||||||
def __init__ ( self, block ):
|
def __init__ ( self, block ):
|
||||||
self.block = block
|
self.block = block
|
||||||
self.innerBb = self.block.bb
|
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.block.path.getTransformation().applyOn( self.innerBb )
|
||||||
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
|
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
|
||||||
self.southSide = SouthSide( self )
|
self.southSide = SouthSide( self )
|
||||||
|
|
|
@ -180,7 +180,7 @@ class Builder ( object ):
|
||||||
def __init__ ( self, conf ):
|
def __init__ ( self, conf ):
|
||||||
self.conf = conf
|
self.conf = conf
|
||||||
self.path = Path( self.conf.icore )
|
self.path = Path( self.conf.icore )
|
||||||
self.block = self.path.getTailInstance().getMasterCell()
|
self.block = self.conf.icore.getMasterCell()
|
||||||
self.bb = self.block.getAbutmentBox()
|
self.bb = self.block.getAbutmentBox()
|
||||||
self.planes = {}
|
self.planes = {}
|
||||||
self.activePlane = None
|
self.activePlane = None
|
||||||
|
@ -211,27 +211,30 @@ class Builder ( object ):
|
||||||
raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' )
|
raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' )
|
||||||
return
|
return
|
||||||
blockCk = None
|
blockCk = None
|
||||||
for plug in self.path.getTailInstance().getPlugs():
|
for plug in self.conf.icore.getPlugs():
|
||||||
if plug.getNet() == self.conf.coronaCk:
|
if plug.getNet() == self.conf.coronaCk:
|
||||||
blockCk = plug.getMasterNet()
|
blockCk = plug.getMasterNet()
|
||||||
if not blockCk:
|
if not blockCk:
|
||||||
raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \
|
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
|
return
|
||||||
htPlugs = []
|
htPlugs = []
|
||||||
ffPlugs = []
|
for plug in self.conf.coronaCk.getPlugs():
|
||||||
for plug in blockCk.getPlugs():
|
print( plug )
|
||||||
if not plug.getInstance().isTerminalNetlist(): continue
|
if plug.getInstance().isTerminalNetlist():
|
||||||
htPlugs.append( plug )
|
htPlugs.append( plug )
|
||||||
if len(htPlugs) != 1:
|
if len(htPlugs) != 1:
|
||||||
message = 'Clock "{}" of block "{}" is not organized as a H-Tree.' \
|
message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \
|
||||||
.format(blockCk.getName(),self.path.getTailInstance().getName())
|
.format( self.conf.coronaCk.getName()
|
||||||
|
, self.conf.icore.getName()
|
||||||
|
, len(htPlugs)) ]
|
||||||
|
print( self.conf.icore )
|
||||||
for plug in htPlugs:
|
for plug in htPlugs:
|
||||||
message += '\n - {}'.format(plug)
|
message += [ '\n - {} {}'.format(plug,plug.getInstance()) ]
|
||||||
raise ErrorMessage( 1, message )
|
raise ErrorMessage( 1, message )
|
||||||
return
|
return
|
||||||
with UpdateSession():
|
with UpdateSession():
|
||||||
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], self.path)
|
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path())
|
||||||
, self.conf.coronaCk
|
, self.conf.coronaCk
|
||||||
, 0 )
|
, 0 )
|
||||||
blockAb = self.block.getAbutmentBox()
|
blockAb = self.block.getAbutmentBox()
|
||||||
|
|
|
@ -248,8 +248,8 @@ class IoPad ( object ):
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def pads ( self ):
|
def pads ( self ):
|
||||||
print( self.ioPadConf )
|
print( self.ioPadConf )
|
||||||
return self.ioPadConf.pads
|
return self.ioPadConf.pads
|
||||||
|
|
||||||
def __str__ ( self ):
|
def __str__ ( self ):
|
||||||
s = '<IoPad "{}" '.format(self.padInstanceName)
|
s = '<IoPad "{}" '.format(self.padInstanceName)
|
||||||
|
|
Loading…
Reference in New Issue