.. -*- Mode: 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_ has one Plug_ for each external net of the *master cell*.
The plug allows to create a **logical** connection bewteen a Net_ of
``fulladder`` and a net from an Instance_ *master cell*.

A plug is somewhat equivalent to an *instance terminal* in other
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 )``. If 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
its 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 enforces 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  unneeded 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 simplify
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 its *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 connection between two
levels of hierarchy. To make the physical connection 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 other
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, let say that we must construct the
Occurrence object with one parameter : the Plug_ for which we want to create a
physical connection.

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