Home > Community > Blogs > Custom IC Design > skill for the skilled what is skill
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).


* 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: What is SKILL++?

Comments(4)Filed under: Custom IC Design, Virtuoso, SKILL, Team SKILL, Allegro, LISP, hierarchy, SKILL++

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:

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.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:


By chanakaya on January 6, 2011
For those who want to try it out interactively with a REPL, type

(toplevel 'ils) in the CIW and go from there.

By Team SKILL on January 6, 2011
Hi Chanakaya,
Yes that's right.  You can also use the inSkill and inScheme macros/primitives to surround code you want evaluated with particular scoping.  E.g.,
 (defvar XYZ 42))
 (defvar XYZ -13))
(inScheme XYZ)
==> 42
(inSkill XYZ)
==> -13

By Andrew Beckett on January 7, 2011
Probably some readers have not grasped the difference between dynamic and lexical scoping (Jim's explanation was a little terse)  - in fact most people may have assumed that the scoping was actually lexical in traditional SKILL.

Lexical scoping is probably the more natural - the extent of the binding of a variable is the block of code (or text, hence the term "lexical") that it is defined in. So you can clearly see where a name is valid, and which variable is which. As I think Jim will show in future postings, you can use this lexical scoping for some pretty neat features in SKILL++.

Dynamic scoping can be thought of as a each variable being a stack - as you declare each variable in a let() (or similar) or define it as a formal parameter of a function, it pushes the new value onto the top of the stack, and then pops it off when that let() or function has returned. What this means is that the binding of a variable may not actually be global - it will see whatever is on the top of the stack at that point in the program's execution. Now this can be extremely useful, and allow you to do some powerful things, but it's probably more of an expert feature and for most users the effects of dynamic scoping only show up when you accidentally forget to declare a local variable.

So I would suggest that lexical scoping is more intuitive and easier to grasp and take advantage of for most novice users, and that dynamic scoping (or at least taking advantage of dynamic scoping) is more of an expert feature.

The lesson is - don't be scared by the "++" in the name SKILL++! You can completely ignore the object system if that scares you (although it shouldn't), yet still take advantage of the neat features that come as a result of lexical scoping without it hurting your brain!


By Team SKILL on January 7, 2011
Hi Andrew, thanks for the comments.  Dynamic variables are interesting creatures.  They certainly provide the SKILL language with an expert feature that few languages can match, especially co-called modern ones.  They'll become even more powerful in combination with some cool upcoming features of 615 and 616.

Leave a Comment

E-mail (will not be published)
 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.