One way to learn how to use the SKILL++ Object System is by extending
an application which already exists. Once you understand how
extension by inheritance works, it will be easier to implement SKILL++
applications from the ground up. I.e., if you understand inheritance,
you can better architect your application to prepare for it.
This episode of SKILL for the Skilled starts with an
existing SKILL++ GUI application and extends it several times. This
is done each time by declaring a subclass of an existing SKILL++ class
and adding methods on existing generic functions.
Overview
The application presented here is a hi GUI which walks an instance of
a designated SKILL++ class across a designated design hierarchy. If
the class of the instance is the base
class
smpDescendDesign
, each cellView in the hierarchy is
silently visited and, thus, is opened into virtual memory.
Please download theSKILL++
code, load the file smpGUI.ils
, and call the
function smpGUI()
.
The SKILL++ programmer is allowed to extend this base class to
augment, circumvent, or modify some of its behavior.
![FILE UNREADABLE]()
In the following paragraphs we'll extend this application in several ways:
- Add diagnostic messages for each cellView visited
- Save the modified cellViews encountered
- Accommodate descent of schematics
- Descend schematic with diagnostic messages
The Sample GUI
What does this application do? If you trace the
smpWalk
function and press Apply on the form, you get an idea of what's
happening.
|[4]smpWalk(#{smpDescendDesign} db:0x311f7d9a)
|[4]smpWalk (smpDescendDesign t)(#{smpDescendDesign} db:0x311f7d9a)
|[6]smpWalk(#{smpDescendDesign 0x2ef12410} db:0x311f7a9a ?depth 1 ?lineage ... )
|[6]smpWalk (smpDescendDesign t)(#{smpDescendDesign} db:0x311f7a9a ?depth 1 ?lineage ... )
|[6]smpWalk (smpDescendDesign t) --> nil
|[6]smpWalk --> nil
...[stuff omitted]...
|[4]smpWalk (smpDescendDesign t) --> (db:0x311f7bf3 db:0x311f7bf2 db:0x311f7b23 db:0x311f7b22 db:0x311f7b1d ... )
|[4]smpWalk --> (db:0x311f7bf3 db:0x311f7bf2 db:0x311f7b23 db:0x311f7b22 db:0x311f7b1d ... )
The SKILL++ code is given insmpGUI.ils
and smpDescendDesign.ils
. You can experiment with it
by loading startup.ils
and calling the
function smpGUI()
.
Extending the Application
A well-written SKILL++ application is extended not by modifying the
original source code, but rather by creating sub-classes of built-in
classes and providing methods on generic functions. This sample
application defines as extensibility points a class
named
smpDescendDesign
and several generic
functions,
smpDescription
,
smpWalk
,
smpGetSwitchMaster
, and
smpFilterInstances
.
If a SKILL++ application is documented well enough, you will be able
to read the documentation to understand which classes can be extended
and which methods need to be overwritten to accomplish the desired
results. Lacking sufficient documentation, you can read the source
code comments.
Printing the Design Hierarchy
We want to extend the application so that the
Class Name field of the GUI contains both strings:
smpDescendDesign
and
smpPrintDesign
. When the user
selects
smpPrintDesign
and presses OK/Apply, an
additional thing should happen: in particular, as the hierarchy is being
visited, messages should be printed to standard output, indicating
information about the cellViews visited, such as the following:
0 -> ether_adc45n adc_sample_hold layout:
1 --> gpdk045 pmoscap2v layout: |C3
1 --> gpdk045 pmoscap2v layout: |C4
1 --> ether_adc45n inv_2x_hv_small layout: |I58
2 ---> gpdk045 nmos2v layout: |I58/|NM0
2 ---> gpdk045 pmos2v layout: |I58/|PM0
What is a Class?
Long-time readers may recall a series of
SKILL for the Skilled
articles some time ago,
Introduction
to Classes (parts 1 through 5).
A class in SKILL++ is an object which specifies a common structure of
other objects (called instances). A class has at least one parent
(called a direct super-class), and zero or more children (called
direct sub-classes). The set of all classes form a directed acyclic
graph from a special class at the top called t
downward
from super-class to sub-class ending at leaf-level classes at the
bottom. The list of the class itself and all such parent classes
starting with the class and terminating at t
is called the
list of super-classes. In SKILL++ this is a well defined and ordered
list.
The class hierarchy is important because a class inherits structure
and behavior from all its super-classes.
Creating a Subclass
The SKILL built-in macro
defclass
is used to create a new
class or a sub-class of an existing class. If you don't specify an
explicit super-class when creating a new class, its parent will be the
special built-in class called
standardObject
.
To create a class named smpPrintDesign
inheriting
from smpDescendDesign
, use the following syntax:
(defclass smpPrintDesign (smpDescendDesign)
())
This defines a simple class hierarchy as shown in the graphic:
![FILE UNREADABLE]()
As far as SKILL++ is concerned, that's all that is necessary to
create a class. However, to register the class with the sample
application, the API function smpAddClass
is provided.
You need to call it with the name of the class. This tells the GUI
form creation function to add the string "smpPrintDesign"
to the cyclic field choices.
(smpAddClass 'smpPrintDesign)
You are free to create other building-block classes without
registering them with
smpAddClass
. Those building-block
classes won't appear in the GUI.
At this point you will have two Class Name choices in the
GUI, but pressing OK/Apply will do the same thing regardless of which
one is active.
What is a Generic Function?
While classes determine hierarchy and structure, generic functions and
their methods implement behavior. A generic function declares the
interface for all the methods of the same name. SKILL++ enforces
parameter list congruency of all the methods of a generic function.
SKILL++ programmers must be careful to enforce return value of the
methods in a way which makes sense for the particular application.
For example, the return value of smpDescription
must be a
string because that string will be used as the value of a multi-line-string
field in an application form.
The Sample API
This sample application pre-defines several generic functions which
together with the
smpDescendDesign
class form the API for
extending the application. A SKILL++ programmer is allowed to
specialize methods of these generic functions on application-specific
classes derived from
smpDescendDesign
.
The generic functions with their documentation are repeated here, but
may also be found in the file
smpGUI.ils.
smpDescription
(defgeneric smpDescription (obj))
Returns a string (with embedded
\n
characters) describing the
action to be preformed if OK/Apply is pressed on the GUI while a
particular class name is selected.
Methods on this generic function should return a string, possibly
strcat'ing the result with
callNextMethod()
.
smpWalk
(defgeneric smpWalk (obj cv @key lineage (depth 0) @rest _others))
Descend the hierarchy of the given cellview. Methods on this
generic function may perform some action for side effect on the
given cellView. Primary methods should call callNextMethod if they
wish the descent to go deeper, and should avoid calling
callNextMethod to prune the descent at this point. The return value
of
smpWalk
is not specified.
ARGUMENTS:
obj
the object being specialized
cv
the opened cellView which is being visited
lineage
a list of instances representing the lineage of this
cellView back to the top level. The first element of
lineage is the immediate parent of the cellView and
the top-level instance is the last element of lineage
depth
an integer indicating the hierarchy level. 0 indicates
the top-level cellView.
smpFilterInstances
(defgeneric smpFilterInstances (obj cv))
Given a
cellView, return the list of instances whose masters should be
descended. The order of the list returned
from
smpFilterInstances
is unimportant.
smpGetSwitchMaster
(defgeneric smpGetSwitchMaster (obj inst))
Given an
instance in a cellView being visited by
smpWalk
,
smpGetSwitchMaster
returns the cellView to descend into. If
smpGetSwitchMaster
returns
nil
, then the
descent is pruned at this point.
Updating the GUI Description Field
The GUI has a
description field. We'd like this description to
change as the user selects a different class name. We can do this by
implementing the method
smpDescription
specialized on the
new class. If you look at
the
smpDescription
documentation
above the comment on the generic function definition, you'll see some
instructions for implementing methods.
These instructions describe how to implement a method
on smpDescription
: all smpDescription
methods are unary functions, each method is expected to return a
string.
(defmethod smpDescription ((_obj smpPrintDesign))
(strcat (callNextMethod)"\nAnd print the names of each lib/cell/view encountered."))
Now if you interactively select the Class
Name smpPrintDesign
in the GUI, the description should
change as shown here. As you see, the original text Descend the
design hierarchy.
has been augmented by the string concatenated
by the new method.
![FILE UNREADABLE]()
Adding the Diagnostic Messages
We now want to add a method to the
smpWalk
generic
function. For clues on how to do this, consult
the
smpWalk
documentation above. We
can see that each method must have two required arguments, and must
accept some optional arguments, in particular
?lineage
and
?depth
.
(defmethod smpWalk ((_obj smpPrintDesign) cv @key lineage (depth 0))
(printf "%2d " depth)
(for _i 0 depth (printf "-"))
(printf "> ")
(printf "%10s %10s %10s: %s\n"
cv~>libName cv~>cellName cv~>viewName
(buildString (reverse lineage~>name) "/"))
(callNextMethod))
The method smpWalk
specializing
on smpPrintDesign
prints some information about the
cellView being visited, then calls callNextMethod
, which
continues with the descent.
The result of pressing the OK/Apply button is now something like the
following being printed to the CIWindow:
0 -> ether_adc45n adc_sample_hold layout:
1 --> gpdk045 pmoscap2v layout: |C3
1 --> gpdk045 pmoscap2v layout: |C4
1 --> ether_adc45n inv_2x_hv_small layout: |I58
2 ---> gpdk045 nmos2v layout: |I58/|NM0
2 ---> gpdk045 pmos2v layout: |I58/|PM0
Limiting the Descent
The
smpFilterInstances
can be implemented for a sub-class
to affect which instances get considered for
visitation. The
documentation
for smpFilterInstances
is shown above.
The following code defines the class smpSaveDesign
and
extends the sample GUI, adding the capability to walk the design
hierarchy, saving any unsaved cellViews.
![FILE UNREADABLE]()
(defclass smpSaveDesign (smpPrintDesign)
())
(defmethod smpDescription ((_obj smpSaveDesign))
(strcat (callNextMethod)
"\nAnd save any unsaved cellViews."))
(defmethod smpWalk ((_obj smpSaveDesign) cv @rest _otherArgs)
(callNextMethod)
(cond
((member cv~>mode '("r" "s"))
nil)
((cv~>modifiedButNotSaved)
(dbSave cv))))
(defmethod smpFilterInstances ((obj smpSaveDesign) cv)
(foreach mapcan ih cv~>instHeaders
(when ih~>instances
(ncons (car ih~>instances)))))
(smpAddClass 'smpSaveDesign)
In this example a method on smpWalk
which saves the
cellView if needed. It doesn't try to save cellViews which are
read-only, nor scratch cellViews. Also it doesn't try to save
anything unless it has modifiedButNotSaved set.
The smpWalk
method specializing
on smpDescendDesign
calls smpFilterInstances
to determine the list of instances to consider for descent.
A smpFilterInstances
method on smpSaveDesign
is added here, which DOES NOT call callNextMethod
. Since
we are descending the hierarchy to save unsaved cellViews, we
don't need to visit the same master more than once. This method
returns a list of instances in the given cellView, one per instance
header, which has an instance. I.e.,
sometimes instHead~>instances
is nil
;
these are skipped.
Descending a Schematic Hierarchy
The classes shown above are great for walking a layout hierarchy. At
each step the
smpWalk
is called recursively on the master
of the instance being examined. To descend a schematic hierarchy, we
ignore the master of the instance which is probably the symbol, and
open and descend explicitly into the schematic when it exists. To do
this we define the class
smpSchematicHierarchy
and
provide the method
smpGetSwitchMaster
. See
the
smpGetSwitchMaster
documentation.
![FILE UNREADABLE]()
(defclass smpSchematicHierarchy (smpDescendDesign)
())
(defmethod smpGetSwitchMaster ((obj smpSchematicHierarchy) inst)
(when (ddGetObj inst~>libName inst~>cellName "schematic")
(dbOpenCellViewByType inst~>libName inst~>cellName "schematic")))
(defmethod smpDescription ((_obj smpSchematicHierarchy))
(strcat (callNextMethod)
"\nAnd descends a schematic hierarchy by looking for schematic cellviews""\n of symbol instances."))
(smpAddClass 'smpSchematicHierarchy)
The important method implemented here
is
smpGetSwitchMaster
, which tests whether the schematic
exists; if so, it opens and returns it. The
smpWalk
method
specializing on
smpDescendDesign
calls
smpGetSwitchMaster
to determine which cellView to
descend into, if any.
Combining Classes with Multiple Inheritance
SKILL++ supports multiple inheritance. This means a class is in
principle allowed to inherit from more than one class.
We can use multiple inheritance to create an option in the sample
GUI, which both descends the schematic hierarchy (based on
class smpSchematicHierarchy
) and prints information as
the visiting occurs (based on class smpPrintDesign
). To
do this we define the class smpPrintSchematic
to inherit
from both smpPrintDesign
and smpSchematicHierarchy
, making the graph of the class
hierarchy look like the following.
![FILE UNREADABLE]()
Here is the code:
(defclass smpPrintSchematic (smpPrintDesign smpSchematicHierarchy)
())
(smpAddClass 'smpPrintSchematic)
Notice in this case that we don't define any new methods. This is
because the methods defined thus far suffice for what we need. For
example: the smpGetSwitchMaster
method for
class smpSchematicHierarchy
will be used. In addition,
since they all call callNextMethod
of smpWalk
for all the classes,
(smpPrintDesign
, smpSchematicHierarchy
,
and smpDescendDesign
) will be used. In addition when
selecting "smpPrintSchematic"
on the GUI, we get a
concatenated description of all the parent classes
of smpPrintSchematic
.
![FILE UNREADABLE]()
Conclusion
Download this
sample
SKILL++ application, and load it by loading
the
startup.ils
file. Again you'll need to start the GUI
by typing
smpGUI()
into the CIWindow.
In this article we looked at a SKILL++ application which extends a
specially designed application form. The application form allows you to select between several different behaviors based on the
name of a selected class.
![FILE UNREADABLE]()
The article shows several examples of class and method declarations
which extend the given sample application in different ways. In
particular it shows some simple examples of:
- How to create a sub-class of an existing class
- How to specialize a method on your class
- How to use
callNextMethod
- How to use simple multiple inheritance
For more specific information on the SKILL++ Object System, please
consult the Cadence online documentation. And as always, please post
comments or questions below.
See also: