Shortcuts & Formatting
Master !FORMAT directives and field skipping for concise circuit descriptions.
Introduction
To reduce typing, entry time, and file sizes, SNL provides powerful shortcuts through keyword abbreviations and the !FORMAT directive.
These features allow you to write compact, readable circuit descriptions without sacrificing clarity.
Keyword-Field Ordering Flexibility
One advantage of a keyword-oriented description language is that the order of the fields within each statement is not important. As an example, the following is a functionally identical restatement of the johnson_counter type block which illustrates SNL's flexibility with regard to part statement and keyword-field ordering.
TYPE=johnson_counter O=q1,q2,q3 I=clock,reset
I=q3 O=back PART=back TYPE=inv
TYPE=and I=reset O=rbuf PART=buf
I=rbuf,one,clock,q1 PART=f2 TYPE=dcf O=q2
I=rbuf,one,clock,q2 TYPE=dcf PART=f3 O=q3
TYPE=dcf I=rbuf,one,clock,back PART=f1 O=q1
It is suggested, however, that a consistent ordering be used to improve readability.
Keyword Abbreviations
SIMIC recognizes abbreviations for almost all SNL keywords. Most keywords can be abbreviated to their first letter or two characters.
Common Abbreviations
| Full Keyword | Abbreviation | Usage Context |
|---|---|---|
| TYPE | T | All statements |
| PART | P | Part statements |
| INPUT-PINS | IPINS, I | Type statements |
| INPUT-NETS | INETS, I | Part statements |
| OUTPUT-PINS | OPINS, O | Type statements |
| OUTPUT-NETS | ONETS, O | Part statements |
| BIDIRECTIONALS | B | All statements |
Example Using Abbreviations
t=full-adder i=a,b,cin o=sum,cout
p=xor1 t=exor i=a,b o=xor1_out
p=and1 t=and i=a,b
p=and2 t=and i=xor1_out,cin
For a complete list of SNL keywords and their abbreviations, see the SNL Keywords Reference.
The !FORMAT Directive
The !FORMAT directive goes beyond simple abbreviations by allowing you to eliminate keywords entirely.
It specifies the order of keyword-fields in subsequent statements, so only the values need to be entered.
Basic Syntax
!FORMAT <keyword1>= <keyword2>= <keyword3>= ...
Once a !FORMAT is defined, each subsequent statement line is interpreted as a series of values that associate
with the keywords in the specified order.
Example: Johnson Counter
This demonstrates the power of !FORMAT for repetitive circuit descriptions:
!format p= t= i= o=
t=johnson_counter i=clock,reset o=q1,q2,q3
buf and reset rbuf
f1 dcf rbuf,one,clock,back q1
f2 dcf rbuf,one,clock,q1 q2
f3 dcf rbuf,one,clock,q2 q3
back inv q3
Breaking this down:
- The
!FORMATstatement declares: 1st field = PART, 2nd = TYPE, 3rd = INPUTS, 4th = OUTPUTS - Each subsequent line follows this pattern without repeating the keywords
- For instance,
f1 dcf rbuf,one,clock,back q1translates to:p=f1 t=dcf i=rbuf,one,clock,back o=q1
!FORMAT Guidelines
Scope and Persistence
- A
!FORMATstatement remains in effect until the next!FORMATstatement !FORMATpersists across multiple files - it remains active from file to file- Unique
!FORMATstatements can be defined for!DELAYand!LOGICALsections
Canceling !FORMAT
To cancel formatting and return to explicit keyword-field entry:
!format
(A !FORMAT directive with no keywords following it.)
Field Skipping with Hyphen (-)
When a statement doesn't require a value for one of the keywords in the current !FORMAT,
use a hyphen (-) as a placeholder to skip that keyword's value.
- to skip fields in the middle of the format list.
If no values are needed for keywords at the end of the format, hyphens are not required.
Example: Skipping the PART Field
!format part= type= i= o=
- and a,b part=c
The hyphen skips the PART field, so and associates with TYPE. Later in the line,
part=c uses an explicit keyword, which overrides formatting for the rest of that statement.
Example: Omitting Trailing Fields
!format p= t= i= o=
c and a,b
The OUTPUT field is omitted (defaults to part name c). No placeholder hyphen is needed
because no other fields follow.
Mixing Formatted and Explicit Entries
If a statement requires a keyword not in the current !FORMAT, or keywords in a different order,
type the complete keyword-field. This suspends formatting for the rest of that statement.
Equivalent Statements Example
All these statements are equivalent when !format part= type= i= o= is active:
!format part= type= i= o=
- and a,b part=c
c and a,b
c and i=a,b o=c
part=c type=and i=a,b o=c
| Line | Explanation |
|---|---|
| 1 | Hyphen skips PART, then part=c keyword overrides remaining format |
| 2 | Fully formatted; OUTPUT omitted (defaults to part name) |
| 3 | Part and type formatted; i=a,b keyword suspends format, requiring o=c |
| 4 | All keywords explicit (no formatting used) |
Practical Tips
When to Use !FORMAT
- Repetitive structures - Counters, shift registers, memory arrays
- Regular patterns - Busses, datapaths with consistent widths
- Large designs - Reduces file size and improves readability
When to Avoid !FORMAT
- Mixed component types - When part statements have varying keyword patterns
- Small circuits - Overhead of
!FORMATmay not be worth it - Unfamiliar readers - Explicit keywords may be clearer for documentation
Combining Techniques
For maximum efficiency, combine !FORMAT with abbreviations and implicit naming:
!f p= t= i=
t=adder i=a,b,cin o=sum,cout
ha1 exor a,b
ha2 exor ha1,cin
a1 and a,b
a2 and ha1,cin
or1 or a1,a2 o=cout
Here, !f abbreviates !format, and most outputs use implicit naming except cout
which needs explicit specification.
The !INCLUDE Directive
The !INCLUDE directive allows you to reference additional SNL files during compilation,
enabling modular circuit descriptions and reusable libraries.
Basic Syntax
!INCLUDE FILE=<file list>
Or, since FILE= is the default keyword:
!INCLUDE <file list>
Usage Examples
c= Include a single library file
!INCLUDE cmoslib
c= Include multiple files
!INCLUDE FILE=stdcells,memories,iocells
c= Can also be written as:
!INC stdcells,memories,iocells
When to Use !INCLUDE
- Library files - Reference standard cell libraries or primitive definitions
- Modular designs - Split large designs across multiple files
- Shared components - Reuse common subcircuits across projects
- Alternative to GET FILE - Include files within the network description itself
Important Restrictions
!INCLUDE statements,
but the maximum nesting depth is 4 levels. This means you can have an initial file that includes
a second file, which includes a third file, which includes a fourth file, but no deeper.
Section Behavior and Placement
The contents of an included file are logically inserted at the exact location of the !INCLUDE statement.
Understanding how sections interact with includes is critical:
Section Directives Are "Sticky"
Section directives (!LOGICAL, !DELAY, !DOCUMENTATION) remain in effect
until explicitly changed by another directive or until the end of a file is reached. However:
- New files default to !LOGICAL: When a new file is included, it is always assumed to start with a !LOGICAL section unless it explicitly begins with a different directive
- !INCLUDE can be used in any section: You can place
!INCLUDEstatements in!LOGICAL,!DELAY, or!DOCUMENTATIONsections - Included file can change sections: If the included file starts with a directive like
!DELAY, that directive takes effect immediately
Practical Implications
c= Example: Including from a !DELAY section
!DELAY
delay=del1 rise=10 fall=12
!INCLUDE stdcells c= stdcells will start in !LOGICAL by default
c= Example: Including delay definitions
!DELAY
delay=del1 rise=10 fall=12
!INCLUDE moredelays c= moredelays should start with !DELAY if it contains delays
c= Example: Preserving sections in included files
c= File: moredelays
!DELAY c= Explicitly declare section to continue delay definitions
delay=del2 rise=15 fall=18
Type Block Boundaries
Since type blocks are not explicitly ended in SNL, place !INCLUDE statements carefully to avoid inadvertently adding included text within a type block definition.
Example: Proper Placement
c= Good practice - include before type definitions
!INCLUDE stdcells
t=counter i=clk,reset o=q[0:3]
p=ff0 t=dff i=clk,reset,d0 o=q[0]
p=ff1 t=dff i=clk,reset,d1 o=q[1]
...
Example: Improper Placement
c= WRONG - include within a type block
t=counter i=clk,reset o=q[0:3]
p=ff0 t=dff i=clk,reset,d0 o=q[0]
!INCLUDE stdcells c= BAD: This adds stdcells content into the counter type!
p=ff1 t=dff i=clk,reset,d1 o=q[1]
!INCLUDE vs GET FILE
Two methods can specify files for compilation:
| Method | Specified | Best For |
|---|---|---|
GET FILE= |
In run command | Top-level files, user-specified file lists |
!INCLUDE |
Within SNL file | Dependencies embedded in the design, library references |
The %DECLARE Statement
The %DECLARE statement groups individual signals into arrays (vectors) and assigns a default
display radix for simulation output. This makes it easier to work with buses and multi-bit signals.
Basic Syntax
%DECLARE <format>=<array list>
Where <format> is one of:
| Format | Abbreviation | Description |
|---|---|---|
| LEVEL | LEV | Standard 15-character level+strength format (alias for LEVEL15) |
| LEVEL15 | — | 15-character representation with level and strength (G,V,S,0,1,X,W,L,H,D,C,Z,F,T,U) |
| LEVEL4 | — | 4-character level-only representation (0, 1, X, Z) |
| OCTAL | OCT | Octal format (0-7) |
| HEXADECIMAL | HEX | Hexadecimal format (0-9, A-F) |
| BIT | — | Alias for HEXADECIMAL |
| INTEGER1 | INT1 | One's complement signed integer |
| INTEGER2 | INT, INT2 | Two's complement signed integer |
| POSINTEGER | POSINT | Positive (unsigned) integer |
- LEVEL15 (default) represents signal levels and drive strengths:
- POWER: G(0), V(1), S(X)
- DRIVING: 0, 1, X
- RESISTIVE: W(0), L(1), H(X)
- FLOATING: D(0), C(1), Z(X)
- UNKNOWN: F(0), T(1), U(X)
- LEVEL4 represents only logic levels: 0, 1, X, Z (ignores strength except floating-unknown)
Array Specification
Arrays can be one-dimensional or two-dimensional:
c= One-dimensional array
%DECLARE HEX=data[0:7]
c= Two-dimensional array
%DECLARE INT=memory[0:15][0:7]
c= Multiple arrays in one statement
%DECLARE OCT=address[0:11],status[0:3],control[0:7]
Scope Rules
%DECLARE statement is local to the type block in which it appears.
Each type block has its own independent namespace for declared arrays.
Placement Requirements
%DECLARE statements must appear within a type block, typically after the TYPE statement
but before PART statements. They cannot appear at the file level or outside of any type definition.
Example: Correct Placement
t=alu i=a,b,opcode o=result,overflow
%declare int=a[0:7],b[0:7],result[0:7]
%declare hex=opcode[0:3]
p=add t=adder8 i=a,b o=sum
p=sub t=subtr8 i=a,b o=diff
...
Example: Incorrect Placement
c= WRONG - cannot be at file level
%declare hex=data[0:7] c= ERROR: Not in a type block!
t=processor i=clk,data o=addr
...
Using Declared Arrays
Once declared, the root name (without indices) can reference the entire array:
t=register i=clk,d o=q
%declare hex=d[0:7],q[0:7]
c= Connect entire array using root name
p=ff t=dff8 i=clk,d o=q
c= Equivalent to explicitly listing all bits:
c= p=ff t=dff8 i=clk,d[0],d[1],...,d[7] o=q[0],q[1],...,q[7]
Benefits of %DECLARE
- Compact notation - Reference entire buses with a single name
- Readable simulation output - Values displayed in meaningful radix (hex, octal, integer)
- Array operations - Simplifies connecting multi-bit buses between components
- Documentation - Makes signal groupings and bit widths explicit
Example: Complete Johnson Counter
t=johnson_counter i=clock,reset o=q
%declare octal=q[1:3]
p=buf t=and i=reset o=rbuf
p=f1 t=dcf i=rbuf,one,clock,back o=q[1]
p=f2 t=dcf i=rbuf,one,clock,q[1] o=q[2]
p=f3 t=dcf i=rbuf,one,clock,q[2] o=q[3]
p=back t=inv i=q[3]
Here, q[1:3] is declared as octal, so during simulation, the three-bit output
will be displayed as a single octal digit (0-7) rather than three separate binary values.