diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index 8e585130..4f6fbfcd 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -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 ) diff --git a/cumulus/src/plugins/alpha/block/bigvia.py b/cumulus/src/plugins/alpha/block/bigvia.py index da479f71..e3f2cfff 100644 --- a/cumulus/src/plugins/alpha/block/bigvia.py +++ b/cumulus/src/plugins/alpha/block/bigvia.py @@ -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 diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index bbd193ba..a65cff3f 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -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 diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 0bc7c36f..d93d1daf 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -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.+)_(?P[\d+])$' ) - m = reSpecialPads.match( self.instanceName ) + m = None + if isinstance(self.instanceName,str): + reSpecialPads = re.compile( r'^(?P.+)_(?P[\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 = '= 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, '-' ) diff --git a/cumulus/src/plugins/alpha/chip/chip.py b/cumulus/src/plugins/alpha/chip/chip.py index 1724e9c9..87a110ba 100644 --- a/cumulus/src/plugins/alpha/chip/chip.py +++ b/cumulus/src/plugins/alpha/chip/chip.py @@ -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() diff --git a/cumulus/src/plugins/alpha/chip/configuration.py b/cumulus/src/plugins/alpha/chip/configuration.py index fcb1f0f6..82245b9b 100644 --- a/cumulus/src/plugins/alpha/chip/configuration.py +++ b/cumulus/src/plugins/alpha/chip/configuration.py @@ -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: diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py index f4851394..e173ef90 100644 --- a/cumulus/src/plugins/alpha/chip/pads.py +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -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" diff --git a/cumulus/src/plugins/alpha/chip/powerplane.py b/cumulus/src/plugins/alpha/chip/powerplane.py index a7ce2b5b..5b39a4e4 100644 --- a/cumulus/src/plugins/alpha/chip/powerplane.py +++ b/cumulus/src/plugins/alpha/chip/powerplane.py @@ -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 = ''.format( self.southPin.getNet().getName() - , DbU.getValueString(self.southPin.getX()) ) + s = ''.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() diff --git a/cumulus/src/plugins/alpha/core2chip/core2chip.py b/cumulus/src/plugins/alpha/core2chip/core2chip.py index 12008cc4..969165e0 100644 --- a/cumulus/src/plugins/alpha/core2chip/core2chip.py +++ b/cumulus/src/plugins/alpha/core2chip/core2chip.py @@ -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() diff --git a/cumulus/src/plugins/alpha/core2chip/sky130.py b/cumulus/src/plugins/alpha/core2chip/sky130.py new file mode 100644 index 00000000..984c672c --- /dev/null +++ b/cumulus/src/plugins/alpha/core2chip/sky130.py @@ -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.+)_(?P[\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 diff --git a/cumulus/src/plugins/alpha/harness/configuration.py b/cumulus/src/plugins/alpha/harness/configuration.py deleted file mode 100644 index fcb1f0f6..00000000 --- a/cumulus/src/plugins/alpha/harness/configuration.py +++ /dev/null @@ -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, '-' ) diff --git a/cumulus/src/plugins/alpha/harness/harness.py b/cumulus/src/plugins/alpha/harness/harness.py deleted file mode 100644 index 1724e9c9..00000000 --- a/cumulus/src/plugins/alpha/harness/harness.py +++ /dev/null @@ -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 ) diff --git a/cumulus/src/plugins/alpha/harness/pads.py b/cumulus/src/plugins/alpha/harness/pads.py new file mode 100644 index 00000000..cea1745b --- /dev/null +++ b/cumulus/src/plugins/alpha/harness/pads.py @@ -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, '-' )