Typo in CMakeLists.txt : AND instead of "and".
This commit is contained in:
parent
767407736d
commit
c5034a9156
|
@ -7,7 +7,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BUILD_DOC and DOXYGEN_FOUND)
|
if (BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( documentation ALL
|
add_custom_target ( documentation ALL
|
||||||
cd ${CRLCORE_SOURCE_DIR}/doc/crlcore
|
cd ${CRLCORE_SOURCE_DIR}/doc/crlcore
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -0,0 +1,36 @@
|
||||||
|
.. -*- Mode: rst -*-
|
||||||
|
.. include:: ../etc/definitions.rst
|
||||||
|
.. include:: ./definitions.rst
|
||||||
|
|
||||||
|
|
||||||
|
9. Advanced Topics
|
||||||
|
==================
|
||||||
|
|
||||||
|
This is a place holder as well as a reminder to myself to write this part of
|
||||||
|
the documentation.
|
||||||
|
|
||||||
|
|
||||||
|
9.1 Occurrence
|
||||||
|
~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The trans-hierarchical workhorse.
|
||||||
|
|
||||||
|
|
||||||
|
9.2 RoutingPads
|
||||||
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Unlike the Plugs_ that only make connexions between two **adjacent**
|
||||||
|
hierarchical levels, RoutingPads_ can refer to a deeply buried terminal.
|
||||||
|
|
||||||
|
|
||||||
|
9.3 HyperNets
|
||||||
|
~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
This class is part of the *virtual flattening* mechanisms, it allows to
|
||||||
|
go through all the components of a trans-hierarchical net.
|
||||||
|
|
||||||
|
|
||||||
|
9.4 Miscellaeous trans-hierarchical functions
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For a starter, how to get all the leaf cells...
|
|
@ -0,0 +1,399 @@
|
||||||
|
.. -*- Mode: rst -*-
|
||||||
|
.. include:: ../etc/definitions.rst
|
||||||
|
.. include:: ./definitions.rst
|
||||||
|
|
||||||
|
|
||||||
|
6. Making a hierarchical Cell -- Netlist
|
||||||
|
========================================
|
||||||
|
|
||||||
|
To illustrate the topic, we will build the netlist of a fulladder from
|
||||||
|
standard cell.
|
||||||
|
|
||||||
|
|fulladder_1|
|
||||||
|
|
||||||
|
|
||||||
|
6.1 Creating an Instance_
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Creating an Instance_ is straigthforward, the constructor needs only three
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
#. The Cell_ **into which** the instance is to be created.
|
||||||
|
#. The name of the instance.
|
||||||
|
#. The **master cell**, the Cell_ model it refers to. The master cell
|
||||||
|
will be part of the hierarchical level just below the ``fulladder``
|
||||||
|
cell.
|
||||||
|
|
||||||
|
.. note:: Do not confuse the cell the instance is create into (``fulladder``)
|
||||||
|
and the cells it refers to (the *master cell* ``xr2_x2``).
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
af = AllianceFramework.get()
|
||||||
|
xr2_x2 = af.getCell( 'xr2_x1', Catalog.State.Views )
|
||||||
|
|
||||||
|
fulladder = af.createCell( 'fulladder' )
|
||||||
|
xr2_1 = Instance.create( fulladder, 'xr2_1', xr2_x2 )
|
||||||
|
|
||||||
|
|
||||||
|
6.2 Creating Nets and connecting to Instances
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
An Instance_ as one Plug_ for each external net of the *master cell*.
|
||||||
|
The plug allows to create a **logical** connexion bewteen a Net_ of
|
||||||
|
``fulladder`` and a net from an Instance_ *master cell*.
|
||||||
|
|
||||||
|
A plug is somewhat equivalent to an *instance terminal* in others
|
||||||
|
well known databases.
|
||||||
|
|
||||||
|
Therefore, a plug is related to two nets:
|
||||||
|
|
||||||
|
#. The net of the *master cell* it is linked to. Obviously that
|
||||||
|
net cannot be changed. You can access the master net with the
|
||||||
|
function ``plug.getMasterNet()``.
|
||||||
|
|
||||||
|
#. The net of ``fulladder`` the plug is connected to. This can
|
||||||
|
be set, it is how we build the netlist. To set the net, use
|
||||||
|
the function ``plug.setNet( net )``. It the argument is ``None``,
|
||||||
|
the plug is *disconnected*.
|
||||||
|
|
||||||
|
To find the plug of an instance associated to a given net in
|
||||||
|
the *master cell*, use ``instance.getPlug( masterNet )``.
|
||||||
|
The ``masterNet`` argument being an object of class net (not
|
||||||
|
it's name).
|
||||||
|
|
||||||
|
Building the :cb:`a` net of ``fulladder``:
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
a = Net.create( fulladder, "a" )
|
||||||
|
a.setExternal( True )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet("i0") ).setNet( a )
|
||||||
|
a2_1 .getPlug( a2_x2.getNet("i0") ).setNet( a )
|
||||||
|
|
||||||
|
|
||||||
|
.. note:: **Limitation of Hurricane Netlists.** There is no explicit
|
||||||
|
terminal object in the |Hurricane| database. Plugs are
|
||||||
|
generated *on the fly* for each *external net* of the
|
||||||
|
instance. One important consequence is that a *net*
|
||||||
|
cannot appear on the interface as two differently named
|
||||||
|
terminals (sometimes referred as *weekly connected*
|
||||||
|
terminals). There is a strict bijection between external
|
||||||
|
nets and plugs.
|
||||||
|
|
||||||
|
While it may be restrictive, it enforce cleaner designs
|
||||||
|
and make it possible for the HyperNet_ concept/class.
|
||||||
|
|
||||||
|
|
||||||
|
6.3 Power supplies special case
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
For supplies, it may be tedious to connect the Plugs_ of each cell one by one
|
||||||
|
(and create a lot of uneeded objects). To avoid that, we may use **Named
|
||||||
|
connections**. If a signal in ``fulladder`` is set to *global*, then it will
|
||||||
|
be considered as connected to any signal with the *same name* and *global* in
|
||||||
|
the master cell of the instances.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
vdd = Net.create( fulladder, "vdd" )
|
||||||
|
vdd.setExternal( True )
|
||||||
|
vdd.setGlobal ( True ) # Will be connected to all the instances.
|
||||||
|
|
||||||
|
|
||||||
|
6.4 Creating the physical view of a Cell netlist
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Even if loaded in the viewer, an Instance will not be displayed
|
||||||
|
until it is placed.
|
||||||
|
|
||||||
|
|
||||||
|
6.4.1 Transformation
|
||||||
|
--------------------
|
||||||
|
|
||||||
|
To place an Instance, we apply a Transformation_ to the coordinate system
|
||||||
|
of the *master cell*. A transformation is composed of two operations :
|
||||||
|
|
||||||
|
#. An Orientation_, which can be a symmetry or a rotation (or a combination
|
||||||
|
of those two). The Orientation **is applied first** to the coordinate
|
||||||
|
system of the *master cell*. The complete list of Orientation and their
|
||||||
|
codes are given on the Orientation documentation page.
|
||||||
|
|
||||||
|
#. A **Translation**, applied in second. Translation are represented by
|
||||||
|
Points_.
|
||||||
|
|
||||||
|
The transformation is a change of coordinate system, be aware that if the
|
||||||
|
abutment box lower left corner of the *master* cell is **not** at ``(0,0)``
|
||||||
|
the result of the Transformation may not be what you expect. To simplificate
|
||||||
|
the computation of the transformation of an instance, always place the
|
||||||
|
lower left corner of the abutment box at ``(0,0)``
|
||||||
|
|
||||||
|
|
||||||
|
6.4.2 Placing an Instance
|
||||||
|
-------------------------
|
||||||
|
|
||||||
|
Assuming that we want to place the cells of the ``fulladder`` into two rows,
|
||||||
|
that the abutment box lower left corner is at ``(0,0)`` (same for the
|
||||||
|
``xr2_x2`` *master cell* layout). Here is the code to place the ``xr2_1``
|
||||||
|
instance to left of the second row.
|
||||||
|
|
||||||
|
Setting the translation on an Instance_ is not enough to make it be displayed,
|
||||||
|
we also must set it's *placement status* to ``Instance.PlacementStatus.PLACED``.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
xr2_1.setTransformation( Transformation( DbU.fromLambda( 0.0)
|
||||||
|
, DbU.fromLambda(100.0)
|
||||||
|
, Transformation.Orientation.MY ) )
|
||||||
|
xr2_1.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
|
||||||
|
|
||||||
|
6.4.3 Nets -- From Plugs to RoutingPads
|
||||||
|
---------------------------------------
|
||||||
|
|
||||||
|
As was stated before, Plugs_ represent a logical connexion between two
|
||||||
|
levels of hierarchy. To make the physical connexion to the *master net*
|
||||||
|
in the instance, we now must create, in the ``fulladder``, a special
|
||||||
|
component which is a kind of *reference* to a component of the
|
||||||
|
*master net* (in the master cell).
|
||||||
|
|
||||||
|
The so called *special component* is a RoutingPad_.
|
||||||
|
|
||||||
|
The ``RoutingPad`` can be considered as an equivalent to ``pin`` in others
|
||||||
|
well known databases.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
rp = RoutingPad.create( a
|
||||||
|
, Occurrence( xr2_1.getPlug( xr2_x2.getNet("i0")) )
|
||||||
|
, RoutingPad.BiggestArea )
|
||||||
|
|
||||||
|
For the second parameter, we must pass an Occurrence_. Occurrence objects will
|
||||||
|
be explained in detail later, for now, suffice to say that we must construct the
|
||||||
|
Occurrence object with one parameter : the Plug_ for which we want to create a
|
||||||
|
physical connexion.
|
||||||
|
|
||||||
|
The RoutingPad_ ``rp`` will be a component of the ``a`` net.
|
||||||
|
|
||||||
|
The third argument ask the constructor of the RoutingPad_ to select in the
|
||||||
|
master net, the component which has the biggest area.
|
||||||
|
|
||||||
|
.. note:: **Component selection.** Not all the components of a net can be
|
||||||
|
selected for connexion through a RoutingPad_. The candidates must
|
||||||
|
have been flagged with the NetExternalComponents_ class.
|
||||||
|
|
||||||
|
See `3.6.3 Creating a Component`_.
|
||||||
|
|
||||||
|
|
||||||
|
6.4.4 Nets -- Regular wiring
|
||||||
|
----------------------------
|
||||||
|
|
||||||
|
After the creation of the RoutingPads_, the wiring is to be created with
|
||||||
|
ordinary layout components (Horizontal_, Vertical_ and Contact_ possibly
|
||||||
|
articulated). Here is the complete code for net ``a``. We made an articulated
|
||||||
|
layout where contacts are created over RoutingPads_ then segments over
|
||||||
|
contacts.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
# Build wiring for a.
|
||||||
|
# Create RoutingPads first.
|
||||||
|
rp1 = RoutingPad.create( a
|
||||||
|
, Occurrence( xr2_1.getPlug( xr2_x2.getNet("i0")) )
|
||||||
|
, RoutingPad.BiggestArea )
|
||||||
|
rp2 = RoutingPad.create( a
|
||||||
|
, Occurrence( a2_1.getPlug( a2_x2.getNet("i0")) )
|
||||||
|
, RoutingPad.BiggestArea )
|
||||||
|
|
||||||
|
# Then regular wiring.
|
||||||
|
contact1 = Contact.create( rp1, via12, toDbU( 0.0), toDbU(-15.0) )
|
||||||
|
contact2 = Contact.create( rp2, via12, toDbU( 0.0), toDbU( 10.0) )
|
||||||
|
turn = Contact.create( a , via23, toDbU(10.0), toDbU( 35.0) )
|
||||||
|
Horizontal.create( contact2, turn , metal2, toDbU(35.0), toDbU(2.0) )
|
||||||
|
Vertical .create( turn , contact1 , metal3, toDbU(10.0), toDbU(2.0) )
|
||||||
|
|
||||||
|
|
||||||
|
.. note:: In order to better see the layout of the wiring only, open the
|
||||||
|
``Controller`` and in the :fboxtt:`Filter` tab, uncheck
|
||||||
|
:fboxtt:`Process Terminal Cells`.
|
||||||
|
|
||||||
|
|
||||||
|
6.5 The Complete Example File
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The example file ``fulladder.py`` can be found in the ``share/doc/coriolis2/examples/scripts/``
|
||||||
|
directory (under the the root of the |Coriolis| installation).
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from Hurricane import *
|
||||||
|
from CRL import *
|
||||||
|
|
||||||
|
|
||||||
|
def toDbU ( l ): return DbU.fromLambda(l)
|
||||||
|
|
||||||
|
|
||||||
|
def doBreak ( level, message ):
|
||||||
|
UpdateSession.close()
|
||||||
|
Breakpoint.stop( level, message )
|
||||||
|
UpdateSession.open()
|
||||||
|
|
||||||
|
|
||||||
|
def buildFulladder ( editor ):
|
||||||
|
|
||||||
|
# Get the Framework and all the master cells.
|
||||||
|
af = AllianceFramework.get()
|
||||||
|
xr2_x2 = af.getCell( 'xr2_x1', Catalog.State.Views )
|
||||||
|
a2_x2 = af.getCell( 'a2_x2' , Catalog.State.Views )
|
||||||
|
o2_x2 = af.getCell( 'o2_x2' , Catalog.State.Views )
|
||||||
|
|
||||||
|
UpdateSession.open()
|
||||||
|
|
||||||
|
fulladder = af.createCell( 'fulladder' )
|
||||||
|
fulladder.setAbutmentBox( Box( toDbU(0.0), toDbU(0.0), toDbU(90.0), toDbU(100.0) ) )
|
||||||
|
|
||||||
|
if editor:
|
||||||
|
UpdateSession.close()
|
||||||
|
editor.setCell( fulladder )
|
||||||
|
editor.fit()
|
||||||
|
UpdateSession.open()
|
||||||
|
|
||||||
|
# Create Instances.
|
||||||
|
a2_1 = Instance.create( fulladder, 'a2_1', a2_x2 )
|
||||||
|
a2_2 = Instance.create( fulladder, 'a2_2', a2_x2 )
|
||||||
|
xr2_1 = Instance.create( fulladder, 'xr2_1', xr2_x2 )
|
||||||
|
xr2_2 = Instance.create( fulladder, 'xr2_2', xr2_x2 )
|
||||||
|
o2_1 = Instance.create( fulladder, 'o2_1', o2_x2 )
|
||||||
|
|
||||||
|
# Create Nets.
|
||||||
|
vss = Net.create( fulladder, "vss" )
|
||||||
|
vss.setExternal( True )
|
||||||
|
vss.setGlobal ( True )
|
||||||
|
|
||||||
|
vdd = Net.create( fulladder, "vdd" )
|
||||||
|
vdd.setExternal( True )
|
||||||
|
vdd.setGlobal ( True )
|
||||||
|
|
||||||
|
cin = Net.create( fulladder, "cin" )
|
||||||
|
cin.setExternal( True )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('i0') ).setNet( cin )
|
||||||
|
a2_2 .getPlug( a2_x2.getNet('i0') ).setNet( cin )
|
||||||
|
|
||||||
|
a = Net.create( fulladder, 'a' )
|
||||||
|
a.setExternal( True )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('i0') ).setNet( a )
|
||||||
|
a2_1 .getPlug( a2_x2.getNet('i0') ).setNet( a )
|
||||||
|
|
||||||
|
b = Net.create( fulladder, 'b' )
|
||||||
|
b.setExternal( True )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('i1') ).setNet( b )
|
||||||
|
a2_1 .getPlug( a2_x2.getNet('i1') ).setNet( b )
|
||||||
|
|
||||||
|
sout_1 = Net.create( fulladder, 'sout_1' )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('q' ) ).setNet( sout_1 )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('i1') ).setNet( sout_1 )
|
||||||
|
a2_2 .getPlug( a2_x2.getNet('i1') ).setNet( sout_1 )
|
||||||
|
|
||||||
|
carry_1 = Net.create( fulladder, 'carry_1' )
|
||||||
|
a2_1.getPlug( a2_x2.getNet('q' ) ).setNet( carry_1 )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('i1') ).setNet( carry_1 )
|
||||||
|
|
||||||
|
carry_2 = Net.create( fulladder, 'carry_2' )
|
||||||
|
a2_2.getPlug( a2_x2.getNet('q' ) ).setNet( carry_2 )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('i0') ).setNet( carry_2 )
|
||||||
|
|
||||||
|
sout = Net.create( fulladder, 'sout' )
|
||||||
|
sout.setExternal( True )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('q') ).setNet( sout )
|
||||||
|
|
||||||
|
cout = Net.create( fulladder, 'cout' )
|
||||||
|
cout.setExternal( True )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('q') ).setNet( cout )
|
||||||
|
|
||||||
|
# Instances placement.
|
||||||
|
a2_1.setTransformation( Transformation( toDbU(0.0)
|
||||||
|
, toDbU(0.0)
|
||||||
|
, Transformation.Orientation.ID ) )
|
||||||
|
a2_1.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Placed a2_1' )
|
||||||
|
|
||||||
|
xr2_1.setTransformation( Transformation( toDbU( 0.0)
|
||||||
|
, toDbU(100.0)
|
||||||
|
, Transformation.Orientation.MY ) )
|
||||||
|
xr2_1.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Placed xr2_1' )
|
||||||
|
|
||||||
|
a2_2.setTransformation( Transformation( toDbU(25.0)
|
||||||
|
, toDbU( 0.0)
|
||||||
|
, Transformation.Orientation.ID ) )
|
||||||
|
a2_2.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Placed a2_2' )
|
||||||
|
|
||||||
|
xr2_2.setTransformation( Transformation( toDbU( 45.0)
|
||||||
|
, toDbU(100.0)
|
||||||
|
, Transformation.Orientation.MY ) )
|
||||||
|
xr2_2.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Placed xr2_2' )
|
||||||
|
|
||||||
|
o2_1.setTransformation( Transformation( toDbU(65.0)
|
||||||
|
, toDbU( 0.0)
|
||||||
|
, Transformation.Orientation.ID ) )
|
||||||
|
o2_1.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Placed o2_1' )
|
||||||
|
|
||||||
|
# Add filler cells.
|
||||||
|
tie_x0 = af.getCell( 'tie_x0', Catalog.State.Views )
|
||||||
|
rowend_x0 = af.getCell( 'rowend_x0', Catalog.State.Views )
|
||||||
|
filler_1 = Instance.create( fulladder, 'filler_1', tie_x0 )
|
||||||
|
filler_2 = Instance.create( fulladder, 'filler_2', rowend_x0 )
|
||||||
|
|
||||||
|
filler_1.setTransformation( Transformation( toDbU(50.0)
|
||||||
|
, toDbU( 0.0)
|
||||||
|
, Transformation.Orientation.ID ) )
|
||||||
|
filler_1.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
|
||||||
|
filler_2.setTransformation( Transformation( toDbU(60.0)
|
||||||
|
, toDbU( 0.0)
|
||||||
|
, Transformation.Orientation.ID ) )
|
||||||
|
filler_2.setPlacementStatus( Instance.PlacementStatus.PLACED )
|
||||||
|
doBreak( 1, 'Filler cell placeds' )
|
||||||
|
|
||||||
|
# Getting the layers.
|
||||||
|
technology = DataBase.getDB().getTechnology()
|
||||||
|
metal2 = technology.getLayer( "METAL2" )
|
||||||
|
metal3 = technology.getLayer( "METAL3" )
|
||||||
|
via12 = technology.getLayer( "VIA12" )
|
||||||
|
via23 = technology.getLayer( "VIA23" )
|
||||||
|
|
||||||
|
# Build wiring for a.
|
||||||
|
# Create RoutingPads first.
|
||||||
|
rp1 = RoutingPad.create( a
|
||||||
|
, Occurrence( xr2_1.getPlug( xr2_x2.getNet("i0")) )
|
||||||
|
, RoutingPad.BiggestArea )
|
||||||
|
rp2 = RoutingPad.create( a
|
||||||
|
, Occurrence( a2_1.getPlug( a2_x2.getNet("i0")) )
|
||||||
|
, RoutingPad.BiggestArea )
|
||||||
|
|
||||||
|
# Then regular wiring.
|
||||||
|
contact1 = Contact.create( rp1, via12, toDbU( 0.0), toDbU(-15.0) )
|
||||||
|
contact2 = Contact.create( rp2, via12, toDbU( 0.0), toDbU( 10.0) )
|
||||||
|
turn = Contact.create( a , via23, toDbU(10.0), toDbU( 35.0) )
|
||||||
|
Horizontal.create( contact2, turn , metal2, toDbU(35.0), toDbU(2.0) )
|
||||||
|
Vertical .create( turn , contact1 , metal3, toDbU(10.0), toDbU(2.0) )
|
||||||
|
|
||||||
|
UpdateSession.close()
|
||||||
|
|
||||||
|
af.saveCell( fulladder, Catalog.State.Views )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def ScriptMain ( **kw ):
|
||||||
|
editor = None
|
||||||
|
if kw.has_key('editor') and kw['editor']:
|
||||||
|
editor = kw['editor']
|
||||||
|
|
||||||
|
buildFulladder( editor )
|
||||||
|
return True
|
|
@ -0,0 +1,51 @@
|
||||||
|
.. -*- Mode: rst -*-
|
||||||
|
.. include:: ../etc/definitions.rst
|
||||||
|
.. include:: ./definitions.rst
|
||||||
|
|
||||||
|
|
||||||
|
7. Working in real mode
|
||||||
|
=======================
|
||||||
|
|
||||||
|
The AllianceFramework_ only manage *symbolic* layout as |Alliance| do.
|
||||||
|
But |Coriolis| is also able to work directly in *real* mode, meaning
|
||||||
|
that distances will be expresseds in microns instead of lambdas.
|
||||||
|
|
||||||
|
The *real* mode will be illustrated by working with the FreePDK45_.
|
||||||
|
|
||||||
|
We will assume that the FreePDK45_ archives is installed under: ::
|
||||||
|
|
||||||
|
/home/dks/
|
||||||
|
|
||||||
|
|
||||||
|
7.1 Loading a |LEF| file
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Importing a |LEF| file is simple, you just call the static function
|
||||||
|
``LefImport.load()``. Multiple |LEF| file can be imported one after
|
||||||
|
another.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
# You must set "DKsdir" to where you did install the NCSU FreePDK 45nm DK.
|
||||||
|
DKsdir = '/home/dks'
|
||||||
|
|
||||||
|
library = LefImport.load( DKsdir + '/FreePDK45/osu_soc/lib/files/gscl45nm.lef' )
|
||||||
|
|
||||||
|
|
||||||
|
.. note:: **Technology checking.** The first imported |LEF| file must contains the
|
||||||
|
technology. The technology described in the |LEF| file will be checked
|
||||||
|
against the one configured in the running instance of |Coriolis| to look
|
||||||
|
for any discrepencies.
|
||||||
|
|
||||||
|
|
||||||
|
7.2 Loading a |Blif| file -- |Yosys|
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The |Blif| format is generated by the Yosys_ logic synthetizer. Here again, it is
|
||||||
|
pretty straightforward: call the static function ``Blif.load()``. If you did make
|
||||||
|
your synthesis on a cell library not managed by AllianceFramework_, For example
|
||||||
|
the one of the FreePDK45, you must load it prior to calling the |Blif| loader.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
cell = Blif.load( 'snx' ) # load "snx.blif" in the working directory.
|
|
@ -0,0 +1,213 @@
|
||||||
|
.. -*- Mode: rst -*-
|
||||||
|
.. include:: ../etc/definitions.rst
|
||||||
|
.. include:: ./definitions.rst
|
||||||
|
|
||||||
|
|
||||||
|
8. Tool Engines (CRL Core)
|
||||||
|
==========================
|
||||||
|
|
||||||
|
The ToolEngine_ class is the base class for all tools developpeds in
|
||||||
|
|Coriolis|. In the rest of the tutorial we will use the names ``tool``
|
||||||
|
or ``engine`` as synonyms.
|
||||||
|
|
||||||
|
|
||||||
|
8.1 Placer -- Etesian
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
To run the placer, create the |Etesian| engine, then call the ``place()``
|
||||||
|
function.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
import Etesian
|
||||||
|
|
||||||
|
# [...]
|
||||||
|
|
||||||
|
etesian = Etesian.EtesianEngine.create(cell)
|
||||||
|
etesian.place()
|
||||||
|
|
||||||
|
You can configure the placer in two ways:
|
||||||
|
|
||||||
|
#. Prior to the creation of the engine, setup an abutment for the cell.
|
||||||
|
The placer will fit the cells into that area. If the area is too
|
||||||
|
small, it will issue an error.
|
||||||
|
|
||||||
|
#. Setup |Etesian| parameters through the ``settings.py`` configuration
|
||||||
|
file. For example:
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
parametersTable = \
|
||||||
|
( ("etesian.effort" , TypeEnumerate , 2 )
|
||||||
|
, ('etesian.uniformDensity' , TypeBool , True )
|
||||||
|
, ('etesian.spaceMargin' , TypePercentage, 3.0 )
|
||||||
|
, ('etesian.aspectRatio' , TypePercentage, 100.0 )
|
||||||
|
)
|
||||||
|
|
||||||
|
With this setup, the cells will be spread uniformally over the
|
||||||
|
area (``etesian.uniformDensity``), with ``3.0%`` of free space
|
||||||
|
added and an aspect ratio of ``100%`` (square shape).
|
||||||
|
|
||||||
|
|
||||||
|
8.1 Router -- Katana
|
||||||
|
~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Like for |Etesian|, you have to create the engine on the cell then call
|
||||||
|
the sequence of functions detailed below.
|
||||||
|
|
||||||
|
.. note:: **Kite vs. Katana.** There are currently two router in |Coriolis|,
|
||||||
|
|Kite| is the old one and digital only. |Katana| is a re-implementation
|
||||||
|
with support for mixed routing (digital **and** analog).
|
||||||
|
Until |Katana| is fully implemented we keep both of them.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
import Anabatic
|
||||||
|
import Katana
|
||||||
|
|
||||||
|
# [...]
|
||||||
|
|
||||||
|
katana = Katana.KatanaEngine.create(cell)
|
||||||
|
katana.digitalInit ()
|
||||||
|
katana.runGlobalRouter ()
|
||||||
|
katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
|
||||||
|
katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
|
||||||
|
katana.runNegociate ( Katana.Flags.NoFlags )
|
||||||
|
|
||||||
|
|
||||||
|
8.2 A Complete Example
|
||||||
|
~~~~~~~~~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
The example file ``toolengines.py`` can be found in the ``share/doc/coriolis2/examples/scripts/``
|
||||||
|
directory (under the the root of the |Coriolis| installation).
|
||||||
|
|
||||||
|
This script automatically place and route the ``fulladder`` netlist as seen
|
||||||
|
previously. The call to the ToolEngines_ is made inside the new function
|
||||||
|
``placeAndRoute()``.
|
||||||
|
|
||||||
|
.. note:: As the ``ToolEngine`` take care of opening and closing UpdateSession_, we
|
||||||
|
do not need the wrapper function ``doBreak()`` around the breakpoints.
|
||||||
|
We directly call Breakpoint_.
|
||||||
|
|
||||||
|
.. note:: The space margin for this example is very high (``30%``), it's only
|
||||||
|
because it's too small for the placer to run correctly. For normal
|
||||||
|
case it is around ``3%``.
|
||||||
|
|
||||||
|
.. code-block:: Python
|
||||||
|
|
||||||
|
#!/usr/bin/python
|
||||||
|
|
||||||
|
import sys
|
||||||
|
from Hurricane import *
|
||||||
|
from CRL import *
|
||||||
|
import Etesian
|
||||||
|
import Anabatic
|
||||||
|
import Katana
|
||||||
|
|
||||||
|
# Everybody needs it.
|
||||||
|
af = AllianceFramework.get()
|
||||||
|
|
||||||
|
|
||||||
|
def toDbU ( l ): return DbU.fromLambda(l)
|
||||||
|
|
||||||
|
|
||||||
|
def buildFulladder ( editor ):
|
||||||
|
|
||||||
|
# Get the Framework and all the master cells.
|
||||||
|
xr2_x2 = af.getCell( 'xr2_x1', Catalog.State.Views )
|
||||||
|
a2_x2 = af.getCell( 'a2_x2' , Catalog.State.Views )
|
||||||
|
o2_x2 = af.getCell( 'o2_x2' , Catalog.State.Views )
|
||||||
|
|
||||||
|
UpdateSession.open()
|
||||||
|
|
||||||
|
fulladder = af.createCell( 'fulladder' )
|
||||||
|
|
||||||
|
# Create Instances.
|
||||||
|
a2_1 = Instance.create( fulladder, 'a2_1', a2_x2 )
|
||||||
|
a2_2 = Instance.create( fulladder, 'a2_2', a2_x2 )
|
||||||
|
xr2_1 = Instance.create( fulladder, 'xr2_1', xr2_x2 )
|
||||||
|
xr2_2 = Instance.create( fulladder, 'xr2_2', xr2_x2 )
|
||||||
|
o2_1 = Instance.create( fulladder, 'o2_1', o2_x2 )
|
||||||
|
|
||||||
|
# Create Nets.
|
||||||
|
vss = Net.create( fulladder, "vss" )
|
||||||
|
vss.setExternal( True )
|
||||||
|
vss.setGlobal ( True )
|
||||||
|
|
||||||
|
vdd = Net.create( fulladder, "vdd" )
|
||||||
|
vdd.setExternal( True )
|
||||||
|
vdd.setGlobal ( True )
|
||||||
|
|
||||||
|
cin = Net.create( fulladder, "cin" )
|
||||||
|
cin.setExternal( True )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('i0') ).setNet( cin )
|
||||||
|
a2_2 .getPlug( a2_x2.getNet('i0') ).setNet( cin )
|
||||||
|
|
||||||
|
a = Net.create( fulladder, 'a' )
|
||||||
|
a.setExternal( True )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('i0') ).setNet( a )
|
||||||
|
a2_1 .getPlug( a2_x2.getNet('i0') ).setNet( a )
|
||||||
|
|
||||||
|
b = Net.create( fulladder, 'b' )
|
||||||
|
b.setExternal( True )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('i1') ).setNet( b )
|
||||||
|
a2_1 .getPlug( a2_x2.getNet('i1') ).setNet( b )
|
||||||
|
|
||||||
|
sout_1 = Net.create( fulladder, 'sout_1' )
|
||||||
|
xr2_1.getPlug( xr2_x2.getNet('q' ) ).setNet( sout_1 )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('i1') ).setNet( sout_1 )
|
||||||
|
a2_2 .getPlug( a2_x2.getNet('i1') ).setNet( sout_1 )
|
||||||
|
|
||||||
|
carry_1 = Net.create( fulladder, 'carry_1' )
|
||||||
|
a2_1.getPlug( a2_x2.getNet('q' ) ).setNet( carry_1 )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('i1') ).setNet( carry_1 )
|
||||||
|
|
||||||
|
carry_2 = Net.create( fulladder, 'carry_2' )
|
||||||
|
a2_2.getPlug( a2_x2.getNet('q' ) ).setNet( carry_2 )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('i0') ).setNet( carry_2 )
|
||||||
|
|
||||||
|
sout = Net.create( fulladder, 'sout' )
|
||||||
|
sout.setExternal( True )
|
||||||
|
xr2_2.getPlug( xr2_x2.getNet('q') ).setNet( sout )
|
||||||
|
|
||||||
|
cout = Net.create( fulladder, 'cout' )
|
||||||
|
cout.setExternal( True )
|
||||||
|
o2_1.getPlug( o2_x2.getNet('q') ).setNet( cout )
|
||||||
|
|
||||||
|
UpdateSession.close()
|
||||||
|
|
||||||
|
af.saveCell( fulladder, Catalog.State.Views )
|
||||||
|
return fulladder
|
||||||
|
|
||||||
|
|
||||||
|
def placeAndRoute ( editor, cell ):
|
||||||
|
# Run the placer.
|
||||||
|
etesian = Etesian.EtesianEngine.create(cell)
|
||||||
|
etesian.place()
|
||||||
|
|
||||||
|
if editor:
|
||||||
|
editor.setCell( cell )
|
||||||
|
editor.fit()
|
||||||
|
|
||||||
|
Breakpoint.stop( 1, 'After placement' )
|
||||||
|
|
||||||
|
# Run the router.
|
||||||
|
katana = Katana.KatanaEngine.create(cell)
|
||||||
|
katana.digitalInit ()
|
||||||
|
katana.runGlobalRouter ()
|
||||||
|
katana.loadGlobalRouting( Anabatic.EngineLoadGrByNet )
|
||||||
|
katana.layerAssign ( Anabatic.EngineNoNetLayerAssign )
|
||||||
|
katana.runNegociate ( Katana.Flags.NoFlags )
|
||||||
|
|
||||||
|
af.saveCell( cell, Catalog.State.Views )
|
||||||
|
return
|
||||||
|
|
||||||
|
|
||||||
|
def ScriptMain ( **kw ):
|
||||||
|
editor = None
|
||||||
|
if kw.has_key('editor') and kw['editor']:
|
||||||
|
editor = kw['editor']
|
||||||
|
|
||||||
|
fulladder = buildFulladder( editor )
|
||||||
|
placeAndRoute( editor, fulladder )
|
||||||
|
return True
|
|
@ -7,7 +7,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_DOC and DOXYGEN_FOUND)
|
if(BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( hurricaneDoc ALL
|
add_custom_target ( hurricaneDoc ALL
|
||||||
cd ${HURRICANE_SOURCE_DIR}/doc/hurricane
|
cd ${HURRICANE_SOURCE_DIR}/doc/hurricane
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_DOC and DOXYGEN_FOUND)
|
if(BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( viewerDoc ALL
|
add_custom_target ( viewerDoc ALL
|
||||||
cd ${HURRICANE_SOURCE_DIR}/doc/viewer
|
cd ${HURRICANE_SOURCE_DIR}/doc/viewer
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if(BUILD_DOC and DOXYGEN_FOUND)
|
if(BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( doc ALL
|
add_custom_target ( doc ALL
|
||||||
cd ${KATABATIC_SOURCE_DIR}/doc
|
cd ${KATABATIC_SOURCE_DIR}/doc
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BUILD_DOC and DOXYGEN_FOUND)
|
if (BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( doc ALL
|
add_custom_target ( doc ALL
|
||||||
cd ${KITE_SOURCE_DIR}/doc
|
cd ${KITE_SOURCE_DIR}/doc
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
tabs.css
|
tabs.css
|
||||||
)
|
)
|
||||||
|
|
||||||
if (BUILD_DOC and DOXYGEN_FOUND)
|
if (BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target ( documentation ALL
|
add_custom_target ( documentation ALL
|
||||||
cd ${UNICORN_SOURCE_DIR}/doc/unicorn
|
cd ${UNICORN_SOURCE_DIR}/doc/unicorn
|
||||||
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
&& ${DOXYGEN_EXECUTABLE} doxyfile
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
|
|
||||||
if(BUILD_DOC and DOXYGEN_FOUND)
|
if(BUILD_DOC AND DOXYGEN_FOUND)
|
||||||
add_custom_target( doc ALL
|
add_custom_target( doc ALL
|
||||||
cd ${VLSISAPD_SOURCE_DIR}/doc && ${DOXYGEN_EXECUTABLE} doxyfile )
|
cd ${VLSISAPD_SOURCE_DIR}/doc && ${DOXYGEN_EXECUTABLE} doxyfile )
|
||||||
endif()
|
endif()
|
||||||
|
|
Loading…
Reference in New Issue