#!/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 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)