From 513bc72541fb43045bd7ef2c33f93c48958ccab2 Mon Sep 17 00:00:00 2001 From: Jean-Paul Chaput Date: Wed, 7 Oct 2020 15:07:16 +0200 Subject: [PATCH] Port & integration of core2chip into alpha/block. * New: In CRL/helpers/utils.py, create a Python "class decorator". Works like a decorator but without the need of implementing the Concrete/Abstract classes structure Design Pattern. Create proxies in the derived class for the base class attributes & methods. * Change: In cumulus/plugins/alpha/block/configuration.py, enrich the BlockState object to support core2chip parameters. Make it even more autonomous from the Block class. * New: In cumulus/plugins/alpha/core2chip, port of the core2chip plugin and integration with the alphs/block plugin. At "constant features" as a first. Only ported "cmos", phlib will be later. --- crlcore/python/CMakeLists.txt | 1 + crlcore/python/helpers/__init__.py | 6 +- crlcore/python/helpers/analogtechno.py | 4 +- crlcore/python/helpers/io.py | 6 +- crlcore/python/helpers/overlay.py | 6 +- crlcore/python/helpers/utils.py | 109 ++++ cumulus/src/CMakeLists.txt | 46 +- cumulus/src/plugins/alpha/block/block.py | 82 +-- .../src/plugins/alpha/block/configuration.py | 170 +++++- .../src/plugins/alpha/core2chip/__init__.py | 0 cumulus/src/plugins/alpha/core2chip/cmos.py | 183 ++++++ .../src/plugins/alpha/core2chip/core2chip.py | 543 ++++++++++++++++++ cumulus/src/plugins/alpha/core2chip/phlib.py | 154 +++++ .../src/plugins/alpha/core2chip/phlib80.py | 133 +++++ 14 files changed, 1368 insertions(+), 75 deletions(-) create mode 100644 crlcore/python/helpers/utils.py create mode 100644 cumulus/src/plugins/alpha/core2chip/__init__.py create mode 100644 cumulus/src/plugins/alpha/core2chip/cmos.py create mode 100644 cumulus/src/plugins/alpha/core2chip/core2chip.py create mode 100644 cumulus/src/plugins/alpha/core2chip/phlib.py create mode 100644 cumulus/src/plugins/alpha/core2chip/phlib80.py diff --git a/crlcore/python/CMakeLists.txt b/crlcore/python/CMakeLists.txt index ced5cd1d..0cf5d1b9 100644 --- a/crlcore/python/CMakeLists.txt +++ b/crlcore/python/CMakeLists.txt @@ -3,3 +3,4 @@ install( FILES helpers/io.py DESTINATION ${PYTHON_SITE_PACKAGES}/crlcore/helpers ) install( FILES helpers/analogtechno.py DESTINATION ${PYTHON_SITE_PACKAGES}/crlcore/helpers ) install( FILES helpers/overlay.py DESTINATION ${PYTHON_SITE_PACKAGES}/crlcore/helpers ) + install( FILES helpers/utils.py DESTINATION ${PYTHON_SITE_PACKAGES}/crlcore/helpers ) diff --git a/crlcore/python/helpers/__init__.py b/crlcore/python/helpers/__init__.py index f5bc1ae4..4a28ef5d 100644 --- a/crlcore/python/helpers/__init__.py +++ b/crlcore/python/helpers/__init__.py @@ -1,11 +1,11 @@ -# -*- mode:Python; explicit-buffer-name: "__init__.py" -*- +# -*- mode:Python -*- # # This file is part of the Coriolis Software. -# Copyright (c) UPMC 2012-2018, All Rights Reserved +# Copyright (c) SU 2012-2020, All Rights Reserved # # +-----------------------------------------------------------------+ # | C O R I O L I S | -# | C o r i o l i s / C h a m s B u i l d e r | +# | Alliance / Hurricane Interface | # | | # | Author : Jean-Paul Chaput | # | E-mail : Jean-Paul.Chaput@lip6.fr | diff --git a/crlcore/python/helpers/analogtechno.py b/crlcore/python/helpers/analogtechno.py index cefa55d4..0bb6b4fb 100644 --- a/crlcore/python/helpers/analogtechno.py +++ b/crlcore/python/helpers/analogtechno.py @@ -1,7 +1,7 @@ -# -*- Mode:Python; explicit-buffer-name: "analogtechno.py" -*- +# -*- Mode:Python -*- # # This file is part of the Coriolis Software. -# Copyright (c) UPMC 2015-2018, All Rights Reserved +# Copyright (c) SU 2015-2020, All Rights Reserved # # +-----------------------------------------------------------------+ # | C O R I O L I S | diff --git a/crlcore/python/helpers/io.py b/crlcore/python/helpers/io.py index 21635816..e08251b6 100644 --- a/crlcore/python/helpers/io.py +++ b/crlcore/python/helpers/io.py @@ -1,11 +1,11 @@ -# -*- mode:Python; explicit-buffer-name: "io.py" -*- +# -*- mode:Python -*- # # This file is part of the Coriolis Software. -# Copyright (c) UPMC 2012-2018, All Rights Reserved +# Copyright (c) SU 2012-2020, All Rights Reserved # # +-----------------------------------------------------------------+ # | C O R I O L I S | -# | C o r i o l i s / C h a m s B u i l d e r | +# | Alliance / Hurricane Interface | # | | # | Author : Jean-Paul Chaput | # | E-mail : Jean-Paul.Chaput@lip6.fr | diff --git a/crlcore/python/helpers/overlay.py b/crlcore/python/helpers/overlay.py index 56d10c0d..ea87a8e5 100644 --- a/crlcore/python/helpers/overlay.py +++ b/crlcore/python/helpers/overlay.py @@ -1,11 +1,11 @@ -# -*- mode:Python; explicit-buffer-name: "__init__.py" -*- +# -*- mode:Python -*- # # This file is part of the Coriolis Software. -# Copyright (c) UPMC 2012-2018, All Rights Reserved +# Copyright (c) SU 2012-2020, All Rights Reserved # # +-----------------------------------------------------------------+ # | C O R I O L I S | -# | C o r i o l i s / C h a m s B u i l d e r | +# | Alliance / Hurricane Interface | # | | # | Author : Jean-Paul Chaput | # | E-mail : Jean-Paul.Chaput@lip6.fr | diff --git a/crlcore/python/helpers/utils.py b/crlcore/python/helpers/utils.py new file mode 100644 index 00000000..80f09d74 --- /dev/null +++ b/crlcore/python/helpers/utils.py @@ -0,0 +1,109 @@ +# -*- mode:Python -*- +# +# 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 o r i o l i s / C h a m s B u i l d e r | +# | | +# | Author : Jean-Paul Chaput | +# | E-mail : Jean-Paul.Chaput@lip6.fr | +# | =============================================================== | +# | Python : "./crlcore/helpers/utils.py" | +# +-----------------------------------------------------------------+ + +""" +Miscellaeous utilities. Contains: + +* ``classdecorator`` : A class decorator, wrap a new class instance + around and exsiting one and create proxies for all it's attributes + and methods. +""" + +from __future__ import print_function +import types +import inspect +import functools + + +def classdecorator ( cls ): + """ + Decorate an instance of a class. It is not an implementation of the Design + Pattern, instead of using Concrete/Abstract classes and inheritance, it just + create proxies for the base class attributes & methods in the derived one. + + Example: + + .. code-block:: python + + class Base ( object ): + + def __init__ ( self, param1 ): + self.param1 = param1 + + def func1 ( self ): + return self.param1 + + @classdecorator + class DecoratedClass ( object ): + + def __init__ ( self, param2 ) + self.param2 = param2 + + def func2 ( self ): + return self.param2 + + base = Base( 'Value1' ) + decorated = Decorated( 'Value2' ) + print( 'decorated.param1 = {}'.format(decorated.param1) ) + print( 'decorated.param2 = {}'.format(decorated.param2) ) + print( 'decorated.func1 = {}'.format(decorated.func1()) ) + print( 'decorated.func2 = {}'.format(decorated.func2()) ) + + + Technical note + ============== + + A hidden attribute ``_baseClass`` is added that contains an *instance* of + the base class (that is, not the class type itself). Then the + ``__setattr__()`` and ``__getattr__()`` of the decorated class instance + (``cls``) are replaced by versions that tries first to find attributes in + the base class. The ``__init__()`` of the decorated class is also + redefined so that it *imports* all the methods of the base class in the + decorated one at runtime. + + Methods binding: the base class methods importeds into the decorated one + stay bound the the *base* class. As far as I understand, this should cause + no problem as long as the base class instance exists, which should always + be the case. + """ + + def wrappedSetattr ( self, attr, v ): + if attr != '_baseClass' and self._baseClass.__dict__.has_key(attr): + self._baseClass.__setattr__( attr, v ) + object.__setattr__( self, attr, v ) + + def wrappedGetattr ( self, attr ): + if attr == '_baseClass': return self.__dict__['_baseClass'] + if self.__dict__.has_key(attr): return self.__dict__[attr] + if not hasattr(self._baseClass,attr): + raise AttributeError( '\'{}\' object has no attribute \'{}\'' \ + .format(self.__class__.__name__,attr) ) + return getattr( self._baseClass, attr ) + + classInit = cls.__init__ + + @functools.wraps(classInit) + def wrappedInit ( self, baseClass, *args, **kwargs ): + self._baseClass = baseClass + for method in inspect.getmembers(self._baseClass, predicate=inspect.ismethod): + if method[0] == '__init__': continue + self.__setattr__( method[0], method[1] ) + classInit( self, *args, **kwargs ) + + cls.__init__ = wrappedInit + cls.__setattr__ = wrappedSetattr + cls.__getattr__ = wrappedGetattr + return cls + diff --git a/cumulus/src/CMakeLists.txt b/cumulus/src/CMakeLists.txt index c5a11ff6..ba922c57 100644 --- a/cumulus/src/CMakeLists.txt +++ b/cumulus/src/CMakeLists.txt @@ -42,28 +42,32 @@ set ( pyTools ${CMAKE_CURRENT_SOURCE_DIR}/tools/blif2vst.py ${CMAKE_CURRENT_SOURCE_DIR}/tools/yosys.py ) - set ( pyPluginAlpha ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/__init__.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/utils.py + set ( pyPluginAlpha ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/utils.py ) - set ( pyPluginBlock ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/__init__.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/__init__.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/configuration.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/spares.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/block.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/clocktree.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/timing.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns2.py - ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns3.py + set ( pyPluginAlphaBlock ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/configuration.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/spares.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/block.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/clocktree.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/timing.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/rsmt.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns1.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns2.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/block/hfns3.py + ) + set ( pyPluginAlphaC2C ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/__init__.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/core2chip.py + ${CMAKE_CURRENT_SOURCE_DIR}/plugins/alpha/core2chip/cmos.py ) - install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus ) - install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins ) - #install ( FILES ${pyPluginBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/block ) - install ( FILES ${pyPluginCTS} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/cts ) - install ( FILES ${pyPluginC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/core2chip ) - install ( FILES ${pyPluginChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/chip ) - install ( FILES ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha ) - install ( FILES ${pyPluginBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block ) + install ( FILES ${pySources} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus ) + install ( FILES ${pyPlugins} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins ) + install ( FILES ${pyPluginCTS} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/cts ) + install ( FILES ${pyPluginC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/core2chip ) + install ( FILES ${pyPluginChip} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/chip ) + install ( FILES ${pyPluginAlpha} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha ) + install ( FILES ${pyPluginAlphaBlock} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/block ) + install ( FILES ${pyPluginAlphaC2C} DESTINATION ${PYTHON_SITE_PACKAGES}/cumulus/plugins/alpha/core2chip ) #install ( PROGRAMS ${pyTools} DESTINATION bin ) diff --git a/cumulus/src/plugins/alpha/block/block.py b/cumulus/src/plugins/alpha/block/block.py index 2a6f386d..b746854a 100644 --- a/cumulus/src/plugins/alpha/block/block.py +++ b/cumulus/src/plugins/alpha/block/block.py @@ -70,8 +70,8 @@ class Side ( object ): and perform pins creation & placement. """ - def __init__ ( self, block, side ): - self.block = block + def __init__ ( self, state, side ): + self.state = state self.side = side self.pinSpecs = [] self.expandPins = True @@ -99,25 +99,25 @@ class Side ( object ): box has been setup. """ if self.side & IoPin.WEST: - self.gauge = self.block.state.gaugeConf.hDeepRG - self.ubegin = self.block.state.yMin - self.uend = self.block.state.yMax - self.sidePos = self.block.state.xMin + self.gauge = self.state.gaugeConf.hDeepRG + self.ubegin = self.state.yMin + self.uend = self.state.yMax + self.sidePos = self.state.xMin elif self.side & IoPin.EAST: - self.gauge = self.block.state.gaugeConf.hDeepRG - self.ubegin = self.block.state.yMin - self.uend = self.block.state.yMax - self.sidePos = self.block.state.xMax + self.gauge = self.state.gaugeConf.hDeepRG + self.ubegin = self.state.yMin + self.uend = self.state.yMax + self.sidePos = self.state.xMax elif self.side & IoPin.SOUTH: - self.gauge = self.block.state.gaugeConf.vDeepRG - self.ubegin = self.block.state.xMin - self.uend = self.block.state.xMax - self.sidePos = self.block.state.yMin + self.gauge = self.state.gaugeConf.vDeepRG + self.ubegin = self.state.xMin + self.uend = self.state.xMax + self.sidePos = self.state.yMin elif self.side & IoPin.NORTH: - self.gauge = self.block.state.gaugeConf.vDeepRG - self.ubegin = self.block.state.xMin - self.uend = self.block.state.xMax - self.sidePos = self.block.state.yMax + self.gauge = self.state.gaugeConf.vDeepRG + self.ubegin = self.state.xMin + self.uend = self.state.xMax + self.sidePos = self.state.yMax def getNextPinPosition ( self, flags, upos, ustep ): """ @@ -179,26 +179,26 @@ class Side ( object ): status = 0 if self.side & (IoPin.NORTH | IoPin.SOUTH): - gauge = self.block.state.gaugeConf.vDeepRG + gauge = self.state.gaugeConf.vDeepRG upos = ioPin.upos for index in ioPin.indexes: pinName = ioPin.stem.format( index ) - net = self.block.state.cell.getNet( pinName ) + net = self.state.cell.getNet( pinName ) if net is None: print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) continue - if net.isClock() and self.block.state.useClockTree: + if net.isClock() and self.state.useClockTree: print( WarningMessage( 'Side.place(IoPin): Skipping clock IoPin "{}".'.format(pinName) )) continue - pinName += '.{}'.format(self.block.state.getIoPinsCounts(net)) + pinName += '.{}'.format(self.state.getIoPinsCounts(net)) pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) - if pinPos.getX() > self.block.state.xMax or pinPos.getX() < self.block.state.xMin: + if pinPos.getX() > self.state.xMax or pinPos.getX() < self.state.xMin: print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside north or south abutment box side.' \ .format(pinName) , '(x:{}, xAB: [{}:{}])' \ .format( DbU.getValueString(pinPos.getX()) - , DbU.getValueString(self.block.state.xMin) - , DbU.getValueString(self.block.state.xMax) ) ] )) + , DbU.getValueString(self.state.xMin) + , DbU.getValueString(self.state.xMax) ) ] )) status += 1 trace( 550, '\tIoPin.place() N/S @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) pin = Pin.create( net @@ -213,26 +213,26 @@ class Side ( object ): ) NetExternalComponents.setExternal( pin ) self.append( pin ) - self.block.state.incIoPinsCounts( net ) + self.state.incIoPinsCounts( net ) if upos: upos += ioPin.ustep else: - gauge = self.block.state.gaugeConf.hDeepRG + gauge = self.state.gaugeConf.hDeepRG upos = ioPin.upos for index in ioPin.indexes: pinName = ioPin.stem.format(index) - net = self.block.state.cell.getNet( pinName ) + net = self.state.cell.getNet( pinName ) if net is None: print( ErrorMessage( 1, [ 'Side.place(IoPin): No net named "{}".'.format(pinName) ] )) continue - pinName += '.{}'.format(self.block.state.getIoPinsCounts(net)) + pinName += '.{}'.format(self.state.getIoPinsCounts(net)) pinPos = self.getNextPinPosition( ioPin.flags, upos, ioPin.ustep ) - if pinPos.getY() > self.block.state.yMax or pinPos.getY() < self.block.state.yMin: + if pinPos.getY() > self.state.yMax or pinPos.getY() < self.state.yMin: print( ErrorMessage( 1, [ 'Side.place(IoPin): Pin "{}" is outside east or west abutment box side.' \ .format(pinName) , '(y:{}, yAB: [{}:{}])' \ .format( DbU.getValueString(pinPos.getY()) - , DbU.getValueString(self.block.state.yMin) - , DbU.getValueString(self.block.state.yMax)) ] )) + , DbU.getValueString(self.state.yMin) + , DbU.getValueString(self.state.yMax)) ] )) status += 1 trace( 550, '\tIoPin.place() E/W @{} "{}" of "{}".\n'.format(pinPos,pinName,net) ) pin = Pin.create( net @@ -247,7 +247,7 @@ class Side ( object ): ) NetExternalComponents.setExternal( pin ) self.append( pin ) - self.block.state.incIoPinsCounts( net ) + self.state.incIoPinsCounts( net ) if upos: upos += ioPin.ustep return status @@ -257,7 +257,7 @@ class Side ( object ): of the abutment box. THey will stick out for one pitch. """ if not self.expandPins: return - rg = self.block.state.gaugeConf.routingGauge + rg = self.state.gaugeConf.routingGauge for pinsAtPos in self.pins.values(): for pin in pinsAtPos: for lg in rg.getLayerGauges(): @@ -285,7 +285,7 @@ class Side ( object ): for pin in self.pins[upos][1:]: pinNames += ', ' + pin.getName() print( ErrorMessage( 1, [ 'Side.checkOverlap(): On {} side of block "{}", {} pins ovelaps.' \ - .format(sideName,self.block.state.cell.getName(),count) + .format(sideName,self.state.cell.getName(),count) , '(@{}: {})' \ .format(DbU.getValueString(upos),pinNames) ] ) ) @@ -309,9 +309,9 @@ class Block ( object ): return None @staticmethod - def create ( cell, ioPins=[] ): + def create ( cell, ioPins=[], ioPads=[] ): """Create a Block and it's configuration object.""" - block = Block( BlockState( cell, ioPins ) ) + block = Block( BlockState( cell, ioPins, ioPads ) ) Block.LUT[ cell ] = block return block @@ -323,10 +323,10 @@ class Block ( object ): self.clockTrees = [] self.hfnTrees = [] self.blockInstances = [] - self.sides = { IoPin.WEST : Side( self, IoPin.WEST ) - , IoPin.EAST : Side( self, IoPin.EAST ) - , IoPin.SOUTH : Side( self, IoPin.SOUTH ) - , IoPin.NORTH : Side( self, IoPin.NORTH ) + self.sides = { IoPin.WEST : Side( self.state, IoPin.WEST ) + , IoPin.EAST : Side( self.state, IoPin.EAST ) + , IoPin.SOUTH : Side( self.state, IoPin.SOUTH ) + , IoPin.NORTH : Side( self.state, IoPin.NORTH ) } if not self.state.cell.getAbutmentBox().isEmpty(): print( ' o Block "{}" is already done, reusing layout.' \ diff --git a/cumulus/src/plugins/alpha/block/configuration.py b/cumulus/src/plugins/alpha/block/configuration.py index 1677238e..e006852b 100644 --- a/cumulus/src/plugins/alpha/block/configuration.py +++ b/cumulus/src/plugins/alpha/block/configuration.py @@ -12,8 +12,8 @@ # | Python : "./plugins/block/configuration.py" | # +-----------------------------------------------------------------+ - import sys +import re import os.path import Cfg from Hurricane import Breakpoint @@ -372,6 +372,168 @@ class GaugeConf ( object ): return +# ------------------------------------------------------------------- +# Class : "IoPadConf". + +class IoPadConf ( object ): + """ + Store all informations related to an I/O pad. It's side, position + and connected nets. + + .. code-block:: python + + # | Side | Pos | Instance | Pad net | To Core net | Enable Net | From Core Net | + ( IoPin.SOUTH, None, 'a_0' , 'a(0)' , 'a(0)' ) + ( IoPin.NORTH, None, 'p_r0' , 'r0' , 'r0_from_pads', 'shift_r' , 'r0_to_pads' ) + ( IoPin.NORTH, None, 'p_y0' , 'y(0)' , 'y_oe' , 'y_to_pads(0)' ) + + self._datas is a table of 8 elements, the seven first coming from + the configuration itself. Direction are taken from the core point + of view. + + Meaning of the table element's: + + +---------+-----------------------------------------------------------+ + | Index | Type | + +=========+===========================================================+ + | 0 | Pad side (north, south, east, west) | + +---------+-----------------------------------------------------------+ + | 1 | Pad absolute position on the side, or None | + +---------+-----------------------------------------------------------+ + | 2 | Pad instance name | + +---------+-----------------------------------------------------------+ + | 3 | Pad connected signal name. | + | | The name of the external signal at chip level | + +---------+-----------------------------------------------------------+ + | 4 | The name of the signal going *from* the pad to the core. | + | | IN direction in the core | + +---------+-----------------------------------------------------------+ + | 5 | The name of the signal going *to* the pad from the core. | + | | OUT direction in core (or None) | + +---------+-----------------------------------------------------------+ + | 6 | The enable signal, coming from the core (or None) | + +---------+-----------------------------------------------------------+ + | 7 | The list of associated IoPads objects. It is set to [] | + | | initially. There may be more than one in the case of | + | | meta-generated power/ground/clock pads | + +---------+-----------------------------------------------------------+ + """ + POWER = 0x0001 + GROUND = 0x0002 + CLOCK = 0x0004 + TRISTATE = 0x0008 + BIDIR = 0x0010 + + def __init__ ( self, datas ): + if not isinstance(datas,tuple): + raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" parameter is not a list.' + , str(datas) ] ) + if len(datas) < 5 and len(datas) > 8: + raise ErrorMessage( 1, [ 'IoPadConf.__init__(): The "datas" list must have between 5 to 7 elements.' + , str(datas) ] ) + self.flags = 0 + self.index = None + self._datas = list( datas ) + while len(self._datas) < 7: + self._datas.append( None ) + self._datas.append( [] ) + reSpecialPads = re.compile( r'^(?P.+)_(?P[\d+])$' ) + m = reSpecialPads.match( self.instanceName ) + if m: + self.index = m.group('index') + if m.group('type') == 'power' : self.flags |= IoPadConf.POWER + if m.group('type') == 'ground': self.flags |= IoPadConf.GROUND + if m.group('type') == 'clock' : self.flags |= IoPadConf.CLOCK + else: + if self._datas[5] is not None: self.flags |= IoPadConf.BIDIR + elif self._datas[6] is not None: self.flags |= IoPadConf.TRISTATE + + @property + def side ( self ): return self._datas[0] + + @property + def position ( self ): return self._datas[1] + + @property + def instanceName ( self ): return self._datas[2] + + @property + def padNetName ( self ): return self._datas[3] + + @property + def fromCoreNetName ( self ): return self._datas[4] + + @property + def toCoreNetName ( self ): return self._datas[5] + + @property + def enableNetName ( self ): return self._datas[6] + + @property + def padSupplyNetName ( self ): return self._datas[3] + + @property + def coreSupplyNetName ( self ): return self._datas[4] + + @property + def padClockNetName ( self ): return self._datas[4] + + @property + def coreClockNetName ( self ): return self._datas[5] + + @property + def nets ( self ): return self._datas[4:6] + + @property + def pads ( self ): return self._datas[7] + + def isPower ( self ): return self.flags & IoPadConf.POWER + def isGround ( self ): return self.flags & IoPadConf.GROUND + def isClock ( self ): return self.flags & IoPadConf.CLOCK + def isTristate ( self ): return self.flags & IoPadConf.TRISTATE + def isBidir ( self ): return self.flags & IoPadConf.BIDIR + + def __repr__ ( self ): + s = '[^(]*)\((?P[\d]+)\)$' ) + + def __init__ ( self, coreToChip, coreNet ): + self.coreToChip = coreToChip + self._flags = 0 + self._chipExtNetName = None # In the case of bidir pad, force external net name. + self.coreNet = coreNet + self.coronaNet = None # Corona net going from core to corona. + self.chipIntNet = None # Chip net going from corona to I/O pad. + self.chipExtNet = None # Chip net going from I/O pad to the outside world. + + m = IoNet.reVHDLVector.match( self.coreNet.getName() ) + if m: + self._flags |= IoNet.IsElem + self._name = m.group('name') + self._index = m.group('index') + else: + self._name = self.coreNet.getName() + self._index = 0 + + self._type = self.coreToChip.getNetType( self._name ) + return + + def __repr__ ( self ): + return ''.format( self.coreNet.getName() + , self.chipExtNet + , self.chipIntNet ) + + def isElem ( self ): return self._flags & IoNet.IsElem + def isEnable ( self ): return self._flags & IoNet.IsEnable + def isGlobal ( self ): return self.isGlobal( self._name ) + def isSpecial ( self ): return self._type != Net.Type.LOGICAL + + @property + def name ( self ): + if self.isSpecial() and self._chipExtNetName: + return self._chipExtNetName + return self._name + + @property + def index ( self ): return self._index + + @property + def coreNetName ( self ): return self.coreNet.getName() + + @property + def coronaNetName ( self ): + s = self._name + if self._flags & IoNet.IsElem: s += '({})'.format(self._index) + return s + + @property + def chipIntNetName ( self ): + return self.chipIntNet.getName() if self.chipIntNet else self.coronaNetName + + @property + def chipExtNetName ( self ): + if self._chipExtNetName is not None: return self._chipExtNetName + if self._flags & IoNet.IsEnable: return 'None' + if self.chipExtNet: return self.chipExtNet.getName() + s = self._name + if self._flags & IoNet.IsElem: s += '({})'.format(self._index) + return s + + @chipExtNetName.setter + def chipExtNetName ( self, name ): self._chipExtNetName = name + + @property + def padInstanceName ( self ): + s = self._name + if self._flags & IoNet.IsElem: s += '_{}'.format(self._index) + return s + + def setEnable ( self, state ): + if state == True: self._flags |= IoNet.IsEnable + else: self._flags &= ~IoNet.IsEnable + + def buildNets ( self, context=DoExtNet ): + """ + Creates the signals in corona and chip Cells, then connect them + together. + """ + netType = Net.Type.LOGICAL + if self.coreNet.isPower (): netType = Net.Type.POWER + if self.coreNet.isGround(): netType = Net.Type.GROUND + if self.coreNet.isClock (): netType = Net.Type.CLOCK + # Corona net, connect to Core instance net. + if not self.coronaNet: + self.coronaNet = Net.create( self.coreToChip.corona, self.coronaNetName ) + self.coronaNet.setExternal ( True ) + self.coronaNet.setDirection( self.coreNet.getDirection() ) + if netType != Net.Type.LOGICAL: + self.coronaNet.setType ( netType ) + self.coronaNet.setGlobal( True ) + self.coreToChip.icore.getPlug( self.coreNet ).setNet( self.coronaNet ) + # Chip "internal" net, connect Corona instance net to I/O inside the chip. + if not self.chipIntNet: + self.chipIntNet = Net.create( self.coreToChip.chip, self.coronaNetName ) + if netType != Net.Type.LOGICAL: + self.chipIntNet.setType( netType ) + self.coreToChip.icorona.getPlug( self.coronaNet ).setNet( self.chipIntNet ) + # Chip "external" net, connected to the pad I/O to the outside world. + if context & IoNet.PadPassthrough: + self.chipExtNet = self.chipIntNet + elif not self.chipExtNet and (context & IoNet.DoExtNet): + self.chipExtNet = self.coreToChip.chip.getNet( self.chipExtNetName ) + if not self.chipExtNet: + self.chipExtNet = Net.create( self.coreToChip.chip, self.chipExtNetName ) + if self.chipExtNet: + self.chipExtNet.setExternal ( True ) + self.chipExtNet.setDirection( self.coreNet.getDirection() ) + + +# ------------------------------------------------------------------- +# Class : "IoPad". + +class IoPad ( object ): + + """ + Manage I/O pad instanciation. Gather between one and three IoNet. + The number of IoNet implies the kind of I/O pad to be used. + + 1. One IoNet mean either an input pad or an output pad. + 2. Two IoNets mean an tristate output pad (the signal and it's + output enable). + 3. Three IoNets mean a bidirectional I/O pad (the signal as input, + the signal as output and it's direction). + """ + + IN = 0x0001 + OUT = 0x0002 + BIDIR = 0x0004 + TRI_OUT = 0x0008 + UNSUPPORTED = 0x0010 + + @staticmethod + def directionToStr ( direction ): + if direction == IoPad.IN: return "IN" + if direction == IoPad.OUT: return "OUT" + if direction == IoPad.BIDIR: return "BIDIR" + if direction == IoPad.TRI_OUT: return "TRI_OUT" + if direction == IoPad.UNSUPPORTED: return "UNSUPPORTED" + return "Invalid value" + + def __init__ ( self, coreToChip, padInstanceName ): + self.coreToChip = coreToChip + self.padInstanceName = padInstanceName + self.direction = 0 + self.nets = [] + self.pads = [] + return + + def __str__ ( self ): + s = '