Introduction to Using Ver0.99
Welcome to the extremely obsoleted instruction manual for Ver0.99.
This is in a very rough format and will be improved in later versions. It
is only a preliminary reference to this particular implementation of
Verilog and
is not meant to be a tutorial to programming in the Verilog Hardware
Description Language. Most notably, the
behavioral extensions are missing
from this document.
Table of Contents
Compilation and Installation
Ver: The Structural Verilog Compiler
Language Syntax
Keywords
Signal Names
Comments
Modules. What are they?
Parameters
Primitive Gates
I/O Ports
Wires
Assign Statements
Module Instantiations
Compilation
Using Libraries
Netlist Exporting
The Verilog to VHDL Translator
The Definition of the Language (as implemented)
Compilation and Installation
If you are going to run Ver on a Linux x86 system, you do not have to compile
anything as all the necessary files may be found in the bin
directory. If these files are not present, you will have to compile it by
running the shell script RunMeToCompile, which may be found in
the ver099
directory. To clean out the directory, you may run CleanScript to
remove all of the executables and object files which the compilation process
created. Source code is left behind.
For the most part, the sourcecode in this package is plain vanilla Unix C code
and should compile on any Unixlike system. However, the scope analyzer
program "Anna" may present some problems on some systems as it
relies on BSD signal handling semantics (in the file event.c) which
reset themselves after a signal handler has been called. It is beyond the
scope of this instructional manual to detail how to compile Anna on
recalcitrant OS's. It has been successfully compiled and run under Linux,
NetBSD (on a 68K Amiga), and AIX on the RS/6000. It has not been tested under
Solaris, however Solaris signal handling is similar to that of Linux, and the
same fixes should be applied if Anna presents any problems.
The individual executabless (ver, vsim, anna, gen,
cyco) are completely self-contained and do not require any additional
data files. As such, they may be moved to any directory that is visible in
the shell path.
Ver: The Structural Verilog Compiler
Ver is a subset of the Verilog Hardware Description Language that incorporates
the structural elements of the language, but not the behavioral ones. The
intent of Ver is to generate netlists in the form of IVF files for a separate
logic simulator; Ver itself is not a simulator.
Language Syntax
Some sections will be presented "out of order," and some concepts
will be used before defining them as a top-down description of the language follows.
Keywords
The following keywords are recognized by the compiler:
and,
assign,
buf,
bufif0,
bufif1,
const0,
const1,
constx,
constz,
endmodule,
highz0,
highz1,
input,
latch,
module,
nand,
nmos,
nor,
not,
notif0,
notif1,
or,
output,
parameter,
pmos,
pull0,
pull1,
pulldown,
pullup,
reg,
rnmos,
rpmos,
scalared,
strong0,
strong1,
supply0,
supply1,
tri0,
tri1,
tri,
triand,
trior,
vectored,
wand,
weak0,
weak1,
wire,
wor,
xnor,
and xor.
At this point in time, the reg behavioral keyword is not
supported. It is in the grammar and generates data for the .ivf
file, but is not valid for vsim. Use latch instead.
And note that this is a structural construct.
Signal Names
Mixed case alphanumeric (along with the underscore character) are permitted.
The only restriction is that a signal must not start with a numeric digit.
Comments
Comments are indicated by the sequence // as is used in C++.
Anything following a // (to the end of the current line) is ignored
by the compiler. Additionally, using the C-like /* ... */ syntax
is acceptable and those comments are permitted to be nested.
Modules. What are they?
Modules are the next step up from primitive gates such as and and or.
A module is composed of primitive gates, latches, wires, input and output
ports, and other modules (via instantiation). Recursive module
definitions (e.g., a instantiates
b which instantiates a) will flag an error and abort the
compiler since recursive definitions cannot be synthesized.
The grammar
covering the position of the module's innards is as follows:
module: modulehdr ENDMODULE ;
modulehdr: modulehdr2p iowbody | modulehdr2p ;
modulehdr2p: modulehdr2 | modulehdr2 param ;
modulehdr2: modulehdr2a ;
modulehdr2a: modulehdr3 LP modsignals RP semis |
modulehdr3 LP RP semis |
modulehdr3 semis ;
modulehdr3: MODULE IDENTIFIER ;
iowbody: iowdecs | iowdecs body | body ;
body: gates | gates body | gates semis | gates semis body ;
semis: SEMI | semis SEMI ;
iowdecs: inputdec iowdecs | outputdec iowdecs |
inputdec | outputdec | inputdec semis | outputdec semis |
inputdec semis iowdecs | outputdec semis iowdecs ;
gates: latchgate SEMI | assign SEMI |
wiredec SEMI | regdec SEMI | bufgate SEMI |
nmosgate SEMI | pmosgate SEMI |
bufif0gate SEMI | bufif1gate SEMI |
notif0gate SEMI | notif1gate SEMI |
notgate SEMI | xorgate SEMI | xnorgate SEMI |
andgate SEMI | orgate SEMI | nandgate SEMI |
norgate SEMI | const0gate SEMI | const1gate SEMI |
constxgate SEMI | constzgate SEMI | component SEMI ;
Note that parameter is a parameter definition,
inputdec and outputdec are input and output
definitions respectively. assign is an assignment statement,
wire is a wire definition, and component is a component
instantion. semis indicates one of more semicolons.
An example is in order:
//
// a cross-coupled nand gate positive edge triggered d-ff
// 19/08/97ajb
//
module dff(q,ck,d);
output q;
input ck,d;
nand#4 (q,x2,qbar),
(qbar,q,x3),
(x1,x4,x2),
(x2,x1,ck),
(x3,x2,ck,x4),
(x4,x3,d);
endmodule
Parameters
Parameters are simply numeric values defined immediately after a module
header. Any identifier defined as a parameter is substituted for
its numerically calculated value. The definition is as follows:
param: parama paramb ;
parama: PARAMETER ;
paramb: pitems SEMI ;
pitem: pitema pitemb ;
pitema: IDENTIFIER EQ ;
pitemb: expression ;
pitems: pitem | pitem COMMA pitems ;
The following example shows how they can be used:
/*
this verilog module models a bus with a select on four different
output values. note that a unary reduction "and" on the xnor of
two bitvectors produces a one when the two vectors are equal.
*/
module bus(sel, o);
parameter
w=8;
input [1:0] sel;
output [w-1:0] o;
wire [w-1:0] o;
bufif1 b0[w-1:0] (o, w'h12, {w{ &(sel^~2'b00) }});
bufif1 b1[w-1:0] (o, w'h34, {w{ &(sel^~2'b01) }});
bufif1 b2[w-1:0] (o, w'h56, {w{ &(sel^~2'b10) }});
bufif1 b3[w-1:0] (o, w'h78, {w{ &(sel^~2'b11) }});
endmodule
Note that specifing parameters across modules and in defparam
statements is not supported at this time.
Primitive Gates
The keywords
and,
buf,
bufif0,
bufif1,
const0,
const1,
constx,
constz
latch,
nand,
nmos,
nor,
not,
notif0,
notif1,
or,
pmos,
pulldown,
pullup,
rnmos,
rpmos,
xnor,
and xor,
belong to the primitive gate set that Ver recognizes.
Gate definitions are as follows:
gatename [#delay |
#(rise, fall) |
#(rise, fall,
highimpedance)] (ports) [,(ports)
...];
Some examples:
or (o,a,b);
or #2(o,a,b,c,d,e,f,g,h);
latch #(2,2)(o,i),(o2,i2),(o3,i3);
const1(x),(y);
Spacing is irrelevant. Note that the usual format is a single output followed
by a series of inputs. The exceptions to this case are the const
gates, which require a single output,
and latch
which requires one output and one input. (The whole model for the time being is clocked
simultaneously with one clock--this is currently being revamped where a latch
may be declared as an (output, datapin, clock) tuple. Cyco throws the clockpin
information away for the time being. Future versions of cyco will handle
multiple clock domains.) not and buf gates may
have multiple outputs followed by a single input.
Specifying both rise and fall will cause the gate delay to be the longest
of the two. This is because vsim can only handle a single delay
value. Additionally, cyco, the cycle simulator throws away all
timing information and does a logic simulation only. This would make the
creation of sequential logical impossible in designs. For that reason, use latch
gates to create storage elements in cyco designs (vsim does not
support latches yet).
Drive strengths may also be specified, but none of that information is
kept. Note that drive strengths are specified before the delay
information in the gate definition.
strength0: SUPPLY0 | STRONG0 | PULL0 | WEAK0 ;
strength1: SUPPLY1 | STRONG1 | PULL1 | WEAK1 ;
drivestrength: LP strength0 COMMA strength1 RP
| LP strength1 COMMA strength0 RP
| LP strength0 COMMA HIGHZ1 RP
| LP strength1 COMMA HIGHZ0 RP
| LP HIGHZ1 COMMA strength0 RP
| LP HIGHZ0 COMMA strength1 RP ;
I/O Ports
I/O ports are specified by the keywords input and output.
Their syntax is as follows:
input [[start:end]]
portname [, portname ...] ;
output [[start:end]] portname [,
portname ...] ;
The italicized brackets are actual brackets required by the syntax and are not
to be confused with the brackets which indicate an optional item.
Examples:
input a;
output a,b,c,d;
input [7:0] a,b;
input [0:7] a,b,c;
input [5:7] a;
output [7:7] c;
Inputs and output statements may be freely mixed in any order. They
must all be grouped at the top of a module definition in one unit.
Wires
Wires generate signal names and are handled similarly:
wire [[start:end]] portname [,
portname ...] ;
Wire types supported are:
WIRE, TRI,
TRI0,
TRI1,
WAND,
TRIAND,
WOR, TRIOR,
SUPPLY0,
and SUPPLY1.
They may also be optionally specified as vectored or
scalared. vectored nets may only be accessed as an
indivisible unit. (i.e., the signal name only--individual bits cannot be
accessed in it, just the whole vector.)
Assign Statements
Assign statements which propagate signals or are equations are of the
form:
assign [#delay |
#(rise,fall)] destsignal[s]
= sourceexpression;
Note that for the multiple bit assign, the left specified bit of the
source goes to
the left specified bit of the destination, and the right specified bit of
the
source goes to
the right specified bit of the destination (with the intermediate bits
getting assigned
likewise). So a statement like:
assign a[7:0] = b[0:7];
will cross the bits from 0..7 to 7..0 just as the
statement
tells it to do.
For assigns, the operators | (or), ~| (nor),
& (and), ~& (nand),
^ (xor), ~^ (xnor),
~ (not), and ! (not) are allowed.
Expressions
may be parenthesized, so an expression like
assign #6 d[3] = (a[3] & (~ b[3]) & (~ c[2])) |
((~ a[3]) & b[3] & (~ c[2])) |
((~ a[3]) & (~ b[3]) & c[2]) |
(a[3] & b[3] & c[2]);
is permissible. Assign statements may be separated by commas if they have a
common delay value. Assigning a value of zero or one cannot be done with the
logical operations. (i.e., it must be the only operation on a signal.)
If you wish to use a logical operation with constants, you'll have to use
the 'b 'o 'h or 'd numeric operators rather than just
a number. Therefore, represent 42 as something like
8'd42.
Multiple bit assignments are possible. For example, assign #1 g = a &
b will assign a bitwise and of vectors a and
b to
g if all three are defined as bitvectors. Additionally, working
with bitvectors in parts, etc. is possible as shown below:
assign #6 d[0:3] = {
(a[0] & (~ b[0]) & (~ cin)) |
((~ a[0]) & b[0] & (~ cin)) |
((~ a[0]) & (~ b[0]) & cin) |
(a[0] & b[0] & cin),
(a[1] & (~ b[1]) & (~ c[0])) |
((~ a[1]) & b[1] & (~ c[0])) |
((~ a[1]) & (~ b[1]) & c[0]) |
(a[1] & b[1] & c[0]),
(a[2] & (~ b[2]) & (~ c[1])) |
((~ a[2]) & b[2] & (~ c[1])) |
((~ a[2]) & (~ b[2]) & c[1]) |
(a[2] & b[2] & c[1]),
(a[3] & (~ b[3]) & (~ c[2])) |
((~ a[3]) & b[3] & (~ c[2])) |
((~ a[3]) & (~ b[3]) & c[2]) |
(a[3] & b[3] & c[2])
};
Module Instantiations
Instantiations give hardware description languages a great deal of power.
Instead of having to repeatedly specify, say, a D flip-flop, it can be packed
into a module and used by a simple module instantiation. The syntax for a
module instantiation is as follows:
component: IDENTIFIER comps ;
comps: component2 | component2 COMMA comps ;
component2:
IDENTIFIER LBRACK expression COLON expression RBRACK LP compsignals RP
| IDENTIFIER LBRACK expression COLON expression RBRACK LP RP
| IDENTIFIER LBRACK expression COLON expression RBRACK
| IDENTIFIER LBRACK expression RBRACK LP compsignals RP
| IDENTIFIER LBRACK expression RBRACK LP RP
| IDENTIFIER LBRACK expression RBRACK
| IDENTIFIER LP compsignals RP
| IDENTIFIER LP RP
| IDENTIFIER
| LP compsignals RP
| LP RP ;
compsignals: compsignals1 | compsignals2 ;
compsignals2: DOT IDENTIFIER LP genidcomp RP
| compsignals2 COMMA DOT IDENTIFIER LP genidcomp RP ;
compsignals1: genidcomp | compsignals1 COMMA genidcomp ;
genidcomp: asexpression2 ;
...where an asexpression2 is any valid single or multibit
expression, and expression is something that generates a numeric
value.
Some examples:
f3mux modx1(x1out, in1, x1r5, x1out, m3, m2, m1, m0, rc[15], clk);
f0mux modx2(x2out, in2, m0, clk);
subtractor88 mody2y1(zeroy2y1, y2y1, y2out, y1out,coy0),
mody1y2(zeroy1y2, y1y2, y1out, y2out,coy);
badd b[0:7] (c,o[0:7],i1[0:7],{i2[0],{7{i2[1]}}},{1'b0,c[1:7]});
For multiple bit signals, if you do not specify a bit range, the whole
vector is
passed in the order defined. Whole expressions with concatenations, logic
expressions such as & | ~, etc.
may be passed as shown above.
Compilation
The compilation process is rather straightforward. Bringing up ver with
the -h option shows the options available:
Usage:
------
ver [input filename] [options]
-h[elp] prints this screen
-f name force flatten from module "name" else autodetect
-s supress parse statistics table
-v output vhdl translation to stdio
Input is from stdin if no input filename is specified. Remember this if you
type ver and the computer waits and does nothing.
Use -f to force a model to be flattened from the name you specify.
This is required if no top level module is present or if you have
multiple top-level modules and the compiler guesses wrong.
The -s option keeps parse statistics (I/O port counts, etc.) from
being displayed.
The -v option will be explained in the section
The Verilog to VHDL Translator.
Here is an example program:
//
// test of assign statements...
// note that the longest rise time in a (rise,fall) pair is used!
// also the wiring delays for temps will equal gate delays!
//
module xor21(x,q,a,b);
output x,q;
input a,b;
assign #(2,1) q=(~a&b)|(a&~b); // calculate it the hard way
xor #(2,1)(x,a,b); // with a gate primitive...
endmodule
Running the compiler by typing ver xor.v -f xor21.v prints the
following to the screen:
Ver: Structural Verilog Compiler v0.98 (w)1998 BSI
Module Name IP OP TP Refs Comps Sigs Gates Wires Regs
---------------------- -- -- -- ---- ----- ---- ----- ----- ----
+xor21 2 2 4 0 0 9 6 1 0
Encountered 1 module, 0 top level, 0 missing.
Flattening from module : xor21
9 symbols, 6 gates, 1 wires, 0 regs in flattened module : xor21.
Wrote file "xor21.ivf" successfully. Exiting.
Running the compiler by typing ver xor.v -s -f xor21.v prints
the following to the screen:
Ver: Structural Verilog Compiler v0.98 (w)1998 BSI
Flattening from module : xor21
9 symbols, 6 gates, 1 wires, 0 regs in flattened module : xor21.
Wrote file "xor21.ivf" successfully. Exiting.
If a module is a "top level" one (it is instantiated by no other
modules and instantiates at least one other module), it will be prefixed with
an uppercase T before its name.
Using Libraries
You may optionally analyze to a library by using the -l flag. By
adding the line library libname; to your Verilog source, if any
modules are not present, they will be grabbed from the lib/libname
directory. Note that you may have a comma separated list of names and
they are searched in the order specified.
Netlist Exporting
An .ivf file is the output of the compilation process. It is to be
read into either vsim or cyco. An explanation of the format
is beyond the scope of this manual, however the netlist generated from the xor.v
file will be shown for illustrative purposes. Note that all signal names
are suffixed with their bit number. If it is a single bit vector, it is zero.
Also, "temporaries" generated from parsing of assign statements
are prefixed with a !T which is impossible for a user to create.
MX xor21.logic{
MP{xor21/b/0 IN;xor21/a/0 IN;xor21/q/0 OUT;xor21/x/0 OUT;}
}
MF{
FS{xor21/!T3/0 }
FS{xor21/x/0 }
FS{xor21/!T2/0 }
FS{xor21/!T4/0 }
FS{xor21/!T1/0 }
FS{xor21/b/0 }
FS{xor21/!T0/0 }
FS{xor21/q/0 }
FS{xor21/a/0 }
FG NL_GATE.1{NL_GATE 20 I 1 xor21/!T4/0 1 xor21/q/0 }
FG XOR.1{XOR 20 I 2 xor21/a/0 xor21/b/0 1 xor21/x/0 }
FG OR.1{OR 0 I 2 xor21/!T1/0 xor21/!T3/0 1 xor21/!T4/0 }
FG AND.1{AND 0 I 2 xor21/a/0 xor21/!T2/0 1 xor21/!T3/0 }
FG NOT.1{NOT 0 I 1 xor21/b/0 1 xor21/!T2/0 }
FG AND.2{AND 0 I 2 xor21/!T0/0 xor21/b/0 1 xor21/!T1/0 }
FG NOT.2{NOT 0 I 1 xor21/a/0 1 xor21/!T0/0 }
}
The Verilog to VHDL Translator
By using the -v flag on the compilation line, a VHDL translation
of your Verilog program will be sent to stdio rather than being written
to an ivf output file. Note this feature is highly experimental at this
time.
Here is a sample input file:
//
// the everpopular cross-coupled nand gate positive edge triggered d-ff
// 19/08/97ajb
//
module dff(q,ck,d);
output q;
input ck,d;
nand#4 (q,x2,qbar),
(qbar,q,x3),
(x1,x4,x2),
(x2,x1,ck),
(x3,x2,ck,x4),
(x4,x3,d);
endmodule
and this is the output generated...
--
-- dff.logic
--
entity dff is port(
q : out bit;
ck : in bit;
d : in bit);
end dff;
architecture logic of dff is
signal x1 : bit;
signal x2 : bit;
signal x3 : bit;
signal x4 : bit;
signal qbar : bit;
begin
x4 <= ( d NAND x3 ) after 4 ns ;
x3 <= ( x4 NAND ck NAND x2 ) after 4 ns ;
x2 <= ( ck NAND x1 ) after 4 ns ;
x1 <= ( x2 NAND x4 ) after 4 ns ;
qbar <= ( x3 NAND q ) after 4 ns ;
q <= ( qbar NAND x2 ) after 4 ns ;
end;
The Definition of the Language (as implemented)
As this is in a constant state of flux, it has been removed. "Real" documentation will be
forthcoming sometime..for the meantime, looking at the included examples should suffice.
17jan99
bybell@linux-workshop.com /
bybell@nc.rr.com