• Skip to main content
  • Skip to search
  • Skip to footer
Cadence Home
  • This search text may be transcribed, used, stored, or accessed by our third-party service providers per our Cookie Policy and Privacy Policy.

  1. Blogs
  2. Analog/Custom Design
  3. SKILL for the Skilled: What is SKILL++?
Team SKILL
Team SKILL

Community Member

Blog Activity
Options
  • Subscribe by email
  • More
  • Cancel
CDNS - RequestDemo

Have a question? Need more information?

Contact Us
Team SKILL
hierarchy
Virtuoso
Lisp
Custom IC Design
SKILL++
SKILL
Allegro

SKILL for the Skilled: What is SKILL++?

4 Jan 2011 • 5 minute read

The way SKILL++ deals with functions is a bit different than the way traditional SKILL deals with them. In this posting I'd like to show how to implement a design hierarchy traversal engine in SKILL++ and use it as an introduction to SKILL++.

What is SKILL++?

SKILL++ is a subset of the SKILL language, not a separate language as one might suppose. The term SKILL++ refers to a small but powerful set of extensions that were made to the core SKILL language in the mid 1990s and are now available for use in many Cadence tools. In fact, any Cadence tool that is extensible by loading and executing SKILL programs is a candidate for using SKILL++, including: Virtuoso, VirtuosoXL, pipo, Assura, Dracula, PVS, Allegro-PCB, cdnsip and probably a few more that I'm forgetting.

Basically the language features are:

  • Lexically scoped variables
  • Single function/variable name space (sometimes called Lisp-1)
  • An object system based on the Common Lisp Object System

By contrast, traditional SKILL offers dynamically scoped variables and separate names spaces (sometimes called Lisp-2) for functions and variables. Dynamic and lexical variables are both useful for different purposes.

What are dynamic and lexical variables?

These two kinds of variables differ semantically but not syntactically. All variables appearing in SKILL++ code are considered lexical while all variables appearing in traditional SKILL code are dynamic.

If you are wondering what the semantic difference is:

  • Dynamic variables allow SKILL expressions to control particular values during a dynamic extent; i.e., while a function and its children functions are pending evaluation. During this time of pending evaluation, dynamic variables are visible globally unless explicitly shadowed by another enclosed binding of the same name.
  • Lexical variables allow functions to isolate visibility of objects so that only a fixed set of expressions have access to the value by name, but extend that access indefinitely -- even after the dynamic extent of pending evaluation.

Perceptions of SKILL++

In this article, we'll ignore the SKILL++ object system and concentrate on the first two of these capabilities -- sometimes referred to jointly as the SKILL++ Scheme Dialect. Unfortunately, the other dialect which lives alongside Scheme has no official marketing name. For lack of a better name, we'll call it traditional SKILL. Hereafter, I'll just use the term SKILL++ rather than the SKILL++ Scheme Dialect.

If you haven't started using SKILL++ yet, the basics are simpler than you might think. If you are completely new to SKILL, you'll find SKILL++ easy and intuitive. If you're a long time SKILL programmer, you'll do things in SKILL++ pretty much the way you would have wanted to 25 years ago when you started learning SKILL. That is, you've already learned the hard way; now you can take a look at the easy way.

How to create SKILL++ code

There are several ways to indicate to the SKILL interpreter that you want to use SKILL++ rather than traditional SKILL. One way is to end your file names with the .ils extension for SKILL++ and .il for traditional SKILL; file.ils is SKILL++; file.il is traditional SKILL.

Please assume all the functions in the remainder of this article are SKILL++.

SKILL++ by example

The first example function, walkCvHier, is an ultra-simple design hierarchy traversal engine. It won't work for all purposes you might need but is good for the purpose of the examples below.

1.1: (defun walkCvHier (cv consume)
1.2: (foreach inst cv~>instances
1.3: (walkCvHier inst~>master consume))
1.4: (consume cv))

This function is a type of higher-order function, because it takes a function as one of its arguments. It is also possible with SKILL++ for functions to compute and create other functions at run time according to their given arguments -- more about this in a future article. Although it is sometimes possible to use traditional SKILL to create higher-order functions with limited capability, my advice is that you always use SKILL++ if you need this abstraction.

How does it work? The function, walkCvHier, steps through the explicit cellView hierarchy such as a layout, assuming you always want to descend into the instance master. At each step of the hierarchy, a given function is applied. You can pass in any function as long as that function can take a cellView as its only argument. The function, walkCvHier, will happily call that function for you at each cellView found of the hierarchy, every time that cellView occurs.

Saving the hierarchy?

Here's an example of how to use walkCvHier. The function saveCvHier asks walkCvHier to call dbSave on each cellView in the hierarchy.

2.1: (defun saveCvHier (cv)
2.2: (walkCvHier cv dbSave))

The function walkCvHier has a local variable consume, declared on line 1.1, which it uses on line 1.4 in the function call position (consume cv). Because this is SKILL++, consume does not refer to the global function of that name, but since there is a local variable of that name, that variable is used instead. The value of that variable better be a function, else an error will occur at run-time. On line 2.2, the saveCvHier function calls dbSave as this second argument. There are several important things to note here:

  • The reference to dbSave on line 2.2 is NOT QUOTED. Why? Because in SKILL++ names of global functions can be referenced exactly as variables.
  • The consume function is called on line 1.4 with normal function calling syntax. Why? Because in SKILL++ you are allowed to call global functions and local functions with the exact same syntax.
  • The name consume does not need to start with a capital letter or an underscore. It need only obey the naming rules for local variables.
Reporting the hierarchy

Suppose that rather than calling dbSave on the hierarchy, you'd like to do something for which there is no built-in function. For example, suppose you want to descend a design hierarchy and report which cellViews are found. You'll need to provide a function which will do the reporting for one cellView. One alternative is to define a function for this purpose, such as _reportCv.
3.1: (defun _reportCv (cv)
3.2: (println (list cv~>libName
3.3: cv~>cellName
3.4: cv~>viewName)))
3.5:
3.6: (defun reportCvHier (cv)
3.7: (walkCvHier cv _reportCv))

The intent here is that _reportCv be private and only be used in this one place. However, because it is defined with defun (the same would be true if it were defined with procedure) it is actually available globally. Its private status cannot be enforced. In the past, privacy has been implemented in traditional SKILL using naming conventions and documentation. SKILL++ provides better fixes this problem by providing ways systematic ways for hiding data.

...to be continued...

What's next?

In the next posting we'll look at local functions, closures (functions with state), and a few slightly more advanced examples using the walkCvHier function.

Jim Newton

See Also:

  • Scheme
  • Lexical vs. dynamic scoping
  • Lexical scoping
  • Dynamic scoping
  • Higher order functions
  • Optimizing lexical variables
  • Encapsulation
  • Common Lisp Object System

CDNS - RequestDemo

Try Cadence Software for your next design!

Free Trials

© 2025 Cadence Design Systems, Inc. All Rights Reserved.

  • Terms of Use
  • Privacy
  • Cookie Policy
  • US Trademarks
  • Do Not Sell or Share My Personal Information