diff --git a/documentation/_build/html/PythonTutorial/AdvancedTopics.html b/documentation/_build/html/PythonTutorial/AdvancedTopics.html new file mode 100644 index 00000000..a671ec8d --- /dev/null +++ b/documentation/_build/html/PythonTutorial/AdvancedTopics.html @@ -0,0 +1,447 @@ + + + + + + + + + + + 9. Advanced Topics — Coriolis 2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ +
+
+
+ +
+

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

+
+
+ + +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/_build/html/PythonTutorial/Netlist.html b/documentation/_build/html/PythonTutorial/Netlist.html new file mode 100644 index 00000000..d0076b32 --- /dev/null +++ b/documentation/_build/html/PythonTutorial/Netlist.html @@ -0,0 +1,786 @@ + + + + + + + + + + + 6. Making a hierarchical Cell – Netlist — Coriolis 2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ +
+
+
+ +
+

6. Making a hierarchical Cell – Netlist

+

To illustrate the topic, we will build the netlist of a fulladder from +standard cell.

+

The fulladder netlist

+
+

6.1 Creating an Instance

+

Creating an Instance is straigthforward, the constructor needs only three +parameters:

+
    +
  1. The Cell into which the instance is to be created.
  2. +
  3. The name of the instance.
  4. +
  5. The master cell, the Cell model it refers to. The master cell +will be part of the hierarchical level just below the fulladder +cell.
  6. +
+
+

Note

+

Do not confuse the cell the instance is create into (fulladder) +and the cells it refers to (the master cell xr2_x2).

+
+
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:

+
    +
  1. 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().
  2. +
  3. 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.
  4. +
+

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 a net of fulladder:

+
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.

+
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 :

+
    +
  1. 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.
  2. +
  3. A Translation, applied in second. Translation are represented by +Points.
  4. +
+

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.

+
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.

+
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.

+
# 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 Filter tab, uncheck +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).

+
#!/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
+
+
+
+
+ + +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/_build/html/PythonTutorial/RealDesigns.html b/documentation/_build/html/PythonTutorial/RealDesigns.html new file mode 100644 index 00000000..b6a4c08d --- /dev/null +++ b/documentation/_build/html/PythonTutorial/RealDesigns.html @@ -0,0 +1,464 @@ + + + + + + + + + + + 7. Working in real mode — Coriolis 2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ +
+
+
+ +
+

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.

+
# 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.

+
cell = Blif.load( 'snx' ) # load "snx.blif" in the working directory.
+
+
+
+
+ + +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/documentation/_build/html/PythonTutorial/ToolEngines.html b/documentation/_build/html/PythonTutorial/ToolEngines.html new file mode 100644 index 00000000..01c12ff6 --- /dev/null +++ b/documentation/_build/html/PythonTutorial/ToolEngines.html @@ -0,0 +1,627 @@ + + + + + + + + + + + 8. Tool Engines (CRL Core) — Coriolis 2 documentation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
+ + + + +
+ + + + + + +
+
+
+ +
+
+
+ +
+

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.

+
import Etesian
+
+# [...]
+
+etesian = Etesian.EtesianEngine.create(cell)
+etesian.place()
+
+
+

You can configure the placer in two ways:

+
    +
  1. 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.

    +
  2. +
  3. Setup Etesian parameters through the settings.py configuration +file. For example:

    +
    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).

    +
  4. +
+
+
+

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.

+
+
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%.

+
+
#!/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
+
+
+
+
+ + +
+ + +
+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file