coriolis/cumulus/src/plugins/chip/BlockCorona.py

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