coriolis/cumulus/src/plugins/clocktree/ClockTree.py

599 lines
24 KiB
Python
Executable File

#!/usr/bin/env python
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2014-2016, 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 GaugeConf
from chip.Configuration import GaugeConfWrapper
except ImportError, e:
serror = str(e)
if serror.startswith('No module named'):
module = serror.split()[-1]
print '[ERROR] The <%s> python module or symbol cannot be loaded.' % module
print ' Please check the integrity of the <coriolis> package.'
if str(e).find('cannot open shared object file'):
library = serror.split(':')[0]
print '[ERROR] The <%s> shared library cannot be loaded.' % library
print ' Under RHEL 6, you must be under devtoolset-2.'
print ' (scl enable devtoolset-2 bash)'
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 ):
@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()
trace( 550, '\tht.build() OK\n' )
ht.place()
trace( 550, '\tht.place() OK\n' )
#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 ):
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._getBufferIo()
self.tieCell = self.framework.getCell( 'rowend_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 _getBufferIo ( self ):
self.bufferCell = self.framework.getCell( Cfg.getParamString('clockTree.buffer').asString()
, CRL.Catalog.State.Views )
if not self.bufferCell:
raise ErrorMessage( 3, [ 'ClockTree: Buffer cell "%s" not found in library,' \
% Cfg.getParamString('clockTree.buffer').asString()
, ' please check the "clockTree.buffer" configuration parameter in "plugins.conf".' ] )
for net in self.bufferCell.getNets():
if not net.isExternal(): continue
if net.isGlobal(): continue
if net.getDirection() & Net.Direction.IN: self.bufferIn = net.getName()
elif net.getDirection() & Net.Direction.OUT: self.bufferOut = net.getName()
trace( 550, '\tbufferIn :<%s>\n' % self.bufferIn )
trace( 550, '\tbufferOut:<%s>\n' % self.bufferOut )
return
def _createChildNet ( self, ibuffer, tag ):
childNet = Net.create( self.cell, tag )
childNet.setType( Net.Type.CLOCK )
getPlugByName(ibuffer, self.bufferOut).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.area.getYMin()) / 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() )
trace( 550, '\rplace top level\n' )
self.usedVTracks += [ getRpBb(self.topBuffer, self.bufferIn).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.verticalDeepDepth).getPitch()
# This is a Steiner point.
node.component = self.createContact( net
, x
, node.y + self.cellGauge.getSliceHeight()/2 - self.routingGauge.getLayerGauge(self.horizontalDeepDepth).getPitch()
, GaugeConf.DeepDepth )
trace( 550, '\tCreate (Steiner) node.component: @Y%d (y:%d - %d) %s\n' \
% (DbU.toLambda(node.realY)
,DbU.toLambda(node.y)
,DbU.toLambda(self.routingGauge.getLayerGauge(self.horizontalDeepDepth).getPitch())
,node.component) )
else:
# This a terminal (graph) point
for edge in node.edges:
flags = GaugeConf.HAccess|GaugeConf.DeepDepth
if not edge.isHorizontal():
if node.isSame(edge.source) or edge.isVertical():
flags &= ~GaugeConf.HAccess
break
flags |= GaugeConf.OffsetTop1
if node.realX in self.usedVTracks:
flags |= GaugeConf.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(), GaugeConf.DeepDepth )
elif edge.isVertical():
self.createVertical ( sourceContact, targetContact, sourceContact.getX(), GaugeConf.DeepDepth )
else:
turn = self.createContact( edge.source.component.getNet()
, sourceContact.getX()
, targetContact.getY()
, GaugeConf.DeepDepth )
self.createVertical ( sourceContact, turn, sourceContact.getX(), GaugeConf.DeepDepth )
self.createHorizontal( turn, targetContact, targetContact.getY(), GaugeConf.DeepDepth )
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,self.bufferOut).getNet()
#bufferRp = self.rpByPlugName( leafBuffer, self.bufferOut, 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 ):
trace( 550, '\tConnecting leafs.\n' )
UpdateSession.open()
leafsByBuffer = {}
hyperMasterClock = HyperNet.create( Occurrence(self.masterClock) )
for plugOccurrence in hyperMasterClock.getLeafPlugOccurrences():
trace( 550, '\tAdding leaf <%s>.\n' % plugOccurrence )
position = plugOccurrence.getBoundingBox().getCenter()
self.addLeaf( position, plugOccurrence )
self.childs[0].connectLeafs()
sys.stdout.flush()
getPlugByName( self.topBuffer, self.bufferIn ).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, self.topTree.bufferOut).getNet()
getPlugByName(self.blBuffer, self.topTree.bufferIn).setNet( self.ckNet )
getPlugByName(self.brBuffer, self.topTree.bufferIn).setNet( self.ckNet )
getPlugByName(self.tlBuffer, self.topTree.bufferIn).setNet( self.ckNet )
getPlugByName(self.trBuffer, self.topTree.bufferIn).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,self.topTree.bufferOut).getNet()
deepPlug = self.topTree.addDeepPlug( leafCk, plugOccurrence.getPath() )
if deepPlug:
leafCk = deepPlug.getMasterNet()
plugOccurrence.getEntity().setNet( leafCk )
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 ):
trace( 550, '\rplace HTreeNode %s\n' % self.ckNet.getName() )
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, self.topTree.bufferIn, self.ckNet ).getX()
, self.topTree.rpAccessByPlugName( self.brBuffer, self.topTree.bufferIn, self.ckNet ).getX() ]
for child in self.childs: child.place()
return
def route ( self ):
trace( 550, '\tHTreeNode.route() %s\n' % self.sourceBuffer.getName() )
leftSourceContact = self.topTree.rpAccessByPlugName( self.sourceBuffer, self.topTree.bufferOut, self.ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
rightSourceContact = self.topTree.rpAccessByPlugName( self.sourceBuffer, self.topTree.bufferOut, self.ckNet , GaugeConf.HAccess|GaugeConf.OffsetBottom1 )
blContact = self.topTree.rpAccessByPlugName( self.blBuffer , self.topTree.bufferIn , self.ckNet )
brContact = self.topTree.rpAccessByPlugName( self.brBuffer , self.topTree.bufferIn , self.ckNet )
tlContact = self.topTree.rpAccessByPlugName( self.tlBuffer , self.topTree.bufferIn , self.ckNet )
trContact = self.topTree.rpAccessByPlugName( self.trBuffer , self.topTree.bufferIn , 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() , 0 )
self.topTree.createHorizontal( rightSourceContact, rightContact , rightSourceContact.getY(), 0 )
self.topTree.createVertical ( leftContact , blContact , leftContact.getX() , 0 )
self.topTree.createVertical ( tlContact , leftContact , leftContact.getX() , 0 )
self.topTree.createVertical ( rightContact , brContact , rightContact.getX() , 0 )
self.topTree.createVertical ( trContact , rightContact , rightContact.getX() , 0 )
for child in self.childs: child.route()
return
def connectLeafs ( self ):
if not self.hasLeafs():
trace( 550, '\tHTreeNode.connectLeafs() %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