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.
This commit is contained in:
Jean-Paul Chaput 2020-10-07 15:07:16 +02:00
parent 9d56066c2d
commit 513bc72541
14 changed files with 1368 additions and 75 deletions

View File

@ -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 )

View File

@ -1,11 +1,11 @@
# -*- mode:Python; explicit-buffer-name: "__init__.py<crlcore/helpers>" -*-
# -*- 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 |

View File

@ -1,7 +1,7 @@
# -*- Mode:Python; explicit-buffer-name: "analogtechno.py<crlcore/helpers>" -*-
# -*- 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 |

View File

@ -1,11 +1,11 @@
# -*- mode:Python; explicit-buffer-name: "io.py<crlcore/helpers>" -*-
# -*- 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 |

View File

@ -1,11 +1,11 @@
# -*- mode:Python; explicit-buffer-name: "__init__.py<crlcore/helpers>" -*-
# -*- 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 |

View File

@ -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

View File

@ -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 )

View File

@ -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.' \

View File

@ -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<type>.+)_(?P<index>[\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 = '<IoPadConf %s pad:{} from:{}'.format(self.instanceName,self.padNetName,self.fromCoreNetName)
if self.isBidir():
s += ' to:{} en:{}'.format(self.toCoreNetName,self.enableNetName)
s += '>'
return s
# ----------------------------------------------------------------------------
# Class : "configuration.ChipConf".
class ChipConf ( object ):
"""
Store the configuration for a complete chip, I/O pads and core/chip
sizes mostly.
"""
def __init__ ( self ):
self.name = 'chip'
self.ioPadGauge = None
self.padInstances = []
self.southPads = []
self.northPads = []
self.eastPads = []
self.westPads = []
def addIoPad ( self, spec, specNb ):
"""
Add an I/O pad specification. The spec argument must be of the form:
"""
ioPadConf = IoPadConf( spec )
if spec[0] & IoPin.SOUTH: self.southPads.append( spec[1] )
elif spec[0] & IoPin.NORTH: self.northPads.append( spec[1] )
elif spec[0] & IoPin.EAST: self.eastPads .append( spec[1] )
elif spec[0] & IoPin.WEST: self.westPads .append( spec[1] )
else:
raise ErrorMessage( 1, [ 'ChipConf.addIoPad(): Unspectified side for {}'.format(ioPadConf)
, '(must be NORTH, SOUTH, EAST or WEST)' ] )
self.padInstances.append( ioPadConf )
# ----------------------------------------------------------------------------
# Class : "configuration.BufferInterface".
@ -580,16 +742,18 @@ class BlockState ( object ):
``framework`` The Framework we are using.
``gaugeConf`` The routing Gauge & Cell gauge.
``bufferConf`` The interface of the buffer cell.
``chip`` The optional chip configuration.
``cell`` The block we are working on.
================= ========================================
"""
def __init__ ( self, cell, ioPins=[] ):
def __init__ ( self, cell, ioPins=[], ioPads=[] ):
self.editor = None
self.framework = CRL.AllianceFramework.get()
self.cfg = CfgCache('',Cfg.Parameter.Priority.Interactive)
self.gaugeConf = GaugeConf()
self.bufferConf = BufferInterface( self.framework )
self.chip = ChipConf()
self.bColumns = 2
self.bRows = 2
self.cell = cell
@ -603,6 +767,8 @@ class BlockState ( object ):
self.ioPinsCounts = {}
for ioPinSpec in ioPins:
self.ioPins.append( IoPin( *ioPinSpec ) )
for line in range(len(ioPads)):
self.chip.addIoPad( ioPads[line], line )
self.cfg.etesian.aspectRatio = None
self.cfg.etesian.spaceMargin = None

View File

@ -0,0 +1,183 @@
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) SU 2019-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/cmos.py" |
# +-----------------------------------------------------------------+
"""
Core2Chip configuration for the SxLib/PxLib Alliance historical
standard cell library.
"""
from __future__ import print_function
import sys
import re
from Hurricane import DbU
from Hurricane import DataBase
from Hurricane import UpdateSession
from Hurricane import Breakpoint
from Hurricane import Transformation
from Hurricane import Instance
from Hurricane import Net
import Viewer
from CRL import Catalog
from CRL import AllianceFramework
from helpers.io import ErrorMessage
from plugins.alpha.core2chip.core2chip import CoreToChip as BaseCoreToChip
from plugins.alpha.core2chip.core2chip import IoNet
from plugins.alpha.core2chip.core2chip import IoPad
class CoreToChip ( BaseCoreToChip ):
def __init__ ( self, core ):
BaseCoreToChip.__init__ ( self, core )
self.ringNetNames = { 'vsse' : None
, 'vssi' : None
, 'vdde' : None
, 'vddi' : None
, 'ck' : None # Go through the pads from pck_px.
}
self.ioPadInfos = { IoPad.IN : BaseCoreToChip.IoPadInfo( 'pi_px' , 'pad', ['t',] )
, IoPad.OUT : BaseCoreToChip.IoPadInfo( 'po_px' , 'pad', ['i',] )
, IoPad.TRI_OUT : BaseCoreToChip.IoPadInfo( 'pot_px' , 'pad', ['i', 'b' ] )
, IoPad.BIDIR : BaseCoreToChip.IoPadInfo( 'piot_px', 'pad', ['i', 't', 'b' ] )
}
self._getPadLib()
return
def _getPadLib ( self ):
self.padLib = AllianceFramework.get().getLibrary( "pxlib" )
if not self.padLib:
message = [ 'CoreToChip.cmos._getPadLib(): Unable to find Alliance "pxlib" library' ]
raise ErrorMessage( 1, message )
def getNetType ( self, netName ):
if netName.startswith('vss'): return Net.Type.GROUND
if netName.startswith('vdd'): return Net.Type.POWER
if netName in ('cki', 'ck'): return Net.Type.CLOCK
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, 'cmos.getCell(): I/O pad library "%s" does not contain cell named "%s"' \
% (self.padLib.getName(),masterCellName) )
return cell
def _buildGroundPads ( 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.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['vssi'] = chipNet
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.POWER )
self.ringNetNames['vsse'] = padNet
ioPadConf.pads.append( Instance.create( self.chip
, 'p_vssick_{}'.format(ioPadConf.index)
, self.getCell('pvssick_px') ) )
ioPadConf.pads.append( Instance.create( self.chip
, 'p_vsseck_{}'.format(ioPadConf.index)
, self.getCell('pvsseck_px') ) )
self._connect( ioPadConf.pads[0], chipNet, 'vssi' )
self._connect( ioPadConf.pads[1], padNet , 'vsse' )
self.groundPadCount += 1
self.chipPads += ioPadConf.pads
def _buildPowerPads ( 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.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['vddi'] = chipNet
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.POWER )
self.ringNetNames['vdde'] = padNet
ioPadConf.pads.append( Instance.create( self.chip
, 'p_vddick_{}'.format(ioPadConf.index)
, self.getCell('pvddick_px') ) )
ioPadConf.pads.append( Instance.create( self.chip
, 'p_vddeck_{}'.format(ioPadConf.index)
, self.getCell('pvddeck_px') ) )
self._connect( ioPadConf.pads[0], chipNet, 'vddi' )
self._connect( ioPadConf.pads[1], padNet , 'vdde' )
self.powerPadCount += 1
self.chipPads += ioPadConf.pads
def _buildClockPads ( self, ioPadConf ):
coreNet = self.core .getNet( ioPadConf.coreSupplyNetName )
coronaNet = self.corona.getNet( ioPadConf.coreSupplyNetName )
chipNet = self.chip .getNet( ioPadConf.coreSupplyNetName+'_core' )
ringNet = self.chip .getNet( ioPadConf.coreSupplyNetName+'_ring' )
padNet = self.chip .getNet( ioPadConf.padSupplyNetName )
if not coronaNet:
coronaNet = Net.create( self.corona, ioPadConf.coreSupplyNetName )
coronaNet.setExternal( True )
coronaNet.setType( Net.Type.CLOCK )
self.icore.getPlug( coreNet ).setNet( coronaNet )
if not chipNet:
chipNet = Net.create( self.chip, ioPadConf.coreSupplyNetName+'_core' )
chipNet.setType ( Net.Type.CLOCK )
self.icorona.getPlug( coronaNet ).setNet( chipNet )
self.coreClock = chipNet
if not ringNet:
ringNet = Net.create( self.chip, ioPadConf.coreSupplyNetName+'_ring' )
ringNet.setType( Net.Type.CLOCK )
self.ringNetNames['ck'] = ringNet
if not padNet:
padNet = Net.create( self.chip, ioPadConf.padSupplyNetName )
padNet.setExternal( True )
padNet.setType ( Net.Type.CLOCK )
ioPadConf.pads.append( Instance.create( self.chip
, 'p_ck_{}'.format(ioPadConf.index)
, self.getCell('pck_px') ) )
self._connect( ioPadConf.pads[0], padNet, 'pad' )
self.clockPadCount += 1
self.chipPads += ioPadConf.pads
def _connectClocks ( self ):
p = re.compile( r'pv[ds]{2}[ei]ck_px' )
for pad in self.chipPads:
if p.match( pad.getMasterCell().getName() ):
self._connect( pad, self.coreClock, 'cko' )

View File

@ -0,0 +1,543 @@
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2019-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/core2chip.py" |
# +-----------------------------------------------------------------+
"""
Automatically generates the chip+corona hierarchical netlists from
the *core* of a design.
* *corona* will contains:
1. Exactly **one** instance of the *core* Cell.
2. All the complex wiring to the pads, typically the *ouput enable*
(``oe``) signal connected to the I/O pads of all bits of a bus.
* *chip* will contains:
1. Exactly **one** instance of the *corona* Cell.
2. All the I/O pads.
The double level chip+corona serves two purpose:
1. The standard router will be run on the *corona* only, removing
the need for it to be able to manages the I/O pads. The routing at
chip level, that is connecting the external pins from the *corona*
to the inner sides of the pads, is straightforward. Mostly a straight
wire.
2. In cases were the *corona* is symbolic layout, but we are required to
use the I/O pads from the foundry (so they are *real* layout), the
boundary between symbolic and real is much easier to manage at
corona/chip level. In that case, the connexion may look like a
small dogleg instead of a straight wire.
"""
from __future__ import print_function
import re
from Hurricane import UpdateSession
from Hurricane import Net
from Hurricane import Instance
from CRL import Catalog
from CRL import AllianceFramework
from helpers import netDirectionToStr
from helpers.overlay import UpdateSession
from helpers.io import ErrorMessage
import plugins.chip
from plugins.alpha.block.block import Block
from plugins.alpha.block.configuration import BlockState
from plugins.alpha.block.configuration import IoPadConf
# -------------------------------------------------------------------
# Class : "IoNet".
class IoNet ( object ):
"""
Handle/create the four following nets:
1. ``self.coreNet`` : The original net from the *core*.
2. ``self.coronaNet`` : The same net at *corona* level.
3. ``self.chipIntNet`` : The same net at *chip* level (connected to the
*internal* terminal of the I/O pad.
4. ``self.chipExtNet`` : The corresponding net on the *outside* of the
I/O pad, that is the bonding area. They make the interface of the
chip itself.
From the name of the core signal we derives the names of those four
signals and the instance name of the I/O pad itself.
It also check:
* If the signal is a bit from a vector (flag ``IsElem``), to keep
vectorization across hierarchical level and index the I/O pad name.
* If the signal is an *output enable*, in that case, no I/O pad
nor chip external signal should be generated.
"""
IsElem = 0x0001
IsEnable = 0x0002
DoExtNet = 0x0008
PadPassthrough = 0x0010
reVHDLVector = re.compile( r'(?P<name>[^(]*)\((?P<index>[\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 '<IoNet "{}" ext:"{}" int:"{}">'.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 = '<IoPad "{}" '.format(self.padInstanceName)
for ioNet in self.nets:
s += ' {}'.format(ioNet.coreNetName)
s += '>'
return s
def addNet ( self, ioNet ):
"""
Add an IoNet. Between one and three IoNets are allowed. Corresponding
respectively to simple input/output pad, tristate output pad and
bidirectional pad. See the class definition.
"""
self.nets.append( ioNet )
if len(self.nets) == 1:
if self.nets[0].coreNet.getDirection() == Net.Direction.IN: self.direction = IoPad.IN
elif self.nets[0].coreNet.getDirection() == Net.Direction.OUT: self.direction = IoPad.OUT
elif self.nets[0].coreNet.getName() == 'scout': self.direction = IoPad.OUT
else:
raise ErrorMessage( 1, 'IoPad.addNet(): Unsupported direction {} ({}) for core net "{}" in I/O pad \"{}\".' \
.format( self.nets[0].coreNet.getDirection()
, netDirectionToStr(self.nets[0].coreNet.getDirection())
, self.nets[0].coreNet.getName()
, self.padInstanceName ))
elif len(self.nets) == 2:
self.direction = IoPad.TRI_OUT
elif len(self.nets) == 3:
self.direction = IoPad.BIDIR
else:
message = [ 'IoPad.addNet(): More than three core nets on I/O pad "{}".' \
.format(self.padInstanceName) ]
for ioNet in self.nets:
message += [ "{}".format(ioNet.coreNet) ]
raise ErrorMessage( 1, message )
return
def createPad ( self ):
"""
Actually perform the I/O pad instanciation and triggers the IoNet
signal creations according to context. For example, the output
enable signal (if any) do not need an external chip signal
(it is *not* connected to the outside world).
"""
fromCoreNet = None
toCoreNet = None
enableNet = None
for ioNet in self.nets:
context = 0
if self.direction == IoPad.TRI_OUT:
if ioNet.isEnable(): enableNet = ioNet
else:
fromCoreNet = ioNet
context |= IoNet.DoExtNet
elif self.direction == IoPad.BIDIR:
if ioNet.coreNet.getDirection() == Net.Direction.IN: toCoreNet = ioNet
if ioNet.coreNet.getDirection() == Net.Direction.OUT:
if ioNet.isEnable(): enableNet = ioNet
else:
fromCoreNet = ioNet
context |= IoNet.DoExtNet
else:
context |= IoNet.DoExtNet
fromCoreNet = ioNet
ioNet.buildNets( context )
if not self.coreToChip.ioPadInfos.has_key(self.direction):
raise ErrorMessage( 1, 'IoPad.createPad(): Unsupported direction {} ({}) for pad "{}".' \
.format( self.direction
, IoPad.directionToStr(self.direction)
, self.padInstanceName ))
padInfo = self.coreToChip.ioPadInfos[ self.direction ]
self.pads.append( Instance.create( self.coreToChip.chip
, self.padInstanceName
, self.coreToChip.getCell(padInfo.name) ) )
CoreToChip._connect( self.pads[0], fromCoreNet.chipExtNet, padInfo.padNet )
CoreToChip._connect( self.pads[0], fromCoreNet.chipIntNet, padInfo.coreNets[0] )
if toCoreNet: CoreToChip._connect( self.pads[0], toCoreNet.chipIntNet, padInfo.coreNets[-2] )
if enableNet: CoreToChip._connect( self.pads[0], enableNet.chipIntNet, padInfo.coreNets[-1] )
self.coreToChip.chipPads += self.pads
# -------------------------------------------------------------------
# Class : "CoreToChip".
class CoreToChip ( object ):
"""
Semi-automated build of a complete chip with I/O pad around a Cell core.
``Core2Chip`` expect configuration informations to be present in the
state attribute of the Block class. So a Block class must be created
before calling it.
At chip level we distinguish bewteen two kind of signals connecting the
I/O pads:
1. *Ring signals*, power supplies and optionally clock(s) that have a
special way of connecting to the pads. They go *through* the I/O pad
in east/west and therefore constitute a complete ring around the
chip (and over the pad). In certain cases there can be some
disruption into that ring for analog pads or different clock
domains.
2. *Normal signals*, that is, digital/analog signals coming and going
to the core actually bearing information.
"""
class IoPadInfo ( object ):
def __init__ ( self, padName, padNet, coreNets ):
self.name = padName
self.padNet = padNet
self.coreNets = coreNets
return
def getNetType ( self, netName ):
raise ErrorMessage( 1, 'coreToChip.getNetType(): This method must be overloaded.' )
def isGlobal ( self, netName ):
raise ErrorMessage( 1, 'coreToChip.isGlobal(): This method must be overloaded.' )
def getCell ( self, masterCellName ):
raise ErrorMessage( 1, 'coreToChip.getCell(): This method must be overloaded.' )
@staticmethod
def _connect ( instance, netO, masterNetO=None ):
"""
Connect ``netO`` to the plug of ``masterNetO`` on ``instance``.
:param instance: The instance to work on.
:param netO: The signal to connect to, could be either the net *name*
or the net object itself.
:param masterNetO: The master net (interal net) of the plug. Could be either
the net *name* or the net object. If not supplied,
``_connect()`` will look for a master net of the same
name as ``netO``
"""
if isinstance(netO,Net): chipNet = netO
else: chipNet = instance.getCell().getNet( netO )
if not masterNetO: masterNet = instance.getMasterCell().getNet( chipNet.getName() )
elif isinstance(masterNetO,Net): masterNet = masterNetO
else: masterNet = instance.getMasterCell().getNet( masterNetO )
instance.getPlug( masterNet ).setNet( chipNet )
return
def __init__ ( self, core ):
if isinstance(core,Block):
state = core.state
elif isinstance(core,BlockState):
state = 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
self.ringNetNames = []
self.ioPadInfos = {}
self.chipPads = []
self.padLib = None
self.core = self.state.cell
self.chip = None
self.corona = None
self.icorona = None
self.icore = None
self._ioNets = {}
self.powerPadCount = 0
self.groundPadCount = 0
self.clockPadCount = 0
return
def hasIoNet ( self, netName ):
"""
Look for an IoNet associated to *core* net ``netName``.
"""
if self._ioNets.has_key(netName): return True
return False
def getIoNet ( self, coreNet ):
"""
Lookup, and create if it doesn't exist, for an IoNet associated to *core*
net ``coreNet``.
:param coreNet: The core net signal, could be either the net *name*
or the net object itself.
"""
if isinstance(coreNet,str):
if self._ioNets.has_key(coreNet): return self._ioNet[ coreNet ]
raise ErrorMessage( 1, 'CoreToChip.getIoNet(): Cannot lookup net "%s" by name.' % coreNet )
if not self._ioNets.has_key(coreNet.getName()):
self._ioNets[ coreNet.getName() ] = IoNet( self, coreNet )
return self._ioNets[ coreNet.getName() ]
def _connectPadRing ( self, padInstance ):
"""Connect ring signals to the I/O pad."""
for masterNetName, netName in self.ringNetNames.items():
CoreToChip._connect( padInstance, netName, masterNetName )
def _connectRing ( self ):
"""Create the pad ring signals and connect them to all pad instances"""
for pad in self.chipPads:
self._connectPadRing( pad )
def _buildStandardPad ( self, ioNet ):
"""
Build all the I/O pads for normal signals (that are not related to
power or clock).
"""
if not self.ioPadInfos.has_key(ioNet.coreNet.getDirection()):
raise ErrorMessage( 1, 'CoreToChip._buildStandardPad(): Unsupported direction %d (%s) for core net "%s".' \
% (ioNet.coreNet.getDirection()
,netDirectionToStr(ioNet.coreNet.getDirection())
,ioNet.coreNet.getName()) )
padInfo = self.ioPadInfos[ ioNet.coreNet.getDirection() ]
ioNet.pads.append( Instance.create( self.chip
, ioNet.padInstanceName
, self.getCell(padInfo.name) ) )
CoreToChip._connect( ioNet.pads[0], ioNet.chipExtNet, padInfo.padNet )
CoreToChip._connect( ioNet.pads[0], ioNet.chipIntNet, padInfo.coreNets[0] )
self.chipPads += ioNet.pads
def _buildGroundPads ( self, ioPadConf ):
"""Build I/O pad relateds to ground signals."""
raise NoImplementedError( 'coreToChip._buildGroundPads(): This method must be overloaded.' )
def _buildPowerPads ( self, ioPadConf ):
"""Build I/O pad relateds to power signals."""
raise NoImplementedError( 'coreToChip._buildPowerPads(): This method must be overloaded.' )
def _buildClockPads ( self, ioPadConf ):
"""Build I/O pad relateds to clock signals."""
raise NoImplementedError( 'coreToChip._buildClockPads(): This method must be overloaded.' )
def _connectClocks ( self ):
"""Connect inner clocks signal to the corona (towards the core) ."""
raise NoImplementedError( 'coreToChip._connectClocks(): This method must be overloaded.' )
def buildChip ( self ):
"""
Build the whole chip+corona hierarchical structure (netlist only)
from the core cell.
"""
af = AllianceFramework.get()
with UpdateSession():
self.chip = af.createCell( self.state.chip.name )
self.corona = af.createCell( 'corona' )
self.icore = Instance.create( self.corona, 'core' , self.core )
self.icorona = Instance.create( self.chip , 'corona', self.corona )
ioPads = []
clockIoNets = []
for padConf in self.state.chip.padInstances:
if padConf.isPower():
self._buildPowerPads( padConf )
continue
if padConf.isGround():
self._buildGroundPads( padConf )
continue
if padConf.isClock():
self._buildClockPads( padConf )
continue
padConf.udata = IoPad( self, padConf.instanceName )
for netName in padConf.nets:
if netName is None: continue
coreNet = self.core.getNet( netName )
if not coreNet:
raise ErrorMessage( 1, 'CoreToChip.buildChip(): "%s" doesn\'t have a "%s" net.'
% (self.core.getName(),netName) )
ioNet = self.getIoNet( coreNet )
if padConf.isBidir() or padConf.isTristate():
if coreNet.getName() == padConf.enableNetName:
ioNet.setEnable( True )
if not ioNet.isEnable():
ioNet.chipExtNetName = padConf.padNetName
padConf.udata.addNet( ioNet )
ioPads.append( padConf )
for coreNet in self.core.getNets():
if not coreNet.isExternal(): continue
elif coreNet.isPower(): continue
elif coreNet.isGround(): continue
elif coreNet.isClock(): continue
elif self.hasIoNet(coreNet.getName()): continue
# Remaining non configured Standard I/O pads.
ioNet = IoNet( self, coreNet )
directPad = IoPadConf( ( 0 # Unkown side.
, None # Unknow position.
, ioNet.padInstanceName
, ioNet.chipExtNetName
, ioNet.coreNetName
) )
directPad.udata = IoPad( self, directPad.instanceName )
directPad.udata.addNet( ioNet )
ioPads.append( directPad )
for ioPad in ioPads:
ioPad.udata.createPad()
self._connectRing()
self._connectClocks()
af.saveCell( self.chip , Catalog.State.Logical )
af.saveCell( self.corona, Catalog.State.Logical )

View File

@ -0,0 +1,154 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2019-2018, 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/cmos.py" |
# +-----------------------------------------------------------------+
import re
from Hurricane import DbU
from Hurricane import DataBase
from Hurricane import UpdateSession
from Hurricane import Breakpoint
from Hurricane import Transformation
from Hurricane import Instance
from Hurricane import Net
import Viewer
from CRL import Catalog
from CRL import AllianceFramework
from helpers.io import ErrorMessage
from core2chip.core2chip import IoPad
from core2chip.core2chip import CoreToChip
class cmos ( CoreToChip ):
def __init__ ( self, core ):
CoreToChip.__init__ ( self, core )
self.ringNetNames = [ 'vsse', 'vssi', 'vdde', 'vddi', ('cki', 'ck') ]
self.ioPadInfos = { IoPad.IN : CoreToChip.IoPadInfo( 'pi_px' , 'pad', ['t',] )
, IoPad.OUT : CoreToChip.IoPadInfo( 'po_px' , 'pad', ['i',] )
, IoPad.TRI_OUT : CoreToChip.IoPadInfo( 'pot_px' , 'pad', ['i', 'b' ] )
, IoPad.BIDIR : CoreToChip.IoPadInfo( 'piot_px', 'pad', ['i', 't', 'b' ] )
}
self._getPadLib()
return
def _getPadLib ( self ):
self.padLib = AllianceFramework.get().getLibrary( "pxlib" )
if not self.padLib:
message = [ 'CoreToChip.cmos._getPadLib(): Unable to find Alliance "pxlib" library' ]
raise ErrorMessage( 1, message )
return
def getNetType ( self, netName ):
if netName.startswith('vss'): return Net.Type.GROUND
if netName.startswith('vdd'): return Net.Type.POWER
if netName in ('cki', 'ck'): return Net.Type.CLOCK
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, 'cmos.getCell(): I/O pad library "%s" does not contain cell named "%s"' \
% (self.padLib.getName(),masterCellName) )
return cell
def _buildGroundPads ( self, ioNet ):
ioNet.buildNets()
vssi = self.chip.getNet( 'vssi' )
vssi.setExternal( True )
vssi.setGlobal ( True )
vssi.setType ( Net.Type.GROUND )
vssi.merge( ioNet.chipIntNet )
ioNet.chipIntNet = vssi
vsse = self.chip.getNet( 'vsse' )
vsse.setExternal( True )
vsse.setGlobal ( True )
vsse.setType ( Net.Type.GROUND )
vsse.merge( ioNet.chipExtNet )
ioNet.chipExtNet = vsse
pads = []
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'ick_%d' % self.groundPadCount
, self.getCell('pvssick_px') ) )
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'eck_%d' % self.groundPadCount
, self.getCell('pvsseck_px') ) )
CoreToChip._connect( pads[0], ioNet.chipIntNet, 'vssi' )
CoreToChip._connect( pads[1], ioNet.chipExtNet, 'vsse' )
for pad in pads: self._connectRing( pad )
self.groundPadCount += 1
self.chipPads += pads
return
def _buildPowerPads ( self, ioNet ):
ioNet.buildNets()
vddi = self.chip.getNet( 'vddi' )
vddi.setExternal( True )
vddi.setGlobal ( True )
vddi.setType ( Net.Type.POWER )
vddi.merge( ioNet.chipIntNet )
ioNet.chipIntNet = vddi
vdde = self.chip.getNet( 'vdde' )
vdde.setExternal( True )
vdde.setGlobal ( True )
vdde.setType ( Net.Type.POWER )
vdde.merge( ioNet.chipExtNet )
ioNet.chipExtNet = vdde
pads = [ ]
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'ick_%d' % self.powerPadCount
, self.getCell('pvddick_px') ) )
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'eck_%d' % self.powerPadCount
, self.getCell('pvddeck_px') ) )
CoreToChip._connect( pads[0], ioNet.chipIntNet, 'vddi' )
CoreToChip._connect( pads[1], ioNet.chipExtNet, 'vdde' )
for pad in pads: self._connectRing( pad )
self.powerPadCount += 1
self.chipPads += pads
return
def _buildClockPads ( self, ioNet ):
ioNet.buildNets()
pads = [ ]
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + '_%d' % self.clockPadCount
, self.getCell('pck_px') ) )
CoreToChip._connect( pads[0], ioNet.chipExtNet, 'pad' )
for pad in pads: self._connectRing( pad )
self.clockPadCount += 1
self.chipPads += pads
p = re.compile( r'pv[ds]{2}[ei]ck_px' )
for pad in self.chipPads:
if p.match( pad.getMasterCell().getName() ):
CoreToChip._connect( pad, ioNet.chipIntNet, 'cko' )
return

View File

@ -0,0 +1,133 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
#
# This file is part of the Coriolis Software.
# Copyright (c) UPMC 2019-2018, 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/phlib80.py" |
# +-----------------------------------------------------------------+
import re
from Hurricane import DbU
from Hurricane import DataBase
from Hurricane import UpdateSession
from Hurricane import Breakpoint
from Hurricane import Transformation
from Hurricane import Instance
from Hurricane import Net
import Viewer
from CRL import Catalog
from CRL import AllianceFramework
from helpers.io import ErrorMessage
from plugins.core2chip.core2chip import IoPad
from plugins.core2chip.core2chip import CoreToChip
class phlib80 ( CoreToChip ):
def __init__ ( self, core ):
CoreToChip.__init__ ( self, core )
self.ringNetNames = [ 'vss', 'vss', ('cki', 'ck') ]
self.ioPadInfos = { IoPad.IN : CoreToChip.IoPadInfo( 'pi_sp' , 'pad', ['t',] )
, IoPad.OUT : CoreToChip.IoPadInfo( 'po_sp' , 'pad', ['i',] )
#, IoPad.TRI_OUT : CoreToChip.IoPadInfo( 'pot_sp' , 'pad', ['i', 'b' ] )
#, IoPad.BIDIR : CoreToChip.IoPadInfo( 'piot_sp', 'pad', ['i', 't', 'b' ] )
}
self._getPadLib()
return
def _getPadLib ( self ):
self.padLib = AllianceFramework.get().getLibrary( 'phlib80' )
if not self.padLib:
message = [ 'CoreToChip.phlib80._getPadLib(): Unable to find Alliance "phlib80" library' ]
raise ErrorMessage( 1, message )
return
def getNetType ( self, netName ):
if netName.startswith('vss'): return Net.Type.GROUND
if netName.startswith('vdd'): return Net.Type.POWER
if netName in ('cko', 'ck'): return Net.Type.CLOCK
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, 'cmos.getCell(): I/O pad library "%s" does not contain cell named "%s"' \
% (self.padLib.getName(),masterCellName) )
return cell
def _buildGroundPads ( self, ioNet ):
ioNet.buildNets()
vss = self.chip.getNet( 'vss' )
vss.setExternal( True )
vss.setGlobal ( True )
vss.setType ( Net.Type.GROUND )
vss.merge( ioNet.chipIntNet )
ioNet.chipIntNet = vss
pads = []
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'ck_%d' % self.groundPadCount
, self.getCell('pvssck2_sp') ) )
CoreToChip._connect( pads[0], ioNet.chipIntNet, 'vss' )
for pad in pads: self._connectRing( pad )
self.groundPadCount += 1
self.chipPads += pads
return
def _buildPowerPads ( self, ioNet ):
ioNet.buildNets()
vdd = self.chip.getNet( 'vdd' )
vdd.setExternal( True )
vdd.setGlobal ( True )
vdd.setType ( Net.Type.POWER )
vdd.merge( ioNet.chipIntNet )
ioNet.chipIntNet = vdd
pads = [ ]
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + 'ck_%d' % self.powerPadCount
, self.getCell('pvddck2_sp') ) )
CoreToChip._connect( pads[0], ioNet.chipIntNet, 'vdd' )
for pad in pads: self._connectRing( pad )
self.powerPadCount += 1
self.chipPads += pads
return
def _buildClockPads ( self, ioNet ):
ioNet.buildNets()
pads = [ ]
pads.append( Instance.create( self.chip
, 'p_' + ioNet.padInstanceName + '_%d' % self.clockPadCount
, self.getCell('pck_sp') ) )
CoreToChip._connect( pads[0], ioNet.chipExtNet, 'pad' )
for pad in pads: self._connectRing( pad )
self.clockPadCount += 1
self.chipPads += pads
p = re.compile( r'pv[ds]{2}ck2_sp' )
for pad in self.chipPads:
if p.match( pad.getMasterCell().getName() ):
CoreToChip._connect( pad, ioNet.chipIntNet, 'cko' )
return