Add support for the SkyWater130 Caravel harness to "core2chip".
It is now possible to automatically nest a core block inside a harness frame, like we do for an ordinary chip whith I/O pads. The DEF harness file "user_project_wrapper.def" must be made available though the block configuration variable: conf.cfg.harness.path = './user_project_wrapper.def' A first small example is given in: alliance-check-toolkit/benchs/counter/sky130_c4m The harness layout is stripped from it's native power grid (but keep the power ring). I/O pad information in block/configuration is slightly "bent* to manage pins instead of complete I/O pads. * Bug: In cumulus/plugins.block.Block.setupAb(), the routingBb was not set up when working in chip mode. Now set (to the corona AB). * Change: In cumulus/plugins.chip.__init__, move there the CoreWire class (from chip/pads.py) so it can be shared with the harness version of pads.py. * Change: In cumulus/plugins.chip.powerplane, compute the intersection between the vertical supply stripes and the deep horizontal power lines in a smarter fashion, so two (or more) vertically contiguous BigVias are merged into one (two BigVia side by side where causing mimimal spacing distance violation on the cut in Sky130).
This commit is contained in:
parent
2ca9e162ef
commit
fe32916d14
|
@ -67,6 +67,7 @@
|
|||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/niolib.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/libresocio.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/sky130.py
|
||||
)
|
||||
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py
|
||||
|
@ -79,15 +80,20 @@
|
|||
set ( pyPluginAlphaMacro ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/macro/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/macro/macro.py
|
||||
)
|
||||
set ( pyPluginAlphaHarness ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/harness/__init__.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/harness/pads.py
|
||||
)
|
||||
|
||||
install ( FILES ${pySources} DESTINATION ${Python_CORIOLISLIB}/cumulus )
|
||||
install ( FILES ${pyPlugins} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins )
|
||||
install ( FILES ${pyPluginCTS} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/cts )
|
||||
install ( FILES ${pyPluginC2C} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/core2chip )
|
||||
install ( FILES ${pyPluginChip} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/chip )
|
||||
install ( FILES ${pyPluginAlpha} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha )
|
||||
install ( FILES ${pyPluginAlphaBlock} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/block )
|
||||
install ( FILES ${pyPluginAlphaC2C} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/core2chip )
|
||||
install ( FILES ${pyPluginAlphaChip} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/chip )
|
||||
install ( FILES ${pyPluginAlphaMacro} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/macro )
|
||||
install ( PROGRAMS ${pyTools} DESTINATION bin )
|
||||
install ( FILES ${pySources} DESTINATION ${Python_CORIOLISLIB}/cumulus )
|
||||
install ( FILES ${pyPlugins} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins )
|
||||
install ( FILES ${pyPluginCTS} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/cts )
|
||||
install ( FILES ${pyPluginC2C} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/core2chip )
|
||||
install ( FILES ${pyPluginC2C} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/core2chip )
|
||||
install ( FILES ${pyPluginChip} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/chip )
|
||||
install ( FILES ${pyPluginAlpha} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha )
|
||||
install ( FILES ${pyPluginAlphaBlock} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/block )
|
||||
install ( FILES ${pyPluginAlphaC2C} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/core2chip )
|
||||
install ( FILES ${pyPluginAlphaChip} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/chip )
|
||||
install ( FILES ${pyPluginAlphaMacro} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/macro )
|
||||
install ( FILES ${pyPluginAlphaHarness} DESTINATION ${Python_CORIOLISLIB}/cumulus/plugins/alpha/harness )
|
||||
install ( PROGRAMS ${pyTools} DESTINATION bin )
|
||||
|
|
|
@ -180,6 +180,8 @@ class BigVia ( object ):
|
|||
trace( 550, '\t| topEnclosure[{}]: {}\n'.format(depth,DbU.getValueString(topEnclosure)) )
|
||||
trace( 550, '\t| botEnclosure[{}]: {}\n'.format(depth,DbU.getValueString(botEnclosure)) )
|
||||
trace( 550, '\t| enclosure [{}]: {}\n'.format(depth,DbU.getValueString(enclosure)) )
|
||||
trace( 550, '\t| cut spacing of {}: {}\n'.format(cutLayer.getName(),DbU.getValueString(cutSpacing)) )
|
||||
trace( 550, '\t| cut side of {}: {}\n'.format(cutLayer.getName(),DbU.getValueString(cutSide)) )
|
||||
cutArea = self.plates[ depth ].getBoundingBox()
|
||||
hEnclosure = enclosure + cutSide//2
|
||||
vEnclosure = hEnclosure
|
||||
|
@ -209,6 +211,7 @@ class BigVia ( object ):
|
|||
x = cutArea.getXMin()
|
||||
self.vias[ depth ].append( [] )
|
||||
while x <= cutArea.getXMax():
|
||||
trace( 550, '\t| cut @({} {})\n'.format( DbU.getValueString(x), DbU.getValueString(y) ))
|
||||
cut = Contact.create( self.net, cutLayer, x, y, cutSide, cutSide )
|
||||
self.vias[ depth ][ -1 ].append( cut )
|
||||
x += cutSide + cutSpacing
|
||||
|
|
|
@ -486,8 +486,7 @@ class Block ( object ):
|
|||
trace( 550, '\tCORE AB is {}\n'.format(self.conf.cell.getAbutmentBox()) )
|
||||
if self.conf.isCoreBlock:
|
||||
self.conf.setupICore()
|
||||
else:
|
||||
self.conf.setRoutingBb( self.conf.cell.getAbutmentBox() )
|
||||
self.conf.setRoutingBb( self.conf.cellPnR.getAbutmentBox() )
|
||||
|
||||
def flattenNets ( self ):
|
||||
if self.flags & Block.FLATTENED: return
|
||||
|
|
|
@ -24,9 +24,8 @@ from Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \
|
|||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace, l, u, n
|
||||
from helpers.utils import classdecorator
|
||||
from helpers.io import ErrorMessage, WarningMessage, catch
|
||||
from helpers.overlay import CfgCache
|
||||
from helpers.overlay import CfgCache, UpdateSession
|
||||
from plugins import getParameter
|
||||
from plugins.rsave import rsave
|
||||
from plugins.alpha.utils import getPlugByName
|
||||
|
@ -657,8 +656,12 @@ class IoPadConf ( object ):
|
|||
if len(self._datas) == 5: self._datas += [ None, None ]
|
||||
elif len(self._datas) == 6: self._datas.insert( 5, None )
|
||||
self._datas.append( [] )
|
||||
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
|
||||
m = reSpecialPads.match( self.instanceName )
|
||||
m = None
|
||||
if isinstance(self.instanceName,str):
|
||||
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
|
||||
m = reSpecialPads.match( self.instanceName )
|
||||
else:
|
||||
self.flags |= IoPadConf.ALL_POWER
|
||||
if m:
|
||||
self.index = m.group('index')
|
||||
if m.group('type') == 'allpower': self.flags |= IoPadConf.ALL_POWER
|
||||
|
@ -723,15 +726,20 @@ class IoPadConf ( object ):
|
|||
def isClock ( self ): return self.flags & IoPadConf.CLOCK
|
||||
def isTristate ( self ): return self.flags & IoPadConf.TRISTATE
|
||||
def isBidir ( self ): return self.flags & IoPadConf.BIDIR
|
||||
def isAnalog ( self ): return self._datas[0] & IoPin.ANALOG
|
||||
|
||||
def isAnalog ( self ):
|
||||
if self._datas[0] is None: return False
|
||||
return self._datas[0] & IoPin.ANALOG
|
||||
|
||||
def __repr__ ( self ):
|
||||
s = '<IoPadConf {} iopad="{}" from="{}"'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
|
||||
s = '<IoPadConf {} iopad="{}" from="{}"'.format(self.instanceName
|
||||
,self.padNetName
|
||||
,self.fromCoreNetName)
|
||||
if self.isBidir():
|
||||
s += ' to="{}" en="{}"'.format(self.toCoreNetName,self.enableNetName)
|
||||
if self.isTristate():
|
||||
s += ' en="{}"'.format(self.enableNetName)
|
||||
s += '>'
|
||||
s += ' flags={:x}>'.format(self.flags)
|
||||
return s
|
||||
|
||||
|
||||
|
@ -753,6 +761,10 @@ class ChipConf ( object ):
|
|||
self.northPads = []
|
||||
self.eastPads = []
|
||||
self.westPads = []
|
||||
self.southPins = []
|
||||
self.northPins = []
|
||||
self.eastPins = []
|
||||
self.westPins = []
|
||||
|
||||
def __setattr__ ( self, attr, value ):
|
||||
object.__setattr__( self, attr, value )
|
||||
|
@ -764,15 +776,28 @@ class ChipConf ( object ):
|
|||
Add an I/O pad specification. The spec argument must be of the form:
|
||||
"""
|
||||
ioPadConf = IoPadConf( spec )
|
||||
if spec[0] & IoPin.SOUTH: self.southPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.NORTH: self.northPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.EAST: self.eastPads .append( ioPadConf )
|
||||
elif spec[0] & IoPin.WEST: self.westPads .append( ioPadConf )
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf)
|
||||
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
|
||||
if spec[0] is not None:
|
||||
if spec[0] & IoPin.SOUTH: self.southPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.NORTH: self.northPads.append( ioPadConf )
|
||||
elif spec[0] & IoPin.EAST: self.eastPads .append( ioPadConf )
|
||||
elif spec[0] & IoPin.WEST: self.westPads .append( ioPadConf )
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspecified side for {}'.format(ioPadConf)
|
||||
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
|
||||
self.padInstances.append( ioPadConf )
|
||||
|
||||
def addHarnessPin ( self, pin, side ):
|
||||
"""
|
||||
Add an Pin to a side. This the terminal pin found in the harness.
|
||||
"""
|
||||
if side & IoPin.SOUTH: self.southPins.append( pin )
|
||||
elif side & IoPin.NORTH: self.northPins.append( pin )
|
||||
elif side & IoPin.EAST: self.eastPins .append( pin )
|
||||
elif side & IoPin.WEST: self.westPins .append( pin )
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'ChipConf.addHarnessPin(): Unspecified side for {}'.format(pin)
|
||||
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
|
||||
|
||||
|
||||
# ----------------------------------------------------------------------------
|
||||
# Class : "configuration.BufferConf".
|
||||
|
@ -1277,6 +1302,7 @@ class BlockConf ( GaugeConf ):
|
|||
self.useHFNS = False
|
||||
self.useSpares = True
|
||||
self.isBuilt = False
|
||||
self.useHarness = False
|
||||
self.ioPins = []
|
||||
self.ioPinsCounts = {}
|
||||
for ioPinSpec in ioPins:
|
||||
|
@ -1407,8 +1433,9 @@ class BlockConf ( GaugeConf ):
|
|||
rsave( topCell, views|flags )
|
||||
else:
|
||||
topCell = self.chip
|
||||
self.corona.setName( self.corona.getName()+'_r' )
|
||||
self.chip .setName( self.chip .getName()+'_r' )
|
||||
if not self.useHarness:
|
||||
self.corona.setName( self.corona.getName()+'_r' )
|
||||
self.chip .setName( self.chip .getName()+'_r' )
|
||||
rsave( self.corona, views|flags, enableSpice=True )
|
||||
rsave( self.chip , views|flags, enableSpice=True )
|
||||
if not self.routingGauge.isSymbolic():
|
||||
|
|
|
@ -23,7 +23,15 @@ dictionnary of other modules.
|
|||
OnHorizontalPitch & OnVerticalPitch.
|
||||
"""
|
||||
|
||||
from helpers.io import WarningMessage
|
||||
from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
|
||||
Box, Transformation , Instance , Net, Pin, \
|
||||
Contact, Horizontal, Vertical, BasicLayer, \
|
||||
Layer
|
||||
from CRL import RoutingGauge, RoutingLayerGauge
|
||||
from helpers import trace, l, u, n, onFGrid
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import UpdateSession
|
||||
|
||||
|
||||
North = 0x0001
|
||||
South = 0x0002
|
||||
|
@ -55,3 +63,399 @@ def importConstants ( symbols ):
|
|||
if isinstance(symbol[1],int):
|
||||
if not symbol[0] in symbols:
|
||||
symbols[ symbol[0] ] = symbol[1]
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "chip.CoreWire"
|
||||
|
||||
class CoreWire ( object ):
|
||||
"""
|
||||
Draw wires to connect an external (chip/harness) terminal belonging
|
||||
to a ``chipNet`` (the *internal* one) to an on-grid Pin on the edge
|
||||
of the corona instance.
|
||||
|
||||
Wires are created in *two* Cells:
|
||||
|
||||
1. At the chip/harness level, where they are using real layout
|
||||
connecting to I/O external pads or the harness pins.
|
||||
|
||||
2. At the corona level, *outside* the corona abutment box, so
|
||||
they overlap with the part draw at chip level, as we know the
|
||||
placement of the corona inside the chip.
|
||||
This part of the wires are *on grid*. And they may also be
|
||||
symbolic if the corona+core is in symbolic layout. This just
|
||||
on the outside of the corona that we make the transition
|
||||
between the real outer chip and the internal symbolic core.
|
||||
|
||||
In the case a complete chip with I/O pad, we can also request the
|
||||
insertion of a jumper to protect against antenna effect. This is
|
||||
not working yet in the case of a harness.
|
||||
"""
|
||||
|
||||
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.addJumper = False
|
||||
self.preferredDir = preferredDir
|
||||
self.inCoronaRange = True
|
||||
self.arraySize = None
|
||||
self.count = count
|
||||
self.viaPitch = DbU.fromLambda( 4.0 )
|
||||
self.gapWidth = 0
|
||||
self._computeCoreLayers()
|
||||
if self.conf.routingGauge.getName() == 'FlexLib':
|
||||
self.addJumper = True
|
||||
|
||||
@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() )
|
||||
trace( 550, '\tsymContactSize=( {}, {} )\n' \
|
||||
.format( DbU.getValueString(self.symContactSize[0])
|
||||
, DbU.getValueString(self.symContactSize[1]) ))
|
||||
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 )
|
||||
coronaTransf = self.conf.icorona.getTransformation()
|
||||
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
|
||||
if self.addJumper:
|
||||
rg = self.conf.routingGauge
|
||||
gaugeM5 = rg.getLayerGauge( 4 )
|
||||
wwidthM5 = gaugeM5.getWireWidth()
|
||||
jumperGap = 3*gaugeM5.getPitch()
|
||||
if self.side == East:
|
||||
gapCenter = xPadMin + 5*gaugeM5.getPitch()
|
||||
else:
|
||||
gapCenter = xPadMax - 5*gaugeM5.getPitch()
|
||||
xJumpMin = gapCenter - jumperGap//2
|
||||
xJumpMax = gapCenter + jumperGap//2
|
||||
hChip1 = Horizontal.create( self.chipNet
|
||||
, self.padSegment.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, self.bbSegment.getHeight()
|
||||
, xPadMin
|
||||
, xJumpMin
|
||||
)
|
||||
trace( 550, '\tChipl1: %s\n' % str(Chipl1) )
|
||||
hChip2 = Horizontal.create( self.chipNet
|
||||
, self.padSegment.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, self.bbSegment.getHeight()
|
||||
, xJumpMax
|
||||
, xPadMax
|
||||
)
|
||||
trace( 550, '\thChip2: %s\n' % str(hChip2) )
|
||||
hChip = hChip2 if self.side == West else hChip1
|
||||
bvia1 = BigVia( self.chipNet
|
||||
, rg.getLayerDepth( self.padSegment.getLayer() )
|
||||
, xJumpMin
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
, 2*wwidthM5
|
||||
, flags=BigVia.AllowAllExpand )
|
||||
bvia1.mergeDepth( gaugeM5.getDepth() )
|
||||
trace( 550, '\tbvia1: %s\n' % str(bvia1) )
|
||||
bvia1.doLayout()
|
||||
bvia2 = BigVia( self.chipNet
|
||||
, rg.getLayerDepth( self.padSegment.getLayer() )
|
||||
, xJumpMax
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
, 2*wwidthM5
|
||||
, flags=BigVia.AllowAllExpand )
|
||||
bvia2.mergeDepth( gaugeM5.getDepth() )
|
||||
bvia2.doLayout()
|
||||
trace( 550, '\tbvia2: %s\n' % str(bvia2) )
|
||||
Horizontal.create( bvia1.getPlate( gaugeM5.getLayer() )
|
||||
, bvia2.getPlate( gaugeM5.getLayer() )
|
||||
, gaugeM5.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
)
|
||||
else:
|
||||
hChip = 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:
|
||||
bb = contact.getBoundingBox()
|
||||
coronaTransf.applyOn( bb )
|
||||
vStrapBb.merge( bb )
|
||||
else:
|
||||
contact = self.conf.coronaContact( self.chipNet
|
||||
, self.symContactLayer
|
||||
, xContact
|
||||
, yCore
|
||||
, self.symContactSize[0]
|
||||
, self.symContactSize[1]
|
||||
, flags
|
||||
)
|
||||
vStrapBb = contact.getBoundingBox( padLayer )
|
||||
coronaTransf.applyOn( vStrapBb )
|
||||
if self.arraySize:
|
||||
if self.side == West: xContact = min( xContact, vStrapBb.getXMin() )
|
||||
else: xContact = max( xContact, vStrapBb.getXMax() )
|
||||
hCorona = 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()
|
||||
)
|
||||
hChipBb = hChip.getBoundingBox( padLayer )
|
||||
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMin() )
|
||||
vStrapBb.merge( vStrapBb.getXMin(), hChipBb.getYMax() )
|
||||
hCoronaBb = hCorona.getBoundingBox( padLayer )
|
||||
self.conf.icorona.getTransformation().applyOn( hCoronaBb )
|
||||
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.getYMin() )
|
||||
vStrapBb.merge( vStrapBb.getXMin(), hCoronaBb.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()
|
||||
)
|
||||
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()
|
||||
trace( 550, '\tSouth pad: yPadMin={}\n'.format(DbU.getValueString(yPadMin) ))
|
||||
#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
|
||||
vChip = 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:
|
||||
bb = contact.getBoundingBox()
|
||||
coronaTransf.applyOn( bb )
|
||||
hStrapBb.merge( bb )
|
||||
trace( 550, '\thStrapBb={} contact={}\n'.format(hStrapBb,contact) )
|
||||
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 )
|
||||
coronaTransf.applyOn( hStrapBb )
|
||||
trace( 550, '\thStrapBb={}\n'.format(hStrapBb) )
|
||||
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 )) )
|
||||
trace( 550, '\tyContact: {:<.1f}L {:<}\n'.format(DbU.toLambda(yContact), DbU.getValueString(yContact)) )
|
||||
trace( 550, '\tyCore: {:<.1f}L {:<}\n'.format(DbU.toLambda(yCore ), DbU.getValueString(yCore )) )
|
||||
vCorona = self.conf.coronaVertical( self.chipNet
|
||||
, self.symSegmentLayer
|
||||
, xCore
|
||||
, self.bbSegment.getWidth()
|
||||
, yContact
|
||||
, yCore
|
||||
)
|
||||
trace( 550, '\tvCorona={}\n'.format(vCorona) )
|
||||
pin = self.conf.coronaPin( self.chipNet
|
||||
, self.count
|
||||
, accessDirection
|
||||
, self.symSegmentLayer
|
||||
, xCore
|
||||
, yCore
|
||||
, self.bbSegment.getWidth()
|
||||
, DbU.fromLambda( 1.0 )
|
||||
)
|
||||
vChipBb = vChip.getBoundingBox()
|
||||
hStrapBb.merge( vChipBb.getXMin(), hStrapBb.getYMin() )
|
||||
hStrapBb.merge( vChipBb.getXMax(), hStrapBb.getYMin() )
|
||||
vCoronaBb = vCorona.getBoundingBox()
|
||||
self.conf.icorona.getTransformation().applyOn( vCoronaBb )
|
||||
hStrapBb.merge( vCoronaBb.getXMin(), hStrapBb.getYMin() )
|
||||
hStrapBb.merge( vCoronaBb.getXMax(), hStrapBb.getYMin() )
|
||||
if self.padSegment.getLayer().isSymbolic():
|
||||
hStrapBb.inflate( -self.padSegment.getLayer().getExtentionCap(), 0
|
||||
, -self.padSegment.getLayer().getExtentionCap(), 0 )
|
||||
hStrap = Horizontal.create( self.chipNet
|
||||
, self.padSegment.getLayer()
|
||||
, hStrapBb.getCenter().getY()
|
||||
, hStrapBb.getHeight()
|
||||
, hStrapBb.getXMin()
|
||||
, hStrapBb.getXMax()
|
||||
)
|
||||
trace( 550, '\thStrap={}\n'.format(hStrap) )
|
||||
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, '-' )
|
||||
|
|
|
@ -44,6 +44,7 @@ import plugins.alpha.chip.pads
|
|||
import plugins.alpha.chip.power
|
||||
import plugins.alpha.chip.powerplane
|
||||
import plugins.alpha.chip.corona
|
||||
import plugins.alpha.harness.pads
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -70,26 +71,33 @@ class Chip ( Block ):
|
|||
return self.conf.validated
|
||||
|
||||
def doChipFloorplan ( self ):
|
||||
print( ' - Chip has {} north pads.'.format(len(self.conf.chipConf.northPads)) )
|
||||
print( ' - Chip has {} south pads.'.format(len(self.conf.chipConf.southPads)) )
|
||||
print( ' - Chip has {} east pads.' .format(len(self.conf.chipConf.eastPads )) )
|
||||
print( ' - Chip has {} west pads.' .format(len(self.conf.chipConf.westPads )) )
|
||||
self.conf.computeCoronaBorder()
|
||||
self.conf.chipValidate()
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
|
||||
self.conf.chip.setAbutmentBox( self.conf.chipAb )
|
||||
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
|
||||
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
|
||||
self.padsCorona = plugins.alpha.chip.pads.Corona( self )
|
||||
self.conf.validated = self.padsCorona.validate()
|
||||
if not self.conf.validated:
|
||||
return False
|
||||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
self.padsCorona = None
|
||||
minHCorona = self.conf.minHCorona
|
||||
minVCorona = self.conf.minVCorona
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
self.conf.chipValidate()
|
||||
if not self.conf.useHarness:
|
||||
print( ' - Chip has {} north pads.'.format(len(self.conf.chipConf.northPads)) )
|
||||
print( ' - Chip has {} south pads.'.format(len(self.conf.chipConf.southPads)) )
|
||||
print( ' - Chip has {} east pads.' .format(len(self.conf.chipConf.eastPads )) )
|
||||
print( ' - Chip has {} west pads.' .format(len(self.conf.chipConf.westPads )) )
|
||||
self.conf.computeCoronaBorder()
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
|
||||
self.conf.chip.setAbutmentBox( self.conf.chipAb )
|
||||
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
|
||||
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
|
||||
self.padsCorona = plugins.alpha.chip.pads.Corona( self )
|
||||
self.conf.validated = self.padsCorona.validate()
|
||||
if not self.conf.validated:
|
||||
return False
|
||||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
minHCorona = self.conf.minHCorona
|
||||
minVCorona = self.conf.minVCorona
|
||||
else:
|
||||
self.padsCorona = plugins.alpha.harness.pads.Corona( self )
|
||||
self.padsCorona.doLayout()
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
innerBb.inflate( minHCorona, minVCorona )
|
||||
coronaAb = self.conf.corona.getAbutmentBox()
|
||||
if innerBb.getWidth() > coronaAb.getWidth():
|
||||
|
@ -121,8 +129,9 @@ class Chip ( Block ):
|
|||
power.connectPower()
|
||||
#power.connectHTrees( self.hTrees )
|
||||
power.doLayout()
|
||||
Breakpoint.stop( 101, 'After Query power.' )
|
||||
else:
|
||||
if self.conf.useHarness:
|
||||
return
|
||||
power = plugins.alpha.chip.power.Builder( self.conf )
|
||||
power.connectPower()
|
||||
power.connectClocks()
|
||||
|
|
|
@ -111,6 +111,8 @@ class ChipConf ( BlockConf ):
|
|||
self.blockageNet = None
|
||||
self.padsHavePosition = False
|
||||
self.chipLogos = []
|
||||
self.minHCorona = 0
|
||||
self.minVCorona = 0
|
||||
trace( 550, '-' )
|
||||
|
||||
@property
|
||||
|
@ -294,7 +296,7 @@ class ChipConf ( BlockConf ):
|
|||
else:
|
||||
uCorona = uCore - coronaAb.getXMin()
|
||||
uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer )
|
||||
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n' \
|
||||
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n' \
|
||||
.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
|
||||
if lg:
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
|
|
|
@ -30,6 +30,7 @@ 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.chip import CoreWire
|
||||
from plugins.alpha.block.block import Block
|
||||
from plugins.alpha.block.bigvia import BigVia
|
||||
|
||||
|
@ -498,359 +499,6 @@ class Side ( object ):
|
|||
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.addJumper = False
|
||||
self.preferredDir = preferredDir
|
||||
self.inCoronaRange = True
|
||||
self.arraySize = None
|
||||
self.count = count
|
||||
self.viaPitch = DbU.fromLambda( 4.0 )
|
||||
self.gapWidth = 0
|
||||
self._computeCoreLayers()
|
||||
if self.conf.routingGauge.getName() == 'FlexLib':
|
||||
self.addJumper = True
|
||||
|
||||
@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
|
||||
if self.addJumper:
|
||||
rg = self.conf.routingGauge
|
||||
gaugeM5 = rg.getLayerGauge( 4 )
|
||||
wwidthM5 = gaugeM5.getWireWidth()
|
||||
jumperGap = 3*gaugeM5.getPitch()
|
||||
if self.side == East:
|
||||
gapCenter = xPadMin + 5*gaugeM5.getPitch()
|
||||
else:
|
||||
gapCenter = xPadMax - 5*gaugeM5.getPitch()
|
||||
xJumpMin = gapCenter - jumperGap//2
|
||||
xJumpMax = gapCenter + jumperGap//2
|
||||
hReal1 = Horizontal.create( self.chipNet
|
||||
, self.padSegment.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, self.bbSegment.getHeight()
|
||||
, xPadMin
|
||||
, xJumpMin
|
||||
)
|
||||
trace( 550, '\thReal1: %s\n' % str(hReal1) )
|
||||
hReal2 = Horizontal.create( self.chipNet
|
||||
, self.padSegment.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, self.bbSegment.getHeight()
|
||||
, xJumpMax
|
||||
, xPadMax
|
||||
)
|
||||
trace( 550, '\thReal2: %s\n' % str(hReal2) )
|
||||
hReal = hReal2 if self.side == West else hReal1
|
||||
bvia1 = BigVia( self.chipNet
|
||||
, rg.getLayerDepth( self.padSegment.getLayer() )
|
||||
, xJumpMin
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
, 2*wwidthM5
|
||||
, flags=BigVia.AllowAllExpand )
|
||||
bvia1.mergeDepth( gaugeM5.getDepth() )
|
||||
trace( 550, '\tbvia1: %s\n' % str(bvia1) )
|
||||
bvia1.doLayout()
|
||||
bvia2 = BigVia( self.chipNet
|
||||
, rg.getLayerDepth( self.padSegment.getLayer() )
|
||||
, xJumpMax
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
, 2*wwidthM5
|
||||
, flags=BigVia.AllowAllExpand )
|
||||
bvia2.mergeDepth( gaugeM5.getDepth() )
|
||||
bvia2.doLayout()
|
||||
trace( 550, '\tbvia2: %s\n' % str(bvia2) )
|
||||
Horizontal.create( bvia1.getPlate( gaugeM5.getLayer() )
|
||||
, bvia2.getPlate( gaugeM5.getLayer() )
|
||||
, gaugeM5.getLayer()
|
||||
, self.bbSegment.getCenter().getY()
|
||||
, wwidthM5
|
||||
)
|
||||
else:
|
||||
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"
|
||||
|
||||
|
|
|
@ -14,10 +14,11 @@
|
|||
|
||||
|
||||
import sys
|
||||
from operator import methodcaller
|
||||
from Hurricane import DbU, Point, Transformation, Box, Interval, \
|
||||
Path, Occurrence, UpdateSession, Net, \
|
||||
Contact, Horizontal, Vertical, Cell, Query, \
|
||||
DataBase, Pin, NetExternalComponents
|
||||
DataBase, Pin, NetExternalComponents, Layer
|
||||
import CRL
|
||||
import helpers
|
||||
from helpers import trace
|
||||
|
@ -122,63 +123,58 @@ class HorizontalRail ( Rail ):
|
|||
def merge ( self, bb ):
|
||||
self.intervals.merge( bb.getXMin(), bb.getXMax() )
|
||||
|
||||
def doLayout ( self, plane, stripes ):
|
||||
trace( 550, ',+', '\tHorizontalRail.doLayout() metal={} {}\n' \
|
||||
.format( plane.metal.getName(), self ))
|
||||
def computeBigViaBbs ( self, plane, stripe, leftBigViaBbs, rightBigViaBbs ):
|
||||
"""
|
||||
Compute the bounding boxes of the intersection of the stripe (vertical)
|
||||
and this horizontal rail. If the stripe is very wide, we put one BigVia
|
||||
on the left adge and another one on the right edge. Hence the two lists.
|
||||
If the stripe is *narrow*, only the left list is filled.
|
||||
The minimal *horizontal* size of the BigVias are such as they contains
|
||||
at least one top level power contact (which is usually very large) or
|
||||
two, if possible.
|
||||
"""
|
||||
trace( 550, ',+', '\tHorizontalRail.computeBigViaBbs() metal={} {} stipe={}\n' \
|
||||
.format( plane.metal.getName(), self, stripe ))
|
||||
viaLayer = plane.conf.routingGauge.getContactLayer( stripe.getLayerDepth()-1 )
|
||||
cutLayer = viaLayer.getCut()
|
||||
cutSide = cutLayer.getMinimalSize()
|
||||
cutSpacing = cutLayer.getMinimalSpacing()
|
||||
enclosure = viaLayer.getTopEnclosure( Layer.EnclosureH )
|
||||
oneCutWidth = cutSide + 2*enclosure
|
||||
twoCutWidth = oneCutWidth + cutSpacing + cutSide
|
||||
viaWidth = plane.conf.vDeepRG.getPitch()*5
|
||||
for stripe in stripes:
|
||||
trace( 550, ',+', '\t{}\n'.format(stripe) )
|
||||
stripeBb = stripe.getBoundingBox()
|
||||
for chunk in self.intervals.chunks:
|
||||
if chunk.getVMax() <= stripeBb.getXMin(): continue
|
||||
if chunk.getVMin() >= stripeBb.getXMax(): break
|
||||
trace( 550, '\t| Chunk=[{} {}]\n'.format( DbU.getValueString(chunk.getVMin())
|
||||
, DbU.getValueString(chunk.getVMax()) ))
|
||||
chunkBb = Box( chunk.getVMin()
|
||||
, self.axis - self.width//2
|
||||
, chunk.getVMax()
|
||||
, self.axis + self.width//2 )
|
||||
overlap = stripeBb.getIntersection( chunkBb )
|
||||
if overlap.isEmpty(): continue
|
||||
if overlap.getWidth() > 2*viaWidth:
|
||||
trace( 550, '\t| Large overlap={}\n'.format(overlap) )
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXMin() + viaWidth//2
|
||||
, overlap.getYCenter()
|
||||
, viaWidth
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXMax() - viaWidth//2
|
||||
, overlap.getYCenter()
|
||||
, viaWidth
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
elif overlap.getWidth() > 2*plane.conf.vDeepRG.getPitch():
|
||||
trace( 550, '\t| Narrow overlap={}\n'.format(overlap) )
|
||||
via = BigVia( stripe.getNet()
|
||||
, plane.getLayerDepth(stripe.getLayer())
|
||||
, overlap.getXCenter()
|
||||
, overlap.getYCenter()
|
||||
, overlap.getWidth()
|
||||
, overlap.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
else:
|
||||
trace( 550, '\t| Too narrow overlap={}, no BigVia\n'.format(overlap) )
|
||||
trace( 550, '-' )
|
||||
stripeBb = stripe.getBoundingBox()
|
||||
for chunk in self.intervals.chunks:
|
||||
if chunk.getVMax() <= stripeBb.getXMin(): continue
|
||||
if chunk.getVMin() >= stripeBb.getXMax(): break
|
||||
trace( 550, '\t| Chunk=[{} {}]\n'.format( DbU.getValueString(chunk.getVMin())
|
||||
, DbU.getValueString(chunk.getVMax()) ))
|
||||
chunkBb = Box( chunk.getVMin()
|
||||
, self.axis - self.width//2
|
||||
, chunk.getVMax()
|
||||
, self.axis + self.width//2 )
|
||||
overlap = stripeBb.getIntersection( chunkBb )
|
||||
if overlap.isEmpty(): continue
|
||||
if overlap.getWidth() > 2*viaWidth:
|
||||
trace( 550, '\t| Large overlap={}\n'.format(overlap) )
|
||||
leftBigViaBbs.append( Box( overlap.getXMin()
|
||||
, overlap.getYMin()
|
||||
, overlap.getXMin() + twoCutWidth
|
||||
, overlap.getYMax()
|
||||
))
|
||||
rightBigViaBbs.append( Box( overlap.getXMax() - twoCutWidth
|
||||
, overlap.getYMin()
|
||||
, overlap.getXMax()
|
||||
, overlap.getYMax()
|
||||
))
|
||||
trace( 550, '\t| left={} right={}\n'.format(leftBigViaBbs[-1],rightBigViaBbs[-1]) )
|
||||
elif overlap.getWidth() > 2*plane.conf.vDeepRG.getPitch():
|
||||
trace( 550, '\t| Narrow overlap={}\n'.format(overlap) )
|
||||
leftBigViaBbs.append( overlap )
|
||||
trace( 550, '\t| left={} right=N/A\n'.format(leftBigViaBbs[-1]) )
|
||||
else:
|
||||
trace( 550, '\t| Too narrow overlap={}, no BigVia\n'.format(overlap) )
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -227,9 +223,14 @@ class Rails ( object ):
|
|||
self.axisLut[ axis ][ width ].merge( bb )
|
||||
|
||||
def doLayout ( self, plane, stripes ):
|
||||
for wrail in self.axisLut.values():
|
||||
for rail in wrail.values():
|
||||
rail.doLayout( plane, stripes )
|
||||
for stripe in stripes:
|
||||
leftBigViaBbs = []
|
||||
rightBigViaBbs = []
|
||||
for wrail in self.axisLut.values():
|
||||
for rail in wrail.values():
|
||||
rail.computeBigViaBbs( plane, stripe, leftBigViaBbs, rightBigViaBbs )
|
||||
stripe.doBigViaLayout( plane, leftBigViaBbs )
|
||||
stripe.doBigViaLayout( plane, rightBigViaBbs )
|
||||
return
|
||||
|
||||
|
||||
|
@ -275,6 +276,8 @@ class Plane ( object ):
|
|||
def getLayer ( self ): return self.metal
|
||||
|
||||
def getLayerDepth ( self, layer ): return self.conf.getLayerDepth( layer )
|
||||
|
||||
def getPlaneDepth ( self ): return self.conf.getLayerDepth( self.metal )
|
||||
|
||||
def addRail ( self, net, bb ):
|
||||
if net.isPower():
|
||||
|
@ -306,8 +309,8 @@ class Stripe ( object ):
|
|||
def conf ( self ): return self.builder.conf
|
||||
|
||||
def __str__ ( self ):
|
||||
s = '<Stripe "{}" @{}>'.format( self.southPin.getNet().getName()
|
||||
, DbU.getValueString(self.southPin.getX()) )
|
||||
s = '<Stripe "{}" @{}>'.format( self.getNet().getName()
|
||||
, DbU.getValueString(self.getX()) )
|
||||
return s
|
||||
|
||||
def getNet ( self ):
|
||||
|
@ -315,11 +318,19 @@ class Stripe ( object ):
|
|||
if self.northPin: return self.northPin.getNet()
|
||||
return None
|
||||
|
||||
def getX ( self ):
|
||||
if self.southPin: return self.southPin.getX()
|
||||
if self.northPin: return self.northPin.getX()
|
||||
return None
|
||||
|
||||
def getLayer ( self ):
|
||||
if self.southPin: return self.southPin.getLayer()
|
||||
if self.northPin: return self.northPin.getLayer()
|
||||
return None
|
||||
|
||||
def getLayerDepth ( self ):
|
||||
return self.conf.routingGauge.getLayerDepth( self.getLayer() )
|
||||
|
||||
def getBoundingBox ( self ):
|
||||
if self.stripe: return self.stripe.getBoundingBox()
|
||||
bb = Box()
|
||||
|
@ -328,13 +339,18 @@ class Stripe ( object ):
|
|||
return bb
|
||||
|
||||
def doLayout ( self ):
|
||||
"""
|
||||
Draw one vertical wire between the north and south Pins of the
|
||||
power stripe. For the computation & drawing of the big VIA, see
|
||||
``doBigViaLayout()``.
|
||||
"""
|
||||
if self.southPin is None:
|
||||
print( ErrorMessage( 1, [ 'Stripes.doLayout(): Power/ground stripe is missing a south Pin.'
|
||||
, '(north:'.format(self.northPin) ] ))
|
||||
, '(north:{})'.format(self.northPin) ] ))
|
||||
return
|
||||
if self.northPin is None:
|
||||
print( ErrorMessage( 1, [ 'Stripes.doLayout(): Power/ground stripe is missing a north Pin.'
|
||||
, '(north:'.format(self.southPin) ] ))
|
||||
, '(south:{})'.format(self.southPin) ] ))
|
||||
return
|
||||
self.stripe = Vertical.create( self.southPin
|
||||
, self.northPin
|
||||
|
@ -342,6 +358,36 @@ class Stripe ( object ):
|
|||
, self.southPin.getX()
|
||||
, self.southPin.getWidth() )
|
||||
|
||||
def doBigViaLayout ( self, plane, bigViaBbs ):
|
||||
"""
|
||||
Draw the layout of the BigVias located at the intersection of the
|
||||
stripe (vertical) and the deep (horizontal) power lines. The VIAs
|
||||
are given as a list of bounding box. Do a pre-processing to try
|
||||
to merge two vertically contiguous vias (with the same width).
|
||||
"""
|
||||
trace( 550, ',+', '\tStripe.doBigViaLayout()\n' )
|
||||
bigViaBbs.sort( key=methodcaller('getYMin') )
|
||||
i = 0
|
||||
while i+1 < len(bigViaBbs):
|
||||
if bigViaBbs[i].getYMax () >= bigViaBbs[i+1].getYMin () \
|
||||
and bigViaBbs[i].getWidth() == bigViaBbs[i+1].getWidth():
|
||||
bigViaBbs[i].merge( bigViaBbs[i+1] )
|
||||
del bigViaBbs[i+1]
|
||||
continue
|
||||
i += 1
|
||||
for viaBb in bigViaBbs:
|
||||
via = BigVia( self.getNet()
|
||||
, plane.getLayerDepth(self.getLayer())
|
||||
, viaBb.getXCenter()
|
||||
, viaBb.getYCenter()
|
||||
, viaBb.getWidth()
|
||||
, viaBb.getHeight()
|
||||
, BigVia.AllowTopMetalExpand|BigVia.AllowVerticalExpand
|
||||
)
|
||||
via.mergeDepth( plane.getLayerDepth(plane.getLayer()) )
|
||||
via.doLayout()
|
||||
trace( 550, '-' )
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "power.Stripes"
|
||||
|
@ -353,24 +399,26 @@ class Stripes ( object ):
|
|||
self.powers = {}
|
||||
self.grounds = {}
|
||||
self.supplyLayer = self.conf.routingGauge.getPowerSupplyGauge().getLayer()
|
||||
for pin in self.conf.coronaVdd.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not key in self.powers: self.powers[ key ] = Stripe( self, pin, None )
|
||||
else: self.powers[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not key in self.powers: self.powers[ key ] = Stripe( self, None, pin )
|
||||
else: self.powers[ key ].northPin = pin
|
||||
for pin in self.conf.coronaVss.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not key in self.grounds: self.grounds[ key ] = Stripe( self, pin, None )
|
||||
else: self.grounds[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not key in self.grounds: self.grounds[ key ] = Stripe( self, None, pin )
|
||||
else: self.grounds[ key ].northPin = pin
|
||||
if self.conf.coronaVdd:
|
||||
for pin in self.conf.coronaVdd.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not key in self.powers: self.powers[ key ] = Stripe( self, pin, None )
|
||||
else: self.powers[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not key in self.powers: self.powers[ key ] = Stripe( self, None, pin )
|
||||
else: self.powers[ key ].northPin = pin
|
||||
if self.conf.coronaVss:
|
||||
for pin in self.conf.coronaVss.getPins():
|
||||
if pin.getLayer() != self.supplyLayer: continue
|
||||
key = pin.getX()
|
||||
if pin.getAccessDirection() == Pin.Direction.SOUTH:
|
||||
if not key in self.grounds: self.grounds[ key ] = Stripe( self, pin, None )
|
||||
else: self.grounds[ key ].southPin = pin
|
||||
elif pin.getAccessDirection() == Pin.Direction.NORTH:
|
||||
if not key in self.grounds: self.grounds[ key ] = Stripe( self, None, pin )
|
||||
else: self.grounds[ key ].northPin = pin
|
||||
|
||||
@property
|
||||
def conf ( self ): return self.builder.conf
|
||||
|
@ -434,8 +482,9 @@ class Builder ( object ):
|
|||
self.planes[ layerGauge.getLayer().getName() ] = Plane( self, layerGauge.getLayer() )
|
||||
|
||||
def connectPower ( self ):
|
||||
trace( 550, '\tpower.Builder.connectPower()\n' )
|
||||
if not self.conf.coronaVdd or not self.conf.coronaVss:
|
||||
raise ErrorMessage( 1, 'Cannot build block power terminals as core vdd and/or vss are not known.' )
|
||||
print( ErrorMessage( 1, 'Cannot build block power terminals as core vdd and/or vss are not known.' ))
|
||||
return
|
||||
goCb = GoCb( self )
|
||||
query = Query()
|
||||
|
@ -444,6 +493,7 @@ class Builder ( object ):
|
|||
query.setArea( self.icoreAb )
|
||||
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
|
||||
query.setStopCellFlags( Cell.Flags_AbstractedSupply )
|
||||
trace( 550, '\tloop over the layer gauge\n' )
|
||||
for layerGauge in self.conf.routingGauge.getLayerGauges():
|
||||
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
|
||||
layer = layerGauge.getLayer()
|
||||
|
|
|
@ -46,8 +46,8 @@ The double level chip+corona serves two purpose:
|
|||
|
||||
#from exceptions import NotImplementedError
|
||||
import re
|
||||
from Hurricane import UpdateSession, Net, Instance
|
||||
from CRL import Catalog, AllianceFramework, Spice
|
||||
from Hurricane import DbU, UpdateSession, Net, Instance, Transformation, Box
|
||||
from CRL import Catalog, AllianceFramework, Spice, DefImport
|
||||
from helpers import trace, netDirectionToStr
|
||||
from helpers.overlay import UpdateSession
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
|
@ -108,6 +108,7 @@ class IoNet ( object ):
|
|||
else:
|
||||
self._name = self.coreNet.getName()
|
||||
self._index = 0
|
||||
if self.coreToChip.useHarness(): self._flags |= IoNet.PadPassthrough
|
||||
self._type = self.coreToChip.getNetType( self._name )
|
||||
trace( 550, '\tIoNet.__init__(): {}\n'.format(self) )
|
||||
|
||||
|
@ -139,6 +140,7 @@ class IoNet ( object ):
|
|||
@property
|
||||
def coronaNetName ( self ):
|
||||
s = self._name
|
||||
if self.coreNet.isSupply(): return s
|
||||
if self.coreNet.getDirection() & Net.Direction.IN:
|
||||
s += '_from_pad'
|
||||
elif self.coreNet.getDirection() & Net.Direction.OUT:
|
||||
|
@ -167,7 +169,15 @@ class IoNet ( object ):
|
|||
s = self._name
|
||||
if self._flags & IoNet.IsElem: s += '_{}'.format(self._index)
|
||||
return s
|
||||
|
||||
|
||||
@property
|
||||
def enableNetName ( self ):
|
||||
if self.coreToChip.useHarness():
|
||||
m = IoNet.reVHDLVector.match(self.chipExtNetName)
|
||||
if m:
|
||||
return 'io_oeb({})'.format( m.group('index') )
|
||||
return '{}_enable'.format(self.padInstanceName)
|
||||
|
||||
def setEnable ( self, state ):
|
||||
if state == True: self._flags |= IoNet.IsEnable
|
||||
else: self._flags &= ~IoNet.IsEnable
|
||||
|
@ -194,6 +204,13 @@ class IoNet ( object ):
|
|||
self.coronaNet.setType ( netType )
|
||||
self.coronaNet.setGlobal( True )
|
||||
self.coreToChip.icore.getPlug( self.coreNet ).setNet( self.coronaNet )
|
||||
# In case of harness, the chip external net should already exists.
|
||||
if self.coreToChip.useHarness():
|
||||
self.chipExtNet = self.coreToChip.chip.getNet( self.chipExtNetName )
|
||||
self.chipIntNet = self.chipExtNet
|
||||
if not self.chipExtNet:
|
||||
raise ErrorMessage( 1, 'IoNet.buildNets(): Not harness net "{}" to connect core net "{}".' \
|
||||
.format( self.chipExtNetName, self.coreNet.getName() ))
|
||||
# Chip "internal" net, connect Corona instance net to I/O inside the chip.
|
||||
if not self.chipIntNet:
|
||||
chipIntNetName = "internal_" + self.coronaNetName
|
||||
|
@ -202,7 +219,9 @@ class IoNet ( object ):
|
|||
self.chipIntNet = Net.create( self.coreToChip.chip, chipIntNetName )
|
||||
if netType != Net.Type.LOGICAL:
|
||||
self.chipIntNet.setType( netType )
|
||||
self.coreToChip.icorona.getPlug( self.coronaNet ).setNet( self.chipIntNet )
|
||||
coronaNetPlug = self.coreToChip.icorona.getPlug( self.coronaNet )
|
||||
if not coronaNetPlug.getNet():
|
||||
coronaNetPlug.setNet( self.chipIntNet )
|
||||
# Chip "external" net, connected to the pad I/O to the outside world.
|
||||
#if self._flags & (IoNet.PadPassthrough | IoNet.IsAnalog):
|
||||
if self._flags & IoNet.PadPassthrough:
|
||||
|
@ -214,6 +233,7 @@ class IoNet ( object ):
|
|||
if self.chipExtNet:
|
||||
self.chipExtNet.setExternal ( True )
|
||||
self.chipExtNet.setDirection( self.coreNet.getDirection() )
|
||||
trace( 550, '\tIoNet.buildNets() {}\n'.format( self ))
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
|
@ -292,12 +312,14 @@ class IoPad ( object ):
|
|||
if self.coreToChip.getPadInfo(self.direction) is None:
|
||||
if (self.direction == IoPad.OUT) \
|
||||
and (self.coreToChip.getPadInfo(IoPad.TRI_OUT) is not None):
|
||||
print( WarningMessage( 'IoPad.addNet(): No simple pad in direction {} for "{}", fallback to output tristate.' \
|
||||
.format(IoPad.directionToStr(self.direction),ioNet.padInstanceName)) )
|
||||
if not self.coreToChip.useHarness():
|
||||
print( WarningMessage( 'IoPad.addNet(): No simple pad in direction {} for "{}", fallback to output tristate.' \
|
||||
.format(IoPad.directionToStr(self.direction),ioNet.padInstanceName)) )
|
||||
self.direction = IoPad.TRI_OUT
|
||||
else:
|
||||
print( WarningMessage( 'IoPad.addNet(): No simple pad in direction {} for "{}", fallback to bi-directional.' \
|
||||
.format(IoPad.directionToStr(self.direction),ioNet.padInstanceName)) )
|
||||
if not self.coreToChip.useHarness():
|
||||
print( WarningMessage( 'IoPad.addNet(): No simple pad in direction {} for "{}", fallback to bi-directional.' \
|
||||
.format(IoPad.directionToStr(self.direction),ioNet.padInstanceName)) )
|
||||
self.direction = IoPad.BIDIR
|
||||
elif len(self.nets) == 2:
|
||||
if self.direction != IoPad.BIDIR:
|
||||
|
@ -341,10 +363,14 @@ class IoPad ( object ):
|
|||
# Case of BIDIR as fallback for simple IN/OUT.
|
||||
self.nets[0].setFlags( IoNet.DoExtNet )
|
||||
self.nets[0].buildNets()
|
||||
if len(self.nets) < 2:
|
||||
enableNet = self.coreToChip.newEnableForNet( self.nets[0] )
|
||||
self.nets.append( self.coreToChip.getIoNet( enableNet ) )
|
||||
self.nets[1].buildNets()
|
||||
hasEnable = not self.coreToChip.useHarness() \
|
||||
or self.nets[0].chipExtNetName.startswith('io_in') \
|
||||
or self.nets[0].chipExtNetName.startswith('io_out')
|
||||
if hasEnable:
|
||||
if len(self.nets) < 2:
|
||||
enableNet = self.coreToChip.newEnableForNet( self.nets[0] )
|
||||
self.nets.append( self.coreToChip.getIoNet( enableNet ) )
|
||||
self.nets[1].buildNets()
|
||||
connexions.append( ( self.nets[0].chipExtNet, padInfo.padNet ) )
|
||||
if self.nets[0].coreNet.getDirection() == Net.Direction.IN:
|
||||
connexions.append( ( self.nets[0].chipIntNet , padInfo.outputNet ) )
|
||||
|
@ -352,7 +378,8 @@ class IoPad ( object ):
|
|||
else:
|
||||
connexions.append( ( self.nets[0].chipIntNet , padInfo.inputNet ) )
|
||||
connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) )
|
||||
connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) )
|
||||
if hasEnable:
|
||||
connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) )
|
||||
elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2):
|
||||
self.nets[0].setFlags( IoNet.DoExtNet )
|
||||
self.nets[0].buildNets()
|
||||
|
@ -380,12 +407,13 @@ class IoPad ( object ):
|
|||
connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) )
|
||||
connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) )
|
||||
connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) )
|
||||
self.pads.append( Instance.create( self.coreToChip.chip
|
||||
, self.padInstanceName
|
||||
, self.coreToChip.getCell(padInfo.name) ) )
|
||||
for connexion in connexions:
|
||||
CoreToChip._connect( self.pads[0], connexion[0], connexion[1] )
|
||||
self.coreToChip.chipPads += self.pads
|
||||
if not self.coreToChip.useHarness():
|
||||
self.pads.append( Instance.create( self.coreToChip.chip
|
||||
, self.padInstanceName
|
||||
, self.coreToChip.getCell(padInfo.name) ) )
|
||||
for connexion in connexions:
|
||||
CoreToChip._connect( self.pads[0], connexion[0], connexion[1] )
|
||||
self.coreToChip.chipPads += self.pads
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
|
@ -394,7 +422,7 @@ class IoPad ( object ):
|
|||
class CoreToChip ( object ):
|
||||
"""
|
||||
Semi-automated build of a complete chip with I/O pad around a Cell core.
|
||||
``Core2Chip`` expect configuration informations to be present in the
|
||||
``CoreToChip`` expect configuration informations to be present in the
|
||||
state attribute of the Block class. So a Block class must be created
|
||||
before calling it.
|
||||
|
||||
|
@ -484,21 +512,22 @@ class CoreToChip ( object ):
|
|||
else:
|
||||
block = Block.lookup( core )
|
||||
if not block:
|
||||
raise ErrorMessage( 1, [ 'Core2Chip.__init__(): Core cell "{}" has no Block defined.' \
|
||||
raise ErrorMessage( 1, [ 'CoreToChip.__init__(): Core cell "{}" has no Block defined.' \
|
||||
.format( core.getName() )
|
||||
] )
|
||||
conf = block.state
|
||||
self.conf = conf
|
||||
self.ringNetNames = []
|
||||
self.ioPadInfos = []
|
||||
self.chipPads = []
|
||||
self.padLib = None
|
||||
self.corona = None
|
||||
self._ioNets = {}
|
||||
self.powerPadCount = 0
|
||||
self.groundPadCount = 0
|
||||
self.clockPadCount = 0
|
||||
self.dummyNetCount = 0
|
||||
self.conf = conf
|
||||
self.conf.useHarness = False
|
||||
self.ringNetNames = []
|
||||
self.ioPadInfos = []
|
||||
self.chipPads = []
|
||||
self.padLib = None
|
||||
self.corona = None
|
||||
self._ioNets = {}
|
||||
self.powerPadCount = 0
|
||||
self.groundPadCount = 0
|
||||
self.clockPadCount = 0
|
||||
self.dummyNetCount = 0
|
||||
return
|
||||
|
||||
@property
|
||||
|
@ -513,6 +542,8 @@ class CoreToChip ( object ):
|
|||
@property
|
||||
def chip ( self ): return self.conf.chip
|
||||
|
||||
def useHarness ( self ): return self.conf.useHarness
|
||||
|
||||
def getPadInfo ( self, padType ):
|
||||
for ioPadInfo in self.ioPadInfos:
|
||||
if ioPadInfo.flags & padType:
|
||||
|
@ -544,7 +575,7 @@ class CoreToChip ( object ):
|
|||
raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \
|
||||
.format(ioNet.coreNet.getName()) )
|
||||
instance = self.conf.constantsConf.createInstance( self.core, constantType )
|
||||
enable = Net.create( self.core, '{}_enable'.format(ioNet.padInstanceName) )
|
||||
enable = Net.create( self.core, ioNet.enableNetName )
|
||||
enable.setExternal ( True )
|
||||
enable.setDirection( Net.Direction.OUT )
|
||||
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable )
|
||||
|
@ -599,36 +630,48 @@ class CoreToChip ( object ):
|
|||
|
||||
def _buildCoreGroundPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to core ground signals."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildIoGroundPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to pad internal ground signals."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildAllGroundPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to ground signals for core and pads."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildCorePowerPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to core power signals."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildIoPowerPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to pad internal power signals."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildAllPowerPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to power signals for core and pads."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' )
|
||||
|
||||
def _buildClockPads ( self, ioPadConf ):
|
||||
"""Build I/O pad relateds to clock signals."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._buildClockPads(): This method must be overloaded.' )
|
||||
|
||||
def _connectClocks ( self ):
|
||||
"""Connect inner clocks signal to the corona (towards the core) ."""
|
||||
if self.useHarness(): return
|
||||
raise NotImplementedError( 'coreToChip._connectClocks(): This method must be overloaded.' )
|
||||
|
||||
def _loadHarness ( self ):
|
||||
"""Load the DEF file containing the reference harness layout."""
|
||||
raise NotImplementedError( 'coreToChip._loadHarness(): This method must be overloaded.' )
|
||||
|
||||
def buildChip ( self ):
|
||||
"""
|
||||
Build the whole chip+corona hierarchical structure (netlist only)
|
||||
|
@ -636,18 +679,33 @@ class CoreToChip ( object ):
|
|||
"""
|
||||
af = AllianceFramework.get()
|
||||
self.conf.cfg.apply()
|
||||
chipName = self.conf.chipConf.name
|
||||
if self.useHarness():
|
||||
self.conf.chip = self._loadHarness()
|
||||
else:
|
||||
self.conf.chip = af.createCell( self.conf.chipConf.name )
|
||||
with UpdateSession():
|
||||
print( ' o Build Chip from Core.' )
|
||||
print( ' - Core: "{}".'.format(self.conf.cell.getName()) )
|
||||
print( ' - Corona: "{}".'.format('corona') )
|
||||
print( ' - Chip: "{}".'.format(self.conf.chipConf.name) )
|
||||
self.conf.chip = af.createCell( self.conf.chipConf.name )
|
||||
print( ' - Core: "{}".'.format(self.conf.cell.getName()) )
|
||||
print( ' - Corona: "{}".'.format('corona') )
|
||||
print( ' - Chip: "{}".'.format(self.conf.chip.getName()) )
|
||||
self.corona = af.createCell( 'corona' )
|
||||
self.conf.icore = Instance.create( self.corona , 'core' , self.conf.cell )
|
||||
self.conf.icorona = Instance.create( self.conf.chip, 'corona', self.corona )
|
||||
if self.useHarness():
|
||||
harnessBb = self.conf.chip.getBoundingBox()
|
||||
harnessAb = self.conf.chip.getAbutmentBox()
|
||||
self.conf.chip.setAbutmentBox( harnessBb )
|
||||
self.conf.corona.setAbutmentBox( Box( 0, 0, harnessAb.getWidth(), harnessAb.getHeight() ))
|
||||
self.conf.icorona.setTransformation( Transformation( harnessAb.getXMin()
|
||||
, harnessAb.getYMin()
|
||||
, Transformation.Orientation.ID ))
|
||||
self.conf.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
ioPads = []
|
||||
clockIoNets = []
|
||||
for ioPadConf in self.conf.chipConf.padInstances:
|
||||
if self.useHarness():
|
||||
ioPadConf.flags = IoPadConf.BIDIR
|
||||
if ioPadConf.isAllPower():
|
||||
self._buildAllPowerPads( ioPadConf )
|
||||
continue
|
||||
|
@ -685,6 +743,7 @@ class CoreToChip ( object ):
|
|||
if coreNet.getName() == ioPadConf.enableNetName:
|
||||
ioNet.setEnable( True )
|
||||
if not ioNet.isEnable():
|
||||
trace( 550, '\tForce pad net name to "{}"\n'.format( ioPadConf.padNetName ))
|
||||
ioNet.chipExtNetName = ioPadConf.padNetName
|
||||
ioPadConf.udata.addNet( ioNet )
|
||||
ioPads.append( ioPadConf )
|
||||
|
@ -712,8 +771,11 @@ class CoreToChip ( object ):
|
|||
#trace( 550, '\tNon-configured core net {}, adding {}\n'.format(coreNet,directPad) )
|
||||
for ioPad in ioPads:
|
||||
ioPad.udata.createPad()
|
||||
self._connectRing()
|
||||
self._connectClocks()
|
||||
#if self.useHarness():
|
||||
# self._connectCorona()
|
||||
else:
|
||||
self._connectRing()
|
||||
self._connectClocks()
|
||||
oneDriver( self.chip )
|
||||
rsave( self.chip, views=Catalog.State.Logical, enableSpice=True )
|
||||
Spice.clearProperties()
|
||||
|
|
|
@ -0,0 +1,238 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2020-2021, 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/core2chip/sky130.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
"""
|
||||
Core2Chip configuration for the Sky130 harness.
|
||||
"""
|
||||
|
||||
import sys
|
||||
import re
|
||||
from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
|
||||
Transformation , Box, Instance , Net, \
|
||||
Contact
|
||||
import Viewer
|
||||
from CRL import Catalog
|
||||
from CRL import AllianceFramework, DefImport
|
||||
from helpers import trace, l, u, n
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import CfgCache, UpdateSession
|
||||
import plugins.alpha.chip
|
||||
from plugins.alpha.block.configuration import IoPin, GaugeConf
|
||||
from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip, \
|
||||
IoNet, IoPad
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "sky130.CoreToChip"
|
||||
|
||||
class CoreToChip ( BaseCoreToChip ):
|
||||
"""
|
||||
Provide harness-specific part for SkyWater 130 (works in real mode).
|
||||
Emulate the behavior of I/O pads.
|
||||
"""
|
||||
rePadType = re.compile(r'(?P<type>.+)_(?P<index>[\d]+)$')
|
||||
|
||||
def __init__ ( self, core ):
|
||||
self.ioPadNames = { 'bidir' :'IOHarnessInOut'
|
||||
, 'analog':'IOHarnessAnalog'
|
||||
, 'vdd' :'IOHarnessVdd'
|
||||
, 'vss' :'IOHarnessVss'
|
||||
, 'iovdd' :'IOHarnessIOVdd'
|
||||
, 'iovss' :'IOHarnessIOVss'
|
||||
}
|
||||
BaseCoreToChip.__init__ ( self, core )
|
||||
self.conf.useHarness = True
|
||||
self.ringNetNames = { 'vssa2' : None
|
||||
, 'vdda2' : None
|
||||
, 'vssa1' : None
|
||||
, 'vdda1' : None
|
||||
, 'vssd2' : None
|
||||
, 'vccd2' : None
|
||||
, 'vssd1' : None
|
||||
, 'vccd1' : None
|
||||
}
|
||||
self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.BIDIR
|
||||
, self.ioPadNames['bidir']
|
||||
, 'pad', ['io_in', 'io_out', 'io_oeb'] )
|
||||
, BaseCoreToChip.IoPadInfo( IoPad.ANALOG
|
||||
, self.ioPadNames['analog']
|
||||
, 'pad', ['pad', 'padres'] )
|
||||
]
|
||||
self._getPadLib()
|
||||
return
|
||||
|
||||
def _getPadLib ( self ):
|
||||
return None
|
||||
|
||||
def getNetType ( self, netName ):
|
||||
if netName.startswith('vss') or netName.startswith('vee'): return Net.Type.GROUND
|
||||
if netName.startswith('vdd') or netName.startswith('vcc'): return Net.Type.POWER
|
||||
return Net.Type.LOGICAL
|
||||
|
||||
def isGlobal ( self, netName ):
|
||||
if netName in self.ringNetNames: return True
|
||||
return False
|
||||
|
||||
def getCell ( self, masterCellName ):
|
||||
raise NotImplementedError( 'coreToChip.getCell(): Harness does not provides I/O pad cells.' )
|
||||
|
||||
def _buildCoreGroundPads ( self, ioPadConf ):
|
||||
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
|
||||
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
|
||||
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
|
||||
if not coronaNet:
|
||||
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
|
||||
coronaNet.setExternal( True )
|
||||
coronaNet.setGlobal ( True )
|
||||
coronaNet.setType ( Net.Type.GROUND )
|
||||
self.icore.getPlug( coreNet ).setNet( coronaNet )
|
||||
if not chipNet:
|
||||
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
|
||||
chipNet.setExternal( True )
|
||||
chipNet.setType ( Net.Type.GROUND )
|
||||
coronaPlug = self.icorona.getPlug( coronaNet )
|
||||
if not coronaPlug.getNet():
|
||||
coronaPlug.setNet( chipNet )
|
||||
self.ringNetNames['vss'] = chipNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_vss_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['vss']) ) )
|
||||
self._connect( ioPadConf.pads[0], chipNet, 'vss' )
|
||||
self.groundPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
|
||||
def _buildIoGroundPads ( self, ioPadConf ):
|
||||
padNet = self.chip.getNet( ioPadConf.padSupplyNetName )
|
||||
if not padNet:
|
||||
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
|
||||
padNet.setExternal( True )
|
||||
padNet.setType ( Net.Type.GROUND )
|
||||
self.ringNetNames['iovss'] = padNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_iovss_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['iovss']) ) )
|
||||
self._connect( ioPadConf.pads[0], padNet , 'iovss' )
|
||||
self.groundPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
|
||||
def _buildCorePowerPads ( self, ioPadConf ):
|
||||
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
|
||||
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
|
||||
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
|
||||
if not coronaNet:
|
||||
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
|
||||
coronaNet.setExternal( True )
|
||||
coronaNet.setGlobal ( True )
|
||||
coronaNet.setType ( Net.Type.POWER )
|
||||
self.icore.getPlug( coreNet ).setNet( coronaNet )
|
||||
if not chipNet:
|
||||
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
|
||||
chipNet.setExternal( True )
|
||||
chipNet.setType ( Net.Type.POWER )
|
||||
self.icorona.getPlug( coronaNet ).setNet( chipNet )
|
||||
self.ringNetNames['vdd'] = chipNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_vdd_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['vdd']) ) )
|
||||
self._connect( ioPadConf.pads[0], chipNet, 'vdd' )
|
||||
self.powerPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
|
||||
def _buildIoPowerPads ( self, ioPadConf ):
|
||||
padNet = self.chip .getNet( ioPadConf.padSupplyNetName )
|
||||
if not padNet:
|
||||
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
|
||||
padNet.setExternal( True )
|
||||
padNet.setType ( Net.Type.POWER )
|
||||
self.ringNetNames['iovdd'] = padNet
|
||||
ioPadConf.pads.append( Instance.create( self.chip
|
||||
, 'p_iovdd_{}'.format(ioPadConf.index)
|
||||
, self.getCell(self.ioPadNames['iovdd']) ) )
|
||||
self._connect( ioPadConf.pads[0], padNet , 'iovdd' )
|
||||
self.powerPadCount += 1
|
||||
self.chipPads += ioPadConf.pads
|
||||
|
||||
def _buildClockPads ( self, ioPadConf ):
|
||||
"""For "Sky130" there is no specialized clock I/O pad. So do nothing."""
|
||||
pass
|
||||
|
||||
def _connectClocks ( self ):
|
||||
"""For "Sky130" there is no pad internal clock ring. So do nothing."""
|
||||
pass
|
||||
|
||||
def _loadHarness ( self ):
|
||||
"""
|
||||
Load the DEF file containing the reference harness layout.
|
||||
Remove the supplied internal power grid and slightly shrink
|
||||
the central P&R area so that I/O pins are fully outside of it.
|
||||
"""
|
||||
self.harness = DefImport.load( self.conf.cfg.harness.path )
|
||||
innerAb = self.harness.getAbutmentBox()
|
||||
wholeBb = self.harness.getBoundingBox()
|
||||
filterBb = Box( wholeBb.getXMin(), innerAb.getYMin()
|
||||
, wholeBb.getXMax(), innerAb.getYMax() )
|
||||
components = []
|
||||
for component in self.harness.getComponentsUnder( filterBb ):
|
||||
if component.getNet().isSupply() and filterBb.contains( component.getBoundingBox() ):
|
||||
components.append( component )
|
||||
for instance in self.harness.getInstancesUnder( filterBb ):
|
||||
components.append( instance )
|
||||
with UpdateSession():
|
||||
for component in components:
|
||||
component.destroy()
|
||||
components = []
|
||||
filterBb = Box( innerAb.getXMin(), wholeBb.getYMin()
|
||||
, innerAb.getXMax(), wholeBb.getYMax() )
|
||||
for component in self.harness.getComponentsUnder( filterBb ):
|
||||
if component.getNet().isSupply() and filterBb.contains( component.getBoundingBox() ):
|
||||
components.append( component )
|
||||
for instance in self.harness.getInstancesUnder( filterBb ):
|
||||
components.append( instance )
|
||||
with UpdateSession():
|
||||
for component in components:
|
||||
component.destroy()
|
||||
areaXMin = innerAb.getXMin()
|
||||
areaYMin = innerAb.getYMin()
|
||||
areaXMax = innerAb.getXMax()
|
||||
areaYMax = innerAb.getYMax()
|
||||
for net in self.harness.getNets():
|
||||
if net.isSupply(): continue
|
||||
for component in net.getComponents():
|
||||
trace( 550, '\t| {}\n'.format(component) )
|
||||
bb = component.getBoundingBox()
|
||||
side = None
|
||||
if bb.getXMin() < innerAb.getXMin():
|
||||
areaXMin = max( areaXMin, bb.getXMax() )
|
||||
side = IoPin.WEST
|
||||
if bb.getXMax() > innerAb.getXMax():
|
||||
areaXMax = min( areaXMax, bb.getXMin() )
|
||||
side = IoPin.EAST
|
||||
if bb.getYMin() < innerAb.getYMin():
|
||||
areaYMin = max( areaYMin, bb.getYMax() )
|
||||
side = IoPin.SOUTH
|
||||
if bb.getYMax() > innerAb.getYMax():
|
||||
areaYMax = min( areaYMax, bb.getYMin() )
|
||||
side = IoPin.NORTH
|
||||
trace( 550, '\tside: {} {}\n'.format(side,type(component)) )
|
||||
if side and isinstance(component,Contact):
|
||||
trace( 550, '\tAdded on {} side: {}\n'.format(side,component) )
|
||||
self.conf.chipConf.addHarnessPin( component, side )
|
||||
area = Box( areaXMin, areaYMin, areaXMax, areaYMax )
|
||||
area.inflate( - self.conf.hRoutingGauge.getPitch()*2
|
||||
, - self.conf.vRoutingGauge.getPitch()*2 )
|
||||
xmodulo = area.getWidth () % self.conf.sliceStep
|
||||
ymodulo = area.getHeight() % self.conf.sliceHeight
|
||||
area.inflate( 0, 0, -xmodulo, -ymodulo )
|
||||
self.harness.setAbutmentBox( area )
|
||||
return self.harness
|
|
@ -1,711 +0,0 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2014-2021, 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/configuration.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
import sys
|
||||
import os.path
|
||||
import Cfg
|
||||
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
|
||||
Path, Layer, Occurrence, Net, RoutingPad, \
|
||||
Horizontal, Vertical, Contact, Pin, Plug, \
|
||||
Instance
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
from helpers import trace
|
||||
from helpers.utils import classdecorator
|
||||
from helpers.overlay import UpdateSession
|
||||
from helpers.io import ErrorMessage, WarningMessage, \
|
||||
vprint, catch
|
||||
import plugins.chip
|
||||
from plugins.alpha.block.configuration import BlockConf
|
||||
|
||||
__all__ = [ 'ChipConf' ]
|
||||
|
||||
|
||||
plugins.alpha.chip.importConstants( globals() )
|
||||
af = CRL.AllianceFramework.get()
|
||||
|
||||
|
||||
# -------------------------------------------------------------------
|
||||
# Class : "Configuration.ChipConf".
|
||||
|
||||
class ChipConf ( BlockConf ):
|
||||
|
||||
@staticmethod
|
||||
def _toSymbolic ( u, rounding ):
|
||||
"""
|
||||
Pitch the coordinates ``u`` to the symbolic grid, according
|
||||
to ``rounding`` (Superior or Inferior).
|
||||
"""
|
||||
oneLambda = DbU.fromLambda( 1.0 )
|
||||
remainder = u % oneLambda
|
||||
if remainder:
|
||||
if rounding == Superior: u = u + (oneLambda - remainder)
|
||||
else: u = u - remainder
|
||||
return u
|
||||
|
||||
@staticmethod
|
||||
def toSymbolic ( v, rounding ):
|
||||
"""
|
||||
Pitch the coordinates of object ``v`` to the symbolic grid,
|
||||
according to ``rounding``. Were ``v`` can be:
|
||||
|
||||
* A scalar, then rounding is Inferior or Superior.
|
||||
* A Box, then rounding is:
|
||||
|
||||
* Inwards: the pitched box will be fully enclosed in the
|
||||
original box.
|
||||
* Outwards: the pitched box will fully enclose the original
|
||||
box.
|
||||
"""
|
||||
if isinstance(v,int): return ChipConf._toSymbolic( v, rounding )
|
||||
if isinstance(v,Box):
|
||||
if rounding & Inwards:
|
||||
roundings = [ Superior
|
||||
, Superior
|
||||
, Inferior
|
||||
, Inferior ]
|
||||
else:
|
||||
roundings = [ Inferior
|
||||
, Inferior
|
||||
, Superior
|
||||
, Superior ]
|
||||
xMin = ChipConf._toSymbolic( v.getXMin(), roundings[0] )
|
||||
yMin = ChipConf._toSymbolic( v.getYMin(), roundings[1] )
|
||||
xMax = ChipConf._toSymbolic( v.getXMax(), roundings[2] )
|
||||
yMax = ChipConf._toSymbolic( v.getYMax(), roundings[3] )
|
||||
return Box( xMin, yMin, xMax, yMax )
|
||||
return v
|
||||
|
||||
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
|
||||
trace( 550, ',+', 'ChipConf.__init__(): "{}"'.format(cell.getName()) )
|
||||
super(ChipConf,self).__init__( cell, ioPins, ioPads )
|
||||
#trace( 550, '\tONE LAMBDA = %s\n' % DbU.getValueString(DbU.fromLambda(1.0)) )
|
||||
self.validated = True
|
||||
# Block Corona parameters (triggers loading from disk).
|
||||
self.cfg.chip.padCoreSide = None
|
||||
self.cfg.chip.supplyRailWidth = None
|
||||
self.cfg.chip.supplyRailPitch = None
|
||||
self.cfg.chip.block.rails.count = None
|
||||
self.cfg.chip.block.rails.hWidth = None
|
||||
self.cfg.chip.block.rails.vWidth = None
|
||||
self.cfg.chip.block.rails.hSpacing = None
|
||||
self.cfg.chip.block.rails.vSpacing = None
|
||||
self._railsCount = self.cfg.chip.block.rails.count
|
||||
# Global Net names.
|
||||
self.blockageName = "blockagenet"
|
||||
# Global Nets.
|
||||
self.coronaVdd = None
|
||||
self.coronaVss = None
|
||||
self.coronaCks = []
|
||||
self.blockageNet = None
|
||||
self.padsHavePosition = False
|
||||
self.chipLogos = []
|
||||
trace( 550, '-' )
|
||||
|
||||
@property
|
||||
def padCoreSide ( self ):
|
||||
return self.cfg.chip.padCoreSide
|
||||
|
||||
@property
|
||||
def railsCount ( self ):
|
||||
return self._railsCount
|
||||
|
||||
@railsCount.setter
|
||||
def railsCount ( self, count ):
|
||||
self._railsCount = count
|
||||
|
||||
@property
|
||||
def hRailWidth ( self ):
|
||||
return self.cfg.chip.block.rails.hWidth
|
||||
|
||||
@property
|
||||
def vRailWidth ( self ):
|
||||
return self.cfg.chip.block.rails.vWidth
|
||||
|
||||
@property
|
||||
def hRailSpace ( self ):
|
||||
return self.cfg.chip.block.rails.hSpacing
|
||||
|
||||
@property
|
||||
def vRailSpace ( self ):
|
||||
return self.cfg.chip.block.rails.vSpacing
|
||||
|
||||
def computeCoronaBorder ( self ):
|
||||
global af
|
||||
if self.useClockTree:
|
||||
clockNets = []
|
||||
for net in self.cellPnR.getNets():
|
||||
if net.isClock():
|
||||
clockNets.append( net )
|
||||
self.railsCount = self.cfg.chip.block.rails.count + len(clockNets)
|
||||
trace( 550, '\tself.railsCount: {}\n'.format(self.railsCount) )
|
||||
hRailsSize = self.railsCount*(self.hRailWidth + self.hRailSpace) + self.hRailSpace
|
||||
if hRailsSize % self.sliceHeight:
|
||||
hRailsSize += self.sliceHeight - (hRailsSize % self.sliceHeight)
|
||||
self.minHCorona = hRailsSize + self.sliceHeight
|
||||
vRailsSize = self.railsCount*(self.vRailWidth + self.vRailSpace) + self.vRailSpace
|
||||
if vRailsSize % self.sliceHeight:
|
||||
vRailsSize += self.sliceHeight - (vRailsSize % self.sliceHeight)
|
||||
self.minVCorona = vRailsSize + self.sliceHeight
|
||||
|
||||
def chipValidate ( self ):
|
||||
#self.checkPads()
|
||||
#self.checkCorona()
|
||||
#self.computeChipSize()
|
||||
#self.checkChipSize()
|
||||
self.findPowerAndClockNets()
|
||||
return
|
||||
|
||||
def getInstanceAb ( self, instance ):
|
||||
ab = instance.getMasterCell().getAbutmentBox()
|
||||
instance.getTransformation().applyOn( ab )
|
||||
if instance.getCell() == self.chip: return ab
|
||||
if instance.getCell() != self.corona:
|
||||
raise ErrorMessage( 1, 'ChipConf.getInstanceAb(): Instance "{}" neither belong to chip or corona.' \
|
||||
.format(instance.getName()) )
|
||||
return ab
|
||||
self.icorona.getTransformation().applyOn( ab )
|
||||
return ab
|
||||
|
||||
def setupICore ( self ):
|
||||
"""
|
||||
Setup the abutment box of the *core* master cell and position it's unique
|
||||
instance (*icore*) in the center of the *corona* master cell.
|
||||
"""
|
||||
with UpdateSession():
|
||||
trace( 550, ',+', '\tChipConf.setupICore()\n' )
|
||||
ab = self.getInstanceAb( self.icorona )
|
||||
if ab.isEmpty():
|
||||
raise ErrorMessage( 1, 'ChipConf.setupICore(): Attempt to setup core *before* corona.' )
|
||||
return
|
||||
#ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
|
||||
ab = self.toSymbolic( ab, Inwards )
|
||||
trace( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
|
||||
if self.core.getAbutmentBox().isEmpty():
|
||||
if not self.coreAb.isEmpty():
|
||||
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
|
||||
ab = self.coreAb
|
||||
else:
|
||||
ab.inflate( -self.minHCorona, -self.minVCorona )
|
||||
self.coreSize = (ab.getWidth(), ab.getHeight())
|
||||
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
|
||||
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
|
||||
self.coreSize = ( self.coreSize[0] - self.coreSize[0] % self.sliceStep
|
||||
, self.coreSize[1] - self.coreSize[1] % self.sliceHeight )
|
||||
self.core.setAbutmentBox( Box( 0, 0, self.coreAb.getWidth(), self.coreAb.getHeight() ) )
|
||||
trace( 550, '\tCORE ab:{}\n'.format(self.coreAb) )
|
||||
coreX = (self.coronaAb.getWidth () - self.coreAb.getWidth ()) // 2
|
||||
trace( 550, '\tCore X, {} '.format(DbU.getValueString(coreX)) )
|
||||
coreX = coreX - (coreX % self.sliceHeight)
|
||||
trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.sliceHeight)
|
||||
, DbU.getValueString(coreX)) )
|
||||
coreY = (self.coronaAb.getHeight() - self.coreAb.getHeight()) // 2
|
||||
coreY = coreY - (coreY % self.sliceHeight)
|
||||
self.icore.setTransformation( Transformation( coreX, coreY, Transformation.Orientation.ID ) )
|
||||
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
trace( 550, '-' )
|
||||
|
||||
def getCoronaNet ( self, chipNet ):
|
||||
for plug in chipNet.getPlugs():
|
||||
if plug.getInstance() == self.icorona:
|
||||
return plug.getMasterNet()
|
||||
return None
|
||||
|
||||
def toRoutingGauge ( self, uMin, uMax, layer ):
|
||||
trace( 550, ',+', '\ttoRoutingGauge() [{} {}] {}\n' \
|
||||
.format(DbU.getValueString(uMin), DbU.getValueString(uMax), layer) )
|
||||
ab = self.corona.getAbutmentBox()
|
||||
lg = None
|
||||
mask = layer.getMask()
|
||||
for layerGauge in self.routingGauge.getLayerGauges():
|
||||
if layerGauge.getLayer().getMask() == mask:
|
||||
lg = layerGauge
|
||||
trace( 550, '\tUsing layer gauge {}\n'.format(lg) )
|
||||
break
|
||||
if uMax < uMin: uMin, uMax = uMax, uMin
|
||||
if lg:
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
abMin = ab.getYMin()
|
||||
abMax = ab.getYMax()
|
||||
else:
|
||||
abMin = ab.getXMin()
|
||||
abMax = ab.getXMax()
|
||||
if uMin <= abMin:
|
||||
shiftRight = abMin - uMin + lg.getPitch()
|
||||
uMin += shiftRight
|
||||
uMax += shiftRight
|
||||
if uMax >= abMax:
|
||||
shiftLeft = uMax - abMax + lg.getPitch()
|
||||
uMin -= shiftLeft
|
||||
uMax -= shiftLeft
|
||||
iTrackMin = lg.getTrackIndex( abMin, abMax, uMin, RoutingLayerGauge.Superior )
|
||||
iTrackMax = lg.getTrackIndex( abMin, abMax, uMax, RoutingLayerGauge.Inferior )
|
||||
if iTrackMax < iTrackMin: iTrackMax = iTrackMin
|
||||
uTrackMin = lg.getTrackPosition( abMin, iTrackMin )
|
||||
uTrackMax = lg.getTrackPosition( abMin, iTrackMax )
|
||||
axis = (uTrackMax + uTrackMin) // 2
|
||||
width = (iTrackMax - iTrackMin) * lg.getPitch() + lg.getWireWidth()
|
||||
if self.routingGauge.isSymbolic():
|
||||
trace( 550, '\tRoutingGauge is symbolic, adjust on lambda.\n' )
|
||||
oneLambda = DbU.fromLambda( 1.0 )
|
||||
if axis % oneLambda:
|
||||
axis -= oneLambda // 2
|
||||
width -= oneLambda
|
||||
trace( 550, '\t[{} {}] -> [{} {}]\n'.format( iTrackMin
|
||||
, iTrackMax
|
||||
, DbU.getValueString(uTrackMin)
|
||||
, DbU.getValueString(uTrackMax) ) )
|
||||
trace( 550, '\taxis: {:.1f}L {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) )
|
||||
trace( 550, '\twidth: {:.1f}L {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) )
|
||||
else:
|
||||
axis = (uMax + uMin) // 2
|
||||
width = (uMax - uMin)
|
||||
trace( 550, '-' )
|
||||
return axis, width
|
||||
|
||||
def toCoronaPitchInChip ( self, uCore, layer ):
|
||||
trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {:.1f}L {}\n' \
|
||||
.format(DbU.toLambda(uCore), DbU.getValueString(uCore)) )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
lg = None
|
||||
mask = layer.getMask()
|
||||
for layerGauge in self.routingGauge.getLayerGauges():
|
||||
if layerGauge.getLayer().getMask() == mask:
|
||||
lg = layerGauge
|
||||
break
|
||||
if not lg:
|
||||
trace( 550, '-' )
|
||||
return 0
|
||||
trace( 550, '\t{}\n'.format(lg) )
|
||||
if lg:
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
uCorona = uCore - coronaAb.getYMin()
|
||||
else:
|
||||
uCorona = uCore - coronaAb.getXMin()
|
||||
uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer )
|
||||
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n' \
|
||||
.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
|
||||
if lg:
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
uCore = uCorona + coronaAb.getYMin()
|
||||
else:
|
||||
uCore = uCorona + coronaAb.getXMin()
|
||||
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {:.1f}L {}\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
|
||||
trace( 550, '\ttoCoronaPitchInChip(): uCore: {:.1f}L {}\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) )
|
||||
trace( 550, '-' )
|
||||
return uCore
|
||||
|
||||
def coronaHorizontal ( self, chipNet, layer, chipY, width, chipXMin, chipXMax ):
|
||||
trace( 550, ',+', '\tChipConf.coronaHorizontal\n' )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
coronaNet = self.getCoronaNet ( chipNet )
|
||||
if not coronaNet: return None
|
||||
coronaY = chipY - coronaAb.getYMin()
|
||||
dxMin = ChipConf.toSymbolic( chipXMin - coronaAb.getXMin(), Superior )
|
||||
dxMax = ChipConf.toSymbolic( chipXMax - coronaAb.getXMin(), Inferior )
|
||||
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
|
||||
trace( 550, '\t| Real\n' )
|
||||
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
|
||||
trace( 550, '\t| dxMin:{} ({:.1f}L)\n' \
|
||||
.format( DbU.getValueString(chipXMin - coronaAb.getXMin())
|
||||
, DbU.toLambda(chipXMin - coronaAb.getXMin()) ) )
|
||||
trace( 550, '\t| dxMax:{}\n'.format(DbU.getValueString(chipXMax - coronaAb.getXMin())) )
|
||||
coronaY, width = self.toRoutingGauge( coronaY - width//2, coronaY + width//2, layer )
|
||||
trace( 550, '\t| On Grid\n' )
|
||||
trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| width:{:.1f}L or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
|
||||
trace( 550, '\t| dxMin:{:.1f}L\n'.format(DbU.toLambda(dxMin)) )
|
||||
trace( 550, '\t| dxMax:{:.1f}L\n'.format(DbU.toLambda(dxMax)) )
|
||||
h = Horizontal.create( coronaNet, layer, coronaY, width, dxMin, dxMax )
|
||||
trace( 550, '\t| {}\n'.format(h) )
|
||||
trace( 550, '-' )
|
||||
return h
|
||||
|
||||
def coronaVertical ( self, chipNet, layer, chipX, width, chipYMin, chipYMax ):
|
||||
trace( 550, ',+', '\tChipConf.coronaVertical\n' )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
coronaNet = self.getCoronaNet( chipNet )
|
||||
if not coronaNet: return None
|
||||
coronaX = chipX - coronaAb.getXMin()
|
||||
dyMin = ChipConf.toSymbolic( chipYMin - coronaAb.getYMin(), Superior )
|
||||
dyMax = ChipConf.toSymbolic( chipYMax - coronaAb.getYMin(), Inferior )
|
||||
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
|
||||
trace( 550, '\t| Real\n' )
|
||||
trace( 550, '\t| axis: {}\n'.format(DbU.getValueString(coronaX)) )
|
||||
trace( 550, '\t| width:{}\n'.format(DbU.getValueString(width)) )
|
||||
coronaX, width = self.toRoutingGauge( coronaX - width//2, coronaX + width//2, layer )
|
||||
trace( 550, '\t| On Grid\n' )
|
||||
trace( 550, '\t| axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
|
||||
trace( 550, '\t| width:{:.1f}L or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
|
||||
v = Vertical.create( coronaNet, layer, coronaX, width, dyMin, dyMax )
|
||||
trace( 550, '\t| {}\n'.format(v) )
|
||||
trace( 550, '-' )
|
||||
return v
|
||||
|
||||
def coronaContact ( self, chipNet, layer, chipX, chipY, width, height, flags=0 ):
|
||||
trace( 550, ',+', '\tChipConf.coronaContact\n' )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
coronaNet = self.getCoronaNet( chipNet )
|
||||
if not coronaNet: return None
|
||||
coronaX = chipX - coronaAb.getXMin()
|
||||
coronaY = chipY - coronaAb.getYMin()
|
||||
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet,layer) )
|
||||
trace( 550, '\t| Real\n' )
|
||||
trace( 550, '\t| center: {:>12} {:>12}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| WxH: {:>12} {:>12}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
|
||||
topLayer = layer.getTop()
|
||||
botLayer = layer.getBottom()
|
||||
if self.isHorizontal(topLayer):
|
||||
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, botLayer )
|
||||
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, topLayer )
|
||||
else:
|
||||
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, topLayer )
|
||||
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, botLayer )
|
||||
if not (flags & OnHorizontalPitch):
|
||||
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
|
||||
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
|
||||
if not (flags & OnVerticalPitch ):
|
||||
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
|
||||
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
|
||||
trace( 550, '\t| On Grid\n' )
|
||||
trace( 550, '\t| X axis: {:>12.1f}L or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
|
||||
trace( 550, '\t| Y axis: {:>12.1f}L or {:>12}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| center: {:>12} {:>12}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| WxH: {:>12} {:>12}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
|
||||
c = Contact.create( coronaNet
|
||||
, layer
|
||||
, coronaX
|
||||
, coronaY
|
||||
, width
|
||||
, height
|
||||
)
|
||||
trace( 550, '\t| {}\n'.format(c) )
|
||||
trace( 550, '-' )
|
||||
return c
|
||||
|
||||
def getViaPitch ( self, viaLayer ):
|
||||
topLayer = viaLayer.getTop()
|
||||
if topLayer.isSymbolic():
|
||||
topLayer = topLayer.getBasicLayer()
|
||||
topEnclosure = viaLayer.getEnclosure( topLayer, Layer.EnclosureH|Layer.EnclosureV )
|
||||
topPitch = 2*topEnclosure + viaLayer.getMinimalSize() + topLayer.getMinimalSpacing()
|
||||
botLayer = viaLayer.getBottom()
|
||||
if botLayer.isSymbolic():
|
||||
botLayer = botLayer.getBasicLayer()
|
||||
botEnclosure = viaLayer.getEnclosure( botLayer, Layer.EnclosureH|Layer.EnclosureV )
|
||||
botPitch = 2*botEnclosure + viaLayer.getMinimalSize() + botLayer.getMinimalSpacing()
|
||||
viaPitch = max( topPitch, botPitch )
|
||||
trace( 550, '\tgetViaPitch of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaPitch)) )
|
||||
trace( 550, '\t| minimal size of {}: {}\n'.format(viaLayer.getName(),DbU.getValueString(viaLayer.getMinimalSize())) )
|
||||
trace( 550, '\t| enclosure of {}: {}\n'.format(topLayer.getName(),DbU.getValueString(topEnclosure)) )
|
||||
trace( 550, '\t| enclosure of {}: {}\n'.format(botLayer.getName(),DbU.getValueString(botEnclosure)) )
|
||||
return viaPitch
|
||||
|
||||
def coronaContactArray ( self, chipNet, layer, chipX, chipY, array, flags ):
|
||||
trace( 550, ',+', '\tChipConf.coronaContactArray\n' )
|
||||
viaPitch = self.getViaPitch( layer )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
coronaNet = self.getCoronaNet( chipNet )
|
||||
if not coronaNet: return None
|
||||
trace( 550, '\t| chipNet: {} {}\n'.format(chipNet, layer) )
|
||||
coronaX = chipX - coronaAb.getXMin()
|
||||
coronaY = chipY - coronaAb.getYMin()
|
||||
topLayer = layer.getTop()
|
||||
if self.isHorizontal(topLayer):
|
||||
coronaX, width = self.toRoutingGauge( coronaX, coronaX, layer.getBottom() )
|
||||
coronaY, height = self.toRoutingGauge( coronaY, coronaY, topLayer )
|
||||
else:
|
||||
coronaX, width = self.toRoutingGauge( coronaX, coronaX, topLayer )
|
||||
coronaY, height = self.toRoutingGauge( coronaY, coronaY, layer.getBottom() )
|
||||
if not (flags & OnHorizontalPitch):
|
||||
trace( 550, '\tNot on horizontal routing pitch, Y on lambda only.\n' )
|
||||
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
|
||||
if not (flags & OnVerticalPitch ):
|
||||
trace( 550, '\tNot on vertical routing pitch, X on lambda only.\n' )
|
||||
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
|
||||
contacts = []
|
||||
xContact = coronaX - viaPitch * (array[0]-1)//2
|
||||
yContact = coronaY - viaPitch * (array[1]-1)//2
|
||||
contactSize = layer.getMinimalSize()
|
||||
trace( 550, '\txContact:{} yContact:{}\n'.format(DbU.getValueString(xContact),DbU.getValueString(yContact)) )
|
||||
for i in range(array[0]):
|
||||
for j in range(array[1]):
|
||||
c = Contact.create( coronaNet
|
||||
, layer
|
||||
, xContact + i*viaPitch
|
||||
, yContact + j*viaPitch
|
||||
, contactSize
|
||||
, contactSize
|
||||
)
|
||||
trace( 550, '\t+ {}\n'.format(c) )
|
||||
contacts.append( c )
|
||||
trace( 550, '-' )
|
||||
return contacts
|
||||
|
||||
def coronaPin ( self, chipNet, count, direction, layer, chipX, chipY, width, height ):
|
||||
trace( 550, ',+', '\tChipConf.coronaPin\n' )
|
||||
coronaAb = self.getInstanceAb( self.icorona )
|
||||
coronaNet = self.getCoronaNet( chipNet )
|
||||
if not coronaNet: return None
|
||||
coronaX = chipX - coronaAb.getXMin()
|
||||
coronaY = chipY - coronaAb.getYMin()
|
||||
trace( 550, '\t| chipNet: {} ({}) {}\n'.format(chipNet, count, layer) )
|
||||
trace( 550, '\t| Real\n' )
|
||||
trace( 550, '\t| center: {} {}\n'.format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| WxH: {} {}\n'.format(DbU.getValueString(width ), DbU.getValueString(height )) )
|
||||
topLayer = layer.getTop()
|
||||
if self.isHorizontal(topLayer):
|
||||
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, layer.getBottom() )
|
||||
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, topLayer )
|
||||
else:
|
||||
coronaX, width = self.toRoutingGauge( coronaX - width //2, coronaX + width //2, topLayer )
|
||||
coronaY, height = self.toRoutingGauge( coronaY - height//2, coronaY + height//2, layer.getBottom() )
|
||||
if direction == Pin.Direction.NORTH or direction == Pin.Direction.SOUTH:
|
||||
trace( 550, '\tEast/West not on horizontal routing pitch, Y on lambda only.\n' )
|
||||
coronaY = self.toSymbolic( chipY - coronaAb.getYMin(), Superior )
|
||||
if direction == Pin.Direction.EAST or direction == Pin.Direction.WEST:
|
||||
trace( 550, '\tNorth/South not on vertical routing pitch, X on lambda only.\n' )
|
||||
coronaX = self.toSymbolic( chipX - coronaAb.getXMin(), Superior )
|
||||
trace( 550, '\t| On Grid\n' )
|
||||
trace( 550, '\t| X axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| Y axis: {:.1f}L or {}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
|
||||
trace( 550, '\t| center: {} {}\n' .format(DbU.getValueString(coronaX), DbU.getValueString(coronaY)) )
|
||||
trace( 550, '\t| WxH: {} {}\n' .format(DbU.getValueString(width ), DbU.getValueString(height )) )
|
||||
c = Pin.create( coronaNet
|
||||
, '{}.{}'.format(coronaNet.getName(),count)
|
||||
, direction
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, layer
|
||||
, coronaX
|
||||
, coronaY
|
||||
, width
|
||||
, height
|
||||
)
|
||||
trace( 550, '\t| {}\n'.format(c) )
|
||||
trace( 550, '-' )
|
||||
return c
|
||||
|
||||
def checkPads ( self ):
|
||||
|
||||
def contains ( padList, side, padInstance ):
|
||||
for i in range(len(padList)):
|
||||
if padList[i][1] == padInstance.getName():
|
||||
if (padInstance.getMasterCell().getAbutmentBox().getHeight() != self.ioPadHeight):
|
||||
raise ErrorMessage( 1, 'The pad [{}] {} ({}) on {} side is not an instance of a pad cell.' \
|
||||
.format(i,padInstance.getName(),padInstance.getMasterCell().getName(),side) )
|
||||
padList[i][1] = padInstance
|
||||
return True
|
||||
return False
|
||||
|
||||
def checkNotFounds ( padList, side ):
|
||||
for i in range(len(padList)):
|
||||
if not isinstance(padList[i][1],Instance):
|
||||
print( ErrorMessage( 1, 'The pad [{}] ({}) of list {} do not exists in netlist (skipped).'
|
||||
.format(i,padList[i][1],side) ))
|
||||
return
|
||||
|
||||
global af
|
||||
cellPads = []
|
||||
for instance in self.chip.getInstances():
|
||||
if contains(self.southPads,'south',instance): continue
|
||||
if contains(self.northPads,'north',instance): continue
|
||||
if contains(self.eastPads ,'east' ,instance): continue
|
||||
if contains(self.westPads ,'west' ,instance): continue
|
||||
if (instance.getMasterCell().getAbutmentBox().getHeight() == self.ioPadHeight):
|
||||
raise ErrorMessage( 1, 'Pad "{}" is not on any side (N/S/E/W).'.format(instance.getName()) )
|
||||
self.validated = False
|
||||
else:
|
||||
self.coronas.append( instance )
|
||||
checkNotFounds( self.southPads, 'south' )
|
||||
checkNotFounds( self.northPads, 'north' )
|
||||
checkNotFounds( self.eastPads , 'east' )
|
||||
checkNotFounds( self.westPads , 'west' )
|
||||
if len(self.coronas) > 1:
|
||||
message = [ 'Chip "{}" have more than one corona:'.format(self.chip.getName()) ]
|
||||
for i in range(len(self.coronas)):
|
||||
message.append( '{}: {}'.format(i,self.coronas[i].getName()) )
|
||||
raise ErrorMessage( 1, message )
|
||||
self.validated = False
|
||||
if len(self.coronas) < 1:
|
||||
raise ErrorMessage( 1, 'Chip "{}" doesn\'t seems to have a corona.' \
|
||||
.format(self.chip.getName()) )
|
||||
self.validated = False
|
||||
else:
|
||||
for instance in self.corona.getInstances():
|
||||
self.cores.append( instance )
|
||||
if len(self.cores) > 1:
|
||||
message = [ 'Chip "{}" have more than one core:'.format(self.chip.getName()) ]
|
||||
for i in range(len(self.cores)):
|
||||
message.append( '{}: {}'.format(i,self.cores[i].getName()) )
|
||||
raise ErrorMessage( 1, message )
|
||||
self.validated = False
|
||||
|
||||
if len(self.cores) < 1:
|
||||
raise ErrorMessage( 1, 'Chip "{} doesn\'t seems to have a core.' \
|
||||
.format(self.chip.getName()) )
|
||||
self.validated = False
|
||||
return
|
||||
|
||||
def findPowerAndClockNets ( self ):
|
||||
if self.icore:
|
||||
for plug in self.icore.getPlugs():
|
||||
masterNet = plug.getMasterNet()
|
||||
netType = masterNet.getType()
|
||||
if netType != Net.Type.POWER \
|
||||
and netType != Net.Type.GROUND \
|
||||
and netType != Net.Type.CLOCK:
|
||||
continue
|
||||
net = plug.getNet()
|
||||
if not net:
|
||||
net = self.corona.getNet( masterNet.getName() )
|
||||
if not net:
|
||||
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Missing global net "{}" at corona level.' \
|
||||
.format(asterNet.getName()) )
|
||||
self._validated = False
|
||||
continue
|
||||
if netType == Net.Type.GROUND:
|
||||
if self.coronaVss and self.coronaVss != net:
|
||||
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple ground nets "{}" and "{}" at corona level.' \
|
||||
.format(self.coronaVss.getName(), net.getName()) )
|
||||
self._validated = False
|
||||
continue
|
||||
else:
|
||||
self.coronaVss = net
|
||||
|
||||
if netType == Net.Type.POWER:
|
||||
if self.coronaVdd and self.coronaVdd != net:
|
||||
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Multiple power nets "{}" and "{}" at corona level.' \
|
||||
.format(self.coronaVdd.getName(), net.getName()) )
|
||||
self._validated = False
|
||||
continue
|
||||
else:
|
||||
self.coronaVdd = net
|
||||
|
||||
if netType == Net.Type.CLOCK:
|
||||
if not net in self.coronaCks:
|
||||
self.coronaCks.append( net )
|
||||
vprint( 2, ' - Using clock "{}".'.format(net.getName()) )
|
||||
for net in self.corona.getNets():
|
||||
if net.getType() == Net.Type.BLOCKAGE:
|
||||
self.blockageNet = net
|
||||
self.blockageName = net.getName()
|
||||
if not self.blockageNet:
|
||||
self.blockageNet = Net.create( self.corona, self.blockageName )
|
||||
self.blockageNet.setType( Net.Type.BLOCKAGE )
|
||||
return
|
||||
|
||||
def checkChipSize ( self ):
|
||||
if self.chipSize[0] % self.sliceStep:
|
||||
print( WarningMessage( 'ChipConf.checkChipSize(): Width of "{}" ({})is not on sliceStep ({}), ajusted.' \
|
||||
.format( self.chipConf.name
|
||||
, DbU.getValueString(self.chipSize[0])
|
||||
, DbU.getValueString(self.sliceStep))) )
|
||||
adjust = self.sliceStep - self.chipSize[0] % self.sliceStep
|
||||
self.chipSize = (self.chipSize[0] + adjust, self.chipSize[1])
|
||||
if self.chipSize[1] % self.sliceStep:
|
||||
print( WarningMessage( 'ChipConf.checkChipSize(): Height of "{}" ({})is not on sliceStep ({}), ajusted.' \
|
||||
.format( self.chipConf.name
|
||||
, DbU.getValueString(self.chipSize[1])
|
||||
, DbU.getValueString(self.sliceStep))) )
|
||||
adjust = self.sliceStep - self.chipSize[1] % self.sliceStep
|
||||
self.chipSize = (self.chipSize[0], self.chipSize[1] + adjust)
|
||||
|
||||
#if self._coreSize.isEmpty(): return
|
||||
#
|
||||
#minWidth = self._coreSize.getWidth () + self._minCorona + 2*self._padHeight
|
||||
#minHeight = self._coreSize.getHeight() + self._minCorona + 2*self._padHeight
|
||||
#
|
||||
#if self._chipSize.getWidth() < minWidth:
|
||||
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
|
||||
# % ( DbU.toLambda(minWidth), DbU.toLambda(self._chipSize.getWidth()) ) )
|
||||
# self._validated = False
|
||||
#
|
||||
#if self._chipSize.getHeight() < minHeight:
|
||||
# raise ErrorMessage( 1, 'Core is too wide to fit into the chip. Needs: %d, but has %d' \
|
||||
# % ( DbU.toLambda(minHeight), DbU.toLambda(self._chipSize.getHeight()) ) )
|
||||
# self._validated = False
|
||||
return
|
||||
|
||||
def checkCorona ( self ):
|
||||
trace( 550, ',+', 'Configuration.checkCorona()\n' )
|
||||
netPads = {}
|
||||
for plug in self.icorona.getPlugs():
|
||||
padNet = plug.getNet()
|
||||
coronaNet = plug.getMasterNet()
|
||||
if not padNet and coronaNet.isGlobal():
|
||||
padNet = self.chip.getNet( coronaNet.getName() )
|
||||
if padNet:
|
||||
if not padNet in netPads:
|
||||
trace( 550, '\t{:>20} <-> {:<20}\n'.format(padNet.getName(),coronaNet.getName()) )
|
||||
netPads[ padNet ] = coronaNet
|
||||
else:
|
||||
raise ErrorMessage( 1, 'ChipConf.checkCorona(): Corona nets "{}" and "{}" connected to the same pad net "{}".' \
|
||||
.format(coronaNet.getName(),netPads[padNet].getName(),padNet.getName()) )
|
||||
self._validated = False
|
||||
trace( 550, '-' )
|
||||
return
|
||||
|
||||
def computeChipSize ( self ):
|
||||
|
||||
def getSideLength ( pads ):
|
||||
sideLength = self.ioPadHeight * 2
|
||||
for pad in pads: sideLength += pad.getMasterCell().getAbutmentBox().getWidth()
|
||||
return sideLength
|
||||
|
||||
if not self.chipSize.isEmpty(): return
|
||||
southPadsLength = getSideLength( self.southPads )
|
||||
northPadsLength = getSideLength( self.northPads )
|
||||
eastPadsLength = getSideLength( self.eastPads )
|
||||
westPadsLength = getSideLength( self.westPads )
|
||||
horizontalPads = max( len(self.southPads), len(self.northPads) )
|
||||
verticalPads = max( len(self.eastPads ), len(self.westPads ) )
|
||||
self.chipSize = ( max( southPadsLength, northPadsLength )
|
||||
, max( westPadsLength, eastPadsLength ) )
|
||||
|
||||
def setupCorona ( self, gapX1, gapY1, gapX2, gapY2 ):
|
||||
ab = self.chip.getAbutmentBox()
|
||||
ab.inflate ( -gapX1, -gapY1, -gapX2, -gapY2 )
|
||||
ab.inflate ( - self.ioPadHeight )
|
||||
ab.translate( - self.ioPadHeight, - self.ioPadHeight)
|
||||
ab = self.toSymbolic( ab, Inwards )
|
||||
|
||||
self. corona.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
|
||||
self.icorona.setTransformation(
|
||||
Transformation( self.toSymbolic( self.ioPadHeight + ab.getXMin(), Superior )
|
||||
, self.toSymbolic( self.ioPadHeight + ab.getYMin(), Superior )
|
||||
, Transformation.Orientation.ID ) )
|
||||
self.icorona.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
self.setRoutingBb( self.corona.getAbutmentBox() )
|
||||
|
||||
def setupCore ( self, gapX1, gapY1, gapX2, gapY2 ):
|
||||
trace( 550, ',+', '\tChipConf.setupCore()\n' )
|
||||
ab = self.getInstanceAb( self.icorona )
|
||||
if ab.isEmpty():
|
||||
raise ErrorMessage( 1, 'ChipConf.setupCore(): Attempt to setup core *before* corona.' )
|
||||
return
|
||||
ab.inflate( -gapX1, -gapY1, -gapX2, -gapY2 )
|
||||
ab = self.toSymbolic( ab, Inwards )
|
||||
tracee( 550, '\tself.coreAb:{}\n'.format(self.coreAb) )
|
||||
if not self.coreAb.isEmpty():
|
||||
trace( 550, '\tUsing user-defined CORE size:{}\n'.format(self.coreSize) )
|
||||
ab = self.coreAb
|
||||
trace( 550, '\tSetting CORE abutment box:{}\n'.format(ab) )
|
||||
self.core.setAbutmentBox( Box( 0, 0, ab.getWidth(), ab.getHeight() ) )
|
||||
self.icore.setTransformation(
|
||||
Transformation( ChipConf.toSymbolic(ab.getXMin(),Inferior) - self.icorona.getTransformation().getTx()
|
||||
, ChipConf.toSymbolic(ab.getYMin(),Inferior) - self.icorona.getTransformation().getTy()
|
||||
, Transformation.Orientation.ID ) )
|
||||
self.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
trace( 550, '-' )
|
|
@ -1,148 +0,0 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2014-2021, 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/chip.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import sys
|
||||
import traceback
|
||||
import os.path
|
||||
import optparse
|
||||
import math
|
||||
import cProfile
|
||||
import pstats
|
||||
import Cfg
|
||||
import Hurricane
|
||||
from Hurricane import DataBase, DbU ,Point, Transformation, Box, \
|
||||
Path, Occurrence, UpdateSession, Breakpoint, \
|
||||
Net, RoutingPad, Contact, Horizontal, Vertical, \
|
||||
Instance, HyperNet, Query
|
||||
import Viewer
|
||||
import CRL
|
||||
from CRL import RoutingLayerGauge
|
||||
import helpers
|
||||
from helpers import trace
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import UpdateSession
|
||||
import Etesian
|
||||
import Anabatic
|
||||
import Katana
|
||||
import Unicorn
|
||||
import plugins
|
||||
import plugins.rsave
|
||||
from plugins.alpha.block.block import Block
|
||||
import plugins.alpha.chip.pads
|
||||
import plugins.alpha.chip.power
|
||||
import plugins.alpha.chip.powerplane
|
||||
import plugins.alpha.chip.corona
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "chip.Chip"
|
||||
|
||||
class Chip ( Block ):
|
||||
|
||||
def __init__ ( self, conf ):
|
||||
super(Chip,self).__init__( conf )
|
||||
|
||||
def validate ( self ):
|
||||
self.conf.validated = True
|
||||
coreAb = self.conf.core.getAbutmentBox()
|
||||
if (not coreAb.isEmpty()):
|
||||
if coreAb.getWidth () <= self.conf.coreAb.getWidth() \
|
||||
and coreAb.getHeight() <= self.conf.coreAb.getHeight():
|
||||
self.conf.coreSize = (coreAb.getWidth(), coreAb.getHeight())
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'Core "{}" already have an abutment box, bigger than the requested one:' \
|
||||
.format(self.conf.core.getName())
|
||||
, " Cell abutment box: {}".format(coreAb)
|
||||
, " Maximum abutment box: {}".format(self.conf.coreAb) ] )
|
||||
self.conf.validated = False
|
||||
return self.conf.validated
|
||||
|
||||
def doChipFloorplan ( self ):
|
||||
print( ' - Chip has {} north pads.'.format(len(self.conf.chipConf.northPads)) )
|
||||
print( ' - Chip has {} south pads.'.format(len(self.conf.chipConf.southPads)) )
|
||||
print( ' - Chip has {} east pads.' .format(len(self.conf.chipConf.eastPads )) )
|
||||
print( ' - Chip has {} west pads.' .format(len(self.conf.chipConf.westPads )) )
|
||||
self.conf.computeCoronaBorder()
|
||||
self.conf.chipValidate()
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.doChipFloorplan(): Chip is not valid, aborting.' )
|
||||
self.conf.chip.setAbutmentBox( self.conf.chipAb )
|
||||
trace( 550, '\tSet chip ab:{}\n'.format(self.conf.chip.getAbutmentBox()) )
|
||||
trace( 550, '\tUsing core ab:{}\n'.format(self.conf.core.getAbutmentBox()) )
|
||||
self.padsCorona = plugins.alpha.chip.pads.Corona( self )
|
||||
self.conf.validated = self.padsCorona.validate()
|
||||
if not self.conf.validated:
|
||||
return False
|
||||
self.padsCorona.doLayout()
|
||||
self.validate()
|
||||
minHCorona = self.conf.minHCorona
|
||||
minVCorona = self.conf.minVCorona
|
||||
innerBb = Box( self.conf.coreAb )
|
||||
innerBb.inflate( minHCorona, minVCorona )
|
||||
coronaAb = self.conf.corona.getAbutmentBox()
|
||||
if innerBb.getWidth() > coronaAb.getWidth():
|
||||
raise ErrorMessage( 1, 'Core is too wide to fit into the corona, needs {} but only has {}.' \
|
||||
.format( DbU.getValueString(innerBb .getWidth())
|
||||
, DbU.getValueString(coronaAb.getWidth()) ) )
|
||||
if innerBb.getHeight() > coronaAb.getHeight():
|
||||
raise ErrorMessage( 1, 'Core is too tall to fit into the corona, needs {} but only has {}.' \
|
||||
.format( DbU.getValueString(innerBb .getHeight())
|
||||
, DbU.getValueString(coronaAb.getHeight()) ) )
|
||||
with UpdateSession():
|
||||
self.conf.core.setAbutmentBox( self.conf.coreAb )
|
||||
x = (coronaAb.getWidth () - self.conf.coreAb.getWidth ()) // 2
|
||||
y = (coronaAb.getHeight() - self.conf.coreAb.getHeight()) // 2
|
||||
trace( 550, '\tCore X, {} '.format(DbU.getValueString(x)) )
|
||||
x = x - (x % self.conf.sliceHeight)
|
||||
trace( 550, ' adjusted on {}, {}\n'.format( DbU.getValueString(self.conf.sliceHeight)
|
||||
, DbU.getValueString(x)) )
|
||||
y = y - (y % self.conf.sliceHeight)
|
||||
self.conf.icore.setTransformation ( Transformation(x,y,Transformation.Orientation.ID) )
|
||||
self.conf.icore.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
self.conf.refresh()
|
||||
|
||||
def doConnectCore ( self ):
|
||||
if self.padsCorona:
|
||||
self.padsCorona.doPowerLayout()
|
||||
if self.conf.routingGauge.hasPowerSupply():
|
||||
power = plugins.alpha.chip.powerplane.Builder( self.conf )
|
||||
power.connectPower()
|
||||
#power.connectHTrees( self.hTrees )
|
||||
power.doLayout()
|
||||
Breakpoint.stop( 101, 'After Query power.' )
|
||||
else:
|
||||
power = plugins.alpha.chip.power.Builder( self.conf )
|
||||
power.connectPower()
|
||||
power.connectClocks()
|
||||
power.doLayout()
|
||||
self.conf.refresh()
|
||||
corona = plugins.alpha.chip.corona.Builder( power )
|
||||
corona.connectPads( self.padsCorona )
|
||||
corona.connectCore()
|
||||
corona.doLayout()
|
||||
self.conf.refresh()
|
||||
|
||||
def doPnR ( self ):
|
||||
super(Chip,self).doPnR()
|
||||
self.conf.refresh( self.conf.chip )
|
||||
return self.conf.validated
|
||||
|
||||
def save ( self, flags=0 ):
|
||||
if not self.conf.validated:
|
||||
raise ErrorMessage( 1, 'chip.save(): Chip is not valid, aborting.' )
|
||||
views = CRL.Catalog.State.Logical
|
||||
if self.conf.routingGauge.isSymbolic():
|
||||
views = views | CRL.Catalog.State.Physical
|
||||
super(Chip,self).save( flags )
|
|
@ -0,0 +1,494 @@
|
|||
|
||||
# This file is part of the Coriolis Software.
|
||||
# Copyright (c) Sorbonne Université 2021-2021, 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/harness/pads.py" |
|
||||
# +-----------------------------------------------------------------+
|
||||
|
||||
|
||||
import sys
|
||||
import re
|
||||
from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
|
||||
Box, Transformation , Instance , Net, Pin, \
|
||||
Contact, Horizontal, Vertical, BasicLayer
|
||||
import Viewer
|
||||
from CRL import Catalog, AllianceFramework, DefImport, \
|
||||
RoutingGauge, RoutingLayerGauge
|
||||
from helpers import trace, l, u, n, onFGrid
|
||||
from helpers.io import ErrorMessage, WarningMessage
|
||||
from helpers.overlay import CfgCache, UpdateSession
|
||||
import plugins.alpha.chip
|
||||
from plugins.alpha.chip import CoreWire
|
||||
from plugins.alpha.block.bigvia import BigVia
|
||||
from plugins.alpha.core2chip.core2chip \
|
||||
import CoreToChip as BaseCoreToChip, \
|
||||
IoNet, IoPad
|
||||
|
||||
plugins.alpha.chip.importConstants( globals() )
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
# Class : "harness.pads.Side"
|
||||
|
||||
class Side ( object ):
|
||||
|
||||
def __init__ ( self, harness, sideType ):
|
||||
self.type = sideType
|
||||
self.harness = harness
|
||||
self.gap = 0
|
||||
self.pins = []
|
||||
self.coreWires = []
|
||||
self.padRails = []
|
||||
if self.type == North:
|
||||
self.sideName = 'north'
|
||||
pins = self.harness.conf.chipConf.northPins
|
||||
elif self.type == South:
|
||||
self.sideName = 'south'
|
||||
pins = self.harness.conf.chipConf.southPins
|
||||
elif self.type == East:
|
||||
self.sideName = 'east'
|
||||
pins = self.harness.conf.chipConf.eastPins
|
||||
elif self.type == West:
|
||||
self.sideName = 'west'
|
||||
pins = self.harness.conf.chipConf.westPins
|
||||
else:
|
||||
raise ErrorMessage( 1, 'harness.Side.__init__(): Invalid value for sideType ({})'.format(sideType))
|
||||
for pin in pins:
|
||||
self.pins.append( pin )
|
||||
|
||||
@property
|
||||
def conf ( self ): return self.harness.conf
|
||||
|
||||
def addChipPin ( self, pin ):
|
||||
if self.hasChipPin(pin): return
|
||||
self.pins.append( pin )
|
||||
|
||||
def hasChipPin ( self, pin ):
|
||||
if pin in self.pins: 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 addSupplyRail ( self, component ):
|
||||
if self.type == North or self.type == South:
|
||||
if not isinstance(component,Horizontal):
|
||||
return
|
||||
self.padRails.append( ( component.getNet()
|
||||
, component.getLayer()
|
||||
, component.getY()
|
||||
, component.getWidth() ) )
|
||||
return
|
||||
if self.type == East or self.type == West:
|
||||
if not isinstance(component,Vertical):
|
||||
return
|
||||
self.padRails.append( ( component.getNet()
|
||||
, component.getLayer()
|
||||
, component.getX()
|
||||
, component.getWidth() ) )
|
||||
|
||||
def drawCoreWires ( self ):
|
||||
trace( 550, ',+', '\tSide.drawCoreWire()\n' )
|
||||
size = len(self.coreWires)
|
||||
if not size:
|
||||
trace( 550, '-' )
|
||||
return
|
||||
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()
|
||||
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
|
||||
if offset < size:
|
||||
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 : "harness.pads.Corona"
|
||||
|
||||
class Corona ( object ):
|
||||
"""
|
||||
Perform the placement of the corona instance inside the harness MPRJ
|
||||
space (centered by default). Draw connecting wires from the *edge*
|
||||
of the corona toward the I/O ports. Also connect the power supplies.
|
||||
|
||||
This is a specialized version of ``core2chip/pads.py``
|
||||
"""
|
||||
|
||||
def __init__ ( self, chip ):
|
||||
self.chip = chip
|
||||
self.northSide = Side( self, North )
|
||||
self.southSide = Side( self, South )
|
||||
self.eastSide = Side( self, East )
|
||||
self.westSide = Side( self, West )
|
||||
self.powerCount = 0
|
||||
self._findPowerRails()
|
||||
|
||||
@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
|
||||
|
||||
def _findPowerRails ( self ):
|
||||
"""
|
||||
Affect the power rails segments (horizontals & vertical) to their
|
||||
relevant side. The side is guessed by the position of the segment
|
||||
relative to the harness abutment box, they are assumed to be all
|
||||
fully outside of it.
|
||||
"""
|
||||
trace( 550, '+', '\tCorona._findPowerRails()\n' )
|
||||
coronaAb = self.conf.icorona.getAbutmentBox()
|
||||
for net in self.conf.chip.getNets():
|
||||
if not net.isSupply(): continue
|
||||
for component in net.getComponents():
|
||||
trace( 550, '\tcomponent: {} {}\n'.format(type(component),component) )
|
||||
if not isinstance(component,Horizontal) and not isinstance(component,Vertical):
|
||||
continue
|
||||
trace( 550, '\t| {}\n'.format(component) )
|
||||
bb = component.getBoundingBox()
|
||||
side = None
|
||||
if bb.getXMin() < coronaAb.getXMin(): side = self.westSide
|
||||
if bb.getXMax() > coronaAb.getXMax(): side = self.eastSide
|
||||
if bb.getYMin() < coronaAb.getYMin(): side = self.southSide
|
||||
if bb.getYMax() > coronaAb.getYMax(): side = self.northSide
|
||||
trace( 550, '\tside: {} {}\n'.format(side,component) )
|
||||
if side:
|
||||
trace( 550, '\tAdded on {} side: {}\n'.format(side,component) )
|
||||
side.addSupplyRail( component )
|
||||
trace( 550, '-' )
|
||||
|
||||
def doLayout ( self ):
|
||||
"""
|
||||
Draw the dogleg wires connecting the harness I/O segments to the nearest
|
||||
on grid pin right at the egde of the core.
|
||||
"""
|
||||
trace( 550, ',+', '\tCorona.doLayout()\n' )
|
||||
rg = self.conf.routingGauge
|
||||
coronaSouthGap = 0
|
||||
for layerGauge in rg.getLayerGauges():
|
||||
self.southSide.gap = max( self.southSide.gap, layerGauge.getPitch() * 2 )
|
||||
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():
|
||||
padConnected = 0
|
||||
chipIntNet = coronaPlug.getNet()
|
||||
if not chipIntNet: continue
|
||||
trace( 550, '\tConnexions on chipIntNet: {}\n'.format(chipIntNet) )
|
||||
trace( 550, '\t| coronaPlug: {}\n'.format(coronaPlug) )
|
||||
padConnected = self._createCoreWire( chipIntNet, padConnected )
|
||||
if padConnected == 0:
|
||||
if not (chipIntNet.isSupply() and self.conf.routingGauge.hasPowerSupply()):
|
||||
trace( 550, '-' )
|
||||
raise ErrorMessage( 1, 'ChipToChip._connectCorona(): Harness net "{}" is not connected to the core.' \
|
||||
.format(chipIntNet.getName()) )
|
||||
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 ) )
|
||||
with UpdateSession():
|
||||
self.northSide.drawCoreWires()
|
||||
self.southSide.drawCoreWires()
|
||||
self.eastSide.drawCoreWires()
|
||||
self.westSide.drawCoreWires()
|
||||
trace( 550, '-' )
|
||||
|
||||
def _createCoreWire ( self, chipIntNet, count ):
|
||||
"""
|
||||
Lookup the pin of the chipIntNet and create the CoreWire object.
|
||||
"""
|
||||
trace( 550, ',+', '\tCorona._createCoreWire()\n' )
|
||||
trace( 550, '\tchipIntNet:{}\n'.format(chipIntNet) )
|
||||
pin = None
|
||||
for ipin in chipIntNet.getPins():
|
||||
pin = ipin
|
||||
bb = pin.getBoundingBox()
|
||||
break
|
||||
trace( 550, '\tpin:{}\n'.format(pin) )
|
||||
if not pin or chipIntNet.isSupply():
|
||||
trace( 550, '-' )
|
||||
return count
|
||||
side = None
|
||||
if self.hasSouthChipPin(pin): side = self.southSide
|
||||
elif self.hasNorthChipPin(pin): side = self.northSide
|
||||
elif self.hasEastChipPin (pin): side = self.eastSide
|
||||
elif self.hasWestChipPin (pin): side = self.westSide
|
||||
if not side:
|
||||
trace( 550, '-' )
|
||||
return count
|
||||
trace( 550, '\tside:{}\n'.format(side.sideName) )
|
||||
rg = self.conf.routingGauge
|
||||
lg = rg.getLayerGauge( pin.getLayer() )
|
||||
gapWidth = 0
|
||||
segments = None
|
||||
inPreferredDir = False
|
||||
if side.type == North or side.type == South:
|
||||
if lg.getDirection() == RoutingLayerGauge.Vertical:
|
||||
inPreferredDir = True
|
||||
else:
|
||||
if lg.getDirection() == RoutingLayerGauge.Horizontal:
|
||||
inPreferredDir = True
|
||||
side.addCoreWire( CoreWire( self, chipIntNet, pin, bb, side.type, inPreferredDir, count ) )
|
||||
side.updateGap( side.coreWires[-1].gapWidth )
|
||||
side.coreWires[-1].addJumper = False
|
||||
count += 1
|
||||
trace( 550, '-' )
|
||||
return count
|
||||
|
||||
def hasNorthChipPin ( self, pin ): return self.northSide.hasChipPin(pin)
|
||||
def hasSouthChipPin ( self, pin ): return self.southSide.hasChipPin(pin)
|
||||
def hasEastChipPin ( self, pin ): return self.eastSide.hasChipPin(pin)
|
||||
def hasWestChipPin ( self, pin ): return self.westSide.hasChipPin(pin)
|
||||
|
||||
def doPowerLayout ( self ):
|
||||
if not self.conf.routingGauge.hasPowerSupply(): return
|
||||
with UpdateSession():
|
||||
capViaWidth = self.conf.vDeepRG.getPitch()*4
|
||||
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() )
|
||||
if not chipPowerNet:
|
||||
for net in self.conf.chip.getNets():
|
||||
if chipPowerNet: break
|
||||
if not net.isPower(): continue
|
||||
for plug in net.getPlugs():
|
||||
if plug.getMasterNet() == powerNet:
|
||||
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() )
|
||||
if not chipGroundNet:
|
||||
for net in self.conf.chip.getNets():
|
||||
if chipGroundNet: break
|
||||
if not net.isGround(): continue
|
||||
for plug in net.getPlugs():
|
||||
if plug.getMasterNet() == groundNet:
|
||||
chipGroundNet = net
|
||||
break
|
||||
if not chipGroundNet:
|
||||
raise ErrorMessage( 1, 'pads.Corona.doPowerLayout(): No ground 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 + 3*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() - 3*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 )
|
||||
|
||||
def _supplyToPad ( self, chipNet, coronaNet, coronaAxis, stripeWidth, side ):
|
||||
"""
|
||||
Draw the wires connecting the north/south corona power pins to the
|
||||
harness I/O ring (on both north and south side). This *do not* draw
|
||||
the power lines *inside* the corona.
|
||||
|
||||
.. note:: As the current e-fabless harness use preferred routing
|
||||
directions at 90° to our own (VHV instead of HVH), we must
|
||||
make a "duck" in m4 to reach the north/south bottom power
|
||||
line in m5 without short-circuit...
|
||||
"""
|
||||
trace( 550, ',+', '\tCorona.Builder._supplyToPads()\n' )
|
||||
supplyLayerDepth = self.conf.routingGauge.getPowerSupplyGauge().getDepth()
|
||||
supplyLayer = self.conf.routingGauge.getPowerSupplyGauge().getLayer()
|
||||
supplyBelowLayer = self.conf.routingGauge.getRoutingLayer( supplyLayerDepth-1 )
|
||||
chipLayer = self.conf.getRoutingLayer( self.conf.routingGauge.getPowerSupplyGauge().getDepth() - 1 )
|
||||
coronaAb = self.conf.icorona.getAbutmentBox()
|
||||
chipAxis = coronaAxis + self.conf.icorona.getTransformation().getTx()
|
||||
trace( 550, '\tchipNet={}\n'.format(chipNet) )
|
||||
trace( 550, '\tchipLayer={}\n'.format(chipLayer) )
|
||||
|
||||
if side == North: rails = self.northSide.padRails
|
||||
elif side == South: rails = self.southSide.padRails
|
||||
else:
|
||||
trace( 550, '-' )
|
||||
return
|
||||
trace( 550, '\trails={}\n'.format(rails) )
|
||||
for net, layer, railAxis, width in rails:
|
||||
trace( 550, '\t| powerNet={}\n'.format(net) )
|
||||
if net != chipNet:
|
||||
continue
|
||||
pinDirection = None
|
||||
viaAxis1 = railAxis
|
||||
viaAxis2 = None
|
||||
if side == North:
|
||||
pinDirection = Pin.Direction.NORTH
|
||||
coronaY = coronaAb.getYMax()
|
||||
masterCoronaY = self.conf.icorona.getMasterCell().getAbutmentBox().getYMax()
|
||||
if layer.getMask() == supplyLayer.getMask():
|
||||
viaAxis1 = self.coreSymBb.getYMax()
|
||||
viaAxis2 = railAxis
|
||||
trace( 550, '\tNorth side supply\n' )
|
||||
elif side == South:
|
||||
pinDirection = Pin.Direction.SOUTH
|
||||
coronaY = coronaAb.getYMin()
|
||||
masterCoronaY = self.conf.icorona.getMasterCell().getAbutmentBox().getYMin()
|
||||
if layer.getMask() == supplyLayer.getMask():
|
||||
viaAxis1 = self.coreSymBb.getYMin()
|
||||
viaAxis2 = railAxis
|
||||
trace( 550, '\tSouth side supply\n' )
|
||||
if pinDirection is not None:
|
||||
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)) )
|
||||
if viaAxis2 is not None:
|
||||
via = BigVia( chipNet
|
||||
, supplyLayerDepth
|
||||
, chipAxis
|
||||
, viaAxis2
|
||||
, stripeWidth
|
||||
, width
|
||||
, BigVia.AllowAllExpand
|
||||
)
|
||||
via.mergeDepth( supplyLayerDepth-1 )
|
||||
via.doLayout()
|
||||
Vertical.create( chipNet
|
||||
, supplyBelowLayer
|
||||
, chipAxis
|
||||
, stripeWidth
|
||||
, viaAxis2
|
||||
, viaAxis1
|
||||
)
|
||||
via = BigVia( chipNet
|
||||
, supplyLayerDepth
|
||||
, chipAxis
|
||||
, viaAxis1
|
||||
, 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()
|
||||
Vertical.create( chipNet
|
||||
, supplyLayer
|
||||
, chipAxis
|
||||
, stripeWidth
|
||||
, viaAxis1
|
||||
, coronaY
|
||||
)
|
||||
pin = Pin.create( coronaNet
|
||||
, '{}.{}'.format(coronaNet.getName(),self.powerCount)
|
||||
, pinDirection
|
||||
, Pin.PlacementStatus.FIXED
|
||||
, supplyLayer
|
||||
, coronaAxis
|
||||
, masterCoronaY
|
||||
, stripeWidth
|
||||
, DbU.fromLambda( 1.0 )
|
||||
)
|
||||
trace( 550, '\tpin={}\n'.format(pin) )
|
||||
self.powerCount += 1
|
||||
break
|
||||
trace( 550, '-' )
|
Loading…
Reference in New Issue