From 541b23216c3da112a3b4e26fe88bdaa1136a53e8 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Mon, 2 Nov 2020 17:42:32 +0100 Subject: [PATCH] Support of FlexLib I/O in Core2Chip & chip plugins (alpha). * New: In cumulus/plugins/core2chip/, support for the FlexLib I/O cells symbolic abstracts ("niolib"). More flexible way of specifying the number and positions of the various power pads, both I/O power and core power. For niolib (FlexLib I/O abstract), support for multiple clocks, that is, clock become ordinary pad (with signals typed as CLOCK). * New: In cumulus/plugins/chip/, added support for niolib and final integration of multiple clocks (only for niolib). --- cumulus/src/CMakeLists.txt | 1 + .../src/plugins/alpha/block/configuration.py | 45 ++-- cumulus/src/plugins/alpha/chip/__init__.py | 18 +- cumulus/src/plugins/alpha/chip/chip.py | 2 +- .../src/plugins/alpha/chip/configuration.py | 70 +++--- cumulus/src/plugins/alpha/chip/corona.py | 86 +++++-- cumulus/src/plugins/alpha/chip/pads.py | 210 +++++++++--------- cumulus/src/plugins/alpha/chip/power.py | 57 +++-- cumulus/src/plugins/alpha/core2chip/cmos.py | 14 +- .../src/plugins/alpha/core2chip/core2chip.py | 201 +++++++++++------ cumulus/src/plugins/alpha/core2chip/niolib.py | 151 +++++++++++++ 11 files changed, 573 insertions(+), 282 deletions(-) create mode 100644 cumulus/src/plugins/alpha/core2chip/niolib.py diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index 6247a414..78d167a7 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -60,6 +60,7 @@ set ( pyPluginAlphaC2C ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/__init__.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/niolib.py ) set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 648e16a9..6c384fca 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -422,11 +422,15 @@ class IoPadConf ( object ): | | meta-generated power/ground/clock pads | +---------+-----------------------------------------------------------+ """ - POWER = 0x0001 - GROUND = 0x0002 - CLOCK = 0x0004 - TRISTATE = 0x0008 - BIDIR = 0x0010 + CORE_POWER = 0x0001 + CORE_GROUND = 0x0002 + IO_POWER = 0x0004 + IO_GROUND = 0x0008 + ALL_POWER = 0x0010 + ALL_GROUND = 0x0020 + CLOCK = 0x0040 + TRISTATE = 0x0080 + BIDIR = 0x0100 def __init__ ( self, datas ): if not isinstance(datas,tuple): @@ -438,6 +442,7 @@ class IoPadConf ( object ): self.flags = 0 self.index = None self._datas = list( datas ) + if len(self._datas) == 4: self._datas += [ None, None, None ] if len(self._datas) == 5: self._datas += [ None, None ] elif len(self._datas) == 6: self._datas.insert( 5, None ) self._datas.append( [] ) @@ -445,9 +450,13 @@ class IoPadConf ( object ): m = reSpecialPads.match( self.instanceName ) if m: self.index = m.group('index') - if m.group('type') == 'power' : self.flags |= IoPadConf.POWER - if m.group('type') == 'ground': self.flags |= IoPadConf.GROUND - if m.group('type') == 'clock' : self.flags |= IoPadConf.CLOCK + if m.group('type') == 'allpower': self.flags |= IoPadConf.ALL_POWER + if m.group('type') == 'iopower': self.flags |= IoPadConf.IO_POWER + if m.group('type') == 'power': self.flags |= IoPadConf.CORE_POWER + if m.group('type') == 'allground': self.flags |= IoPadConf.ALL_GROUND + if m.group('type') == 'ioground': self.flags |= IoPadConf.IO_GROUND + if m.group('type') == 'ground': self.flags |= IoPadConf.CORE_GROUND + if m.group('type') == 'clock' : self.flags |= IoPadConf.CLOCK else: if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE @@ -478,7 +487,9 @@ class IoPadConf ( object ): def padSupplyNetName ( self ): return self._datas[3] @property - def coreSupplyNetName ( self ): return self._datas[4] + def coreSupplyNetName ( self ): + if self._datas[4] is not None: return self._datas[4] + return self._datas[3] @property def padClockNetName ( self ): return self._datas[4] @@ -491,12 +502,16 @@ class IoPadConf ( object ): @property def pads ( self ): return self._datas[7] - - def isPower ( self ): return self.flags & IoPadConf.POWER - def isGround ( self ): return self.flags & IoPadConf.GROUND - 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 isCorePower ( self ): return self.flags & IoPadConf.CORE_POWER + def isIoPower ( self ): return self.flags & IoPadConf.IO_POWER + def isAllPower ( self ): return self.flags & IoPadConf.ALL_POWER + def isCoreGround ( self ): return self.flags & IoPadConf.CORE_GROUND + def isIoGround ( self ): return self.flags & IoPadConf.IO_GROUND + def isAllGround ( self ): return self.flags & IoPadConf.ALL_GROUND + 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 __repr__ ( self ): s = ''.format( self.side.getRailNet(self.order) + return ''.format( self.side.getRailNet(self.order).getName() , self.order , DbU.getValueString(self.axis) ) def connect ( self, contact ): + trace( 550, ',+', '\tTry to connect to: {}\n'.format(self) ) contactBb = contact.getBoundingBox() if contactBb.getXMin() < self.side.innerBb.getXMin() \ or contactBb.getXMax() > self.side.innerBb.getXMax(): + trace( 550, '-' ) raise ErrorMessage( 1, [ '{} is outside rail/corona X range,'.format(contact) , 'power pad is likely to be to far off west or east.' , '(core:{})'.format(self.side.innerBb) ] ) if self.vias.has_key(contact.getX()): return False + trace( 550, '\tvias:{}\n'.format(self.vias) ) keys = self.vias.keys() keys.sort() insertIndex = bisect.bisect_left( keys, contact.getX() ) - if len(keys) > 0: + trace( 550, '\tinsertIndex:{}\n'.format(insertIndex) ) if insertIndex < len(keys): insertPosition = keys[ insertIndex ] + trace( 550, '\tinsertPosition:{}\n'.format(insertPosition) ) if contactBb.getXMax() >= self.vias[insertPosition][2].getBoundingBox().getXMin(): + trace( 550, ',-', '\tFailed: overlap with existing contact @{}.\n' \ + .format(self.vias[insertPosition][2]) ) return False if insertIndex > 0: if self.vias[keys[insertIndex-1]][2].getBoundingBox().getXMax() >= contactBb.getXMin(): + trace( 550, ',-', '\tFailed: overlap with existing contact @{}.\n' \ + .format(self.vias[keys[insertIndex-1]][2]) ) return False self.vias[ contact.getX() ] = [ contact.getX() , StackedVia( self.net @@ -144,6 +152,7 @@ class HorizontalRail ( Rail ): , DbU.getValueString(contact.getX()) , DbU.getValueString(self.axis)) ) self.vias[ contact.getX() ][1].mergeDepth( self.side.getLayerDepth(contact.getLayer()) ) + trace( 550, '-' ) return True def doLayout ( self ): @@ -183,7 +192,7 @@ class VerticalRail ( Rail ): trace( 550, '\t{}\n'.format(self) ) def __str__ ( self ): - return ''.format( self.side.getRailNet(self.order) + return ''.format( self.side.getRailNet(self.order).getName() , self.order , DbU.getValueString(self.axis) ) @@ -217,14 +226,14 @@ class VerticalRail ( Rail ): , 'power pad is likely to be to far off north or south.' , '(core:{})'.format(self.side.innerBb) ] ) if self.vias.has_key(contact.getY()): return False - trace( 550, ',+', '\tVerticalRail.connect() [{}] @{}\n'.format(self.order,DbU.toLambda(self.axis)) ) + trace( 550, ',+', '\tVerticalRail.connect() [{}] @{}\n'.format(self.order,DbU.getValueString(self.axis)) ) trace( 550, '\t{}\n'.format(contact) ) keys = self.vias.keys() keys.sort() insertIndex = bisect.bisect_left( keys, contact.getY() ) trace( 550, ',+', '\tkeys:' ) for key in keys: - trace( 550, ' {}'.format(DbU.toLambda(key)) ) + trace( 550, ' {}'.format(DbU.getValueString(key)) ) trace( 550, '\n' ) if len(keys) > 0: @@ -266,9 +275,18 @@ class Side ( object ): def __init__ ( self, corona ): self.corona = corona + @property + def side ( self ): + raise NotImplementedError('Side.side is not implemented in base class.') + @property def railsCount ( self ): return self.corona.railsCount + @property + def coronaCks ( self ): + if self.corona.conf.useClockTree: return self.corona.conf.coronaCks + return [] + @property def innerBb ( self ): return self.corona.innerBb @@ -296,6 +314,7 @@ class Side ( object ): @property def blockageNet ( self ): return self.corona.blockageNet + def isHorizontal ( self ): return (self.side & HORIZONTAL) == HORIZONTAL def getLayerDepth ( self, metal ): return self.corona.getLayerDepth(metal) def getRail ( self, i ): return self.rails[i] def getRailNet ( self, i ): return self.corona.getRailNet(i) @@ -318,27 +337,41 @@ class Side ( object ): return self.rails[-(i+1)] def connect ( self, blockSide ): + trace( 550, '\tSide.connect()\n' ) for terminal in blockSide.terminals: trace( 550, '\tterminal:{}\n'.format(terminal) ) for rail in self.rails: rail.connect( terminal[1] ) + def getRailRange ( self, net ): + if net.isClock(): return range(len(self.rails)) + if not net.isSupply(): return [] + if self.side & HORIZONTAL: + trace( 550, '\tHORIZONTAL rail.\n' ) + return range( len(self.coronaCks), len(self.rails) ) + else: + trace( 550, '\t{} > {}\n'.format(self.horizontalDepth,self.verticalDepth) ) + if self.horizontalDepth > self.verticalDepth: + return range( len(self.coronaCks), len(self.rails) ) + trace( 550, '\tUsing half rails only.\n' ) + return range( len(self.coronaCks) + len(self.rails)/2 - 2, len(self.rails) ) + def connectPads ( self, padSide ): - for contact in padSide.pins: - if contact.getNet().isClock(): - for i in range(len(self.rails)): - trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) ) - self.getOuterRail(i).connect( contact ) - elif contact.getNet().isSupply(): - self.getOuterRail( 0 ).connect( contact ) - halfRails = (len(self.rails)-1)/2 - trace( 550, '\thalfRails:{}\n'.format(halfRails) ) + #for contact in padSide.pins: + # if contact.getNet().isClock(): + # for i in range(len(self.rails)): + # trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.getValueString(self.getOuterRail(i).axis)) ) + # self.getOuterRail(i).connect( contact ) + # elif contact.getNet().isSupply(): + # self.getOuterRail( 0 ).connect( contact ) for contact in padSide.pins: if not contact.getNet().isSupply() and not contact.getNet().isClock(): continue trace( 550, ',+', '\tConnect pad contact {}\n'.format(contact) ) - for i in range(halfRails): - trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.toLambda(self.getOuterRail(i).axis)) ) - self.getOuterRail(i).connect( contact ) + railRange = self.getRailRange( contact.getNet() ) + trace( 550, '\trailRange:{}\n'.format(railRange) ) + for i in railRange: + trace( 550, '\tConnect to [-{}] @{}\n'.format(i, DbU.getValueString(self.getInnerRail(i).axis)) ) + self.getInnerRail(i).connect( contact ) trace( 550, '-' ) def doLayout ( self ): @@ -367,6 +400,9 @@ class SouthSide ( HorizontalSide ): HorizontalSide.__init__( self, corona ) return + @property + def side ( self ): return South + def getRailAxis ( self, i ): return self.innerBb.getYMin() - self.hRailWidth/2 - self.hRailSpace \ - i*(self.hRailWidth + self.hRailSpace) @@ -384,6 +420,9 @@ class NorthSide ( HorizontalSide ): HorizontalSide.__init__( self, corona ) return + @property + def side ( self ): return North + def getRailAxis ( self, i ): return self.innerBb.getYMax() + self.hRailWidth/2 + self.hRailSpace \ + i*(self.hRailWidth + self.hRailSpace) @@ -446,12 +485,15 @@ class WestSide ( VerticalSide ): def __init__ ( self, corona ): VerticalSide.__init__( self, corona ) + @property + def side ( self ): return West + def getRailAxis ( self, i ): return self.innerBb.getXMin() - self.vRailWidth/2 - self.vRailSpace \ - i*(self.vRailWidth + self.vRailSpace) def corner0 ( self, i ): return self.corners[SouthWest][i] - def corner1 ( self, i ): return self.corners[NorthWest ][i] + def corner1 ( self, i ): return self.corners[NorthWest][i] def addBlockages ( self ): sideXMin = self.getOuterRail(0).axis - self.vRailWidth @@ -467,12 +509,15 @@ class EastSide ( VerticalSide ): def __init__ ( self, corona ): VerticalSide.__init__( self, corona ) + @property + def side ( self ): return East + def getRailAxis ( self, i ): return self.innerBb.getXMax() + self.vRailWidth/2 + self.vRailSpace \ + i*(self.vRailWidth + self.vRailSpace) def corner0 ( self, i ): return self.corners[SouthEast][i] - def corner1 ( self, i ): return self.corners[NorthEast ][i] + def corner1 ( self, i ): return self.corners[NorthEast][i] def addBlockages ( self ): sideXMin = self.getInnerRail(0).axis - self.vRailWidth @@ -532,7 +577,8 @@ class Builder ( object ): return self.conf.routingGauge.getLayerDepth( metal ) def getRailNet ( self, i ): - if self.conf.useClockTree and i == 0: return self.conf.coronaCk + if self.conf.useClockTree and i < len(self.conf.coronaCks): + return self.conf.coronaCks[i] if i % 2: return self.conf.coronaVss return self.conf.coronaVdd diff --git a/cumulus/src/plugins/alpha/chip/pads.py b/cumulus/src/plugins/alpha/chip/pads.py index 5e4eb809..19bd983a 100644 --- a/cumulus/src/plugins/alpha/chip/pads.py +++ b/cumulus/src/plugins/alpha/chip/pads.py @@ -278,78 +278,64 @@ class Side ( object ): self.u += gapWidth def _placePad ( self, padInstance ): - if self.type == North: - x = self.conf.chipAb.getXMin() + self.u - y = self.conf.chipAb.getYMax() - - if self.corona.padOrient == Transformation.Orientation.ID: - orientation = Transformation.Orientation.MY - else: - orientation = Transformation.Orientation.ID - y -= self.conf.ioPadHeight - - elif self.type == South: - x = self.conf.chipAb.getXMin() + self.u - y = self.conf.chipAb.getYMin() - - if self.corona.padOrient == Transformation.Orientation.ID: - orientation = Transformation.Orientation.ID - else: - orientation = Transformation.Orientation.MY - y += self.conf.ioPadHeight - - elif self.type == West: - x = self.conf.chipAb.getXMin() - y = self.conf.chipAb.getYMin() + self.u - - if self.corona.padOrient == Transformation.Orientation.ID: - orientation = Transformation.Orientation.R3 - y += padInstance.getMasterCell().getAbutmentBox().getWidth() - else: - orientation = Transformation.Orientation.R1 - x += padInstance.getMasterCell().getAbutmentBox().getHeight() - - elif self.type == East: - x = self.conf.chipAb.getXMax() - y = self.conf.chipAb.getYMin() + self.u - - if self.corona.padOrient == Transformation.Orientation.ID: - orientation = Transformation.Orientation.R1 - else: - orientation = Transformation.Orientation.R3 - x -= padInstance.getMasterCell().getAbutmentBox().getHeight() - y += padInstance.getMasterCell().getAbutmentBox().getWidth() - - padInstance.setTransformation ( Transformation( self.toGrid(x), self.toGrid(y), orientation ) ) - padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED ) - - self.u += padInstance.getMasterCell().getAbutmentBox().getWidth() - - p = None - if self.conf.ioPadGauge.getName() == 'pxlib': - p = re.compile( r'p(?Pv[sd]{2}[ei])ck_px' ) - - if self.conf.ioPadGauge.getName().startswith('phlib'): - p = re.compile( r'p(?Pv[sd]{2})ck2_sp' ) - - if p: - m = p.match( padInstance.getMasterCell().getName() ) - - padName = 'pad' - if m: padName = m.group( 'power' ) - - padNet = padInstance.getMasterCell().getNet( padName ) - #print 'padName:', padName, 'padNet:', padNet - if padNet: - plug = padInstance.getPlug( padNet ) - chipNet = plug.getNet() - - if not chipNet and padNet.isGlobal(): - chipNet = padInstance.getCell().getNet( padNet.getName() ) - - if chipNet: - rp = RoutingPad.create( chipNet, Occurrence(plug), RoutingPad.BiggestArea ) - return + if self.type == North: + x = self.conf.chipAb.getXMin() + self.u + y = self.conf.chipAb.getYMax() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.MY + else: + orientation = Transformation.Orientation.ID + y -= self.conf.ioPadHeight + elif self.type == South: + x = self.conf.chipAb.getXMin() + self.u + y = self.conf.chipAb.getYMin() + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.ID + else: + orientation = Transformation.Orientation.MY + y += self.conf.ioPadHeight + elif self.type == West: + x = self.conf.chipAb.getXMin() + y = self.conf.chipAb.getYMin() + self.u + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R3 + y += padInstance.getMasterCell().getAbutmentBox().getWidth() + else: + orientation = Transformation.Orientation.R1 + x += padInstance.getMasterCell().getAbutmentBox().getHeight() + elif self.type == East: + x = self.conf.chipAb.getXMax() + y = self.conf.chipAb.getYMin() + self.u + if self.corona.padOrient == Transformation.Orientation.ID: + orientation = Transformation.Orientation.R1 + else: + orientation = Transformation.Orientation.R3 + x -= padInstance.getMasterCell().getAbutmentBox().getHeight() + y += padInstance.getMasterCell().getAbutmentBox().getWidth() + padInstance.setTransformation ( Transformation( self.toGrid(x), self.toGrid(y), orientation ) ) + padInstance.setPlacementStatus( Instance.PlacementStatus.FIXED ) + self.u += padInstance.getMasterCell().getAbutmentBox().getWidth() + p = None + if self.conf.ioPadGauge.getName() == 'pxlib': + p = re.compile( r'p(?Pv[sd]{2}[ei])ck_px' ) + if self.conf.ioPadGauge.getName().startswith('phlib'): + p = re.compile( r'p(?Pv[sd]{2})ck2_sp' ) + if self.conf.ioPadGauge.getName() == 'niolib': + p = re.compile( r'(?P(io)?v[sd]{2})' ) + if p: + m = p.match( padInstance.getMasterCell().getName() ) + padName = 'pad' + if m: padName = m.group( 'power' ) + padNet = padInstance.getMasterCell().getNet( padName ) + trace( 550, '\tpadName:{} padNet:{}\n'.format(padName,padNet) ) + if padNet: + plug = padInstance.getPlug( padNet ) + chipNet = plug.getNet() + if not chipNet and padNet.isGlobal(): + chipNet = padInstance.getCell().getNet( padNet.getName() ) + if chipNet: + rp = RoutingPad.create( chipNet, Occurrence(plug), RoutingPad.BiggestArea ) + return def _placePads ( self ): padLength = 0 @@ -483,7 +469,6 @@ class Side ( object ): class CoreWire ( object ): # Should be read from the symbolic technology rules. - viaPitch = DbU.fromLambda( 4.0 ) NoOffset = 0x0000 AtBegin = 0x0001 @@ -501,6 +486,9 @@ class CoreWire ( object ): self.inCoronaRange = True self.arraySize = None self.count = count + self.viaPitch = DbU.fromLambda( 4.0 ) + self.gapWidth = 0 + self._computeCoreLayers() @property def conf ( self ): return self.corona.conf @@ -548,22 +536,22 @@ class CoreWire ( object ): self.symContactSize = ( self.bbSegment.getHeight(), self.bbSegment.getHeight() ) else: self.symContactSize = ( self.bbSegment.getWidth(), self.bbSegment.getWidth() ) - + self.viaPitch = self.conf.getViaPitch( self.symContactLayer ) contactMinSize = 2*self.symContactLayer.getEnclosure( self.symSegmentLayer.getBasicLayer() , Layer.EnclosureH|Layer.EnclosureV ) \ + self.symContactLayer.getMinimalSize() arrayWidth = self.symContactSize[0] - arrayCount = (arrayWidth - contactMinSize) / CoreWire.viaPitch - trace( 550, '\tCoreWire.viaPitch: {}l\n'.format(DbU.toLambda(CoreWire.viaPitch)) ) + arrayCount = (arrayWidth - contactMinSize) / self.viaPitch trace( 550, '\tcontactMinSize: {}l, arrayWidth: {}l, arrayCount: {}\n' \ .format(DbU.toLambda(contactMinSize),DbU.toLambda(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]) ) + #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.' \ @@ -594,7 +582,8 @@ class CoreWire ( object ): xPadMax = xContact xCore = coronaAb.getXMin() if not self.preferredDir: - xPadMax += self.bbSegment.getHeight()/2 + #xPadMax += self.bbSegment.getHeight()/2 + xPadMin += 3*vPitch else: accessDirection = Pin.Direction.EAST xPadMax = self.bbSegment.getXMax() @@ -602,7 +591,8 @@ class CoreWire ( object ): xPadMin = xContact xCore = coronaAb.getXMax() if not self.preferredDir: - xPadMin -= self.bbSegment.getHeight()/2 + #xPadMin -= self.bbSegment.getHeight()/2 + xPadMin -= 3*vPitch hReal = Horizontal.create( self.chipNet , self.padSegment.getLayer() , self.bbSegment.getCenter().getY() @@ -683,16 +673,18 @@ class CoreWire ( object ): yPadMax = self.corona.coreSymBb.getYMin() - self.offset * 2*hPitch yContact = yPadMax yCore = coronaAb.getYMin() - if not self.preferredDir: - yPadMax += self.bbSegment.getWidth()/2 + #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 + #if not self.preferredDir: + # yPadMin -= self.bbSegment.getWidth()/2 + # yPadMin -= 3*hPitch vReal = Vertical.create( self.chipNet , self.padSegment.getLayer() , self.bbSegment.getCenter().getX() @@ -805,9 +797,10 @@ class Corona ( object ): self.padSpacers = [] self.padCorner = [] self.padRails = [] # [ , [net, layer, axis, width] ] - if Cfg.hasParameter('chip.padCoreSide'): - if Cfg.getParamString('chip.padCoreSide').asString().lower() == 'south': - self.padOrient = Transformation.Orientation.MY + self.conf.cfg.chip.padCoreSide = None + if self.conf.cfg.chip.padCoreSide.lower() == 'south': + self.padOrient = Transformation.Orientation.MY + trace( 550, '\tchip.padCoreSide: {}\n'.format(self.conf.cfg.chip.padCoreSide) ) self._allPadsAnalysis() if Cfg.hasParameter('chip.padSpacers'): for spacerName in Cfg.getParamString('chip.padSpacers').asString().split(','): @@ -889,10 +882,10 @@ class Corona ( object ): if plug.getMasterNet().isGlobal(): net = self.conf.cell.getNet( plug.getMasterNet().getName() ) if not net: - raise ErrorMessage( 1, 'PadsCorona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \ + raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \ % plug.getMasterNet().getName(), padCell.getName() ) else: - raise ErrorMessage( 1, 'PadsCorona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \ + raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \ % plug.getMasterNet().getName(), padCell.getName() ) if net: self.padRails.append( ( net @@ -901,12 +894,18 @@ class Corona ( object ): , component.getWidth() ) ) def _createCoreWire ( self, chipIntNet, padNet, padInstance, count ): + trace( 550, ',+', '\tCorona._createCoreWire()\n' ) + trace( 550, '\tchipIntNet:{}\n'.format(chipIntNet) ) + trace( 550, '\tpadNet:{}\n'.format(padNet) ) + trace( 550, '\tpadInstance:{}\n'.format(padInstance) ) side = None if self.hasSouthPad(padInstance): side = self.southSide elif self.hasNorthPad(padInstance): side = self.northSide elif self.hasEastPad (padInstance): side = self.eastSide elif self.hasWestPad (padInstance): side = self.westSide - if not side: return count + if not side: + trace( 550, '-' ) + return count innerBb = self.conf.chip.getAbutmentBox().inflate( -self.conf.ioPadHeight ) rg = self.conf.routingGauge hsegments = {} @@ -946,25 +945,28 @@ class Corona ( object ): coreWires = [] if segments: for segment, bb in segments: - if not inPreferredDir: - if side.type == North or side.type == South: - trace( 550, '\tNorth/South "{}" but RDir H, gapWidth: {}\n' \ - .format(chipIntNet.getName(),DbU.getValueString(bb.getWidth()) ) ) - side.updateGap( bb.getWidth() ) - else: - trace( 550, '\tEast/West "{}" but RDir V, gapWidth: {}\n' \ - .format(chipIntNet.getName(),DbU.getValueString(bb.getHeight())) ) - side.updateGap( bb.getHeight() ) side.addCoreWire( CoreWire( self, chipIntNet, segment, bb, side.type, inPreferredDir, count ) ) + side.updateGap( side.coreWires[-1].gapWidth ) + #if not inPreferredDir: + # if side.type == North or side.type == South: + # trace( 550, '\tNorth/South "{}" but RDir H, gapWidth: {}\n' \ + # .format(chipIntNet.getName(),DbU.getValueString(bb.getWidth()) ) ) + # side.updateGap( bb.getWidth() ) + # else: + # trace( 550, '\tEast/West "{}" but RDir V, gapWidth: {}\n' \ + # .format(chipIntNet.getName(),DbU.getValueString(bb.getHeight())) ) + # side.updateGap( bb.getHeight() ) count += 1 else: if not (chipIntNet.isGlobal() or chipIntNet.isSupply() or chipIntNet.isClock()): - raise ErrorMessage( 1, [ 'PadsCorona._createCoreWire(): In I/O pad "{}" ({},{}),' \ + trace( 550, '-' ) + raise ErrorMessage( 1, [ 'Corona._createCoreWire(): In I/O pad "{}" ({},{}),' \ .format( padInstance.getMasterCell().getName() , padInstance.getName(), padInstance.getTransformation() ) , 'connector "{}" has no suitable segment for net "{}".' \ .format( padNet, chipIntNet.getName() ) ] ) + trace( 550, '-' ) return count def _placeInnerCorona ( self ): diff --git a/cumulus/src/plugins/alpha/chip/power.py b/cumulus/src/plugins/alpha/chip/power.py index 80845a44..6e890869 100644 --- a/cumulus/src/plugins/alpha/chip/power.py +++ b/cumulus/src/plugins/alpha/chip/power.py @@ -15,28 +15,19 @@ import sys -from Hurricane import DbU -from Hurricane import Point -from Hurricane import Transformation -from Hurricane import Box -from Hurricane import Interval -from Hurricane import Path -from Hurricane import Occurrence -from Hurricane import UpdateSession -from Hurricane import Net -from Hurricane import Contact -from Hurricane import Horizontal -from Hurricane import Vertical -from Hurricane import Query +from Hurricane import DbU, Point, Transformation, Box, Interval, \ + Path, Occurrence, UpdateSession, Net, \ + Contact, Horizontal, Vertical, Query import CRL import helpers from helpers import trace -from helpers.io import ErrorMessage -from helpers.io import WarningMessage +from helpers.io import ErrorMessage, WarningMessage from helpers.overlay import UpdateSession import plugins import plugins.chip +__all__ = [ 'Builder' ] + plugins.chip.importConstants( globals() ) @@ -203,28 +194,23 @@ class Builder ( object ): query.doQuery() self.activePlane = None - def connectClock ( self ): - if not self.conf.useClockTree: - print WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." ) - return - if not self.conf.coronaCk: - raise ErrorMessage( 1, 'Cannot build clock terminal as ck is not known.' ) - return + def _connectClock ( self, ck ): + trace( 550, '\tpower.Builder._connectClock() {}\n'.format(ck) ) blockCk = None for plug in self.conf.icore.getPlugs(): - if plug.getNet() == self.conf.coronaCk: + if plug.getNet() == ck: blockCk = plug.getMasterNet() if not blockCk: raise ErrorMessage( 1, 'Block "{}" has no net connected to the clock "{}".' \ - .format(self.conf.icore.getName(),self.conf.coronaCk.getName()) ) + .format(self.conf.icore.getName(),ck.getName()) ) return htPlugs = [] - for plug in self.conf.coronaCk.getPlugs(): + for plug in ck.getPlugs(): if plug.getInstance().isTerminalNetlist(): htPlugs.append( plug ) if len(htPlugs) != 1: message = [ 'Clock "{}" of block "{}" is not organized as a H-Tree ({} plugs).' \ - .format( self.conf.coronaCk.getName() + .format( ck.getName() , self.conf.icore.getName() , len(htPlugs)) ] for plug in htPlugs: @@ -232,13 +218,11 @@ class Builder ( object ): raise ErrorMessage( 1, message ) return with UpdateSession(): - bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()) - , self.conf.coronaCk - , 0 ) + bufferRp = self.conf.rpAccessByOccurrence( Occurrence(htPlugs[0], Path()), ck, 0 ) blockAb = self.block.getAbutmentBox() self.path.getTransformation().applyOn( blockAb ) layerGauge = self.conf.routingGauge.getLayerGauge(self.conf.verticalDepth) - contact = Contact.create( self.conf.coronaCk + contact = Contact.create( ck , self.conf.routingGauge.getRoutingLayer(self.conf.verticalDepth) , bufferRp.getX() , blockAb.getYMax() @@ -249,7 +233,18 @@ class Builder ( object ): self.activePlane = self.planes[ layerGauge.getLayer().getName() ] bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() ) self.path.getTransformation().getInvert().applyOn( bb ) - self.activePlane.addTerminal( self.conf.coronaCk, Plane.Vertical, bb ) + self.activePlane.addTerminal( ck, Plane.Vertical, bb ) + trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) ) + + def connectClocks ( self ): + if not self.conf.useClockTree: + print WarningMessage( "Clock tree generation has been disabled ('chip.clockTree':False)." ) + return + if len(self.conf.coronaCks) == 0: + raise ErrorMessage( 1, 'Cannot build clock terminal as no clock is not known.' ) + return + for ck in self.conf.coronaCks: + self._connectClock( ck ) def doLayout ( self ): with UpdateSession(): diff --git a/cumulus/src/plugins/alpha/core2chip/cmos.py b/cumulus/src/plugins/alpha/core2chip/cmos.py index 223c2a9e..85276401 100644 --- a/cumulus/src/plugins/alpha/core2chip/cmos.py +++ b/cumulus/src/plugins/alpha/core2chip/cmos.py @@ -47,11 +47,11 @@ class CoreToChip ( BaseCoreToChip ): , 'vddi' : None , 'ck' : None # Go through the pads from pck_px. } - self.ioPadInfos = { IoPad.IN : BaseCoreToChip.IoPadInfo( 'pi_px' , 'pad', ['t',] ) - , IoPad.OUT : BaseCoreToChip.IoPadInfo( 'po_px' , 'pad', ['i',] ) - , IoPad.TRI_OUT : BaseCoreToChip.IoPadInfo( 'pot_px' , 'pad', ['i', 'b' ] ) - , IoPad.BIDIR : BaseCoreToChip.IoPadInfo( 'piot_px', 'pad', ['i', 't', 'b' ] ) - } + self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.IN , 'pi_px' , 'pad', ['t',] ) + , BaseCoreToChip.IoPadInfo( IoPad.OUT , 'po_px' , 'pad', ['i',] ) + , BaseCoreToChip.IoPadInfo( IoPad.TRI_OUT, 'pot_px' , 'pad', ['i', 'b'] ) + , BaseCoreToChip.IoPadInfo( IoPad.BIDIR , 'piot_px', 'pad', ['i', 't', 'b'] ) + ] self._getPadLib() return @@ -79,7 +79,7 @@ class CoreToChip ( BaseCoreToChip ): % (self.padLib.getName(),masterCellName) ) return cell - def _buildGroundPads ( self, ioPadConf ): + def _buildAllGroundPads ( self, ioPadConf ): coreNet = self.core .getNet( ioPadConf.coreSupplyNetName ) coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName ) chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName ) @@ -112,7 +112,7 @@ class CoreToChip ( BaseCoreToChip ): self.groundPadCount += 1 self.chipPads += ioPadConf.pads - def _buildPowerPads ( self, ioPadConf ): + def _buildAllPowerPads ( self, ioPadConf ): coreNet = self.core .getNet( ioPadConf.coreSupplyNetName ) coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName ) chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName ) diff --git a/cumulus/src/plugins/alpha/core2chip/core2chip.py b/cumulus/src/plugins/alpha/core2chip/core2chip.py index f65f299c..200a9537 100644 --- a/cumulus/src/plugins/alpha/core2chip/core2chip.py +++ b/cumulus/src/plugins/alpha/core2chip/core2chip.py @@ -44,20 +44,16 @@ The double level chip+corona serves two purpose: """ from __future__ import print_function +from exceptions import NotImplementedError import re -from Hurricane import UpdateSession -from Hurricane import Net -from Hurricane import Instance -from CRL import Catalog -from CRL import AllianceFramework -from helpers import trace -from helpers import netDirectionToStr +from Hurricane import UpdateSession, Net, Instance +from CRL import Catalog, AllianceFramework +from helpers import trace, netDirectionToStr from helpers.overlay import UpdateSession -from helpers.io import ErrorMessage +from helpers.io import ErrorMessage, WarningMessage import plugins.chip from plugins.alpha.block.block import Block -from plugins.alpha.block.configuration import BlockConf -from plugins.alpha.block.configuration import IoPadConf +from plugins.alpha.block.configuration import BlockConf, IoPadConf # ------------------------------------------------------------------- @@ -116,10 +112,12 @@ class IoNet ( object ): , self.chipExtNet , self.chipIntNet ) - def isElem ( self ): return self._flags & IoNet.IsElem - def isEnable ( self ): return self._flags & IoNet.IsEnable - def isGlobal ( self ): return self.isGlobal( self._name ) - def isSpecial ( self ): return self._type != Net.Type.LOGICAL + def isElem ( self ): return self._flags & IoNet.IsElem + def isEnable ( self ): return self._flags & IoNet.IsEnable + def isGlobal ( self ): return self.isGlobal( self._name ) + def isSpecial ( self ): return self._type != Net.Type.LOGICAL + def setFlags ( self, flags ): self._flags |= flags + def resetFlags ( self, flags ): self._flags &= ~flags @property def name ( self ): @@ -169,7 +167,7 @@ class IoNet ( object ): if state == True: self._flags |= IoNet.IsEnable else: self._flags &= ~IoNet.IsEnable - def buildNets ( self, context=DoExtNet ): + def buildNets ( self ): """ Creates the signals in corona and chip Cells, then connect them together. @@ -194,9 +192,9 @@ class IoNet ( object ): self.chipIntNet.setType( netType ) self.coreToChip.icorona.getPlug( self.coronaNet ).setNet( self.chipIntNet ) # Chip "external" net, connected to the pad I/O to the outside world. - if context & IoNet.PadPassthrough: + if self._flags & IoNet.PadPassthrough: self.chipExtNet = self.chipIntNet - elif not self.chipExtNet and (context & IoNet.DoExtNet): + elif not self.chipExtNet and (self._flags & IoNet.DoExtNet): self.chipExtNet = self.coreToChip.chip.getNet( self.chipExtNetName ) if not self.chipExtNet: self.chipExtNet = Net.create( self.coreToChip.chip, self.chipExtNetName ) @@ -274,13 +272,18 @@ class IoPad ( object ): , netDirectionToStr(self.nets[0].coreNet.getDirection()) , self.nets[0].coreNet.getName() , self.padInstanceName )) + if self.coreToChip.getPadInfo(self.direction) is None: + print( WarningMessage( 'IoPad.addNet(): No simple pad in direction {} for "{}", fallback to bi-directional.' \ + .format(netDirectionToStr(self.direction),ioNet.padInstanceName)) ) + self.direction = IoPad.BIDIR elif len(self.nets) == 2: - self.direction = IoPad.TRI_OUT + if self.direction != IoPad.BIDIR: + self.direction = IoPad.TRI_OUT elif len(self.nets) == 3: self.direction = IoPad.BIDIR else: - message = [ 'IoPad.addNet(): More than three core nets on I/O pad "{}".' \ - .format(self.padInstanceName) ] + message = [ 'IoPad.addNet(): More than three core nets ({}) on I/O pad "{}".' \ + .format(len(self.nets),self.padInstanceName) ] for ioNet in self.nets: message += [ "{}".format(ioNet.coreNet) ] raise ErrorMessage( 1, message ) @@ -293,40 +296,48 @@ class IoPad ( object ): enable signal (if any) do not need an external chip signal (it is *not* connected to the outside world). """ - fromCoreNet = None - toCoreNet = None - enableNet = None - for ioNet in self.nets: - context = 0 - if self.direction == IoPad.TRI_OUT: - if ioNet.isEnable(): enableNet = ioNet - else: - fromCoreNet = ioNet - context |= IoNet.DoExtNet - elif self.direction == IoPad.BIDIR: - if ioNet.coreNet.getDirection() == Net.Direction.IN: toCoreNet = ioNet - if ioNet.coreNet.getDirection() == Net.Direction.OUT: - if ioNet.isEnable(): enableNet = ioNet - else: - fromCoreNet = ioNet - context |= IoNet.DoExtNet - else: - context |= IoNet.DoExtNet - fromCoreNet = ioNet - ioNet.buildNets( context ) - if not self.coreToChip.ioPadInfos.has_key(self.direction): + padInfo = self.coreToChip.getPadInfo( self.direction ) + if padInfo is None: raise ErrorMessage( 1, 'IoPad.createPad(): Unsupported direction {} ({}) for pad "{}".' \ .format( self.direction , IoPad.directionToStr(self.direction) , self.padInstanceName )) - padInfo = self.coreToChip.ioPadInfos[ self.direction ] + connexions = [] + # Case of BIDIR as fallback for simple IN/OUT. + if (self.direction == IoPad.BIDIR) and (len(self.nets) < 3): + self.nets[0].setFlags( IoNet.DoExtNet ) + self.nets[0].buildNets() + 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.inputNet ) ) + connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) ) + else: + connexions.append( ( self.nets[0].chipIntNet , padInfo.outputNet ) ) + connexions.append( ( self.coreToChip.newDummyNet(), padInfo.inputNet ) ) + connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) + else: + for ioNet in self.nets: + if not ioNet.isEnable(): + ioNet.setFlags( IoNet.DoExtNet ) + ioNet.buildNets() + connexions.append( ( self.nets[0].chipExtNet, padInfo.padNet ) ) + if self.direction == IoPad.IN: + connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) ) + elif self.direction == IoPad.OUT: + connexions.append( ( self.nets[0].chipIntNet, padInfo.outputNet ) ) + elif self.direction == IoPad.TRI_OUT: + connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) ) + connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) + elif self.direction == IoPad.BUDIR: + 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) ) ) - CoreToChip._connect( self.pads[0], fromCoreNet.chipExtNet, padInfo.padNet ) - CoreToChip._connect( self.pads[0], fromCoreNet.chipIntNet, padInfo.coreNets[0] ) - if toCoreNet: CoreToChip._connect( self.pads[0], toCoreNet.chipIntNet, padInfo.coreNets[-2] ) - if enableNet: CoreToChip._connect( self.pads[0], enableNet.chipIntNet, padInfo.coreNets[-1] ) + for connexion in connexions: + CoreToChip._connect( self.pads[0], connexion[0], connexion[1] ) self.coreToChip.chipPads += self.pads @@ -356,12 +367,35 @@ class CoreToChip ( object ): class IoPadInfo ( object ): - def __init__ ( self, padName, padNet, coreNets ): + def __init__ ( self, flags, padName, padNet, coreNets ): + self.flags = flags self.name = padName self.padNet = padNet self.coreNets = coreNets return + @property + def inputNet ( self ): + if self.flags & (IoPad.IN|IoPad.BIDIR|IoPad.TRI_OUT): + return self.coreNets[0] + return None + + @property + def outputNet ( self ): + if self.flags & (IoPad.IN|IoPad.BIDIR|IoPad.TRI_OUT): + return self.coreNets[1] + elif self.flags & IoPad.OUT: + return self.coreNets[0] + return None + + @property + def enableNet ( self ): + if self.flags & IoPad.BIDIR: + return self.coreNets[2] + elif self.flags & IoPad.TRI_OUT: + return self.coreNets[1] + return None + def getNetType ( self, netName ): raise ErrorMessage( 1, 'coreToChip.getNetType(): This method must be overloaded.' ) @@ -409,7 +443,7 @@ class CoreToChip ( object ): state = block.state self.state = state self.ringNetNames = [] - self.ioPadInfos = {} + self.ioPadInfos = [] self.chipPads = [] self.padLib = None self.corona = None @@ -417,6 +451,7 @@ class CoreToChip ( object ): self.powerPadCount = 0 self.groundPadCount = 0 self.clockPadCount = 0 + self.dummyNetCount = 0 return @property @@ -431,6 +466,12 @@ class CoreToChip ( object ): @property def chip ( self ): return self.state.chip + def getPadInfo ( self, padType ): + for ioPadInfo in self.ioPadInfos: + if ioPadInfo.flags & padType: + return ioPadInfo + return None + def hasIoNet ( self, netName ): """ Look for an IoNet associated to *core* net ``netName``. @@ -438,6 +479,11 @@ class CoreToChip ( object ): if self._ioNets.has_key(netName): return True return False + def newDummyNet ( self ): + dummy = Net.create( self.chip, '{}_dummy_{}'.format(self.chip.getName(),self.dummyNetCount) ) + self.dummyNetCount += 1 + return dummy + def getIoNet ( self, coreNet ): """ Lookup, and create if it doesn't exist, for an IoNet associated to *core* @@ -469,12 +515,12 @@ class CoreToChip ( object ): Build all the I/O pads for normal signals (that are not related to power or clock). """ - if not self.ioPadInfos.has_key(ioNet.coreNet.getDirection()): + padInfo = self.getPadInfo( ioNet.coreNet.getDirection() ) + if not padInfo: raise ErrorMessage( 1, 'CoreToChip._buildStandardPad(): Unsupported direction %d (%s) for core net "%s".' \ % (ioNet.coreNet.getDirection() ,netDirectionToStr(ioNet.coreNet.getDirection()) ,ioNet.coreNet.getName()) ) - padInfo = self.ioPadInfos[ ioNet.coreNet.getDirection() ] ioNet.pads.append( Instance.create( self.chip , ioNet.padInstanceName , self.getCell(padInfo.name) ) ) @@ -482,21 +528,37 @@ class CoreToChip ( object ): CoreToChip._connect( ioNet.pads[0], ioNet.chipIntNet, padInfo.coreNets[0] ) self.chipPads += ioNet.pads - def _buildGroundPads ( self, ioPadConf ): - """Build I/O pad relateds to ground signals.""" - raise NoImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' ) + def _buildCoreGroundPads ( self, ioPadConf ): + """Build I/O pad relateds to core ground signals.""" + raise NotImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' ) - def _buildPowerPads ( self, ioPadConf ): - """Build I/O pad relateds to power signals.""" - raise NoImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' ) + def _buildIoGroundPads ( self, ioPadConf ): + """Build I/O pad relateds to pad internal ground signals.""" + 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.""" + raise NotImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' ) + + def _buildCorePowerPads ( self, ioPadConf ): + """Build I/O pad relateds to core power signals.""" + raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' ) + + def _buildIoPowerPads ( self, ioPadConf ): + """Build I/O pad relateds to pad internal power signals.""" + 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.""" + raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' ) def _buildClockPads ( self, ioPadConf ): """Build I/O pad relateds to clock signals.""" - raise NoImplementedError( 'coreToChip._buildClockPads(): This method must be overloaded.' ) + raise NotImplementedError( 'coreToChip._buildClockPads(): This method must be overloaded.' ) def _connectClocks ( self ): """Connect inner clocks signal to the corona (towards the core) .""" - raise NoImplementedError( 'coreToChip._connectClocks(): This method must be overloaded.' ) + raise NotImplementedError( 'coreToChip._connectClocks(): This method must be overloaded.' ) def buildChip ( self ): """ @@ -504,6 +566,7 @@ class CoreToChip ( object ): from the core cell. """ af = AllianceFramework.get() + self.state.cfg.apply() with UpdateSession(): print( ' o Build Chip from Core.' ) print( ' - Core: "{}".'.format(self.state.cell.getName()) ) @@ -516,11 +579,23 @@ class CoreToChip ( object ): ioPads = [] clockIoNets = [] for ioPadConf in self.state.chipConf.padInstances: - if ioPadConf.isPower(): - self._buildPowerPads( ioPadConf ) + if ioPadConf.isAllPower(): + self._buildAllPowerPads( ioPadConf ) continue - if ioPadConf.isGround(): - self._buildGroundPads( ioPadConf ) + if ioPadConf.isCorePower(): + self._buildCorePowerPads( ioPadConf ) + continue + if ioPadConf.isIoPower(): + self._buildIoPowerPads( ioPadConf ) + continue + if ioPadConf.isAllGround(): + self._buildAllGroundPads( ioPadConf ) + continue + if ioPadConf.isCoreGround(): + self._buildCoreGroundPads( ioPadConf ) + continue + if ioPadConf.isIoGround(): + self._buildIoGroundPads( ioPadConf ) continue if ioPadConf.isClock(): self._buildClockPads( ioPadConf ) diff --git a/cumulus/src/plugins/alpha/core2chip/niolib.py b/cumulus/src/plugins/alpha/core2chip/niolib.py new file mode 100644 index 00000000..9ecde7b2 --- /dev/null +++ b/cumulus/src/plugins/alpha/core2chip/niolib.py @@ -0,0 +1,151 @@ +# -*- coding: utf-8 -*- +# +# This file is part of the Coriolis Software. +# Copyright (c) SU 2019-2020, All Rights Reserved +# +# +-----------------------------------------------------------------+ +# | C O R I O L I S | +# | C u m u l u s - P y t h o n T o o l s | +# | | +# | Author : Jean-Paul CHAPUT | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./plugins/core2chip/niolib.py" | +# +-----------------------------------------------------------------+ + +""" +Core2Chip configuration for the FlexLib I/O pad library ("niolib"). +""" + +from __future__ import print_function +import sys +import re +from Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \ + Transformation , Instance , Net +import Viewer +from CRL import Catalog +from CRL import AllianceFramework +from helpers.io import ErrorMessage, WarningMessage +from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip, \ + IoNet, IoPad + + +class CoreToChip ( BaseCoreToChip ): + rePadType = re.compile(r'(?P.+)_(?P[\d]+)$') + + def __init__ ( self, core ): + BaseCoreToChip.__init__ ( self, core ) + self.ringNetNames = { 'iovdd' : None + , 'iovss' : None + , 'vdd' : None + , 'vss' : None + } + self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.BIDIR, 'gpio', 'pad', ['i', 'o', 'oe'] ) + ] + self._getPadLib() + return + + def _getPadLib ( self ): + self.padLib = AllianceFramework.get().getLibrary( "niolib" ) + if not self.padLib: + message = [ 'CoreToChip.niolib._getPadLib(): Unable to find Alliance "niolib" library' ] + raise ErrorMessage( 1, message ) + + def getNetType ( self, netName ): + if netName.startswith('vss') or netName.startswith('iovss'): return Net.Type.GROUND + if netName.startswith('vdd') or netName.startswith('iovdd'): 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 ): + #cell = self.padLib.getCell( masterCellName ) + cell = AllianceFramework.get().getCell( masterCellName, Catalog.State.Views ) + if not cell: + raise ErrorMessage( 1, 'cmos.getCell(): I/O pad library "%s" does not contain cell named "%s"' \ + % (self.padLib.getName(),masterCellName) ) + return cell + + 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 ) + self.icorona.getPlug( coronaNet ).setNet( chipNet ) + self.ringNetNames['vss'] = chipNet + ioPadConf.pads.append( Instance.create( self.chip + , 'p_vss_{}'.format(ioPadConf.index) + , self.getCell('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('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('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('iovdd') ) ) + self._connect( ioPadConf.pads[0], padNet , 'iovdd' ) + self.powerPadCount += 1 + self.chipPads += ioPadConf.pads + + def _buildClockPads ( self, ioPadConf ): + """For "niolib" there is no specialized clock I/O pad. So do nothing.""" + pass + + def _connectClocks ( self ): + """For "niolib" there is no pad internal clock ring. So do nothing.""" + pass