509 lines
20 KiB
Python
509 lines
20 KiB
Python
#!/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/chip/BlockCorona.py" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
|
|
import bisect
|
|
from operator import methodcaller
|
|
import Cfg
|
|
from Hurricane import DbU
|
|
from Hurricane import Point
|
|
from Hurricane import Transformation
|
|
from Hurricane import Box
|
|
from Hurricane import Path
|
|
from Hurricane import Occurrence
|
|
from Hurricane import UpdateSession
|
|
from Hurricane import Net
|
|
from Hurricane import Contact
|
|
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
|
|
import plugins
|
|
from plugins import StackedVia
|
|
import chip.BlockPower
|
|
|
|
|
|
class Rail ( object ):
|
|
|
|
def __init__ ( self, side, order, axis ):
|
|
self.side = side
|
|
self.order = order
|
|
self.axis = axis
|
|
self.vias = { } # Key:pos Element: [pos,railContact,blockContact]
|
|
return
|
|
|
|
@property
|
|
def net ( self ): return self.side.getRailNet(self.order)
|
|
|
|
|
|
class HorizontalRail ( Rail ):
|
|
|
|
def __init__ ( self, side, order, axis ):
|
|
Rail.__init__( self, side, order, axis )
|
|
return
|
|
|
|
def connect ( self, contact ):
|
|
contactBb = contact.getBoundingBox()
|
|
if contactBb.getXMin() < self.side.innerBb.getXMin() \
|
|
or contactBb.getXMax() > self.side.innerBb.getXMax():
|
|
raise ErrorMessage( 1, [ '%s is outside rail/corona X range,' % str(contact)
|
|
, 'power pad is likely to be to far off west or east.'
|
|
, '(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.vias.has_key(contact.getX()): return False
|
|
|
|
keys = self.vias.keys()
|
|
keys.sort()
|
|
insertIndex = bisect.bisect_left( keys, contact.getX() )
|
|
|
|
if len(keys) > 0:
|
|
if insertIndex < len(keys):
|
|
insertPosition = keys[ insertIndex ]
|
|
if contactBb.getXMax() >= self.vias[insertPosition][2].getBoundingBox().getXMin():
|
|
#print 'Reject contact %s intersect NEXT' % str(contact)
|
|
return False
|
|
if insertIndex > 0:
|
|
if self.vias[keys[insertIndex-1]][2].getBoundingBox().getXMax() >= contactBb.getXMin():
|
|
#print 'Reject contact %s intersect PREVIOUS' % str(contact)
|
|
return False
|
|
|
|
self.vias[ contact.getX() ] = [ contact.getX()
|
|
, StackedVia( self.net
|
|
, self.side.getLayerDepth(self.side.getHLayer())
|
|
, contact.getX()
|
|
, self.axis
|
|
, 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 ):
|
|
#print 'HorizontalRail[%s] @%d' % (self.order,DbU.toLambda(self.axis))
|
|
|
|
railVias = [ self.side.corner0(self.order)
|
|
, 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() )
|
|
, via[2]
|
|
, via[2].getLayer()
|
|
, via[2].getX()
|
|
, via[2].getWidth()
|
|
)
|
|
railVias.append( via[1].getVia( self.side.getVLayer()) )
|
|
|
|
railVias.sort( key=methodcaller('getY') )
|
|
|
|
for i in range(1,len(railVias)):
|
|
Horizontal.create( railVias[i-1]
|
|
, railVias[i]
|
|
, self.side.getHLayer()
|
|
, self.axis
|
|
, self.side.hRailWidth
|
|
)
|
|
return
|
|
|
|
|
|
class VerticalRail ( Rail ):
|
|
|
|
def __init__ ( self, side, order, axis ):
|
|
Rail.__init__( self, side, order, axis )
|
|
return
|
|
|
|
def doLayout ( self ):
|
|
#print 'VerticalRail[%s] @%d' % (self.order,DbU.toLambda(self.axis))
|
|
|
|
railVias = [ self.side.corner0(self.order)
|
|
, self.side.corner1(self.order) ]
|
|
|
|
for via in self.vias.values():
|
|
if via[1].getNet() != via[2].getNet(): continue
|
|
|
|
via[1].doLayout()
|
|
Horizontal.create( via[1].getVia( via[2].getLayer() )
|
|
, via[2]
|
|
, via[2].getLayer()
|
|
, via[2].getY()
|
|
, via[2].getHeight()
|
|
)
|
|
railVias.append( via[1].getVia(self.side.getVLayer()) )
|
|
|
|
railVias.sort( key=methodcaller('getY') )
|
|
|
|
for i in range(1,len(railVias)):
|
|
Vertical.create( railVias[i-1]
|
|
, railVias[i]
|
|
, self.side.getVLayer()
|
|
, self.axis
|
|
, self.side.vRailWidth
|
|
)
|
|
|
|
routingGauge = CRL.AllianceFramework.get().getRoutingGauge()
|
|
for depth in range(self.side.verticalDepth-2,self.vias.values()[0][1]._bottomDepth,-2):
|
|
blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer()
|
|
pitch = routingGauge.getLayerPitch(depth)
|
|
|
|
for i in range(1,len(railVias)):
|
|
Vertical.create( self.side.blockageNet
|
|
, blockageLayer
|
|
, self.axis
|
|
, self.side.vRailWidth
|
|
, railVias[i-1].getBoundingBox().getYMax() + pitch
|
|
, railVias[i ].getBoundingBox().getYMin() - pitch
|
|
)
|
|
|
|
return
|
|
|
|
def connect ( self, contact ):
|
|
contactBb = contact.getBoundingBox()
|
|
if contactBb.getYMin() < self.side.innerBb.getYMin() \
|
|
or contactBb.getYMax() > self.side.innerBb.getYMax():
|
|
raise ErrorMessage( 1, [ '%s is outside rail/corona Y range' % str(contact)
|
|
, '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.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() )
|
|
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 ]
|
|
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():
|
|
trace( 550, ',--', '\tReject %s intersect NEXT\n' % contact )
|
|
return False
|
|
if insertIndex > 0:
|
|
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():
|
|
trace( 550, ',--', '\tReject %s intersect PREVIOUS\n' % contact )
|
|
return False
|
|
|
|
self.vias[ contact.getY() ] = [ contact.getY()
|
|
, StackedVia( self.net
|
|
, self.side.getLayerDepth(self.side.getVLayer())
|
|
, self.axis
|
|
, contact.getY()
|
|
, self.side.vRailWidth - DbU.fromLambda(1.0)
|
|
, contact.getHeight() - DbU.fromLambda(1.0)
|
|
)
|
|
, contact ]
|
|
trace(550, ',--' '\tADD %s\n' % contact )
|
|
self.vias[ contact.getY() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) )
|
|
return True
|
|
|
|
|
|
class Side ( object ):
|
|
|
|
def __init__ ( self, corona ):
|
|
self._corona = corona
|
|
return
|
|
|
|
@property
|
|
def railsNb ( self ): return self._corona._railsNb
|
|
@property
|
|
def innerBb ( self ): return self._corona._innerBb
|
|
@property
|
|
def hRailWidth ( self ): return self._corona._hRailWidth
|
|
@property
|
|
def hRailSpace ( self ): return self._corona._hRailSpace
|
|
@property
|
|
def vRailWidth ( self ): return self._corona._vRailWidth
|
|
@property
|
|
def vRailSpace ( self ): return self._corona._vRailSpace
|
|
@property
|
|
def corners ( self ): return self._corona._corners
|
|
@property
|
|
def horizontalDepth ( self ): return self._corona.horizontalDepth
|
|
@property
|
|
def verticalDepth ( self ): return self._corona.verticalDepth
|
|
@property
|
|
def blockageNet ( self ): return self._corona.blockageNet
|
|
|
|
def getLayerDepth ( self, metal ): return self._corona.getLayerDepth(metal)
|
|
def getRail ( self, i ): return self._rails[i]
|
|
def getRailNet ( self, i ): return self._corona.getRailNet(i)
|
|
def getHLayer ( self ): return self._corona.getHLayer()
|
|
def getVLayer ( self ): return self._corona.getVLayer()
|
|
|
|
def getRailAxis ( self, i ):
|
|
raise ErrorMessage( 1, 'Side.getRailAxis(): Must never be called on base class.' )
|
|
|
|
def getInnerRail ( self, i ):
|
|
if i >= len(self._rails):
|
|
raise ErrorMessage( 1, 'Side.getInnerRail(): no rail %d (only: %d).' % (i,len(self._rails)) )
|
|
return self._rails[i]
|
|
|
|
def getOuterRail ( self, i ):
|
|
if i >= len(self._rails):
|
|
raise ErrorMessage( 1, 'Side.getOuterRail(): no rail %d (only: %d).' % (i,len(self._rails)) )
|
|
return self._rails[-(i+1)]
|
|
|
|
def connect ( self, blockSide ):
|
|
for terminal in blockSide.terminals:
|
|
for rail in self._rails:
|
|
rail.connect( terminal[1] )
|
|
return
|
|
|
|
def connectPads ( self, padSide ):
|
|
for terminal in padSide._powerContacts:
|
|
#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):
|
|
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 ):
|
|
for rail in self._rails: rail.doLayout()
|
|
return
|
|
|
|
|
|
class HorizontalSide ( Side ):
|
|
|
|
def __init__ ( self, corona ):
|
|
#print 'HorizontalSide.__init__()'
|
|
Side.__init__( self, corona )
|
|
|
|
self._rails = []
|
|
for i in range(self.railsNb):
|
|
self._rails.append( HorizontalRail(self,i,self.getRailAxis(i)) )
|
|
#print ' Rail [%i] @%d' % (i,DbU.toLambda(self._rails[-1].axis))
|
|
return
|
|
|
|
|
|
class SouthSide ( HorizontalSide ):
|
|
|
|
def __init__ ( self, corona ):
|
|
HorizontalSide.__init__( self, corona )
|
|
return
|
|
|
|
def getRailAxis ( self, i ):
|
|
return self.innerBb.getYMin() - self.hRailWidth/2 - self.hRailSpace \
|
|
- i*(self.hRailWidth + self.hRailSpace)
|
|
|
|
def corner0 ( self, i ): return self.corners[chip.SouthWest][i]
|
|
def corner1 ( self, i ): return self.corners[chip.SouthEast][i]
|
|
|
|
|
|
class NorthSide ( HorizontalSide ):
|
|
|
|
def __init__ ( self, corona ):
|
|
HorizontalSide.__init__( self, corona )
|
|
return
|
|
|
|
def getRailAxis ( self, i ):
|
|
return self.innerBb.getYMax() + self.hRailWidth/2 + self.hRailSpace \
|
|
+ i*(self.hRailWidth + self.hRailSpace)
|
|
|
|
def corner0 ( self, i ): return self.corners[chip.NorthWest ][i]
|
|
def corner1 ( self, i ): return self.corners[chip.NorthEast][i]
|
|
|
|
|
|
class VerticalSide ( Side ):
|
|
|
|
def __init__ ( self, corona ):
|
|
Side.__init__( self, corona )
|
|
|
|
self._rails = []
|
|
for i in range(self.railsNb):
|
|
self._rails.append( VerticalRail(self,i,self.getRailAxis(i)) )
|
|
return
|
|
|
|
|
|
class WestSide ( VerticalSide ):
|
|
|
|
def __init__ ( self, corona ):
|
|
VerticalSide.__init__( self, corona )
|
|
return
|
|
|
|
def getRailAxis ( self, i ):
|
|
return self.innerBb.getXMin() - self.vRailWidth/2 - self.vRailSpace \
|
|
- i*(self.vRailWidth + self.vRailSpace)
|
|
|
|
def corner0 ( self, i ): return self.corners[chip.SouthWest][i]
|
|
def corner1 ( self, i ): return self.corners[chip.NorthWest ][i]
|
|
|
|
|
|
class EastSide ( VerticalSide ):
|
|
|
|
def __init__ ( self, corona ):
|
|
VerticalSide.__init__( self, corona )
|
|
return
|
|
|
|
def getRailAxis ( self, i ):
|
|
return self.innerBb.getXMax() + self.vRailWidth/2 + self.vRailSpace \
|
|
+ i*(self.vRailWidth + self.vRailSpace)
|
|
|
|
def corner0 ( self, i ): return self.corners[chip.SouthEast][i]
|
|
def corner1 ( self, i ): return self.corners[chip.NorthEast ][i]
|
|
|
|
|
|
class Corona ( object ):
|
|
|
|
def __init__ ( self, block ):
|
|
#if not isinstance(block,plugins.chip.BlockPower.Block):
|
|
# raise ErrorMessage( 1, 'Attempt to create a Corona on a non-Block object.' )
|
|
|
|
self._railsNb = Cfg.getParamInt('chip.block.rails.count').asInt()
|
|
self._hRailWidth = DbU.fromLambda( Cfg.getParamInt('chip.block.rails.hWidth' ).asInt() )
|
|
self._vRailWidth = DbU.fromLambda( Cfg.getParamInt('chip.block.rails.vWidth' ).asInt() )
|
|
self._hRailSpace = DbU.fromLambda( Cfg.getParamInt('chip.block.rails.hSpacing').asInt() )
|
|
self._vRailSpace = DbU.fromLambda( Cfg.getParamInt('chip.block.rails.vSpacing').asInt() )
|
|
|
|
self._block = block
|
|
self._innerBb = self._block.bb
|
|
self._block.path.getTransformation().applyOn( self._innerBb )
|
|
self._innerBb.inflate( self._hRailSpace/2, self._vRailSpace/2 )
|
|
|
|
if not self.useClockTree: self._railsNb -= 1
|
|
|
|
self._southSide = SouthSide( self )
|
|
self._northSide = NorthSide( self )
|
|
self._westSide = WestSide ( self )
|
|
self._eastSide = EastSide ( self )
|
|
|
|
return
|
|
|
|
@property
|
|
def useClockTree ( self ): return self._block.useClockTree
|
|
@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
|
|
@property
|
|
def blockageNet ( self ): return self._block.blockageNet
|
|
|
|
def getLayerDepth ( self, metal ):
|
|
return self.routingGauge.getLayerDepth( metal )
|
|
|
|
def getRailNet ( self, i ):
|
|
if self.useClockTree and 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()
|
|
|
|
def getVLayer ( self ):
|
|
return self.routingGauge.getLayerGauge( self.verticalDepth ).getLayer()
|
|
|
|
def connectBlock ( self ):
|
|
for plane in self._block.planes.values():
|
|
for side in plane.sides.values():
|
|
self._southSide.connect( side[chip.South] )
|
|
self._northSide.connect( side[chip.North] )
|
|
self._westSide .connect( side[chip.West ] )
|
|
self._eastSide .connect( side[chip.East ] )
|
|
return
|
|
|
|
def connectPads ( self, padsCorona ):
|
|
self._southSide.connectPads( padsCorona.southSide )
|
|
self._northSide.connectPads( padsCorona.northSide )
|
|
self._eastSide.connectPads( padsCorona.eastSide )
|
|
self._westSide.connectPads( padsCorona.westSide )
|
|
return
|
|
|
|
def doLayout ( self ):
|
|
self._corners = { chip.SouthWest : []
|
|
, chip.SouthEast : []
|
|
, chip.NorthWest : []
|
|
, chip.NorthEast : []
|
|
}
|
|
|
|
contactDepth = self.horizontalDepth
|
|
if self.horizontalDepth > self.verticalDepth:
|
|
contactDepth = self.verticalDepth
|
|
|
|
for i in range(self._railsNb):
|
|
xBL = self._westSide .getRail(i).axis
|
|
yBL = self._southSide.getRail(i).axis
|
|
xTR = self._eastSide .getRail(i).axis
|
|
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)
|
|
, xBL, yBL
|
|
, self._hRailWidth
|
|
, self._vRailWidth
|
|
) )
|
|
self._corners[chip.NorthWest].append(
|
|
Contact.create( net
|
|
, self.routingGauge.getContactLayer(contactDepth)
|
|
, xBL, yTR
|
|
, self._hRailWidth
|
|
, self._vRailWidth
|
|
) )
|
|
self._corners[chip.SouthEast].append(
|
|
Contact.create( net
|
|
, self.routingGauge.getContactLayer(contactDepth)
|
|
, xTR, yBL
|
|
, self._hRailWidth
|
|
, self._vRailWidth
|
|
) )
|
|
self._corners[chip.NorthEast].append(
|
|
Contact.create( net
|
|
, self.routingGauge.getContactLayer(contactDepth)
|
|
, xTR, yTR
|
|
, self._hRailWidth
|
|
, self._vRailWidth
|
|
) )
|
|
|
|
self._southSide.doLayout()
|
|
self._northSide.doLayout()
|
|
self._westSide .doLayout()
|
|
self._eastSide .doLayout()
|
|
return
|