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
|
||||
realTechno = 'hcmos9'
|
||||
realDir = None
|
||||
tab = None
|
||||
_trace = None
|
||||
|
||||
|
||||
def stype ( o ): return str(type(o)).split("'")[1]
|
||||
|
@ -168,18 +170,100 @@ class Dots ( object ):
|
|||
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 symbolicDir
|
||||
global realDir
|
||||
global tab
|
||||
global _trace
|
||||
|
||||
if sysConfDir != None: return
|
||||
|
||||
tab = Tab()
|
||||
_trace = Trace()
|
||||
|
||||
reSysConfDir = re.compile(r'.*etc\/coriolis2')
|
||||
print ' o Locating configuration directory:'
|
||||
if not quiet: print ' o Locating configuration directory:'
|
||||
|
||||
for path in sys.path:
|
||||
if reSysConfDir.match(path):
|
||||
sysConfDir = path
|
||||
print ' - <%s>' % sysConfDir
|
||||
if not quiet: print ' - <%s>' % sysConfDir
|
||||
break
|
||||
|
||||
if not sysConfDir:
|
||||
|
@ -192,7 +276,7 @@ def staticInitialization ():
|
|||
raise ErrorMessage( 1, [ 'Cannot locate the directoty holding the configuration files.'
|
||||
, 'The path is something ending by <.../etc/coriolis2>.'] )
|
||||
|
||||
print ' - <%s>' % sysConfDir
|
||||
if not quiet: print ' - <%s>' % sysConfDir
|
||||
symbolicDir = os.path.join( sysConfDir, symbolicTechno )
|
||||
realDir = os.path.join( sysConfDir, realTechno )
|
||||
return
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -5,8 +5,12 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/Alliance.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/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
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/BlockPower.py
|
||||
|
@ -17,4 +21,5 @@
|
|||
|
||||
install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus )
|
||||
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 )
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# | Python : "./plugins/ChipPlugin.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
try:
|
||||
import sys
|
||||
import traceback
|
||||
|
@ -41,6 +42,7 @@ try:
|
|||
import Viewer
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
import helpers
|
||||
from helpers import ErrorMessage
|
||||
from helpers import WarningMessage
|
||||
import Nimbus
|
||||
|
@ -50,6 +52,7 @@ try:
|
|||
import Kite
|
||||
import Unicorn
|
||||
import plugins
|
||||
import clocktree.ClockTree
|
||||
import chip.Configuration
|
||||
import chip.BlockPower
|
||||
import chip.BlockCorona
|
||||
|
@ -71,10 +74,10 @@ except Exception, e:
|
|||
# Plugin working part.
|
||||
|
||||
|
||||
class PlaceCore ( chip.Configuration.Wrapper ):
|
||||
class PlaceCore ( chip.Configuration.ChipConfWrapper ):
|
||||
|
||||
def __init__ ( self, confWrapper ):
|
||||
chip.Configuration.Wrapper.__init__( self, confWrapper.conf )
|
||||
def __init__ ( self, conf ):
|
||||
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||
self.validated = False
|
||||
return
|
||||
|
||||
|
@ -113,12 +116,33 @@ class PlaceCore ( chip.Configuration.Wrapper ):
|
|||
def doPlacement ( self ):
|
||||
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
|
||||
|
||||
mauka = Mauka.MaukaEngine.create( self.cores[0].getMasterCell() )
|
||||
mauka.run()
|
||||
mauka.destroy()
|
||||
|
||||
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.destroy()
|
||||
return
|
||||
|
||||
|
||||
|
@ -139,6 +163,9 @@ def unicornHook ( **kw ):
|
|||
|
||||
def ScriptMain ( **kw ):
|
||||
try:
|
||||
helpers.staticInitialization( quiet=True )
|
||||
#helpers.setTraceLevel( 550 )
|
||||
|
||||
cell, editor = plugins.kwParseMain( **kw )
|
||||
|
||||
conf = chip.Configuration.loadConfiguration( cell )
|
||||
|
@ -151,10 +178,17 @@ def ScriptMain ( **kw ):
|
|||
placeCore = PlaceCore( conf )
|
||||
placeCore.validate()
|
||||
placeCore.doFloorplan()
|
||||
editor.fit()
|
||||
|
||||
placeCore.doPlacement()
|
||||
corePower = chip.BlockPower.Block( Path(conf.cores[0]), conf.vddi, conf.vssi )
|
||||
corePower.queryPower()
|
||||
editor.fit()
|
||||
|
||||
corePower = chip.BlockPower.Block( conf )
|
||||
corePower.connectPower()
|
||||
corePower.connectClock()
|
||||
corePower.doLayout()
|
||||
editor.fit()
|
||||
|
||||
coreCorona = chip.BlockCorona.Corona( corePower )
|
||||
coreCorona.connectPads( padsCorona )
|
||||
coreCorona.connectBlock()
|
||||
|
@ -167,5 +201,8 @@ def ScriptMain ( **kw ):
|
|||
except Exception, e:
|
||||
print '\n\n', e; errorCode = 1
|
||||
traceback.print_tb(sys.exc_info()[2])
|
||||
|
||||
sys.stdout.flush()
|
||||
sys.stderr.flush()
|
||||
|
||||
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 = []
|
||||
return
|
||||
|
||||
def getNet ( self ): return self._net
|
||||
|
||||
def mergeDepth ( self, depth ):
|
||||
if self._hasLayout:
|
||||
print WarningMessage( 'StackedVia.mergeDepth(): Cannot be called *after* StackVia.doLayout()' )
|
||||
|
|
|
@ -30,6 +30,7 @@ from Hurricane import Horizontal
|
|||
from Hurricane import Vertical
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace
|
||||
from helpers import ErrorMessage
|
||||
from helpers import WarningMessage
|
||||
from plugins import StackedVia
|
||||
|
@ -64,7 +65,7 @@ class HorizontalRail ( Rail ):
|
|||
, '(corona:%s)' % str(self.side.innerBb) ] )
|
||||
|
||||
#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
|
||||
|
||||
keys = self.vias.keys()
|
||||
|
@ -87,26 +88,14 @@ class HorizontalRail ( Rail ):
|
|||
, self.side.getLayerDepth(self.side.getHLayer())
|
||||
, contact.getX()
|
||||
, self.axis
|
||||
, contact.getWidth()
|
||||
, self.side.hRailWidth
|
||||
, contact.getWidth() - DbU.fromLambda(1.0)
|
||||
, self.side.hRailWidth - DbU.fromLambda(1.0)
|
||||
)
|
||||
, contact ]
|
||||
#print ' ADD contact @ [%d %d]' % (DbU.toLambda(contact.getX()), DbU.toLambda(self.axis))
|
||||
self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
||||
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 ):
|
||||
#print 'HorizontalRail[%s] @%d' % (self.order,DbU.toLambda(self.axis))
|
||||
|
||||
|
@ -114,6 +103,8 @@ class HorizontalRail ( Rail ):
|
|||
, self.side.corner1(self.order) ]
|
||||
|
||||
for via in self.vias.values():
|
||||
if via[1].getNet() != via[2].getNet(): continue
|
||||
|
||||
via[1].doLayout()
|
||||
#print ' Connect:', via[2], 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) ]
|
||||
|
||||
for via in self.vias.values():
|
||||
#print ' Connect: ', via[2]
|
||||
if via[1].getNet() != via[2].getNet(): continue
|
||||
|
||||
via[1].doLayout()
|
||||
Horizontal.create( via[1].getVia( via[2].getLayer() )
|
||||
, via[2]
|
||||
|
@ -178,30 +170,36 @@ class VerticalRail ( Rail ):
|
|||
, 'power pad is likely to be to far off north or south.'
|
||||
, '(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
|
||||
|
||||
trace( 550, ',+', '\tVerticalRail.connect() [%s] @%d\n' % (self.order,DbU.toLambda(self.axis)) )
|
||||
trace( 550, contact )
|
||||
|
||||
keys = self.vias.keys()
|
||||
keys.sort()
|
||||
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 insertIndex < len(keys):
|
||||
insertPosition = keys[ insertIndex ]
|
||||
#print 'insertIndex:%d' % insertIndex
|
||||
#print 'Check NEXT contactBb:%s via:%s' \
|
||||
# % ( str(contactBb)
|
||||
# , str(self.vias[insertPosition][2].getBoundingBox()) )
|
||||
trace( 550, '\tinsertIndex:%d' % insertIndex )
|
||||
trace( 550, '\tCheck NEXT contactBb:%s via:%s\n' \
|
||||
% ( contactBb
|
||||
, self.vias[insertPosition][2].getBoundingBox()) )
|
||||
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
|
||||
if insertIndex > 0:
|
||||
#print 'check PREVIOUS contactBb:%s via:%s' \
|
||||
# % ( str(contactBb)
|
||||
# , str(self.vias[keys[insertIndex-1]][2].getBoundingBox()) )
|
||||
trace( 550, '\tcheck PREVIOUS contactBb:%s via:%s\n' \
|
||||
% ( contactBb
|
||||
, self.vias[keys[insertIndex-1]][2].getBoundingBox()) )
|
||||
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
|
||||
|
||||
self.vias[ contact.getY() ] = [ contact.getY()
|
||||
|
@ -209,11 +207,11 @@ class VerticalRail ( Rail ):
|
|||
, self.side.getLayerDepth(self.side.getVLayer())
|
||||
, self.axis
|
||||
, contact.getY()
|
||||
, self.side.vRailWidth
|
||||
, contact.getHeight()
|
||||
, self.side.vRailWidth - DbU.fromLambda(1.0)
|
||||
, contact.getHeight() - DbU.fromLambda(1.0)
|
||||
)
|
||||
, contact ]
|
||||
#print 'ADD %s' % str(contact)
|
||||
trace(550, ',--' '\tADD %s\n' % contact )
|
||||
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
||||
return True
|
||||
|
||||
|
@ -265,12 +263,18 @@ class Side ( object ):
|
|||
return
|
||||
|
||||
def connectPads ( self, padSide ):
|
||||
halfRails = len(self._rails)/2
|
||||
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):
|
||||
#print ' Connect to [-%i] @%d' % (i, DbU.toLambda(self.getOuterRail(i).axis))
|
||||
self.getOuterRail(i).connect( terminal )
|
||||
trace( 550, '\tConnect to [-%i] @%d\n' % (i+1, DbU.toLambda(self.getOuterRail(i+1).axis)) )
|
||||
self.getOuterRail(i+1).connect( terminal )
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
def doLayout ( self ):
|
||||
|
@ -364,60 +368,45 @@ class Corona ( object ):
|
|||
if not isinstance(block,chip.BlockPower.Block):
|
||||
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._innerBb = self._block.bb
|
||||
self._block = block
|
||||
self._innerBb = self._block.bb
|
||||
self._block.path.getTransformation().applyOn( self._innerBb )
|
||||
|
||||
self._railsNb = 4
|
||||
self._railsNb = 5
|
||||
self._hRailWidth = DbU.fromLambda( 12.0 )
|
||||
self._vRailWidth = DbU.fromLambda( 12.0 )
|
||||
self._hRailSpace = DbU.fromLambda( 6.0 )
|
||||
self._vRailSpace = DbU.fromLambda( 6.0 )
|
||||
self._topLayerDepth = 0
|
||||
self._horizontalDepth = 0
|
||||
self._verticalDepth = 0
|
||||
|
||||
self._southSide = SouthSide( self )
|
||||
self._northSide = NorthSide( self )
|
||||
self._westSide = WestSide ( self )
|
||||
self._eastSide = EastSide ( self )
|
||||
self._southSide = SouthSide( self )
|
||||
self._northSide = NorthSide( self )
|
||||
self._westSide = WestSide ( self )
|
||||
self._eastSide = EastSide ( self )
|
||||
|
||||
self._guessHvLayers()
|
||||
return
|
||||
|
||||
def _guessHvLayers ( self ):
|
||||
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()
|
||||
|
||||
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
|
||||
@property
|
||||
def routingGauge ( self ): return self._block.routingGauge
|
||||
@property
|
||||
def topLayerDepth ( self ): return self._block.topLayerDepth
|
||||
@property
|
||||
def horizontalDepth ( self ): return self._block.horizontalDepth
|
||||
@property
|
||||
def verticalDepth ( self ): return self._block.verticalDepth
|
||||
|
||||
def getLayerDepth ( self, metal ):
|
||||
return self._routingGauge.getLayerDepth( metal )
|
||||
return self.routingGauge.getLayerDepth( metal )
|
||||
|
||||
def getRailNet ( self, i ):
|
||||
if i == self._railsNb-1: return self._block.cko
|
||||
if i % 2: return self._block.vssi
|
||||
return self._block.vddi
|
||||
|
||||
def getHLayer ( self ):
|
||||
return self._routingGauge.getLayerGauge( self._horizontalDepth ).getLayer()
|
||||
return self.routingGauge.getLayerGauge( self.horizontalDepth ).getLayer()
|
||||
|
||||
def getVLayer ( self ):
|
||||
return self._routingGauge.getLayerGauge( self._verticalDepth ).getLayer()
|
||||
return self.routingGauge.getLayerGauge( self.verticalDepth ).getLayer()
|
||||
|
||||
def connectBlock ( self ):
|
||||
for plane in self._block.planes.values():
|
||||
|
@ -436,15 +425,15 @@ class Corona ( object ):
|
|||
return
|
||||
|
||||
def doLayout ( self ):
|
||||
self._corners = { chip.SouthWest : []
|
||||
self._corners = { chip.SouthWest : []
|
||||
, chip.SouthEast : []
|
||||
, chip.NorthWest : []
|
||||
, chip.NorthEast : []
|
||||
, chip.NorthWest : []
|
||||
, chip.NorthEast : []
|
||||
}
|
||||
|
||||
contactDepth = self._horizontalDepth
|
||||
if self._horizontalDepth > self._verticalDepth:
|
||||
contactDepth = self._verticalDepth
|
||||
contactDepth = self.horizontalDepth
|
||||
if self.horizontalDepth > self.verticalDepth:
|
||||
contactDepth = self.verticalDepth
|
||||
|
||||
for i in range(self._railsNb):
|
||||
xBL = self._westSide .getRail(i).axis
|
||||
|
@ -453,30 +442,31 @@ class Corona ( object ):
|
|||
yTR = self._northSide.getRail(i).axis
|
||||
net = self.getRailNet( i )
|
||||
|
||||
self.routingGauge.getContactLayer(contactDepth)
|
||||
self._corners[chip.SouthWest].append(
|
||||
Contact.create( net
|
||||
, self._routingGauge.getContactLayer(contactDepth)
|
||||
, self.routingGauge.getContactLayer(contactDepth)
|
||||
, xBL, yBL
|
||||
, self._hRailWidth
|
||||
, self._vRailWidth
|
||||
) )
|
||||
self._corners[chip.NorthWest].append(
|
||||
Contact.create( net
|
||||
, self._routingGauge.getContactLayer(contactDepth)
|
||||
, self.routingGauge.getContactLayer(contactDepth)
|
||||
, xBL, yTR
|
||||
, self._hRailWidth
|
||||
, self._vRailWidth
|
||||
) )
|
||||
self._corners[chip.SouthEast].append(
|
||||
Contact.create( net
|
||||
, self._routingGauge.getContactLayer(contactDepth)
|
||||
, self.routingGauge.getContactLayer(contactDepth)
|
||||
, xTR, yBL
|
||||
, self._hRailWidth
|
||||
, self._vRailWidth
|
||||
) )
|
||||
self._corners[chip.NorthEast].append(
|
||||
Contact.create( net
|
||||
, self._routingGauge.getContactLayer(contactDepth)
|
||||
, self.routingGauge.getContactLayer(contactDepth)
|
||||
, xTR, yTR
|
||||
, self._hRailWidth
|
||||
, self._vRailWidth
|
||||
|
|
|
@ -14,6 +14,7 @@
|
|||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import sys
|
||||
from Hurricane import DbU
|
||||
from Hurricane import Point
|
||||
from Hurricane import Transformation
|
||||
|
@ -28,11 +29,17 @@ from Hurricane import Horizontal
|
|||
from Hurricane import Vertical
|
||||
from Hurricane import Query
|
||||
import CRL
|
||||
import helpers
|
||||
from helpers import trace
|
||||
from helpers import ErrorMessage
|
||||
from helpers import WarningMessage
|
||||
import chip.Configuration
|
||||
|
||||
|
||||
helpers.staticInitialization( quiet=True )
|
||||
helpers.trace.level = 550
|
||||
|
||||
|
||||
class Side ( object ):
|
||||
|
||||
def __init__ ( self, block, side, net, metal ):
|
||||
|
@ -90,13 +97,16 @@ class Side ( object ):
|
|||
height = 0
|
||||
y = self.block.bb.getYMax()
|
||||
|
||||
minWidth = DbU.fromLambda( 6.0 )
|
||||
for terminal in self.terminals:
|
||||
if self.side == chip.West or self.side == chip.East:
|
||||
center = Point( x, terminal[0].getCenter() )
|
||||
height = terminal[0].getSize()
|
||||
if height < minWidth: height = minWidth
|
||||
elif self.side == chip.North or self.side == chip.South:
|
||||
center = Point( terminal[0].getCenter(), y )
|
||||
width = terminal[0].getSize()
|
||||
if width < minWidth: width = minWidth
|
||||
|
||||
self.block.path.getTransformation().applyOn( center )
|
||||
|
||||
|
@ -172,14 +182,13 @@ class GoCb ( object ):
|
|||
return
|
||||
|
||||
|
||||
class Block ( object ):
|
||||
class Block ( chip.Configuration.ChipConfWrapper ):
|
||||
|
||||
def __init__ ( self, path, vddi, vssi ):
|
||||
self.path = path
|
||||
self.cell = self.path.getTailInstance().getMasterCell()
|
||||
self.bb = self.cell.getAbutmentBox()
|
||||
self.vddi = vddi
|
||||
self.vssi = vssi
|
||||
def __init__ ( self, conf ):
|
||||
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||
self.path = Path( self.cores[0] )
|
||||
self.block = self.path.getTailInstance().getMasterCell()
|
||||
self.bb = self.block.getAbutmentBox()
|
||||
self.planes = { }
|
||||
self.activePlane = None
|
||||
|
||||
|
@ -190,7 +199,7 @@ class Block ( object ):
|
|||
return
|
||||
|
||||
|
||||
def queryPower ( self ):
|
||||
def connectPower ( self ):
|
||||
if not self.vddi or not self.vssi:
|
||||
print ErrorMessage( 1, 'Cannot build block power terminals as vddi and/or vss are not known.' )
|
||||
return
|
||||
|
@ -198,7 +207,7 @@ class Block ( object ):
|
|||
goCb = GoCb( self )
|
||||
query = Query()
|
||||
query.setGoCallback( goCb )
|
||||
query.setCell( self.cell )
|
||||
query.setCell( self.block )
|
||||
query.setArea( self.bb )
|
||||
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
||||
|
||||
|
@ -210,6 +219,59 @@ class Block ( object ):
|
|||
self.activePlane = None
|
||||
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 ):
|
||||
UpdateSession.open()
|
||||
for plane in self.planes.values():
|
||||
|
|
|
@ -19,19 +19,312 @@ import os.path
|
|||
import Cfg
|
||||
from Hurricane import DbU
|
||||
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 RoutingPad
|
||||
from Hurricane import Contact
|
||||
from Hurricane import Horizontal
|
||||
from Hurricane import Vertical
|
||||
from Hurricane import Plug
|
||||
from Hurricane import Instance
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace
|
||||
from helpers import ErrorMessage
|
||||
from helpers import WarningMessage
|
||||
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
|
||||
def _readChipSize( chipConfig ):
|
||||
if not chipConfig.has_key('chip.size'): return Box()
|
||||
chipSize = chipConfig['chip.size']
|
||||
def _readChipSize( chipConfigDict ):
|
||||
if not chipConfigDict.has_key('chip.size'): return Box()
|
||||
chipSize = chipConfigDict['chip.size']
|
||||
if not isinstance(chipSize,tuple):
|
||||
print ErrorMessage( 1, 'The Chip size parameter is *not* a tuple.' )
|
||||
return Box()
|
||||
|
@ -42,11 +335,11 @@ class Configuration ( object ):
|
|||
|
||||
|
||||
@staticmethod
|
||||
def _readCoreSize( chipConfig ):
|
||||
if not chipConfig.has_key('core.size'):
|
||||
def _readCoreSize( chipConfigDict ):
|
||||
if not chipConfigDict.has_key('core.size'):
|
||||
print ErrorMessage( 1, 'The Core size parameter is missing.' )
|
||||
return Box()
|
||||
coreSize = chipConfig['core.size']
|
||||
coreSize = chipConfigDict['core.size']
|
||||
if not isinstance(coreSize,tuple):
|
||||
print ErrorMessage( 1, 'The Core size parameter is *not* a tuple.' )
|
||||
return Box()
|
||||
|
@ -56,9 +349,18 @@ class Configuration ( object ):
|
|||
return Box( 0, 0, DbU.fromLambda(coreSize[0]), DbU.fromLambda(coreSize[1]) )
|
||||
|
||||
|
||||
def _readPads ( self, chipConfig, keyword ):
|
||||
if not chipConfig.has_key(keyword): return []
|
||||
padNameList = chipConfig[keyword]
|
||||
@staticmethod
|
||||
def _readClockTree( chipConfigDict ):
|
||||
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):
|
||||
print ErrorMessage( 1, 'The "%s" entry is not a list.' )
|
||||
return []
|
||||
|
@ -104,13 +406,11 @@ class Configuration ( object ):
|
|||
return
|
||||
|
||||
|
||||
def __init__ ( self, chipConfig, cell ):
|
||||
if not isinstance(chipConfig,dict):
|
||||
def __init__ ( self, chipConfigDict, cell ):
|
||||
if not isinstance(chipConfigDict,dict):
|
||||
raise ErrorMessage( 1, 'The "chip" variable is not a dictionnary.' )
|
||||
|
||||
self._validated = True
|
||||
self._routingGauge = None
|
||||
self._topLayerDepth = 0
|
||||
self._cell = cell
|
||||
# Block Corona parameters.
|
||||
self._railsNb = DbU.fromLambda( getParameter('chip','chip.block.rails.count' ).asInt() )
|
||||
|
@ -138,40 +438,23 @@ class Configuration ( object ):
|
|||
self._clockPad = None
|
||||
self._powerPad = None
|
||||
self._cores = []
|
||||
self._southPads = self._readPads( chipConfig, 'pads.south' )
|
||||
self._northPads = self._readPads( chipConfig, 'pads.north' )
|
||||
self._eastPads = self._readPads( chipConfig, 'pads.east' )
|
||||
self._westPads = self._readPads( chipConfig, 'pads.west' )
|
||||
self._coreSize = Configuration._readCoreSize( chipConfig )
|
||||
self._chipSize = Configuration._readChipSize( chipConfig )
|
||||
self._southPads = self._readPads( chipConfigDict, 'pads.south' )
|
||||
self._northPads = self._readPads( chipConfigDict, 'pads.north' )
|
||||
self._eastPads = self._readPads( chipConfigDict, 'pads.east' )
|
||||
self._westPads = self._readPads( chipConfigDict, 'pads.west' )
|
||||
self._coreSize = ChipConf._readCoreSize( chipConfigDict )
|
||||
self._chipSize = ChipConf._readChipSize( chipConfigDict )
|
||||
self._minCorona = DbU.fromLambda( 100 )
|
||||
self._padWidth = 0
|
||||
self._padHeight = 0
|
||||
self._useClockTree = ChipConf._readClockTree( chipConfigDict )
|
||||
|
||||
self.loadRoutingGauge()
|
||||
self.checkPads()
|
||||
self.computeChipSize()
|
||||
self.findPowerAndClockNets()
|
||||
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 ):
|
||||
af = CRL.AllianceFramework.get()
|
||||
cellPads = []
|
||||
|
@ -268,86 +551,88 @@ class Configuration ( object ):
|
|||
return None
|
||||
|
||||
|
||||
class Wrapper ( object ):
|
||||
# -------------------------------------------------------------------
|
||||
# Class : "Configuration.ChipConfWrapper".
|
||||
|
||||
def __init__ ( self, conf ):
|
||||
if not isinstance(conf,Configuration):
|
||||
raise ErrorMessage('Attempt to create a Wrapper() from non-Configuration object.')
|
||||
self._conf = conf
|
||||
class ChipConfWrapper ( GaugeConfWrapper ):
|
||||
|
||||
def __init__ ( self, gaugeConf, chipConf ):
|
||||
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
|
||||
|
||||
def isValid ( self ): return self._conf._validated
|
||||
def isValid ( self ): return self._chipConf._validated
|
||||
|
||||
@property
|
||||
def conf ( self ): return self._conf
|
||||
def chipConf ( self ): return self._chipConf
|
||||
|
||||
@property
|
||||
def routingGauge ( self ): return self._conf._routingGauge
|
||||
@property
|
||||
def topLayerDepth ( self ): return self._conf._topLayerDepth
|
||||
|
||||
@property
|
||||
def cell ( self ): return self._conf._cell
|
||||
def cell ( self ): return self._chipConf._cell
|
||||
|
||||
# Global Net names.
|
||||
@property
|
||||
def vddeName ( self ): return self._conf._vddeName
|
||||
def vddeName ( self ): return self._chipConf._vddeName
|
||||
@property
|
||||
def vsseName ( self ): return self._conf._vsseName
|
||||
def vsseName ( self ): return self._chipConf._vsseName
|
||||
@property
|
||||
def vddiName ( self ): return self._conf._vddiName
|
||||
def vddiName ( self ): return self._chipConf._vddiName
|
||||
@property
|
||||
def vssiName ( self ): return self._conf._vssiName
|
||||
def vssiName ( self ): return self._chipConf._vssiName
|
||||
@property
|
||||
def ckiName ( self ): return self._conf._ckiName
|
||||
def ckiName ( self ): return self._chipConf._ckiName
|
||||
@property
|
||||
def ckoName ( self ): return self._conf._ckoName
|
||||
def ckoName ( self ): return self._chipConf._ckoName
|
||||
@property
|
||||
def ckName ( self ): return self._conf._ckName
|
||||
def ckName ( self ): return self._chipConf._ckName
|
||||
|
||||
# Global Nets.
|
||||
@property
|
||||
def vdde ( self ): return self._conf._vdde
|
||||
def vdde ( self ): return self._chipConf._vdde
|
||||
@property
|
||||
def vsse ( self ): return self._conf._vsse
|
||||
def vsse ( self ): return self._chipConf._vsse
|
||||
@property
|
||||
def vddi ( self ): return self._conf._vddi
|
||||
def vddi ( self ): return self._chipConf._vddi
|
||||
@property
|
||||
def vssi ( self ): return self._conf._vssi
|
||||
def vssi ( self ): return self._chipConf._vssi
|
||||
@property
|
||||
def cki ( self ): return self._conf._cki
|
||||
def cki ( self ): return self._chipConf._cki
|
||||
@property
|
||||
def cko ( self ): return self._conf._cko
|
||||
def cko ( self ): return self._chipConf._cko
|
||||
@property
|
||||
def ck ( self ): return self._conf._ck
|
||||
def ck ( self ): return self._chipConf._ck
|
||||
|
||||
# Various.
|
||||
@property
|
||||
def clockPad ( self ): return self._conf._clockPad
|
||||
@property
|
||||
def powerPad ( self ): return self._conf._powerPad
|
||||
@property
|
||||
def cores ( self ): return self._conf._cores
|
||||
@property
|
||||
def southPads ( self ): return self._conf._southPads
|
||||
@property
|
||||
def northPads ( self ): return self._conf._northPads
|
||||
@property
|
||||
def eastPads ( self ): return self._conf._eastPads
|
||||
@property
|
||||
def westPads ( self ): return self._conf._westPads
|
||||
@property
|
||||
def coreSize ( self ): return self._conf._coreSize
|
||||
def clockPad ( self ): return self._chipConf._clockPad
|
||||
@property
|
||||
def powerPad ( self ): return self._chipConf._powerPad
|
||||
@property
|
||||
def cores ( self ): return self._chipConf._cores
|
||||
@property
|
||||
def southPads ( self ): return self._chipConf._southPads
|
||||
@property
|
||||
def northPads ( self ): return self._chipConf._northPads
|
||||
@property
|
||||
def eastPads ( self ): return self._chipConf._eastPads
|
||||
@property
|
||||
def westPads ( self ): return self._chipConf._westPads
|
||||
@property
|
||||
def coreSize ( self ): return self._chipConf._coreSize
|
||||
@coreSize.setter
|
||||
def coreSize ( self, ab ): self._conf._coreSize = ab
|
||||
def coreSize ( self, ab ): self._chipConf._coreSize = ab
|
||||
@property
|
||||
def chipSize ( self ): return self._chipConf._chipSize
|
||||
@property
|
||||
def minCorona ( self ): return self._chipConf._minCorona
|
||||
@property
|
||||
def padWidth ( self ): return self._chipConf._padWidth
|
||||
@property
|
||||
def padHeight ( self ): return self._chipConf._padHeight
|
||||
@property
|
||||
def chipSize ( self ): return self._conf._chipSize
|
||||
@property
|
||||
def minCorona ( self ): return self._conf._minCorona
|
||||
@property
|
||||
def padWidth ( self ): return self._conf._padWidth
|
||||
@property
|
||||
def padHeight ( self ): return self._conf._padHeight
|
||||
def useClockTree ( self ): return self._chipConf._useClockTree
|
||||
|
||||
|
||||
def loadConfiguration ( cell ):
|
||||
|
@ -360,4 +645,5 @@ def loadConfiguration ( cell ):
|
|||
raise WarningMessage( 'Module <%s> do not provides the chip variable, skipped.' \
|
||||
% 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
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace
|
||||
from helpers import ErrorMessage
|
||||
from helpers import WarningMessage
|
||||
import chip.Configuration
|
||||
|
@ -108,12 +109,24 @@ class Side ( object ):
|
|||
|
||||
def _createPowerContacts ( self, pad, net ):
|
||||
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:
|
||||
hvDepth = self._corona.getHDepth()
|
||||
hvDepth = self._corona.padHDepth
|
||||
|
||||
trace( 550, ',+', '\t_createPowerContacts() for %s\n' % net.getName() )
|
||||
|
||||
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 self._corona.routingGauge.getLayerDepth(component.getLayer()) != hvDepth: continue
|
||||
if not isinstance(component,Vertical): continue
|
||||
|
@ -128,6 +141,7 @@ class Side ( object ):
|
|||
position = Point( component.getX(), masterCell.getAbutmentBox().getYMin() )
|
||||
pad.getTransformation().applyOn( position )
|
||||
|
||||
connecteds = True
|
||||
self._powerContacts.append( Contact.create( net
|
||||
, component.getLayer()
|
||||
, position.getX()
|
||||
|
@ -135,6 +149,11 @@ class Side ( object ):
|
|||
, width
|
||||
, height
|
||||
) )
|
||||
if not connecteds:
|
||||
print WarningMessage( 'Cannot find a suitable connector for <%s> on pad <%s>'
|
||||
% (net.getName(),pad.getName()) )
|
||||
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
|
||||
|
@ -149,6 +168,7 @@ class Side ( object ):
|
|||
#print 'Power pad:', pad
|
||||
self._createPowerContacts( pad, self._corona.vddi )
|
||||
self._createPowerContacts( pad, self._corona.vssi )
|
||||
self._createPowerContacts( pad, self._corona.cko )
|
||||
return
|
||||
|
||||
|
||||
|
@ -226,10 +246,10 @@ class Side ( object ):
|
|||
return
|
||||
|
||||
|
||||
class Corona ( chip.Configuration.Wrapper ):
|
||||
class Corona ( chip.Configuration.ChipConfWrapper ):
|
||||
|
||||
def __init__ ( self, confWrapper ):
|
||||
chip.Configuration.Wrapper.__init__( self, confWrapper.conf )
|
||||
def __init__ ( self, conf ):
|
||||
chip.Configuration.ChipConfWrapper.__init__( self, conf.gaugeConf, conf.chipConf )
|
||||
self.validated = False
|
||||
self._northSide = Side( self, chip.North )
|
||||
self._southSide = Side( self, chip.South )
|
||||
|
@ -243,7 +263,7 @@ class Corona ( chip.Configuration.Wrapper ):
|
|||
self._powerRails = [] # [ , [net, layer, axis, width] ]
|
||||
|
||||
self._locatePadRails()
|
||||
self._guessHvLayers()
|
||||
self._guessPadHvLayers()
|
||||
return
|
||||
|
||||
@property
|
||||
|
@ -254,6 +274,10 @@ class Corona ( chip.Configuration.Wrapper ):
|
|||
def eastSide ( self ): return self._eastSide
|
||||
@property
|
||||
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 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 getRailAxis ( self, i ): return self._powerRails[i][2]
|
||||
def getRailWidth ( self, i ): return self._powerRails[i][3]
|
||||
def getHDepth ( self ): return self._horizontalDepth
|
||||
def getVDepth ( self ): return self._verticalDepth
|
||||
|
||||
|
||||
def validate ( self ):
|
||||
|
@ -316,7 +338,7 @@ class Corona ( chip.Configuration.Wrapper ):
|
|||
# )
|
||||
return
|
||||
|
||||
def _guessHvLayers ( self ):
|
||||
def _guessPadHvLayers ( self ):
|
||||
if not self.powerPad:
|
||||
print ErrorMessage( 1, 'There must be at least one pad of model "pvddick_px" to guess the pad power terminals.' )
|
||||
return False
|
||||
|
@ -329,18 +351,18 @@ class Corona ( chip.Configuration.Wrapper ):
|
|||
|
||||
#print 'available depth:', availableDepths
|
||||
|
||||
self._horizontalDepth = 0
|
||||
self._verticalDepth = 0
|
||||
self._horizontalPadDepth = 0
|
||||
self._verticalPadDepth = 0
|
||||
for depth in range(0,self.topLayerDepth+1):
|
||||
if not depth in availableDepths: continue
|
||||
|
||||
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
||||
self._horizontalDepth = depth
|
||||
self._horizontalPadDepth = depth
|
||||
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
||||
self._verticalDepth = depth
|
||||
self._verticalPadDepth = depth
|
||||
|
||||
#print 'h:', self._horizontalDepth
|
||||
#print 'v:', self._verticalDepth
|
||||
#print 'h:', self._horizontalPadDepth
|
||||
#print 'v:', self._verticalPadDepth
|
||||
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