Sunteți pe pagina 1din 82

Verilog

Tutorial
2
Contents
1. Introduction
1. Verilog
2. The Manual
3. Gate Types

2. Lexicography
1. White Space and Comments
2. Operators
3. Numbers
4. Strings

3. DataTypes
1. Nets
2. Registers
3. Vectors
4. Numbers
5. Arrays
6. Tri-state

4. Operators
1. Arithmetic
2. Logical
3. Relational
4. Equality
5. Bitwise
6. Reduction
7. Shift
8. Concatenation and Replication

3
5. System Tasks
1. Output
2. Monitoring a Stimulation
3. Stopping a Simulation

6. Large Worked Example: Multiplexor


1. Introduction and Logic diargram
2. Breakdown of Gate Level Description
3. Breakdown of Logic Level Description
4. Breakdown of Case Description
5. Conditional Operator Implementation
6. Stimulus for Multiplexor

7. Modules
1. Modules
2. Stimulus

8. Ports
1. Port Lists
2. Port Connections

9. Basic Blocks
1. Introduction to Procedural Contructs
2. The initial Block
3. The always Block

10. Large Worked Example : Binary Counter


1. Introduction and Logical Diagram
2. Gate Level Description
3. Behavioral Description
4. The John Cooley Challenge

4
11. Timing Control
1. Delay Based
2. Event Based
3. Sensitivity (Trigger) List
4. Gates : Information Propagation Delays

12. Branches
1. If-else
2. Case Statement
3. The Conditional Operator

13. Loops
1. Introduction to Looping Constructs
2. While Loop
3. For Loop
4. Repeat Loop
5. Forever Loop

14. Extras
1. Opening Files
2. Writing to a File

3. Closing a File
4. Manipulating Memories Files

15. Appendices
1. Operator Precedance
2. Keywords
3. System Tasks and Functions
4. Nets Types
5. Creating Input Vectors

5
6
1 Introduction

1.1 The Verilog Hardware Description Language.


Verilog has come as long way since it started at Gateway Design Automation in 1984 . It is
now used extensively in the design of integrated circiuts and digital systems.
Verilog has been designed to be intuitive and simple to learn, this is why a programmer may
see many similarities between Verilog and other popular languages like pascal and C.
Verilog can closely simulate real circuits using built-in primitives, user-defined primitives,
timing checks, pin-to-pin delay simulation and the ability to apply external stimulus to
designs enabling testing before synthesis.
The extention which made Verilog really take off was the Synthesis technology introduced in
1987. This, coupled with Verilog's ability to extensively verify a digital design, enabled quick
hardware design.

1.2 Forward
This manual is by no means an extensive Verilog manual, it has been written with the
Engineering student in mind. Some features are omitted to allow a simpler introduction.
The manual was initially prepared by Saleem Chauhan and maintained by Gerard M Blair.
While every attempt has been made to validate the information, errors may still exist;
therefore, we offer no guarantees and are grateful for any feedback on the material found
herein.

1.3 Gate Types


Keywords: and, nand, or , nor, xor, xnor, buf, not.
Some of the gates supplied by Verilog are given above, to use a gate it has to be given inputs
and allocated space to put its output. A name can be given to the gate but this is optional. The
and and or gates have one output and can have two or more inputs. For example an and gate,

and <name><list of arguments>


and myand(out, in1, in2, in3); // legal and gate with three inputs
and (out, in1, in2); // legal gate with no name.

7
Note the convention of putting the output at the start of the argument list, this is used by the
predefined gates in Verilog, and and throughout this manual.
The buf and not gates each have one input and one or more outputs. The conventional is the
same, the outputs come first and the last argument in the list is the input.

buf mybuf(out1, out2, out3, in);


not (out, in);
EXERCISE
a) Draw out the truth tables for a two input xnor gate.
b) What value of a is displayed ?

module testgate;
reg b, c;
wire a, d, e;

and (d, b, c);


or (e, d, c);
nand(a, e, b);

initial begin
b=1; c=0;
#10 $display("a = %b", a);
end

endmodule

8
2 Lexicography
Verilog, like any high level language has a number of tokens which we will discuss in this
section. Tokens can be comments, delimiters, numbers, strings, identifiers and keywords. All
keywords are in lower case.

2.1 White space and Comments


White Space
The white space characters are space (\b), tabs (\t), newlines (\n). These are ignored except in
strings

Comments
Two types of comments are supported, single line comments starting with // and multiple line
comments delimited by /* ... */. Comments cannot be nested.

It is usually a good idea to use single line comments to comment code and multiple lines
comments to comment out sections of code when debugging.

2.2 Operators
Verilog has three types of operators, they take either one, two or three operands. Unary
operators appear on the left of their operand, binary in the middle, and ternary seperates its
three operands by two operators.

clock = ~clock; // ~ is the unary bitwise negation operator,


// clock is the operand
c = a || b; // || is the binary logical or, a and b are the operands
r = s ? t : u; // ?: is the ternary conditional operator, which
// reads r = [if s is true then t else u]

2.3 Numbers
Integers
Integers can be in binary ( b or B ), decimal ( d or D ), hexidecimal ( h or H ) or octal ( o or O ).
Numbers are specified by
1. <size>'<base><number> : for a full description
2. <base><number> : this is given a default size which is machine dependant but at least 32 bits.
3. <number> : this is given a default base of decimal

9
The size specifies the exact number of bits used by the number. For example, a 4 bit binary will
have 4 as the size specification and a 4 digit hexadecimal will have 16 as the size specification
since each hexadecimal digit requires 4 bits.

8'b10100010 // 8 bit number in binary representation


8'hA2 // 8 bit number in hexadecimal representation

X and Z values
x represents an unknown, and z a high impedance value. An x declares 4 unknown bits in
hexadecimal, 3 in octal and 1 in binary. z declares high impedance values similarly.
Alternatively z, when used in numbers, can be written as ? This is advised in case expressions
to enhance readability.

4'b10x0 // 4 bit binary with 2nd least sig. fig. unknown


4'b101z // 4 bit binary with least sig. fig. of high impededamce
12'dz // 12 bit decimal high impedance number
12'd? // 12 bit decimal high impedance 'don't-care' number
8'h4x // 8 bit number in hexidecimal representation with the
// four least significant bits unknown

Negative numbers
A number can be declared to be negative by putting a minus sign infront of the size. The
minus sign must appear at the start of a number (in all three formats given above), ie. it must
not appear between the size specifier and base, nor between the base and the format
specidications.

-8'd5 // 2's compliment of 5, held in 8 bits


8'b-5 // illegal syntax

Underscore
Underscores can be put anywhere in a number, except the beginning, to improve readability.

16'b0001_1010_1000_1111 // use of underscore to improve readability


8'b_0001_1010 // illegal use of underscore

Real
Real numbers can be in either decimal or scientific format, if expressed in decimal format
they must have at least one digit either side of the decimal point.

1.8
3_2387.3398_3047
3.8e10 // e or E for exponent
2.1e-9
3. // illegal

10
2.4 Strings
Strings are delimited by " ... ", and cannot be on multiple lines.

"hello world"; // legal string


"good
b
y
e
wo
rld"; // illegal string

11
12
3 Data Types

3.1 Nets
Keywords: wire, supply0, supply1
default value: z
default size: 1 bit
Nets represent the continuous updating of outputs with respect to their changing inputs. For
example in the figure below, c is connected to a by a not gate. if c is declared and initialised
as shown, it will continuously be driven by the changing value of a, its new value will not
have to be explicitly assigned to it.

If the drivers of a wire have the same value, the wire assumes this value. If the drivers have
different values it chooses the strongest, if the strengths are the same the wire assumes the
value of unknown, x.
The most frequently used net is the wire, two others which may be useful are supply0, and
supply1, these model power supplies in a circuit.

3.2 Registers
Keywords: reg
default value: x
default size: 1 bit
The fundamental difference between nets and registers is that registers have to be assigned
values explicitly. That value is held until a new assignment is made. This property can, for
example, be used to model a E-type flip flop as shown in figure below, with corresponding
Verilog code given below.

13
module E_ff(q, data, enable, reset, clock);
output q;
input data, enable, reset, clock;
reg q;

always @(posedge clock) // whenever the clock makes a transition to 1


if (reset == 0)
q = 1'b0;
else if (enable==1)
q = data;
// implicitly : else q = q:

endmodule

Register q holds the same value until it us changed by an explicit assignment.


As a contrast, if we go into a higher level module, for example the stimulus shown below, the
output from the E_ff would have to be assigned as a net so that the E_ff module can drive its
value. So now q is a wire.

module stimulus;
reg data, enable, clock, reset;
wire q;

initial begin
clock = 1'b0;
forever #5 clock = ~clock;
end

E_ff eff0(q, data, enable, reset, clock);


// as with 'c' in the previous section, the wire 'q' will now have its
// value driven into it by the E_ff module.

initial begin
reset = 1'b0;
#10 reset = 1'b1;
data = 1'b1;
#20 enable = 1;
#10 data = 1'b0;
#10 data = 1'b1;

14
#10 enable = 0;
#10 data = 1'b0;
#10 data = 1'b1;
#10 enable = 1;
#10 reset = 1'b0;
#30 $finish;
end

initial
$monitor($time, " q = %d", q);

endmodule

EXERCISE
Consider the stimulus above and predict the output for q. Then stimulus and check your answer.

3.3 Vectors
Both the register and net data types can be any number of bits wide if declared as vectors.
Vectors can be accessed either in whole or in part, the left hand number is always the most
significant number in the vector. See below for examples of vector declarations.

reg [3:0] output; // output is a 4-bit register


wire [31:0] data; // data is a 32-bit wire
reg [7:0] a;

data[3:0] = output; // partial assignment


output = 4'b0101; // assignment to the whole register

It is important to be consistant in the ordering of the vector width declaration. Normally the
most significant figure is written first.

reg [3:0] a; // it is important to adopt one convention for


reg [0:3] b; // the declaration of vector width.
EXERCISE
a) Declare an 8 bit wire with variable name address.
b) Assign 4'b1010 to its 4 most signficant bits.

15
3.4 Numbers
Integers
Keywords: integer
default value: x
default size: dependant on the host machine, but at least 32 bits
Integers are similar to registers but can store signed (i.e. negative as well as positive numbers)
whereas registers can only store positive numbers.

Real numbers
Keywords: real
default value: x
default size: again host machine dependant, but at least 64 bits
Real numbers can be in decimal or scientific format as shown in the example below. When
written with a decimal point, there must be at least one number on either side of the point. A
real number is converted to an integer by rounding to the nearest integer.

// 1.3 a real number in decimal format


// 1.3e27 a real number in scientific format

real pedantic_pi;
integer relaxed_pi;

initial begin
pedantic_pi = 3.141596259;
relaxed_pi = pedantic_pi; // relaxed_pi is set to 3
end

A warning about using registers vs. integers for signed values

An arithmetic operation is treated differently depending on the data type of the operand. A
register operand is treated as an unsigned value and an integer value is treated as a signed
value. Therefore if a negative value, such as -4'd12, is assigned to a register, it will stored as a
positive integer which is its 2's complement value. So when used as an operand the 2's
complement value will be used causing unintentional behaviour. If stored in an integer, the
behaviour would be as expected, using signed arithmetic.

16
3.5 Arrays
Registers, integers and time data types can be declared as arrays, as shown in the example
below. Note the size of the array comes after the variable name in the declaration and after the
variable name but before the bit reference in an assignment. So :-
declaration: <data_type_spec> {size} <variable_name> {array_size}
reference: <variable_name> {array_reference} {bit_reference}

reg data [7:0]; // 8 1-bit data elements


integer [3:0] out [31:0]; // 32 4-bit output elements

data[5]; // referencing the 5th data element

Memories
Memories are simply an array of registers. The syntax is the same as above, we will discuss
modelling RAM and ROM using memories in a later section.

reg [15:0] mem16_1024 [1023:0]; // memory mem16_1024 is 1K of 16 bit elements


mem16_1024[489]; // referencing element 489 of mem16_1024

It is always good practice to use informative names like mem16_1024 to help keep track of
memories.
EXERCISE
Instantiated a 2k memory of 8 bit elements.

3.6 Tri-state
A tri-state driver is one which will output either HIGH, LOW or "nothing".
In some architectures, many different modules need to be able to put data onto (to drive) the
same bus, at different times. Thus they all connect to the one common bus - but a set of
control signals seek to ensure that only one of them is driving a signal at any one time.
In Verilog, this is modelled using different signal "strengths". There is a signal value: z,
which is called "high-impedance". This basically means that a node is isolated, that is not
driven. It is possible to assign this value to a net.
Normally if two values are simultaneously written to a net, the result is unknown: x; however,
if a driven value is also assigned to the same net as a high-impedance value, the driven value
will over-ride the z. This is the basis for the following tri-state driver:

17
module triDriver(bus, drive, value);
inout [3:0] bus;
input drive;
input [3:0] value;

assign #2 bus = (drive == 1) ? value : 4'bz;

endmodule // triDriver

When the drive signal is high, the bus is driven to the data value, otherwise, this driver
outputs only a high-impedance and hence can be over-ridden by any other driven value.
NOTE: the bus is a wire and is designated as an inout variable on the port declarations.
The following example shows the effect of several control combinations on three tri-state
buffers:

module myTest;
wire [3:0] bus;
reg drive0, drive1, drive2;

integer i;

triDriver mod1 (bus, drive0, i[3:0]);


triDriver mod2 (bus, drive1, 4'hf);
triDriver mod3 (bus, drive2, 4'h0);

initial begin
for (i = 0; i < 12; i = i + 1) begin
#5 {drive2, drive1, drive0} = i;
#5 $display ($time," %b %b %d", i[2:0], bus, bus);
end
$finish;
end // initial begin

endmodule // myTest

giving output:

10 000 zzzz z
20 001 0001 1
30 010 1111 15
40 011 xx11 X
50 100 0000 0
60 101 0x0x X
70 110 xxxx x
80 111 xxxx x
90 000 zzzz z
100 001 1001 9
110 010 1111 15
120 011 1x11 X

18
4 Operators

4.1 Arithmetic operators


keysymbols: *, /, +, -, %
The binary operators are multiply, divide, add, subtract and modulus used as shown in the
examples below.

module arithTest;
reg [3:0] a, b;

initial begin
a = 4'b1100; // 12
b = 4'b0011; // 3

$displayb(a * b); // multiplication, evaluates to 4'b1000


// the four least significant bits of 36
$display(a / b); // division, evaluates to 4
$display(a + b); // addition, evaluates to 15
$display(a - b); // subtraction, evaluates to 9
$display((a + 1'b1) % b); // modulus, evaluates to 1

end

endmodule // arithTest

The unary operators are plus and minus, and have higher precedance than binary operators.
Note If any bit of an operand is unknown: x, then the result of any arithmetic operation is also
unknown.

4.2 Logical Operators


Keysymbols: &&, ||, !.
The logical operators are logical and, logical or and logical not.All logical operators evaluate
to either true ( 1 ), false ( 0 ), or unknown ( x ). An operand is true if it is non zero, and false if
it is zero. An unknown or a high impedance value evaluates as false. An operand can be a
variable or an expression which evaluates to either true or false as defined above.

19
module logicalTest;

reg [3:0] a, b, c;

initial begin
a = 2; b = 0; c = 4'hx;

$display(a && b); // logical and, evaluates to 0


$display(a || b); // logical or, evaluates to 1
$display(!a); // logical not, evaluates to 0
$display(a || c); // evaluates to 1, unknown || 1 (=1)
$display(!c); // evalutes to unknown
end

endmodule // logicalTest

EXERCISE
What do the following evaluate to ?
a) !(67)
b) 0 && 1;
c) 1 || 2;
d) 0 || (1 &&1) || !1
e) What value of gamma is displayed if the following module is run ?

module testlogical;
integer alpha, beta, gamma;

initial begin
alpha = 1'b0;
beta = 1'b0;
gamma = 1'b0;
alpha = !beta;
gamma = alpha || beta;
$display("gamma = %d", gamma);
end
endmodule // testlogical

4.3 Relational Operators


Keysymbols: >, <, >=, <=.
The relational operators are less than, more than, less then or equal to and more than or equal
to. The true and false values are defined in the same way as above in the logical operator. In
this case if any operand is unknown the whole expression evaluates to unknown. See
examples below.

20
module relatTest;
reg [3:0] a, b ,c, d;

initial begin
a=2;
b=5;
c=2;
d=4'hx;

$display(a < b); // LHS less than RHS, evaluates to true, 1


$display(a > b); // LHS more than RHS, evaluates to false, 0
$display(a >= c); // more than or equal to, evaluates to true, 1
$display(d <= a); // less than or equal to, evaluates to unknown
end
endmodule // relatTest

EXERCISE
How many times will the following while loop execute ?

module relatTest2;
reg [3:0] a, b ,c, d;

initial begin
a = 1;
b = 4;
c = 0;
while (b >= c)
if (b > a) c = c + 1;
$display(c);
end
endmodule // relatTest2

4.4 Equality
keysymbols: ==, !=, ===, !==.
The equality operators are logical equality, logical inequality, case equality and case
inequality. These operators compare the operands bit-by-corresponding-bit for equality.
The logical operators will return unknown if "significant" bits are unknown or high-
impedence (x or z)
The case operators look for "equality" also with respect to bits which are unknown or high
impedence.
If one operand is shorter than the other, it is expanded with 0s unless the most significant bit
is unknown.

21
module equTest;
reg [3:0] a, b ,c, d, e, f;

initial begin
a = 4; b = 7; // these default to decimal bases
c = 4'b010;
d = 4'bx10;
e = 4'bx101;
f = 4'bxx01;

$displayb(c); // outputs 0010


$displayb(d); // outputs xx10

$display(a == b); // logical equality, evaluates to 0


$display(c != d); // logical inequality, evaluates to x
$display(c != f); // logical inequality, evaluates to 1
$display(d === e); // case equality, evaluates to 0
$display(c !== d); // case inequality, evaluates to 1
end
endmodule // equTest
EXERCISE
What do the following evaluate to ?

$displayb(3'b101 != 3'b010);
$displayb(4'b0001 == 4'b1);
$displayb(4'b101x == 4'b101x);
$displayb(4'b101x === 4'b101x);

4.5 Bitwise Operators


keysymbols: ~, &, |, ^, (~^, ^~).
The bitwise operators are negation, and, or, xor and xnor. Bitwise operators perform a bit-by-
corresponding-bit operation on both operands, if one operand is shorter it is bit extended to
the left with zeros. See examples below.

module bitTest;
reg [3:0] a, b ,c;

initial begin
a = 4'b1100; b = 4'b0011; c = 4'b0101;

$displayb(~a); // bitwise negation, evaluates to 4'b0011


$displayb(a & c); // bitwise and, evaluates to 4'b0100
$displayb(a | b); // bitwise or, evaluates to 4'b1111
$displayb(b ^ c); // bitwise xor, evaluates to 4'b0110
$displayb(a ~^ c); // bitwise xnor, evaluates to 4'b0110

end
endmodule // bitTest

22
EXERCISE

What do the following display?

$displayb(~2'b01);
$displayb(4'b1010 ^ 4'b10);
$displayb(4'bx | 1'b1);

4.6 Reduction Operator


Keysymbols: &, ~&, |, ~|, ^, ~^, ^~.
The reduction operators are and, nand, or, nor, xor xnor and an alternative xnor. They take one operand
and perform a bit-by-next-bit operation, starting with the two leftmost bits, giving a 1-bit result.

module reductTest;
reg [3:0] a, b ,c;

initial begin
a = 4'b1111;
b = 4'b0101;
c = 4'b0011;

$displayb(& a); // bitwise and, (same as 1&1&1&1), evaluates to 1


$displayb(| b); // bitwise or, (same as 0|1|0|1), evaluates to 1
$displayb(^ b); // bitwise xor, (same as 0^1^0^1), evaluates to 0
end

endmodule // reductTest

Note: the bitwise xor and xnor are useful in generating parity checks.
Please note carefully the differences in logical, bitwise and reduction operators. The symbols for bitwise
and reduction overlap but the number of operands is different in those cases.
EXERCISE
What do the following evaluate to ?

$displayb(& 1'b10);
$displayb(| 3'b101x);
$displayb(^ 4'b1101);

23
4.7 Shift Operator
Keysymbols: >>, <<.
The shift operators are shift left and shift right. The shift operator takes a vector and a number indicating
the shift. The empty bits caused by shifting are filled with zeros. See examples below.

module shiftTest;
reg [3:0] a;

initial begin
a = 4'b1010;

$displayb(a << 1); // shift left by 1, evaluates to 4'b0100


$displayb(a >> 2); // shift right by 2, evaluates to 4'b0010
end

endmodule // shiftTest
This operator is useful in modelling shift registers, long multiplication algorithms, etc.
EXERCISE
What does the following evaluate to ?

$displayb((4'b0110 == (4'b1100 >> 1)));


$displayb((4'b0110 == (4'b1100 << 1)));

4.8 Concatenation
keysymbols: {, }
The concatenation operator appends sized nets, registers, bit select, part select and constants.

module concatTest;
reg a;
reg [1:0] b;
reg [5:0] c;

initial begin
a = 1'b1;
b = 2'b00;
c = 6'b101001;

$displayb({a, b}); // produces a 3-bit number 3'b100


$displayb({c[5:3], a}); // produces 4-bit number 4'b1011

end

endmodule // concatTest

24
4.9 Replication
Replication can be used along side concatenation to repeat a number as many times as
specified, see example below.

module replicTest;
reg a;
reg [1:0] b;
reg [5:0] c;

initial begin
a = 1'b1;
b = 2'b00;

$displayb({4{a}}); // evaluates as 1111


c = {4{a}};
$displayb(c); // evaluates as 001111
end

endmodule // replicTest
According to the IEEE standard, replication and concatenation can be combined as in: c =
{4{a}, b} however, the current software at Edinburgh University does not allow this.
EXERCISE
What does d evaluate to in the following ?

module replicTest2;
reg a;
reg [1:0] b;
reg [3:0] c;
reg [9:0] d;

initial begin
a = 1'b1;
b = 2'b01;
c = {4{a}};
d = {b, c, b};

$displayb(d);
end

endmodule // replicTest2

25
26
5 System Tasks
For certain routine operations Verilog provides system tasks. all such tasks are in the form
$keyword. In this section we will discuss writing to output, monitoring a simulation and
ending a simulation.

5.1 Writing to Standard Output


Keyword: $display, $displayb, $displayh, $displayo, $write, $writeb, $writeh, $writeo.
The most useful of these is $display.This can be used for displaying strings, expression or
values of variables. Here are some examples of usage.

$display("Hello Dr Blair");
--- output: Hello Dr Blair

$display($time) // current simulation time.


--- output: 460

counter = 4'b10;
$display(" The count is %b", counter);
--- output: The count is 0010
The formatting syntax is similar to that of printf in the C programming language. For
$display and $display, they are:

-------------------------------------------
| Format Specifications |
-------------------------------------------
| Format | Display |
| -------- | ---------------------------- |
| %d or %D | Decimal |
| %b or %B | Binary |
| %h or %H | Hexadecimal |
| %o or %O | Octal |
| %m or %M | Hierarchical name |
| %t or %T | Time format |
| %e or %E | Real in scientific format |
| %f or %F | Real in decimal formal |
| %g or %G | Real in shorter of above two |
-------------------------------------------
The escape sequence for printing special characters are:
--------------------
| Escape Sequences |
--------------------
| \n | newline |
| \t | tabulate |
| \\ | print \ |
| \" | print " |
| %% | print % |
--------------------

27
$write is identical to $display except it does not automatically put a newline at the end of its
output.
EXERCISE What does $display without any arguments output? What does that tell you about
$write?
If the formatting character is omitted, the various commands default as below:

---------------------------
| Default Format Specs |
---------------------------
| Task | Default |
| --------- | ----------- |
| $display | decimal |
| $displayb | binary |
| $displayh | hexadecimal |
| $displayo | octal |
| $write | decimal |
| $writeb | binary |
| $writeh | hexadecimal |
| $writeo | octal |
---------------------------
Thus
$write(5'b01101);
$writeb(" ", 5'b01101);
$writeh(" ", 5'b01101);
$writeo(" ", 5'b01101,"\n");
produces:
13 01101 0d 15

5.2 Monitoring a Simulation.


Keywords: $monitor, $monitoron, $monitoroff
The format of $monitor is exactly the same as $display The difference is that an output
occurs on any change in the variables, rather than at specified times. Thus the $monitor
command established a list of variable which are watched, and in practice it is written to be
executed at the beginning of the simulation.
Monitoring can be enabled or disabled using $monitoron or $monitoroff respectively.
Monitoring is on by default at the beginning of a simulation. The example below shows how a
simulation can be monitored.

28
module myTest;
integer a,b;

initial begin
a = 2;
b = 4;
forever begin
#5 a = a + b;
#5 b = a - 1;
end // forever begin
end // initial begin

initial #40 $finish;

initial begin
$monitor($time, " a = %d, b = %d", a, b);
end // initial begin

endmodule // myTest

will output:

0 a = 2, b = 4
5 a = 6, b = 4
10 a = 6, b = 5
15 a = 11, b = 5
20 a = 11, b = 10
25 a = 21, b = 10
30 a = 21, b = 20
35 a = 41, b = 20

5.3 Ending a simulation.


Keywords: $stop, $finish.
$finish exits the simulation and passes control to the operating system. $stop suspend the
simulation and puts Verilog into interative mode. See example below.

initial begin
clock = 1'b0;
... // whatever you want to be doing
#200 $stop // this will suspend the simulation and put it in
// interactive mode
#500 $finish // this will end the simulation alltogether.
end

29
30
6 Large Worked Example: Multiplexor

In this section we will work through a Verilog design line by line. This section is for those
who want to jump ahead and get a full flavour of the language before learning all the nitty
gritty.
The example program will be a 4 to 1 multiplexor and will be implemented using three
method, each a higher level of abstraction than the last.

Below is a logic diagram for a 4 to 1 multiplexor.

31
6.2 Gate Level Implementation.
Here is the gate level implementation of the given multiplexor.

module multiplexor4_1(out, in1, in2, in3, in4, cntrl1, cntrl2);

output out;
input in1, in2, in3, in4, cntrl1, cntrl2;
wire notcntlr1, notcntrl2, w, x, y, z;

not (notcntrl1, cntrl1);


not (notcntrl2, cntrl2);

and (w, in1, notcntrl1, notcntrl2);


and (x, in2, notcntrl1, cntrl2);
and (y, in3, cntrl1, notcntrl2);
and (z, in4, cntrl1, cntrl2);

or (out, w, x, y, z);

endmodule
Now we break up the code and go through it line by line.

module multiplexor4_1(out, in1, in2, in3, in4, cntrl1, cntrl2);

The first line of any module description is the keyword module followed by the module name
by which it can be referenced. Then the port list, this is all that can be seen from outside the
module. The order of the port list is conventionally output first.
The line is ended with a semicolon, this may seem strange to C programmers but is required
in Verilog.

output out;
input in1, in2, in3, in4, cntrl1, cntrl2;

All the ports in the port list must be declared as input, output or inout, these are then assumed
to be wire data types unless declared otherwise. When declared as wire Verilog expects a
implicit assignment to the output and values to be driven into the inputs by an external
module.

wire notcntrl1, notcntrl2, w, x, y, z;

This declares the internal wires, these represent connections between hardware elements.
Values are driven onto them by the output of the devices to whicih they are connected.

not (notcntrl1, cntrl1);


not (notcntrl2, cntrl2);

32
If you look are the logic diagram, it is clear what is happening here. This is a description of a
not gate, the output is notcntrl1 and the input is cntrl1. Note the gate has no name, naming is
not compulsory for predefined gates provided by verilog. Earlier we said that a value will be
driven into notcntrl1, this is what the not gate does; everytime the value of the input, cntrl1
changes, the value of notcntrl1 is updated automatically.

and (w, in1, notcntrl1, notcntrl2);


and (x, in2, notcntrl1, cntrl2);
and (y, in3, cntrl1, notcntrl2);
and (z, in4, cntrl1, cntrl2);

or (out, w, x, y, z);

These drive the values into w, x, y and z respectively in the same way described above. The
connections in the logic diagram can be used to verify the connection are correct. Note: each
line ends with a semicolon (;).

endmodule
The end of a module is indicated by the keyword endmodule.

6.3 Logic Statement Implementation.


Now we implement the same multiplexor as a logic statement.

module multiplexor4_1 (out, in1, in2, in3 ,in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;

assign out = (in1 & ~cntrl1 & ~cntrl2) |


(in2 & ~cntrl1 & cntrl2) |
(in3 & cntrl1 & ~cntrl2) |
(in4 & cntrl1 & cntrl2);
endmodule

This is a higher level of abstraction than the gate level description, it is still fairly
unintelligible, we will see it becoming more and more intelligible as we move up levels of
abstractions in the following sections.

module multiplexor4_1 (out, in1, in2, in3 ,in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;

The first few lines must stay the same so any module which is accessing the multiplexor does
not have to change, ie. the communication stays the same.

assign out = (in1 & ~cntrl1 & ~cntrl2) |


(in2 & ~cntrl1 & cntrl2) |
(in3 & cntrl1 & ~cntrl2) |
(in4 & cntrl1 & cntrl2);
endmodule

33
This is a continuous assignment to the wire out. It is reevaluated and assigned to out
everytime any of the operands change.

6.4 Case Statement Implementation


The multiplexor is now implemented using a case statement. This is a lot easier to understand,
there are four assignments, each is made explicitly.

module multiplexor4_1 (out, in1, in2, in3, in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;
reg out;

always @(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)


case ({cntrl1, cntrl2})
2'b00 : out = in1;
2'b01 : out = in2;
2'b10 : out = in3;
2'b11 : out = in4;
default : $display("Please check control bits");
endcase
endmodule

The first three lines are the same as in the previous section.

module multiplexor4_1 (out, in1, in2, in3, in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;
reg out;

But now we have out defined as a register, this is because we are going to assign values to it
explicitly and not drive them, this is called procedural assignment. A wire data type cannot be
assigned to explicitly, it must have its value driven into it by a device (eg. another module, a
gate, etc), called continuous assignment

always @(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)

If this is read as it is written, " always at [a change in] (in1 or in2 or...." it is clear what is going
on. This is a construct containing statements which are only executed when any of the variables
in the list of variables change. The list of variables is called the sensitivity list, because this
construct is sensitive to their change. The keyword are always @( expr or expr ... );

case ({cntrl2, cntrl1})


2'b00 : out = in1;
2'b01 : out = in2;
2'b10 : out = in3;
2'b11 : out = in4;
default : $display("Please check control bits");
endcase
endmodule

34
This is a case statement indicated by the keyword case, it is similar to the case statement in C.
The conditional is ({cntrl2,cntrl1}), the concatenation of cntr2 and cntr1 into a 2-bit number.
The test values are 2'b00 etc, and the actions are out= in1; etc. It has a default if none of the
tests are met, and ends with a endcase.
Note the difference in procedural and continuous assignments, here the control signals are
tested and out is assigned a value accordingly.

6.5 Conditional Operator Implementation


module multiplexor4_1 (out, in1, in2, in3, in4, cntrl1, cntrl2);
output out;
input in1, in2, in3, in4, cntrl1, cntrl2;

assign out = cntrl1 ? (cntrl2 ? in4 : in3) : (cntrl2 ? in2 : in1);

endmodule

6.6 The Stimulus Module


Once a module has been designed it can be tested by applying test inputs. This is idea of the
stimulus module. It calls the design module and uses its functionality, then results can be
monitored to verify its design. A well written stimulus will be able to put the whole design
through its paces.

Below is the stimulus for the multiplexor examples given in the previous sections, the same
stimulus can be applied to each of the designs above since they look the same externally and
are performing the same function, only in different ways.

module muxstimulus;
reg IN1, IN2, IN3, IN4, CNTRL1, CNTRL2;
wire OUT;

multiplexor4_1 mux1_4(OUT, IN1, IN2, IN3, IN4, CNTRL1, CNTRL2);

initial begin
IN1 = 1; IN2 = 0; IN3 = 1; IN4 = 0;
$display("Initial arbitrary values");
#0 $display("input1 = %b, input2 = %b, input3 = %b, input4 = %b\n",
IN1, IN2, IN3, IN4);

{CNTRL1, CNTRL2} = 2'b00;


#1 $display("cntrl1=%b, cntrl2=%b, output is %b", CNTRL1, CNTRL2, OUT);

{CNTRL1, CNTRL2} = 2'b01;


#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

{CNTRL1, CNTRL2} = 2'b10;


#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

35
{CNTRL1, CNTRL2} = 2'b11;
#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

end

endmodule

Now we look at this part by part.

module muxstimulus;

This is a top level module it, ie. nothing else calls it to use its functionality, so it doesn't need
a port list. The keyword module remains and the module name should be chosen to to
indicate that it is a stimulus module.

reg IN1, IN2, IN3, IN4, CNTRL1, CNTRL2;


wire OUT;

Remember the inputs to the multiplexor are in1, in2, in3, in4, cntrl1 and cntrl2; and the output
from the multiplexor is out. The idea of the stimulus is to apply artificial stimulus to the
inputs and see what values are assigned to out by the multiplexor4_1 module.
So we want to be able to assign values to the inputs and values to be driven into the output. It
follows that the inputs must be reg data types and the output must be a wire.

multiplexor4_1 mux1_4(OUT, IN1, IN2, IN3, IN4, CNTRL1, CNTRL2);

This calls the multiplexor4_1 module, the syntax is


<module_name> <instance_name> (port list);
The instance name is necessary when calling user defined modules, this is to aid the traversal
down the hierarchy of design (but we will not cover this aspect of the language). The port list
sets up the correspondence of the stimulus module variable with the variables of the design
module. The post list must be in the same order when the module is called as when it is
defined to ensure the variables correspond as expected.
Now multiplexor4_1 is active, if the inputs change, ie. are assigned test values, it will
compute a value for the output and drive it into out.

initial begin
IN1 = 1; IN2 = 0; IN3 = 1; IN4 = 0;
$display("Initial arbitrary values");
#0 $display("input1 = %b, input2 = %b, input3 = %b, input4 = %b\n",
IN1, IN2, IN3, IN4);

The main part of the simulation is enclosed in the construct initial begin ... end. This is a way
of grouping statements which may run concurrently, since there is only one initial block in
this example, its use is not fully illustrated.

36
First the inputs are assigned arbitrary values and these are displayed using $display. Note the
#0 before the display statement. This is to ensure that the display is made after the assignment
of values to the input. The assignments are made at simulation time 0, putting a #0 ensures
that the $display is executed at the end of the 0 time slice. The execution of an assignment
using = is always in the order given so these don't have to be time controlled.
The syntax of the $display is similar to that of printf in C,
$display( expr1, expr2, ...., exprN); exprN can be variables, expressions or quotes strings.

{CNTRL1, CNTRL2} = 2'b00;


#1 $display("cntrl1=%b, cntrl2=%b, output is %b", CNTRL1, CNTRL2, OUT);

The first line is an assignment to the control signals and is the same as saying
CNTRL1 = 0;
CNTRL2 = 0;
The concatenation operator { } can be used to make group assignments. The number of bits in
the assignment must be the same as the number of bits in the variables.
Now that the inputs and control signals have values multiplexor4_1 module will drive a value
into out. We want to test whether this value is the one we expect so we can check it using
$display.

{CNTRL1, CNTRL2} = 2'b01;


#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

{CNTRL1, CNTRL2} = 2'b10;


#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

{CNTRL1, CNTRL2} = 2'b11;


#1 $display("cntrl1=%b, cntrl2=%b output is %b", CNTRL1, CNTRL2, OUT);

end
endmodule

In the same way the values of the control signals are changed and the value of the output is
checked via the display.
Note the $display statements have a delay associated with them, the first is delayed by 1 time
unit, the second by 1 after that (ie. 2 units from the start of the simulation). This is to ensure
the displays are delayed until the correct values have been assigned to the control signals.
This test file does not fully exercise the multiplexor, but it is a good initial check.

37
38
7 Design Blocks

7.1 Modules
The E-type flip flop is made of a D-type flip flop, an inverting multiplexor and a nor gate. We
see this hierarchy in the figure below. We can break the mutliplexor down further but this
level of detail is sufficient for this section.

There are two angles to approach the design of the E-type flip flop in Verilog:
Topdown- start with the E-type flip flop and add more detail.
Bottom up- start with the basic flip flop an inverting multiplexor and a nor gate, and build up,
ie generalise the detail.
We will use a bottom up methodology, but typically a combination of both is used.
We start with the D-type, it is encapsulated as a module, enclosed in the keywords
module <module_name> ... endmodule, as below.

module dff(q, data, clock);


output q;
input data, clock;
reg q;

always @(posedge clock)


q = data;
endmodule // dff

Now we need an inverting multiplexor and we similarly describe it by its behaviour.

module mux2_1(out, in1, in2, cntrl);


output out;
input in1, in2, cntrl;

assign out = cntrl ? ~in1 : ~in2;


endmodule // mux2_1

39
The top level E-type will use the functionality enclosed in the D-type and the multiplexer. To
call a module we have to call it by name and give it another name by which it will be known
in the higher level module.

module e_ff(q, data, enable, reset, clock);


output q;
input data, enable, reset, clock;
wire norout, muxout;

mux2_1 mod1 (muxout, data, q, enable);


nor (norout, reset, muxout);
dff dff0 (q, norout, clock);
endmodule

To instantiate, ie. call and use, a users defined modue we use the syntax
name_of_module instance_name (port_list);

7.2 Stimulus
To test whether modules we have written are doing what we intended them to, we have a way
of applying stimulus to the inputs and checking whether the outputs correspond. This is called
a stimulus module. The syntax is exactly the same as the modules seen already, but a stimulus
module does not have a port list because it has no input and explicit outputs. We would like to
apply waveforms to the clock, enable and reset to see how the output of the module
e_ffbehaves

module e_ffStimulus;
reg data, enable, reset, clock;
wire q;

e_ff mod1 (q, data, enable, reset, clock);

initial begin
clock = 1'b0;
forever clock = #5 ~clock;
end

initial begin
enable = 1'b0; // initialize enable variable
reset = 1'b1; // the E type has an active high reset, so
#20 reset = 1'b0; // we begin by resetting.
data = 1'b1; // set the data HIGH
#10 enable = 1'b1; // and then enable data latching
#10 data = 1'b1; // change the data value
#20 data = 1'b0; // change the data value
#30 data = 1'b1; // change the data value
#10 data = 1'b0; // change the data value
#10 data = 1'b1; // change the data value
#20 enable = 1'b0; // disable data latching
#10 data = 1'b0; // change the data value - no effect?
#10 reset = 1'b1; // reset again
#20 $finish; // finally we must end the simulation using
end // $finish this also stops the clock

40
initial begin
$display($time, " reset, enable, data, q ");
$display($time, " %d %d %d %d",
reset, enable, data, q);
forever #10 $display($time, " %d %d %d %d",
reset, enable, data, q);
end

endmodule // e_ffStimulus

EXERCISE
a) Run the stimulus using, cut and paste, with the code from the previous section - interpret
the output
b) Write a single behavioural module for the E-type flipflop and test it using the above
stimulus

41
42
8 Ports

Ports provide a means for a module to communicate through input and output. Let us go back
to the E-type flip flop example given in the previous section. The input/ ouput of the D-type
relative to the E-type is shown below.

module d_ff(q, d, reset, clock);


module e_ff(q, d, enable, reset, clock);
module Stimulus;

8.1 Port Lists


The I/O for the D-type is generated by the E-type, the I/O for the E-type is generated by the
top level module in this case the stimulus. The stimulus module has no I/O so does not need a
port list.
Every port in the port list must be declared as input, output or inout, in the module. All ports
declared as one of the above is assumed to be a wire by default, to declare it otherwise it is
neccessary to declare it again. For example in the D-type flip flop we want the ouput to hold
on to its value until the next clock edge so it has to be a register.

module d_ff(q, d, reset, clock);


output q; // all ports must be declared
input d, reset, clock; // as input or output
reg q; // the ports can be declared again as required.
Note: by convention, the outputs of the module is always first in the port list. This convention
is also used in the predefined modules in Verilog.

43
8.2 Connection Rules
We will talk of two type of modules, the outer and inner modules, as an analogy the outer
module is the E-type and the inner module is the D-type. It might be useful to take a look at
the section on modules to understand this.

8.2.1 Inputs
In an inner module inputs must always be of a net type, since values will be driven into them.
In the outer module the input may be a net type or a reg.

8.2.2 Outputs
In an inner module outputs can be of a net type or a reg. In an outer module the output must
be of a net type since values will be driven into them by the inner module.

8.2.3 Inouts
Inouts must always be of a net type.

8.2.4 Port Matching


When calling a module the width of each port must be the same, eg, a 4-bit register cannot be
matched to a 2-bit register.
However, output ports may remain unconnected, by missing out their name in the port list.
This would be useful if some outputs were for debugging purposes or if some outputs of a
more general module were not required in a particular context. However input ports cannot be
omitted for obvious reasons.
For example:
d_ff dff0( , d, reset, clock); // the output (q) has been omitted
// the comma is ESSENTIAL

Connecting Ports
Ports can be connected by either ordered list or by name. The ordered list method is
recommended for the beginner, in this method the port list in the module instantiation is in the
same order as in the module definition. See example below.

module d_ff( q, d, reset, clock);


...
endmodule

module e_ff(q, d , enable, reset, clock);


output q;
input d, enable, reset, clock;
wire inD;
...
d_ff dff0(q, inD, reset, clock);
...
endmodule

44
The second method is by name, when instantiating, the ports in the definition are
accompanied by the corresponding port name in the instantiation. EXERCISE
a) Draw a diagram for your own reference illustrating the constraints on the input, output and
inouts.
b) Using the module interfaces for the d_ff and the e_ff modules above, write code to
complete them AND a toggle flip-flop: t_ff, based upon a call to the e_ff module. The
function of the toggle flipflop is to either change its output or to hold its output on each new
rising clock edge according to a control signal: toggle. It should also have a synchronous
reset.

45
46
9 Basic Blocks

9.1 Introduction to Procedural Constructs


There are two kinds of assignment, continuous and procedural. Continuous assignments can
only be made to nets, or a concatenation of nets. The operands can be of any data type. If one
of the operands on the right hand side (RHS) of the assignment change, as the name suggests,
the net on the left hand side (LHS) of the assignment is updated. In this way values are said to
be driven into nets. Continuous assignments can be used to replace gate level descriptions
with a higher level of abstraction.
Procedural assignments are made to reg, integer, real or time, they need updating constantly
to reflect any change in the value of the operands on the RHS.

9.2 Initial Block


Keywords: initial
An initial block consists of a statement or a group of statements enclosed in begin... end
which will be executed only once at simulation time 0. If there is more than one block they
execute concurrently and independently. The initial block is normally used for initialisation,
monitoring, generating wave forms (eg, clock pulses) and processes which are executed once
in a simulation. An example of initialisation and wave generation is given below

initial
clock = 1'b0; // variable initialization

initial
begin // multiple statements have to be grouped
alpha = 0;
#10 alpha = 1; // waveform generation
#20 alpha = 0;
#5 alpha = 1;
#7 alpha = 0;
#10 alpha = 1;
#20 alpha = 0;
end;

47
EXERCISE
a) Note that the first initial block in the example does not contain the keywords begin and
end. Why is this ?

9.3 Always Block


Keywords: always
An always block is similar to the initial block, but the statements inside an always block will
repeated continuously, in a looping fashion, until stopped by $finish or $stop.
Note: the $finish command actually terminates the simulation where as $stop. merely pauses
it and awaits further instructions. Thus $finish is the preferred command unless you are using
an interactive version of the simulator.
One way to simulate a clock pulse is shown in the example below. Note, this is not the best
way to simulate a clock. See the section on the forever loop for a better method.

module pulse;

reg clock;

initial clock = 1'b0; // start the clock at 0


always #10 clock = ~clock; // toggle every 10 time units
initial #5000 $finish // end the simulation after 5000 time units

endmodule

EXERCISE
Using the initial and always constructs describe the wave for the following.

reg clock;
reg [1:0] alpha;

48
49
10 Large Worked Example: The Binary
counter

10.1 Introduction and Logical Diagram


Now we will implement a binary counter, and add extention to it as we describe it in higher
levels of abstraction. The counter which will be implemented counts in binary from 0 to 12.
At 12 it resets itself to 0 and starts again.
Below is a logic diagram for the binary counter. The commented Verilog description of the
counter can be found here

50
10.2 Gate level Description: Binary Counter
Basic Code

// 4-bit binary counter

module counter4_bit(q, d, increment, load_data, global_reset, clock);


output [3:0] q;
input [3:0] d;
input load_data, global_reset, clock, increment;
wire t1, t2, t3; // internal wires
wire see12, reset; // internal wires

// internal wires are used to move information around the module,


// they can be imagined to be temporary variables, storing the ouput
// from one gate and feeding it into another.

et_ff etff0(q[0], d[0], increment, load_data, reset, clock);


et_ff etff1(q[1], d[1], t1, load_data, reset, clock);
et_ff etff2(q[2], d[2], t2, load_data, reset, clock);
et_ff etff3(q[3], d[3], t3, load_data, reset, clock);

and a1(t1, increment, q[0]); // increment signals are derived from the
and a2(t2, t1, q[1]); // the previous increment signal by and-ing
and a3(t3, t2, q[2]); // with the output form the previous
//ET-type

recog12 r1(see12, q); // everytime the output changed this


// checks if it is a 12, if so 'see12' is
// set to 1.
or or1(reset, see12, global_reset); // reset to 0 if 'global_reset'
// or 'see12' is high

endmodule // counter4_bit

module et_ff(q, data, toggle, load_data, reset, clock);


output q;
input data, toggle, load_data, reset, clock;
wire m1, m2;

mux mux0(m1, ~q, q, toggle);


mux mux1(m2, data, m1, load_data);
dff dff0(q, m2, reset, clock);

endmodule // et_ff

module mux(out, in1, in2, cntrl);


output out;
input in1, in2, cntrl;

assign out = cntrl ? in1 : in2;


// this is a continuous assignment so it is renewed everytime an
// operand changed. if (cntrl==1) out = in1, else out = in2.

endmodule // mux

51
module dff(q, data, reset, clock);
output q;
input data, reset, clock;
reg q;

always @(posedge clock) // at every clock edge, if reset is 1, q is


if (reset == 1) // reset to 0, else it is set to data, which
q = 0; // as we said earlier can be either data, q or ~q
else q = data;

endmodule

module recog12(flag, in);


input [3:0] in;
output flag;

assign flag = (in == 4'b1100) ? 1 : 0;


// here we see that if the input is 12 the flag will be set to 1,
// otherwise it will be set to 0.

endmodule // recog12

module stumulus;
wire [3:0] q;
reg [3:0] d;
reg load_data, global_reset, clk, increment;

counter4_bit mod1 (q, d, increment, load_data, global_reset, clk);

initial begin
global_reset = 0;
clk = 0;
increment = 0;
load_data = 0;
d = 4'b0100;

#10 global_reset = 1;
#20 global_reset = 0;
#20 load_data = 1;
#20 load_data = 0;
#20 increment = 1;
#200 global_reset = 1;
#20 global_reset = 0;
#50 load_data = 1;
#20 load_data = 0;
#10 increment = 0;
#20 $finish;
end // initial begin

always #5 clk = ~clk;

always #10 $display ($time," %b %b %b %d -> %b %d",


increment, load_data, global_reset, d, q, q);

endmodule // stimulus

52
Break down

module counter4_bit(q, d, increment, load_data, global_reset, clock);


output [3:0] q;
input [3:0] d;
input load_data, global_reset, clock, increment;
wire t1, t2, t3; // internal wires
wire see12, reset; // internal wires

The first line is the start of the module, declaring the name and the port list. The output is q
and there other signals are all inputs. t1, t2, t3, see12 and reset are all declared as internal
wires which connect the various gates/sub-modules within the module.

et_ff etff0(q[0], d[0], increment, load_data, reset, clock);


et_ff etff1(q[1], d[1], t1, load_data, reset, clock);
et_ff etff2(q[2], d[2], t2, load_data, reset, clock);
et_ff etff3(q[3], d[3], t3, load_data, reset, clock);

There are 4 Enable/Toggle flip flops in the logic diagram, each of which is instatiated here.
Note each instantiation has a name. q.

and a1(t1, increment, q[0]);


and a2(t2, t1, q[1]);
and a3(t3, t2, q[2]);

The increment signal is anded with the output from the last E-T flipflop to assert the toggle
signal for the next E-T flipflop; this can be seen in logic diagram.

recog12 r1(see12, q);


or or1(reset, see12, global_reset);

Everytime q changes the value of see12 is updated; when it reaches 12, the internal reset
signal is raised by the or gate and the flipflops will all be reset on the next rising clock edge.

53
10.3 Behavioural Model
In the previous section we saw the gate level description of a binary counter, now we will
implement the same counter using a behavioural description. It uses the same stimulus
module but is a lot easier to understand and modify.

// 4-bit binary up-counter - of period 13

module counter4_bit(q, d, increment, load_data, global_reset, clock);


output [3:0] q;
input [3:0] d;
input load_data, global_reset, clock, increment;

reg [3:0] q;

always @(posedge clock)


if (global_reset)
q = 4'b0000;
else if (load_data)
q = d;
else if (increment) begin
if (q == 12)
q = 0;
else
q = q + 1;
end

endmodule // counter4_bit

It would be a good idea to compare the port declarations of both implementations at this point and see
the similarities. The only difference is that the output q is now also declared as a register. EXERCISE
why?
EXERCISE Using the stimulus defined in the gate-level description, simulate the behavioural
model and verify that the same (correct ?) results are obtained.
This implementation is a lot easier to update than the previous gate level implementation.
Circuits are thus normally written in this form and reduced to gate level descriptions by
Verilog applications (ie synthesis).
To convert the above into a down counter, all we need to do is changed the + sign in the third
if to a - and alter the "end" condition so that 0 is followed by 12. Because of this, it is
convenient to make the "global_reset" condition equal to 12 also. While this is not necessary
for the Verilog behavioural code, it simplifies the gate level implementation [why?].

54
// 4-bit binary down-counter - of period 13
module counter4_bit(q, d, decrement, load_data, global_reset, clock);

// some appropriate declarations

always @(posedge clock)


if (global_reset)
q = 12;
else if (load_data)
q = d;
else if (decrement)
begin
if (q == 0)
q = 12;
else
q = q - 1;
end

endmodule

Up-Down counter
If a counter has a period which is a power of two, it is simpler to design since the counter
"wraps round" and the 'end" condition does not need to be explicitly detected. Thus for a four
bit register, 15 + 1 = 0 and 0 - 1 = 15.
Below is the code for a 4-bit counter (with period 16) which can either count up or down
according to an extra input signal.

// 4-bit binary up-down-counter - of period 16


module counter4_bit(q, d, updown, count, load_data, global_reset, clock);

// some appropriate declarations

always @(posedge clock)


if (reset)
q = 0;
else if (load_data)
q = d;
else if (count)
begin
if (updown)
q = q + 1;
else
q = q - 1;
end

endmodule

EXERCISE Change the updown counter given to count in 3s.

55
56
11 Timing Control
There are three types of timing control, delay based, event based and level sensitive. We will
discuss the useful aspects of each in turn.

11.1 Delay-Based
Syntax: timing_control_statement::== delay_based statement*
delay_based::== # delay_value
This method introduces a delay between when a statement is encountered and when it is
executed.

initial begin
a = 0; // executed at simulation time 0
#10 b = 2; // executed at simulation time 10
#15 c = a; // ... at time 25
#b c = 4; // ... at time 27
b=5; // ... at time 27
end

The delay value can be specified by a constant or variable. Note the time is not in seconds, it
is relative to the current unit of time. A common example is the creation of a clock signal:

initial begin
clock = 1'b0;
forever #5 clock = ~clock;
end

This will make the clock flip every 5 time units giving a wave form as shown.
EXERCISE
In the following module what would be the values of
a) a at time 15 units;
b) b at 17 units
c) c at 18 units
d) a at 30 units

57
module testdelay(a, b, c);
output [3:0] a, b, c;
reg [3:0] a, b, c;

initial begin
#10 a = 3;
#5 b = 4;
#6 c = 5;
#8 a = a + b;
end

endmodule

11.2 Event-Based
Syntax:
event_control_statement::==
@ event_identifier
| @ (event_expression)

event_expression::==
| exp
| event_id
| posedge exp
| negedge exp
| event_exp or event_exp.
Event-based timing control allows conditional execution based on the occupance of a named
event. Verilog waits on a predefined signal or a user defined variable to change before it
executes a block.

@ (clock) a = b; // when the clock changes value, execute a = b

@ (negedge clock) a = b; // when the clock change to a 0, execute a=b

a = @(posedge clock) b; // evaluate b immediately and assign to a on


// a positive clock edge.

Triggers
Triggers can be understood from the following example.

event data_in; // user-defined event

always @(negedge clock)


if (data[8]==1) -> data_in; // trigger the event

always @(data_in) // event triggered block


mem[0:1] = buf;

This can be read as: at every negative clock edge, check if data[8] is 1, if so assert data_in.
When data_in is asserted, the statement if the second always is executed.
58
11.3 Sensitivity List
Syntax: event_list_statement::==
@ (event_exp or event_exp)
event_exp::==
(event_exp or event_exp).
If we wish to execute a block when any of a number of variables change we can use the
sensitivity list to list the triggers seperated by or

always @ (i_change or he_changes or she_changes)


somebody_changed = 1;

A change in any of the variables will cause execution of the second statement. As you can see
this is just a simple extention to the idea of event based timing control described in the
previous section.

11.4 Gate Delays


Syntax:
delay_statement::==
gate_name delay_exp gate_details

delay_exp::==
# delay_time
This type of delay is only associated with the primitive gates defined within Verilog.

and #(5) a1(out, in1, in2);

59
60
12 Branch Statements
12.1 The if statement.
Syntax: if (conditional_expression) statement{ else statement}
The if statement causes a conditional branch. If the conditional expression evaluates to true
the first statement or set of statements is executed, else the second statement or set of
statements is executed, ( the syntax is very similar to that of pascal). To group statements use
the keywords begin... end
To illustrate the use of an if statement consider the 4 to 1 multiplexor in figure A,
implemented using a logic equation in example B and using an if statement in example C.

Figure A : Above : The 4 to 1 multiplexor

module multiplexor4_1 (out, in1, in2, in3 ,in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;

assign out = (~cntrl2 & ~cntrl1 & in1) | // The output is in1 when both
( cntrl2 & ~cntrl1 & in2) | // cntrls are low, etc.
(~cntrl2 & cntrl1 & in3) |
( cntrl2 & cntrl1 & in4) ;
// Note this is a continous assignment, if an operand on the right
// hand side changes, the left hand side will reflect the change.

endmodule

61
Example B : Above : Implementation of a 4 to 1 multiplexor using a logic equation.

module multiplexor4_1 (out, in1, in2, in3 ,in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;
reg out; // Note that this is now a register

always @(in1 or in2 or in3 or in4 or cntrl1 or cntrl2)


if (cntrl1==1)
if (cntrl2==1)
out = in4;
else out = in3;
else
if (cntrl2==1)
out = in2;
else out = in1;

endmodule
Example C : Above : Implementation of a 4 to 1 multiplexor using a if statement.
EXERCISE
Write the stimulus block for the above multiplexor, you will have to show that the correct
input is selected according to the values of the control bits.

12.2 The case statement.


The above method for implementing the multiplexor already looks hard to follow, if there are
more than 4 input lines it would become almost impossible to write out the correct if
statement. A clearer implementation uses a case statement (this is very similar in syntax to the
case statement in C).
Syntax:
conditional::== case (condition) case_item+ endcase
case_item::==
expression+ (seperated by commas) : statement* |
default : statement*
An implementation of the 4 to 1 multiplexor using the case statement.

module multiplexor4_1 (out, in1, in2, in3, in4, cntrl1, cntrl2);


output out;
input in1, in2, in3, in4, cntrl1, cntrl2;
reg out; // note must be a register

always @(in1 | in2 | in3 | in4 | cntrl1 | cntrl2)


case ({cntrl2, cntrl1}) // concatenation
2'b00 : out = in1;
2'b01 : out = in2;
2'b10 : out = in3;
2'b11 : out = in4;
default : $display("Please check control bits");
endcase
endmodule

62
The stimulus block is the same as the one for the above multiplexor descriptions.
Variants of the case statement are casez and casex. Whereas the case statement compares the
expression to the condition bit by bit, insuring the 0, 1, x, and zs match, the casez treats all the
zs in the condition and expression as ?s, ie irrelevants. The casex similarly treats all the xs
and zs as ?s. These alteratives, if not used carefuly and sparingly can easily lead to bugs.
EXERCISE
What is the output from the following:

module testCase(value);
input [4:0] value;

always @(value)
casez (value)
5'b010zx : $display("%b: Matched OK", value);
default : $display("%b: Did not match", value);
endcase // casez (value)

endmodule // testCase

module runTest;
reg [4:0] value;

testCase mod1 (value);

initial begin
#10 value = 5'bzz01x;
#10 value = 5'bxxxzx;
#10 value = 5'b010xz;
#10 value = 5'bzzz0z;
#10 $finish;
end // initial begin
endmodule // runTest

12.2 The conditional operator


This is similar to the conditional operator in C, it can be imagined to be an abbreviated if-else.
The conditional expression is evaluated in the same way, if it evaluates to true the
true_expression is evaluated else the false_expression.
Syntax: conditional_expression ? true_expression : false_expression
To illustrate the conditional operator consider the implementation of a 2 to 1 multiplexor
below:

assign out = control ? in2 : in1;

The true and false expressions can themselves be conditional operators, so enabling more than
one interdependant conditional_expression. Conditional operators can be useful in modelling
conditional data assignment.

63
EXERCISE
Implement a 4 to 1 multiplexor using a nested conditonal operator, making sure it uses the
same simulation block as before

64
13 Looping Constructs

13.1 Introduction
The four looping constructs in Verilog are while, for, repeat and forever. All of these can
only appear inside initial and always blocks.
The basic idea of each of the loops is :
while: executes a statement or set of statements while a condition is true.

for: executes a statement or a set of statements. This loop can initialise, test and increment the
index variable in a neat fashion.

repeat: executes a statement or a set of statements a fixed number of times.

forever: executes a statement or a set of statements forever and ever, or until the simulation is
halted.

13.2 While Loop


Syntax: looping_statement::== while (conditional) statement
The while loop executes while the conditional is true, the conditional can consist of any
logical expression. Statements in the loop can be grouped using the keywords begin ... end.
The example below illustrates a while loop.

/* How many cups of volume 33 ml does it


take to fill a jug of volume 1 litre */

`define JUGVOL 1000


`define CUPVOL 33

module cup_and_jugs;
integer cup, jug;

initial begin
cup = 0; jug = 0;
while (jug < `JUGVOL) begin
jug = jug + `CUPVOL;
cup = cup + 1;
end // while (jug < JUG_VOL)

$display("It takes %d cups", cup);


end // initial begin

endmodule // cup_and_jugs

65
Notice the use of the "define" statement.
EXERCISE
How many times does the folowing while loop say hello?

initial begin
a = 5;
c = 0;

while (a != c) begin
$display("Hello");
c = c + 1;
end
end

13.3 For Loop


Syntax:
for (reg_initialisation ; conditional ; reg_update) statement
The for loop is the same as the for loop in C. It has three parts: the first part is executed once,
before the loop is entered; the second part is the test which (when true causes the loop to re-
iterate); and the third part is executed at the end of each iteration.

integer list [31:0];


integer index;

initial begin
for(index = 0; index < 32; index = index + 1)
list[index] = index + index;
end

EXERCISE Initialise the following memory so that each location contains its own address
plus 24 ie. memory16_256[0] contains 0000000000011000, (24 in decimal).

reg [15:0] memory16_256 [255:0];

13.4 Repeat Loop


Syntax: looping_statement::==
repeat (conditional) statement
A repeat loop executes a fixed number of times, the conditional can be a constant, variable or
a signal value but must contain a number. If the conditional is a variable or a signal value, it is
evaluated only at the entry to the loop and not again during execution. The jug and cups
example in the previous section cannot be implemented using a repeat loop, Why? but array
initialisation can be, How? The example below illustrates the loop.

66
module comply;
int count;
// counting down from 128

initial begin
count = 128;
repeat (count) begin
$display("%d seconds to comply", count);
count = count - 1;
end
end

endmodule

Note: The loop will execute 128 times regardless of whether the value of count changes after
entry to the loop.
EXERCISE
Think of a situation where the for loop would be prefered over a repeat loop.

13.5 Forever Loop


Syntax: forever statement
The forever loop executes continuously until the end of a simulation is requested by a
$finish. It can be thought of as a while loop whose condition is never false. The forever loop
must be used with a timing control to limit its execution, otherwise its statement would be
executed continuously at the expense of the rest of the design. The use of a forever loop is
shown below.

reg clock;

initial begin
clock = 1'b0;
forever #5 clock = ~clock; // the clock flips every 5 time units.
end

initial #2000 $finish;


EXERCISE
What is the problem with the following loop

reg clock;

initial begin
clock = 1'b0;
#5 forever clock = ~clock; // the clock flips every 5 time units.
end

initial #2000 $finish;

67
68
14 Extras

14.1 Opening a file


keywords: $open
Syntax: <file_handle> = $fopen("<file_name");
The default output of a Verilog program normally goes to the standard ouput but this can be
redirected to a file.
The file handle mentioned in the syntax above is a 32 bit descriptor. Out of the 32 bits only
one bit is high, for the standard output has its least significant bit set. Everytime a call is made
to $fopen a new handle is created with the next bit to the left is set to high. So the first call
would set the 2nd least significant bit, the second call would set the bit next to that, and so on.
Below is an example showing how to open files.

integer handleA, handleB; // an integer has 32 bits so is perfect


// for this usage

initial begin
handleA = $fopen("myfile.out);
// handleA = 0000_0000_0000_0000_0000_0000_0000_0010
handleB = $fopen("anotherfile.out");
// handleB = 0000_0000_0000_0000_0000_0000_0000_0100
end

Now we can write to any of the opened files. There is a maximum of 31 files open.

14.2 Writing to a file


Keywords: $fdisplay, $fmonitor, $fwrite
Syntax:
$fdisplay(<file_handles>, --same as display--);
$fmonitor(<file_handles>, --same as monitor--);
$fwrite(<file_handles>, --same as write--);
More than one channel can be specified by assigning the file_handles an integer with more
than one bit set. So for example if we wanted to write to standard output and to myfile as
described in the previous page, file_handles would be
0000_0000_0000_0000_0000_0000_0000_0011.
The example below illustrates the usage.

69
// using the handles described in the previous section

integer channelsA;

initial begin
channelsA = handleA | 1; // now th 2 MSBs are set to output
$fdisplay(channelsA, "Hello"); // will be to 'myfile' and
standard outut
end

14.3 Closing a file


Keywords: $fclose Syntax: $fclose(handle);
When using many files, it is normally a good idea to close any files that are no longer in use.
Once a file has been closed using $fclose it cannot be written to and another file can then use
the handle.

14.5 Initialising Memories


Keywords: $readmemb, $readmemh
Syntax:
$readmemb("<file_name>", <memory_name>");
$readmemb("<file_name>", <memory_name>, memory_start");
$readmemb("<file_name>", <memory_name>, memory_start, memory_finish");
The file_name and memory_nameare memory_start and memory_finish are optional, it
missed out they default to the start index of the named memory and the end of the named
memory respectively.
Memories can be stored in a file in the format shown below, the address is specified as @
<address>, where the address is in hexadecimal.

@003
00000011
00000100
00000101
00000110
00000111
00001000
00001001

With the above file it can be seen if the memory is large it would become very tedious to
work out the address of a specific byte, so it is normally a good idea to use milestones along
the memory file, so a larger file may look something like the following:

70
@003
00000011
00000100
00000101
@006
00000110
00000111
@008
00001000
00001001
or if the data is contiguous, omit the address entirely.
Now that a memory file exists to access it, it has to be initialised for memory reading. This
can be done by the following.

module testmemory;
reg [7:0] memory [9:0];
integer index;

initial begin
$readmemb("mem.dat", memory);

for(index = 0; index < 10; index = index + 1)


$display("memory[%d] = %b", index[4:0], memory[index]);
end
endmodule // testmemory

with the file mem.data as

1000_0001
1000_0010
0000_0000
0000_0001
0000_0010
0000_0011
0000_0100
0000_0101
0000_0110
0000_0000

71
EXERCISE
Store the above data in a file and run the above programme
Consider and understand the following code (run it to check):

module fileDemo;

integer handle, channels, index, rand;


reg [7:0] memory [15:0];

initial begin
handle = $fopen("mem.dat");
channels = handle | 1;
$display("Generating contents of file mem.dat");
$fdisplay(channels, "@2");

for(index = 0; index < 14; index = index + 1) begin


rand = $random;
$fdisplay(channels, "%b", rand[12:5]);
end

$fclose(handle);

$readmemb("mem.dat", memory);

$display("\nContents of memory array");


for(index = 0; index < 16; index = index + 1)
$displayb(memory[index]);
end

endmodule // fileDemo

72
A. Operator Precedence
If no parentheses are used to separate operands then Verilog uses the following rules of
precedence. It is normally a good idea to use parentheses to make expressions readable.
Below is a list of all operators provided by Verilog and their precedence rules.

List of Operators provided by Verilog


-----------------------------------------------------------
| Operator | Operator | Operation | Number of |
| Type | Symbol | | Operands |
-----------------------------------------------------------
| Arithmetic | * | multiply | two |
| | / | divide | two |
| | + | add | two |
| | - | subtract | two |
| | % | modulus | two |
-----------------------------------------------------------
| Logical | ! | logical negation | one |
| | && | logical and | two |
| | || | logical or | two |
-----------------------------------------------------------
| Relational | > | greater than | two |
| | < | less than | two |
| | >= | greater or equal | two |
| | <= | less or equal | two |
-----------------------------------------------------------
| Equality | == | equality | two |
| | != | inequality | two |
| | === | case equality | two |
| | !== | case inequality | two |
-----------------------------------------------------------
| Bitwise | ~ | bitwise negation | one |
| | & | bitwise and | two |
| | | | bitwise or | two |
| | ^ | bitwise xor | two |
| | ^~or~^ | bitwise xnor | two |
-----------------------------------------------------------
| Reduction | & | reduction and | one |
| | ~& | reduction nand | one |
| | | | reduction or | one |
| | ~| | reduction nor | one |
| | ^ | reduction xor | one |
| | ^~or^~ | reduction xnor | one |
-----------------------------------------------------------
| Shift | >> | right shift | two |
| | << | left shift | two |
----------------------------------------------- -----------
| Concatenation | {} | concatenation | any |
-----------------------------------------------------------
| Replication | {{}} | replication | any |
-----------------------------------------------------------
| Conditional | ?: | conditional | three |
-----------------------------------------------------------

73
Operator Precedence
-----------------------------------
| Operator | Precedence |
-----------------------------------
| + - ! ~ (unary) | highest |
| * / % | |
| + - (binary) | |
| << >> | |
| < <= > >= | |
| == != === !== | |
| & ~& | |
| ^ ^~ | |
| | ~| | |
| && | |
| || | |
| ?: (conditional) | lowest |
-----------------------------------

74
B. Keywords
Below is a list of keywords provided by verilog in alphabetical order.

always
and
assign
attribute
begin
buf
bufif0
bufif1
case
casex
casez
cmos
deassign
default
defpram
disable
edge
else
end
endattribute
endcase
endfunction
endmodule
endprimitive
endspecify
endtable
endtask
event
for
force
forever
fork
function
highz0
highz1
if
initial
inout
input
integer
join
large
macromodule
meduim
module
nand
negedge
nmos
nor
not
notif0
notif1
or

75
output
parameter
pmos
posedge
primitive
pull0
pull1
pulldown
pullup
rcmos
real
realtime
reg
release
repeat
rtranif1
scalared
signed
small
specify
specpram
strength
strong0
strong1
supply0
supply1
table
task
time
tran
tranif0
tranif1
tri
tri0
tri1
triand
trior
trireg
unsigned
vectored
wait
wand
weak0
weak1
while
wire
wor
xnor
xor

76
C. System Tasks and functions
The following are the system tasks and function provided by Verilog.

$bitstoreal
$countdrivers
$display
$fclose
$fdisplay
$fmonitor
$fopen
$fstrobe
$fwrite
$finish
$getpattern
$history
$incsave
$input
$itor
$key
$list
$log
$monitor
$monitoroff
$monitoron
$nokey

77
78
D. Net Types
The net types provided by Verilog are given below.

supply0
supply1
tri
triand
trior
trireg
tri0
tri1
wand
wire
wor

79
80
E. Verilog Input Vectors
To create input vectors for our simulations, we need only a very small subset of Verilog.
These pages give some examples

initial
begin
clk = 1'b0;
globalReset = 1'b1;
in = 1'b1;
end
The expression: 1'b0 indicates a binary number of value 0. In fact, for setting the values zero
and one, you need only type 0 and 1.
There are two main sections:
initial
begin
-----
end

always
begin
-----
end
Notice that "blocks" of code in Verilog are "bracketed" by the keywords begin and end - in C
this is done by "{" and "}".
The initial block is started at the beginning of the simulation. Thus it is the place to initialize
signals and to define a sequence of signal changes.
The always clock is a sequence of signals which is repeated throughout the simulation.
The delay between signal changes (or events) is specified by a number following a # sign.
Thus:

#160 globalReset = 0;
#160 in = 0;
#160 in = 1;
#320 in = 0;

says: wait 160 time units and set globalReset to zero, then wait 160 time units and set the in to
zero, then etc
Notice that the delay is measured from the last event rather than from the beginning of the
simulation.
The most common us of the always block is to define the clock signal. The following:

always
begin
#10 clk = ~clk;
end

81
says that clk should be set to the inverse of the value of clk every 10 time units - which
defines a clock signal of period 20 time units.
Thus the general approach is to setup the clock and other regularly alternating signals in
always blocks and to define the sequence of changing signals in the initial block.
Warning: it is wise to end the initial block with a statement:

#<delay> $finish;

This causes the simulation to finish at the end of the initial block - if this is not present, the
interactive simulation will continue until you press the interrupt button on the interactive
simulator panel (probably long after useful information has been produced).
The repeat command may be useful. If you have a sequence of signal changes with is repeated
for a given number (say 10) times then this can be coded as follows:

repeat(10)
begin
#40 in = 0;
#20 in = 1;
end

These repeat blocks may be nested.


One further command may be useful: a random number generator. The following produces
numbers in the range [0, n-1]:

{$random} % n

(The smudgy character is the percent sign "%" - which is difficult to read in some netscape
fonts).
The exception is random ones and zeros because some random number generators are not
quite random in the least significant bit (lsb). For this it is necessary to divide the first term by
an even number to remove the lsb before the modulus operation.

{$random} / 16 % 2

Combining these two commands we have the following which is a sequence of 14 random
inputs changing ever 20 time units:

repeat(14)
begin
#20 in = {$random} / 16 % 2;
end
Note:

• every statement (though not the blocks) must end with a ";"

82

S-ar putea să vă placă și