608 lines
23 KiB
Plaintext
608 lines
23 KiB
Plaintext
|
|
NETGEN -- An embedded-language netlist specification.
|
|||
|
|
|
|||
|
|
NETGEN consists of a set of C language subroutines intended to facilitate
|
|||
|
|
the specification of netlists of circuits that are ill-suited to
|
|||
|
|
conventional schematic-capture paradigms.
|
|||
|
|
|
|||
|
|
Some of the features of the NETGEN system:
|
|||
|
|
|
|||
|
|
1) full hierarchical specification of the circuit in question.
|
|||
|
|
2) powerful list-based operators that permit rapid declaration
|
|||
|
|
and subsequent connection of semantic structures such as busses,
|
|||
|
|
signal vectors, port lists, etc.
|
|||
|
|
3) optional topology-driven front end, providing connectivity of
|
|||
|
|
cells according to a composition-by-abuttment paradigm.
|
|||
|
|
4) dynamic scoping rules governing visibility of ports and nodes.
|
|||
|
|
5) support for multiple output netlist file formats,
|
|||
|
|
including .NTK, .EXT (and consequently .SIM), .ACTEL, and .WOMBAT.
|
|||
|
|
In addition, hierarchical .NTK files can be read, providing an
|
|||
|
|
alternate mechanism to input cells.
|
|||
|
|
|
|||
|
|
Hierarchical specification of circuits.
|
|||
|
|
|
|||
|
|
The basic unit in defining a circuit is a CELL. A cell, in turn, can
|
|||
|
|
contain any number of other cells, called INSTANCES. A cell has some
|
|||
|
|
special nodes, called PORTS, that are the connections that can be
|
|||
|
|
made to the cell when it is instanced. When a cell is actually
|
|||
|
|
instanced, these ports are called PINS within the context of the cell
|
|||
|
|
being constructed. The ports (of the current cell) and pins (of
|
|||
|
|
previously defined cells) may connect together directly, or through
|
|||
|
|
optional NODES.
|
|||
|
|
|
|||
|
|
So much for the definitions. Now the good news: within a CELL, there
|
|||
|
|
are 3 kinds of elements (PORTS, NODES, and PINS); these are treated
|
|||
|
|
ABSOLUTELY IDENTICALLY from the user's perspective. NETGEN has a uniform
|
|||
|
|
internal representation with a single operator: "connect". In defining
|
|||
|
|
a cell, the user "connects" ports, nodes, and pins as required to construct
|
|||
|
|
the desired circuit. In particular, there is no real notion of a "wire"
|
|||
|
|
within NETGEN; situations where named signal lines would be useful can
|
|||
|
|
be accomodated by using named internal nodes.
|
|||
|
|
|
|||
|
|
In it's simplest form, the user interface to NETGEN consists of
|
|||
|
|
four procedures:
|
|||
|
|
|
|||
|
|
|
|||
|
|
void CellDef(char *name);
|
|||
|
|
|
|||
|
|
Declares cell "name", and appends all future commands to the definition
|
|||
|
|
of that cell.
|
|||
|
|
|
|||
|
|
|
|||
|
|
void Port(char *name);
|
|||
|
|
|
|||
|
|
Declares a port node called "name" within the current cell.
|
|||
|
|
|
|||
|
|
|
|||
|
|
void Node(char *name);
|
|||
|
|
|
|||
|
|
Declares an internal node called "name" within the current cell.
|
|||
|
|
|
|||
|
|
|
|||
|
|
void Instance(char *cell, *instancename);
|
|||
|
|
|
|||
|
|
Incorporates an instance of cell "cell" into the current cell; the
|
|||
|
|
instance is called "instancename", which must be a unique identifier
|
|||
|
|
within the context of the current cell (the function Next(cell) is
|
|||
|
|
often useful in generating this unique identifier). The Instance()
|
|||
|
|
procedure generates a set of PINS corresponding to the ports of
|
|||
|
|
"cell"; these pins are named "instancename"/"portname".
|
|||
|
|
|
|||
|
|
As a (trivial) example, consider the following definition of
|
|||
|
|
the elements within a CMOS inverter:
|
|||
|
|
|
|||
|
|
CellDef("inv");
|
|||
|
|
PortDef("in");
|
|||
|
|
PortDef("out");
|
|||
|
|
PortDef("vdd");
|
|||
|
|
PortDef("gnd");
|
|||
|
|
Instance("p","pullup");
|
|||
|
|
Instance("n","pulldown");
|
|||
|
|
|
|||
|
|
Instance() also has some subtle side-effects. See the section
|
|||
|
|
below on dynamic scoping for a discussion of how these can be used
|
|||
|
|
to implicitly connect elements automatically.
|
|||
|
|
|
|||
|
|
Connecting up the circuit; (or, using wirelists effectively).
|
|||
|
|
|
|||
|
|
We must now specify how the above elements are to be interconnected.
|
|||
|
|
The most general form of this operator is:
|
|||
|
|
|
|||
|
|
void Connect(char *list1, *list2);
|
|||
|
|
|
|||
|
|
In its simplest form, list1 and list2 are the names of two elements
|
|||
|
|
to be connected together. In the above example,
|
|||
|
|
|
|||
|
|
Connect("pulldown/source", "gnd");
|
|||
|
|
Connect("pullup/source", "vdd");
|
|||
|
|
Connect("pulldown/gate", "in");
|
|||
|
|
Connect("pullup/gate", "in");
|
|||
|
|
Connect("pulldown/drain", "out");
|
|||
|
|
Connect("pullup/drain", "out");
|
|||
|
|
|
|||
|
|
completes the specification of the inverter. However, the same result
|
|||
|
|
can be obtained more simply by the use of WILDCARDS in the list-constructor
|
|||
|
|
strings list1 and list2. Supported wildcards are the UNIX(TM) shell
|
|||
|
|
wildcards (*,?,{},[]) where:
|
|||
|
|
* matches 0 or more characters (unlike csh, "/" is treated
|
|||
|
|
identically to any other character).
|
|||
|
|
? matches any single character.
|
|||
|
|
{} delimits alternate choices. For example "c{a,o}t" matches "cat"
|
|||
|
|
and "cot".
|
|||
|
|
[] delimits ranges for matching a single character. For example,
|
|||
|
|
"cell[1-3]" matches "cell1", "cell2", and "cell3". Multiple
|
|||
|
|
ranges can be specified (e.g. [a-mp-x]), as can excluded
|
|||
|
|
ranges ([~a-m]).
|
|||
|
|
|
|||
|
|
Full regular expression pattern matching is also available. To use this
|
|||
|
|
form, set the global flag UnixWildcards to 0, and see regexp(3) for
|
|||
|
|
detailed syntax.
|
|||
|
|
|
|||
|
|
The result of Connecting two lists is the following:
|
|||
|
|
a) if the lists are the same length, corresponding pairs of elements
|
|||
|
|
are connected to each other,
|
|||
|
|
b) if one of the lists has a single element, all elements of the
|
|||
|
|
other list are connected to that element,
|
|||
|
|
c) otherwise, the lists are of unequal lengths and an error is reported.
|
|||
|
|
|
|||
|
|
Thus, the inverter can be specified simply by:
|
|||
|
|
Connect("*drain", "out");
|
|||
|
|
Connect("*gate", "in");
|
|||
|
|
Connect("*up/source", "vdd");
|
|||
|
|
Connect("*down/source", "gnd");
|
|||
|
|
|
|||
|
|
The ORDER of generated list elements is the same as the order in which
|
|||
|
|
the elements were added to the cell. In the above example,
|
|||
|
|
"*gate" gets expanded to {"pullup/gate","pulldown/gate"}. It is possible
|
|||
|
|
to take advantage of wildcards (and this bit of information) even
|
|||
|
|
further:
|
|||
|
|
Connect("*drain", "out");
|
|||
|
|
Connect("*gate", "in");
|
|||
|
|
Connect("*source","*d");
|
|||
|
|
|
|||
|
|
The user should, however, try to minimize the abuse of wildcards at
|
|||
|
|
the expense of clarity. Wildcards are provided to expedite grouping
|
|||
|
|
of elements with associated semantics (see the section below on
|
|||
|
|
topological specification of interconnection), NOT to minimize the
|
|||
|
|
keystrokes required to specify a netlist.
|
|||
|
|
|
|||
|
|
The relationship between placement and interconnect.
|
|||
|
|
|
|||
|
|
NETGEN provides a simple model for VLSI cell placement: cells are
|
|||
|
|
rectangular and have ports along the perimeter on 4 sides (N,S,E,W).
|
|||
|
|
Composition is by abuttment and can occur in either the horizontal
|
|||
|
|
or vertical direction. When two cells are placed so that they share
|
|||
|
|
an edge, the port lists along that edge of the respective cells are
|
|||
|
|
generated, and the Connect operator is invoked on them. Ports along
|
|||
|
|
the othogonal edges are propagated as ports of the cell being defined.
|
|||
|
|
The (implied) order of ports in cells is bottom-to-top on vertical
|
|||
|
|
edges, and left-to-right on horizontal edges, corresponding to the
|
|||
|
|
order of placement of subsequent cells.
|
|||
|
|
|
|||
|
|
void Place(char *name);
|
|||
|
|
|
|||
|
|
An instance of cell "name" is generated, and placed in a direction
|
|||
|
|
corresponding to the "Composition" flag (if Composition==HORIZONTAL,
|
|||
|
|
the cell is placed to the right of any previously placed cells; if
|
|||
|
|
Composition==VERTICAL, the cell is placed above; if
|
|||
|
|
Composition==NONE, a call to Place(name) is equivalent to
|
|||
|
|
Instance(name,Next(name))). A unique instance name is generated for
|
|||
|
|
the cell, by appending an integer (starting at 1) to "name". Ports
|
|||
|
|
along abutting edges are "sealed", and ports along orthogonal edges
|
|||
|
|
are made ports of the cell being defined. In the first call to Place
|
|||
|
|
within a cell, the leftmost (or bottom, if Composition==VERTICAL)
|
|||
|
|
ports of cell "name" are defined to be the corresponding ports of the
|
|||
|
|
cell being defined. In order to correctly generate the port list at
|
|||
|
|
the other end of the cell, the procedure:
|
|||
|
|
|
|||
|
|
void EndCell();
|
|||
|
|
|
|||
|
|
must be called to end the current cell definition. It is good form to
|
|||
|
|
always terminate cell definitions with this statement (even if you
|
|||
|
|
did not use the implicit composition mechanism) -- one side-effect of
|
|||
|
|
EndCell() is to arbitrarily connect all otherwise disconnected nodes
|
|||
|
|
if the global variable NoDisconnectedNodes is set to 1 (the default is 0).
|
|||
|
|
|
|||
|
|
In order to understand the relationship between topology and connectivity,
|
|||
|
|
the user must adhere to a particular NAMING CONVENTION. Ports must
|
|||
|
|
be declared in the correct order (bottom-to-top and left-to-right),
|
|||
|
|
and with the following syntax: the side of the port is prepended
|
|||
|
|
to the port name, separated by a ".". For example, if the input
|
|||
|
|
to the inverter is to be on the left (west) side, we would
|
|||
|
|
replace the previous definition of port "in" by:
|
|||
|
|
|
|||
|
|
Port("W.in");
|
|||
|
|
|
|||
|
|
Corresponding changes are required for the other ports (for example,
|
|||
|
|
"E.out", "N.vdd", "S.gnd"). Then, the specification for a chain of 4
|
|||
|
|
inverters (perhaps an exponential horn for a pad driver) takes the
|
|||
|
|
form:
|
|||
|
|
|
|||
|
|
CellDef("exphorn");
|
|||
|
|
Composition = HORIZONTAL;
|
|||
|
|
for (i=0; i<4; i++) Place("inv");
|
|||
|
|
EndCell();
|
|||
|
|
|
|||
|
|
This code fragment specifies a cell "exphorn" that takes a single
|
|||
|
|
input on the left (west) side, generates a single output on the
|
|||
|
|
right side, and has 4 ports on the top (which should be connected
|
|||
|
|
to vdd in the cell that calls "exphorn"), and 4 on the bottom (gnd).
|
|||
|
|
|
|||
|
|
To simplify code fragments such as the above, the procedure
|
|||
|
|
|
|||
|
|
void Array(char *name, int count)
|
|||
|
|
|
|||
|
|
is provided, and is equivalent to "for (i=0;i<count;i++) Place(name)".
|
|||
|
|
|
|||
|
|
Scoping rules for identifiers; Implicit (global) connections.
|
|||
|
|
|
|||
|
|
It is often inconvenient to have to continually declare high
|
|||
|
|
connectivity nodes (e.g. power rails, bit/word lines, etc.) explicitly
|
|||
|
|
as parameters to each cell. Also, the number of ports of generated
|
|||
|
|
cells (see example above) can be kept managable.
|
|||
|
|
|
|||
|
|
The solution to this problem takes the form of scoping rules for
|
|||
|
|
element names; when a cell is instantiated within the context of a
|
|||
|
|
calling cell, particular elements within the CALLED cell are
|
|||
|
|
implicitly connected to elements in the PARENT cell. This binding
|
|||
|
|
process is exactly analogous to local/global variables within nested
|
|||
|
|
PASCAL procedure declarations, but the process is slightly different:
|
|||
|
|
instead of declaring LOCAL variables, and assuming all others to have
|
|||
|
|
GLOBAL visibility, particular ports (i.e. explicitly global objects)
|
|||
|
|
are declared to obey certain implicit connection rules by the
|
|||
|
|
following:
|
|||
|
|
|
|||
|
|
void Global(char *name);
|
|||
|
|
|
|||
|
|
Semantically, "name" is a PORT that connects itself automatically
|
|||
|
|
when the cell is instanced. In particular, a port obtained by a call
|
|||
|
|
to Global("xxx") in cell B will automatically connect to an element
|
|||
|
|
named "xxx" in cell A, whenever A instantiates B. If "xxx" does not
|
|||
|
|
exist in A, the instantiation of B will CAUSE a global port named
|
|||
|
|
"xxx" to be declared (by a call to Global("xxx") in A). The result
|
|||
|
|
of this action is that the unbound variable "xxx" is now propagated
|
|||
|
|
to the next level of the hierarchy. This dynamic scoping allows
|
|||
|
|
cell B (which is instantiated within cell A) to be declared
|
|||
|
|
BEFORE cell A.
|
|||
|
|
|
|||
|
|
An example is useful. Reconsider the "inv" cell above, but this
|
|||
|
|
time change the definitions of the power ports to :
|
|||
|
|
|
|||
|
|
Global("vdd");
|
|||
|
|
Global("gnd");
|
|||
|
|
|
|||
|
|
The previous code fragment for "exphorn" would now result
|
|||
|
|
in a cell with 4 ports, named "vdd", "gnd", "W.inv1/W.in" and
|
|||
|
|
"E.inv4/E.out" (instead of the previous exphorn, which had 10 ports).
|
|||
|
|
|
|||
|
|
Naming conventions:
|
|||
|
|
|
|||
|
|
Within the context of the calling cell:
|
|||
|
|
|
|||
|
|
1) Ports:
|
|||
|
|
<instance name> SEPARATOR <port name>
|
|||
|
|
|
|||
|
|
2) Ports - Oriented:
|
|||
|
|
<side> { PORT_DELIMITER <instance name> PORT_DELIMITER <side>}* \
|
|||
|
|
PORT_DELIMITER <port name>
|
|||
|
|
|
|||
|
|
3) Ports - Global:
|
|||
|
|
<port name> -- name propagates unchanged, but is bound to
|
|||
|
|
locally-declared identifier of same name.
|
|||
|
|
|
|||
|
|
4) Ports - Unique Global:
|
|||
|
|
<my class name> INSTANCE_DELIMITER <instance name> SEPARATOR <port name>
|
|||
|
|
|
|||
|
|
5) Flattened cells:
|
|||
|
|
<instance name> { SEPARATOR <instance name> }* SEPARATOR <port name>
|
|||
|
|
|
|||
|
|
6) Cells read from NTK:
|
|||
|
|
<instance class> INSTANCE_DELIMITER <instance name> SEPARATOR <port name>
|
|||
|
|
|
|||
|
|
|
|||
|
|
|
|||
|
|
Other Procedures (i.e. what else do I need to know?)
|
|||
|
|
|
|||
|
|
In order to use the NETGEN package, the user's program must include
|
|||
|
|
the library, link the correct object module, and initialize the package.
|
|||
|
|
|
|||
|
|
The first is accomplished by the line:
|
|||
|
|
|
|||
|
|
#include "netgen.h"
|
|||
|
|
|
|||
|
|
at the top of every program. In practice, "netgen.h" is not likely
|
|||
|
|
to be found in the current directory, so ask a system guru where it
|
|||
|
|
is located. The same goes for the object file "netgen.a" that must
|
|||
|
|
be linked in (via a command-line parameter in UNIX; if you are
|
|||
|
|
running NETGEN on a PC (or maybe even someday on a chipmunk) talk
|
|||
|
|
to a system mangler).
|
|||
|
|
|
|||
|
|
The NETGEN package is written in ANSI-standard C, and requires
|
|||
|
|
an ANSI-C compiler. On many UNIX systems, the GNU C compiler
|
|||
|
|
is known to work; the incantation to compile a user's main
|
|||
|
|
program main.c is:
|
|||
|
|
|
|||
|
|
gcc -o main main.c netgen.a
|
|||
|
|
|
|||
|
|
|
|||
|
|
The NETGEN package is initialized via a call to:
|
|||
|
|
|
|||
|
|
void Initialize();
|
|||
|
|
|
|||
|
|
This procedure sets up the internal data structures, and pre-defines
|
|||
|
|
two types of cells: n- and p-channel transistors. These cells are
|
|||
|
|
declared by the following code (which is actually inside Initialize()):
|
|||
|
|
|
|||
|
|
CellDef("p");
|
|||
|
|
Primitive();
|
|||
|
|
PortDef("gate");
|
|||
|
|
PortDef("drain");
|
|||
|
|
PortDef("source");
|
|||
|
|
EndCell();
|
|||
|
|
CellDef("n");
|
|||
|
|
Primitive();
|
|||
|
|
PortDef("gate");
|
|||
|
|
PortDef("drain");
|
|||
|
|
PortDef("source");
|
|||
|
|
EndCell();
|
|||
|
|
|
|||
|
|
The procedure Primitive() in the above code fragment informs
|
|||
|
|
NETGEN that the element is a primitive, and not to be further
|
|||
|
|
decomposed when an output netlist file is written. This mechanism
|
|||
|
|
assumes that the system READING the netlist understands the
|
|||
|
|
meaning of the element.
|
|||
|
|
|
|||
|
|
A slightly more powerful initialization routine is:
|
|||
|
|
|
|||
|
|
void InitializeCommandLine(int argc, char *argv[]);
|
|||
|
|
|
|||
|
|
This routine parses any command-line arguements (interpreted as
|
|||
|
|
commands to the Query() routine), and processes them first. A single
|
|||
|
|
'-' in the command line indicates that interactive operation should
|
|||
|
|
follow these commands.
|
|||
|
|
|
|||
|
|
For the user's convenience, an alternative to the Instance/Connect
|
|||
|
|
mechanism is provided; when a cell is instantiated, explicit
|
|||
|
|
connections may be specified to each of its ports via the procedure:
|
|||
|
|
|
|||
|
|
void Cell(char *CellName, char *PortNameList, ...);
|
|||
|
|
|
|||
|
|
The strings passed in PortNameList, and any subsequent (assumed char *)
|
|||
|
|
are of one of two forms:
|
|||
|
|
|
|||
|
|
1) they are a list of "port=element" strings. In this case, their
|
|||
|
|
order is unimportant; the ports of the cell are connected to the
|
|||
|
|
corresponding element. For example,
|
|||
|
|
Cell("n", "drain=n1", "gate=g1", "source=n2");
|
|||
|
|
does the obvious thing.
|
|||
|
|
|
|||
|
|
2) arguements do not contain "=", but may contain wildcards, in which
|
|||
|
|
case they are expanded into lists, and this list is sealed with the
|
|||
|
|
port list obtained when CellName is instanced (and after any "=" ports
|
|||
|
|
are matched). For example, an n-channel device in parallel with
|
|||
|
|
another (named "tran1") can be obtained by:
|
|||
|
|
Cell("n", "tran1/*");
|
|||
|
|
|
|||
|
|
In both of these cases, the portnames of CellName are also added to the
|
|||
|
|
namespace of the current cell, so subsequent calls to Connect()
|
|||
|
|
operate correctly.
|
|||
|
|
|
|||
|
|
Along the lines of Cell(), two other procedures are defined:
|
|||
|
|
|
|||
|
|
void N(char *PortNameList, ...);
|
|||
|
|
void P(char *PortNameList, ...);
|
|||
|
|
|
|||
|
|
These are merely calls to Cell(), with the CellName arguement
|
|||
|
|
hard-wired to "n" and "p", respectively.
|
|||
|
|
|
|||
|
|
A slight variant on Cell() is the Wire() procedure:
|
|||
|
|
|
|||
|
|
void Wire(char *instance_name, ...);
|
|||
|
|
|
|||
|
|
This procedure accepts the name of an instance, and a list of ports
|
|||
|
|
identical to Cell(). The only difference is that for Wire(), the
|
|||
|
|
instance name is explicitly required, while for Cell() it is
|
|||
|
|
totally suppressed (in fact, the user cannot even find out what it was).
|
|||
|
|
The "=" form of the parameter list can be used in Wire() as well.
|
|||
|
|
|
|||
|
|
Other Useful Functions
|
|||
|
|
|
|||
|
|
Because many element names are derived from others, NETGEN
|
|||
|
|
provides some useful functions to manipulate temporary strings:
|
|||
|
|
|
|||
|
|
char *Str(char *format, ...);
|
|||
|
|
|
|||
|
|
This function takes a format string and a variable arguement list
|
|||
|
|
in a manner identical to printf(), and returns a pointer to a
|
|||
|
|
temporary string. There are only a small number of these (statically
|
|||
|
|
allocated) strings available, so you must use the pointer quickly.
|
|||
|
|
Typical use is in declaring a "subscripted" cell: CellDef(Str("array%d", i));
|
|||
|
|
|
|||
|
|
Finally, as a convenience to the user, a procedure:
|
|||
|
|
|
|||
|
|
void Query(void);
|
|||
|
|
|
|||
|
|
puts NETGEN in an interactive mode, where the user is permitted
|
|||
|
|
to choose between output netlist formats, input files to read, and
|
|||
|
|
various other things. It is a convenient way to end a program.
|
|||
|
|
|
|||
|
|
If your version of NETGEN was compiled with X11 support, a more
|
|||
|
|
general command parser is available as:
|
|||
|
|
|
|||
|
|
void X_main_loop(int argc, char *argv[]);
|
|||
|
|
|
|||
|
|
|
|||
|
|
Generating Output
|
|||
|
|
|
|||
|
|
The main output format currently supported is the Caltech NTK
|
|||
|
|
format. An output file is created by calling:
|
|||
|
|
|
|||
|
|
void Ntk(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
All nodes are named, with the following priority given to nodes
|
|||
|
|
with multiple elements connected to them. Highest priority
|
|||
|
|
goes to port names, then to internal node names, and finally
|
|||
|
|
to instance pin names. Certain shortcomings in the .NTK specification
|
|||
|
|
(such as the inability to connect two ports within a cell) are
|
|||
|
|
dealt with correctly. If filename is NULL, or an empty string,
|
|||
|
|
a file name is generated by appending .ntk to "cellname".
|
|||
|
|
|
|||
|
|
|
|||
|
|
Late news flash: the MAGIC hierarchical extract format
|
|||
|
|
is now supported to a limited. To generate .EXT files, call
|
|||
|
|
|
|||
|
|
void Ext(char *cellname);
|
|||
|
|
|
|||
|
|
This procedure generates a .EXT file for EACH(!) cell class.
|
|||
|
|
The only thing .EXT is good for is to run EXT2SIM on, in order to
|
|||
|
|
get the other MAGIC netlist format (flattened list of
|
|||
|
|
transistors only.). SIM output can be generated directly by:
|
|||
|
|
|
|||
|
|
void Sim(char *cellname);
|
|||
|
|
|
|||
|
|
NETGEN also supports the Actel(TM) cell libraries and netlist
|
|||
|
|
file format. To access these cells, call the procedure:
|
|||
|
|
|
|||
|
|
void ActelLib();
|
|||
|
|
|
|||
|
|
These cells are then regular NETGEN objects, whose elements
|
|||
|
|
are accessed by the names described in the Actel gate catalog.
|
|||
|
|
For example, the pins on a 2-input NAND gate are
|
|||
|
|
"thisgate/A", "thisgate/B", and "thisgate/Y", after a call
|
|||
|
|
to Instance("NAND2","thisgate").
|
|||
|
|
|
|||
|
|
Actel .adl files are written by calling the procedure:
|
|||
|
|
|
|||
|
|
void Actel(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
As before, if filename is NULL, or an empty string, a file name is
|
|||
|
|
generated by appending .adl to "cellname".
|
|||
|
|
|
|||
|
|
NETGEN supports the netlist format required by
|
|||
|
|
the WOMBAT netlist comparison program. Such files
|
|||
|
|
are written by the procedure:
|
|||
|
|
|
|||
|
|
void Wombat(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
WOMBAT requires flat (non-hierarchical) netlists. See the
|
|||
|
|
Flatten() procedure below.
|
|||
|
|
|
|||
|
|
NETGEN also supports two popular circuit simulator formats:
|
|||
|
|
|
|||
|
|
void SpiceCell(char *cellname, char *filename);
|
|||
|
|
void EsacapCell(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
Of course, because NETGEN only maintains topological information and
|
|||
|
|
not device sizing information, writing circuit simulator input files
|
|||
|
|
generally requires some manual post-processing.
|
|||
|
|
|
|||
|
|
NETGEN also supports an output format that is, in fact, the specification
|
|||
|
|
of the netlist using the NETGEN C-language embedded interface:
|
|||
|
|
|
|||
|
|
void Ccode(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
This procedure creates a file that is suitable for inclusion and compilation
|
|||
|
|
within a program that, when linked with the netgen libraries, will
|
|||
|
|
re-create the netlist.
|
|||
|
|
|
|||
|
|
Finally, NETGEN provides a machine-dependent (i.e., nonportable)
|
|||
|
|
but fast netlist format, based on a binary dump of its internal data
|
|||
|
|
structures:
|
|||
|
|
|
|||
|
|
void WriteNetgenFile(char *cellname, char *filename);
|
|||
|
|
|
|||
|
|
|
|||
|
|
Other Cell Manipulation commands
|
|||
|
|
|
|||
|
|
Two routines are also provided to manipulate the cell dictionary
|
|||
|
|
(the list of defined cells):
|
|||
|
|
|
|||
|
|
void CellDelete(char *cellname);
|
|||
|
|
|
|||
|
|
This procedure deletes the definition of 'cellname' from the dictionary.
|
|||
|
|
It does NOT care whether instances of 'cellname' exist within other cells.
|
|||
|
|
This procedure is useful for remapping sub-cells within a design, by
|
|||
|
|
deleting the original cells, then subsequently loading in new definitions.
|
|||
|
|
|
|||
|
|
void CellRename(char *from, char *to);
|
|||
|
|
|
|||
|
|
This procedure deletes the definition of cell 'from', and creates an
|
|||
|
|
identical cell in 'to'. If cell 'to' already exists, that cell is overwritten.
|
|||
|
|
|
|||
|
|
void CellCopy(char *from, char *to);
|
|||
|
|
|
|||
|
|
Copy cell 'from', calling the new cell 'to'. If 'to' exists already,
|
|||
|
|
its definition is overwritten.
|
|||
|
|
|
|||
|
|
NETGEN also supports some hierarchy-manipulation functions:
|
|||
|
|
|
|||
|
|
void Flatten(char *cellname);
|
|||
|
|
|
|||
|
|
The Flatten() procedure actually flattens the internal data
|
|||
|
|
structure, and is consequently irreversible. Of course,
|
|||
|
|
flattened cells can also be written out in any of the
|
|||
|
|
other netlist formats.
|
|||
|
|
|
|||
|
|
void FlattenInstancesOf(char *classname);
|
|||
|
|
|
|||
|
|
This procedure flattens all instances of 'classname' within other
|
|||
|
|
cells. However, any hierarchy within 'classname' remains.
|
|||
|
|
|
|||
|
|
|
|||
|
|
Alternative Input Formats
|
|||
|
|
|
|||
|
|
In addition to the embedded procedural interface for declaring/defining
|
|||
|
|
cells, NETGEN is able to read hierarchical .NTK files directly,
|
|||
|
|
and convert them into the internal element list representation.
|
|||
|
|
These cells can then be operated on identically to procedurally defined
|
|||
|
|
cells. This process facilitates using a (separately generated, perhaps
|
|||
|
|
by a graphical schematic capture system) cell library, then using
|
|||
|
|
NETGEN as a composition tool.
|
|||
|
|
|
|||
|
|
In fact, many different input netlist formats are supported:
|
|||
|
|
|
|||
|
|
char *ReadNtk(char *filename);
|
|||
|
|
char *ReadExt(char *filename);
|
|||
|
|
char *ReadSim(char *filename);
|
|||
|
|
char *ReadSpice(char *filename);
|
|||
|
|
char *ReadNetgenFile(char *filename);
|
|||
|
|
|
|||
|
|
All of these procedures return the name of the top-level cell that
|
|||
|
|
was read.
|
|||
|
|
|
|||
|
|
A general file-reading interface is provided by:
|
|||
|
|
|
|||
|
|
char *ReadNetlist(char *filename);
|
|||
|
|
|
|||
|
|
This procedure selects one of the above netlist formats, based on
|
|||
|
|
the file extension of the 'filename' arguement.
|
|||
|
|
|
|||
|
|
Testing graph isomorphism.
|
|||
|
|
|
|||
|
|
NETGEN includes a fast, powerful probabilistic algorithm for
|
|||
|
|
verifying whether two netlists represent isomorphic graphs.
|
|||
|
|
The favored interface to this facility is the 'netcomp' program
|
|||
|
|
that is built along with the 'netgen' interface. However, advanced
|
|||
|
|
users may need the additional functionality provided by the C-language
|
|||
|
|
interface:
|
|||
|
|
|
|||
|
|
void NETCOMP(void);
|
|||
|
|
|
|||
|
|
This is a primitive command-line interpreter (similar to Query())
|
|||
|
|
that gives the user access to all the internal capabilities of netcomp.
|
|||
|
|
A simpler interface is given by:
|
|||
|
|
|
|||
|
|
int Compare(char *cell1, char *cell2);
|
|||
|
|
|
|||
|
|
This procedure returns 1 if the two cells are isomorphic, and 0 otherwise.
|
|||
|
|
If you consider MOS transistor sources and drains to be equivalent
|
|||
|
|
(i.e., permutable), set the integer variable EquivalenceTransistors to 1.
|
|||
|
|
This is appropriate for extracted outputs of VLSI circuits, but (typically)
|
|||
|
|
not for asymmetrical circuit-simulator specifications.
|
|||
|
|
|
|||
|
|
|
|||
|
|
Command-line interface and X-windows interface.
|
|||
|
|
|
|||
|
|
By default in UNIX, if the DISPLAY environment variable is set, netgen
|
|||
|
|
starts an X-window application. Otherwise, a command-line interface
|
|||
|
|
is executed, running the function Query() described above. In either case,
|
|||
|
|
any command-line arguements are passed through Query(); if the last
|
|||
|
|
command is a single dash ("-"), the regular command parser is started
|
|||
|
|
AFTER the command-line commands are executed. Otherwise, netgen
|
|||
|
|
terminates.
|
|||
|
|
|
|||
|
|
|
|||
|
|
Future work:
|
|||
|
|
|
|||
|
|
* 1) have ntk generate file of output
|
|||
|
|
* 2) capture wildcard query routine into library (returning a string, so
|
|||
|
|
user can incorporate it into interactive programs).
|
|||
|
|
* 3) add "internal ports" to implement scoping rules for variable names.
|
|||
|
|
* 4) find out what output format WOMBAT requires and generate it.
|
|||
|
|
5) add simple operators to act on element lists: move, delete, reverse
|
|||
|
|
* 6) don't forget to mention Initialize() procedure
|
|||
|
|
* 7) discuss alternatives to Instance() (e.g. Cell(), and N(), P())
|
|||
|
|
* 8) ability to flatten cells
|
|||
|
|
* 9) learn to write ACTEL format
|
|||
|
|
* 10) more streamlined syntax for Global ports
|
|||
|
|
* 11) don't forget to mention Primitive() procedure.
|