Sie sind auf Seite 1von 82

Verilog

Tutorial

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

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

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

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.

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

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

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

8'b-5 // illegal syntax

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

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

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

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.

its new value will not have to be explicitly assigned to it. If the drivers of

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.

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

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;

#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;

reg [0:3] b; // the declaration of vector width.

// it is important to adopt one convention for

EXERCISE

a) Declare an 8 bit wire with variable name address.

b) Assign 4'b1010 to its 4 most signficant bits.

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

// 1.3e27 a real number in scientific format

a real number in decimal 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.

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;

drive;

input

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

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.

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.

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

initial begin

a=2;

b=5;

c=2;

d=4'hx;

$display(a < b); $display(a > b);

// LHS less than RHS, evaluates to true, 1 // 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 = $display(c);

end endmodule // relatTest2

c + 1;

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.

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);

$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

// bitwise negation, evaluates to 4'b0011

end endmodule // bitTest

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);

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); $displayb(a >> 2);

end

endmodule // shiftTest

// shift left by 1, evaluates to 4'b0100 // shift right by 2, evaluates to 4'b0010

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;

end

$displayb({a, b});

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

// produces a 3-bit number 3'b100

endmodule // concatTest

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 reg [1:0] b; reg [5:0] c;

a;

initial begin

a = 1'b1;

b = 2'b00;

end

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

c = {4{a}};

$displayb(c);

// evaluates as 001111

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;

a;

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

reg

initial begin

a = 1'b1;

b = 2'b01;

c = {4{a}};

d = {b, c, b};

$displayb(d);

end

endmodule // replicTest2

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 |

--------------------

|

| tabulate |

| newline

\n |

\t |

| \\ |

print \

|

| \"

|

print "

|

| %% |

print %

|

--------------------

$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.

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

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.

three method, each a higher level of abstraction than the last. Below is a logic diagram

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);

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) |

cntrl2) |

(in2 & ~cntrl1 &

(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) |

cntrl2) |

(in2 & ~cntrl1 &

(in3 &

cntrl1 & ~cntrl2) |

(in4 &

cntrl1 & cntrl2);

endmodule

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

on. This is a construct containing statements which are only executed when any of the variables

it is clear what is going

"

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

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);

{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

of grouping statements which may run concurrently, since there is only one initial block in this example, its use is not fully illustrated.

end. This is a way

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.

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.

but this level of detail is sufficient for this section. There are two angles to approach

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

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; reset = 1'b1; #20 reset = 1'b0; data = 1'b1;

// initialize enable variable // the E type has an active high reset, so // we begin by resetting. // set the data HIGH

end

#10 enable = 1'b1; // and then enable data latching

#10 data = 1'b1; #20 data = 1'b0; #30 data = 1'b1; #10 data = 1'b0; #10 data = 1'b1;

#20 enable = 1'b0; // disable data latching

#10 data = 1'b0; #10 reset = 1'b1; #20 $finish;

// change the data value // change the data value // change the data value // change the data value // change the data value

// change the data value - no effect? // reset again // finally we must end the simulation using // $finish this also stops the clock

initial begin

$display($time, " reset, enable, data, q ");

$display($time, "

reset, enable, data, q); forever #10 $display($time, " reset, enable, data, q);

%d

%d

%d

%d",

%d

%d

end

endmodule // e_ffStimulus

%d

%d",

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

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.

ouput of the D-type relative to the E-type is shown below. module d_ff(q, d, reset, clock);

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;

input d, reset, clock; // as input or output reg q; // the ports can be declared again as required.

// all ports must be declared

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.

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

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.

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

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

end

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;

// waveform generation #20 alpha = 0; #5 alpha = 1; #7 alpha = 0; #10

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;

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

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

Below is a logic diagram for the binary counter. The commented Verilog description of the counter

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] input [3:0] d;

input load_data, global_reset, clock, increment;

q;

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]); and a3(t3, t2, q[2]);

// the previous increment signal by and-ing // with the output form the previous //ET-type

recog12 r1(see12, q);

// 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

// everytime the output changed this

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

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)

q = 0;

else q = data;

endmodule

// reset to 0, else it is set to data, which

// as we said earlier can be either data, q or ~q

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

Break down

module counter4_bit(q, d, increment, load_data, global_reset, clock); output [3:0] q;

input

input load_data, global_reset, clock, increment;

[3:0] d;

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.

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]

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

q;

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?].

// 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.

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

begin clock = 1'b0; forever #5 clock = ~clock; end This will make the clock flip

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

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;

@ (negedge clock) a = b;

a = @(posedge clock) b;

// when the clock changes value, execute a = b

// when the clock change to a 0, execute a=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) mem[0:1] = buf;

// event triggered block

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.

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);

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

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.

end

in example B and using an if statement in example C. end Figure A : Above

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 &

( cntrl2 &

cntrl1 & in3) |

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

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

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.

EXERCISE

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

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 The example below illustrates a while loop.

end.

/* 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

Notice the use of the "define" statement.

EXERCISE How many times does the folowing while loop say hello?

initial begin

a

c

= 5;

= 0;

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

end

end

c

=

c +

1;

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.

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;

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.

// 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 standard outut end

to

'myfile' and

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:

@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

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

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

handle, channels, index, rand;

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

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

|

-----------------------------------------------------------

Operator Precedence

-----------------------------------

| Operator

| Precedence |

-----------------------------------

| + - ! ~ (unary)

|

highest

|

| *

/

%

|

|

| + - (binary)

|

|

| << >>

 

|

|

| < <= > >=

|

|

| == != === !==

|

|

| & ~&

 

|

|

| ^ ^~

|

|

| ~|

|

|

|

| &&

|

|

| ||

|

|

| ?: (conditional)

|

lowest

|

-----------------------------------

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

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

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

D.

Net Types

The net types provided by Verilog are given below.

supply0

supply1

tri

triand

trior

trireg

tri0

tri1

wand

wire

wor

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

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