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:
parent
0a5fbd9ff0
commit
3d33c4e66a
|
@ -61,6 +61,13 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py
|
||||
)
|
||||
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/power.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/corona.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/pads.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/chip.py
|
||||
)
|
||||
|
||||
install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
|
||||
install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins )
|
||||
|
@ -70,4 +77,5 @@
|
|||
install ( FILES ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha )
|
||||
install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block )
|
||||
install ( FILES ${pyPluginAlphaC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/core2chip )
|
||||
install ( FILES ${pyPluginAlphaChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/chip )
|
||||
#install ( PROGRAMS ${pyTools} DESTINATION bin )
|
||||
|
|
|
@ -56,7 +56,8 @@ from alpha.block.clocktree import ClockTree
|
|||
#from alpha.block.hfns2 import BufferTree
|
||||
from alpha.block.hfns3 import BufferTree
|
||||
from alpha.block.configuration import IoPin
|
||||
from alpha.block.configuration import BlockState
|
||||
from alpha.block.configuration import BlockConf
|
||||
from alpha.block.configuration import GaugeConf
|
||||
|
||||
timing.staticInit()
|
||||
|
||||
|
@ -70,8 +71,8 @@ class Side ( object ):
|
|||
and perform pins creation & placement.
|
||||
"""
|
||||
|
||||
def __init__ ( self, state, side ):
|
||||
self.state = state
|
||||
def __init__ ( self, conf, side ):
|
||||
self.conf = conf
|
||||
self.side = side
|
||||
self.pinSpecs = []
|
||||
self.expandPins = True
|
||||
|
@ -99,25 +100,25 @@ class Side ( object ):
|
|||
box has been setup.
|
||||
"""
|
||||
if self.side & IoPin.WEST:
|
||||
self.gauge = self.state.gaugeConf.hDeepRG
|
||||
self.ubegin = self.state.yMin
|
||||
self.uend = self.state.yMax
|
||||
self.sidePos = self.state.xMin
|
||||
self.gauge = self.conf.hDeepRG
|
||||
self.ubegin = self.conf.yMin
|
||||
self.uend = self.conf.yMax
|
||||
self.sidePos = self.conf.xMin
|
||||
elif self.side & IoPin.EAST:
|
||||
self.gauge = self.state.gaugeConf.hDeepRG
|
||||
self.ubegin = self.state.yMin
|
||||
self.uend = self.state.yMax
|
||||
self.sidePos = self.state.xMax
|
||||
self.gauge = self.conf.hDeepRG
|
||||
self.ubegin = self.conf.yMin
|
||||
self.uend = self.conf.yMax
|
||||
self.sidePos = self.conf.xMax
|
||||
elif self.side & IoPin.SOUTH:
|
||||
self.gauge = self.state.gaugeConf.vDeepRG
|
||||
self.ubegin = self.state.xMin
|
||||
self.uend = self.state.xMax
|
||||
self.sidePos = self.state.yMin
|
||||
self.gauge = self.conf.vDeepRG
|
||||
self.ubegin = self.conf.xMin
|
||||
self.uend = self.conf.xMax
|
||||
self.sidePos = self.conf.yMin
|
||||
elif self.side & IoPin.NORTH:
|
||||
self.gauge = self.state.gaugeConf.vDeepRG
|
||||
self.ubegin = self.state.xMin
|
||||
self.uend = self.state.xMax
|
||||
self.sidePos = self.state.yMax
|
||||
self.gauge = self.conf.vDeepRG
|
||||
self.ubegin = self.conf.xMin
|
||||
self.uend = self.conf.xMax
|
||||
self.sidePos = self.conf.yMax
|
||||
|
||||
def getNextPinPosition ( self, flags, upos, ustep ):
|
||||
"""
|
||||
|
@ -179,26 +180,26 @@ class Side ( object ):
|
|||
|
||||
status = 0
|
||||
if self.side & (IoPin.NORTH | IoPin.SOUTH):
|
||||
gauge = self.state.gaugeConf.vDeepRG
|
||||
gauge = self.conf.vDeepRG
|
||||
upos = ioPin.upos
|
||||
for index in ioPin.indexes:
|
||||
pinName = ioPin.stem.format( index )
|
||||
net = self.state.cell.getNet( pinName )
|
||||
net = self.conf.cell.getNet( pinName )
|
||||
if net is None:
|
||||
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
|
||||
continue
|
||||
if net.isClock() and self.state.useClockTree:
|
||||
if net.isClock() and self.conf.useClockTree:
|
||||
print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) ))
|
||||
continue
|
||||
pinName += '.{}'.format(self.state.getIoPinsCounts(net))
|
||||
pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
|
||||
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
|
||||
if pinPos.getX() > self.state.xMax or pinPos.getX() < self.state.xMin:
|
||||
if pinPos.getX() > self.conf.xMax or pinPos.getX() < self.conf.xMin:
|
||||
print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside north or south abutment box side.' \
|
||||
.format(pinName)
|
||||
, '(x:{}, xAB: [{}:{}])' \
|
||||
.format( DbU.getValueString(pinPos.getX())
|
||||
, DbU.getValueString(self.state.xMin)
|
||||
, DbU.getValueString(self.state.xMax) ) ] ))
|
||||
, DbU.getValueString(self.conf.xMin)
|
||||
, DbU.getValueString(self.conf.xMax) ) ] ))
|
||||
status += 1
|
||||
trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
|
||||
pin = Pin.create( net
|
||||
|
@ -213,26 +214,26 @@ class Side ( object ):
|
|||
)
|
||||
NetExternalComponents.setExternal( pin )
|
||||
self.append( pin )
|
||||
self.state.incIoPinsCounts( net )
|
||||
self.conf.incIoPinsCounts( net )
|
||||
if upos: upos += ioPin.ustep
|
||||
else:
|
||||
gauge = self.state.gaugeConf.hDeepRG
|
||||
gauge = self.conf.hDeepRG
|
||||
upos = ioPin.upos
|
||||
for index in ioPin.indexes:
|
||||
pinName = ioPin.stem.format(index)
|
||||
net = self.state.cell.getNet( pinName )
|
||||
net = self.conf.cell.getNet( pinName )
|
||||
if net is None:
|
||||
print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] ))
|
||||
continue
|
||||
pinName += '.{}'.format(self.state.getIoPinsCounts(net))
|
||||
pinName += '.{}'.format(self.conf.getIoPinsCounts(net))
|
||||
pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep )
|
||||
if pinPos.getY() > self.state.yMax or pinPos.getY() < self.state.yMin:
|
||||
if pinPos.getY() > self.conf.yMax or pinPos.getY() < self.conf.yMin:
|
||||
print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside east or west abutment box side.' \
|
||||
.format(pinName)
|
||||
, '(y:{}, yAB: [{}:{}])' \
|
||||
.format( DbU.getValueString(pinPos.getY())
|
||||
, DbU.getValueString(self.state.yMin)
|
||||
, DbU.getValueString(self.state.yMax)) ] ))
|
||||
, DbU.getValueString(self.conf.yMin)
|
||||
, DbU.getValueString(self.conf.yMax)) ] ))
|
||||
status += 1
|
||||
trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
|
||||
pin = Pin.create( net
|
||||
|
@ -247,7 +248,7 @@ class Side ( object ):
|
|||
)
|
||||
NetExternalComponents.setExternal( pin )
|
||||
self.append( pin )
|
||||
self.state.incIoPinsCounts( net )
|
||||
self.conf.incIoPinsCounts( net )
|
||||
if upos: upos += ioPin.ustep
|
||||
return status
|
||||
|
||||
|
@ -257,7 +258,7 @@ class Side ( object ):
|
|||
of the abutment box. THey will stick out for one pitch.
|
||||
"""
|
||||
if not self.expandPins: return
|
||||
rg = self.state.gaugeConf.routingGauge
|
||||
rg = self.conf.routingGauge
|
||||
for pinsAtPos in self.pins.values():
|
||||
for pin in pinsAtPos:
|
||||
for lg in rg.getLayerGauges():
|
||||
|
@ -285,7 +286,7 @@ class Side ( object ):
|
|||
for pin in self.pins[upos][1:]:
|
||||
pinNames += ', ' + pin.getName()
|
||||
print( ErrorMessage( 1, [ 'Side.checkOverlap(): On {} side of block "{}", {} pins ovelaps.' \
|
||||
.format(sideName,self.state.cell.getName(),count)
|
||||
.format(sideName,self.conf.cell.getName(),count)
|
||||
, '(@{}: {})' \
|
||||
.format(DbU.getValueString(upos),pinNames) ] ) )
|
||||
|
||||
|
@ -308,34 +309,31 @@ class Block ( object ):
|
|||
if Block.LUT.has_key(cell): return Block.LUT[cell]
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def create ( cell, ioPins=[], ioPads=[] ):
|
||||
"""Create a Block and it's configuration object."""
|
||||
block = Block( BlockState( cell, ioPins, ioPads ) )
|
||||
Block.LUT[ cell ] = block
|
||||
return block
|
||||
|
||||
def __init__ ( self, state ):
|
||||
"""Not to be used directly, please see Block.create()."""
|
||||
def __init__ ( self, conf ):
|
||||
"""
|
||||
Create a Block object. The only parameter ``conf`` must be a BlockConf
|
||||
object which contains the complete block configuration.
|
||||
"""
|
||||
self.flags = 0
|
||||
self.state = state
|
||||
self.conf = conf
|
||||
self.spares = Spares( self )
|
||||
self.clockTrees = []
|
||||
self.hfnTrees = []
|
||||
self.blockInstances = []
|
||||
self.sides = { IoPin.WEST : Side( self.state, IoPin.WEST )
|
||||
, IoPin.EAST : Side( self.state, IoPin.EAST )
|
||||
, IoPin.SOUTH : Side( self.state, IoPin.SOUTH )
|
||||
, IoPin.NORTH : Side( self.state, IoPin.NORTH )
|
||||
self.sides = { IoPin.WEST : Side( self.conf, IoPin.WEST )
|
||||
, IoPin.EAST : Side( self.conf, IoPin.EAST )
|
||||
, IoPin.SOUTH : Side( self.conf, IoPin.SOUTH )
|
||||
, IoPin.NORTH : Side( self.conf, IoPin.NORTH )
|
||||
}
|
||||
if not self.state.cell.getAbutmentBox().isEmpty():
|
||||
if not self.conf.cell.getAbutmentBox().isEmpty():
|
||||
print( ' o Block "{}" is already done, reusing layout.' \
|
||||
.format(self.state.cell.getName()) )
|
||||
self.state.cell.setTerminalNetlist( True )
|
||||
self.state.isBuilt = True
|
||||
.format(self.conf.cell.getName()) )
|
||||
self.conf.cell.setTerminalNetlist( True )
|
||||
self.conf.isBuilt = True
|
||||
else:
|
||||
print( ' o Block "{}" will be generated.' \
|
||||
.format(self.state.cell.getName()) )
|
||||
.format(self.conf.cell.getName()) )
|
||||
Block.LUT[ self.conf.cell ] = self
|
||||
|
||||
def setUnexpandPins ( self, sides ):
|
||||
"""
|
||||
|
@ -359,48 +357,57 @@ class Block ( object ):
|
|||
various configuration parameters (aspect ratio, space margin, fixed
|
||||
height or width, ...).
|
||||
"""
|
||||
if not self.state.cell.getAbutmentBox().isEmpty():
|
||||
trace( 550, '\tBlockConf.setupAb() {}\n'.format(self.conf.cell) )
|
||||
if not self.conf.cell.getAbutmentBox().isEmpty():
|
||||
pass
|
||||
elif not self.conf.coreAb.isEmpty():
|
||||
self.conf.core.setAbutmentBox( self.conf.coreAb )
|
||||
elif len(self.blockInstances):
|
||||
with UpdateSession():
|
||||
ab = Box( 0, 0, self.state.fixedWidth, self.state.fixedHeight )
|
||||
self.state.cell.setAbutmentBox( ab )
|
||||
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences():
|
||||
ab = Box( 0, 0, self.conf.fixedWidth, self.conf.fixedHeight )
|
||||
self.conf.cell.setAbutmentBox( ab )
|
||||
for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
|
||||
instance = occurrence.getEntity()
|
||||
subCell = instance.getMasterCell()
|
||||
subCell.setAbutmentBox( ab )
|
||||
for occurrence in self.state.cell.getNonTerminalNetlistInstanceOccurrences():
|
||||
for occurrence in self.conf.cell.getNonTerminalNetlistInstanceOccurrences():
|
||||
instance = occurrence.getEntity()
|
||||
instance.setTransformation( Transformation() )
|
||||
for blockInstance in self.blockInstances:
|
||||
blockInstance.place()
|
||||
else:
|
||||
sysSpaceMargin = self.state.cfg.etesian.spaceMargin
|
||||
sysSpaceMargin = self.conf.cfg.etesian.spaceMargin
|
||||
blockSpaceMargin = sysSpaceMargin + self.spares.getSpareSpaceMargin()
|
||||
self.state.cfg.etesian.spaceMargin = blockSpaceMargin
|
||||
self.state.cfg.apply()
|
||||
self.conf.cfg.etesian.spaceMargin = blockSpaceMargin
|
||||
self.conf.cfg.apply()
|
||||
with UpdateSession():
|
||||
etesian = Etesian.EtesianEngine.create( self.state.cell )
|
||||
if self.state.fixedWidth: etesian.setFixedAbWidth ( self.state.fixedWidth )
|
||||
if self.state.fixedHeight: etesian.setFixedAbHeight( self.state.fixedHeight )
|
||||
etesian = Etesian.EtesianEngine.create( self.conf.cell )
|
||||
if self.conf.fixedWidth: etesian.setFixedAbWidth ( self.conf.fixedWidth )
|
||||
if self.conf.fixedHeight: etesian.setFixedAbHeight( self.conf.fixedHeight )
|
||||
etesian.setDefaultAb()
|
||||
etesian.destroy()
|
||||
self.state.cfg.etesian.spaceMargin = sysSpaceMargin
|
||||
self.state.cfg.apply()
|
||||
self.conf.cfg.etesian.spaceMargin = sysSpaceMargin
|
||||
self.conf.cfg.apply()
|
||||
ab = self.conf.cell.getAbutmentBox()
|
||||
self.conf.coreSize = (ab.getWidth(), ab.getHeight())
|
||||
trace( 550, '\tSetting core ab from Cell:{}\n'.format(self.conf.coreAb) )
|
||||
for side in self.sides.values(): side.setupAb()
|
||||
trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) )
|
||||
if self.conf.isCoreBlock:
|
||||
self.conf.setupICore()
|
||||
|
||||
def addClockTrees ( self ):
|
||||
"""Create the trunk of all the clock trees (recursive H-Tree)."""
|
||||
print( ' o Building clock tree(s).' )
|
||||
af = CRL.AllianceFramework.get()
|
||||
clockNets = []
|
||||
for net in self.state.cell.getNets():
|
||||
for net in self.conf.cell.getNets():
|
||||
if af.isCLOCK(net.getName()): 'CLOCK: {}'.format(net)
|
||||
if net.isClock():
|
||||
trace( 550, '\tBlock.addClockTrees(): Found clock {}.\n'.format(net) )
|
||||
clockNets.append( net )
|
||||
if not clockNets:
|
||||
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.state.cell.getName()) )
|
||||
raise ErrorMessage( 3, 'Block.clockTree(): Cell "{}" has no clock net(s).'.format(self.conf.cell.getName()) )
|
||||
with UpdateSession():
|
||||
for clockNet in clockNets:
|
||||
print( ' - "{}".'.format(clockNet.getName()) )
|
||||
|
@ -421,12 +428,12 @@ class Block ( object ):
|
|||
"""Create the trunk of all the high fanout nets."""
|
||||
print( ' o Building high fanout nets trees.' )
|
||||
if self.spares:
|
||||
maxSinks = timing.tech.getSinksEstimate( self.state.bufferConf.name )
|
||||
maxSinks = timing.tech.getSinksEstimate( self.conf.bufferConf.name )
|
||||
dots( 82
|
||||
, ' - Max sinks for buffer "{}"'.format(self.state.bufferConf.name)
|
||||
, ' - Max sinks for buffer "{}"'.format(self.conf.bufferConf.name)
|
||||
, ' {}'.format(maxSinks) )
|
||||
nets = []
|
||||
for net in self.state.cell.getNets():
|
||||
for net in self.conf.cell.getNets():
|
||||
sinksCount = 0
|
||||
for rp in net.getRoutingPads(): sinksCount += 1
|
||||
if sinksCount > maxSinks:
|
||||
|
@ -459,7 +466,7 @@ class Block ( object ):
|
|||
"""
|
||||
faileds = 0
|
||||
with UpdateSession():
|
||||
for ioPin in self.state.ioPins:
|
||||
for ioPin in self.conf.ioPins:
|
||||
if ioPin.flags & IoPin.SOUTH: side = self.sides[IoPin.SOUTH]
|
||||
elif ioPin.flags & IoPin.NORTH: side = self.sides[IoPin.NORTH]
|
||||
elif ioPin.flags & IoPin.EAST: side = self.sides[IoPin.EAST ]
|
||||
|
@ -467,7 +474,7 @@ class Block ( object ):
|
|||
faileds += side.place( ioPin )
|
||||
if faileds:
|
||||
raise ErrorMessage( 3, 'Block.placeIoPins(): Cell "{}" has {} badly placed pins.' \
|
||||
.format(self.state.cell.getName(),faileds) )
|
||||
.format(self.conf.cell.getName(),faileds) )
|
||||
|
||||
def checkIoPins ( self ):
|
||||
"""
|
||||
|
@ -475,7 +482,7 @@ class Block ( object ):
|
|||
"""
|
||||
for side in self.sides.values():
|
||||
side.checkOverlaps()
|
||||
for net in self.state.cell.getNets():
|
||||
for net in self.conf.cell.getNets():
|
||||
if not net.isExternal(): continue
|
||||
if net.isSupply(): continue
|
||||
hasPins = False
|
||||
|
@ -496,12 +503,17 @@ class Block ( object ):
|
|||
side.expand()
|
||||
|
||||
def place ( self ):
|
||||
etesian = Etesian.EtesianEngine.create( self.state.cell )
|
||||
if self.conf.isCoreBlock:
|
||||
etesian = Etesian.EtesianEngine.create( self.conf.corona )
|
||||
etesian.setBlock( self.conf.icore )
|
||||
else:
|
||||
etesian = Etesian.EtesianEngine.create( self.conf.cell )
|
||||
etesian.place()
|
||||
etesian.destroy()
|
||||
|
||||
def route ( self ):
|
||||
katana = Katana.KatanaEngine.create( self.state.cell )
|
||||
routedCell = self.conf.corona if self.conf.isCoreBlock else self.conf.cell
|
||||
katana = Katana.KatanaEngine.create( routedCell )
|
||||
#katana.printConfiguration ()
|
||||
katana.digitalInit ()
|
||||
#katana.runNegociatePreRouted()
|
||||
|
@ -519,9 +531,9 @@ class Block ( object ):
|
|||
|
||||
def addBlockages ( self ):
|
||||
with UpdateSession():
|
||||
net = self.state.cell.getNet( 'blockagenet' )
|
||||
ab = self.state.cell.getAbutmentBox()
|
||||
rg = self.state.gaugeConf.routingGauge
|
||||
net = self.conf.cell.getNet( 'blockagenet' )
|
||||
ab = self.conf.cell.getAbutmentBox()
|
||||
rg = self.conf.routingGauge
|
||||
for lg in rg.getLayerGauges():
|
||||
if lg.getType() == RoutingLayerGauge.PinOnly: continue
|
||||
blockage = lg.getBlockageLayer()
|
||||
|
@ -545,44 +557,46 @@ class Block ( object ):
|
|||
, ab.getYMax() - dyBorder
|
||||
)
|
||||
|
||||
def build ( self ):
|
||||
def doPnR ( self ):
|
||||
"""
|
||||
Perform all the steps required to build the layout of the block.
|
||||
The first step is to build all the blockInstance it depends upon,
|
||||
so they will appear as ``NetListTerminal`` and we can place them
|
||||
in their parent cell.
|
||||
"""
|
||||
editor = self.state.editor
|
||||
print( ' o Builing block "{}".'.format(self.state.cell.getName()) )
|
||||
editor = self.conf.editor
|
||||
print( ' o Builing block "{}".'.format(self.conf.cell.getName()) )
|
||||
for blockInstance in self.blockInstances:
|
||||
blockInstance.block.state.editor = editor
|
||||
if not blockInstance.block.state.isBuilt:
|
||||
blockInstance.block.conf.editor = editor
|
||||
if not blockInstance.block.conf.isBuilt:
|
||||
print( ' - Build sub-block "{}".' \
|
||||
.format(blockInstance.block.state.cell.getName()) )
|
||||
.format(blockInstance.block.conf.cell.getName()) )
|
||||
blockInstance.block.build()
|
||||
if editor: editor.setCell( self.state.cell )
|
||||
self.state.cfg.apply()
|
||||
if editor: editor.setCell( self.conf.cell )
|
||||
self.conf.cfg.apply()
|
||||
iteration = -1
|
||||
while True:
|
||||
iteration += 1
|
||||
if iteration > 0: break
|
||||
self.setupAb()
|
||||
self.placeIoPins()
|
||||
self.checkIoPins()
|
||||
if not self.conf.isCoreBlock:
|
||||
self.placeIoPins()
|
||||
self.checkIoPins()
|
||||
self.spares.build()
|
||||
if self.state.useClockTree: self.addClockTrees()
|
||||
if self.conf.useClockTree: self.addClockTrees()
|
||||
self.addHfnBuffers()
|
||||
if editor: editor.fit()
|
||||
#Breakpoint.stop( 0, 'Clock tree(s) done.' )
|
||||
self.place()
|
||||
self.findHfnTrees()
|
||||
break
|
||||
if self.state.useClockTree: self.splitClocks()
|
||||
if self.conf.useClockTree: self.splitClocks()
|
||||
if self.conf.isCoreBlock: self.doConnectCore()
|
||||
status = self.route()
|
||||
self.addBlockages()
|
||||
self.expandIoPins()
|
||||
self.state.isBuilt = True
|
||||
plugins.rsave.rsave( self.state.cell )
|
||||
if not self.conf.isCoreBlock:
|
||||
self.addBlockages()
|
||||
self.expandIoPins()
|
||||
self.conf.isBuilt = True
|
||||
return status
|
||||
|
||||
def useBlockInstance ( self, instancePathName , transf ):
|
||||
|
@ -602,7 +616,7 @@ class Block ( object ):
|
|||
iNames = instancePathName.split('.')
|
||||
path = Path()
|
||||
for iName in iNames:
|
||||
if path.isEmpty(): parentCell = self.state.cell
|
||||
if path.isEmpty(): parentCell = self.conf.cell
|
||||
else: parentCell = path.getTailInstance().getMasterCell()
|
||||
instance = parentCell.getInstance( iName )
|
||||
if not instance:
|
||||
|
@ -620,6 +634,11 @@ class Block ( object ):
|
|||
return
|
||||
blockIns = BlockInstance( tailInstance, transf )
|
||||
self.blockInstances.append( blockIns )
|
||||
|
||||
def save ( self ):
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'block.save(): Chip is not valid, aborting.' )
|
||||
self.spares.save()
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
|
|
@ -42,7 +42,7 @@ from helpers.io import WarningMessage
|
|||
from helpers.io import catch
|
||||
from helpers.overlay import UpdateSession
|
||||
from plugins import getParameter
|
||||
from plugins import utils
|
||||
from plugins.alpha import utils
|
||||
from plugins.alpha.block.configuration import GaugeConf
|
||||
from plugins.alpha.block.spares import Spares
|
||||
|
||||
|
@ -97,11 +97,10 @@ class ClockTree ( object ):
|
|||
trace( 550, '-' )
|
||||
return False
|
||||
|
||||
gaugeConf = self.spares.state.gaugeConf
|
||||
bufferConf = self.spares.state.bufferConf
|
||||
gaugeConf = self.spares.conf
|
||||
bufferConf = self.spares.conf.bufferConf
|
||||
ckNet = qt.bOutputPlug.getNet()
|
||||
self.subNets.append( ckNet )
|
||||
|
||||
leftSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
||||
rightSourceContact = gaugeConf.rpAccessByPlugName( qt.buffer , bufferConf.output, ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
|
||||
blContact = gaugeConf.rpAccessByPlugName( qt.bl.buffer, bufferConf.input , ckNet )
|
||||
|
@ -110,7 +109,6 @@ class ClockTree ( object ):
|
|||
trContact = gaugeConf.rpAccessByPlugName( qt.tr.buffer, bufferConf.input , ckNet )
|
||||
leftContact = gaugeConf.createContact( ckNet, blContact.getX(), leftSourceContact.getY(), 0 )
|
||||
rightContact = gaugeConf.createContact( ckNet, brContact.getX(), rightSourceContact.getY(), 0 )
|
||||
|
||||
leftSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, leftSourceContact.getX(), 0 )
|
||||
leftSourceY = gaugeConf.getNearestHorizontalTrack( qt.root.area, leftSourceContact.getY(), 0 )
|
||||
rightSourceX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightSourceContact.getX(), 0 )
|
||||
|
@ -119,26 +117,22 @@ class ClockTree ( object ):
|
|||
rightX = gaugeConf.getNearestVerticalTrack ( qt.root.area, rightContact.getX(), 0 )
|
||||
tlY = gaugeConf.getNearestHorizontalTrack( qt.root.area, tlContact.getY(), 0 )
|
||||
blY = gaugeConf.getNearestHorizontalTrack( qt.root.area, blContact.getY(), 0 )
|
||||
|
||||
gaugeConf.setStackPosition( leftSourceContact, leftSourceX, leftSourceY )
|
||||
gaugeConf.setStackPosition( rightSourceContact, rightSourceX, rightSourceY )
|
||||
gaugeConf.setStackPosition( tlContact, leftX, tlY )
|
||||
gaugeConf.setStackPosition( blContact, leftX, blY )
|
||||
gaugeConf.setStackPosition( trContact, rightX, tlY )
|
||||
gaugeConf.setStackPosition( brContact, rightX, blY )
|
||||
|
||||
leftContact .setX( leftX )
|
||||
leftContact .setY( leftSourceY )
|
||||
rightContact.setX( rightX )
|
||||
rightContact.setY( rightSourceY )
|
||||
|
||||
gaugeConf.createHorizontal( leftContact , leftSourceContact, leftSourceY , 0 )
|
||||
gaugeConf.createHorizontal( rightSourceContact, rightContact , rightSourceY, 0 )
|
||||
gaugeConf.createVertical ( leftContact , blContact , leftX , 0 )
|
||||
gaugeConf.createVertical ( tlContact , leftContact , leftX , 0 )
|
||||
gaugeConf.createVertical ( rightContact , brContact , rightX , 0 )
|
||||
gaugeConf.createVertical ( trContact , rightContact , rightX , 0 )
|
||||
|
||||
if qt.isRoot():
|
||||
ckNet = self.clockNet
|
||||
trace( 550, '\tRemoving any previous pin...\n' )
|
||||
|
@ -147,24 +141,23 @@ class ClockTree ( object ):
|
|||
for pin in pins:
|
||||
print( WarningMessage('ClockTree._rrouteHTree(): Removing {}.'.format(pin)) )
|
||||
pin.destroy()
|
||||
|
||||
layerGauge = gaugeConf.vRoutingGauge
|
||||
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
||||
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
|
||||
rootPin = Pin.create( ckNet
|
||||
, ckNet.getName()+'.0'
|
||||
, Pin.Direction.NORTH
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, layerGauge.getLayer()
|
||||
, x
|
||||
, qt.area.getYMax()
|
||||
, layerGauge.getViaWidth()
|
||||
, layerGauge.getViaWidth()
|
||||
)
|
||||
gaugeConf.setStackPosition( rootContact, x, y )
|
||||
gaugeConf.createVertical( rootContact, rootPin, x, 0 )
|
||||
|
||||
if not self.spares.conf.isCoreBlock:
|
||||
layerGauge = gaugeConf.vRoutingGauge
|
||||
rootContact = gaugeConf.rpAccessByPlugName( qt.buffer, bufferConf.input, ckNet, 0 )
|
||||
x = gaugeConf.getNearestVerticalTrack ( qt.area, rootContact.getX(), 0 )
|
||||
y = gaugeConf.getNearestHorizontalTrack( qt.area, rootContact.getY(), 0 )
|
||||
rootPin = Pin.create( ckNet
|
||||
, ckNet.getName()+'.0'
|
||||
, Pin.Direction.NORTH
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, layerGauge.getLayer()
|
||||
, x
|
||||
, qt.area.getYMax()
|
||||
, layerGauge.getViaWidth()
|
||||
, layerGauge.getViaWidth()
|
||||
)
|
||||
gaugeConf.setStackPosition( rootContact, x, y )
|
||||
gaugeConf.createVertical( rootContact, rootPin, x, 0 )
|
||||
for leaf in qt.leafs:
|
||||
self._rrouteHTree( leaf )
|
||||
trace( 550, '-' )
|
||||
|
@ -189,6 +182,7 @@ class ClockTree ( object ):
|
|||
Disconnect the registers from the main clock and reconnect them to
|
||||
the leaf buffers of the clock tree.
|
||||
"""
|
||||
bufferConf = self.spares.conf.bufferConf
|
||||
quadTree = self.spares.quadTree
|
||||
quadTree.bufferTag = self.clockNet.getName()
|
||||
quadTree.rselectBuffer( self.clockIndex, self.clockIndex, 0 )
|
||||
|
@ -197,3 +191,10 @@ class ClockTree ( object ):
|
|||
for plugOccurrence in hyperClock.getTerminalNetlistPlugOccurrences():
|
||||
quadTree.attachToLeaf( plugOccurrence )
|
||||
quadTree.rsplitNetlist()
|
||||
if self.spares.conf.isCoreBlock:
|
||||
plug = utils.getPlugByName( quadTree.buffer, bufferConf.input )
|
||||
plug.setNet( self.clockNet )
|
||||
trace( 550, '\tCore mode, setting only root plug "{}"\n'.format(self.clockNet.getName()) )
|
||||
trace( 550, '\tPlug of "{}"\n'.format(self.clockNet.getName()) )
|
||||
for plug in self.clockNet.getPlugs():
|
||||
trace( 550, '\t| {}\n'.format(plug) )
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# | Python : "./plugins/block/configuration.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
from __future__ import print_function
|
||||
import sys
|
||||
import re
|
||||
import os.path
|
||||
|
@ -36,6 +37,7 @@ from Hurricane import Instance
|
|||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace, l, u, n
|
||||
from helpers.utils import classdecorator
|
||||
from helpers.io import ErrorMessage
|
||||
from helpers.io import WarningMessage
|
||||
from helpers.io import catch
|
||||
|
@ -128,8 +130,8 @@ class GaugeConf ( object ):
|
|||
self.topLayerDepth = layerGauge.getDepth()
|
||||
break
|
||||
if not self.topLayerDepth:
|
||||
print WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \
|
||||
.format(self._routingGauge.getDepth()) )
|
||||
print( WarningMessage( 'Gauge top layer not defined, using top of gauge ({}).' \
|
||||
.format(self._routingGauge.getDepth()) ))
|
||||
self._topLayerDepth = self._routingGauge.getDepth() - 1
|
||||
|
||||
self.horizontalDepth = -1
|
||||
|
@ -157,10 +159,11 @@ class GaugeConf ( object ):
|
|||
return
|
||||
|
||||
def _loadIoPadGauge ( self, ioPadGaugeName ):
|
||||
trace( 550, ',+', '\tGaugeConf._loadIoPadGauge(): "{}".\n'.format(ioPadGaugeName) )
|
||||
self._ioPadGauge = CRL.AllianceFramework.get().getCellGauge( ioPadGaugeName )
|
||||
if not self._ioPadGauge:
|
||||
print WarningMessage( 'IO pad gauge "%s" not found.' % ioPadGaugeName )
|
||||
return
|
||||
print( WarningMessage( 'IO pad gauge "{}" not found.'.format(ioPadGaugeName) ))
|
||||
trace( 550, '-' )
|
||||
|
||||
def isHorizontal ( self, layer ):
|
||||
mask = layer.getMask()
|
||||
|
@ -169,8 +172,8 @@ class GaugeConf ( object ):
|
|||
if lg.getDirection() == RoutingLayerGauge.Horizontal: return True
|
||||
return False
|
||||
|
||||
print ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "%s" is not part of gauge "%s", cannot know preferred direction.' \
|
||||
% (layer.getName(), self._routingGauge.getName()) )
|
||||
print( ErrorMessage( 1, 'GaugeConf.isHorizontal(): Layer "{}" is not part of gauge "{}", cannot know preferred direction.' \
|
||||
.format(layer.getName(), self._routingGauge.getName()) ))
|
||||
return False
|
||||
|
||||
def isVertical ( self, layer ): return not self.isHorizontal( layer )
|
||||
|
@ -310,7 +313,7 @@ class GaugeConf ( object ):
|
|||
|
||||
trace( 550, '-' )
|
||||
return contact1
|
||||
|
||||
|
||||
def rpByOccurrence ( self, occurrence, net ):
|
||||
plug = occurrence.getEntity()
|
||||
if self._plugToRp.has_key(plug):
|
||||
|
@ -327,7 +330,7 @@ class GaugeConf ( object ):
|
|||
else:
|
||||
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
||||
self._plugToRp[plug] = rp
|
||||
return self.rpAccess( self._rpByOccurrence(occurrence,net), flags )
|
||||
return self.rpAccess( self.rpByOccurrence(occurrence,net), flags )
|
||||
|
||||
def rpByPlug ( self, plug, net ):
|
||||
if self._plugToRp.has_key(plug):
|
||||
|
@ -356,7 +359,7 @@ class GaugeConf ( object ):
|
|||
segment = component
|
||||
count += 1
|
||||
if count > 1:
|
||||
message = [ 'GaugeConf::_setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count)
|
||||
message = [ 'GaugeConf::setStackPosition(): There must be exactly one segment connected to contact, not {}.'.format(count)
|
||||
, '+ {}'.format(topContact) ]
|
||||
for component in topContact.getSlaveComponents():
|
||||
message.append( '| {}'.format(component) )
|
||||
|
@ -434,8 +437,8 @@ class IoPadConf ( object ):
|
|||
self.flags = 0
|
||||
self.index = None
|
||||
self._datas = list( datas )
|
||||
while len(self._datas) < 7:
|
||||
self._datas.append( None )
|
||||
if len(self._datas) == 5: self._datas += [ None, None ]
|
||||
elif len(self._datas) == 6: self._datas.insert( 5, None )
|
||||
self._datas.append( [] )
|
||||
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
|
||||
m = reSpecialPads.match( self.instanceName )
|
||||
|
@ -447,6 +450,7 @@ class IoPadConf ( object ):
|
|||
else:
|
||||
if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR
|
||||
elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE
|
||||
trace( 550, '\tIoPadConf._datas: {}\n'.format(self._datas) )
|
||||
|
||||
@property
|
||||
def side ( self ): return self._datas[0]
|
||||
|
@ -482,7 +486,7 @@ class IoPadConf ( object ):
|
|||
def coreClockNetName ( self ): return self._datas[5]
|
||||
|
||||
@property
|
||||
def nets ( self ): return self._datas[4:6]
|
||||
def nets ( self ): return self._datas[4:7]
|
||||
|
||||
@property
|
||||
def pads ( self ): return self._datas[7]
|
||||
|
@ -494,9 +498,11 @@ class IoPadConf ( object ):
|
|||
def isBidir ( self ): return self.flags & IoPadConf.BIDIR
|
||||
|
||||
def __repr__ ( self ):
|
||||
s = '<IoPadConf %s pad:{} from:{}'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
|
||||
s = '<IoPadConf {} pad:{} from:{}'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
|
||||
if self.isBidir():
|
||||
s += ' to:{} en:{}'.format(self.toCoreNetName,self.enableNetName)
|
||||
if self.isTristate():
|
||||
s += ' en:{}'.format(self.enableNetName)
|
||||
s += '>'
|
||||
return s
|
||||
|
||||
|
@ -510,7 +516,8 @@ class ChipConf ( object ):
|
|||
sizes mostly.
|
||||
"""
|
||||
|
||||
def __init__ ( self ):
|
||||
def __init__ ( self, blockConf ):
|
||||
self.blockConf = blockConf
|
||||
self.name = 'chip'
|
||||
self.ioPadGauge = None
|
||||
self.padInstances = []
|
||||
|
@ -519,15 +526,20 @@ class ChipConf ( object ):
|
|||
self.eastPads = []
|
||||
self.westPads = []
|
||||
|
||||
def __setattr__ ( self, attr, value ):
|
||||
object.__setattr__( self, attr, value )
|
||||
if attr == 'ioPadGauge' and value is not None:
|
||||
self.blockConf._loadIoPadGauge( value )
|
||||
|
||||
def addIoPad ( self, spec, specNb ):
|
||||
"""
|
||||
Add an I/O pad specification. The spec argument must be of the form:
|
||||
"""
|
||||
ioPadConf = IoPadConf( spec )
|
||||
if spec[0] & IoPin.SOUTH: self.southPads.append( spec[1] )
|
||||
elif spec[0] & IoPin.NORTH: self.northPads.append( spec[1] )
|
||||
elif spec[0] & IoPin.EAST: self.eastPads .append( spec[1] )
|
||||
elif spec[0] & IoPin.WEST: self.westPads .append( spec[1] )
|
||||
if spec[0] & IoPin.SOUTH: self.southPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.NORTH: self.northPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.EAST: self.eastPads .append( ioPadConf )
|
||||
elif spec[0] & IoPin.WEST: self.westPads .append( ioPadConf )
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf)
|
||||
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
|
||||
|
@ -666,18 +678,18 @@ class IoPin ( object ):
|
|||
# else:
|
||||
# indexes = self.count
|
||||
# if self.flags & (IoPin.NORTH | IoPin.SOUTH):
|
||||
# gauge = block.state.gaugeConf.vDeepRG
|
||||
# gauge = block.conf.gaugeConf.vDeepRG
|
||||
# for index in indexes:
|
||||
# pinName = self.stem.format(index)
|
||||
# net = block.state.cell.getNet( pinName )
|
||||
# net = block.conf.cell.getNet( pinName )
|
||||
# if net is None:
|
||||
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
|
||||
# continue
|
||||
# pinName += '.{}'.format(block.state.getIoPinsCounts(net))
|
||||
# pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
|
||||
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep )
|
||||
# if pinPos.getX() > block.state.xMax or pinPos.getX() < block.state.xMin:
|
||||
# if pinPos.getX() > block.conf.xMax or pinPos.getX() < block.conf.xMin:
|
||||
# print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside north or south abutment box side.'.format(pinName)
|
||||
# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.state.xMax)) ] ))
|
||||
# , '(x:"{}", AB xMax:{})'.format(DbU.getValueString(pinPos.getX()),DbU.getValueString(block.conf.xMax)) ] ))
|
||||
# status += 1
|
||||
# trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
|
||||
# pin = Pin.create( net
|
||||
|
@ -692,21 +704,21 @@ class IoPin ( object ):
|
|||
# )
|
||||
# NetExternalComponents.setExternal( pin )
|
||||
# side.append( self.flags, pin )
|
||||
# block.state.incIoPinsCounts( net )
|
||||
# block.conf.incIoPinsCounts( net )
|
||||
# if self.upos: self.upos + self.ustep
|
||||
# else:
|
||||
# gauge = block.state.gaugeConf.hDeepRG
|
||||
# gauge = block.conf.gaugeConf.hDeepRG
|
||||
# for index in indexes:
|
||||
# pinName = self.stem.format(index)
|
||||
# net = block.state.cell.getNet( pinName )
|
||||
# net = block.conf.cell.getNet( pinName )
|
||||
# if net is None:
|
||||
# print( ErrorMessage( 1, [ 'IoPin.place(): No net named "{}".'.format(pinName) ] ))
|
||||
# continue
|
||||
# pinName += '.{}'.format(block.state.getIoPinsCounts(net))
|
||||
# pinName += '.{}'.format(block.conf.getIoPinsCounts(net))
|
||||
# pinPos = side.getNextPinPosition( self.flags, self.upos, self.ustep )
|
||||
# if pinPos.getY() > block.state.yMax or pinPos.getY() < block.state.yMin:
|
||||
# if pinPos.getY() > block.conf.yMax or pinPos.getY() < block.conf.yMin:
|
||||
# print( ErrorMessage( 1, [ 'IoPin.place(): Pin "{}" is outside east or west abutment box side.'.format(pinName)
|
||||
# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.state.yMax)) ] ))
|
||||
# , '(y:"{}", AB yMax:{})'.format(DbU.getValueString(pinPos.getY()),DbU.getValueString(block.conf.yMax)) ] ))
|
||||
# status += 1
|
||||
# trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) )
|
||||
# pin = Pin.create( net
|
||||
|
@ -721,18 +733,18 @@ class IoPin ( object ):
|
|||
# )
|
||||
# NetExternalComponents.setExternal( pin )
|
||||
# side.append( self.flags, pin )
|
||||
# block.state.incIoPinsCounts( net )
|
||||
# block.conf.incIoPinsCounts( net )
|
||||
# if self.upos: self.upos + self.ustep
|
||||
# return status
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Class : "configuration.BlockState".
|
||||
# Class : "configuration.BlockConf".
|
||||
|
||||
class BlockState ( object ):
|
||||
class BlockConf ( GaugeConf ):
|
||||
"""
|
||||
BlockState centralize all the configurations informations related to a
|
||||
given block.
|
||||
BlockConf centralize all the configurations informations related to a
|
||||
given block. It must be derived/build upon a GaugeConf class.
|
||||
|
||||
It contains:
|
||||
|
||||
|
@ -748,15 +760,19 @@ class BlockState ( object ):
|
|||
"""
|
||||
|
||||
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
|
||||
super(BlockConf,self).__init__()
|
||||
self.validated = True
|
||||
self.editor = None
|
||||
self.framework = CRL.AllianceFramework.get()
|
||||
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
|
||||
self.gaugeConf = GaugeConf()
|
||||
self.bufferConf = BufferInterface( self.framework )
|
||||
self.chip = ChipConf()
|
||||
self.chipConf = ChipConf( self )
|
||||
self.bColumns = 2
|
||||
self.bRows = 2
|
||||
self.cell = cell
|
||||
self.icore = None
|
||||
self.icorona = None
|
||||
self.chip = None
|
||||
self.fixedWidth = None
|
||||
self.fixedHeight = None
|
||||
self.deltaAb = [ 0, 0, 0, 0 ]
|
||||
|
@ -768,12 +784,14 @@ class BlockState ( object ):
|
|||
for ioPinSpec in ioPins:
|
||||
self.ioPins.append( IoPin( *ioPinSpec ) )
|
||||
for line in range(len(ioPads)):
|
||||
self.chip.addIoPad( ioPads[line], line )
|
||||
|
||||
self.chipConf.addIoPad( ioPads[line], line )
|
||||
self.cfg.etesian.aspectRatio = None
|
||||
self.cfg.etesian.spaceMargin = None
|
||||
self.cfg.block.spareSide = None
|
||||
|
||||
@property
|
||||
def isCoreBlock ( self ): return self.chip is not None
|
||||
|
||||
@property
|
||||
def bufferWidth ( self ): return self.bufferConf.width
|
||||
|
||||
|
@ -792,8 +810,38 @@ class BlockState ( object ):
|
|||
@property
|
||||
def yMax ( self ): return self.cell.getAbutmentBox().getYMax()
|
||||
|
||||
@property
|
||||
def coreAb ( self ):
|
||||
if not hasattr(self,'coreSize'): return Box()
|
||||
trace( 550, '\tcoreAb:[{} {}]\n'.format( DbU.getValueString(self.coreSize[0])
|
||||
, DbU.getValueString(self.coreSize[1]) ))
|
||||
return Box( 0, 0, self.coreSize[0], self.coreSize[1] )
|
||||
|
||||
@property
|
||||
def coronaAb ( self ):
|
||||
if self.corona is None: return Box()
|
||||
return self.corona.getAbutmentBox()
|
||||
|
||||
@property
|
||||
def chipAb ( self ):
|
||||
if not hasattr(self,'chipSize'): return Box()
|
||||
return Box( 0, 0, self.chipSize[0], self.chipSize[1] )
|
||||
|
||||
@property
|
||||
def corona ( self ): return self.icorona.getMasterCell()
|
||||
|
||||
@property
|
||||
def core ( self ): return self.cell
|
||||
|
||||
def setEditor ( self, editor ): self.editor = editor
|
||||
|
||||
def refresh ( self, cell=None ):
|
||||
if not self.editor: return
|
||||
if cell is not None:
|
||||
if cell != self.editor.getCell():
|
||||
self.editor.setCell( cell )
|
||||
self.editor.fit()
|
||||
|
||||
def createBuffer ( self ):
|
||||
return self.bufferConf.createBuffer( self.cell )
|
||||
|
||||
|
|
|
@ -78,7 +78,7 @@ class SlicedArea ( object ):
|
|||
but closest to the parent's center area (so, ideally, on the cluster's
|
||||
edge).
|
||||
"""
|
||||
state = cluster.bufferTree.spares.state
|
||||
state = cluster.bufferTree.spares.conf
|
||||
self.cluster = cluster
|
||||
self.rows = {}
|
||||
self.iposition = None
|
||||
|
@ -96,20 +96,20 @@ class SlicedArea ( object ):
|
|||
@property
|
||||
def bInputPlug ( self ):
|
||||
"""The input Plug of the buffer."""
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input )
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input )
|
||||
|
||||
@property
|
||||
def bOutputPlug ( self ):
|
||||
"""The output Plug of the buffer."""
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output )
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output )
|
||||
|
||||
def buildSlicesUnder ( self ):
|
||||
"""
|
||||
UNUSED. Kept as reference example.
|
||||
Rebuild slices structure under a specific area (must be small).
|
||||
"""
|
||||
state = self.cluster.bufferTree.spares.state
|
||||
sliceHeight = state.gaugeConf.sliceHeight
|
||||
state = self.cluster.bufferTree.spares.conf
|
||||
sliceHeight = state.sliceHeight
|
||||
cell = state.cell
|
||||
cellAb = cell.getAbutmentBox()
|
||||
insertArea = Box( self.cluster.getCenter() )
|
||||
|
@ -141,7 +141,7 @@ class SlicedArea ( object ):
|
|||
"""
|
||||
global af
|
||||
catalog = af.getCatalog()
|
||||
bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width
|
||||
bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width
|
||||
for key in self.rows.keys():
|
||||
row = self.rows[ key ]
|
||||
trace( 550, '\t+ Row:\n' )
|
||||
|
@ -189,9 +189,9 @@ class SlicedArea ( object ):
|
|||
"""
|
||||
if self.iposition is None:
|
||||
raise ErrorMessage( 2, 'SlicedArea.insertBuffer(): No position defined to wedge the buffer.' )
|
||||
state = self.cluster.bufferTree.spares.state
|
||||
state = self.cluster.bufferTree.spares.conf
|
||||
catalog = af.getCatalog()
|
||||
bufferLength = self.cluster.bufferTree.spares.state.bufferConf.width
|
||||
bufferLength = self.cluster.bufferTree.spares.conf.bufferConf.width
|
||||
tieLength = 0
|
||||
transf = None
|
||||
if self.iposition[2] & SlicedArea.REPLACE:
|
||||
|
@ -460,7 +460,7 @@ class Cluster ( object ):
|
|||
|
||||
def show ( self ):
|
||||
"""Select the RoutingPad of the cluster in the editor."""
|
||||
editor = self.bufferTree.spares.state.editor
|
||||
editor = self.bufferTree.spares.conf.editor
|
||||
if not editor: return False
|
||||
editor.unselectAll()
|
||||
editor.setCumulativeSelection( True )
|
||||
|
@ -531,7 +531,7 @@ class BufferTree ( object ):
|
|||
self.isDeepNet = True
|
||||
self.clusterDepth = 0
|
||||
self.clusters = [ [] ]
|
||||
self.bufName = self.spares.state.bufferConf.name
|
||||
self.bufName = self.spares.conf.bufferConf.name
|
||||
self.netCount = 0
|
||||
self.netName = self.net.getName()
|
||||
self.netIndex = None
|
||||
|
@ -570,7 +570,7 @@ class BufferTree ( object ):
|
|||
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
|
||||
else:
|
||||
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
|
||||
net = Net.create( self.spares.state.cell, subNetName )
|
||||
net = Net.create( self.spares.conf.cell, subNetName )
|
||||
self.netCount += 1
|
||||
return net
|
||||
|
||||
|
@ -689,7 +689,7 @@ class BufferTree ( object ):
|
|||
self.clusters[-1].append( Cluster(self,cluster,self.clusterDepth+1) )
|
||||
#if cluster.show():
|
||||
# Breakpoint.stop( 0, 'Showing cluster of {} RoutingPads'.format(cluster.size) )
|
||||
editor = self.spares.state.editor
|
||||
editor = self.spares.conf.editor
|
||||
if editor:
|
||||
editor.unselectAll()
|
||||
editor.setCumulativeSelection( False )
|
||||
|
@ -723,7 +723,7 @@ class BufferTree ( object ):
|
|||
driverRpOcc = self.rpDriver.getPlugOccurrence()
|
||||
topNetName = self.net.getName()
|
||||
self.net.destroy()
|
||||
self.net = Net.create( self.spares.state.cell, topNetName )
|
||||
self.net = Net.create( self.spares.conf.cell, topNetName )
|
||||
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
|
||||
deepDriverNet = deepPlug.getMasterNet()
|
||||
driverRpOcc.getEntity().setNet( deepDriverNet )
|
||||
|
|
|
@ -89,12 +89,12 @@ class Cluster ( object ):
|
|||
@property
|
||||
def bInputPlug ( self ):
|
||||
"""The input Plug of the buffer."""
|
||||
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.input )
|
||||
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.input )
|
||||
|
||||
@property
|
||||
def bOutputPlug ( self ):
|
||||
"""The output Plug of the buffer."""
|
||||
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.state.bufferConf.output )
|
||||
return utils.getPlugByName( self.instBuffer, self.bufferTree.spares.conf.bufferConf.output )
|
||||
|
||||
def createBufInputRp ( self, net ):
|
||||
"""Create a RoutingPad for the buffer input Plug (terminal)."""
|
||||
|
@ -194,7 +194,7 @@ class BufferTree ( object ):
|
|||
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
|
||||
else:
|
||||
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
|
||||
net = Net.create( self.spares.state.cell, subNetName )
|
||||
net = Net.create( self.spares.conf.cell, subNetName )
|
||||
self.netCount += 1
|
||||
return net
|
||||
|
||||
|
@ -254,7 +254,7 @@ class BufferTree ( object ):
|
|||
driverRpOcc = self.rpDriver.getPlugOccurrence()
|
||||
topNetName = self.net.getName()
|
||||
self.net.destroy()
|
||||
self.net = Net.create( self.spares.state.cell, topNetName )
|
||||
self.net = Net.create( self.spares.conf.cell, topNetName )
|
||||
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
|
||||
deepDriverNet = deepPlug.getMasterNet()
|
||||
driverRpOcc.getEntity().setNet( deepDriverNet )
|
||||
|
|
|
@ -77,7 +77,7 @@ class SlicedArea ( object ):
|
|||
but closest to the parent's center area (so, ideally, on the cluster's
|
||||
edge).
|
||||
"""
|
||||
state = cluster.bufferTree.spares.state
|
||||
state = cluster.bufferTree.spares.conf
|
||||
self.cluster = cluster
|
||||
if cluster.parent is None:
|
||||
attractor = cluster.getCenter()
|
||||
|
@ -93,12 +93,12 @@ class SlicedArea ( object ):
|
|||
@property
|
||||
def bInputPlug ( self ):
|
||||
"""The input Plug of the buffer."""
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.input )
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.input )
|
||||
|
||||
@property
|
||||
def bOutputPlug ( self ):
|
||||
"""The output Plug of the buffer."""
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.state.bufferConf.output )
|
||||
return utils.getPlugByName( self.buffer, self.cluster.bufferTree.spares.conf.bufferConf.output )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
|
@ -328,21 +328,21 @@ class Cluster ( object ):
|
|||
graph.addNode( self
|
||||
, driverCenter.getX()
|
||||
, self.bufferTree.spares.toYGCellGrid(driverCenter.getY())
|
||||
+ self.bufferTree.spares.state.gaugeConf.sliceHeight / 2
|
||||
+ self.bufferTree.spares.conf.sliceHeight / 2
|
||||
, rsmt.Node.Driver )
|
||||
for anchor in self.mergedAnchors:
|
||||
sinkCenter = anchor.bInputRp.getPosition()
|
||||
graph.addNode( anchor
|
||||
, sinkCenter.getX()
|
||||
, self.bufferTree.spares.toYGCellGrid(sinkCenter.getY())
|
||||
+ self.bufferTree.spares.state.gaugeConf.sliceHeight / 2 )
|
||||
+ self.bufferTree.spares.conf.sliceHeight / 2 )
|
||||
#graph.doIteratedOneSteiner()
|
||||
graph.doFlute()
|
||||
graph.createGRSegments()
|
||||
|
||||
def show ( self ):
|
||||
"""Select the RoutingPad of the cluster in the editor."""
|
||||
editor = self.bufferTree.spares.state.editor
|
||||
editor = self.bufferTree.spares.conf.editor
|
||||
if not editor: return False
|
||||
editor.unselectAll()
|
||||
editor.setCumulativeSelection( True )
|
||||
|
@ -421,7 +421,7 @@ class BufferTree ( object ):
|
|||
self.isDeepNet = True
|
||||
self.clusterDepth = 0
|
||||
self.clusters = [ [] ]
|
||||
self.bufName = self.spares.state.bufferConf.name
|
||||
self.bufName = self.spares.conf.bufferConf.name
|
||||
self.netCount = 0
|
||||
self.netName = self.net.getName()
|
||||
self.netIndex = None
|
||||
|
@ -460,7 +460,7 @@ class BufferTree ( object ):
|
|||
subNetName = '{}_hfns_{}'.format( self.netName, self.netCount )
|
||||
else:
|
||||
subNetName = '{}_bit{}_hfns_{}'.format( self.netName, self.netIndex, self.netCount )
|
||||
net = Net.create( self.spares.state.cell, subNetName )
|
||||
net = Net.create( self.spares.conf.cell, subNetName )
|
||||
self.netCount += 1
|
||||
return net
|
||||
|
||||
|
@ -604,7 +604,7 @@ class BufferTree ( object ):
|
|||
driverRpOcc = self.rpDriver.getPlugOccurrence()
|
||||
topNetName = self.net.getName()
|
||||
self.net.destroy()
|
||||
self.net = Net.create( self.spares.state.cell, topNetName )
|
||||
self.net = Net.create( self.spares.conf.cell, topNetName )
|
||||
deepPlug = self.spares.raddTransNet( self.net, driverRpOcc.getPath() )
|
||||
deepDriverNet = deepPlug.getMasterNet()
|
||||
driverRpOcc.getEntity().setNet( deepDriverNet )
|
||||
|
|
|
@ -59,8 +59,8 @@ class BufferPool ( object ):
|
|||
|
||||
def __init__ ( self, quadTree ):
|
||||
self.quadTree = quadTree
|
||||
self.columns = quadTree.spares.state.bColumns
|
||||
self.rows = quadTree.spares.state.bRows
|
||||
self.columns = quadTree.spares.conf.bColumns
|
||||
self.rows = quadTree.spares.conf.bRows
|
||||
self.area = Box()
|
||||
self.buffers = []
|
||||
self.selectedIndex = None
|
||||
|
@ -145,12 +145,12 @@ class BufferPool ( object ):
|
|||
"""Create the matrix of instances buffer."""
|
||||
trace( 540, ',+', '\tBufferPool.createBuffers()\n' )
|
||||
|
||||
state = self.quadTree.spares.state
|
||||
sliceHeight = state.gaugeConf.sliceHeight
|
||||
conf = self.quadTree.spares.conf
|
||||
sliceHeight = conf.sliceHeight
|
||||
x = self.quadTree.onXPitch( self.quadTree.area.getXCenter()
|
||||
- (state.bufferConf.width * self.columns)/2 )
|
||||
- (conf.bufferConf.width * self.columns)/2 )
|
||||
y = self.quadTree.onYSlice( self.quadTree.area.getYCenter()
|
||||
- (state.bufferConf.height * self.rows)/2 )
|
||||
- (conf.bufferConf.height * self.rows)/2 )
|
||||
slice = y / sliceHeight
|
||||
|
||||
trace( 540, '\tSlice height: {}\n'.format(DbU.getValueString(sliceHeight)) )
|
||||
|
@ -163,8 +163,8 @@ class BufferPool ( object ):
|
|||
y += sliceHeight
|
||||
for column in range(self.columns):
|
||||
index = self.toIndex(column,row)
|
||||
transf = Transformation( x + column*state.bufferConf.width, y, orientation )
|
||||
instance = state.createBuffer()
|
||||
transf = Transformation( x + column*conf.bufferConf.width, y, orientation )
|
||||
instance = conf.createBuffer()
|
||||
instance.setTransformation( transf )
|
||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
self.buffers[ index ][1] = instance
|
||||
|
@ -213,7 +213,7 @@ class QuadTree ( object ):
|
|||
|
||||
@staticmethod
|
||||
def create ( spares ):
|
||||
root = QuadTree( spares, None, spares.state.cell.getAbutmentBox() )
|
||||
root = QuadTree( spares, None, spares.conf.cell.getAbutmentBox() )
|
||||
root.rpartition()
|
||||
return root
|
||||
|
||||
|
@ -277,7 +277,7 @@ class QuadTree ( object ):
|
|||
catalog = framework.getCatalog()
|
||||
instancesNb = 0
|
||||
bufNb = 0
|
||||
for occurrence in self.spares.state.cell.getTerminalNetlistInstanceOccurrences():
|
||||
for occurrence in self.spares.conf.cell.getTerminalNetlistInstanceOccurrences():
|
||||
cellName = occurrence.getEntity().getMasterCell().getName()
|
||||
cstate = catalog.getState( cellName )
|
||||
if cstate and cstate.isFeed(): continue
|
||||
|
@ -291,10 +291,10 @@ class QuadTree ( object ):
|
|||
if rtotal:
|
||||
print( ' o Detailed use of spare buffers.' )
|
||||
dots( 82
|
||||
, ' - Useds: '
|
||||
, ' - Useds '
|
||||
, ' {}/{} ({:.1%})'.format(rused,rtotal,float(rused)/float(rtotal)) )
|
||||
dots( 82
|
||||
, ' - Buffer ratio: '
|
||||
, ' - Buffer ratio '
|
||||
, ' {}/{} ({:.1%})'.format( rtotal
|
||||
, instancesNb+bufNb
|
||||
, float(rtotal)/float(instancesNb+bufNb)) )
|
||||
|
@ -347,21 +347,21 @@ class QuadTree ( object ):
|
|||
@property
|
||||
def bInputPlug ( self ):
|
||||
"""The input Plug of the currently selected buffer in the pool."""
|
||||
return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.input )
|
||||
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.input )
|
||||
|
||||
@property
|
||||
def bOutputPlug ( self ):
|
||||
"""The output Plug of the currently selected buffer in the pool."""
|
||||
return utils.getPlugByName( self.buffer, self.spares.state.bufferConf.output )
|
||||
return utils.getPlugByName( self.buffer, self.spares.conf.bufferConf.output )
|
||||
|
||||
def onYSlice ( self, y ):
|
||||
"""Returns the coordinate of the slice immediately inferior to Y."""
|
||||
modulo = (y - self.area.getYMin()) % self.spares.state.gaugeConf.sliceHeight
|
||||
modulo = (y - self.area.getYMin()) % self.spares.conf.sliceHeight
|
||||
return y - modulo
|
||||
|
||||
def onXPitch ( self, x ):
|
||||
"""Returns the coordinate of the pitch immediately inferior to X."""
|
||||
modulo = (x - self.area.getXMin()) % self.spares.state.gaugeConf.sliceStep
|
||||
modulo = (x - self.area.getXMin()) % self.spares.conf.sliceStep
|
||||
return x - modulo
|
||||
|
||||
def selectFree ( self ):
|
||||
|
@ -382,7 +382,7 @@ class QuadTree ( object ):
|
|||
trace( 540, '\tQuadTree.connectBuffer(): rtag:"{}"\n'.format(self.rtag) )
|
||||
plug = self.bOutputPlug
|
||||
if not plug.getNet():
|
||||
outputNetBuff = Net.create( self.spares.state.cell,'{}_{}' \
|
||||
outputNetBuff = Net.create( self.spares.conf.cell,'{}_{}' \
|
||||
.format(self.root.bufferTag,self.rtag) )
|
||||
plug.setNet( outputNetBuff )
|
||||
trace( 540, '\t| {}\n'.format(plug) )
|
||||
|
@ -417,10 +417,10 @@ class QuadTree ( object ):
|
|||
quad-tree, but only a vertical or horizontal bi-partition.
|
||||
"""
|
||||
trace( 540, ',+', '\tQuadTree.partition(): {} (spareSide:{})\n' \
|
||||
.format(self.area, DbU.getValueString(self.spares.state.cfg.block.spareSide)) )
|
||||
.format(self.area, DbU.getValueString(self.spares.conf.cfg.block.spareSide)) )
|
||||
|
||||
spareSide = self.spares.state.cfg.block.spareSide
|
||||
sliceHeight = self.spares.state.gaugeConf.sliceHeight
|
||||
spareSide = self.spares.conf.cfg.block.spareSide
|
||||
sliceHeight = self.spares.conf.sliceHeight
|
||||
side = float(spareSide)
|
||||
aspectRatio = float(self.area.getWidth()) / float(self.area.getHeight())
|
||||
|
||||
|
@ -684,7 +684,7 @@ class QuadTree ( object ):
|
|||
trace( 540, '\t| deepNetBuff: {} {}\n'.format(deepNetBuff,netBuff) )
|
||||
plug.getEntity().setNet( deepNetBuff )
|
||||
|
||||
maxSinks = self.spares.state.bufferConf.maxSinks
|
||||
maxSinks = self.spares.conf.bufferConf.maxSinks
|
||||
if len(self.plugs) > maxSinks:
|
||||
print( WarningMessage( 'QuadTree.splitNetlist(): More than {} sink points ({}) on "{}".' \
|
||||
.format(maxSinks,len(self.plugs),netBuff.getName())) )
|
||||
|
@ -713,7 +713,7 @@ class Spares ( object ):
|
|||
MARK_USED = 0x00020000
|
||||
|
||||
def __init__ ( self, block ):
|
||||
self.state = block.state
|
||||
self.conf = block.conf
|
||||
self.quadTree = None
|
||||
self.cloneds = []
|
||||
self.strayBuffers = []
|
||||
|
@ -725,36 +725,36 @@ class Spares ( object ):
|
|||
self.quadTree = None
|
||||
self.cloneds = []
|
||||
self.strayBuffers = []
|
||||
self.state.resetBufferCount()
|
||||
self.conf.resetBufferCount()
|
||||
|
||||
def getSpareSpaceMargin ( self ):
|
||||
"""
|
||||
Compute the percentage of margin space to compensate for the spare
|
||||
buffers (row*columns) with a supplemental margin factor of 1.3 or 1.4.
|
||||
"""
|
||||
if not self.state.useSpares: return 0.0
|
||||
spareSide = self.state.cfg.block.spareSide
|
||||
if not self.conf.useSpares: return 0.0
|
||||
spareSide = self.conf.cfg.block.spareSide
|
||||
if not spareSide:
|
||||
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): "block.spareSide" parameter is zero ({}).' \
|
||||
.format(spareSide) )
|
||||
areaLength = spareSide * spareSide / self.state.gaugeConf.sliceHeight
|
||||
bufferLength = self.state.bufferConf.width * self.state.bColumns * self.state.bRows
|
||||
areaLength = spareSide * spareSide / self.conf.sliceHeight
|
||||
bufferLength = self.conf.bufferConf.width * self.conf.bColumns * self.conf.bRows
|
||||
if not areaLength:
|
||||
raise ErrorMessage( 3, 'Spares.getSpareSpaceMargin(): Spare leaf area is zero.' )
|
||||
return (float(bufferLength) * 1.4) / float(areaLength)
|
||||
|
||||
def toXGCellGrid ( self, x ):
|
||||
"""Find the nearest X (inferior) on the Cell gauge grid (sliceStep)."""
|
||||
dx = x - self.state.xMin
|
||||
return self.state.xMin + (dx - dx % self.state.gaugeConf.sliceStep)
|
||||
dx = x - self.conf.xMin
|
||||
return self.conf.xMin + (dx - dx % self.conf.sliceStep)
|
||||
|
||||
def toYGCellGrid ( self, y ):
|
||||
"""Find the nearest Y (inferior) on the Cell gauge grid (sliceHeight)."""
|
||||
dy = y - self.state.yMin
|
||||
return self.state.yMin + (dy - dy % self.state.gaugeConf.sliceHeight)
|
||||
dy = y - self.conf.yMin
|
||||
return self.conf.yMin + (dy - dy % self.conf.sliceHeight)
|
||||
|
||||
def build ( self ):
|
||||
if not self.state.useSpares: return
|
||||
if not self.conf.useSpares: return
|
||||
trace( 540, ',+', '\tSpares.build()\n' )
|
||||
with UpdateSession():
|
||||
self.quadTree = QuadTree.create( self )
|
||||
|
@ -768,7 +768,7 @@ class Spares ( object ):
|
|||
"""Add a new stray buffer at ``position``."""
|
||||
trace( 540, ',+', '\tSpares.addStrayBuffer()\n' )
|
||||
|
||||
sliceHeight = self.state.gaugeConf.sliceHeight
|
||||
sliceHeight = self.conf.sliceHeight
|
||||
x = self.quadTree.onXPitch( position.getX() )
|
||||
y = self.quadTree.onYSlice( position.getY() )
|
||||
slice = y / sliceHeight
|
||||
|
@ -778,7 +778,7 @@ class Spares ( object ):
|
|||
orientation = Transformation.Orientation.MY
|
||||
y += sliceHeight
|
||||
transf = Transformation( x, y, orientation )
|
||||
instance = self.state.createBuffer()
|
||||
instance = self.conf.createBuffer()
|
||||
instance.setTransformation( transf )
|
||||
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
unoverlapDx = self.quadTree.getUnoverlapDx( instance.getAbutmentBox() )
|
||||
|
@ -801,7 +801,9 @@ class Spares ( object ):
|
|||
return leaf.selectFree()
|
||||
|
||||
def addClonedCell ( self, masterCell ):
|
||||
if not masterCell in self.cloneds: self.cloneds.append( masterCell )
|
||||
if not masterCell in self.cloneds:
|
||||
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
|
||||
self.cloneds.append( masterCell )
|
||||
return
|
||||
|
||||
def raddTransNet ( self, topNet, path ):
|
||||
|
@ -839,8 +841,9 @@ class Spares ( object ):
|
|||
*plug master net* and the *tail path*.
|
||||
"""
|
||||
|
||||
if path.isEmpty(): return None
|
||||
|
||||
if path.isEmpty():
|
||||
self.addClonedCell( topNet.getCell() )
|
||||
return None
|
||||
tailPath = path.getTailPath()
|
||||
headInstance = path.getHeadInstance()
|
||||
headPlug = utils.getPlugByNet(headInstance,topNet)
|
||||
|
@ -856,9 +859,9 @@ class Spares ( object ):
|
|||
% (topNet.getName(),headInstance.getName(),masterCell.getName()) )
|
||||
headPlug.setNet( topNet )
|
||||
self.addClonedCell( masterCell )
|
||||
self.addClonedCell( headInstance.getCell() )
|
||||
else:
|
||||
masterNet = headPlug.getMasterNet()
|
||||
|
||||
if tailPath.isEmpty(): return headPlug
|
||||
return self.raddTransNet( masterNet, tailPath )
|
||||
|
||||
|
@ -880,13 +883,14 @@ class Spares ( object ):
|
|||
if not masterCell.isTerminal():
|
||||
self.rsave( masterCell )
|
||||
|
||||
def save ( self, topCell ):
|
||||
def save ( self ):
|
||||
"""
|
||||
Frontend to Spares.rsave(). Append the "_cts" suffix to the cloned
|
||||
cells, then call rsave().
|
||||
"""
|
||||
trace( 550,'\tSpares.save() on "{}"\n'.format(self.conf.cell.getName()) )
|
||||
for cell in self.cloneds:
|
||||
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
|
||||
cell.setName( cell.getName()+'_cts' )
|
||||
self.rsave( topCell )
|
||||
self.rsave( self.conf.cell )
|
||||
return
|
||||
|
||||
|
|
|
@ -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]
|
|
@ -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 )
|
|
@ -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, '-' )
|
|
@ -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
|
@ -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()
|
|
@ -88,18 +88,18 @@ class CoreToChip ( BaseCoreToChip ):
|
|||
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
|
||||
coronaNet.setExternal( True )
|
||||
coronaNet.setGlobal ( True )
|
||||
coronaNet.setType ( Net.Type.POWER )
|
||||
coronaNet.setType ( Net.Type.GROUND )
|
||||
self.icore.getPlug( coreNet ).setNet( coronaNet )
|
||||
if not chipNet:
|
||||
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
|
||||
chipNet.setExternal( True )
|
||||
chipNet.setType ( Net.Type.POWER )
|
||||
chipNet.setType ( Net.Type.GROUND )
|
||||
self.icorona.getPlug( coronaNet ).setNet( chipNet )
|
||||
self.ringNetNames['vssi'] = chipNet
|
||||
if not padNet:
|
||||
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
|
||||
padNet.setExternal( True )
|
||||
padNet.setType ( Net.Type.POWER )
|
||||
padNet.setType ( Net.Type.GROUND )
|
||||
self.ringNetNames['vsse'] = padNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_vssick_{}'.format(ioPadConf.index)
|
||||
|
|
|
@ -50,12 +50,13 @@ from Hurricane import Net
|
|||
from Hurricane import Instance
|
||||
from CRL import Catalog
|
||||
from CRL import AllianceFramework
|
||||
from helpers import trace
|
||||
from helpers import netDirectionToStr
|
||||
from helpers.overlay import UpdateSession
|
||||
from helpers.io import ErrorMessage
|
||||
import plugins.chip
|
||||
from plugins.alpha.block.block import Block
|
||||
from plugins.alpha.block.configuration import BlockState
|
||||
from plugins.alpha.block.configuration import BlockConf
|
||||
from plugins.alpha.block.configuration import IoPadConf
|
||||
|
||||
|
||||
|
@ -99,7 +100,6 @@ class IoNet ( object ):
|
|||
self.coronaNet = None # Corona net going from core to corona.
|
||||
self.chipIntNet = None # Chip net going from corona to I/O pad.
|
||||
self.chipExtNet = None # Chip net going from I/O pad to the outside world.
|
||||
|
||||
m = IoNet.reVHDLVector.match( self.coreNet.getName() )
|
||||
if m:
|
||||
self._flags |= IoNet.IsElem
|
||||
|
@ -108,9 +108,8 @@ class IoNet ( object ):
|
|||
else:
|
||||
self._name = self.coreNet.getName()
|
||||
self._index = 0
|
||||
|
||||
self._type = self.coreToChip.getNetType( self._name )
|
||||
return
|
||||
trace( 550, '\tIoNet.__init__(): {}\n'.format(self) )
|
||||
|
||||
def __repr__ ( self ):
|
||||
return '<IoNet "{}" ext:"{}" int:"{}">'.format( self.coreNet.getName()
|
||||
|
@ -137,6 +136,10 @@ class IoNet ( object ):
|
|||
@property
|
||||
def coronaNetName ( self ):
|
||||
s = self._name
|
||||
if self.coreNet.getDirection() & Net.Direction.IN:
|
||||
s += '_from_pad'
|
||||
elif self.coreNet.getDirection() & Net.Direction.OUT:
|
||||
s += '_to_pad'
|
||||
if self._flags & IoNet.IsElem: s += '({})'.format(self._index)
|
||||
return s
|
||||
|
||||
|
@ -233,13 +236,20 @@ class IoPad ( object ):
|
|||
if direction == IoPad.UNSUPPORTED: return "UNSUPPORTED"
|
||||
return "Invalid value"
|
||||
|
||||
def __init__ ( self, coreToChip, padInstanceName ):
|
||||
self.coreToChip = coreToChip
|
||||
self.padInstanceName = padInstanceName
|
||||
self.direction = 0
|
||||
self.nets = []
|
||||
self.pads = []
|
||||
def __init__ ( self, coreToChip, ioPadConf ):
|
||||
self.coreToChip = coreToChip
|
||||
self.ioPadConf = ioPadConf
|
||||
self.direction = 0
|
||||
self.nets = []
|
||||
return
|
||||
|
||||
@property
|
||||
def padInstanceName ( self ): return self.ioPadConf.instanceName
|
||||
|
||||
@property
|
||||
def pads ( self ):
|
||||
print( self.ioPadConf )
|
||||
return self.ioPadConf.pads
|
||||
|
||||
def __str__ ( self ):
|
||||
s = '<IoPad "{}" '.format(self.padInstanceName)
|
||||
|
@ -389,7 +399,7 @@ class CoreToChip ( object ):
|
|||
def __init__ ( self, core ):
|
||||
if isinstance(core,Block):
|
||||
state = core.state
|
||||
elif isinstance(core,BlockState):
|
||||
elif isinstance(core,BlockConf):
|
||||
state = core
|
||||
else:
|
||||
block = Block.lookup( core )
|
||||
|
@ -403,17 +413,25 @@ class CoreToChip ( object ):
|
|||
self.ioPadInfos = {}
|
||||
self.chipPads = []
|
||||
self.padLib = None
|
||||
self.core = self.state.cell
|
||||
self.chip = None
|
||||
self.corona = None
|
||||
self.icorona = None
|
||||
self.icore = None
|
||||
self._ioNets = {}
|
||||
self.powerPadCount = 0
|
||||
self.groundPadCount = 0
|
||||
self.clockPadCount = 0
|
||||
return
|
||||
|
||||
@property
|
||||
def core ( self ): return self.state.cell
|
||||
|
||||
@property
|
||||
def icore ( self ): return self.state.icore
|
||||
|
||||
@property
|
||||
def icorona ( self ): return self.state.icorona
|
||||
|
||||
@property
|
||||
def chip ( self ): return self.state.chip
|
||||
|
||||
def hasIoNet ( self, netName ):
|
||||
"""
|
||||
Look for an IoNet associated to *core* net ``netName``.
|
||||
|
@ -439,6 +457,7 @@ class CoreToChip ( object ):
|
|||
def _connectPadRing ( self, padInstance ):
|
||||
"""Connect ring signals to the I/O pad."""
|
||||
for masterNetName, netName in self.ringNetNames.items():
|
||||
trace( 550, '\tCoreToChip._connectPadRing(): master:{} net:{}\n'.format(masterNetName,netName) )
|
||||
CoreToChip._connect( padInstance, netName, masterNetName )
|
||||
|
||||
def _connectRing ( self ):
|
||||
|
@ -487,37 +506,42 @@ class CoreToChip ( object ):
|
|||
"""
|
||||
af = AllianceFramework.get()
|
||||
with UpdateSession():
|
||||
self.chip = af.createCell( self.state.chip.name )
|
||||
self.corona = af.createCell( 'corona' )
|
||||
self.icore = Instance.create( self.corona, 'core' , self.core )
|
||||
self.icorona = Instance.create( self.chip , 'corona', self.corona )
|
||||
print( ' o Build Chip from Core.' )
|
||||
print( ' - Core: "{}".'.format(self.state.cell.getName()) )
|
||||
print( ' - Corona: "{}".'.format('corona') )
|
||||
print( ' - Chip: "{}".'.format(self.state.chipConf.name) )
|
||||
self.state.chip = af.createCell( self.state.chipConf.name )
|
||||
self.corona = af.createCell( 'corona' )
|
||||
self.state.icore = Instance.create( self.corona , 'core' , self.state.cell )
|
||||
self.state.icorona = Instance.create( self.state.chip, 'corona', self.corona )
|
||||
ioPads = []
|
||||
clockIoNets = []
|
||||
for padConf in self.state.chip.padInstances:
|
||||
if padConf.isPower():
|
||||
self._buildPowerPads( padConf )
|
||||
for ioPadConf in self.state.chipConf.padInstances:
|
||||
if ioPadConf.isPower():
|
||||
self._buildPowerPads( ioPadConf )
|
||||
continue
|
||||
if padConf.isGround():
|
||||
self._buildGroundPads( padConf )
|
||||
if ioPadConf.isGround():
|
||||
self._buildGroundPads( ioPadConf )
|
||||
continue
|
||||
if padConf.isClock():
|
||||
self._buildClockPads( padConf )
|
||||
if ioPadConf.isClock():
|
||||
self._buildClockPads( ioPadConf )
|
||||
continue
|
||||
padConf.udata = IoPad( self, padConf.instanceName )
|
||||
for netName in padConf.nets:
|
||||
ioPadConf.udata = IoPad( self, ioPadConf )
|
||||
for netName in ioPadConf.nets:
|
||||
if netName is None: continue
|
||||
coreNet = self.core.getNet( netName )
|
||||
if not coreNet:
|
||||
raise ErrorMessage( 1, 'CoreToChip.buildChip(): "%s" doesn\'t have a "%s" net.'
|
||||
% (self.core.getName(),netName) )
|
||||
raise ErrorMessage( 1, 'CoreToChip.buildChip(): "{}" doesn\'t have a "{}" net.' \
|
||||
.format(self.core.getName(),netName) )
|
||||
ioNet = self.getIoNet( coreNet )
|
||||
if padConf.isBidir() or padConf.isTristate():
|
||||
if coreNet.getName() == padConf.enableNetName:
|
||||
if ioPadConf.isBidir() or ioPadConf.isTristate():
|
||||
if coreNet.getName() == ioPadConf.enableNetName:
|
||||
ioNet.setEnable( True )
|
||||
if not ioNet.isEnable():
|
||||
ioNet.chipExtNetName = padConf.padNetName
|
||||
padConf.udata.addNet( ioNet )
|
||||
ioPads.append( padConf )
|
||||
ioNet.chipExtNetName = ioPadConf.padNetName
|
||||
ioPadConf.udata.addNet( ioNet )
|
||||
ioPads.append( ioPadConf )
|
||||
trace( 550, '\tProcessed all IoPadConf, looking for orphaned core nets...\n' )
|
||||
for coreNet in self.core.getNets():
|
||||
if not coreNet.isExternal(): continue
|
||||
elif coreNet.isPower(): continue
|
||||
|
@ -535,6 +559,7 @@ class CoreToChip ( object ):
|
|||
directPad.udata = IoPad( self, directPad.instanceName )
|
||||
directPad.udata.addNet( ioNet )
|
||||
ioPads.append( directPad )
|
||||
trace( 550, '\tNon-configured core net {}, adding {}\n'.format(coreNet,directPad) )
|
||||
for ioPad in ioPads:
|
||||
ioPad.udata.createPad()
|
||||
self._connectRing()
|
||||
|
|
|
@ -43,7 +43,6 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
|
|||
"""
|
||||
framework = CRL.AllianceFramework.get()
|
||||
if depth == 0: print( ' o Recursive Save-Cell.' )
|
||||
|
||||
sviews = ''
|
||||
if views & CRL.Catalog.State.Logical:
|
||||
sviews += 'netlist'
|
||||
|
@ -58,19 +57,16 @@ def rsave ( cell, views=CRL.Catalog.State.Physical, depth=0 ):
|
|||
if views & CRL.Catalog.State.Physical:
|
||||
if sviews: sviews += ','
|
||||
sviews += 'layout'
|
||||
|
||||
print( ' {}+ {} ({}).'.format(' '*(depth*2), cell.getName(), sviews) )
|
||||
if cell.isUniquified(): views |= CRL.Catalog.State.Logical
|
||||
framework.saveCell( cell, views )
|
||||
|
||||
for instance in cell.getInstances():
|
||||
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
|
||||
#print( ' {}| {}.'.format(' '*(depth*2), instance) )
|
||||
masterCell = instance.getMasterCell()
|
||||
|
||||
if not masterCell.isTerminalNetlist():
|
||||
rsave( masterCell, views, depth+1 )
|
||||
#else:
|
||||
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
|
||||
#else:
|
||||
# print( ' {}| Master cell is terminal netlist {}.'.format(' '*(depth*2), instance.getMasterCell()) )
|
||||
return
|
||||
|
||||
|
||||
|
@ -100,11 +96,8 @@ def scriptMain ( **kw ):
|
|||
return 0
|
||||
rsave( cell, views )
|
||||
CRL.destroyAllVHDL()
|
||||
|
||||
except Exception, e:
|
||||
helpers.io.catch( e )
|
||||
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
return 0
|
||||
|
|
Loading…
Reference in New Issue