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:
Jean-Paul Chaput 2014-08-15 19:05:27 +02:00
parent 20f8d004e2
commit fb4a7457a1
13 changed files with 2555 additions and 295 deletions

View File

@ -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

View File

@ -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 )

View File

@ -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

View File

@ -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

View File

@ -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()' )

View File

@ -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

View File

@ -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():

View File

@ -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 ) )

View File

@ -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

View File

@ -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

View File

@ -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