First basic version of ClockTree & Chip plugins.
* New: In Cumulus, first versions of the ClockTree and Chip plugins. Clock Tree plugin: - It is strongly advised to use have 4 metal routing layers for the tree to work. Otherwise, problems can arise with the detailed routing (fully obstructed terminals). - H-Tree can only be build (for now) for design with a form factor between 0.5 an 2. - The tree is created at the block top-level and only the leafs are trans-hierarchically created on the instances/models. The new cell with a clock tree, along with all it's sub-models is created with a "_clocked" suffix. - Leaf cells are connected through a simple Minimum Steiner Tree. - Shorts are avoided by a systematic shift of the wires according to their kind. No wire must pre-exist. When used as a sub-module of "chip" the wires cannot be moved. When created on a block, the wires can be loaded in the detailed router as manual global router. Chip Plugin: - Perform the pad placement and corona creation. Replacement at last of the clunky code from Wu Yifei. - Relies on a Python configuration file '<design>_chip.py' with a "chip" dictionnary.
This commit is contained in:
parent
20f8d004e2
commit
fb4a7457a1
|
@ -31,6 +31,8 @@ symbolicTechno = 'cmos'
|
||||||
symbolicDir = None
|
symbolicDir = None
|
||||||
realTechno = 'hcmos9'
|
realTechno = 'hcmos9'
|
||||||
realDir = None
|
realDir = None
|
||||||
|
tab = None
|
||||||
|
_trace = None
|
||||||
|
|
||||||
|
|
||||||
def stype ( o ): return str(type(o)).split("'")[1]
|
def stype ( o ): return str(type(o)).split("'")[1]
|
||||||
|
@ -168,18 +170,100 @@ class Dots ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def staticInitialization ():
|
class Tab ( object ):
|
||||||
|
|
||||||
|
def __init__ ( self, stepSize=2 ):
|
||||||
|
self._stepSize = stepSize
|
||||||
|
self._tsize = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
def inc ( self, step=1 ): self._tsize += step*self._stepSize
|
||||||
|
def dec ( self, step=1 ):
|
||||||
|
if step*self._stepSize < self._tsize:
|
||||||
|
self._tsize -= step*self._stepSize
|
||||||
|
else:
|
||||||
|
self._tsize = 0
|
||||||
|
return
|
||||||
|
|
||||||
|
def __str__ ( self ): return ' '*self._tsize
|
||||||
|
|
||||||
|
|
||||||
|
class Trace ( object ):
|
||||||
|
|
||||||
|
def __init__ ( self ):
|
||||||
|
self._tab = Tab()
|
||||||
|
self._level = 10000
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def level ( self ): return self._level
|
||||||
|
@level.setter
|
||||||
|
def level ( self, level ): self._level = level
|
||||||
|
|
||||||
|
def write ( self, level, arg1='', arg2=None ):
|
||||||
|
if level < self._level: return
|
||||||
|
|
||||||
|
sflags = [ '', '' ]
|
||||||
|
message = None
|
||||||
|
if isinstance(arg1,str) and len(arg1) and arg1[0] in '+-,':
|
||||||
|
sflags = arg1.split( ',' , 1 )
|
||||||
|
if len(sflags) < 2: sflags.append('')
|
||||||
|
message = arg2
|
||||||
|
else:
|
||||||
|
message = arg1
|
||||||
|
|
||||||
|
for f in sflags[0]:
|
||||||
|
if f == '+': self._tab.inc()
|
||||||
|
if f == '-': self._tab.dec()
|
||||||
|
|
||||||
|
if message:
|
||||||
|
if not isinstance(message,str):
|
||||||
|
message = '\t'+str(message)+'\n'
|
||||||
|
|
||||||
|
if len(message) and message[0] == '\t':
|
||||||
|
sys.stderr.write( str(self._tab) )
|
||||||
|
sys.stderr.write( message[1:] )
|
||||||
|
else:
|
||||||
|
sys.stderr.write( message )
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
|
for f in sflags[1]:
|
||||||
|
if f == '+': self._tab.inc()
|
||||||
|
if f == '-': self._tab.dec()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def trace ( *args ):
|
||||||
|
global _trace
|
||||||
|
_trace.write( *args )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def setTraceLevel ( level ):
|
||||||
|
global _trace
|
||||||
|
_trace.level = level
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def staticInitialization ( quiet=False ):
|
||||||
global sysConfDir
|
global sysConfDir
|
||||||
global symbolicDir
|
global symbolicDir
|
||||||
global realDir
|
global realDir
|
||||||
|
global tab
|
||||||
|
global _trace
|
||||||
|
|
||||||
|
if sysConfDir != None: return
|
||||||
|
|
||||||
|
tab = Tab()
|
||||||
|
_trace = Trace()
|
||||||
|
|
||||||
reSysConfDir = re.compile(r'.*etc\/coriolis2')
|
reSysConfDir = re.compile(r'.*etc\/coriolis2')
|
||||||
print ' o Locating configuration directory:'
|
if not quiet: print ' o Locating configuration directory:'
|
||||||
|
|
||||||
for path in sys.path:
|
for path in sys.path:
|
||||||
if reSysConfDir.match(path):
|
if reSysConfDir.match(path):
|
||||||
sysConfDir = path
|
sysConfDir = path
|
||||||
print ' - <%s>' % sysConfDir
|
if not quiet: print ' - <%s>' % sysConfDir
|
||||||
break
|
break
|
||||||
|
|
||||||
if not sysConfDir:
|
if not sysConfDir:
|
||||||
|
@ -192,7 +276,7 @@ def staticInitialization ():
|
||||||
raise ErrorMessage( 1, [ 'Cannot locate the directoty holding the configuration files.'
|
raise ErrorMessage( 1, [ 'Cannot locate the directoty holding the configuration files.'
|
||||||
, 'The path is something ending by <.../etc/coriolis2>.'] )
|
, 'The path is something ending by <.../etc/coriolis2>.'] )
|
||||||
|
|
||||||
print ' - <%s>' % sysConfDir
|
if not quiet: print ' - <%s>' % sysConfDir
|
||||||
symbolicDir = os.path.join( sysConfDir, symbolicTechno )
|
symbolicDir = os.path.join( sysConfDir, symbolicTechno )
|
||||||
realDir = os.path.join( sysConfDir, realTechno )
|
realDir = os.path.join( sysConfDir, realTechno )
|
||||||
return
|
return
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,12 @@
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/Alliance.py
|
${CMAKE_CURRENT_SOURCE_DIR}/Alliance.py
|
||||||
)
|
)
|
||||||
set ( pyPlugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins/__init__.py
|
set ( pyPlugins ${CMAKE_CURRENT_SOURCE_DIR}/plugins/__init__.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/ClockTree.py
|
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/ChipPlugin.py
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/ChipPlugin.py
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/ClockTreePlugin.py
|
||||||
|
)
|
||||||
|
set ( pyPluginCT ${CMAKE_CURRENT_SOURCE_DIR}/plugins/clocktree/__init__.py
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/clocktree/RSMT.py
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/clocktree/ClockTree.py
|
||||||
)
|
)
|
||||||
set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py
|
set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/BlockPower.py
|
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/BlockPower.py
|
||||||
|
@ -17,4 +21,5 @@
|
||||||
|
|
||||||
install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
|
install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
|
||||||
install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins )
|
install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins )
|
||||||
|
install ( FILES ${pyPluginCT} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/clocktree )
|
||||||
install ( FILES ${pyPluginChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/chip )
|
install ( FILES ${pyPluginChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/chip )
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
# | Python : "./plugins/ChipPlugin.py" |
|
# | Python : "./plugins/ChipPlugin.py" |
|
||||||
# +-----------------------------------------------------------------+
|
# +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import sys
|
import sys
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -41,6 +42,7 @@ try:
|
||||||
import Viewer
|
import Viewer
|
||||||
import CRL
|
import CRL
|
||||||
from CRL import RoutingLayerGauge
|
from CRL import RoutingLayerGauge
|
||||||
|
import helpers
|
||||||
from helpers import ErrorMessage
|
from helpers import ErrorMessage
|
||||||
from helpers import WarningMessage
|
from helpers import WarningMessage
|
||||||
import Nimbus
|
import Nimbus
|
||||||
|
@ -50,6 +52,7 @@ try:
|
||||||
import Kite
|
import Kite
|
||||||
import Unicorn
|
import Unicorn
|
||||||
import plugins
|
import plugins
|
||||||
|
import clocktree.ClockTree
|
||||||
import chip.Configuration
|
import chip.Configuration
|
||||||
import chip.BlockPower
|
import chip.BlockPower
|
||||||
import chip.BlockCorona
|
import chip.BlockCorona
|
||||||
|
@ -71,10 +74,10 @@ except Exception, e:
|
||||||
# Plugin working part.
|
# Plugin working part.
|
||||||
|
|
||||||
|
|
||||||
class PlaceCore ( chip.Configuration.Wrapper ):
|
class PlaceCore ( chip.Configuration.ChipConfWrapper ):
|
||||||
|
|
||||||
def __init__ ( self, confWrapper ):
|
def __init__ ( self, conf ):
|
||||||
chip.Configuration.Wrapper.__init__( self, confWrapper.conf )
|
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||||
self.validated = False
|
self.validated = False
|
||||||
return
|
return
|
||||||
|
|
||||||
|
@ -113,10 +116,31 @@ class PlaceCore ( chip.Configuration.Wrapper ):
|
||||||
def doPlacement ( self ):
|
def doPlacement ( self ):
|
||||||
if not self.validated: return
|
if not self.validated: return
|
||||||
|
|
||||||
checkUnplaced = plugins.CheckUnplaced( self.cores[0].getMasterCell(), plugins.NoFlags )
|
coreCell = self.cores[0].getMasterCell()
|
||||||
|
|
||||||
|
checkUnplaced = plugins.CheckUnplaced( coreCell, plugins.NoFlags )
|
||||||
if not checkUnplaced.check(): return
|
if not checkUnplaced.check(): return
|
||||||
|
|
||||||
mauka = Mauka.MaukaEngine.create( self.cores[0].getMasterCell() )
|
ckCore = None
|
||||||
|
for plug in self.cko.getPlugs():
|
||||||
|
if plug.getInstance() == self.cores[0]:
|
||||||
|
ckCore = plug.getMasterNet()
|
||||||
|
if not ckCore:
|
||||||
|
print WarningMessage( 'Core <%s> is not connected to chip clock.'
|
||||||
|
% self.cores[0].getName() )
|
||||||
|
|
||||||
|
if self.useClockTree and ckCore:
|
||||||
|
ht = clocktree.ClockTree.HTree.create( self, coreCell, ckCore, coreCell.getAbutmentBox() )
|
||||||
|
ht.addCloned( self.cell )
|
||||||
|
mauka = Mauka.MaukaEngine.create( coreCell )
|
||||||
|
mauka.run()
|
||||||
|
mauka.destroy()
|
||||||
|
ht.connectLeaf()
|
||||||
|
ht.prune()
|
||||||
|
ht.route()
|
||||||
|
ht.save( self.cell )
|
||||||
|
else:
|
||||||
|
mauka = Mauka.MaukaEngine.create( coreCell )
|
||||||
mauka.run()
|
mauka.run()
|
||||||
mauka.destroy()
|
mauka.destroy()
|
||||||
return
|
return
|
||||||
|
@ -139,6 +163,9 @@ def unicornHook ( **kw ):
|
||||||
|
|
||||||
def ScriptMain ( **kw ):
|
def ScriptMain ( **kw ):
|
||||||
try:
|
try:
|
||||||
|
helpers.staticInitialization( quiet=True )
|
||||||
|
#helpers.setTraceLevel( 550 )
|
||||||
|
|
||||||
cell, editor = plugins.kwParseMain( **kw )
|
cell, editor = plugins.kwParseMain( **kw )
|
||||||
|
|
||||||
conf = chip.Configuration.loadConfiguration( cell )
|
conf = chip.Configuration.loadConfiguration( cell )
|
||||||
|
@ -151,10 +178,17 @@ def ScriptMain ( **kw ):
|
||||||
placeCore = PlaceCore( conf )
|
placeCore = PlaceCore( conf )
|
||||||
placeCore.validate()
|
placeCore.validate()
|
||||||
placeCore.doFloorplan()
|
placeCore.doFloorplan()
|
||||||
|
editor.fit()
|
||||||
|
|
||||||
placeCore.doPlacement()
|
placeCore.doPlacement()
|
||||||
corePower = chip.BlockPower.Block( Path(conf.cores[0]), conf.vddi, conf.vssi )
|
editor.fit()
|
||||||
corePower.queryPower()
|
|
||||||
|
corePower = chip.BlockPower.Block( conf )
|
||||||
|
corePower.connectPower()
|
||||||
|
corePower.connectClock()
|
||||||
corePower.doLayout()
|
corePower.doLayout()
|
||||||
|
editor.fit()
|
||||||
|
|
||||||
coreCorona = chip.BlockCorona.Corona( corePower )
|
coreCorona = chip.BlockCorona.Corona( corePower )
|
||||||
coreCorona.connectPads( padsCorona )
|
coreCorona.connectPads( padsCorona )
|
||||||
coreCorona.connectBlock()
|
coreCorona.connectBlock()
|
||||||
|
@ -168,4 +202,7 @@ def ScriptMain ( **kw ):
|
||||||
print '\n\n', e; errorCode = 1
|
print '\n\n', e; errorCode = 1
|
||||||
traceback.print_tb(sys.exc_info()[2])
|
traceback.print_tb(sys.exc_info()[2])
|
||||||
|
|
||||||
|
sys.stdout.flush()
|
||||||
|
sys.stderr.flush()
|
||||||
|
|
||||||
return 0
|
return 0
|
||||||
|
|
|
@ -0,0 +1,114 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# This file is part of the Coriolis Software.
|
||||||
|
# Copyright (c) UPMC 2014-2014, 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@asim.lip6.fr |
|
||||||
|
# | =============================================================== |
|
||||||
|
# | Python : "./plugins/ClockTreePlugin.py" |
|
||||||
|
# +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import os.path
|
||||||
|
import math
|
||||||
|
import Cfg
|
||||||
|
import Hurricane
|
||||||
|
import Viewer
|
||||||
|
import CRL
|
||||||
|
from CRL import RoutingLayerGauge
|
||||||
|
import helpers
|
||||||
|
from helpers import trace
|
||||||
|
from helpers import ErrorMessage
|
||||||
|
import Mauka
|
||||||
|
import Unicorn
|
||||||
|
import plugins
|
||||||
|
import clocktree.ClockTree
|
||||||
|
import chip.Configuration
|
||||||
|
except ImportError, e:
|
||||||
|
module = str(e).split()[-1]
|
||||||
|
|
||||||
|
print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module
|
||||||
|
print ' Please check the integrity of the <coriolis> package.'
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception, e:
|
||||||
|
print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python'
|
||||||
|
print ' modules. Something may be wrong at Python/C API level.\n'
|
||||||
|
print ' %s' % e
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
# --------------------------------------------------------------------
|
||||||
|
# Plugin hook functions, unicornHook:menus, ScritMain:call
|
||||||
|
|
||||||
|
def unicornHook ( **kw ):
|
||||||
|
plugins.kwUnicornHook( 'plugins.clockTree'
|
||||||
|
, 'ClockTree'
|
||||||
|
, 'Build a buffered H-Tree for the clock'
|
||||||
|
, sys.modules[__name__].__file__
|
||||||
|
, **kw
|
||||||
|
)
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def ScriptMain ( **kw ):
|
||||||
|
try:
|
||||||
|
errorCode = 0
|
||||||
|
|
||||||
|
print ' o Cleaning up any previous run.'
|
||||||
|
for fileName in os.listdir('.'):
|
||||||
|
if fileName.endswith('.ap'):
|
||||||
|
print ' - <%s>' % fileName
|
||||||
|
os.unlink(fileName)
|
||||||
|
|
||||||
|
cell = None
|
||||||
|
if kw.has_key('cell') and kw['cell']:
|
||||||
|
cell = kw['cell']
|
||||||
|
|
||||||
|
editor = None
|
||||||
|
if kw.has_key('editor') and kw['editor']:
|
||||||
|
editor = kw['editor']
|
||||||
|
print ' o Editor detected, running in graphic mode.'
|
||||||
|
if cell == None: cell = editor.getCell()
|
||||||
|
|
||||||
|
if cell == None:
|
||||||
|
raise ErrorMessage( 3, 'ClockTree: No cell loaded yet.' )
|
||||||
|
|
||||||
|
framework = CRL.AllianceFramework.get()
|
||||||
|
cellGauge = framework.getCellGauge()
|
||||||
|
|
||||||
|
if cell.getAbutmentBox().isEmpty():
|
||||||
|
spaceMargin = Cfg.getParamPercentage('nimbus.spaceMargin').asPercentage() / 100.0 + 0.02
|
||||||
|
aspectRatio = Cfg.getParamPercentage('nimbus.aspectRatio').asPercentage() / 100.0
|
||||||
|
clocktree.ClockTree.computeAbutmentBox( cell, spaceMargin, aspectRatio, cellGauge )
|
||||||
|
if editor: editor.fit()
|
||||||
|
|
||||||
|
ht = clocktree.ClockTree.HTree.create( chip.Configuration.GaugeConfWrapper(chip.Configuration.GaugeConf())
|
||||||
|
, cell, None, cell.getAbutmentBox() )
|
||||||
|
if editor: editor.refresh()
|
||||||
|
mauka = Mauka.MaukaEngine.create( cell )
|
||||||
|
mauka.run()
|
||||||
|
mauka.destroy()
|
||||||
|
ht.connectLeaf()
|
||||||
|
ht.prune()
|
||||||
|
ht.route()
|
||||||
|
ht.save( cell )
|
||||||
|
|
||||||
|
#showNet( cell, 'ck_htree_bl_bl_bl' )
|
||||||
|
#showNet( cell, 'ck_htree_bl_bl_br' )
|
||||||
|
#showNet( cell, 'ck_htree_bl_bl_tl' )
|
||||||
|
#showNet( cell, 'ck_htree_bl_bl_tr' )
|
||||||
|
|
||||||
|
except ErrorMessage, e:
|
||||||
|
print e; errorCode = e.code
|
||||||
|
except Exception, e:
|
||||||
|
print '\n\n', e; errorCode = 1
|
||||||
|
traceback.print_tb(sys.exc_info()[2])
|
||||||
|
|
||||||
|
return 0
|
|
@ -111,6 +111,8 @@ class StackedVia ( object ):
|
||||||
self._vias = []
|
self._vias = []
|
||||||
return
|
return
|
||||||
|
|
||||||
|
def getNet ( self ): return self._net
|
||||||
|
|
||||||
def mergeDepth ( self, depth ):
|
def mergeDepth ( self, depth ):
|
||||||
if self._hasLayout:
|
if self._hasLayout:
|
||||||
print WarningMessage( 'StackedVia.mergeDepth(): Cannot be called *after* StackVia.doLayout()' )
|
print WarningMessage( 'StackedVia.mergeDepth(): Cannot be called *after* StackVia.doLayout()' )
|
||||||
|
|
|
@ -30,6 +30,7 @@ from Hurricane import Horizontal
|
||||||
from Hurricane import Vertical
|
from Hurricane import Vertical
|
||||||
import CRL
|
import CRL
|
||||||
from CRL import RoutingLayerGauge
|
from CRL import RoutingLayerGauge
|
||||||
|
from helpers import trace
|
||||||
from helpers import ErrorMessage
|
from helpers import ErrorMessage
|
||||||
from helpers import WarningMessage
|
from helpers import WarningMessage
|
||||||
from plugins import StackedVia
|
from plugins import StackedVia
|
||||||
|
@ -64,7 +65,7 @@ class HorizontalRail ( Rail ):
|
||||||
, '(corona:%s)' % str(self.side.innerBb) ] )
|
, '(corona:%s)' % str(self.side.innerBb) ] )
|
||||||
|
|
||||||
#print ' HorizontalRail.connect() net:%s contact:%s' % (self.net.getName(),str(contact))
|
#print ' HorizontalRail.connect() net:%s contact:%s' % (self.net.getName(),str(contact))
|
||||||
if self.net != contact.getNet(): return False
|
#if self.net != contact.getNet(): return False
|
||||||
if self.vias.has_key(contact.getX()): return False
|
if self.vias.has_key(contact.getX()): return False
|
||||||
|
|
||||||
keys = self.vias.keys()
|
keys = self.vias.keys()
|
||||||
|
@ -87,26 +88,14 @@ class HorizontalRail ( Rail ):
|
||||||
, self.side.getLayerDepth(self.side.getHLayer())
|
, self.side.getLayerDepth(self.side.getHLayer())
|
||||||
, contact.getX()
|
, contact.getX()
|
||||||
, self.axis
|
, self.axis
|
||||||
, contact.getWidth()
|
, contact.getWidth() - DbU.fromLambda(1.0)
|
||||||
, self.side.hRailWidth
|
, self.side.hRailWidth - DbU.fromLambda(1.0)
|
||||||
)
|
)
|
||||||
, contact ]
|
, contact ]
|
||||||
#print ' ADD contact @ [%d %d]' % (DbU.toLambda(contact.getX()), DbU.toLambda(self.axis))
|
#print ' ADD contact @ [%d %d]' % (DbU.toLambda(contact.getX()), DbU.toLambda(self.axis))
|
||||||
self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
||||||
return True
|
return True
|
||||||
|
|
||||||
def doLayout ( self ):
|
|
||||||
for via in self.vias.values():
|
|
||||||
via[1].doLayout()
|
|
||||||
|
|
||||||
Horizontal.create( self.side.corner0(self.order)
|
|
||||||
, self.side.corner1(self.order)
|
|
||||||
, self.side.getHLayer()
|
|
||||||
, self.axis
|
|
||||||
, self.side.hRailWidth
|
|
||||||
)
|
|
||||||
return
|
|
||||||
|
|
||||||
def doLayout ( self ):
|
def doLayout ( self ):
|
||||||
#print 'HorizontalRail[%s] @%d' % (self.order,DbU.toLambda(self.axis))
|
#print 'HorizontalRail[%s] @%d' % (self.order,DbU.toLambda(self.axis))
|
||||||
|
|
||||||
|
@ -114,6 +103,8 @@ class HorizontalRail ( Rail ):
|
||||||
, self.side.corner1(self.order) ]
|
, self.side.corner1(self.order) ]
|
||||||
|
|
||||||
for via in self.vias.values():
|
for via in self.vias.values():
|
||||||
|
if via[1].getNet() != via[2].getNet(): continue
|
||||||
|
|
||||||
via[1].doLayout()
|
via[1].doLayout()
|
||||||
#print ' Connect:', via[2], via[1].getVia( via[2].getLayer() )
|
#print ' Connect:', via[2], via[1].getVia( via[2].getLayer() )
|
||||||
Vertical.create( via[1].getVia( via[2].getLayer() )
|
Vertical.create( via[1].getVia( via[2].getLayer() )
|
||||||
|
@ -149,7 +140,8 @@ class VerticalRail ( Rail ):
|
||||||
, self.side.corner1(self.order) ]
|
, self.side.corner1(self.order) ]
|
||||||
|
|
||||||
for via in self.vias.values():
|
for via in self.vias.values():
|
||||||
#print ' Connect: ', via[2]
|
if via[1].getNet() != via[2].getNet(): continue
|
||||||
|
|
||||||
via[1].doLayout()
|
via[1].doLayout()
|
||||||
Horizontal.create( via[1].getVia( via[2].getLayer() )
|
Horizontal.create( via[1].getVia( via[2].getLayer() )
|
||||||
, via[2]
|
, via[2]
|
||||||
|
@ -178,30 +170,36 @@ class VerticalRail ( Rail ):
|
||||||
, 'power pad is likely to be to far off north or south.'
|
, 'power pad is likely to be to far off north or south.'
|
||||||
, '(corona:%s)' % str(self.side.innerBb) ] )
|
, '(corona:%s)' % str(self.side.innerBb) ] )
|
||||||
|
|
||||||
if self.net != contact.getNet(): return False
|
#if self.net != contact.getNet(): return False
|
||||||
if self.vias.has_key(contact.getY()): return False
|
if self.vias.has_key(contact.getY()): return False
|
||||||
|
|
||||||
|
trace( 550, ',+', '\tVerticalRail.connect() [%s] @%d\n' % (self.order,DbU.toLambda(self.axis)) )
|
||||||
|
trace( 550, contact )
|
||||||
|
|
||||||
keys = self.vias.keys()
|
keys = self.vias.keys()
|
||||||
keys.sort()
|
keys.sort()
|
||||||
insertIndex = bisect.bisect_left( keys, contact.getY() )
|
insertIndex = bisect.bisect_left( keys, contact.getY() )
|
||||||
#print 'keys:', keys
|
trace( 550, ',+', '\tkeys:' )
|
||||||
|
for key in keys:
|
||||||
|
trace( 550, ' %d' % DbU.toLambda(key) )
|
||||||
|
trace( 550, '\n' )
|
||||||
|
|
||||||
if len(keys) > 0:
|
if len(keys) > 0:
|
||||||
if insertIndex < len(keys):
|
if insertIndex < len(keys):
|
||||||
insertPosition = keys[ insertIndex ]
|
insertPosition = keys[ insertIndex ]
|
||||||
#print 'insertIndex:%d' % insertIndex
|
trace( 550, '\tinsertIndex:%d' % insertIndex )
|
||||||
#print 'Check NEXT contactBb:%s via:%s' \
|
trace( 550, '\tCheck NEXT contactBb:%s via:%s\n' \
|
||||||
# % ( str(contactBb)
|
% ( contactBb
|
||||||
# , str(self.vias[insertPosition][2].getBoundingBox()) )
|
, self.vias[insertPosition][2].getBoundingBox()) )
|
||||||
if contactBb.getYMax() >= self.vias[insertPosition][2].getBoundingBox().getYMin():
|
if contactBb.getYMax() >= self.vias[insertPosition][2].getBoundingBox().getYMin():
|
||||||
# print 'Reject %s intersect NEXT' % str(contact)
|
trace( 550, ',--', '\tReject %s intersect NEXT\n' % contact )
|
||||||
return False
|
return False
|
||||||
if insertIndex > 0:
|
if insertIndex > 0:
|
||||||
#print 'check PREVIOUS contactBb:%s via:%s' \
|
trace( 550, '\tcheck PREVIOUS contactBb:%s via:%s\n' \
|
||||||
# % ( str(contactBb)
|
% ( contactBb
|
||||||
# , str(self.vias[keys[insertIndex-1]][2].getBoundingBox()) )
|
, self.vias[keys[insertIndex-1]][2].getBoundingBox()) )
|
||||||
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getYMax() >= contactBb.getYMin():
|
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getYMax() >= contactBb.getYMin():
|
||||||
# print 'Reject %s intersect PREVIOUS' % str(contact)
|
trace( 550, ',--', '\tReject %s intersect PREVIOUS\n' % contact )
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.vias[ contact.getY() ] = [ contact.getY()
|
self.vias[ contact.getY() ] = [ contact.getY()
|
||||||
|
@ -209,11 +207,11 @@ class VerticalRail ( Rail ):
|
||||||
, self.side.getLayerDepth(self.side.getVLayer())
|
, self.side.getLayerDepth(self.side.getVLayer())
|
||||||
, self.axis
|
, self.axis
|
||||||
, contact.getY()
|
, contact.getY()
|
||||||
, self.side.vRailWidth
|
, self.side.vRailWidth - DbU.fromLambda(1.0)
|
||||||
, contact.getHeight()
|
, contact.getHeight() - DbU.fromLambda(1.0)
|
||||||
)
|
)
|
||||||
, contact ]
|
, contact ]
|
||||||
#print 'ADD %s' % str(contact)
|
trace(550, ',--' '\tADD %s\n' % contact )
|
||||||
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
@ -265,12 +263,18 @@ class Side ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
def connectPads ( self, padSide ):
|
def connectPads ( self, padSide ):
|
||||||
halfRails = len(self._rails)/2
|
|
||||||
for terminal in padSide._powerContacts:
|
for terminal in padSide._powerContacts:
|
||||||
#print 'Connect pad terminal ', terminal
|
#print ' Connect to [-%i] @%d' % (0, DbU.toLambda(self.getOuterRail(0).axis))
|
||||||
|
self.getOuterRail( 0 ).connect( terminal )
|
||||||
|
|
||||||
|
halfRails = (len(self._rails)-1)/2
|
||||||
|
trace( 550, 'halfRails:%i' % halfRails )
|
||||||
|
for terminal in padSide._powerContacts:
|
||||||
|
trace( 550, ',+', '\tConnect pad terminal %s\n' % terminal )
|
||||||
for i in range(halfRails):
|
for i in range(halfRails):
|
||||||
#print ' Connect to [-%i] @%d' % (i, DbU.toLambda(self.getOuterRail(i).axis))
|
trace( 550, '\tConnect to [-%i] @%d\n' % (i+1, DbU.toLambda(self.getOuterRail(i+1).axis)) )
|
||||||
self.getOuterRail(i).connect( terminal )
|
self.getOuterRail(i+1).connect( terminal )
|
||||||
|
trace( 550, '-' )
|
||||||
return
|
return
|
||||||
|
|
||||||
def doLayout ( self ):
|
def doLayout ( self ):
|
||||||
|
@ -364,60 +368,45 @@ class Corona ( object ):
|
||||||
if not isinstance(block,chip.BlockPower.Block):
|
if not isinstance(block,chip.BlockPower.Block):
|
||||||
raise ErrorMessage( 1, 'Attempt to create a Corona on a non-Block object.' )
|
raise ErrorMessage( 1, 'Attempt to create a Corona on a non-Block object.' )
|
||||||
|
|
||||||
self._framework = CRL.AllianceFramework.get()
|
|
||||||
self._routingGauge = self._framework.getRoutingGauge()
|
|
||||||
self._block = block
|
self._block = block
|
||||||
self._innerBb = self._block.bb
|
self._innerBb = self._block.bb
|
||||||
self._block.path.getTransformation().applyOn( self._innerBb )
|
self._block.path.getTransformation().applyOn( self._innerBb )
|
||||||
|
|
||||||
self._railsNb = 4
|
self._railsNb = 5
|
||||||
self._hRailWidth = DbU.fromLambda( 12.0 )
|
self._hRailWidth = DbU.fromLambda( 12.0 )
|
||||||
self._vRailWidth = DbU.fromLambda( 12.0 )
|
self._vRailWidth = DbU.fromLambda( 12.0 )
|
||||||
self._hRailSpace = DbU.fromLambda( 6.0 )
|
self._hRailSpace = DbU.fromLambda( 6.0 )
|
||||||
self._vRailSpace = DbU.fromLambda( 6.0 )
|
self._vRailSpace = DbU.fromLambda( 6.0 )
|
||||||
self._topLayerDepth = 0
|
|
||||||
self._horizontalDepth = 0
|
|
||||||
self._verticalDepth = 0
|
|
||||||
|
|
||||||
self._southSide = SouthSide( self )
|
self._southSide = SouthSide( self )
|
||||||
self._northSide = NorthSide( self )
|
self._northSide = NorthSide( self )
|
||||||
self._westSide = WestSide ( self )
|
self._westSide = WestSide ( self )
|
||||||
self._eastSide = EastSide ( self )
|
self._eastSide = EastSide ( self )
|
||||||
|
|
||||||
self._guessHvLayers()
|
|
||||||
return
|
return
|
||||||
|
|
||||||
def _guessHvLayers ( self ):
|
@property
|
||||||
topLayer = Cfg.getParamString('katabatic.topRoutingLayer').asString()
|
def routingGauge ( self ): return self._block.routingGauge
|
||||||
self._topLayerDepth = 0
|
@property
|
||||||
for layerGauge in self._routingGauge.getLayerGauges():
|
def topLayerDepth ( self ): return self._block.topLayerDepth
|
||||||
if layerGauge.getLayer().getName() == topLayer:
|
@property
|
||||||
self._topLayerDepth = layerGauge.getDepth()
|
def horizontalDepth ( self ): return self._block.horizontalDepth
|
||||||
break
|
@property
|
||||||
if not self._topLayerDepth:
|
def verticalDepth ( self ): return self._block.verticalDepth
|
||||||
print WarningMessage( 'Gauge top layer not defined, using top of gauge (%d).' \
|
|
||||||
% self._routingGauge.getDepth() )
|
|
||||||
self._topLayerDepth = self._routingGauge.getDepth()
|
|
||||||
|
|
||||||
for depth in range(0,self._topLayerDepth+1):
|
|
||||||
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
|
||||||
self._horizontalDepth = depth
|
|
||||||
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
|
||||||
self._verticalDepth = depth
|
|
||||||
return
|
|
||||||
|
|
||||||
def getLayerDepth ( self, metal ):
|
def getLayerDepth ( self, metal ):
|
||||||
return self._routingGauge.getLayerDepth( metal )
|
return self.routingGauge.getLayerDepth( metal )
|
||||||
|
|
||||||
def getRailNet ( self, i ):
|
def getRailNet ( self, i ):
|
||||||
|
if i == self._railsNb-1: return self._block.cko
|
||||||
if i % 2: return self._block.vssi
|
if i % 2: return self._block.vssi
|
||||||
return self._block.vddi
|
return self._block.vddi
|
||||||
|
|
||||||
def getHLayer ( self ):
|
def getHLayer ( self ):
|
||||||
return self._routingGauge.getLayerGauge( self._horizontalDepth ).getLayer()
|
return self.routingGauge.getLayerGauge( self.horizontalDepth ).getLayer()
|
||||||
|
|
||||||
def getVLayer ( self ):
|
def getVLayer ( self ):
|
||||||
return self._routingGauge.getLayerGauge( self._verticalDepth ).getLayer()
|
return self.routingGauge.getLayerGauge( self.verticalDepth ).getLayer()
|
||||||
|
|
||||||
def connectBlock ( self ):
|
def connectBlock ( self ):
|
||||||
for plane in self._block.planes.values():
|
for plane in self._block.planes.values():
|
||||||
|
@ -442,9 +431,9 @@ class Corona ( object ):
|
||||||
, chip.NorthEast : []
|
, chip.NorthEast : []
|
||||||
}
|
}
|
||||||
|
|
||||||
contactDepth = self._horizontalDepth
|
contactDepth = self.horizontalDepth
|
||||||
if self._horizontalDepth > self._verticalDepth:
|
if self.horizontalDepth > self.verticalDepth:
|
||||||
contactDepth = self._verticalDepth
|
contactDepth = self.verticalDepth
|
||||||
|
|
||||||
for i in range(self._railsNb):
|
for i in range(self._railsNb):
|
||||||
xBL = self._westSide .getRail(i).axis
|
xBL = self._westSide .getRail(i).axis
|
||||||
|
@ -453,30 +442,31 @@ class Corona ( object ):
|
||||||
yTR = self._northSide.getRail(i).axis
|
yTR = self._northSide.getRail(i).axis
|
||||||
net = self.getRailNet( i )
|
net = self.getRailNet( i )
|
||||||
|
|
||||||
|
self.routingGauge.getContactLayer(contactDepth)
|
||||||
self._corners[chip.SouthWest].append(
|
self._corners[chip.SouthWest].append(
|
||||||
Contact.create( net
|
Contact.create( net
|
||||||
, self._routingGauge.getContactLayer(contactDepth)
|
, self.routingGauge.getContactLayer(contactDepth)
|
||||||
, xBL, yBL
|
, xBL, yBL
|
||||||
, self._hRailWidth
|
, self._hRailWidth
|
||||||
, self._vRailWidth
|
, self._vRailWidth
|
||||||
) )
|
) )
|
||||||
self._corners[chip.NorthWest].append(
|
self._corners[chip.NorthWest].append(
|
||||||
Contact.create( net
|
Contact.create( net
|
||||||
, self._routingGauge.getContactLayer(contactDepth)
|
, self.routingGauge.getContactLayer(contactDepth)
|
||||||
, xBL, yTR
|
, xBL, yTR
|
||||||
, self._hRailWidth
|
, self._hRailWidth
|
||||||
, self._vRailWidth
|
, self._vRailWidth
|
||||||
) )
|
) )
|
||||||
self._corners[chip.SouthEast].append(
|
self._corners[chip.SouthEast].append(
|
||||||
Contact.create( net
|
Contact.create( net
|
||||||
, self._routingGauge.getContactLayer(contactDepth)
|
, self.routingGauge.getContactLayer(contactDepth)
|
||||||
, xTR, yBL
|
, xTR, yBL
|
||||||
, self._hRailWidth
|
, self._hRailWidth
|
||||||
, self._vRailWidth
|
, self._vRailWidth
|
||||||
) )
|
) )
|
||||||
self._corners[chip.NorthEast].append(
|
self._corners[chip.NorthEast].append(
|
||||||
Contact.create( net
|
Contact.create( net
|
||||||
, self._routingGauge.getContactLayer(contactDepth)
|
, self.routingGauge.getContactLayer(contactDepth)
|
||||||
, xTR, yTR
|
, xTR, yTR
|
||||||
, self._hRailWidth
|
, self._hRailWidth
|
||||||
, self._vRailWidth
|
, self._vRailWidth
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
# +-----------------------------------------------------------------+
|
# +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
import sys
|
||||||
from Hurricane import DbU
|
from Hurricane import DbU
|
||||||
from Hurricane import Point
|
from Hurricane import Point
|
||||||
from Hurricane import Transformation
|
from Hurricane import Transformation
|
||||||
|
@ -28,11 +29,17 @@ from Hurricane import Horizontal
|
||||||
from Hurricane import Vertical
|
from Hurricane import Vertical
|
||||||
from Hurricane import Query
|
from Hurricane import Query
|
||||||
import CRL
|
import CRL
|
||||||
|
import helpers
|
||||||
|
from helpers import trace
|
||||||
from helpers import ErrorMessage
|
from helpers import ErrorMessage
|
||||||
from helpers import WarningMessage
|
from helpers import WarningMessage
|
||||||
import chip.Configuration
|
import chip.Configuration
|
||||||
|
|
||||||
|
|
||||||
|
helpers.staticInitialization( quiet=True )
|
||||||
|
helpers.trace.level = 550
|
||||||
|
|
||||||
|
|
||||||
class Side ( object ):
|
class Side ( object ):
|
||||||
|
|
||||||
def __init__ ( self, block, side, net, metal ):
|
def __init__ ( self, block, side, net, metal ):
|
||||||
|
@ -90,13 +97,16 @@ class Side ( object ):
|
||||||
height = 0
|
height = 0
|
||||||
y = self.block.bb.getYMax()
|
y = self.block.bb.getYMax()
|
||||||
|
|
||||||
|
minWidth = DbU.fromLambda( 6.0 )
|
||||||
for terminal in self.terminals:
|
for terminal in self.terminals:
|
||||||
if self.side == chip.West or self.side == chip.East:
|
if self.side == chip.West or self.side == chip.East:
|
||||||
center = Point( x, terminal[0].getCenter() )
|
center = Point( x, terminal[0].getCenter() )
|
||||||
height = terminal[0].getSize()
|
height = terminal[0].getSize()
|
||||||
|
if height < minWidth: height = minWidth
|
||||||
elif self.side == chip.North or self.side == chip.South:
|
elif self.side == chip.North or self.side == chip.South:
|
||||||
center = Point( terminal[0].getCenter(), y )
|
center = Point( terminal[0].getCenter(), y )
|
||||||
width = terminal[0].getSize()
|
width = terminal[0].getSize()
|
||||||
|
if width < minWidth: width = minWidth
|
||||||
|
|
||||||
self.block.path.getTransformation().applyOn( center )
|
self.block.path.getTransformation().applyOn( center )
|
||||||
|
|
||||||
|
@ -172,14 +182,13 @@ class GoCb ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class Block ( object ):
|
class Block ( chip.Configuration.ChipConfWrapper ):
|
||||||
|
|
||||||
def __init__ ( self, path, vddi, vssi ):
|
def __init__ ( self, conf ):
|
||||||
self.path = path
|
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||||
self.cell = self.path.getTailInstance().getMasterCell()
|
self.path = Path( self.cores[0] )
|
||||||
self.bb = self.cell.getAbutmentBox()
|
self.block = self.path.getTailInstance().getMasterCell()
|
||||||
self.vddi = vddi
|
self.bb = self.block.getAbutmentBox()
|
||||||
self.vssi = vssi
|
|
||||||
self.planes = { }
|
self.planes = { }
|
||||||
self.activePlane = None
|
self.activePlane = None
|
||||||
|
|
||||||
|
@ -190,7 +199,7 @@ class Block ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def queryPower ( self ):
|
def connectPower ( self ):
|
||||||
if not self.vddi or not self.vssi:
|
if not self.vddi or not self.vssi:
|
||||||
print ErrorMessage( 1, 'Cannot build block power terminals as vddi and/or vss are not known.' )
|
print ErrorMessage( 1, 'Cannot build block power terminals as vddi and/or vss are not known.' )
|
||||||
return
|
return
|
||||||
|
@ -198,7 +207,7 @@ class Block ( object ):
|
||||||
goCb = GoCb( self )
|
goCb = GoCb( self )
|
||||||
query = Query()
|
query = Query()
|
||||||
query.setGoCallback( goCb )
|
query.setGoCallback( goCb )
|
||||||
query.setCell( self.cell )
|
query.setCell( self.block )
|
||||||
query.setArea( self.bb )
|
query.setArea( self.bb )
|
||||||
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
||||||
|
|
||||||
|
@ -210,6 +219,59 @@ class Block ( object ):
|
||||||
self.activePlane = None
|
self.activePlane = None
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def connectClock ( self ):
|
||||||
|
if not self.cko:
|
||||||
|
print 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.cko:
|
||||||
|
blockCk = plug.getMasterNet()
|
||||||
|
|
||||||
|
if not blockCk:
|
||||||
|
print ErrorMessage( 1, 'Block <%s> has no net connected to the clock <%s>.'
|
||||||
|
% (self.path.getTailInstance().getName(),self.ck.getName()) )
|
||||||
|
return
|
||||||
|
|
||||||
|
plugs = []
|
||||||
|
for plug in blockCk.getPlugs():
|
||||||
|
if plug.getInstance().getName() == 'ck_htree':
|
||||||
|
plugs.append( plug )
|
||||||
|
|
||||||
|
if len(plugs) != 1:
|
||||||
|
message = 'Block <%s> has not exactly one H-Tree connecteds to the clock <%s>:' \
|
||||||
|
% (self.path.getTailInstance().getName(),blockCk.getName())
|
||||||
|
for plug in plugs:
|
||||||
|
message += '\n - %s' % plug
|
||||||
|
print ErrorMessage( 1, message )
|
||||||
|
return
|
||||||
|
|
||||||
|
UpdateSession.open()
|
||||||
|
bufferRp = self.rpAccessByOccurrence( Occurrence(plugs[0], self.path), self.cko )
|
||||||
|
blockAb = self.block.getAbutmentBox()
|
||||||
|
self.path.getTransformation().applyOn( blockAb )
|
||||||
|
layerGauge = self.routingGauge.getLayerGauge(self.verticalDepth)
|
||||||
|
|
||||||
|
contact = Contact.create( self.cko
|
||||||
|
, self.routingGauge.getRoutingLayer(self.verticalDepth)
|
||||||
|
, bufferRp.getX()
|
||||||
|
, blockAb.getYMax()
|
||||||
|
, layerGauge.getViaWidth()
|
||||||
|
, layerGauge.getViaWidth()
|
||||||
|
)
|
||||||
|
segment = self.createVertical( bufferRp, contact, bufferRp.getX() )
|
||||||
|
|
||||||
|
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
|
||||||
|
bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() )
|
||||||
|
self.path.getTransformation().getInvert().applyOn( bb )
|
||||||
|
self.activePlane.addTerminal( self.cko, Plane.Vertical, bb )
|
||||||
|
|
||||||
|
UpdateSession.close()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
def doLayout ( self ):
|
def doLayout ( self ):
|
||||||
UpdateSession.open()
|
UpdateSession.open()
|
||||||
for plane in self.planes.values():
|
for plane in self.planes.values():
|
||||||
|
|
|
@ -19,19 +19,312 @@ import os.path
|
||||||
import Cfg
|
import Cfg
|
||||||
from Hurricane import DbU
|
from Hurricane import DbU
|
||||||
from Hurricane import Box
|
from Hurricane import Box
|
||||||
|
from Hurricane import Transformation
|
||||||
|
from Hurricane import Box
|
||||||
|
from Hurricane import Path
|
||||||
|
from Hurricane import Occurrence
|
||||||
from Hurricane import Net
|
from Hurricane import Net
|
||||||
|
from Hurricane import RoutingPad
|
||||||
|
from Hurricane import Contact
|
||||||
|
from Hurricane import Horizontal
|
||||||
|
from Hurricane import Vertical
|
||||||
|
from Hurricane import Plug
|
||||||
|
from Hurricane import Instance
|
||||||
import CRL
|
import CRL
|
||||||
|
from CRL import RoutingLayerGauge
|
||||||
|
from helpers import trace
|
||||||
from helpers import ErrorMessage
|
from helpers import ErrorMessage
|
||||||
from helpers import WarningMessage
|
from helpers import WarningMessage
|
||||||
from plugins import getParameter
|
from plugins import getParameter
|
||||||
|
|
||||||
|
|
||||||
class Configuration ( object ):
|
def breakpoint ( editor, level, message ):
|
||||||
|
if editor:
|
||||||
|
editor.fit()
|
||||||
|
editor.refresh()
|
||||||
|
Breakpoint.stop( level, message )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def getPlugByName ( instance, netName ):
|
||||||
|
masterCell = instance.getMasterCell()
|
||||||
|
masterNet = masterCell.getNet( netName )
|
||||||
|
if masterNet:
|
||||||
|
return instance.getPlug( masterNet )
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def getPlugByNet ( instance, net ):
|
||||||
|
for plug in net.getPlugs():
|
||||||
|
if plug.getInstance() == instance:
|
||||||
|
return plug
|
||||||
|
return None
|
||||||
|
|
||||||
|
|
||||||
|
def getRpBb ( instance, netName ):
|
||||||
|
bb = Box()
|
||||||
|
for net in instance.getMasterCell().getNets():
|
||||||
|
if net.isExternal() and net.getName() == netName:
|
||||||
|
for component in net.getExternalComponents():
|
||||||
|
if isinstance(component,Vertical):
|
||||||
|
bb = component.getBoundingBox()
|
||||||
|
instance.getTransformation().applyOn( bb )
|
||||||
|
return bb
|
||||||
|
|
||||||
|
|
||||||
|
def showNet ( cell, netName ):
|
||||||
|
net = cell.getNet(netName)
|
||||||
|
if not net:
|
||||||
|
print ErrorMessage( 3, 'Cell %s doesn\'t have net %s' % (cell.getName(),netName) )
|
||||||
|
return
|
||||||
|
|
||||||
|
print 'Components of', netName
|
||||||
|
for component in net.getComponents():
|
||||||
|
print '| ', component, component.getBoundingBox()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def destroyNetComponents ( net ):
|
||||||
|
# 1. We cannot iterate over a Hurricane Collection if we are deleting
|
||||||
|
# some of it's elements at the same time (could be improved as it
|
||||||
|
# is an intrusive map.
|
||||||
|
# 2. Lazy programming: as we don't know the destruction order, some
|
||||||
|
# components can be deleted by (previous) others so we can endup
|
||||||
|
# on dangling Python proxy which send an exception that we catch.
|
||||||
|
# 3. Plugs are not destroyed (they cannot as they are part of the
|
||||||
|
# Instance). They stay connected to the net.
|
||||||
|
toDestroy = []
|
||||||
|
for component in net.getComponents():
|
||||||
|
if not isinstance(component,Plug):
|
||||||
|
toDestroy.append( component )
|
||||||
|
for component in toDestroy:
|
||||||
|
try:
|
||||||
|
component.destroy()
|
||||||
|
except:
|
||||||
|
pass
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Class : "Configuration.GaugeConf".
|
||||||
|
|
||||||
|
class GaugeConf ( object ):
|
||||||
|
|
||||||
|
HAccess = 0x0001
|
||||||
|
OffsetRight1 = 0x0002
|
||||||
|
OffsetTop1 = 0x0004
|
||||||
|
OffsetBottom1 = 0x0008
|
||||||
|
|
||||||
|
def __init__ ( self ):
|
||||||
|
self._routingGauge = None
|
||||||
|
self._topLayerDepth = 0
|
||||||
|
self._plugToRp = { }
|
||||||
|
|
||||||
|
self._loadRoutingGauge()
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def _loadRoutingGauge ( self ):
|
||||||
|
self._routingGauge = CRL.AllianceFramework.get().getRoutingGauge()
|
||||||
|
|
||||||
|
topLayer = Cfg.getParamString('katabatic.topRoutingLayer').asString()
|
||||||
|
|
||||||
|
self._topLayerDepth = 0
|
||||||
|
for layerGauge in self._routingGauge.getLayerGauges():
|
||||||
|
if layerGauge.getLayer().getName() == topLayer:
|
||||||
|
self._topLayerDepth = layerGauge.getDepth()
|
||||||
|
break
|
||||||
|
if not self._topLayerDepth:
|
||||||
|
print WarningMessage( 'Gauge top layer not defined, using top of gauge (%d).' \
|
||||||
|
% self._routingGauge.getDepth() )
|
||||||
|
self._topLayerDepth = self._routingGauge.getDepth()
|
||||||
|
|
||||||
|
self._horizontalDepth = 0
|
||||||
|
self._verticalDepth = 0
|
||||||
|
for depth in range(0,self._topLayerDepth+1):
|
||||||
|
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
||||||
|
self._horizontalDepth = depth
|
||||||
|
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
||||||
|
self._verticalDepth = depth
|
||||||
|
return
|
||||||
|
|
||||||
|
def _createContact ( self, net, x, y ):
|
||||||
|
return Contact.create( net
|
||||||
|
, self._routingGauge.getContactLayer(self._horizontalDepth)
|
||||||
|
, x, y
|
||||||
|
, self._routingGauge.getLayerGauge(self._horizontalDepth).getViaWidth()
|
||||||
|
, self._routingGauge.getLayerGauge(self._horizontalDepth).getViaWidth()
|
||||||
|
)
|
||||||
|
|
||||||
|
def _createHorizontal ( self, source, target, y ):
|
||||||
|
segment = Horizontal.create( source
|
||||||
|
, target
|
||||||
|
, self._routingGauge.getRoutingLayer(self._horizontalDepth)
|
||||||
|
, y
|
||||||
|
, self._routingGauge.getLayerGauge(self._horizontalDepth).getWireWidth()
|
||||||
|
)
|
||||||
|
trace( 550, segment )
|
||||||
|
return segment
|
||||||
|
|
||||||
|
def _createVertical ( self, source, target, x ):
|
||||||
|
segment = Vertical.create( source
|
||||||
|
, target
|
||||||
|
, self._routingGauge.getRoutingLayer(self._verticalDepth)
|
||||||
|
, x
|
||||||
|
, self._routingGauge.getLayerGauge(self._verticalDepth).getWireWidth()
|
||||||
|
)
|
||||||
|
trace( 550, segment )
|
||||||
|
return segment
|
||||||
|
|
||||||
|
def _rpAccess ( self, rp, flags ):
|
||||||
|
trace( 550, ',+', '\t_rpAccess() %s\n' % str(rp) )
|
||||||
|
|
||||||
|
contact1 = Contact.create( rp, self._routingGauge.getContactLayer(0), 0, 0 )
|
||||||
|
|
||||||
|
if flags & GaugeConf.OffsetBottom1:
|
||||||
|
contact1.setDy( self._routingGauge.getLayerGauge(self._horizontalDepth).getPitch() )
|
||||||
|
|
||||||
|
if flags & GaugeConf.OffsetTop1:
|
||||||
|
contact1.setDy( - self._routingGauge.getLayerGauge(self._horizontalDepth).getPitch() )
|
||||||
|
|
||||||
|
trace( 550, contact1 )
|
||||||
|
|
||||||
|
if flags & GaugeConf.HAccess: stopDepth = self._horizontalDepth
|
||||||
|
else: stopDepth = self._verticalDepth
|
||||||
|
|
||||||
|
for depth in range(1,stopDepth):
|
||||||
|
xoffset = 0
|
||||||
|
if flags & GaugeConf.OffsetRight1 and depth == 1:
|
||||||
|
xoffset = self._routingGauge.getLayerGauge(depth+1).getPitch()
|
||||||
|
contact2 = Contact.create( rp.getNet()
|
||||||
|
, self._routingGauge.getContactLayer(depth)
|
||||||
|
, contact1.getX() + xoffset
|
||||||
|
, contact1.getY()
|
||||||
|
, self._routingGauge.getLayerGauge(depth).getViaWidth()
|
||||||
|
, self._routingGauge.getLayerGauge(depth).getViaWidth()
|
||||||
|
)
|
||||||
|
trace( 550, contact2 )
|
||||||
|
if self._routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
||||||
|
segment = Horizontal.create( contact1
|
||||||
|
, contact2
|
||||||
|
, self._routingGauge.getRoutingLayer(depth)
|
||||||
|
, contact1.getY()
|
||||||
|
, self._routingGauge.getLayerGauge(depth).getWireWidth()
|
||||||
|
)
|
||||||
|
trace( 550, segment )
|
||||||
|
else:
|
||||||
|
segment = Vertical.create( contact1
|
||||||
|
, contact2
|
||||||
|
, self._routingGauge.getRoutingLayer(depth)
|
||||||
|
, contact1.getX()
|
||||||
|
, self._routingGauge.getLayerGauge(depth).getWireWidth()
|
||||||
|
)
|
||||||
|
trace( 550, segment )
|
||||||
|
contact1 = contact2
|
||||||
|
|
||||||
|
trace( 550, '-' )
|
||||||
|
return contact1
|
||||||
|
|
||||||
|
def _rpByOccurrence ( self, occurrence, net ):
|
||||||
|
plug = occurrence.getEntity()
|
||||||
|
if self._plugToRp.has_key(plug):
|
||||||
|
rp = self._plugToRp[plug]
|
||||||
|
else:
|
||||||
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
||||||
|
self._plugToRp[plug] = rp
|
||||||
|
|
||||||
|
return rp
|
||||||
|
|
||||||
|
def _rpAccessByOccurrence ( self, occurrence, net, flags ):
|
||||||
|
plug = occurrence.getEntity()
|
||||||
|
if self._plugToRp.has_key(plug):
|
||||||
|
rp = self._plugToRp[plug]
|
||||||
|
else:
|
||||||
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
||||||
|
self._plugToRp[plug] = rp
|
||||||
|
|
||||||
|
return self._rpAccess( self._rpByOccurrence(occurrence,net), flags )
|
||||||
|
|
||||||
|
def _rpByPlug ( self, plug, net ):
|
||||||
|
if self._plugToRp.has_key(plug):
|
||||||
|
rp = self._plugToRp[plug]
|
||||||
|
else:
|
||||||
|
occurrence = Occurrence( plug, Path(net.getCell(),'') )
|
||||||
|
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
|
||||||
|
self._plugToRp[plug] = rp
|
||||||
|
|
||||||
|
return rp
|
||||||
|
|
||||||
|
def _rpByPlugName ( self, instance, plugName, net ):
|
||||||
|
return self._rpByPlug( getPlugByName(instance,plugName), net )
|
||||||
|
|
||||||
|
def _rpAccessByPlug ( self, plug, net, flags ):
|
||||||
|
return self._rpAccess( self._rpByPlug(plug,net), flags )
|
||||||
|
|
||||||
|
def _rpAccessByPlugName ( self, instance, plugName, net, flags=0 ):
|
||||||
|
return self._rpAccess( self._rpByPlugName(instance,plugName,net), flags )
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Class : "Configuration.GaugeConfWrapper".
|
||||||
|
|
||||||
|
class GaugeConfWrapper ( object ):
|
||||||
|
|
||||||
|
def __init__ ( self, conf ):
|
||||||
|
#print id(conf), type(conf)
|
||||||
|
#if not isinstance(conf,GaugeConf):
|
||||||
|
# raise ErrorMessage( 1, 'Attempt to create a GaugeConfWrapper() from non-GaugeConf object.' )
|
||||||
|
self._gaugeConf = conf
|
||||||
|
return
|
||||||
|
|
||||||
|
@property
|
||||||
|
def gaugeConf ( self ): return self._gaugeConf
|
||||||
|
|
||||||
|
@property
|
||||||
|
def routingGauge ( self ): return self._gaugeConf._routingGauge
|
||||||
|
@property
|
||||||
|
def topLayerDepth ( self ): return self._gaugeConf._topLayerDepth
|
||||||
|
@property
|
||||||
|
def horizontalDepth ( self ): return self._gaugeConf._horizontalDepth
|
||||||
|
@property
|
||||||
|
def verticalDepth ( self ): return self._gaugeConf._verticalDepth
|
||||||
|
|
||||||
|
def loadRoutingGauge ( self ): self._gaugeConf._loadRoutingGauge()
|
||||||
|
|
||||||
|
def rpByOccurrence ( self, occurrence, net ):
|
||||||
|
return self._gaugeConf._rpByOccurrence ( occurrence, net )
|
||||||
|
|
||||||
|
def rpByPlugName ( self, instance, plugName, net ):
|
||||||
|
return self._gaugeConf._rpByPlugName ( instance, plugName, net )
|
||||||
|
|
||||||
|
def rpAccess ( self, rp, flags=0 ):
|
||||||
|
return self._gaugeConf._rpAccess( rp, flags )
|
||||||
|
|
||||||
|
def rpAccessByOccurrence ( self, occurrence, net, flags=0 ):
|
||||||
|
return self.gaugeConf._rpAccessByOccurrence ( occurrence, net, flags )
|
||||||
|
|
||||||
|
def rpAccessByPlugName ( self, instance, plugName, net, flags=0 ):
|
||||||
|
return self._gaugeConf._rpAccessByPlugName( instance, plugName, net, flags )
|
||||||
|
|
||||||
|
def createContact ( self, net, x, y ):
|
||||||
|
return self._gaugeConf._createContact( net, x, y )
|
||||||
|
|
||||||
|
def createHorizontal ( self, source, target, y ):
|
||||||
|
return self._gaugeConf._createHorizontal( source, target, y )
|
||||||
|
|
||||||
|
def createVertical ( self, source, target, x ):
|
||||||
|
return self._gaugeConf._createVertical( source, target, x )
|
||||||
|
|
||||||
|
|
||||||
|
# -------------------------------------------------------------------
|
||||||
|
# Class : "Configuration.ChipConf".
|
||||||
|
|
||||||
|
class ChipConf ( object ):
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _readChipSize( chipConfig ):
|
def _readChipSize( chipConfigDict ):
|
||||||
if not chipConfig.has_key('chip.size'): return Box()
|
if not chipConfigDict.has_key('chip.size'): return Box()
|
||||||
chipSize = chipConfig['chip.size']
|
chipSize = chipConfigDict['chip.size']
|
||||||
if not isinstance(chipSize,tuple):
|
if not isinstance(chipSize,tuple):
|
||||||
print ErrorMessage( 1, 'The Chip size parameter is *not* a tuple.' )
|
print ErrorMessage( 1, 'The Chip size parameter is *not* a tuple.' )
|
||||||
return Box()
|
return Box()
|
||||||
|
@ -42,11 +335,11 @@ class Configuration ( object ):
|
||||||
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _readCoreSize( chipConfig ):
|
def _readCoreSize( chipConfigDict ):
|
||||||
if not chipConfig.has_key('core.size'):
|
if not chipConfigDict.has_key('core.size'):
|
||||||
print ErrorMessage( 1, 'The Core size parameter is missing.' )
|
print ErrorMessage( 1, 'The Core size parameter is missing.' )
|
||||||
return Box()
|
return Box()
|
||||||
coreSize = chipConfig['core.size']
|
coreSize = chipConfigDict['core.size']
|
||||||
if not isinstance(coreSize,tuple):
|
if not isinstance(coreSize,tuple):
|
||||||
print ErrorMessage( 1, 'The Core size parameter is *not* a tuple.' )
|
print ErrorMessage( 1, 'The Core size parameter is *not* a tuple.' )
|
||||||
return Box()
|
return Box()
|
||||||
|
@ -56,9 +349,18 @@ class Configuration ( object ):
|
||||||
return Box( 0, 0, DbU.fromLambda(coreSize[0]), DbU.fromLambda(coreSize[1]) )
|
return Box( 0, 0, DbU.fromLambda(coreSize[0]), DbU.fromLambda(coreSize[1]) )
|
||||||
|
|
||||||
|
|
||||||
def _readPads ( self, chipConfig, keyword ):
|
@staticmethod
|
||||||
if not chipConfig.has_key(keyword): return []
|
def _readClockTree( chipConfigDict ):
|
||||||
padNameList = chipConfig[keyword]
|
useClockTree = False
|
||||||
|
if chipConfigDict.has_key('chip.clockTree'):
|
||||||
|
if chipConfigDict['chip.clockTree']:
|
||||||
|
useClockTree = True
|
||||||
|
return useClockTree
|
||||||
|
|
||||||
|
|
||||||
|
def _readPads ( self, chipConfigDict, keyword ):
|
||||||
|
if not chipConfigDict.has_key(keyword): return []
|
||||||
|
padNameList = chipConfigDict[keyword]
|
||||||
if not isinstance(padNameList,list):
|
if not isinstance(padNameList,list):
|
||||||
print ErrorMessage( 1, 'The "%s" entry is not a list.' )
|
print ErrorMessage( 1, 'The "%s" entry is not a list.' )
|
||||||
return []
|
return []
|
||||||
|
@ -104,13 +406,11 @@ class Configuration ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def __init__ ( self, chipConfig, cell ):
|
def __init__ ( self, chipConfigDict, cell ):
|
||||||
if not isinstance(chipConfig,dict):
|
if not isinstance(chipConfigDict,dict):
|
||||||
raise ErrorMessage( 1, 'The "chip" variable is not a dictionnary.' )
|
raise ErrorMessage( 1, 'The "chip" variable is not a dictionnary.' )
|
||||||
|
|
||||||
self._validated = True
|
self._validated = True
|
||||||
self._routingGauge = None
|
|
||||||
self._topLayerDepth = 0
|
|
||||||
self._cell = cell
|
self._cell = cell
|
||||||
# Block Corona parameters.
|
# Block Corona parameters.
|
||||||
self._railsNb = DbU.fromLambda( getParameter('chip','chip.block.rails.count' ).asInt() )
|
self._railsNb = DbU.fromLambda( getParameter('chip','chip.block.rails.count' ).asInt() )
|
||||||
|
@ -138,40 +438,23 @@ class Configuration ( object ):
|
||||||
self._clockPad = None
|
self._clockPad = None
|
||||||
self._powerPad = None
|
self._powerPad = None
|
||||||
self._cores = []
|
self._cores = []
|
||||||
self._southPads = self._readPads( chipConfig, 'pads.south' )
|
self._southPads = self._readPads( chipConfigDict, 'pads.south' )
|
||||||
self._northPads = self._readPads( chipConfig, 'pads.north' )
|
self._northPads = self._readPads( chipConfigDict, 'pads.north' )
|
||||||
self._eastPads = self._readPads( chipConfig, 'pads.east' )
|
self._eastPads = self._readPads( chipConfigDict, 'pads.east' )
|
||||||
self._westPads = self._readPads( chipConfig, 'pads.west' )
|
self._westPads = self._readPads( chipConfigDict, 'pads.west' )
|
||||||
self._coreSize = Configuration._readCoreSize( chipConfig )
|
self._coreSize = ChipConf._readCoreSize( chipConfigDict )
|
||||||
self._chipSize = Configuration._readChipSize( chipConfig )
|
self._chipSize = ChipConf._readChipSize( chipConfigDict )
|
||||||
self._minCorona = DbU.fromLambda( 100 )
|
self._minCorona = DbU.fromLambda( 100 )
|
||||||
self._padWidth = 0
|
self._padWidth = 0
|
||||||
self._padHeight = 0
|
self._padHeight = 0
|
||||||
|
self._useClockTree = ChipConf._readClockTree( chipConfigDict )
|
||||||
|
|
||||||
self.loadRoutingGauge()
|
|
||||||
self.checkPads()
|
self.checkPads()
|
||||||
self.computeChipSize()
|
self.computeChipSize()
|
||||||
self.findPowerAndClockNets()
|
self.findPowerAndClockNets()
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
def loadRoutingGauge ( self ):
|
|
||||||
self._routingGauge = CRL.AllianceFramework.get().getRoutingGauge()
|
|
||||||
|
|
||||||
topLayer = Cfg.getParamString('katabatic.topRoutingLayer').asString()
|
|
||||||
|
|
||||||
self._topLayerDepth = 0
|
|
||||||
for layerGauge in self._routingGauge.getLayerGauges():
|
|
||||||
if layerGauge.getLayer().getName() == topLayer:
|
|
||||||
self._topLayerDepth = layerGauge.getDepth()
|
|
||||||
break
|
|
||||||
if not self._topLayerDepth:
|
|
||||||
print WarningMessage( 'Gauge top layer not defined, using top of gauge (%d).' \
|
|
||||||
% self._routingGauge.getDepth() )
|
|
||||||
self._topLayerDepth = self._routingGauge.getDepth()
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
def checkPads ( self ):
|
def checkPads ( self ):
|
||||||
af = CRL.AllianceFramework.get()
|
af = CRL.AllianceFramework.get()
|
||||||
cellPads = []
|
cellPads = []
|
||||||
|
@ -268,86 +551,88 @@ class Configuration ( object ):
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
||||||
class Wrapper ( object ):
|
# -------------------------------------------------------------------
|
||||||
|
# Class : "Configuration.ChipConfWrapper".
|
||||||
|
|
||||||
def __init__ ( self, conf ):
|
class ChipConfWrapper ( GaugeConfWrapper ):
|
||||||
if not isinstance(conf,Configuration):
|
|
||||||
raise ErrorMessage('Attempt to create a Wrapper() from non-Configuration object.')
|
def __init__ ( self, gaugeConf, chipConf ):
|
||||||
self._conf = conf
|
GaugeConfWrapper.__init__( self, gaugeConf )
|
||||||
|
|
||||||
|
if not isinstance(chipConf,ChipConf):
|
||||||
|
raise ErrorMessage( 1, 'Attempt to create a ChipConfWrapper() from non-ChipConf object.' )
|
||||||
|
self._chipConf = chipConf
|
||||||
return
|
return
|
||||||
|
|
||||||
def isValid ( self ): return self._conf._validated
|
def isValid ( self ): return self._chipConf._validated
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def conf ( self ): return self._conf
|
def chipConf ( self ): return self._chipConf
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def routingGauge ( self ): return self._conf._routingGauge
|
def cell ( self ): return self._chipConf._cell
|
||||||
@property
|
|
||||||
def topLayerDepth ( self ): return self._conf._topLayerDepth
|
|
||||||
|
|
||||||
@property
|
|
||||||
def cell ( self ): return self._conf._cell
|
|
||||||
|
|
||||||
# Global Net names.
|
# Global Net names.
|
||||||
@property
|
@property
|
||||||
def vddeName ( self ): return self._conf._vddeName
|
def vddeName ( self ): return self._chipConf._vddeName
|
||||||
@property
|
@property
|
||||||
def vsseName ( self ): return self._conf._vsseName
|
def vsseName ( self ): return self._chipConf._vsseName
|
||||||
@property
|
@property
|
||||||
def vddiName ( self ): return self._conf._vddiName
|
def vddiName ( self ): return self._chipConf._vddiName
|
||||||
@property
|
@property
|
||||||
def vssiName ( self ): return self._conf._vssiName
|
def vssiName ( self ): return self._chipConf._vssiName
|
||||||
@property
|
@property
|
||||||
def ckiName ( self ): return self._conf._ckiName
|
def ckiName ( self ): return self._chipConf._ckiName
|
||||||
@property
|
@property
|
||||||
def ckoName ( self ): return self._conf._ckoName
|
def ckoName ( self ): return self._chipConf._ckoName
|
||||||
@property
|
@property
|
||||||
def ckName ( self ): return self._conf._ckName
|
def ckName ( self ): return self._chipConf._ckName
|
||||||
|
|
||||||
# Global Nets.
|
# Global Nets.
|
||||||
@property
|
@property
|
||||||
def vdde ( self ): return self._conf._vdde
|
def vdde ( self ): return self._chipConf._vdde
|
||||||
@property
|
@property
|
||||||
def vsse ( self ): return self._conf._vsse
|
def vsse ( self ): return self._chipConf._vsse
|
||||||
@property
|
@property
|
||||||
def vddi ( self ): return self._conf._vddi
|
def vddi ( self ): return self._chipConf._vddi
|
||||||
@property
|
@property
|
||||||
def vssi ( self ): return self._conf._vssi
|
def vssi ( self ): return self._chipConf._vssi
|
||||||
@property
|
@property
|
||||||
def cki ( self ): return self._conf._cki
|
def cki ( self ): return self._chipConf._cki
|
||||||
@property
|
@property
|
||||||
def cko ( self ): return self._conf._cko
|
def cko ( self ): return self._chipConf._cko
|
||||||
@property
|
@property
|
||||||
def ck ( self ): return self._conf._ck
|
def ck ( self ): return self._chipConf._ck
|
||||||
|
|
||||||
# Various.
|
# Various.
|
||||||
@property
|
@property
|
||||||
def clockPad ( self ): return self._conf._clockPad
|
def clockPad ( self ): return self._chipConf._clockPad
|
||||||
@property
|
@property
|
||||||
def powerPad ( self ): return self._conf._powerPad
|
def powerPad ( self ): return self._chipConf._powerPad
|
||||||
@property
|
@property
|
||||||
def cores ( self ): return self._conf._cores
|
def cores ( self ): return self._chipConf._cores
|
||||||
@property
|
@property
|
||||||
def southPads ( self ): return self._conf._southPads
|
def southPads ( self ): return self._chipConf._southPads
|
||||||
@property
|
@property
|
||||||
def northPads ( self ): return self._conf._northPads
|
def northPads ( self ): return self._chipConf._northPads
|
||||||
@property
|
@property
|
||||||
def eastPads ( self ): return self._conf._eastPads
|
def eastPads ( self ): return self._chipConf._eastPads
|
||||||
@property
|
@property
|
||||||
def westPads ( self ): return self._conf._westPads
|
def westPads ( self ): return self._chipConf._westPads
|
||||||
@property
|
@property
|
||||||
def coreSize ( self ): return self._conf._coreSize
|
def coreSize ( self ): return self._chipConf._coreSize
|
||||||
@coreSize.setter
|
@coreSize.setter
|
||||||
def coreSize ( self, ab ): self._conf._coreSize = ab
|
def coreSize ( self, ab ): self._chipConf._coreSize = ab
|
||||||
@property
|
@property
|
||||||
def chipSize ( self ): return self._conf._chipSize
|
def chipSize ( self ): return self._chipConf._chipSize
|
||||||
@property
|
@property
|
||||||
def minCorona ( self ): return self._conf._minCorona
|
def minCorona ( self ): return self._chipConf._minCorona
|
||||||
@property
|
@property
|
||||||
def padWidth ( self ): return self._conf._padWidth
|
def padWidth ( self ): return self._chipConf._padWidth
|
||||||
@property
|
@property
|
||||||
def padHeight ( self ): return self._conf._padHeight
|
def padHeight ( self ): return self._chipConf._padHeight
|
||||||
|
@property
|
||||||
|
def useClockTree ( self ): return self._chipConf._useClockTree
|
||||||
|
|
||||||
|
|
||||||
def loadConfiguration ( cell ):
|
def loadConfiguration ( cell ):
|
||||||
|
@ -360,4 +645,5 @@ def loadConfiguration ( cell ):
|
||||||
raise WarningMessage( 'Module <%s> do not provides the chip variable, skipped.' \
|
raise WarningMessage( 'Module <%s> do not provides the chip variable, skipped.' \
|
||||||
% confFile )
|
% confFile )
|
||||||
|
|
||||||
return Wrapper( Configuration( confModule.__dict__['chip'], cell ) )
|
return ChipConfWrapper( GaugeConf()
|
||||||
|
, ChipConf ( confModule.__dict__['chip'], cell ) )
|
||||||
|
|
|
@ -30,6 +30,7 @@ from Hurricane import Vertical
|
||||||
from Hurricane import Instance
|
from Hurricane import Instance
|
||||||
import CRL
|
import CRL
|
||||||
from CRL import RoutingLayerGauge
|
from CRL import RoutingLayerGauge
|
||||||
|
from helpers import trace
|
||||||
from helpers import ErrorMessage
|
from helpers import ErrorMessage
|
||||||
from helpers import WarningMessage
|
from helpers import WarningMessage
|
||||||
import chip.Configuration
|
import chip.Configuration
|
||||||
|
@ -108,12 +109,24 @@ class Side ( object ):
|
||||||
|
|
||||||
def _createPowerContacts ( self, pad, net ):
|
def _createPowerContacts ( self, pad, net ):
|
||||||
if self._type == chip.North or self._type == chip.South:
|
if self._type == chip.North or self._type == chip.South:
|
||||||
hvDepth = self._corona.getVDepth()
|
hvDepth = self._corona.padVDepth
|
||||||
elif self._type == chip.East or self._type == chip.West:
|
elif self._type == chip.East or self._type == chip.West:
|
||||||
hvDepth = self._corona.getHDepth()
|
hvDepth = self._corona.padHDepth
|
||||||
|
|
||||||
|
trace( 550, ',+', '\t_createPowerContacts() for %s\n' % net.getName() )
|
||||||
|
|
||||||
masterCell = pad.getMasterCell()
|
masterCell = pad.getMasterCell()
|
||||||
for component in masterCell.getNet(net.getName()).getExternalComponents():
|
if net.isGlobal(): components = masterCell.getNet(net.getName()).getExternalComponents()
|
||||||
|
else:
|
||||||
|
for plug in net.getPlugs():
|
||||||
|
if plug.getInstance() == pad:
|
||||||
|
trace( 550, '\tFound Plug on %s\n' % pad )
|
||||||
|
components = plug.getMasterNet().getExternalComponents()
|
||||||
|
|
||||||
|
connecteds = False
|
||||||
|
for component in components:
|
||||||
|
trace( 550, '\t- %s\n' % component )
|
||||||
|
|
||||||
if component.getBoundingBox().getYMin() > masterCell.getAbutmentBox().getYMin(): continue
|
if component.getBoundingBox().getYMin() > masterCell.getAbutmentBox().getYMin(): continue
|
||||||
if self._corona.routingGauge.getLayerDepth(component.getLayer()) != hvDepth: continue
|
if self._corona.routingGauge.getLayerDepth(component.getLayer()) != hvDepth: continue
|
||||||
if not isinstance(component,Vertical): continue
|
if not isinstance(component,Vertical): continue
|
||||||
|
@ -128,6 +141,7 @@ class Side ( object ):
|
||||||
position = Point( component.getX(), masterCell.getAbutmentBox().getYMin() )
|
position = Point( component.getX(), masterCell.getAbutmentBox().getYMin() )
|
||||||
pad.getTransformation().applyOn( position )
|
pad.getTransformation().applyOn( position )
|
||||||
|
|
||||||
|
connecteds = True
|
||||||
self._powerContacts.append( Contact.create( net
|
self._powerContacts.append( Contact.create( net
|
||||||
, component.getLayer()
|
, component.getLayer()
|
||||||
, position.getX()
|
, position.getX()
|
||||||
|
@ -135,6 +149,11 @@ class Side ( object ):
|
||||||
, width
|
, width
|
||||||
, height
|
, height
|
||||||
) )
|
) )
|
||||||
|
if not connecteds:
|
||||||
|
print WarningMessage( 'Cannot find a suitable connector for <%s> on pad <%s>'
|
||||||
|
% (net.getName(),pad.getName()) )
|
||||||
|
|
||||||
|
trace( 550, '-' )
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -149,6 +168,7 @@ class Side ( object ):
|
||||||
#print 'Power pad:', pad
|
#print 'Power pad:', pad
|
||||||
self._createPowerContacts( pad, self._corona.vddi )
|
self._createPowerContacts( pad, self._corona.vddi )
|
||||||
self._createPowerContacts( pad, self._corona.vssi )
|
self._createPowerContacts( pad, self._corona.vssi )
|
||||||
|
self._createPowerContacts( pad, self._corona.cko )
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
@ -226,10 +246,10 @@ class Side ( object ):
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
class Corona ( chip.Configuration.Wrapper ):
|
class Corona ( chip.Configuration.ChipConfWrapper ):
|
||||||
|
|
||||||
def __init__ ( self, confWrapper ):
|
def __init__ ( self, conf ):
|
||||||
chip.Configuration.Wrapper.__init__( self, confWrapper.conf )
|
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||||
self.validated = False
|
self.validated = False
|
||||||
self._northSide = Side( self, chip.North )
|
self._northSide = Side( self, chip.North )
|
||||||
self._southSide = Side( self, chip.South )
|
self._southSide = Side( self, chip.South )
|
||||||
|
@ -243,7 +263,7 @@ class Corona ( chip.Configuration.Wrapper ):
|
||||||
self._powerRails = [] # [ , [net, layer, axis, width] ]
|
self._powerRails = [] # [ , [net, layer, axis, width] ]
|
||||||
|
|
||||||
self._locatePadRails()
|
self._locatePadRails()
|
||||||
self._guessHvLayers()
|
self._guessPadHvLayers()
|
||||||
return
|
return
|
||||||
|
|
||||||
@property
|
@property
|
||||||
|
@ -254,6 +274,10 @@ class Corona ( chip.Configuration.Wrapper ):
|
||||||
def eastSide ( self ): return self._eastSide
|
def eastSide ( self ): return self._eastSide
|
||||||
@property
|
@property
|
||||||
def westSide ( self ): return self._westSide
|
def westSide ( self ): return self._westSide
|
||||||
|
@property
|
||||||
|
def padHDepth ( self ): return self._horizontalPadDepth
|
||||||
|
@property
|
||||||
|
def padVDepth ( self ): return self._verticalPadDepth
|
||||||
|
|
||||||
def getSwCorner ( self, i ): return self._corners[chip.SouthWest][i]
|
def getSwCorner ( self, i ): return self._corners[chip.SouthWest][i]
|
||||||
def getSeCorner ( self, i ): return self._corners[chip.SouthEast][i]
|
def getSeCorner ( self, i ): return self._corners[chip.SouthEast][i]
|
||||||
|
@ -263,8 +287,6 @@ class Corona ( chip.Configuration.Wrapper ):
|
||||||
def getRailLayer ( self, i ): return self._powerRails[i][1]
|
def getRailLayer ( self, i ): return self._powerRails[i][1]
|
||||||
def getRailAxis ( self, i ): return self._powerRails[i][2]
|
def getRailAxis ( self, i ): return self._powerRails[i][2]
|
||||||
def getRailWidth ( self, i ): return self._powerRails[i][3]
|
def getRailWidth ( self, i ): return self._powerRails[i][3]
|
||||||
def getHDepth ( self ): return self._horizontalDepth
|
|
||||||
def getVDepth ( self ): return self._verticalDepth
|
|
||||||
|
|
||||||
|
|
||||||
def validate ( self ):
|
def validate ( self ):
|
||||||
|
@ -316,7 +338,7 @@ class Corona ( chip.Configuration.Wrapper ):
|
||||||
# )
|
# )
|
||||||
return
|
return
|
||||||
|
|
||||||
def _guessHvLayers ( self ):
|
def _guessPadHvLayers ( self ):
|
||||||
if not self.powerPad:
|
if not self.powerPad:
|
||||||
print ErrorMessage( 1, 'There must be at least one pad of model "pvddick_px" to guess the pad power terminals.' )
|
print ErrorMessage( 1, 'There must be at least one pad of model "pvddick_px" to guess the pad power terminals.' )
|
||||||
return False
|
return False
|
||||||
|
@ -329,18 +351,18 @@ class Corona ( chip.Configuration.Wrapper ):
|
||||||
|
|
||||||
#print 'available depth:', availableDepths
|
#print 'available depth:', availableDepths
|
||||||
|
|
||||||
self._horizontalDepth = 0
|
self._horizontalPadDepth = 0
|
||||||
self._verticalDepth = 0
|
self._verticalPadDepth = 0
|
||||||
for depth in range(0,self.topLayerDepth+1):
|
for depth in range(0,self.topLayerDepth+1):
|
||||||
if not depth in availableDepths: continue
|
if not depth in availableDepths: continue
|
||||||
|
|
||||||
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
||||||
self._horizontalDepth = depth
|
self._horizontalPadDepth = depth
|
||||||
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
||||||
self._verticalDepth = depth
|
self._verticalPadDepth = depth
|
||||||
|
|
||||||
#print 'h:', self._horizontalDepth
|
#print 'h:', self._horizontalPadDepth
|
||||||
#print 'v:', self._verticalDepth
|
#print 'v:', self._verticalPadDepth
|
||||||
return
|
return
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,569 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# This file is part of the Coriolis Software.
|
||||||
|
# Copyright (c) UPMC 2014-2014, 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@asim.lip6.fr |
|
||||||
|
# | =============================================================== |
|
||||||
|
# | Python : "./plugins/clocktree/ClockTree.py" |
|
||||||
|
# +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
import traceback
|
||||||
|
import os.path
|
||||||
|
import optparse
|
||||||
|
import math
|
||||||
|
import Cfg
|
||||||
|
import Hurricane
|
||||||
|
from Hurricane import DbU
|
||||||
|
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 Plug
|
||||||
|
from Hurricane import Instance
|
||||||
|
from Hurricane import HyperNet
|
||||||
|
import Viewer
|
||||||
|
import CRL
|
||||||
|
from CRL import RoutingLayerGauge
|
||||||
|
import helpers
|
||||||
|
from helpers import trace
|
||||||
|
from helpers import ErrorMessage
|
||||||
|
import Nimbus
|
||||||
|
import Metis
|
||||||
|
import Mauka
|
||||||
|
import Katabatic
|
||||||
|
import Kite
|
||||||
|
import Unicorn
|
||||||
|
import plugins
|
||||||
|
from clocktree.RSMT import RSMT
|
||||||
|
from chip.Configuration import getPlugByNet
|
||||||
|
from chip.Configuration import getPlugByName
|
||||||
|
from chip.Configuration import getRpBb
|
||||||
|
from chip.Configuration import destroyNetComponents
|
||||||
|
from chip.Configuration import GaugeConfWrapper
|
||||||
|
except ImportError, e:
|
||||||
|
module = str(e).split()[-1]
|
||||||
|
|
||||||
|
print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module
|
||||||
|
print ' Please check the integrity of the <coriolis> package.'
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception, e:
|
||||||
|
print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python'
|
||||||
|
print ' modules. Something may be wrong at Python/C API level.\n'
|
||||||
|
print ' %s' % e
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
class HTree ( GaugeConfWrapper ):
|
||||||
|
|
||||||
|
HAccess = 0x0001
|
||||||
|
OffsetRight1 = 0x0002
|
||||||
|
OffsetTop1 = 0x0004
|
||||||
|
OffsetBottom1 = 0x0008
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def create ( conf, cell, clockNet, clockBox ):
|
||||||
|
if clockBox.isEmpty(): raise ErrorMessage( 3, 'ClockTree: The clock area is empty.' )
|
||||||
|
|
||||||
|
aspectRatio = DbU.toLambda( clockBox.getWidth() ) / DbU.toLambda( clockBox.getHeight() )
|
||||||
|
if aspectRatio > 1.5 or aspectRatio < 0.5:
|
||||||
|
raise ErrorMessage( 3, 'ClockTree: aspect ratio %f is disproportionate, must be between 0.5 and 1.5.' \
|
||||||
|
% aspectRatio )
|
||||||
|
|
||||||
|
ht = HTree( conf, cell, clockNet, clockBox )
|
||||||
|
print ' o Creating Clock H-Tree for <%s>.' % cell.getName()
|
||||||
|
ht.build()
|
||||||
|
ht.place()
|
||||||
|
#ht.route()
|
||||||
|
print ' - H-Tree depth: %d' % ht.getTreeDepth()
|
||||||
|
trace( 550, '\tusedVTracks: %s\n' % str(ht.usedVTracks) )
|
||||||
|
return ht
|
||||||
|
|
||||||
|
def __init__ ( self, conf, cell, clockNet, area ):
|
||||||
|
print type(conf)
|
||||||
|
print type(conf.gaugeConf)
|
||||||
|
sys.stdout.flush()
|
||||||
|
GaugeConfWrapper.__init__( self, conf.gaugeConf )
|
||||||
|
|
||||||
|
self.minSide = DbU.fromLambda( Cfg.getParamInt('clockTree.minimumSide').asInt() )
|
||||||
|
if self.minSide < DbU.fromLambda(100.0):
|
||||||
|
raise ErrorMessage( 3, 'ClockTree: clockTree.minimumSide (%g) is less than 100 lambda.' \
|
||||||
|
% DbU.toLambda(self.minSide) )
|
||||||
|
|
||||||
|
self.framework = CRL.AllianceFramework.get()
|
||||||
|
self.cell = cell
|
||||||
|
self.area = area
|
||||||
|
self.childs = []
|
||||||
|
self.bufferCell = self.framework.getCell( 'buf_x2', CRL.Catalog.State.Logical )
|
||||||
|
self.tieCell = self.framework.getCell( 'tie_x0', CRL.Catalog.State.Views )
|
||||||
|
self.cellGauge = self.framework.getCellGauge()
|
||||||
|
self.topBuffer = Instance.create( self.cell, 'ck_htree', self.bufferCell )
|
||||||
|
self.cloneds = [ self.cell ]
|
||||||
|
self.usedVTracks = []
|
||||||
|
self._feedCount = 0
|
||||||
|
|
||||||
|
self.masterClock = clockNet
|
||||||
|
if not self.masterClock:
|
||||||
|
for net in cell.getNets():
|
||||||
|
if net.isClock():
|
||||||
|
self.masterClock = net
|
||||||
|
break
|
||||||
|
if not self.masterClock:
|
||||||
|
print '[WARNING] Cell %s has no clock net.' % cell.getName()
|
||||||
|
self._createChildNet( self.topBuffer, 'ck_htree' )
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def _createChildNet ( self, ibuffer, tag ):
|
||||||
|
childNet = Net.create( self.cell, tag )
|
||||||
|
childNet.setType( Net.Type.CLOCK )
|
||||||
|
getPlugByName(ibuffer, 'q').setNet( childNet )
|
||||||
|
return
|
||||||
|
|
||||||
|
def feedCounter ( self ):
|
||||||
|
self._feedCount += 1
|
||||||
|
return self._feedCount
|
||||||
|
|
||||||
|
def toXCellGrid ( self, x ): return x - (x % self.cellGauge.getSliceStep ())
|
||||||
|
def toYCellGrid ( self, y ): return y - (y % self.cellGauge.getSliceHeight())
|
||||||
|
|
||||||
|
def rpDistance ( self, rp1, rp2 ):
|
||||||
|
dx = abs( rp1.getX() - rp2.getX() )
|
||||||
|
dy = abs( self.toYCellGrid(rp1.getY()) - self.toYCellGrid(rp2.getY()) )
|
||||||
|
return dx+dy
|
||||||
|
|
||||||
|
def placeInstance ( self, instance, x, y ):
|
||||||
|
xslice = self.toXCellGrid(x)
|
||||||
|
yslice = self.toYCellGrid(y)
|
||||||
|
|
||||||
|
transformation = Transformation.Orientation.ID
|
||||||
|
if (yslice / self.cellGauge.getSliceHeight()) % 2 != 0:
|
||||||
|
transformation = Transformation.Orientation.MY
|
||||||
|
yslice += self.cellGauge.getSliceHeight()
|
||||||
|
|
||||||
|
instance.setTransformation ( Transformation(xslice, yslice, transformation) )
|
||||||
|
instance.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||||
|
return
|
||||||
|
|
||||||
|
def destroyInstance ( self, instance ):
|
||||||
|
transformation = instance.getTransformation()
|
||||||
|
instanceWidth = instance.getMasterCell().getAbutmentBox().getWidth()
|
||||||
|
tieWidth = self.tieCell.getAbutmentBox().getWidth()
|
||||||
|
|
||||||
|
instance.destroy()
|
||||||
|
x = transformation.getTx()
|
||||||
|
for i in range(instanceWidth/tieWidth):
|
||||||
|
feed = Instance.create( self.cell
|
||||||
|
, 'htree_feed_%i' % self.feedCounter()
|
||||||
|
, self.tieCell
|
||||||
|
, Transformation(x,transformation.getTy(),transformation.getOrientation())
|
||||||
|
#, Instance.PlacementStatus.PLACED
|
||||||
|
)
|
||||||
|
x += tieWidth
|
||||||
|
return
|
||||||
|
|
||||||
|
def getTreeDepth ( self ):
|
||||||
|
return self.childs[0].getTreeDepth()
|
||||||
|
|
||||||
|
def getLeafBufferUnder ( self, point ):
|
||||||
|
return self.childs[0].getLeafBufferUnder( point )
|
||||||
|
|
||||||
|
def addLeaf ( self, point, plugOccurrence ):
|
||||||
|
self.childs[0].addLeaf( point, plugOccurrence )
|
||||||
|
|
||||||
|
def build ( self ):
|
||||||
|
self.childs.append( HTreeNode( self, self.topBuffer, self.area, '', HTreeNode.RootBranch ) )
|
||||||
|
return
|
||||||
|
|
||||||
|
def place ( self ):
|
||||||
|
UpdateSession.open()
|
||||||
|
center = self.area.getCenter()
|
||||||
|
self.placeInstance( self.topBuffer, center.getX(), center.getY() )
|
||||||
|
self.usedVTracks += [ getRpBb(self.topBuffer, 'i').getCenter().getX() ]
|
||||||
|
self.childs[0].place()
|
||||||
|
UpdateSession.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
def route ( self ):
|
||||||
|
UpdateSession.open()
|
||||||
|
self.childs[0].route()
|
||||||
|
UpdateSession.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
def prune ( self ):
|
||||||
|
UpdateSession.open()
|
||||||
|
self.childs[0].prune()
|
||||||
|
UpdateSession.close()
|
||||||
|
return
|
||||||
|
|
||||||
|
def addCloned ( self, masterCell ):
|
||||||
|
if not masterCell in self.cloneds: self.cloneds.append( masterCell )
|
||||||
|
return
|
||||||
|
|
||||||
|
def addDeepPlug ( self, topNet, path ):
|
||||||
|
if path.isEmpty(): return None
|
||||||
|
|
||||||
|
tailPath = path.getTailPath()
|
||||||
|
headInstance = path.getHeadInstance()
|
||||||
|
headPlug = getPlugByNet(headInstance,topNet)
|
||||||
|
if headPlug:
|
||||||
|
if tailPath.isEmpty(): return headPlug
|
||||||
|
return self.addDeepPlug( headPlug.getMasterNet(), tailPath )
|
||||||
|
|
||||||
|
masterCell = headInstance.getMasterCell()
|
||||||
|
masterNet = Net.create( masterCell, topNet.getName() )
|
||||||
|
masterNet.setExternal ( True )
|
||||||
|
masterNet.setType ( Net.Type.CLOCK )
|
||||||
|
masterNet.setDirection( Net.Direction.IN )
|
||||||
|
headPlug = headInstance.getPlug( masterNet )
|
||||||
|
if not headPlug:
|
||||||
|
raise ErrorMessage( 3, 'Plug not created for %s on instance %s of %s' \
|
||||||
|
% (topNet.getName(),headInstance.getName(),masterCell.getName()) )
|
||||||
|
headPlug.setNet( topNet )
|
||||||
|
self.addCloned( masterCell )
|
||||||
|
|
||||||
|
if tailPath.isEmpty(): return headPlug
|
||||||
|
return self.addDeepPlug( masterNet, tailPath )
|
||||||
|
|
||||||
|
def _RSMTtoLayout( self, mst, net ):
|
||||||
|
for node in mst.nodes:
|
||||||
|
if not node.component:
|
||||||
|
x = node.realX
|
||||||
|
if node.realX in self.usedVTracks:
|
||||||
|
x += self.routingGauge.getLayerGauge(self.verticalDepth).getPitch()
|
||||||
|
# This is a Steiner point.
|
||||||
|
node.component = self.createContact( net
|
||||||
|
, x
|
||||||
|
, node.realY - self.routingGauge.getLayerGauge(self.horizontalDepth).getPitch() )
|
||||||
|
trace( 550, '\tCreate node.component: @Y%d (y:%d) %s\n' % (DbU.toLambda(node.realY)
|
||||||
|
,DbU.toLambda(node.y)
|
||||||
|
,node.component) )
|
||||||
|
else:
|
||||||
|
# This a terminal (graph) point
|
||||||
|
for edge in node.edges:
|
||||||
|
flags = HTree.HAccess
|
||||||
|
if not edge.isHorizontal():
|
||||||
|
if node.isSame(edge.source) or edge.isVertical():
|
||||||
|
flags = 0
|
||||||
|
break
|
||||||
|
flags |= HTree.OffsetTop1
|
||||||
|
if node.realX in self.usedVTracks:
|
||||||
|
flags |= HTree.OffsetRight1
|
||||||
|
node.component = self.rpAccess( node.component, flags )
|
||||||
|
|
||||||
|
for edge in mst.edges:
|
||||||
|
sourceContact = edge.source.component
|
||||||
|
targetContact = edge.target.component
|
||||||
|
|
||||||
|
if edge.isHorizontal():
|
||||||
|
self.createHorizontal( sourceContact, targetContact, targetContact.getY() )
|
||||||
|
elif edge.isVertical():
|
||||||
|
self.createVertical ( sourceContact, targetContact, sourceContact.getX() )
|
||||||
|
else:
|
||||||
|
turn = self.createContact( edge.source.component.getNet()
|
||||||
|
, sourceContact.getX()
|
||||||
|
, targetContact.getY() )
|
||||||
|
self.createVertical ( sourceContact, turn, sourceContact.getX() )
|
||||||
|
self.createHorizontal( turn, targetContact, targetContact.getY() )
|
||||||
|
return
|
||||||
|
|
||||||
|
def _connectLeafs ( self, leafBuffer, leafs ):
|
||||||
|
trace( 550, ',+', '\tBuffer <%s> has %i leafs.\n' % (leafBuffer.getName(),len(leafs)) )
|
||||||
|
if len(leafs) == 0: return
|
||||||
|
|
||||||
|
leafCk = getPlugByName(leafBuffer,'q').getNet()
|
||||||
|
bufferRp = self.rpByPlugName( leafBuffer, 'q', leafCk )
|
||||||
|
|
||||||
|
rsmt = RSMT( leafCk.getName() )
|
||||||
|
rsmt.addNode( bufferRp, bufferRp.getX(), self.toYCellGrid(bufferRp.getY()) )
|
||||||
|
for leaf in leafs:
|
||||||
|
registerRp = self.rpByOccurrence( leaf, leafCk )
|
||||||
|
rsmt.addNode( registerRp, registerRp.getX(), self.toYCellGrid(registerRp.getY()) )
|
||||||
|
|
||||||
|
rsmt.runI1S()
|
||||||
|
self._RSMTtoLayout( rsmt, leafCk )
|
||||||
|
|
||||||
|
trace( 550, '-' )
|
||||||
|
return
|
||||||
|
|
||||||
|
def connectLeaf ( self ):
|
||||||
|
UpdateSession.open()
|
||||||
|
|
||||||
|
leafsByBuffer = {}
|
||||||
|
hyperMasterClock = HyperNet.create( Occurrence(self.masterClock) )
|
||||||
|
for plugOccurrence in hyperMasterClock.getLeafPlugOccurrences():
|
||||||
|
position = plugOccurrence.getBoundingBox().getCenter()
|
||||||
|
self.addLeaf( position, plugOccurrence )
|
||||||
|
|
||||||
|
self.childs[0].connectLeafs()
|
||||||
|
sys.stdout.flush()
|
||||||
|
|
||||||
|
getPlugByName( self.topBuffer, 'i' ).setNet( self.masterClock )
|
||||||
|
UpdateSession.close()
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def _rsave ( self, cell ):
|
||||||
|
flags = CRL.Catalog.State.Physical
|
||||||
|
if cell.getName().endswith('_clocked'):
|
||||||
|
flags = flags | CRL.Catalog.State.Logical
|
||||||
|
self.framework.saveCell( cell, flags )
|
||||||
|
|
||||||
|
for instance in cell.getInstances():
|
||||||
|
masterCell = instance.getMasterCell()
|
||||||
|
if not masterCell.isTerminal():
|
||||||
|
self._rsave( masterCell )
|
||||||
|
|
||||||
|
def save ( self, topCell ):
|
||||||
|
for cell in self.cloneds:
|
||||||
|
cell.setName( cell.getName()+'_clocked' )
|
||||||
|
|
||||||
|
self._rsave( topCell )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class HTreeNode ( object ):
|
||||||
|
|
||||||
|
RootBranch = 0x0001
|
||||||
|
LeftBranch = 0x0002
|
||||||
|
RightBranch = 0x0004
|
||||||
|
UpBranch = 0x0008
|
||||||
|
DownBranch = 0x0010
|
||||||
|
|
||||||
|
def __init__ ( self, topTree, sourceBuffer, area, prefix, flags ):
|
||||||
|
self.topTree = topTree
|
||||||
|
self.childs = []
|
||||||
|
self.blLeafs = []
|
||||||
|
self.brLeafs = []
|
||||||
|
self.tlLeafs = []
|
||||||
|
self.trLeafs = []
|
||||||
|
self.flags = flags
|
||||||
|
self.sourceBuffer = sourceBuffer
|
||||||
|
self.area = area
|
||||||
|
self.prefix = prefix
|
||||||
|
|
||||||
|
self.blBuffer = Instance.create( self.topTree.cell, 'ck_htree'+self.prefix+'_bl_ins', self.topTree.bufferCell )
|
||||||
|
self.brBuffer = Instance.create( self.topTree.cell, 'ck_htree'+self.prefix+'_br_ins', self.topTree.bufferCell )
|
||||||
|
self.tlBuffer = Instance.create( self.topTree.cell, 'ck_htree'+self.prefix+'_tl_ins', self.topTree.bufferCell )
|
||||||
|
self.trBuffer = Instance.create( self.topTree.cell, 'ck_htree'+self.prefix+'_tr_ins', self.topTree.bufferCell )
|
||||||
|
self.ckNet = getPlugByName(self.sourceBuffer, 'q').getNet()
|
||||||
|
getPlugByName(self.blBuffer, 'i').setNet( self.ckNet )
|
||||||
|
getPlugByName(self.brBuffer, 'i').setNet( self.ckNet )
|
||||||
|
getPlugByName(self.tlBuffer, 'i').setNet( self.ckNet )
|
||||||
|
getPlugByName(self.trBuffer, 'i').setNet( self.ckNet )
|
||||||
|
|
||||||
|
self.topTree._createChildNet( self.blBuffer, 'ck_htree'+self.prefix+'_bl' )
|
||||||
|
self.topTree._createChildNet( self.brBuffer, 'ck_htree'+self.prefix+'_br' )
|
||||||
|
self.topTree._createChildNet( self.tlBuffer, 'ck_htree'+self.prefix+'_tl' )
|
||||||
|
self.topTree._createChildNet( self.trBuffer, 'ck_htree'+self.prefix+'_tr' )
|
||||||
|
|
||||||
|
halfWidth = self.area.getHalfWidth ()
|
||||||
|
halfHeight = self.area.getHalfHeight()
|
||||||
|
if halfWidth >= self.topTree.minSide and halfHeight >= self.topTree.minSide:
|
||||||
|
# Recursive call.
|
||||||
|
self.childs.append( HTreeNode( self.topTree, self.blBuffer, self.blArea(), self.prefix+'_bl', 0 ) )
|
||||||
|
self.childs.append( HTreeNode( self.topTree, self.brBuffer, self.brArea(), self.prefix+'_br', 0 ) )
|
||||||
|
self.childs.append( HTreeNode( self.topTree, self.tlBuffer, self.tlArea(), self.prefix+'_tl', 0 ) )
|
||||||
|
self.childs.append( HTreeNode( self.topTree, self.trBuffer, self.trArea(), self.prefix+'_tr', 0 ) )
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def xmin ( self ): return self.area.getXMin()
|
||||||
|
def xmax ( self ): return self.area.getXMax()
|
||||||
|
def ymin ( self ): return self.area.getYMin()
|
||||||
|
def ymax ( self ): return self.area.getYMax()
|
||||||
|
def halfWidth ( self ): return self.area.getHalfWidth()
|
||||||
|
def halfHeight( self ): return self.area.getHalfHeight()
|
||||||
|
|
||||||
|
def blArea ( self ):
|
||||||
|
return Box( self.xmin() , self.ymin()
|
||||||
|
, self.xmin()+self.halfWidth(), self.ymin()+self.halfHeight() )
|
||||||
|
|
||||||
|
def brArea ( self ):
|
||||||
|
return Box( self.xmin()+self.halfWidth(), self.ymin()
|
||||||
|
, self.xmax() , self.ymin()+self.halfHeight() )
|
||||||
|
|
||||||
|
def tlArea ( self ):
|
||||||
|
return Box( self.xmin() , self.ymin()+self.halfHeight()
|
||||||
|
, self.xmin()+self.halfWidth(), self.ymax() )
|
||||||
|
|
||||||
|
def trArea ( self ):
|
||||||
|
return Box( self.xmin()+self.halfWidth(), self.ymin()+self.halfHeight()
|
||||||
|
, self.xmax() , self.ymax() )
|
||||||
|
|
||||||
|
def getTreeDepth ( self ):
|
||||||
|
if self.childs: return self.childs[0].getTreeDepth()+1
|
||||||
|
return 1
|
||||||
|
|
||||||
|
def hasLeafs ( self ):
|
||||||
|
hasLeafsFlag = False
|
||||||
|
if self.childs:
|
||||||
|
hasLeafsFlag |= self.childs[0].hasLeafs()
|
||||||
|
hasLeafsFlag |= self.childs[1].hasLeafs()
|
||||||
|
hasLeafsFlag |= self.childs[2].hasLeafs()
|
||||||
|
hasLeafsFlag |= self.childs[3].hasLeafs()
|
||||||
|
return hasLeafsFlag
|
||||||
|
|
||||||
|
hasLeafsFlag |= (len(self.blLeafs) != 0)
|
||||||
|
hasLeafsFlag |= (len(self.brLeafs) != 0)
|
||||||
|
hasLeafsFlag |= (len(self.tlLeafs) != 0)
|
||||||
|
hasLeafsFlag |= (len(self.trLeafs) != 0)
|
||||||
|
return hasLeafsFlag
|
||||||
|
|
||||||
|
def addLeaf ( self, point, plugOccurrence ):
|
||||||
|
if self.childs:
|
||||||
|
if self.blArea().contains(point): self.childs[0].addLeaf( point, plugOccurrence )
|
||||||
|
elif self.brArea().contains(point): self.childs[1].addLeaf( point, plugOccurrence )
|
||||||
|
elif self.tlArea().contains(point): self.childs[2].addLeaf( point, plugOccurrence )
|
||||||
|
else: self.childs[3].addLeaf( point, plugOccurrence )
|
||||||
|
return
|
||||||
|
|
||||||
|
leafBuffer = None
|
||||||
|
if self.blArea().contains(point):
|
||||||
|
self.blLeafs.append( plugOccurrence )
|
||||||
|
leafBuffer = self.blBuffer
|
||||||
|
elif self.brArea().contains(point):
|
||||||
|
self.brLeafs.append( plugOccurrence )
|
||||||
|
leafBuffer = self.brBuffer
|
||||||
|
elif self.tlArea().contains(point):
|
||||||
|
self.tlLeafs.append( plugOccurrence )
|
||||||
|
leafBuffer = self.tlBuffer
|
||||||
|
else:
|
||||||
|
self.trLeafs.append( plugOccurrence )
|
||||||
|
leafBuffer = self.trBuffer
|
||||||
|
|
||||||
|
leafCk = getPlugByName(leafBuffer,'q').getNet()
|
||||||
|
deepPlug = self.topTree.addDeepPlug( leafCk, plugOccurrence.getPath() )
|
||||||
|
plugOccurrence.getEntity().setNet( deepPlug.getMasterNet() )
|
||||||
|
|
||||||
|
return
|
||||||
|
|
||||||
|
def getLeafBufferUnder ( self, point ):
|
||||||
|
if self.childs:
|
||||||
|
if self.blArea().contains(point): return self.childs[0].getLeafBufferUnder(point)
|
||||||
|
if self.brArea().contains(point): return self.childs[1].getLeafBufferUnder(point)
|
||||||
|
if self.tlArea().contains(point): return self.childs[2].getLeafBufferUnder(point)
|
||||||
|
if self.trArea().contains(point): return self.childs[3].getLeafBufferUnder(point)
|
||||||
|
|
||||||
|
if self.blArea().contains(point): return self.blBuffer
|
||||||
|
if self.brArea().contains(point): return self.brBuffer
|
||||||
|
if self.tlArea().contains(point): return self.tlBuffer
|
||||||
|
return self.trBuffer
|
||||||
|
|
||||||
|
def place ( self ):
|
||||||
|
x = self.area.getXMin() + self.area.getWidth ()/4
|
||||||
|
y = self.area.getYMin() + self.area.getHeight()/4
|
||||||
|
halfWidth = self.area.getHalfWidth ()
|
||||||
|
halfHeight = self.area.getHalfHeight()
|
||||||
|
|
||||||
|
self.topTree.placeInstance( self.blBuffer, x , y )
|
||||||
|
self.topTree.placeInstance( self.brBuffer, x+halfWidth, y )
|
||||||
|
self.topTree.placeInstance( self.tlBuffer, x , y+halfHeight )
|
||||||
|
self.topTree.placeInstance( self.trBuffer, x+halfWidth, y+halfHeight )
|
||||||
|
|
||||||
|
self.topTree.usedVTracks += \
|
||||||
|
[ self.topTree.rpAccessByPlugName( self.blBuffer, 'i', self.ckNet ).getX()
|
||||||
|
, self.topTree.rpAccessByPlugName( self.brBuffer, 'i', self.ckNet ).getX() ]
|
||||||
|
|
||||||
|
for child in self.childs: child.place()
|
||||||
|
return
|
||||||
|
|
||||||
|
def route ( self ):
|
||||||
|
if not self.hasLeafs(): return
|
||||||
|
|
||||||
|
leftSourceContact = self.topTree.rpAccessByPlugName( self.sourceBuffer, 'q', self.ckNet , HTree.HAccess|HTree.OffsetBottom1 )
|
||||||
|
rightSourceContact = self.topTree.rpAccessByPlugName( self.sourceBuffer, 'q', self.ckNet , HTree.HAccess|HTree.OffsetBottom1 )
|
||||||
|
blContact = self.topTree.rpAccessByPlugName( self.blBuffer , 'i', self.ckNet )
|
||||||
|
brContact = self.topTree.rpAccessByPlugName( self.brBuffer , 'i', self.ckNet )
|
||||||
|
tlContact = self.topTree.rpAccessByPlugName( self.tlBuffer , 'i', self.ckNet )
|
||||||
|
trContact = self.topTree.rpAccessByPlugName( self.trBuffer , 'i', self.ckNet )
|
||||||
|
leftContact = self.topTree.createContact( self.ckNet, blContact.getX(), leftSourceContact.getY() )
|
||||||
|
rightContact = self.topTree.createContact( self.ckNet, brContact.getX(), rightSourceContact.getY() )
|
||||||
|
self.topTree.createHorizontal( leftContact , leftSourceContact, leftSourceContact.getY() )
|
||||||
|
self.topTree.createHorizontal( rightSourceContact, rightContact , rightSourceContact.getY() )
|
||||||
|
self.topTree.createVertical ( leftContact , blContact , leftContact.getX() )
|
||||||
|
self.topTree.createVertical ( tlContact , leftContact , leftContact.getX() )
|
||||||
|
self.topTree.createVertical ( rightContact , brContact , rightContact.getX() )
|
||||||
|
self.topTree.createVertical ( trContact , rightContact , rightContact.getX() )
|
||||||
|
|
||||||
|
for child in self.childs: child.route()
|
||||||
|
return
|
||||||
|
|
||||||
|
def connectLeafs ( self ):
|
||||||
|
if not self.hasLeafs():
|
||||||
|
trace( 550, '\tHTree %s has no leafs\n' % self.sourceBuffer.getName() )
|
||||||
|
|
||||||
|
if self.childs:
|
||||||
|
self.childs[0].connectLeafs()
|
||||||
|
self.childs[1].connectLeafs()
|
||||||
|
self.childs[2].connectLeafs()
|
||||||
|
self.childs[3].connectLeafs()
|
||||||
|
return
|
||||||
|
|
||||||
|
if len(self.blLeafs): self.topTree._connectLeafs( self.blBuffer, self.blLeafs )
|
||||||
|
if len(self.brLeafs): self.topTree._connectLeafs( self.brBuffer, self.brLeafs )
|
||||||
|
if len(self.tlLeafs): self.topTree._connectLeafs( self.tlBuffer, self.tlLeafs )
|
||||||
|
if len(self.trLeafs): self.topTree._connectLeafs( self.trBuffer, self.trLeafs )
|
||||||
|
return
|
||||||
|
|
||||||
|
def prune ( self ):
|
||||||
|
for child in self.childs: child.prune()
|
||||||
|
if self.hasLeafs(): return
|
||||||
|
|
||||||
|
destroyNetComponents( self.ckNet )
|
||||||
|
|
||||||
|
self.topTree.destroyInstance( self.blBuffer )
|
||||||
|
self.topTree.destroyInstance( self.brBuffer )
|
||||||
|
self.topTree.destroyInstance( self.tlBuffer )
|
||||||
|
self.topTree.destroyInstance( self.trBuffer )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def computeAbutmentBox ( cell, spaceMargin, aspectRatio, cellGauge ):
|
||||||
|
sliceHeight = DbU.toLambda( cellGauge.getSliceHeight() )
|
||||||
|
|
||||||
|
instancesNb = 0
|
||||||
|
cellLength = 0
|
||||||
|
for occurrence in cell.getLeafInstanceOccurrences():
|
||||||
|
instance = occurrence.getEntity()
|
||||||
|
instancesNb += 1
|
||||||
|
cellLength += int( DbU.toLambda(instance.getMasterCell().getAbutmentBox().getWidth()) )
|
||||||
|
|
||||||
|
# ar = x/y S = x*y = spaceMargin*SH x=S/y ar = S/y^2
|
||||||
|
# y = sqrt(S/AR)
|
||||||
|
gcellLength = float(cellLength)*(1+spaceMargin) / sliceHeight
|
||||||
|
rows = math.sqrt( gcellLength/aspectRatio )
|
||||||
|
if math.trunc(rows) != rows: rows = math.trunc(rows) + 1
|
||||||
|
else: rows = math.trunc(rows)
|
||||||
|
columns = gcellLength / rows
|
||||||
|
if math.trunc(columns) != columns: columns = math.trunc(columns) + 1
|
||||||
|
else: columns = math.trunc(columns)
|
||||||
|
|
||||||
|
print ' o Creating abutment box (margin:%.1f%%, aspect ratio:%.1f%%, g-length:%.1fl)' \
|
||||||
|
% (spaceMargin*100.0,aspectRatio*100.0,(cellLength/sliceHeight))
|
||||||
|
print ' - GCell grid: [%dx%d]' % (columns,rows)
|
||||||
|
|
||||||
|
UpdateSession.open()
|
||||||
|
abutmentBox = Box( DbU.fromLambda(0)
|
||||||
|
, DbU.fromLambda(0)
|
||||||
|
, DbU.fromLambda(columns*sliceHeight)
|
||||||
|
, DbU.fromLambda(rows *sliceHeight)
|
||||||
|
)
|
||||||
|
cell.setAbutmentBox( abutmentBox )
|
||||||
|
UpdateSession.close()
|
||||||
|
|
||||||
|
return abutmentBox
|
|
@ -0,0 +1,371 @@
|
||||||
|
#!/usr/bin/env python
|
||||||
|
#
|
||||||
|
# This file is part of the Coriolis Software.
|
||||||
|
# Copyright (c) UPMC 2014-2014, 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@asim.lip6.fr |
|
||||||
|
# | =============================================================== |
|
||||||
|
# | Python : "./plugins/clocktree/RSMT.py" |
|
||||||
|
# +-----------------------------------------------------------------+
|
||||||
|
|
||||||
|
|
||||||
|
try:
|
||||||
|
import sys
|
||||||
|
import Cfg
|
||||||
|
import Hurricane
|
||||||
|
from Hurricane import DbU
|
||||||
|
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
|
||||||
|
import Viewer
|
||||||
|
import CRL
|
||||||
|
from CRL import RoutingLayerGauge
|
||||||
|
import helpers
|
||||||
|
from helpers import trace
|
||||||
|
from helpers import ErrorMessage
|
||||||
|
import plugins
|
||||||
|
except ImportError, e:
|
||||||
|
module = str(e).split()[-1]
|
||||||
|
|
||||||
|
print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module
|
||||||
|
print ' Please check the integrity of the <coriolis> package.'
|
||||||
|
sys.exit(1)
|
||||||
|
except Exception, e:
|
||||||
|
print '[ERROR] A strange exception occurred while loading the basic Coriolis/Python'
|
||||||
|
print ' modules. Something may be wrong at Python/C API level.\n'
|
||||||
|
print ' %s' % e
|
||||||
|
sys.exit(2)
|
||||||
|
|
||||||
|
|
||||||
|
def manhattanDistance ( node1, node2 ):
|
||||||
|
return abs(node1.x - node2.x) + abs(node1.y - node2.y)
|
||||||
|
|
||||||
|
|
||||||
|
class Node ( object ):
|
||||||
|
|
||||||
|
GraphPoint = 0x0001
|
||||||
|
SteinerPoint = 0x0002
|
||||||
|
KeepPoint = 0x0004
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def showNodes ( level, nodes ):
|
||||||
|
for node in nodes:
|
||||||
|
trace( level, node )
|
||||||
|
return
|
||||||
|
|
||||||
|
def __init__ ( self, component, x, y, flags=0 ):
|
||||||
|
self._component = component
|
||||||
|
self._edges = [ ]
|
||||||
|
self._x = x
|
||||||
|
self._y = y
|
||||||
|
self._realY = y
|
||||||
|
self._back = None
|
||||||
|
self._distance = DbU.fromLambda(1000.0)
|
||||||
|
self._flags = flags
|
||||||
|
|
||||||
|
if component: self._flags = self._flags|Node.GraphPoint|Node.KeepPoint
|
||||||
|
else: self._flags = self._flags|Node.SteinerPoint
|
||||||
|
return
|
||||||
|
|
||||||
|
def __cmp__ ( self, other ):
|
||||||
|
return self.distance - other.distance
|
||||||
|
|
||||||
|
def __str__ ( self ):
|
||||||
|
return '<Node P:%d,%d (realY:%d) d:%d %s>' % ( DbU.toLambda(self.x)
|
||||||
|
, DbU.toLambda(self.y)
|
||||||
|
, DbU.toLambda(self.realY)
|
||||||
|
, DbU.toLambda(self.distance)
|
||||||
|
, str(self.component)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def component ( self ): return self._component
|
||||||
|
@property
|
||||||
|
def x ( self ): return self._x
|
||||||
|
@property
|
||||||
|
def y ( self ): return self._y
|
||||||
|
@property
|
||||||
|
def realX ( self ): return self._x
|
||||||
|
@property
|
||||||
|
def realY ( self ): return self._realY
|
||||||
|
@property
|
||||||
|
def back ( self ): return self._back
|
||||||
|
@property
|
||||||
|
def distance ( self ): return self._distance
|
||||||
|
@property
|
||||||
|
def flags ( self ): return self._flags
|
||||||
|
@property
|
||||||
|
def edges ( self ): return self._edges
|
||||||
|
@property
|
||||||
|
def degree ( self ): return len(self._edges)
|
||||||
|
@component.setter
|
||||||
|
def component ( self, component ): self._component = component
|
||||||
|
@realY.setter
|
||||||
|
def realY ( self, y ): self._realY = y
|
||||||
|
|
||||||
|
def setFlags ( self, flags ): self._flags = self._flags | flags
|
||||||
|
def unsetFlags ( self, flags ): self._flags = self._flags & ~flags
|
||||||
|
|
||||||
|
def addEdge ( self, edge ): self._edges.append( edge )
|
||||||
|
def delEdge ( self, edge ):
|
||||||
|
for i in range(len(self._edges)):
|
||||||
|
if self._edges[i] == edge:
|
||||||
|
del self._edges[i]
|
||||||
|
return
|
||||||
|
|
||||||
|
def isSame ( self, other ): return id(self) == id(other)
|
||||||
|
|
||||||
|
def update ( self, node ):
|
||||||
|
distance = manhattanDistance( self, node )
|
||||||
|
if distance < self.distance:
|
||||||
|
self._distance = distance
|
||||||
|
self._back = node
|
||||||
|
return True
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
|
class Edge ( object ):
|
||||||
|
|
||||||
|
def __init__ ( self, source, target ):
|
||||||
|
self._source = source
|
||||||
|
self._target = target
|
||||||
|
self._length = manhattanDistance( self._source, self._target )
|
||||||
|
self._source.addEdge( self )
|
||||||
|
self._target.addEdge( self )
|
||||||
|
return
|
||||||
|
|
||||||
|
def __del__ ( self ):
|
||||||
|
self._source.delEdge( self )
|
||||||
|
self._target.delEdge( self )
|
||||||
|
return
|
||||||
|
|
||||||
|
def __str__ ( self ):
|
||||||
|
return '<Edge S:%d,%d T:%d,%d len:%d>' % ( DbU.toLambda(self.source.x)
|
||||||
|
, DbU.toLambda(self.source.y)
|
||||||
|
, DbU.toLambda(self.target.x)
|
||||||
|
, DbU.toLambda(self.target.y)
|
||||||
|
, DbU.toLambda(self.length)
|
||||||
|
)
|
||||||
|
|
||||||
|
@property
|
||||||
|
def source ( self ): return self._source
|
||||||
|
@property
|
||||||
|
def target ( self ): return self._target
|
||||||
|
@property
|
||||||
|
def length ( self ): return self._length
|
||||||
|
|
||||||
|
def isHorizontal ( self ): return self.source.y == self.target.y
|
||||||
|
def isVertical ( self ): return self.source.x == self.target.x
|
||||||
|
|
||||||
|
|
||||||
|
class Graph ( object ):
|
||||||
|
|
||||||
|
def __init__ ( self, name ):
|
||||||
|
self._nodes = [ ]
|
||||||
|
self._edges = [ ]
|
||||||
|
self._length = 0
|
||||||
|
self._name = name
|
||||||
|
return
|
||||||
|
|
||||||
|
def __len__ ( self ): return self._length
|
||||||
|
|
||||||
|
@property
|
||||||
|
def name ( self ): return self._name
|
||||||
|
@property
|
||||||
|
def length ( self ): return self._length
|
||||||
|
@property
|
||||||
|
def nodes ( self ): return self._nodes
|
||||||
|
@property
|
||||||
|
def edges ( self ): return self._edges
|
||||||
|
|
||||||
|
def addNode ( self, component, x, y ):
|
||||||
|
self._nodes.append( Node( component, x, y ) )
|
||||||
|
return
|
||||||
|
|
||||||
|
def copyNode ( self, node ):
|
||||||
|
self.addNode( node.component, node.x, node.y )
|
||||||
|
self._nodes[-1].realY = node.realY
|
||||||
|
|
||||||
|
def setNodes ( self, nodes ):
|
||||||
|
self.__init__( self.name )
|
||||||
|
for node in nodes:
|
||||||
|
self.copyNode( node )
|
||||||
|
return
|
||||||
|
|
||||||
|
def showNodes ( self, level ):
|
||||||
|
trace( level, '+,+', '\tGraph Nodes:\n' )
|
||||||
|
for node in self._nodes:
|
||||||
|
trace( level, node )
|
||||||
|
trace(level, '--')
|
||||||
|
return
|
||||||
|
|
||||||
|
def showEdges ( self, level ):
|
||||||
|
trace( level, '+,+', '\tGraph Edges:\n' )
|
||||||
|
for edge in self._edges:
|
||||||
|
trace( level, edge )
|
||||||
|
trace(level, '--')
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RMST ( Graph ):
|
||||||
|
|
||||||
|
def __init__ ( self, name ):
|
||||||
|
Graph.__init__( self, name )
|
||||||
|
return
|
||||||
|
|
||||||
|
def runPrim ( self ):
|
||||||
|
self._edges = [ ]
|
||||||
|
self._length = 0
|
||||||
|
|
||||||
|
if len(self._nodes) < 2: return
|
||||||
|
if len(self._nodes) == 2:
|
||||||
|
self._edges.append( Edge( self._nodes[0], self._nodes[1] ) )
|
||||||
|
self._length = self._edges[0].length
|
||||||
|
return
|
||||||
|
|
||||||
|
trace(500, '+')
|
||||||
|
|
||||||
|
toReach = [ ]
|
||||||
|
self._nodes[0]._distance = 0
|
||||||
|
for node in self._nodes[1:]:
|
||||||
|
node.update( self._nodes[0] )
|
||||||
|
toReach.append( node )
|
||||||
|
toReach.sort()
|
||||||
|
|
||||||
|
trace( 500, '+' , '\tPrim (initial stack)\n' )
|
||||||
|
trace( 500, '+,+', '\tS %s\n' % self._nodes[0] )
|
||||||
|
Node.showNodes( 500, toReach )
|
||||||
|
trace( 500, '---' )
|
||||||
|
|
||||||
|
while len(toReach):
|
||||||
|
nearest = toReach.pop(0)
|
||||||
|
self._edges.append( Edge( nearest, nearest.back ) )
|
||||||
|
trace( 500, '++,--', '\tAdding %s\n' % self._edges[-1] )
|
||||||
|
|
||||||
|
for node in toReach:
|
||||||
|
node.update( nearest )
|
||||||
|
toReach.sort()
|
||||||
|
|
||||||
|
trace( 500, '+' , '\tPrim (current stack)\n' )
|
||||||
|
trace( 500, '+,+', '\tS %s\n' % self._nodes[0] )
|
||||||
|
Node.showNodes( 500, toReach )
|
||||||
|
trace( 500, '---' )
|
||||||
|
|
||||||
|
for edge in self._edges:
|
||||||
|
self._length += edge.length
|
||||||
|
|
||||||
|
trace( 500, '-' )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
class RSMT ( Graph ):
|
||||||
|
|
||||||
|
def __init__ ( self, name ):
|
||||||
|
Graph.__init__( self, name )
|
||||||
|
self._hananNodes = [ ]
|
||||||
|
return
|
||||||
|
|
||||||
|
def _computeHanan ( self ):
|
||||||
|
xs = [ ]
|
||||||
|
ys = [ ]
|
||||||
|
realYs = { }
|
||||||
|
for node in self._nodes:
|
||||||
|
if not node.x in xs: xs.append( node.x )
|
||||||
|
if not node.y in xs:
|
||||||
|
ys.append( node.y )
|
||||||
|
realYs[ node.y ] = node.component.getY()
|
||||||
|
xs.sort()
|
||||||
|
ys.sort()
|
||||||
|
|
||||||
|
trace( 550, '+,+', '\tHanan matrix: %ix%i' % (len(xs),len(ys)) )
|
||||||
|
|
||||||
|
self._hananNodes = [ ]
|
||||||
|
for x in xs:
|
||||||
|
trace( 550, '\n' )
|
||||||
|
trace( 550, '\t' )
|
||||||
|
for y in ys:
|
||||||
|
isNode = False
|
||||||
|
for node in self._nodes:
|
||||||
|
if node.x == x and node.y == y: isNode = True
|
||||||
|
if isNode:
|
||||||
|
trace( 550, ' -:%04.2d,%04.2d' % (DbU.toLambda(x),DbU.toLambda(y)) )
|
||||||
|
continue
|
||||||
|
trace( 550, ' H:%04.2d,%04.2d' % (DbU.toLambda(x),DbU.toLambda(y)) )
|
||||||
|
|
||||||
|
self._hananNodes.append( Node( None, x, y ) )
|
||||||
|
self._hananNodes[-1].realY = realYs[ y ]
|
||||||
|
trace( 550, ',--', "\n" )
|
||||||
|
return
|
||||||
|
|
||||||
|
def runI1S ( self ):
|
||||||
|
self._edges = [ ]
|
||||||
|
self._length = 0
|
||||||
|
|
||||||
|
if len(self._nodes) < 2: return
|
||||||
|
if len(self._nodes) == 2:
|
||||||
|
self._edges.append( Edge( self._nodes[0], self._nodes[1] ) )
|
||||||
|
self._length = self._edges[0].length
|
||||||
|
return
|
||||||
|
|
||||||
|
self._computeHanan()
|
||||||
|
count = 0
|
||||||
|
|
||||||
|
trace( 550, '++' )
|
||||||
|
minMST = RMST( 'MST[%i]' % count )
|
||||||
|
minMST.setNodes( self._nodes )
|
||||||
|
minMST.runPrim()
|
||||||
|
trace( 550, '-,+', '\tInitial %s length %d\n' % (minMST.name,DbU.toLambda(len(minMST))) )
|
||||||
|
minMST.showEdges( 550 )
|
||||||
|
trace( 550, '-' )
|
||||||
|
|
||||||
|
addedSteiner = True
|
||||||
|
while addedSteiner:
|
||||||
|
addedSteiner = False
|
||||||
|
for steinerNode in self._hananNodes:
|
||||||
|
count += 1
|
||||||
|
trace( 550, '\tTrying with Steiner point H:%d,%d\n' \
|
||||||
|
% (DbU.toLambda(steinerNode.x),DbU.toLambda(steinerNode.y)) )
|
||||||
|
mst = RMST( 'MST[%i]' % count )
|
||||||
|
mst.setNodes( self._nodes )
|
||||||
|
mst.copyNode( steinerNode )
|
||||||
|
mst.runPrim()
|
||||||
|
|
||||||
|
trace( 550, '\tCurrent %s length %d\n' % (mst.name,DbU.toLambda(len(mst))) )
|
||||||
|
mst.showEdges( 550 )
|
||||||
|
if len(mst) < len(minMST):
|
||||||
|
trace( 550, '\tAccept min RST.\n' )
|
||||||
|
minMST = mst
|
||||||
|
addedSteiner = True
|
||||||
|
|
||||||
|
if addedSteiner:
|
||||||
|
self.copyNode( minMST.nodes[-1] )
|
||||||
|
self.nodes[-1].setFlags( Node.KeepPoint )
|
||||||
|
|
||||||
|
i = 0
|
||||||
|
while i < len(self._edges):
|
||||||
|
if self._nodes[i].flags & Node.SteinerPoint \
|
||||||
|
and self._nodes[i].degree < 3:
|
||||||
|
trace( 550, 'Deleting unused Steiner point H:%d,%d' \
|
||||||
|
% (DbU.toLambda(self._nodes[i].x),DbU.toLambda(self._nodes[i].y)) )
|
||||||
|
del self._nodes[i]
|
||||||
|
else:
|
||||||
|
i += 1
|
||||||
|
|
||||||
|
self._nodes = minMST.nodes
|
||||||
|
self._edges = minMST.edges
|
||||||
|
self._length = minMST.length
|
||||||
|
trace( 550, '-' )
|
||||||
|
return
|
Loading…
Reference in New Issue