Added support for real LibreSOCIO pads.

* New: In cumulus/plugins.block.configuration, added class ConstantsConf
    to store information and create instances of "zero" and "one" cells.
    Added attribute in BlockConf class.
* Change: In cumulus/plugins.block.configuration, moved the cell cloning
    and saving from block.spares.Spares to configuration.BlockConf as
    it is a service that can be used by other modules than just spares.
    Other modules may modificate the netlists also, like in XXXX.
* Change: In cumulus/plugins.chip.configuration, in various methods,
    manage both cases when the layer is symbolic or real (difference
    in accessing the underlying BasicLayers).
* Change: In cumulus/plugins.chip.configuration, less clutered display
    of lambda length in trace mode (and use of 'L' as 'l' was too close
    to '1').
* Bug: In cumulus/plugins.chip.corona.VerticalSide.addBlockages(),
    as the clock are now on the *inner* rail(s), blockage must be on
    the *outer* rails (power lines).
* New: In cumulus/plugins.chip.pads.Corner, add support for 45 degree
    corners (cfg setting "chip.use45corners").
* New: In cumulus/plugins.chip.pads.Side.check(), correct computation
    of the side's length. Was using the ioPadStep instead of the pad
    cell width!
* Change: In cumulus/plugins.chip.pads.Corona._padAnalysis(), LibreSOCIO
    pads uses Verticals for their ring wires (common sense would want
    them *Horizontal*). So they must be included in the physical pin
    detection, but in turn this cause havoc in pxlib... So create a
    filtering according to the library name. This is *not* robust
    but will do for now.
* New: In cumulus/plugins.chip.pad.core2chip.CoreToChip, rename
    self.state into self.conf for clarity.
      New method newEnableForNet(), to create "enable" nets on the
    fly for emulated In/Out pads.
      As it can edit the netlist (new "enable" nets) call the
    BlockConf.rsave() method instead of direct saving through
    AllianceFramework.
      Raise NotImplementederror instead of ErrorMessage.
* New: In cumulus/plugins.chip.pad.core2chip.IoPad.createPad(),
    on emulated In/Out I/O pad like for LibreSOC, generate on the fly
    the right enable signal.
      If an enable signal is given, it will be used (backward
    compatible with the previous behavior).
* New: In cumulus/plugins.chip.pad.core2chip, support for real
    LibreSOCIO pads in libresocio.py module.
This commit is contained in:
Jean-Paul Chaput 2020-11-11 14:29:56 +01:00
parent 1b6d5bd09d
commit acc9405ba3
10 changed files with 523 additions and 200 deletions

View File

@ -61,6 +61,7 @@
${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
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/libresocio.py
)
set ( pyPluginAlphaChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/chip/configuration.py

View File

@ -517,14 +517,14 @@ class Block ( object ):
#katana.printConfiguration ()
katana.digitalInit ()
#katana.runNegociatePreRouted()
#Breakpoint.stop( 0, 'Block.route() Before global routing.' )
Breakpoint.stop( 100, 'Block.route() Before global routing.' )
katana.runGlobalRouter ( Katana.Flags.NoFlags )
katana.loadGlobalRouting ( Anabatic.EngineLoadGrByNet )
#Breakpoint.stop( 0, 'Block.route() After global routing.' )
Breakpoint.stop( 100, 'Block.route() After global routing.' )
katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
katana.runNegociate ( Katana.Flags.NoFlags )
success = katana.isDetailedRoutingSuccess()
#Breakpoint.stop( 0, 'Block.route() done, success:{}.'.format(success) )
Breakpoint.stop( 100, 'Block.route() done, success:{}.'.format(success) )
katana.finalizeLayout()
katana.destroy()
return success
@ -639,7 +639,7 @@ class Block ( object ):
def save ( self ):
if not self.conf.validated:
raise ErrorMessage( 1, 'block.save(): Chip is not valid, aborting.' )
self.spares.save()
self.conf.save()
# ----------------------------------------------------------------------------

View File

@ -47,6 +47,18 @@ from plugins import getParameter
from plugins.alpha.utils import getPlugByName
def findCellOutput ( cell, callerName, parameterId ):
"""Find the *external* output net of a cell and return it's name."""
for net in cell.getNets():
if not net.isExternal(): continue
if net.isGlobal(): continue
elif net.getDirection() & Net.Direction.OUT:
return net.getName()
raise ErrorMessage( 3, [ '{}: Cannot guess the input terminal of "{}",' \
.format(callerName,Cfg.getParamString(parameterId).asString())
, ' please check that the Nets directions are set.' ] )
# ----------------------------------------------------------------------------
# Class : "configuration.GaugeConf".
@ -580,7 +592,7 @@ class BufferConf ( object ):
trace( 550, '-' )
raise ErrorMessage( 3, [ 'BufferConf.__init__(): Buffer cell "{}" not found in library,' \
.format(Cfg.getParamString('spares.buffer').asString())
, ' please check the "spares.buffer" configuration parameter in "plugins.conf".' ] )
, ' please check the "spares.buffer" configuration parameter in "plugins.py".' ] )
trace( 550, '\t| masterCell :{}\n'.format(self.masterCell) )
trace( 550, '\t| maximum sinks:{}\n'.format(self.maxSinks) )
self.count = 0
@ -627,6 +639,90 @@ class BufferConf ( object ):
self.count = 0
# ----------------------------------------------------------------------------
# Class : "configuration.ConstantsConf".
class ConstantsConf ( object ):
"""
Store informations on cells used to generate constant signals ("zero"
and "one")
"""
ZERO = 1
ONE = 2
def __init__ ( self, framework, cfg ):
trace( 550, ',+', '\tConstantsConf.__init__()\n' )
cfg.etesian.cell.zero = None
cfg.etesian.cell.one = None
self.zeroCell = framework.getCell( cfg.etesian.cell.zero, CRL.Catalog.State.Views )
self.oneCell = framework.getCell( cfg.etesian.cell.one , CRL.Catalog.State.Views )
if not self.zeroCell:
trace( 550, '-' )
raise ErrorMessage( 3, [ 'ConstantsConf.__init__(): Zero cell "{}" not found in library,' \
.format(cfg.etesian.cell.zero)
, ' please check the "etesian.cell.zero" configuration parameter in "etesian.py".' ] )
if not self.oneCell:
trace( 550, '-' )
raise ErrorMessage( 3, [ 'ConstantsConf.__init__(): One cell "{}" not found in library,' \
.format(cfg.etesian.cell.zero)
, ' please check the "etesian.cell.one" configuration parameter in "etesian.py".' ] )
trace( 550, '\t| zeroCell:{}\n'.format(self.zeroCell) )
trace( 550, '\t| oneCell :{}\n'.format(self.oneCell ) )
self.zeroCount = 0
self.oneCount = 0
self.zeroOutput = findCellOutput( self.zeroCell, 'ConstantsConf.__init__()', 'etesian.cell.zero' )
self.oneOutput = findCellOutput( self.oneCell , 'ConstantsConf.__init__()', 'etesian.cell.one' )
trace( 550, '\t| zeroOutput:"{}"\n'.format(self.zeroOutput) )
trace( 550, '\t| oneOutput :"{}"\n'.format(self.oneOutput ) )
trace( 550, '-' )
return
def name ( self, cellType ):
"""Returns the master cell *name* of the selected type."""
if cellType == ConstantsConf.ZERO: return self.zeroCell.getName()
elif cellType == ConstantsConf.ONE : return self.oneCell .getName()
return None
def output ( self, cellType ):
"""Returns the master cell *output* of the selected type."""
if cellType == ConstantsConf.ZERO: return self.zeroOutput
elif cellType == ConstantsConf.ONE : return self.oneOutput
return None
def width ( self, cellType ):
"""Returns the master cell abutment box width of the selected type."""
if cellType == ConstantsConf.ZERO: return self.zeroCell.getAbutmentBox().getWidth()
elif cellType == ConstantsConf.ONE : return self.oneCell .getAbutmentBox().getWidth()
return None
def height ( self, cellType ):
"""Returns the master cell abutment box height of the selected type."""
if cellType == ConstantsConf.ZERO: return self.zeroCell.getAbutmentBox().getHeight()
elif cellType == ConstantsConf.ONE : return self.oneCell .getAbutmentBox().getHeight()
return None
def createInstance ( self, cell, cellType ):
"""
Create a new zero/one *instance* in Cell. The instance is named "constant_<type>_<Nb>",
where ``<type>`` is the kind of constante (zero or one) and ``<Nb>`` is an ever
incrementing counter (self.<type>count).
"""
instance = None
if cellType == ConstantsConf.ZERO:
instance = Instance.create( cell, 'constant_zero_{}'.format(self.zeroCount), self.zeroCell )
self.zeroCount += 1
elif cellType == ConstantsConf.ONE:
instance = Instance.create( cell, 'constant_one_{}'.format(self.oneCount), self.oneCell )
self.oneCount += 1
return instance
def resetCounts ( self ):
"""Reset the zero/one instance counters (to use only in case of design reset)."""
self.zeroCount = 0
self.oneCount = 0
# ----------------------------------------------------------------------------
# Class : "configuration.FeedsConf".
@ -852,28 +948,30 @@ class BlockConf ( GaugeConf ):
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
super(BlockConf,self).__init__()
self.validated = True
self.editor = None
self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.bufferConf = BufferConf( self.framework )
self.feedsConf = FeedsConf( self.framework )
self.chipConf = ChipConf( self )
self.bColumns = 2
self.bRows = 2
self.cell = cell
self.icore = None
self.icorona = None
self.chip = None
self.fixedWidth = None
self.fixedHeight = None
self.deltaAb = [ 0, 0, 0, 0 ]
self.useClockTree = False
self.useHFNS = False
self.useSpares = True
self.isBuilt = False
self.ioPins = []
self.ioPinsCounts = {}
self.validated = True
self.editor = None
self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.bufferConf = BufferConf( self.framework )
self.constantsConf = ConstantsConf( self.framework, self.cfg )
self.feedsConf = FeedsConf( self.framework )
self.chipConf = ChipConf( self )
self.bColumns = 2
self.bRows = 2
self.cloneds = []
self.cell = cell
self.icore = None
self.icorona = None
self.chip = None
self.fixedWidth = None
self.fixedHeight = None
self.deltaAb = [ 0, 0, 0, 0 ]
self.useClockTree = False
self.useHFNS = False
self.useSpares = True
self.isBuilt = False
self.ioPins = []
self.ioPinsCounts = {}
for ioPinSpec in ioPins:
self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(ioPads)):
@ -957,3 +1055,39 @@ class BlockConf ( GaugeConf ):
def resetBufferCount ( self ):
self.bufferConf.resetBufferCount()
def addClonedCell ( self, masterCell ):
if not masterCell in self.cloneds:
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
self.cloneds.append( masterCell )
return
def rsave ( self, cell ):
"""
Save the complete cell hierarchy. Saves only the physical view, except
for the ones that has been cloned (their names should end up by "_cts"),
for which logical and physical views are to be saved. They are completely
new cells.
"""
flags = CRL.Catalog.State.Physical
if cell.getName().endswith('_cts'):
flags = flags | CRL.Catalog.State.Logical
self.framework.saveCell( cell, flags )
for instance in cell.getInstances():
masterCell = instance.getMasterCell()
if not masterCell.isTerminal():
self.rsave( masterCell )
def save ( self ):
"""
Frontend to BlockConf.rsave(). Append the "_cts" suffix to the cloned
cells, then call rsave().
"""
trace( 550,'\tBlockConf.save() on "{}"\n'.format(self.cell.getName()) )
for cell in self.cloneds:
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
cell.setName( cell.getName()+'_cts' )
if self.chip is None:
self.cell.setName( self.cell.getName()+'_r' )
self.rsave( self.cell )
return

View File

@ -732,7 +732,6 @@ class Spares ( object ):
def __init__ ( self, block ):
self.conf = block.conf
self.quadTree = None
self.cloneds = []
self.strayBuffers = []
def reset ( self ):
@ -838,12 +837,6 @@ class Spares ( object ):
raise ErrorMessage( 2, 'Spares.getFreeBufferUnder(): No more free buffers under {}.'.format(area) )
return leaf.selectFree()
def addClonedCell ( self, masterCell ):
if not masterCell in self.cloneds:
trace( 550, '\tNew cloned cell: "{}"\n'.format(masterCell) )
self.cloneds.append( masterCell )
return
def raddTransNet ( self, topNet, path ):
"""
Add a net through a whole hierarchy of Instance/Cells. The master cells
@ -881,7 +874,7 @@ class Spares ( object ):
trace( 540, '\tSpares.raddTransNet() top:{} path:{}\n'.format(topNet,path) )
if path.isEmpty():
self.addClonedCell( topNet.getCell() )
self.conf.addClonedCell( topNet.getCell() )
return None
tailPath = path.getTailPath()
headInstance = path.getHeadInstance()
@ -898,8 +891,8 @@ class Spares ( object ):
raise ErrorMessage( 3, 'Plug not created for %s on instance %s of %s' \
% (topNet.getName(),headInstance.getName(),masterCell.getName()) )
headPlug.setNet( topNet )
self.addClonedCell( masterCell )
self.addClonedCell( headInstance.getCell() )
self.conf.addClonedCell( masterCell )
self.conf.addClonedCell( headInstance.getCell() )
else:
masterNet = headPlug.getMasterNet()
trace( 540, '\ttailPath {}\n'.format(tailPath) )
@ -909,35 +902,3 @@ class Spares ( object ):
def removeUnusedBuffers ( self ):
with UpdateSession():
self.quadTree.removeUnusedBuffers()
def rsave ( self, cell ):
"""
Save the complete cell hierarchy. Saves only the physical view, except
for the ones that has been cloned (their names should end up by "_cts"),
for which logical and physical views are to be saved. They are completely
new cells.
"""
flags = CRL.Catalog.State.Physical
if cell.getName().endswith('_cts'):
flags = flags | CRL.Catalog.State.Logical
framework.saveCell( cell, flags )
for instance in cell.getInstances():
masterCell = instance.getMasterCell()
if not masterCell.isTerminal():
self.rsave( masterCell )
def save ( self ):
"""
Frontend to Spares.rsave(). Append the "_cts" suffix to the cloned
cells, then call rsave().
"""
trace( 550,'\tSpares.save() on "{}"\n'.format(self.conf.cell.getName()) )
for cell in self.cloneds:
trace( 550, '\tRenaming cloned cell: "{}"\n'.format(cell) )
cell.setName( cell.getName()+'_cts' )
if self.conf.chip is None:
self.conf.cell.setName( self.conf.cell.getName()+'_r' )
self.rsave( self.conf.cell )
return

View File

@ -238,13 +238,17 @@ class ChipConf ( BlockConf ):
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) )
trace( 550, '\taxis: {}l {}\n'.format(DbU.toLambda(axis ), DbU.getValueString(axis )) )
trace( 550, '\twidth: {}l {}\n'.format(DbU.toLambda(width), DbU.getValueString(width)) )
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)
@ -252,8 +256,8 @@ class ChipConf ( BlockConf ):
return axis, width
def toCoronaPitchInChip ( self, uCore, layer ):
trace( 550, ',+', '\tChipConf.toCoronaPitchInChip(): uCore: {}l {}\n' \
.format(DbU.toLambda(uCore), DbU.getValueString(uCore)) )
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()
@ -271,15 +275,15 @@ class ChipConf ( BlockConf ):
else:
uCorona = uCore - coronaAb.getXMin()
uCorona, width = self.toRoutingGauge( uCorona, uCorona, layer )
trace( 550, '\ttoCoronaPitchInChip(): uCorona: {}l {}\n' \
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: {}l %s\n'.format(DbU.toLambda(uCorona), DbU.getValueString(uCorona)) )
trace( 550, '\ttoCoronaPitchInChip(): uCore: {}l %s\n'.format(DbU.toLambda(uCore ), DbU.getValueString(uCore )) )
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
@ -295,16 +299,16 @@ class ChipConf ( BlockConf ):
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:{} ({}l)\n' \
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: {}l or {}\n'.format(DbU.toLambda(coronaY), DbU.getValueString(coronaY)) )
trace( 550, '\t| width:{}l or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
trace( 550, '\t| dxMin:{}l\n'.format(DbU.toLambda(dxMin)) )
trace( 550, '\t| dxMax:{}l\n'.format(DbU.toLambda(dxMax)) )
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, '-' )
@ -324,8 +328,8 @@ class ChipConf ( BlockConf ):
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: {} or {}\n'.format(DbU.toLambda(coronaX), DbU.getValueString(coronaX)) )
trace( 550, '\t| width:{} or {}\n'.format(DbU.toLambda(width) , DbU.getValueString(width)) )
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, '-' )
@ -343,12 +347,13 @@ class ChipConf ( BlockConf ):
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, layer.getBottom() )
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, layer.getBottom() )
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 )
@ -356,10 +361,10 @@ class ChipConf ( BlockConf ):
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} or {:>12}\n'.format(DbU.toLambda(coronaX) , DbU.getValueString(coronaX)) )
trace( 550, '\t| Y axis: {:>12} 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 )) )
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
@ -373,17 +378,20 @@ class ChipConf ( BlockConf ):
def getViaPitch ( self, viaLayer ):
topLayer = viaLayer.getTop()
topPitch = 2*viaLayer.getEnclosure \
( topLayer.getBasicLayer(), Layer.EnclosureH|Layer.EnclosureV ) \
+ viaLayer.getMinimalSize() \
+ topLayer.getMinimalSpacing()
if topLayer.isSymbolic():
topLayer = topLayer.getBasicLayer()
topEnclosure = viaLayer.getEnclosure( topLayer, Layer.EnclosureH|Layer.EnclosureV )
topPitch = 2*topEnclosure + viaLayer.getMinimalSize() + topLayer.getMinimalSpacing()
botLayer = viaLayer.getBottom()
botPitch = 2*viaLayer.getEnclosure \
( botLayer.getBasicLayer(), Layer.EnclosureH|Layer.EnclosureV ) \
+ viaLayer.getMinimalSize() \
+ botLayer.getMinimalSpacing()
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 {}: {}l\n'.format(viaLayer.getName(),DbU.getValueString(viaPitch)) )
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 ):
@ -412,7 +420,7 @@ class ChipConf ( BlockConf ):
xContact = coronaX - viaPitch * (array[0]-1)/2
yContact = coronaY - viaPitch * (array[1]-1)/2
contactSize = layer.getMinimalSize()
trace( 550, '\txContact:{}l yContact:{}l\n'.format(DbU.toLambda(xContact),DbU.toLambda(yContact)) )
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
@ -452,10 +460,10 @@ class ChipConf ( BlockConf ):
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: {} or {}\n'.format(DbU.toLambda(coronaY) , DbU.getValueString(coronaY)) )
trace( 550, '\t| Y axis: {} 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 )) )
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

View File

@ -451,8 +451,10 @@ class VerticalSide ( Side ):
if via[1].getNet() != via[2].getNet(): continue
spans.merge( via[1]._y - via[1]._height/2, via[1]._y + via[1]._height/2 )
routingGauge = self.corona.routingGauge
for depth in range(self.getInnerRail(0).vias.values()[0][1].bottomDepth
,self.getInnerRail(0).vias.values()[0][1].topDepth ):
print( self.getOuterRail(0) )
print( self.getOuterRail(0).vias.values() )
for depth in range(self.getOuterRail(0).vias.values()[0][1].bottomDepth
,self.getOuterRail(0).vias.values()[0][1].topDepth ):
blockageLayer = routingGauge.getRoutingLayer(depth).getBlockageLayer()
pitch = routingGauge.getLayerPitch(depth)
for chunk in spans.chunks:

View File

@ -18,30 +18,16 @@ import sys
import re
from operator import itemgetter
import Cfg
from Hurricane import DbU
from Hurricane import Point
from Hurricane import Transformation
from Hurricane import Interval
from Hurricane import Box
from Hurricane import Path
from Hurricane import Occurrence
from Hurricane import UpdateSession
from Hurricane import Layer
from Hurricane import BasicLayer
from Hurricane import Net
from Hurricane import Pin
from Hurricane import Contact
from Hurricane import Segment
from Hurricane import Horizontal
from Hurricane import Vertical
from Hurricane import RoutingPad
from Hurricane import Instance
from Hurricane import DbU, Point, Transformation, Interval, Box, \
Path, Occurrence, UpdateSession, Layer, \
BasicLayer, Net, Pin, Contact, Segment, \
Horizontal, Vertical, Diagonal, RoutingPad, \
Instance
import CRL
from CRL import RoutingLayerGauge
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.alpha.chip
@ -62,38 +48,58 @@ class Corner ( object ):
def conf ( self ): return self.corona.conf
def _getPoints ( self, axis ):
"""
Compute the various coordinates to draw the corner for a wire
positioned at ``axis`` distance from the *border* of the chip.
xExtend and yExtend are used only in case of 45 degree corners,
the 0.5 ratio is an approximate of ``sqrt(2) - 1``.
"""
if self.type == SouthWest:
xCorner = self.conf.chipAb.getXMin() + axis
yCorner = self.conf.chipAb.getYMin() + axis
xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight
xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) )
yExtend = xExtend
elif self.type == SouthEast:
xCorner = self.conf.chipAb.getXMax() - axis
yCorner = self.conf.chipAb.getYMin() + axis
xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMin() + self.conf.ioPadHeight
xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) )
yExtend = - xExtend
elif self.type == NorthEast:
xCorner = self.conf.chipAb.getXMax() - axis
yCorner = self.conf.chipAb.getYMax() - axis
xBb = self.conf.chipAb.getXMax() - self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight
xExtend = long( 0.5 * float(self.conf.ioPadHeight - axis) )
yExtend = xExtend
elif self.type == NorthWest:
xCorner = self.conf.chipAb.getXMin() + axis
yCorner = self.conf.chipAb.getYMax() - axis
xBb = self.conf.chipAb.getXMin() + self.conf.ioPadHeight
yBb = self.conf.chipAb.getYMax() - self.conf.ioPadHeight
return xCorner, yCorner, xBb, yBb
xExtend = - long( 0.5 * float(self.conf.ioPadHeight - axis) )
yExtend = - xExtend
return xCorner, yCorner, xBb, yBb, xExtend, yExtend
def _createCorner ( self ):
self.corona.conf.cfg.chip.use45corners = None
for rail in self.corona.padRails:
net = rail[0]
layer = rail[1]
axis = rail[2]
width = rail[3]
xCorner, yCorner, xBb, yBb = self._getPoints( axis )
Contact .create( net, layer, xCorner, yCorner, width, width )
Horizontal.create( net, layer, yCorner, width, xCorner, xBb )
Vertical .create( net, layer, xCorner, width, yCorner, yBb )
xCorner, yCorner, xBb, yBb, xExtend, yExtend = self._getPoints( axis )
if self.corona.conf.cfg.chip.use45corners:
Diagonal.create( net, layer, Point(xBb+xExtend,yCorner), Point(xCorner,yBb+yExtend), width )
Horizontal.create( net, layer, yCorner, width, xBb+xExtend, xBb )
Vertical .create( net, layer, xCorner, width, yBb+yExtend, yBb )
else:
Contact .create( net, layer, xCorner, yCorner, width, width )
Horizontal.create( net, layer, yCorner, width, xCorner, xBb )
Vertical .create( net, layer, xCorner, width, yCorner, yBb )
def _getTransformation ( self ):
if self.type == SouthWest:
@ -243,9 +249,10 @@ class Side ( object ):
checkName = 'east pads'
elif self.type == South: checkName = 'south pads'
elif self.type == West: checkName = 'west pads'
self.conf.validated = self._check( len(self.pads) * self.conf.ioPadStep
+ 2*self.conf.ioPadHeight
, checkName ) and self.conf.validated
padLength = 2*self.conf.ioPadHeight
for pad in self.pads:
padLength += pad[1].getMasterCell().getAbutmentBox().getWidth()
self.conf.validated = self._check( padLength, checkName ) and self.conf.validated
return self.conf.validated
def _fillPadSpacing ( self, gapWidth ):
@ -537,13 +544,16 @@ class CoreWire ( object ):
else:
self.symContactSize = ( self.bbSegment.getWidth(), self.bbSegment.getWidth() )
self.viaPitch = self.conf.getViaPitch( self.symContactLayer )
contactMinSize = 2*self.symContactLayer.getEnclosure( self.symSegmentLayer.getBasicLayer()
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: {}l, arrayWidth: {}l, arrayCount: {}\n' \
.format(DbU.toLambda(contactMinSize),DbU.toLambda(arrayWidth),arrayCount) )
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):
@ -731,7 +741,7 @@ class CoreWire ( object ):
if self.arraySize:
if self.side == South: yContact = min( yContact, hStrapBb.getYMin() )
else: yContact = max( yContact, hStrapBb.getYMax() )
trace( 550, '\txCore: %sl %s\n' % (DbU.toLambda(xCore), DbU.getValueString(xCore)) )
trace( 550, '\txCore: {:.1f}L {}\n'.format(DbU.toLambda(xCore), DbU.getValueString(xCore)) )
self.conf.coronaVertical( self.chipNet
, self.symSegmentLayer
, xCore
@ -855,43 +865,52 @@ class Corona ( object ):
if not self.padLib: self.padLib = padCell.getLibrary()
for plug in padInstance.getPlugs():
for component in plug.getMasterNet().getComponents():
if component is None: continue
bb = component.getBoundingBox()
hspan = Interval( bb.getXMin(), bb.getXMax() )
axis = bb.getCenter().getY()
if isinstance(component,Horizontal):
hspan = Interval( component.getBoundingBox().getXMin()
, component.getBoundingBox().getXMax() )
# Specific hack for Alliance pxlib pad library.
if self.conf.ioPadGauge.getName() == 'pxlib':
if plug.getMasterNet().isClock():
hspan.inflate( DbU.fromLambda(5.0) )
else:
hspan.inflate( component.getWidth() / 2 )
if hspan.contains( ab.getXMin() ) or hspan.contains( ab.getXMax() ):
duplicate = False
if self.padOrient == Transformation.Orientation.ID:
axis = component.getY()
else:
axis = self.conf.ioPadHeight - component.getY()
for rail in self.padRails:
if rail[0] == plug.getNet() \
and rail[1] == component.getLayer() \
and rail[2] == axis:
duplicate = True
break
if not duplicate:
net = plug.getNet()
if not net:
if plug.getMasterNet().isGlobal():
net = self.conf.cell.getNet( plug.getMasterNet().getName() )
if not net:
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, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \
% plug.getMasterNet().getName(), padCell.getName() )
if net:
self.padRails.append( ( net
, component.getLayer()
, axis
, component.getWidth() ) )
width = component.getWidth()
elif isinstance(component,Vertical):
width = bb.getHeight()
else:
continue
# Specific hack for Alliance pxlib pad library.
if self.conf.ioPadGauge.getName() == 'pxlib':
if isinstance(component,Vertical):
continue
if plug.getMasterNet().isClock():
hspan.inflate( DbU.fromLambda(5.0) )
else:
hspan.inflate( component.getWidth() / 2 )
if hspan.contains( ab.getXMin() ) or hspan.contains( ab.getXMax() ):
duplicate = False
if self.padOrient == Transformation.Orientation.ID:
pass
else:
axis = self.conf.ioPadHeight - axis
for rail in self.padRails:
if rail[0] == plug.getNet() \
and rail[1] == component.getLayer() \
and rail[2] == axis:
duplicate = True
break
if not duplicate:
net = plug.getNet()
if not net:
if plug.getMasterNet().isGlobal():
net = self.conf.cell.getNet( plug.getMasterNet().getName() )
if not net:
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, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \
% plug.getMasterNet().getName(), padCell.getName() )
if net:
self.padRails.append( ( net
, component.getLayer()
, axis
, width ) )
def _createCoreWire ( self, chipIntNet, padNet, padInstance, count ):
trace( 550, ',+', '\tCorona._createCoreWire()\n' )
@ -906,6 +925,12 @@ class Corona ( object ):
if not side:
trace( 550, '-' )
return count
if chipIntNet.isPower() and not padInstance.getName().startswith('p_vdd'):
trace( 550, '-' )
return count
if chipIntNet.isGround() and not padInstance.getName().startswith('p_vss'):
trace( 550, '-' )
return count
innerBb = self.conf.chip.getAbutmentBox().inflate( -self.conf.ioPadHeight )
rg = self.conf.routingGauge
hsegments = {}

View File

@ -155,7 +155,10 @@ class GoCb ( object ):
if go.getNet().getType() == long(Net.Type.GROUND): rootNet = self.block.conf.coronaVss
if not rootNet: return
if self.block.activePlane:
bb = go.getBoundingBox( self.block.activePlane.metal.getBasicLayer() )
layer = self.block.activePlane.metal
if layer.isSymbolic():
layer = layer.getBasicLayer()
bb = go.getBoundingBox( layer )
query.getPath().getTransformation().applyOn( bb )
self.block.activePlane.addTerminal( rootNet, direction, bb )
else:
@ -190,7 +193,10 @@ class Builder ( object ):
query.setFilter( Query.DoComponents|Query.DoTerminalCells )
for layerGauge in self.conf.routingGauge.getLayerGauges():
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
query.setBasicLayer( layerGauge.getLayer().getBasicLayer() )
layer = layerGauge.getLayer()
if layer.isSymbolic():
layer = layer.getBasicLayer()
query.setBasicLayer( layer )
query.doQuery()
self.activePlane = None
@ -231,7 +237,10 @@ class Builder ( object ):
)
segment = self.conf.createVertical( bufferRp, contact, bufferRp.getX(), 0 )
self.activePlane = self.planes[ layerGauge.getLayer().getName() ]
bb = segment.getBoundingBox( self.activePlane.metal.getBasicLayer() )
layer = self.activePlane.metal
if layer.isSymbolic():
layer = layer.getBasicLayer()
bb = segment.getBoundingBox( layer )
self.path.getTransformation().getInvert().applyOn( bb )
self.activePlane.addTerminal( ck, Plane.Vertical, bb )
trace( 550, '\tAdded terminal of {} to vertical plane @{}\n'.format(ck,bb) )

View File

@ -52,8 +52,9 @@ from helpers import trace, netDirectionToStr
from helpers.overlay import UpdateSession
from helpers.io import ErrorMessage, WarningMessage
import plugins.chip
from plugins.alpha.utils import getPlugByName
from plugins.alpha.block.block import Block
from plugins.alpha.block.configuration import BlockConf, IoPadConf
from plugins.alpha.block.configuration import BlockConf, IoPadConf, ConstantsConf
# -------------------------------------------------------------------
@ -307,6 +308,9 @@ class IoPad ( object ):
if (self.direction == IoPad.BIDIR) and (len(self.nets) < 3):
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()
connexions.append( ( self.nets[0].chipExtNet, padInfo.padNet ) )
if self.nets[0].coreNet.getDirection() == Net.Direction.IN:
@ -329,7 +333,7 @@ class IoPad ( object ):
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:
elif self.direction == IoPad.BIDIR:
connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) )
connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) )
connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) )
@ -398,13 +402,13 @@ class CoreToChip ( object ):
def getNetType ( self, netName ):
raise ErrorMessage( 1, 'coreToChip.getNetType(): This method must be overloaded.' )
raise NotImplementedError( 'coreToChip.getNetType(): This method must be overloaded.' )
def isGlobal ( self, netName ):
raise ErrorMessage( 1, 'coreToChip.isGlobal(): This method must be overloaded.' )
raise NotImplementedError( 'coreToChip.isGlobal(): This method must be overloaded.' )
def getCell ( self, masterCellName ):
raise ErrorMessage( 1, 'coreToChip.getCell(): This method must be overloaded.' )
raise NotImplementedError( 'coreToChip.getCell(): This method must be overloaded.' )
@staticmethod
def _connect ( instance, netO, masterNetO=None ):
@ -431,17 +435,17 @@ class CoreToChip ( object ):
def __init__ ( self, core ):
if isinstance(core,Block):
state = core.state
conf = core.state
elif isinstance(core,BlockConf):
state = core
conf = core
else:
block = Block.lookup( core )
if not block:
raise ErrorMessage( 1, [ 'Core2Chip.__init__(): Core cell "{}" has no Block defined.' \
.format( core.getName() )
] )
state = block.state
self.state = state
conf = block.state
self.conf = conf
self.ringNetNames = []
self.ioPadInfos = []
self.chipPads = []
@ -455,16 +459,16 @@ class CoreToChip ( object ):
return
@property
def core ( self ): return self.state.cell
def core ( self ): return self.conf.cell
@property
def icore ( self ): return self.state.icore
def icore ( self ): return self.conf.icore
@property
def icorona ( self ): return self.state.icorona
def icorona ( self ): return self.conf.icorona
@property
def chip ( self ): return self.state.chip
def chip ( self ): return self.conf.chip
def getPadInfo ( self, padType ):
for ioPadInfo in self.ioPadInfos:
@ -480,10 +484,30 @@ class CoreToChip ( object ):
return False
def newDummyNet ( self ):
"""Create a dummy net in *chip* cell (for unconnected terminals)."""
dummy = Net.create( self.chip, '{}_dummy_{}'.format(self.chip.getName(),self.dummyNetCount) )
self.dummyNetCount += 1
return dummy
def newEnableForNet ( self, ioNet ):
"""
Create a new enable signal, in *core* cell, to control the associated I/O pad.
This is to be used in the case of bi-directional I/O pads used as simples inputs
or outputs.
"""
if ioNet.coreNet.getDirection() & Net.Direction.IN: constantType = ConstantsConf.ZERO
elif ioNet.coreNet.getDirection() & Net.Direction.OUT: constantType = ConstantsConf.ONE
else:
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.setExternal ( True )
enable.setDirection( Net.Direction.OUT )
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable )
self.conf.addClonedCell( self.conf.core )
return enable
def getIoNet ( self, coreNet ):
"""
Lookup, and create if it doesn't exist, for an IoNet associated to *core*
@ -566,19 +590,19 @@ class CoreToChip ( object ):
from the core cell.
"""
af = AllianceFramework.get()
self.state.cfg.apply()
self.conf.cfg.apply()
with UpdateSession():
print( ' o Build Chip from Core.' )
print( ' - Core: "{}".'.format(self.state.cell.getName()) )
print( ' - Core: "{}".'.format(self.conf.cell.getName()) )
print( ' - Corona: "{}".'.format('corona') )
print( ' - Chip: "{}".'.format(self.state.chipConf.name) )
self.state.chip = af.createCell( self.state.chipConf.name )
self.corona = af.createCell( 'corona' )
self.state.icore = Instance.create( self.corona , 'core' , self.state.cell )
self.state.icorona = Instance.create( self.state.chip, 'corona', self.corona )
print( ' - Chip: "{}".'.format(self.conf.chipConf.name) )
self.conf.chip = af.createCell( self.conf.chipConf.name )
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 )
ioPads = []
clockIoNets = []
for ioPadConf in self.state.chipConf.padInstances:
for ioPadConf in self.conf.chipConf.padInstances:
if ioPadConf.isAllPower():
self._buildAllPowerPads( ioPadConf )
continue
@ -638,5 +662,4 @@ class CoreToChip ( object ):
ioPad.udata.createPad()
self._connectRing()
self._connectClocks()
af.saveCell( self.chip , Catalog.State.Logical )
af.saveCell( self.corona, Catalog.State.Logical )
self.conf.rsave( self.chip )

View File

@ -0,0 +1,160 @@
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) SU 2020-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/libresocio.py" |
# +-----------------------------------------------------------------+
"""
Core2Chip configuration for the FlexLib I/O pad library.
It provides the same features as the symbolic "niolib", but is
using the real cells provided by LibreSOC.py. For now, apart from
cell library change, the only difference is that the cell names are
in upppercase. We can use them because, in real mode, we are less
dependent from the Alliance design flow.
"""
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 ):
"""
Provide pad-specific part for LibreSOCIO I/O pads (works in real mode).
"""
rePadType = re.compile(r'(?P<type>.+)_(?P<index>[\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', ['s', 'd', 'de'] )
]
self._getPadLib()
return
def _getPadLib ( self ):
self.padLib = AllianceFramework.get().getLibrary( "LibreSOCIO" )
if not self.padLib:
message = [ 'CoreToChip.libresocio._getPadLib(): Unable to find Alliance "LibreSOCIO" 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, 'libresocio.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 "LibreSOCIO" there is no specialized clock I/O pad. So do nothing."""
pass
def _connectClocks ( self ):
"""For "LibreSOCIO" there is no pad internal clock ring. So do nothing."""
pass