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/core2chip.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.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 ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins ) 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 ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha )
install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block ) install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block )
install ( FILES ${pyPluginAlphaC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/core2chip ) 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 ) #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.hfns2 import BufferTree
from alpha.block.hfns3 import BufferTree from alpha.block.hfns3 import BufferTree
from alpha.block.configuration import IoPin 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() timing.staticInit()
@ -70,8 +71,8 @@ class Side ( object ):
and perform pins creation & placement. and perform pins creation & placement.
""" """
def __init__ ( self, state, side ): def __init__ ( self, conf, side ):
self.state = state self.conf = conf
self.side = side self.side = side
self.pinSpecs = [] self.pinSpecs = []
self.expandPins = True self.expandPins = True
@ -99,25 +100,25 @@ class Side ( object ):
box has been setup. box has been setup.
""" """
if self.side & IoPin.WEST: if self.side & IoPin.WEST:
self.gauge = self.state.gaugeConf.hDeepRG self.gauge = self.conf.hDeepRG
self.ubegin = self.state.yMin self.ubegin = self.conf.yMin
self.uend = self.state.yMax self.uend = self.conf.yMax
self.sidePos = self.state.xMin self.sidePos = self.conf.xMin
elif self.side & IoPin.EAST: elif self.side & IoPin.EAST:
self.gauge = self.state.gaugeConf.hDeepRG self.gauge = self.conf.hDeepRG
self.ubegin = self.state.yMin self.ubegin = self.conf.yMin
self.uend = self.state.yMax self.uend = self.conf.yMax
self.sidePos = self.state.xMax self.sidePos = self.conf.xMax
elif self.side & IoPin.SOUTH: elif self.side & IoPin.SOUTH:
self.gauge = self.state.gaugeConf.vDeepRG self.gauge = self.conf.vDeepRG
self.ubegin = self.state.xMin self.ubegin = self.conf.xMin
self.uend = self.state.xMax self.uend = self.conf.xMax
self.sidePos = self.state.yMin self.sidePos = self.conf.yMin
elif self.side & IoPin.NORTH: elif self.side & IoPin.NORTH:
self.gauge = self.state.gaugeConf.vDeepRG self.gauge = self.conf.vDeepRG
self.ubegin = self.state.xMin self.ubegin = self.conf.xMin
self.uend = self.state.xMax self.uend = self.conf.xMax
self.sidePos = self.state.yMax self.sidePos = self.conf.yMax
def getNextPinPosition ( self, flags, upos, ustep ): def getNextPinPosition ( self, flags, upos, ustep ):
""" """
@ -179,26 +180,26 @@ class Side ( object ):
status = 0 status = 0
if self.side & (IoPin.NORTH | IoPin.SOUTH): if self.side & (IoPin.NORTH | IoPin.SOUTH):
gauge = self.state.gaugeConf.vDeepRG gauge = self.conf.vDeepRG
upos = ioPin.upos upos = ioPin.upos
for index in ioPin.indexes: for index in ioPin.indexes:
pinName = ioPin.stem.format( index ) pinName = ioPin.stem.format( index )
net = self.state.cell.getNet( pinName ) net = self.conf.cell.getNet( pinName )
if net is None: if net is None:
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
continue 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) )) print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) ))
continue continue
pinName += '.{}'.format(self.state.getIoPinsCounts(net)) pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) 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.' \ print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside north or south abutment box side.' \
.format(pinName) .format(pinName)
, '(x:{}, xAB: [{}:{}])' \ , '(x:{}, xAB: [{}:{}])' \
.format( DbU.getValueString(pinPos.getX()) .format( DbU.getValueString(pinPos.getX())
, DbU.getValueString(self.state.xMin) , DbU.getValueString(self.conf.xMin)
, DbU.getValueString(self.state.xMax) ) ] )) , DbU.getValueString(self.conf.xMax) ) ] ))
status += 1 status += 1
trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
pin = Pin.create( net pin = Pin.create( net
@ -213,26 +214,26 @@ class Side ( object ):
) )
NetExternalComponents.setExternal( pin ) NetExternalComponents.setExternal( pin )
self.append( pin ) self.append( pin )
self.state.incIoPinsCounts( net ) self.conf.incIoPinsCounts( net )
if upos: upos += ioPin.ustep if upos: upos += ioPin.ustep
else: else:
gauge = self.state.gaugeConf.hDeepRG gauge = self.conf.hDeepRG
upos = ioPin.upos upos = ioPin.upos
for index in ioPin.indexes: for index in ioPin.indexes:
pinName = ioPin.stem.format(index) pinName = ioPin.stem.format(index)
net = self.state.cell.getNet( pinName ) net = self.conf.cell.getNet( pinName )
if net is None: if net is None:
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
continue continue
pinName += '.{}'.format(self.state.getIoPinsCounts(net)) pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) 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.' \ print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside east or west abutment box side.' \
.format(pinName) .format(pinName)
, '(y:{}, yAB: [{}:{}])' \ , '(y:{}, yAB: [{}:{}])' \
.format( DbU.getValueString(pinPos.getY()) .format( DbU.getValueString(pinPos.getY())
, DbU.getValueString(self.state.yMin) , DbU.getValueString(self.conf.yMin)
, DbU.getValueString(self.state.yMax)) ] )) , DbU.getValueString(self.conf.yMax)) ] ))
status += 1 status += 1
trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
pin = Pin.create( net pin = Pin.create( net
@ -247,7 +248,7 @@ class Side ( object ):
) )
NetExternalComponents.setExternal( pin ) NetExternalComponents.setExternal( pin )
self.append( pin ) self.append( pin )
self.state.incIoPinsCounts( net ) self.conf.incIoPinsCounts( net )
if upos: upos += ioPin.ustep if upos: upos += ioPin.ustep
return status return status
@ -257,7 +258,7 @@ class Side ( object ):
of the abutment box. THey will stick out for one pitch. of the abutment box. THey will stick out for one pitch.
""" """
if not self.expandPins: return if not self.expandPins: return
rg = self.state.gaugeConf.routingGauge rg = self.conf.routingGauge
for pinsAtPos in self.pins.values(): for pinsAtPos in self.pins.values():
for pin in pinsAtPos: for pin in pinsAtPos:
for lg in rg.getLayerGauges(): for lg in rg.getLayerGauges():
@ -285,7 +286,7 @@ class Side ( object ):
for pin in self.pins[upos][1:]: for pin in self.pins[upos][1:]:
pinNames += ', ' + pin.getName() pinNames += ', ' + pin.getName()
print( ErrorMessage( 1, [ 'Side.checkOverlap(): On {} side of block "{}", {} pins ovelaps.' \ 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) ] ) ) .format(DbU.getValueString(upos),pinNames) ] ) )
@ -308,34 +309,31 @@ class Block ( object ):
if Block.LUT.has_key(cell): return Block.LUT[cell] if Block.LUT.has_key(cell): return Block.LUT[cell]
return None return None
@staticmethod def __init__ ( self, conf ):
def create ( cell, ioPins=[], ioPads=[] ): """
"""Create a Block and it's configuration object.""" Create a Block object. The only parameter ``conf`` must be a BlockConf
block = Block( BlockState( cell, ioPins, ioPads ) ) object which contains the complete block configuration.
Block.LUT[ cell ] = block """
return block
def __init__ ( self, state ):
"""Not to be used directly, please see Block.create()."""
self.flags = 0 self.flags = 0
self.state = state self.conf = conf
self.spares = Spares( self ) self.spares = Spares( self )
self.clockTrees = [] self.clockTrees = []
self.hfnTrees = [] self.hfnTrees = []
self.blockInstances = [] self.blockInstances = []
self.sides = { IoPin.WEST : Side( self.state, IoPin.WEST ) self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
, IoPin.EAST : Side( self.state, IoPin.EAST ) , IoPin.EAST : Side( self.conf, IoPin.EAST )
, IoPin.SOUTH : Side( self.state, IoPin.SOUTH ) , IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
, IoPin.NORTH : Side( self.state, IoPin.NORTH ) , 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.' \ print( ' o Block "{}" is already done, reusing layout.' \
.format(self.state.cell.getName()) ) .format(self.conf.cell.getName()) )
self.state.cell.setTerminalNetlist( True ) self.conf.cell.setTerminalNetlist( True )
self.state.isBuilt = True self.conf.isBuilt = True
else: else:
print( ' o Block "{}" will be generated.' \ 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 ): def setUnexpandPins ( self, sides ):
""" """
@ -359,48 +357,57 @@ class Block ( object ):
various configuration parameters (aspect ratio, space margin, fixed various configuration parameters (aspect ratio, space margin, fixed
height or width, ...). 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 pass
elif not self.conf.coreAb.isEmpty():
self.conf.core.setAbutmentBox( self.conf.coreAb )
elif len(self.blockInstances): elif len(self.blockInstances):
with UpdateSession(): with UpdateSession():
ab = Box( 0, 0, self.state.fixedWidth, self.state.fixedHeight ) ab = Box( 0, 0, self.conf.fixedWidth, self.conf.fixedHeight )
self.state.cell.setAbutmentBox( ab ) self.conf.cell.setAbutmentBox( ab )
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences(): for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
instance = occurrence.getEntity() instance = occurrence.getEntity()
subCell = instance.getMasterCell() subCell = instance.getMasterCell()
subCell.setAbutmentBox( ab ) subCell.setAbutmentBox( ab )
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences(): for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
instance = occurrence.getEntity() instance = occurrence.getEntity()
instance.setTransformation( Transformation() ) instance.setTransformation( Transformation() )
for blockInstance in self.blockInstances: for blockInstance in self.blockInstances:
blockInstance.place() blockInstance.place()
else: else:
sysSpaceMargin = self.state.cfg.etesian.spaceMargin sysSpaceMargin = self.conf.cfg.etesian.spaceMargin
blockSpaceMargin = sysSpaceMargin + self.spares.getSpareSpaceMargin() blockSpaceMargin = sysSpaceMargin + self.spares.getSpareSpaceMargin()
self.state.cfg.etesian.spaceMargin = blockSpaceMargin self.conf.cfg.etesian.spaceMargin = blockSpaceMargin
self.state.cfg.apply() self.conf.cfg.apply()
with UpdateSession(): with UpdateSession():
etesian = Etesian.EtesianEngine.create( self.state.cell ) etesian = Etesian.EtesianEngine.create( self.conf.cell )
if self.state.fixedWidth: etesian.setFixedAbWidth ( self.state.fixedWidth ) if self.conf.fixedWidth: etesian.setFixedAbWidth ( self.conf.fixedWidth )
if self.state.fixedHeight: etesian.setFixedAbHeight( self.state.fixedHeight ) if self.conf.fixedHeight: etesian.setFixedAbHeight( self.conf.fixedHeight )
etesian.setDefaultAb() etesian.setDefaultAb()
etesian.destroy() etesian.destroy()
self.state.cfg.etesian.spaceMargin = sysSpaceMargin self.conf.cfg.etesian.spaceMargin = sysSpaceMargin
self.state.cfg.apply() 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() 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 ): def addClockTrees ( self ):
"""Create the trunk of all the clock trees (recursive H-Tree).""" """Create the trunk of all the clock trees (recursive H-Tree)."""
print( ' o Building clock tree(s).' ) print( ' o Building clock tree(s).' )
af = CRL.AllianceFramework.get() af = CRL.AllianceFramework.get()
clockNets = [] clockNets = []
for net in self.state.cell.getNets(): for net in self.conf.cell.getNets():
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net) if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
if net.isClock(): if net.isClock():
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) ) trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
clockNets.append( net ) clockNets.append( net )
if not clockNets: 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(): with UpdateSession():
for clockNet in clockNets: for clockNet in clockNets:
print( ' - "{}".'.format(clockNet.getName()) ) print( ' - "{}".'.format(clockNet.getName()) )
@ -421,12 +428,12 @@ class Block ( object ):
"""Create the trunk of all the high fanout nets.""" """Create the trunk of all the high fanout nets."""
print( ' o Building high fanout nets trees.' ) print( ' o Building high fanout nets trees.' )
if self.spares: if self.spares:
maxSinks = timing.tech.getSinksEstimate( self.state.bufferConf.name ) maxSinks = timing.tech.getSinksEstimate( self.conf.bufferConf.name )
dots( 82 dots( 82
, ' - Max sinks for buffer "{}"'.format(self.state.bufferConf.name) , ' - Max sinks for buffer "{}"'.format(self.conf.bufferConf.name)
, ' {}'.format(maxSinks) ) , ' {}'.format(maxSinks) )
nets = [] nets = []
for net in self.state.cell.getNets(): for net in self.conf.cell.getNets():
sinksCount = 0 sinksCount = 0
for rp in net.getRoutingPads(): sinksCount += 1 for rp in net.getRoutingPads(): sinksCount += 1
if sinksCount > maxSinks: if sinksCount > maxSinks:
@ -459,7 +466,7 @@ class Block ( object ):
""" """
faileds = 0 faileds = 0
with UpdateSession(): with UpdateSession():
for ioPin in self.state.ioPins: for ioPin in self.conf.ioPins:
if ioPin.flags & IoPin.SOUTH: side = self.sides[IoPin.SOUTH] if ioPin.flags & IoPin.SOUTH: side = self.sides[IoPin.SOUTH]
elif ioPin.flags & IoPin.NORTH: side = self.sides[IoPin.NORTH] elif ioPin.flags & IoPin.NORTH: side = self.sides[IoPin.NORTH]
elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ] elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ]
@ -467,7 +474,7 @@ class Block ( object ):
faileds += side.place( ioPin ) faileds += side.place( ioPin )
if faileds: if faileds:
raise ErrorMessage( 3, 'Block.placeIoPins(): Cell "{}" has {} badly placed pins.' \ 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 ): def checkIoPins ( self ):
""" """
@ -475,7 +482,7 @@ class Block ( object ):
""" """
for side in self.sides.values(): for side in self.sides.values():
side.checkOverlaps() side.checkOverlaps()
for net in self.state.cell.getNets(): for net in self.conf.cell.getNets():
if not net.isExternal(): continue if not net.isExternal(): continue
if net.isSupply(): continue if net.isSupply(): continue
hasPins = False hasPins = False
@ -496,12 +503,17 @@ class Block ( object ):
side.expand() side.expand()
def place ( self ): 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.place()
etesian.destroy() etesian.destroy()
def route ( self ): 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.printConfiguration ()
katana.digitalInit () katana.digitalInit ()
#katana.runNegociatePreRouted() #katana.runNegociatePreRouted()
@ -519,9 +531,9 @@ class Block ( object ):
def addBlockages ( self ): def addBlockages ( self ):
with UpdateSession(): with UpdateSession():
net = self.state.cell.getNet( 'blockagenet' ) net = self.conf.cell.getNet( 'blockagenet' )
ab = self.state.cell.getAbutmentBox() ab = self.conf.cell.getAbutmentBox()
rg = self.state.gaugeConf.routingGauge rg = self.conf.routingGauge
for lg in rg.getLayerGauges(): for lg in rg.getLayerGauges():
if lg.getType() == RoutingLayerGauge.PinOnly: continue if lg.getType() == RoutingLayerGauge.PinOnly: continue
blockage = lg.getBlockageLayer() blockage = lg.getBlockageLayer()
@ -545,44 +557,46 @@ class Block ( object ):
, ab.getYMax() - dyBorder , ab.getYMax() - dyBorder
) )
def build ( self ): def doPnR ( self ):
""" """
Perform all the steps required to build the layout of the block. Perform all the steps required to build the layout of the block.
The first step is to build all the blockInstance it depends upon, The first step is to build all the blockInstance it depends upon,
so they will appear as ``NetListTerminal`` and we can place them so they will appear as ``NetListTerminal`` and we can place them
in their parent cell. in their parent cell.
""" """
editor = self.state.editor editor = self.conf.editor
print( ' o Builing block "{}".'.format(self.state.cell.getName()) ) print( ' o Builing block "{}".'.format(self.conf.cell.getName()) )
for blockInstance in self.blockInstances: for blockInstance in self.blockInstances:
blockInstance.block.state.editor = editor blockInstance.block.conf.editor = editor
if not blockInstance.block.state.isBuilt: if not blockInstance.block.conf.isBuilt:
print( ' - Build sub-block "{}".' \ print( ' - Build sub-block "{}".' \
.format(blockInstance.block.state.cell.getName()) ) .format(blockInstance.block.conf.cell.getName()) )
blockInstance.block.build() blockInstance.block.build()
if editor: editor.setCell( self.state.cell ) if editor: editor.setCell( self.conf.cell )
self.state.cfg.apply() self.conf.cfg.apply()
iteration = -1 iteration = -1
while True: while True:
iteration += 1 iteration += 1
if iteration > 0: break if iteration > 0: break
self.setupAb() self.setupAb()
self.placeIoPins() if not self.conf.isCoreBlock:
self.checkIoPins() self.placeIoPins()
self.checkIoPins()
self.spares.build() self.spares.build()
if self.state.useClockTree: self.addClockTrees() if self.conf.useClockTree: self.addClockTrees()
self.addHfnBuffers() self.addHfnBuffers()
if editor: editor.fit() if editor: editor.fit()
#Breakpoint.stop( 0, 'Clock tree(s) done.' ) #Breakpoint.stop( 0, 'Clock tree(s) done.' )
self.place() self.place()
self.findHfnTrees() self.findHfnTrees()
break break
if self.state.useClockTree: self.splitClocks() if self.conf.useClockTree: self.splitClocks()
if self.conf.isCoreBlock: self.doConnectCore()
status = self.route() status = self.route()
self.addBlockages() if not self.conf.isCoreBlock:
self.expandIoPins() self.addBlockages()
self.state.isBuilt = True self.expandIoPins()
plugins.rsave.rsave( self.state.cell ) self.conf.isBuilt = True
return status return status
def useBlockInstance ( self, instancePathName , transf ): def useBlockInstance ( self, instancePathName , transf ):
@ -602,7 +616,7 @@ class Block ( object ):
iNames = instancePathName.split('.') iNames = instancePathName.split('.')
path = Path() path = Path()
for iName in iNames: for iName in iNames:
if path.isEmpty(): parentCell = self.state.cell if path.isEmpty(): parentCell = self.conf.cell
else: parentCell = path.getTailInstance().getMasterCell() else: parentCell = path.getTailInstance().getMasterCell()
instance = parentCell.getInstance( iName ) instance = parentCell.getInstance( iName )
if not instance: if not instance:
@ -620,6 +634,11 @@ class Block ( object ):
return return
blockIns = BlockInstance( tailInstance, transf ) blockIns = BlockInstance( tailInstance, transf )
self.blockInstances.append( blockIns ) 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.io import catch
from helpers.overlay import UpdateSession from helpers.overlay import UpdateSession
from plugins import getParameter from plugins import getParameter
from plugins import utils from plugins.alpha import utils
from plugins.alpha.block.configuration import GaugeConf from plugins.alpha.block.configuration import GaugeConf
from plugins.alpha.block.spares import Spares from plugins.alpha.block.spares import Spares
@ -97,11 +97,10 @@ class ClockTree ( object ):
trace( 550, '-' ) trace( 550, '-' )
return False return False
gaugeConf = self.spares.state.gaugeConf gaugeConf = self.spares.conf
bufferConf = self.spares.state.bufferConf bufferConf = self.spares.conf.bufferConf
ckNet = qt.bOutputPlug.getNet() ckNet = qt.bOutputPlug.getNet()
self.subNets.append( ckNet ) self.subNets.append( ckNet )
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 ) leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceContact = 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 ) 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 ) trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 ) leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 ) rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 ) leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 )
leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 ) leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 )
rightSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightSourceContact.getX(), 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 ) rightX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightContact.getX(), 0 )
tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 ) tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 )
blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 ) blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 )
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY ) gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY ) gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
gaugeConf.setStackPosition( tlContact, leftX, tlY ) gaugeConf.setStackPosition( tlContact, leftX, tlY )
gaugeConf.setStackPosition( blContact, leftX, blY ) gaugeConf.setStackPosition( blContact, leftX, blY )
gaugeConf.setStackPosition( trContact, rightX, tlY ) gaugeConf.setStackPosition( trContact, rightX, tlY )
gaugeConf.setStackPosition( brContact, rightX, blY ) gaugeConf.setStackPosition( brContact, rightX, blY )
leftContact .setX( leftX ) leftContact .setX( leftX )
leftContact .setY( leftSourceY ) leftContact .setY( leftSourceY )
rightContact.setX( rightX ) rightContact.setX( rightX )
rightContact.setY( rightSourceY ) rightContact.setY( rightSourceY )
gaugeConf.createHorizontal( leftContact , leftSourceContact, leftSourceY , 0 ) gaugeConf.createHorizontal( leftContact , leftSourceContact, leftSourceY , 0 )
gaugeConf.createHorizontal( rightSourceContact, rightContact , rightSourceY, 0 ) gaugeConf.createHorizontal( rightSourceContact, rightContact , rightSourceY, 0 )
gaugeConf.createVertical ( leftContact , blContact , leftX , 0 ) gaugeConf.createVertical ( leftContact , blContact , leftX , 0 )
gaugeConf.createVertical ( tlContact , leftContact , leftX , 0 ) gaugeConf.createVertical ( tlContact , leftContact , leftX , 0 )
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 ) gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 ) gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
if qt.isRoot(): if qt.isRoot():
ckNet = self.clockNet ckNet = self.clockNet
trace( 550, '\tRemoving any previous pin...\n' ) trace( 550, '\tRemoving any previous pin...\n' )
@ -147,24 +141,23 @@ class ClockTree ( object ):
for pin in pins: for pin in pins:
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) ) print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
pin.destroy() pin.destroy()
if not self.spares.conf.isCoreBlock:
layerGauge = gaugeConf.vRoutingGauge layerGauge = gaugeConf.vRoutingGauge
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 ) rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 ) x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 ) y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
rootPin = Pin.create( ckNet rootPin = Pin.create( ckNet
, ckNet.getName()+'.0' , ckNet.getName()+'.0'
, Pin.Direction.NORTH , Pin.Direction.NORTH
, Pin.PlacementStatus.FIXED , Pin.PlacementStatus.FIXED
, layerGauge.getLayer() , layerGauge.getLayer()
, x , x
, qt.area.getYMax() , qt.area.getYMax()
, layerGauge.getViaWidth() , layerGauge.getViaWidth()
, layerGauge.getViaWidth() , layerGauge.getViaWidth()
) )
gaugeConf.setStackPosition( rootContact, x, y ) gaugeConf.setStackPosition( rootContact, x, y )
gaugeConf.createVertical( rootContact, rootPin, x, 0 ) gaugeConf.createVertical( rootContact, rootPin, x, 0 )
for leaf in qt.leafs: for leaf in qt.leafs:
self._rrouteHTree( leaf ) self._rrouteHTree( leaf )
trace( 550, '-' ) trace( 550, '-' )
@ -189,6 +182,7 @@ class ClockTree ( object ):
Disconnect the registers from the main clock and reconnect them to Disconnect the registers from the main clock and reconnect them to
the leaf buffers of the clock tree. the leaf buffers of the clock tree.
""" """
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree quadTree = self.spares.quadTree
quadTree.bufferTag = self.clockNet.getName() quadTree.bufferTag = self.clockNet.getName()
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 ) quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
@ -197,3 +191,10 @@ class ClockTree ( object ):
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences(): for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
quadTree.attachToLeaf( plugOccurrence ) quadTree.attachToLeaf( plugOccurrence )
quadTree.rsplitNetlist() 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" | # | Python : "./plugins/block/configuration.py" |
# +-----------------------------------------------------------------+ # +-----------------------------------------------------------------+
from __future__ import print_function
import sys import sys
import re import re
import os.path import os.path
@ -36,6 +37,7 @@ from Hurricane import Instance
import CRL import CRL
from CRL import RoutingLayerGauge from CRL import RoutingLayerGauge
from helpers import trace, l, u, n from helpers import trace, l, u, n
from helpers.utils import classdecorator
from helpers.io import ErrorMessage from helpers.io import ErrorMessage
from helpers.io import WarningMessage from helpers.io import WarningMessage
from helpers.io import catch from helpers.io import catch
@ -128,8 +130,8 @@ class GaugeConf ( object ):
self.topLayerDepth = layerGauge.getDepth() self.topLayerDepth = layerGauge.getDepth()
break break
if not self.topLayerDepth: if not self.topLayerDepth:
print WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \ print( WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \
.format(self._routingGauge.getDepth()) ) .format(self._routingGauge.getDepth()) ))
self._topLayerDepth = self._routingGauge.getDepth() - 1 self._topLayerDepth = self._routingGauge.getDepth() - 1
self.horizontalDepth = -1 self.horizontalDepth = -1
@ -157,10 +159,11 @@ class GaugeConf ( object ):
return return
def _loadIoPadGauge ( self, ioPadGaugeName ): def _loadIoPadGauge ( self, ioPadGaugeName ):
trace( 550, ',+', '\tGaugeConf._loadIoPadGauge(): "{}".\n'.format(ioPadGaugeName) )
self._ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName ) self._ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName )
if not self._ioPadGauge: if not self._ioPadGauge:
print WarningMessage( 'IO pad gauge "%s" not found.' % ioPadGaugeName ) print( WarningMessage( 'IO pad gauge "{}" not found.'.format(ioPadGaugeName) ))
return trace( 550, '-' )
def isHorizontal ( self, layer ): def isHorizontal ( self, layer ):
mask = layer.getMask() mask = layer.getMask()
@ -169,8 +172,8 @@ class GaugeConf ( object ):
if lg.getDirection() == RoutingLayerGauge.Horizontal: return True if lg.getDirection() == RoutingLayerGauge.Horizontal: return True
return False return False
print ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "%s" is not part of gauge "%s", cannot know preferred direction.' \ print( ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "{}" is not part of gauge "{}", cannot know preferred direction.' \
% (layer.getName(), self._routingGauge.getName()) ) .format(layer.getName(), self._routingGauge.getName()) ))
return False return False
def isVertical ( self, layer ): return not self.isHorizontal( layer ) def isVertical ( self, layer ): return not self.isHorizontal( layer )
@ -310,7 +313,7 @@ class GaugeConf ( object ):
trace( 550, '-' ) trace( 550, '-' )
return contact1 return contact1
def rpByOccurrence ( self, occurrence, net ): def rpByOccurrence ( self, occurrence, net ):
plug = occurrence.getEntity() plug = occurrence.getEntity()
if self._plugToRp.has_key(plug): if self._plugToRp.has_key(plug):
@ -327,7 +330,7 @@ class GaugeConf ( object ):
else: else:
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea ) rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
self._plugToRp[plug] = rp 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 ): def rpByPlug ( self, plug, net ):
if self._plugToRp.has_key(plug): if self._plugToRp.has_key(plug):
@ -356,7 +359,7 @@ class GaugeConf ( object ):
segment = component segment = component
count += 1 count += 1
if 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) ] , '+ {}'.format(topContact) ]
for component in topContact.getSlaveComponents(): for component in topContact.getSlaveComponents():
message.append( '| {}'.format(component) ) message.append( '| {}'.format(component) )
@ -434,8 +437,8 @@ class IoPadConf ( object ):
self.flags = 0 self.flags = 0
self.index = None self.index = None
self._datas = list( datas ) self._datas = list( datas )
while len(self._datas) < 7: if len(self._datas) == 5: self._datas += [ None, None ]
self._datas.append( None ) elif len(self._datas) == 6: self._datas.insert( 5, None )
self._datas.append( [] ) self._datas.append( [] )
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' ) reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
m = reSpecialPads.match( self.instanceName ) m = reSpecialPads.match( self.instanceName )
@ -447,6 +450,7 @@ class IoPadConf ( object ):
else: else:
if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR
elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE
trace( 550, '\tIoPadConf._datas: {}\n'.format(self._datas) )
@property @property
def side ( self ): return self._datas[0] def side ( self ): return self._datas[0]
@ -482,7 +486,7 @@ class IoPadConf ( object ):
def coreClockNetName ( self ): return self._datas[5] def coreClockNetName ( self ): return self._datas[5]
@property @property
def nets ( self ): return self._datas[4:6] def nets ( self ): return self._datas[4:7]
@property @property
def pads ( self ): return self._datas[7] def pads ( self ): return self._datas[7]
@ -494,9 +498,11 @@ class IoPadConf ( object ):
def isBidir ( self ): return self.flags & IoPadConf.BIDIR def isBidir ( self ): return self.flags & IoPadConf.BIDIR
def __repr__ ( self ): 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(): if self.isBidir():
s += ' to:{} en:{}'.format(self.toCoreNetName,self.enableNetName) s += ' to:{} en:{}'.format(self.toCoreNetName,self.enableNetName)
if self.isTristate():
s += ' en:{}'.format(self.enableNetName)
s += '>' s += '>'
return s return s
@ -510,7 +516,8 @@ class ChipConf ( object ):
sizes mostly. sizes mostly.
""" """
def __init__ ( self ): def __init__ ( self, blockConf ):
self.blockConf = blockConf
self.name = 'chip' self.name = 'chip'
self.ioPadGauge = None self.ioPadGauge = None
self.padInstances = [] self.padInstances = []
@ -519,15 +526,20 @@ class ChipConf ( object ):
self.eastPads = [] self.eastPads = []
self.westPads = [] 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 ): def addIoPad ( self, spec, specNb ):
""" """
Add an I/O pad specification. The spec argument must be of the form: Add an I/O pad specification. The spec argument must be of the form:
""" """
ioPadConf = IoPadConf( spec ) ioPadConf = IoPadConf( spec )
if spec[0] & IoPin.SOUTH: self.southPads.append( spec[1] ) if spec[0] & IoPin.SOUTH: self.southPads.append( ioPadConf )
elif spec[0] & IoPin.NORTH: self.northPads.append( spec[1] ) elif spec[0] & IoPin.NORTH: self.northPads.append( ioPadConf )
elif spec[0] & IoPin.EAST: self.eastPads .append( spec[1] ) elif spec[0] & IoPin.EAST: self.eastPads .append( ioPadConf )
elif spec[0] & IoPin.WEST: self.westPads .append( spec[1] ) elif spec[0] & IoPin.WEST: self.westPads .append( ioPadConf )
else: else:
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf) raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf)
, '(must be NORTH, SOUTH, EAST or WEST)' ] ) , '(must be NORTH, SOUTH, EAST or WEST)' ] )
@ -666,18 +678,18 @@ class IoPin ( object ):
# else: # else:
# indexes = self.count # indexes = self.count
# if self.flags & (IoPin.NORTH | IoPin.SOUTH): # if self.flags & (IoPin.NORTH | IoPin.SOUTH):
# gauge = block.state.gaugeConf.vDeepRG # gauge = block.conf.gaugeConf.vDeepRG
# for index in indexes: # for index in indexes:
# pinName = self.stem.format(index) # pinName = self.stem.format(index)
# net = block.state.cell.getNet( pinName ) # net = block.conf.cell.getNet( pinName )
# if net is None: # if net is None:
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] )) # print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
# continue # continue
# pinName += '.{}'.format(block.state.getIoPinsCounts(net)) # pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep ) # 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) # 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 # status += 1
# trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) # trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
# pin = Pin.create( net # pin = Pin.create( net
@ -692,21 +704,21 @@ class IoPin ( object ):
# ) # )
# NetExternalComponents.setExternal( pin ) # NetExternalComponents.setExternal( pin )
# side.append( self.flags, pin ) # side.append( self.flags, pin )
# block.state.incIoPinsCounts( net ) # block.conf.incIoPinsCounts( net )
# if self.upos: self.upos + self.ustep # if self.upos: self.upos + self.ustep
# else: # else:
# gauge = block.state.gaugeConf.hDeepRG # gauge = block.conf.gaugeConf.hDeepRG
# for index in indexes: # for index in indexes:
# pinName = self.stem.format(index) # pinName = self.stem.format(index)
# net = block.state.cell.getNet( pinName ) # net = block.conf.cell.getNet( pinName )
# if net is None: # if net is None:
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] )) # print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
# continue # continue
# pinName += '.{}'.format(block.state.getIoPinsCounts(net)) # pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep ) # 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) # 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 # status += 1
# trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) # trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
# pin = Pin.create( net # pin = Pin.create( net
@ -721,18 +733,18 @@ class IoPin ( object ):
# ) # )
# NetExternalComponents.setExternal( pin ) # NetExternalComponents.setExternal( pin )
# side.append( self.flags, pin ) # side.append( self.flags, pin )
# block.state.incIoPinsCounts( net ) # block.conf.incIoPinsCounts( net )
# if self.upos: self.upos + self.ustep # if self.upos: self.upos + self.ustep
# return status # return status
# ---------------------------------------------------------------------------- # ----------------------------------------------------------------------------
# Class : "configuration.BlockState". # Class : "configuration.BlockConf".
class BlockState ( object ): class BlockConf ( GaugeConf ):
""" """
BlockState centralize all the configurations informations related to a BlockConf centralize all the configurations informations related to a
given block. given block. It must be derived/build upon a GaugeConf class.
It contains: It contains:
@ -748,15 +760,19 @@ class BlockState ( object ):
""" """
def __init__ ( self, cell, ioPins=[], ioPads=[] ): def __init__ ( self, cell, ioPins=[], ioPads=[] ):
super(BlockConf,self).__init__()
self.validated = True
self.editor = None self.editor = None
self.framework = CRL.AllianceFramework.get() self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive) self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.gaugeConf = GaugeConf()
self.bufferConf = BufferInterface( self.framework ) self.bufferConf = BufferInterface( self.framework )
self.chip = ChipConf() self.chipConf = ChipConf( self )
self.bColumns = 2 self.bColumns = 2
self.bRows = 2 self.bRows = 2
self.cell = cell self.cell = cell
self.icore = None
self.icorona = None
self.chip = None
self.fixedWidth = None self.fixedWidth = None
self.fixedHeight = None self.fixedHeight = None
self.deltaAb = [ 0, 0, 0, 0 ] self.deltaAb = [ 0, 0, 0, 0 ]
@ -768,12 +784,14 @@ class BlockState ( object ):
for ioPinSpec in ioPins: for ioPinSpec in ioPins:
self.ioPins.append( IoPin( *ioPinSpec ) ) self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(ioPads)): 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.aspectRatio = None
self.cfg.etesian.spaceMargin = None self.cfg.etesian.spaceMargin = None
self.cfg.block.spareSide = None self.cfg.block.spareSide = None
@property
def isCoreBlock ( self ): return self.chip is not None
@property @property
def bufferWidth ( self ): return self.bufferConf.width def bufferWidth ( self ): return self.bufferConf.width
@ -792,8 +810,38 @@ class BlockState ( object ):
@property @property
def yMax ( self ): return self.cell.getAbutmentBox().getYMax() 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 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 ): def createBuffer ( self ):
return self.bufferConf.createBuffer( self.cell ) 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 but closest to the parent's center area (so, ideally, on the cluster's
edge). edge).
""" """
state = cluster.bufferTree.spares.state state = cluster.bufferTree.spares.conf
self.cluster = cluster self.cluster = cluster
self.rows = {} self.rows = {}
self.iposition = None self.iposition = None
@ -96,20 +96,20 @@ class SlicedArea ( object ):
@property @property
def bInputPlug ( self ): def bInputPlug ( self ):
"""The input Plug of the buffer.""" """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 @property
def bOutputPlug ( self ): def bOutputPlug ( self ):
"""The output Plug of the buffer.""" """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 ): def buildSlicesUnder ( self ):
""" """
UNUSED. Kept as reference example. UNUSED. Kept as reference example.
Rebuild slices structure under a specific area (must be small). Rebuild slices structure under a specific area (must be small).
""" """
state = self.cluster.bufferTree.spares.state state = self.cluster.bufferTree.spares.conf
sliceHeight = state.gaugeConf.sliceHeight sliceHeight = state.sliceHeight
cell = state.cell cell = state.cell
cellAb = cell.getAbutmentBox() cellAb = cell.getAbutmentBox()
insertArea = Box( self.cluster.getCenter() ) insertArea = Box( self.cluster.getCenter() )
@ -141,7 +141,7 @@ class SlicedArea ( object ):
""" """
global af global af
catalog = af.getCatalog() 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(): for key in self.rows.keys():
row = self.rows[ key ] row = self.rows[ key ]
trace( 550, '\t+ Row:\n' ) trace( 550, '\t+ Row:\n' )
@ -189,9 +189,9 @@ class SlicedArea ( object ):
""" """
if self.iposition is None: if self.iposition is None:
raise ErrorMessage( 2, 'SlicedArea.insertBuffer(): No position defined to wedge the buffer.' ) 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() catalog = af.getCatalog()
bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width
tieLength = 0 tieLength = 0
transf = None transf = None
if self.iposition[2] & SlicedArea.REPLACE: if self.iposition[2] & SlicedArea.REPLACE:
@ -460,7 +460,7 @@ class Cluster ( object ):
def show ( self ): def show ( self ):
"""Select the RoutingPad of the cluster in the editor.""" """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 if not editor: return False
editor.unselectAll() editor.unselectAll()
editor.setCumulativeSelection( True ) editor.setCumulativeSelection( True )
@ -531,7 +531,7 @@ class BufferTree ( object ):
self.isDeepNet = True self.isDeepNet = True
self.clusterDepth = 0 self.clusterDepth = 0
self.clusters = [ [] ] self.clusters = [ [] ]
self.bufName = self.spares.state.bufferConf.name self.bufName = self.spares.conf.bufferConf.name
self.netCount = 0 self.netCount = 0
self.netName = self.net.getName() self.netName = self.net.getName()
self.netIndex = None self.netIndex = None
@ -570,7 +570,7 @@ class BufferTree ( object ):
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount ) subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
else: else:
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount ) 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 self.netCount += 1
return net return net
@ -689,7 +689,7 @@ class BufferTree ( object ):
self.clusters[-1].append( Cluster(self,cluster,self.clusterDepth+1) ) self.clusters[-1].append( Cluster(self,cluster,self.clusterDepth+1) )
#if cluster.show(): #if cluster.show():
# Breakpoint.stop( 0, 'Showing cluster of {} RoutingPads'.format(cluster.size) ) # Breakpoint.stop( 0, 'Showing cluster of {} RoutingPads'.format(cluster.size) )
editor = self.spares.state.editor editor = self.spares.conf.editor
if editor: if editor:
editor.unselectAll() editor.unselectAll()
editor.setCumulativeSelection( False ) editor.setCumulativeSelection( False )
@ -723,7 +723,7 @@ class BufferTree ( object ):
driverRpOcc = self.rpDriver.getPlugOccurrence() driverRpOcc = self.rpDriver.getPlugOccurrence()
topNetName = self.net.getName() topNetName = self.net.getName()
self.net.destroy() 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() ) deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
deepDriverNet = deepPlug.getMasterNet() deepDriverNet = deepPlug.getMasterNet()
driverRpOcc.getEntity().setNet( deepDriverNet ) driverRpOcc.getEntity().setNet( deepDriverNet )

View File

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

View File

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

View File

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

View File

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