coriolis/cumulus/src/plugins/alpha/chip/pads.py

1319 lines
66 KiB
Python

# This file is part of the Coriolis Software.
# Copyright (c) SU 2014-2020, 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@lip6.fr |
# | =============================================================== |
# | Python : "./plugins/chip/pads.py" |
# +-----------------------------------------------------------------+
from __future__ import print_function
import sys
import re
from operator import itemgetter
from Hurricane import DbU, Point, Transformation, Interval, Box, \
Path, Occurrence, UpdateSession, Layer, \
BasicLayer, Net, Pin, Contact, Segment, \
Horizontal, Vertical, Diagonal, RoutingPad, \
Instance, DataBase
import CRL
from CRL import RoutingGauge, RoutingLayerGauge
import helpers
from helpers import trace, l, u, n, onFGrid
from helpers.io import ErrorMessage, WarningMessage
from helpers.overlay import UpdateSession
import plugins.alpha.chip
from plugins.alpha.block.bigvia import BigVia
plugins.alpha.chip.importConstants( globals() )
# --------------------------------------------------------------------
# Class : "pads.Corner"
class Corner ( object ):
def __init__ ( self, corona, cornerType ):
self.type = cornerType
self.corona = corona
self.padCorner = None
@property
def conf ( self ): return self.corona.conf
def _getPoints ( self, axis ):
"""
Compute the various coordinates to draw the corner for a wire
positioned at ``axis`` distance from the *border* of the chip.
xExtend and yExtend are used only in case of 45 degree corners,
the 0.5 ratio is an approximate of ``sqrt(2) - 1``.
"""
if self.type == SouthWest:
xCorner = self.conf.chipAb.getXMin() + axis
yCorner = self.conf.chipAb.getYMin() + axis
xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight
xExtend = - onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) )
yExtend = xExtend
elif self.type == SouthEast:
xCorner = self.conf.chipAb.getXMax() - axis
yCorner = self.conf.chipAb.getYMin() + axis
xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight
xExtend = onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) )
yExtend = - xExtend
elif self.type == NorthEast:
xCorner = self.conf.chipAb.getXMax() - axis
yCorner = self.conf.chipAb.getYMax() - axis
xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight
xExtend = onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) )
yExtend = xExtend
elif self.type == NorthWest:
xCorner = self.conf.chipAb.getXMin() + axis
yCorner = self.conf.chipAb.getYMax() - axis
xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight
xExtend = - onFGrid( long( 0.5 * float(self.conf.ioPadHeight - axis) ) )
yExtend = - xExtend
return xCorner, yCorner, xBb, yBb, xExtend, yExtend
def _createCorner ( self ):
self.corona.conf.cfg.chip.use45corners = None
for rail in self.corona.padRails:
net = rail[0]
layer = rail[1]
axis = rail[2]
width = rail[3]
xCorner, yCorner, xBb, yBb, xExtend, yExtend = self._getPoints( axis )
if self.corona.conf.cfg.chip.use45corners:
Diagonal.create( net, layer, Point(xBb+xExtend,yCorner), Point(xCorner,yBb+yExtend), width )
Horizontal.create( net, layer, yCorner, width, xBb+xExtend, xBb )
Vertical .create( net, layer, xCorner, width, yBb+yExtend, yBb )
else:
Contact .create( net, layer, xCorner, yCorner, width, width )
Horizontal.create( net, layer, yCorner, width, xCorner, xBb )
Vertical .create( net, layer, xCorner, width, yCorner, yBb )
def _getTransformation ( self ):
if self.type == SouthWest:
name = 'padcorner_sw'
x = self.conf.chipAb.getXMin()
y = self.conf.chipAb.getYMin()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.ID
else:
orientation = Transformation.Orientation.R1
x += self.padCorner.getAbutmentBox().getWidth()
elif self.type == SouthEast:
name = 'padcorner_se'
x = self.conf.chipAb.getXMax()
y = self.conf.chipAb.getYMin()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R1
else:
orientation = Transformation.Orientation.R2
x += self.padCorner.getAbutmentBox().getWidth()
y += self.padCorner.getAbutmentBox().getHeight()
elif self.type == NorthEast:
name = 'padcorner_ne'
x = self.conf.chipAb.getXMax()
y = self.conf.chipAb.getYMax()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R2
else:
orientation = Transformation.Orientation.R3
x -= self.padCorner.getAbutmentBox().getwidth()
y -= self.padCorner.getAbutmentBox().getHeight()
elif self.type == NorthWest:
name = 'padcorner_nw'
x = self.conf.chipAb.getXMin()
y = self.conf.chipAb.getYMax()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R3
else:
orientation = Transformation.Orientation.ID
y -= self.padCorner.getAbutmentBox().getHeight()
return name, Transformation( x, y, orientation )
def _instanciateCorner ( self ):
name, transformation = self._getTransformation()
corner = Instance.create( self.conf.cell
, name, self.corona.padCorner
, transformation
, Instance.PlacementStatus.FIXED
)
def doLayout ( self ):
if self.corona.padCorner: self._instanciateCorner()
else: self._createCorner()
# --------------------------------------------------------------------
# Class : "pads.Side"
class Side ( object ):
def __init__ ( self, corona, sideType ):
self.type = sideType
self.corona = corona
self.pins = []
self.u = self.conf.ioPadHeight
self.spacerCount = 0
self.gap = 0
self.coreWires = []
if self.type == North:
self.pads = self.corona.northPads
self.sideName = 'north'
self.sideLength = self.conf.chipAb.getWidth()
elif self.type == South:
self.pads = self.corona.southPads
self.sideName = 'south'
self.sideLength = self.conf.chipAb.getWidth()
elif self.type == East:
self.pads = self.corona.eastPads
self.sideName = 'east'
self.sideLength = self.conf.chipAb.getHeight()
elif self.type == West:
self.pads = self.corona.westPads
self.sideName = 'west'
self.sideLength = self.conf.chipAb.getHeight()
else:
raise ErrorMessage( 1, 'Pads.Side.__init__(): Invalid value for sideType ({})'.format(sideType))
self.spacerNames = 'padspacer_' + self.sideName + '_%d'
@property
def conf ( self ): return self.corona.conf
def toGrid ( self, u ): return self.corona.toGrid( u )
def getAxis ( self, i ):
if self.type == North: return self.conf.chipAb.getYMax() - self.conf.ioPadHeight + self.corona.powerRails[i][2]
elif self.type == South: return self.conf.chipAb.getYMin() + self.conf.ioPadHeight - self.corona.powerRails[i][2]
elif self.type == East: return self.conf.chipAb.getXMax() - self.conf.ioPadHeight + self.corona.powerRails[i][2]
elif self.type == West: return self.conf.chipAb.getXMin() + self.conf.ioPadHeight - self.corona.powerRails[i][2]
else:
raise ErrorMessage( 1, 'Pads.Side.__init__(): Invalid value for sideType ({})'.format(sideType))
return 0
def hasPad ( self, padInstance ):
for pad in self.pads:
if pad[1] == padInstance:
return True
return False
def addCoreWire ( self, coreWire ):
self.coreWires.append( coreWire )
return
def updateGap ( self, gapWidth ):
self.gap = max( self.gap, gapWidth )
return
def _check ( self, checkSize, checkName ):
sideName = 'unknown'
chipSize = 0
if self.type == North or self.type == South:
chipSize = self.conf.chipAb.getWidth()
sideName = 'wide'
elif self.type == East or self.type == West:
chipSize = self.conf.chipAb.getHeight()
sideName = 'tall'
if checkSize > chipSize:
sliceHeight = self.conf.sliceHeight
if checkSize % sliceHeight != 0:
checkSize += sliceHeight - (checkSize % sliceHeight)
raise ErrorMessage( 1, [ 'Chip is not {} enought to accomodate the {},' \
.format(sideName,checkName)
, 'needs {}, but only has {}.' \
.format( DbU.getValueString(checkSize), DbU.getValueString(chipSize) )
] )
return False
return True
def check ( self ):
self.validated = True
if self.type == North:
self.conf.validated = self._check \
( self.conf.coronaAb.getWidth() + 2*self.conf.ioPadHeight, 'core' )
checkName = 'north pads'
elif self.type == East:
self.conf.validated = self._check \
( self.conf.coronaAb.getHeight() + 2*self.conf.ioPadHeight, 'core' )
checkName = 'east pads'
elif self.type == South: checkName = 'south pads'
elif self.type == West: checkName = 'west pads'
padLength = 2*self.conf.ioPadHeight
for pad in self.pads:
padLength += pad[1].getMasterCell().getAbutmentBox().getWidth()
self.conf.validated = self._check( padLength, checkName ) and self.conf.validated
return self.conf.validated
def _fillPadSpacing ( self, gapWidth ):
def _getWidth ( spacer ): return spacer.getAbutmentBox().getWidth()
def _nextSpacer ( iPadSpacer ):
while iPadSpacer < len(self.corona.padSpacers) \
and gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
iPadSpacer += 1
return iPadSpacer
if not self.corona.padSpacers:
self.u += gapWidth
return
iPadSpacer = 0
iPadSpacer = _nextSpacer( iPadSpacer )
while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0:
gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] )
spacer = Instance.create( self.conf.cell
, self.spacerNames % self.spacerCount
, self.corona.padSpacers[iPadSpacer])
self.spacerCount += 1
self._placePad( spacer )
if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
iPadSpacer = _nextSpacer( iPadSpacer )
if gapWidth != 0:
raise ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \
.format(self.sideName,DbU.getValueString(gapWidth)) )
self.u += gapWidth
def _placePad ( self, padInstance ):
if self.type == North:
x = self.conf.chipAb.getXMin() + self.u
y = self.conf.chipAb.getYMax()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.MY
else:
orientation = Transformation.Orientation.ID
y -= self.conf.ioPadHeight
x = self.toGrid( x )
elif self.type == South:
x = self.conf.chipAb.getXMin() + self.u
y = self.conf.chipAb.getYMin()
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.ID
else:
orientation = Transformation.Orientation.MY
y += self.conf.ioPadHeight
x = self.toGrid( x )
elif self.type == West:
x = self.conf.chipAb.getXMin()
y = self.conf.chipAb.getYMin() + self.u
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R3
y += padInstance.getMasterCell().getAbutmentBox().getWidth()
else:
orientation = Transformation.Orientation.R1
x += padInstance.getMasterCell().getAbutmentBox().getHeight()
y = self.toGrid( y )
elif self.type == East:
x = self.conf.chipAb.getXMax()
y = self.conf.chipAb.getYMin() + self.u
if self.corona.padOrient == Transformation.Orientation.ID:
orientation = Transformation.Orientation.R1
else:
orientation = Transformation.Orientation.R3
x -= padInstance.getMasterCell().getAbutmentBox().getHeight()
y += padInstance.getMasterCell().getAbutmentBox().getWidth()
y = self.toGrid( y )
padInstance.setTransformation ( Transformation( x, y, orientation ) )
padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED )
self.u += padInstance.getMasterCell().getAbutmentBox().getWidth()
p = None
if self.conf.ioPadGauge.getName() == 'pxlib':
p = re.compile( r'p(?P<power>v[sd]{2}[ei])ck_px' )
if self.conf.ioPadGauge.getName().startswith('phlib'):
p = re.compile( r'p(?P<power>v[sd]{2})ck2_sp' )
if self.conf.ioPadGauge.getName() == 'niolib':
p = re.compile( r'(?P<power>(io)?v[sd]{2})' )
if p:
m = p.match( padInstance.getMasterCell().getName() )
padName = 'pad'
if m: padName = m.group( 'power' )
padNet = padInstance.getMasterCell().getNet( padName )
trace( 550, '\tpadName:{} padNet:{}\n'.format(padName,padNet) )
if padNet:
plug = padInstance.getPlug( padNet )
chipNet = plug.getNet()
if not chipNet and padNet.isGlobal():
chipNet = padInstance.getCell().getNet( padNet.getName() )
if chipNet:
rp = RoutingPad.create( chipNet, Occurrence(plug), RoutingPad.BiggestArea )
return
def _placePads ( self ):
padLength = 0
for pad in self.pads: padLength += pad[1].getMasterCell().getAbutmentBox().getWidth()
padSpacing = (self.sideLength - 2*self.conf.ioPadHeight - padLength) / (len(self.pads) + 1)
if self.conf.padsHavePosition:
position = self.u
for pad in self.pads:
trace( 550, '\tPlace pad {} @{}\n'.format(pad[1],DbU.getValueString(pad[0])) )
if pad[0] < position:
pad[0] = position
trace( 550, '\tShift position @{}\n'.format(DbU.getValueString(pad[0])) )
pad[0] = self.toGrid( pad[0] )
position = pad[0] + pad[1].getMasterCell().getAbutmentBox().getWidth()
else:
spacing = 0
minSpacing = self.corona.minPadSpacing
position = self.u
for i in range(len(self.pads)):
spacing += padSpacing
nextPosition = self.toGrid( position + spacing )
if nextPosition - position >= minSpacing:
position += spacing
spacing = 0
self.pads[i][0] = self.toGrid( position )
position += self.pads[i][1].getMasterCell().getAbutmentBox().getWidth()
for pad in self.pads:
self._fillPadSpacing( pad[0] - self.u )
self._placePad( pad[1] )
self._fillPadSpacing( self.sideLength - self.conf.ioPadHeight - self.u )
def _getUMin ( self, box ):
if self.type == North or self.type == South:
return box.getXMin()
return box.getYMin()
def _getUMax ( self, box ):
if self.type == North or self.type == South:
return box.getXMax()
return box.getYMax()
def _createSegment ( self, rail, uMin, uMax ):
net, layer, axis, width = rail
if self.conf.ioPadGauge.getName() == 'pxlib':
if net.isClock():
uMin -= DbU.fromLambda(5.0)
uMax += DbU.fromLambda(5.0)
else:
uMin -= width/2
uMax += width/2
if self.type == North or self.type == South:
if self.type == North:
axis = self.conf.chipAb.getYMax() - axis
Horizontal.create( net, layer, axis, width, uMin, uMax )
else:
if self.type == East:
axis = self.conf.chipAb.getXMax() - axis
Vertical.create( net, layer, axis, width, uMin, uMax )
def _routePads ( self ):
if self.type == South or self.type == North:
startCorner = self.conf.chipAb.getXMin()
stopCorner = self.conf.chipAb.getXMax()
elif self.type == West or self.type == East:
startCorner = self.conf.chipAb.getYMin()
stopCorner = self.conf.chipAb.getYMax()
else:
return
startCorner += self.conf.ioPadHeight
stopCorner -= self.conf.ioPadHeight
if len(self.pads) == 0:
return
padAb = self.conf.getInstanceAb( self.pads[0][1] )
for irail in range(len(self.corona.padRails)):
self._createSegment( self.corona.padRails[ irail ]
, startCorner
, self._getUMin(padAb) )
padAb = self.conf.getInstanceAb( self.pads[-1][1] )
for irail in range(len(self.corona.padRails)):
self._createSegment( self.corona.padRails[ irail ]
, self._getUMax(padAb)
, stopCorner )
for i in range(len(self.pads)-1):
padAb1 = self.conf.getInstanceAb( self.pads[i ][1] )
padAb2 = self.conf.getInstanceAb( self.pads[i+1][1] )
for rail in self.corona.padRails:
self._createSegment( rail, self._getUMax(padAb1), self._getUMin(padAb2) )
def doLayout ( self ):
self._placePads()
if not self.corona.padSpacers:
self._routePads()
def drawCoreWires ( self ):
trace( 550, ',+', '\tSide.drawCoreWire()\n' )
if self.type == West or self.type == East:
trace( 550, '\tSort East/West\n' )
self.coreWires.sort( key=lambda wire: wire.bbSegment.getCenter().getY() )
if self.type == North or self.type == South:
trace( 550, '\tSort North/South\n' )
self.coreWires.sort( key=lambda wire: wire.bbSegment.getCenter().getX() )
for wire in self.coreWires:
wire.updateInCorona()
size = len(self.coreWires)
offset = 0
for i in range(size):
if self.coreWires[i].inCoronaRange: break
offset += 1
for i in range(offset):
self.coreWires[i].setOffset( i+1, CoreWire.AtBegin )
offset = 0
for i in range(1,size+1):
if self.coreWires[-i].inCoronaRange: break
offset += 1
for i in range(offset):
self.coreWires[ -(offset+1) ].setOffset( i+1, CoreWire.AtEnd )
for wire in self.coreWires:
if self.type == West or self.type == East:
trace( 550, '\t| %s %s %d %s inRange:%s\n' % ( wire.chipNet.getName()
, DbU.getValueString(wire.bbSegment.getCenter().getY())
, wire.count
, wire.padSegment.getLayer()
, wire.inCoronaRange ) )
if self.type == North or self.type == South:
trace( 550, '\t| %s %s %d %s inRange:%s\n' % ( wire.chipNet.getName()
, DbU.getValueString(wire.bbSegment.getCenter().getX())
, wire.count
, wire.padSegment.getLayer()
, wire.inCoronaRange ) )
wire.drawWire()
trace( 550, '-' )
# --------------------------------------------------------------------
# Class : "pads.CoreWire"
class CoreWire ( object ):
# Should be read from the symbolic technology rules.
NoOffset = 0x0000
AtBegin = 0x0001
AtEnd = 0x0002
def __init__ ( self, corona, chipNet, padSegment, bbSegment, side, preferredDir, count ):
self.corona = corona
self.chipNet = chipNet
self.padSegment = padSegment
self.bbSegment = bbSegment
self.offset = 0
self.offsetType = CoreWire.NoOffset
self.side = side
self.preferredDir = preferredDir
self.inCoronaRange = True
self.arraySize = None
self.count = count
self.viaPitch = DbU.fromLambda( 4.0 )
self.gapWidth = 0
self._computeCoreLayers()
@property
def conf ( self ): return self.corona.conf
def updateInCorona ( self ):
coronaAb = self.conf.getInstanceAb( self.conf.icorona )
if self.side == South or self.side == North:
xCoronaPin = self.bbSegment.getCenter().getX()
if xCoronaPin <= coronaAb.getXMin(): self.inCoronaRange = False
elif xCoronaPin >= coronaAb.getXMax(): self.inCoronaRange = False
if self.side == East or self.side == West:
yCoronaPin = self.bbSegment.getCenter().getY()
if yCoronaPin <= coronaAb.getYMin(): self.inCoronaRange = False
elif yCoronaPin >= coronaAb.getYMax(): self.inCoronaRange = False
def setOffset ( self, offset, offsetType ):
self.offset = offset
self.offsetType = offsetType
def _computeCoreLayers ( self ):
rg = self.conf.routingGauge
mask = self.padSegment.getLayer().getMask()
trace( 550, ',+', '\tCoreWire._computeCoreLayers()\n' )
trace( 550, '\tbbSegment: {}\n'.format(self.bbSegment) )
self.symSegmentLayer = None
for layerGauge in rg.getLayerGauges():
if layerGauge.getDepth() > self.conf.topLayerDepth: break
if layerGauge.getLayer().getMask() == mask:
self.symSegmentLayer = layerGauge.getLayer()
if self.preferredDir:
self.symContactLayer = self.symSegmentLayer
if self.side & (West|East):
self.symContactSize = ( layerGauge.getWireWidth(), self.bbSegment.getHeight() )
else:
self.symContactSize = ( self.bbSegment.getWidth(), layerGauge.getWireWidth() )
else:
depth = layerGauge.getDepth()
if layerGauge.getDepth() + 1 > self.conf.topLayerDepth:
self.symSegmentLayer = rg.getLayerGauge( depth-1 ).getLayer()
depth -= 1
else:
self.symSegmentLayer = rg.getLayerGauge( depth+1 ).getLayer()
self.symContactLayer = rg.getContactLayer( depth )
if self.side & (West|East):
self.symContactSize = ( self.bbSegment.getHeight(), self.bbSegment.getHeight() )
else:
self.symContactSize = ( self.bbSegment.getWidth(), self.bbSegment.getWidth() )
self.viaPitch = self.conf.getViaPitch( self.symContactLayer )
basicLayer = self.symSegmentLayer
if basicLayer.isSymbolic():
basicLayer = basicLayer.getBasicLayer()
contactMinSize = 2*self.symContactLayer.getEnclosure( basicLayer
, Layer.EnclosureH|Layer.EnclosureV ) \
+ self.symContactLayer.getMinimalSize()
arrayWidth = self.symContactSize[0]
arrayCount = (arrayWidth - contactMinSize) / self.viaPitch
trace( 550, '\tcontactMinSize: {}, arrayWidth: {}, arrayCount: {}\n' \
.format(DbU.getValueString(contactMinSize),DbU.getValueString(arrayWidth),arrayCount) )
if arrayCount < 0: arrayCount = 0
#if arrayCount < 3:
if self.side & (North|South):
self.arraySize = ( arrayCount+1, 2 )
else:
self.arraySize = ( 2, arrayCount+1 )
trace( 550, '\tarraySize = ({},{})\n'.format(self.arraySize[0], self.arraySize[1]) )
self.gapWidth = 4*self.viaPitch
trace( 550, ',-' )
return
raise ErrorMessage( 1, 'CoreWire._computeCoreLayers(): Layer of IO pad segment "%s" is not in routing gauge.' \
.format(self.chipNet.getName()) )
trace( 550, ',-' )
def drawWire ( self ):
trace( 550, ',+', '\tCoreWire.drawWire(): chip:"{}"\n'.format(self.chipNet.getName()) )
coronaAb = self.conf.getInstanceAb( self.conf.icorona )
self._computeCoreLayers()
padLayer = self.padSegment.getLayer()
if not isinstance(padLayer,BasicLayer):
padLayer = padLayer.getBasicLayer()
if self.side == West or self.side == East:
flags = OnHorizontalPitch
hPitch = self.conf.getPitch( self.symSegmentLayer )
vPitch = self.conf.getPitch( self.padSegment.getLayer() )
yCore = self.conf.toCoronaPitchInChip( self.bbSegment.getCenter().getY(), self.symSegmentLayer )
if self.offset:
if self.offsetType == CoreWire.AtBegin:
yCore += 2*hPitch*self.offset
else:
yCore -= 2*hPitch*self.offset
if self.side == West:
accessDirection = Pin.Direction.WEST
xPadMin = self.bbSegment.getXMin()
xContact = self.corona.coreSymBb.getXMin() - self.offset * 2*vPitch
xPadMax = xContact
xCore = coronaAb.getXMin()
if not self.preferredDir:
#xPadMax += self.bbSegment.getHeight()/2
xPadMin += 3*vPitch
else:
accessDirection = Pin.Direction.EAST
xPadMax = self.bbSegment.getXMax()
xContact = self.corona.coreSymBb.getXMax() + self.offset * 2*vPitch
xPadMin = xContact
xCore = coronaAb.getXMax()
if not self.preferredDir:
#xPadMin -= self.bbSegment.getHeight()/2
xPadMin -= 3*vPitch
hReal = Horizontal.create( self.chipNet
, self.padSegment.getLayer()
, self.bbSegment.getCenter().getY()
, self.bbSegment.getHeight()
, xPadMin
, xPadMax
)
trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) )
if self.arraySize:
contacts = self.conf.coronaContactArray( self.chipNet
, self.symContactLayer
, xContact
, yCore
, self.arraySize
, flags
)
vStrapBb = Box()
for contact in contacts:
vStrapBb.merge( contact.getBoundingBox() )
else:
contact = self.conf.coronaContact( self.chipNet
, self.symContactLayer
, xContact
, yCore
, self.symContactSize[0]
, self.symContactSize[1]
, flags
)
vStrapBb = contact.getBoundingBox( padLayer )
hRealBb = hReal.getBoundingBox( padLayer )
self.conf.icorona.getTransformation().applyOn( vStrapBb )
vStrapBb.merge( vStrapBb.getXMin(), hRealBb.getYMin() )
vStrapBb.merge( vStrapBb.getXMin(), hRealBb.getYMax() )
if self.padSegment.getLayer().isSymbolic():
vStrapBb.inflate( 0, -self.padSegment.getLayer().getExtentionCap()
, 0, -self.padSegment.getLayer().getExtentionCap() )
Vertical.create( self.chipNet
, self.padSegment.getLayer()
, vStrapBb.getCenter().getX()
, vStrapBb.getWidth()
, vStrapBb.getYMin()
, vStrapBb.getYMax()
)
if self.arraySize:
if self.side == West: xContact = min( xContact, vStrapBb.getXMin() )
else: xContact = max( xContact, vStrapBb.getXMax() )
self.conf.coronaHorizontal( self.chipNet
, self.symSegmentLayer
, yCore
, self.bbSegment.getHeight()
, xContact
, xCore
)
trace( 550, '\tCORONA PIN: {} {}\n'.format(self.chipNet, self.count) )
pin = self.conf.coronaPin( self.chipNet
, self.count
, accessDirection
, self.symSegmentLayer
, xCore
, yCore
, DbU.fromLambda( 1.0 )
, self.bbSegment.getHeight()
)
else:
flags = OnVerticalPitch
hPitch = self.conf.getPitch( self.padSegment.getLayer() )
vPitch = self.conf.getPitch( self.symSegmentLayer )
trace( 550, '\t%s translated of %s\n' % (self.symSegmentLayer, DbU.getValueString( 2*vPitch*self.offset )) )
xCore = self.conf.toCoronaPitchInChip( self.bbSegment.getCenter().getX(), self.symSegmentLayer )
if self.offset:
if self.offsetType == CoreWire.AtBegin:
xCore += 2*vPitch*self.offset
else:
xCore -= 2*vPitch*self.offset
if self.side == South:
accessDirection = Pin.Direction.SOUTH
yPadMin = self.bbSegment.getYMin()
yPadMax = self.corona.coreSymBb.getYMin() - self.offset * 2*hPitch
yContact = yPadMax
yCore = coronaAb.getYMin()
#if not self.preferredDir:
# yPadMax += self.bbSegment.getWidth()/2
# yPadMin += 3*hPitch
else:
accessDirection = Pin.Direction.NORTH
yPadMax = self.bbSegment.getYMax()
yPadMin = self.corona.coreSymBb.getYMax() + self.offset * 2*hPitch
yContact = yPadMin
yCore = coronaAb.getYMax()
#if not self.preferredDir:
# yPadMin -= self.bbSegment.getWidth()/2
# yPadMin -= 3*hPitch
vReal = Vertical.create( self.chipNet
, self.padSegment.getLayer()
, self.bbSegment.getCenter().getX()
, self.bbSegment.getWidth()
, yPadMin
, yPadMax
)
trace( 550, '\tself.arraySize: %s\n' % str(self.arraySize) )
if self.arraySize:
contacts = self.conf.coronaContactArray( self.chipNet
, self.symContactLayer
, xCore
, yContact
, self.arraySize
, flags
)
hStrapBb = Box()
for contact in contacts:
hStrapBb.merge( contact.getBoundingBox() )
else:
contact = self.conf.coronaContact( self.chipNet
, self.symContactLayer
, self.bbSegment.getCenter().getX()
, yContact
, self.symContactSize[0]
, self.symContactSize[1]
, flags
)
hStrapBb = contact.getBoundingBox( padLayer )
vRealBb = vReal.getBoundingBox()
self.conf.icorona.getTransformation().applyOn( hStrapBb )
hStrapBb.merge( vRealBb.getXMin(), hStrapBb.getYMin() )
hStrapBb.merge( vRealBb.getXMax(), hStrapBb.getYMin() )
if self.padSegment.getLayer().isSymbolic():
hStrapBb.inflate( -self.padSegment.getLayer().getExtentionCap(), 0
, -self.padSegment.getLayer().getExtentionCap(), 0 )
Horizontal.create( self.chipNet
, self.padSegment.getLayer()
, hStrapBb.getCenter().getY()
, hStrapBb.getHeight()
, hStrapBb.getXMin()
, hStrapBb.getXMax()
)
if self.arraySize:
if self.side == South: yContact = min( yContact, hStrapBb.getYMin() )
else: yContact = max( yContact, hStrapBb.getYMax() )
trace( 550, '\txCore: {:.1f}L {}\n'.format(DbU.toLambda(xCore), DbU.getValueString(xCore)) )
self.conf.coronaVertical( self.chipNet
, self.symSegmentLayer
, xCore
, self.bbSegment.getWidth()
, yContact
, yCore
)
pin = self.conf.coronaPin( self.chipNet
, self.count
, accessDirection
, self.symSegmentLayer
, xCore
, yCore
, self.bbSegment.getWidth()
, DbU.fromLambda( 1.0 )
)
if self.side & North: self.corona.northSide.pins.append( pin )
if self.side & South: self.corona.southSide.pins.append( pin )
if self.side & East : self.corona.eastSide .pins.append( pin )
if self.side & West : self.corona.westSide .pins.append( pin )
trace( 550, '-' )
# --------------------------------------------------------------------
# Class : "pads.Corona"
class Corona ( object ):
def __init__ ( self, chip ):
def _cmpPad ( pad1, pad2):
width1 = pad1.getAbutmentBox().getWidth()
width2 = pad2.getAbutmentBox().getWidth()
if width1 == width2: return 0
if width1 > width2: return -1
return 1
def _dupPads ( padsConf ):
duplicateds = []
for ioPadConf in padsConf:
for padInstance in ioPadConf.pads:
position = 0 if ioPadConf.position is None else ioPadConf.position
duplicateds.append( [ position, padInstance ] )
return duplicateds
self.chip = chip
self.conf.validated = False
self.northPads = _dupPads( self.conf.chipConf.northPads )
self.southPads = _dupPads( self.conf.chipConf.southPads )
self.eastPads = _dupPads( self.conf.chipConf.eastPads )
self.westPads = _dupPads( self.conf.chipConf.westPads )
self.northSide = Side( self, North )
self.southSide = Side( self, South )
self.eastSide = Side( self, East )
self.westSide = Side( self, West )
self.corners = { SouthWest : Corner( self, SouthWest )
, SouthEast : Corner( self, SouthEast )
, NorthWest : Corner( self, NorthWest )
, NorthEast : Corner( self, NorthEast )
}
self.padLib = None
self.padOrient = Transformation.Orientation.ID
self.padSpacers = []
self.padCorner = []
self.padRails = [] # [ , [net, layer, axis, width] ]
self.powerCount = 0
self.conf.cfg.chip.padCoreSide = None
if self.conf.cfg.chip.padCoreSide.lower() == 'south':
self.padOrient = Transformation.Orientation.MY
trace( 550, '\tchip.padCoreSide: {}\n'.format(self.conf.cfg.chip.padCoreSide) )
self._allPadsAnalysis()
self.conf.cfg.chip.minPadSpacing = None
self.conf.cfg.chip.padSpacers = None
self.conf.cfg.chip.padCorner = None
if self.conf.cfg.chip.padSpacers is not None:
for spacerName in self.conf.cfg.chip.padSpacers.split(','):
spacerCell = self.padLib.getCell( spacerName )
if spacerCell: self.padSpacers.append( spacerCell )
else:
raise ErrorMessage( 1, 'Corona.__init__(): Missing spacer cell "{}"'.format(spacerName) )
self.padSpacers.sort( _cmpPad )
if self.conf.cfg.chip.padCorner is not None:
self.padCorner = self.padLib.getCell( self.conf.cfg.chip.padCorner )
if self.conf.cfg.chip.minPadSpacing is None:
self.conf.cfg.chip.minPadSpacing = 0
@property
def conf ( self ): return self.chip.conf
@property
def supplyRailWidth ( self ): return self.conf.cfg.chip.supplyRailWidth
@property
def supplyRailPitch ( self ): return self.conf.cfg.chip.supplyRailPitch
@property
def minPadSpacing ( self ): return self.conf.cfg.chip.minPadSpacing
def toGrid ( self, u ): return u - (u % self.conf.ioPadPitch)
def validate ( self ):
self._allPadsAnalysis()
self.conf.validated = self.northSide.check()
self.conf.validated = self.southSide.check() and self.conf.validated
self.conf.validated = self.eastSide.check() and self.conf.validated
self.conf.validated = self.westSide.check() and self.conf.validated
return self.conf.validated
def hasNorthPad ( self, padInstance ): return self.northSide.hasPad(padInstance)
def hasSouthPad ( self, padInstance ): return self.southSide.hasPad(padInstance)
def hasEastPad ( self, padInstance ): return self.eastSide.hasPad(padInstance)
def hasWestPad ( self, padInstance ): return self.westSide.hasPad(padInstance)
def hasPad ( self, padInstance ):
if self.hasNorthPad(padInstance): return True
if self.hasSouthPad(padInstance): return True
if self.hasEastPad (padInstance): return True
if self.hasWestPad (padInstance): return True
return False
def _allPadsAnalysis ( self ):
for pad in self.southPads:
self._padAnalysis( pad[1] )
if self.padRails: return
for pad in self.northPads:
self._padAnalysis( pad[1] )
if self.padRails: return
for pad in self.eastPads:
self._padAnalysis( pad[1] )
if self.padRails: return
for pad in self.westPads:
self._padAnalysis( pad[1] )
if self.padRails: return
def _padAnalysis ( self, padInstance ):
if self.padRails: return
padCell = padInstance.getMasterCell()
ab = padCell.getAbutmentBox()
if not self.padLib: self.padLib = padCell.getLibrary()
for plug in padInstance.getPlugs():
for component in plug.getMasterNet().getComponents():
if component is None: continue
bb = component.getBoundingBox()
hspan = Interval( bb.getXMin(), bb.getXMax() )
axis = bb.getCenter().getY()
if isinstance(component,Horizontal):
width = component.getWidth()
elif isinstance(component,Vertical):
width = bb.getHeight()
else:
continue
# Specific hack for Alliance pxlib pad library.
if self.conf.ioPadGauge.getName() == 'pxlib':
if isinstance(component,Vertical):
continue
if plug.getMasterNet().isClock():
hspan.inflate( DbU.fromLambda(5.0) )
else:
hspan.inflate( component.getWidth() / 2 )
if hspan.contains( ab.getXMin() ) or hspan.contains( ab.getXMax() ):
duplicate = False
if self.padOrient == Transformation.Orientation.ID:
pass
else:
axis = self.conf.ioPadHeight - axis
for rail in self.padRails:
if rail[0] == plug.getNet() \
and rail[1] == component.getLayer() \
and rail[2] == axis:
duplicate = True
break
if not duplicate:
net = plug.getNet()
if not net:
if plug.getMasterNet().isGlobal():
net = self.conf.cell.getNet( plug.getMasterNet().getName() )
if not net:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \
% plug.getMasterNet().getName(), padCell.getName() )
else:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \
% plug.getMasterNet().getName(), padCell.getName() )
if net:
self.padRails.append( ( net
, component.getLayer()
, axis
, width ) )
def _createCoreWire ( self, chipIntNet, padNet, padInstance, count ):
trace( 550, ',+', '\tCorona._createCoreWire()\n' )
trace( 550, '\tchipIntNet:{}\n'.format(chipIntNet) )
trace( 550, '\tpadNet:{}\n'.format(padNet) )
trace( 550, '\tpadInstance:{}\n'.format(padInstance) )
side = None
if self.hasSouthPad(padInstance): side = self.southSide
elif self.hasNorthPad(padInstance): side = self.northSide
elif self.hasEastPad (padInstance): side = self.eastSide
elif self.hasWestPad (padInstance): side = self.westSide
if not side:
trace( 550, '-' )
return count
if chipIntNet.isPower() and not padInstance.getName().startswith('p_vdd'):
trace( 550, '-' )
return count
if chipIntNet.isGround() and not padInstance.getName().startswith('p_vss'):
trace( 550, '-' )
return count
innerBb = self.conf.chip.getAbutmentBox().inflate( -self.conf.ioPadHeight )
rg = self.conf.routingGauge
hsegments = {}
vsegments = {}
trace( 550, '\tinnerBb: {}\n'.format(innerBb) )
for component in padNet.getExternalComponents():
if isinstance(component,Segment) or isinstance(component,Contact):
bb = component.getBoundingBox()
padInstance.getTransformation().applyOn( bb )
trace( 550, '\t| External:{} bb:{}\n'.format(component,bb) )
if self.conf.routingGauge.hasPowerSupply():
if chipIntNet.isPower() or chipIntNet.isGround():
trace( 550, '\t| Skipped, pads uses distributed power terminals.\n' )
continue
if self.conf.chipConf.ioPadGauge == 'LibreSOCIO':
if chipIntNet.isPower() or chipIntNet.isGround():
if side.type == North or side.type == South:
#bb.inflate( -u(0.6), 0 )
if bb.getWidth() > u(35.0):
bb.inflate( (u(34.0) - bb.getWidth()) / 2, 0 )
else:
#bb.inflate( 0, -u(0.6) )
if bb.getHeight() > u(35.0):
bb.inflate( 0, (u(34.0) - bb.getHeight()) / 2 )
if bb.intersect(innerBb):
trace( 550, '\t| Accepted.\n' )
lg = rg.getLayerGauge( component.getLayer() )
depth = lg.getDepth()
if depth > self.conf.topLayerDepth: continue
if lg.getDirection() == RoutingLayerGauge.Vertical:
if not vsegments.has_key(depth): vsegments[ depth ] = []
vsegments[ depth ].append( (component,bb) )
else:
if not hsegments.has_key(depth): hsegments[ depth ] = []
hsegments[ depth ].append( (component,bb) )
gapWidth = 0
segments = None
inPreferredDir = False
if side.type == North or side.type == South:
if len(vsegments):
inPreferredDir = True
segments = vsegments[ min(vsegments.keys()) ]
elif len(hsegments):
segments = hsegments[ min(hsegments.keys()) ]
else:
if len(hsegments):
inPreferredDir = True
segments = hsegments[ min(hsegments.keys()) ]
elif len(vsegments):
segments = vsegments[ min(vsegments.keys()) ]
coreWires = []
if segments:
for segment, bb in segments:
side.addCoreWire( CoreWire( self, chipIntNet, segment, bb, side.type, inPreferredDir, count ) )
side.updateGap( side.coreWires[-1].gapWidth )
#if not inPreferredDir:
# if side.type == North or side.type == South:
# trace( 550, '\tNorth/South "{}" but RDir H, gapWidth: {}\n' \
# .format(chipIntNet.getName(),DbU.getValueString(bb.getWidth()) ) )
# side.updateGap( bb.getWidth() )
# else:
# trace( 550, '\tEast/West "{}" but RDir V, gapWidth: {}\n' \
# .format(chipIntNet.getName(),DbU.getValueString(bb.getHeight())) )
# side.updateGap( bb.getHeight() )
count += 1
else:
if not (chipIntNet.isGlobal() or chipIntNet.isSupply() or chipIntNet.isClock()):
trace( 550, '-' )
raise ErrorMessage( 1, [ 'Corona._createCoreWire(): In I/O pad "{}" ({},{}),' \
.format( padInstance.getMasterCell().getName()
, padInstance.getName(), padInstance.getTransformation() )
, 'connector "{}" has no suitable segment for net "{}".' \
.format( padNet, chipIntNet.getName() )
] )
trace( 550, '-' )
return count
def _placeInnerCorona ( self ):
trace( 550, ',+', '\tCorona._placeInnerCorona()\n' )
rg = self.conf.routingGauge
coronaSouthGap = 0
for layerGauge in rg.getLayerGauges():
self.southSide.gap = max( self.southSide.gap, layerGauge.getPitch() * 6 )
self.northSide.gap = self.southSide.gap
self.eastSide.gap = self.southSide.gap
self.westSide.gap = self.southSide.gap
for coronaPlug in self.conf.icorona.getPlugs():
chipIntNet = coronaPlug.getNet()
if not chipIntNet:
trace( 550, '-' )
raise ErrorMessage( 1, 'PadsCorona._placeInnerCorona(): Corona net "{}" is not connected to a pad.' \
.format(coronaPlug.getMasterNet().getName()) )
continue
padConnected = 0
doneInstances = []
trace( 550, '\tConnexions on chipIntNet: {}\n'.format(chipIntNet) )
for chipPlug in chipIntNet.getPlugs():
trace( 550, '\t| chipPlug: {}\n'.format(chipPlug) )
doneInstances.append( chipPlug.getInstance() )
padNet = chipPlug.getMasterNet()
padConnected = self._createCoreWire( chipIntNet, padNet, doneInstances[-1], padConnected )
if chipIntNet.isGlobal():
for instance in self.conf.cell.getInstances():
if instance in doneInstances: continue
doneInstances.append( instance )
padNet = instance.getMasterCell().getNet( chipIntNet.getName() )
if not padNet: continue
padConnected = self._createCoreWire( chipIntNet, padNet, doneInstances[-1], padConnected )
if padConnected == 0:
if not (chipIntNet.isSupply() and self.conf.routingGauge.hasPowerSupply()):
trace( 550, '-' )
raise ErrorMessage( 1, 'PadsCorona._placeInnerCorona(): Chip net "{}" is not connected to a pad.' \
.format(chipIntNet.getName()) )
self.conf.setupCorona( self.westSide.gap, self.southSide.gap, self.eastSide.gap, self.northSide.gap )
self.coreSymBb = self.conf.getInstanceAb( self.conf.icorona )
self.coreSymBb.inflate( self.conf.toSymbolic( self.westSide.gap /2, Superior )
, self.conf.toSymbolic( self.southSide.gap/2, Superior )
, self.conf.toSymbolic( self.eastSide.gap /2, Inferior )
, self.conf.toSymbolic( self.northSide.gap/2, Inferior ) )
self.southSide.drawCoreWires()
self.northSide.drawCoreWires()
self.eastSide .drawCoreWires()
self.westSide .drawCoreWires()
if len(self.southSide.coreWires) \
and len(self.westSide .coreWires) \
and not self.southSide.coreWires[0].inCoronaRange \
and not self.westSide .coreWires[0].inCoronaRange:
print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on south-east corner are outside corona range.'
, 'This will generate a short-circuit between S:"{}" and W:"{}".' \
.format( self.southSide.coreWires[0].chipNet.getName()
, self.westSide .coreWires[0].chipNet.getName()) ] ))
if len(self.southSide.coreWires) \
and len(self.eastSide .coreWires) \
and not self.southSide.coreWires[-1].inCoronaRange \
and not self.eastSide .coreWires[ 0].inCoronaRange:
print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on south-west corner are outside corona range.'
, 'This will generate a short-circuit between S:"{}" and E:"{}.' \
.format( self.southSide.coreWires[-1].chipNet.getName()
, self.eastSide .coreWires[ 0].chipNet.getName()) ] ))
if len(self.northSide.coreWires) \
and len(self.westSide .coreWires) \
and not self.northSide.coreWires[ 0].inCoronaRange \
and not self.westSide .coreWires[-1].inCoronaRange:
print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on north-east corner are outside corona range.'
, 'This will generate a short-circuit between N:"%s" and W:"%s".' % \
( self.northSide.coreWires[ 0].chipNet.getName()
, self.westSide .coreWires[-1].chipNet.getName()) ] ))
if len(self.northSide.coreWires) \
and len(self.eastSide .coreWires) \
and not self.northSide.coreWires[-1].inCoronaRange \
and not self.eastSide .coreWires[-1].inCoronaRange:
print( ErrorMessage( 1, [ 'Corona._placeInnerCorona(): Both pads on north-west corner are outside corona range.'
, 'This will generate a short-circuit between N:"%s" and E:"%s.' % \
( self.northSide.coreWires[-1].chipNet.getName()
, self.eastSide .coreWires[-1].chipNet.getName()) ] ))
trace( 550, '-' )
def _supplyToPad ( self, chipNet, coronaNet, coronaAxis, stripeWidth, side ):
trace( 550, ',+', '\tCorona.Builder._supplyToPads()\n' )
supplyLayerDepth = self.conf.routingGauge.getPowerSupplyGauge().getDepth()
supplyLayer = self.conf.routingGauge.getPowerSupplyGauge().getLayer()
chipLayer = self.conf.getRoutingLayer( self.conf.routingGauge.getPowerSupplyGauge().getDepth() - 1 )
coronaAb = self.conf.icorona.getAbutmentBox()
chipAxis = coronaAxis + self.conf.icorona.getTransformation().getTx()
trace( 550, '\tchipLayer={}\n'.format(chipLayer) )
for rail in self.padRails:
net = rail[0]
layer = rail[1]
railAxis = rail[2]
width = rail[3]
if net != chipNet or chipLayer.getMask() != layer.getMask():
continue
if side == North:
trace( 550, '\tcoronaAb={}\n'.format(coronaAb) )
trace( 550, '\tcoronaAxis={}\n'.format(DbU.getValueString(coronaAxis)) )
trace( 550, '\tchipAxis={}\n'.format(DbU.getValueString(chipAxis)) )
trace( 550, '\trailNet={} <-> {}\n'.format(net,chipNet) )
trace( 550, '\trailAxis={}\n'.format(DbU.getValueString(railAxis)) )
Vertical.create( chipNet
, supplyLayer
, chipAxis
, stripeWidth
, coronaAb.getYMax()
, self.conf.chipAb.getYMax() - railAxis
)
via = BigVia( chipNet
, supplyLayerDepth
, chipAxis
, self.conf.chipAb.getYMax() - railAxis
, stripeWidth
, width
, BigVia.AllowAllExpand
)
trace( 550, '\tpower depth: {}\n'.format( self.conf.routingGauge.getPowerSupplyGauge().getDepth() ))
via.mergeDepth( self.conf.routingGauge.getPowerSupplyGauge().getDepth()-1 )
via.doLayout()
pin = Pin.create( coronaNet
, '{}.{}'.format(coronaNet.getName(),self.powerCount)
, Pin.Direction.NORTH
, Pin.PlacementStatus.FIXED
, supplyLayer
, coronaAxis
, self.conf.icorona.getMasterCell().getAbutmentBox().getYMax()
, stripeWidth
, DbU.fromLambda( 1.0 )
)
trace( 550, '\tpin={}\n'.format(pin) )
self.powerCount += 1
elif side == South:
Vertical.create( chipNet
, supplyLayer
, chipAxis
, stripeWidth
, self.conf.chipAb.getYMin() + railAxis
, coronaAb.getYMin()
)
via = BigVia( chipNet
, supplyLayerDepth
, chipAxis
, self.conf.chipAb.getYMin() + railAxis
, stripeWidth
, width
, BigVia.AllowAllExpand
)
via.mergeDepth( supplyLayerDepth-1 )
via.doLayout()
pin = Pin.create( coronaNet
, '{}.{}'.format(coronaNet.getName(),self.powerCount)
, Pin.Direction.SOUTH
, Pin.PlacementStatus.FIXED
, supplyLayer
, coronaAxis
, self.conf.icorona.getMasterCell().getAbutmentBox().getYMin()
, stripeWidth
, DbU.fromLambda( 1.0 )
)
self.powerCount += 1
trace( 550, '-' )
def doLayout ( self ):
if not self.conf.validated: return
with UpdateSession():
for corner in self.corners.values():
corner.doLayout()
self.northSide.doLayout()
self.southSide.doLayout()
self.eastSide.doLayout()
self.westSide.doLayout()
self._placeInnerCorona()
self.conf.chip.setRouted( True )
def doPowerLayout ( self ):
if not self.conf.routingGauge.hasPowerSupply(): return
with UpdateSession():
capViaWidth = self.conf.vDeepRG.getPitch()*3
coreAb = self.conf.coreAb
powerNet = None
groundNet = None
chipPowerNet = None
chipGroundNet = None
corona = self.conf.corona
for net in corona.getNets():
if net.isPower (): powerNet = net
if net.isGround(): groundNet = net
if powerNet:
if powerNet.isGlobal():
chipPowerNet = self.conf.chip.getNet( powerNet.getName() )
else:
for net in self.conf.chip.getNets():
if net.getName() == powerNet.getName():
chipPowerNet = net
break
if not chipPowerNet:
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No core power net not connected in "{}"' \
.format(self.conf.chip.getName()) )
else:
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No power net found in "{}"' \
.format(corona.getName()) )
if groundNet:
if groundNet.isGlobal():
chipGroundNet = self.conf.chip.getNet( groundNet.getName() )
else:
for net in self.conf.chip.getNets():
if net.getName() == groundNet.getName():
chipGroundNet = net
break
if not chipGroundNet:
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No core power net not connected in "{}"' \
.format(self.conf.chip.getName()) )
else:
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No ground net found in "{}"' \
.format(corona.getName()) )
icore = self.conf.icore
xcore = icore.getTransformation().getTx()
stripeSpecs = []
stripesNb = int( (coreAb.getWidth() - 8*capViaWidth + self.supplyRailWidth) \
/ self.supplyRailPitch - 1 )
offset = (coreAb.getWidth() - self.supplyRailPitch*(stripesNb-1)) / 2
stripeSpecs.append( [ xcore + capViaWidth/2 , capViaWidth ] )
stripeSpecs.append( [ xcore + 2*capViaWidth + capViaWidth/2 , capViaWidth ] )
if self.chip.spares and len(self.chip.spares.rleafX) > 1:
rleafX = self.chip.spares.rleafX
spacing = (rleafX[1] - rleafX[0]) / 2
stepOffset = 0
step = 1
trace( 550, '\trleafX\n' )
for i in range(len(rleafX)):
trace( 550, '\t| rleafX[{}] = {}\n'.format(i,DbU.getValueString(rleafX[i])))
if spacing < self.supplyRailPitch:
stepOffset = 1
step = 2
spacing = (rleafX[2] - rleafX[0]) / 2
if step == 1:
stripeSpecs.append( [ rleafX[0] - spacing, self.supplyRailWidth ] )
trace( 550, '\tstripe[N/A] @{}\n'.format(DbU.getValueString(stripeSpecs[-1][0])))
else:
stripeSpecs.append( [ rleafX[0], self.supplyRailWidth ] )
trace( 550, '\tstripe[N/A] @{}\n'.format(DbU.getValueString(stripeSpecs[-1][0])))
for i in range( stepOffset, len(rleafX)-stepOffset, step ):
if step == 1:
stripeSpecs.append( [ rleafX[i], self.supplyRailWidth ] )
trace( 550, '\tstripe[{}] @{}\n'.format(i,DbU.getValueString(stripeSpecs[-1][0])))
stripeSpecs.append( [ rleafX[i] + spacing, self.supplyRailWidth ] )
trace( 550, '\tstripe[{}] @{}\n'.format(i,DbU.getValueString(stripeSpecs[-1][0])))
else:
for i in range(stripesNb):
stripeSpecs.append( [ xcore + offset + i*self.supplyRailPitch
, self.supplyRailWidth
] )
stripeSpecs.append( [ xcore + coreAb.getWidth() - 2*capViaWidth - capViaWidth/2 , capViaWidth ] )
stripeSpecs.append( [ xcore + coreAb.getWidth() - capViaWidth/2 , capViaWidth ] )
trace( 550, '\ticoreAb={}\n'.format(icore.getAbutmentBox()) )
trace( 550, '\tcapViaWidth={}\n'.format(DbU.getValueString(capViaWidth)))
for i in range(len(stripeSpecs)):
if i % 2:
chipNet = chipPowerNet
coronaNet = powerNet
else:
chipNet = chipGroundNet
coronaNet = groundNet
trace( 550, '\tstripe[{}] @{}\n'.format(i,DbU.getValueString(stripeSpecs[i][0])))
self._supplyToPad( chipNet, coronaNet, stripeSpecs[i][0], stripeSpecs[i][1], North )
self._supplyToPad( chipNet, coronaNet, stripeSpecs[i][0], stripeSpecs[i][1], South )
#for istripe in range(stripesNb):
# trace( 550, '\tistripe={}\n'.format(istripe) )
# axis = xcore + offset + istripe*self.supplyRailPitch
# if istripe % 2:
# coronaNet = groundNet
# chipNet = chipGroundNet
# else:
# coronaNet = powerNet
# chipNet = chipPowerNet
# self._supplyToPad( chipNet, coronaNet, axis, North )
# self._supplyToPad( chipNet, coronaNet, axis, South )