394 lines
16 KiB
Python
394 lines
16 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/PadsCorona.py" |
|
|
# +-----------------------------------------------------------------+
|
|
|
|
|
|
from operator import itemgetter
|
|
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
|
|
from Hurricane import Instance
|
|
import CRL
|
|
from CRL import RoutingLayerGauge
|
|
from helpers import ErrorMessage
|
|
from helpers import WarningMessage
|
|
import chip.Configuration
|
|
|
|
|
|
class Side ( object ):
|
|
|
|
def __init__ ( self, corona, sideType ):
|
|
self._type = sideType
|
|
self._corona = corona
|
|
self._powerContacts = []
|
|
|
|
if self._type == chip.North: self._pads = self._corona.northPads
|
|
elif self._type == chip.South: self._pads = self._corona.southPads
|
|
elif self._type == chip.East: self._pads = self._corona.eastPads
|
|
elif self._type == chip.West: self._pads = self._corona.westPads
|
|
else:
|
|
raise ErrorMessage( 1, 'PadsCorona.Side.__init__(): Invalid value for sideType (%d)' % sideType )
|
|
return
|
|
|
|
|
|
def _toGrid ( self, v ): return v - (v % DbU.fromLambda(5.0))
|
|
|
|
|
|
def getAxis ( self, i ):
|
|
if self._type == chip.North: return self._corona.chipSize.getXMax() - self._corona.padHeight + self._corona._powerRails[i][2]
|
|
elif self._type == chip.South: return self._corona.chipSize.getXMin() + self._corona.padHeight - self._corona._powerRails[i][2]
|
|
elif self._type == chip.East: return self._corona.chipSize.getYMax() - self._corona.padHeight + self._corona._powerRails[i][2]
|
|
elif self._type == chip.West: return self._corona.chipSize.getYMin() + self._corona.padHeight - self._corona._powerRails[i][2]
|
|
else:
|
|
raise ErrorMessage( 1, 'PadsCorona.Side.__init__(): Invalid value for sideType (%d)' % sideType )
|
|
return 0
|
|
|
|
|
|
def _check ( self, checkSize, checkName ):
|
|
sideName = 'unknown'
|
|
chipSize = 0
|
|
if self._type == chip.North or self._type == chip.South:
|
|
chipSize = self._corona.chipSize.getWidth()
|
|
sideName = 'wide'
|
|
elif self._type == chip.East or self._type == chip.West:
|
|
chipSize = self._corona.chipSize.getHeight()
|
|
sideName = 'tall'
|
|
|
|
if checkSize > chipSize:
|
|
print ErrorMessage( 1, [ 'Chip is not %s enought to accomodate the %s,' % (sideName,checkName)
|
|
, 'needs %dl, but only has %dl.'
|
|
% ( DbU.toLambda(checkSize), DbU.toLambda(chipSize) )
|
|
] )
|
|
return False
|
|
return True
|
|
|
|
|
|
def check ( self ):
|
|
validated = True
|
|
if self._type == chip.North:
|
|
self.validated = self._check( self._corona.coreSize.getWidth()
|
|
+ 2*self._corona.minCorona
|
|
+ 2*self._corona.padHeight
|
|
, 'core' )
|
|
checkName = 'north pads'
|
|
elif self._type == chip.East:
|
|
self.validated = self._check( self._corona.coreSize.getHeight()
|
|
+ 2*self._corona.minCorona
|
|
+ 2*self._corona.padHeight
|
|
, 'core' )
|
|
checkName = 'east pads'
|
|
elif self._type == chip.South: checkName = 'south pads'
|
|
elif self._type == chip.West: checkName = 'west pads'
|
|
|
|
validated = self._check( len(self._pads)*self._corona.padWidth
|
|
+ 2*self._corona.padHeight
|
|
, checkName ) and validated
|
|
return validated
|
|
|
|
|
|
def _createPowerContacts ( self, pad, net ):
|
|
if self._type == chip.North or self._type == chip.South:
|
|
hvDepth = self._corona.getVDepth()
|
|
elif self._type == chip.East or self._type == chip.West:
|
|
hvDepth = self._corona.getHDepth()
|
|
|
|
masterCell = pad.getMasterCell()
|
|
for component in masterCell.getNet(net.getName()).getExternalComponents():
|
|
if component.getBoundingBox().getYMin() > masterCell.getAbutmentBox().getYMin(): continue
|
|
if self._corona.routingGauge.getLayerDepth(component.getLayer()) != hvDepth: continue
|
|
if not isinstance(component,Vertical): continue
|
|
|
|
if self._type == chip.North or self._type == chip.South:
|
|
width = component.getWidth()
|
|
height = 0
|
|
else:
|
|
width = 0
|
|
height = component.getWidth()
|
|
|
|
position = Point( component.getX(), masterCell.getAbutmentBox().getYMin() )
|
|
pad.getTransformation().applyOn( position )
|
|
|
|
self._powerContacts.append( Contact.create( net
|
|
, component.getLayer()
|
|
, position.getX()
|
|
, position.getY()
|
|
, width
|
|
, height
|
|
) )
|
|
return
|
|
|
|
|
|
def _createAllPowerContacts ( self ):
|
|
for pad in self._pads:
|
|
masterCell = pad.getMasterCell()
|
|
if masterCell.getName() != 'pvddick_px' \
|
|
and masterCell.getName() != 'pvssick_px' \
|
|
and masterCell.getName() != 'pvddeck_px' \
|
|
and masterCell.getName() != 'pvsseck_px':
|
|
continue
|
|
#print 'Power pad:', pad
|
|
self._createPowerContacts( pad, self._corona.vddi )
|
|
self._createPowerContacts( pad, self._corona.vssi )
|
|
return
|
|
|
|
|
|
def _placePads ( self ):
|
|
if self._type == chip.North:
|
|
hAdvance = True
|
|
orientation = Transformation.Orientation.ID
|
|
sideLength = self._corona.chipSize.getWidth()
|
|
x = self._corona.padHeight
|
|
y = self._corona.chipSize.getHeight() - self._corona.padHeight
|
|
elif self._type == chip.South:
|
|
hAdvance = True
|
|
orientation = Transformation.Orientation.MY
|
|
sideLength = self._corona.chipSize.getWidth()
|
|
x = self._corona.padHeight
|
|
y = self._corona.padHeight
|
|
elif self._type == chip.East:
|
|
hAdvance = False
|
|
orientation = Transformation.Orientation.R3
|
|
sideLength = self._corona.chipSize.getHeight()
|
|
x = self._corona.chipSize.getWidth() - self._corona.padHeight
|
|
y = self._corona.padHeight + self._corona.padWidth
|
|
elif self._type == chip.West:
|
|
hAdvance = False
|
|
orientation = Transformation.Orientation.R1
|
|
sideLength = self._corona.chipSize.getHeight()
|
|
x = self._corona.padHeight
|
|
y = self._corona.padHeight
|
|
|
|
step = (sideLength - 2*self._corona.padHeight) / len(self._pads)
|
|
for pad in self._pads:
|
|
pad.setTransformation ( Transformation( self._toGrid(x), self._toGrid(y), orientation ) )
|
|
pad.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
|
if hAdvance: x += step
|
|
else: y += step
|
|
return
|
|
|
|
|
|
def _routePads ( self ):
|
|
for i in range(len(self._corona._powerRails)):
|
|
if self._type == chip.South:
|
|
Horizontal.create( self._corona._corners[chip.SouthWest ][i]
|
|
, self._corona._corners[chip.SouthEast][i]
|
|
, self._corona._powerRails[i][1]
|
|
, self.getAxis( i )
|
|
, self._corona._powerRails[i][3]
|
|
)
|
|
elif self._type == chip.North:
|
|
Horizontal.create( self._corona._corners[chip.NorthWest ][i]
|
|
, self._corona._corners[chip.NorthEast][i]
|
|
, self._corona._powerRails[i][1]
|
|
, self.getAxis( i )
|
|
, self._corona._powerRails[i][3]
|
|
)
|
|
elif self._type == chip.East:
|
|
Vertical.create( self._corona._corners[chip.SouthEast][i]
|
|
, self._corona._corners[chip.NorthEast ][i]
|
|
, self._corona._powerRails[i][1]
|
|
, self.getAxis( i )
|
|
, self._corona._powerRails[i][3]
|
|
)
|
|
elif self._type == chip.West:
|
|
Vertical.create( self._corona._corners[chip.SouthWest][i]
|
|
, self._corona._corners[chip.NorthWest ][i]
|
|
, self._corona._powerRails[i][1]
|
|
, self.getAxis( i )
|
|
, self._corona._powerRails[i][3]
|
|
)
|
|
return
|
|
|
|
def doLayout ( self ):
|
|
self._placePads()
|
|
self._routePads()
|
|
self._createAllPowerContacts()
|
|
return
|
|
|
|
|
|
class Corona ( chip.Configuration.Wrapper ):
|
|
|
|
def __init__ ( self, confWrapper ):
|
|
chip.Configuration.Wrapper.__init__( self, confWrapper.conf )
|
|
self.validated = False
|
|
self._northSide = Side( self, chip.North )
|
|
self._southSide = Side( self, chip.South )
|
|
self._eastSide = Side( self, chip.East )
|
|
self._westSide = Side( self, chip.West )
|
|
self._corners = { chip.SouthWest : []
|
|
, chip.SouthEast : []
|
|
, chip.NorthWest : []
|
|
, chip.NorthEast : []
|
|
}
|
|
self._powerRails = [] # [ , [net, layer, axis, width] ]
|
|
|
|
self._locatePadRails()
|
|
self._guessHvLayers()
|
|
return
|
|
|
|
@property
|
|
def southSide ( self ): return self._southSide
|
|
@property
|
|
def northSide ( self ): return self._northSide
|
|
@property
|
|
def eastSide ( self ): return self._eastSide
|
|
@property
|
|
def westSide ( self ): return self._westSide
|
|
|
|
def getSwCorner ( self, i ): return self._corners[chip.SouthWest][i]
|
|
def getSeCorner ( self, i ): return self._corners[chip.SouthEast][i]
|
|
def getNwCorner ( self, i ): return self._corners[chip.NorthWest][i]
|
|
def getNeCorner ( self, i ): return self._corners[chip.NorthEast][i]
|
|
def getRailNet ( self, i ): return self._powerRails[i][0]
|
|
def getRailLayer ( self, i ): return self._powerRails[i][1]
|
|
def getRailAxis ( self, i ): return self._powerRails[i][2]
|
|
def getRailWidth ( self, i ): return self._powerRails[i][3]
|
|
def getHDepth ( self ): return self._horizontalDepth
|
|
def getVDepth ( self ): return self._verticalDepth
|
|
|
|
|
|
def validate ( self ):
|
|
self.validated = self._northSide.check()
|
|
self.validated = self._southSide.check() and self.validated
|
|
self.validated = self._eastSide.check() and self.validated
|
|
self.validated = self._westSide.check() and self.validated
|
|
return self.validated
|
|
|
|
|
|
def _locatePadRails ( self ):
|
|
if not self.clockPad:
|
|
print ErrorMessage( 1, 'There must be at least one pad of model "pck_px" to guess the pad rails.' )
|
|
return False
|
|
|
|
for plug in self.clockPad.getPlugs():
|
|
masterNet = plug.getMasterNet()
|
|
netType = masterNet.getType()
|
|
net = plug.getNet()
|
|
|
|
if netType != Net.Type.POWER \
|
|
and netType != Net.Type.GROUND \
|
|
and netType != Net.Type.CLOCK:
|
|
continue
|
|
|
|
if not net:
|
|
net = self.cell.getNet( masterNet.getName() )
|
|
if not net:
|
|
print ErrorMessage( 1, 'Missing global net <%s> at chip level.' % masterNet.getName() )
|
|
continue
|
|
|
|
for component in masterNet.getExternalComponents():
|
|
if not isinstance(component,Horizontal): continue
|
|
xs = component.getSourcePosition().getX()
|
|
xt = component.getTargetPosition().getX()
|
|
if xs < xt: length = xt - xs
|
|
else: length = xs - xt
|
|
if length < self.padWidth*.6: continue
|
|
|
|
self._powerRails.append( [ net, component.getLayer(), component.getY(), component.getWidth() ] )
|
|
|
|
self._powerRails.sort( key=itemgetter(2) )
|
|
|
|
#for rail in self._powerRails:
|
|
# print 'Pad rail %s @%d width:%d layer:%s' % ( str(rail[0].getName())
|
|
# , DbU.toLambda(rail[2])
|
|
# , DbU.toLambda(rail[3])
|
|
# , str(rail[1].getName())
|
|
# )
|
|
return
|
|
|
|
def _guessHvLayers ( self ):
|
|
if not self.powerPad:
|
|
print ErrorMessage( 1, 'There must be at least one pad of model "pvddick_px" to guess the pad power terminals.' )
|
|
return False
|
|
|
|
availableDepths = set()
|
|
masterCell = self.powerPad.getMasterCell()
|
|
for component in masterCell.getNet('vddi').getExternalComponents():
|
|
if component.getBoundingBox().getYMin() <= masterCell.getAbutmentBox().getYMin():
|
|
availableDepths.add( self.routingGauge.getLayerDepth(component.getLayer()) )
|
|
|
|
#print 'available depth:', availableDepths
|
|
|
|
self._horizontalDepth = 0
|
|
self._verticalDepth = 0
|
|
for depth in range(0,self.topLayerDepth+1):
|
|
if not depth in availableDepths: continue
|
|
|
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Horizontal:
|
|
self._horizontalDepth = depth
|
|
if self.routingGauge.getLayerGauge(depth).getDirection() == RoutingLayerGauge.Vertical:
|
|
self._verticalDepth = depth
|
|
|
|
#print 'h:', self._horizontalDepth
|
|
#print 'v:', self._verticalDepth
|
|
return
|
|
|
|
|
|
def doLayout ( self ):
|
|
if not self.validated: return
|
|
UpdateSession.open()
|
|
self.cell.setAbutmentBox( self.chipSize )
|
|
|
|
for i in range(len(self._powerRails)):
|
|
xBL = self._westSide .getAxis(i)
|
|
yBL = self._southSide.getAxis(i)
|
|
xTR = self._eastSide .getAxis(i)
|
|
yTR = self._northSide.getAxis(i)
|
|
|
|
self._corners[chip.SouthWest].append(
|
|
Contact.create( self.getRailNet(i)
|
|
, self.getRailLayer(i)
|
|
, xBL, yBL
|
|
, self.getRailWidth(i)
|
|
, self.getRailWidth(i)
|
|
) )
|
|
self._corners[chip.NorthWest].append(
|
|
Contact.create( self.getRailNet(i)
|
|
, self.getRailLayer(i)
|
|
, xBL, yTR
|
|
, self.getRailWidth(i)
|
|
, self.getRailWidth(i)
|
|
) )
|
|
self._corners[chip.SouthEast].append(
|
|
Contact.create( self.getRailNet(i)
|
|
, self.getRailLayer(i)
|
|
, xTR, yBL
|
|
, self.getRailWidth(i)
|
|
, self.getRailWidth(i)
|
|
) )
|
|
self._corners[chip.NorthEast].append(
|
|
Contact.create( self.getRailNet(i)
|
|
, self.getRailLayer(i)
|
|
, xTR, yTR
|
|
, self.getRailWidth(i)
|
|
, self.getRailWidth(i)
|
|
) )
|
|
|
|
self._northSide.doLayout()
|
|
self._southSide.doLayout()
|
|
self._eastSide.doLayout()
|
|
self._westSide.doLayout()
|
|
|
|
UpdateSession.close()
|
|
return
|