From 9274c21c14ab73e8ddacf633d5da395b2ce31097 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Mon, 25 Sep 2023 23:50:20 +0200 Subject: [PATCH] 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... --- .../technos/node180/gf180mcu/mcu9t5v0.py | 2 +- .../node180/gf180mcu_c4m/StdCell3V3Lib.py | 13 +- .../technos/node180/gf180mcu_c4m/iolib.py | 12 +- cumulus/src/CMakeLists.txt | 1 + cumulus/src/designflow/technos.py | 1 - cumulus/src/plugins/block/configuration.py | 18 +- cumulus/src/plugins/chip/pads.py | 8 +- cumulus/src/plugins/core2chip/core2chip.py | 62 ++++- cumulus/src/plugins/core2chip/gf180mcu.py | 248 ++++++++++++++++++ 9 files changed, 334 insertions(+), 31 deletions(-) create mode 100644 cumulus/src/plugins/core2chip/gf180mcu.py diff --git a/crlcore/python/technos/node180/gf180mcu/mcu9t5v0.py b/crlcore/python/technos/node180/gf180mcu/mcu9t5v0.py index 682bf53f..283e73e7 100644 --- a/crlcore/python/technos/node180/gf180mcu/mcu9t5v0.py +++ b/crlcore/python/technos/node180/gf180mcu/mcu9t5v0.py @@ -181,7 +181,7 @@ def _routing (): cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = [1, None] cfg.katana.longGlobalRipupLimit = 5 - cfg.chip.padCoreSide = 'South' + cfg.chip.padCoreSide = 'North' # Plugins setup cfg.clockTree.minimumSide = u(5.04) * 6 cfg.clockTree.buffer = 'gf180mcu_fd_sc_mcu9t5v0__clkbuf_2' diff --git a/crlcore/python/technos/node180/gf180mcu_c4m/StdCell3V3Lib.py b/crlcore/python/technos/node180/gf180mcu_c4m/StdCell3V3Lib.py index c56bae45..947397d0 100644 --- a/crlcore/python/technos/node180/gf180mcu_c4m/StdCell3V3Lib.py +++ b/crlcore/python/technos/node180/gf180mcu_c4m/StdCell3V3Lib.py @@ -99,6 +99,10 @@ def _routing(): ) af.addCellGauge(cg) af.setCellGauge('StdCell3V3Lib') + lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 ) + lg5.setType( CRL.RoutingLayerGauge.PowerSupply ) + env = af.getEnvironment() + env.setRegister( '.*sff.*' ) # Place & Route setup with CfgCache(priority=Cfg.Parameter.Priority.ConfigurationFile) as cfg: @@ -162,17 +166,8 @@ def _routing(): cfg.katana.globalRipupLimit = 5 cfg.katana.globalRipupLimit = [1, None] 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.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.buffer = 'buf_x1' cfg.clockTree.placerEngine = 'Etesian' diff --git a/crlcore/python/technos/node180/gf180mcu_c4m/iolib.py b/crlcore/python/technos/node180/gf180mcu_c4m/iolib.py index 517c36bc..b0233069 100644 --- a/crlcore/python/technos/node180/gf180mcu_c4m/iolib.py +++ b/crlcore/python/technos/node180/gf180mcu_c4m/iolib.py @@ -27,8 +27,9 @@ def _routing (): cfg.chip.block.rails.vWidth = u(30.0) cfg.chip.block.rails.hSpacing = u( 6.0) cfg.chip.block.rails.vSpacing = u( 6.0) - cfg.chip.padCorner = 'gf180mcu_fd_io__cor_5lm' - cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10_5lm,gf180mcu_fd_io__fill5_5lm,gf180mcu_fd_io__fill1_5lm' + #cfg.chip.padCorner = 'gf180mcu_fd_io__cor' + #cfg.chip.padSpacers = 'gf180mcu_fd_io__fill10,gf180mcu_fd_io__fill5,gf180mcu_fd_io__fill1' + cfg.chip.padCoreSide = 'North' af = AllianceFramework.get() cg = CellGauge.create( 'LEF.GF_IO_Site' , 'Metal2' # pin layer name. @@ -57,7 +58,6 @@ def _loadIoLib ( pdkDir ): print( ' 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' - print( cellsDir ) for lefFile in cellsDir.glob( '*/*_5lm.lef' ): print( lefFile ) gdsFile = lefFile.with_suffix( '.gds' ) @@ -65,6 +65,12 @@ def _loadIoLib ( pdkDir ): Gds.setTopCellName( gdsFile.stem[:-4] ) Gds.load( ioLib, gdsFile.as_posix(), Gds.Layer_0_IsBoundary|Gds.NoBlockages ) 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 ) diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index ebfe627e..8f9c5691 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -65,6 +65,7 @@ ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/niolib.py ${CMAKE_CURRENT_SOURCE_DIR}/plugins/core2chip/libresocio.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 ${CMAKE_CURRENT_SOURCE_DIR}/plugins/chip/constants.py diff --git a/cumulus/src/designflow/technos.py b/cumulus/src/designflow/technos.py index 84748464..66903f13 100644 --- a/cumulus/src/designflow/technos.py +++ b/cumulus/src/designflow/technos.py @@ -284,7 +284,6 @@ def setupGf180mcu_c4m ( checkToolkit=None cfg.misc.verboseLevel2 = True cfg.etesian.graphics = 3 cfg.etesian.spaceMargin = 0.10 - cfg.anabatic.topRoutingLayer = 'metal6' cfg.katana.eventsLimit = 4000000 af = CRL.AllianceFramework.get() lg5 = af.getRoutingGauge('StdCell3V3Lib').getLayerGauge( 5 ) diff --git a/cumulus/src/plugins/block/configuration.py b/cumulus/src/plugins/block/configuration.py index 78efa292..97cdaa7d 100644 --- a/cumulus/src/plugins/block/configuration.py +++ b/cumulus/src/plugins/block/configuration.py @@ -15,6 +15,7 @@ import sys import re import os.path +import collections from operator import itemgetter from ... import Cfg from ...Hurricane import DataBase, Breakpoint, DbU, Box, Transformation, \ @@ -1449,7 +1450,22 @@ class BlockConf ( GaugeConf ): for ioPinSpec in self.ioPinsArg: self.ioPins.append( IoPin( *ioPinSpec ) ) for line in range(len(self.ioPadsArg)): - self.chipConf.addIoPad( self.ioPadsArg[line], line ) + 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 ) trace( 550, ',-' ) @property diff --git a/cumulus/src/plugins/chip/pads.py b/cumulus/src/plugins/chip/pads.py index 85c55f1b..e281f346 100644 --- a/cumulus/src/plugins/chip/pads.py +++ b/cumulus/src/plugins/chip/pads.py @@ -693,11 +693,11 @@ class Corona ( object ): 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() ) + raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is not connected and there is no global net (in pad "{}").' \ + .format( 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() ) + raise ErrorMessage( 1, 'Corona._padAnalysis(): Ring net "{}" is neither connected nor global (in pad "{}").' \ + .format( plug.getMasterNet().getName(), padCell.getName() )) if net: self.padRails.append( ( net , component.getLayer() diff --git a/cumulus/src/plugins/core2chip/core2chip.py b/cumulus/src/plugins/core2chip/core2chip.py index b6fb0505..8dd436e3 100644 --- a/cumulus/src/plugins/core2chip/core2chip.py +++ b/cumulus/src/plugins/core2chip/core2chip.py @@ -375,6 +375,7 @@ class IoPad ( object ): or self.nets[0].chipExtNetName.startswith('io_in') \ or self.nets[0].chipExtNetName.startswith('io_out') if hasEnable: + trace( 550, '\tself.nets = {}\n'.format( self.nets )) if len(self.nets) < 2: enableNet = self.coreToChip.newEnableForNet( self.nets[0] ) 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.coreToChip.newDummyNet(), padInfo.outputNet ) ) if hasEnable: + trace( 550, '\tenable Pad={} <-> {}\n'.format( padInfo.enableNet, self.nets[1].chipIntNet )) connexions.append( ( self.nets[1].chipIntNet, padInfo.enableNet ) ) elif (self.direction == IoPad.TRI_OUT) and (len(self.nets) < 2): 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[1].chipIntNet, padInfo.outputNet ) ) 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(): self.pads.append( Instance.create( self.coreToChip.chip , self.padInstanceName @@ -448,13 +455,21 @@ class CoreToChip ( object ): to the core actually bearing information. """ + class IoControlInfo ( object ): + + def __init__ ( self, name, defaultState ): + self.name = name + self.defaultState = defaultState + pass + class IoPadInfo ( object ): - def __init__ ( self, flags, padName, padNet, coreNets ): - self.flags = flags - self.name = padName - self.padNet = padNet - self.coreNets = coreNets + def __init__ ( self, flags, padName, padNet, coreNets, controlNets=[] ): + self.flags = flags + self.name = padName + self.padNet = padNet + self.coreNets = coreNets + self.controlNets = [ CoreToChip.IoControlInfo( net[0], net[1] ) for net in controlNets ] return @property @@ -508,6 +523,10 @@ class CoreToChip ( object ): if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() ) elif isinstance(masterNetO,Net): masterNet = 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 ) return @@ -571,6 +590,22 @@ class CoreToChip ( object ): self.dummyNetCount += 1 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 ): """ Create a new enable signal, in *core* cell, to control the associated I/O pad. @@ -582,13 +617,16 @@ class CoreToChip ( object ): 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, ioNet.enableNetName ) - 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 + return self.newControlNet( ioNet.enableNetName, constantType ) + + def newControlForPad ( self, ioPadInfo, ioControlInfo ): + """ + Create a new control signal, in *core* cell, to control the associated I/O pad. + This is to be used for all I/O pads controls nets, save the "enable" signal. + """ + constantType = ConstantsConf.ONE if ioControlInfo.defaultState else ConstantsConf.ZERO + controlNetName = '{}_{}'.format( ioPadInfo.instanceName, ioControlInfo.name ) + return self.newControlNet( controlNetName, constantType ) def getIoNet ( self, coreNet ): """ diff --git a/cumulus/src/plugins/core2chip/gf180mcu.py b/cumulus/src/plugins/core2chip/gf180mcu.py new file mode 100644 index 00000000..b1d402e4 --- /dev/null +++ b/cumulus/src/plugins/core2chip/gf180mcu.py @@ -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.+)_(?P[\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