Move the creation of I/O spacer cells from chip.pads to core2chip.
* Change: In cumulus.plugins.core2chip.CoreToChip, add new methods: * hasCornerCell() (return False) * hasFillerCells() (return False) * getCornerCell() (raise NotImplementedError) * createSpacer() (raise NotImplementedError) * createCorner() (raise NotImplementedError) Those methods needs to be overloaded in derived classes when I/O spacers and corner cells are supplied. In IoPad, add a NON_CONNECT case for dummy pad that are not connected. * New: In cumulus.plugins.chip.pads, delegate spacer & corner creation to the coreToChip concrete class. * New: In cumulus.plugins.block.configuration.IoPadConf, add support for non-connected (dummy) pads.
This commit is contained in:
parent
0bd39fa839
commit
a11e2a4a7d
|
@ -661,7 +661,8 @@ class GaugeConf ( object ):
|
|||
class IoPadConf ( object ):
|
||||
"""
|
||||
Store all informations related to an I/O pad. It's side, position
|
||||
and connected nets.
|
||||
and connected nets. The kind of pad is guessed from the number of
|
||||
nets.
|
||||
|
||||
.. code-block:: python
|
||||
|
||||
|
@ -669,6 +670,7 @@ class IoPadConf ( object ):
|
|||
( IoPin.SOUTH, None, 'a_0' , 'a(0)' , 'a(0)' )
|
||||
( IoPin.NORTH, None, 'p_r0' , 'r0' , 'r0_from_pads', 'shift_r' , 'r0_to_pads' )
|
||||
( IoPin.NORTH, None, 'p_y0' , 'y(0)' , 'y_oe' , 'y_to_pads(0)' )
|
||||
( IoPin.NORTH, None, 'nc_0' )
|
||||
|
||||
self._datas is a table of 8 elements, the seven first coming from
|
||||
the configuration itself. Direction are taken from the core point
|
||||
|
@ -710,17 +712,20 @@ class IoPadConf ( object ):
|
|||
CLOCK = 0x0040
|
||||
TRISTATE = 0x0080
|
||||
BIDIR = 0x0100
|
||||
NON_CONNECT = 0x0200
|
||||
|
||||
def __init__ ( self, datas ):
|
||||
if not isinstance(datas,tuple):
|
||||
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is not a tuple.'
|
||||
if isinstance(datas,list ): self._datas = datas
|
||||
elif isinstance(datas,tuple): self._datas = list( datas )
|
||||
else:
|
||||
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is neither a list nor a tuple.'
|
||||
, str(datas) ] )
|
||||
if len(datas) < 5 and len(datas) > 8:
|
||||
if len(datas) != 3 and len(datas) < 5 and len(datas) > 8:
|
||||
raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" list must have between 5 to 7 elements.'
|
||||
, str(datas) ] )
|
||||
self.flags = 0
|
||||
self.index = None
|
||||
self._datas = list( datas )
|
||||
if len(self._datas) == 3: self._datas += [ None, None, None, None ]
|
||||
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 )
|
||||
|
@ -742,7 +747,8 @@ class IoPadConf ( object ):
|
|||
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
|
||||
if self._datas[3] is None: self.flags |= IoPadConf.NON_CONNECT
|
||||
elif self._datas[5] is not None: self.flags |= IoPadConf.BIDIR
|
||||
elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE
|
||||
sPos = ''
|
||||
if self._datas[1]:
|
||||
|
@ -799,6 +805,7 @@ 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 isNonConnect ( self ): return self.flags & IoPadConf.NON_CONNECT
|
||||
|
||||
def isAnalog ( self ):
|
||||
if self._datas[0] is None: return False
|
||||
|
|
|
@ -149,15 +149,13 @@ class Corner ( object ):
|
|||
|
||||
def _instanciateCorner ( self ):
|
||||
name, transformation = self._getTransformation()
|
||||
corner = Instance.create( self.conf.chip
|
||||
, name, self.corona.padCorner
|
||||
, transformation
|
||||
, Instance.PlacementStatus.FIXED
|
||||
)
|
||||
corner = self.conf.coreToChip.createCorner( name )
|
||||
corner.setTransformation ( transformation )
|
||||
corner.setPlacementStatus( Instance.PlacementStatus.FIXED )
|
||||
|
||||
def doLayout ( self ):
|
||||
if self.corona.padCorner: self._instanciateCorner()
|
||||
else: self._createCorner()
|
||||
if self.conf.coreToChip.hasCornerCell(): self._instanciateCorner()
|
||||
else: self._createCorner()
|
||||
|
||||
|
||||
# --------------------------------------------------------------------
|
||||
|
@ -261,34 +259,55 @@ class Side ( object ):
|
|||
return self.conf.validated
|
||||
|
||||
def _fillPadSpacing ( self, gapWidth ):
|
||||
|
||||
def _getWidth ( spacer ): return spacer.getAbutmentBox().getWidth()
|
||||
|
||||
def _nextSpacer ( iPadSpacer ):
|
||||
while iPadSpacer < len(self.corona.padSpacers) \
|
||||
and gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
|
||||
iPadSpacer += 1
|
||||
return iPadSpacer
|
||||
|
||||
if not self.corona.padSpacers:
|
||||
"""
|
||||
Fill ``gapWidth`` with I/O pad spacer (Use widest cells first).
|
||||
"""
|
||||
if not self.conf.coreToChip.hasFillerCells():
|
||||
self.u += gapWidth
|
||||
return
|
||||
iPadSpacer = 0
|
||||
iPadSpacer = _nextSpacer( iPadSpacer )
|
||||
while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0:
|
||||
gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] )
|
||||
spacer = Instance.create( self.conf.chip
|
||||
, self.spacerNames % self.spacerCount
|
||||
, self.corona.padSpacers[iPadSpacer])
|
||||
self.spacerCount += 1
|
||||
|
||||
while gapWidth > 0:
|
||||
spacer = self.conf.coreToChip.createSpacer( gapWidth )
|
||||
if not spacer:
|
||||
print( ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads @{} on {} side, {} remains.' \
|
||||
.format( DbU.getValueString(self.u)
|
||||
, self.sideName
|
||||
, DbU.getValueString(gapWidth) )))
|
||||
break
|
||||
self._placePad( spacer )
|
||||
if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
|
||||
iPadSpacer = _nextSpacer( iPadSpacer )
|
||||
if gapWidth != 0:
|
||||
print( ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \
|
||||
.format(self.sideName,DbU.getValueString(gapWidth)) ))
|
||||
gapWidth -= spacer.getMasterCell().getAbutmentBox().getWidth()
|
||||
trace( 550, '\tself.u:{} gapWidth:{} after spacer {}\n'.format( DbU.getValueString(self.u)
|
||||
, DbU.getValueString(gapWidth)
|
||||
, spacer ))
|
||||
self.u += gapWidth
|
||||
|
||||
#def _getWidth ( spacer ): return spacer.getAbutmentBox().getWidth()
|
||||
#
|
||||
#def _nextSpacer ( iPadSpacer ):
|
||||
# while iPadSpacer < len(self.corona.padSpacers) \
|
||||
# and gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
|
||||
# iPadSpacer += 1
|
||||
# return iPadSpacer
|
||||
#
|
||||
#if not self.corona.padSpacers:
|
||||
# self.u += gapWidth
|
||||
# return
|
||||
#iPadSpacer = 0
|
||||
#iPadSpacer = _nextSpacer( iPadSpacer )
|
||||
#while iPadSpacer < len(self.corona.padSpacers) and gapWidth > 0:
|
||||
# gapWidth -= _getWidth( self.corona.padSpacers[iPadSpacer] )
|
||||
# spacer = Instance.create( self.conf.chip
|
||||
# , self.spacerNames % self.spacerCount
|
||||
# , self.corona.padSpacers[iPadSpacer])
|
||||
# self.spacerCount += 1
|
||||
# self._placePad( spacer )
|
||||
# if gapWidth < _getWidth(self.corona.padSpacers[iPadSpacer]):
|
||||
# iPadSpacer = _nextSpacer( iPadSpacer )
|
||||
#if gapWidth != 0:
|
||||
# print( ErrorMessage( 1, 'PadsCorona.Side._placePads(): Pad fillers cannot close the gap between pads on {} side, {} remains.' \
|
||||
# .format(self.sideName,DbU.getValueString(gapWidth)) ))
|
||||
#self.u += gapWidth
|
||||
|
||||
def _placePad ( self, padInstance ):
|
||||
padAb = padInstance.getMasterCell().getAbutmentBox()
|
||||
if self.type == North:
|
||||
|
@ -401,7 +420,10 @@ class Side ( object ):
|
|||
for pad in self.pads:
|
||||
self._fillPadSpacing( pad[0] - self.u )
|
||||
self._placePad( pad[1] )
|
||||
self._fillPadSpacing( self.sideLength - self.conf.ioPadHeight - self.u )
|
||||
cornerWidth = self.conf.ioPadHeight
|
||||
if self.conf.coreToChip.hasCornerCell():
|
||||
cornerWidth = self.conf.coreToChip.getCornerCell().getAbutmentBox().getWidth()
|
||||
self._fillPadSpacing( self.sideLength - cornerWidth - self.u )
|
||||
|
||||
def _getUMin ( self, box ):
|
||||
if self.type == North or self.type == South:
|
||||
|
|
|
@ -261,6 +261,7 @@ class IoPad ( object ):
|
|||
UNSUPPORTED = 0x0020
|
||||
FILLER = 0x0040
|
||||
CORNER = 0x0080
|
||||
NON_CONNECT = 0x0100
|
||||
|
||||
@staticmethod
|
||||
def directionToStr ( direction ):
|
||||
|
@ -270,12 +271,13 @@ class IoPad ( object ):
|
|||
if direction == IoPad.TRI_OUT: return "TRI_OUT"
|
||||
if direction == IoPad.ANALOG: return "ANALOG"
|
||||
if direction == IoPad.UNSUPPORTED: return "UNSUPPORTED"
|
||||
if direction == IoPad.NON_CONNECT: return "NON_CONNECT"
|
||||
return "Invalid value"
|
||||
|
||||
def __init__ ( self, coreToChip, ioPadConf ):
|
||||
self.coreToChip = coreToChip
|
||||
self.ioPadConf = ioPadConf
|
||||
self.direction = 0
|
||||
self.direction = IoPad.NON_CONNECT
|
||||
self.nets = []
|
||||
return
|
||||
|
||||
|
@ -363,6 +365,8 @@ class IoPad ( object ):
|
|||
self.nets[0].buildNets()
|
||||
connexions.append( ( self.nets[0].chipExtNet, padInfo.padNet ) )
|
||||
connexions.append( ( self.nets[0].chipIntNet, padInfo.coreNets[1] ) )
|
||||
elif (self.direction == IoPad.NON_CONNECT):
|
||||
pass
|
||||
elif (self.direction == IoPad.BIDIR) and (len(self.nets) < 3):
|
||||
# Case of BIDIR as fallback for simple IN/OUT.
|
||||
self.nets[0].setFlags( IoNet.DoExtNet )
|
||||
|
@ -670,6 +674,26 @@ class CoreToChip ( object ):
|
|||
"""Load the DEF file containing the reference harness layout."""
|
||||
raise NotImplementedError( 'coreToChip._loadHarness(): This method must be overloaded.' )
|
||||
|
||||
def hasCornerCell ( self ):
|
||||
"""Is there a special cell for corners. This method may be overloaded."""
|
||||
return False
|
||||
|
||||
def hasFillerCells ( self ):
|
||||
"""Is there a special cell(s) for filling gaps. This method may be overloaded."""
|
||||
return False
|
||||
|
||||
def getCornerCell ( self, instanceName=None ):
|
||||
"""Return the model of corner cell."""
|
||||
raise NotImplementedError( 'coreToChip.getCornerCell(): This method must be overloaded.' )
|
||||
|
||||
def createSpacer ( self, gapWidth ):
|
||||
"""Return a new instance of spacer cell."""
|
||||
raise NotImplementedError( 'coreToChip.createSpacer(): This method must be overloaded.' )
|
||||
|
||||
def createCorner ( self ):
|
||||
"""Return a new instance of corner cell."""
|
||||
raise NotImplementedError( 'coreToChip.createCorner(): This method must be overloaded' )
|
||||
|
||||
def buildChip ( self ):
|
||||
"""
|
||||
Build the whole chip+corona hierarchical structure (netlist only)
|
||||
|
|
Loading…
Reference in New Issue