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:
Jean-Paul Chaput 2020-10-23 22:28:42 +02:00
parent e6e667c6c7
commit b9f2a5bf28
9 changed files with 206 additions and 65 deletions

View File

@ -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()

View File

@ -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) )

View File

@ -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 ]

View File

@ -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

View File

@ -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 )

View File

@ -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

View File

@ -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 )

View File

@ -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()

View File

@ -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)