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:
parent
9d56066c2d
commit
513bc72541
|
@ -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 )
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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 |
|
||||
|
|
|
@ -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
|
||||
|
|
@ -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 )
|
||||
|
|
|
@ -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.' \
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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' )
|
|
@ -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 )
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue