Support for gf180mcu native I/O pads.

* Bug: In CRL/technos.node180.gf180mcu_c4m.iolib.py, remove the VDD and
    VSS ring terminals in the pad as only *some* of the have it.
    Assume that it is a bug from GF. The power rail will still be ok
    as it connect by abutment (with the filler & other I/O pads).
* New: In cumulus.plugins.block.configuration.py, added support for
    iterable I/O pad specifications in ioPads argument.
* New: In cumulus.plugins.core2chip.core2chip.py, add support for
    any number of control signals on I/O pads. Not fully implemented
    yet, as we only allow to hard-wire them either to one or zero.
      Raise an error if _connect() fails to find a master net, so
    we don't fail strangely later...
This commit is contained in:
Jean-Paul Chaput 2023-09-25 23:50:20 +02:00
parent 4420da664e
commit 9274c21c14
9 changed files with 334 additions and 31 deletions

View File

@ -181,7 +181,7 @@ def _routing ():
cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = 5
cfg.katana.globalRipupLimit = [1, None] cfg.katana.globalRipupLimit = [1, None]
cfg.katana.longGlobalRipupLimit = 5 cfg.katana.longGlobalRipupLimit = 5
cfg.chip.padCoreSide = 'South' cfg.chip.padCoreSide = 'North'
# Plugins setup # Plugins setup
cfg.clockTree.minimumSide = u(5.04) * 6 cfg.clockTree.minimumSide = u(5.04) * 6
cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2' cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2'

View File

@ -99,6 +99,10 @@ def _routing():
) )
af.addCellGauge(cg) af.addCellGauge(cg)
af.setCellGauge('StdCell3V3Lib') af.setCellGauge('StdCell3V3Lib')
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )
lg5.setType( CRL.RoutingLayerGauge.PowerSupply )
env = af.getEnvironment()
env.setRegister( '.*sff.*' )
# Place & Route setup # Place & Route setup
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg: with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
@ -162,17 +166,8 @@ def _routing():
cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = 5
cfg.katana.globalRipupLimit = [1, None] cfg.katana.globalRipupLimit = [1, None]
cfg.katana.longGlobalRipupLimit = 5 cfg.katana.longGlobalRipupLimit = 5
cfg.chip.padCoreSide = 'South'
# Plugins setup
with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg:
cfg.viewer.minimumSize = 500 cfg.viewer.minimumSize = 500
cfg.viewer.pixelThreshold = 10 cfg.viewer.pixelThreshold = 10
cfg.chip.block.rails.count = 5
cfg.chip.block.rails.hWidth = u(2.68)
cfg.chip.block.rails.vWidth = u(2.68)
cfg.chip.block.rails.hSpacing = u(0.7)
cfg.chip.block.rails.vSpacing = u(0.7)
cfg.clockTree.minimumSide = l(600) cfg.clockTree.minimumSide = l(600)
cfg.clockTree.buffer = 'buf_x1' cfg.clockTree.buffer = 'buf_x1'
cfg.clockTree.placerEngine = 'Etesian' cfg.clockTree.placerEngine = 'Etesian'

View File

@ -27,8 +27,9 @@ def _routing ():
cfg.chip.block.rails.vWidth = u(30.0) cfg.chip.block.rails.vWidth = u(30.0)
cfg.chip.block.rails.hSpacing = u( 6.0) cfg.chip.block.rails.hSpacing = u( 6.0)
cfg.chip.block.rails.vSpacing = u( 6.0) cfg.chip.block.rails.vSpacing = u( 6.0)
cfg.chip.padCorner = 'gf180mcu_fd_io__cor_5lm' #cfg.chip.padCorner = 'gf180mcu_fd_io__cor'
cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10_5lm,gf180mcu_fd_io__fill5_5lm,gf180mcu_fd_io__fill1_5lm' #cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10,gf180mcu_fd_io__fill5,gf180mcu_fd_io__fill1'
cfg.chip.padCoreSide = 'North'
af = AllianceFramework.get() af = AllianceFramework.get()
cg = CellGauge.create( 'LEF.GF_IO_Site' cg = CellGauge.create( 'LEF.GF_IO_Site'
, 'Metal2' # pin layer name. , 'Metal2' # pin layer name.
@ -57,7 +58,6 @@ def _loadIoLib ( pdkDir ):
print( ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() )) print( ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() ))
io.vprint( 1, ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() )) io.vprint( 1, ' o Setup GF180MCU I/O library in {}.'.format( ioLib.getName() ))
cellsDir = pdkDir / 'libraries' / 'gf180mcu_fd_io' / 'latest' / 'cells' cellsDir = pdkDir / 'libraries' / 'gf180mcu_fd_io' / 'latest' / 'cells'
print( cellsDir )
for lefFile in cellsDir.glob( '*/*_5lm.lef' ): for lefFile in cellsDir.glob( '*/*_5lm.lef' ):
print( lefFile ) print( lefFile )
gdsFile = lefFile.with_suffix( '.gds' ) gdsFile = lefFile.with_suffix( '.gds' )
@ -65,6 +65,12 @@ def _loadIoLib ( pdkDir ):
Gds.setTopCellName( gdsFile.stem[:-4] ) Gds.setTopCellName( gdsFile.stem[:-4] )
Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages ) Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages )
LefImport.load( lefFile.as_posix() ) LefImport.load( lefFile.as_posix() )
# Demote the VDD/VSS nets until we understand how that works.
for cell in ioLib.getCells():
for net in cell.getNets():
if net.getName() in ('VDD', 'VSS'):
net.setExternal( False )
net.setGlobal( False )
af.wrapLibrary( ioLib, 1 ) af.wrapLibrary( ioLib, 1 )

View File

@ -65,6 +65,7 @@
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/niolib.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/niolib.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/sky130.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/sky130.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/gf180mcu.py
) )
set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py set ( pyPluginChip ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/__init__.py
${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py

View File

@ -284,7 +284,6 @@ def setupGf180mcu_c4m ( checkToolkit=None
cfg.misc.verboseLevel2 = True cfg.misc.verboseLevel2 = True
cfg.etesian.graphics = 3 cfg.etesian.graphics = 3
cfg.etesian.spaceMargin = 0.10 cfg.etesian.spaceMargin = 0.10
cfg.anabatic.topRoutingLayer = 'metal6'
cfg.katana.eventsLimit = 4000000 cfg.katana.eventsLimit = 4000000
af = CRL.AllianceFramework.get() af = CRL.AllianceFramework.get()
lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 ) lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 )

View File

@ -15,6 +15,7 @@
import sys import sys
import re import re
import os.path import os.path
import collections
from operator import itemgetter from operator import itemgetter
from ... import Cfg from ... import Cfg
from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \ from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \
@ -1449,6 +1450,21 @@ class BlockConf ( GaugeConf ):
for ioPinSpec in self.ioPinsArg: for ioPinSpec in self.ioPinsArg:
self.ioPins.append( IoPin( *ioPinSpec ) ) self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(self.ioPadsArg)): for line in range(len(self.ioPadsArg)):
bits = []
if not isinstance(self.ioPadsArg[line][-1],str) \
and isinstance(self.ioPadsArg[line][-1],collections.Iterable):
bits = self.ioPadsArg[line][-1]
elif isinstance(self.ioPadsArg[line][-1],int):
bits = range( self.ioPadsArg[line][-1] )
if bits != []:
for bit in bits:
spec = [ self.ioPadsArg[line][0]
, self.ioPadsArg[line][1]
]
for i in range( 2, len(self.ioPadsArg[line])-1 ):
spec.append( self.ioPadsArg[line][i].format( bit ))
self.chipConf.addIoPad( spec, line )
else:
self.chipConf.addIoPad( self.ioPadsArg[line], line ) self.chipConf.addIoPad( self.ioPadsArg[line], line )
trace( 550, ',-' ) trace( 550, ',-' )

View File

@ -693,11 +693,11 @@ class Corona ( object ):
if plug.getMasterNet().isGlobal(): if plug.getMasterNet().isGlobal():
net = self.conf.cell.getNet( plug.getMasterNet().getName() ) net = self.conf.cell.getNet( plug.getMasterNet().getName() )
if not net: if not net:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is not connected and there is no global net (in pad \"%s").' \ raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is not connected and there is no global net (in pad "{}").' \
% plug.getMasterNet().getName(), padCell.getName() ) .format( plug.getMasterNet().getName(), padCell.getName() ))
else: else:
raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "%s" is neither connected nor global (in pad \"%s").' \ raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is neither connected nor global (in pad "{}").' \
% plug.getMasterNet().getName(), padCell.getName() ) .format( plug.getMasterNet().getName(), padCell.getName() ))
if net: if net:
self.padRails.append( ( net self.padRails.append( ( net
, component.getLayer() , component.getLayer()

View File

@ -375,6 +375,7 @@ class IoPad ( object ):
or self.nets[0].chipExtNetName.startswith('io_in') \ or self.nets[0].chipExtNetName.startswith('io_in') \
or self.nets[0].chipExtNetName.startswith('io_out') or self.nets[0].chipExtNetName.startswith('io_out')
if hasEnable: if hasEnable:
trace( 550, '\tself.nets = {}\n'.format( self.nets ))
if len(self.nets) < 2: if len(self.nets) < 2:
enableNet = self.coreToChip.newEnableForNet( self.nets[0] ) enableNet = self.coreToChip.newEnableForNet( self.nets[0] )
self.nets.append( self.coreToChip.getIoNet( enableNet ) ) self.nets.append( self.coreToChip.getIoNet( enableNet ) )
@ -387,6 +388,7 @@ class IoPad ( object ):
connexions.append( ( self.nets[0].chipIntNet , padInfo.inputNet ) ) connexions.append( ( self.nets[0].chipIntNet , padInfo.inputNet ) )
connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) ) connexions.append( ( self.coreToChip.newDummyNet(), padInfo.outputNet ) )
if hasEnable: if hasEnable:
trace( 550, '\tenable Pad={} <-> {}\n'.format( padInfo.enableNet, self.nets[1].chipIntNet ))
connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) )
elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2): elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2):
self.nets[0].setFlags( IoNet.DoExtNet ) self.nets[0].setFlags( IoNet.DoExtNet )
@ -415,6 +417,11 @@ class IoPad ( object ):
connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) ) connexions.append( ( self.nets[0].chipIntNet, padInfo.inputNet ) )
connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) ) connexions.append( ( self.nets[1].chipIntNet, padInfo.outputNet ) )
connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) ) connexions.append( ( self.nets[2].chipIntNet, padInfo.enableNet ) )
for controlInfo in padInfo.controlNets:
controlNet = self.coreToChip.newControlForPad( self.ioPadConf, controlInfo )
self.nets.append( self.coreToChip.getIoNet( controlNet ) )
self.nets[-1].buildNets()
connexions.append( ( self.nets[-1].chipIntNet, controlInfo.name ) )
if not self.coreToChip.useHarness(): if not self.coreToChip.useHarness():
self.pads.append( Instance.create( self.coreToChip.chip self.pads.append( Instance.create( self.coreToChip.chip
, self.padInstanceName , self.padInstanceName
@ -448,13 +455,21 @@ class CoreToChip ( object ):
to the core actually bearing information. to the core actually bearing information.
""" """
class IoControlInfo ( object ):
def __init__ ( self, name, defaultState ):
self.name = name
self.defaultState = defaultState
pass
class IoPadInfo ( object ): class IoPadInfo ( object ):
def __init__ ( self, flags, padName, padNet, coreNets ): def __init__ ( self, flags, padName, padNet, coreNets, controlNets=[] ):
self.flags = flags self.flags = flags
self.name = padName self.name = padName
self.padNet = padNet self.padNet = padNet
self.coreNets = coreNets self.coreNets = coreNets
self.controlNets = [ CoreToChip.IoControlInfo( net[0], net[1] ) for net in controlNets ]
return return
@property @property
@ -508,6 +523,10 @@ class CoreToChip ( object ):
if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() ) if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() )
elif isinstance(masterNetO,Net): masterNet = masterNetO elif isinstance(masterNetO,Net): masterNet = masterNetO
else: masterNet = instance.getMasterCell().getNet( masterNetO ) else: masterNet = instance.getMasterCell().getNet( masterNetO )
if not masterNet:
raise ErrorMessage( 1, [ 'CoreToChip._connect(): No net "{}" in cell "{}".' \
.format( masterNetO, instance.getMasterCell().getName() )
] )
instance.getPlug( masterNet ).setNet( chipNet ) instance.getPlug( masterNet ).setNet( chipNet )
return return
@ -571,6 +590,22 @@ class CoreToChip ( object ):
self.dummyNetCount += 1 self.dummyNetCount += 1
return dummy return dummy
def newControlNet ( self, controlName, constantType ):
"""
Create a new control signal, in *core* cell, to control the associated I/O pad.
The control signal is tied to a constant value, either zero or one.
:param controlName: The name of the control net *in the core cell*.
:param constantType: Whether the control signal is set to zero or one.
"""
instance = self.conf.constantsConf.createInstance( self.core, constantType )
control = Net.create( self.core, controlName )
control.setExternal ( True )
control.setDirection( Net.Direction.OUT )
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( control )
self.conf.addClonedCell( self.conf.core )
return control
def newEnableForNet ( self, ioNet ): def newEnableForNet ( self, ioNet ):
""" """
Create a new enable signal, in *core* cell, to control the associated I/O pad. Create a new enable signal, in *core* cell, to control the associated I/O pad.
@ -582,13 +617,16 @@ class CoreToChip ( object ):
else: else:
raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \ raise ErrorMessage( 2, 'CoreToChip.newEnableForNet(): Net "{}" is neither IN nor OUT.' \
.format(ioNet.coreNet.getName()) ) .format(ioNet.coreNet.getName()) )
instance = self.conf.constantsConf.createInstance( self.core, constantType ) return self.newControlNet( ioNet.enableNetName, constantType )
enable = Net.create( self.core, ioNet.enableNetName )
enable.setExternal ( True ) def newControlForPad ( self, ioPadInfo, ioControlInfo ):
enable.setDirection( Net.Direction.OUT ) """
getPlugByName( instance, self.conf.constantsConf.output(constantType) ).setNet( enable ) Create a new control signal, in *core* cell, to control the associated I/O pad.
self.conf.addClonedCell( self.conf.core ) This is to be used for all I/O pads controls nets, save the "enable" signal.
return enable """
constantType = ConstantsConf.ONE if ioControlInfo.defaultState else ConstantsConf.ZERO
controlNetName = '{}_{}'.format( ioPadInfo.instanceName, ioControlInfo.name )
return self.newControlNet( controlNetName, constantType )
def getIoNet ( self, coreNet ): def getIoNet ( self, coreNet ):
""" """

View File

@ -0,0 +1,248 @@
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) Sorbonne Université 2020-2023, 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 Global Foudries 180nm I/O pad library (GF180MCU).
"""
import sys
import re
from ...Hurricane import DbU, DataBase, UpdateSession, Breakpoint, \
Transformation , Instance , Net
from ...CRL import Catalog, AllianceFramework
from ...helpers import trace
from ...helpers.io import ErrorMessage, WarningMessage
from ...helpers.overlay import CfgCache
from .core2chip import CoreToChip as BaseCoreToChip, IoNet, IoPad
class CoreToChip ( BaseCoreToChip ):
"""
Provide pad-specific part for GF180MCU I/O pads (works in real mode).
"""
rePadType = re.compile(r'(?P<type>.+)_(?P<index>[\d]+)$')
def __init__ ( self, core ):
with CfgCache() as cfg:
cfg.chip.useAbstractPads = False
self.ioPadNames = { 'in' :'gf180mcu_fd_io__in_s'
, 'bidir' :'gf180mcu_fd_io__bi_t'
, 'analog' :'gf180mcu_fd_io__asig_5p0'
, 'vdd' :'gf180mcu_fd_io__dvdd'
, 'vss' :'gf180mcu_fd_io__dvss'
, 'corner' :'gf180mcu_fd_io__cor'
, 'spacer1' :'gf180mcu_fd_io__fill1'
, 'spacer5' :'gf180mcu_fd_io__fill5'
, 'spacer10' :'gf180mcu_fd_io__fill10'
}
BaseCoreToChip.__init__ ( self, core )
self.ringNetNames = { 'DVDD' : None
, 'DVSS' : None
#, 'VDD' : None
#, 'VSS' : None
}
self.ioPadInfos = [ BaseCoreToChip.IoPadInfo( IoPad.IN
, self.ioPadNames['in']
, 'PAD', ['Y'], [ ( 'PU' , False )
, ( 'PD' , False )
] )
, BaseCoreToChip.IoPadInfo( IoPad.BIDIR
, self.ioPadNames['bidir']
, 'PAD', ['A', 'Y', 'OE'], [ ( 'SL' , True )
, ( 'CS' , True )
, ( 'PU' , False )
, ( 'PD' , False )
, ( 'PDRV0', False )
, ( 'PDRV1', False )
, ( 'IE' , True )
] )
, BaseCoreToChip.IoPadInfo( IoPad.ANALOG
, self.ioPadNames['analog']
, 'ASIG5V', ['asig5v'] )
, BaseCoreToChip.IoPadInfo( IoPad.CORNER
, self.ioPadNames['corner']
, None, [] )
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
, self.ioPadNames['spacer1']
, None, [] )
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
, self.ioPadNames['spacer5']
, None, [] )
, BaseCoreToChip.IoPadInfo( IoPad.FILLER
, self.ioPadNames['spacer10']
, None, [] )
]
self.cornerCount = 0
self.spacerCount = 0
self.padSpacers = []
self._getPadLib()
return
def _getPadLib ( self ):
"""
Check that the I/O pad library is present and pre-load the spacer cells.
"""
def _cmpPad ( pad ):
"""Used to sort I/O pads by decreasing width."""
return pad.getAbutmentBox().getWidth()
self.padLib = AllianceFramework.get().getLibrary( "iolib" )
if not self.padLib:
message = [ 'CoreToChip.libresocio._getPadLib(): Unable to find Alliance "iolib" library' ]
raise ErrorMessage( 1, message )
for ioPadInfo in self.ioPadInfos:
if ioPadInfo.flags & IoPad.FILLER:
spacerCell = self.padLib.getCell( ioPadInfo.name )
if spacerCell: self.padSpacers.append( spacerCell )
else:
raise ErrorMessage( 1, 'CoreToChip.gf180mcu._getPadLib(): Missing spacer cell "{}"'.format(spacerName) )
self.padSpacers = sorted( self.padSpacers, key=_cmpPad, reverse=True )
def getNetType ( self, netName ):
if netName.lower().startswith('vss') or netName.lower().startswith('dvss'): return Net.Type.GROUND
if netName.lower().startswith('vdd') or netName.lower().startswith('dvdd'): 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 _buildAllGroundPads ( self, ioPadConf ):
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
padNet = 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 )
self.icore.getPlug( coreNet ).setNet( coronaNet )
if not chipNet:
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName )
chipNet.setExternal( True )
chipNet.setType ( Net.Type.GROUND )
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.GROUND )
coronaPlug = self.icorona.getPlug( coronaNet )
if not coronaPlug.getNet():
coronaPlug.setNet( chipNet )
self.ringNetNames['DVSS' ] = chipNet
#self.ringNetNames['VSS' ] = padNet
ioPadConf.pads.append( Instance.create( self.chip
, 'p_iovss_{}'.format(ioPadConf.index)
, self.getCell(self.ioPadNames['vss']) ) )
#self._connect( ioPadConf.pads[0], chipNet, 'VSS' )
self._connect( ioPadConf.pads[0], padNet , 'DVSS' )
self.groundPadCount += 1
self.chipPads += ioPadConf.pads
def _buildAllPowerPads ( self, ioPadConf ):
trace( 550, ',+', '\tgf180mcu.CoreToChip()\n' )
trace( 550, '\tcoreSupplyNetName="{}"\n'.format( ioPadConf.coreSupplyNetName ))
trace( 550, '\tpadSupplyNetName ="{}"\n'.format( ioPadConf.padSupplyNetName ))
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName )
padNet = 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 )
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 )
trace( 550, '\tchipNet ="{}"\n'.format( chipNet ))
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.POWER )
self.ringNetNames['DVDD'] = chipNet
#self.ringNetNames['VDD'] = padNet
trace( 550, '\tpadNet ="{}"\n'.format( padNet ))
ioPadConf.pads.append( Instance.create( self.chip
, 'p_iovdd_{}'.format(ioPadConf.index)
, self.getCell(self.ioPadNames['vdd']) ) )
#self._connect( ioPadConf.pads[0], chipNet, 'VDD' )
self._connect( ioPadConf.pads[0], padNet , 'DVDD' )
self.powerPadCount += 1
self.chipPads += ioPadConf.pads
trace( 550, '-,' )
def _buildClockPads ( self, ioPadConf ):
"""For "GF180MCU" there is no specialized clock I/O pad. So do nothing."""
pass
def _connectClocks ( self ):
"""For "GF180MCU" there is no pad internal clock ring. So do nothing."""
pass
def hasCornerCell ( self ):
"""Overload of CoreToChip, YES we have dedicated corner cells."""
return True
def hasFillerCells ( self ):
"""Overload of CoreToChip, YES we have dedicated filler cells."""
return True
def getCornerCell ( self ):
"""Return the model of corner cell."""
return self.getCell( self.ioPadNames['corner'] )
def createSpacer ( self, gapWidth ):
"""Return a new instance of spacer cell."""
spacerCell = None
for candidate in self.padSpacers:
if gapWidth >= candidate.getAbutmentBox().getWidth():
spacerCell = candidate
break
if not spacerCell:
return None
spacer = Instance.create( self.chip
, 'pad_spacer_{}'.format( self.spacerCount )
, spacerCell )
self.spacerCount += 1
#self._connect( spacer, self.ringNetNames['vddring'], 'vddring' )
self._connect( spacer, self.ringNetNames['DVDD'], 'DVDD' )
#self._connect( spacer, self.ringNetNames['gndring'], 'gndring' )
self._connect( spacer, self.ringNetNames['DVSS'], 'DVSS' )
return spacer
def createCorner ( self, instanceName=None ):
"""Return a new instance of corner cell."""
if instanceName is None:
instanceName = 'pad_corner_{}'.format( self.cornerCount )
corner = Instance.create( self.chip, instanceName, self.getCornerCell() )
self.cornerCount += 1
self._connect( corner, self.ringNetNames['DVDD'], 'DVDD' )
#self._connect( corner, self.ringNetNames['vddcore'], 'vddcore' )
self._connect( corner, self.ringNetNames['DVSS'], 'DVSS' )
#self._connect( corner, self.ringNetNames['gndcore'], 'gndcore' )
return corner