Hierarchical PCells

As your designs become more complex it is important to divide your design in several blocks that are manageable by themselves. These blocks are then reused at several points in the design. Introducing hierarchy in your design allows you to do create manageable blocks without duplicating code. This is important as this makes components more robust, less prone to errors, easier to document and easier to modify. We strongly recommend that you use hierarchy in your designs. It may look like overhead in the beginning, but it pays off later when you increase the complexity of your designs.


Within IPKISS PCells, it is possible to reuse cells hierarchically through ChildCells. Each ChildCell has views that have to be instantiated as instances (once or several times) in the views of the parent PCell. To use a ChildCell in a Parent Cell you need to go through the following steps:

  1. Define a class that is going to be used as a ChildCell. This is a regular PCell with regular views.

  2. Declare the existence of a ChildCell in your parent PCell. This is done via a special property named ChildCellProperty.

  3. In each view of your parent cell one or several instances of the corresponding view has to be placed. In each view this happens through a special method: _generate_instances() and some other functions that are specific to each view.

In the figure below, these steps are illustrated in pseudo-code for a Parent Cell that uses 2 ChildCells. The first ChildCell (child_1) is instantiated twice in every view, whereas the second ChildCell(child_2) is instantiated once.

Circuit simulation overview.

Illustration of ChildCells.

We will now dig a bit deeper in the last two steps: The definition of the ChildCellProperty and the instantiations of the views of the child cells in the views of the parent cell.


For a parent PCell to use child PCells in a hierarchical way, the child cells have to be declared with ChildCellProperty. ChildCellProperties are different from other properties as they make the views of the child cells available in the corresponding views of the parent cell.

This is best exemplified by the following piece of code:

class ParentPCell(i3.PCell):

    # 1.
    child = i3.ChildCellProperty()

    def _some_method_using_child(self):
       self.child #Refers to the child pcell.

    class Layout(i3.LayoutView):

       # 2.
       def _some_method_using_child(self):
          self.child # refers to the layout (that inherits from i3.LayoutView) of the child.

    class Netlist(i3.NetlistView)
      # 3.
       def _some_method_using_child(self):
          self.child # refers to the Netlist view (that inherits from i3.NetlistView) of the child
  1. Here we define child as child cell of ParentPCell

  2. In the Layout view the self.child will refer to the Layout view of child. The views are matched by the viewtype from which they inherit. This means that Child will have to have a view that inherits from i3.Layoutview

  3. In the NetlistView view the self.child will refer to the NetlistView view of child. The views are matched by the viewtype from which they inherit. This means that Child will have to have a view that inherits from i3.NetlistView

Corresponding views are from the same view type, which means that they inherit from one of the base view types as represented in the table below.

View class

Base view type

Instance type



i3.SRef, i3.ARef, i3.MRef




CircuitModel (previously CapheModel)




When a cell has two views that are from the same base view type, ChildCellProperty will pick the one that is set as the default_view of that type. You can read more on default view types in the pcell guide. See also the example below: Overriding views originating from ChildCellProperty.

Adding the child views

As mentioned before, the next step is adding one or several instances of each child view to the views of the parent. In each view, this is done in the method _generate_instances. Inside _generate_instances functions specific to the base view type add each of the instances.

In the Layout view for example, this can be done through SRef, where a name and a transformation have to be defined.

class ParentPCell(i3.PCell):

    child = i3.ChildCellProperty()

    class Layout(i3.LayoutView):

       def _generate_instances(self,insts):
         insts += i3.SRef(self.child, name="Name of the instance", transformation =...)

For other views this is very similar: in the table above, a listing of the Base View Type and the corresponding functions to use inside _generate_instances is given.

Overriding views originating from ChildCellProperty

It may be that the default_view that is automatically set by ChildCellProperty in each view of the Parent cell is not be the one you want. In that case you can always override it using _default_ methods that can override the default value of any property. Let’s illustrate this with a code excerpt.

class Child(i3.PCell):
   class Layout(i3.LayoutView):
      # this is the default layout
   class LayoutBlackBox(i3.LayoutView):
      # this is a black box layout
   class Netlist(i3.NetlistView):

class ParentPCell(i3.PCell):

    child = i3.ChildCellProperty()

    def _some_method_using_child(self):
         self.child # refers to the PCell of child.

    class Layout(i3.LayoutView):

       # Override the LayoutView of child to be used with "LayoutBlackBox", which is also defined in Child
       def _default_child(self):
          child_lay = self.cell.child.get_default_view("LayoutBlackBox")
          # optionally, set parameters on the layout view
          return child_lay

       def _some_method_using_child(self):
          self.child # now refers to the view Layout2.

    class Netlist(i3.NetlistView):

       def _some_method_using_child(self):
          self.child # Refers to the default Netlist view of the child

In the code excerpt we have overridden the default layout view of self.child. It now refers to the LayoutBlackBox view.

Caution setting properties of child cell

If the child cells are automatically calculated by a _default method in the parent cell, as with the ParentPCell.Layout above, you should not modify properties on the child cell using the pattern below, since it may lead to undefined behaviour:

parent = ParentPCell(name="parent")
lay = parent.Layout()
lay.child.some_property = 10.0 # This is not OK - undefined behaviour

The reason is that in this case, the parent cell is responsible of calculating its child cells. Since you are not the owner of that child cell, it is difficult to predict what would happen since the parent cell might have defined interdependencies.

If on the other hand you created the child cell yourself, it is possible to modify parameters:

child = Child(name="achild")
child_lay = child.LayoutBlackBox(some_property=2.0)

parent = ParentPCell(name="parent", child=child)
parent_lay = parent.Layout()
print parent_lay.child # will print an instance of LayoutBlackBox

It is important to set the default view of the child to the LayoutBlackBox, otherwise it will still use the default Layout view!