Digital Design and Verilog HDL Fundamentals
Digital Design and Verilog HDL Fundamentals
HDL
Digital
Design and
Modeling
254x178 HB
51547_FM.indd 2 1/22/07 3:29:44 PM
Verilog ®
HDL
Digital
Design and
Modeling
Joseph Cavanagh
Santa Clara University
This book contains information obtained from authentic and highly regarded sources. Reprinted material is quoted
with permission, and sources are indicated. A wide variety of references are listed. Reasonable efforts have been made to
publish reliable data and information, but the author and the publisher cannot assume responsibility for the validity of
all materials or for the consequences of their use.
No part of this book may be reprinted, reproduced, transmitted, or utilized in any form by any electronic, mechanical, or
other means, now known or hereafter invented, including photocopying, microfilming, and recording, or in any informa‑
tion storage or retrieval system, without written permission from the publishers.
For permission to photocopy or use material electronically from this work, please access www.copyright.com (http://
www.copyright.com/) or contact the Copyright Clearance Center, Inc. (CCC) 222 Rosewood Drive, Danvers, MA 01923,
978‑750‑8400. CCC is a not‑for‑profit organization that provides licenses and registration for a variety of users. For orga‑
nizations that have been granted a photocopy license by the CCC, a separate system of payment has been arranged.
Trademark Notice: Product or corporate names may be trademarks or registered trademarks, and are used only for
identification and explanation without intent to infringe.
TK7868.D5C395 2007
621.39’2‑‑dc22 2006052725
Preface xv
Chapter 1 Introduction 1
1.1 History of HDL 1
1.2 Verilog HDL 2
1.2.1 IEEE Standard 3
1.2.2 Features 3
1.3 Assertion Levels 3
Chapter 2 Overview 7
2.1 Design Methodologies 7
2.2 Modulo-16 Synchronous Counter 9
2.3 Four-Bit Ripple Adder 12
2.4 Modules and Ports 15
2.4.1 Designing a Test Bench for Simulation 16
2.4.2 Construct Definitions 20
2.5 Introduction to Dataflow Modeling 21
2.5.1 Two-Input Exclusive-OR Gate 22
2.5.2 Four 2-Input AND Gates with Delay 24
2.6 Introduction to Behavioral Modeling 26
2.6.1 Three-Input OR Gate 27
2.6.2 Four-Bit Adder 32
2.6.3 Modulo-16 Synchronous Counter 34
2.7 Introduction to Structural Modeling 37
2.7.1 Sum-of-Products Implementation 38
2.7.2 Full Adder 42
2.7.3 Four-Bit Ripple Adder 48
2.8 Introduction to Mixed-Design Modeling 56
2.8.1 Full Adder 56
2.9 Problems 60
Index 891
There are two dominant hardware description languages (HDLs): Verilog HDL and
Very High Speed Integrated Circuit (VHSIC) HDL (VHDL). Both are Institute of
Electrical and Electronics Engineers (IEEE) standards: Verilog IEEE standard 1364-
1995 and VHDL IEEE standard 1076-1993. Of the two hardware description lan-
guages, Verilog HDL is the most widely used. The Verilog language provides a
means to model a digital system at many levels of abstraction from a logic gate to a
complex digital system to a mainframe computer.
The purpose of this book is to present the complete Verilog language together
with a wide variety of examples so that the reader can gain a firm foundation in the
design of digital systems using Verilog HDL. The different modeling constructs sup-
ported by Verilog are described in detail. Numerous examples are designed in each
chapter, including both combinational and sequential logic.
The examples include counters of different moduli, half adders, full adders, a
carry lookahead adder, array multipliers, the Booth multiply algorithm, different
types of Moore and Mealy machines, including sequence detectors, a Hamming code
error detection and correction circuit, a binary-coded decimal (BCD) adder/subtrac-
tor, arithmetic and logic units (ALUs), and the complete design of a pipelined
reduced instruction set computer (RISC) processor. Also included are synchronous
sequential machines and asynchronous sequential machines, including pulse-mode
asynchronous sequential machines.
Emphasis is placed on the detailed design of various Verilog projects. The
projects include the design module, the test bench module, the outputs obtained from
the simulator, and the waveforms obtained from the simulator that illustrate the com-
plete functional operation of the design. Where applicable, a detailed review of the
theory of the topic is presented together with the logic design principles. This
includes state diagrams, Karnaugh maps, equations, and the logic diagram.
The book is intended to be tutorial, and as such, is comprehensive and self con-
tained. All designs are carried through to completion — nothing is left unfinished or
partially designed. Each chapter includes numerous problems of varying complexity
to be designed by the reader.
Chapter 1 provides a short history of HDLs and introduces Verilog HDL. Differ-
ent modeling constructs are presented as well as different ways to indicate the active
level (or assertion level) of a signal.
Chapter 2 presents an overview of Verilog HDL and discusses the different
design methodologies used in designing a project. The chapter is intended to intro-
duce the reader to the basic concepts of Verilog modeling techniques, including data-
flow modeling, behavioral modeling, and structural modeling. Examples are
xvi Preface
presented to illustrate the different modeling techniques. There is also a section that
incorporates more than one modeling construct into a mixed-design model. Later
chapters present these modeling constructs in more detail. The concept of ports and
modules is introduced in conjunction with the use of test benches for module design
verification.
Chapter 3 presents the language elements used in Verilog. These consist of com-
ments, identifiers, keywords, data types, parameters, and a set of values that deter-
mine the logic state of a net. Comments are placed in the Verilog code to explain the
function of a line of code or a block of code. Identifiers are names given to an object
or variable so that they can be referenced elsewhere in the module. Verilog provides
a list of predefined keywords that are used to define the language constructs. There
are two predefined data types: nets and registers. Nets connect logical elements; reg-
isters provide storage elements. Compiler directives are used to induce changes dur-
ing the compilation of a Verilog module.
Chapter 4 covers the expressions used in Verilog. Expressions consist of oper-
ands and operators, which are the basis of the language. Operands can be any of the
following data types: constant, parameter, net, register, bit-select, part-select, or a
memory element. Verilog contains a large set of operators that perform various oper-
ations on different types of data. The following categories of operators are available
in Verilog: arithmetic, logical, relational, equality, bitwise, reduction, shift, condi-
tional, concatenation, and replication.
Chapter 5 introduces gate-level modeling using built-in primitive gates. Verilog
has a profuse set of built-in primitive gates that are used to model nets, including
and, nand, or, nor, xor, xnor, and not, among others. This chapter presents a
design methodology that is characterized by a low level of abstraction, in which the
logic hardware is described in terms of gates. This is similar to designing logic by
drawing logic gate symbols. Gate delays are also introduced in this chapter. All
gates have a propagation delay, which is the time necessary for a signal to propagate
from the input terminals, through the internal circuitry, to the output terminal.
Examples of iterative networks and a priority encoder are presented as design exam-
ples using built-in primitives.
Chapter 6 covers user-defined primitives (UDPs), which are primitive logic
functions that are designed according to user specifications. These primitive func-
tions are usually at a higher level of abstraction than the built-in primitives. They are
independent primitives and do not instantiate other primitives or modules. They can
be used in the design of both combinational and sequential logic circuits. Sequential
primitives include level-sensitive and edge-sensitive circuits. Several design exam-
ples are included in this chapter, including a binary-to-Gray code converter, a full
adder designed from two half adders, multiplexers, a level-sensitive latch, an edge-
sensitive flip-flop, a modulo-8 counter, and a Moore finite-state synchronous sequen-
tial machine, among others.
Chapter 7 presents dataflow modeling, which is the first of three primary model-
ing constructs. Dataflow modeling is at a higher level of abstraction than either
built-in primitives or UDPs. Dataflow modeling uses the continuous assignment
statement to design combinational logic without employing logic gates and intercon-
necting wires. Design examples presented in this chapter include the use of
Preface xvii
Appendix A presents a brief discussion on event handling using the event queue.
Operations that occur in a Verilog module are typically handled by an event queue.
Appendix B presents a procedure to implement a Verilog project. Appendix C con-
tains the solutions to selected problems in each chapter.
The material presented in this book represents more than two decades of com-
puter equipment design by the author. The book is not intended as a text on logic
design, although this subject is reviewed where applicable. It is assumed that the
reader has an adequate background in combinational and sequential logic design.
The book presents the Verilog HDL with numerous design examples to help the
reader thoroughly understand this popular HDL.
This book is designed for practicing electrical engineers, computer engineers,
and computer scientists; for graduate students in electrical engineering, computer
engineering, and computer science; and for senior-level undergraduate students.
A special thanks to Dr. Ivan Pesic, CEO of Silvaco International, for allowing
use of the SILOS Simulation Environment software for the examples in this book.
SILOS is an intuitive, easy to use, yet powerful Verilog HDL simulator for logic ver-
ification.
I would like to express my appreciation and thanks to the following people who
gave generously of their time and expertise to review the manuscript and submit
comments: Professor Daniel W. Lewis, Chair, Department of Computer Engineering,
Santa Clara University who supported me in all my endeavors; Dr. Geri Lamble;
Steve Midford, who reviewed the entire manuscript and offered many helpful sug-
gestions and comments; and Ron Lewerenz. Thanks also to Nora Konopka and the
staff at Taylor & Francis for their support.
Joseph Cavanagh
1.1 History of HDL
1.2 Verilog HDL
1.3 Assertion Levels
1
Introduction
This book covers the design of combinational and sequential logic using the Verilog
hardware description language (HDL). An HDL is a method of designing digital hard-
ware by means of software. A considerable saving of time can be realized when de-
signing systems using an HDL. This offers a competitive advantage by reducing the
time-to-market for a system. Another advantage is that the design can be simulated
and tested for correct functional operation before implementing the system in hard-
ware. Any errors that are found during simulation can be corrected before committing
the design to expensive hardware implementation.
and waveforms. Many of these languages were proprietary and not placed in the
public domain. Verilog HDL is one of two primary hardware description languages.
The other main HDL is the Very High Speed Integrated Circuit (VHSIC) hardware de-
scription language (VHDL). VHDL was developed for the United States Department
of Defense and was created jointly by IBM, Texas Instruments, and Intermetrics. Al-
though VHDL has not achieved the widespread acceptance of Verilog, both are IEEE
standards.
HDLs allow the designer to easily and quickly express architectural concepts in a
precise notation without the aid of logic diagrams. All HDLs express the same fun-
damental concepts, but in slightly different notations.
Verilog HDL was developed by Phillip Moorby in 1984 as a proprietary HDL for
Gateway Design Automation. Gateway was later acquired by Cadence Design Sys-
tems, which placed the language in the public domain in 1990. The Open Verilog In-
ternational was then formed to promote the Verilog HDL language. In 1995, Verilog
was made an IEEE standard HDL (IEEE Standard 1364-1995) and is described in the
Verilog Hardware Description Language Reference Manual.
1.2.2 Features
Logic primitives such as AND, OR, NAND, and NOR gates are part of the Verilog
language. These are built-in primitives that can be instantiated into a module. The de-
signer also has the option of creating a user-defined primitive (UDP), which can then
be instantiated into a module in the same way as a built-in primitive. UDPs can be any
logic function such as a multiplexer, decoder, encoder, or flip-flop.
Different types of delays can be introduced into a logic circuit including: inter-
statement, intrastatement, inertial, and transport delays. These will be defined later in
the appropriate sections.
Designs can be modeled in three different modeling constructs: (1) dataflow, (2)
behavioral, and (3) structural. Module design can also be done in a mixed-design
style, which incorporates the above constructs as well as built-in and user-defined
primitives. Structural modeling can be described for any number of module instanti-
ations.
Verilog does not impose a limit to the size of the system; therefore, SILOS can be
used to design any size system. Verilog can be used not only to design all the modules
of a system, but also to design the test bench that is used for simulation.
Verilog also has available bitwise logic functions such as bitwise AND (&) and
bitwise OR ( | ). High-level programming language constructs such as multiway
branching (case statements), conditional statements, and loops are also available.
level for the variables; that is, the logical 1 (or true) state, in contrast to the logical 0
(or false) state.
Thus, a signal can be asserted either plus or minus, depending upon the active
condition of the signal at that point. For example, Figure 1.1(a) specifies that the
AND function will be realized when both input A and input B are at their more posi-
tive potential, thus generating an output at its more positive potential. The word pos-
itive as used here does not necessarily mean a positive voltage level, but merely the
more positive of two voltage levels. Therefore, the output of the AND gate of Figure
1.1(a) can be written as + (A & B).
To illustrate that a plus level does not necessarily mean a positive voltage level,
consider two logic families: transistor-transistor logic (TTL) and emitter-coupled
logic (ECL). The TTL family uses a + 5 volt power supply. A plus level is approxi-
mately + 3.5 volts and above; a minus level is approximately + 0.2 volts. The ECL
family uses a – 5.2 volt power supply. A plus level is approximately – 0.95 volts; a
minus level is approximately – 1.7 volts. Although – 0.95 volts is a negative voltage,
it is the more positive of the two ECL voltages.
The logic symbol of Figure 1.1(b) is a NAND gate in which inputs A and B must
both be at their more positive potential for the output to be at its more negative
potential. A small circle (or wedge symbol for IEEE std 91-1984 logic functions) at
the input or output of a logic gate indicates a more negative potential. The output of
the NAND gate can be written as – (A & B).
Figure 1.1(c) illustrates a NOR gate used for the AND function. In this case,
inputs A and B must be active (or asserted) at their more negative potential in order
for the output to be at its more positive potential. The output can be written as + (A &
B). A variable can be active (or asserted) at a high and a low level at the same time,
as shown in Figure 1.2.
Figure 1.1(d) shows a NAND gate used for the OR function. Either input A or B
(or both) must be at its more negative potential to assert the output at its more posi-
tive potential. The output can be written as + (A | B), where the symbol ( | ) indicates
the OR operation in Verilog.
1.3 Assertion Levels 5
+A
+A
+B +(A & B) +B
+(A & B)
(a)
+A
+A –(A & B)
+B +B
–(A & B)
(b)
–A
–A +(A & B) –B
–B
+(A & B)
(c)
–A
–A –B
–B +(A | B)
+(A | B)
(d)
Figure 1.1 Logic symbols and waveforms for AND, NAND, NOR, and NAND
(negative-input OR).
y1
D +y1
> –y1
+x1
+x1 –x1
Figure 1.2 Signals can be active high and low at the same time.
51547_FM.indd 2 1/22/07 3:29:44 PM
2.1 Design Methodologies 2.6 Introduction to Behavioral
2.2 Modulo-16 Synchronous Modeling
Counter 2.7 Introduction to Structural
2.3 Four-Bit Ripple Adder Modeling
2
2.4 Modules and Ports 2.8 Introduction to Mixed-
2.5 Introduction to Dataflow Design Modeling
Modeling 2.9 Problems
Overview
This chapter provides a brief introduction to the design methodologies and modeling
constructs of the Verilog hardware description language (HDL). Modules and ports
will be presented. Modules are the basic units that describe the design of the Verilog
hardware. Ports allow the modules to communicate with the external environment;
that is, other modules and input/output signals. Different methods will be presented
for designing test benches. Test benches are used to apply input vectors to the module
in order to test the functional operation of the module in a simulation environment.
Three module constructs will be described together with applications of each type
of module. The different modules are: dataflow modeling, behavioral modeling, and
structural modeling. Examples will be shown for each type of modeling. There will
also be an introduction to mixed-design modeling, which uses a combination of the
three main modeling techniques.
These become the building blocks with which to design the next higher level. The
blocks from each level become the building blocks for the next higher level. This pro-
cess continues until the top level is reached.
Top-level block
Top-level block
The system architect defines the specifications for the machine in the top-level
block; for example, a pipelined reduced instruction set computer (RISC). The second-
level blocks would consist of the different units in the computer such as instruction
cache, instruction unit, decode unit, execution unit, register file, and data cache. The
bottom level consists of the hardware in each of the six units.
For example, the instruction cache contains a program counter and an increment-
er. The decode unit contains hardware to decode the instruction into its constituent
parts such as operation code, source address, and destination address. The execution
unit contains the arithmetic and logic unit and associated registers and multiplexers.
The D flip-flop input logic blocks will now be expanded to show more detail.
These blocks represent the logic for the input equations of the D flip-flops. The equa-
tions will be obtained using Karnaugh maps in the traditional manner. Using the
10 Chapter 2 Overview
counting sequence shown above, the Karnaugh maps are illustrated in Figure 2.4. The
equations for the D flip-flops are shown in Equation 2.1. The logic diagram, obtained
from the D flip-flop input equations, is shown in Figure 2.5.
y1 y0 y1 y0
y3 y2 00 01 11 10 y3 y2 00 01 11 10
0 1 3 2 0 1 3 2
00 0 0 0 0 00 0 0 1 0
4 5 7 6 4 5 7 6
01 0 0 1 0 01 1 1 0 1
12 13 15 14 12 13 15 14
11 1 1 0 1 11 1 1 0 1
8 9 11 10 8 9 11 10
10 1 1 1 1 10 0 0 1 0
Dy3 Dy2
y1 y0 y1 y0
y3 y2 00 01 11 10 y3 y2 00 01 11 10
0 1 3 2 0 1 3 2
00 0 1 0 1 00 1 0 0 1
4 5 7 6 4 5 7 6
01 0 1 0 1 01 1 0 0 1
12 13 15 14 12 13 15 14
11 0 1 0 1 11 1 0 0 1
8 9 11 10 8 9 11 10
10 0 1 0 1 10 1 0 0 1
Dy1 Dy0
The reconfigured top-down design is illustrated in Figure 2.6 showing more detail
for the bottom-level leaf nodes. The leaf nodes represent the input logic for the D flip-
flops. The input logic is obtained by designing the appropriate gates as separate
2.2 Modulo-16 Synchronous Counter 11
modules and then instantiating the modules into the structural module that represents
the modulo-16 synchronous counter. Modules for the 2-input, 3-input, and 4-input
AND gates are labeled AND2, AND3, and AND4, respectively. Modules for the 3-in-
put and 4-input OR gates are labeled OR3 and OR4, respectively. There is one exclu-
sive-OR gate module labeled XOR2.
+Clock
+y3
–y2
–y1 y3
D +y3
–y0
–y3 > –y3
+y2
+y1
+y0
+y2
–y1 y2
–y0 D +y2
–y2
+y1 > –y2
+y0
y1
D +y1
> –y1
y0
–y0 D +y0
> –y0
The truth tables for a half adder and full adder are shown in Table 2.1 and Table
2.2, respectively. The corresponding equations are listed in Equation 2.2 and Equation
2.3. The logic diagram for the half adder is shown in Figure 2.8 and for the full adder
in Figure 2.9.
Half Half OR2 Half Half OR2 Half Half OR2 Half Half OR2
adder adder adder adder adder adder adder adder
+a
+b +sum
+cout
+cin
+cout
A Verilog module defines the information that describes the relationship between
the inputs and outputs of a logic circuit. A structural module will have one or more in-
stantiations of other modules or logic primitives. In Figure 2.11, the first line is a com-
ment, indicated by (//). In the second line, and2 is the module name; this is followed
by left and right parentheses containing the module ports, which is followed by a
16 Chapter 2 Overview
semicolon. The inputs and outputs are defined by the keywords input and output.
The ports are declared as wire in this dataflow module. Dataflow modeling is covered
in detail in Chapter 7. The keyword assign describes the behavior of the circuit. Out-
put z1 is assigned the value of x1 ANDed (&) with x2 . This continuous assignment
statement is discussed in detail in Chapter 7.
endmodule
Figure 2.11 Verilog module for an AND gate with two inputs.
This section describes the techniques for writing test benches in Verilog HDL. When
a Verilog module is finished, it must be tested to ensure that it operates according to
the machine specifications. The functionality of the module can be tested by applying
stimulus to the inputs and checking the outputs. The test bench will display the inputs
and outputs in a radix (binary, octal, hexadecimal, or decimal) as well as the wave-
forms. It is good practice to keep the design module and test bench module separate.
The test bench contains an instantiation of the unit under test and Verilog code to
generate input stimulus and to monitor and display the response to the stimulus. Fig-
ure 2.12 shows a simple test bench to test the 2-input AND gate of Figure 2.11. Line
1 is a comment indicating that the module is a test bench for a 2-input AND gate. Line
2 contains the keyword module followed by the module name, which includes tb in-
dicating a test bench module. The name of the module and the name of the module un-
der test are the same for ease of cross-referencing.
Line 4 specifies that the inputs are reg type variables; that is, they contain their
values until they are assigned new values. Outputs are assigned as type wire in test
benches. Output nets are driven by the output ports of the module under test. Line 7
contains an initial statement, which executes only once. Verilog provides a means to
2.4 Modules and Ports 17
monitor a signal when its value changes. This is accomplished by the $monitor task.
The $monitor continuously monitors the values of the variables indicated in the pa-
rameter list that is enclosed in parentheses. It will display the value of the variables
whenever a variable changes state. The quoted string within the task is printed and
specifies that the variables are to be shown in binary (%b). The $monitor is invoked
only once. Line 11 is a second initial statement that allows the procedural code be-
tween the begin . . . end block statements to be executed only once.
//display variables
initial
$monitor ("x1 = %b, x2 = %b, z1 = %b", x1, x2, z1);
#10 x1 = 1'b1;
20 x2 = 1'b0;
#10 x1 = 1'b1;
x2 = 1'b1;
25 #10 $stop;
end
endmodule
Figure 2.12 Test bench for the 2-input AND gate of Figure 2.11.
18 Chapter 2 Overview
Lines 13 and 14 specify that at time 0 (#0), inputs x1 and x2 are assigned values of
0, where 1 is the width of the value (one bit), ' is a separator, b indicates binary, and 0
is the value. Line 16 specifies that 10 time units later, the inputs change to: x1 = 0 and
x2 = 1. This process continues until all possible values of two variables have been ap-
plied to the inputs. Simulation stops at 10 time units after the last input vector has been
applied ($stop). The total time for simulation is 40 time units — the sum of all the
time units.
Line 29 begins the instantiation of the module into the test bench. The name of the
instantiation must be the same as the module under test, in this case, and2. This is fol-
lowed by an instance name (inst1) followed by a left parenthesis. The . x1 variable in
line 30 refers to a port in the module that corresponds to a port (x1 ) in the test bench.
All the ports in the module under test must be listed. The keyword endmodule is the
last line in the test bench.
The binary outputs for this test bench are shown in Figure 2.13 and the waveforms
in Figure 2.14. The output can be presented in binary (b or B), in octal (o or O), in
hexadecimal (h or H), or in decimal (d or D). The waveforms show the values of the
input and output variables at the specified simulation times. Notice that the inputs
change value every 10 time units and that the duration of simulation is 40 time units.
The time units can be specified for any duration.
The Verilog syntax will be covered in greater detail in subsequent chapters. It is
important at this point to concentrate on how the module under test is simulated and in-
stantiated into the test bench.
x1 = 0, x2 = 0, z1 = 0
x1 = 0, x2 = 1, z1 = 0
x1 = 1, x2 = 0, z1 = 0
x1 = 1, x2 = 1, z1 = 1
Figure 2.13 Binary outputs for the test bench of Figure 2.12 for a 2-input AND
gate.
Figure 2.14 Waveforms for the test bench of Figure 2.12 for a 2-input AND gate.
2.4 Modules and Ports 19
initial
begin
#0 clk = 0;
#5 clk = 1;
#5 clk = 0;
#20 clk = 1;
#5 clk = 0;
#20 clk = 1;
#5 clk = 0;
#10 $stop;
end
endmodule
Figure 2.15 Verilog code to generate clock pulses with a 20% duty cycle.
Figure 2.16 Waveform showing clock pulses with a 20% duty cycle.
20 Chapter 2 Overview
In Figure 2.15, the clock begins at time 0 with a value of 0. Five time units later,
the clock is assigned a value of 1; five time units later (at time 10), the clock goes low
(0), 20 time units later (at time 30), the clock goes high (1); five time units later (at time
35), the clock is again assigned a value of 0. It is important to note that the times spec-
ified in the code are accumulative; that is, when the clock goes low five time units after
the second pulse, this occurs at time 35. Simulation stops at time 70, 10 time units af-
ter the last pulse goes low.
Before introducing dataflow, behavioral, structural, and mixed modeling tech-
niques, some definitions will be presented. These definitions fall into the general cat-
egory of procedural constructs.
Whenever the value of a variable in the right-hand side expression changes, the
right-hand side is evaluated and the value is assigned to the left-hand side after any
specified delay. That is, the right-hand side creates a value that is assigned to the target
variable. The delay specifies the time duration between the time a variable on the
right-hand side changes and the time the new value is assigned to the left-hand side.
Blocking statement Blocking assignments are used only when describing com-
binational logic in a procedural block. Blocking assignment statements are executed
in the order in which they are listed in a procedural block. In a blocking assignment
statement, the assignment to the left-hand side variable takes place before the follow-
ing statement in the sequential block is executed. The symbol that represents a block-
ing statement is (=).
For example, the 2-input AND gate shown in the Verilog code of Figure 2.11 uses
the continuous assignment statement to assign a value to z1 whenever x1 or x2 changes
value (assign z1 = x1 & x2 ;). Since no delay is specified, the default value is zero de-
lay.
This section presents the design of a 2-input exclusive-OR gate using dataflow mod-
eling. The circuit is shown in Figure 2.17 and the Verilog code is in Figure 2.18. Note
that the symbol for the exclusive-OR function is the caret.
+x1
+x2 +z1
assign z1 = x1 ^ x2;
endmodule
Figure 2.18 Verilog code for the 2-input exclusive-OR gate of Figure 2.17.
The test bench for the exclusive-OR gate will be different than the one shown in
Figure 2.12 for the 2-input AND gate. Several new modeling constructs are shown in
the exclusive-OR test bench of Figure 2.19. Since there are two inputs to the exclu-
sive-OR gate, all four combinations of two variables must be applied to the circuit.
This is accomplished by a for-loop statement, which is similar in construction to a for
loop in the C programming language.
2.5 Introduction to Dataflow Modeling 23
Following the keyword begin is the name of the block: apply_stimulus. In this
block, a 3-bit reg variable is declared called invect. This guarantees that all combina-
tions of the two inputs will be tested by the for loop, which applies input vectors of
x1 x2 = 00, 01, 10, 11 to the circuit. The for loop stops when the pattern 100 is detected
by the test segment (invect < 4). If only a 2-bit vector were applied, then the expres-
sion (invect < 4) would always be true and the loop would never terminate. The in-
crement segment of the for loop does not support an increment designated as
invect++; therefore, the long notation must be used: invect = invect + 1.
The target of the first assignment within the for loop ({x1 , x2 } = invect [2:0]) rep-
resents a concatenated target. The concatenation of inputs x1 and x2 is performed by
positioning them within braces: {x1 , x2 }. A vector of three bits ([2:0]) is then assigned
to the inputs. This will apply inputs of 00, 01, 10, 11, and stop when the vector is 100.
The initial statement also contains a system task ($display) which prints the ar-
gument values — within the quotation marks — in binary. The concatenated vari-
ables x1 and x2 are listed first; therefore, their values are obtained from the first
argument to the right of the quotation marks: {x1 , x2 }. The value for the second vari-
able z1 is obtained from the second argument to the right of the quotation marks. The
delay time (#10) in the system task specifies that the task is to be executed after 10 time
units; that is, the delay between the application of a vector and the response of the
module. This delay represents the propagation delay of the logic. The simulation re-
sults are shown in binary format in Figure 2.20 and the waveforms in Figure 2.21.
Figure 2.19 Test bench for the 2-input exclusive-OR gate module of Figure 2.18.
24 Chapter 2 Overview
{x1x2} = 00, z1 = 0
{x1x2} = 01, z1 = 1
{x1x2} = 10, z1 = 1
{x1x2} = 11, z1 = 0
Figure 2.20 Binary outputs for the test bench of Figure 2.19.
Figure 2.21 Waveforms for the 2-input exclusive-OR gate test bench of Figure
2.19.
assign #5 z1 = x1 & x2 ;
2.5 Introduction to Dataflow Modeling 25
The #5 indicates five time units. Whenever x1 or x2 changes value, the right-hand ex-
pression is evaluated and the value is assigned to the left-hand variable z1 after five
time units. The actual unit of time is specified by the `timescale compiler directive.
For example, the statement
indicates that one time unit is specified as 10 nanoseconds (ns) with a precision of 100
picoseconds (ps). This property is called inertial delay.
Figure 2.22 illustrates a logic circuit with four 2-input AND gates. Two scalars —
x1 and x2 — are specified as the inputs; the output of the circuit is a vector of four
bits: z1, where z1 = z1[0], z1[1], z1[2], and z1[3]. Figure 2.23 shows the Verilog code
for Figure 2.22 using a time unit of 10 ns with a precision of 1 ns.
When input x1 or x2 changes value, the new value of the right-hand statement is
assigned to the left-side after a delay of 20 ns. The test bench of Figure 2.24 lists six
sets of vectors to be assigned to the inputs. The resulting waveforms are shown in Fig-
ure 2.25. Note that when x1 or x2 changes state, the output of the circuit is delayed by
20 ns.
–x1
–x2 +z1[0]
–x1
+x2 +z1[1]
+x1
–x2 +z1[2]
+x1
+x1 +z1[3]
Figure 2.22 Four 2-input AND gates with scalar inputs and a vector output.
Figure 2.23 Verilog code for the logic circuit of Figure 2.22.
26 Chapter 2 Overview
endmodule
initial #5 x1 = 1'b0;
$monitor ("x1 x2=%b, z1=%b", x2 = 1'b0;
{x1, x2}, z1);
#5 $stop;
//apply input vectors end
initial
begin //instantiate the module
#0 x1 = 1'b0; //into the test bench
x2 = 1'b0; four_and_delay inst1 (
.x1(x1),
#5 x1 = 1'b1; .x2(x2),
x2 = 1'b0; .z1(z1)
);
#5 x1 = 1'b1;
x2 = 1'b1; endmodule
Figure 2.24 Test bench for the Verilog code of Figure 2.23 for the circuit of
Figure 2.22.
Figure 2.25 Waveforms for the four AND gates with delay using the test bench of
Figure 2.24.
Figure 2.26 shows a 3-input OR gate, which will be designed using behavioral mod-
eling. The behavioral module is shown in Figure 2.27 using an always statement. The
expression within the parentheses is called an event control or sensitivity list. When-
ever a variable in the event control list changes value, the statements in the begin . . .
end block will be executed; that is, if either x1 or x2 or x3 changes value, the following
statement will be executed:
z1 = x1 | x2 | x3 ;
+x1
+x2 +z1
+x3
The test bench for the module is shown in Figure 2.28. As stated previously, the
inputs for a test bench are of type reg because they retain their value until changed, and
the outputs are of type wire. To ensure that all eight combinations of the inputs are
tested, a register vector called invect is specified as four bits: 3 through 0, where bit 0
is the low-order bit. This guarantees that a vector of x1 x2 x3 = 111 will be applied to
the OR gate inputs. The inputs are applied in sequence, x1 x2 x3 = 000 through 111.
When an input vector of x1 x2 x3 = 1000 is reached, the test in the for loop returns a val-
ue of false and the simulator exits the statements in the begin . . . end sequence.
The binary outputs of the simulator are shown in Figure 2.29 listing the output value
for z1 for all combinations of inputs. The waveforms are shown in Figure 2.30.
endmodule
Figure 2.27 Behavioral module for the 3-input OR gate of Figure 2.26.
The statements within the sequential block are called blocking statements because
execution of the following statement is blocked until the current statement completes
execution; that is, the statements within a sequential block execute sequentially. An
2.6 Introduction to Behavioral Modeling 29
optional delay may be associated with a procedural assignment. There are two types
of delays: interstatement and intrastatement.
endmodule
Figure 2.28 Test bench for the 3-input OR gate module of Figure 2.27.
{x1x2x3} = 000, z1 = 0
{x1x2x3} = 001, z1 = 1
{x1x2x3} = 010, z1 = 1
{x1x2x3} = 011, z1 = 1
{x1x2x3} = 100, z1 = 1
{x1x2x3} = 101, z1 = 1
{x1x2x3} = 110, z1 = 1
{x1x2x3} = 111, z1 = 1
Figure 2.29 Binary outputs for the test bench of Figure 2.28.
30 Chapter 2 Overview
Figure 2.30 Waveforms for the test bench of Figure 2.28 for the 3-input OR gate
module of Figure 2.26.
z1 = x1 | x2
#5 z2 = x1 & x2
When the first statement has completed execution, a delay of five time units will
be taken before executing the second statement. An intrastatement delay is a delay on
the right-hand side of the statement and indicates that the right-hand side is to be eval-
uated, wait the specified number of time units, and then assign the value to the left-
hand side. This can be used to simulate logic gate delays. The following is an example
of an intrastatement delay:
z1 = #5 x1 & x2
The statement evaluates the logical function x1 AND x2 , waits five time units, then as-
signs the result to z1. If no delay is specified in a procedural assignment, then zero de-
lay is the default delay and the assignment occurs instantaneously.
2.6 Introduction to Behavioral Modeling 31
initial
begin
x1 = #0 1'b0;
x2 = #0 1'b0;
x1 = #1 1'b1;
x2 = #0.5 1'b1;
x1 = #1 1'b0;
x2 = #2 1'b0;
x1 = #1 1'b1;
x2 = #2 1'b1;
x1 = #2 1'b0;
x2 = #1 1'b0;
end
endmodule
The top-down structural architecture of a 4-bit ripple adder was shown in Section 2.3.
A similar 4-bit adder will now be designed using behavioral modeling to illustrate the
differences between the two modeling techniques. Figure 2.33 depicts the block dia-
gram of the adder, but does not indicate the internal logic. Figure 2.34 shows the be-
havioral module for the 4-bit adder. Note that only the behavior of the adder is
specified, not the internal logic elements as in the structural architecture. The behavior
is specified as:
sum = a + b + cin
The behavioral module does not indicate the specifics as to how to design the adder;
the Verilog code simply specifies the functionality of the module. Also, the sum vari-
able is specified as a 5-bit vector to include the carry-out of the adder. The augend
a[3:0] and addend b[3:0] remain as 4-bit vectors with the carry-in (cin) as a scalar.
Four-bit adder
a [3:0] a
b [3:0] b sum sum [4:0]
cin cin
Inputs are declared as type wire and outputs as type reg in behavioral modeling.
Operands a and b are specified as 4-bit vectors: a[3], . . . , a[0] and b[3], . . . , b[0],
where a[0] and b[0] are the low-order bits of a and b, respectively. The always state-
ment continuously checks for a change of value to the operands and the carry-in. If a
or b or cin change value, then the statement in the begin . . . end block is executed. The
right-hand side of the expression is evaluated and then assigned to sum.
The test bench is shown in Figure 2.35, in which six sets of input vectors are ap-
plied to the operands. The binary outputs obtained from the test bench are shown in
Figure 2.36 and the corresponding waveforms in Figure 2.37. The values of operands
a, b, and sum are given in hexadecimal. By double-clicking the sum[4:0] entry in the
SILOS Data Analyzer, the individual bits of the sum can be displayed.
2.6 Introduction to Behavioral Modeling 33
Figure 2.35 Test bench for the 4-bit adder module of Figure 2.34.
34 Chapter 2 Overview
Figure 2.36 Binary outputs for the 4-bit adder obtained from the test bench of Fig-
ure 2.35.
Figure 2.37 Waveforms for the 4-bit adder module of Figure 2.34.
Figure 2.5 showed the gate-level design of a modulo-16 synchronous counter. The
same counter will now be designed using behavioral modeling. This is a much simpler
approach because the counter is not designed using Karnaugh maps and equations to
provide discrete logic gates and flip-flops. Also, the storage elements are not speci-
fied. Verilog is simply given the counting sequence; the counter is then designed by
Verilog according to the specifications. Figure 2.38 shows the symbol for the modulo-
16 counter.
2.6 Introduction to Behavioral Modeling 35
Modulo-16
counter count [0]
clock > count [1]
count [3:0]
count [2]
rst_n reset count [3]
The Verilog module is shown in Figure 2.39 using nonblocking statements in the
procedural block. There are three ports: clk, rst_n, and count, which is defined as a 4-
bit vector, where count [0] is the low-order bit. The always statement contains two
events in the sensitivity list: posedge clk and negedge rst_n. When the system clock
transitions from a low level to a high level, the counter is incremented. The % symbol
indicates a modulus or remainder such that the counter increments from 0 to 15, then
begins again at a count of 0. The variable rst_n is the conventional way to indicate an
active-low reset signal. If the reset signal is at a low voltage level, then the counter is
reset to a value of count = 0000.
The test bench is shown in Figure 2.40. When a change occurs on count, the
&monitor task will display the current count as a binary value. The reset signal is
conditioned to an active-low level for five time units initially, then made inactive five
time units later. The clock signal is initially set to 0, then alternates between positive
and negative levels indefinitely. This is accomplished by the keyword forever, which
assigns the clock the value of the complemented clock every 10 time units. The du-
ration of simulation is defined to be 320 time units, which is sufficient duration to gen-
erate a counting sequence of 0000, . . . . , 1111, 0000 to show the modulo-16 counting
sequence.
The binary outputs are shown in Figure 2.41 as obtained from the $monitor task
in the test bench. The waveforms are shown in Figure 2.42 and indicate the same
counting sequence, but in hexadecimal notation. By clicking the (+) sign to left of the
count [3:0] signal name or by double-clicking the count [3:0] signal name, the indi-
vidual bits of the counter are obtained.
//define clock
initial
begin
#0 clk = 1'b0;
forever
#10clk = ~clk;
end
Figure 2.40 Test bench for the modulo-16 counter of Figure 2.39.
2.7 Introduction to Structural Modeling 37
Figure 2.41 Binary outputs for the modulo-16 counter of Figure 2.39 obtained
from the test bench of Figure 2.40.
Figure 2.42 Waveforms for the modulo-16 counter of Figure 2.39 obtained from
the test bench of Figure 2.40.
This section will implement the sum-of-products expression of Equation 2.4 using
structural modeling. The structural module will instantiate the following four sub-
modules: and2, and3, and4, and or3 as shown in Figure 2.43. The ports of the sub-
modules are indicated by small black squares and correspond to the port names in the
respective modules. The module name is shown outside the dashed line and the
instance name associated with the module is shown within the dashed line. The struc-
tural module is called sop.
The modules for and2, and3, and4, and or3 are shown in Figure 2.44. The struc-
tural module is shown in Figure 2.45, which instantiates the four sub-modules. The
instantiation modules and the instance names directly correspond to those shown in
Figure 2.43. For example, in instance 2 of the structural module, port . x1 of the and3
module connects to x2 (+x2 ) of the structural module; port . x2 connects to ~x3 (–x3 ),
port . x3 connects to x4 (+x4 ); and port . z1 connects to net2. This represents the port
connections and internal nets of the structural module. The structural module test
bench is shown in Figure 2.46.
sop
and2
inst1
+x1 x1 z1 net1
+x2 x2
and3 or3
inst2 inst4
x1 x1
x2 z1 net2 x2 z1 net4
–x3 x3 x3 +z1
+x4
and4
inst3
x1
–x1 x2
–x2 x3 z1 net3
+x3 x4
Figure 2.43 Structural module for the sum-of-products equation of Equation 2.4.
2.7 Introduction to Structural Modeling 39
Figure 2.44 Modules for and2, and3, and4, and or3 that will be instantiated into
the sum-of-products structural module of Figure 2.45.
The binary values for output z1 as obtained from the test bench are shown in Fig-
ure 2.47 for all combinations of the input variables. Output z1 is a logical 1 for the con-
ditions that satisfy Equation 2.4 and can be verified by the Karnaugh map of Figure
2.48. The resulting waveforms are shown in Figure 2.49.
Figure 2.45 Structural module for the sum-of-products equation of Equation 2.4.
40 Chapter 2 Overview
endmodule
Figure 2.46 Test bench for the structural module of Figure 2.45.
2.7 Introduction to Structural Modeling 41
Figure 2.47 Binary outputs for the test bench of Figure 2.46.
x3 x4
x1 x2 00 01 11 10
00 0 0 1 0
01 0 1 0 0
11 1 1 1 1
10 0 0 0 0
z1
Figure 2.48 Karnaugh map for the sum-of-products expression of Equation 2.4.
42 Chapter 2 Overview
Figure 2.49 Waveforms for Figure 2.45 using the test bench of Figure 2.46.
A full adder will now be synthesized with two half adders and an OR gate using struc-
tural modeling. Recall that a full adder can be designed using a top-down approach as
shown in Figure 2.50. The equations for a half adder and a full adder are shown in
Equation 2.5 and 2.6, respectively, and the corresponding gate level designs in Figure
2.51 and Figure 2.52.
Full adder
XOR2 XOR2
AND2 AND2
Figure 2.50 Top-down design for a full adder using two half adders.
2.7 Introduction to Structural Modeling 43
sum = a ⊕ b
cout = ab (2.5)
sum = a ⊕ b ⊕ cin
cout = cin (a ⊕ b) + ab (2.6)
half_adder_df
+a
+b +sum
+cout
Figure 2.51 Logic diagram for a half adder to be instantiated into a full adder
structural design.
full_adder_struc
half_adder_df
half_adder_df
inst1
+a ha_sum[1] inst2
ha_sum[0]
+b +sum
ha_cy[1]
ha_cy[0]
+cin
+cout
Figure 2.52 Logic diagram for a full adder using two half adders instantiated into
a structural module.
44 Chapter 2 Overview
The half adder module is named half_adder_df, which is then instantiated two
times into the structural module full_adder_struc. In the full adder module, internal
wires are specified for the sum and carry-out of the two half adders. The sum from the
two half adders is a 2-bit vector with bits named ha_sum[1] and ha_sum[0], where bit
0 is the low-order bit. The carry-out from the two half adders is a 2-bit vector with bits
named ha_cy[1] and ha_cy[0], where bit 0 is the low-order bit.
The Verilog code for the half adder is shown in Figure 2.53, where the symbol (^)
is the exclusive-OR function and (&) is the AND function. As stated previously, all
modules that are to be instantiated into a structural module should be tested for correct
functional operation before they are instantiated. The test bench for the half adder is
shown in Figure 2.54 in which all combinations of the two operands are applied to the
inputs.
The $monitor system task continuously monitors the values of the variables spec-
ified in the parameter list. When any of the variables change value, all of the variables
are displayed. The test bench displays the variables in the binary radix (%b). The re-
sulting binary outputs are shown in Figure 2.55. The $stop task provides a stop during
simulation. System tasks are covered in detail in Chapter 10. The waveforms shown
in Figure 2.56 display the binary variables in a graphical representation.
The full adder structural module is shown in Figure 2.57. In instantiation inst1, in-
put port .a of the half adder connects to input a (+a) of the full adder structural module
and port .b connects to input b (+b). The output port .sum connects to net ha_sum[1]
in the structural module, which is an output of the half adder and declared as a wire.
The carry-out cout of the half adder connects to net ha_cy[1] in the structural module.
In instantiation inst2, input port .a of the half adder connects to net ha_sum[1] and
port .b connects to input cin (+cin) of the full adder module. The sum and cout ports of
the half adder connect to nets ha_sum[0] and ha_cy[0] of the full adder, respectively.
The two continuous assignment statements assign output sum of the full adder the val-
ue of ha_sum[0] and cout the value of the logical OR of ha_cy[0] and ha_cy[1].
//dataflow half_adder
module half_adder_df (a, b, sum, cout);
assign sum = a ^ b;
assign cout = a & b;
endmodule
Figure 2.53 Verilog code for the half adder of Figure 2.51.
2.7 Introduction to Structural Modeling 45
initial
$monitor ("ab = %b, sum = %b, cout = %b",
{a, b}, sum, cout);
initial
begin
#0 a = 1'b0;
b = 1'b0;
#10a = 1'b0;
b = 1'b1;
#10a = 1'b1;
b = 1'b0;
#10a = 1'b1;
b = 1'b1;
#10 $stop;
end
Figure 2.54 Test bench for the half adder module of Figure 2.53.
Figure 2.55 Binary outputs obtained from the test bench of Figure 2.54 for the half
adder module of Figure 2.53.
46 Chapter 2 Overview
input a, b, cin;
output sum, cout;
half_adder_df inst2 (
.a(ha_sum[1]),
.b(cin),
.sum(ha_sum[0]),
.cout(ha_cy[0])
);
endmodule
The test bench for the full adder structural module is shown in Figure 2.58 in
which all possible combinations of three variables are applied to the inputs. The bi-
nary outputs are shown in Figure 2.59 and the waveforms in Figure 2.60.
#10a = 1'b0;
b = 1'b1;
cin = 1'b1;
#10a = 1'b1;
b = 1'b0;
cin = 1'b0;
Figure 2.58 Test bench for the full adder module of Figure 2.57.
48 Chapter 2 Overview
Figure 2.59 Binary outputs for the test bench of Figure 2.58.
Figure 2.60 Waveforms for the test bench of Figure 2.58 for the structural full
adder of Figure 2.57.
functionality. The binary outputs and waveforms will be obtained for several combi-
nations of the augend and addend.
full_adder
a a sum sum
b b
cin cin cout cout
Figure 2.62 shows the Verilog code for the full adder. The module is called
full_adder and has five ports: a, b, cin, sum, and cout. Figure 2.63 shows the module
for the test bench. The test bench provides all combinations of the three bits assigned
to augend a, addend b, and the carry-in cin. The binary outputs and waveforms are
shown in Figure 2.64 and Figure 2.65, respectively.
//define wires
wire a, b, cin;
wire sum, cout;
//continuous assign
assign sum = (a ^ b) ^ cin;
assign cout = cin & (a ^ b) | (a & b);
endmodule
When the full adder has been verified for correct functional operation, it is then in-
stantiated into the 4-bit ripple adder structural model. When the operation of the ripple
adder has been verified, it can then be used as a 4-bit-slice module to design a 16-bit or
larger adder. For a 16-bit adder, the 4-bit slice is instantiated four times into a struc-
tural module to produce a 16-bit adder. Because Verilog supports a mixture of mod-
eling styles within a module, the 4-bit adder and 16-bit adder can be designed using
built-in primitives and continuous assignment statements.
In a later chapter, the design of a carry-lookahead adder will be presented. A car-
ry-lookahead adder negates the drawback of the slow carry propagation delay in a rip-
ple adder in which the carry is propagated serially between stages. The carry-
lookahead method adds additional logic in each adder stage such that the carry-in to
any stage is a function only of the two operand bits of that stage and the low-order car-
ry-in to the adder. The carry-in to a stage is no longer the result of the carry-out from
the previous lower-order stage.
reg a, b, cin;
wire sum, cout;
endmodule
Figure 2.63 Test bench for the full adder module of Figure 2.62.
2.7 Introduction to Structural Modeling 51
Figure 2.64 Binary outputs for the full adder of Figure 2.62 obtained from the test
bench of Figure 2.63.
Figure 2.65 Waveforms for the full adder of Figure 2.62 obtained from the test
bench of Figure 2.63.
The logic diagram for the 4-bit ripple adder is shown in Figure 2.66. The module
for the 4-bit ripple adder is shown in Figure 2.67 using four instantiations of the Ver-
ilog code of Figure 2.62. The name of the module is ripple_adder_4; the ports are a,
b, cin, sum, and cout. The keywords input and output tell Verilog which ports are
used for external communication. Input ports are defaulted to wire in Verilog; how-
ever, the keyword wire is listed for all ports for completeness. The carry-out (cout) of
the 4-bit adder is assigned the value of the internal carry c[3].
The full adder is instantiated four times into the structural module of the ripple
adder. In all instantiations, the name of the full adder (full_adder) is used. This is fol-
lowed by the instance name; for example, inst1 and inst2. The form .a(a[0] ) indicates
a connection between port a in the instance module (full_adder) to the expression a[0]
52 Chapter 2 Overview
in the test bench. This method is instantiation by name and eliminates the need to
know the order of the ports in the instantiated module. This is particularly useful when
a large number of ports must be instantiated. The other method is instantiation by po-
sition, which is prone to errors when many ports are to be instantiated in the same order
as indicated in the instance module.
full_adder
a[0] a sum sum[0]
b[0] b inst1
cin cin cout c[0]
full_adder
a[1] a sum sum[1]
b[1] b inst2
cin cout c[1]
full_adder
a[2] a sum sum[2]
b[2] b inst3
cin cout c[2]
full_adder
a[3] a sum sum[3]
b[3] b inst4
c[3]
cin cout cout
In instantiation inst2 of the ripple_adder_4 module, note that port . a of the full
adder connects to a[1] of the ripple adder module. This is also shown in the logic
2.7 Introduction to Structural Modeling 53
diagram of Figure 2.66. In a similar manner, in inst3, the .a port of the instance mod-
ule connects to a[2] of the ripple adder module. The carry-out (.cout) of inst3 con-
nects to c[2] of the structural module. The final carry-out (cout) of the full adder in
inst4 connects to the carry-out of the 4-bit ripple adder.
The test bench for the 4-bit ripple adder module is shown in Figure 2.68. The
name of the module under test is normally used as the name of the test bench module
(with _tb appended). This allows for ease of cross-referencing. All Verilog modules
are saved with the .v extension. Inputs for test benches are declared as type reg be-
cause they retain their values during simulation. Outputs are declared as wire for test
benches.
As explained previously, Verilog provides a mechanism to monitor a variable
when it changes state. This facility is provided by the $monitor task. All parameters
within the quotation marks are displayed in the radix indicated. The parameter values
are obtained from the variables to the right of the quotation marks, in the same posi-
tional relationship. The $monitor continuously monitors the values of the variables
specified in the parameter list (within the quotation marks) and displays all the param-
eters in the list whenever any variable changes value.
input [3:0]a, b;
input cin;
wire [3:0]a, b;
wire cin;
wire [3:0] sum;
wire cout;
wire [3:0]c;//define internal carries
full_adder inst2 (
.a(a[1]),
.b(b[1]),
.cin(c[0]),
.sum(sum[1]),
.cout(c[1])
);
full_adder inst3 (
.a(a[2]),
.b(b[2]),
.cin(c[1]),
.sum(sum[2]),
.cout(c[2])
);
full_adder inst4 (
.a(a[3]),
.b(b[3]),
.cin(c[2]),
.sum(sum[3]),
.cout(c[3])
);
endmodule
Following the $monitor task is a section of code that applies a sequence of input
vectors to the module under test. Six sets of input vectors are shown. The first set of
vectors is applied at time 0, where the augend a is assigned a value of 3. The statement
a = 4'b0011 specifies that the field for the value of a is four bits wide, the radix is bi-
nary, and the value is 3. The addend b is assigned a value of 4; the carry-in c is 0. The
result of the first set of vectors is: sum = 7, cout = 0 as shown in the binary outputs of
Figure 2.69. In the last set of input vectors, a = 15, b = 6, and cin = 1. This generates
the following results: sum = 6, cout = 1, where cout has a weight of 24.
Simulation stops 10 time units after the last set of inputs has been applied. The
unit under test is instantiated by name, not by position. Thus, port . a in the ripple
adder module connects to a of the test bench. The waveforms are shown in Figure
2.70.
2.7 Introduction to Structural Modeling 55
#10 a = 4'b0111;
b = 4'b0110;
cin = 1'b1;
Figure 2.68 Test bench module for the 4-bit ripple adder of Figure 2.67.
Figure 2.69 Binary outputs obtained from the adder test bench of Figure 2.68.
56 Chapter 2 Overview
Figure 2.70 Waveforms for the 4-bit ripple adder test bench of Figure 2.68. The
values for the variables are shown in hexadecimal.
In Section 2.7.2, a full adder was designed using structural modeling. The same adder
will now be designed using mixed-design modeling. The equations for a full adder are
restated below for convenience, where a and b are the augend and addend, respec-
tively, cin is the carry-in to the adder, sum is the result, and cout is the carry-out.
sum = (a ⊕ b) ⊕ cin
cout = cin (a ⊕ b) + ab
2.8 Introduction to Mixed-Design Modeling 57
The full adder of Figure 2.52 is redrawn in Figure 2.71. The Verilog module for
the full adder is shown in Figure 2.72. The variable cout is used in an always state-
ment; therefore, it must be defined as type reg. There is an internal net declared as
net1. Gate instantiation using a built-in primitive is used for the exclusive-OR func-
tion that generates net1. Behavioral modeling uses the always statement to define
cout and dataflow modeling uses continuous assignment to define the sum.
+a net 1
+b +sum
+cin
+cout
//built-in primitive
xor (net1, a, b);
Figure 2.72 Verilog module for the full adder of Figure 2.71 using mixed-design
modeling.
58 Chapter 2 Overview
//behavioral
always @ (a or b or cin)
begin
cout = cin & (a ^ b) | (a & b);
end
//dataflow
assign sum = net1 ^ cin;
endmodule
The test bench is shown in Figure 2.73 in a slightly different version. The input
vectors for each time unit are listed on the same line — a semicolon separates the indi-
vidual bits. The complete set of vectors generates all combinations of the three inputs.
The binary outputs are listed in Figure 2.74 and the data analyzer waveforms are
shown in Figure 2.75. The binary outputs and waveforms are identical to those of the
full adder of Section 2.7.2.
reg a, b, cin;
wire sum, cout;
//display variables
initial
$monitor ("a b cin = %b %b %b, sum = %b, cout = %b",
a, b, cin, sum, cout);
Figure 2.73 Test bench for the mixed-design full adder of Figure 2.72.
2.8 Introduction to Mixed-Design Modeling 59
Figure 2.74 Binary outputs for the mixed-design full adder of Figure 2.72.
Figure 2.75 Waveforms for the mixed-design full adder of Figure 2.72.
60 Chapter 2 Overview
2.9 Problems
2.1 Design a 4-input AND gate using dataflow modeling. Design a test bench and
obtain the binary outputs and waveforms.
2.2 Design a 4-input AND gate using behavioral modeling. Design a test bench
and obtain the binary outputs and waveforms.
2.3 Design a 2-input NAND gate using dataflow modeling. Design a test bench
and obtain the binary outputs and waveforms.
2.4 Design a 2-input NAND gate using behavioral modeling. Design a test bench
and obtain the binary outputs and waveforms.
2.5 Design a 2-input NOR gate using dataflow modeling. Design a test bench and
obtain the binary outputs and waveforms.
2.6 Design a 2-input NOR gate using behavioral modeling. Design a test bench
and obtain the binary outputs and waveforms.
2.8 Implement the logic diagram shown below using dataflow modeling. Design
a test bench and obtain the binary outputs and waveforms.
+x1
+x2
–x3
–x4
+z1
2.9 Implement the logic diagram shown in the previous problem using structural
modeling. Design a test bench and obtain the binary outputs and waveforms.
2.10 Implement the logic diagram shown below using dataflow modeling. Design
a test bench and obtain the binary outputs and waveforms.
2.9 Problems 61
+x1
–x2
+x3 +z1
+x4
2.11 Implement the logic diagram shown below using dataflow modeling. Design
a test bench and obtain the binary outputs and waveforms.
+x1
–x2
+z1
+x3
2.12 Given the Karnaugh map shown below, obtain the minimum sum-of-products
expression and the minimum product-of-sums expression. Then implement
both expressions using behavioral modeling. Design two test benches and
compare the binary outputs and waveforms.
x3 x4
x1 x2 00 01 11 10
00 0 0 1 0
01 0 1 1 0
11 0 1 1 0
10 1 1 1 1
z1
x5 = 0 x5 = 1
x3 x4 x3 x4
x1 x2 00 01 11 10 x1 x2 00 01 11 10
00 0 1 1 0 00 0 1 1 0
01 1 1 1 1 01 1 1 1 1
11 0 1 0 0 11 1 1 0 0
10 0 1 1 1 10 1 1 1 0
z1
2.14 Minimize the following equation, then implement the result using structural
modeling:
2.15 Minimize the following equation, then implement the result using structural
modeling:
2.16 Obtain the equation for a logic circuit that generates an output when the 4-bit
unsigned binary number z1 = x1 x2 x3 x4 is greater than 5, but less than 10,
where x4 is the low-order bit. The equation is to be in a minimal sum-of-prod-
uct form. Then implement the equation using behavioral modeling.
2.17 Plot the expression shown below on a Karnaugh map using x4 as a map-
entered variable and obtain the minimized equation in a sum-of-products
form. Then implement the equation using structural modeling.
z1 = x1' x2' x3' (x4 ) + x1' x2 x3' (x4 ) + x1 x2 x3' (x4 ) + x1 x2' x3 (x4 ) + x1 x2' x3 (x4' )
2.18 Given the Karnaugh map shown below, obtain the minimized expression for
z1. Then implement the result using structural modeling.
2.9 Problems 63
x2 x3
x1 00 01 11 10
0 1 3 2
0 x4 0 0 x4 + x4 '
4 5 7 6
1 x4 ' x4 + x4' x4 ' 0
z1
2.19 Obtain the minimized product-of-sums expression for the function z1 repre-
sented by the Karnaugh map shown below. Then implement the result using
dataflow, behavioral, structural, and mixed-design modeling.
x5 = 0 x5 = 1
x3 x4 x3 x4
x1 x2 00 01 11 10 x1 x2 00 01 11 10
0 2 6 4 1 3 7 5
00 0 0 0 0 00 1 1 1 1
8 10 14 12 9 11 15 13
01 0 0 0 0 01 0 1 1 0
24 26 30 28 25 27 31 29
11 0 1 1 0 11 0 1 1 0
16 18 22 20 17 19 23 21
10 1 1 1 0 10 1 1 1 1
z1
51547_FM.indd 2 1/22/07 3:29:44 PM
3.1 Comments
3.2 Identifiers
3.3 Keywords
3.4 Value Set
3.5 Data Types
3
3.6 Compiler Directives
3.7 Problems
Language Elements
Language elements are the constituent parts of the Verilog language. They consist of
comments, identifiers, keywords, data types, parameters, and a set of values which de-
termines the logic value of a net. Also included in this chapter are compiler directives
and an introduction to system tasks and functions, which are covered in more detail in
Chapter 10.
3.1 Comments
Comments can be inserted into a Verilog module to explain the function of a particular
block of code or a line of code. There are two types of comments: single line and mul-
tiple lines. A single-line comment is indicated by a double forward slash (//) and may
be placed on a separate line or at the end of a line of code, as shown below.
A single-line comment usually explains the function of the following block of code. A
comment on a line of code explains the function of that particular line of code. All
characters that follow the forward slashes are ignored by the compiler.
66 Chapter 3 Language Elements
3.2 Identifiers
An identifier is a name given to an object or variable so that it can be referenced else-
where in the design. Identifier names are used for modules, registers, ports, wires, or
module instance names. Also, begin . . . end blocks may include an identifier. An
identifier consists of a sequence of characters that can be letters, digits, $, or under-
score ( _ ). The first character of an identifier must be a letter or an underscore. The $
character is reserved for system tasks. Identifiers are case sensitive. For example,
Clock and clock are different identifiers. An identifier refers to a unique object in the
module in which it is defined.
When a module is instantiated into another module, the module instance name is
considered to be an identifier. An identifier can contain up to 1024 characters; how-
ever, the first character cannot be a digit. Examples of identifiers are shown below,
where input, output, and reg are keywords.
Escaped identifiers Escaped identifiers begin with a backslash ( \) and end with
a white space (space, tab, or new line) and provide a means to include any printable
ASCII character in an identifier. The backslash and whitespace are not part of the
identifier. An escaped identifier that contains a keyword is different than the keyword.
For example, \ assign is different than the keyword assign. Examples of escaped iden-
tifiers are shown below.
\2005
\~$~
\*****
3.3 Keywords 67
3.3 Keywords
Verilog HDL reserves a list of special predefined, nonescaped identifiers called key-
words which are used to define the language constructs. Only lower case keywords
are used for reserved words. A list of keywords is shown by category in Table 3.1.
Category Keywords
Bidirectional Gates rtran rtranif0 rtranif1
tran tranif0 tranif1
Charge Storage Strengths large medium small
CMOS Gates cmos rcmos
Combinational Logic and buf nand
Gates nor not or
xnor xor
Continuous Assignment assign
Data Types integer real realtime
reg scalared time
tri tri0 tri1
triand trior trireg
vectored wand wire
wor
Module Declaration endmodule module
MOS Gates nmos pmos rnmos
rpmos
Multiway Branching case casex casez
default endcase
Named Event event
Parameters defparam parameter specparam
Port Declaration inout input output
Procedural Constructs always initial
Procedural Continuous assign deassign force
Assignment release
Procedural Flow Control begin disable else
end for forever
fork if join
repeat wait while
Pull Gates pulldown pullup
68 Chapter 3 Language Elements
Category Keywords
Signal Strengths highz0 highz1 pull0
pull1 strong0 strong1
supply0 supply1 weak0
weak1
Specify Block endspecify specify
Tasks and Functions endfunction endtask function
task
Three-State Gates bufif0 bufif1 notif0
notif1
Timing Control edge negedge posedge
User-Defined Primitives endprimitive endtable primitive
table
tran, tranif0, tranif1, rtran, rtranif0, rtranif1 These are bidirectional primitive
gates. The signals on either side of the gates can be specified as inputs or outputs; that
is, either signal can be the driver. The inputs and outputs are classified as scalar sig-
nals. The tran gate (switch) acts as a buffer between the two signals. One terminal
can be declared as input or inout, the other declared as output or inout. The tran
primitive is instantiated as shown below, where the instance name inst1 is optional.
The primitives tranif0 and tranif1 also have two bidirectional terminals plus a
control input. The tranif0 gate connects the two signals only if the control input is a
logical 0; otherwise, the output of the gate is a high impedance. The tranif1 gate trans-
mits only if the control input is a logical 1; otherwise, the output of the gate is a high
impedance. That is, the output logic value is the same as the input logic value or a high
impedance. The tranif0 and tranif1 primitives are instantiated as shown below,
where the control input is listed last.
There are also three bidirectional gates — called resistive gates — that operate
the same as the previous gates, but have a higher source-to-drain impedance. This
3.3 Keywords 69
reduces the signal strength. The resistive gates are declared with the same keywords,
but prefixed with an r — for example, rtran, rtranif0, and rtranif1. The resistive
gates have the same syntax as the non-resistive gates. Figure 3.1 shows the logic di-
agrams for the six types of bidirectional gates.
inout1 inout2
tran / rtran
–control +control
tranif0 / rtranif0 tranif1 / rtranif1
small, medium, large There are three charge storage strengths that relate to the
capacitance of a net: small, medium, and large. A trireg net, which models the
charge stored on a net, can have a charge strength associated with the net when the
drivers are in a high impedance state. The amount of charge stored determines the size
of the capacitance associated with the net. A driver for a trireg net will generate three
states: logic 0, logic 1, or x. If all drivers on the net generate a high impedance output,
then the net retains the last value driven onto the net. The default strength is medium.
Optional delay times can also be specified for a trireg net, indicating the rise de-
lay, the fall delay, and the charge decay time. The charge decays when all the drivers
of the net are in a high impedance state. If no delay is specified, then the charge on the
trireg net does not decay. A trireg net can be forced to a high impedance state by a
force procedural continuous assignment.
70 Chapter 3 Language Elements
cmos The cmos gate can be modeled with an nmos and a pmos device to imple-
ment a cmos transmission gate. There are two enable inputs: one for the n-channel de-
vice and one for the p-channel device. A cmos gate transmits data from input to output
when its two control signals are in complementary states; that is, the n-channel control
is a logic 1 and the p-channel control is a logic 0. If the states of the control signals are
reversed, then the output is in a high impedance state. These control inputs allow both
transistors to be either on (transmit) or off (high impedance). A cmos gate can be in-
stantiated as shown below, where the instance inst1 name is optional.
rcmos The rcmos gate is a high resistive version of the cmos gate.
These are built-in primitive gates used to describe a net and have one or more scalar in-
puts, but only one scalar output. The output signal is listed first, followed by the inputs
in any order. The outputs are declared as wire; the inputs can be declared as either
wire or reg. The gates represent a combinational logic function and can be instanti-
ated into a module, as follows, where the instance name is optional:
Two or more instances of the same type of gate can be specified in the same construct,
as follows:
and This is a built-in primitive gate that operates according to the truth table shown
in Table 3.2 for a 2-input AND gate.
3.3 Keywords 71
Table 3.2 Truth Table for the Logical AND Built-In Primitive
Inputs Output Inputs Output
x1 x2 z1 x1 x2 z1
0 0 0 x 0 0
0 1 0 x 1 x
1 0 0 x x x
1 1 1 x z x
0 x 0 z 0 0
0 z 0 z 1 x
1 x x z x x
1 z x z z x
The x entry in Table 3.2 represents an unknown logic value. The z entry repre-
sents a high impedance state. Simulators use the z value to indicate when the driver of
a net is disabled or not connected. AND gates can be represented by two symbols as
shown below for the AND function and the OR function.
AND gate for the AND function AND gate for the OR function
buf A buf gate is a noninverting primitive with one scalar input and one or more
scalar outputs. The output terminals are listed first when instantiated; the input is list-
ed last, as shown below. The instance name is optional.
The truth table for a buf gate is shown in Table 3.3 for one output.
72 Chapter 3 Language Elements
Input Output
0 0
1 1
x x
z x
nand This is a built-in primitive gate that operates according to the truth table
shown in Table 3.4 for a 2-input NAND gate.
Table 3.4 Truth Table for the Logical NAND Built-In Primitive
Inputs Output Inputs Output
x1 x2 z1 x1 x2 z1
0 0 1 x 0 1
0 1 1 x 1 x
1 0 1 x x x
1 1 0 x z x
0 x 1 z 0 1
0 z 1 z 1 x
1 x x z x x
1 z x z z x
NAND gates can be represented by two symbols as shown below for the AND
function and the OR function.
NAND gate for the AND function NAND gate for the OR function
DeMorgan’s theorems are associated with NAND and NOR gates and convert the
complement of a sum term or a product term into a corresponding product or sum term,
respectively. For every x1 , x2 ∈ B,
3.3 Keywords 73
nor This is a built-in primitive gate that operates according to the truth table shown
in Table 3.5 for a 2-input NOR gate.
Table 3.5 Truth Table for the Logical NOR Built-In Primitive
Inputs Output Inputs Output
x1 x2 z1 x1 x2 z1
0 0 1 x 0 x
0 1 0 x 1 0
1 0 0 x x x
1 1 0 x z x
0 x x z 0 x
0 z x z 1 0
1 x 0 z x x
1 z 0 z z x
NOR gates can be represented by two symbols as shown below for the OR func-
tion and the AND function.
NOR gate for the OR function NOR gate for the AND function
not A not gate is an inverting built-in primitive with one scalar input and one or
more scalar outputs. The output terminals are listed first when instantiated; the input
is listed last, as shown below. The instance name is optional.
The truth table for a not gate is shown in Table 3.6 for one output.