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:
Jean-Paul Chaput 2021-12-11 19:52:31 +01:00
parent 2ca9e162ef
commit fe32916d14
14 changed files with 1466 additions and 1383 deletions

View File

@ -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 )

View File

@ -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

View File

@ -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

View File

@ -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():

View File

@ -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, '-' )

View File

@ -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()

View File

@ -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:

View File

@ -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"

View File

@ -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()

View File

@ -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()

View File

@ -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

View File

@ -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, '-' )

View File

@ -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 )

View File

@ -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, '-' )