Home > Community > Blogs > Custom IC Design > skill for the skilled skill and hi app forms
 
Login with a Cadence account.
Not a member yet?
Create a permanent login account to make interactions with Cadence more conveniennt.

Register | Membership benefits
Get email delivery of the Custom IC Design blog (individual posts).
 

Email

* Required Fields

Recipients email * (separate multiple addresses with commas)

Your name *

Your email *

Message *

Contact Us

* Required Fields
First Name *

Last Name *

Email *

Company / Institution *

Comments: *

SKILL for the Skilled: SKILL++ hi App Forms

Comments(4)Filed under: Virtuoso, SKILL, SKILL++, schematic, object orientation, object system, software development, Jim Newton, layout, schematic hierarchy, design hierarchy, layout hierarchyOne 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 the SKILL++ 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 in smpGUI.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:

Comments(4)

By Prabhakar on December 24, 2013
When I tried to load the first code i.e. code which is given in Overview section.
load("sample/smpGUI.ils")
;;;;;;;;;;;;;;error;;;;;;;;;;;;;
*Error* lambda: formal argument must be a symbol - lambda((_field form cellName \@aux (libName (&->value))) nil (setf ((form->view)->choices) cons("" when(& &))))
*Error* load: error while loading file - "smpgui/smpGUI.ils" at line 120
;;;;;end error;;;;;;;;;;;;;;
Can somebody let me know how to use this code ...?
---
Thanks & Regards
Prabhakar. K

By Team SKILL on January 6, 2014
Hi Prabhakar, Can you try typing the following in the CIW:

CIW> (lambda (@aux x) nil)

Does this trigger an error, or does it return a function object?  If it triggers an error, that probably means you are not using a sufficiently new version of virtuoso to run the code sample.

As a workaround, you might search and replace @aux with @key in the .ils file and see whether you can load the file.  Please let me know whether this works or whether I should try to figure out how to back-port the code to your skill version

Kind regards

Jim


By Ted Paone on May 8, 2014
When did @aux get added to SKILL? Is it documented?

Ted


By Team SKILL on May 12, 2014
Hi Ted, The @aux syntax in a lambda-list declares a variable in the same environment as the other parameters to the function, but which is not visible in any way to the call-site.  
The following two are semantically equivalent.
(defun F (a b @key c @rest c @aux d e f)
  ...)
(defun F (a b @key c @rest c)
  (let (d e f)
    ...))
The correspondence between @aux and let is a bit more complicated in the case that you provide default values for the @aux variables.
@aux has been added to SKILL as a way to optimize critical functions by reducing the number of environments.
Sorry but, I don't know the exact ISR they were added.
I'll check around to try to get you an answer to that question.
About the documentation, you seem to be right that the documentation is lagging.
I hope this helps.
Jim

Leave a Comment


Name
E-mail (will not be published)
Comment
 I have read and agree to the Terms of use and Community Guidelines.
Community Guidelines
The Cadence Design Communities support Cadence users and technologists interacting to exchange ideas, news, technical information, and best practices to solve problems and get the most from Cadence technology. The community is open to everyone, and to provide the most value, we require participants to follow our Community Guidelines that facilitate a quality exchange of ideas and information. By accessing, contributing, using or downloading any materials from the site, you agree to be bound by the full Community Guidelines.