Port of the chip P&R plugins into Alpha.

Note: The port is not complete. Integration of LKCL patches will
      follow shortly.

* Change: In cumulus/plugins/alpha/block, more simple inheritance
    scheme. Use classic inheritance instead of @classdecorator.
    BlockConf (renamed from BlockState) now inherit from GaugeConf,
    Double inheritance tree, for Block/Chip and BlockConf/ChipConf.
    Allow an uniform syntax for configuration parameters.
* New: In cumulus/plugins/alpha/chip, port of the chip plugin and
    integrate with the block plugin. It is now a derived class of
    Block. ChipConf is also a derived from BlockConf.
      Obsolete "./coriolis2/ioring.py", all informations are given
    though the ChipConf state class.
* New: In cumulus/plugins/alpha/core2chip, only Alliance/pxlib is
    ported yet.
This commit is contained in:
Jean-Paul Chaput 2020-10-14 15:26:46 +02:00
parent 0a5fbd9ff0
commit 3d33c4e66a
17 changed files with 3193 additions and 278 deletions

View File

@ -61,6 +61,13 @@
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py
)
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/power.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/corona.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/pads.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/chip.py
)
install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins )
@ -70,4 +77,5 @@
install ( FILES ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha )
install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block )
install ( FILES ${pyPluginAlphaC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/core2chip )
install ( FILES ${pyPluginAlphaChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/chip )
#install ( PROGRAMS ${pyTools} DESTINATION bin )

View File

@ -56,7 +56,8 @@ from alpha.block.clocktree import ClockTree
#from alpha.block.hfns2 import BufferTree
from alpha.block.hfns3 import BufferTree
from alpha.block.configuration import IoPin
from alpha.block.configuration import BlockState
from alpha.block.configuration import BlockConf
from alpha.block.configuration import GaugeConf
timing.staticInit()
@ -70,8 +71,8 @@ class Side ( object ):
and perform pins creation & placement.
"""
def __init__ ( self, state, side ):
self.state = state
def __init__ ( self, conf, side ):
self.conf = conf
self.side = side
self.pinSpecs = []
self.expandPins = True
@ -99,25 +100,25 @@ class Side ( object ):
box has been setup.
"""
if self.side & IoPin.WEST:
self.gauge = self.state.gaugeConf.hDeepRG
self.ubegin = self.state.yMin
self.uend = self.state.yMax
self.sidePos = self.state.xMin
self.gauge = self.conf.hDeepRG
self.ubegin = self.conf.yMin
self.uend = self.conf.yMax
self.sidePos = self.conf.xMin
elif self.side & IoPin.EAST:
self.gauge = self.state.gaugeConf.hDeepRG
self.ubegin = self.state.yMin
self.uend = self.state.yMax
self.sidePos = self.state.xMax
self.gauge = self.conf.hDeepRG
self.ubegin = self.conf.yMin
self.uend = self.conf.yMax
self.sidePos = self.conf.xMax
elif self.side & IoPin.SOUTH:
self.gauge = self.state.gaugeConf.vDeepRG
self.ubegin = self.state.xMin
self.uend = self.state.xMax
self.sidePos = self.state.yMin
self.gauge = self.conf.vDeepRG
self.ubegin = self.conf.xMin
self.uend = self.conf.xMax
self.sidePos = self.conf.yMin
elif self.side & IoPin.NORTH:
self.gauge = self.state.gaugeConf.vDeepRG
self.ubegin = self.state.xMin
self.uend = self.state.xMax
self.sidePos = self.state.yMax
self.gauge = self.conf.vDeepRG
self.ubegin = self.conf.xMin
self.uend = self.conf.xMax
self.sidePos = self.conf.yMax
def getNextPinPosition ( self, flags, upos, ustep ):
"""
@ -179,26 +180,26 @@ class Side ( object ):
status = 0
if self.side & (IoPin.NORTH | IoPin.SOUTH):
gauge = self.state.gaugeConf.vDeepRG
gauge = self.conf.vDeepRG
upos = ioPin.upos
for index in ioPin.indexes:
pinName = ioPin.stem.format( index )
net = self.state.cell.getNet( pinName )
net = self.conf.cell.getNet( pinName )
if net is None:
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
continue
if net.isClock() and self.state.useClockTree:
if net.isClock() and self.conf.useClockTree:
print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) ))
continue
pinName += '.{}'.format(self.state.getIoPinsCounts(net))
pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
if pinPos.getX() > self.state.xMax or pinPos.getX() < self.state.xMin:
if pinPos.getX() > self.conf.xMax or pinPos.getX() < self.conf.xMin:
print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside north or south abutment box side.' \
.format(pinName)
, '(x:{}, xAB: [{}:{}])' \
.format( DbU.getValueString(pinPos.getX())
, DbU.getValueString(self.state.xMin)
, DbU.getValueString(self.state.xMax) ) ] ))
, DbU.getValueString(self.conf.xMin)
, DbU.getValueString(self.conf.xMax) ) ] ))
status += 1
trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
pin = Pin.create( net
@ -213,26 +214,26 @@ class Side ( object ):
)
NetExternalComponents.setExternal( pin )
self.append( pin )
self.state.incIoPinsCounts( net )
self.conf.incIoPinsCounts( net )
if upos: upos += ioPin.ustep
else:
gauge = self.state.gaugeConf.hDeepRG
gauge = self.conf.hDeepRG
upos = ioPin.upos
for index in ioPin.indexes:
pinName = ioPin.stem.format(index)
net = self.state.cell.getNet( pinName )
net = self.conf.cell.getNet( pinName )
if net is None:
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
continue
pinName += '.{}'.format(self.state.getIoPinsCounts(net))
pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
if pinPos.getY() > self.state.yMax or pinPos.getY() < self.state.yMin:
if pinPos.getY() > self.conf.yMax or pinPos.getY() < self.conf.yMin:
print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside east or west abutment box side.' \
.format(pinName)
, '(y:{}, yAB: [{}:{}])' \
.format( DbU.getValueString(pinPos.getY())
, DbU.getValueString(self.state.yMin)
, DbU.getValueString(self.state.yMax)) ] ))
, DbU.getValueString(self.conf.yMin)
, DbU.getValueString(self.conf.yMax)) ] ))
status += 1
trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
pin = Pin.create( net
@ -247,7 +248,7 @@ class Side ( object ):
)
NetExternalComponents.setExternal( pin )
self.append( pin )
self.state.incIoPinsCounts( net )
self.conf.incIoPinsCounts( net )
if upos: upos += ioPin.ustep
return status
@ -257,7 +258,7 @@ class Side ( object ):
of the abutment box. THey will stick out for one pitch.
"""
if not self.expandPins: return
rg = self.state.gaugeConf.routingGauge
rg = self.conf.routingGauge
for pinsAtPos in self.pins.values():
for pin in pinsAtPos:
for lg in rg.getLayerGauges():
@ -285,7 +286,7 @@ class Side ( object ):
for pin in self.pins[upos][1:]:
pinNames += ', ' + pin.getName()
print( ErrorMessage( 1, [ 'Side.checkOverlap(): On {} side of block "{}", {} pins ovelaps.' \
.format(sideName,self.state.cell.getName(),count)
.format(sideName,self.conf.cell.getName(),count)
, '(@{}: {})' \
.format(DbU.getValueString(upos),pinNames) ] ) )
@ -308,34 +309,31 @@ class Block ( object ):
if Block.LUT.has_key(cell): return Block.LUT[cell]
return None
@staticmethod
def create ( cell, ioPins=[], ioPads=[] ):
"""Create a Block and it's configuration object."""
block = Block( BlockState( cell, ioPins, ioPads ) )
Block.LUT[ cell ] = block
return block
def __init__ ( self, state ):
"""Not to be used directly, please see Block.create()."""
def __init__ ( self, conf ):
"""
Create a Block object. The only parameter ``conf`` must be a BlockConf
object which contains the complete block configuration.
"""
self.flags = 0
self.state = state
self.conf = conf
self.spares = Spares( self )
self.clockTrees = []
self.hfnTrees = []
self.blockInstances = []
self.sides = { IoPin.WEST : Side( self.state, IoPin.WEST )
, IoPin.EAST : Side( self.state, IoPin.EAST )
, IoPin.SOUTH : Side( self.state, IoPin.SOUTH )
, IoPin.NORTH : Side( self.state, IoPin.NORTH )
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
, IoPin.EAST : Side( self.conf, IoPin.EAST )
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
, IoPin.NORTH : Side( self.conf, IoPin.NORTH )
}
if not self.state.cell.getAbutmentBox().isEmpty():
if not self.conf.cell.getAbutmentBox().isEmpty():
print( ' o Block "{}" is already done, reusing layout.' \
.format(self.state.cell.getName()) )
self.state.cell.setTerminalNetlist( True )
self.state.isBuilt = True
.format(self.conf.cell.getName()) )
self.conf.cell.setTerminalNetlist( True )
self.conf.isBuilt = True
else:
print( ' o Block "{}" will be generated.' \
.format(self.state.cell.getName()) )
.format(self.conf.cell.getName()) )
Block.LUT[ self.conf.cell ] = self
def setUnexpandPins ( self, sides ):
"""
@ -359,48 +357,57 @@ class Block ( object ):
various configuration parameters (aspect ratio, space margin, fixed
height or width, ...).
"""
if not self.state.cell.getAbutmentBox().isEmpty():
trace( 550, '\tBlockConf.setupAb() {}\n'.format(self.conf.cell) )
if not self.conf.cell.getAbutmentBox().isEmpty():
pass
elif not self.conf.coreAb.isEmpty():
self.conf.core.setAbutmentBox( self.conf.coreAb )
elif len(self.blockInstances):
with UpdateSession():
ab = Box( 0, 0, self.state.fixedWidth, self.state.fixedHeight )
self.state.cell.setAbutmentBox( ab )
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences():
ab = Box( 0, 0, self.conf.fixedWidth, self.conf.fixedHeight )
self.conf.cell.setAbutmentBox( ab )
for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
instance = occurrence.getEntity()
subCell = instance.getMasterCell()
subCell.setAbutmentBox( ab )
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences():
for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
instance = occurrence.getEntity()
instance.setTransformation( Transformation() )
for blockInstance in self.blockInstances:
blockInstance.place()
else:
sysSpaceMargin = self.state.cfg.etesian.spaceMargin
sysSpaceMargin = self.conf.cfg.etesian.spaceMargin
blockSpaceMargin = sysSpaceMargin + self.spares.getSpareSpaceMargin()
self.state.cfg.etesian.spaceMargin = blockSpaceMargin
self.state.cfg.apply()
self.conf.cfg.etesian.spaceMargin = blockSpaceMargin
self.conf.cfg.apply()
with UpdateSession():
etesian = Etesian.EtesianEngine.create( self.state.cell )
if self.state.fixedWidth: etesian.setFixedAbWidth ( self.state.fixedWidth )
if self.state.fixedHeight: etesian.setFixedAbHeight( self.state.fixedHeight )
etesian = Etesian.EtesianEngine.create( self.conf.cell )
if self.conf.fixedWidth: etesian.setFixedAbWidth ( self.conf.fixedWidth )
if self.conf.fixedHeight: etesian.setFixedAbHeight( self.conf.fixedHeight )
etesian.setDefaultAb()
etesian.destroy()
self.state.cfg.etesian.spaceMargin = sysSpaceMargin
self.state.cfg.apply()
self.conf.cfg.etesian.spaceMargin = sysSpaceMargin
self.conf.cfg.apply()
ab = self.conf.cell.getAbutmentBox()
self.conf.coreSize = (ab.getWidth(), ab.getHeight())
trace( 550, '\tSetting core ab from Cell:{}\n'.format(self.conf.coreAb) )
for side in self.sides.values(): side.setupAb()
trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) )
if self.conf.isCoreBlock:
self.conf.setupICore()
def addClockTrees ( self ):
"""Create the trunk of all the clock trees (recursive H-Tree)."""
print( ' o Building clock tree(s).' )
af = CRL.AllianceFramework.get()
clockNets = []
for net in self.state.cell.getNets():
for net in self.conf.cell.getNets():
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
if net.isClock():
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
clockNets.append( net )
if not clockNets:
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.state.cell.getName()) )
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.conf.cell.getName()) )
with UpdateSession():
for clockNet in clockNets:
print( ' - "{}".'.format(clockNet.getName()) )
@ -421,12 +428,12 @@ class Block ( object ):
"""Create the trunk of all the high fanout nets."""
print( ' o Building high fanout nets trees.' )
if self.spares:
maxSinks = timing.tech.getSinksEstimate( self.state.bufferConf.name )
maxSinks = timing.tech.getSinksEstimate( self.conf.bufferConf.name )
dots( 82
, ' - Max sinks for buffer "{}"'.format(self.state.bufferConf.name)
, ' - Max sinks for buffer "{}"'.format(self.conf.bufferConf.name)
, ' {}'.format(maxSinks) )
nets = []
for net in self.state.cell.getNets():
for net in self.conf.cell.getNets():
sinksCount = 0
for rp in net.getRoutingPads(): sinksCount += 1
if sinksCount > maxSinks:
@ -459,7 +466,7 @@ class Block ( object ):
"""
faileds = 0
with UpdateSession():
for ioPin in self.state.ioPins:
for ioPin in self.conf.ioPins:
if ioPin.flags & IoPin.SOUTH: side = self.sides[IoPin.SOUTH]
elif ioPin.flags & IoPin.NORTH: side = self.sides[IoPin.NORTH]
elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ]
@ -467,7 +474,7 @@ class Block ( object ):
faileds += side.place( ioPin )
if faileds:
raise ErrorMessage( 3, 'Block.placeIoPins(): Cell "{}" has {} badly placed pins.' \
.format(self.state.cell.getName(),faileds) )
.format(self.conf.cell.getName(),faileds) )
def checkIoPins ( self ):
"""
@ -475,7 +482,7 @@ class Block ( object ):
"""
for side in self.sides.values():
side.checkOverlaps()
for net in self.state.cell.getNets():
for net in self.conf.cell.getNets():
if not net.isExternal(): continue
if net.isSupply(): continue
hasPins = False
@ -496,12 +503,17 @@ class Block ( object ):
side.expand()
def place ( self ):
etesian = Etesian.EtesianEngine.create( self.state.cell )
if self.conf.isCoreBlock:
etesian = Etesian.EtesianEngine.create( self.conf.corona )
etesian.setBlock( self.conf.icore )
else:
etesian = Etesian.EtesianEngine.create( self.conf.cell )
etesian.place()
etesian.destroy()
def route ( self ):
katana = Katana.KatanaEngine.create( self.state.cell )
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
katana = Katana.KatanaEngine.create( routedCell )
#katana.printConfiguration ()
katana.digitalInit ()
#katana.runNegociatePreRouted()
@ -519,9 +531,9 @@ class Block ( object ):
def addBlockages ( self ):
with UpdateSession():
net = self.state.cell.getNet( 'blockagenet' )
ab = self.state.cell.getAbutmentBox()
rg = self.state.gaugeConf.routingGauge
net = self.conf.cell.getNet( 'blockagenet' )
ab = self.conf.cell.getAbutmentBox()
rg = self.conf.routingGauge
for lg in rg.getLayerGauges():
if lg.getType() == RoutingLayerGauge.PinOnly: continue
blockage = lg.getBlockageLayer()
@ -545,44 +557,46 @@ class Block ( object ):
, ab.getYMax() - dyBorder
)
def build ( self ):
def doPnR ( self ):
"""
Perform all the steps required to build the layout of the block.
The first step is to build all the blockInstance it depends upon,
so they will appear as ``NetListTerminal`` and we can place them
in their parent cell.
"""
editor = self.state.editor
print( ' o Builing block "{}".'.format(self.state.cell.getName()) )
editor = self.conf.editor
print( ' o Builing block "{}".'.format(self.conf.cell.getName()) )
for blockInstance in self.blockInstances:
blockInstance.block.state.editor = editor
if not blockInstance.block.state.isBuilt:
blockInstance.block.conf.editor = editor
if not blockInstance.block.conf.isBuilt:
print( ' - Build sub-block "{}".' \
.format(blockInstance.block.state.cell.getName()) )
.format(blockInstance.block.conf.cell.getName()) )
blockInstance.block.build()
if editor: editor.setCell( self.state.cell )
self.state.cfg.apply()
if editor: editor.setCell( self.conf.cell )
self.conf.cfg.apply()
iteration = -1
while True:
iteration += 1
if iteration > 0: break
self.setupAb()
self.placeIoPins()
self.checkIoPins()
if not self.conf.isCoreBlock:
self.placeIoPins()
self.checkIoPins()
self.spares.build()
if self.state.useClockTree: self.addClockTrees()
if self.conf.useClockTree: self.addClockTrees()
self.addHfnBuffers()
if editor: editor.fit()
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
self.place()
self.findHfnTrees()
break
if self.state.useClockTree: self.splitClocks()
if self.conf.useClockTree: self.splitClocks()
if self.conf.isCoreBlock: self.doConnectCore()
status = self.route()
self.addBlockages()
self.expandIoPins()
self.state.isBuilt = True
plugins.rsave.rsave( self.state.cell )
if not self.conf.isCoreBlock:
self.addBlockages()
self.expandIoPins()
self.conf.isBuilt = True
return status
def useBlockInstance ( self, instancePathName , transf ):
@ -602,7 +616,7 @@ class Block ( object ):
iNames = instancePathName.split('.')
path = Path()
for iName in iNames:
if path.isEmpty(): parentCell = self.state.cell
if path.isEmpty(): parentCell = self.conf.cell
else: parentCell = path.getTailInstance().getMasterCell()
instance = parentCell.getInstance( iName )
if not instance:
@ -620,6 +634,11 @@ class Block ( object ):
return
blockIns = BlockInstance( tailInstance, transf )
self.blockInstances.append( blockIns )
def save ( self ):
if not self.conf.validated:
raise ErrorMessage( 1, 'block.save(): Chip is not valid, aborting.' )
self.spares.save()
# ----------------------------------------------------------------------------

View File

@ -42,7 +42,7 @@ from helpers.io import WarningMessage
from helpers.io import catch
from helpers.overlay import UpdateSession
from plugins import getParameter
from plugins import utils
from plugins.alpha import utils
from plugins.alpha.block.configuration import GaugeConf
from plugins.alpha.block.spares import Spares
@ -97,11 +97,10 @@ class ClockTree ( object ):
trace( 550, '-' )
return False
gaugeConf = self.spares.state.gaugeConf
bufferConf = self.spares.state.bufferConf
gaugeConf = self.spares.conf
bufferConf = self.spares.conf.bufferConf
ckNet = qt.bOutputPlug.getNet()
self.subNets.append( ckNet )
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet )
@ -110,7 +109,6 @@ class ClockTree ( object ):
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 )
leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 )
rightSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightSourceContact.getX(), 0 )
@ -119,26 +117,22 @@ class ClockTree ( object ):
rightX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightContact.getX(), 0 )
tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 )
blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 )
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
gaugeConf.setStackPosition( tlContact, leftX, tlY )
gaugeConf.setStackPosition( blContact, leftX, blY )
gaugeConf.setStackPosition( trContact, rightX, tlY )
gaugeConf.setStackPosition( brContact, rightX, blY )
leftContact .setX( leftX )
leftContact .setY( leftSourceY )
rightContact.setX( rightX )
rightContact.setY( rightSourceY )
gaugeConf.createHorizontal( leftContact , leftSourceContact, leftSourceY , 0 )
gaugeConf.createHorizontal( rightSourceContact, rightContact , rightSourceY, 0 )
gaugeConf.createVertical ( leftContact , blContact , leftX , 0 )
gaugeConf.createVertical ( tlContact , leftContact , leftX , 0 )
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
if qt.isRoot():
ckNet = self.clockNet
trace( 550, '\tRemoving any previous pin...\n' )
@ -147,24 +141,23 @@ class ClockTree ( object ):
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 )
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
rootPin = Pin.create( ckNet
, ckNet.getName()+'.0'
, Pin.Direction.NORTH
, Pin.PlacementStatus.FIXED
, layerGauge.getLayer()
, x
, qt.area.getYMax()
, layerGauge.getViaWidth()
, layerGauge.getViaWidth()
)
gaugeConf.setStackPosition( rootContact, x, y )
gaugeConf.createVertical( rootContact, rootPin, x, 0 )
if not self.spares.conf.isCoreBlock:
layerGauge = gaugeConf.vRoutingGauge
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
rootPin = Pin.create( ckNet
, ckNet.getName()+'.0'
, Pin.Direction.NORTH
, Pin.PlacementStatus.FIXED
, layerGauge.getLayer()
, x
, qt.area.getYMax()
, layerGauge.getViaWidth()
, layerGauge.getViaWidth()
)
gaugeConf.setStackPosition( rootContact, x, y )
gaugeConf.createVertical( rootContact, rootPin, x, 0 )
for leaf in qt.leafs:
self._rrouteHTree( leaf )
trace( 550, '-' )
@ -189,6 +182,7 @@ class ClockTree ( object ):
Disconnect the registers from the main clock and reconnect them to
the leaf buffers of the clock tree.
"""
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree
quadTree.bufferTag = self.clockNet.getName()
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
@ -197,3 +191,10 @@ class ClockTree ( object ):
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
quadTree.attachToLeaf( 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()) )
for plug in self.clockNet.getPlugs():
trace( 550, '\t| {}\n'.format(plug) )

View File

@ -12,6 +12,7 @@
# | Python : "./plugins/block/configuration.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
import sys
import re
import os.path
@ -36,6 +37,7 @@ from Hurricane import Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace, l, u, n
from helpers.utils import classdecorator
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.io import catch
@ -128,8 +130,8 @@ class GaugeConf ( object ):
self.topLayerDepth = layerGauge.getDepth()
break
if not self.topLayerDepth:
print WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \
.format(self._routingGauge.getDepth()) )
print( WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \
.format(self._routingGauge.getDepth()) ))
self._topLayerDepth = self._routingGauge.getDepth() - 1
self.horizontalDepth = -1
@ -157,10 +159,11 @@ class GaugeConf ( object ):
return
def _loadIoPadGauge ( self, ioPadGaugeName ):
trace( 550, ',+', '\tGaugeConf._loadIoPadGauge(): "{}".\n'.format(ioPadGaugeName) )
self._ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName )
if not self._ioPadGauge:
print WarningMessage( 'IO pad gauge "%s" not found.' % ioPadGaugeName )
return
print( WarningMessage( 'IO pad gauge "{}" not found.'.format(ioPadGaugeName) ))
trace( 550, '-' )
def isHorizontal ( self, layer ):
mask = layer.getMask()
@ -169,8 +172,8 @@ class GaugeConf ( object ):
if lg.getDirection() == RoutingLayerGauge.Horizontal: return True
return False
print ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "%s" is not part of gauge "%s", cannot know preferred direction.' \
% (layer.getName(), self._routingGauge.getName()) )
print( ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "{}" is not part of gauge "{}", cannot know preferred direction.' \
.format(layer.getName(), self._routingGauge.getName()) ))
return False
def isVertical ( self, layer ): return not self.isHorizontal( layer )
@ -310,7 +313,7 @@ class GaugeConf ( object ):
trace( 550, '-' )
return contact1
def rpByOccurrence ( self, occurrence, net ):
plug = occurrence.getEntity()
if self._plugToRp.has_key(plug):
@ -327,7 +330,7 @@ class GaugeConf ( object ):
else:
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
self._plugToRp[plug] = rp
return self.rpAccess( self._rpByOccurrence(occurrence,net), flags )
return self.rpAccess( self.rpByOccurrence(occurrence,net), flags )
def rpByPlug ( self, plug, net ):
if self._plugToRp.has_key(plug):
@ -356,7 +359,7 @@ class GaugeConf ( object ):
segment = component
count += 1
if count > 1:
message = [ 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count)
message = [ 'GaugeConf::setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count)
, '+ {}'.format(topContact) ]
for component in topContact.getSlaveComponents():
message.append( '| {}'.format(component) )
@ -434,8 +437,8 @@ class IoPadConf ( object ):
self.flags = 0
self.index = None
self._datas = list( datas )
while len(self._datas) < 7:
self._datas.append( None )
if len(self._datas) == 5: self._datas += [ None, None ]
elif len(self._datas) == 6: self._datas.insert( 5, None )
self._datas.append( [] )
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
m = reSpecialPads.match( self.instanceName )
@ -447,6 +450,7 @@ class IoPadConf ( object ):
else:
if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR
elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE
trace( 550, '\tIoPadConf._datas: {}\n'.format(self._datas) )
@property
def side ( self ): return self._datas[0]
@ -482,7 +486,7 @@ class IoPadConf ( object ):
def coreClockNetName ( self ): return self._datas[5]
@property
def nets ( self ): return self._datas[4:6]
def nets ( self ): return self._datas[4:7]
@property
def pads ( self ): return self._datas[7]
@ -494,9 +498,11 @@ class IoPadConf ( object ):
def isBidir ( self ): return self.flags & IoPadConf.BIDIR
def __repr__ ( self ):
s = '<IoPadConf %s pad:{} from:{}'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
s = '<IoPadConf {} pad:{} from:{}'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
if self.isBidir():
s += ' to:{} en:{}'.format(self.toCoreNetName,self.enableNetName)
if self.isTristate():
s += ' en:{}'.format(self.enableNetName)
s += '>'
return s
@ -510,7 +516,8 @@ class ChipConf ( object ):
sizes mostly.
"""
def __init__ ( self ):
def __init__ ( self, blockConf ):
self.blockConf = blockConf
self.name = 'chip'
self.ioPadGauge = None
self.padInstances = []
@ -519,15 +526,20 @@ class ChipConf ( object ):
self.eastPads = []
self.westPads = []
def __setattr__ ( self, attr, value ):
object.__setattr__( self, attr, value )
if attr == 'ioPadGauge' and value is not None:
self.blockConf._loadIoPadGauge( value )
def addIoPad ( self, spec, specNb ):
"""
Add an I/O pad specification. The spec argument must be of the form:
"""
ioPadConf = IoPadConf( spec )
if spec[0] & IoPin.SOUTH: self.southPads.append( spec[1] )
elif spec[0] & IoPin.NORTH: self.northPads.append( spec[1] )
elif spec[0] & IoPin.EAST: self.eastPads .append( spec[1] )
elif spec[0] & IoPin.WEST: self.westPads .append( spec[1] )
if spec[0] & IoPin.SOUTH: self.southPads.append( ioPadConf )
elif spec[0] & IoPin.NORTH: self.northPads.append( ioPadConf )
elif spec[0] & IoPin.EAST: self.eastPads .append( ioPadConf )
elif spec[0] & IoPin.WEST: self.westPads .append( ioPadConf )
else:
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf)
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
@ -666,18 +678,18 @@ class IoPin ( object ):
# else:
# indexes = self.count
# if self.flags & (IoPin.NORTH | IoPin.SOUTH):
# gauge = block.state.gaugeConf.vDeepRG
# gauge = block.conf.gaugeConf.vDeepRG
# for index in indexes:
# pinName = self.stem.format(index)
# net = block.state.cell.getNet( pinName )
# net = block.conf.cell.getNet( pinName )
# if net is None:
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
# continue
# pinName += '.{}'.format(block.state.getIoPinsCounts(net))
# pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep )
# if pinPos.getX() > block.state.xMax or pinPos.getX() < block.state.xMin:
# if pinPos.getX() > block.conf.xMax or pinPos.getX() < block.conf.xMin:
# print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside north or south abutment box side.'.format(pinName)
# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.state.xMax)) ] ))
# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.conf.xMax)) ] ))
# status += 1
# trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
# pin = Pin.create( net
@ -692,21 +704,21 @@ class IoPin ( object ):
# )
# NetExternalComponents.setExternal( pin )
# side.append( self.flags, pin )
# block.state.incIoPinsCounts( net )
# block.conf.incIoPinsCounts( net )
# if self.upos: self.upos + self.ustep
# else:
# gauge = block.state.gaugeConf.hDeepRG
# gauge = block.conf.gaugeConf.hDeepRG
# for index in indexes:
# pinName = self.stem.format(index)
# net = block.state.cell.getNet( pinName )
# net = block.conf.cell.getNet( pinName )
# if net is None:
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
# continue
# pinName += '.{}'.format(block.state.getIoPinsCounts(net))
# pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep )
# if pinPos.getY() > block.state.yMax or pinPos.getY() < block.state.yMin:
# if pinPos.getY() > block.conf.yMax or pinPos.getY() < block.conf.yMin:
# print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside east or west abutment box side.'.format(pinName)
# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.state.yMax)) ] ))
# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.conf.yMax)) ] ))
# status += 1
# trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
# pin = Pin.create( net
@ -721,18 +733,18 @@ class IoPin ( object ):
# )
# NetExternalComponents.setExternal( pin )
# side.append( self.flags, pin )
# block.state.incIoPinsCounts( net )
# block.conf.incIoPinsCounts( net )
# if self.upos: self.upos + self.ustep
# return status
# ----------------------------------------------------------------------------
# Class : "configuration.BlockState".
# Class : "configuration.BlockConf".
class BlockState ( object ):
class BlockConf ( GaugeConf ):
"""
BlockState centralize all the configurations informations related to a
given block.
BlockConf centralize all the configurations informations related to a
given block. It must be derived/build upon a GaugeConf class.
It contains:
@ -748,15 +760,19 @@ class BlockState ( object ):
"""
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
super(BlockConf,self).__init__()
self.validated = True
self.editor = None
self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.gaugeConf = GaugeConf()
self.bufferConf = BufferInterface( self.framework )
self.chip = ChipConf()
self.chipConf = ChipConf( self )
self.bColumns = 2
self.bRows = 2
self.cell = cell
self.icore = None
self.icorona = None
self.chip = None
self.fixedWidth = None
self.fixedHeight = None
self.deltaAb = [ 0, 0, 0, 0 ]
@ -768,12 +784,14 @@ class BlockState ( object ):
for ioPinSpec in ioPins:
self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(ioPads)):
self.chip.addIoPad( ioPads[line], line )
self.chipConf.addIoPad( ioPads[line], line )
self.cfg.etesian.aspectRatio = None
self.cfg.etesian.spaceMargin = None
self.cfg.block.spareSide = None
@property
def isCoreBlock ( self ): return self.chip is not None
@property
def bufferWidth ( self ): return self.bufferConf.width
@ -792,8 +810,38 @@ class BlockState ( object ):
@property
def yMax ( self ): return self.cell.getAbutmentBox().getYMax()
@property
def coreAb ( self ):
if not hasattr(self,'coreSize'): return Box()
trace( 550, '\tcoreAb:[{} {}]\n'.format( DbU.getValueString(self.coreSize[0])
, DbU.getValueString(self.coreSize[1]) ))
return Box( 0, 0, self.coreSize[0], self.coreSize[1] )
@property
def coronaAb ( self ):
if self.corona is None: return Box()
return self.corona.getAbutmentBox()
@property
def chipAb ( self ):
if not hasattr(self,'chipSize'): return Box()
return Box( 0, 0, self.chipSize[0], self.chipSize[1] )
@property
def corona ( self ): return self.icorona.getMasterCell()
@property
def core ( self ): return self.cell
def setEditor ( self, editor ): self.editor = editor
def refresh ( self, cell=None ):
if not self.editor: return
if cell is not None:
if cell != self.editor.getCell():
self.editor.setCell( cell )
self.editor.fit()
def createBuffer ( self ):
return self.bufferConf.createBuffer( self.cell )

View File

@ -78,7 +78,7 @@ class SlicedArea ( object ):
but closest to the parent's center area (so, ideally, on the cluster's
edge).
"""
state = cluster.bufferTree.spares.state
state = cluster.bufferTree.spares.conf
self.cluster = cluster
self.rows = {}
self.iposition = None
@ -96,20 +96,20 @@ class SlicedArea ( object ):
@property
def bInputPlug ( self ):
"""The input Plug of the buffer."""
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input )
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input )
@property
def bOutputPlug ( self ):
"""The output Plug of the buffer."""
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output )
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output )
def buildSlicesUnder ( self ):
"""
UNUSED. Kept as reference example.
Rebuild slices structure under a specific area (must be small).
"""
state = self.cluster.bufferTree.spares.state
sliceHeight = state.gaugeConf.sliceHeight
state = self.cluster.bufferTree.spares.conf
sliceHeight = state.sliceHeight
cell = state.cell
cellAb = cell.getAbutmentBox()
insertArea = Box( self.cluster.getCenter() )
@ -141,7 +141,7 @@ class SlicedArea ( object ):
"""
global af
catalog = af.getCatalog()
bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width
bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width
for key in self.rows.keys():
row = self.rows[ key ]
trace( 550, '\t+ Row:\n' )
@ -189,9 +189,9 @@ class SlicedArea ( object ):
"""
if self.iposition is None:
raise ErrorMessage( 2, 'SlicedArea.insertBuffer(): No position defined to wedge the buffer.' )
state = self.cluster.bufferTree.spares.state
state = self.cluster.bufferTree.spares.conf
catalog = af.getCatalog()
bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width
bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width
tieLength = 0
transf = None
if self.iposition[2] & SlicedArea.REPLACE:
@ -460,7 +460,7 @@ class Cluster ( object ):
def show ( self ):
"""Select the RoutingPad of the cluster in the editor."""
editor = self.bufferTree.spares.state.editor
editor = self.bufferTree.spares.conf.editor
if not editor: return False
editor.unselectAll()
editor.setCumulativeSelection( True )
@ -531,7 +531,7 @@ class BufferTree ( object ):
self.isDeepNet = True
self.clusterDepth = 0
self.clusters = [ [] ]
self.bufName = self.spares.state.bufferConf.name
self.bufName = self.spares.conf.bufferConf.name
self.netCount = 0
self.netName = self.net.getName()
self.netIndex = None
@ -570,7 +570,7 @@ class BufferTree ( object ):
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
else:
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
net = Net.create( self.spares.state.cell, subNetName )
net = Net.create( self.spares.conf.cell, subNetName )
self.netCount += 1
return net
@ -689,7 +689,7 @@ class BufferTree ( object ):
self.clusters[-1].append( Cluster(self,cluster,self.clusterDepth+1) )
#if cluster.show():
# Breakpoint.stop( 0, 'Showing cluster of {} RoutingPads'.format(cluster.size) )
editor = self.spares.state.editor
editor = self.spares.conf.editor
if editor:
editor.unselectAll()
editor.setCumulativeSelection( False )
@ -723,7 +723,7 @@ class BufferTree ( object ):
driverRpOcc = self.rpDriver.getPlugOccurrence()
topNetName = self.net.getName()
self.net.destroy()
self.net = Net.create( self.spares.state.cell, topNetName )
self.net = Net.create( self.spares.conf.cell, topNetName )
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
deepDriverNet = deepPlug.getMasterNet()
driverRpOcc.getEntity().setNet( deepDriverNet )

View File

@ -89,12 +89,12 @@ class Cluster ( object ):
@property
def bInputPlug ( self ):
"""The input Plug of the buffer."""
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.input )
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.input )
@property
def bOutputPlug ( self ):
"""The output Plug of the buffer."""
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.output )
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.output )
def createBufInputRp ( self, net ):
"""Create a RoutingPad for the buffer input Plug (terminal)."""
@ -194,7 +194,7 @@ class BufferTree ( object ):
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
else:
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
net = Net.create( self.spares.state.cell, subNetName )
net = Net.create( self.spares.conf.cell, subNetName )
self.netCount += 1
return net
@ -254,7 +254,7 @@ class BufferTree ( object ):
driverRpOcc = self.rpDriver.getPlugOccurrence()
topNetName = self.net.getName()
self.net.destroy()
self.net = Net.create( self.spares.state.cell, topNetName )
self.net = Net.create( self.spares.conf.cell, topNetName )
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
deepDriverNet = deepPlug.getMasterNet()
driverRpOcc.getEntity().setNet( deepDriverNet )

View File

@ -77,7 +77,7 @@ class SlicedArea ( object ):
but closest to the parent's center area (so, ideally, on the cluster's
edge).
"""
state = cluster.bufferTree.spares.state
state = cluster.bufferTree.spares.conf
self.cluster = cluster
if cluster.parent is None:
attractor = cluster.getCenter()
@ -93,12 +93,12 @@ class SlicedArea ( object ):
@property
def bInputPlug ( self ):
"""The input Plug of the buffer."""
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input )
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input )
@property
def bOutputPlug ( self ):
"""The output Plug of the buffer."""
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output )
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output )
# ----------------------------------------------------------------------------
@ -328,21 +328,21 @@ class Cluster ( object ):
graph.addNode( self
, driverCenter.getX()
, self.bufferTree.spares.toYGCellGrid(driverCenter.getY())
+ self.bufferTree.spares.state.gaugeConf.sliceHeight / 2
+ self.bufferTree.spares.conf.sliceHeight / 2
, rsmt.Node.Driver )
for anchor in self.mergedAnchors:
sinkCenter = anchor.bInputRp.getPosition()
graph.addNode( anchor
, sinkCenter.getX()
, self.bufferTree.spares.toYGCellGrid(sinkCenter.getY())
+ self.bufferTree.spares.state.gaugeConf.sliceHeight / 2 )
+ self.bufferTree.spares.conf.sliceHeight / 2 )
#graph.doIteratedOneSteiner()
graph.doFlute()
graph.createGRSegments()
def show ( self ):
"""Select the RoutingPad of the cluster in the editor."""
editor = self.bufferTree.spares.state.editor
editor = self.bufferTree.spares.conf.editor
if not editor: return False
editor.unselectAll()
editor.setCumulativeSelection( True )
@ -421,7 +421,7 @@ class BufferTree ( object ):
self.isDeepNet = True
self.clusterDepth = 0
self.clusters = [ [] ]
self.bufName = self.spares.state.bufferConf.name
self.bufName = self.spares.conf.bufferConf.name
self.netCount = 0
self.netName = self.net.getName()
self.netIndex = None
@ -460,7 +460,7 @@ class BufferTree ( object ):
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
else:
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
net = Net.create( self.spares.state.cell, subNetName )
net = Net.create( self.spares.conf.cell, subNetName )
self.netCount += 1
return net
@ -604,7 +604,7 @@ class BufferTree ( object ):
driverRpOcc = self.rpDriver.getPlugOccurrence()
topNetName = self.net.getName()
self.net.destroy()
self.net = Net.create( self.spares.state.cell, topNetName )
self.net = Net.create( self.spares.conf.cell, topNetName )
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
deepDriverNet = deepPlug.getMasterNet()
driverRpOcc.getEntity().setNet( deepDriverNet )

View File

@ -59,8 +59,8 @@ class BufferPool ( object ):
def __init__ ( self, quadTree ):
self.quadTree = quadTree
self.columns = quadTree.spares.state.bColumns
self.rows = quadTree.spares.state.bRows
self.columns = quadTree.spares.conf.bColumns
self.rows = quadTree.spares.conf.bRows
self.area = Box()
self.buffers = []
self.selectedIndex = None
@ -145,12 +145,12 @@ class BufferPool ( object ):
"""Create the matrix of instances buffer."""
trace( 540, ',+', '\tBufferPool.createBuffers()\n' )
state = self.quadTree.spares.state
sliceHeight = state.gaugeConf.sliceHeight
conf = self.quadTree.spares.conf
sliceHeight = conf.sliceHeight
x = self.quadTree.onXPitch( self.quadTree.area.getXCenter()
- (state.bufferConf.width * self.columns)/2 )
- (conf.bufferConf.width * self.columns)/2 )
y = self.quadTree.onYSlice( self.quadTree.area.getYCenter()
- (state.bufferConf.height * self.rows)/2 )
- (conf.bufferConf.height * self.rows)/2 )
slice = y / sliceHeight
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
@ -163,8 +163,8 @@ class BufferPool ( object ):
y += sliceHeight
for column in range(self.columns):
index = self.toIndex(column,row)
transf = Transformation( x + column*state.bufferConf.width, y, orientation )
instance = state.createBuffer()
transf = Transformation( x + column*conf.bufferConf.width, y, orientation )
instance = conf.createBuffer()
instance.setTransformation( transf )
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.buffers[ index ][1] = instance
@ -213,7 +213,7 @@ class QuadTree ( object ):
@staticmethod
def create ( spares ):
root = QuadTree( spares, None, spares.state.cell.getAbutmentBox() )
root = QuadTree( spares, None, spares.conf.cell.getAbutmentBox() )
root.rpartition()
return root
@ -277,7 +277,7 @@ class QuadTree ( object ):
catalog = framework.getCatalog()
instancesNb = 0
bufNb = 0
for occurrence in self.spares.state.cell.getTerminalNetlistInstanceOccurrences():
for occurrence in self.spares.conf.cell.getTerminalNetlistInstanceOccurrences():
cellName = occurrence.getEntity().getMasterCell().getName()
cstate = catalog.getState( cellName )
if cstate and cstate.isFeed(): continue
@ -291,10 +291,10 @@ class QuadTree ( object ):
if rtotal:
print( ' o Detailed use of spare buffers.' )
dots( 82
, ' - Useds: '
, ' - Useds '
, ' {}/{} ({:.1%})'.format(rused,rtotal,float(rused)/float(rtotal)) )
dots( 82
, ' - Buffer ratio: '
, ' - Buffer ratio '
, ' {}/{} ({:.1%})'.format( rtotal
, instancesNb+bufNb
, float(rtotal)/float(instancesNb+bufNb)) )
@ -347,21 +347,21 @@ class QuadTree ( object ):
@property
def bInputPlug ( self ):
"""The input Plug of the currently selected buffer in the pool."""
return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.input )
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.input )
@property
def bOutputPlug ( self ):
"""The output Plug of the currently selected buffer in the pool."""
return utils.getPlugByName( self.buffer, self.spares.state.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.state.gaugeConf.sliceHeight
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.state.gaugeConf.sliceStep
modulo = (x - self.area.getXMin()) % self.spares.conf.sliceStep
return x - modulo
def selectFree ( self ):
@ -382,7 +382,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.state.cell,'{}_{}' \
outputNetBuff = Net.create( self.spares.conf.cell,'{}_{}' \
.format(self.root.bufferTag,self.rtag) )
plug.setNet( outputNetBuff )
trace( 540, '\t| {}\n'.format(plug) )
@ -417,10 +417,10 @@ class QuadTree ( object ):
quad-tree, but only a vertical or horizontal bi-partition.
"""
trace( 540, ',+', '\tQuadTree.partition(): {} (spareSide:{})\n' \
.format(self.area, DbU.getValueString(self.spares.state.cfg.block.spareSide)) )
.format(self.area, DbU.getValueString(self.spares.conf.cfg.block.spareSide)) )
spareSide = self.spares.state.cfg.block.spareSide
sliceHeight = self.spares.state.gaugeConf.sliceHeight
spareSide = self.spares.conf.cfg.block.spareSide
sliceHeight = self.spares.conf.sliceHeight
side = float(spareSide)
aspectRatio = float(self.area.getWidth()) / float(self.area.getHeight())
@ -684,7 +684,7 @@ class QuadTree ( object ):
trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
plug.getEntity().setNet( deepNetBuff )
maxSinks = self.spares.state.bufferConf.maxSinks
maxSinks = self.spares.conf.bufferConf.maxSinks
if len(self.plugs) > maxSinks:
print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \
.format(maxSinks,len(self.plugs),netBuff.getName())) )
@ -713,7 +713,7 @@ class Spares ( object ):
MARK_USED = 0x00020000
def __init__ ( self, block ):
self.state = block.state
self.conf = block.conf
self.quadTree = None
self.cloneds = []
self.strayBuffers = []
@ -725,36 +725,36 @@ class Spares ( object ):
self.quadTree = None
self.cloneds = []
self.strayBuffers = []
self.state.resetBufferCount()
self.conf.resetBufferCount()
def getSpareSpaceMargin ( self ):
"""
Compute the percentage of margin space to compensate for the spare
buffers (row*columns) with a supplemental margin factor of 1.3 or 1.4.
"""
if not self.state.useSpares: return 0.0
spareSide = self.state.cfg.block.spareSide
if not self.conf.useSpares: return 0.0
spareSide = self.conf.cfg.block.spareSide
if not spareSide:
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): "block.spareSide" parameter is zero ({}).' \
.format(spareSide) )
areaLength = spareSide * spareSide / self.state.gaugeConf.sliceHeight
bufferLength = self.state.bufferConf.width * self.state.bColumns * self.state.bRows
areaLength = spareSide * spareSide / self.conf.sliceHeight
bufferLength = self.conf.bufferConf.width * self.conf.bColumns * self.conf.bRows
if not areaLength:
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
return (float(bufferLength) * 1.4) / float(areaLength)
def toXGCellGrid ( self, x ):
"""Find the nearest X (inferior) on the Cell gauge grid (sliceStep)."""
dx = x - self.state.xMin
return self.state.xMin + (dx - dx % self.state.gaugeConf.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.state.yMin
return self.state.yMin + (dy - dy % self.state.gaugeConf.sliceHeight)
dy = y - self.conf.yMin
return self.conf.yMin + (dy - dy % self.conf.sliceHeight)
def build ( self ):
if not self.state.useSpares: return
if not self.conf.useSpares: return
trace( 540, ',+', '\tSpares.build()\n' )
with UpdateSession():
self.quadTree = QuadTree.create( self )
@ -768,7 +768,7 @@ class Spares ( object ):
"""Add a new stray buffer at ``position``."""
trace( 540, ',+', '\tSpares.addStrayBuffer()\n' )
sliceHeight = self.state.gaugeConf.sliceHeight
sliceHeight = self.conf.sliceHeight
x = self.quadTree.onXPitch( position.getX() )
y = self.quadTree.onYSlice( position.getY() )
slice = y / sliceHeight
@ -778,7 +778,7 @@ class Spares ( object ):
orientation = Transformation.Orientation.MY
y += sliceHeight
transf = Transformation( x, y, orientation )
instance = self.state.createBuffer()
instance = self.conf.createBuffer()
instance.setTransformation( transf )
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
unoverlapDx = self.quadTree.getUnoverlapDx( instance.getAbutmentBox() )
@ -801,7 +801,9 @@ class Spares ( object ):
return leaf.selectFree()
def addClonedCell ( self, masterCell ):
if not masterCell in self.cloneds: self.cloneds.append( masterCell )
if not masterCell in self.cloneds:
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
self.cloneds.append( masterCell )
return
def raddTransNet ( self, topNet, path ):
@ -839,8 +841,9 @@ class Spares ( object ):
*plug master net* and the *tail path*.
"""
if path.isEmpty(): return None
if path.isEmpty():
self.addClonedCell( topNet.getCell() )
return None
tailPath = path.getTailPath()
headInstance = path.getHeadInstance()
headPlug = utils.getPlugByNet(headInstance,topNet)
@ -856,9 +859,9 @@ class Spares ( object ):
% (topNet.getName(),headInstance.getName(),masterCell.getName()) )
headPlug.setNet( topNet )
self.addClonedCell( masterCell )
self.addClonedCell( headInstance.getCell() )
else:
masterNet = headPlug.getMasterNet()
if tailPath.isEmpty(): return headPlug
return self.raddTransNet( masterNet, tailPath )
@ -880,13 +883,14 @@ class Spares ( object ):
if not masterCell.isTerminal():
self.rsave( masterCell )
def save ( self, topCell ):
def save ( self ):
"""
Frontend to Spares.rsave(). Append the "_cts" suffix to the cloned
cells, then call rsave().
"""
trace( 550,'\tSpares.save() on "{}"\n'.format(self.conf.cell.getName()) )
for cell in self.cloneds:
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
cell.setName( cell.getName()+'_cts' )
self.rsave( topCell )
self.rsave( self.conf.cell )
return

View File

@ -0,0 +1,56 @@
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2014-2018, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/__init__.py" |
# +-----------------------------------------------------------------+
"""
Define constants to be used through all "chip" plugin modules, along
with the importConstants() function to import then directly in the
dictionnary of other modules.
* For corona sides: North, South, East & West.
* For corona corners: SouthWest, SouthEast, NorthWest & NorthEast.
* For rounding operation: Superior, Inferior, Inwards,
OnHorizontalPitch & OnVerticalPitch.
"""
from __future__ import print_function
from helpers.io import WarningMessage
North = 0x0001
South = 0x0002
East = 0x0004
West = 0x0008
SouthWest = South|West
SouthEast = South|East
NorthWest = North|West
NorthEast = North|East
Superior = 0x0010
Inferior = 0x0020
Inwards = 0x0040
OnHorizontalPitch = 0x0080
OnVerticalPitch = 0x0100
def importConstants ( symbols ):
"""
Import chip module symbol constants in the another module dictionnary
(i.e. globals()).
"""
if not isinstance(symbols,dict):
print( WarningMessage( 'plugins.chip.__init__.importConstants(), argument is not a symbol table.' ))
return
for symbol in globals().items():
if isinstance(symbol[1],int) or isinstance(symbol[1],long):
if not symbols.has_key(symbol[0]):
symbols[ symbol[0] ] = symbol[1]

View File

@ -0,0 +1,153 @@
# This file is part of the Coriolis Software.
# Copyright (c) SU 2014-2020, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/chip.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
from __future__ import absolute_import
import sys
import traceback
import os.path
import optparse
import math
import cProfile
import pstats
import Cfg
import Hurricane
from Hurricane import DataBase
from Hurricane import DbU
from Hurricane import Point
from Hurricane import Transformation
from Hurricane import Box
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import UpdateSession
from Hurricane import Breakpoint
from Hurricane import Net
from Hurricane import RoutingPad
from Hurricane import Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Instance
from Hurricane import HyperNet
from Hurricane import Query
import Viewer
import CRL
from CRL import RoutingLayerGauge
import helpers
from helpers import trace
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.overlay import UpdateSession
import Etesian
import Anabatic
import Katana
import Unicorn
import plugins
import plugins.rsave
from plugins.alpha.block.block import Block
import plugins.alpha.chip.pads
import plugins.alpha.chip.power
import plugins.alpha.chip.corona
# --------------------------------------------------------------------
# Class : "chip.Chip"
class Chip ( Block ):
def __init__ ( self, conf ):
super(Chip,self).__init__( conf )
print( 'Core: {}'.format(self.conf.core) )
print( '| AB: {}'.format(self.conf.core.getAbutmentBox()) )
def validate ( self ):
self.conf.validated = True
coreAb = self.conf.core.getAbutmentBox()
if (not coreAb.isEmpty()):
if coreAb.getWidth () <= self.conf.coreAb.getWidth() \
and coreAb.getHeight() <= self.conf.coreAb.getHeight():
self.conf.coreSize = (coreAb.getWidth(), coreAb.getHeight())
else:
raise ErrorMessage( 1, [ 'Core "{}" already have an abutment box, bigger than the requested one:' \
.format(self.conf.core.getName())
, " Cell abutment box: {}".format(coreAb)
, " Maximum abutment box: {}".format(self.conf.coreAb) ] )
self.conf.validated = False
return self.conf.validated
def doCoronaFloorplan ( self ):
if not self.conf.validated:
raise ErrorMessage( 1, 'chip.doCoronaFloorplan(): Chip is not valid, aborting.' )
return
minHCorona = self.conf.minHCorona
minVCorona = self.conf.minVCorona
innerBb = Box( self.conf.coreAb )
innerBb.inflate( minHCorona, minVCorona )
coronaAb = self.conf.corona.getAbutmentBox()
if innerBb.getWidth() > coronaAb.getWidth():
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
.format( DbU.getValueString(innerBb .getWidth())
, DbU.getValueString(coronaAb.getWidth()) ) )
if innerBb.getHeight() > coronaAb.getHeight():
raise ErrorMessage( 1, 'Core is too tall to fit into the corona, needs {} but only has {}.' \
.format( DbU.getValueString(innerBb .getHeight())
, DbU.getValueString(coronaAb.getHeight()) ) )
with UpdateSession():
self.conf.core.setAbutmentBox( self.conf.coreAb )
x = (coronaAb.getWidth () - self.conf.coreAb.getWidth ()) / 2
y = (coronaAb.getHeight() - self.conf.coreAb.getHeight()) / 2
x = x - (x % self.conf.sliceHeight)
y = y - (y % self.conf.sliceHeight)
self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) )
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
def doConnectCore ( self ):
power = plugins.alpha.chip.power.Builder( self.conf )
power.connectPower()
power.connectClock()
power.doLayout()
self.conf.refresh()
corona = plugins.alpha.chip.corona.Builder( power )
corona.connectPads( self.padsCorona )
corona.connectCore()
corona.doLayout()
self.conf.refresh()
def doPnR ( self ):
self.conf.computeCoronaBorder()
self.conf.chipValidate()
if not self.conf.validated:
raise ErrorMessage( 1, 'chip.doChipPnR(): Chip is not valid, aborting.' )
self.conf.chip.setAbutmentBox( self.conf.chipAb )
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
self.padsCorona = plugins.alpha.chip.pads.Corona( self.conf )
self.conf.validated = self.padsCorona.validate()
if not self.conf.validated:
return False
self.padsCorona.doLayout()
self.validate()
self.doCoronaFloorplan()
self.conf.refresh()
super(Chip,self).doPnR()
self.conf.refresh( self.conf.chip )
return self.conf.validated
def save ( self ):
if not self.conf.validated:
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
super(Chip,self).save()
af = CRL.AllianceFramework.get()
af.saveCell( self.conf.corona, CRL.Catalog.State.Views )
af.saveCell( self.conf.chip , CRL.Catalog.State.Views )

View File

@ -0,0 +1,665 @@
# This file is part of the Coriolis Software.
# Copyright (c) SU 2014-2020, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/configuration.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
import sys
import os.path
import Cfg
from Hurricane import Breakpoint
from Hurricane import DbU
from Hurricane import Box
from Hurricane import Transformation
from Hurricane import Box
from Hurricane import Path
from Hurricane import Layer
from Hurricane import Occurrence
from Hurricane import Net
from Hurricane import RoutingPad
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Contact
from Hurricane import Pin
from Hurricane import Plug
from Hurricane import Instance
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers.utils import classdecorator
from helpers.overlay import UpdateSession
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.io import catch
from plugins import getParameter
import plugins.chip
from plugins.alpha.block.configuration import BlockConf
plugins.alpha.chip.importConstants( globals() )
# -------------------------------------------------------------------
# Class : "Configuration.ChipConf".
class ChipConf ( BlockConf ):
@staticmethod
def _toSymbolic ( u, rounding ):
"""
Pitch the coordinates ``u`` to the symbolic grid, according
to ``rounding`` (Superior or Inferior).
"""
oneLambda = DbU.fromLambda( 1.0 )
remainder = u % oneLambda
if remainder:
if rounding == Superior: u = u + (oneLambda - remainder)
else: u = u - remainder
return u
@staticmethod
def toSymbolic ( v, rounding ):
"""
Pitch the coordinates of object ``v`` to the symbolic grid,
according to ``rounding``. Were ``v`` can be:
* A scalar, then rounding is Inferior or Superior.
* A Box, then rounding is:
* Inwards: the pitched box will be fully enclosed in the
original box.
* Outwards: the pitched box will fully enclose the original
box.
"""
if isinstance(v,long): return ChipConf._toSymbolic( v, rounding )
if isinstance(v,Box):
if rounding & Inwards:
roundings = [ Superior
, Superior
, Inferior
, Inferior ]
else:
roundings = [ Inferior
, Inferior
, Superior
, Superior ]
xMin = ChipConf._toSymbolic( v.getXMin(), roundings[0] )
yMin = ChipConf._toSymbolic( v.getYMin(), roundings[1] )
xMax = ChipConf._toSymbolic( v.getXMax(), roundings[2] )
yMax = ChipConf._toSymbolic( v.getYMax(), roundings[3] )
return Box( xMin, yMin, xMax, yMax )
return v
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
trace( 550, ',+', 'ChipConf.__init__(): "{}"'.format(cell.getName()) )
print( super(ChipConf,self).__init__ )
super(ChipConf,self).__init__( cell, ioPins, ioPads )
# trace( 550, '\tONE LAMBDA = %s\n' % DbU.getValueString(DbU.fromLambda(1.0)) )
self.validated = True
# Block Corona parameters (triggers loading from disk).
self.cfg.chip.block.rails.count = None
self.cfg.chip.block.rails.hWidth = None
self.cfg.chip.block.rails.vWidth = None
self.cfg.chip.block.rails.hSpacing = None
self.cfg.chip.block.rails.vSpacing = None
self._railsCount = self.cfg.chip.block.rails.count
# Global Net names.
self.blockageName = "blockagenet"
# Global Nets.
self.coronaVdd = None
self.coronaVss = None
self.coronaCk = None
self.blockageNet = None
self.padsHavePosition = False
trace( 550, '-' )
@property
def railsCount ( self ):
return self._railsCount
@railsCount.setter
def railsCount ( self, count ):
self._railsCount = count
@property
def hRailWidth ( self ):
return self.cfg.chip.block.rails.hWidth
@property
def vRailWidth ( self ):
return self.cfg.chip.block.rails.vWidth
@property
def hRailSpace ( self ):
return self.cfg.chip.block.rails.hSpacing
@property
def vRailSpace ( self ):
return self.cfg.chip.block.rails.vSpacing
def computeCoronaBorder ( self ):
if self.useClockTree:
trace( 550, '\tcomputeCoronaBorder() useClockTree: {}\n'.format(self.useClockTree) )
self.railsCount = self.cfg.chip.block.rails.count + 1
trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) )
self.minHCorona = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace + self.sliceHeight
self.minVCorona = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace + 10*self.sliceStep
def chipValidate ( self ):
#self.checkPads()
#self.checkCorona()
#self.computeChipSize()
#self.checkChipSize()
self.findPowerAndClockNets()
return
def getInstanceAb ( self, instance ):
ab = instance.getMasterCell().getAbutmentBox()
instance.getTransformation().applyOn( ab )
if instance.getCell() == self.chip: return ab
if instance.getCell() != self.corona:
raise ErrorMessage( 1, 'ChipConf.getInstanceAb(): Instance "{}" neither belong to chip or corona.' \
.format(instance.getName()) )
return ab
self.icorona.getTransformation().applyOn( ab )
return ab
def setupICore ( self ):
"""
Setup the abutment box of the *core* master cell and position it's unique
instance (*icore*) in the center of the *corona* master cell.
"""
with UpdateSession():
trace( 550, ',+', '\tChipConf.setupICore()\n' )
ab = self.getInstanceAb( self.icorona )
if ab.isEmpty():
raise ErrorMessage( 1, 'ChipConf.setupICore(): Attempt to setup core *before* corona.' )
return
#ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
ab = self.toSymbolic( ab, Inwards )
trace( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
if self.core.getAbutmentBox().isEmpty():
if not self.coreAb.isEmpty():
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
ab = self.coreAb
else:
ab.inflate( -self.minHCorona, -self.minVCorona )
self.coreSize = (ab.getWidth(), ab.getHeight())
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) )
coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) / 2
coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) / 2
coreX = coreX - (coreX % self.sliceStep)
coreY = coreY - (coreY % self.sliceHeight)
self.icore.setTransformation( Transformation( coreX, coreY, Transformation.Orientation.ID ) )
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
trace( 550, '-' )
def getCoronaNet ( self, chipNet ):
for plug in chipNet.getPlugs():
if plug.getInstance() == self.icorona:
return plug.getMasterNet()
return None
def toRoutingGauge ( self, uMin, uMax, layer ):
trace( 550, ',+', '\ttoRoutingGauge() [{} {}] {}\n' \
.format(DbU.getValueString(uMin), DbU.getValueString(uMax), layer) )
ab = self.corona.getAbutmentBox()
lg = None
mask = layer.getMask()
for layerGauge in self.routingGauge.getLayerGauges():
if layerGauge.getLayer().getMask() == mask:
lg = layerGauge
trace( 550, '\tUsing layer gauge {}\n'.format(lg) )
break
if uMax < uMin: uMin, uMax = uMax, uMin
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
abMin = ab.getYMin()
abMax = ab.getYMax()
else:
abMin = ab.getXMin()
abMax = ab.getXMax()
if uMin <= abMin:
shiftRight = abMin - uMin + lg.getPitch()
uMin += shiftRight
uMax += shiftRight
if uMax >= abMax:
shiftLeft = uMax - abMax + lg.getPitch()
uMin -= shiftLeft
uMax -= shiftLeft
iTrackMin = lg.getTrackIndex( abMin, abMax, uMin, RoutingLayerGauge.Superior )
iTrackMax = lg.getTrackIndex( abMin, abMax, uMax, RoutingLayerGauge.Inferior )
if iTrackMax < iTrackMin: iTrackMax = iTrackMin
uTrackMin = lg.getTrackPosition( abMin, iTrackMin )
uTrackMax = lg.getTrackPosition( abMin, iTrackMax )
axis = (uTrackMax + uTrackMin) / 2
width = (iTrackMax - iTrackMin) * lg.getPitch() + lg.getWireWidth()
if self.routingGauge.isSymbolic():
oneLambda = DbU.fromLambda( 1.0 )
if axis % oneLambda:
axis -= oneLambda / 2
width -= oneLambda
trace( 550, '\t[{} {}]\n'.format(iTrackMin, iTrackMax) )
trace( 550, '\taxis: {}l {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) )
trace( 550, '\twidth: {}l {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) )
else:
axis = (uMax + uMin) / 2
width = (uMax - uMin)
trace( 550, '-' )
return axis, width
def toCoronaPitchInChip ( self, uCore, layer ):
trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {}l %s\n' \
.format(DbU.toLambda(uCore), DbU.getValueString(uCore)) )
coronaAb = self.getInstanceAb( self.icorona )
lg = None
mask = layer.getMask()
for layerGauge in self.routingGauge.getLayerGauges():
if layerGauge.getLayer().getMask() == mask:
lg = layerGauge
break
if not lg:
trace( 550, '-' )
return 0
trace( 550, '\t{}\n'.format(lg) )
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
uCorona = uCore - coronaAb.getYMin()
else:
uCorona = uCore - coronaAb.getXMin()
uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer )
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l {}\n' \
.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
if lg:
if lg.getDirection() == RoutingLayerGauge.Horizontal:
uCore = uCorona + coronaAb.getYMin()
else:
uCore = uCorona + coronaAb.getXMin()
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l %s\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
trace( 550, '\ttoCoronaPitchInChip(): uCore: {}l %s\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) )
trace( 550, '-' )
return uCore
def coronaHorizontal ( self, chipNet, layer, chipY, width, chipXMin, chipXMax ):
trace( 550, ',+', '\tChipConf.coronaHorizontal\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet ( chipNet )
if not coronaNet: return None
coronaY = chipY - coronaAb.getYMin()
dxMin = ChipConf.toSymbolic( chipXMin - coronaAb.getXMin(), Superior )
dxMax = ChipConf.toSymbolic( chipXMax - coronaAb.getXMin(), Inferior )
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaY)) )
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
trace( 550, '\t| dxMin:{} ({}l)\n' \
.format( DbU.getValueString(chipXMin - coronaAb.getXMin())
, DbU.toLambda(chipXMin - coronaAb.getXMin()) ) )
trace( 550, '\t| dxMax:{}\n'.format(DbU.getValueString(chipXMax - coronaAb.getXMin())) )
coronaY, width = self.toRoutingGauge( coronaY - width/2, coronaY + width/2, layer )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| axis: {}l or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
trace( 550, '\t| width:{}l or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
trace( 550, '\t| dxMin:{}l\n'.format(DbU.toLambda(dxMin)) )
trace( 550, '\t| dxMax:{}l\n'.format(DbU.toLambda(dxMax)) )
h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax )
trace( 550, '\t| {}\n'.format(h) )
trace( 550, '-' )
return h
def coronaVertical ( self, chipNet, layer, chipX, width, chipYMin, chipYMax ):
trace( 550, ',+', '\tChipConf.coronaVertical\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
dyMin = ChipConf.toSymbolic( chipYMin - coronaAb.getYMin(), Superior )
dyMax = ChipConf.toSymbolic( chipYMax - coronaAb.getYMin(), Inferior )
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaX)) )
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
coronaX, width = self.toRoutingGauge( coronaX - width/2, coronaX + width/2, layer )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| axis: {} or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
trace( 550, '\t| width:{} or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
v = Vertical.create( coronaNet, layer, coronaX, width, dyMin, dyMax )
trace( 550, '\t| {}\n'.format(v) )
trace( 550, '-' )
return v
def coronaContact ( self, chipNet, layer, chipX, chipY, width, height, flags=0 ):
trace( 550, ',+', '\tChipConf.coronaContact\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet,layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| center: {:>12} {:>12}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {:>12} {:>12}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
topLayer = layer.getTop()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, layer.getBottom() )
coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, topLayer )
coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, layer.getBottom() )
if not (flags & OnHorizontalPitch):
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if not (flags & OnVerticalPitch ):
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| X axis: {:>12} or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
trace( 550, '\t| Y axis: {:>12} or {:>12}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
trace( 550, '\t| center: {:>12} {:>12}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {:>12} {:>12}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
c = Contact.create( coronaNet
, layer
, coronaX
, coronaY
, width
, height
)
trace( 550, '\t| {}\n'.format(c) )
trace( 550, '-' )
return c
def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ):
trace( 550, ',+', '\tChipConf.coronaContactArray\n' )
viaPitch = layer.getMinimalSize() + layer.getMinimalSpacing()
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
topLayer = layer.getTop()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX, coronaX, layer.getBottom() )
coronaY, height = self.toRoutingGauge( coronaY, coronaY, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX, coronaX, topLayer )
coronaY, height = self.toRoutingGauge( coronaY, coronaY, layer.getBottom() )
if not (flags & OnHorizontalPitch):
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if not (flags & OnVerticalPitch ):
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
contacts = []
xContact = coronaX - viaPitch * (array[0]-1)/2
yContact = coronaY - viaPitch * (array[1]-1)/2
contactSize = layer.getMinimalSize()
trace( 550, '\txContact:{}l yContact:{}l\n'.format(DbU.toLambda(xContact),DbU.toLambda(yContact)) )
for i in range(array[0]):
for j in range(array[1]):
c = Contact.create( coronaNet
, layer
, xContact + i*viaPitch
, yContact + j*viaPitch
, contactSize
, contactSize
)
trace( 550, '\t+ {}\n'.format(c) )
contacts.append( c )
trace( 550, '-' )
return contacts
def coronaPin ( self, chipNet, count, direction, layer, chipX, chipY, width, height ):
trace( 550, ',+', '\tChipConf.coronaPin\n' )
coronaAb = self.getInstanceAb( self.icorona )
coronaNet = self.getCoronaNet( chipNet )
if not coronaNet: return None
coronaX = chipX - coronaAb.getXMin()
coronaY = chipY - coronaAb.getYMin()
trace( 550, '\t| chipNet: {} ({}) {}\n'.format(chipNet, count, layer) )
trace( 550, '\t| Real\n' )
trace( 550, '\t| center: {} {}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {} {}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
topLayer = layer.getTop()
if self.isHorizontal(topLayer):
coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, layer.getBottom() )
coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, topLayer )
else:
coronaX, width = self.toRoutingGauge( coronaX - width /2, coronaX + width /2, topLayer )
coronaY, height = self.toRoutingGauge( coronaY - height/2, coronaY + height/2, layer.getBottom() )
if direction == Pin.Direction.NORTH or direction == Pin.Direction.SOUTH:
trace( 550, '\tEast/West not on horizontal routing pitch, Y on lambda only.\n' )
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
if direction == Pin.Direction.EAST or direction == Pin.Direction.WEST:
trace( 550, '\tNorth/South not on vertical routing pitch, X on lambda only.\n' )
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
trace( 550, '\t| On Grid\n' )
trace( 550, '\t| X axis: {} or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
trace( 550, '\t| Y axis: {} or {}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
trace( 550, '\t| center: {} {}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
trace( 550, '\t| WxH: {} {}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
c = Pin.create( coronaNet
, '{}.{}'.format(coronaNet.getName(),count)
, direction
, Pin.PlacementStatus.FIXED
, layer
, coronaX
, coronaY
, width
, height
)
trace( 550, '\t| {}\n'.format(c) )
trace( 550, '-' )
return c
def checkPads ( self ):
def contains ( padList, side, padInstance ):
for i in range(len(padList)):
if padList[i][1] == padInstance.getName():
if (padInstance.getMasterCell().getAbutmentBox().getHeight() != self.ioPadHeight):
raise ErrorMessage( 1, 'The pad [{}] {} ({}) on {} side is not an instance of a pad cell.' \
.format(i,padInstance.getName(),padInstance.getMasterCell().getName(),side) )
padList[i][1] = padInstance
return True
return False
def checkNotFounds ( padList, side ):
for i in range(len(padList)):
if not isinstance(padList[i][1],Instance):
print( ErrorMessage( 1, 'The pad [{}] ({}) of list {} do not exists in netlist (skipped).'
.format(i,padList[i][1],side) ))
return
af = CRL.AllianceFramework.get()
cellPads = []
for instance in self.chip.getInstances():
if contains(self.southPads,'south',instance): continue
if contains(self.northPads,'north',instance): continue
if contains(self.eastPads ,'east' ,instance): continue
if contains(self.westPads ,'west' ,instance): continue
if (instance.getMasterCell().getAbutmentBox().getHeight() == self.ioPadHeight):
raise ErrorMessage( 1, 'Pad "{}" is not on any side (N/S/E/W).'.format(instance.getName()) )
self.validated = False
else:
self.coronas.append( instance )
checkNotFounds( self.southPads, 'south' )
checkNotFounds( self.northPads, 'north' )
checkNotFounds( self.eastPads , 'east' )
checkNotFounds( self.westPads , 'west' )
if len(self.coronas) > 1:
message = [ 'Chip "{}" have more than one corona:'.format(self.chip.getName()) ]
for i in range(len(self.coronas)):
message.append( '{}: {}'.format(i,self.coronas[i].getName()) )
raise ErrorMessage( 1, message )
self.validated = False
if len(self.coronas) < 1:
raise ErrorMessage( 1, 'Chip "{}" doesn\'t seems to have a corona.' \
.format(self.chip.getName()) )
self.validated = False
else:
for instance in self.corona.getInstances():
self.cores.append( instance )
if len(self.cores) > 1:
message = [ 'Chip "{}" have more than one core:'.format(self.chip.getName()) ]
for i in range(len(self.cores)):
message.append( '{}: {}'.format(i,self.cores[i].getName()) )
raise ErrorMessage( 1, message )
self.validated = False
if len(self.cores) < 1:
raise ErrorMessage( 1, 'Chip "{} doesn\'t seems to have a core.' \
.format(self.chip.getName()) )
self.validated = False
return
def findPowerAndClockNets ( self ):
if self.icore:
for plug in self.icore.getPlugs():
masterNet = plug.getMasterNet()
netType = masterNet.getType()
if netType != Net.Type.POWER \
and netType != Net.Type.GROUND \
and netType != Net.Type.CLOCK:
continue
net = plug.getNet()
if not net:
net = self.corona.getNet( masterNet.getName() )
if not net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Missing global net "{}" at corona level.' \
.format(asterNet.getName()) )
self._validated = False
continue
if netType == Net.Type.GROUND:
if self.coronaVss and self.coronaVss != net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple ground nets "{}" and "{}" at corona level.' \
.format(self.coronaVss.getName(), net.getName()) )
self._validated = False
continue
else:
self.coronaVss = net
if netType == Net.Type.POWER:
if self.coronaVdd and self.coronaVdd != net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple power nets "{}" and "{}" at corona level.' \
.format(self.coronaVdd.getName(), net.getName()) )
self._validated = False
continue
else:
self.coronaVdd = net
if netType == Net.Type.CLOCK:
if self.coronaCk and self.coronaCk != net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple clock nets "{}" and "{}" at corona level.' \
.format(self.coronaCk.getName(), net.getName()) )
self._validated = False
continue
else:
self.coronaCk = net
for net in self.corona.getNets():
if net.getType() == Net.Type.BLOCKAGE:
self.blockageNet = net
self.blockageName = net.getName()
if not self.blockageNet:
self.blockageNet = Net.create( self.corona, self.blockageName )
self.blockageNet.setType( Net.Type.BLOCKAGE )
return
def checkChipSize ( self ):
#if self._coreSize.isEmpty(): return
#
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
#minHeight = self._coreSize.getHeight() + self._minCorona + 2*self._padHeight
#
#if self._chipSize.getWidth() < minWidth:
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
# % ( DbU.toLambda(minWidth), DbU.toLambda(self._chipSize.getWidth()) ) )
# self._validated = False
#
#if self._chipSize.getHeight() < minHeight:
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
# % ( DbU.toLambda(minHeight), DbU.toLambda(self._chipSize.getHeight()) ) )
# self._validated = False
return
def checkCorona ( self ):
trace( 550, ',+', 'Configuration.checkCorona()\n' )
netPads = {}
for plug in self.icorona.getPlugs():
padNet = plug.getNet()
coronaNet = plug.getMasterNet()
if not padNet and coronaNet.isGlobal():
padNet = self.chip.getNet( coronaNet.getName() )
if padNet:
if not netPads.has_key(padNet):
trace( 550, '\t{:>20} <-> {:<20}\n'.format(padNet.getName(),coronaNet.getName()) )
netPads[ padNet ] = coronaNet
else:
raise ErrorMessage( 1, 'ChipConf.checkCorona(): Corona nets "{}" and "{}" connected to the same pad net "{}".' \
.format(coronaNet.getName(),netPads[padNet].getName(),padNet.getName()) )
self._validated = False
trace( 550, '-' )
return
def computeChipSize ( self ):
def getSideLength ( pads ):
sideLength = self.ioPadHeight * 2
for pad in pads: sideLength += pad.getMasterCell().getAbutmentBox().getWidth()
return sideLength
if not self.chipSize.isEmpty(): return
southPadsLength = getSideLength( self.southPads )
northPadsLength = getSideLength( self.northPads )
eastPadsLength = getSideLength( self.eastPads )
westPadsLength = getSideLength( self.westPads )
horizontalPads = max( len(self.southPads), len(self.northPads) )
verticalPads = max( len(self.eastPads ), len(self.westPads ) )
self.chipSize = ( max( southPadsLength, northPadsLength )
, max( westPadsLength, eastPadsLength ) )
def setupCorona ( self, gapX1, gapY1, gapX2, gapY2 ):
ab = self.chip.getAbutmentBox()
ab.inflate ( -gapX1, -gapY1, -gapX2, -gapY2 )
ab.inflate ( - self.ioPadHeight )
ab.translate( - self.ioPadHeight, - self.ioPadHeight)
ab = self.toSymbolic( ab, Inwards )
self. corona.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
self.icorona.setTransformation(
Transformation( self.toSymbolic( self.ioPadHeight + ab.getXMin(), Superior )
, self.toSymbolic( self.ioPadHeight + ab.getYMin(), Superior )
, Transformation.Orientation.ID ) )
self.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED )
def setupCore ( self, gapX1, gapY1, gapX2, gapY2 ):
trace( 550, ',+', '\tChipConf.setupCore()\n' )
ab = self.getInstanceAb( self.icorona )
if ab.isEmpty():
raise ErrorMessage( 1, 'ChipConf.setupCore(): Attempt to setup core *before* corona.' )
return
ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
ab = self.toSymbolic( ab, Inwards )
tracee( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
if not self.coreAb.isEmpty():
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
ab = self.coreAb
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
self.icore.setTransformation(
Transformation( ChipConf.toSymbolic(ab.getXMin(),Inferior) - self.icorona.getTransformation().getTx()
, ChipConf.toSymbolic(ab.getYMin(),Inferior) - self.icorona.getTransformation().getTy()
, Transformation.Orientation.ID ) )
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
trace( 550, '-' )

View File

@ -0,0 +1,628 @@
# This file is part of the Coriolis Software.
# Copyright (c) SU 2014-2020, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/corona.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
import bisect
from operator import methodcaller
import Cfg
from Hurricane import DbU
from Hurricane import Point
from Hurricane import Interval
from Hurricane import Box
from Hurricane import Transformation
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import Net
from Hurricane import Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Pad
import CRL
from CRL import RoutingLayerGauge
from helpers import trace
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.overlay import UpdateSession
import plugins
from plugins import StackedVia
import plugins.alpha.chip
plugins.alpha.chip.importConstants( globals() )
# --------------------------------------------------------------------
# Class : "corona.IntervalSet"
class IntervalSet ( object ):
def __init__ ( self ):
self.chunks = []
return
def merge ( self, min, max ):
toMerge = Interval( min, max )
imerge = len(self.chunks)
length = len(self.chunks)
i = 0
while i < length:
if imerge >= length:
if toMerge.getVMax() < self.chunks[i].getVMin():
self.chunks.insert( i, toMerge )
length += 1
imerge = 0
break
if toMerge.intersect(self.chunks[i]):
imerge = i
self.chunks[imerge].merge( toMerge )
else:
if toMerge.getVMax() >= self.chunks[i].getVMin():
self.chunks[imerge].merge( self.chunks[i] )
del self.chunks[ i ]
length -= 1
continue
else:
break
i += 1
if imerge >= length:
self.chunks.insert( length, toMerge )
# --------------------------------------------------------------------
# Class : "corona.Rail"
class Rail ( object ):
def __init__ ( self, side, order, axis ):
self.side = side
self.order = order
self.axis = axis
self.vias = {} # Key:pos Element:[pos,railContact,blockContact]
@property
def net ( self ): return self.side.getRailNet(self.order)
# --------------------------------------------------------------------
# Class : "corona.HorizontalRail"
class HorizontalRail ( Rail ):
def __init__ ( self, side, order, axis ):
Rail.__init__( self, side, order, axis )
trace( 550, '\t{}\n'.format(self) )
def __str__ ( self ):
return '<HorizontalRail "{}" ({}) @{}>'.format( self.side.getRailNet(self.order)
, self.order
, DbU.getValueString(self.axis) )
def connect ( self, contact ):
contactBb = contact.getBoundingBox()
if contactBb.getXMin() < self.side.innerBb.getXMin() \
or contactBb.getXMax() > self.side.innerBb.getXMax():
raise ErrorMessage( 1, [ '{} is outside rail/corona X range,'.format(contact)
, 'power pad is likely to be to far off west or east.'
, '(core:{})'.format(self.side.innerBb) ] )
if self.vias.has_key(contact.getX()): return False
keys = self.vias.keys()
keys.sort()
insertIndex = bisect.bisect_left( keys, contact.getX() )
if len(keys) > 0:
if insertIndex < len(keys):
insertPosition = keys[ insertIndex ]
if contactBb.getXMax() >= self.vias[insertPosition][2].getBoundingBox().getXMin():
return False
if insertIndex > 0:
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getXMax() >= contactBb.getXMin():
return False
self.vias[ contact.getX() ] = [ contact.getX()
, StackedVia( self.net
, self.side.getLayerDepth(self.side.getHLayer())
, contact.getX()
, self.axis
, contact.getWidth() - DbU.fromLambda(1.0)
, self.side.hRailWidth - DbU.fromLambda(1.0)
)
, contact ]
trace( 550, '\tADD "{}" contact "{}" @ [{} {}]\n' \
.format( contact.getNet().getName()
, contact.getLayer().getName()
, DbU.getValueString(contact.getX())
, DbU.getValueString(self.axis)) )
self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
return True
def doLayout ( self ):
trace( 550, ',+', '\tHorizontalRail.doLayout() order:{} @{}\n' \
.format( self.order,DbU.getValueString(self.axis )))
railVias = [ self.side.corner0(self.order)
, self.side.corner1(self.order) ]
for via in self.vias.values():
if via[1].getNet() != via[2].getNet(): continue
via[1].mergeDepth( self.side.getLayerDepth(self.side.getVLayer()) )
via[1].doLayout()
Vertical.create( via[1].getVia( via[2].getLayer() )
, via[2]
, via[2].getLayer()
, via[2].getX()
, via[2].getWidth()
)
railVias.append( via[1].getVia( self.side.getVLayer()) )
for i in range(1,len(railVias)):
h = Horizontal.create( railVias[i-1]
, railVias[i]
, self.side.getHLayer()
, self.axis
, self.side.hRailWidth
)
trace( 550, '\t| {}\n'.format(h) )
trace( 550, '-' )
# --------------------------------------------------------------------
# Class : "corona.VerticalRail"
class VerticalRail ( Rail ):
def __init__ ( self, side, order, axis ):
Rail.__init__( self, side, order, axis )
trace( 550, '\t{}\n'.format(self) )
def __str__ ( self ):
return '<VerticalRail "{}" ({}) @{}>'.format( self.side.getRailNet(self.order)
, self.order
, DbU.getValueString(self.axis) )
def doLayout ( self ):
railVias = [ self.side.corner0(self.order)
, self.side.corner1(self.order) ]
for via in self.vias.values():
if via[1].getNet() != via[2].getNet(): continue
via[1].doLayout()
Horizontal.create( via[1].getVia( via[2].getLayer() )
, via[2]
, via[2].getLayer()
, via[2].getY()
, via[2].getHeight()
)
railVias.append( via[1].getVia(self.side.getVLayer()) )
railVias.sort( key=methodcaller('getY') )
for i in range(1,len(railVias)):
Vertical.create( railVias[i-1]
, railVias[i]
, self.side.getVLayer()
, self.axis
, self.side.vRailWidth
)
def connect ( self, contact ):
contactBb = contact.getBoundingBox()
if contactBb.getYMin() < self.side.innerBb.getYMin() \
or contactBb.getYMax() > self.side.innerBb.getYMax():
raise ErrorMessage( 1, [ '{} is outside rail/corona Y range'.format(contact)
, 'power pad is likely to be to far off north or south.'
, '(core:{})'.format(self.side.innerBb) ] )
if self.vias.has_key(contact.getY()): return False
trace( 550, ',+', '\tVerticalRail.connect() [{}] @{}\n'.format(self.order,DbU.toLambda(self.axis)) )
trace( 550, '\t{}\n'.format(contact) )
keys = self.vias.keys()
keys.sort()
insertIndex = bisect.bisect_left( keys, contact.getY() )
trace( 550, ',+', '\tkeys:' )
for key in keys:
trace( 550, ' {}'.format(DbU.toLambda(key)) )
trace( 550, '\n' )
if len(keys) > 0:
if insertIndex < len(keys):
insertPosition = keys[ insertIndex ]
trace( 550, '\tinsertIndex:{}'.format(insertIndex) )
trace( 550, '\tCheck NEXT contactBb:{} via:{}\n' \
.format( contactBb
, self.vias[insertPosition][2].getBoundingBox()) )
if contactBb.getYMax() >= self.vias[insertPosition][2].getBoundingBox().getYMin():
trace( 550, ',--', '\tReject {} intersect NEXT\n'.format(contact) )
return False
if insertIndex > 0:
trace( 550, '\tcheck PREVIOUS contactBb:{} via:{}\n' \
.format( contactBb
, self.vias[keys[insertIndex-1]][2].getBoundingBox()) )
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getYMax() >= contactBb.getYMin():
trace( 550, ',--', '\tReject {} intersect PREVIOUS\n'.format(contact) )
return False
self.vias[ contact.getY() ] = [ contact.getY()
, StackedVia( self.net
, self.side.getLayerDepth(self.side.getVLayer())
, self.axis
, contact.getY()
, self.side.vRailWidth - DbU.fromLambda(1.0)
, contact.getHeight() - DbU.fromLambda(1.0)
)
, contact ]
trace(550, ',--' '\tADD {}\n'.format(contact) )
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
return True
# --------------------------------------------------------------------
# Class : "corona.Side"
class Side ( object ):
def __init__ ( self, corona ):
self.corona = corona
@property
def railsCount ( self ): return self.corona.railsCount
@property
def innerBb ( self ): return self.corona.innerBb
@property
def hRailWidth ( self ): return self.corona.hRailWidth
@property
def hRailSpace ( self ): return self.corona.hRailSpace
@property
def vRailWidth ( self ): return self.corona.vRailWidth
@property
def vRailSpace ( self ): return self.corona.vRailSpace
@property
def corners ( self ): return self.corona.corners
@property
def horizontalDepth ( self ): return self.corona.horizontalDepth
@property
def verticalDepth ( self ): return self.corona.verticalDepth
@property
def blockageNet ( self ): return self.corona.blockageNet
def getLayerDepth ( self, metal ): return self.corona.getLayerDepth(metal)
def getRail ( self, i ): return self.rails[i]
def getRailNet ( self, i ): return self.corona.getRailNet(i)
def getHLayer ( self ): return self.corona.getHLayer()
def getVLayer ( self ): return self.corona.getVLayer()
def getRailAxis ( self, i ):
raise ErrorMessage( 1, 'Side.getRailAxis(): Must never be called on base class.' )
def getInnerRail ( self, i ):
if i >= len(self.rails):
raise ErrorMessage( 1, 'Side.getInnerRail(): no rail {} (only:{}).' \
.format(i,len(self.rails)) )
return self.rails[i]
def getOuterRail ( self, i ):
if i >= len(self.rails):
raise ErrorMessage( 1, 'Side.getOuterRail(): no rail {} (only: {}).' \
.format(i,len(self.rails)) )
return self.rails[-(i+1)]
def connect ( self, blockSide ):
for terminal in blockSide.terminals:
trace( 550, '\tterminal:{}\n'.format(terminal) )
for rail in self.rails:
rail.connect( terminal[1] )
def connectPads ( self, padSide ):
for contact in padSide.pins:
if contact.getNet().isClock():
for i in range(len(self.rails)):
trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) )
self.getOuterRail(i).connect( contact )
elif contact.getNet().isSupply():
self.getOuterRail( 0 ).connect( contact )
halfRails = (len(self.rails)-1)/2
trace( 550, '\thalfRails:{}\n'.format(halfRails) )
for contact in padSide.pins:
if not contact.getNet().isSupply() and not contact.getNet().isClock(): continue
trace( 550, ',+', '\tConnect pad contact {}\n'.format(contact) )
for i in range(halfRails):
trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) )
self.getOuterRail(i).connect( contact )
trace( 550, '-' )
def doLayout ( self ):
for rail in self.rails: rail.doLayout()
# --------------------------------------------------------------------
# Class : "corona.HorizontalSide"
class HorizontalSide ( Side ):
def __init__ ( self, corona ):
Side.__init__( self, corona )
self.rails = []
for i in range(self.railsCount):
self.rails.append( HorizontalRail(self,i,self.getRailAxis(i)) )
return
# --------------------------------------------------------------------
# Class : "corona.SouthSide"
class SouthSide ( HorizontalSide ):
def __init__ ( self, corona ):
HorizontalSide.__init__( self, corona )
return
def getRailAxis ( self, i ):
return self.innerBb.getYMin() - self.hRailWidth/2 - self.hRailSpace \
- i*(self.hRailWidth + self.hRailSpace)
def corner0 ( self, i ): return self.corners[SouthWest][i]
def corner1 ( self, i ): return self.corners[SouthEast][i]
# --------------------------------------------------------------------
# Class : "corona.NorthSide"
class NorthSide ( HorizontalSide ):
def __init__ ( self, corona ):
HorizontalSide.__init__( self, corona )
return
def getRailAxis ( self, i ):
return self.innerBb.getYMax() + self.hRailWidth/2 + self.hRailSpace \
+ i*(self.hRailWidth + self.hRailSpace)
def corner0 ( self, i ): return self.corners[NorthWest][i]
def corner1 ( self, i ): return self.corners[NorthEast][i]
# --------------------------------------------------------------------
# Class : "corona.VerticalSide"
class VerticalSide ( Side ):
def __init__ ( self, corona ):
Side.__init__( self, corona )
self.rails = []
for i in range(self.railsCount):
self.rails.append( VerticalRail(self,i,self.getRailAxis(i)) )
return
def addBlockages ( self, sideXMin, sideXMax ):
spans = IntervalSet()
for rail in self.rails:
for via in rail.vias.values():
if via[1].getNet() != via[2].getNet(): continue
spans.merge( via[1]._y - via[1]._height/2, via[1]._y + via[1]._height/2 )
routingGauge = self.corona.routingGauge
for depth in range(self.getInnerRail(0).vias.values()[0][1].bottomDepth
,self.getInnerRail(0).vias.values()[0][1].topDepth ):
blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer()
pitch = routingGauge.getLayerPitch(depth)
for chunk in spans.chunks:
Horizontal.create( self.blockageNet
, blockageLayer
, (chunk.getVMax() + chunk.getVMin())/2
, chunk.getVMax() - chunk.getVMin() + pitch*2
, sideXMin
, sideXMax
)
depth -= 2
if depth > 0:
blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer()
pitch = routingGauge.getLayerPitch(depth)
for chunk in spans.chunks:
Horizontal.create( self.blockageNet
, blockageLayer
, (chunk.getVMax() + chunk.getVMin())/2
, chunk.getVMax() - chunk.getVMin() + pitch*2
, sideXMin
, sideXMax
)
# --------------------------------------------------------------------
# Class : "corona.WestSide"
class WestSide ( VerticalSide ):
def __init__ ( self, corona ):
VerticalSide.__init__( self, corona )
def getRailAxis ( self, i ):
return self.innerBb.getXMin() - self.vRailWidth/2 - self.vRailSpace \
- i*(self.vRailWidth + self.vRailSpace)
def corner0 ( self, i ): return self.corners[SouthWest][i]
def corner1 ( self, i ): return self.corners[NorthWest ][i]
def addBlockages ( self ):
sideXMin = self.getOuterRail(0).axis - self.vRailWidth
sideXMax = self.getInnerRail(0).axis + self.vRailWidth
VerticalSide.addBlockages( self, sideXMin, sideXMax )
# --------------------------------------------------------------------
# Class : "corona.EastSide"
class EastSide ( VerticalSide ):
def __init__ ( self, corona ):
VerticalSide.__init__( self, corona )
def getRailAxis ( self, i ):
return self.innerBb.getXMax() + self.vRailWidth/2 + self.vRailSpace \
+ i*(self.vRailWidth + self.vRailSpace)
def corner0 ( self, i ): return self.corners[SouthEast][i]
def corner1 ( self, i ): return self.corners[NorthEast ][i]
def addBlockages ( self ):
sideXMin = self.getInnerRail(0).axis - self.vRailWidth
sideXMax = self.getOuterRail(0).axis + self.vRailWidth
VerticalSide.addBlockages( self, sideXMin, sideXMax )
# --------------------------------------------------------------------
# Class : "corona.Builder"
class Builder ( object ):
def __init__ ( self, block ):
self.block = block
self.innerBb = self.block.bb
self.block.path.getTransformation().applyOn( self.innerBb )
self.innerBb.inflate( self.hRailSpace/2, self.vRailSpace/2 )
self.southSide = SouthSide( self )
self.northSide = NorthSide( self )
self.westSide = WestSide ( self )
self.eastSide = EastSide ( self )
@property
def conf ( self ): return self.block.conf
@property
def routingGauge ( self ): return self.conf.routingGauge
@property
def topLayerDepth ( self ): return self.conf.topLayerDepth
@property
def horizontalDepth ( self ): return self.conf.horizontalDepth
@property
def verticalDepth ( self ): return self.conf.verticalDepth
@property
def blockageNet ( self ): return self.conf.blockageNet
@property
def railsCount ( self ): return self.conf.railsCount
@property
def hRailWidth ( self ): return self.conf.cfg.chip.block.rails.hWidth
@property
def vRailWidth ( self ): return self.conf.cfg.chip.block.rails.vWidth
@property
def hRailSpace ( self ): return self.conf.cfg.chip.block.rails.hSpacing
@property
def vRailSpace ( self ): return self.conf.cfg.chip.block.rails.vSpacing
def getLayerDepth ( self, metal ):
return self.conf.routingGauge.getLayerDepth( metal )
def getRailNet ( self, i ):
if self.conf.useClockTree and i == 0: return self.conf.coronaCk
if i % 2: return self.conf.coronaVss
return self.conf.coronaVdd
def getHLayer ( self ):
return self.routingGauge.getLayerGauge( self.horizontalDepth ).getLayer()
def getVLayer ( self ):
return self.routingGauge.getLayerGauge( self.verticalDepth ).getLayer()
def connectCore ( self ):
for plane in self.block.planes.values():
for side in plane.sides.values():
self.southSide.connect( side[South] )
self.northSide.connect( side[North] )
self.westSide .connect( side[West ] )
self.eastSide .connect( side[East ] )
def connectPads ( self, padsCorona ):
self.southSide.connectPads( padsCorona.southSide )
self.northSide.connectPads( padsCorona.northSide )
self.eastSide .connectPads( padsCorona.eastSide )
self.westSide .connectPads( padsCorona.westSide )
return
def doLayout ( self ):
self.corners = { SouthWest : []
, SouthEast : []
, NorthWest : []
, NorthEast : []
}
contactDepth = self.horizontalDepth
if self.horizontalDepth > self.verticalDepth:
contactDepth = self.verticalDepth
with UpdateSession():
blBox = Box()
brBox = Box()
tlBox = Box()
trBox = Box()
for i in range(self.railsCount):
xBL = self.westSide .getRail(i).axis
yBL = self.southSide.getRail(i).axis
xTR = self.eastSide .getRail(i).axis
yTR = self.northSide.getRail(i).axis
net = self.getRailNet( i )
blBox.merge( xBL, yBL )
brBox.merge( xTR, yBL )
tlBox.merge( xBL, yTR )
trBox.merge( xTR, yTR )
self.routingGauge.getContactLayer(contactDepth)
self.corners[SouthWest].append(
Contact.create( net
, self.routingGauge.getContactLayer(contactDepth)
, xBL, yBL
, self.hRailWidth
, self.vRailWidth
) )
self.corners[NorthWest].append(
Contact.create( net
, self.routingGauge.getContactLayer(contactDepth)
, xBL, yTR
, self.hRailWidth
, self.vRailWidth
) )
self.corners[SouthEast].append(
Contact.create( net
, self.routingGauge.getContactLayer(contactDepth)
, xTR, yBL
, self.hRailWidth
, self.vRailWidth
) )
self.corners[NorthEast].append(
Contact.create( net
, self.routingGauge.getContactLayer(contactDepth)
, xTR, yTR
, self.hRailWidth
, self.vRailWidth
) )
self.southSide.doLayout()
self.northSide.doLayout()
self.westSide .doLayout()
self.eastSide .doLayout()
self.westSide.addBlockages()
self.eastSide.addBlockages()
blBox.inflate( self.hRailWidth, self.vRailWidth )
brBox.inflate( self.hRailWidth, self.vRailWidth )
tlBox.inflate( self.hRailWidth, self.vRailWidth )
trBox.inflate( self.hRailWidth, self.vRailWidth )
for depth in range( 1, self.conf.topLayerDepth + 1 ):
blockageLayer = self.routingGauge.getRoutingLayer(depth).getBlockageLayer()
Pad.create( self.blockageNet, blockageLayer, blBox )
Pad.create( self.blockageNet, blockageLayer, brBox )
Pad.create( self.blockageNet, blockageLayer, tlBox )
Pad.create( self.blockageNet, blockageLayer, trBox )

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,256 @@
#!/usr/bin/env python
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2014-2018, All Rights Reserved
#
# +-----------------------------------------------------------------+
# | C O R I O L I S |
# | C u m u l u s - P y t h o n T o o l s |
# | |
# | Author : Jean-Paul CHAPUT |
# | E-mail : Jean-Paul.Chaput@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/blockpower.py" |
# +-----------------------------------------------------------------+
import sys
from Hurricane import DbU
from Hurricane import Point
from Hurricane import Transformation
from Hurricane import Box
from Hurricane import Interval
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import UpdateSession
from Hurricane import Net
from Hurricane import Contact
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import Query
import CRL
import helpers
from helpers import trace
from helpers.io import ErrorMessage
from helpers.io import WarningMessage
from helpers.overlay import UpdateSession
import plugins
import plugins.chip
plugins.chip.importConstants( globals() )
# --------------------------------------------------------------------
# Class : "power.Side"
class Side ( object ):
def __init__ ( self, block, side, net, metal ):
self.block = block
self.side = side
self.net = net
self.metal = metal
self.deltaWidth = metal.getExtentionWidth()*2
self.terminals = []
def addTerminal ( self, position, width ):
toMerge = Interval( position-width/2, position+width/2 )
length = len(self.terminals)
imerge = length
ichunk = 0
while ichunk < length:
if imerge == length:
if toMerge.getVMax() < self.terminals[ichunk][0].getVMin():
self.terminals.insert( ichunk, [ toMerge, None ] )
imerge = ichunk
length += 1
break
if toMerge.intersect(self.terminals[ichunk][0]):
imerge = ichunk
self.terminals[ichunk][0].merge( toMerge )
else:
if toMerge.getVMax() >= self.terminals[ichunk][0].getVMin():
self.terminals[imerge][0].merge( self.terminals[ichunk][0] )
del self.terminals[ichunk]
length -= 1
continue
else:
break
ichunk += 1
if ichunk == length:
self.terminals.append( [ toMerge, None ] )
def doLayout ( self ):
if self.side == West:
width = 0
x = self.block.bb.getXMin()
elif self.side == East:
width = 0
x = self.block.bb.getXMax()
elif self.side == South:
height = 0
y = self.block.bb.getYMin()
elif self.side == North:
height = 0
y = self.block.bb.getYMax()
minWidth = DbU.fromLambda( 6.0 )
for terminal in self.terminals:
if self.side == West or self.side == East:
center = Point( x, terminal[0].getCenter() )
height = terminal[0].getSize() - self.deltaWidth
if height < minWidth: height = minWidth
elif self.side == North or self.side == South:
center = Point( terminal[0].getCenter(), y )
width = terminal[0].getSize() - self.deltaWidth
if width < minWidth: width = minWidth
self.block.path.getTransformation().applyOn( center )
contact = Contact.create( self.net, self.metal, center.getX(), center.getY(), width, height )
terminal[ 1 ] = contact
# --------------------------------------------------------------------
# Class : "power.Plane"
class Plane ( object ):
Horizontal = 0001
Vertical = 0002
def __init__ ( self, block, metal ):
self.block = block
self.metal = metal
self.sides = {}
def addTerminal ( self, net, direction, bb ):
if not self.sides.has_key(net):
self.sides[ net ] = { North : Side(self.block,North,net,self.metal)
, South : Side(self.block,South,net,self.metal)
, East : Side(self.block,East ,net,self.metal)
, West : Side(self.block,West ,net,self.metal)
}
sides = self.sides[ net ]
if direction == Plane.Horizontal:
if bb.getXMin() <= self.block.bb.getXMin():
sides[West].addTerminal( bb.getCenter().getY(), bb.getHeight() )
if bb.getXMax() >= self.block.bb.getXMax():
sides[East].addTerminal( bb.getCenter().getY(), bb.getHeight() )
if direction == Plane.Vertical:
if bb.getYMin() <= self.block.bb.getYMin():
sides[South].addTerminal( bb.getCenter().getX(), bb.getWidth() )
if bb.getYMax() >= self.block.bb.getYMax():
sides[North].addTerminal( bb.getCenter().getX(), bb.getWidth() )
def doLayout ( self ):
for sidesOfNet in self.sides.values():
for side in sidesOfNet.values():
side.doLayout()
# --------------------------------------------------------------------
# Class : "power.Plane"
class GoCb ( object ):
def __init__ ( self, block ):
self.block = block
def __call__ ( self, query, go ):
direction = None
if isinstance(go,Horizontal): direction = Plane.Horizontal
if isinstance(go,Vertical): direction = Plane.Vertical
if not direction: return
rootNet = None
if go.getNet().getType() == long(Net.Type.POWER): rootNet = self.block.conf.coronaVdd
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.block.conf.coronaVss
if not rootNet: return
if self.block.activePlane:
bb = go.getBoundingBox( self.block.activePlane.metal.getBasicLayer() )
query.getPath().getTransformation().applyOn( bb )
self.block.activePlane.addTerminal( rootNet, direction, bb )
else:
print WarningMessage( 'BlockPower.GoCb() callback called without an active plane.' )
return
# --------------------------------------------------------------------
# Class : "power.Builder"
class Builder ( object ):
def __init__ ( self, conf ):
self.conf = conf
self.path = Path( self.conf.icore )
self.block = self.path.getTailInstance().getMasterCell()
self.bb = self.block.getAbutmentBox()
self.planes = {}
self.activePlane = None
for layerGauge in self.conf.routingGauge.getLayerGauges():
self.planes[ layerGauge.getLayer().getName() ] = Plane( self, layerGauge.getLayer() )
def connectPower ( self ):
if not self.conf.coronaVdd or not self.conf.coronaVss:
raise ErrorMessage( 1, 'Cannot build block power terminals as core vdd and/or vss are not known.' )
return
goCb = GoCb( self )
query = Query()
query.setGoCallback( goCb )
query.setCell( self.block )
query.setArea( self.block.getAbutmentBox() )
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
for layerGauge in self.conf.routingGauge.getLayerGauges():
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
query.setBasicLayer( layerGauge.getLayer().getBasicLayer() )
query.doQuery()
self.activePlane = None
def connectClock ( self ):
if not self.conf.useClockTree:
print WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." )
return
if not self.conf.coronaCk:
raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' )
return
blockCk = None
for plug in self.path.getTailInstance().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()) )
return
htPlugs = []
ffPlugs = []
for plug in blockCk.getPlugs():
if not plug.getInstance().isTerminalNetlist(): continue
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())
for plug in htPlugs:
message += '\n - {}'.format(plug)
raise ErrorMessage( 1, message )
return
with UpdateSession():
bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], self.path)
, self.conf.coronaCk
, 0 )
blockAb = self.block.getAbutmentBox()
self.path.getTransformation().applyOn( blockAb )
layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth)
contact = Contact.create( self.conf.coronaCk
, self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth)
, bufferRp.getX()
, blockAb.getYMax()
, layerGauge.getViaWidth()
, layerGauge.getViaWidth()
)
segment = self.conf.createVertical( bufferRp, contact, bufferRp.getX(), 0 )
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() )
self.path.getTransformation().getInvert().applyOn( bb )
self.activePlane.addTerminal( self.conf.coronaCk, Plane.Vertical, bb )
def doLayout ( self ):
with UpdateSession():
for plane in self.planes.values():
plane.doLayout()

View File

@ -88,18 +88,18 @@ class CoreToChip ( BaseCoreToChip ):
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal( True )
coronaNet.setGlobal ( True )
coronaNet.setType ( Net.Type.POWER )
coronaNet.setType ( Net.Type.GROUND )
self.icore.getPlug( coreNet ).setNet( coronaNet )
if not chipNet:
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
chipNet.setExternal( True )
chipNet.setType ( Net.Type.POWER )
chipNet.setType ( Net.Type.GROUND )
self.icorona.getPlug( coronaNet ).setNet( chipNet )
self.ringNetNames['vssi'] = chipNet
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.POWER )
padNet.setType ( Net.Type.GROUND )
self.ringNetNames['vsse'] = padNet
ioPadConf.pads.append( Instance.create( self.chip
, 'p_vssick_{}'.format(ioPadConf.index)

View File

@ -50,12 +50,13 @@ from Hurricane import Net
from Hurricane import Instance
from CRL import Catalog
from CRL import AllianceFramework
from helpers import trace
from helpers import netDirectionToStr
from helpers.overlay import UpdateSession
from helpers.io import ErrorMessage
import plugins.chip
from plugins.alpha.block.block import Block
from plugins.alpha.block.configuration import BlockState
from plugins.alpha.block.configuration import BlockConf
from plugins.alpha.block.configuration import IoPadConf
@ -99,7 +100,6 @@ class IoNet ( object ):
self.coronaNet = None # Corona net going from core to corona.
self.chipIntNet = None # Chip net going from corona to I/O pad.
self.chipExtNet = None # Chip net going from I/O pad to the outside world.
m = IoNet.reVHDLVector.match( self.coreNet.getName() )
if m:
self._flags |= IoNet.IsElem
@ -108,9 +108,8 @@ class IoNet ( object ):
else:
self._name = self.coreNet.getName()
self._index = 0
self._type = self.coreToChip.getNetType( self._name )
return
trace( 550, '\tIoNet.__init__(): {}\n'.format(self) )
def __repr__ ( self ):
return '<IoNet "{}" ext:"{}" int:"{}">'.format( self.coreNet.getName()
@ -137,6 +136,10 @@ class IoNet ( object ):
@property
def coronaNetName ( self ):
s = self._name
if self.coreNet.getDirection() & Net.Direction.IN:
s += '_from_pad'
elif self.coreNet.getDirection() & Net.Direction.OUT:
s += '_to_pad'
if self._flags & IoNet.IsElem: s += '({})'.format(self._index)
return s
@ -233,13 +236,20 @@ class IoPad ( object ):
if direction == IoPad.UNSUPPORTED: return "UNSUPPORTED"
return "Invalid value"
def __init__ ( self, coreToChip, padInstanceName ):
self.coreToChip = coreToChip
self.padInstanceName = padInstanceName
self.direction = 0
self.nets = []
self.pads = []
def __init__ ( self, coreToChip, ioPadConf ):
self.coreToChip = coreToChip
self.ioPadConf = ioPadConf
self.direction = 0
self.nets = []
return
@property
def padInstanceName ( self ): return self.ioPadConf.instanceName
@property
def pads ( self ):
print( self.ioPadConf )
return self.ioPadConf.pads
def __str__ ( self ):
s = '<IoPad "{}" '.format(self.padInstanceName)
@ -389,7 +399,7 @@ class CoreToChip ( object ):
def __init__ ( self, core ):
if isinstance(core,Block):
state = core.state
elif isinstance(core,BlockState):
elif isinstance(core,BlockConf):
state = core
else:
block = Block.lookup( core )
@ -403,17 +413,25 @@ class CoreToChip ( object ):
self.ioPadInfos = {}
self.chipPads = []
self.padLib = None
self.core = self.state.cell
self.chip = None
self.corona = None
self.icorona = None
self.icore = None
self._ioNets = {}
self.powerPadCount = 0
self.groundPadCount = 0
self.clockPadCount = 0
return
@property
def core ( self ): return self.state.cell
@property
def icore ( self ): return self.state.icore
@property
def icorona ( self ): return self.state.icorona
@property
def chip ( self ): return self.state.chip
def hasIoNet ( self, netName ):
"""
Look for an IoNet associated to *core* net ``netName``.
@ -439,6 +457,7 @@ class CoreToChip ( object ):
def _connectPadRing ( self, padInstance ):
"""Connect ring signals to the I/O pad."""
for masterNetName, netName in self.ringNetNames.items():
trace( 550, '\tCoreToChip._connectPadRing(): master:{} net:{}\n'.format(masterNetName,netName) )
CoreToChip._connect( padInstance, netName, masterNetName )
def _connectRing ( self ):
@ -487,37 +506,42 @@ class CoreToChip ( object ):
"""
af = AllianceFramework.get()
with UpdateSession():
self.chip = af.createCell( self.state.chip.name )
self.corona = af.createCell( 'corona' )
self.icore = Instance.create( self.corona, 'core' , self.core )
self.icorona = Instance.create( self.chip , 'corona', self.corona )
print( ' o Build Chip from Core.' )
print( ' - Core: "{}".'.format(self.state.cell.getName()) )
print( ' - Corona: "{}".'.format('corona') )
print( ' - Chip: "{}".'.format(self.state.chipConf.name) )
self.state.chip = af.createCell( self.state.chipConf.name )
self.corona = af.createCell( 'corona' )
self.state.icore = Instance.create( self.corona , 'core' , self.state.cell )
self.state.icorona = Instance.create( self.state.chip, 'corona', self.corona )
ioPads = []
clockIoNets = []
for padConf in self.state.chip.padInstances:
if padConf.isPower():
self._buildPowerPads( padConf )
for ioPadConf in self.state.chipConf.padInstances:
if ioPadConf.isPower():
self._buildPowerPads( ioPadConf )
continue
if padConf.isGround():
self._buildGroundPads( padConf )
if ioPadConf.isGround():
self._buildGroundPads( ioPadConf )
continue
if padConf.isClock():
self._buildClockPads( padConf )
if ioPadConf.isClock():
self._buildClockPads( ioPadConf )
continue
padConf.udata = IoPad( self, padConf.instanceName )
for netName in padConf.nets:
ioPadConf.udata = IoPad( self, ioPadConf )
for netName in ioPadConf.nets:
if netName is None: continue
coreNet = self.core.getNet( netName )
if not coreNet:
raise ErrorMessage( 1, 'CoreToChip.buildChip(): "%s" doesn\'t have a "%s" net.'
% (self.core.getName(),netName) )
raise ErrorMessage( 1, 'CoreToChip.buildChip(): "{}" doesn\'t have a "{}" net.' \
.format(self.core.getName(),netName) )
ioNet = self.getIoNet( coreNet )
if padConf.isBidir() or padConf.isTristate():
if coreNet.getName() == padConf.enableNetName:
if ioPadConf.isBidir() or ioPadConf.isTristate():
if coreNet.getName() == ioPadConf.enableNetName:
ioNet.setEnable( True )
if not ioNet.isEnable():
ioNet.chipExtNetName = padConf.padNetName
padConf.udata.addNet( ioNet )
ioPads.append( padConf )
ioNet.chipExtNetName = ioPadConf.padNetName
ioPadConf.udata.addNet( ioNet )
ioPads.append( ioPadConf )
trace( 550, '\tProcessed all IoPadConf, looking for orphaned core nets...\n' )
for coreNet in self.core.getNets():
if not coreNet.isExternal(): continue
elif coreNet.isPower(): continue
@ -535,6 +559,7 @@ class CoreToChip ( object ):
directPad.udata = IoPad( self, directPad.instanceName )
directPad.udata.addNet( ioNet )
ioPads.append( directPad )
trace( 550, '\tNon-configured core net {}, adding {}\n'.format(coreNet,directPad) )
for ioPad in ioPads:
ioPad.udata.createPad()
self._connectRing()

View File

@ -43,7 +43,6 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
"""
framework = CRL.AllianceFramework.get()
if depth == 0: print( ' o Recursive Save-Cell.' )
sviews = ''
if views & CRL.Catalog.State.Logical:
sviews += 'netlist'
@ -58,19 +57,16 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
if views & CRL.Catalog.State.Physical:
if sviews: sviews += ','
sviews += 'layout'
print( ' {}+ {} ({}).'.format(' '*(depth*2), cell.getName(), sviews) )
if cell.isUniquified(): views |= CRL.Catalog.State.Logical
framework.saveCell( cell, views )
for instance in cell.getInstances():
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
masterCell = instance.getMasterCell()
if not masterCell.isTerminalNetlist():
rsave( masterCell, views, depth+1 )
#else:
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
#else:
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
return
@ -100,11 +96,8 @@ def scriptMain ( **kw ):
return 0
rsave( cell, views )
CRL.destroyAllVHDL()
except Exception, e:
helpers.io.catch( e )
sys.stdout.flush()
sys.stderr.flush()
return 0