Change SkyWater130 Caravel harness connecting strategy.

* Change: In cumulus/plugins/core2chip, instead of the user providing
    an explicit mapping towards the harness I/O pins, we expect that
    the core block must have I/O pins with names matching thoses of
    the harness. That way, connections are automatically made.
* Change: In cumulus/plugins/block/htree, if the root signal of the
    H-Tree is a bit from a vector (like "io_in(0)"), then remove the
    vector index notation on all the stem name of all the sub-nets.
    Done by the unbitify() function: "io_in(0)" => "io_in_bit0".
This commit is contained in:
Jean-Paul Chaput 2021-12-17 15:58:57 +01:00
parent 76d468f6d5
commit ae1f08f039
5 changed files with 150 additions and 75 deletions

View File

@ -661,7 +661,8 @@ class IoPadConf ( object ):
reSpecialPads = re.compile( r'^(?P<type>.+)_(?P<index>[\d+])$' )
m = reSpecialPads.match( self.instanceName )
else:
self.flags |= IoPadConf.ALL_POWER
if self.instanceName is not None:
self.flags |= IoPadConf.ALL_POWER
if m:
self.index = m.group('index')
if m.group('type') == 'allpower': self.flags |= IoPadConf.ALL_POWER
@ -771,6 +772,8 @@ class ChipConf ( object ):
if attr == 'ioPadGauge' and value is not None:
self.blockConf._loadIoPadGauge( value )
def ioPadsCount ( self ): return len(self.padInstances)
def addIoPad ( self, spec, specNb ):
"""
Add an I/O pad specification. The spec argument must be of the form:

View File

@ -15,6 +15,7 @@
import sys
import os.path
import re
import Cfg
from Hurricane import Breakpoint, DbU, Box, Transformation, Box, \
Path, Layer, Occurrence, Net, HyperNet, \
@ -31,6 +32,16 @@ from plugins.alpha.block.configuration import GaugeConf
from plugins.alpha.block.spares import Spares
def unbitify ( rawName ):
"""
Remove the bit indexation from the net name, if any.
"""
p = re.compile( r'(?P<name>.+)\((?P<index>\d+)\)' )
m = p.match( rawName )
if not m: return rawName
return '{}_bit{}'.format( m.group('name'), m.group('index') )
# ----------------------------------------------------------------------------
# Class : "htree.HTree".
@ -223,7 +234,7 @@ class HTree ( object ):
buffers of the leafs of the QuadTree.
"""
qt = self.spares.quadTree
qt.bufferTag = self.treeNet.getName()
qt.bufferTag = unbitify( self.treeNet.getName() )
qt.runselect()
qt.rselectBuffer( self.treeIndex
, self.treeIndex
@ -239,7 +250,7 @@ class HTree ( object ):
"""
bufferConf = self.spares.conf.bufferConf
quadTree = self.spares.quadTree
quadTree.bufferTag = self.treeNet.getName()
quadTree.bufferTag = unbitify( self.treeNet.getName() )
quadTree.runselect()
quadTree.rselectBuffer( self.treeIndex, self.treeIndex, self.flags)
with UpdateSession():

View File

@ -574,7 +574,7 @@ class ChipConf ( BlockConf ):
net = self.corona.getNet( masterNet.getName() )
if not net:
raise ErrorMessage( 1, 'ChipConf.findPowerAndClockNets(): Missing global net "{}" at corona level.' \
.format(asterNet.getName()) )
.format(masterNet.getName()) )
self._validated = False
continue
if netType == Net.Type.GROUND:

View File

@ -57,7 +57,7 @@ from plugins.checks import oneDriver
from plugins.alpha.utils import getPlugByName
from plugins.alpha.block.block import Block
from plugins.alpha.block.configuration import BlockConf, IoPadConf, ConstantsConf
# -------------------------------------------------------------------
# Class : "IoNet".
@ -155,7 +155,10 @@ class IoNet ( object ):
@property
def chipExtNetName ( self ):
if self._chipExtNetName is not None: return self._chipExtNetName
if self._flags & IoNet.IsEnable: return 'None'
if self._flags & IoNet.IsEnable:
if self.coreToChip.useHarness():
return 'io_oeb({})'.format( self._index )
return 'None'
if self.chipExtNet: return self.chipExtNet.getName()
s = self._name
if self._flags & IoNet.IsElem: s += '({})'.format(self._index)
@ -209,7 +212,7 @@ class IoNet ( object ):
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 "{}".' \
raise ErrorMessage( 1, 'IoNet.buildNets(): No 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:
@ -285,7 +288,7 @@ class IoPad ( object ):
def __str__ ( self ):
s = '<IoPad "{}" '.format(self.padInstanceName)
for ioNet in self.nets:
s += ' {}'.format(ioNet.coreNetName)
s += ' "{}" <-> "{}"'.format(ioNet.coreNetName,ioNet.chipExtNetName)
s += ' direction={}'.format(self.direction)
s += '>'
return s
@ -630,33 +633,28 @@ 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.' )
raise NotImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded, on {}' \
.format(ioPadConf) )
def _buildClockPads ( self, ioPadConf ):
"""Build I/O pad relateds to clock signals."""
@ -665,7 +663,6 @@ class CoreToChip ( object ):
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 ):
@ -704,29 +701,37 @@ class CoreToChip ( object ):
ioPads = []
clockIoNets = []
for ioPadConf in self.conf.chipConf.padInstances:
if self.useHarness():
ioPadConf.flags = IoPadConf.BIDIR
trace( 550, ',+', '\tioPadConf={}\n'.format( ioPadConf ))
if ioPadConf.isAllPower():
self._buildAllPowerPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isCorePower():
self._buildCorePowerPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isIoPower():
self._buildIoPowerPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isAllGround():
self._buildAllGroundPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isCoreGround():
self._buildCoreGroundPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isIoGround():
self._buildIoGroundPads( ioPadConf )
trace( 550, '-' )
continue
if ioPadConf.isClock():
self._buildClockPads( ioPadConf )
trace( 550, '-' )
continue
if self.useHarness():
ioPadConf.flags = IoPadConf.BIDIR
ioPadConf.udata = IoPad( self, ioPadConf )
for netName in ioPadConf.nets:
if netName is None: continue
@ -741,12 +746,14 @@ class CoreToChip ( object ):
else:
if ioPadConf.isBidir() or ioPadConf.isTristate():
if coreNet.getName() == ioPadConf.enableNetName:
trace( 550, '\tFlag core net name "{}" as enable\n'.format( coreNet.getName() ))
ioNet.setEnable( True )
if not ioNet.isEnable():
if not ioNet.isEnable() and not self.conf.useHarness:
trace( 550, '\tForce pad net name to "{}"\n'.format( ioPadConf.padNetName ))
ioNet.chipExtNetName = ioPadConf.padNetName
ioPadConf.udata.addNet( ioNet )
ioPads.append( ioPadConf )
trace( 550, '-' )
trace( 550, '\tProcessed all IoPadConf, looking for orphaned core nets...\n' )
for coreNet in self.core.getNets():
if not coreNet.isExternal(): continue
@ -771,8 +778,6 @@ class CoreToChip ( object ):
#trace( 550, '\tNon-configured core net {}, adding {}\n'.format(coreNet,directPad) )
for ioPad in ioPads:
ioPad.udata.createPad()
#if self.useHarness():
# self._connectCorona()
else:
self._connectRing()
self._connectClocks()

View File

@ -33,6 +33,93 @@ from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip, \
IoNet, IoPad
# -------------------------------------------------------------------
# Class : "MatchHarnessIos".
class MatchHarnessIos ( object ):
"""
In case the connections of the core to the I/O pins are not specified
(empty ioPadsSpecs list), try to guess the connection by names.
.. note:: Currently, only matching with the (io_in,io_out,io_oeb),
power and clock are supported.
"""
def __init__ ( self, coreToChip ):
self.coreToChip = coreToChip
self.digitalIos = []
for i in range(38):
self.digitalIos.append( [None, None, None] )
self.clock = None
self.digitalVdd = None
self.digitalVss = None
@property
def conf ( self ): return self.coreToChip.conf
def matchCore ( self ):
print( ' o Using implicit Caravel harness connections.' )
reIoIn = re.compile( r'^(?P<name>\w+)\((?P<index>\d+)\)$' )
for net in self.conf.core.getNets():
if not net.isExternal(): continue
if net.isClock():
self.clock = net
continue
if net.isPower():
self.digitalVdd = net
continue
if net.isGround():
self.digitalVss = net
continue
m = reIoIn.match( net.getName() )
if m:
index = int( m.group('index') )
if index >= 38:
continue
if m.group('name') == 'io_in':
self.digitalIos[ index ][0] = net
elif m.group('name') == 'io_out':
self.digitalIos[ index ][1] = net
elif m.group('name') == 'io_oeb':
self.digitalIos[ index ][2] = net
else:
print( WarningMessage('Unable to match "{}" into harness net.'.format( net.getName() )))
else:
print( WarningMessage('Unable to match "{}" into harness net.'.format( net.getName() )))
if self.digitalVdd:
self.conf.chipConf.addIoPad( (None, None, 'power_0', 'vccd1', self.digitalVdd.getName()), 0 )
else:
print( WarningMessage('Missing digital power net in "{}".'.format(self.conf.core.getName())) )
if self.digitalVss:
self.conf.chipConf.addIoPad( (None, None, 'ground_0', 'vssd1', self.digitalVss.getName()), 0 )
else:
print( WarningMessage('Missing digital ground net in "{}".'.format(self.conf.core.getName())) )
if self.clock:
self.conf.chipConf.addIoPad( (None, None, None, 'user_clock2', self.clock.getName()), 0 )
else:
print( WarningMessage('Missing digital clock net in "{}".'.format(self.conf.core.getName())) )
for i in range(38):
ioNets = self.digitalIos[ i ]
if ioNets[0] and ioNets[1] and ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[0].getName()
, ioNets[0].getName()
, ioNets[1].getName()
, ioNets[2].getName() ), 0 )
elif ioNets[0] and not ioNets[1] and not ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[0].getName()
, ioNets[0].getName() ), 0 )
elif not ioNets[0] and not ioNets[1] and ioNets[2]:
self.conf.chipConf.addIoPad( ( None, None, None, ioNets[2].getName()
, ioNets[2].getName() ), 0 )
elif not ioNets[0] and not ioNets[1] and not ioNets[2]:
continue
else:
print( WarningMessage( [ 'Incomplete digital connexion to I/O pad "{}".'.format(index)
, '* In :{}'.format( ioNets[0] )
, '* Out:{}'.format( ioNets[1] )
, '* OEb:{}'.format( ioNets[2] ) ]))
# --------------------------------------------------------------------
# Class : "sky130.CoreToChip"
@ -70,6 +157,8 @@ class CoreToChip ( BaseCoreToChip ):
, 'pad', ['pad', 'padres'] )
]
self._getPadLib()
if self.conf.chipConf.ioPadsCount() == 0:
MatchHarnessIos( self ).matchCore()
return
def _getPadLib ( self ):
@ -88,80 +177,47 @@ class CoreToChip ( BaseCoreToChip ):
raise NotImplementedError( 'coreToChip.getCell(): Harness does not provides I/O pad cells.' )
def _buildCoreGroundPads ( self, ioPadConf ):
trace( 550, '\tsky130.CoreToChip._buildGroundPowerPads()\n' )
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.padSupplyNetName )
if not coronaNet:
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal( True )
coronaNet.setGlobal ( True )
coronaNet.setType ( Net.Type.GROUND )
coronaNet.setExternal ( True )
coronaNet.setGlobal ( True )
coronaNet.setDirection( Net.Direction.IN )
coronaNet.setType ( Net.Type.GROUND )
self.icore.getPlug( coreNet ).setNet( coronaNet )
trace( 550, '\tCreated corona ground net: {}\n'.format(coronaNet) )
if not chipNet:
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
chipNet.setExternal( True )
chipNet.setType ( Net.Type.GROUND )
raise ErrorMessage( 1, 'Harness do not provide ground net ""{}' \
.format( ioPadConf.padSupplyNetName ))
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 ):
trace( 550, '\tsky130.CoreToChip._buildCorePowerPads()\n' )
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.padSupplyNetName )
if not coronaNet:
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal( True )
coronaNet.setGlobal ( True )
coronaNet.setType ( Net.Type.POWER )
coronaNet.setExternal ( True )
coronaNet.setGlobal ( True )
coronaNet.setDirection( Net.Direction.IN )
coronaNet.setType ( Net.Type.POWER )
self.icore.getPlug( coreNet ).setNet( coronaNet )
trace( 550, '\tCreated corona power net: {}\n'.format(coronaNet) )
if not chipNet:
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
chipNet.setExternal( True )
chipNet.setType ( Net.Type.POWER )
raise ErrorMessage( 1, 'Harness do not provide power net ""{}' \
.format( ioPadConf.padSupplyNetName ))
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' )
coronaPlug = self.icorona.getPlug( coronaNet )
if not coronaPlug.getNet():
coronaPlug.setNet( chipNet )
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."""