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.
ChildCells
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:
Define a class that is going to be used as a ChildCell. This is a regular PCell with regular views.
Declare the existence of a ChildCell in your parent PCell. This is done via a special property named
ChildCellProperty
.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.
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.
ChildCellProperty
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
Here we define
child
as child cell ofParentPCell
In the Layout view the
self.child
will refer to the Layout view ofchild
. The views are matched by the viewtype from which they inherit. This means that Child will have to have a view that inherits fromi3.Layoutview
In the NetlistView view the
self.child
will refer to the NetlistView view ofchild
. The views are matched by the viewtype from which they inherit. This means that Child will have to have a view that inherits fromi3.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 |
Layout |
|
|
Netlist |
|
|
CircuitModel (previously CapheModel) |
|
Note
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
child_lay.set(paramX=10)
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)
child.set_default_view("LayoutBlackBox")
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!