coriolis/cumulus/src/plugins/ClockTree.py

583 lines
22 KiB
Python
Executable File

#!/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.cpp" |
# +-----------------------------------------------------------------+
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 Instance
from Hurricane import HyperNet
import Viewer
import CRL
from CRL import RoutingLayerGauge
from helpers import ErrorMessage
import Nimbus
import Metis
import Mauka
import Katabatic
import Kite
import Unicorn
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)
# Will be moved away from the students eyes in the future.
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 ):
#print 'getPlugByNet:', net, 'connected to', instance
for plug in net.getPlugs():
#print '|', plug
if plug.getInstance() == instance:
#print '| Found.'
return plug
#print '| NOT Found'
return None
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
class HTree ( object ):
HAccess = 0x0001
@staticmethod
def create ( cell, 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( cell, clockBox )
print ' o Creating Clock H-Tree for <%s>.' % cell.getName()
ht.build()
ht.place()
ht.route()
print ' - H-Tree depth: %d' % ht.getTreeDepth()
return ht
def __init__ ( self, cell, area ):
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.cellGauge = self.framework.getCellGauge()
self.routingGauge = self.framework.getRoutingGauge()
self.topBuffer = Instance.create( self.cell, 'ck_htree', self.bufferCell )
self.cloneds = [ self.cell ]
self.plugToRp = {}
self._createChildNet( self.topBuffer, 'ck_htree' )
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 '[WARNING] 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
self.masterClock = None
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()
return
def _createChildNet ( self, ibuffer, tag ):
childNet = Net.create( self.cell, tag )
childNet.setType( Net.Type.CLOCK )
getPlugByName(ibuffer, 'q').setNet( childNet )
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 ):
return Horizontal.create( source
, target
, self.routingGauge.getRoutingLayer(self.horizontalDepth)
, y
, self.routingGauge.getLayerGauge(self.horizontalDepth).getWireWidth()
)
def _createVertical ( self, source, target, x ):
return Vertical.create( source
, target
, self.routingGauge.getRoutingLayer(self.verticalDepth)
, x
, self.routingGauge.getLayerGauge(self.verticalDepth).getWireWidth()
)
def _rpAccess ( self, rp, net, flags=0 ):
contact1 = Contact.create( rp, self.routingGauge.getContactLayer(0), 0, 0 )
if flags & HTree.HAccess: stopDepth = self.horizontalDepth
else: stopDepth = self.verticalDepth
for depth in range(1,stopDepth):
contact2 = Contact.create( net
, self.routingGauge.getContactLayer(depth)
, contact1.getX()
, contact1.getY()
, self.routingGauge.getLayerGauge(depth).getViaWidth()
, self.routingGauge.getLayerGauge(depth).getViaWidth()
)
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
Horizontal.create( contact1
, contact2
, self.routingGauge.getRoutingLayer(depth)
, contact1.getY()
, self.routingGauge.getLayerGauge(depth).getWireWidth()
)
else:
Vertical.create( contact1
, contact2
, self.routingGauge.getRoutingLayer(depth)
, contact1.getX()
, self.routingGauge.getLayerGauge(depth).getWireWidth()
)
contact1 = contact2
return contact1
def _rpAccessByOccurrence ( self, occurrence, net, flags=0 ):
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( rp, net, flags )
def _rpAccessByPlug ( self, plug, net, flags=0 ):
if self.plugToRp.has_key(plug):
rp = self.plugToRp[plug]
else:
occurrence = Occurrence( plug, Path(self.cell,'') )
rp = RoutingPad.create( net, occurrence, RoutingPad.BiggestArea )
self.plugToRp[plug] = rp
return self._rpAccess( rp, net, flags )
def _rpAccessByPlugName ( self, instance, plugName, net, flags=0 ):
return self._rpAccessByPlug( getPlugByName(instance,plugName), net, flags )
def toXCellGrid ( self, x ): return x - (x % self.cellGauge.getSliceStep ())
def toYCellGrid ( self, y ): return y - (y % self.cellGauge.getSliceHeight())
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 getTreeDepth ( self ):
return self.childs[0].getTreeDepth()
def getLeafBufferUnder ( self, point ):
return self.childs[0].getLeafBufferUnder( point )
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.childs[0].place()
UpdateSession.close()
return
def route ( self ):
UpdateSession.open()
self.childs[0].route()
UpdateSession.close()
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 )
if not masterCell in self.cloneds: self.cloneds.append( masterCell )
if tailPath.isEmpty(): return headPlug
return self.addDeepPlug( masterNet, tailPath )
def connectLeaf ( self ):
UpdateSession.open()
leafConnects = []
hyperMasterClock = HyperNet.create( Occurrence(self.masterClock) )
for plugOccurrence in hyperMasterClock.getLeafPlugOccurrences():
position = plugOccurrence.getBoundingBox().getCenter()
leafBuffer = self.getLeafBufferUnder( position )
leafCk = getPlugByName(leafBuffer,'q').getNet()
deepPlug = self.addDeepPlug( leafCk, plugOccurrence.getPath() )
leafConnects.append( (deepPlug,plugOccurrence,leafCk,leafBuffer) )
for deepPlug, plugOccurrence, leafCk, leafBuffer in leafConnects:
plugOccurrence.getEntity().setNet( deepPlug.getMasterNet() )
bufferContact = self._rpAccessByPlugName( leafBuffer, 'q', leafCk , HTree.HAccess )
registerContact = self._rpAccessByOccurrence( plugOccurrence, leafCk, 0 )
turn = self._createContact( leafCk, registerContact.getX(), bufferContact.getY() )
self._createVertical ( registerContact, turn, registerContact.getX() )
self._createHorizontal( turn, bufferContact, bufferContact.getY() )
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 ):
for cell in self.cloneds:
cell.setName( cell.getName()+'_clocked' )
self._rsave( self.cell )
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.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 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 )
for child in self.childs: child.place()
return
def route ( self ):
leftSourceContact = self.topTree._rpAccessByPlugName( self.sourceBuffer, 'q', self.ckNet , HTree.HAccess )
rightSourceContact = self.topTree._rpAccessByPlugName( self.sourceBuffer, 'q', self.ckNet , HTree.HAccess )
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 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
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
computeAbutmentBox( cell, spaceMargin, aspectRatio, cellGauge )
if editor: editor.fit()
ht = HTree.create( cell, cell.getAbutmentBox() )
if editor: editor.refresh()
mauka = Mauka.MaukaEngine.create( cell )
mauka.run()
mauka.destroy()
ht.connectLeaf()
ht.save()
#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
if __name__ == '__main__':
ScriptMain()
sys.exit(0)