|Developer||Cadence Design Systems|
|Stable release||? / ?|
|Cadence Allegro, Cadence APD, Cadence Concept HDL and Cadence Virtuoso. Major LISP implementation — Cadence UniCAD.|
|Scheme, Common Lisp, CLOS|
SKILL is a Lisp dialect used as a scripting language and PCell (parameterized cells) description language used in many EDA software suites by Cadence Design Systems (e.g. Cadence Allegro and Cadence Virtuoso). It was originally put forth in an IEEE paper in 1990.
SKILL was originally based on a flavor of Lisp called “Franz Lisp” created at UC Berkeley by the students of Professor Richard J. Fateman. SKILL is not an acronym; it is a name. For trademark reasons Cadence prefers it be capitalized.
Franz Lisp and all other flavors of LISP were eventually superseded by an ANSI standard for Lisp called "Common Lisp." Historically, SKILL was known as IL. SKILL was a library of IL functions. The name was originally an initialism for Silicon Compiler Interface Language (SCIL), pronounced "SKIL", which then morphed into "SKILL", a plain English word that was easier for everyone to remember.
"IL" was just Interface Language. Whilst SKILL was used initially to describe the API rather than the language, the snappier name stuck. The name "IL" remains a common file extension used for SKILL code ".il" designating that the code contained in the file has lisp-2 semantics. Another possible file extension is ".ils" designating that the content has lisp-1 semantics.
Comments are delimited by either the traditional Lisp semicolon
(car mylist) ; Comment from semicolon to end of the line
or C-style comments
/* Comment */ car(mylist) /* Another comment */
SKILL programmers have a choice of expression syntaxes. Traditional Lisp syntax such as
can be mixed with C-like syntax such as
White space between the function name and the opening parenthesis, as in
is also allowed but has a different meaning. For example,
(list car (mylist))
has the traditional lisp meaning of a call to the list function with two operands car and (mylist), the first of which is a variable reference, and the second a call to the mylist function. Usually this is not what the beginner programmer intended. Thus, SKILL novices usually incorrectly think of car (mylist) as a syntax error.
Certain arithmetic operations can be also called using an infix notation. Thus each of the following is recognized and in fact are represented the same internally
(plus 1 2 3 4 5 6 7) plus(1 2 3 4 5 6 7) 1+2+3+4+5+6+7
Functions may be called using several different indirect second order functions.
(inSkill (apply 'plus '(1 2 3 4 5 6 7))) (inScheme (apply plus '(1 2 3 4 5 6 7))) (inSkill (apply 'plus 1 2 3 '(4 5 6 7))) (inScheme (apply plus 1 2 3 '(4 5 6 7))) (inSkill (funcall 'plus 1 2 3 4 5 6 7))) (inScheme (funcall plus 1 2 3 4 5 6 7)))
This infix notation was introduced to make it easier for programmers familiar with C and other procedural languages to understand and write SKILL code.
SKILL indeed internally represents the language as traditional Lisp S-expression, the surface syntax loosens this restriction compared to other lisps. More elaborate examples look quite different from their Lisp equivalents. For example, the factorial function in SKILL may be represented several different ways which are all compiled to the identical internal representation.
;; C style procedure (factorial(n) if ( n <= 1 then 1 else n * factorial(n-1) ) )
;; LISP style (procedure (factorial n) (if (leqp n 1) then 1 else (times n (factorial (difference n 1)))))
;; Hybrid style (procedure (factorial n) (if n <= 1 then 1 else n * (factorial n-1)))
Objects and types
The SKILL language supports several built-in object types: symbol, list, fixnum, flonum, string, port, assocTable, array, funobj, envobj, and stdobj.
The SKILL language supports both dynamic (sometimes referred to as special) and lexical variables. However, a single function is limited to interpret its variables homogeneously. There are several ways of syntactically indicating whether a function be interpreted lexically or dynamically. One of which are to use (inSkill ..) and (inScheme ...) forms indicating dynamic and lexical scoping respectively.
(inSkill (lambda (A B) (A B)))
In the inSkill example A and B are dynamic variables in the parameter list of the lambda (the lambda list), and (A B) within the body of the function is interpreted as a call to the globally defined function A passing the value of the local dynamic variable B.
(inScheme (lambda (A B) (A B)))
In the inScheme example A and B are lexical variables in both the lambda list, and also (A B) within the body of the function which is interpreted as a call to the function A which has been passed and a parameter the value of the local lexical variable B.
inSkill and inScheme forms may be mixed within a single function with some degree of flexibility.
(inScheme (lambda (A B) (A (inSkill B) B)))
In this example a lexical 2-ary function is created which calls A, a function passed as its first argument, passing two parameters: the value of the dynamic variable B and also the value of the local lexical variable B.
SKILL supports several kinds of functions. In addition to the functions and special forms built into the language, users can create functions in their own applications of several varieties.
Anonymous functions including lexical closures.
(lambda (A) (lambda (B) (plus A B)))
Lambda functions which evaluate their arguments using normal left-to-right evaluation rules.
(defun (A B) (list A A B B))
Nlambda functions which do not evaluate their arguments, but pass their operands unevaluated at run time.
(nprocedure (A) (when (listp A) (eval A)))
Macros which are evaluated by expanding at load/compile time. The sexpressions a macro returns (evaluates to) become input for the compiler, and is thus evaluated at run time.
(defmacro nif (num if_plus if_zero if_minus) (let ((var (gensym))) `(let ((,var ,num)) (cond ((plusp ,var) ,if_plus) ((zerop ,var) ,if_zero) (t ,if_minus)))))
SKILL supports CLOS-like generic functions which are allowed to have an optional default implementation.
(defgeneric generic_add (a b c))
SKILL supports CLOS-like methods which specialize on all their required arguments. (Older versions of SKILL only support specialization of the first argument.)
(defmethod generic_add ((a fixnum) (b number) (c list)) (apply plus a b c))
Local functions of two sorts are supported with flet and labels. If local functions are defined with flet such as inner1 and inner2 below, neither one can see the other's definition.
(defun outer () (flet ((inner1 () (printf "hello")) (inner2 () (printf "world"))) (inner1) (printf " ") (inner2) (newline)))
If local functions are defined with labels such as inner1 and inner2 below, all of them see the other's definition. Local function are only supported in lexical mode.
(defun outer () (labels ((inner1 () (printf "hello")) (inner2 () (inner1) (printf " world\n"))) (inner2)))
Additional commands are added to the language for functions specific to a certain tool. For example, functions specific to the PCB Editor have the prefix “axl” (e.g.
axlDBGetDesign), and commands specific to the Design Entry tool have the prefix “cn” (e.g.
Here are some examples of SKILL.
First, a basic “Hello world”:
SKILL supports tail call optimization, if it is explicitly enabled. Here is a tail recursive version of factorial which requires no stack space for the recursion if optimizeTailCall is enabled.
(sstatus optimizeTailCall t) (defun factorial (n) (flet ((repeat (n factorial) (if (plusp n) (repeat (sub1 n) n * factorial)) factorial))) (repeat n 1)))
The following definition is a more idiomatic iterative definition.
(defun factorial (n) (let ((answer 1)) (for i 2 n answer = answer * i) answer)))
This example shows how variables are assigned and scoped, using
procedure( swap() let( ((a 1) (b 2)) c = a a = b b = c printf("%d %d %d\n" a b c) ) )
b are scoped within the
let function, but variable
c is not. As a result,
c becomes a global variable that can be accessed without the scope of the
swap function. Here is what happens when swap is executed and
c are then printed:
> swap 2 1 1 t > a *Error* toplevel: undefined variable - a > b *Error* toplevel: undefined variable - b > c 1
- G. Wood and H-F S. Law, "SKILL - An Interactive Procedural Design Environment," Proceedings of Custom Integrated Circuits Conference, 1986, pp. 544–547
- Quan Nguyen, "CAD Scripting Languages", "A collection of Perl, Ruby, Python,Tcl and SKILL Scripts". Published by RAMACAD INC. ISBN 0-9777812-2-4, ISBN 978-0-9777812-2-5. A Sample from Google Books
- A Quick Tour of SKILL Programming with command-line examples of SKILL codes versus Perl, Ruby, Python & TCL (go to the end of the blog)
- A SKILL users' group is currently hosted on Yahoo! Groups under the name "skill_school" (https://groups.yahoo.com/neo/groups/skill_school link]).
- Cadence also hosts two SKILL users' group forums on their Cadence Community website. One is dedicated to Allegro PCB SKILL (PCB SKILL), and the other is dedicated to IC SKILL (Custom IC SKILL).
- No known users' group currently exists for Cadence Concept SKILL scripting (as of May 2010).
More SKILL Programming Examples: http://www.cadence.com/community/forums/T/10274.aspx
- Cadence Design Systems
- CopperCAD Design — a commercial site for Custom and Pre-Packaged SKILL programs
- SKILL for the Skilled: Making Programs Clear and Concise
- SKILL for the Skilled: Rule of English Translation
- SKILL for the Skilled: What is SKILL++?
- SKILL for the Skilled: Continued Introduction to SKILL++
- SKILL for the Skilled: Sorting With SKILL++